@alfakit/vue 0.1.8 → 0.1.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/components/actions/ActionModal.js.map +1 -1
  3. package/dist/components/actions/ActionModal.vue.d.ts.map +1 -1
  4. package/dist/components/actions/ActionModal.vue_vue_type_script_setup_true_lang.js +1 -1
  5. package/dist/components/actions/ActionModal.vue_vue_type_script_setup_true_lang.js.map +1 -1
  6. package/dist/components/form/FormBlock.js.map +1 -1
  7. package/dist/components/form/FormBlock.vue.d.ts.map +1 -1
  8. package/dist/components/form/FormBlock.vue_vue_type_script_setup_true_lang.js +79 -78
  9. package/dist/components/form/FormBlock.vue_vue_type_script_setup_true_lang.js.map +1 -1
  10. package/dist/components/panel/BottomNav.js.map +1 -1
  11. package/dist/components/panel/BottomNav.vue_vue_type_script_setup_true_lang.js +2 -2
  12. package/dist/components/panel/BottomNav.vue_vue_type_script_setup_true_lang.js.map +1 -1
  13. package/dist/components/panel/KeyboardShortcuts.js.map +1 -1
  14. package/dist/components/panel/KeyboardShortcuts.vue_vue_type_script_setup_true_lang.js +1 -1
  15. package/dist/components/panel/KeyboardShortcuts.vue_vue_type_script_setup_true_lang.js.map +1 -1
  16. package/dist/components/panel/NavGroup.js.map +1 -1
  17. package/dist/components/panel/NavGroup.vue_vue_type_script_setup_true_lang.js +3 -3
  18. package/dist/components/panel/NavGroup.vue_vue_type_script_setup_true_lang.js.map +1 -1
  19. package/dist/components/panel/NavItem.js.map +1 -1
  20. package/dist/components/panel/NavItem.vue.d.ts.map +1 -1
  21. package/dist/components/panel/NavItem.vue_vue_type_script_setup_true_lang.js +1 -1
  22. package/dist/components/panel/NavItem.vue_vue_type_script_setup_true_lang.js.map +1 -1
  23. package/dist/components/panel/NavSubItem.js.map +1 -1
  24. package/dist/components/panel/NavSubItem.vue.d.ts.map +1 -1
  25. package/dist/components/panel/NavSubItem.vue_vue_type_script_setup_true_lang.js +1 -1
  26. package/dist/components/panel/NavSubItem.vue_vue_type_script_setup_true_lang.js.map +1 -1
  27. package/dist/components/ui/TooltipTrigger.js.map +1 -1
  28. package/dist/components/ui/TooltipTrigger.vue.d.ts +2 -2
  29. package/dist/components/ui/TooltipTrigger.vue.d.ts.map +1 -1
  30. package/dist/components/ui/TooltipTrigger.vue_vue_type_script_setup_true_lang.js +10 -7
  31. package/dist/components/ui/TooltipTrigger.vue_vue_type_script_setup_true_lang.js.map +1 -1
  32. package/dist/eject-manifest.json +2 -2
  33. package/dist/layouts/TopNavLayout.js.map +1 -1
  34. package/dist/layouts/TopNavLayout.vue_vue_type_script_setup_true_lang.js +2 -2
  35. package/dist/layouts/TopNavLayout.vue_vue_type_script_setup_true_lang.js.map +1 -1
  36. package/dist/layouts/TopNavMenu.js.map +1 -1
  37. package/dist/layouts/TopNavMenu.vue_vue_type_script_setup_true_lang.js +1 -1
  38. package/dist/layouts/TopNavMenu.vue_vue_type_script_setup_true_lang.js.map +1 -1
  39. package/dist/standalone/AlfakitComponent.js.map +1 -1
  40. package/dist/standalone/AlfakitComponent.vue.d.ts.map +1 -1
  41. package/dist/standalone/AlfakitComponent.vue_vue_type_script_setup_true_lang.js +29 -24
  42. package/dist/standalone/AlfakitComponent.vue_vue_type_script_setup_true_lang.js.map +1 -1
  43. package/dist/standalone.css +10 -6
  44. package/dist/starter-kit/AlfakitStarterKitRoot.js.map +1 -1
  45. package/dist/starter-kit/AlfakitStarterKitRoot.vue.d.ts.map +1 -1
  46. package/dist/starter-kit/AlfakitStarterKitRoot.vue_vue_type_script_setup_true_lang.js +25 -21
  47. package/dist/starter-kit/AlfakitStarterKitRoot.vue_vue_type_script_setup_true_lang.js.map +1 -1
  48. package/package.json +2 -2
  49. package/src/components/actions/ActionModal.vue +2 -0
  50. package/src/components/form/FormBlock.vue +15 -2
  51. package/src/components/panel/BottomNav.vue +2 -2
  52. package/src/components/panel/KeyboardShortcuts.vue +1 -1
  53. package/src/components/panel/NavGroup.vue +3 -3
  54. package/src/components/panel/NavItem.vue +5 -1
  55. package/src/components/panel/NavSubItem.vue +5 -1
  56. package/src/components/ui/TooltipTrigger.vue +4 -1
  57. package/src/layouts/TopNavLayout.vue +2 -2
  58. package/src/layouts/TopNavMenu.vue +1 -1
  59. package/src/standalone/AlfakitComponent.vue +8 -1
  60. package/src/starter-kit/AlfakitStarterKitRoot.vue +6 -0
@@ -1,40 +1,44 @@
1
1
  import { provideAlfakit as e } from "../context.js";
2
2
  import { setToasterId as t, showToast as n } from "../components/notifications/flash-toasts.js";
3
- import r from "../AlfakitRoot.js";
4
- import { starterKitContext as i } from "./runtime.js";
5
- import { STARTER_KIT_TOASTER_ID as a, installStarterKitRuntime as o, syncStarterKitPage as s } from "@alfakit/core";
6
- import { usePage as c } from "@inertiajs/vue3";
7
- import { createElementBlock as l, createVNode as u, defineComponent as d, onMounted as f, onUnmounted as p, openBlock as m, renderSlot as h, unref as g, watch as _, withCtx as v } from "vue";
3
+ import r from "../components/panel/DebugPanelSlot.js";
4
+ import i from "../AlfakitRoot.js";
5
+ import { starterKitContext as a } from "./runtime.js";
6
+ import { STARTER_KIT_TOASTER_ID as o, installStarterKitRuntime as s, syncStarterKitPage as c } from "@alfakit/core";
7
+ import { usePage as l } from "@inertiajs/vue3";
8
+ import { createElementBlock as u, createElementVNode as d, createVNode as f, defineComponent as p, onMounted as m, onUnmounted as h, openBlock as g, renderSlot as _, unref as v, watch as y, withCtx as b } from "vue";
8
9
  //#region src/starter-kit/AlfakitStarterKitRoot.vue?vue&type=script&setup=true&lang.ts
9
- var y = ["dir", "lang"], b = /*@__PURE__*/ d({
10
+ var x = ["dir", "lang"], S = {
11
+ "data-slot": "starter-kit-debug-panel",
12
+ class: "fixed end-16 bottom-4 z-40"
13
+ }, C = /*@__PURE__*/ p({
10
14
  __name: "AlfakitStarterKitRoot",
11
15
  props: { options: {} },
12
- setup(d) {
13
- let b = i(d.options ?? {}), x = c();
14
- return e(b), _(() => x.props.alfakit?.endpoints, (e) => {
15
- e && b.actions.setEndpoints({
16
+ setup(p) {
17
+ let C = a(p.options ?? {}), w = l();
18
+ return e(C), y(() => w.props.alfakit?.endpoints, (e) => {
19
+ e && C.actions.setEndpoints({
16
20
  action: e.action ?? "",
17
21
  modal: e.modal ?? ""
18
22
  });
19
23
  }, {
20
24
  immediate: !0,
21
25
  flush: "sync"
22
- }), f(() => {
23
- o((e) => n(e), (e, t, n) => b.translator.t(e, t, n)), t(a), _(() => x.props, (e) => s(e), { immediate: !0 });
24
- }), p(() => {
25
- s(null), t(void 0);
26
- }), (e, t) => (m(), l("div", {
26
+ }), m(() => {
27
+ s((e) => n(e), (e, t, n) => C.translator.t(e, t, n)), t(o), y(() => w.props, (e) => c(e), { immediate: !0 });
28
+ }), h(() => {
29
+ c(null), t(void 0);
30
+ }), (e, t) => (g(), u("div", {
27
31
  "data-slot": "starter-kit-root",
28
- dir: g(x).props.alfakit?.localization?.direction ?? "ltr",
29
- lang: g(x).props.alfakit?.localization?.tag,
32
+ dir: v(w).props.alfakit?.localization?.direction ?? "ltr",
33
+ lang: v(w).props.alfakit?.localization?.tag,
30
34
  class: "contents"
31
- }, [u(r, { "toaster-id": g(a) }, {
32
- default: v(() => [h(e.$slots, "default")]),
35
+ }, [f(i, { "toaster-id": v(o) }, {
36
+ default: b(() => [_(e.$slots, "default"), d("div", S, [f(r)])]),
33
37
  _: 3
34
- }, 8, ["toaster-id"])], 8, y));
38
+ }, 8, ["toaster-id"])], 8, x));
35
39
  }
36
40
  });
37
41
  //#endregion
38
- export { b as default };
42
+ export { C as default };
39
43
 
40
44
  //# sourceMappingURL=AlfakitStarterKitRoot.vue_vue_type_script_setup_true_lang.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"AlfakitStarterKitRoot.vue_vue_type_script_setup_true_lang.js","names":["props","_openBlock","_createElementBlock","_unref","_createVNode","AlfakitRoot","_withCtx","_renderSlot","AlfakitRoot_default","_hoisted_1","AlfakitStarterKitRoot_vue_vue_type_script_setup_true_lang_default","context","starterKitContext","__props","page","usePage","provideAlfakit","watch","endpoints","onMounted","installStarterKitRuntime","showToast","notification","key","replacements","fallback","setToasterId","STARTER_KIT_TOASTER_ID","syncStarterKitPage","value","onUnmounted","openBlock","createElementBlock","unref","createVNode","withCtx","renderSlot","_ctx"],"sources":["../../src/starter-kit/AlfakitStarterKitRoot.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport {\n STARTER_KIT_TOASTER_ID,\n installStarterKitRuntime,\n syncStarterKitPage,\n type AlfakitPageProps,\n} from '@alfakit/core'\nimport { usePage } from '@inertiajs/vue3'\nimport { onMounted, onUnmounted, watch } from 'vue'\nimport AlfakitRoot from '../AlfakitRoot.vue'\nimport { setToasterId, showToast } from '../components/notifications/flash-toasts'\nimport { provideAlfakit } from '../context'\nimport { starterKitContext, type StarterKitPageOptions } from './runtime'\n\n/**\n * The Inertia layout around every Alfakit page in starter kit mode, inside the host layout:\n * Alfakit's context, modals, toasts and the reading direction. It stays mounted while the\n * user moves between Alfakit pages.\n */\nconst props = defineProps<{ options?: StarterKitPageOptions }>()\nconst context = starterKitContext(props.options ?? {})\nconst page = usePage<AlfakitPageProps>()\n\nprovideAlfakit(context)\n\n// Endpoints follow the open page (synchronously, before children run actions).\nwatch(\n () => page.props.alfakit?.endpoints,\n (endpoints) => {\n if (endpoints) {\n context.actions.setEndpoints({ action: endpoints.action ?? '', modal: endpoints.modal ?? '' })\n }\n },\n { immediate: true, flush: 'sync' },\n)\n\nonMounted(() => {\n installStarterKitRuntime(\n (notification) => showToast(notification),\n (key, replacements, fallback) => context.translator.t(key, replacements, fallback),\n )\n setToasterId(STARTER_KIT_TOASTER_ID)\n\n watch(\n () => page.props,\n (value) => syncStarterKitPage(value as AlfakitPageProps),\n { immediate: true },\n )\n})\n\nonUnmounted(() => {\n // A host page is open: its errors and toasts are the host's again.\n syncStarterKitPage(null)\n setToasterId(undefined)\n})\n</script>\n\n<template>\n <!-- The reading direction and language of Alfakit's content only: the host layout around it\n (sidebar, header) and the app's own pages keep the document's. -->\n <div\n data-slot=\"starter-kit-root\"\n :dir=\"page.props.alfakit?.localization?.direction ?? 'ltr'\"\n :lang=\"page.props.alfakit?.localization?.tag\"\n class=\"contents\"\n >\n <AlfakitRoot :toaster-id=\"STARTER_KIT_TOASTER_ID\">\n <slot />\n </AlfakitRoot>\n </div>\n</template>\n"],"mappings":";;;;;;;;;;;;EAoBA,IAAMW,IAAUC,EAAkBZ,EAAM,WAAW,CAAC,CAAC,GAC/Cc,IAAOC,EAA0B;SAEvCC,EAAeL,CAAO,GAGtBM,QACQH,EAAK,MAAM,SAAS,YACzB,MAAc;GACb,AAAII,KACFP,EAAQ,QAAQ,aAAa;IAAE,QAAQO,EAAU,UAAU;IAAI,OAAOA,EAAU,SAAS;GAAG,CAAC;EAEjG,GACA;GAAE,WAAW;GAAM,OAAO;EAAO,CACnC,GAEAC,QAAgB;GAOd,AANAC,GACG,MAAiBC,EAAUC,CAAY,IACvC,GAAK,GAAc,MAAaX,EAAQ,WAAW,EAAEY,GAAKC,GAAcC,CAAQ,CACnF,GACAC,EAAaC,CAAsB,GAEnCV,QACQH,EAAK,QACV,MAAUc,EAAmBC,CAAyB,GACvD,EAAE,WAAW,GAAK,CACpB;EACF,CAAC,GAEDC,QAAkB;GAGhB,AADAF,EAAmB,IAAI,GACvBF,EAAa,KAAA,CAAS;EACxB,CAAC,cAMCzB,EAAA,GAAAC,EASM,OAAA;GARJ,aAAU;GACT,KAAKC,EAAAW,CAAA,CAAI,CAAC,MAAM,SAAS,cAAc,aAAS;GAChD,MAAMX,EAAAW,CAAA,CAAI,CAAC,MAAM,SAAS,cAAc;GACzC,OAAM;EAENV,GAAAA,CAAAA,EAEcC,GAAA,EAFA,cAAYF,EAAAwB,CAAA,EAAsB,GAAA;GAC9C,SAAArB,QAAQ,CAARC,EAAQ8B,EAAA,QAAA,SAAA,CAAA,CAAA"}
1
+ {"version":3,"file":"AlfakitStarterKitRoot.vue_vue_type_script_setup_true_lang.js","names":["props","_openBlock","_createElementBlock","_unref","_createVNode","AlfakitRoot","_withCtx","_renderSlot","_createElementVNode","DebugPanelSlot","DebugPanelSlot_default","AlfakitRoot_default","_hoisted_1","_hoisted_2","AlfakitStarterKitRoot_vue_vue_type_script_setup_true_lang_default","context","starterKitContext","__props","page","usePage","provideAlfakit","watch","endpoints","onMounted","installStarterKitRuntime","showToast","notification","key","replacements","fallback","setToasterId","STARTER_KIT_TOASTER_ID","syncStarterKitPage","value","onUnmounted","openBlock","createElementBlock","unref","createVNode","withCtx","renderSlot","_ctx","createElementVNode"],"sources":["../../src/starter-kit/AlfakitStarterKitRoot.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport {\n STARTER_KIT_TOASTER_ID,\n installStarterKitRuntime,\n syncStarterKitPage,\n type AlfakitPageProps,\n} from '@alfakit/core'\nimport { usePage } from '@inertiajs/vue3'\nimport { onMounted, onUnmounted, watch } from 'vue'\nimport AlfakitRoot from '../AlfakitRoot.vue'\nimport DebugPanelSlot from '../components/panel/DebugPanelSlot.vue'\nimport { setToasterId, showToast } from '../components/notifications/flash-toasts'\nimport { provideAlfakit } from '../context'\nimport { starterKitContext, type StarterKitPageOptions } from './runtime'\n\n/**\n * The Inertia layout around every Alfakit page in starter kit mode, inside the host layout:\n * Alfakit's context, modals, toasts and the reading direction. It stays mounted while the\n * user moves between Alfakit pages.\n */\nconst props = defineProps<{ options?: StarterKitPageOptions }>()\nconst context = starterKitContext(props.options ?? {})\nconst page = usePage<AlfakitPageProps>()\n\nprovideAlfakit(context)\n\n// Endpoints follow the open page (synchronously, before children run actions).\nwatch(\n () => page.props.alfakit?.endpoints,\n (endpoints) => {\n if (endpoints) {\n context.actions.setEndpoints({ action: endpoints.action ?? '', modal: endpoints.modal ?? '' })\n }\n },\n { immediate: true, flush: 'sync' },\n)\n\nonMounted(() => {\n installStarterKitRuntime(\n (notification) => showToast(notification),\n (key, replacements, fallback) => context.translator.t(key, replacements, fallback),\n )\n setToasterId(STARTER_KIT_TOASTER_ID)\n\n watch(\n () => page.props,\n (value) => syncStarterKitPage(value as AlfakitPageProps),\n { immediate: true },\n )\n})\n\nonUnmounted(() => {\n // A host page is open: its errors and toasts are the host's again.\n syncStarterKitPage(null)\n setToasterId(undefined)\n})\n</script>\n\n<template>\n <!-- The reading direction and language of Alfakit's content only: the host layout around it\n (sidebar, header) and the app's own pages keep the document's. -->\n <div\n data-slot=\"starter-kit-root\"\n :dir=\"page.props.alfakit?.localization?.direction ?? 'ltr'\"\n :lang=\"page.props.alfakit?.localization?.tag\"\n class=\"contents\"\n >\n <AlfakitRoot :toaster-id=\"STARTER_KIT_TOASTER_ID\">\n <slot />\n <!-- The debug panel's button lives in AlfaKit's top bar, which a starter kit doesn't\n render: float it in the corner (nothing without `alfakitDebug`). -->\n <div data-slot=\"starter-kit-debug-panel\" class=\"fixed end-16 bottom-4 z-40\">\n <DebugPanelSlot />\n </div>\n </AlfakitRoot>\n </div>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;EAqBA,IAAMe,IAAUC,EAAkBhB,EAAM,WAAW,CAAC,CAAC,GAC/CkB,IAAOC,EAA0B;SAEvCC,EAAeL,CAAO,GAGtBM,QACQH,EAAK,MAAM,SAAS,YACzB,MAAc;GACb,AAAII,KACFP,EAAQ,QAAQ,aAAa;IAAE,QAAQO,EAAU,UAAU;IAAI,OAAOA,EAAU,SAAS;GAAG,CAAC;EAEjG,GACA;GAAE,WAAW;GAAM,OAAO;EAAO,CACnC,GAEAC,QAAgB;GAOd,AANAC,GACG,MAAiBC,EAAUC,CAAY,IACvC,GAAK,GAAc,MAAaX,EAAQ,WAAW,EAAEY,GAAKC,GAAcC,CAAQ,CACnF,GACAC,EAAaC,CAAsB,GAEnCV,QACQH,EAAK,QACV,MAAUc,EAAmBC,CAAyB,GACvD,EAAE,WAAW,GAAK,CACpB;EACF,CAAC,GAEDC,QAAkB;GAGhB,AADAF,EAAmB,IAAI,GACvBF,EAAa,KAAA,CAAS;EACxB,CAAC,cAMC7B,EAAA,GAAAC,EAcM,OAAA;GAbJ,aAAU;GACT,KAAKC,EAAAe,CAAA,CAAI,CAAC,MAAM,SAAS,cAAc,aAAS;GAChD,MAAMf,EAAAe,CAAA,CAAI,CAAC,MAAM,SAAS,cAAc;GACzC,OAAM;EAENd,GAAAA,CAAAA,EAOcC,GAAA,EAPA,cAAYF,EAAA4B,CAAA,EAAsB,GAAA;GAC9C,SAAAzB,QAAQ,CAARC,EAAQkC,EAAA,QAAA,SAAA,GAGRjC,EAEM,OAFNK,GAEM,CADJT,EAAkBK,CAAA,CAAA,CAAA,CAAA,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alfakit/vue",
3
- "version": "0.1.8",
3
+ "version": "0.1.9",
4
4
  "description": "Vue 3 + shadcn-vue renderer for Alfakit, the Laravel admin panel builder by Alfa Six.",
5
5
  "license": "MIT",
6
6
  "author": "Alfa Six (https://alfasixbh.com)",
@@ -96,7 +96,7 @@
96
96
  "reka-ui": "^2.11.0",
97
97
  "tailwind-merge": "^3.7.0",
98
98
  "vue-sonner": "^2.0.9",
99
- "@alfakit/core": "0.1.8"
99
+ "@alfakit/core": "0.1.9"
100
100
  },
101
101
  "peerDependencies": {
102
102
  "@inertiajs/vue3": "^3.0.0",
@@ -426,6 +426,8 @@ const hasBody = computed(() =>
426
426
  cn(
427
427
  schema.stickyHeader &&
428
428
  'bg-background sticky -top-6 z-10 -mx-6 -mt-6 rounded-t-lg border-b px-6 pt-6 pb-4',
429
+ // Room for the close button (X): a long heading would run under it.
430
+ schema.closeButton !== false && (schema.stickyHeader ? 'pe-12' : 'pe-6'),
429
431
  )
430
432
  "
431
433
  >
@@ -4,6 +4,7 @@ import {
4
4
  FormStore,
5
5
  applyFormRefresh,
6
6
  formActionsVisible,
7
+ formIdPrefix,
7
8
  formIdentity,
8
9
  formRefreshFor,
9
10
  isImplicitSubmit,
@@ -18,9 +19,16 @@ import {
18
19
  wizardProgressStore,
19
20
  } from '@alfakit/core'
20
21
  import { router } from '@inertiajs/vue3'
21
- import { computed, onBeforeUnmount, onMounted, onScopeDispose, watch } from 'vue'
22
+ import { computed, onBeforeUnmount, onMounted, onScopeDispose, useId, watch } from 'vue'
22
23
  import { useStore } from '../../composables/use-store'
23
- import { useActionRunner, useAlfakitProps, usePageSchema, usePanel, useT } from '../../context'
24
+ import {
25
+ useActionRunner,
26
+ useAlfakitProps,
27
+ usePageSchema,
28
+ usePanel,
29
+ useStandalone,
30
+ useT,
31
+ } from '../../context'
24
32
  import ActionList from '../actions/ActionList.vue'
25
33
  import SchemaRenderer from '../schema/SchemaRenderer.vue'
26
34
  import { showToast } from '../notifications/flash-toasts'
@@ -39,9 +47,14 @@ const runner = useActionRunner()
39
47
  const t = useT()
40
48
  const token = computed(() => page.value?.token ?? '')
41
49
 
50
+ // Several standalone components can share a page (and field names): each form gets its own
51
+ // field id prefix, so labels and errors point at their own inputs.
52
+ const standalone = useStandalone()
53
+ const instanceId = useId()
42
54
  const store = new FormStore(props.block, {
43
55
  token: token.value,
44
56
  component: props.block.component,
57
+ idPrefix: standalone ? formIdPrefix(`form-${instanceId}`) : undefined,
45
58
  refreshUrl: panel.value.endpoints.schemaRefresh,
46
59
  optionsUrl: panel.value.endpoints.schemaOptions,
47
60
  validateUrl: panel.value.endpoints.schemaValidate,
@@ -40,7 +40,7 @@ const url = (item: NavigationItemSchema): string => navigationItemUrl(item) ?? '
40
40
  :aria-label="t('navigation', {}, 'Navigation')"
41
41
  class="md:hidden"
42
42
  >
43
- <template v-for="item in items.primary" :key="item.label">
43
+ <template v-for="item in items.primary" :key="item.url ?? item.label">
44
44
  <a
45
45
  v-if="item.openInNewTab"
46
46
  v-bind="item.extraAttributes ?? {}"
@@ -91,7 +91,7 @@ const url = (item: NavigationItemSchema): string => navigationItemUrl(item) ?? '
91
91
  >
92
92
  <Link
93
93
  v-for="item in overflowLinks"
94
- :key="item.label"
94
+ :key="item.url ?? item.label"
95
95
  :href="url(item)"
96
96
  :data-active="isNavigationItemActive(item) ? 'true' : undefined"
97
97
  class="hover:bg-accent data-[active=true]:bg-accent flex min-h-11 items-center gap-3 rounded-md px-3 font-medium [&_svg]:size-4"
@@ -70,7 +70,7 @@ const registrations = computed(() =>
70
70
  config.value
71
71
  ? JSON.stringify({
72
72
  token: page.value?.token ?? '',
73
- home: panel.value.url ?? null,
73
+ home: panel.value.dashboardUrl ?? panel.value.url ?? null,
74
74
  commands: (panel.value.commandPalette?.commands ?? []).filter(
75
75
  (command) => command.keyBindings?.length && !command.disabled,
76
76
  ),
@@ -25,7 +25,7 @@ const contentClass = () => cn(flyout() && 'group-data-[collapsible=icon]:hidden'
25
25
  <SidebarGroup v-if="!props.group.label" v-bind="attributes()">
26
26
  <SidebarGroupContent>
27
27
  <SidebarMenu>
28
- <NavItem v-for="item in props.group.items" :key="item.label" :item="item" />
28
+ <NavItem v-for="item in props.group.items" :key="item.url ?? item.label" :item="item" />
29
29
  </SidebarMenu>
30
30
  </SidebarGroupContent>
31
31
  </SidebarGroup>
@@ -36,7 +36,7 @@ const contentClass = () => cn(flyout() && 'group-data-[collapsible=icon]:hidden'
36
36
  </SidebarGroupLabel>
37
37
  <SidebarGroupContent :class="contentClass()">
38
38
  <SidebarMenu>
39
- <NavItem v-for="item in props.group.items" :key="item.label" :item="item" />
39
+ <NavItem v-for="item in props.group.items" :key="item.url ?? item.label" :item="item" />
40
40
  </SidebarMenu>
41
41
  </SidebarGroupContent>
42
42
  <NavGroupFlyout v-if="flyout()" :group="props.group" />
@@ -67,7 +67,7 @@ const contentClass = () => cn(flyout() && 'group-data-[collapsible=icon]:hidden'
67
67
  <CollapsibleContent>
68
68
  <SidebarGroupContent :class="contentClass()">
69
69
  <SidebarMenu>
70
- <NavItem v-for="item in props.group.items" :key="item.label" :item="item" />
70
+ <NavItem v-for="item in props.group.items" :key="item.url ?? item.label" :item="item" />
71
71
  </SidebarMenu>
72
72
  </SidebarGroupContent>
73
73
  </CollapsibleContent>
@@ -63,7 +63,11 @@ const t = useT()
63
63
  </CollapsibleTrigger>
64
64
  <CollapsibleContent>
65
65
  <SidebarMenuSub>
66
- <NavSubItem v-for="child in props.item.children" :key="child.label" :item="child" />
66
+ <NavSubItem
67
+ v-for="child in props.item.children"
68
+ :key="child.url ?? child.label"
69
+ :item="child"
70
+ />
67
71
  </SidebarMenuSub>
68
72
  </CollapsibleContent>
69
73
  </SidebarMenuItem>
@@ -65,7 +65,11 @@ const badgeClass = computed(() =>
65
65
  </CollapsibleTrigger>
66
66
  <CollapsibleContent>
67
67
  <SidebarMenuSub>
68
- <NavSubItem v-for="child in props.item.children" :key="child.label" :item="child" />
68
+ <NavSubItem
69
+ v-for="child in props.item.children"
70
+ :key="child.url ?? child.label"
71
+ :item="child"
72
+ />
69
73
  </SidebarMenuSub>
70
74
  </CollapsibleContent>
71
75
  </Collapsible>
@@ -5,7 +5,10 @@ const props = defineProps<TooltipTriggerProps>()
5
5
  </script>
6
6
 
7
7
  <template>
8
- <TooltipTrigger v-bind="props" data-slot="tooltip-trigger">
8
+ <!-- With as-child the child keeps its own data-slot (an action's `button`). -->
9
+ <TooltipTrigger
10
+ v-bind="{ ...(props.asChild ? {} : { 'data-slot': 'tooltip-trigger' }), ...props }"
11
+ >
9
12
  <slot />
10
13
  </TooltipTrigger>
11
14
  </template>
@@ -97,7 +97,7 @@ const linkClass =
97
97
  </p>
98
98
  <Link
99
99
  v-for="item in group.items.flatMap((entry) => [entry, ...(entry.children ?? [])])"
100
- :key="item.label"
100
+ :key="item.url ?? item.label"
101
101
  :href="item.url ?? '#'"
102
102
  :data-active="item.active ? 'true' : undefined"
103
103
  class="hover:bg-accent data-[active=true]:bg-accent flex items-center gap-2 rounded-md px-2 py-2 font-medium [&_svg]:size-4"
@@ -133,7 +133,7 @@ const linkClass =
133
133
  :items="group.items"
134
134
  :active="group.items.some(isActive)"
135
135
  />
136
- <template v-for="item in group.items" v-else :key="item.label">
136
+ <template v-for="item in group.items" v-else :key="item.url ?? item.label">
137
137
  <TopNavMenu
138
138
  v-if="item.children && item.children.length > 0"
139
139
  :label="item.label"
@@ -36,7 +36,7 @@ const props = defineProps<{
36
36
  <ChevronDownIcon class="opacity-60" />
37
37
  </DropdownMenuTrigger>
38
38
  <DropdownMenuContent align="start" class="min-w-48">
39
- <DropdownMenuItem v-for="item in props.items" :key="item.label" as-child>
39
+ <DropdownMenuItem v-for="item in props.items" :key="item.url ?? item.label" as-child>
40
40
  <Link
41
41
  v-bind="item.extraAttributes ?? {}"
42
42
  :href="item.url ?? '#'"
@@ -69,9 +69,16 @@ const poll = (target: string, interval: string | number | null | undefined) =>
69
69
  state.poll(target, interval)
70
70
  const refresh = (targets: string[]) => state.refresh(targets)
71
71
 
72
+ // Inside a panel page: the panel's registry and translator, but this component's own action
73
+ // runner, so its actions post to its own endpoints with its own token (not the panel's: 403).
72
74
  const context: AlfakitContextValue = parent
73
75
  ? {
74
76
  ...parent,
77
+ actions: createStandaloneContext(
78
+ { action: props.component.endpoints.action, modal: props.component.endpoints.modal },
79
+ props.components,
80
+ poll,
81
+ ).actions,
75
82
  registry: createStandaloneRegistry(props.components, parent.registry),
76
83
  poll,
77
84
  refresh,
@@ -201,7 +208,7 @@ onMounted(() => {
201
208
  <slot name="footer" />
202
209
  </div>
203
210
  <ActionModals />
204
- <AlfakitToaster v-if="ownsToaster" claimed />
211
+ <AlfakitToaster v-if="ownsToaster" claimed :dir="direction" />
205
212
  </TooltipProvider>
206
213
  </component>
207
214
  </template>
@@ -8,6 +8,7 @@ import {
8
8
  import { usePage } from '@inertiajs/vue3'
9
9
  import { onMounted, onUnmounted, watch } from 'vue'
10
10
  import AlfakitRoot from '../AlfakitRoot.vue'
11
+ import DebugPanelSlot from '../components/panel/DebugPanelSlot.vue'
11
12
  import { setToasterId, showToast } from '../components/notifications/flash-toasts'
12
13
  import { provideAlfakit } from '../context'
13
14
  import { starterKitContext, type StarterKitPageOptions } from './runtime'
@@ -66,6 +67,11 @@ onUnmounted(() => {
66
67
  >
67
68
  <AlfakitRoot :toaster-id="STARTER_KIT_TOASTER_ID">
68
69
  <slot />
70
+ <!-- The debug panel's button lives in AlfaKit's top bar, which a starter kit doesn't
71
+ render: float it in the corner (nothing without `alfakitDebug`). -->
72
+ <div data-slot="starter-kit-debug-panel" class="fixed end-16 bottom-4 z-40">
73
+ <DebugPanelSlot />
74
+ </div>
69
75
  </AlfakitRoot>
70
76
  </div>
71
77
  </template>