@alfakit/vue 0.1.2 → 0.1.6

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 (281) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/AlfakitRoot.js.map +1 -1
  3. package/dist/AlfakitRoot.vue.d.ts.map +1 -1
  4. package/dist/AlfakitRoot.vue_vue_type_script_setup_true_lang.js +3 -1
  5. package/dist/AlfakitRoot.vue_vue_type_script_setup_true_lang.js.map +1 -1
  6. package/dist/components/actions/ActionGroupMenu.js.map +1 -1
  7. package/dist/components/actions/ActionGroupMenu.vue.d.ts.map +1 -1
  8. package/dist/components/actions/ActionGroupMenu.vue_vue_type_script_setup_true_lang.js +69 -65
  9. package/dist/components/actions/ActionGroupMenu.vue_vue_type_script_setup_true_lang.js.map +1 -1
  10. package/dist/components/actions/ActionModal.js.map +1 -1
  11. package/dist/components/actions/ActionModal.vue.d.ts.map +1 -1
  12. package/dist/components/actions/ActionModal.vue_vue_type_script_setup_true_lang.js +17 -15
  13. package/dist/components/actions/ActionModal.vue_vue_type_script_setup_true_lang.js.map +1 -1
  14. package/dist/components/ai/AiCopilot.js.map +1 -1
  15. package/dist/components/ai/AiCopilot.vue.d.ts +2 -0
  16. package/dist/components/ai/AiCopilot.vue.d.ts.map +1 -1
  17. package/dist/components/ai/AiCopilot.vue_vue_type_script_setup_true_lang.js +7 -2
  18. package/dist/components/ai/AiCopilot.vue_vue_type_script_setup_true_lang.js.map +1 -1
  19. package/dist/components/cms/CmsPage.vue_vue_type_script_setup_true_lang.js +19 -19
  20. package/dist/components/cms/CmsPage.vue_vue_type_script_setup_true_lang.js.map +1 -1
  21. package/dist/components/cms/LivePreview.js.map +1 -1
  22. package/dist/components/cms/LivePreview.vue.d.ts.map +1 -1
  23. package/dist/components/cms/LivePreview.vue_vue_type_script_setup_true_lang.js +83 -83
  24. package/dist/components/cms/LivePreview.vue_vue_type_script_setup_true_lang.js.map +1 -1
  25. package/dist/components/fields/BuilderField.js.map +1 -1
  26. package/dist/components/fields/BuilderField.vue.d.ts.map +1 -1
  27. package/dist/components/fields/BuilderField.vue_vue_type_script_setup_true_lang.js +162 -157
  28. package/dist/components/fields/BuilderField.vue_vue_type_script_setup_true_lang.js.map +1 -1
  29. package/dist/components/fields/ImageEditorDialog.js.map +1 -1
  30. package/dist/components/fields/ImageEditorDialog.vue.d.ts.map +1 -1
  31. package/dist/components/fields/ImageEditorDialog.vue_vue_type_script_setup_true_lang.js +46 -46
  32. package/dist/components/fields/ImageEditorDialog.vue_vue_type_script_setup_true_lang.js.map +1 -1
  33. package/dist/components/fields/KeyValueField.js.map +1 -1
  34. package/dist/components/fields/KeyValueField.vue.d.ts.map +1 -1
  35. package/dist/components/fields/KeyValueField.vue_vue_type_script_setup_true_lang.js +66 -66
  36. package/dist/components/fields/KeyValueField.vue_vue_type_script_setup_true_lang.js.map +1 -1
  37. package/dist/components/fields/ModalTablePicker.js.map +1 -1
  38. package/dist/components/fields/ModalTablePicker.vue.d.ts.map +1 -1
  39. package/dist/components/fields/ModalTablePicker.vue_vue_type_script_setup_true_lang.js +113 -113
  40. package/dist/components/fields/ModalTablePicker.vue_vue_type_script_setup_true_lang.js.map +1 -1
  41. package/dist/components/fields/RepeaterField.js.map +1 -1
  42. package/dist/components/fields/RepeaterField.vue.d.ts.map +1 -1
  43. package/dist/components/fields/RepeaterField.vue_vue_type_script_setup_true_lang.js +12 -12
  44. package/dist/components/fields/RepeaterField.vue_vue_type_script_setup_true_lang.js.map +1 -1
  45. package/dist/components/fields/RichEditorInput.js.map +1 -1
  46. package/dist/components/fields/RichEditorInput.vue.d.ts.map +1 -1
  47. package/dist/components/fields/RichEditorInput.vue_vue_type_script_setup_true_lang.js +166 -165
  48. package/dist/components/fields/RichEditorInput.vue_vue_type_script_setup_true_lang.js.map +1 -1
  49. package/dist/components/fields/SliderField.vue_vue_type_script_setup_true_lang.js.map +1 -1
  50. package/dist/components/fields/item-actions.d.ts +2 -2
  51. package/dist/components/fields/item-actions.d.ts.map +1 -1
  52. package/dist/components/fields/item-actions.js +31 -31
  53. package/dist/components/fields/item-actions.js.map +1 -1
  54. package/dist/components/form/FormBlock.js.map +1 -1
  55. package/dist/components/form/FormBlock.vue.d.ts.map +1 -1
  56. package/dist/components/form/FormBlock.vue_vue_type_script_setup_true_lang.js +1 -1
  57. package/dist/components/form/FormBlock.vue_vue_type_script_setup_true_lang.js.map +1 -1
  58. package/dist/components/form/form-context.js +25 -25
  59. package/dist/components/form/form-context.js.map +1 -1
  60. package/dist/components/kanban/KanbanBoard.js.map +1 -1
  61. package/dist/components/kanban/KanbanBoard.vue.d.ts.map +1 -1
  62. package/dist/components/kanban/KanbanBoard.vue_vue_type_script_setup_true_lang.js +5 -2
  63. package/dist/components/kanban/KanbanBoard.vue_vue_type_script_setup_true_lang.js.map +1 -1
  64. package/dist/components/kanban/KanbanColumnHeader.js.map +1 -1
  65. package/dist/components/kanban/KanbanColumnHeader.vue.d.ts.map +1 -1
  66. package/dist/components/kanban/KanbanColumnHeader.vue_vue_type_script_setup_true_lang.js +64 -64
  67. package/dist/components/kanban/KanbanColumnHeader.vue_vue_type_script_setup_true_lang.js.map +1 -1
  68. package/dist/components/layout/SectionComponent.js.map +1 -1
  69. package/dist/components/layout/SectionComponent.vue.d.ts.map +1 -1
  70. package/dist/components/layout/SectionComponent.vue_vue_type_script_setup_true_lang.js +23 -23
  71. package/dist/components/layout/SectionComponent.vue_vue_type_script_setup_true_lang.js.map +1 -1
  72. package/dist/components/panel/DebugPanel.vue_vue_type_script_setup_true_lang.js +8 -8
  73. package/dist/components/panel/DebugPanel.vue_vue_type_script_setup_true_lang.js.map +1 -1
  74. package/dist/components/panel/GlobalSearchPalette.js.map +1 -1
  75. package/dist/components/panel/GlobalSearchPalette.vue.d.ts.map +1 -1
  76. package/dist/components/panel/GlobalSearchPalette.vue_vue_type_script_setup_true_lang.js +102 -96
  77. package/dist/components/panel/GlobalSearchPalette.vue_vue_type_script_setup_true_lang.js.map +1 -1
  78. package/dist/components/panel/NavGroup.vue_vue_type_script_setup_true_lang.js +10 -10
  79. package/dist/components/panel/NavGroup.vue_vue_type_script_setup_true_lang.js.map +1 -1
  80. package/dist/components/panel/NavGroupFlyout.vue_vue_type_script_setup_true_lang.js +9 -9
  81. package/dist/components/panel/NavGroupFlyout.vue_vue_type_script_setup_true_lang.js.map +1 -1
  82. package/dist/components/panel/NavItem.vue_vue_type_script_setup_true_lang.js +16 -16
  83. package/dist/components/panel/NavItem.vue_vue_type_script_setup_true_lang.js.map +1 -1
  84. package/dist/components/panel/NavSubItem.vue_vue_type_script_setup_true_lang.js +10 -10
  85. package/dist/components/panel/NavSubItem.vue_vue_type_script_setup_true_lang.js.map +1 -1
  86. package/dist/components/panel/TenantMenu.vue_vue_type_script_setup_true_lang.js +35 -35
  87. package/dist/components/panel/TenantMenu.vue_vue_type_script_setup_true_lang.js.map +1 -1
  88. package/dist/components/panel/Topbar.vue_vue_type_script_setup_true_lang.js +11 -11
  89. package/dist/components/panel/Topbar.vue_vue_type_script_setup_true_lang.js.map +1 -1
  90. package/dist/components/realtime/use-live-updates.d.ts.map +1 -1
  91. package/dist/components/realtime/use-live-updates.js +24 -23
  92. package/dist/components/realtime/use-live-updates.js.map +1 -1
  93. package/dist/components/table/BooleanCell.vue_vue_type_script_setup_true_lang.js +2 -1
  94. package/dist/components/table/BooleanCell.vue_vue_type_script_setup_true_lang.js.map +1 -1
  95. package/dist/components/table/ColumnHeader.js.map +1 -1
  96. package/dist/components/table/ColumnHeader.vue.d.ts.map +1 -1
  97. package/dist/components/table/ColumnHeader.vue_vue_type_script_setup_true_lang.js +55 -49
  98. package/dist/components/table/ColumnHeader.vue_vue_type_script_setup_true_lang.js.map +1 -1
  99. package/dist/components/table/ColumnManager.js.map +1 -1
  100. package/dist/components/table/ColumnManager.vue.d.ts.map +1 -1
  101. package/dist/components/table/ColumnManager.vue_vue_type_script_setup_true_lang.js +5 -4
  102. package/dist/components/table/ColumnManager.vue_vue_type_script_setup_true_lang.js.map +1 -1
  103. package/dist/components/table/ContentLayoutSort.js.map +1 -1
  104. package/dist/components/table/ContentLayoutSort.vue.d.ts.map +1 -1
  105. package/dist/components/table/ContentLayoutSort.vue_vue_type_script_setup_true_lang.js +5 -5
  106. package/dist/components/table/ContentLayoutSort.vue_vue_type_script_setup_true_lang.js.map +1 -1
  107. package/dist/components/table/SelectCell.vue_vue_type_script_setup_true_lang.js +2 -1
  108. package/dist/components/table/SelectCell.vue_vue_type_script_setup_true_lang.js.map +1 -1
  109. package/dist/components/table/SelectComboboxCell.vue_vue_type_script_setup_true_lang.js +2 -1
  110. package/dist/components/table/SelectComboboxCell.vue_vue_type_script_setup_true_lang.js.map +1 -1
  111. package/dist/components/table/TableCellContent.js.map +1 -1
  112. package/dist/components/table/TableCellContent.vue.d.ts.map +1 -1
  113. package/dist/components/table/TableCellContent.vue_vue_type_script_setup_true_lang.js +4 -3
  114. package/dist/components/table/TableCellContent.vue_vue_type_script_setup_true_lang.js.map +1 -1
  115. package/dist/components/table/TablePagination.js.map +1 -1
  116. package/dist/components/table/TablePagination.vue.d.ts.map +1 -1
  117. package/dist/components/table/TablePagination.vue_vue_type_script_setup_true_lang.js +87 -87
  118. package/dist/components/table/TablePagination.vue_vue_type_script_setup_true_lang.js.map +1 -1
  119. package/dist/components/table/TextInputCell.vue_vue_type_script_setup_true_lang.js +2 -1
  120. package/dist/components/table/TextInputCell.vue_vue_type_script_setup_true_lang.js.map +1 -1
  121. package/dist/components/table/cell-update.d.ts +6 -0
  122. package/dist/components/table/cell-update.d.ts.map +1 -1
  123. package/dist/components/table/cell-update.js.map +1 -1
  124. package/dist/components/translation-manager/TranslationManagerView.vue_vue_type_script_setup_true_lang.js +1 -1
  125. package/dist/components/translation-manager/TranslationManagerView.vue_vue_type_script_setup_true_lang.js.map +1 -1
  126. package/dist/components/ui/CommandAutoHighlight.js +7 -0
  127. package/dist/components/ui/CommandAutoHighlight.js.map +1 -0
  128. package/dist/components/ui/CommandAutoHighlight.vue.d.ts +21 -0
  129. package/dist/components/ui/CommandAutoHighlight.vue.d.ts.map +1 -0
  130. package/dist/components/ui/CommandAutoHighlight.vue_vue_type_script_setup_true_lang.js +18 -0
  131. package/dist/components/ui/CommandAutoHighlight.vue_vue_type_script_setup_true_lang.js.map +1 -0
  132. package/dist/components/ui/DialogContent.js.map +1 -1
  133. package/dist/components/ui/DialogContent.vue.d.ts.map +1 -1
  134. package/dist/components/ui/DialogContent.vue_vue_type_script_setup_true_lang.js +13 -12
  135. package/dist/components/ui/DialogContent.vue_vue_type_script_setup_true_lang.js.map +1 -1
  136. package/dist/components/ui/PopoverContent.js.map +1 -1
  137. package/dist/components/ui/PopoverContent.vue.d.ts.map +1 -1
  138. package/dist/components/ui/PopoverContent.vue_vue_type_script_setup_true_lang.js +9 -8
  139. package/dist/components/ui/PopoverContent.vue_vue_type_script_setup_true_lang.js.map +1 -1
  140. package/dist/components/ui/SheetContent.js.map +1 -1
  141. package/dist/components/ui/SheetContent.vue.d.ts.map +1 -1
  142. package/dist/components/ui/SheetContent.vue_vue_type_script_setup_true_lang.js +13 -12
  143. package/dist/components/ui/SheetContent.vue_vue_type_script_setup_true_lang.js.map +1 -1
  144. package/dist/components/ui/TooltipContent.js.map +1 -1
  145. package/dist/components/ui/TooltipContent.vue.d.ts.map +1 -1
  146. package/dist/components/ui/TooltipContent.vue_vue_type_script_setup_true_lang.js +9 -8
  147. package/dist/components/ui/TooltipContent.vue_vue_type_script_setup_true_lang.js.map +1 -1
  148. package/dist/context.d.ts +7 -0
  149. package/dist/context.d.ts.map +1 -1
  150. package/dist/context.js +29 -26
  151. package/dist/context.js.map +1 -1
  152. package/dist/create-alfakit.d.ts.map +1 -1
  153. package/dist/create-alfakit.js +33 -31
  154. package/dist/create-alfakit.js.map +1 -1
  155. package/dist/eject-manifest.json +11 -2
  156. package/dist/index.d.ts +1 -0
  157. package/dist/index.d.ts.map +1 -1
  158. package/dist/index.js +219 -217
  159. package/dist/layouts/AppLayout.vue_vue_type_script_setup_true_lang.js +8 -8
  160. package/dist/layouts/AppLayout.vue_vue_type_script_setup_true_lang.js.map +1 -1
  161. package/dist/layouts/AuthLayout.vue_vue_type_script_setup_true_lang.js +9 -9
  162. package/dist/layouts/FullscreenLayout.vue_vue_type_script_setup_true_lang.js +8 -8
  163. package/dist/layouts/FullscreenLayout.vue_vue_type_script_setup_true_lang.js.map +1 -1
  164. package/dist/layouts/TopNavLayout.vue_vue_type_script_setup_true_lang.js +15 -15
  165. package/dist/layouts/TopNavLayout.vue_vue_type_script_setup_true_lang.js.map +1 -1
  166. package/dist/layouts/lazy-layouts.d.ts +10 -0
  167. package/dist/layouts/lazy-layouts.d.ts.map +1 -0
  168. package/dist/layouts/lazy-layouts.js +8 -0
  169. package/dist/layouts/lazy-layouts.js.map +1 -0
  170. package/dist/layouts/panel-layouts.d.ts +8 -0
  171. package/dist/layouts/panel-layouts.d.ts.map +1 -0
  172. package/dist/layouts/panel-layouts.js +15 -0
  173. package/dist/layouts/panel-layouts.js.map +1 -0
  174. package/dist/lib/lazy.d.ts.map +1 -1
  175. package/dist/lib/lazy.js +2 -2
  176. package/dist/lib/lazy.js.map +1 -1
  177. package/dist/pages/PageShell.js.map +1 -1
  178. package/dist/pages/PageShell.vue.d.ts.map +1 -1
  179. package/dist/pages/PageShell.vue_vue_type_script_setup_true_lang.js +39 -42
  180. package/dist/pages/PageShell.vue_vue_type_script_setup_true_lang.js.map +1 -1
  181. package/dist/standalone/AlfakitComponent.js.map +1 -1
  182. package/dist/standalone/AlfakitComponent.vue.d.ts.map +1 -1
  183. package/dist/standalone/AlfakitComponent.vue_vue_type_script_setup_true_lang.js +56 -52
  184. package/dist/standalone/AlfakitComponent.vue_vue_type_script_setup_true_lang.js.map +1 -1
  185. package/dist/standalone.css +7 -0
  186. package/dist/starter-kit/AlfakitStarterKitRoot.js.map +1 -1
  187. package/dist/starter-kit/AlfakitStarterKitRoot.vue.d.ts +2 -2
  188. package/dist/starter-kit/AlfakitStarterKitRoot.vue.d.ts.map +1 -1
  189. package/dist/starter-kit/AlfakitStarterKitRoot.vue_vue_type_script_setup_true_lang.js +17 -12
  190. package/dist/starter-kit/AlfakitStarterKitRoot.vue_vue_type_script_setup_true_lang.js.map +1 -1
  191. package/dist/starter-kit/dashboard-widgets.d.ts +54 -0
  192. package/dist/starter-kit/dashboard-widgets.d.ts.map +1 -0
  193. package/dist/starter-kit/dashboard-widgets.js +54 -0
  194. package/dist/starter-kit/dashboard-widgets.js.map +1 -0
  195. package/dist/starter-kit/index.d.ts +2 -1
  196. package/dist/starter-kit/index.d.ts.map +1 -1
  197. package/dist/starter-kit/index.js +5 -4
  198. package/dist/starter-kit/runtime.d.ts +6 -0
  199. package/dist/starter-kit/runtime.d.ts.map +1 -1
  200. package/dist/starter-kit/runtime.js +19 -15
  201. package/dist/starter-kit/runtime.js.map +1 -1
  202. package/dist/starter-kit/starter-kit.d.ts.map +1 -1
  203. package/dist/starter-kit/starter-kit.js +8 -8
  204. package/dist/starter-kit/starter-kit.js.map +1 -1
  205. package/dist/starter-kit/widgets/CopilotTrigger.js +7 -0
  206. package/dist/starter-kit/widgets/CopilotTrigger.js.map +1 -0
  207. package/dist/starter-kit/widgets/CopilotTrigger.vue.d.ts +12 -0
  208. package/dist/starter-kit/widgets/CopilotTrigger.vue.d.ts.map +1 -0
  209. package/dist/starter-kit/widgets/CopilotTrigger.vue_vue_type_script_setup_true_lang.js +23 -0
  210. package/dist/starter-kit/widgets/CopilotTrigger.vue_vue_type_script_setup_true_lang.js.map +1 -0
  211. package/dist/starter-kit/widgets/LoadedCopilot.js +7 -0
  212. package/dist/starter-kit/widgets/LoadedCopilot.js.map +1 -0
  213. package/dist/starter-kit/widgets/LoadedCopilot.vue.d.ts +8 -0
  214. package/dist/starter-kit/widgets/LoadedCopilot.vue.d.ts.map +1 -0
  215. package/dist/starter-kit/widgets/LoadedCopilot.vue_vue_type_script_setup_true_lang.js +31 -0
  216. package/dist/starter-kit/widgets/LoadedCopilot.vue_vue_type_script_setup_true_lang.js.map +1 -0
  217. package/dist/starter-kit/widgets/StarterKitImpersonationBanner.js +7 -0
  218. package/dist/starter-kit/widgets/StarterKitImpersonationBanner.js.map +1 -0
  219. package/dist/starter-kit/widgets/StarterKitImpersonationBanner.vue.d.ts +8 -0
  220. package/dist/starter-kit/widgets/StarterKitImpersonationBanner.vue.d.ts.map +1 -0
  221. package/dist/starter-kit/widgets/StarterKitImpersonationBanner.vue_vue_type_script_setup_true_lang.js +34 -0
  222. package/dist/starter-kit/widgets/StarterKitImpersonationBanner.vue_vue_type_script_setup_true_lang.js.map +1 -0
  223. package/dist/starter-kit/widgets/index.d.ts +40 -9
  224. package/dist/starter-kit/widgets/index.d.ts.map +1 -1
  225. package/dist/starter-kit/widgets/index.js +21 -18
  226. package/dist/starter-kit/widgets/index.js.map +1 -1
  227. package/dist/starter-kit/widgets/loaded.d.ts +10 -0
  228. package/dist/starter-kit/widgets/loaded.d.ts.map +1 -0
  229. package/dist/starter-kit/widgets/loaded.js +5 -0
  230. package/dist/styles.css +9 -2
  231. package/dist/themes.css +6 -1
  232. package/package.json +2 -2
  233. package/src/AlfakitRoot.vue +9 -1
  234. package/src/components/actions/ActionGroupMenu.vue +13 -1
  235. package/src/components/actions/ActionModal.vue +9 -0
  236. package/src/components/ai/AiCopilot.vue +7 -1
  237. package/src/components/cms/LivePreview.vue +8 -2
  238. package/src/components/fields/BuilderField.vue +15 -2
  239. package/src/components/fields/ImageEditorDialog.vue +7 -3
  240. package/src/components/fields/KeyValueField.vue +3 -2
  241. package/src/components/fields/ModalTablePicker.vue +7 -2
  242. package/src/components/fields/RepeaterField.vue +2 -3
  243. package/src/components/fields/RichEditorInput.vue +3 -0
  244. package/src/components/fields/item-actions.ts +31 -10
  245. package/src/components/form/FormBlock.vue +2 -1
  246. package/src/components/form/form-context.ts +2 -2
  247. package/src/components/kanban/KanbanBoard.vue +15 -3
  248. package/src/components/kanban/KanbanColumnHeader.vue +6 -4
  249. package/src/components/layout/SectionComponent.vue +10 -4
  250. package/src/components/panel/GlobalSearchPalette.vue +2 -0
  251. package/src/components/realtime/use-live-updates.ts +3 -1
  252. package/src/components/table/ColumnHeader.vue +23 -12
  253. package/src/components/table/ColumnManager.vue +12 -8
  254. package/src/components/table/ContentLayoutSort.vue +7 -1
  255. package/src/components/table/TableCellContent.vue +4 -2
  256. package/src/components/table/TablePagination.vue +12 -7
  257. package/src/components/table/cell-update.ts +6 -0
  258. package/src/components/ui/CommandAutoHighlight.vue +27 -0
  259. package/src/components/ui/DialogContent.vue +5 -1
  260. package/src/components/ui/PopoverContent.vue +5 -1
  261. package/src/components/ui/SheetContent.vue +5 -1
  262. package/src/components/ui/TooltipContent.vue +5 -1
  263. package/src/context.ts +10 -0
  264. package/src/create-alfakit.ts +5 -0
  265. package/src/index.ts +2 -0
  266. package/src/layouts/lazy-layouts.ts +14 -0
  267. package/src/layouts/panel-layouts.ts +17 -0
  268. package/src/lib/lazy.ts +11 -1
  269. package/src/pages/PageShell.vue +5 -6
  270. package/src/standalone/AlfakitComponent.vue +17 -6
  271. package/src/starter-kit/AlfakitStarterKitRoot.vue +12 -3
  272. package/src/starter-kit/dashboard-widgets.ts +93 -0
  273. package/src/starter-kit/index.ts +7 -1
  274. package/src/starter-kit/runtime.ts +17 -1
  275. package/src/starter-kit/starter-kit.ts +2 -1
  276. package/src/starter-kit/widgets/CopilotTrigger.vue +58 -0
  277. package/src/starter-kit/widgets/LoadedCopilot.vue +29 -0
  278. package/src/starter-kit/widgets/StarterKitImpersonationBanner.vue +57 -0
  279. package/src/starter-kit/widgets/index.ts +56 -11
  280. package/src/starter-kit/widgets/loaded.ts +9 -0
  281. package/src/styles.css +9 -2
@@ -261,24 +261,28 @@ const move = (name: string, offset: -1 | 1, event: MouseEvent) => {
261
261
  reorder(name, moveColumnInManager(names.value, name, offset, props.table.columnGroups))
262
262
  }
263
263
 
264
- const apply = () => {
265
- if (orderDraft.value && orderChanged.value) void save(orderDraft.value)
266
-
267
- if (draft.value && columnDraftChanged(props.table.visibleColumns, draft.value)) {
268
- visitTable(props.table.identifier, { columns: draft.value }, ['page'])
269
- }
264
+ // The order is saved before the visibility visit: both requests share the session, and a
265
+ // visit running alongside the save would write the old order back when it finishes.
266
+ const apply = async () => {
267
+ const order = orderDraft.value && orderChanged.value ? orderDraft.value : null
268
+ const columns =
269
+ draft.value && columnDraftChanged(props.table.visibleColumns, draft.value) ? draft.value : null
270
270
 
271
271
  draft.value = null
272
272
  orderDraft.value = null
273
273
  announcement.value = ''
274
274
  open.value = false
275
+
276
+ if (order) await save(order)
277
+
278
+ if (columns) visitTable(props.table.identifier, { columns }, ['page'])
275
279
  }
276
280
 
277
281
  // Reset: the defined column order and, for toggleable columns, the default visibility.
278
- const reset = () => {
282
+ const reset = async () => {
279
283
  if (reorderable.value) {
280
284
  orderDraft.value = null
281
- void save([])
285
+ await save([])
282
286
  }
283
287
 
284
288
  if (toggleable.value) {
@@ -14,6 +14,12 @@ const props = defineProps<{ table: TableSchema; columns: ColumnSchema[] }>()
14
14
  const t = useT()
15
15
  const sortable = computed(() => props.columns.filter((column) => column.sortable))
16
16
  const direction = computed(() => props.table.sort?.direction ?? 'asc')
17
+ // A default sort on a column the select doesn't list (`created_at`) shows the placeholder.
18
+ const selected = computed(() =>
19
+ sortable.value.some((column) => column.name === props.table.sort?.column)
20
+ ? (props.table.sort?.column ?? '')
21
+ : '',
22
+ )
17
23
 
18
24
  const sortBy = (event: Event) => {
19
25
  const value = (event.target as HTMLSelectElement).value
@@ -39,7 +45,7 @@ const flip = () =>
39
45
  <label class="flex items-center gap-2 text-sm">
40
46
  <span class="sr-only">{{ t('table.sort_by', {}, 'Sort by') }}</span>
41
47
  <select
42
- :value="props.table.sort?.column ?? ''"
48
+ :value="selected"
43
49
  class="border-input h-8 rounded-md border bg-transparent px-2 text-sm"
44
50
  @change="sortBy"
45
51
  >
@@ -22,7 +22,9 @@ import TextInputCell from './TextInputCell.vue'
22
22
  const props = defineProps<CellProps>()
23
23
  const registry = useRegistry()
24
24
  // A component registered as `column:<type>` replaces the built-in cell renderer.
25
- const custom = computed(() => registry.resolve(columnRegistryKey(props.column)))
25
+ const custom = computed(() =>
26
+ props.fromRegistry ? undefined : registry.resolve(columnRegistryKey(props.column)),
27
+ )
26
28
  const t = useT()
27
29
  // `ViewColumn`: the application component registered under the column's `view()` name.
28
30
  const viewName = computed(() => (props.column as { component?: string }).component ?? '')
@@ -106,7 +108,7 @@ const descriptionPosition = computed(
106
108
  </script>
107
109
 
108
110
  <template>
109
- <component :is="custom" v-if="custom" v-bind="props" />
111
+ <component :is="custom" v-if="custom" v-bind="props" :from-registry="true" />
110
112
  <component
111
113
  :is="view"
112
114
  v-else-if="view"
@@ -10,12 +10,13 @@ import {
10
10
  } from '@alfakit/core'
11
11
  import { ChevronLeftIcon, ChevronRightIcon, ChevronsLeftIcon, ChevronsRightIcon } from '@lucide/vue'
12
12
  import { computed, onBeforeUnmount, ref, watch } from 'vue'
13
- import { useT } from '../../context'
13
+ import { useFormatter, useT } from '../../context'
14
14
  import { Icon } from '../../lib/icons'
15
15
  import Button from '../ui/Button.vue'
16
16
 
17
17
  const props = defineProps<{ table: TableSchema }>()
18
18
  const t = useT()
19
+ const format = useFormatter()
19
20
  const pagination = computed(() => props.table.pagination)
20
21
 
21
22
  function pageWindow(current: number, last: number): Array<number | null> {
@@ -66,13 +67,17 @@ const summary = computed(() => {
66
67
  return numbered.value
67
68
  ? t(
68
69
  'table.showing',
69
- { first: value.from, last: value.to, total: numbered.value.total },
70
- `Showing ${value.from}–${value.to} of ${numbered.value.total}`,
70
+ {
71
+ first: format.value.number(value.from),
72
+ last: format.value.number(value.to),
73
+ total: format.value.number(numbered.value.total),
74
+ },
75
+ 'Showing :first–:last of :total',
71
76
  )
72
77
  : t(
73
78
  'table.showing_range',
74
- { first: value.from, last: value.to },
75
- `Showing ${value.from}–${value.to}`,
79
+ { first: format.value.number(value.from), last: format.value.number(value.to) },
80
+ 'Showing :first–:last',
76
81
  )
77
82
  })
78
83
  const goTo = (page: number) => visitTable(props.table.identifier, { page }, ['page'])
@@ -173,7 +178,7 @@ onBeforeUnmount(() => observer?.disconnect())
173
178
  @change="setPerPage"
174
179
  >
175
180
  <option v-for="option in pagination.pageOptions" :key="option" :value="String(option)">
176
- {{ option === 'all' ? t('table.all', {}, 'All') : option }}
181
+ {{ option === 'all' ? t('table.all', {}, 'All') : format.number(option) }}
177
182
  </option>
178
183
  </select>
179
184
  </label>
@@ -251,7 +256,7 @@ onBeforeUnmount(() => observer?.disconnect())
251
256
  size="icon-sm"
252
257
  :aria-current="page === numbered.currentPage ? 'page' : undefined"
253
258
  @click="goTo(page)"
254
- >{{ page }}</Button
259
+ >{{ format.number(page) }}</Button
255
260
  >
256
261
  </template>
257
262
  </template>
@@ -10,6 +10,12 @@ export interface CellProps {
10
10
  recordKey: RecordKey
11
11
  token: string
12
12
  component: string
13
+ /**
14
+ * Set when this renderer was picked from the registry (`column:<type>`): it then renders
15
+ * the built-in cell instead of looking itself up again, so an ejected `TableCellContent`
16
+ * registered for a column type doesn't render itself forever.
17
+ */
18
+ fromRegistry?: boolean
13
19
  }
14
20
 
15
21
  export function useCellUpdate(props: CellProps) {
@@ -0,0 +1,27 @@
1
+ <script setup lang="ts">
2
+ import { injectListboxRootContext } from 'reka-ui'
3
+ import { nextTick, watch } from 'vue'
4
+
5
+ /**
6
+ * Inside a `Command`: highlights the first item when `items` change and nothing (still on
7
+ * the page) is highlighted, as cmdk does in React. Results that arrive after typing (a
8
+ * server search) would otherwise leave Enter with nothing to select.
9
+ */
10
+ const props = defineProps<{ items: unknown }>()
11
+ const root = injectListboxRootContext()
12
+
13
+ watch(
14
+ () => props.items,
15
+ () =>
16
+ nextTick(() => {
17
+ const highlighted = root.highlightedElement.value
18
+
19
+ if (!highlighted || !highlighted.isConnected) root.highlightFirstItem()
20
+ }),
21
+ { deep: true },
22
+ )
23
+ </script>
24
+
25
+ <template>
26
+ <slot />
27
+ </template>
@@ -6,6 +6,7 @@ import {
6
6
  DialogContent,
7
7
  DialogOverlay,
8
8
  DialogPortal,
9
+ useDirection,
9
10
  useForwardPropsEmits,
10
11
  type DialogContentEmits,
11
12
  type DialogContentProps,
@@ -28,6 +29,9 @@ defineOptions({ inheritAttrs: false })
28
29
 
29
30
  const emits = defineEmits<DialogContentEmits>()
30
31
  const forwarded = useForwardPropsEmits(reactiveOmit(props, 'class', 'showCloseButton'), emits)
32
+ // Portaled outside Alfakit's root: carry the reading direction (starter kit pages and
33
+ // standalone components leave <html dir> to the host).
34
+ const dir = useDirection()
31
35
  const t = useT()
32
36
  </script>
33
37
 
@@ -39,7 +43,7 @@ const t = useT()
39
43
  />
40
44
  <DialogContent
41
45
  data-slot="dialog-content"
42
- v-bind="{ ...forwarded, ...$attrs }"
46
+ v-bind="{ dir, ...forwarded, ...$attrs }"
43
47
  :class="
44
48
  cn(
45
49
  'bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 sm:max-w-lg',
@@ -3,6 +3,7 @@ import { reactiveOmit } from '@vueuse/core'
3
3
  import {
4
4
  PopoverContent,
5
5
  PopoverPortal,
6
+ useDirection,
6
7
  useForwardPropsEmits,
7
8
  type PopoverContentEmits,
8
9
  type PopoverContentProps,
@@ -20,13 +21,16 @@ defineOptions({ inheritAttrs: false })
20
21
 
21
22
  const emits = defineEmits<PopoverContentEmits>()
22
23
  const forwarded = useForwardPropsEmits(reactiveOmit(props, 'class'), emits)
24
+ // Portaled outside Alfakit's root: carry the reading direction (starter kit pages and
25
+ // standalone components leave <html dir> to the host).
26
+ const dir = useDirection()
23
27
  </script>
24
28
 
25
29
  <template>
26
30
  <PopoverPortal>
27
31
  <PopoverContent
28
32
  data-slot="popover-content"
29
- v-bind="{ ...forwarded, ...$attrs }"
33
+ v-bind="{ ...forwarded, dir: forwarded.dir ?? dir, ...$attrs }"
30
34
  :class="
31
35
  cn(
32
36
  'bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-72 origin-(--reka-popover-content-transform-origin) rounded-md border p-4 shadow-md outline-hidden',
@@ -6,6 +6,7 @@ import {
6
6
  DialogContent,
7
7
  DialogOverlay,
8
8
  DialogPortal,
9
+ useDirection,
9
10
  useForwardPropsEmits,
10
11
  type DialogContentEmits,
11
12
  type DialogContentProps,
@@ -35,6 +36,9 @@ const forwarded = useForwardPropsEmits(
35
36
  reactiveOmit(props, 'class', 'side', 'showCloseButton'),
36
37
  emits,
37
38
  )
39
+ // Portaled outside Alfakit's root: carry the reading direction (starter kit pages and
40
+ // standalone components leave <html dir> to the host).
41
+ const dir = useDirection()
38
42
  const t = useT()
39
43
  </script>
40
44
 
@@ -46,7 +50,7 @@ const t = useT()
46
50
  />
47
51
  <DialogContent
48
52
  data-slot="sheet-content"
49
- v-bind="{ ...forwarded, ...$attrs }"
53
+ v-bind="{ dir, ...forwarded, ...$attrs }"
50
54
  :class="
51
55
  cn(
52
56
  'bg-background data-[state=open]:animate-in data-[state=closed]:animate-out fixed z-50 flex flex-col gap-4 shadow-lg transition ease-in-out data-[state=closed]:duration-300 data-[state=open]:duration-500',
@@ -4,6 +4,7 @@ import {
4
4
  TooltipArrow,
5
5
  TooltipContent,
6
6
  TooltipPortal,
7
+ useDirection,
7
8
  useForwardPropsEmits,
8
9
  type TooltipContentEmits,
9
10
  type TooltipContentProps,
@@ -21,13 +22,16 @@ defineOptions({ inheritAttrs: false })
21
22
 
22
23
  const emits = defineEmits<TooltipContentEmits>()
23
24
  const forwarded = useForwardPropsEmits(reactiveOmit(props, 'class'), emits)
25
+ // Portaled outside Alfakit's root: carry the reading direction (starter kit pages and
26
+ // standalone components leave <html dir> to the host).
27
+ const dir = useDirection()
24
28
  </script>
25
29
 
26
30
  <template>
27
31
  <TooltipPortal>
28
32
  <TooltipContent
29
33
  data-slot="tooltip-content"
30
- v-bind="{ ...forwarded, ...$attrs }"
34
+ v-bind="{ dir, ...forwarded, ...$attrs }"
31
35
  :class="
32
36
  cn(
33
37
  'bg-foreground text-background animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-fit origin-(--reka-tooltip-content-transform-origin) rounded-md px-3 py-1.5 text-xs text-balance',
package/src/context.ts CHANGED
@@ -36,6 +36,11 @@ export interface AlfakitContextValue {
36
36
  * their own schemas by token.
37
37
  */
38
38
  poll?: (target: string, interval: string | number | null | undefined) => () => void
39
+ /**
40
+ * Fetches fresh schemas of components now (`live()` tables and widgets after a record
41
+ * change). Panels leave it out (a partial reload); components outside panels fetch theirs.
42
+ */
43
+ refresh?: (targets: string[]) => Promise<void>
39
44
  }
40
45
 
41
46
  export const ALFAKIT_KEY: InjectionKey<AlfakitContextValue> = Symbol('alfakit')
@@ -69,6 +74,11 @@ export function usePollComponent(): NonNullable<AlfakitContextValue['poll']> {
69
74
  return inject(ALFAKIT_KEY, null)?.poll ?? pollComponent
70
75
  }
71
76
 
77
+ /** How `live()` components refresh: their own fetch outside panels, else a partial reload. */
78
+ export function useRefreshComponents(): AlfakitContextValue['refresh'] {
79
+ return inject(ALFAKIT_KEY, null)?.refresh
80
+ }
81
+
72
82
  export function provideAlfakit(value: AlfakitContextValue): void {
73
83
  provide(ALFAKIT_KEY, value)
74
84
  }
@@ -6,6 +6,7 @@ import {
6
6
  configureCharts,
7
7
  configureRealtime,
8
8
  debugRecorder,
9
+ documentNonce,
9
10
  effectiveErrorNotifications,
10
11
  initializeAppearance,
11
12
  installErrorNotifications,
@@ -27,6 +28,7 @@ import type { App, DefineComponent } from 'vue'
27
28
  import AlfakitRoot from './AlfakitRoot.vue'
28
29
  import { showToast } from './components/notifications/flash-toasts'
29
30
  import { ALFAKIT_KEY, type AlfakitContextValue, type AnyComponent } from './context'
31
+ import { panelLayouts } from './layouts/panel-layouts'
30
32
  import { discoverComponents } from './lib/discovery'
31
33
  import { preloadIcons } from './lib/icons'
32
34
  import AlfakitPage from './pages/AlfakitPage.vue'
@@ -54,6 +56,7 @@ export function bootAlfakit(
54
56
  // Auto-registered files sit between the built-ins and the explicit `components` / `pages`.
55
57
  const discovered = discoverComponents(options.discover)
56
58
  const registry = createDefaultRegistry()
59
+ .registerMany(panelLayouts)
57
60
  .registerMany(discovered.components)
58
61
  .registerMany(options.components ?? {})
59
62
  const pages: Record<string, AnyComponent> = {
@@ -158,6 +161,8 @@ export function bootAlfakit(
158
161
  return createInertiaApp<AlfakitPageProps>({
159
162
  title: (title) => title,
160
163
  progress: options.progress === undefined ? { color: 'var(--primary)' } : options.progress,
164
+ // The page's CSP nonce, so the progress bar's injected <style> passes a nonce-based policy.
165
+ nonce: documentNonce(),
161
166
  resolve: (name, page) => {
162
167
  const component = pages[name]
163
168
 
package/src/index.ts CHANGED
@@ -102,6 +102,8 @@ export { discoverComponents, discoveredComponent, type DiscoveredComponents } fr
102
102
  export { Icon, hasIcon, resolveIcon } from './lib/icons'
103
103
  export { cn } from './lib/utils'
104
104
  export * from './pages'
105
+ // `createAlfakit()` registers these; a registry built by hand for `AlfakitPage` needs them too.
106
+ export { panelLayouts } from './layouts/panel-layouts'
105
107
  export { createDefaultRegistry } from './registry'
106
108
  export * from './standalone'
107
109
  export * from './starter-kit'
@@ -0,0 +1,14 @@
1
+ import { lazyComponents } from '@alfakit/core'
2
+ import type { AnyComponent } from '../context'
3
+ import { discoveredComponent } from '../lib/discovery'
4
+
5
+ /**
6
+ * The fullscreen layout (`$layout = 'fullscreen'`), loaded on demand by starter kit pages:
7
+ * they render in the host's layout, so the page chunk never imports the panel's header,
8
+ * menus and notifications for a layout few pages use. Only the starter kit registers it;
9
+ * `createAlfakit()` registers the layouts themselves up front (`panelLayouts`), so a panel's
10
+ * bundle has no extra lazy entry points.
11
+ */
12
+ export const lazyPanelLayouts: Record<string, AnyComponent> = lazyComponents<AnyComponent>({
13
+ 'layout:fullscreen': () => import('./FullscreenLayout.vue').then((m) => m.default),
14
+ }).map(discoveredComponent).components
@@ -0,0 +1,17 @@
1
+ import type { AnyComponent } from '../context'
2
+ import AppLayout from './AppLayout.vue'
3
+ import AuthLayout from './AuthLayout.vue'
4
+ import BlankLayout from './BlankLayout.vue'
5
+ import FullscreenLayout from './FullscreenLayout.vue'
6
+
7
+ /**
8
+ * The panel's own layouts (sidebar or top navigation, auth card, blank, fullscreen), which
9
+ * `createAlfakit()` registers up front. Starter kit pages render in the host's layout and
10
+ * never import these: `PageShell` loads one on demand if such a page asks for it.
11
+ */
12
+ export const panelLayouts: Record<string, AnyComponent> = {
13
+ 'layout:app': AppLayout,
14
+ 'layout:auth': AuthLayout,
15
+ 'layout:blank': BlankLayout,
16
+ 'layout:fullscreen': FullscreenLayout,
17
+ }
package/src/lib/lazy.ts CHANGED
@@ -29,8 +29,18 @@ export function lazyComponent(
29
29
  inheritAttrs: false,
30
30
  setup(_, { attrs }) {
31
31
  const mounted = useAppMounted()
32
+ // Picked once per instance: switching from the async wrapper to the loaded component
33
+ // on a later render would be a new component type, so Vue would remount it and its
34
+ // state (a spreadsheet's undo history, an editor's selection) would be lost.
35
+ let component: Component | null = null
32
36
 
33
- return () => h(mounted.value ? (loaded ?? Async) : fallback, attrs)
37
+ return () => {
38
+ if (!mounted.value) return h(fallback, attrs)
39
+
40
+ component ??= loaded ?? Async
41
+
42
+ return h(component, attrs)
43
+ }
34
44
  },
35
45
  })
36
46
  }
@@ -5,10 +5,7 @@ import { computed, onBeforeUnmount, watch } from 'vue'
5
5
  import KeyboardShortcuts from '../components/panel/KeyboardShortcuts.vue'
6
6
  import Slot from '../components/panel/Slot.vue'
7
7
  import { useRegistry } from '../context'
8
- import AppLayout from '../layouts/AppLayout.vue'
9
- import AuthLayout from '../layouts/AuthLayout.vue'
10
8
  import BlankLayout from '../layouts/BlankLayout.vue'
11
- import FullscreenLayout from '../layouts/FullscreenLayout.vue'
12
9
  import SubNavigationLayout from '../components/panel/SubNavigationLayout.vue'
13
10
  import ConflictBanner from '../components/realtime/ConflictBanner.vue'
14
11
  import PageHeader from './PageHeader.vue'
@@ -17,10 +14,12 @@ const props = defineProps<{ page: PageSchema }>()
17
14
  const registry = useRegistry()
18
15
 
19
16
  // Each layout can be replaced: createAlfakit({ components: { 'layout:app': MyLayout } }).
20
- const Auth = computed(() => registry.resolve('layout:auth') ?? AuthLayout)
17
+ // `createAlfakit()` registers the panel's layouts (`panelLayouts`), the starter kit its content
18
+ // layout; importing the panel layouts here would put the sidebar in every starter kit page.
19
+ const Auth = computed(() => registry.resolve('layout:auth') ?? BlankLayout)
21
20
  const Blank = computed(() => registry.resolve('layout:blank') ?? BlankLayout)
22
- const Fullscreen = computed(() => registry.resolve('layout:fullscreen') ?? FullscreenLayout)
23
- const App = computed(() => registry.resolve('layout:app') ?? AppLayout)
21
+ const Fullscreen = computed(() => registry.resolve('layout:fullscreen') ?? BlankLayout)
22
+ const App = computed(() => registry.resolve('layout:app') ?? BlankLayout)
24
23
  // Edit pages: somebody else saved the record (`detectConflicts()`, `Panel::realtime()`).
25
24
  const Conflicts = computed(() => registry.resolve('page:conflict-banner') ?? ConflictBanner)
26
25
 
@@ -67,14 +67,23 @@ const version = ref(0)
67
67
  const state = new StandaloneComponentState(props.component, () => version.value++)
68
68
  const poll = (target: string, interval: string | number | null | undefined) =>
69
69
  state.poll(target, interval)
70
+ const refresh = (targets: string[]) => state.refresh(targets)
70
71
 
71
72
  const context: AlfakitContextValue = parent
72
- ? { ...parent, registry: createStandaloneRegistry(props.components, parent.registry), poll }
73
- : createStandaloneContext(
74
- { action: props.component.endpoints.action, modal: props.component.endpoints.modal },
75
- props.components,
73
+ ? {
74
+ ...parent,
75
+ registry: createStandaloneRegistry(props.components, parent.registry),
76
76
  poll,
77
- )
77
+ refresh,
78
+ }
79
+ : {
80
+ ...createStandaloneContext(
81
+ { action: props.component.endpoints.action, modal: props.component.endpoints.modal },
82
+ props.components,
83
+ poll,
84
+ ),
85
+ refresh,
86
+ }
78
87
 
79
88
  provide(ALFAKIT_KEY, context)
80
89
 
@@ -124,9 +133,11 @@ onMounted(() => {
124
133
  { immediate: true },
125
134
  )
126
135
 
136
+ // The watcher runs before the new payload renders: hand it over, or the response would
137
+ // count as stale and lazy widgets (a calendar after its action) keep their old schema.
127
138
  watch(
128
139
  () => props.component.token,
129
- () => void state.loadLazy(),
140
+ () => void state.loadLazy(props.component),
130
141
  { immediate: true },
131
142
  )
132
143
 
@@ -56,7 +56,16 @@ onUnmounted(() => {
56
56
  </script>
57
57
 
58
58
  <template>
59
- <AlfakitRoot :toaster-id="STARTER_KIT_TOASTER_ID">
60
- <slot />
61
- </AlfakitRoot>
59
+ <!-- The reading direction and language of Alfakit's content only: the host layout around it
60
+ (sidebar, header) and the app's own pages keep the document's. -->
61
+ <div
62
+ data-slot="starter-kit-root"
63
+ :dir="page.props.alfakit?.localization?.direction ?? 'ltr'"
64
+ :lang="page.props.alfakit?.localization?.tag"
65
+ class="contents"
66
+ >
67
+ <AlfakitRoot :toaster-id="STARTER_KIT_TOASTER_ID">
68
+ <slot />
69
+ </AlfakitRoot>
70
+ </div>
62
71
  </template>
@@ -0,0 +1,93 @@
1
+ import {
2
+ standaloneWidgetCount,
3
+ starterKitDashboardWidgets,
4
+ type StandaloneComponentSchema,
5
+ } from '@alfakit/core'
6
+ import { usePage } from '@inertiajs/vue3'
7
+ import { computed, defineComponent, h, type PropType } from 'vue'
8
+ import type { AnyComponent } from '../context'
9
+ import { lazyComponent } from '../lib/lazy'
10
+
11
+ /** Widget-sized boxes until the widgets' code has loaded (also during SSR). */
12
+ const WidgetsPlaceholder = defineComponent({
13
+ name: 'AlfakitWidgetsPlaceholder',
14
+ props: {
15
+ component: { type: Object as PropType<StandaloneComponentSchema>, required: true },
16
+ // Declared so it does not fall through as an attribute.
17
+ components: { type: Object as PropType<Record<string, AnyComponent>>, default: undefined },
18
+ },
19
+ setup(props) {
20
+ return () =>
21
+ h(
22
+ 'div',
23
+ {
24
+ 'data-slot': 'starter-kit-widgets-placeholder',
25
+ 'aria-busy': 'true',
26
+ class: 'grid auto-rows-min gap-4 md:grid-cols-2',
27
+ },
28
+ Array.from({ length: Math.max(standaloneWidgetCount(props.component), 1) }, (_, index) =>
29
+ h('div', {
30
+ key: index,
31
+ 'aria-hidden': 'true',
32
+ class: 'bg-muted h-28 animate-pulse rounded-xl',
33
+ }),
34
+ ),
35
+ )
36
+ },
37
+ })
38
+
39
+ const LoadedWidgets = lazyComponent(
40
+ 'AlfakitLoadedWidgets',
41
+ () => import('../standalone/AlfakitComponent.vue').then((module) => module.default),
42
+ WidgetsPlaceholder,
43
+ )
44
+
45
+ /**
46
+ * The dashboard widgets of a `starterKit()` panel on the host's own dashboard. Reads the
47
+ * `alfakitWidgets` prop (shared on the panel's `starterKitDashboard()` pages only, the
48
+ * starter kit's `/dashboard` by default) and renders the widgets with the host's theme, as
49
+ * `<AlfakitComponent>` renders standalone widgets: lazy widgets, polling and table widget
50
+ * actions go through the panel's endpoints. Its code loads once mounted; the server render
51
+ * and hydration show placeholders. Renders its default slot (the kit's placeholder boxes)
52
+ * when there are no widgets to show: other pages, guests, users who may not open the panel.
53
+ *
54
+ * ```vue
55
+ * <script setup lang="ts">
56
+ * import { AlfakitWidgets } from '@alfakit/vue'
57
+ * </script>
58
+ *
59
+ * <template>
60
+ * <AlfakitWidgets>
61
+ * <MyEmptyState />
62
+ * </AlfakitWidgets>
63
+ * </template>
64
+ * ```
65
+ */
66
+ export const AlfakitWidgets = defineComponent({
67
+ name: 'AlfakitWidgets',
68
+ inheritAttrs: false,
69
+ props: {
70
+ /** The `starterKit()` panel whose widgets to show (the first one by default). */
71
+ panel: { type: String as PropType<string | undefined>, default: undefined },
72
+ /** Frontend components of custom widgets (`{ RevenueWidget }`), as for `<AlfakitComponent>`. */
73
+ components: {
74
+ type: Object as PropType<Record<string, AnyComponent> | undefined>,
75
+ default: undefined,
76
+ },
77
+ },
78
+ setup(props, { attrs, slots }) {
79
+ const page = usePage()
80
+ const component = computed(() => starterKitDashboardWidgets(page.props, props.panel))
81
+
82
+ return () =>
83
+ component.value
84
+ ? h('div', { 'data-slot': 'starter-kit-widgets' }, [
85
+ h(LoadedWidgets, {
86
+ component: component.value,
87
+ components: props.components,
88
+ class: attrs.class,
89
+ }),
90
+ ])
91
+ : slots.default?.()
92
+ },
93
+ })
@@ -1,5 +1,11 @@
1
1
  export { default as AlfakitStarterKitRoot } from './AlfakitStarterKitRoot.vue'
2
+ export { AlfakitWidgets } from './dashboard-widgets'
2
3
  export { useAlfakitNavigation, type AlfakitNavigation } from './navigation'
3
4
  export { createStarterKitPage, type StarterKitPageOptions } from './starter-kit'
4
5
  export { default as StarterKitContentLayout } from './StarterKitContentLayout.vue'
5
- export { AlfakitNotifications, AlfakitSearch, AlfakitTenantSwitcher } from './widgets'
6
+ export {
7
+ AlfakitCopilot,
8
+ AlfakitNotifications,
9
+ AlfakitSearch,
10
+ AlfakitTenantSwitcher,
11
+ } from './widgets'
@@ -6,6 +6,9 @@ import {
6
6
  } from '@alfakit/core'
7
7
  import { showToast } from '../components/notifications/flash-toasts'
8
8
  import type { AlfakitContextValue, AnyComponent } from '../context'
9
+ import AuthLayout from '../layouts/AuthLayout.vue'
10
+ import { lazyPanelLayouts } from '../layouts/lazy-layouts'
11
+ import { discoverComponents } from '../lib/discovery'
9
12
  import { preloadIcons } from '../lib/icons'
10
13
  import AlfakitPage from '../pages/AlfakitPage.vue'
11
14
  import { createDefaultRegistry } from '../registry'
@@ -21,6 +24,12 @@ export interface StarterKitPageOptions extends Pick<
21
24
  * `null` renders the pages without a host layout.
22
25
  */
23
26
  layout?: AnyComponent | null
27
+ /**
28
+ * Auto-registered custom components, as for `createAlfakit({ discover })`: pass
29
+ * `import.meta.glob('../../alfakit/{fields,columns,entries,widgets,pages,components,blocks}/**\/*.vue')`
30
+ * from `resources/js/pages/Alfakit/Page.vue` and every file there registers under its name.
31
+ */
32
+ discover?: AlfakitOptions<AnyComponent>['discover']
24
33
  }
25
34
 
26
35
  // One context for the browser session (it survives navigations between host and Alfakit
@@ -28,14 +37,21 @@ export interface StarterKitPageOptions extends Pick<
28
37
  let browserContext: AlfakitContextValue | null = null
29
38
 
30
39
  function createStarterKitContext(options: StarterKitPageOptions): AlfakitContextValue {
40
+ // The host's layout replaces the panel's. Auth pages (invitations, tenant registration)
41
+ // keep the panel's card; the fullscreen layout loads on demand.
42
+ // Auto-registered files sit between the built-ins and the explicit `components` / `pages`.
43
+ const discovered = discoverComponents(options.discover)
31
44
  const registry = createDefaultRegistry()
45
+ .registerMany(lazyPanelLayouts)
46
+ .register('layout:auth', AuthLayout)
32
47
  .register('layout:app', StarterKitContentLayout)
48
+ .registerMany(discovered.components)
33
49
  .registerMany(options.components ?? {})
34
50
  const translator = new Translator()
35
51
 
36
52
  return {
37
53
  registry,
38
- pages: { 'Alfakit/Page': AlfakitPage, ...options.pages },
54
+ pages: { 'Alfakit/Page': AlfakitPage, ...discovered.pages, ...options.pages },
39
55
  translator,
40
56
  actions: new ActionRunner({
41
57
  endpoints: { action: '', modal: '' },