@alfakit/vue 0.1.9 → 0.1.10

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 (122) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/dist/app/components.d.ts.map +1 -1
  3. package/dist/app/components.js +1 -0
  4. package/dist/app/components.js.map +1 -1
  5. package/dist/components/dev-tools/DevToolsInspector.js.map +1 -1
  6. package/dist/components/dev-tools/DevToolsInspector.vue.d.ts.map +1 -1
  7. package/dist/components/dev-tools/DevToolsInspector.vue_vue_type_script_setup_true_lang.js +1 -1
  8. package/dist/components/dev-tools/DevToolsInspector.vue_vue_type_script_setup_true_lang.js.map +1 -1
  9. package/dist/components/fields/CheckboxListField.js.map +1 -1
  10. package/dist/components/fields/CheckboxListField.vue.d.ts.map +1 -1
  11. package/dist/components/fields/CheckboxListField.vue_vue_type_script_setup_true_lang.js +2 -2
  12. package/dist/components/fields/CheckboxListField.vue_vue_type_script_setup_true_lang.js.map +1 -1
  13. package/dist/components/fields/DatePickerField.js.map +1 -1
  14. package/dist/components/fields/DatePickerField.vue.d.ts.map +1 -1
  15. package/dist/components/fields/DatePickerField.vue_vue_type_script_setup_true_lang.js +34 -32
  16. package/dist/components/fields/DatePickerField.vue_vue_type_script_setup_true_lang.js.map +1 -1
  17. package/dist/components/fields/RichEditorSuggestions.js.map +1 -1
  18. package/dist/components/fields/RichEditorSuggestions.vue.d.ts +1 -1
  19. package/dist/components/fields/RichEditorSuggestions.vue.d.ts.map +1 -1
  20. package/dist/components/fields/RichEditorSuggestions.vue_vue_type_script_setup_true_lang.js +29 -23
  21. package/dist/components/fields/RichEditorSuggestions.vue_vue_type_script_setup_true_lang.js.map +1 -1
  22. package/dist/components/fields/RichEditorToolbarGroup.js.map +1 -1
  23. package/dist/components/fields/RichEditorToolbarGroup.vue.d.ts.map +1 -1
  24. package/dist/components/fields/RichEditorToolbarGroup.vue_vue_type_script_setup_true_lang.js +9 -4
  25. package/dist/components/fields/RichEditorToolbarGroup.vue_vue_type_script_setup_true_lang.js.map +1 -1
  26. package/dist/components/file-manager/FileManagerView.js.map +1 -1
  27. package/dist/components/file-manager/FileManagerView.vue.d.ts.map +1 -1
  28. package/dist/components/file-manager/FileManagerView.vue_vue_type_script_setup_true_lang.js +5 -1
  29. package/dist/components/file-manager/FileManagerView.vue_vue_type_script_setup_true_lang.js.map +1 -1
  30. package/dist/components/layout/CalloutComponent.js.map +1 -1
  31. package/dist/components/layout/CalloutComponent.vue.d.ts.map +1 -1
  32. package/dist/components/layout/CalloutComponent.vue_vue_type_script_setup_true_lang.js +43 -39
  33. package/dist/components/layout/CalloutComponent.vue_vue_type_script_setup_true_lang.js.map +1 -1
  34. package/dist/components/layout/EmptyStateComponent.js.map +1 -1
  35. package/dist/components/layout/EmptyStateComponent.vue.d.ts.map +1 -1
  36. package/dist/components/layout/EmptyStateComponent.vue_vue_type_script_setup_true_lang.js +29 -26
  37. package/dist/components/layout/EmptyStateComponent.vue_vue_type_script_setup_true_lang.js.map +1 -1
  38. package/dist/components/layout/MixedContent.js.map +1 -1
  39. package/dist/components/layout/MixedContent.vue.d.ts +5 -3
  40. package/dist/components/layout/MixedContent.vue.d.ts.map +1 -1
  41. package/dist/components/layout/MixedContent.vue_vue_type_script_setup_true_lang.js +5 -4
  42. package/dist/components/layout/MixedContent.vue_vue_type_script_setup_true_lang.js.map +1 -1
  43. package/dist/components/layout/SectionComponent.js.map +1 -1
  44. package/dist/components/layout/SectionComponent.vue.d.ts.map +1 -1
  45. package/dist/components/layout/SectionComponent.vue_vue_type_script_setup_true_lang.js +12 -8
  46. package/dist/components/layout/SectionComponent.vue_vue_type_script_setup_true_lang.js.map +1 -1
  47. package/dist/components/notifications/NotificationsMenu.js.map +1 -1
  48. package/dist/components/notifications/NotificationsMenu.vue.d.ts.map +1 -1
  49. package/dist/components/notifications/NotificationsMenu.vue_vue_type_script_setup_true_lang.js +133 -104
  50. package/dist/components/notifications/NotificationsMenu.vue_vue_type_script_setup_true_lang.js.map +1 -1
  51. package/dist/components/panel/ShortcutsOverlay.js.map +1 -1
  52. package/dist/components/panel/ShortcutsOverlay.vue.d.ts.map +1 -1
  53. package/dist/components/panel/ShortcutsOverlay.vue_vue_type_script_setup_true_lang.js +20 -19
  54. package/dist/components/panel/ShortcutsOverlay.vue_vue_type_script_setup_true_lang.js.map +1 -1
  55. package/dist/components/table/ColumnManager.js.map +1 -1
  56. package/dist/components/table/ColumnManager.vue.d.ts.map +1 -1
  57. package/dist/components/table/ColumnManager.vue_vue_type_script_setup_true_lang.js +6 -6
  58. package/dist/components/table/ColumnManager.vue_vue_type_script_setup_true_lang.js.map +1 -1
  59. package/dist/components/table/Spreadsheet.js.map +1 -1
  60. package/dist/components/table/Spreadsheet.vue.d.ts.map +1 -1
  61. package/dist/components/table/Spreadsheet.vue_vue_type_script_setup_true_lang.js +37 -33
  62. package/dist/components/table/Spreadsheet.vue_vue_type_script_setup_true_lang.js.map +1 -1
  63. package/dist/components/translation-manager/TranslationManagerView.js.map +1 -1
  64. package/dist/components/translation-manager/TranslationManagerView.vue.d.ts.map +1 -1
  65. package/dist/components/translation-manager/TranslationManagerView.vue_vue_type_script_setup_true_lang.js +1 -1
  66. package/dist/components/translation-manager/TranslationManagerView.vue_vue_type_script_setup_true_lang.js.map +1 -1
  67. package/dist/components/ui/SidebarMenuButton.js.map +1 -1
  68. package/dist/components/ui/SidebarMenuButton.vue.d.ts.map +1 -1
  69. package/dist/components/ui/SidebarMenuButton.vue_vue_type_script_setup_true_lang.js +12 -12
  70. package/dist/components/ui/SidebarMenuButton.vue_vue_type_script_setup_true_lang.js.map +1 -1
  71. package/dist/components/widgets/StatCard.js.map +1 -1
  72. package/dist/components/widgets/StatCard.vue.d.ts.map +1 -1
  73. package/dist/components/widgets/StatCard.vue_vue_type_script_setup_true_lang.js +30 -30
  74. package/dist/components/widgets/StatCard.vue_vue_type_script_setup_true_lang.js.map +1 -1
  75. package/dist/eject-manifest.json +2 -2
  76. package/dist/pages/AlfakitPage.js.map +1 -1
  77. package/dist/pages/AlfakitPage.vue.d.ts.map +1 -1
  78. package/dist/pages/AlfakitPage.vue_vue_type_script_setup_true_lang.js +16 -19
  79. package/dist/pages/AlfakitPage.vue_vue_type_script_setup_true_lang.js.map +1 -1
  80. package/dist/standalone/AlfakitComponent.js.map +1 -1
  81. package/dist/standalone/AlfakitComponent.vue.d.ts.map +1 -1
  82. package/dist/standalone/AlfakitComponent.vue_vue_type_script_setup_true_lang.js +2 -2
  83. package/dist/standalone/AlfakitComponent.vue_vue_type_script_setup_true_lang.js.map +1 -1
  84. package/dist/standalone/runtime.d.ts.map +1 -1
  85. package/dist/standalone/runtime.js +25 -25
  86. package/dist/standalone/runtime.js.map +1 -1
  87. package/dist/standalone.css +2 -1
  88. package/dist/starter-kit/AlfakitStarterKitRoot.js.map +1 -1
  89. package/dist/starter-kit/AlfakitStarterKitRoot.vue.d.ts.map +1 -1
  90. package/dist/starter-kit/AlfakitStarterKitRoot.vue_vue_type_script_setup_true_lang.js +1 -1
  91. package/dist/starter-kit/AlfakitStarterKitRoot.vue_vue_type_script_setup_true_lang.js.map +1 -1
  92. package/dist/starter-kit/navigation.d.ts +6 -1
  93. package/dist/starter-kit/navigation.d.ts.map +1 -1
  94. package/dist/starter-kit/navigation.js +11 -10
  95. package/dist/starter-kit/navigation.js.map +1 -1
  96. package/dist/styles.css +2 -1
  97. package/dist/themes.css +4 -0
  98. package/package.json +2 -2
  99. package/src/app/components.ts +3 -0
  100. package/src/components/dev-tools/DevToolsInspector.vue +1 -1
  101. package/src/components/fields/CheckboxListField.vue +2 -2
  102. package/src/components/fields/DatePickerField.vue +1 -0
  103. package/src/components/fields/RichEditorSuggestions.vue +13 -6
  104. package/src/components/fields/RichEditorToolbarGroup.vue +16 -1
  105. package/src/components/file-manager/FileManagerView.vue +3 -1
  106. package/src/components/layout/CalloutComponent.vue +15 -2
  107. package/src/components/layout/EmptyStateComponent.vue +10 -1
  108. package/src/components/layout/MixedContent.vue +12 -4
  109. package/src/components/layout/SectionComponent.vue +20 -4
  110. package/src/components/notifications/NotificationsMenu.vue +45 -1
  111. package/src/components/panel/ShortcutsOverlay.vue +27 -22
  112. package/src/components/table/ColumnManager.vue +6 -4
  113. package/src/components/table/Spreadsheet.vue +9 -4
  114. package/src/components/translation-manager/TranslationManagerView.vue +1 -1
  115. package/src/components/ui/SidebarMenuButton.vue +6 -0
  116. package/src/components/widgets/StatCard.vue +6 -3
  117. package/src/pages/AlfakitPage.vue +13 -3
  118. package/src/standalone/AlfakitComponent.vue +8 -4
  119. package/src/standalone/runtime.ts +3 -0
  120. package/src/starter-kit/AlfakitStarterKitRoot.vue +3 -2
  121. package/src/starter-kit/navigation.ts +12 -1
  122. package/src/styles.css +2 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # @alfakit/vue
2
2
 
3
+ ## 0.1.10
4
+
5
+ ### Patch Changes
6
+
7
+ - Back after a save shows fresh data; parent navigation items expand; custom page components render once with live props; no extraneous-attribute warning on `AppPage`; `useAlfakitNavigation().userMenuItems` for starter kits; push toggle in `<AlfakitNotifications />`; rich editor focus, form-context actions and column manager Reset fixes.
8
+
3
9
  ## 0.1.9
4
10
 
5
11
  ### Patch Changes
@@ -1 +1 @@
1
- {"version":3,"file":"components.d.ts","sourceRoot":"","sources":["../../src/app/components.ts"],"names":[],"mappings":"AAAA,OAAO,EAAyB,KAAK,YAAY,EAAE,KAAK,UAAU,EAAE,MAAM,eAAe,CAAA;AAEzF,OAAO,EAAgC,KAAK,WAAW,EAAE,KAAK,QAAQ,EAAE,MAAM,KAAK,CAAA;AAOnF;;;;GAIG;AAEH,0DAA0D;AAC1D,wBAAgB,UAAU,IAAI,WAAW,CAAC,UAAU,GAAG,SAAS,CAAC,CAOhE;AAED,uFAAuF;AACvF,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,WAAW,CAAC,YAAY,GAAG,SAAS,CAAC,CAI/E;AAED;;;GAGG;AACH,eAAO,MAAM,OAAO;;yPAsBlB,CAAA;AAEF,yFAAyF;AACzF,eAAO,MAAM,SAAS;IAGlB,yFAAyF;;;;;;cAE/C,QAAQ,CAAC,OAAO,CAAC;;;;;;;;IAF3D,yFAAyF;;;;;;cAE/C,QAAQ,CAAC,OAAO,CAAC;;;;;4EAmB7D,CAAA;AAoBF,8FAA8F;AAC9F,eAAO,MAAM,QAAQ;;;;;;cAd2B,QAAQ,CAAC,OAAO,CAAC;;;;;;;;;;;cAAjB,QAAQ,CAAC,OAAO,CAAC;;;;;;4EAcH,CAAA;AAE9D,+FAA+F;AAC/F,eAAO,MAAM,SAAS;;;;;;cAjB0B,QAAQ,CAAC,OAAO,CAAC;;;;;;;;;;;cAAjB,QAAQ,CAAC,OAAO,CAAC;;;;;;4EAiBC,CAAA;AAElE,4FAA4F;AAC5F,eAAO,MAAM,YAAY;;;;;;cApBuB,QAAQ,CAAC,OAAO,CAAC;;;;;;;;;;;cAAjB,QAAQ,CAAC,OAAO,CAAC;;;;;;4EAoBa,CAAA;AAE9E,qDAAqD;AACrD,eAAO,MAAM,WAAW;;cAGQ,QAAQ,CAAC,QAAQ,GAAG,QAAQ,CAAC;;;;cACf,QAAQ,CAAC,OAAO,CAAC;;;;;;;cAD/B,QAAQ,CAAC,QAAQ,GAAG,QAAQ,CAAC;;;;cACf,QAAQ,CAAC,OAAO,CAAC;;;;;;4EAa7D,CAAA"}
1
+ {"version":3,"file":"components.d.ts","sourceRoot":"","sources":["../../src/app/components.ts"],"names":[],"mappings":"AAAA,OAAO,EAAyB,KAAK,YAAY,EAAE,KAAK,UAAU,EAAE,MAAM,eAAe,CAAA;AAEzF,OAAO,EAAgC,KAAK,WAAW,EAAE,KAAK,QAAQ,EAAE,MAAM,KAAK,CAAA;AAOnF;;;;GAIG;AAEH,0DAA0D;AAC1D,wBAAgB,UAAU,IAAI,WAAW,CAAC,UAAU,GAAG,SAAS,CAAC,CAOhE;AAED,uFAAuF;AACvF,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,WAAW,CAAC,YAAY,GAAG,SAAS,CAAC,CAI/E;AAED;;;GAGG;AACH,eAAO,MAAM,OAAO;;yPAyBlB,CAAA;AAEF,yFAAyF;AACzF,eAAO,MAAM,SAAS;IAGlB,yFAAyF;;;;;;cAE/C,QAAQ,CAAC,OAAO,CAAC;;;;;;;;IAF3D,yFAAyF;;;;;;cAE/C,QAAQ,CAAC,OAAO,CAAC;;;;;4EAmB7D,CAAA;AAoBF,8FAA8F;AAC9F,eAAO,MAAM,QAAQ;;;;;;cAd2B,QAAQ,CAAC,OAAO,CAAC;;;;;;;;;;;cAAjB,QAAQ,CAAC,OAAO,CAAC;;;;;;4EAcH,CAAA;AAE9D,+FAA+F;AAC/F,eAAO,MAAM,SAAS;;;;;;cAjB0B,QAAQ,CAAC,OAAO,CAAC;;;;;;;;;;;cAAjB,QAAQ,CAAC,OAAO,CAAC;;;;;;4EAiBC,CAAA;AAElE,4FAA4F;AAC5F,eAAO,MAAM,YAAY;;;;;;cApBuB,QAAQ,CAAC,OAAO,CAAC;;;;;;;;;;;cAAjB,QAAQ,CAAC,OAAO,CAAC;;;;;;4EAoBa,CAAA;AAE9E,qDAAqD;AACrD,eAAO,MAAM,WAAW;;cAGQ,QAAQ,CAAC,QAAQ,GAAG,QAAQ,CAAC;;;;cACf,QAAQ,CAAC,OAAO,CAAC;;;;;;;cAD/B,QAAQ,CAAC,QAAQ,GAAG,QAAQ,CAAC;;;;cACf,QAAQ,CAAC,OAAO,CAAC;;;;;;4EAa7D,CAAA"}
@@ -17,6 +17,7 @@ function p(e) {
17
17
  }
18
18
  var m = u({
19
19
  name: "AppPage",
20
+ inheritAttrs: !1,
20
21
  setup(e, { slots: t }) {
21
22
  let i = f(), a = n();
22
23
  return r({
@@ -1 +1 @@
1
- {"version":3,"file":"components.js","names":["PageShell","ContentBlockRenderer","ContentBlockRenderer_default","PageShell_default","useAppPage","props","useAlfakitProps","page","usePageSchema","computed","resolveLazyComponents","usePageBlock","block","key","AppPage","defineComponent","panel","usePanel","providePageActionContext","h","Head","slots","PageBlock","item","cn","namedBlock","prefix","fallbackKey","PageForm","PageTable","PageInfolist","PageWidgets"],"sources":["../../src/app/components.ts"],"sourcesContent":["import { resolveLazyComponents, type ContentBlock, type PageSchema } from '@alfakit/core'\nimport { Head } from '@inertiajs/vue3'\nimport { computed, defineComponent, h, type ComputedRef, type PropType } from 'vue'\nimport { providePageActionContext } from '../components/actions/action-context'\nimport { useAlfakitProps, usePageSchema, usePanel } from '../context'\nimport { cn } from '../lib/utils'\nimport ContentBlockRenderer from '../pages/ContentBlockRenderer.vue'\nimport PageShell from '../pages/PageShell.vue'\n\n/**\n * Building blocks for custom page components: the page shell with the panel layout, and the\n * page's PHP-defined pieces rendered by name, with live fields, actions, uploads and polling\n * working exactly as on schema-driven pages.\n */\n\n/** The current page with its lazy components resolved. */\nexport function useAppPage(): ComputedRef<PageSchema | undefined> {\n const props = useAlfakitProps()\n const page = usePageSchema()\n\n return computed(() =>\n page.value ? resolveLazyComponents(page.value, props.value.alfakitLazy) : undefined,\n )\n}\n\n/** A content block of the page by key (`form:customer`, `table`, `headerWidgets`…). */\nexport function usePageBlock(key: string): ComputedRef<ContentBlock | undefined> {\n const page = useAppPage()\n\n return computed(() => page.value?.content.find((block) => block.key === key))\n}\n\n/**\n * The page's layout (sidebar and topbar, `fullscreen`…), heading, header actions and\n * document title around a custom component: `<AppPage>…</AppPage>`.\n */\nexport const AppPage = defineComponent({\n name: 'AppPage',\n setup(_, { slots }) {\n const page = useAppPage()\n const panel = usePanel()\n\n providePageActionContext({\n get token() {\n return page.value?.token ?? ''\n },\n component: 'page',\n })\n\n return () => {\n if (!page.value) return slots.default?.()\n\n return [\n h(Head, { title: `${page.value.title} - ${panel.value.brandName}` }),\n h(PageShell, { page: page.value }, { default: () => slots.default?.() }),\n ]\n }\n },\n})\n\n/** Render any content block of the page by key; the `fallback` slot when it has none. */\nexport const PageBlock = defineComponent({\n name: 'PageBlock',\n props: {\n /** `form:customer`, `table:products`, `infolist:summary`, `form`, `table`, `content`… */\n name: { type: String, required: true },\n class: { type: [String, Array, Object] as PropType<unknown>, default: undefined },\n },\n setup(props, { slots }) {\n const page = useAppPage()\n const block = computed(() => page.value?.content.find((item) => item.key === props.name))\n\n return () =>\n block.value\n ? h(\n 'div',\n {\n 'data-slot': 'page-block',\n 'data-block': props.name,\n class: cn('min-w-0', props.class as string | undefined),\n },\n [h(ContentBlockRenderer, { block: block.value })],\n )\n : slots.fallback?.()\n },\n})\n\nfunction namedBlock(name: string, prefix: string, fallbackKey: string) {\n return defineComponent({\n name,\n props: {\n name: { type: String, default: undefined },\n class: { type: [String, Array, Object] as PropType<unknown>, default: undefined },\n },\n setup(props, { slots }) {\n return () =>\n h(\n PageBlock,\n { name: props.name ? `${prefix}:${props.name}` : fallbackKey, class: props.class },\n slots,\n )\n },\n })\n}\n\n/** A form defined by `{name}Form(Schema $schema)` (or the page's `form()` without a name). */\nexport const PageForm = namedBlock('PageForm', 'form', 'form')\n\n/** A table defined by `{name}Table(Table $table)` (or the page's `table()` without a name). */\nexport const PageTable = namedBlock('PageTable', 'table', 'table')\n\n/** An infolist defined by `{name}Infolist(Schema $schema)` (or the page's `infolist()`). */\nexport const PageInfolist = namedBlock('PageInfolist', 'infolist', 'infolist')\n\n/** The page's header (default) or footer widgets. */\nexport const PageWidgets = defineComponent({\n name: 'PageWidgets',\n props: {\n position: { type: String as PropType<'header' | 'footer'>, default: 'header' },\n class: { type: [String, Array, Object] as PropType<unknown>, default: undefined },\n },\n setup(props, { slots }) {\n return () =>\n h(\n PageBlock,\n {\n name: props.position === 'footer' ? 'footerWidgets' : 'headerWidgets',\n class: props.class,\n },\n slots,\n )\n },\n})\n"],"mappings":";;;;;;;;;AAgBA,SAAgBI,IAAkD;CAChE,IAAMC,IAAQC,EAAgB,GACxBC,IAAOC,EAAc;CAE3B,OAAOC,QACLF,EAAK,QAAQG,EAAsBH,EAAK,OAAOF,EAAM,MAAM,WAAW,IAAI,KAAA,CAC5E;AACF;AAGA,SAAgBM,EAAa,GAAoD;CAC/E,IAAMJ,IAAOH,EAAW;CAExB,OAAOK,QAAeF,EAAK,OAAO,QAAQ,MAAM,MAAUK,EAAM,QAAQC,CAAG,CAAC;AAC9E;AAMA,IAAaC,IAAUC,EAAgB;CACrC,MAAM;CACN,MAAM,GAAG,EAAE,YAAS;EAClB,IAAMR,IAAOH,EAAW,GAClBY,IAAQC,EAAS;EASvB,OAPAC,EAAyB;GACvB,IAAI,QAAQ;IACV,OAAOX,EAAK,OAAO,SAAS;GAC9B;GACA,WAAW;EACb,CAAC,SAGMA,EAAK,QAEH,CACLY,EAAEC,GAAM,EAAE,OAAO,GAAGb,EAAK,MAAM,MAAM,KAAKS,EAAM,MAAM,YAAY,CAAC,GACnEG,EAAEnB,GAAW,EAAE,MAAMO,EAAK,MAAM,GAAG,EAAE,eAAec,EAAM,UAAU,EAAE,CAAC,CACzE,IALwBA,EAAM,UAAU;CAO5C;AACF,CAAC,GAGYC,IAAYP,EAAgB;CACvC,MAAM;CACN,OAAO;EAEL,MAAM;GAAE,MAAM;GAAQ,UAAU;EAAK;EACrC,OAAO;GAAE,MAAM;IAAC;IAAQ;IAAO;GAAM;GAAwB,SAAS,KAAA;EAAU;CAClF;CACA,MAAM,GAAO,EAAE,YAAS;EACtB,IAAMR,IAAOH,EAAW,GAClBQ,IAAQH,QAAeF,EAAK,OAAO,QAAQ,MAAM,MAASgB,EAAK,QAAQlB,EAAM,IAAI,CAAC;EAExF,aACEO,EAAM,QACFO,EACE,OACA;GACE,aAAa;GACb,cAAcd,EAAM;GACpB,OAAOmB,EAAG,WAAWnB,EAAM,KAA2B;EACxD,GACA,CAACc,EAAElB,GAAsB,EAAE,OAAOW,EAAM,MAAM,CAAC,CAAC,CAClD,IACAS,EAAM,WAAW;CACzB;AACF,CAAC;AAED,SAASI,EAAW,GAAc,GAAgB,GAAqB;CACrE,OAAOV,EAAgB;EACrB;EACA,OAAO;GACL,MAAM;IAAE,MAAM;IAAQ,SAAS,KAAA;GAAU;GACzC,OAAO;IAAE,MAAM;KAAC;KAAQ;KAAO;IAAM;IAAwB,SAAS,KAAA;GAAU;EAClF;EACA,MAAM,GAAO,EAAE,YAAS;GACtB,aACEI,EACEG,GACA;IAAE,MAAMjB,EAAM,OAAO,GAAGqB,EAAO,GAAGrB,EAAM,SAASsB;IAAa,OAAOtB,EAAM;GAAM,GACjFgB,CACF;EACJ;CACF,CAAC;AACH;AAGA,IAAaO,IAAWH,EAAW,YAAY,QAAQ,MAAM,GAGhDI,IAAYJ,EAAW,aAAa,SAAS,OAAO,GAGpDK,IAAeL,EAAW,gBAAgB,YAAY,UAAU,GAGhEM,IAAchB,EAAgB;CACzC,MAAM;CACN,OAAO;EACL,UAAU;GAAE,MAAM;GAAyC,SAAS;EAAS;EAC7E,OAAO;GAAE,MAAM;IAAC;IAAQ;IAAO;GAAM;GAAwB,SAAS,KAAA;EAAU;CAClF;CACA,MAAM,GAAO,EAAE,YAAS;EACtB,aACEI,EACEG,GACA;GACE,MAAMjB,EAAM,aAAa,WAAW,kBAAkB;GACtD,OAAOA,EAAM;EACf,GACAgB,CACF;CACJ;AACF,CAAC"}
1
+ {"version":3,"file":"components.js","names":["PageShell","ContentBlockRenderer","ContentBlockRenderer_default","PageShell_default","useAppPage","props","useAlfakitProps","page","usePageSchema","computed","resolveLazyComponents","usePageBlock","block","key","AppPage","defineComponent","panel","usePanel","providePageActionContext","h","Head","slots","PageBlock","item","cn","namedBlock","prefix","fallbackKey","PageForm","PageTable","PageInfolist","PageWidgets"],"sources":["../../src/app/components.ts"],"sourcesContent":["import { resolveLazyComponents, type ContentBlock, type PageSchema } from '@alfakit/core'\nimport { Head } from '@inertiajs/vue3'\nimport { computed, defineComponent, h, type ComputedRef, type PropType } from 'vue'\nimport { providePageActionContext } from '../components/actions/action-context'\nimport { useAlfakitProps, usePageSchema, usePanel } from '../context'\nimport { cn } from '../lib/utils'\nimport ContentBlockRenderer from '../pages/ContentBlockRenderer.vue'\nimport PageShell from '../pages/PageShell.vue'\n\n/**\n * Building blocks for custom page components: the page shell with the panel layout, and the\n * page's PHP-defined pieces rendered by name, with live fields, actions, uploads and polling\n * working exactly as on schema-driven pages.\n */\n\n/** The current page with its lazy components resolved. */\nexport function useAppPage(): ComputedRef<PageSchema | undefined> {\n const props = useAlfakitProps()\n const page = usePageSchema()\n\n return computed(() =>\n page.value ? resolveLazyComponents(page.value, props.value.alfakitLazy) : undefined,\n )\n}\n\n/** A content block of the page by key (`form:customer`, `table`, `headerWidgets`…). */\nexport function usePageBlock(key: string): ComputedRef<ContentBlock | undefined> {\n const page = useAppPage()\n\n return computed(() => page.value?.content.find((block) => block.key === key))\n}\n\n/**\n * The page's layout (sidebar and topbar, `fullscreen`…), heading, header actions and\n * document title around a custom component: `<AppPage>…</AppPage>`.\n */\nexport const AppPage = defineComponent({\n name: 'AppPage',\n // The page component's undeclared Inertia props fall through to here; AppPage takes no\n // HTML attributes and renders several root nodes.\n inheritAttrs: false,\n setup(_, { slots }) {\n const page = useAppPage()\n const panel = usePanel()\n\n providePageActionContext({\n get token() {\n return page.value?.token ?? ''\n },\n component: 'page',\n })\n\n return () => {\n if (!page.value) return slots.default?.()\n\n return [\n h(Head, { title: `${page.value.title} - ${panel.value.brandName}` }),\n h(PageShell, { page: page.value }, { default: () => slots.default?.() }),\n ]\n }\n },\n})\n\n/** Render any content block of the page by key; the `fallback` slot when it has none. */\nexport const PageBlock = defineComponent({\n name: 'PageBlock',\n props: {\n /** `form:customer`, `table:products`, `infolist:summary`, `form`, `table`, `content`… */\n name: { type: String, required: true },\n class: { type: [String, Array, Object] as PropType<unknown>, default: undefined },\n },\n setup(props, { slots }) {\n const page = useAppPage()\n const block = computed(() => page.value?.content.find((item) => item.key === props.name))\n\n return () =>\n block.value\n ? h(\n 'div',\n {\n 'data-slot': 'page-block',\n 'data-block': props.name,\n class: cn('min-w-0', props.class as string | undefined),\n },\n [h(ContentBlockRenderer, { block: block.value })],\n )\n : slots.fallback?.()\n },\n})\n\nfunction namedBlock(name: string, prefix: string, fallbackKey: string) {\n return defineComponent({\n name,\n props: {\n name: { type: String, default: undefined },\n class: { type: [String, Array, Object] as PropType<unknown>, default: undefined },\n },\n setup(props, { slots }) {\n return () =>\n h(\n PageBlock,\n { name: props.name ? `${prefix}:${props.name}` : fallbackKey, class: props.class },\n slots,\n )\n },\n })\n}\n\n/** A form defined by `{name}Form(Schema $schema)` (or the page's `form()` without a name). */\nexport const PageForm = namedBlock('PageForm', 'form', 'form')\n\n/** A table defined by `{name}Table(Table $table)` (or the page's `table()` without a name). */\nexport const PageTable = namedBlock('PageTable', 'table', 'table')\n\n/** An infolist defined by `{name}Infolist(Schema $schema)` (or the page's `infolist()`). */\nexport const PageInfolist = namedBlock('PageInfolist', 'infolist', 'infolist')\n\n/** The page's header (default) or footer widgets. */\nexport const PageWidgets = defineComponent({\n name: 'PageWidgets',\n props: {\n position: { type: String as PropType<'header' | 'footer'>, default: 'header' },\n class: { type: [String, Array, Object] as PropType<unknown>, default: undefined },\n },\n setup(props, { slots }) {\n return () =>\n h(\n PageBlock,\n {\n name: props.position === 'footer' ? 'footerWidgets' : 'headerWidgets',\n class: props.class,\n },\n slots,\n )\n },\n})\n"],"mappings":";;;;;;;;;AAgBA,SAAgBI,IAAkD;CAChE,IAAMC,IAAQC,EAAgB,GACxBC,IAAOC,EAAc;CAE3B,OAAOC,QACLF,EAAK,QAAQG,EAAsBH,EAAK,OAAOF,EAAM,MAAM,WAAW,IAAI,KAAA,CAC5E;AACF;AAGA,SAAgBM,EAAa,GAAoD;CAC/E,IAAMJ,IAAOH,EAAW;CAExB,OAAOK,QAAeF,EAAK,OAAO,QAAQ,MAAM,MAAUK,EAAM,QAAQC,CAAG,CAAC;AAC9E;AAMA,IAAaC,IAAUC,EAAgB;CACrC,MAAM;CAGN,cAAc;CACd,MAAM,GAAG,EAAE,YAAS;EAClB,IAAMR,IAAOH,EAAW,GAClBY,IAAQC,EAAS;EASvB,OAPAC,EAAyB;GACvB,IAAI,QAAQ;IACV,OAAOX,EAAK,OAAO,SAAS;GAC9B;GACA,WAAW;EACb,CAAC,SAGMA,EAAK,QAEH,CACLY,EAAEC,GAAM,EAAE,OAAO,GAAGb,EAAK,MAAM,MAAM,KAAKS,EAAM,MAAM,YAAY,CAAC,GACnEG,EAAEnB,GAAW,EAAE,MAAMO,EAAK,MAAM,GAAG,EAAE,eAAec,EAAM,UAAU,EAAE,CAAC,CACzE,IALwBA,EAAM,UAAU;CAO5C;AACF,CAAC,GAGYC,IAAYP,EAAgB;CACvC,MAAM;CACN,OAAO;EAEL,MAAM;GAAE,MAAM;GAAQ,UAAU;EAAK;EACrC,OAAO;GAAE,MAAM;IAAC;IAAQ;IAAO;GAAM;GAAwB,SAAS,KAAA;EAAU;CAClF;CACA,MAAM,GAAO,EAAE,YAAS;EACtB,IAAMR,IAAOH,EAAW,GAClBQ,IAAQH,QAAeF,EAAK,OAAO,QAAQ,MAAM,MAASgB,EAAK,QAAQlB,EAAM,IAAI,CAAC;EAExF,aACEO,EAAM,QACFO,EACE,OACA;GACE,aAAa;GACb,cAAcd,EAAM;GACpB,OAAOmB,EAAG,WAAWnB,EAAM,KAA2B;EACxD,GACA,CAACc,EAAElB,GAAsB,EAAE,OAAOW,EAAM,MAAM,CAAC,CAAC,CAClD,IACAS,EAAM,WAAW;CACzB;AACF,CAAC;AAED,SAASI,EAAW,GAAc,GAAgB,GAAqB;CACrE,OAAOV,EAAgB;EACrB;EACA,OAAO;GACL,MAAM;IAAE,MAAM;IAAQ,SAAS,KAAA;GAAU;GACzC,OAAO;IAAE,MAAM;KAAC;KAAQ;KAAO;IAAM;IAAwB,SAAS,KAAA;GAAU;EAClF;EACA,MAAM,GAAO,EAAE,YAAS;GACtB,aACEI,EACEG,GACA;IAAE,MAAMjB,EAAM,OAAO,GAAGqB,EAAO,GAAGrB,EAAM,SAASsB;IAAa,OAAOtB,EAAM;GAAM,GACjFgB,CACF;EACJ;CACF,CAAC;AACH;AAGA,IAAaO,IAAWH,EAAW,YAAY,QAAQ,MAAM,GAGhDI,IAAYJ,EAAW,aAAa,SAAS,OAAO,GAGpDK,IAAeL,EAAW,gBAAgB,YAAY,UAAU,GAGhEM,IAAchB,EAAgB;CACzC,MAAM;CACN,OAAO;EACL,UAAU;GAAE,MAAM;GAAyC,SAAS;EAAS;EAC7E,OAAO;GAAE,MAAM;IAAC;IAAQ;IAAO;GAAM;GAAwB,SAAS,KAAA;EAAU;CAClF;CACA,MAAM,GAAO,EAAE,YAAS;EACtB,aACEI,EACEG,GACA;GACE,MAAMjB,EAAM,aAAa,WAAW,kBAAkB;GACtD,OAAOA,EAAM;EACf,GACAgB,CACF;CACJ;AACF,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"DevToolsInspector.js","names":["_sfc_main","DevToolsInspector_vue_vue_type_script_setup_true_lang_default","DevToolsInspector_default"],"sources":["../../../src/components/dev-tools/DevToolsInspector.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport {\n byteLength,\n formatBytes,\n inspectableProps,\n jsonEntries,\n jsonScalar,\n latestServerTiming,\n prettyJson,\n searchJson,\n} from '@alfakit/core'\nimport { router } from '@inertiajs/vue3'\nimport { BracesIcon, CheckIcon, CopyIcon, ExternalLinkIcon } from '@lucide/vue'\nimport { computed, onBeforeUnmount, onMounted, ref } from 'vue'\nimport { useAlfakitProps, useDirection, useFormatter, useT } from '../../context'\nimport Button from '../ui/Button.vue'\nimport Input from '../ui/Input.vue'\nimport ScrollArea from '../ui/ScrollArea.vue'\nimport Sheet from '../ui/Sheet.vue'\nimport SheetContent from '../ui/SheetContent.vue'\nimport SheetDescription from '../ui/SheetDescription.vue'\nimport SheetHeader from '../ui/SheetHeader.vue'\nimport SheetTitle from '../ui/SheetTitle.vue'\nimport SheetTrigger from '../ui/SheetTrigger.vue'\nimport DevToolsJsonNode from './DevToolsJsonNode.vue'\n\n/**\n * The schema inspector: a floating developer button that opens a drawer with the page's\n * props as a searchable JSON tree (with a copy button), what the context token identifies,\n * the server time reported in `Server-Timing`, the payload size and editor links for the\n * PHP classes behind the page. Rendered only for pages that carry `alfakitDevTools`.\n */\nconst t = useT()\nconst formatter = useFormatter()\nconst direction = useDirection()\nconst props = useAlfakitProps()\nconst tools = computed(() => props.value.alfakitDevTools)\nconst data = computed(() => inspectableProps(props.value as unknown as Record<string, unknown>))\nconst payload = computed(() => byteLength(props.value))\nconst query = ref('')\nconst copied = ref(false)\nconst serverTime = ref<number | null>(null)\nconst search = computed(() => searchJson(data.value, query.value))\nconst roots = computed(() => jsonEntries(data.value))\nconst parameters = computed(() => Object.entries(tools.value?.context.parameters ?? {}))\n\nlet stop: (() => void) | undefined\nlet timer: ReturnType<typeof setTimeout> | undefined\n\nonMounted(() => {\n serverTime.value = latestServerTiming()\n // Re-read after every visit: the latest response carries the newest header.\n stop = router.on('finish', () => {\n serverTime.value = latestServerTiming()\n })\n})\n\nonBeforeUnmount(() => {\n stop?.()\n clearTimeout(timer)\n})\n\nconst copy = () => {\n void navigator.clipboard?.writeText(prettyJson(data.value)).then(() => {\n copied.value = true\n clearTimeout(timer)\n timer = setTimeout(() => (copied.value = false), 2000)\n })\n}\n\nconst time = (value: number | null) =>\n value === null ? t('dev_tools.never', {}, 'Never') : formatter.value.dateTime(value * 1000)\n</script>\n\n<template>\n <Sheet v-if=\"tools\">\n <SheetTrigger as-child>\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"icon\"\n :aria-label=\"t('dev_tools.open', {}, 'Open schema inspector')\"\n data-slot=\"dev-tools-toggle\"\n class=\"fixed end-4 bottom-4 z-40 rounded-full shadow-md\"\n >\n <BracesIcon />\n </Button>\n </SheetTrigger>\n <SheetContent\n :side=\"direction === 'rtl' ? 'left' : 'right'\"\n class=\"flex w-full flex-col gap-0 p-0 sm:max-w-xl\"\n >\n <div data-slot=\"dev-tools\" class=\"flex min-h-0 flex-1 flex-col\">\n <SheetHeader class=\"border-b\">\n <SheetTitle class=\"flex items-center gap-2\">\n <BracesIcon class=\"size-4\" />\n {{ t('dev_tools.title', {}, 'Schema inspector') }}\n </SheetTitle>\n <SheetDescription class=\"truncate font-mono text-xs\" :title=\"tools.context.page\">\n {{ tools.context.page }}\n </SheetDescription>\n </SheetHeader>\n <ScrollArea class=\"min-h-0 flex-1\">\n <div class=\"space-y-5 p-4 text-sm\">\n <dl class=\"grid grid-cols-2 gap-3\">\n <div class=\"rounded-md border p-3\">\n <dt class=\"text-muted-foreground text-xs\">\n {{ t('dev_tools.server_time', {}, 'Server time') }}\n </dt>\n <dd class=\"font-mono text-sm font-semibold tabular-nums\">\n {{\n serverTime === null\n ? t('dev_tools.not_measured', {}, 'Not measured')\n : t(\n 'dev_tools.milliseconds',\n { value: formatter.number(serverTime) },\n ':value ms',\n )\n }}\n </dd>\n </div>\n <div class=\"rounded-md border p-3\">\n <dt class=\"text-muted-foreground text-xs\">\n {{ t('dev_tools.payload', {}, 'Payload size') }}\n </dt>\n <dd class=\"font-mono text-sm font-semibold tabular-nums\">\n {{ formatBytes(payload) }}\n </dd>\n </div>\n </dl>\n\n <section data-slot=\"dev-tools-context\">\n <h3 class=\"mb-2 text-sm font-medium\">\n {{ t('dev_tools.context', {}, 'Context token') }}\n </h3>\n <dl class=\"grid grid-cols-[auto_1fr] gap-x-4 gap-y-1 text-xs\">\n <dt class=\"text-muted-foreground\">{{ t('dev_tools.panel', {}, 'Panel') }}</dt>\n <dd class=\"min-w-0 truncate font-mono\">{{ tools.context.panel }}</dd>\n <dt class=\"text-muted-foreground\">{{ t('dev_tools.page', {}, 'Page') }}</dt>\n <dd class=\"min-w-0 truncate font-mono\" :title=\"tools.context.page\">\n {{ tools.context.page }}\n </dd>\n <template v-if=\"tools.context.component\">\n <dt class=\"text-muted-foreground\">\n {{ t('dev_tools.component', {}, 'Component') }}\n </dt>\n <dd class=\"min-w-0 truncate font-mono\">{{ tools.context.component }}</dd>\n </template>\n <template v-if=\"tools.tenant !== null\">\n <dt class=\"text-muted-foreground\">{{ t('dev_tools.tenant', {}, 'Tenant') }}</dt>\n <dd class=\"min-w-0 truncate font-mono\">{{ tools.tenant }}</dd>\n </template>\n <template v-for=\"[key, value] in parameters\" :key=\"key\">\n <dt class=\"text-muted-foreground\">{{ key }}</dt>\n <dd class=\"min-w-0 truncate font-mono\">{{ jsonScalar(value) }}</dd>\n </template>\n <dt class=\"text-muted-foreground\">\n {{ t('dev_tools.bound_to_user', {}, 'Bound to the user') }}\n </dt>\n <dd>\n {{\n tools.context.boundToUser\n ? t('dev_tools.yes', {}, 'Yes')\n : t('dev_tools.no', {}, 'No')\n }}\n </dd>\n <dt class=\"text-muted-foreground\">{{ t('dev_tools.issued_at', {}, 'Issued') }}</dt>\n <dd>{{ time(tools.context.issuedAt) }}</dd>\n <dt class=\"text-muted-foreground\">\n {{ t('dev_tools.expires_at', {}, 'Expires') }}\n </dt>\n <dd>{{ time(tools.context.expiresAt) }}</dd>\n </dl>\n </section>\n\n <section data-slot=\"dev-tools-classes\">\n <h3 class=\"mb-2 text-sm font-medium\">{{ t('dev_tools.classes', {}, 'Classes') }}</h3>\n <ul class=\"divide-y rounded-md border text-xs\">\n <li\n v-for=\"item in tools.classes\"\n :key=\"item.role\"\n class=\"flex items-center gap-2 px-3 py-1.5\"\n >\n <span class=\"text-muted-foreground w-16 shrink-0\">\n {{ t(`dev_tools.roles.${item.role}`, {}, item.role) }}\n </span>\n <span\n class=\"min-w-0 flex-1 truncate font-mono\"\n :title=\"item.file ? `${item.file}:${item.line ?? 1}` : item.class\"\n >\n {{ item.class }}\n </span>\n <a\n v-if=\"item.url\"\n :href=\"item.url\"\n class=\"text-primary inline-flex shrink-0 items-center gap-1 hover:underline\"\n :aria-label=\"\n t(\n 'dev_tools.open_in_editor',\n { class: item.class, editor: tools.editor ?? '' },\n 'Open :class in :editor',\n )\n \"\n >\n <ExternalLinkIcon class=\"size-3.5\" />\n </a>\n </li>\n </ul>\n <p v-if=\"tools.editor === null\" class=\"text-muted-foreground mt-2 text-xs\">\n {{\n t(\n 'dev_tools.no_editor',\n {},\n 'Set APP_EDITOR (config app.editor) to open these classes in your editor.',\n )\n }}\n </p>\n </section>\n\n <section data-slot=\"dev-tools-schema\">\n <div class=\"mb-2 flex items-center gap-2\">\n <h3 class=\"me-auto text-sm font-medium\">\n {{ t('dev_tools.schema', {}, 'Schema') }}\n </h3>\n <Button type=\"button\" variant=\"ghost\" size=\"sm\" @click=\"copy\">\n <CheckIcon v-if=\"copied\" />\n <CopyIcon v-else />\n {{\n copied\n ? t('dev_tools.copied', {}, 'Copied')\n : t('dev_tools.copy', {}, 'Copy JSON')\n }}\n </Button>\n </div>\n <Input\n v-model=\"query\"\n type=\"search\"\n :placeholder=\"t('dev_tools.search', {}, 'Search keys and values')\"\n :aria-label=\"t('dev_tools.search', {}, 'Search keys and values')\"\n class=\"mb-2 h-8\"\n />\n <p\n v-if=\"query.trim() !== '' && search.matches.size === 0\"\n class=\"text-muted-foreground text-sm\"\n >\n {{\n t('dev_tools.no_matches', { query: query.trim() }, 'Nothing matches “:query”.')\n }}\n </p>\n <ul\n v-else\n dir=\"ltr\"\n role=\"tree\"\n :aria-label=\"t('dev_tools.schema', {}, 'Schema')\"\n class=\"bg-muted/40 overflow-x-auto rounded-md p-2 text-start font-mono text-xs leading-relaxed\"\n >\n <DevToolsJsonNode\n v-for=\"entry in roots\"\n :key=\"entry.path\"\n :entry=\"entry\"\n :depth=\"0\"\n :search=\"search\"\n :query=\"query\"\n />\n </ul>\n </section>\n </div>\n </ScrollArea>\n </div>\n </SheetContent>\n </Sheet>\n</template>\n"],"mappings":""}
1
+ {"version":3,"file":"DevToolsInspector.js","names":["_sfc_main","DevToolsInspector_vue_vue_type_script_setup_true_lang_default","DevToolsInspector_default"],"sources":["../../../src/components/dev-tools/DevToolsInspector.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport {\n byteLength,\n formatBytes,\n inspectableProps,\n jsonEntries,\n jsonScalar,\n latestServerTiming,\n prettyJson,\n searchJson,\n} from '@alfakit/core'\nimport { router } from '@inertiajs/vue3'\nimport { BracesIcon, CheckIcon, CopyIcon, ExternalLinkIcon } from '@lucide/vue'\nimport { computed, onBeforeUnmount, onMounted, ref } from 'vue'\nimport { useAlfakitProps, useDirection, useFormatter, useT } from '../../context'\nimport Button from '../ui/Button.vue'\nimport Input from '../ui/Input.vue'\nimport ScrollArea from '../ui/ScrollArea.vue'\nimport Sheet from '../ui/Sheet.vue'\nimport SheetContent from '../ui/SheetContent.vue'\nimport SheetDescription from '../ui/SheetDescription.vue'\nimport SheetHeader from '../ui/SheetHeader.vue'\nimport SheetTitle from '../ui/SheetTitle.vue'\nimport SheetTrigger from '../ui/SheetTrigger.vue'\nimport DevToolsJsonNode from './DevToolsJsonNode.vue'\n\n/**\n * The schema inspector: a floating developer button that opens a drawer with the page's\n * props as a searchable JSON tree (with a copy button), what the context token identifies,\n * the server time reported in `Server-Timing`, the payload size and editor links for the\n * PHP classes behind the page. Rendered only for pages that carry `alfakitDevTools`.\n */\nconst t = useT()\nconst formatter = useFormatter()\nconst direction = useDirection()\nconst props = useAlfakitProps()\nconst tools = computed(() => props.value.alfakitDevTools)\nconst data = computed(() => inspectableProps(props.value as unknown as Record<string, unknown>))\nconst payload = computed(() => byteLength(props.value))\nconst query = ref('')\nconst copied = ref(false)\nconst serverTime = ref<number | null>(null)\nconst search = computed(() => searchJson(data.value, query.value))\nconst roots = computed(() => jsonEntries(data.value))\nconst parameters = computed(() => Object.entries(tools.value?.context.parameters ?? {}))\n\nlet stop: (() => void) | undefined\nlet timer: ReturnType<typeof setTimeout> | undefined\n\nonMounted(() => {\n serverTime.value = latestServerTiming()\n // Re-read after every visit: the latest response carries the newest header.\n stop = router.on('finish', () => {\n serverTime.value = latestServerTiming()\n })\n})\n\nonBeforeUnmount(() => {\n stop?.()\n clearTimeout(timer)\n})\n\nconst copy = () => {\n void navigator.clipboard?.writeText(prettyJson(data.value)).then(() => {\n copied.value = true\n clearTimeout(timer)\n timer = setTimeout(() => (copied.value = false), 2000)\n })\n}\n\nconst time = (value: number | null) =>\n value === null ? t('dev_tools.never', {}, 'Never') : formatter.value.dateTime(value * 1000)\n</script>\n\n<template>\n <Sheet v-if=\"tools\">\n <SheetTrigger as-child>\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"icon\"\n :aria-label=\"t('dev_tools.open', {}, 'Open schema inspector')\"\n data-slot=\"dev-tools-toggle\"\n class=\"fixed end-4 bottom-16 z-40 rounded-full shadow-md [[data-slot=starter-kit-root]_&]:end-auto [[data-slot=starter-kit-root]_&]:right-4\"\n >\n <BracesIcon />\n </Button>\n </SheetTrigger>\n <SheetContent\n :side=\"direction === 'rtl' ? 'left' : 'right'\"\n class=\"flex w-full flex-col gap-0 p-0 sm:max-w-xl\"\n >\n <div data-slot=\"dev-tools\" class=\"flex min-h-0 flex-1 flex-col\">\n <SheetHeader class=\"border-b\">\n <SheetTitle class=\"flex items-center gap-2\">\n <BracesIcon class=\"size-4\" />\n {{ t('dev_tools.title', {}, 'Schema inspector') }}\n </SheetTitle>\n <SheetDescription class=\"truncate font-mono text-xs\" :title=\"tools.context.page\">\n {{ tools.context.page }}\n </SheetDescription>\n </SheetHeader>\n <ScrollArea class=\"min-h-0 flex-1\">\n <div class=\"space-y-5 p-4 text-sm\">\n <dl class=\"grid grid-cols-2 gap-3\">\n <div class=\"rounded-md border p-3\">\n <dt class=\"text-muted-foreground text-xs\">\n {{ t('dev_tools.server_time', {}, 'Server time') }}\n </dt>\n <dd class=\"font-mono text-sm font-semibold tabular-nums\">\n {{\n serverTime === null\n ? t('dev_tools.not_measured', {}, 'Not measured')\n : t(\n 'dev_tools.milliseconds',\n { value: formatter.number(serverTime) },\n ':value ms',\n )\n }}\n </dd>\n </div>\n <div class=\"rounded-md border p-3\">\n <dt class=\"text-muted-foreground text-xs\">\n {{ t('dev_tools.payload', {}, 'Payload size') }}\n </dt>\n <dd class=\"font-mono text-sm font-semibold tabular-nums\">\n {{ formatBytes(payload) }}\n </dd>\n </div>\n </dl>\n\n <section data-slot=\"dev-tools-context\">\n <h3 class=\"mb-2 text-sm font-medium\">\n {{ t('dev_tools.context', {}, 'Context token') }}\n </h3>\n <dl class=\"grid grid-cols-[auto_1fr] gap-x-4 gap-y-1 text-xs\">\n <dt class=\"text-muted-foreground\">{{ t('dev_tools.panel', {}, 'Panel') }}</dt>\n <dd class=\"min-w-0 truncate font-mono\">{{ tools.context.panel }}</dd>\n <dt class=\"text-muted-foreground\">{{ t('dev_tools.page', {}, 'Page') }}</dt>\n <dd class=\"min-w-0 truncate font-mono\" :title=\"tools.context.page\">\n {{ tools.context.page }}\n </dd>\n <template v-if=\"tools.context.component\">\n <dt class=\"text-muted-foreground\">\n {{ t('dev_tools.component', {}, 'Component') }}\n </dt>\n <dd class=\"min-w-0 truncate font-mono\">{{ tools.context.component }}</dd>\n </template>\n <template v-if=\"tools.tenant !== null\">\n <dt class=\"text-muted-foreground\">{{ t('dev_tools.tenant', {}, 'Tenant') }}</dt>\n <dd class=\"min-w-0 truncate font-mono\">{{ tools.tenant }}</dd>\n </template>\n <template v-for=\"[key, value] in parameters\" :key=\"key\">\n <dt class=\"text-muted-foreground\">{{ key }}</dt>\n <dd class=\"min-w-0 truncate font-mono\">{{ jsonScalar(value) }}</dd>\n </template>\n <dt class=\"text-muted-foreground\">\n {{ t('dev_tools.bound_to_user', {}, 'Bound to the user') }}\n </dt>\n <dd>\n {{\n tools.context.boundToUser\n ? t('dev_tools.yes', {}, 'Yes')\n : t('dev_tools.no', {}, 'No')\n }}\n </dd>\n <dt class=\"text-muted-foreground\">{{ t('dev_tools.issued_at', {}, 'Issued') }}</dt>\n <dd>{{ time(tools.context.issuedAt) }}</dd>\n <dt class=\"text-muted-foreground\">\n {{ t('dev_tools.expires_at', {}, 'Expires') }}\n </dt>\n <dd>{{ time(tools.context.expiresAt) }}</dd>\n </dl>\n </section>\n\n <section data-slot=\"dev-tools-classes\">\n <h3 class=\"mb-2 text-sm font-medium\">{{ t('dev_tools.classes', {}, 'Classes') }}</h3>\n <ul class=\"divide-y rounded-md border text-xs\">\n <li\n v-for=\"item in tools.classes\"\n :key=\"item.role\"\n class=\"flex items-center gap-2 px-3 py-1.5\"\n >\n <span class=\"text-muted-foreground w-16 shrink-0\">\n {{ t(`dev_tools.roles.${item.role}`, {}, item.role) }}\n </span>\n <span\n class=\"min-w-0 flex-1 truncate font-mono\"\n :title=\"item.file ? `${item.file}:${item.line ?? 1}` : item.class\"\n >\n {{ item.class }}\n </span>\n <a\n v-if=\"item.url\"\n :href=\"item.url\"\n class=\"text-primary inline-flex shrink-0 items-center gap-1 hover:underline\"\n :aria-label=\"\n t(\n 'dev_tools.open_in_editor',\n { class: item.class, editor: tools.editor ?? '' },\n 'Open :class in :editor',\n )\n \"\n >\n <ExternalLinkIcon class=\"size-3.5\" />\n </a>\n </li>\n </ul>\n <p v-if=\"tools.editor === null\" class=\"text-muted-foreground mt-2 text-xs\">\n {{\n t(\n 'dev_tools.no_editor',\n {},\n 'Set APP_EDITOR (config app.editor) to open these classes in your editor.',\n )\n }}\n </p>\n </section>\n\n <section data-slot=\"dev-tools-schema\">\n <div class=\"mb-2 flex items-center gap-2\">\n <h3 class=\"me-auto text-sm font-medium\">\n {{ t('dev_tools.schema', {}, 'Schema') }}\n </h3>\n <Button type=\"button\" variant=\"ghost\" size=\"sm\" @click=\"copy\">\n <CheckIcon v-if=\"copied\" />\n <CopyIcon v-else />\n {{\n copied\n ? t('dev_tools.copied', {}, 'Copied')\n : t('dev_tools.copy', {}, 'Copy JSON')\n }}\n </Button>\n </div>\n <Input\n v-model=\"query\"\n type=\"search\"\n :placeholder=\"t('dev_tools.search', {}, 'Search keys and values')\"\n :aria-label=\"t('dev_tools.search', {}, 'Search keys and values')\"\n class=\"mb-2 h-8\"\n />\n <p\n v-if=\"query.trim() !== '' && search.matches.size === 0\"\n class=\"text-muted-foreground text-sm\"\n >\n {{\n t('dev_tools.no_matches', { query: query.trim() }, 'Nothing matches “:query”.')\n }}\n </p>\n <ul\n v-else\n dir=\"ltr\"\n role=\"tree\"\n :aria-label=\"t('dev_tools.schema', {}, 'Schema')\"\n class=\"bg-muted/40 overflow-x-auto rounded-md p-2 text-start font-mono text-xs leading-relaxed\"\n >\n <DevToolsJsonNode\n v-for=\"entry in roots\"\n :key=\"entry.path\"\n :entry=\"entry\"\n :depth=\"0\"\n :search=\"search\"\n :query=\"query\"\n />\n </ul>\n </section>\n </div>\n </ScrollArea>\n </div>\n </SheetContent>\n </Sheet>\n</template>\n"],"mappings":""}
@@ -1 +1 @@
1
- {"version":3,"file":"DevToolsInspector.vue.d.ts","sourceRoot":"","sources":["../../../src/components/dev-tools/DevToolsInspector.vue"],"names":[],"mappings":";AAi6BA,wBAKG"}
1
+ {"version":3,"file":"DevToolsInspector.vue.d.ts","sourceRoot":"","sources":["../../../src/components/dev-tools/DevToolsInspector.vue"],"names":[],"mappings":";AAm6BA,wBAKG"}
@@ -47,7 +47,7 @@ var A = {
47
47
  size: "icon",
48
48
  "aria-label": w(H)("dev_tools.open", {}, "Open schema inspector"),
49
49
  "data-slot": "dev-tools-toggle",
50
- class: "fixed end-4 bottom-4 z-40 rounded-full shadow-md"
50
+ class: "fixed end-4 bottom-16 z-40 rounded-full shadow-md [[data-slot=starter-kit-root]_&]:end-auto [[data-slot=starter-kit-root]_&]:right-4"
51
51
  }, {
52
52
  default: T(() => [v(w(E))]),
53
53
  _: 1
@@ -1 +1 @@
1
- {"version":3,"file":"DevToolsInspector.vue_vue_type_script_setup_true_lang.js","names":["_openBlock","_createBlock","Sheet","_withCtx","_createVNode","SheetTrigger","Button","_unref","SheetContent","_createElementVNode","SheetHeader","SheetTitle","_createTextVNode","_toDisplayString","SheetDescription","ScrollArea","_createElementBlock","_Fragment","_createCommentVNode","_renderList","Input","DevToolsJsonNode","Button_default","Input_default","Sheet_default","SheetContent_default","SheetDescription_default","SheetHeader_default","SheetTitle_default","SheetTrigger_default","ScrollArea_default","DevToolsJsonNode_default","_hoisted_1","_hoisted_2","_hoisted_3","_hoisted_4","_hoisted_5","_hoisted_6","_hoisted_7","_hoisted_8","_hoisted_9","_hoisted_10","_hoisted_11","_hoisted_12","_hoisted_13","_hoisted_14","_hoisted_15","_hoisted_16","_hoisted_17","_hoisted_18","_hoisted_19","_hoisted_20","_hoisted_21","_hoisted_22","_hoisted_23","_hoisted_24","_hoisted_25","_hoisted_26","_hoisted_27","_hoisted_28","_hoisted_29","_hoisted_30","_hoisted_31","_hoisted_32","_hoisted_33","_hoisted_34","_hoisted_35","_hoisted_36","_hoisted_37","DevToolsInspector_vue_vue_type_script_setup_true_lang_default","t","useT","formatter","useFormatter","direction","useDirection","props","useAlfakitProps","tools","computed","data","inspectableProps","payload","byteLength","query","ref","copied","serverTime","search","searchJson","roots","jsonEntries","parameters","stop","timer","onMounted","latestServerTiming","router","onBeforeUnmount","copy","prettyJson","time","value","openBlock","createBlock","withCtx","createVNode","unref","BracesIcon","createElementVNode","createTextVNode","toDisplayString","formatBytes","createElementBlock","Fragment","createCommentVNode","renderList","key","jsonScalar","item","ExternalLinkIcon","CheckIcon","CopyIcon","_cache","$event","entry"],"sources":["../../../src/components/dev-tools/DevToolsInspector.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport {\n byteLength,\n formatBytes,\n inspectableProps,\n jsonEntries,\n jsonScalar,\n latestServerTiming,\n prettyJson,\n searchJson,\n} from '@alfakit/core'\nimport { router } from '@inertiajs/vue3'\nimport { BracesIcon, CheckIcon, CopyIcon, ExternalLinkIcon } from '@lucide/vue'\nimport { computed, onBeforeUnmount, onMounted, ref } from 'vue'\nimport { useAlfakitProps, useDirection, useFormatter, useT } from '../../context'\nimport Button from '../ui/Button.vue'\nimport Input from '../ui/Input.vue'\nimport ScrollArea from '../ui/ScrollArea.vue'\nimport Sheet from '../ui/Sheet.vue'\nimport SheetContent from '../ui/SheetContent.vue'\nimport SheetDescription from '../ui/SheetDescription.vue'\nimport SheetHeader from '../ui/SheetHeader.vue'\nimport SheetTitle from '../ui/SheetTitle.vue'\nimport SheetTrigger from '../ui/SheetTrigger.vue'\nimport DevToolsJsonNode from './DevToolsJsonNode.vue'\n\n/**\n * The schema inspector: a floating developer button that opens a drawer with the page's\n * props as a searchable JSON tree (with a copy button), what the context token identifies,\n * the server time reported in `Server-Timing`, the payload size and editor links for the\n * PHP classes behind the page. Rendered only for pages that carry `alfakitDevTools`.\n */\nconst t = useT()\nconst formatter = useFormatter()\nconst direction = useDirection()\nconst props = useAlfakitProps()\nconst tools = computed(() => props.value.alfakitDevTools)\nconst data = computed(() => inspectableProps(props.value as unknown as Record<string, unknown>))\nconst payload = computed(() => byteLength(props.value))\nconst query = ref('')\nconst copied = ref(false)\nconst serverTime = ref<number | null>(null)\nconst search = computed(() => searchJson(data.value, query.value))\nconst roots = computed(() => jsonEntries(data.value))\nconst parameters = computed(() => Object.entries(tools.value?.context.parameters ?? {}))\n\nlet stop: (() => void) | undefined\nlet timer: ReturnType<typeof setTimeout> | undefined\n\nonMounted(() => {\n serverTime.value = latestServerTiming()\n // Re-read after every visit: the latest response carries the newest header.\n stop = router.on('finish', () => {\n serverTime.value = latestServerTiming()\n })\n})\n\nonBeforeUnmount(() => {\n stop?.()\n clearTimeout(timer)\n})\n\nconst copy = () => {\n void navigator.clipboard?.writeText(prettyJson(data.value)).then(() => {\n copied.value = true\n clearTimeout(timer)\n timer = setTimeout(() => (copied.value = false), 2000)\n })\n}\n\nconst time = (value: number | null) =>\n value === null ? t('dev_tools.never', {}, 'Never') : formatter.value.dateTime(value * 1000)\n</script>\n\n<template>\n <Sheet v-if=\"tools\">\n <SheetTrigger as-child>\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"icon\"\n :aria-label=\"t('dev_tools.open', {}, 'Open schema inspector')\"\n data-slot=\"dev-tools-toggle\"\n class=\"fixed end-4 bottom-4 z-40 rounded-full shadow-md\"\n >\n <BracesIcon />\n </Button>\n </SheetTrigger>\n <SheetContent\n :side=\"direction === 'rtl' ? 'left' : 'right'\"\n class=\"flex w-full flex-col gap-0 p-0 sm:max-w-xl\"\n >\n <div data-slot=\"dev-tools\" class=\"flex min-h-0 flex-1 flex-col\">\n <SheetHeader class=\"border-b\">\n <SheetTitle class=\"flex items-center gap-2\">\n <BracesIcon class=\"size-4\" />\n {{ t('dev_tools.title', {}, 'Schema inspector') }}\n </SheetTitle>\n <SheetDescription class=\"truncate font-mono text-xs\" :title=\"tools.context.page\">\n {{ tools.context.page }}\n </SheetDescription>\n </SheetHeader>\n <ScrollArea class=\"min-h-0 flex-1\">\n <div class=\"space-y-5 p-4 text-sm\">\n <dl class=\"grid grid-cols-2 gap-3\">\n <div class=\"rounded-md border p-3\">\n <dt class=\"text-muted-foreground text-xs\">\n {{ t('dev_tools.server_time', {}, 'Server time') }}\n </dt>\n <dd class=\"font-mono text-sm font-semibold tabular-nums\">\n {{\n serverTime === null\n ? t('dev_tools.not_measured', {}, 'Not measured')\n : t(\n 'dev_tools.milliseconds',\n { value: formatter.number(serverTime) },\n ':value ms',\n )\n }}\n </dd>\n </div>\n <div class=\"rounded-md border p-3\">\n <dt class=\"text-muted-foreground text-xs\">\n {{ t('dev_tools.payload', {}, 'Payload size') }}\n </dt>\n <dd class=\"font-mono text-sm font-semibold tabular-nums\">\n {{ formatBytes(payload) }}\n </dd>\n </div>\n </dl>\n\n <section data-slot=\"dev-tools-context\">\n <h3 class=\"mb-2 text-sm font-medium\">\n {{ t('dev_tools.context', {}, 'Context token') }}\n </h3>\n <dl class=\"grid grid-cols-[auto_1fr] gap-x-4 gap-y-1 text-xs\">\n <dt class=\"text-muted-foreground\">{{ t('dev_tools.panel', {}, 'Panel') }}</dt>\n <dd class=\"min-w-0 truncate font-mono\">{{ tools.context.panel }}</dd>\n <dt class=\"text-muted-foreground\">{{ t('dev_tools.page', {}, 'Page') }}</dt>\n <dd class=\"min-w-0 truncate font-mono\" :title=\"tools.context.page\">\n {{ tools.context.page }}\n </dd>\n <template v-if=\"tools.context.component\">\n <dt class=\"text-muted-foreground\">\n {{ t('dev_tools.component', {}, 'Component') }}\n </dt>\n <dd class=\"min-w-0 truncate font-mono\">{{ tools.context.component }}</dd>\n </template>\n <template v-if=\"tools.tenant !== null\">\n <dt class=\"text-muted-foreground\">{{ t('dev_tools.tenant', {}, 'Tenant') }}</dt>\n <dd class=\"min-w-0 truncate font-mono\">{{ tools.tenant }}</dd>\n </template>\n <template v-for=\"[key, value] in parameters\" :key=\"key\">\n <dt class=\"text-muted-foreground\">{{ key }}</dt>\n <dd class=\"min-w-0 truncate font-mono\">{{ jsonScalar(value) }}</dd>\n </template>\n <dt class=\"text-muted-foreground\">\n {{ t('dev_tools.bound_to_user', {}, 'Bound to the user') }}\n </dt>\n <dd>\n {{\n tools.context.boundToUser\n ? t('dev_tools.yes', {}, 'Yes')\n : t('dev_tools.no', {}, 'No')\n }}\n </dd>\n <dt class=\"text-muted-foreground\">{{ t('dev_tools.issued_at', {}, 'Issued') }}</dt>\n <dd>{{ time(tools.context.issuedAt) }}</dd>\n <dt class=\"text-muted-foreground\">\n {{ t('dev_tools.expires_at', {}, 'Expires') }}\n </dt>\n <dd>{{ time(tools.context.expiresAt) }}</dd>\n </dl>\n </section>\n\n <section data-slot=\"dev-tools-classes\">\n <h3 class=\"mb-2 text-sm font-medium\">{{ t('dev_tools.classes', {}, 'Classes') }}</h3>\n <ul class=\"divide-y rounded-md border text-xs\">\n <li\n v-for=\"item in tools.classes\"\n :key=\"item.role\"\n class=\"flex items-center gap-2 px-3 py-1.5\"\n >\n <span class=\"text-muted-foreground w-16 shrink-0\">\n {{ t(`dev_tools.roles.${item.role}`, {}, item.role) }}\n </span>\n <span\n class=\"min-w-0 flex-1 truncate font-mono\"\n :title=\"item.file ? `${item.file}:${item.line ?? 1}` : item.class\"\n >\n {{ item.class }}\n </span>\n <a\n v-if=\"item.url\"\n :href=\"item.url\"\n class=\"text-primary inline-flex shrink-0 items-center gap-1 hover:underline\"\n :aria-label=\"\n t(\n 'dev_tools.open_in_editor',\n { class: item.class, editor: tools.editor ?? '' },\n 'Open :class in :editor',\n )\n \"\n >\n <ExternalLinkIcon class=\"size-3.5\" />\n </a>\n </li>\n </ul>\n <p v-if=\"tools.editor === null\" class=\"text-muted-foreground mt-2 text-xs\">\n {{\n t(\n 'dev_tools.no_editor',\n {},\n 'Set APP_EDITOR (config app.editor) to open these classes in your editor.',\n )\n }}\n </p>\n </section>\n\n <section data-slot=\"dev-tools-schema\">\n <div class=\"mb-2 flex items-center gap-2\">\n <h3 class=\"me-auto text-sm font-medium\">\n {{ t('dev_tools.schema', {}, 'Schema') }}\n </h3>\n <Button type=\"button\" variant=\"ghost\" size=\"sm\" @click=\"copy\">\n <CheckIcon v-if=\"copied\" />\n <CopyIcon v-else />\n {{\n copied\n ? t('dev_tools.copied', {}, 'Copied')\n : t('dev_tools.copy', {}, 'Copy JSON')\n }}\n </Button>\n </div>\n <Input\n v-model=\"query\"\n type=\"search\"\n :placeholder=\"t('dev_tools.search', {}, 'Search keys and values')\"\n :aria-label=\"t('dev_tools.search', {}, 'Search keys and values')\"\n class=\"mb-2 h-8\"\n />\n <p\n v-if=\"query.trim() !== '' && search.matches.size === 0\"\n class=\"text-muted-foreground text-sm\"\n >\n {{\n t('dev_tools.no_matches', { query: query.trim() }, 'Nothing matches “:query”.')\n }}\n </p>\n <ul\n v-else\n dir=\"ltr\"\n role=\"tree\"\n :aria-label=\"t('dev_tools.schema', {}, 'Schema')\"\n class=\"bg-muted/40 overflow-x-auto rounded-md p-2 text-start font-mono text-xs leading-relaxed\"\n >\n <DevToolsJsonNode\n v-for=\"entry in roots\"\n :key=\"entry.path\"\n :entry=\"entry\"\n :depth=\"0\"\n :search=\"search\"\n :query=\"query\"\n />\n </ul>\n </section>\n </div>\n </ScrollArea>\n </div>\n </SheetContent>\n </Sheet>\n</template>\n"],"mappings":"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"}
1
+ {"version":3,"file":"DevToolsInspector.vue_vue_type_script_setup_true_lang.js","names":["_openBlock","_createBlock","Sheet","_withCtx","_createVNode","SheetTrigger","Button","_unref","SheetContent","_createElementVNode","SheetHeader","SheetTitle","_createTextVNode","_toDisplayString","SheetDescription","ScrollArea","_createElementBlock","_Fragment","_createCommentVNode","_renderList","Input","DevToolsJsonNode","Button_default","Input_default","Sheet_default","SheetContent_default","SheetDescription_default","SheetHeader_default","SheetTitle_default","SheetTrigger_default","ScrollArea_default","DevToolsJsonNode_default","_hoisted_1","_hoisted_2","_hoisted_3","_hoisted_4","_hoisted_5","_hoisted_6","_hoisted_7","_hoisted_8","_hoisted_9","_hoisted_10","_hoisted_11","_hoisted_12","_hoisted_13","_hoisted_14","_hoisted_15","_hoisted_16","_hoisted_17","_hoisted_18","_hoisted_19","_hoisted_20","_hoisted_21","_hoisted_22","_hoisted_23","_hoisted_24","_hoisted_25","_hoisted_26","_hoisted_27","_hoisted_28","_hoisted_29","_hoisted_30","_hoisted_31","_hoisted_32","_hoisted_33","_hoisted_34","_hoisted_35","_hoisted_36","_hoisted_37","DevToolsInspector_vue_vue_type_script_setup_true_lang_default","t","useT","formatter","useFormatter","direction","useDirection","props","useAlfakitProps","tools","computed","data","inspectableProps","payload","byteLength","query","ref","copied","serverTime","search","searchJson","roots","jsonEntries","parameters","stop","timer","onMounted","latestServerTiming","router","onBeforeUnmount","copy","prettyJson","time","value","openBlock","createBlock","withCtx","createVNode","unref","BracesIcon","createElementVNode","createTextVNode","toDisplayString","formatBytes","createElementBlock","Fragment","createCommentVNode","renderList","key","jsonScalar","item","ExternalLinkIcon","CheckIcon","CopyIcon","_cache","$event","entry"],"sources":["../../../src/components/dev-tools/DevToolsInspector.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport {\n byteLength,\n formatBytes,\n inspectableProps,\n jsonEntries,\n jsonScalar,\n latestServerTiming,\n prettyJson,\n searchJson,\n} from '@alfakit/core'\nimport { router } from '@inertiajs/vue3'\nimport { BracesIcon, CheckIcon, CopyIcon, ExternalLinkIcon } from '@lucide/vue'\nimport { computed, onBeforeUnmount, onMounted, ref } from 'vue'\nimport { useAlfakitProps, useDirection, useFormatter, useT } from '../../context'\nimport Button from '../ui/Button.vue'\nimport Input from '../ui/Input.vue'\nimport ScrollArea from '../ui/ScrollArea.vue'\nimport Sheet from '../ui/Sheet.vue'\nimport SheetContent from '../ui/SheetContent.vue'\nimport SheetDescription from '../ui/SheetDescription.vue'\nimport SheetHeader from '../ui/SheetHeader.vue'\nimport SheetTitle from '../ui/SheetTitle.vue'\nimport SheetTrigger from '../ui/SheetTrigger.vue'\nimport DevToolsJsonNode from './DevToolsJsonNode.vue'\n\n/**\n * The schema inspector: a floating developer button that opens a drawer with the page's\n * props as a searchable JSON tree (with a copy button), what the context token identifies,\n * the server time reported in `Server-Timing`, the payload size and editor links for the\n * PHP classes behind the page. Rendered only for pages that carry `alfakitDevTools`.\n */\nconst t = useT()\nconst formatter = useFormatter()\nconst direction = useDirection()\nconst props = useAlfakitProps()\nconst tools = computed(() => props.value.alfakitDevTools)\nconst data = computed(() => inspectableProps(props.value as unknown as Record<string, unknown>))\nconst payload = computed(() => byteLength(props.value))\nconst query = ref('')\nconst copied = ref(false)\nconst serverTime = ref<number | null>(null)\nconst search = computed(() => searchJson(data.value, query.value))\nconst roots = computed(() => jsonEntries(data.value))\nconst parameters = computed(() => Object.entries(tools.value?.context.parameters ?? {}))\n\nlet stop: (() => void) | undefined\nlet timer: ReturnType<typeof setTimeout> | undefined\n\nonMounted(() => {\n serverTime.value = latestServerTiming()\n // Re-read after every visit: the latest response carries the newest header.\n stop = router.on('finish', () => {\n serverTime.value = latestServerTiming()\n })\n})\n\nonBeforeUnmount(() => {\n stop?.()\n clearTimeout(timer)\n})\n\nconst copy = () => {\n void navigator.clipboard?.writeText(prettyJson(data.value)).then(() => {\n copied.value = true\n clearTimeout(timer)\n timer = setTimeout(() => (copied.value = false), 2000)\n })\n}\n\nconst time = (value: number | null) =>\n value === null ? t('dev_tools.never', {}, 'Never') : formatter.value.dateTime(value * 1000)\n</script>\n\n<template>\n <Sheet v-if=\"tools\">\n <SheetTrigger as-child>\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"icon\"\n :aria-label=\"t('dev_tools.open', {}, 'Open schema inspector')\"\n data-slot=\"dev-tools-toggle\"\n class=\"fixed end-4 bottom-16 z-40 rounded-full shadow-md [[data-slot=starter-kit-root]_&]:end-auto [[data-slot=starter-kit-root]_&]:right-4\"\n >\n <BracesIcon />\n </Button>\n </SheetTrigger>\n <SheetContent\n :side=\"direction === 'rtl' ? 'left' : 'right'\"\n class=\"flex w-full flex-col gap-0 p-0 sm:max-w-xl\"\n >\n <div data-slot=\"dev-tools\" class=\"flex min-h-0 flex-1 flex-col\">\n <SheetHeader class=\"border-b\">\n <SheetTitle class=\"flex items-center gap-2\">\n <BracesIcon class=\"size-4\" />\n {{ t('dev_tools.title', {}, 'Schema inspector') }}\n </SheetTitle>\n <SheetDescription class=\"truncate font-mono text-xs\" :title=\"tools.context.page\">\n {{ tools.context.page }}\n </SheetDescription>\n </SheetHeader>\n <ScrollArea class=\"min-h-0 flex-1\">\n <div class=\"space-y-5 p-4 text-sm\">\n <dl class=\"grid grid-cols-2 gap-3\">\n <div class=\"rounded-md border p-3\">\n <dt class=\"text-muted-foreground text-xs\">\n {{ t('dev_tools.server_time', {}, 'Server time') }}\n </dt>\n <dd class=\"font-mono text-sm font-semibold tabular-nums\">\n {{\n serverTime === null\n ? t('dev_tools.not_measured', {}, 'Not measured')\n : t(\n 'dev_tools.milliseconds',\n { value: formatter.number(serverTime) },\n ':value ms',\n )\n }}\n </dd>\n </div>\n <div class=\"rounded-md border p-3\">\n <dt class=\"text-muted-foreground text-xs\">\n {{ t('dev_tools.payload', {}, 'Payload size') }}\n </dt>\n <dd class=\"font-mono text-sm font-semibold tabular-nums\">\n {{ formatBytes(payload) }}\n </dd>\n </div>\n </dl>\n\n <section data-slot=\"dev-tools-context\">\n <h3 class=\"mb-2 text-sm font-medium\">\n {{ t('dev_tools.context', {}, 'Context token') }}\n </h3>\n <dl class=\"grid grid-cols-[auto_1fr] gap-x-4 gap-y-1 text-xs\">\n <dt class=\"text-muted-foreground\">{{ t('dev_tools.panel', {}, 'Panel') }}</dt>\n <dd class=\"min-w-0 truncate font-mono\">{{ tools.context.panel }}</dd>\n <dt class=\"text-muted-foreground\">{{ t('dev_tools.page', {}, 'Page') }}</dt>\n <dd class=\"min-w-0 truncate font-mono\" :title=\"tools.context.page\">\n {{ tools.context.page }}\n </dd>\n <template v-if=\"tools.context.component\">\n <dt class=\"text-muted-foreground\">\n {{ t('dev_tools.component', {}, 'Component') }}\n </dt>\n <dd class=\"min-w-0 truncate font-mono\">{{ tools.context.component }}</dd>\n </template>\n <template v-if=\"tools.tenant !== null\">\n <dt class=\"text-muted-foreground\">{{ t('dev_tools.tenant', {}, 'Tenant') }}</dt>\n <dd class=\"min-w-0 truncate font-mono\">{{ tools.tenant }}</dd>\n </template>\n <template v-for=\"[key, value] in parameters\" :key=\"key\">\n <dt class=\"text-muted-foreground\">{{ key }}</dt>\n <dd class=\"min-w-0 truncate font-mono\">{{ jsonScalar(value) }}</dd>\n </template>\n <dt class=\"text-muted-foreground\">\n {{ t('dev_tools.bound_to_user', {}, 'Bound to the user') }}\n </dt>\n <dd>\n {{\n tools.context.boundToUser\n ? t('dev_tools.yes', {}, 'Yes')\n : t('dev_tools.no', {}, 'No')\n }}\n </dd>\n <dt class=\"text-muted-foreground\">{{ t('dev_tools.issued_at', {}, 'Issued') }}</dt>\n <dd>{{ time(tools.context.issuedAt) }}</dd>\n <dt class=\"text-muted-foreground\">\n {{ t('dev_tools.expires_at', {}, 'Expires') }}\n </dt>\n <dd>{{ time(tools.context.expiresAt) }}</dd>\n </dl>\n </section>\n\n <section data-slot=\"dev-tools-classes\">\n <h3 class=\"mb-2 text-sm font-medium\">{{ t('dev_tools.classes', {}, 'Classes') }}</h3>\n <ul class=\"divide-y rounded-md border text-xs\">\n <li\n v-for=\"item in tools.classes\"\n :key=\"item.role\"\n class=\"flex items-center gap-2 px-3 py-1.5\"\n >\n <span class=\"text-muted-foreground w-16 shrink-0\">\n {{ t(`dev_tools.roles.${item.role}`, {}, item.role) }}\n </span>\n <span\n class=\"min-w-0 flex-1 truncate font-mono\"\n :title=\"item.file ? `${item.file}:${item.line ?? 1}` : item.class\"\n >\n {{ item.class }}\n </span>\n <a\n v-if=\"item.url\"\n :href=\"item.url\"\n class=\"text-primary inline-flex shrink-0 items-center gap-1 hover:underline\"\n :aria-label=\"\n t(\n 'dev_tools.open_in_editor',\n { class: item.class, editor: tools.editor ?? '' },\n 'Open :class in :editor',\n )\n \"\n >\n <ExternalLinkIcon class=\"size-3.5\" />\n </a>\n </li>\n </ul>\n <p v-if=\"tools.editor === null\" class=\"text-muted-foreground mt-2 text-xs\">\n {{\n t(\n 'dev_tools.no_editor',\n {},\n 'Set APP_EDITOR (config app.editor) to open these classes in your editor.',\n )\n }}\n </p>\n </section>\n\n <section data-slot=\"dev-tools-schema\">\n <div class=\"mb-2 flex items-center gap-2\">\n <h3 class=\"me-auto text-sm font-medium\">\n {{ t('dev_tools.schema', {}, 'Schema') }}\n </h3>\n <Button type=\"button\" variant=\"ghost\" size=\"sm\" @click=\"copy\">\n <CheckIcon v-if=\"copied\" />\n <CopyIcon v-else />\n {{\n copied\n ? t('dev_tools.copied', {}, 'Copied')\n : t('dev_tools.copy', {}, 'Copy JSON')\n }}\n </Button>\n </div>\n <Input\n v-model=\"query\"\n type=\"search\"\n :placeholder=\"t('dev_tools.search', {}, 'Search keys and values')\"\n :aria-label=\"t('dev_tools.search', {}, 'Search keys and values')\"\n class=\"mb-2 h-8\"\n />\n <p\n v-if=\"query.trim() !== '' && search.matches.size === 0\"\n class=\"text-muted-foreground text-sm\"\n >\n {{\n t('dev_tools.no_matches', { query: query.trim() }, 'Nothing matches “:query”.')\n }}\n </p>\n <ul\n v-else\n dir=\"ltr\"\n role=\"tree\"\n :aria-label=\"t('dev_tools.schema', {}, 'Schema')\"\n class=\"bg-muted/40 overflow-x-auto rounded-md p-2 text-start font-mono text-xs leading-relaxed\"\n >\n <DevToolsJsonNode\n v-for=\"entry in roots\"\n :key=\"entry.path\"\n :entry=\"entry\"\n :depth=\"0\"\n :search=\"search\"\n :query=\"query\"\n />\n </ul>\n </section>\n </div>\n </ScrollArea>\n </div>\n </SheetContent>\n </Sheet>\n</template>\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"CheckboxListField.js","names":["_sfc_main","CheckboxListField_vue_vue_type_script_setup_true_lang_default","CheckboxListField_default"],"sources":["../../../src/components/fields/CheckboxListField.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { CheckboxListSchema } from '@alfakit/core'\nimport { fieldIds, gridColumnsClasses, htmlLabelToText, isOptionGroup } from '@alfakit/core'\nimport { computed, onBeforeUnmount, ref, watch } from 'vue'\nimport { useT } from '../../context'\nimport { textColorClasses } from '../../lib/colors'\nimport { Icon } from '../../lib/icons'\nimport { cn } from '../../lib/utils'\nimport { useField } from '../form/form-context'\nimport FieldWrapper from '../schema/FieldWrapper.vue'\nimport Button from '../ui/Button.vue'\nimport Checkbox from '../ui/Checkbox.vue'\nimport Input from '../ui/Input.vue'\nimport Label from '../ui/Label.vue'\n\nconst props = defineProps<{ component: CheckboxListSchema }>()\nconst t = useT()\nconst { value, setValue, error, id, disabled, readOnly, aria } = useField<Array<\n string | number\n> | null>(() => props.component)\nconst search = ref('')\n// `searchDebounce()`: the list is filtered by `query`, which trails the input.\nconst query = ref('')\nlet queryTimer: ReturnType<typeof setTimeout> | undefined\n\nwatch(search, (term) => {\n clearTimeout(queryTimer)\n\n if (!props.component.searchDebounce) {\n query.value = term\n\n return\n }\n\n queryTimer = setTimeout(() => (query.value = term), props.component.searchDebounce)\n})\nonBeforeUnmount(() => clearTimeout(queryTimer))\n\nconst selected = computed(() => (value.value ?? []).map(String))\nconst options = computed(() =>\n props.component.options.flatMap((option) => (isOptionGroup(option) ? option.options : [option])),\n)\nconst visible = computed(() =>\n options.value.filter((option) =>\n (props.component.allowHtml ? htmlLabelToText(option.label) : option.label)\n .toLowerCase()\n .includes(query.value.toLowerCase()),\n ),\n)\n\n/**\n * `gridDirection('column')`: options flow down each column (CSS columns). Classes are\n * spelled out so Tailwind generates them.\n */\nconst COLUMN_FLOW_CLASSES: Record<number, string> = {\n 2: 'md:columns-2',\n 3: 'md:columns-3',\n 4: 'md:columns-4',\n 5: 'md:columns-5',\n 6: 'md:columns-6',\n}\nconst columnFlow = computed(\n () => props.component.gridDirection === 'column' && (props.component.gridColumns ?? 1) > 1,\n)\n\nconst toggle = (key: string, checked: boolean) => {\n setValue(checked ? [...selected.value, key] : selected.value.filter((item) => item !== key))\n}\n</script>\n\n<template>\n <FieldWrapper :field=\"props.component\" :html-for=\"id\" :error=\"error\">\n <div class=\"flex flex-col gap-2\">\n <div\n v-if=\"props.component.searchable || (props.component.bulkToggleable && !readOnly)\"\n class=\"flex items-center gap-2\"\n >\n <Input\n v-if=\"props.component.searchable\"\n v-model=\"search\"\n :placeholder=\"props.component.searchPrompt ?? t('search', {}, 'Search')\"\n :aria-label=\"props.component.searchPrompt ?? t('search', {}, 'Search')\"\n class=\"h-8\"\n />\n <div v-if=\"props.component.bulkToggleable && !readOnly\" class=\"flex gap-1\">\n <Button\n v-if=\"!props.component.selectAllAction?.hidden\"\n type=\"button\"\n variant=\"link\"\n size=\"sm\"\n data-slot=\"select-all\"\n :disabled=\"disabled\"\n @click=\"\n setValue(options.filter((option) => !option.disabled).map((option) => option.value))\n \"\n >\n <Icon\n v-if=\"props.component.selectAllAction?.icon\"\n :name=\"props.component.selectAllAction.icon\"\n />\n {{ props.component.selectAllAction?.label ?? t('table.select_all', {}, 'Select all') }}\n </Button>\n <Button\n v-if=\"!props.component.deselectAllAction?.hidden\"\n type=\"button\"\n variant=\"link\"\n size=\"sm\"\n data-slot=\"deselect-all\"\n :disabled=\"disabled\"\n @click=\"setValue([])\"\n >\n <Icon\n v-if=\"props.component.deselectAllAction?.icon\"\n :name=\"props.component.deselectAllAction.icon\"\n />\n {{\n props.component.deselectAllAction?.label ??\n t('table.deselect_all', {}, 'Deselect all')\n }}\n </Button>\n </div>\n </div>\n <div\n :data-grid-direction=\"props.component.gridDirection\"\n :class=\"\n cn(\n props.component.inline\n ? 'flex flex-wrap gap-4'\n : columnFlow\n ? cn(\n 'gap-x-3 *:mb-3 *:break-inside-avoid',\n COLUMN_FLOW_CLASSES[props.component.gridColumns ?? 1],\n )\n : 'grid gap-3',\n !props.component.inline &&\n !columnFlow &&\n gridColumnsClasses(\n props.component.gridColumns\n ? { default: 1, md: props.component.gridColumns }\n : { default: 1 },\n ),\n )\n \"\n role=\"group\"\n :aria-labelledby=\"props.component.label ? fieldIds(id).label : undefined\"\n :aria-describedby=\"aria['aria-describedby']\"\n >\n <div v-for=\"option in visible\" :key=\"option.value\" class=\"flex items-start gap-2\">\n <Checkbox\n :id=\"`${id}-${option.value}`\"\n :model-value=\"selected.includes(option.value)\"\n :disabled=\"disabled || readOnly || option.disabled\"\n :aria-invalid=\"aria['aria-invalid']\"\n class=\"mt-0.5\"\n @update:model-value=\"toggle(option.value, $event === true)\"\n />\n <div class=\"grid gap-0.5\">\n <Label\n :for=\"`${id}-${option.value}`\"\n :class=\"cn('font-normal', option.color && textColorClasses[option.color])\"\n ><Icon v-if=\"option.icon\" :name=\"option.icon\" class=\"size-4\" /><span\n v-if=\"props.component.allowHtml\"\n v-html=\"option.label\"\n /><template v-else>{{ option.label }}</template></Label\n >\n <p v-if=\"option.description\" class=\"text-muted-foreground text-xs\">\n {{ option.description }}\n </p>\n </div>\n </div>\n </div>\n <p\n v-if=\"props.component.searchable && query !== '' && visible.length === 0\"\n data-slot=\"checkbox-list-empty\"\n role=\"status\"\n class=\"text-muted-foreground text-sm\"\n >\n {{ props.component.noSearchResultsMessage ?? t('no_results', {}, 'No results.') }}\n </p>\n </div>\n </FieldWrapper>\n</template>\n"],"mappings":""}
1
+ {"version":3,"file":"CheckboxListField.js","names":["_sfc_main","CheckboxListField_vue_vue_type_script_setup_true_lang_default","CheckboxListField_default"],"sources":["../../../src/components/fields/CheckboxListField.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { CheckboxListSchema } from '@alfakit/core'\nimport { fieldIds, gridColumnsClasses, htmlLabelToText, isOptionGroup } from '@alfakit/core'\nimport { computed, onBeforeUnmount, ref, watch } from 'vue'\nimport { useT } from '../../context'\nimport { textColorClasses } from '../../lib/colors'\nimport { Icon } from '../../lib/icons'\nimport { cn } from '../../lib/utils'\nimport { useField } from '../form/form-context'\nimport FieldWrapper from '../schema/FieldWrapper.vue'\nimport Button from '../ui/Button.vue'\nimport Checkbox from '../ui/Checkbox.vue'\nimport Input from '../ui/Input.vue'\nimport Label from '../ui/Label.vue'\n\nconst props = defineProps<{ component: CheckboxListSchema }>()\nconst t = useT()\nconst { value, setValue, error, id, disabled, readOnly, aria } = useField<Array<\n string | number\n> | null>(() => props.component)\nconst search = ref('')\n// `searchDebounce()`: the list is filtered by `query`, which trails the input.\nconst query = ref('')\nlet queryTimer: ReturnType<typeof setTimeout> | undefined\n\nwatch(search, (term) => {\n clearTimeout(queryTimer)\n\n if (!props.component.searchDebounce) {\n query.value = term\n\n return\n }\n\n queryTimer = setTimeout(() => (query.value = term), props.component.searchDebounce)\n})\nonBeforeUnmount(() => clearTimeout(queryTimer))\n\nconst selected = computed(() => (value.value ?? []).map(String))\nconst options = computed(() =>\n props.component.options.flatMap((option) => (isOptionGroup(option) ? option.options : [option])),\n)\nconst visible = computed(() =>\n options.value.filter((option) =>\n (props.component.allowHtml ? htmlLabelToText(option.label) : option.label)\n .toLowerCase()\n .includes(query.value.toLowerCase()),\n ),\n)\n\n/**\n * `gridDirection('column')`: options flow down each column (CSS columns). Classes are\n * spelled out so Tailwind generates them.\n */\nconst COLUMN_FLOW_CLASSES: Record<number, string> = {\n 2: 'md:columns-2',\n 3: 'md:columns-3',\n 4: 'md:columns-4',\n 5: 'md:columns-5',\n 6: 'md:columns-6',\n}\nconst columnFlow = computed(\n () => props.component.gridDirection === 'column' && (props.component.gridColumns ?? 1) > 1,\n)\n\nconst toggle = (key: string, checked: boolean) => {\n setValue(checked ? [...selected.value, key] : selected.value.filter((item) => item !== key))\n}\n</script>\n\n<template>\n <FieldWrapper :field=\"props.component\" :html-for=\"id\" :error=\"error\">\n <div class=\"flex flex-col gap-2\">\n <div\n v-if=\"props.component.searchable || (props.component.bulkToggleable && !readOnly)\"\n class=\"flex min-w-0 flex-wrap items-center gap-2\"\n >\n <Input\n v-if=\"props.component.searchable\"\n v-model=\"search\"\n :placeholder=\"props.component.searchPrompt ?? t('search', {}, 'Search')\"\n :aria-label=\"props.component.searchPrompt ?? t('search', {}, 'Search')\"\n class=\"h-8\"\n />\n <div v-if=\"props.component.bulkToggleable && !readOnly\" class=\"flex flex-wrap gap-1\">\n <Button\n v-if=\"!props.component.selectAllAction?.hidden\"\n type=\"button\"\n variant=\"link\"\n size=\"sm\"\n data-slot=\"select-all\"\n :disabled=\"disabled\"\n @click=\"\n setValue(options.filter((option) => !option.disabled).map((option) => option.value))\n \"\n >\n <Icon\n v-if=\"props.component.selectAllAction?.icon\"\n :name=\"props.component.selectAllAction.icon\"\n />\n {{ props.component.selectAllAction?.label ?? t('table.select_all', {}, 'Select all') }}\n </Button>\n <Button\n v-if=\"!props.component.deselectAllAction?.hidden\"\n type=\"button\"\n variant=\"link\"\n size=\"sm\"\n data-slot=\"deselect-all\"\n :disabled=\"disabled\"\n @click=\"setValue([])\"\n >\n <Icon\n v-if=\"props.component.deselectAllAction?.icon\"\n :name=\"props.component.deselectAllAction.icon\"\n />\n {{\n props.component.deselectAllAction?.label ??\n t('table.deselect_all', {}, 'Deselect all')\n }}\n </Button>\n </div>\n </div>\n <div\n :data-grid-direction=\"props.component.gridDirection\"\n :class=\"\n cn(\n props.component.inline\n ? 'flex flex-wrap gap-4'\n : columnFlow\n ? cn(\n 'gap-x-3 *:mb-3 *:break-inside-avoid',\n COLUMN_FLOW_CLASSES[props.component.gridColumns ?? 1],\n )\n : 'grid gap-3',\n !props.component.inline &&\n !columnFlow &&\n gridColumnsClasses(\n props.component.gridColumns\n ? { default: 1, md: props.component.gridColumns }\n : { default: 1 },\n ),\n )\n \"\n role=\"group\"\n :aria-labelledby=\"props.component.label ? fieldIds(id).label : undefined\"\n :aria-describedby=\"aria['aria-describedby']\"\n >\n <div v-for=\"option in visible\" :key=\"option.value\" class=\"flex items-start gap-2\">\n <Checkbox\n :id=\"`${id}-${option.value}`\"\n :model-value=\"selected.includes(option.value)\"\n :disabled=\"disabled || readOnly || option.disabled\"\n :aria-invalid=\"aria['aria-invalid']\"\n class=\"mt-0.5\"\n @update:model-value=\"toggle(option.value, $event === true)\"\n />\n <div class=\"grid gap-0.5\">\n <Label\n :for=\"`${id}-${option.value}`\"\n :class=\"cn('font-normal', option.color && textColorClasses[option.color])\"\n ><Icon v-if=\"option.icon\" :name=\"option.icon\" class=\"size-4\" /><span\n v-if=\"props.component.allowHtml\"\n v-html=\"option.label\"\n /><template v-else>{{ option.label }}</template></Label\n >\n <p v-if=\"option.description\" class=\"text-muted-foreground text-xs\">\n {{ option.description }}\n </p>\n </div>\n </div>\n </div>\n <p\n v-if=\"props.component.searchable && query !== '' && visible.length === 0\"\n data-slot=\"checkbox-list-empty\"\n role=\"status\"\n class=\"text-muted-foreground text-sm\"\n >\n {{ props.component.noSearchResultsMessage ?? t('no_results', {}, 'No results.') }}\n </p>\n </div>\n </FieldWrapper>\n</template>\n"],"mappings":""}
@@ -1 +1 @@
1
- {"version":3,"file":"CheckboxListField.vue.d.ts","sourceRoot":"","sources":["../../../src/components/fields/CheckboxListField.vue"],"names":[],"mappings":"AAwLA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAA;AAcvD,KAAK,WAAW,GAAG;IAAE,SAAS,EAAE,kBAAkB,CAAA;CAAE,CAAC;;AAmXrD,wBAMG"}
1
+ {"version":3,"file":"CheckboxListField.vue.d.ts","sourceRoot":"","sources":["../../../src/components/fields/CheckboxListField.vue"],"names":[],"mappings":"AAwLA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAA;AAcvD,KAAK,WAAW,GAAG;IAAE,SAAS,EAAE,kBAAkB,CAAA;CAAE,CAAC;;AAsXrD,wBAMG"}
@@ -13,10 +13,10 @@ import { Fragment as m, computed as h, createBlock as g, createCommentVNode as _
13
13
  //#region src/components/fields/CheckboxListField.vue?vue&type=script&setup=true&lang.ts
14
14
  var M = { class: "flex flex-col gap-2" }, N = {
15
15
  key: 0,
16
- class: "flex items-center gap-2"
16
+ class: "flex min-w-0 flex-wrap items-center gap-2"
17
17
  }, ee = {
18
18
  key: 1,
19
- class: "flex gap-1"
19
+ class: "flex flex-wrap gap-1"
20
20
  }, te = [
21
21
  "data-grid-direction",
22
22
  "aria-labelledby",
@@ -1 +1 @@
1
- {"version":3,"file":"CheckboxListField.vue_vue_type_script_setup_true_lang.js","names":["_openBlock","_createBlock","FieldWrapper","_unref","_withCtx","_createElementVNode","_createElementBlock","Input","_createCommentVNode","Button","Icon","_createTextVNode","_toDisplayString","_normalizeClass","_Fragment","_renderList","_createVNode","Checkbox","Label","Icon_default","Button_default","Checkbox_default","Input_default","Label_default","FieldWrapper_default","_hoisted_1","_hoisted_2","_hoisted_3","_hoisted_4","_hoisted_5","_hoisted_6","_hoisted_7","_hoisted_8","CheckboxListField_vue_vue_type_script_setup_true_lang_default","props","__props","t","useT","useField","search","ref","query","queryTimer","watch","term","onBeforeUnmount","selected","computed","value","options","isOptionGroup","option","visible","htmlLabelToText","COLUMN_FLOW_CLASSES","columnFlow","toggle","checked","key","item","openBlock","createBlock","unref","id","error","withCtx","createElementVNode","readOnly","createElementBlock","_cache","$event","createCommentVNode","disabled","setValue","createTextVNode","toDisplayString","normalizeClass","cn","gridColumnsClasses","fieldIds","aria","Fragment","renderList","createVNode","textColorClasses"],"sources":["../../../src/components/fields/CheckboxListField.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { CheckboxListSchema } from '@alfakit/core'\nimport { fieldIds, gridColumnsClasses, htmlLabelToText, isOptionGroup } from '@alfakit/core'\nimport { computed, onBeforeUnmount, ref, watch } from 'vue'\nimport { useT } from '../../context'\nimport { textColorClasses } from '../../lib/colors'\nimport { Icon } from '../../lib/icons'\nimport { cn } from '../../lib/utils'\nimport { useField } from '../form/form-context'\nimport FieldWrapper from '../schema/FieldWrapper.vue'\nimport Button from '../ui/Button.vue'\nimport Checkbox from '../ui/Checkbox.vue'\nimport Input from '../ui/Input.vue'\nimport Label from '../ui/Label.vue'\n\nconst props = defineProps<{ component: CheckboxListSchema }>()\nconst t = useT()\nconst { value, setValue, error, id, disabled, readOnly, aria } = useField<Array<\n string | number\n> | null>(() => props.component)\nconst search = ref('')\n// `searchDebounce()`: the list is filtered by `query`, which trails the input.\nconst query = ref('')\nlet queryTimer: ReturnType<typeof setTimeout> | undefined\n\nwatch(search, (term) => {\n clearTimeout(queryTimer)\n\n if (!props.component.searchDebounce) {\n query.value = term\n\n return\n }\n\n queryTimer = setTimeout(() => (query.value = term), props.component.searchDebounce)\n})\nonBeforeUnmount(() => clearTimeout(queryTimer))\n\nconst selected = computed(() => (value.value ?? []).map(String))\nconst options = computed(() =>\n props.component.options.flatMap((option) => (isOptionGroup(option) ? option.options : [option])),\n)\nconst visible = computed(() =>\n options.value.filter((option) =>\n (props.component.allowHtml ? htmlLabelToText(option.label) : option.label)\n .toLowerCase()\n .includes(query.value.toLowerCase()),\n ),\n)\n\n/**\n * `gridDirection('column')`: options flow down each column (CSS columns). Classes are\n * spelled out so Tailwind generates them.\n */\nconst COLUMN_FLOW_CLASSES: Record<number, string> = {\n 2: 'md:columns-2',\n 3: 'md:columns-3',\n 4: 'md:columns-4',\n 5: 'md:columns-5',\n 6: 'md:columns-6',\n}\nconst columnFlow = computed(\n () => props.component.gridDirection === 'column' && (props.component.gridColumns ?? 1) > 1,\n)\n\nconst toggle = (key: string, checked: boolean) => {\n setValue(checked ? [...selected.value, key] : selected.value.filter((item) => item !== key))\n}\n</script>\n\n<template>\n <FieldWrapper :field=\"props.component\" :html-for=\"id\" :error=\"error\">\n <div class=\"flex flex-col gap-2\">\n <div\n v-if=\"props.component.searchable || (props.component.bulkToggleable && !readOnly)\"\n class=\"flex items-center gap-2\"\n >\n <Input\n v-if=\"props.component.searchable\"\n v-model=\"search\"\n :placeholder=\"props.component.searchPrompt ?? t('search', {}, 'Search')\"\n :aria-label=\"props.component.searchPrompt ?? t('search', {}, 'Search')\"\n class=\"h-8\"\n />\n <div v-if=\"props.component.bulkToggleable && !readOnly\" class=\"flex gap-1\">\n <Button\n v-if=\"!props.component.selectAllAction?.hidden\"\n type=\"button\"\n variant=\"link\"\n size=\"sm\"\n data-slot=\"select-all\"\n :disabled=\"disabled\"\n @click=\"\n setValue(options.filter((option) => !option.disabled).map((option) => option.value))\n \"\n >\n <Icon\n v-if=\"props.component.selectAllAction?.icon\"\n :name=\"props.component.selectAllAction.icon\"\n />\n {{ props.component.selectAllAction?.label ?? t('table.select_all', {}, 'Select all') }}\n </Button>\n <Button\n v-if=\"!props.component.deselectAllAction?.hidden\"\n type=\"button\"\n variant=\"link\"\n size=\"sm\"\n data-slot=\"deselect-all\"\n :disabled=\"disabled\"\n @click=\"setValue([])\"\n >\n <Icon\n v-if=\"props.component.deselectAllAction?.icon\"\n :name=\"props.component.deselectAllAction.icon\"\n />\n {{\n props.component.deselectAllAction?.label ??\n t('table.deselect_all', {}, 'Deselect all')\n }}\n </Button>\n </div>\n </div>\n <div\n :data-grid-direction=\"props.component.gridDirection\"\n :class=\"\n cn(\n props.component.inline\n ? 'flex flex-wrap gap-4'\n : columnFlow\n ? cn(\n 'gap-x-3 *:mb-3 *:break-inside-avoid',\n COLUMN_FLOW_CLASSES[props.component.gridColumns ?? 1],\n )\n : 'grid gap-3',\n !props.component.inline &&\n !columnFlow &&\n gridColumnsClasses(\n props.component.gridColumns\n ? { default: 1, md: props.component.gridColumns }\n : { default: 1 },\n ),\n )\n \"\n role=\"group\"\n :aria-labelledby=\"props.component.label ? fieldIds(id).label : undefined\"\n :aria-describedby=\"aria['aria-describedby']\"\n >\n <div v-for=\"option in visible\" :key=\"option.value\" class=\"flex items-start gap-2\">\n <Checkbox\n :id=\"`${id}-${option.value}`\"\n :model-value=\"selected.includes(option.value)\"\n :disabled=\"disabled || readOnly || option.disabled\"\n :aria-invalid=\"aria['aria-invalid']\"\n class=\"mt-0.5\"\n @update:model-value=\"toggle(option.value, $event === true)\"\n />\n <div class=\"grid gap-0.5\">\n <Label\n :for=\"`${id}-${option.value}`\"\n :class=\"cn('font-normal', option.color && textColorClasses[option.color])\"\n ><Icon v-if=\"option.icon\" :name=\"option.icon\" class=\"size-4\" /><span\n v-if=\"props.component.allowHtml\"\n v-html=\"option.label\"\n /><template v-else>{{ option.label }}</template></Label\n >\n <p v-if=\"option.description\" class=\"text-muted-foreground text-xs\">\n {{ option.description }}\n </p>\n </div>\n </div>\n </div>\n <p\n v-if=\"props.component.searchable && query !== '' && visible.length === 0\"\n data-slot=\"checkbox-list-empty\"\n role=\"status\"\n class=\"text-muted-foreground text-sm\"\n >\n {{ props.component.noSearchResultsMessage ?? t('no_results', {}, 'No results.') }}\n </p>\n </div>\n </FieldWrapper>\n</template>\n"],"mappings":"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"}
1
+ {"version":3,"file":"CheckboxListField.vue_vue_type_script_setup_true_lang.js","names":["_openBlock","_createBlock","FieldWrapper","_unref","_withCtx","_createElementVNode","_createElementBlock","Input","_createCommentVNode","Button","Icon","_createTextVNode","_toDisplayString","_normalizeClass","_Fragment","_renderList","_createVNode","Checkbox","Label","Icon_default","Button_default","Checkbox_default","Input_default","Label_default","FieldWrapper_default","_hoisted_1","_hoisted_2","_hoisted_3","_hoisted_4","_hoisted_5","_hoisted_6","_hoisted_7","_hoisted_8","CheckboxListField_vue_vue_type_script_setup_true_lang_default","props","__props","t","useT","useField","search","ref","query","queryTimer","watch","term","onBeforeUnmount","selected","computed","value","options","isOptionGroup","option","visible","htmlLabelToText","COLUMN_FLOW_CLASSES","columnFlow","toggle","checked","key","item","openBlock","createBlock","unref","id","error","withCtx","createElementVNode","readOnly","createElementBlock","_cache","$event","createCommentVNode","disabled","setValue","createTextVNode","toDisplayString","normalizeClass","cn","gridColumnsClasses","fieldIds","aria","Fragment","renderList","createVNode","textColorClasses"],"sources":["../../../src/components/fields/CheckboxListField.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { CheckboxListSchema } from '@alfakit/core'\nimport { fieldIds, gridColumnsClasses, htmlLabelToText, isOptionGroup } from '@alfakit/core'\nimport { computed, onBeforeUnmount, ref, watch } from 'vue'\nimport { useT } from '../../context'\nimport { textColorClasses } from '../../lib/colors'\nimport { Icon } from '../../lib/icons'\nimport { cn } from '../../lib/utils'\nimport { useField } from '../form/form-context'\nimport FieldWrapper from '../schema/FieldWrapper.vue'\nimport Button from '../ui/Button.vue'\nimport Checkbox from '../ui/Checkbox.vue'\nimport Input from '../ui/Input.vue'\nimport Label from '../ui/Label.vue'\n\nconst props = defineProps<{ component: CheckboxListSchema }>()\nconst t = useT()\nconst { value, setValue, error, id, disabled, readOnly, aria } = useField<Array<\n string | number\n> | null>(() => props.component)\nconst search = ref('')\n// `searchDebounce()`: the list is filtered by `query`, which trails the input.\nconst query = ref('')\nlet queryTimer: ReturnType<typeof setTimeout> | undefined\n\nwatch(search, (term) => {\n clearTimeout(queryTimer)\n\n if (!props.component.searchDebounce) {\n query.value = term\n\n return\n }\n\n queryTimer = setTimeout(() => (query.value = term), props.component.searchDebounce)\n})\nonBeforeUnmount(() => clearTimeout(queryTimer))\n\nconst selected = computed(() => (value.value ?? []).map(String))\nconst options = computed(() =>\n props.component.options.flatMap((option) => (isOptionGroup(option) ? option.options : [option])),\n)\nconst visible = computed(() =>\n options.value.filter((option) =>\n (props.component.allowHtml ? htmlLabelToText(option.label) : option.label)\n .toLowerCase()\n .includes(query.value.toLowerCase()),\n ),\n)\n\n/**\n * `gridDirection('column')`: options flow down each column (CSS columns). Classes are\n * spelled out so Tailwind generates them.\n */\nconst COLUMN_FLOW_CLASSES: Record<number, string> = {\n 2: 'md:columns-2',\n 3: 'md:columns-3',\n 4: 'md:columns-4',\n 5: 'md:columns-5',\n 6: 'md:columns-6',\n}\nconst columnFlow = computed(\n () => props.component.gridDirection === 'column' && (props.component.gridColumns ?? 1) > 1,\n)\n\nconst toggle = (key: string, checked: boolean) => {\n setValue(checked ? [...selected.value, key] : selected.value.filter((item) => item !== key))\n}\n</script>\n\n<template>\n <FieldWrapper :field=\"props.component\" :html-for=\"id\" :error=\"error\">\n <div class=\"flex flex-col gap-2\">\n <div\n v-if=\"props.component.searchable || (props.component.bulkToggleable && !readOnly)\"\n class=\"flex min-w-0 flex-wrap items-center gap-2\"\n >\n <Input\n v-if=\"props.component.searchable\"\n v-model=\"search\"\n :placeholder=\"props.component.searchPrompt ?? t('search', {}, 'Search')\"\n :aria-label=\"props.component.searchPrompt ?? t('search', {}, 'Search')\"\n class=\"h-8\"\n />\n <div v-if=\"props.component.bulkToggleable && !readOnly\" class=\"flex flex-wrap gap-1\">\n <Button\n v-if=\"!props.component.selectAllAction?.hidden\"\n type=\"button\"\n variant=\"link\"\n size=\"sm\"\n data-slot=\"select-all\"\n :disabled=\"disabled\"\n @click=\"\n setValue(options.filter((option) => !option.disabled).map((option) => option.value))\n \"\n >\n <Icon\n v-if=\"props.component.selectAllAction?.icon\"\n :name=\"props.component.selectAllAction.icon\"\n />\n {{ props.component.selectAllAction?.label ?? t('table.select_all', {}, 'Select all') }}\n </Button>\n <Button\n v-if=\"!props.component.deselectAllAction?.hidden\"\n type=\"button\"\n variant=\"link\"\n size=\"sm\"\n data-slot=\"deselect-all\"\n :disabled=\"disabled\"\n @click=\"setValue([])\"\n >\n <Icon\n v-if=\"props.component.deselectAllAction?.icon\"\n :name=\"props.component.deselectAllAction.icon\"\n />\n {{\n props.component.deselectAllAction?.label ??\n t('table.deselect_all', {}, 'Deselect all')\n }}\n </Button>\n </div>\n </div>\n <div\n :data-grid-direction=\"props.component.gridDirection\"\n :class=\"\n cn(\n props.component.inline\n ? 'flex flex-wrap gap-4'\n : columnFlow\n ? cn(\n 'gap-x-3 *:mb-3 *:break-inside-avoid',\n COLUMN_FLOW_CLASSES[props.component.gridColumns ?? 1],\n )\n : 'grid gap-3',\n !props.component.inline &&\n !columnFlow &&\n gridColumnsClasses(\n props.component.gridColumns\n ? { default: 1, md: props.component.gridColumns }\n : { default: 1 },\n ),\n )\n \"\n role=\"group\"\n :aria-labelledby=\"props.component.label ? fieldIds(id).label : undefined\"\n :aria-describedby=\"aria['aria-describedby']\"\n >\n <div v-for=\"option in visible\" :key=\"option.value\" class=\"flex items-start gap-2\">\n <Checkbox\n :id=\"`${id}-${option.value}`\"\n :model-value=\"selected.includes(option.value)\"\n :disabled=\"disabled || readOnly || option.disabled\"\n :aria-invalid=\"aria['aria-invalid']\"\n class=\"mt-0.5\"\n @update:model-value=\"toggle(option.value, $event === true)\"\n />\n <div class=\"grid gap-0.5\">\n <Label\n :for=\"`${id}-${option.value}`\"\n :class=\"cn('font-normal', option.color && textColorClasses[option.color])\"\n ><Icon v-if=\"option.icon\" :name=\"option.icon\" class=\"size-4\" /><span\n v-if=\"props.component.allowHtml\"\n v-html=\"option.label\"\n /><template v-else>{{ option.label }}</template></Label\n >\n <p v-if=\"option.description\" class=\"text-muted-foreground text-xs\">\n {{ option.description }}\n </p>\n </div>\n </div>\n </div>\n <p\n v-if=\"props.component.searchable && query !== '' && visible.length === 0\"\n data-slot=\"checkbox-list-empty\"\n role=\"status\"\n class=\"text-muted-foreground text-sm\"\n >\n {{ props.component.noSearchResultsMessage ?? t('no_results', {}, 'No results.') }}\n </p>\n </div>\n </FieldWrapper>\n</template>\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"DatePickerField.js","names":["_sfc_main","DatePickerField_vue_vue_type_script_setup_true_lang_default","DatePickerField_default"],"sources":["../../../src/components/fields/DatePickerField.vue"],"sourcesContent":["<script lang=\"ts\">\nimport { defineComponent, h } from 'vue'\nimport { lazyComponent } from '../../lib/lazy'\n\n// The month grid (reka-ui) loads the first time a picker opens (or is hovered or focused),\n// not with the form.\nconst loadCalendar = () => import('../ui/Calendar.vue').then((module) => module.default)\nconst Calendar = lazyComponent(\n 'AlfakitCalendar',\n loadCalendar,\n defineComponent({\n name: 'AlfakitCalendarLoading',\n inheritAttrs: false,\n render: () => h('div', { 'aria-busy': 'true', class: 'h-[18.5rem] w-[15.5rem]' }),\n }),\n)\n</script>\n\n<script setup lang=\"ts\">\nimport {\n formatPhpDate,\n LocaleFormatter,\n timeInputStep,\n wallClockNow,\n type DatePickerSchema,\n} from '@alfakit/core'\nimport { CalendarDate, type DateValue } from '@internationalized/date'\nimport { CalendarIcon } from '@lucide/vue'\nimport { format as formatDate, isValid, parse } from 'date-fns'\nimport { computed, ref } from 'vue'\nimport { useDirection, useFormatter, useLocalization, useT } from '../../context'\nimport { cn } from '../../lib/utils'\nimport { useField } from '../form/form-context'\nimport FieldWrapper from '../schema/FieldWrapper.vue'\nimport Button from '../ui/Button.vue'\nimport Input from '../ui/Input.vue'\nimport Popover from '../ui/Popover.vue'\nimport PopoverContent from '../ui/PopoverContent.vue'\nimport PopoverTrigger from '../ui/PopoverTrigger.vue'\nimport { phpToDateFnsFormat } from './date-format'\nimport SelectAffixes from './SelectAffixes.vue'\n\nconst props = defineProps<{ component: DatePickerSchema }>()\nconst { value, setValue, blur, error, id, disabled, readOnly, aria } = useField<string | null>(\n () => props.component,\n)\nconst open = ref(false)\n\nconst storageFormat = computed(() => phpToDateFnsFormat(props.component.format))\nconst t = useT()\nconst direction = useDirection()\nconst panelFormat = useFormatter()\nconst localization = useLocalization()\n// `locale()` overrides the panel's language for this picker only.\nconst locale = computed(() => props.component.locale ?? localization.value?.tag ?? 'en')\nconst format = computed(() =>\n props.component.locale\n ? new LocaleFormatter(\n props.component.locale,\n panelFormat.value.currencyCode,\n panelFormat.value.timeZone,\n )\n : panelFormat.value,\n)\nconst listId = computed(() => (props.component.datalist ? `${id}-list` : undefined))\n\n// Month and weekday names come from Intl, so they follow the user's language.\nconst display = (date: Date): string =>\n props.component.displayFormat\n ? formatPhpDate(date, props.component.displayFormat, locale.value)\n : format.value.date(date, {\n ...(props.component.hasDate ? { dateStyle: 'medium' as const } : {}),\n ...(props.component.hasTime ? { timeStyle: 'short' as const } : {}),\n timeZone: undefined,\n })\n\nconst nativeType = computed(() =>\n !props.component.hasDate ? 'time' : props.component.hasTime ? 'datetime-local' : 'date',\n)\nconst nativeFormat = computed(() =>\n nativeType.value === 'time'\n ? props.component.hasSeconds\n ? 'HH:mm:ss'\n : 'HH:mm'\n : nativeType.value === 'datetime-local'\n ? props.component.hasSeconds\n ? \"yyyy-MM-dd'T'HH:mm:ss\"\n : \"yyyy-MM-dd'T'HH:mm\"\n : 'yyyy-MM-dd',\n)\n\nconst parsed = computed(() =>\n value.value ? parse(value.value, storageFormat.value, new Date()) : null,\n)\nconst selectedDate = computed(() =>\n parsed.value && isValid(parsed.value) ? parsed.value : undefined,\n)\nconst nativeValue = computed(() =>\n selectedDate.value ? formatDate(selectedDate.value, nativeFormat.value) : (value.value ?? ''),\n)\n\nfunction toNative(raw: string): string | undefined {\n const date = parse(raw, storageFormat.value, new Date())\n\n return isValid(date) ? formatDate(date, nativeFormat.value) : undefined\n}\n\nfunction parseStored(raw: string): Date {\n return parse(raw, storageFormat.value, new Date())\n}\n\nconst onNativeInput = (raw: string) => {\n if (raw === '') {\n setValue(null)\n\n return\n }\n\n const date = parse(raw, nativeFormat.value, new Date())\n setValue(isValid(date) ? formatDate(date, storageFormat.value) : raw)\n}\n\n// Calendar (reka-ui) works with @internationalized/date values.\nconst toCalendarDate = (date: Date): CalendarDate =>\n new CalendarDate(date.getFullYear(), date.getMonth() + 1, date.getDate())\nconst calendarValue = computed(() =>\n selectedDate.value ? toCalendarDate(selectedDate.value) : undefined,\n)\nconst minValue = computed(() =>\n props.component.minDate ? toCalendarDate(parseStored(props.component.minDate)) : undefined,\n)\nconst maxValue = computed(() =>\n props.component.maxDate ? toCalendarDate(parseStored(props.component.maxDate)) : undefined,\n)\nconst disabledDates = computed(() =>\n (props.component.disabledDates ?? []).map((date) => toCalendarDate(parseStored(date)).toString()),\n)\nconst isDateDisabled = (date: DateValue) => disabledDates.value.includes(date.toString())\n// `defaultFocusedDate()`: the month the calendar opens on while the field is empty.\nconst focusedPlaceholder = computed(() => {\n if (!props.component.defaultFocusedDate) return undefined\n\n const date = parseStored(props.component.defaultFocusedDate)\n\n return isValid(date) ? toCalendarDate(date) : undefined\n})\nconst step = computed(() => timeInputStep(props.component))\n\nconst onSelect = (next: DateValue | undefined) => {\n if (!next) {\n setValue(null)\n\n return\n }\n\n const base = selectedDate.value\n const withTime = new Date(\n next.year,\n next.month - 1,\n next.day,\n base?.getHours() ?? 0,\n base?.getMinutes() ?? 0,\n base?.getSeconds() ?? 0,\n )\n setValue(formatDate(withTime, storageFormat.value))\n\n if (props.component.closeOnDateSelection && !props.component.hasTime) {\n open.value = false\n blur()\n }\n}\n\nconst timeValue = computed(() =>\n selectedDate.value\n ? formatDate(selectedDate.value, props.component.hasSeconds ? 'HH:mm:ss' : 'HH:mm')\n : '',\n)\n\nconst onTimeInput = (raw: string) => {\n const base = selectedDate.value ?? wallClockNow(props.component.timezone)\n const [hours = '0', minutes = '0', seconds = '0'] = raw.split(':')\n const next = new Date(\n base.getFullYear(),\n base.getMonth(),\n base.getDate(),\n Number(hours),\n Number(minutes),\n Number(seconds),\n )\n setValue(formatDate(next, storageFormat.value))\n}\n\n// Kept out of the template: a `|` union there is parsed as a (removed) Vue 2 filter.\nconst weekStartsOn = computed(\n () => (props.component.firstDayOfWeek ?? 1) as 0 | 1 | 2 | 3 | 4 | 5 | 6,\n)\n</script>\n\n<template>\n <FieldWrapper :field=\"props.component\" :html-for=\"id\" :error=\"error\">\n <SelectAffixes :component=\"props.component\" :error=\"error\">\n <Input\n v-if=\"props.component.native || !props.component.hasDate\"\n :id=\"id\"\n :type=\"nativeType\"\n :name=\"props.component.name\"\n :model-value=\"nativeValue\"\n :step=\"step\"\n :min=\"props.component.minDate ? toNative(props.component.minDate) : undefined\"\n :max=\"props.component.maxDate ? toNative(props.component.maxDate) : undefined\"\n :disabled=\"disabled\"\n :readonly=\"readOnly\"\n :required=\"props.component.required\"\n :lang=\"props.component.locale\"\n :list=\"listId\"\n :aria-invalid=\"aria['aria-invalid']\"\n :aria-describedby=\"aria['aria-describedby']\"\n :aria-required=\"aria['aria-required']\"\n v-bind=\"props.component.extraInputAttributes\"\n @update:model-value=\"onNativeInput\"\n @blur=\"blur\"\n />\n <Popover v-else :open=\"open\" @update:open=\"open = $event && !readOnly\">\n <PopoverTrigger as-child>\n <Button\n :id=\"id\"\n type=\"button\"\n data-input=\"\"\n variant=\"outline\"\n :disabled=\"disabled\"\n @pointerenter=\"loadCalendar\"\n @focus=\"loadCalendar\"\n :aria-invalid=\"aria['aria-invalid']\"\n :aria-describedby=\"aria['aria-describedby']\"\n :class=\"\n cn(\n 'w-full justify-start font-normal',\n !selectedDate && 'text-muted-foreground',\n error && 'border-destructive',\n )\n \"\n >\n <CalendarIcon class=\"size-4\" />\n {{\n selectedDate\n ? display(selectedDate)\n : (props.component.placeholder ?? t('form.pick_date', {}, 'Pick a date'))\n }}\n </Button>\n </PopoverTrigger>\n <PopoverContent class=\"w-auto p-0\" align=\"start\">\n <Calendar\n :model-value=\"calendarValue\"\n :locale=\"locale\"\n :dir=\"direction\"\n :today=\"toCalendarDate(wallClockNow(props.component.timezone))\"\n :week-starts-on=\"weekStartsOn\"\n :min-value=\"minValue\"\n :max-value=\"maxValue\"\n :default-placeholder=\"focusedPlaceholder\"\n :is-date-disabled=\"isDateDisabled\"\n initial-focus\n @update:model-value=\"onSelect($event as DateValue | undefined)\"\n />\n <div v-if=\"props.component.hasTime\" class=\"border-t p-3\">\n <Input\n type=\"time\"\n :step=\"step\"\n :model-value=\"timeValue\"\n @update:model-value=\"onTimeInput\"\n @blur=\"blur\"\n />\n </div>\n </PopoverContent>\n </Popover>\n <datalist\n v-if=\"(props.component.native || !props.component.hasDate) && props.component.datalist\"\n :id=\"listId\"\n >\n <option\n v-for=\"option in props.component.datalist\"\n :key=\"option\"\n :value=\"toNative(option) ?? option\"\n />\n </datalist>\n </SelectAffixes>\n </FieldWrapper>\n</template>\n"],"mappings":""}
1
+ {"version":3,"file":"DatePickerField.js","names":["_sfc_main","DatePickerField_vue_vue_type_script_setup_true_lang_default","DatePickerField_default"],"sources":["../../../src/components/fields/DatePickerField.vue"],"sourcesContent":["<script lang=\"ts\">\nimport { defineComponent, h } from 'vue'\nimport { lazyComponent } from '../../lib/lazy'\n\n// The month grid (reka-ui) loads the first time a picker opens (or is hovered or focused),\n// not with the form.\nconst loadCalendar = () => import('../ui/Calendar.vue').then((module) => module.default)\nconst Calendar = lazyComponent(\n 'AlfakitCalendar',\n loadCalendar,\n defineComponent({\n name: 'AlfakitCalendarLoading',\n inheritAttrs: false,\n render: () => h('div', { 'aria-busy': 'true', class: 'h-[18.5rem] w-[15.5rem]' }),\n }),\n)\n</script>\n\n<script setup lang=\"ts\">\nimport {\n formatPhpDate,\n LocaleFormatter,\n timeInputStep,\n wallClockNow,\n type DatePickerSchema,\n} from '@alfakit/core'\nimport { CalendarDate, type DateValue } from '@internationalized/date'\nimport { CalendarIcon } from '@lucide/vue'\nimport { format as formatDate, isValid, parse } from 'date-fns'\nimport { computed, ref } from 'vue'\nimport { useDirection, useFormatter, useLocalization, useT } from '../../context'\nimport { cn } from '../../lib/utils'\nimport { useField } from '../form/form-context'\nimport FieldWrapper from '../schema/FieldWrapper.vue'\nimport Button from '../ui/Button.vue'\nimport Input from '../ui/Input.vue'\nimport Popover from '../ui/Popover.vue'\nimport PopoverContent from '../ui/PopoverContent.vue'\nimport PopoverTrigger from '../ui/PopoverTrigger.vue'\nimport { phpToDateFnsFormat } from './date-format'\nimport SelectAffixes from './SelectAffixes.vue'\n\nconst props = defineProps<{ component: DatePickerSchema }>()\nconst { value, setValue, blur, error, id, disabled, readOnly, aria } = useField<string | null>(\n () => props.component,\n)\nconst open = ref(false)\n\nconst storageFormat = computed(() => phpToDateFnsFormat(props.component.format))\nconst t = useT()\nconst direction = useDirection()\nconst panelFormat = useFormatter()\nconst localization = useLocalization()\n// `locale()` overrides the panel's language for this picker only.\nconst locale = computed(() => props.component.locale ?? localization.value?.tag ?? 'en')\nconst format = computed(() =>\n props.component.locale\n ? new LocaleFormatter(\n props.component.locale,\n panelFormat.value.currencyCode,\n panelFormat.value.timeZone,\n )\n : panelFormat.value,\n)\nconst listId = computed(() => (props.component.datalist ? `${id}-list` : undefined))\n\n// Month and weekday names come from Intl, so they follow the user's language.\nconst display = (date: Date): string =>\n props.component.displayFormat\n ? formatPhpDate(date, props.component.displayFormat, locale.value)\n : format.value.date(date, {\n ...(props.component.hasDate ? { dateStyle: 'medium' as const } : {}),\n ...(props.component.hasTime ? { timeStyle: 'short' as const } : {}),\n timeZone: undefined,\n })\n\nconst nativeType = computed(() =>\n !props.component.hasDate ? 'time' : props.component.hasTime ? 'datetime-local' : 'date',\n)\nconst nativeFormat = computed(() =>\n nativeType.value === 'time'\n ? props.component.hasSeconds\n ? 'HH:mm:ss'\n : 'HH:mm'\n : nativeType.value === 'datetime-local'\n ? props.component.hasSeconds\n ? \"yyyy-MM-dd'T'HH:mm:ss\"\n : \"yyyy-MM-dd'T'HH:mm\"\n : 'yyyy-MM-dd',\n)\n\nconst parsed = computed(() =>\n value.value ? parse(value.value, storageFormat.value, new Date()) : null,\n)\nconst selectedDate = computed(() =>\n parsed.value && isValid(parsed.value) ? parsed.value : undefined,\n)\nconst nativeValue = computed(() =>\n selectedDate.value ? formatDate(selectedDate.value, nativeFormat.value) : (value.value ?? ''),\n)\n\nfunction toNative(raw: string): string | undefined {\n const date = parse(raw, storageFormat.value, new Date())\n\n return isValid(date) ? formatDate(date, nativeFormat.value) : undefined\n}\n\nfunction parseStored(raw: string): Date {\n return parse(raw, storageFormat.value, new Date())\n}\n\nconst onNativeInput = (raw: string) => {\n if (raw === '') {\n setValue(null)\n\n return\n }\n\n const date = parse(raw, nativeFormat.value, new Date())\n setValue(isValid(date) ? formatDate(date, storageFormat.value) : raw)\n}\n\n// Calendar (reka-ui) works with @internationalized/date values.\nconst toCalendarDate = (date: Date): CalendarDate =>\n new CalendarDate(date.getFullYear(), date.getMonth() + 1, date.getDate())\nconst calendarValue = computed(() =>\n selectedDate.value ? toCalendarDate(selectedDate.value) : undefined,\n)\nconst minValue = computed(() =>\n props.component.minDate ? toCalendarDate(parseStored(props.component.minDate)) : undefined,\n)\nconst maxValue = computed(() =>\n props.component.maxDate ? toCalendarDate(parseStored(props.component.maxDate)) : undefined,\n)\nconst disabledDates = computed(() =>\n (props.component.disabledDates ?? []).map((date) => toCalendarDate(parseStored(date)).toString()),\n)\nconst isDateDisabled = (date: DateValue) => disabledDates.value.includes(date.toString())\n// `defaultFocusedDate()`: the month the calendar opens on while the field is empty.\nconst focusedPlaceholder = computed(() => {\n if (!props.component.defaultFocusedDate) return undefined\n\n const date = parseStored(props.component.defaultFocusedDate)\n\n return isValid(date) ? toCalendarDate(date) : undefined\n})\nconst step = computed(() => timeInputStep(props.component))\n\nconst onSelect = (next: DateValue | undefined) => {\n if (!next) {\n setValue(null)\n\n return\n }\n\n const base = selectedDate.value\n const withTime = new Date(\n next.year,\n next.month - 1,\n next.day,\n base?.getHours() ?? 0,\n base?.getMinutes() ?? 0,\n base?.getSeconds() ?? 0,\n )\n setValue(formatDate(withTime, storageFormat.value))\n\n if (props.component.closeOnDateSelection && !props.component.hasTime) {\n open.value = false\n blur()\n }\n}\n\nconst timeValue = computed(() =>\n selectedDate.value\n ? formatDate(selectedDate.value, props.component.hasSeconds ? 'HH:mm:ss' : 'HH:mm')\n : '',\n)\n\nconst onTimeInput = (raw: string) => {\n const base = selectedDate.value ?? wallClockNow(props.component.timezone)\n const [hours = '0', minutes = '0', seconds = '0'] = raw.split(':')\n const next = new Date(\n base.getFullYear(),\n base.getMonth(),\n base.getDate(),\n Number(hours),\n Number(minutes),\n Number(seconds),\n )\n setValue(formatDate(next, storageFormat.value))\n}\n\n// Kept out of the template: a `|` union there is parsed as a (removed) Vue 2 filter.\nconst weekStartsOn = computed(\n () => (props.component.firstDayOfWeek ?? 1) as 0 | 1 | 2 | 3 | 4 | 5 | 6,\n)\n</script>\n\n<template>\n <FieldWrapper :field=\"props.component\" :html-for=\"id\" :error=\"error\">\n <SelectAffixes :component=\"props.component\" :error=\"error\">\n <Input\n v-if=\"props.component.native || !props.component.hasDate\"\n :id=\"id\"\n :type=\"nativeType\"\n :name=\"props.component.name\"\n :model-value=\"nativeValue\"\n :step=\"step\"\n :min=\"props.component.minDate ? toNative(props.component.minDate) : undefined\"\n :max=\"props.component.maxDate ? toNative(props.component.maxDate) : undefined\"\n :disabled=\"disabled\"\n :readonly=\"readOnly\"\n :required=\"props.component.required\"\n :lang=\"props.component.locale\"\n :list=\"listId\"\n :aria-invalid=\"aria['aria-invalid']\"\n :aria-describedby=\"aria['aria-describedby']\"\n :aria-required=\"aria['aria-required']\"\n v-bind=\"props.component.extraInputAttributes\"\n @update:model-value=\"onNativeInput\"\n @blur=\"blur\"\n />\n <Popover v-else :open=\"open\" @update:open=\"open = $event && !readOnly\">\n <PopoverTrigger as-child>\n <Button\n :id=\"id\"\n type=\"button\"\n data-input=\"\"\n variant=\"outline\"\n :disabled=\"disabled\"\n @pointerenter=\"loadCalendar\"\n @focus=\"loadCalendar\"\n :aria-invalid=\"aria['aria-invalid']\"\n :aria-describedby=\"aria['aria-describedby']\"\n :class=\"\n cn(\n 'w-full justify-start font-normal',\n !selectedDate && 'text-muted-foreground',\n error && 'border-destructive',\n )\n \"\n >\n <CalendarIcon class=\"size-4\" />\n {{\n selectedDate\n ? display(selectedDate)\n : (props.component.placeholder ?? t('form.pick_date', {}, 'Pick a date'))\n }}\n </Button>\n </PopoverTrigger>\n <PopoverContent class=\"w-auto p-0\" align=\"start\">\n <Calendar\n :model-value=\"calendarValue\"\n :calendar-label=\"props.component.label || t('form.pick_date', {}, 'Pick a date')\"\n :locale=\"locale\"\n :dir=\"direction\"\n :today=\"toCalendarDate(wallClockNow(props.component.timezone))\"\n :week-starts-on=\"weekStartsOn\"\n :min-value=\"minValue\"\n :max-value=\"maxValue\"\n :default-placeholder=\"focusedPlaceholder\"\n :is-date-disabled=\"isDateDisabled\"\n initial-focus\n @update:model-value=\"onSelect($event as DateValue | undefined)\"\n />\n <div v-if=\"props.component.hasTime\" class=\"border-t p-3\">\n <Input\n type=\"time\"\n :step=\"step\"\n :model-value=\"timeValue\"\n @update:model-value=\"onTimeInput\"\n @blur=\"blur\"\n />\n </div>\n </PopoverContent>\n </Popover>\n <datalist\n v-if=\"(props.component.native || !props.component.hasDate) && props.component.datalist\"\n :id=\"listId\"\n >\n <option\n v-for=\"option in props.component.datalist\"\n :key=\"option\"\n :value=\"toNative(option) ?? option\"\n />\n </datalist>\n </SelectAffixes>\n </FieldWrapper>\n</template>\n"],"mappings":""}
@@ -1 +1 @@
1
- {"version":3,"file":"DatePickerField.vue.d.ts","sourceRoot":"","sources":["../../../src/components/fields/DatePickerField.vue"],"names":[],"mappings":"AAkSA,OAAO,EAKL,KAAK,gBAAgB,EACtB,MAAM,eAAe,CAAA;;eAmCU,gBAAgB;;eAAhB,gBAAgB;;AADhD,wBAkfK"}
1
+ {"version":3,"file":"DatePickerField.vue.d.ts","sourceRoot":"","sources":["../../../src/components/fields/DatePickerField.vue"],"names":[],"mappings":"AAmSA,OAAO,EAKL,KAAK,gBAAgB,EACtB,MAAM,eAAe,CAAA;;eAmCU,gBAAgB;;eAAhB,gBAAgB;;AADhD,wBAofK"}