@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
@@ -6,178 +6,178 @@ import re from "../actions/ActionList.js";
6
6
  import { useOptionalFormStore as r } from "../form/form-context.js";
7
7
  import { CMS_PREVIEW_DEVICES as i, CmsAutosave as ie, callCmsAutosave as ae, cmsPreviewFitsBeside as oe, cmsPreviewOpensOnLoad as se, rememberedCmsPreview as ce, reserveCmsPreviewSpace as le, resolveStickyOffset as ue } from "@alfakit/core";
8
8
  import { Fragment as de, computed as a, createBlock as o, createCommentVNode as s, createElementBlock as c, createElementVNode as l, createTextVNode as u, createVNode as d, defineComponent as f, normalizeClass as p, normalizeStyle as m, onBeforeUnmount as fe, onMounted as pe, openBlock as h, ref as g, renderList as me, resolveDynamicComponent as he, shallowRef as ge, toDisplayString as _, unref as v, watch as y, withCtx as b } from "vue";
9
- import { CheckIcon as _e, CircleAlertIcon as ve, EyeIcon as ye, LoaderCircleIcon as be, Maximize2Icon as xe, Minimize2Icon as x, MonitorIcon as S, SmartphoneIcon as C, TabletIcon as w, XIcon as T } from "@lucide/vue";
9
+ import { CheckIcon as _e, CircleAlertIcon as ve, EyeIcon as ye, LoaderCircleIcon as be, Maximize2Icon as xe, Minimize2Icon as Se, MonitorIcon as x, SmartphoneIcon as S, TabletIcon as C, XIcon as w } from "@lucide/vue";
10
10
  //#region src/components/cms/LivePreview.vue?vue&type=script&setup=true&lang.ts
11
- var E = { class: "flex min-w-0 flex-1 basis-64 flex-col gap-0.5" }, D = {
11
+ var T = { class: "flex min-w-0 flex-1 basis-64 flex-col gap-0.5" }, E = {
12
12
  key: 0,
13
13
  class: "flex flex-wrap items-center gap-x-2 gap-y-1 text-sm",
14
14
  "data-slot": "cms-editor-status"
15
- }, O = { class: "text-muted-foreground" }, k = {
15
+ }, D = { class: "text-muted-foreground" }, O = {
16
16
  class: "text-muted-foreground flex min-h-4 items-center gap-1.5 text-xs",
17
17
  role: "status",
18
18
  "aria-live": "polite"
19
- }, A = { class: "flex flex-wrap items-center gap-2" }, j = ["aria-label", "data-full-screen"], M = { class: "flex items-center justify-between gap-2 border-b px-3 py-2" }, Se = ["aria-label"], Ce = { class: "sr-only" }, we = { class: "text-muted-foreground hidden truncate text-xs sm:block" }, Te = { class: "flex items-center gap-1" }, Ee = { class: "sr-only" }, De = { class: "sr-only" }, Oe = { class: "bg-muted/40 flex flex-1 justify-center overflow-auto p-3" }, ke = ["src", "title"], N = /*@__PURE__*/ f({
19
+ }, k = { class: "flex flex-wrap items-center gap-2" }, A = ["aria-label", "data-full-screen"], j = { class: "flex items-center justify-between gap-2 border-b px-3 py-2" }, Ce = ["aria-label"], we = { class: "sr-only" }, Te = { class: "text-muted-foreground hidden truncate text-xs sm:block" }, Ee = { class: "flex items-center gap-1" }, De = { class: "sr-only" }, Oe = { class: "sr-only" }, ke = { class: "bg-muted/40 flex flex-1 justify-center overflow-auto p-3" }, Ae = ["src", "title"], M = /*@__PURE__*/ f({
20
20
  __name: "LivePreview",
21
21
  props: { component: {} },
22
22
  setup(f) {
23
- let N = f, P = ee(), F = r(), I = e(), Ae = t(), L = g(null), R = g(!1), z = g(!1), B = g(!1), V = a(() => z.value || B.value), H = g("desktop"), U = ge({
24
- status: N.component.savedAt ? "saved" : "idle",
25
- savedAt: N.component.savedAt ?? null,
26
- previewUrl: N.component.previewUrl,
23
+ let M = f, N = ee(), P = r(), F = e(), je = t(), I = g(null), L = g(!1), R = g(!1), z = g(!1), B = a(() => R.value || z.value), V = g("desktop"), H = ge({
24
+ status: M.component.savedAt ? "saved" : "idle",
25
+ savedAt: M.component.savedAt ?? null,
26
+ previewUrl: M.component.previewUrl,
27
27
  version: 0,
28
- hasChanges: N.component.hasChanges ?? !1
29
- }), W = g("0px"), je = a(() => ({
30
- token: I.value?.token ?? "",
28
+ hasChanges: M.component.hasChanges ?? !1
29
+ }), U = g("0px"), Me = a(() => ({
30
+ token: F.value?.token ?? "",
31
31
  component: "page"
32
- })), G = a(() => U.value.hasChanges && N.component.changedStatus ? N.component.changedStatus : N.component.status), Me = {
32
+ })), W = a(() => H.value.hasChanges && M.component.changedStatus ? M.component.changedStatus : M.component.status), G = a(() => H.value.hasChanges && M.component.changedActions ? M.component.changedActions : M.component.actions), Ne = {
33
33
  gray: "border-border bg-muted text-foreground",
34
34
  success: "border-emerald-600/30 bg-emerald-500/10 text-emerald-700 dark:text-emerald-300",
35
35
  warning: "border-amber-600/30 bg-amber-500/10 text-amber-700 dark:text-amber-300",
36
36
  info: "border-sky-600/30 bg-sky-500/10 text-sky-700 dark:text-sky-300",
37
37
  danger: "border-red-600/30 bg-red-500/10 text-red-700 dark:text-red-300"
38
- }, Ne = Object.keys(i), Pe = {
39
- desktop: S,
40
- tablet: w,
41
- phone: C
42
- }, Fe = {
38
+ }, Pe = Object.keys(i), Fe = {
39
+ desktop: x,
40
+ tablet: C,
41
+ phone: S
42
+ }, Ie = {
43
43
  desktop: "Desktop",
44
44
  tablet: "Tablet",
45
45
  phone: "Phone"
46
- }, K = a(() => i[H.value]), q = a(() => {
47
- switch (U.value.status) {
48
- case "saving": return P("cms.saving", {}, "Saving…");
49
- case "saved": return P("cms.saved", {}, "Draft saved automatically");
50
- case "pending": return P("cms.unsaved", {}, "Unsaved changes");
51
- case "error": return P("cms.save_failed", {}, "Your latest changes couldn't be saved. They will be tried again.");
46
+ }, K = a(() => i[V.value]), q = a(() => {
47
+ switch (H.value.status) {
48
+ case "saving": return N("cms.saving", {}, "Saving…");
49
+ case "saved": return N("cms.saved", {}, "Draft saved automatically");
50
+ case "pending": return N("cms.unsaved", {}, "Unsaved changes");
51
+ case "error": return N("cms.save_failed", {}, "Your latest changes couldn't be saved. They will be tried again.");
52
52
  default: return "";
53
53
  }
54
54
  }), J = null, Y = null, X = () => {};
55
55
  function Z(e) {
56
- e.key === "Escape" && R.value && (z.value && !B.value ? z.value = !1 : Q(!1));
56
+ e.key === "Escape" && L.value && (R.value && !z.value ? R.value = !1 : Q(!1));
57
57
  }
58
58
  function Q(e) {
59
- R.value = e, ce(e ? "open" : "closed");
59
+ L.value = e, ce(e ? "open" : "closed");
60
60
  }
61
61
  function $() {
62
- R.value && (B.value = !oe(L.value));
62
+ L.value && (z.value = !oe(I.value));
63
63
  }
64
64
  return pe(() => {
65
- if (window.addEventListener("keydown", Z), window.addEventListener("resize", $), W.value = ue(null), N.component.previewUrl && se(L.value) && (R.value = !0), !F) return;
65
+ if (window.addEventListener("keydown", Z), window.addEventListener("resize", $), U.value = ue(null), M.component.previewUrl && se(I.value) && (L.value = !0), !P) return;
66
66
  J = new ie({
67
- debounce: N.component.debounce,
68
- previewUrl: N.component.previewUrl,
69
- savedAt: N.component.savedAt,
70
- hasChanges: N.component.hasChanges,
71
- save: (e) => ae(N.component.autosaveMethod, e, {
72
- token: I.value?.token ?? "",
73
- endpoint: Ae.value?.endpoints?.pageCall ?? ""
67
+ debounce: M.component.debounce,
68
+ previewUrl: M.component.previewUrl,
69
+ savedAt: M.component.savedAt,
70
+ hasChanges: M.component.hasChanges,
71
+ save: (e) => ae(M.component.autosaveMethod, e, {
72
+ token: F.value?.token ?? "",
73
+ endpoint: je.value?.endpoints?.pageCall ?? ""
74
74
  }),
75
- onChange: (e) => U.value = e
75
+ onChange: (e) => H.value = e
76
76
  });
77
- let e = F.state.values;
78
- Y = F.subscribe((t) => {
77
+ let e = P.state.values;
78
+ Y = P.subscribe((t) => {
79
79
  t.values !== e && (e = t.values, J?.schedule(t.values));
80
80
  });
81
- }), y(R, $), y([R, V], ([e, t]) => {
82
- X(), X = e && !t ? le(L.value, "min(50vw, 56rem)") : () => {};
81
+ }), y(L, $), y([L, B], ([e, t]) => {
82
+ X(), X = e && !t ? le(I.value, "min(50vw, 56rem)") : () => {};
83
83
  }), fe(() => {
84
84
  window.removeEventListener("keydown", Z), window.removeEventListener("resize", $), Y?.(), X();
85
85
  let e = J;
86
86
  e?.flush().finally(() => e.dispose());
87
87
  }), (e, t) => (h(), c("div", {
88
88
  ref_key: "root",
89
- ref: L,
89
+ ref: I,
90
90
  "data-slot": "cms-live-preview",
91
- style: m({ top: W.value }),
91
+ style: m({ top: U.value }),
92
92
  class: "bg-background sticky z-20 flex flex-wrap items-center gap-x-4 gap-y-2 rounded-xl border px-3 py-2.5 shadow-sm"
93
93
  }, [
94
- l("div", E, [G.value ? (h(), c("p", D, [d(ne, {
94
+ l("div", T, [W.value ? (h(), c("p", E, [d(ne, {
95
95
  variant: "outline",
96
- "data-color": G.value.color,
97
- class: p(Me[G.value.color] ?? "")
96
+ "data-color": W.value.color,
97
+ class: p(Ne[W.value.color] ?? "")
98
98
  }, {
99
- default: b(() => [u(_(G.value.label), 1)]),
99
+ default: b(() => [u(_(W.value.label), 1)]),
100
100
  _: 1
101
- }, 8, ["data-color", "class"]), l("span", O, _(G.value.description), 1)])) : s("", !0), l("p", k, [U.value.status === "saving" ? (h(), o(v(be), {
101
+ }, 8, ["data-color", "class"]), l("span", D, _(W.value.description), 1)])) : s("", !0), l("p", O, [H.value.status === "saving" ? (h(), o(v(be), {
102
102
  key: 0,
103
103
  class: "size-4 animate-spin",
104
104
  "aria-hidden": "true"
105
- })) : U.value.status === "error" ? (h(), o(v(ve), {
105
+ })) : H.value.status === "error" ? (h(), o(v(ve), {
106
106
  key: 1,
107
107
  class: "text-destructive size-4",
108
108
  "aria-hidden": "true"
109
- })) : U.value.status === "saved" ? (h(), o(v(_e), {
109
+ })) : H.value.status === "saved" ? (h(), o(v(_e), {
110
110
  key: 2,
111
111
  class: "size-4",
112
112
  "aria-hidden": "true"
113
113
  })) : s("", !0), u(" " + _(q.value), 1)])]),
114
- l("div", A, [U.value.previewUrl ? (h(), o(n, {
114
+ l("div", k, [H.value.previewUrl ? (h(), o(n, {
115
115
  key: 0,
116
116
  type: "button",
117
- variant: R.value ? "secondary" : "outline",
117
+ variant: L.value ? "secondary" : "outline",
118
118
  size: "sm",
119
- "aria-pressed": R.value,
120
- title: v(P)("cms.live_preview_help", {}, "See the page as visitors will, updated as you type."),
119
+ "aria-pressed": L.value,
120
+ title: v(N)("cms.live_preview_help", {}, "See the page as visitors will, updated as you type."),
121
121
  "data-slot": "cms-live-preview-toggle",
122
- onClick: t[0] ||= (e) => Q(!R.value)
122
+ onClick: t[0] ||= (e) => Q(!L.value)
123
123
  }, {
124
- default: b(() => [d(v(ye), { "aria-hidden": "true" }), u(" " + _(R.value ? v(P)("cms.hide_preview", {}, "Hide preview") : v(P)("cms.live_preview", {}, "Live preview")), 1)]),
124
+ default: b(() => [d(v(ye), { "aria-hidden": "true" }), u(" " + _(L.value ? v(N)("cms.hide_preview", {}, "Hide preview") : v(N)("cms.live_preview", {}, "Live preview")), 1)]),
125
125
  _: 1
126
126
  }, 8, [
127
127
  "variant",
128
128
  "aria-pressed",
129
129
  "title"
130
- ])) : s("", !0), N.component.actions?.length ? (h(), c("div", {
130
+ ])) : s("", !0), G.value?.length ? (h(), c("div", {
131
131
  key: 1,
132
132
  onPointerdownCapture: t[1] ||= (e) => v(J)?.flush()
133
133
  }, [d(re, {
134
- actions: N.component.actions,
135
- context: je.value,
134
+ actions: G.value,
135
+ context: Me.value,
136
136
  size: "sm"
137
137
  }, null, 8, ["actions", "context"])], 32)) : s("", !0)]),
138
- R.value && U.value.previewUrl ? (h(), c("section", {
138
+ L.value && H.value.previewUrl ? (h(), c("section", {
139
139
  key: 0,
140
- "aria-label": v(P)("cms.live_preview", {}, "Live preview"),
140
+ "aria-label": v(N)("cms.live_preview", {}, "Live preview"),
141
141
  "data-slot": "cms-live-preview-pane",
142
- "data-full-screen": V.value || void 0,
143
- style: m({ top: V.value ? "0px" : W.value }),
144
- class: p(v(te)("bg-background fixed end-0 bottom-0 z-50 flex flex-col border-s shadow-xl", V.value ? "inset-x-0 border-s-0" : "w-full lg:w-[min(50vw,56rem)]"))
145
- }, [l("header", M, [
142
+ "data-full-screen": B.value || void 0,
143
+ style: m({ top: B.value ? "0px" : U.value }),
144
+ class: p(v(te)("bg-background fixed end-0 bottom-0 z-50 flex flex-col border-s shadow-xl", B.value ? "inset-x-0 border-s-0" : "w-full lg:w-[min(50vw,56rem)]"))
145
+ }, [l("header", j, [
146
146
  l("div", {
147
147
  class: "flex items-center gap-1",
148
148
  role: "group",
149
- "aria-label": v(P)("cms.preview_width", {}, "Preview width")
150
- }, [(h(!0), c(de, null, me(v(Ne), (e) => (h(), o(n, {
149
+ "aria-label": v(N)("cms.preview_width", {}, "Preview width")
150
+ }, [(h(!0), c(de, null, me(v(Pe), (e) => (h(), o(n, {
151
151
  key: e,
152
152
  type: "button",
153
- variant: H.value === e ? "secondary" : "ghost",
153
+ variant: V.value === e ? "secondary" : "ghost",
154
154
  size: "icon-sm",
155
- "aria-pressed": H.value === e,
156
- onClick: (t) => H.value = e
155
+ "aria-pressed": V.value === e,
156
+ onClick: (t) => V.value = e
157
157
  }, {
158
- default: b(() => [(h(), o(he(Pe[e]), { "aria-hidden": "true" })), l("span", Ce, _(v(P)(`cms.device_${e}`, {}, Fe[e])), 1)]),
158
+ default: b(() => [(h(), o(he(Fe[e]), { "aria-hidden": "true" })), l("span", we, _(v(N)(`cms.device_${e}`, {}, Ie[e])), 1)]),
159
159
  _: 2
160
160
  }, 1032, [
161
161
  "variant",
162
162
  "aria-pressed",
163
163
  "onClick"
164
- ]))), 128))], 8, Se),
165
- l("p", we, _(q.value), 1),
166
- l("div", Te, [B.value ? s("", !0) : (h(), o(n, {
164
+ ]))), 128))], 8, Ce),
165
+ l("p", Te, _(q.value), 1),
166
+ l("div", Ee, [z.value ? s("", !0) : (h(), o(n, {
167
167
  key: 0,
168
168
  type: "button",
169
169
  variant: "ghost",
170
170
  size: "icon-sm",
171
- "aria-pressed": z.value,
172
- onClick: t[2] ||= (e) => z.value = !z.value
171
+ "aria-pressed": R.value,
172
+ onClick: t[2] ||= (e) => R.value = !R.value
173
173
  }, {
174
- default: b(() => [z.value ? (h(), o(v(x), {
174
+ default: b(() => [R.value ? (h(), o(v(Se), {
175
175
  key: 0,
176
176
  "aria-hidden": "true"
177
177
  })) : (h(), o(v(xe), {
178
178
  key: 1,
179
179
  "aria-hidden": "true"
180
- })), l("span", Ee, _(z.value ? v(P)("cms.exit_full_screen", {}, "Exit full screen") : v(P)("cms.full_screen", {}, "Full screen")), 1)]),
180
+ })), l("span", De, _(R.value ? v(N)("cms.exit_full_screen", {}, "Exit full screen") : v(N)("cms.full_screen", {}, "Full screen")), 1)]),
181
181
  _: 1
182
182
  }, 8, ["aria-pressed"])), d(n, {
183
183
  type: "button",
@@ -185,23 +185,23 @@ var E = { class: "flex min-w-0 flex-1 basis-64 flex-col gap-0.5" }, D = {
185
185
  size: "icon-sm",
186
186
  onClick: t[3] ||= (e) => Q(!1)
187
187
  }, {
188
- default: b(() => [d(v(T), { "aria-hidden": "true" }), l("span", De, _(v(P)("cms.close_preview", {}, "Close preview")), 1)]),
188
+ default: b(() => [d(v(w), { "aria-hidden": "true" }), l("span", Oe, _(v(N)("cms.close_preview", {}, "Close preview")), 1)]),
189
189
  _: 1
190
190
  })])
191
- ]), l("div", Oe, [(h(), c("iframe", {
192
- key: U.value.version,
193
- src: U.value.previewUrl,
194
- title: v(P)("cms.preview_frame", {}, "Page preview"),
191
+ ]), l("div", ke, [(h(), c("iframe", {
192
+ key: H.value.version,
193
+ src: H.value.previewUrl,
194
+ title: v(N)("cms.preview_frame", {}, "Page preview"),
195
195
  class: "bg-background h-full rounded-md border shadow-sm",
196
196
  style: m({
197
197
  width: K.value === null ? "100%" : `${K.value}px`,
198
198
  maxWidth: "100%"
199
199
  })
200
- }, null, 12, ke))])], 14, j)) : s("", !0)
200
+ }, null, 12, Ae))])], 14, A)) : s("", !0)
201
201
  ], 4));
202
202
  }
203
203
  });
204
204
  //#endregion
205
- export { N as default };
205
+ export { M as default };
206
206
 
207
207
  //# sourceMappingURL=LivePreview.vue_vue_type_script_setup_true_lang.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"LivePreview.vue_vue_type_script_setup_true_lang.js","names":["_openBlock","_createElementBlock","_normalizeStyle","_createElementVNode","_createVNode","Badge","_normalizeClass","_withCtx","_createTextVNode","_toDisplayString","_createCommentVNode","_createBlock","_unref","Button","ActionList","_Fragment","_renderList","_resolveDynamicComponent","Badge_default","Button_default","ActionList_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","LivePreview_vue_vue_type_script_setup_true_lang_default","props","__props","t","useT","form","useOptionalFormStore","page","usePageSchema","panel","usePanel","root","ref","open","fullScreen","overlay","expanded","computed","device","snapshot","shallowRef","top","actionContext","status","STATUS_COLORS","devices","CMS_PREVIEW_DEVICES","icons","MonitorIcon","TabletIcon","SmartphoneIcon","labels","width","statusLabel","autosave","unsubscribe","release","onKey","event","setOpen","next","rememberedCmsPreview","measure","cmsPreviewFitsBeside","onMounted","resolveStickyOffset","cmsPreviewOpensOnLoad","CmsAutosave","callCmsAutosave","state","values","watch","isOpen","isFull","reserveCmsPreviewSpace","onBeforeUnmount","current","openBlock","createElementBlock","normalizeStyle","createElementVNode","createVNode","normalizeClass","withCtx","createTextVNode","toDisplayString","createCommentVNode","createBlock","unref","LoaderCircleIcon","CircleAlertIcon","CheckIcon","_cache","EyeIcon","cn","Fragment","renderList","name","resolveDynamicComponent","Minimize2Icon","Maximize2Icon","XIcon"],"sources":["../../../src/components/cms/LivePreview.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport {\n CMS_PREVIEW_DEVICES,\n CmsAutosave,\n callCmsAutosave,\n cmsPreviewFitsBeside,\n cmsPreviewOpensOnLoad,\n rememberedCmsPreview,\n resolveStickyOffset,\n reserveCmsPreviewSpace,\n type CmsAutosaveSnapshot,\n type CmsLivePreviewSchema,\n type CmsPreviewDevice,\n} from '@alfakit/core'\nimport {\n CheckIcon,\n CircleAlertIcon,\n EyeIcon,\n LoaderCircleIcon,\n Maximize2Icon,\n Minimize2Icon,\n MonitorIcon,\n SmartphoneIcon,\n TabletIcon,\n XIcon,\n} from '@lucide/vue'\nimport { computed, onBeforeUnmount, onMounted, ref, shallowRef, watch } from 'vue'\nimport { usePageSchema, usePanel, useT } from '../../context'\nimport { cn } from '../../lib/utils'\nimport { useOptionalFormStore } from '../form/form-context'\nimport ActionList from '../actions/ActionList.vue'\nimport Badge from '../ui/Badge.vue'\nimport Button from '../ui/Button.vue'\n\n/**\n * The page editor's autosave status and live preview (schema type `CmsLivePreview`).\n * Changes are autosaved as a draft a moment after typing stops; the preview pane shows\n * the signed preview of that draft beside the form, full screen, or at tablet and phone\n * widths.\n */\nconst props = defineProps<{ component: CmsLivePreviewSchema }>()\n\nconst t = useT()\nconst form = useOptionalFormStore()\nconst page = usePageSchema()\nconst panel = usePanel()\nconst root = ref<HTMLElement | null>(null)\nconst open = ref(false)\nconst fullScreen = ref(false)\n// Too narrow for the form beside the pane (e.g. 1280px with the sidebar): full-screen overlay.\nconst overlay = ref(false)\nconst expanded = computed(() => fullScreen.value || overlay.value)\nconst device = ref<CmsPreviewDevice>('desktop')\nconst snapshot = shallowRef<CmsAutosaveSnapshot>({\n status: props.component.savedAt ? 'saved' : 'idle',\n savedAt: props.component.savedAt ?? null,\n previewUrl: props.component.previewUrl,\n version: 0,\n hasChanges: props.component.hasChanges ?? false,\n})\nconst top = ref('0px')\nconst actionContext = computed(() => ({ token: page.value?.token ?? '', component: 'page' }))\nconst status = computed(() =>\n snapshot.value.hasChanges && props.component.changedStatus\n ? props.component.changedStatus\n : props.component.status,\n)\n/** Badge colours of the status (the server's `PageState` colours). */\nconst STATUS_COLORS: Record<string, string> = {\n gray: 'border-border bg-muted text-foreground',\n success: 'border-emerald-600/30 bg-emerald-500/10 text-emerald-700 dark:text-emerald-300',\n warning: 'border-amber-600/30 bg-amber-500/10 text-amber-700 dark:text-amber-300',\n info: 'border-sky-600/30 bg-sky-500/10 text-sky-700 dark:text-sky-300',\n danger: 'border-red-600/30 bg-red-500/10 text-red-700 dark:text-red-300',\n}\n\nconst devices = Object.keys(CMS_PREVIEW_DEVICES) as CmsPreviewDevice[]\nconst icons = { desktop: MonitorIcon, tablet: TabletIcon, phone: SmartphoneIcon }\nconst labels = { desktop: 'Desktop', tablet: 'Tablet', phone: 'Phone' }\nconst width = computed(() => CMS_PREVIEW_DEVICES[device.value])\n\nconst statusLabel = computed(() => {\n switch (snapshot.value.status) {\n case 'saving':\n return t('cms.saving', {}, 'Saving…')\n case 'saved':\n return t('cms.saved', {}, 'Draft saved automatically')\n case 'pending':\n return t('cms.unsaved', {}, 'Unsaved changes')\n case 'error':\n return t(\n 'cms.save_failed',\n {},\n \"Your latest changes couldn't be saved. They will be tried again.\",\n )\n default:\n return ''\n }\n})\n\nlet autosave: CmsAutosave | null = null\nlet unsubscribe: (() => void) | null = null\nlet release: () => void = () => {}\n\nfunction onKey(event: KeyboardEvent) {\n if (event.key !== 'Escape' || !open.value) return\n if (fullScreen.value && !overlay.value) fullScreen.value = false\n else setOpen(false)\n}\n\n/** Open or collapse the pane, remembering the choice for the next visit. */\nfunction setOpen(next: boolean) {\n open.value = next\n rememberedCmsPreview(next ? 'open' : 'closed')\n}\n\nfunction measure() {\n if (open.value) overlay.value = !cmsPreviewFitsBeside(root.value)\n}\n\nonMounted(() => {\n window.addEventListener('keydown', onKey)\n window.addEventListener('resize', measure)\n // Stick right under the panel's topbar when it sticks too.\n top.value = resolveStickyOffset(null)\n // Wide screens open the pane beside the form; the viewer's last choice wins.\n if (props.component.previewUrl && cmsPreviewOpensOnLoad(root.value)) open.value = true\n\n if (!form) return\n\n autosave = new CmsAutosave({\n debounce: props.component.debounce,\n previewUrl: props.component.previewUrl,\n savedAt: props.component.savedAt,\n hasChanges: props.component.hasChanges,\n save: (state) =>\n callCmsAutosave(props.component.autosaveMethod, state, {\n token: page.value?.token ?? '',\n endpoint: panel.value?.endpoints?.pageCall ?? '',\n }),\n onChange: (next) => (snapshot.value = next),\n })\n\n let values = form.state.values\n unsubscribe = form.subscribe((state) => {\n if (state.values !== values) {\n values = state.values\n autosave?.schedule(state.values)\n }\n })\n})\n\n// Side by side, the form makes room for the pane.\nwatch(open, measure)\nwatch([open, expanded], ([isOpen, isFull]) => {\n release()\n release = isOpen && !isFull ? reserveCmsPreviewSpace(root.value, 'min(50vw, 56rem)') : () => {}\n})\n\nonBeforeUnmount(() => {\n window.removeEventListener('keydown', onKey)\n window.removeEventListener('resize', measure)\n unsubscribe?.()\n release()\n const current = autosave\n void current?.flush().finally(() => current.dispose())\n})\n</script>\n\n<template>\n <div\n ref=\"root\"\n data-slot=\"cms-live-preview\"\n :style=\"{ top }\"\n class=\"bg-background sticky z-20 flex flex-wrap items-center gap-x-4 gap-y-2 rounded-xl border px-3 py-2.5 shadow-sm\"\n >\n <div class=\"flex min-w-0 flex-1 basis-64 flex-col gap-0.5\">\n <p\n v-if=\"status\"\n class=\"flex flex-wrap items-center gap-x-2 gap-y-1 text-sm\"\n data-slot=\"cms-editor-status\"\n >\n <Badge\n variant=\"outline\"\n :data-color=\"status.color\"\n :class=\"STATUS_COLORS[status.color] ?? ''\"\n >{{ status.label }}</Badge\n >\n <span class=\"text-muted-foreground\">{{ status.description }}</span>\n </p>\n <p\n class=\"text-muted-foreground flex min-h-4 items-center gap-1.5 text-xs\"\n role=\"status\"\n aria-live=\"polite\"\n >\n <LoaderCircleIcon\n v-if=\"snapshot.status === 'saving'\"\n class=\"size-4 animate-spin\"\n aria-hidden=\"true\"\n />\n <CircleAlertIcon\n v-else-if=\"snapshot.status === 'error'\"\n class=\"text-destructive size-4\"\n aria-hidden=\"true\"\n />\n <CheckIcon v-else-if=\"snapshot.status === 'saved'\" class=\"size-4\" aria-hidden=\"true\" />\n {{ statusLabel }}\n </p>\n </div>\n <div class=\"flex flex-wrap items-center gap-2\">\n <Button\n v-if=\"snapshot.previewUrl\"\n type=\"button\"\n :variant=\"open ? 'secondary' : 'outline'\"\n size=\"sm\"\n :aria-pressed=\"open\"\n :title=\"\n t('cms.live_preview_help', {}, 'See the page as visitors will, updated as you type.')\n \"\n data-slot=\"cms-live-preview-toggle\"\n @click=\"setOpen(!open)\"\n >\n <EyeIcon aria-hidden=\"true\" />\n {{\n open\n ? t('cms.hide_preview', {}, 'Hide preview')\n : t('cms.live_preview', {}, 'Live preview')\n }}\n </Button>\n <div v-if=\"props.component.actions?.length\" @pointerdown.capture=\"autosave?.flush()\">\n <ActionList :actions=\"props.component.actions\" :context=\"actionContext\" size=\"sm\" />\n </div>\n </div>\n <section\n v-if=\"open && snapshot.previewUrl\"\n :aria-label=\"t('cms.live_preview', {}, 'Live preview')\"\n data-slot=\"cms-live-preview-pane\"\n :data-full-screen=\"expanded || undefined\"\n :style=\"{ top: expanded ? '0px' : top }\"\n :class=\"\n cn(\n 'bg-background fixed end-0 bottom-0 z-50 flex flex-col border-s shadow-xl',\n expanded ? 'inset-x-0 border-s-0' : 'w-full lg:w-[min(50vw,56rem)]',\n )\n \"\n >\n <header class=\"flex items-center justify-between gap-2 border-b px-3 py-2\">\n <div\n class=\"flex items-center gap-1\"\n role=\"group\"\n :aria-label=\"t('cms.preview_width', {}, 'Preview width')\"\n >\n <Button\n v-for=\"name in devices\"\n :key=\"name\"\n type=\"button\"\n :variant=\"device === name ? 'secondary' : 'ghost'\"\n size=\"icon-sm\"\n :aria-pressed=\"device === name\"\n @click=\"device = name\"\n >\n <component :is=\"icons[name]\" aria-hidden=\"true\" />\n <span class=\"sr-only\">{{ t(`cms.device_${name}`, {}, labels[name]) }}</span>\n </Button>\n </div>\n <p class=\"text-muted-foreground hidden truncate text-xs sm:block\">{{ statusLabel }}</p>\n <div class=\"flex items-center gap-1\">\n <Button\n v-if=\"!overlay\"\n type=\"button\"\n variant=\"ghost\"\n size=\"icon-sm\"\n :aria-pressed=\"fullScreen\"\n @click=\"fullScreen = !fullScreen\"\n >\n <Minimize2Icon v-if=\"fullScreen\" aria-hidden=\"true\" />\n <Maximize2Icon v-else aria-hidden=\"true\" />\n <span class=\"sr-only\">{{\n fullScreen\n ? t('cms.exit_full_screen', {}, 'Exit full screen')\n : t('cms.full_screen', {}, 'Full screen')\n }}</span>\n </Button>\n <Button type=\"button\" variant=\"ghost\" size=\"icon-sm\" @click=\"setOpen(false)\">\n <XIcon aria-hidden=\"true\" />\n <span class=\"sr-only\">{{ t('cms.close_preview', {}, 'Close preview') }}</span>\n </Button>\n </div>\n </header>\n <div class=\"bg-muted/40 flex flex-1 justify-center overflow-auto p-3\">\n <iframe\n :key=\"snapshot.version\"\n :src=\"snapshot.previewUrl\"\n :title=\"t('cms.preview_frame', {}, 'Page preview')\"\n class=\"bg-background h-full rounded-md border shadow-sm\"\n :style=\"{ width: width === null ? '100%' : `${width}px`, maxWidth: '100%' }\"\n />\n </div>\n </section>\n </div>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;EAwCA,IAAMqC,IAAQC,GAERC,IAAIC,GAAK,GACTC,IAAOC,EAAqB,GAC5BC,IAAOC,EAAc,GACrBC,KAAQC,EAAS,GACjBC,IAAOC,EAAwB,IAAI,GACnCC,IAAOD,EAAI,EAAK,GAChBE,IAAaF,EAAI,EAAK,GAEtBG,IAAUH,EAAI,EAAK,GACnBI,IAAWC,QAAeH,EAAW,SAASC,EAAQ,KAAK,GAC3DG,IAASN,EAAsB,SAAS,GACxCO,IAAWC,GAAgC;GAC/C,QAAQnB,EAAM,UAAU,UAAU,UAAU;GAC5C,SAASA,EAAM,UAAU,WAAW;GACpC,YAAYA,EAAM,UAAU;GAC5B,SAAS;GACT,YAAYA,EAAM,UAAU,cAAc;EAC5C,CAAC,GACKoB,IAAMT,EAAI,KAAK,GACfU,KAAgBL,SAAgB;GAAE,OAAOV,EAAK,OAAO,SAAS;GAAI,WAAW;EAAO,EAAE,GACtFgB,IAASN,QACbE,EAAS,MAAM,cAAclB,EAAM,UAAU,gBACzCA,EAAM,UAAU,gBAChBA,EAAM,UAAU,MACtB,GAEMuB,KAAwC;GAC5C,MAAM;GACN,SAAS;GACT,SAAS;GACT,MAAM;GACN,QAAQ;EACV,GAEMC,KAAU,OAAO,KAAKC,CAAmB,GACzCC,KAAQ;GAAE,SAASC;GAAa,QAAQC;GAAY,OAAOC;EAAe,GAC1EC,KAAS;GAAE,SAAS;GAAW,QAAQ;GAAU,OAAO;EAAQ,GAChEC,IAAQf,QAAeS,EAAoBR,EAAO,MAAM,GAExDe,IAAchB,QAAe;GACjC,QAAQE,EAAS,MAAM,QAAvB;IACE,KAAK,UACH,OAAOhB,EAAE,cAAc,CAAC,GAAG,SAAS;IACtC,KAAK,SACH,OAAOA,EAAE,aAAa,CAAC,GAAG,2BAA2B;IACvD,KAAK,WACH,OAAOA,EAAE,eAAe,CAAC,GAAG,iBAAiB;IAC/C,KAAK,SACH,OAAOA,EACL,mBACA,CAAC,GACD,kEACF;IACF,SACE,OAAO;GACX;EACF,CAAC,GAEG+B,IAA+B,MAC/BC,IAAmC,MACnCC,UAA4B,CAAC;EAEjC,SAASC,EAAM,GAAsB;GACnC,AAAIC,EAAM,QAAQ,YAAazB,EAAK,UAChCC,EAAW,SAAS,CAACC,EAAQ,QAAO,EAAW,QAAQ,KACtDwB,EAAQ,EAAK;EACpB;EAGA,SAASA,EAAQ,GAAe;GAE9B,AADA,EAAK,QAAQC,GACbC,GAAqBD,IAAO,SAAS,QAAQ;EAC/C;EAEA,SAASE,IAAU;GACjB,AAAI7B,EAAK,UAAO,EAAQ,QAAQ,CAAC8B,GAAqBhC,EAAK,KAAK;EAClE;SAEAiC,SAAgB;GAQd,IAPA,OAAO,iBAAiB,WAAWP,CAAK,GACxC,OAAO,iBAAiB,UAAUK,CAAO,GAEzC,EAAI,QAAQG,GAAoB,IAAI,GAEhC5C,EAAM,UAAU,cAAc6C,GAAsBnC,EAAK,KAAK,MAAG,EAAK,QAAQ,KAE9E,CAACN,GAAM;GAEX,IAAW,IAAI0C,GAAY;IACzB,UAAU9C,EAAM,UAAU;IAC1B,YAAYA,EAAM,UAAU;IAC5B,SAASA,EAAM,UAAU;IACzB,YAAYA,EAAM,UAAU;IAC5B,OAAO,MACL+C,GAAgB/C,EAAM,UAAU,gBAAgBgD,GAAO;KACrD,OAAO1C,EAAK,OAAO,SAAS;KAC5B,UAAUE,GAAM,OAAO,WAAW,YAAY;IAChD,CAAC;IACH,WAAW,MAAU,EAAS,QAAQ+B;GACxC,CAAC;GAED,IAAIU,IAAS7C,EAAK,MAAM;GACxB,IAAcA,EAAK,WAAW,MAAU;IACtC,AAAI4C,EAAM,WAAWC,MACnB,IAASD,EAAM,QACff,GAAU,SAASe,EAAM,MAAM;GAEnC,CAAC;EACH,CAAC,GAGDE,EAAMtC,GAAM6B,CAAO,GACnBS,EAAM,CAACtC,GAAMG,CAAQ,IAAI,CAACoC,GAAQC,OAAY;GAE5C,AADAjB,EAAQ,GACR,IAAUgB,KAAU,CAACC,IAASC,GAAuB3C,EAAK,OAAO,kBAAkB,UAAU,CAAC;EAChG,CAAC,GAED4C,SAAsB;GAIpB,AAHA,OAAO,oBAAoB,WAAWlB,CAAK,GAC3C,OAAO,oBAAoB,UAAUK,CAAO,GAC5CP,IAAc,GACdC,EAAQ;GACR,IAAMoB,IAAUtB;GAChB,GAAc,MAAM,CAAC,CAAC,cAAcsB,EAAQ,QAAQ,CAAC;EACvD,CAAC,cAIC5F,EAAA,GAAAC,EAiIM,OAAA;GAhIA,SAAA;GAAJ,KAAI8C;GACJ,aAAU;GACT,OAAK7C,EAAA,EAAA,KAAIuD,EAAA,MAAG,CAAA;GACb,OAAM;;GAENtD,EAgCM,OAhCNkB,GAgCM,CA9BIsC,EAAA,SADR3D,EAAA,GAAAC,EAYI,KAZJqB,GAYI,CAPFlB,EAKCC,IAAA;IAJC,SAAQ;IACP,cAAYsD,EAAA,MAAO;IACnB,OAAKrD,EAAEsD,GAAcD,EAAA,MAAO,UAAK,EAAA;;IACjC,SAAApD,QAAkB,CAAfC,EAAAC,EAAAkD,EAAA,MAAO,KAAK,GAAA,CAAA,CAAA,CAAA;;GAElBxD,GAAAA,GAAAA,CAAAA,cAAAA,OAAAA,CAAAA,GAAAA,EAAmE,QAAnEoB,GAAmEd,EAA5BkD,EAAA,MAAO,WAAW,GAAA,CAAA,CAAA,CAAA,KAAA2C,EAAA,IAAA,EAAA,GAE3DnG,EAiBI,KAjBJqB,GAiBI,CAXM+B,EAAA,MAAS,WAAM,YADvBvD,EAAA,GAAAW,EAIEC,EAAA6F,EAAA,GAAA;;IAFA,OAAM;IACN,eAAY;GAGD,CAAA,KAAAlD,EAAA,MAAS,WAAM,WAD5BvD,EAAA,GAAAW,EAIEC,EAAA8F,EAAA,GAAA;;IAFA,OAAM;IACN,eAAY;GAEQ,CAAA,KAAAnD,EAAA,MAAS,WAAM,WAArCvD,EAAA,GAAAW,EAAuFC,EAAA+F,EAAA,GAAA;;IAApC,OAAM;IAAS,eAAY;GAASnG,CAAAA,KAAAA,EAAAA,IAAAA,EAAAA,GAAAA,EAAA,MACvFC,EAAG4D,EAAA,KAAW,GAAA,CAAA,CAAA,CAAA,CAAA,CAAA;GAGlBlE,EAuBM,OAvBNsB,GAuBM,CArBI8B,EAAA,MAAS,cADjBvD,EAAA,GAAAW,EAkBSE,GAAA;;IAhBP,MAAK;IACJ,SAASoC,EAAA,QAAI,cAAA;IACd,MAAK;IACJ,gBAAcA,EAAA;IACd,OAAkBrC,EAAA2B,CAAA,CAAC,CAAA,yBAAA,CAAA,GAAA,qDAAA;IAGpB,aAAU;IACT,SAAK,AAAAqE,EAAA,QAAA,MAAEjC,EAAO,CAAE1B,EAAA,KAAI;;IAErB,SAAA1C,QAA8B,CAA9BH,EAA8BQ,EAAAiG,EAAA,GAAA,EAArB,eAAY,OAAM,CAAA,GAAGrG,EAAA,MAC9BC,EACEwC,EAAA,QAAmBrC,EAAA2B,CAAA,CAAC,CAAA,oBAAA,CAAA,GAAA,cAAA,IAAuD3B,EAAA2B,CAAA,CAAC,CAAA,oBAAA,CAAA,GAAA,cAAA,CAAA,GAAA,CAAA,CAAA,CAAA;;;;;;GAKrE,CAAA,KAAA+D,EAAA,IAAA,EAAA,GAAAjE,EAAM,UAAU,SAAS,UAApCrC,EAAA,GAAAC,EAEM,OAAA;;IAF4D,sBAAA,AAAA2G,EAAA,QAAA,MAAAhG,EAAA0D,CAAA,CAAQ,EAAE,MAAK;GAC/ElE,GAAAA,CAAAA,EAAoFU,IAAA;IAAvE,SAASuB,EAAM,UAAU;IAAU,SAASqB,GAAA;IAAe,MAAK;;GAIzET,EAAA,SAAQM,EAAA,MAAS,cADzBvD,EAAA,GAAAC,EAiEU,WAAA;;IA/DP,cAAYW,EAAA2B,CAAA,CAAC,CAAA,oBAAA,CAAA,GAAA,cAAA;IACd,aAAU;IACT,oBAAkBa,EAAA,SAAY,KAAA;IAC9B,OAAKlD,EAAA,EAAA,KAASkD,EAAA,QAAQ,QAAWK,EAAA,MAAG,CAAA;IACpC,OAAKnD,EAAWM,EAAAkG,EAAA,CAAE,CAAA,4EAAkG1D,EAAA,QAAQ,yBAAA,+BAAA,CAAA;GAO7HjD,GAAAA,CAAAA,EA0CS,UA1CTwB,GA0CS;IAzCPxB,EAiBM,OAAA;KAhBJ,OAAM;KACN,MAAK;KACJ,cAAYS,EAAA2B,CAAA,CAAC,CAAA,qBAAA,CAAA,GAAA,eAAA;IAEdvC,GAAAA,EAAAA,EAAA,EAAA,GAAAC,EAWSc,IAAA,MAAAC,GAVQJ,EAAAiD,EAAA,IAAR,OADT7D,EAAA,GAAAW,EAWSE,GAAA;KATN,KAAKoG;KACN,MAAK;KACJ,SAAS3D,EAAA,UAAW2D,IAAI,cAAA;KACzB,MAAK;KACJ,gBAAc3D,EAAA,UAAW2D;KACzB,UAAK,MAAE,EAAA,QAASA;;KAEjB,SAAA1G,QAAkD,EAAlDP,EAAA,GAAAW,EAAkDM,GAAlC8C,GAAMkD,EAAI,GAAA,EAAG,eAAY,OAAM,CAAA,IAC/C9G,EAA4E,QAA5E0B,IAA4EpB,EAAnDG,EAAA2B,CAAA,CAAC,CAAA,cAAe0E,KAAI,CAAA,GAAQ9C,GAAO8C,EAAI,CAAA,GAAA,CAAA,CAAA,CAAA;;;;;;;IAGpE9G,EAAuF,KAAvF2B,IAAuFrB,EAAlB4D,EAAA,KAAW,GAAA,CAAA;IAChFlE,EAqBM,OArBN4B,IAqBM,CAnBKoB,EAAA,QAeT/C,EAAAA,IAAAA,EAAAA,KAhBAJ,EAAA,GAAAW,EAeSE,GAAA;;KAbP,MAAK;KACL,SAAQ;KACR,MAAK;KACJ,gBAAcqC,EAAA;KACd,SAAK,AAAA0D,EAAA,QAAA,MAAE,EAAA,QAAU,CAAI1D,EAAA;;KAEtB,SAAA3C,QAAsD,CAAjC2C,EAAA,SAArBlD,EAAA,GAAAW,EAAsDC,EAAAuG,CAAA,GAAA;;MAArB,eAAY;KAC7CnH,CAAAA,MAAAA,EAAA,GAAAW,EAA2CC,EAAAwG,EAAA,GAAA;;MAArB,eAAY;KAClCjH,CAAAA,IAAAA,EAIS,QAJT6B,IAISvB,EAHPyC,EAAA,QAA6BtC,EAAA2B,CAAA,CAAC,CAAA,wBAAA,CAAA,GAAA,kBAAA,IAAmE3B,EAAA2B,CAAA,CAAC,CAAA,mBAAA,CAAA,GAAA,aAAA,CAAA,GAAA,CAAA,CAAA,CAAA;;IAKtGnC,GAAAA,GAAAA,CAAAA,cAAAA,CAAAA,IAAAA,EAGSS,GAAA;KAHD,MAAK;KAAS,SAAQ;KAAQ,MAAK;KAAW,SAAK,AAAA+F,EAAA,QAAA,MAAEjC,EAAO,EAAA;;KAClE,SAAApE,QAA4B,CAA5BH,EAA4BQ,EAAAyG,CAAA,GAAA,EAArB,eAAY,OAAM,CAAA,GACzBlH,EAA8E,QAA9E8B,IAA8ExB,EAArDG,EAAA2B,CAAA,CAAC,CAAA,qBAAA,CAAA,GAAA,eAAA,CAAA,GAAA,CAAA,CAAA,CAAA;;;GAIhCpC,CAAAA,GAAAA,EAQM,OARN+B,IAQM,EAPJlC,EAAA,GAAAC,EAME,UAAA;IALC,KAAKsD,EAAA,MAAS;IACd,KAAKA,EAAA,MAAS;IACd,OAAO3C,EAAA2B,CAAA,CAAC,CAAA,qBAAA,CAAA,GAAA,cAAA;IACT,OAAM;IACL,OAAKrC,EAAA;KAAA,OAAWkE,EAAA,UAAK,OAAA,SAAA,GAAwBA,EAAA,MAAK;KAAA,UAAA;IAAA,CAAA"}
1
+ {"version":3,"file":"LivePreview.vue_vue_type_script_setup_true_lang.js","names":["_openBlock","_createElementBlock","_normalizeStyle","_createElementVNode","_createVNode","Badge","_normalizeClass","_withCtx","_createTextVNode","_toDisplayString","_createCommentVNode","_createBlock","_unref","Button","ActionList","_Fragment","_renderList","_resolveDynamicComponent","Badge_default","Button_default","ActionList_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","LivePreview_vue_vue_type_script_setup_true_lang_default","props","__props","t","useT","form","useOptionalFormStore","page","usePageSchema","panel","usePanel","root","ref","open","fullScreen","overlay","expanded","computed","device","snapshot","shallowRef","top","actionContext","status","actions","STATUS_COLORS","devices","CMS_PREVIEW_DEVICES","icons","MonitorIcon","TabletIcon","SmartphoneIcon","labels","width","statusLabel","autosave","unsubscribe","release","onKey","event","setOpen","next","rememberedCmsPreview","measure","cmsPreviewFitsBeside","onMounted","resolveStickyOffset","cmsPreviewOpensOnLoad","CmsAutosave","callCmsAutosave","state","values","watch","isOpen","isFull","reserveCmsPreviewSpace","onBeforeUnmount","current","openBlock","createElementBlock","normalizeStyle","createElementVNode","createVNode","normalizeClass","withCtx","createTextVNode","toDisplayString","createCommentVNode","createBlock","unref","LoaderCircleIcon","CircleAlertIcon","CheckIcon","_cache","EyeIcon","cn","Fragment","renderList","name","resolveDynamicComponent","Minimize2Icon","Maximize2Icon","XIcon"],"sources":["../../../src/components/cms/LivePreview.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport {\n CMS_PREVIEW_DEVICES,\n CmsAutosave,\n callCmsAutosave,\n cmsPreviewFitsBeside,\n cmsPreviewOpensOnLoad,\n rememberedCmsPreview,\n resolveStickyOffset,\n reserveCmsPreviewSpace,\n type CmsAutosaveSnapshot,\n type CmsLivePreviewSchema,\n type CmsPreviewDevice,\n} from '@alfakit/core'\nimport {\n CheckIcon,\n CircleAlertIcon,\n EyeIcon,\n LoaderCircleIcon,\n Maximize2Icon,\n Minimize2Icon,\n MonitorIcon,\n SmartphoneIcon,\n TabletIcon,\n XIcon,\n} from '@lucide/vue'\nimport { computed, onBeforeUnmount, onMounted, ref, shallowRef, watch } from 'vue'\nimport { usePageSchema, usePanel, useT } from '../../context'\nimport { cn } from '../../lib/utils'\nimport { useOptionalFormStore } from '../form/form-context'\nimport ActionList from '../actions/ActionList.vue'\nimport Badge from '../ui/Badge.vue'\nimport Button from '../ui/Button.vue'\n\n/**\n * The page editor's autosave status and live preview (schema type `CmsLivePreview`).\n * Changes are autosaved as a draft a moment after typing stops; the preview pane shows\n * the signed preview of that draft beside the form, full screen, or at tablet and phone\n * widths.\n */\nconst props = defineProps<{ component: CmsLivePreviewSchema }>()\n\nconst t = useT()\nconst form = useOptionalFormStore()\nconst page = usePageSchema()\nconst panel = usePanel()\nconst root = ref<HTMLElement | null>(null)\nconst open = ref(false)\nconst fullScreen = ref(false)\n// Too narrow for the form beside the pane (e.g. 1280px with the sidebar): full-screen overlay.\nconst overlay = ref(false)\nconst expanded = computed(() => fullScreen.value || overlay.value)\nconst device = ref<CmsPreviewDevice>('desktop')\nconst snapshot = shallowRef<CmsAutosaveSnapshot>({\n status: props.component.savedAt ? 'saved' : 'idle',\n savedAt: props.component.savedAt ?? null,\n previewUrl: props.component.previewUrl,\n version: 0,\n hasChanges: props.component.hasChanges ?? false,\n})\nconst top = ref('0px')\nconst actionContext = computed(() => ({ token: page.value?.token ?? '', component: 'page' }))\nconst status = computed(() =>\n snapshot.value.hasChanges && props.component.changedStatus\n ? props.component.changedStatus\n : props.component.status,\n)\n// \"Publish changes\" appears as soon as an autosave makes the draft differ.\nconst actions = computed(() =>\n snapshot.value.hasChanges && props.component.changedActions\n ? props.component.changedActions\n : props.component.actions,\n)\n/** Badge colours of the status (the server's `PageState` colours). */\nconst STATUS_COLORS: Record<string, string> = {\n gray: 'border-border bg-muted text-foreground',\n success: 'border-emerald-600/30 bg-emerald-500/10 text-emerald-700 dark:text-emerald-300',\n warning: 'border-amber-600/30 bg-amber-500/10 text-amber-700 dark:text-amber-300',\n info: 'border-sky-600/30 bg-sky-500/10 text-sky-700 dark:text-sky-300',\n danger: 'border-red-600/30 bg-red-500/10 text-red-700 dark:text-red-300',\n}\n\nconst devices = Object.keys(CMS_PREVIEW_DEVICES) as CmsPreviewDevice[]\nconst icons = { desktop: MonitorIcon, tablet: TabletIcon, phone: SmartphoneIcon }\nconst labels = { desktop: 'Desktop', tablet: 'Tablet', phone: 'Phone' }\nconst width = computed(() => CMS_PREVIEW_DEVICES[device.value])\n\nconst statusLabel = computed(() => {\n switch (snapshot.value.status) {\n case 'saving':\n return t('cms.saving', {}, 'Saving…')\n case 'saved':\n return t('cms.saved', {}, 'Draft saved automatically')\n case 'pending':\n return t('cms.unsaved', {}, 'Unsaved changes')\n case 'error':\n return t(\n 'cms.save_failed',\n {},\n \"Your latest changes couldn't be saved. They will be tried again.\",\n )\n default:\n return ''\n }\n})\n\nlet autosave: CmsAutosave | null = null\nlet unsubscribe: (() => void) | null = null\nlet release: () => void = () => {}\n\nfunction onKey(event: KeyboardEvent) {\n if (event.key !== 'Escape' || !open.value) return\n if (fullScreen.value && !overlay.value) fullScreen.value = false\n else setOpen(false)\n}\n\n/** Open or collapse the pane, remembering the choice for the next visit. */\nfunction setOpen(next: boolean) {\n open.value = next\n rememberedCmsPreview(next ? 'open' : 'closed')\n}\n\nfunction measure() {\n if (open.value) overlay.value = !cmsPreviewFitsBeside(root.value)\n}\n\nonMounted(() => {\n window.addEventListener('keydown', onKey)\n window.addEventListener('resize', measure)\n // Stick right under the panel's topbar when it sticks too.\n top.value = resolveStickyOffset(null)\n // Wide screens open the pane beside the form; the viewer's last choice wins.\n if (props.component.previewUrl && cmsPreviewOpensOnLoad(root.value)) open.value = true\n\n if (!form) return\n\n autosave = new CmsAutosave({\n debounce: props.component.debounce,\n previewUrl: props.component.previewUrl,\n savedAt: props.component.savedAt,\n hasChanges: props.component.hasChanges,\n save: (state) =>\n callCmsAutosave(props.component.autosaveMethod, state, {\n token: page.value?.token ?? '',\n endpoint: panel.value?.endpoints?.pageCall ?? '',\n }),\n onChange: (next) => (snapshot.value = next),\n })\n\n let values = form.state.values\n unsubscribe = form.subscribe((state) => {\n if (state.values !== values) {\n values = state.values\n autosave?.schedule(state.values)\n }\n })\n})\n\n// Side by side, the form makes room for the pane.\nwatch(open, measure)\nwatch([open, expanded], ([isOpen, isFull]) => {\n release()\n release = isOpen && !isFull ? reserveCmsPreviewSpace(root.value, 'min(50vw, 56rem)') : () => {}\n})\n\nonBeforeUnmount(() => {\n window.removeEventListener('keydown', onKey)\n window.removeEventListener('resize', measure)\n unsubscribe?.()\n release()\n const current = autosave\n void current?.flush().finally(() => current.dispose())\n})\n</script>\n\n<template>\n <div\n ref=\"root\"\n data-slot=\"cms-live-preview\"\n :style=\"{ top }\"\n class=\"bg-background sticky z-20 flex flex-wrap items-center gap-x-4 gap-y-2 rounded-xl border px-3 py-2.5 shadow-sm\"\n >\n <div class=\"flex min-w-0 flex-1 basis-64 flex-col gap-0.5\">\n <p\n v-if=\"status\"\n class=\"flex flex-wrap items-center gap-x-2 gap-y-1 text-sm\"\n data-slot=\"cms-editor-status\"\n >\n <Badge\n variant=\"outline\"\n :data-color=\"status.color\"\n :class=\"STATUS_COLORS[status.color] ?? ''\"\n >{{ status.label }}</Badge\n >\n <span class=\"text-muted-foreground\">{{ status.description }}</span>\n </p>\n <p\n class=\"text-muted-foreground flex min-h-4 items-center gap-1.5 text-xs\"\n role=\"status\"\n aria-live=\"polite\"\n >\n <LoaderCircleIcon\n v-if=\"snapshot.status === 'saving'\"\n class=\"size-4 animate-spin\"\n aria-hidden=\"true\"\n />\n <CircleAlertIcon\n v-else-if=\"snapshot.status === 'error'\"\n class=\"text-destructive size-4\"\n aria-hidden=\"true\"\n />\n <CheckIcon v-else-if=\"snapshot.status === 'saved'\" class=\"size-4\" aria-hidden=\"true\" />\n {{ statusLabel }}\n </p>\n </div>\n <div class=\"flex flex-wrap items-center gap-2\">\n <Button\n v-if=\"snapshot.previewUrl\"\n type=\"button\"\n :variant=\"open ? 'secondary' : 'outline'\"\n size=\"sm\"\n :aria-pressed=\"open\"\n :title=\"\n t('cms.live_preview_help', {}, 'See the page as visitors will, updated as you type.')\n \"\n data-slot=\"cms-live-preview-toggle\"\n @click=\"setOpen(!open)\"\n >\n <EyeIcon aria-hidden=\"true\" />\n {{\n open\n ? t('cms.hide_preview', {}, 'Hide preview')\n : t('cms.live_preview', {}, 'Live preview')\n }}\n </Button>\n <div v-if=\"actions?.length\" @pointerdown.capture=\"autosave?.flush()\">\n <ActionList :actions=\"actions\" :context=\"actionContext\" size=\"sm\" />\n </div>\n </div>\n <section\n v-if=\"open && snapshot.previewUrl\"\n :aria-label=\"t('cms.live_preview', {}, 'Live preview')\"\n data-slot=\"cms-live-preview-pane\"\n :data-full-screen=\"expanded || undefined\"\n :style=\"{ top: expanded ? '0px' : top }\"\n :class=\"\n cn(\n 'bg-background fixed end-0 bottom-0 z-50 flex flex-col border-s shadow-xl',\n expanded ? 'inset-x-0 border-s-0' : 'w-full lg:w-[min(50vw,56rem)]',\n )\n \"\n >\n <header class=\"flex items-center justify-between gap-2 border-b px-3 py-2\">\n <div\n class=\"flex items-center gap-1\"\n role=\"group\"\n :aria-label=\"t('cms.preview_width', {}, 'Preview width')\"\n >\n <Button\n v-for=\"name in devices\"\n :key=\"name\"\n type=\"button\"\n :variant=\"device === name ? 'secondary' : 'ghost'\"\n size=\"icon-sm\"\n :aria-pressed=\"device === name\"\n @click=\"device = name\"\n >\n <component :is=\"icons[name]\" aria-hidden=\"true\" />\n <span class=\"sr-only\">{{ t(`cms.device_${name}`, {}, labels[name]) }}</span>\n </Button>\n </div>\n <p class=\"text-muted-foreground hidden truncate text-xs sm:block\">{{ statusLabel }}</p>\n <div class=\"flex items-center gap-1\">\n <Button\n v-if=\"!overlay\"\n type=\"button\"\n variant=\"ghost\"\n size=\"icon-sm\"\n :aria-pressed=\"fullScreen\"\n @click=\"fullScreen = !fullScreen\"\n >\n <Minimize2Icon v-if=\"fullScreen\" aria-hidden=\"true\" />\n <Maximize2Icon v-else aria-hidden=\"true\" />\n <span class=\"sr-only\">{{\n fullScreen\n ? t('cms.exit_full_screen', {}, 'Exit full screen')\n : t('cms.full_screen', {}, 'Full screen')\n }}</span>\n </Button>\n <Button type=\"button\" variant=\"ghost\" size=\"icon-sm\" @click=\"setOpen(false)\">\n <XIcon aria-hidden=\"true\" />\n <span class=\"sr-only\">{{ t('cms.close_preview', {}, 'Close preview') }}</span>\n </Button>\n </div>\n </header>\n <div class=\"bg-muted/40 flex flex-1 justify-center overflow-auto p-3\">\n <iframe\n :key=\"snapshot.version\"\n :src=\"snapshot.previewUrl\"\n :title=\"t('cms.preview_frame', {}, 'Page preview')\"\n class=\"bg-background h-full rounded-md border shadow-sm\"\n :style=\"{ width: width === null ? '100%' : `${width}px`, maxWidth: '100%' }\"\n />\n </div>\n </section>\n </div>\n</template>\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"BuilderField.js","names":["_sfc_main","BuilderField_vue_vue_type_script_setup_true_lang_default","BuilderField_default"],"sources":["../../../src/components/fields/BuilderField.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { BuilderBlockSchema, BuilderItemState, BuilderSchema } from '@alfakit/core'\nimport {\n isDeferredPlaceholder,\n VIRTUAL_ESTIMATES,\n builderItemLabel,\n builderItems,\n builderItemSchema,\n canAddBuilderBlock,\n cloneIndexedState,\n cloneRepeaterItem,\n fieldIds,\n insertBuilderItem,\n itemActionContext,\n moveIndexedState,\n moveRepeaterItem,\n removeIndexedState,\n removeRepeaterItem,\n reorderedItemKeys,\n resolveItemAction,\n virtualizeOptions,\n type ActionSchema,\n type ItemActionName,\n} from '@alfakit/core'\nimport { PencilIcon } from '@lucide/vue'\nimport { computed, ref } from 'vue'\nimport { useScrollToErroredItem, useVirtualList } from '../../composables/use-virtual-list'\nimport { useActionRunner, useFormatter, useOptionalRegistry, useT } from '../../context'\nimport { Icon } from '../../lib/icons'\nimport { cn } from '../../lib/utils'\nimport DeferredSchema from '../layout/DeferredSchema.vue'\nimport { useField, useOptionalFormStore } from '../form/form-context'\nimport { useFieldActionContext } from '../schema/field-actions'\nimport FieldWrapper from '../schema/FieldWrapper.vue'\nimport SchemaRenderer from '../schema/SchemaRenderer.vue'\nimport Button from '../ui/Button.vue'\nimport Collapsible from '../ui/Collapsible.vue'\nimport CollapsibleContent from '../ui/CollapsibleContent.vue'\nimport AddActionRow from './AddActionRow.vue'\nimport CollapseAllActions from './CollapseAllActions.vue'\nimport ItemHeaderActions from './ItemHeaderActions.vue'\nimport { useItemActionFallbacks, useItemMoves, useRunItemAction } from './item-actions'\nimport BuilderBlockActionsMenu from './BuilderBlockActionsMenu.vue'\nimport BuilderBlockPicker from './BuilderBlockPicker.vue'\nimport BuilderBlockPickerPanel from './BuilderBlockPickerPanel.vue'\n\n/**\n * A list of blocks, each with its own schema. Items use the server's per-item schema\n * when it describes the same block, else the block's template (fresh, moved or cloned\n * items the server has not seen yet).\n */\nconst props = defineProps<{ component: BuilderSchema }>()\nconst t = useT()\nconst formatter = useFormatter()\nconst registry = useOptionalRegistry()\nconst form = useOptionalFormStore()\nconst context = useFieldActionContext(() => props.component)\nconst runItemAction = useRunItemAction(context)\nconst fallbacks = useItemActionFallbacks()\nconst serverItemOf = (index: number) => {\n const server = props.component.items[index]\n\n return server && server.type === items.value[index]?.type ? server : undefined\n}\nconst resolve = (name: ItemActionName, index?: number) =>\n resolveItemAction(\n name,\n props.component,\n index === undefined ? undefined : serverItemOf(index),\n name === 'add' ? { ...fallbacks.add, label: props.component.addActionLabel } : fallbacks[name],\n )\n\nconst {\n value,\n setValue,\n error,\n id,\n disabled: fieldDisabled,\n readOnly,\n aria,\n} = useField<unknown>(() => props.component)\nconst locked = computed(() => fieldDisabled.value || readOnly.value)\nconst items = computed(() => builderItems(value.value))\nconst collapsed = ref<Record<number, boolean>>({})\nconst editing = ref<Record<number, boolean>>({})\nconst dragIndex = ref<number | null>(null)\n// Long lists render only the visible blocks (plus a few around them).\nconst virtual = useVirtualList(\n () => items.value.length,\n () => virtualizeOptions(props.component.virtualize, VIRTUAL_ESTIMATES.item, 12),\n)\nuseScrollToErroredItem(virtual, () => props.component.statePath)\nconst visibleItems = computed(() =>\n virtual.indexes.value.map((index) => ({ item: items.value[index] as BuilderItemState, index })),\n)\n\nconst blockOf = (type: string) => props.component.blocks.find((block) => block.name === type)\nconst isCollapsed = (index: number) => collapsed.value[index] ?? props.component.collapsed ?? false\nconst canAdd = computed(\n () =>\n props.component.addable &&\n !locked.value &&\n (props.component.maxItems == null || items.value.length < props.component.maxItems),\n)\nconst canDelete = computed(\n () =>\n props.component.deletable &&\n !locked.value &&\n (props.component.minItems == null || items.value.length > props.component.minItems),\n)\nconst canClone = (item: BuilderItemState) => {\n const block = blockOf(item.type)\n\n return Boolean(\n props.component.cloneable &&\n canAdd.value &&\n block &&\n canAddBuilderBlock(props.component, block, items.value),\n )\n}\n\nconst draggable = computed(\n () =>\n props.component.reorderable &&\n props.component.reorderableWithDragAndDrop !== false &&\n !locked.value &&\n resolve('reorder') !== null,\n)\nconst buttons = computed(\n () =>\n props.component.reorderable &&\n props.component.reorderableWithButtons !== false &&\n !locked.value,\n)\nconst addAction = computed(() => resolve('add'))\nconst showEmptyPicker = computed(\n () =>\n canAdd.value &&\n addAction.value !== null &&\n !addAction.value.disabled &&\n props.component.blocks.length > 0,\n)\nconst menu = computed(() => Boolean(props.component.blockActionsMenu) && !locked.value)\nconst runner = useActionRunner()\n// `blockActionsMenu()`: built-in actions run in the browser unless customised.\nconst onMenuAction = (name: ItemActionName, index: number) =>\n runItemAction(resolve(name, index), { item: String(index) }, () => {\n if (name === 'moveUp') moves.moveWithButton(index, index - 1)\n else if (name === 'moveDown') moves.moveWithButton(index, index + 1)\n else if (name === 'clone') cloneItem(index)\n else if (name === 'delete') removeItem(index)\n })\nconst onMenuExtra = (action: ActionSchema, index: number) =>\n void runner.trigger(action, itemActionContext(context.value, { item: String(index) }))\n\nconst update = (next: unknown[]) => setValue(next as BuilderItemState[])\nconst moveItem = (from: number, to: number) => {\n update(moveRepeaterItem(items.value, from, to))\n collapsed.value = moveIndexedState(collapsed.value, from, to)\n editing.value = moveIndexedState(editing.value, from, to)\n}\n// Move buttons: announced, one at a time, focus kept on the moved item.\nconst moves = useItemMoves(\n value,\n (from, to) => moveItem(from, to),\n (index) => builderItemLabel(props.component, items.value, index),\n () => items.value.length,\n)\nconst moveAnnouncement = moves.announcement\nconst moveContainer = moves.container\nconst removeItem = (index: number) => {\n update(removeRepeaterItem(items.value, index))\n collapsed.value = removeIndexedState(collapsed.value, index)\n editing.value = removeIndexedState(editing.value, index)\n}\nconst cloneItem = (index: number) => {\n update(cloneRepeaterItem(items.value, index))\n collapsed.value = cloneIndexedState(collapsed.value, index)\n editing.value = cloneIndexedState(editing.value, index)\n}\nconst addBlock = (block: BuilderBlockSchema) =>\n runItemAction(addAction.value, { block: block.name }, () =>\n update(insertBuilderItem(items.value, block)),\n )\n// A drop runs the reorder action: in the browser, or on the server when customised.\nconst onDrop = (index: number) => {\n const from = dragIndex.value\n dragIndex.value = null\n if (from === null || from === index) return\n runItemAction(\n resolve('reorder'),\n { items: reorderedItemKeys(items.value.length, from, index) },\n () => moveItem(from, index),\n )\n}\nconst setAllCollapsed = (value: boolean) => {\n collapsed.value = Object.fromEntries(items.value.map((_, index) => [index, value]))\n}\n\n// Previews (`blockPreviews()`): server HTML or a registered `builder-preview:{name}`.\nconst previewComponentOf = (index: number) => {\n const name =\n serverItemOf(index)?.previewComponent ??\n blockOf(items.value[index]?.type ?? '')?.previewComponent\n\n return name ? registry?.resolve(`builder-preview:${name}`) : undefined\n}\nconst hasPreview = (index: number) =>\n props.component.blockPreviews === true &&\n (previewComponentOf(index) !== undefined || Boolean(serverItemOf(index)?.preview))\nconst showPreview = (index: number) => hasPreview(index) && !editing.value[index]\n// Closing the editor re-renders the previews from the server.\nconst toggleEditing = (index: number) => {\n const open = !editing.value[index]\n editing.value = { ...editing.value, [index]: open }\n if (!open) void form?.refresh(props.component.statePath)\n}\nconst openEditor = (index: number) => {\n if (!locked.value) toggleEditing(index)\n}\nconst previewIsButton = computed(() => !props.component.interactivePreviews && !locked.value)\n</script>\n\n<template>\n <!-- `deferLoading()`: a skeleton until the field scrolls into view. -->\n <DeferredSchema\n v-if=\"isDeferredPlaceholder(props.component)\"\n v-slot=\"{ component: loaded }\"\n :component=\"props.component\"\n >\n <BuilderField :component=\"loaded\" />\n </DeferredSchema>\n <FieldWrapper v-else :field=\"props.component\" :html-for=\"id\" :error=\"error\">\n <div ref=\"moveContainer\" class=\"flex flex-col gap-3\" data-slot=\"builder\">\n <span aria-live=\"polite\" aria-atomic=\"true\" class=\"sr-only\" data-slot=\"item-move-status\">{{\n moveAnnouncement\n }}</span>\n <!-- No blocks yet: the picker is right there instead of behind a button. -->\n <div\n v-if=\"items.length === 0 && showEmptyPicker\"\n data-slot=\"builder-empty\"\n class=\"bg-muted/30 flex flex-col gap-3 rounded-lg border border-dashed p-3 sm:p-4\"\n >\n <div class=\"px-1\">\n <p class=\"text-sm font-medium\">\n {{ t('builder.empty_heading', {}, 'Add your first block') }}\n </p>\n <p class=\"text-muted-foreground text-sm\">\n {{\n t(\n 'builder.empty_description',\n {},\n 'Pick one to start. You can add more, reorder and remove them at any time.',\n )\n }}\n </p>\n </div>\n <BuilderBlockPickerPanel\n :component=\"props.component\"\n :items=\"items\"\n class=\"bg-card max-h-[28rem] rounded-md border\"\n @pick=\"addBlock\"\n />\n </div>\n <p\n v-else-if=\"items.length === 0\"\n class=\"text-muted-foreground rounded-lg border border-dashed p-4 text-center text-sm\"\n >\n {{ t('builder.empty', {}, 'No blocks yet.') }}\n </p>\n <CollapseAllActions\n v-if=\"props.component.collapsible && items.length > 0\"\n :context=\"context\"\n :collapse-all=\"resolve('collapseAll')\"\n :expand-all=\"resolve('expandAll')\"\n @collapse-all=\"setAllCollapsed(true)\"\n @expand-all=\"setAllCollapsed(false)\"\n />\n <ul\n :id=\"id\"\n :ref=\"virtual.attach\"\n :aria-labelledby=\"props.component.label ? fieldIds(id).label : undefined\"\n :aria-describedby=\"aria['aria-describedby']\"\n :style=\"virtual.style.value\"\n :class=\"cn('grid gap-3', items.length === 0 && 'hidden')\"\n >\n <li\n v-for=\"{ item, index } in visibleItems\"\n :key=\"index\"\n :ref=\"virtual.item\"\n :data-index=\"index\"\n :aria-setsize=\"virtual.range.value.active ? items.length : undefined\"\n :aria-posinset=\"virtual.range.value.active ? index + 1 : undefined\"\n :data-block=\"item.type\"\n :draggable=\"draggable\"\n :class=\"\n cn('bg-card min-w-0 rounded-lg border shadow-xs', dragIndex === index && 'opacity-50')\n \"\n @dragstart=\"dragIndex = index\"\n @dragover=\"draggable && $event.preventDefault()\"\n @drop=\"onDrop(index)\"\n @dragend=\"dragIndex = null\"\n >\n <Collapsible :open=\"!isCollapsed(index)\">\n <div\n class=\"flex flex-wrap items-center gap-1 border-b px-2 py-1.5\"\n data-slot=\"item-header\"\n >\n <span\n v-if=\"draggable\"\n class=\"text-muted-foreground cursor-grab\"\n :title=\"resolve('reorder')?.label ?? undefined\"\n aria-hidden=\"true\"\n ><Icon :name=\"resolve('reorder')?.icon ?? 'grip-vertical'\"\n /></span>\n <Icon\n v-if=\"\n props.component.blockIcons &&\n (blockOf(item.type)?.icon ?? props.component.items[index]?.icon)\n \"\n :name=\"blockOf(item.type)?.icon ?? props.component.items[index]?.icon\"\n class=\"text-muted-foreground size-4\"\n />\n <span\n v-if=\"props.component.blockNumbers\"\n class=\"text-muted-foreground text-xs tabular-nums\"\n >{{ formatter.number(index + 1) }}</span\n >\n <span class=\"flex min-w-0 flex-1 items-baseline gap-2\">\n <span\n v-if=\"props.component.blockLabels\"\n dir=\"auto\"\n class=\"min-w-0 shrink-0 truncate text-sm font-medium sm:max-w-[60%]\"\n >{{ builderItemLabel(props.component, items, index) }}</span\n >\n <span\n v-if=\"serverItemOf(index)?.summary\"\n dir=\"auto\"\n class=\"text-muted-foreground min-w-0 truncate text-sm\"\n data-slot=\"builder-item-summary\"\n >{{ serverItemOf(index)?.summary }}</span\n >\n </span>\n <ItemHeaderActions\n :context=\"context\"\n :item-key=\"String(index)\"\n :index=\"index\"\n :count=\"items.length\"\n :resolve=\"(name: ItemActionName) => resolve(name, index)\"\n :extra-actions=\"menu || locked ? undefined : serverItemOf(index)?.actions\"\n :buttons=\"buttons && !menu\"\n :can-clone=\"canClone(item) && !menu\"\n :can-delete=\"canDelete && !menu\"\n :collapsible=\"Boolean(props.component.collapsible)\"\n :collapsed=\"isCollapsed(index)\"\n @move=\"moves.moveWithButton\"\n @clone=\"cloneItem(index)\"\n @delete=\"removeItem(index)\"\n @toggle=\"collapsed = { ...collapsed, [index]: !isCollapsed(index) }\"\n >\n <Button\n v-if=\"hasPreview(index) && !locked\"\n type=\"button\"\n variant=\"ghost\"\n size=\"icon-xs\"\n :aria-label=\"t('builder.edit_block', {}, 'Edit block')\"\n :aria-pressed=\"Boolean(editing[index])\"\n @click=\"toggleEditing(index)\"\n ><Icon\n name=\"alfakit::forms.components.builder.actions.edit\"\n :fallback=\"PencilIcon\"\n /></Button>\n <BuilderBlockActionsMenu\n v-if=\"menu\"\n :label=\"builderItemLabel(props.component, items, index) ?? ''\"\n :resolve=\"(name: ItemActionName) => resolve(name, index)\"\n :can-move-up=\"buttons && index > 0\"\n :can-move-down=\"buttons && index < items.length - 1\"\n :can-clone=\"canClone(item)\"\n :can-delete=\"canDelete\"\n :extra-actions=\"serverItemOf(index)?.actions\"\n @action=\"(name: ItemActionName) => onMenuAction(name, index)\"\n @extra=\"(action: ActionSchema) => onMenuExtra(action, index)\"\n />\n </ItemHeaderActions>\n </div>\n <CollapsibleContent>\n <div\n v-if=\"showPreview(index)\"\n data-slot=\"builder-preview\"\n :class=\"cn('p-4', previewIsButton && 'cursor-pointer')\"\n :role=\"previewIsButton ? 'button' : undefined\"\n :tabindex=\"previewIsButton ? 0 : undefined\"\n :aria-label=\"\n previewIsButton ? t('builder.edit_block', {}, 'Edit block') : undefined\n \"\n @click=\"previewIsButton && openEditor(index)\"\n @keydown.enter.prevent=\"previewIsButton && openEditor(index)\"\n @keydown.space.prevent=\"previewIsButton && openEditor(index)\"\n >\n <div :class=\"cn(!props.component.interactivePreviews && 'pointer-events-none')\">\n <component\n :is=\"previewComponentOf(index)\"\n v-if=\"previewComponentOf(index)\"\n :data=\"item.data\"\n :block=\"item.type\"\n :index=\"index\"\n />\n <!-- Server-rendered `Block::preview()` HTML (Blade escapes the data). -->\n <!-- eslint-disable-next-line vue/no-v-html -->\n <div v-else v-html=\"serverItemOf(index)?.preview ?? ''\" />\n </div>\n </div>\n <div v-else class=\"p-4\">\n <SchemaRenderer\n :components=\"builderItemSchema(props.component, items, index)\"\n :columns=\"\n blockOf(item.type)?.columns ??\n props.component.items[index]?.columns ?? { default: 1 }\n \"\n />\n </div>\n </CollapsibleContent>\n </Collapsible>\n </li>\n </ul>\n <AddActionRow\n v-if=\"canAdd && addAction && props.component.blocks.length > 0 && items.length > 0\"\n :alignment=\"props.component.addActionAlignment\"\n >\n <BuilderBlockPicker :component=\"props.component\" :items=\"items\" @pick=\"addBlock\">\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n :disabled=\"addAction?.disabled\"\n data-slot=\"builder-add\"\n ><Icon v-if=\"addAction?.icon\" :name=\"addAction.icon\" /> {{ addAction?.label }}</Button\n >\n </BuilderBlockPicker>\n </AddActionRow>\n </div>\n </FieldWrapper>\n</template>\n"],"mappings":""}
1
+ {"version":3,"file":"BuilderField.js","names":["_sfc_main","BuilderField_vue_vue_type_script_setup_true_lang_default","BuilderField_default"],"sources":["../../../src/components/fields/BuilderField.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { BuilderBlockSchema, BuilderItemState, BuilderSchema } from '@alfakit/core'\nimport {\n isDeferredPlaceholder,\n VIRTUAL_ESTIMATES,\n builderItemLabel,\n builderItems,\n builderItemSchema,\n canAddBuilderBlock,\n cloneIndexedState,\n cloneRepeaterItem,\n fieldIds,\n insertBuilderItem,\n itemActionContext,\n moveIndexedState,\n moveRepeaterItem,\n removeIndexedState,\n removeRepeaterItem,\n reorderedItemKeys,\n resolveItemAction,\n virtualizeOptions,\n type ActionSchema,\n type ItemActionName,\n} from '@alfakit/core'\nimport { PencilIcon } from '@lucide/vue'\nimport { computed, ref } from 'vue'\nimport { useScrollToErroredItem, useVirtualList } from '../../composables/use-virtual-list'\nimport { useActionRunner, useFormatter, useOptionalRegistry, useT } from '../../context'\nimport { Icon } from '../../lib/icons'\nimport { cn } from '../../lib/utils'\nimport DeferredSchema from '../layout/DeferredSchema.vue'\nimport { useField, useOptionalFormStore } from '../form/form-context'\nimport { useFieldActionContext } from '../schema/field-actions'\nimport FieldWrapper from '../schema/FieldWrapper.vue'\nimport SchemaRenderer from '../schema/SchemaRenderer.vue'\nimport Button from '../ui/Button.vue'\nimport Collapsible from '../ui/Collapsible.vue'\nimport CollapsibleContent from '../ui/CollapsibleContent.vue'\nimport AddActionRow from './AddActionRow.vue'\nimport CollapseAllActions from './CollapseAllActions.vue'\nimport ItemHeaderActions from './ItemHeaderActions.vue'\nimport { useItemActionFallbacks, useItemMoves, useRunItemAction } from './item-actions'\nimport BuilderBlockActionsMenu from './BuilderBlockActionsMenu.vue'\nimport BuilderBlockPicker from './BuilderBlockPicker.vue'\nimport BuilderBlockPickerPanel from './BuilderBlockPickerPanel.vue'\n\n/**\n * A list of blocks, each with its own schema. Items use the server's per-item schema\n * when it describes the same block, else the block's template (fresh, moved or cloned\n * items the server has not seen yet).\n */\nconst props = defineProps<{ component: BuilderSchema }>()\nconst t = useT()\nconst formatter = useFormatter()\nconst registry = useOptionalRegistry()\nconst form = useOptionalFormStore()\nconst context = useFieldActionContext(() => props.component)\nconst runItemAction = useRunItemAction(context)\nconst fallbacks = useItemActionFallbacks('builder')\nconst serverItemOf = (index: number) => {\n const server = props.component.items[index]\n\n return server && server.type === items.value[index]?.type ? server : undefined\n}\nconst resolve = (name: ItemActionName, index?: number) =>\n resolveItemAction(\n name,\n props.component,\n index === undefined ? undefined : serverItemOf(index),\n name === 'add' ? { ...fallbacks.add, label: props.component.addActionLabel } : fallbacks[name],\n )\n\nconst {\n value,\n setValue,\n error,\n id,\n disabled: fieldDisabled,\n readOnly,\n aria,\n} = useField<unknown>(() => props.component)\nconst locked = computed(() => fieldDisabled.value || readOnly.value)\nconst items = computed(() => builderItems(value.value))\nconst collapsed = ref<Record<number, boolean>>({})\nconst editing = ref<Record<number, boolean>>({})\nconst dragIndex = ref<number | null>(null)\n// Long lists render only the visible blocks (plus a few around them).\nconst virtual = useVirtualList(\n () => items.value.length,\n () => virtualizeOptions(props.component.virtualize, VIRTUAL_ESTIMATES.item, 12),\n)\nuseScrollToErroredItem(virtual, () => props.component.statePath)\nconst visibleItems = computed(() =>\n virtual.indexes.value.map((index) => ({ item: items.value[index] as BuilderItemState, index })),\n)\n\nconst blockOf = (type: string) => props.component.blocks.find((block) => block.name === type)\nconst isCollapsed = (index: number) => collapsed.value[index] ?? props.component.collapsed ?? false\nconst canAdd = computed(\n () =>\n props.component.addable &&\n !locked.value &&\n (props.component.maxItems == null || items.value.length < props.component.maxItems),\n)\nconst canDelete = computed(\n () =>\n props.component.deletable &&\n !locked.value &&\n (props.component.minItems == null || items.value.length > props.component.minItems),\n)\nconst canClone = (item: BuilderItemState) => {\n const block = blockOf(item.type)\n\n return Boolean(\n props.component.cloneable &&\n canAdd.value &&\n block &&\n canAddBuilderBlock(props.component, block, items.value),\n )\n}\n\nconst draggable = computed(\n () =>\n props.component.reorderable &&\n props.component.reorderableWithDragAndDrop !== false &&\n !locked.value &&\n resolve('reorder') !== null,\n)\nconst buttons = computed(\n () =>\n props.component.reorderable &&\n props.component.reorderableWithButtons !== false &&\n !locked.value,\n)\nconst addAction = computed(() => resolve('add'))\nconst showEmptyPicker = computed(\n () =>\n canAdd.value &&\n addAction.value !== null &&\n !addAction.value.disabled &&\n props.component.blocks.length > 0,\n)\nconst menu = computed(() => Boolean(props.component.blockActionsMenu) && !locked.value)\nconst runner = useActionRunner()\n// `blockActionsMenu()`: built-in actions run in the browser unless customised.\nconst onMenuAction = (name: ItemActionName, index: number) =>\n runItemAction(resolve(name, index), { item: String(index) }, () => {\n if (name === 'moveUp') moves.moveWithButton(index, index - 1)\n else if (name === 'moveDown') moves.moveWithButton(index, index + 1)\n else if (name === 'clone') cloneItem(index)\n else if (name === 'delete') removeItem(index)\n })\nconst onMenuExtra = (action: ActionSchema, index: number) =>\n void runner.trigger(action, itemActionContext(context.value, { item: String(index) }))\n\nconst update = (next: unknown[]) => setValue(next as BuilderItemState[])\nconst moveItem = (from: number, to: number) => {\n update(moveRepeaterItem(items.value, from, to))\n collapsed.value = moveIndexedState(collapsed.value, from, to)\n editing.value = moveIndexedState(editing.value, from, to)\n}\n// Move buttons: announced, one at a time, focus kept on the moved item.\nconst moves = useItemMoves(\n value,\n (from, to) => moveItem(from, to),\n (index) => builderItemLabel(props.component, items.value, index),\n () => items.value.length,\n)\nconst moveAnnouncement = moves.announcement\nconst moveContainer = moves.container\nconst removeItem = (index: number) => {\n update(removeRepeaterItem(items.value, index))\n collapsed.value = removeIndexedState(collapsed.value, index)\n editing.value = removeIndexedState(editing.value, index)\n}\nconst cloneItem = (index: number) => {\n update(cloneRepeaterItem(items.value, index))\n collapsed.value = cloneIndexedState(collapsed.value, index)\n editing.value = cloneIndexedState(editing.value, index)\n}\nconst addBlock = (block: BuilderBlockSchema) =>\n runItemAction(addAction.value, { block: block.name }, () =>\n update(insertBuilderItem(items.value, block)),\n )\n// A drop runs the reorder action: in the browser, or on the server when customised.\nconst onDrop = (index: number) => {\n const from = dragIndex.value\n dragIndex.value = null\n if (from === null || from === index) return\n runItemAction(\n resolve('reorder'),\n { items: reorderedItemKeys(items.value.length, from, index) },\n () => moveItem(from, index),\n )\n}\nconst setAllCollapsed = (value: boolean) => {\n collapsed.value = Object.fromEntries(items.value.map((_, index) => [index, value]))\n if (value) refreshSummaries(items.value.map((_, index) => index))\n}\n// Summaries are made on the server: collapsing items whose block has one brings them up\n// to date with the edits.\nconst refreshSummaries = (indexes: number[]) => {\n if (indexes.some((index) => blockOf(items.value[index]?.type ?? '')?.summary)) {\n void form?.refresh(props.component.statePath)\n }\n}\nconst toggleCollapsed = (index: number) => {\n const collapse = !isCollapsed(index)\n collapsed.value = { ...collapsed.value, [index]: collapse }\n if (collapse) refreshSummaries([index])\n}\n\n// Previews (`blockPreviews()`): server HTML or a registered `builder-preview:{name}`.\nconst previewComponentOf = (index: number) => {\n const name =\n serverItemOf(index)?.previewComponent ??\n blockOf(items.value[index]?.type ?? '')?.previewComponent\n\n return name ? registry?.resolve(`builder-preview:${name}`) : undefined\n}\nconst hasPreview = (index: number) =>\n props.component.blockPreviews === true &&\n (previewComponentOf(index) !== undefined || Boolean(serverItemOf(index)?.preview))\nconst showPreview = (index: number) => hasPreview(index) && !editing.value[index]\n// Closing the editor re-renders the previews from the server.\nconst toggleEditing = (index: number) => {\n const open = !editing.value[index]\n editing.value = { ...editing.value, [index]: open }\n if (!open) void form?.refresh(props.component.statePath)\n}\nconst openEditor = (index: number) => {\n if (!locked.value) toggleEditing(index)\n}\nconst previewIsButton = computed(() => !props.component.interactivePreviews && !locked.value)\n</script>\n\n<template>\n <!-- `deferLoading()`: a skeleton until the field scrolls into view. -->\n <DeferredSchema\n v-if=\"isDeferredPlaceholder(props.component)\"\n v-slot=\"{ component: loaded }\"\n :component=\"props.component\"\n >\n <BuilderField :component=\"loaded\" />\n </DeferredSchema>\n <FieldWrapper v-else :field=\"props.component\" :html-for=\"id\" :error=\"error\">\n <div ref=\"moveContainer\" class=\"flex flex-col gap-3\" data-slot=\"builder\">\n <span aria-live=\"polite\" aria-atomic=\"true\" class=\"sr-only\" data-slot=\"item-move-status\">{{\n moveAnnouncement\n }}</span>\n <!-- No blocks yet: the picker is right there instead of behind a button. -->\n <div\n v-if=\"items.length === 0 && showEmptyPicker\"\n data-slot=\"builder-empty\"\n class=\"bg-muted/30 flex flex-col gap-3 rounded-lg border border-dashed p-3 sm:p-4\"\n >\n <div class=\"px-1\">\n <p class=\"text-sm font-medium\">\n {{ t('builder.empty_heading', {}, 'Add your first block') }}\n </p>\n <p class=\"text-muted-foreground text-sm\">\n {{\n t(\n 'builder.empty_description',\n {},\n 'Pick one to start. You can add more, reorder and remove them at any time.',\n )\n }}\n </p>\n </div>\n <BuilderBlockPickerPanel\n :component=\"props.component\"\n :items=\"items\"\n class=\"bg-card max-h-[28rem] rounded-md border\"\n @pick=\"addBlock\"\n />\n </div>\n <p\n v-else-if=\"items.length === 0\"\n class=\"text-muted-foreground rounded-lg border border-dashed p-4 text-center text-sm\"\n >\n {{ t('builder.empty', {}, 'No blocks yet.') }}\n </p>\n <CollapseAllActions\n v-if=\"props.component.collapsible && items.length > 0\"\n :context=\"context\"\n :collapse-all=\"resolve('collapseAll')\"\n :expand-all=\"resolve('expandAll')\"\n @collapse-all=\"setAllCollapsed(true)\"\n @expand-all=\"setAllCollapsed(false)\"\n />\n <ul\n :id=\"id\"\n :ref=\"virtual.attach\"\n :aria-labelledby=\"props.component.label ? fieldIds(id).label : undefined\"\n :aria-describedby=\"aria['aria-describedby']\"\n :style=\"virtual.style.value\"\n :class=\"cn('grid gap-3', items.length === 0 && 'hidden')\"\n >\n <li\n v-for=\"{ item, index } in visibleItems\"\n :key=\"index\"\n :ref=\"virtual.item\"\n :data-index=\"index\"\n :aria-setsize=\"virtual.range.value.active ? items.length : undefined\"\n :aria-posinset=\"virtual.range.value.active ? index + 1 : undefined\"\n :data-block=\"item.type\"\n :draggable=\"draggable\"\n :class=\"\n cn('bg-card min-w-0 rounded-lg border shadow-xs', dragIndex === index && 'opacity-50')\n \"\n @dragstart=\"dragIndex = index\"\n @dragover=\"draggable && $event.preventDefault()\"\n @drop=\"onDrop(index)\"\n @dragend=\"dragIndex = null\"\n >\n <Collapsible :open=\"!isCollapsed(index)\">\n <div\n class=\"flex flex-wrap items-center gap-1 border-b px-2 py-1.5\"\n data-slot=\"item-header\"\n >\n <span\n v-if=\"draggable\"\n class=\"text-muted-foreground cursor-grab\"\n :title=\"resolve('reorder')?.label ?? undefined\"\n aria-hidden=\"true\"\n ><Icon :name=\"resolve('reorder')?.icon ?? 'grip-vertical'\"\n /></span>\n <Icon\n v-if=\"\n props.component.blockIcons &&\n (blockOf(item.type)?.icon ?? props.component.items[index]?.icon)\n \"\n :name=\"blockOf(item.type)?.icon ?? props.component.items[index]?.icon\"\n class=\"text-muted-foreground size-4\"\n />\n <span\n v-if=\"props.component.blockNumbers\"\n class=\"text-muted-foreground text-xs tabular-nums\"\n >{{ formatter.number(index + 1) }}</span\n >\n <span class=\"flex min-w-0 flex-1 items-baseline gap-2\">\n <span\n v-if=\"props.component.blockLabels\"\n dir=\"auto\"\n class=\"min-w-0 shrink-0 truncate text-sm font-medium sm:max-w-[60%]\"\n >{{ builderItemLabel(props.component, items, index) }}</span\n >\n <span\n v-if=\"serverItemOf(index)?.summary\"\n dir=\"auto\"\n class=\"text-muted-foreground min-w-0 truncate text-sm\"\n data-slot=\"builder-item-summary\"\n >{{ serverItemOf(index)?.summary }}</span\n >\n </span>\n <ItemHeaderActions\n :context=\"context\"\n :item-key=\"String(index)\"\n :index=\"index\"\n :count=\"items.length\"\n :resolve=\"(name: ItemActionName) => resolve(name, index)\"\n :extra-actions=\"menu || locked ? undefined : serverItemOf(index)?.actions\"\n :buttons=\"buttons && !menu\"\n :can-clone=\"canClone(item) && !menu\"\n :can-delete=\"canDelete && !menu\"\n :collapsible=\"Boolean(props.component.collapsible)\"\n :collapsed=\"isCollapsed(index)\"\n @move=\"moves.moveWithButton\"\n @clone=\"cloneItem(index)\"\n @delete=\"removeItem(index)\"\n @toggle=\"toggleCollapsed(index)\"\n >\n <Button\n v-if=\"hasPreview(index) && !locked\"\n type=\"button\"\n variant=\"ghost\"\n size=\"icon-xs\"\n :aria-label=\"t('builder.edit_block', {}, 'Edit block')\"\n :aria-pressed=\"Boolean(editing[index])\"\n @click=\"toggleEditing(index)\"\n ><Icon\n name=\"alfakit::forms.components.builder.actions.edit\"\n :fallback=\"PencilIcon\"\n /></Button>\n <BuilderBlockActionsMenu\n v-if=\"menu\"\n :label=\"builderItemLabel(props.component, items, index) ?? ''\"\n :resolve=\"(name: ItemActionName) => resolve(name, index)\"\n :can-move-up=\"buttons && index > 0\"\n :can-move-down=\"buttons && index < items.length - 1\"\n :can-clone=\"canClone(item)\"\n :can-delete=\"canDelete\"\n :extra-actions=\"serverItemOf(index)?.actions\"\n @action=\"(name: ItemActionName) => onMenuAction(name, index)\"\n @extra=\"(action: ActionSchema) => onMenuExtra(action, index)\"\n />\n </ItemHeaderActions>\n </div>\n <CollapsibleContent>\n <div\n v-if=\"showPreview(index)\"\n data-slot=\"builder-preview\"\n :class=\"cn('p-4', previewIsButton && 'cursor-pointer')\"\n :role=\"previewIsButton ? 'button' : undefined\"\n :tabindex=\"previewIsButton ? 0 : undefined\"\n :aria-label=\"\n previewIsButton ? t('builder.edit_block', {}, 'Edit block') : undefined\n \"\n @click=\"previewIsButton && openEditor(index)\"\n @keydown.enter.prevent=\"previewIsButton && openEditor(index)\"\n @keydown.space.prevent=\"previewIsButton && openEditor(index)\"\n >\n <div :class=\"cn(!props.component.interactivePreviews && 'pointer-events-none')\">\n <component\n :is=\"previewComponentOf(index)\"\n v-if=\"previewComponentOf(index)\"\n :data=\"item.data\"\n :block=\"item.type\"\n :index=\"index\"\n />\n <!-- Server-rendered `Block::preview()` HTML (Blade escapes the data). -->\n <!-- eslint-disable-next-line vue/no-v-html -->\n <div v-else v-html=\"serverItemOf(index)?.preview ?? ''\" />\n </div>\n </div>\n <div v-else class=\"p-4\">\n <SchemaRenderer\n :components=\"builderItemSchema(props.component, items, index)\"\n :columns=\"\n blockOf(item.type)?.columns ??\n props.component.items[index]?.columns ?? { default: 1 }\n \"\n />\n </div>\n </CollapsibleContent>\n </Collapsible>\n </li>\n </ul>\n <AddActionRow\n v-if=\"canAdd && addAction && props.component.blocks.length > 0 && items.length > 0\"\n :alignment=\"props.component.addActionAlignment\"\n >\n <BuilderBlockPicker :component=\"props.component\" :items=\"items\" @pick=\"addBlock\">\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n :disabled=\"addAction?.disabled\"\n data-slot=\"builder-add\"\n ><Icon v-if=\"addAction?.icon\" :name=\"addAction.icon\" /> {{ addAction?.label }}</Button\n >\n </BuilderBlockPicker>\n </AddActionRow>\n </div>\n </FieldWrapper>\n</template>\n"],"mappings":""}
@@ -1 +1 @@
1
- {"version":3,"file":"BuilderField.vue.d.ts","sourceRoot":"","sources":["../../../src/components/fields/BuilderField.vue"],"names":[],"mappings":"AA8bA,OAAO,KAAK,EAAwC,aAAa,EAAE,MAAM,eAAe,CAAA;AA6CxF;;;;GAIG;AACH,KAAK,WAAW,GAAG;IAAE,SAAS,EAAE,aAAa,CAAA;CAAE,CAAC;;AAq0BhD,wBAMG"}
1
+ {"version":3,"file":"BuilderField.vue.d.ts","sourceRoot":"","sources":["../../../src/components/fields/BuilderField.vue"],"names":[],"mappings":"AA2cA,OAAO,KAAK,EAAwC,aAAa,EAAE,MAAM,eAAe,CAAA;AA6CxF;;;;GAIG;AACH,KAAK,WAAW,GAAG;IAAE,SAAS,EAAE,aAAa,CAAA;CAAE,CAAC;;AAk1BhD,wBAMG"}