includio-cms 0.25.0 → 0.26.0

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 (349) hide show
  1. package/API.md +57 -4
  2. package/CHANGELOG.md +53 -0
  3. package/DOCS.md +1 -1
  4. package/README.md +2 -0
  5. package/ROADMAP.md +6 -0
  6. package/dist/admin/client/account/lang.d.ts +1 -0
  7. package/dist/admin/client/account/lang.js +4 -2
  8. package/dist/admin/client/account/profile-section.svelte +2 -2
  9. package/dist/admin/client/account/security-section.svelte +27 -4
  10. package/dist/admin/client/account/sessions-section.svelte +1 -1
  11. package/dist/admin/client/admin/admin-after-login-layout-content.svelte +1 -1
  12. package/dist/admin/client/admin/dashboard-page.svelte +34 -10
  13. package/dist/admin/client/collection/bulk-actions-bar.svelte +86 -44
  14. package/dist/admin/client/collection/bulk-actions-bar.svelte.d.ts +3 -1
  15. package/dist/admin/client/collection/collection-entries.svelte +52 -36
  16. package/dist/admin/client/collection/collection-entries.svelte.d.ts +3 -0
  17. package/dist/admin/client/collection/collection.svelte +28 -14
  18. package/dist/admin/client/collection/collection.svelte.d.ts +3 -0
  19. package/dist/admin/client/collection/data-table.svelte +279 -130
  20. package/dist/admin/client/collection/data-table.svelte.d.ts +11 -0
  21. package/dist/admin/client/collection/date-cell.svelte +4 -4
  22. package/dist/admin/client/collection/row-actions.svelte +2 -1
  23. package/dist/admin/client/collection/sortable-header.svelte +33 -9
  24. package/dist/admin/client/collection/state-display.svelte +102 -0
  25. package/dist/admin/client/collection/state-display.svelte.d.ts +12 -0
  26. package/dist/admin/client/collection/status-badge.svelte +99 -11
  27. package/dist/admin/client/collection/status-badge.svelte.d.ts +15 -1
  28. package/dist/admin/client/collection/table-pagination.svelte +21 -6
  29. package/dist/admin/client/collection/table-toolbar.svelte +105 -80
  30. package/dist/admin/client/collection/table-toolbar.svelte.d.ts +11 -8
  31. package/dist/admin/client/entry/entry-form.svelte +36 -11
  32. package/dist/admin/client/entry/entry-form.svelte.d.ts +1 -0
  33. package/dist/admin/client/entry/entry-header.svelte +22 -15
  34. package/dist/admin/client/entry/entry-header.svelte.d.ts +1 -0
  35. package/dist/admin/client/entry/entry.svelte +269 -165
  36. package/dist/admin/client/entry/header/a11y-header-badge.svelte +47 -0
  37. package/dist/admin/client/entry/header/a11y-header-badge.svelte.d.ts +8 -0
  38. package/dist/admin/client/entry/header/publish-panel.svelte +69 -13
  39. package/dist/admin/client/entry/header/save-indicator.svelte +57 -28
  40. package/dist/admin/client/entry/header/save-indicator.svelte.d.ts +1 -0
  41. package/dist/admin/client/entry/header/status-badge.svelte +60 -15
  42. package/dist/admin/client/entry/header/status-badge.svelte.d.ts +1 -2
  43. package/dist/admin/client/entry/header/version-history-sheet.svelte +1 -1
  44. package/dist/admin/client/entry/hybrid/hybrid-layout.svelte +74 -23
  45. package/dist/admin/client/entry/hybrid/hybrid-preview.svelte +1 -1
  46. package/dist/admin/client/entry/utils.d.ts +14 -0
  47. package/dist/admin/client/entry/utils.js +28 -0
  48. package/dist/admin/client/form/form-submission/form-submission.svelte +2 -2
  49. package/dist/admin/client/form/form-submissions.svelte +143 -194
  50. package/dist/admin/client/form/form-submissions.svelte.d.ts +2 -0
  51. package/dist/admin/client/login/lang.d.ts +3 -0
  52. package/dist/admin/client/login/lang.js +10 -4
  53. package/dist/admin/client/login/login-form.svelte +8 -1
  54. package/dist/admin/client/login/reset-password-page.svelte +24 -3
  55. package/dist/admin/client/login/schema.d.ts +14 -2
  56. package/dist/admin/client/login/schema.js +19 -8
  57. package/dist/admin/client/maintenance/maintenance-page.svelte +16 -17
  58. package/dist/admin/client/media/media-page.svelte +1 -1
  59. package/dist/admin/client/shop/coupon-edit-page.svelte +117 -13
  60. package/dist/admin/client/shop/coupon-form.svelte +282 -138
  61. package/dist/admin/client/shop/coupon-form.svelte.d.ts +1 -9
  62. package/dist/admin/client/shop/coupon-new-page.svelte +40 -10
  63. package/dist/admin/client/shop/coupon-new-page.svelte.d.ts +2 -17
  64. package/dist/admin/client/shop/coupon-schema.d.ts +28 -0
  65. package/dist/admin/client/shop/coupon-schema.js +53 -0
  66. package/dist/admin/client/shop/coupons-list-page.svelte +262 -118
  67. package/dist/admin/client/shop/coupons-list-page.svelte.d.ts +16 -1
  68. package/dist/admin/client/shop/shipping-method-edit-page.svelte +108 -59
  69. package/dist/admin/client/shop/shipping-method-form.svelte +36 -9
  70. package/dist/admin/client/shop/shipping-method-new-page.svelte +44 -13
  71. package/dist/admin/client/shop/shipping-methods-list-page.svelte +101 -59
  72. package/dist/admin/client/shop/shop-order-detail-page.svelte +113 -84
  73. package/dist/admin/client/shop/shop-orders-list-page.svelte +302 -152
  74. package/dist/admin/client/shop/shop-orders-list-page.svelte.d.ts +18 -1
  75. package/dist/admin/client/shop/shop-products-list-page.svelte +355 -118
  76. package/dist/admin/client/shop/shop-products-list-page.svelte.d.ts +19 -1
  77. package/dist/admin/client/users/accept-invite-page.svelte +24 -3
  78. package/dist/admin/client/users/create-user-dialog.svelte +3 -8
  79. package/dist/admin/client/users/lang.d.ts +2 -0
  80. package/dist/admin/client/users/lang.js +4 -0
  81. package/dist/admin/client/users/pending-invitations.svelte +2 -9
  82. package/dist/admin/client/users/user-name-cell.svelte +20 -0
  83. package/dist/admin/client/users/user-name-cell.svelte.d.ts +9 -0
  84. package/dist/admin/client/users/user-role-badge.svelte +16 -0
  85. package/dist/admin/client/users/user-role-badge.svelte.d.ts +7 -0
  86. package/dist/admin/client/users/user-row-actions.svelte +72 -0
  87. package/dist/admin/client/users/user-row-actions.svelte.d.ts +20 -0
  88. package/dist/admin/client/users/user-sessions-sheet.svelte +2 -11
  89. package/dist/admin/client/users/users-page.svelte +283 -497
  90. package/dist/admin/client/users/users-page.svelte.d.ts +12 -1
  91. package/dist/admin/components/dashboard/form-submissions-widget.svelte +59 -74
  92. package/dist/admin/components/dashboard/recent-activity.svelte +17 -5
  93. package/dist/admin/components/dashboard/recent-entries.svelte +19 -7
  94. package/dist/admin/components/dialogs/confirmation-dialog.svelte +105 -0
  95. package/dist/admin/components/dialogs/confirmation-dialog.svelte.d.ts +13 -0
  96. package/dist/admin/components/fields/block-picker-modal.svelte +6 -0
  97. package/dist/admin/components/fields/blocks-field.svelte +46 -1
  98. package/dist/admin/components/fields/boolean-field.svelte +1 -1
  99. package/dist/admin/components/fields/field-renderer.svelte +23 -21
  100. package/dist/admin/components/fields/file-field.svelte +344 -30
  101. package/dist/admin/components/fields/media-field.svelte +16 -2
  102. package/dist/admin/components/fields/radio-field.svelte +22 -0
  103. package/dist/admin/components/fields/relation-field.svelte +123 -97
  104. package/dist/admin/components/fields/relation-picker-dialog.svelte +2 -2
  105. package/dist/admin/components/fields/seo-field.svelte +60 -30
  106. package/dist/admin/components/fields/shop-field.svelte +9 -4
  107. package/dist/admin/components/fields/simple-array-field.svelte +321 -151
  108. package/dist/admin/components/fields/simple-array-field.svelte.d.ts +3 -0
  109. package/dist/admin/components/fields/slug-field.svelte +146 -21
  110. package/dist/admin/components/fields/text-field-wrapper.svelte +37 -20
  111. package/dist/admin/components/fields/text-field.svelte +7 -2
  112. package/dist/admin/components/fields/url-field-wrapper.svelte +10 -0
  113. package/dist/admin/components/fields/url-field.svelte +36 -23
  114. package/dist/admin/components/forms/form-error-summary.svelte +143 -0
  115. package/dist/admin/components/forms/form-error-summary.svelte.d.ts +27 -0
  116. package/dist/admin/components/layout/app-sidebar.svelte +7 -2
  117. package/dist/admin/components/layout/detail-page-shell.svelte +71 -0
  118. package/dist/admin/components/layout/detail-page-shell.svelte.d.ts +24 -0
  119. package/dist/admin/components/layout/lang.d.ts +5 -0
  120. package/dist/admin/components/layout/lang.js +10 -0
  121. package/dist/admin/components/layout/layout-renderer.svelte +71 -2
  122. package/dist/admin/components/layout/layout-renderer.svelte.d.ts +1 -0
  123. package/dist/admin/components/layout/layout-tabs.svelte +172 -0
  124. package/dist/admin/components/layout/layout-tabs.svelte.d.ts +24 -0
  125. package/dist/admin/components/layout/nav-breadcrumbs.svelte +25 -7
  126. package/dist/admin/components/layout/nav-collections.svelte +23 -36
  127. package/dist/admin/components/layout/nav-forms.svelte +19 -35
  128. package/dist/admin/components/layout/nav-main.svelte +3 -28
  129. package/dist/admin/components/layout/nav-search.svelte +70 -2
  130. package/dist/admin/components/layout/nav-section.svelte +77 -0
  131. package/dist/admin/components/layout/nav-section.svelte.d.ts +22 -0
  132. package/dist/admin/components/layout/nav-shop.svelte +3 -27
  133. package/dist/admin/components/layout/nav-singletons.svelte +16 -28
  134. package/dist/admin/components/layout/page-header.stories.svelte +93 -0
  135. package/dist/admin/components/layout/page-header.stories.svelte.d.ts +27 -0
  136. package/dist/admin/components/layout/page-header.svelte +68 -0
  137. package/dist/admin/components/layout/page-header.svelte.d.ts +17 -0
  138. package/dist/admin/components/layout/site-header.svelte +9 -0
  139. package/dist/admin/components/layout/site-header.svelte.d.ts +2 -17
  140. package/dist/admin/components/media/file/file-name-input.svelte +6 -2
  141. package/dist/admin/components/media/file/file-preview.svelte +130 -17
  142. package/dist/admin/components/media/file-upload.svelte +16 -7
  143. package/dist/admin/components/media/file-upload.svelte.d.ts +1 -0
  144. package/dist/admin/components/media/files-list.svelte +153 -53
  145. package/dist/admin/components/media/files-list.svelte.d.ts +1 -0
  146. package/dist/admin/components/media/media-library.svelte +577 -198
  147. package/dist/admin/components/media/media-library.svelte.d.ts +4 -0
  148. package/dist/admin/components/media/media-selector.svelte +4 -2
  149. package/dist/admin/components/media/media-selector.svelte.d.ts +1 -0
  150. package/dist/admin/components/media/tag-sidebar.svelte +4 -4
  151. package/dist/admin/components/tiptap/FigureNodeView.svelte +10 -0
  152. package/dist/admin/components/tiptap/bubble-menu.svelte +104 -0
  153. package/dist/admin/components/tiptap/bubble-menu.svelte.d.ts +19 -0
  154. package/dist/admin/components/tiptap/content-editor.svelte +28 -24
  155. package/dist/admin/components/tiptap/editor-toolbar.svelte +7 -7
  156. package/dist/admin/components/tiptap/extensions.js +5 -1
  157. package/dist/admin/components/tiptap/image-dialog.svelte +5 -1
  158. package/dist/admin/components/tiptap/link-dialog.svelte +2 -0
  159. package/dist/admin/components/tiptap/tiptap-editor.svelte +18 -20
  160. package/dist/admin/components/tiptap/video-dialog.svelte +1 -1
  161. package/dist/admin/i18n/errors.d.ts +140 -0
  162. package/dist/admin/i18n/errors.js +151 -0
  163. package/dist/admin/remote/entry.remote.d.ts +59 -4
  164. package/dist/admin/remote/entry.remote.js +239 -62
  165. package/dist/admin/remote/shop.remote.d.ts +37 -32
  166. package/dist/admin/remote/shop.remote.js +9 -2
  167. package/dist/admin/shared/password-generate.d.ts +6 -0
  168. package/dist/admin/shared/password-generate.js +40 -0
  169. package/dist/admin/shared/password-schema.d.ts +6 -0
  170. package/dist/admin/shared/password-schema.js +10 -3
  171. package/dist/admin/styles/admin.css +23 -6
  172. package/dist/admin/styles/tokens.md +244 -0
  173. package/dist/admin/utils/accordionActivation.d.ts +13 -0
  174. package/dist/admin/utils/accordionActivation.js +35 -0
  175. package/dist/admin/utils/entryLabel.d.ts +23 -0
  176. package/dist/admin/utils/entryLabel.js +51 -12
  177. package/dist/admin/utils/field-a11y.d.ts +29 -0
  178. package/dist/admin/utils/field-a11y.js +23 -0
  179. package/dist/admin/utils/fieldPathElement.d.ts +9 -0
  180. package/dist/admin/utils/fieldPathElement.js +18 -0
  181. package/dist/admin/utils/fileDisplay.d.ts +10 -0
  182. package/dist/admin/utils/fileDisplay.js +26 -0
  183. package/dist/admin/utils/flattenFormErrors.d.ts +19 -0
  184. package/dist/admin/utils/flattenFormErrors.js +102 -0
  185. package/dist/admin/utils/formatters.d.ts +12 -0
  186. package/dist/admin/utils/{formatDate.js → formatters.js} +23 -2
  187. package/dist/admin/utils/scrollWithin.d.ts +9 -0
  188. package/dist/admin/utils/scrollWithin.js +32 -0
  189. package/dist/admin/utils/tabActivation.d.ts +12 -0
  190. package/dist/admin/utils/tabActivation.js +24 -0
  191. package/dist/cms/runtime/schema.d.ts +1 -0
  192. package/dist/cms/runtime/schema.js +1 -0
  193. package/dist/cms/runtime/types.d.ts +80 -7
  194. package/dist/components/ui/accordion/accordion-content.svelte +17 -3
  195. package/dist/components/ui/accordion/accordion.stories.svelte +21 -1
  196. package/dist/components/ui/alert/alert.stories.svelte +14 -0
  197. package/dist/components/ui/alert-dialog/alert-dialog.stories.svelte +45 -0
  198. package/dist/components/ui/alert-dialog/alert-dialog.stories.svelte.d.ts +27 -0
  199. package/dist/components/ui/avatar/avatar.stories.svelte +27 -0
  200. package/dist/components/ui/badge/badge.stories.svelte +15 -0
  201. package/dist/components/ui/breadcrumb/breadcrumb.stories.svelte +47 -0
  202. package/dist/components/ui/breadcrumb/breadcrumb.svelte +1 -1
  203. package/dist/components/ui/button/button.stories.svelte +53 -6
  204. package/dist/components/ui/button/button.svelte +39 -5
  205. package/dist/components/ui/button/button.svelte.d.ts +4 -0
  206. package/dist/components/ui/button-group/button-group.stories.svelte +44 -0
  207. package/dist/components/ui/button-group/button-group.stories.svelte.d.ts +27 -0
  208. package/dist/components/ui/calendar/calendar.stories.svelte +36 -0
  209. package/dist/components/ui/calendar/calendar.stories.svelte.d.ts +27 -0
  210. package/dist/components/ui/card/card.stories.svelte +7 -0
  211. package/dist/components/ui/carousel/carousel.stories.svelte +43 -0
  212. package/dist/components/ui/carousel/carousel.stories.svelte.d.ts +27 -0
  213. package/dist/components/ui/checkbox/checkbox.stories.svelte +67 -0
  214. package/dist/components/ui/checkbox/checkbox.stories.svelte.d.ts +27 -0
  215. package/dist/components/ui/checkbox/checkbox.svelte +3 -3
  216. package/dist/components/ui/command/command.stories.svelte +18 -0
  217. package/dist/components/ui/data-table/data-table.stories.svelte +61 -0
  218. package/dist/components/ui/data-table/data-table.stories.svelte.d.ts +18 -0
  219. package/dist/components/ui/dialog/dialog-content.svelte +5 -0
  220. package/dist/components/ui/dialog/dialog-content.svelte.d.ts +2 -0
  221. package/dist/components/ui/dialog/dialog.stories.svelte +35 -0
  222. package/dist/components/ui/dropdown-menu/dropdown-menu.stories.svelte +74 -0
  223. package/dist/components/ui/dropdown-menu/dropdown-menu.stories.svelte.d.ts +27 -0
  224. package/dist/components/ui/field/field-context.svelte.d.ts +22 -0
  225. package/dist/components/ui/field/field-context.svelte.js +9 -0
  226. package/dist/components/ui/field/field-control.svelte +18 -0
  227. package/dist/components/ui/field/field-control.svelte.d.ts +8 -0
  228. package/dist/components/ui/field/field-description.svelte +12 -0
  229. package/dist/components/ui/field/field-error.svelte +14 -6
  230. package/dist/components/ui/field/field-label.svelte +10 -0
  231. package/dist/components/ui/field/field.stories.svelte +95 -9
  232. package/dist/components/ui/field/field.svelte +57 -0
  233. package/dist/components/ui/field/field.svelte.d.ts +2 -0
  234. package/dist/components/ui/field/index.d.ts +3 -1
  235. package/dist/components/ui/field/index.js +4 -2
  236. package/dist/components/ui/form/form-field-errors.svelte +1 -1
  237. package/dist/components/ui/form/form.stories.svelte +25 -0
  238. package/dist/components/ui/form/form.stories.svelte.d.ts +26 -0
  239. package/dist/components/ui/input/input.stories.svelte +26 -0
  240. package/dist/components/ui/input-group/input-group-input.svelte.d.ts +1 -1
  241. package/dist/components/ui/input-group/input-group.stories.svelte +43 -0
  242. package/dist/components/ui/input-group/input-group.stories.svelte.d.ts +27 -0
  243. package/dist/components/ui/item/item.stories.svelte +61 -0
  244. package/dist/components/ui/item/item.stories.svelte.d.ts +27 -0
  245. package/dist/components/ui/label/label.stories.svelte +7 -0
  246. package/dist/components/ui/live-region/index.d.ts +1 -0
  247. package/dist/components/ui/live-region/index.js +1 -0
  248. package/dist/components/ui/live-region/live-region-demo.svelte +32 -0
  249. package/dist/components/ui/live-region/live-region-demo.svelte.d.ts +7 -0
  250. package/dist/components/ui/live-region/live-region.stories.svelte +23 -0
  251. package/dist/components/ui/live-region/live-region.stories.svelte.d.ts +26 -0
  252. package/dist/components/ui/live-region/live-region.svelte +12 -0
  253. package/dist/components/ui/live-region/live-region.svelte.d.ts +8 -0
  254. package/dist/components/ui/popover/popover.stories.svelte +34 -0
  255. package/dist/components/ui/radio-group/radio-group.stories.svelte +58 -0
  256. package/dist/components/ui/radio-group/radio-group.stories.svelte.d.ts +27 -0
  257. package/dist/components/ui/resizable/resizable.stories.svelte +56 -0
  258. package/dist/components/ui/resizable/resizable.stories.svelte.d.ts +27 -0
  259. package/dist/components/ui/select/select.stories.svelte +49 -0
  260. package/dist/components/ui/separator/separator.stories.svelte +18 -0
  261. package/dist/components/ui/sheet/sheet.stories.svelte +34 -0
  262. package/dist/components/ui/sidebar/sidebar-input.svelte.d.ts +1 -1
  263. package/dist/components/ui/sidebar/sidebar-menu-button.svelte +1 -0
  264. package/dist/components/ui/sidebar/sidebar-trigger.svelte +1 -1
  265. package/dist/components/ui/sidebar/sidebar.stories.svelte +72 -0
  266. package/dist/components/ui/sidebar/sidebar.stories.svelte.d.ts +27 -0
  267. package/dist/components/ui/skeleton/skeleton.stories.svelte +39 -0
  268. package/dist/components/ui/skeleton/skeleton.stories.svelte.d.ts +27 -0
  269. package/dist/components/ui/skeleton/skeleton.svelte +6 -0
  270. package/dist/components/ui/sonner/index.d.ts +1 -1
  271. package/dist/components/ui/sonner/index.js +1 -1
  272. package/dist/components/ui/sonner/sonner.stories.svelte +7 -0
  273. package/dist/components/ui/sonner/sonner.svelte +17 -1
  274. package/dist/components/ui/sonner/sonner.svelte.d.ts +6 -0
  275. package/dist/components/ui/spinner/spinner.stories.svelte +30 -0
  276. package/dist/components/ui/spinner/spinner.stories.svelte.d.ts +27 -0
  277. package/dist/components/ui/switch/switch.stories.svelte +56 -0
  278. package/dist/components/ui/switch/switch.stories.svelte.d.ts +27 -0
  279. package/dist/components/ui/table/table-cell.svelte +1 -1
  280. package/dist/components/ui/table/table-head.svelte +1 -1
  281. package/dist/components/ui/table/table.stories.svelte +68 -0
  282. package/dist/components/ui/table/table.stories.svelte.d.ts +27 -0
  283. package/dist/components/ui/table/table.svelte +1 -1
  284. package/dist/components/ui/tabs/tabs.stories.svelte +48 -0
  285. package/dist/components/ui/tabs/tabs.stories.svelte.d.ts +27 -0
  286. package/dist/components/ui/textarea/textarea.stories.svelte +21 -0
  287. package/dist/components/ui/toggle/toggle.stories.svelte +23 -0
  288. package/dist/components/ui/toggle-group/toggle-group.stories.svelte +43 -0
  289. package/dist/components/ui/tooltip/tooltip.stories.svelte +46 -6
  290. package/dist/core/fields/fieldSchemaToTs.d.ts +7 -0
  291. package/dist/core/fields/fieldSchemaToTs.js +234 -90
  292. package/dist/core/fields/layoutUtils.d.ts +4 -1
  293. package/dist/core/fields/layoutUtils.js +41 -4
  294. package/dist/core/fields/resolveSeo.d.ts +70 -0
  295. package/dist/core/fields/resolveSeo.js +88 -0
  296. package/dist/core/fields/seoFieldDescriptor.d.ts +43 -0
  297. package/dist/core/fields/seoFieldDescriptor.js +74 -0
  298. package/dist/core/fields/slugPath.d.ts +13 -0
  299. package/dist/core/fields/slugPath.js +32 -0
  300. package/dist/core/fields/urlUtils.d.ts +8 -0
  301. package/dist/core/fields/urlUtils.js +27 -0
  302. package/dist/core/index.d.ts +1 -0
  303. package/dist/core/index.js +1 -0
  304. package/dist/core/server/entries/operations/create.js +13 -0
  305. package/dist/core/server/entries/operations/get.d.ts +7 -0
  306. package/dist/core/server/entries/operations/get.js +10 -6
  307. package/dist/core/server/entries/operations/slugUniqueness.d.ts +37 -0
  308. package/dist/core/server/entries/operations/slugUniqueness.js +116 -0
  309. package/dist/core/server/entries/operations/update.d.ts +6 -1
  310. package/dist/core/server/entries/operations/update.js +24 -1
  311. package/dist/core/server/fields/slugResolver.d.ts +3 -13
  312. package/dist/core/server/fields/slugResolver.js +8 -37
  313. package/dist/core/server/generator/fields.js +10 -17
  314. package/dist/core/server/generator/formFields.js +2 -1
  315. package/dist/core/server/generator/generator.js +4 -4
  316. package/dist/core/server/generator/utils.d.ts +1 -0
  317. package/dist/core/server/generator/utils.js +4 -0
  318. package/dist/paraglide/messages/_index.d.ts +3 -36
  319. package/dist/paraglide/messages/_index.js +3 -71
  320. package/dist/paraglide/messages/hello_world.d.ts +5 -0
  321. package/dist/paraglide/messages/hello_world.js +33 -0
  322. package/dist/paraglide/messages/login_hello.d.ts +16 -0
  323. package/dist/paraglide/messages/login_hello.js +34 -0
  324. package/dist/paraglide/messages/login_please_login.d.ts +16 -0
  325. package/dist/paraglide/messages/login_please_login.js +34 -0
  326. package/dist/shop/server/orders.d.ts +1 -0
  327. package/dist/shop/server/orders.js +14 -0
  328. package/dist/shop/server/shop-data.d.ts +2 -0
  329. package/dist/shop/server/shop-data.js +20 -5
  330. package/dist/sveltekit/server/handle.js +17 -0
  331. package/dist/types/cms.schema.js +4 -2
  332. package/dist/types/fields.d.ts +35 -0
  333. package/dist/types/index.d.ts +1 -1
  334. package/dist/types/layout.d.ts +35 -2
  335. package/dist/updates/0.26.0/index.d.ts +2 -0
  336. package/dist/updates/0.26.0/index.js +51 -0
  337. package/dist/updates/index.js +3 -1
  338. package/package.json +29 -7
  339. package/dist/admin/client/collection/empty-state.svelte +0 -28
  340. package/dist/admin/client/collection/empty-state.svelte.d.ts +0 -9
  341. package/dist/admin/client/form/submission-status-badge.svelte +0 -41
  342. package/dist/admin/client/form/submission-status-badge.svelte.d.ts +0 -7
  343. package/dist/admin/components/media/file-preview.svelte +0 -51
  344. package/dist/admin/components/media/file-preview.svelte.d.ts +0 -6
  345. package/dist/admin/utils/formatDate.d.ts +0 -5
  346. package/dist/paraglide/messages/en.d.ts +0 -5
  347. package/dist/paraglide/messages/en.js +0 -14
  348. package/dist/paraglide/messages/pl.d.ts +0 -5
  349. package/dist/paraglide/messages/pl.js +0 -14
@@ -1,3 +1,14 @@
1
- declare const UsersPage: import("svelte").Component<Record<string, never>, {}, "">;
1
+ type User = {
2
+ id: string;
3
+ name: string;
4
+ email: string;
5
+ role: string;
6
+ createdAt: Date;
7
+ };
8
+ type Props = {
9
+ data?: User[];
10
+ state?: 'loading' | 'error' | 'ok';
11
+ };
12
+ declare const UsersPage: import("svelte").Component<Props, {}, "">;
2
13
  type UsersPage = ReturnType<typeof UsersPage>;
3
14
  export default UsersPage;
@@ -1,6 +1,6 @@
1
1
  <script lang="ts">
2
2
  import { useInterfaceLanguage } from '../../state/interface-language.svelte.js';
3
- import { formatRelativeDate as formatRelativeDateUtil } from '../../utils/formatDate.js';
3
+ import { formatRelativeDate as formatRelativeDateUtil } from '../../utils/formatters.js';
4
4
  import Skeleton from '../../../components/ui/skeleton/skeleton.svelte';
5
5
  import { getRemotes } from '../../../sveltekit/index.js';
6
6
  import { getLocalizedLabel } from '../../utils/collectionLabel.js';
@@ -9,21 +9,9 @@
9
9
  const interfaceLanguage = useInterfaceLanguage();
10
10
  const remotes = getRemotes();
11
11
 
12
- const lang: Record<InterfaceLanguage, {
13
- title: string;
14
- viewAll: string;
15
- noSubmissions: string;
16
- }> = {
17
- pl: {
18
- title: 'Zgłoszenia',
19
- viewAll: 'Wszystkie →',
20
- noSubmissions: 'Brak zgłoszeń'
21
- },
22
- en: {
23
- title: 'Submissions',
24
- viewAll: 'View all →',
25
- noSubmissions: 'No submissions'
26
- }
12
+ const lang: Record<InterfaceLanguage, { title: string; noSubmissions: string; unread: string }> = {
13
+ pl: { title: 'Zgłoszenia', noSubmissions: 'Brak zgłoszeń', unread: 'nieprzeczytane' },
14
+ en: { title: 'Submissions', noSubmissions: 'No submissions', unread: 'unread' }
27
15
  };
28
16
 
29
17
  function formatRelativeDate(date: Date): string {
@@ -31,75 +19,72 @@
31
19
  }
32
20
 
33
21
  const query = $derived(remotes.getSubmissionsOverview());
22
+
23
+ // Flat list of the most recent submissions across all forms, newest first.
24
+ const recentSubmissions = $derived.by(() => {
25
+ const overview = query.current;
26
+ if (!overview) return [];
27
+ return overview
28
+ .flatMap((form) =>
29
+ form.recent.map((s) => ({
30
+ ...s,
31
+ formLabel: getLocalizedLabel(form.label as Localized, interfaceLanguage.current) ?? form.slug
32
+ }))
33
+ )
34
+ .sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime())
35
+ .slice(0, 6);
36
+ });
34
37
  </script>
35
38
 
36
39
  <section class="dash-card dash-card--forms" aria-labelledby="forms-heading">
37
40
  <div class="dash-card-header">
38
41
  <h2 class="dash-card-title" id="forms-heading">{lang[interfaceLanguage.current].title}</h2>
39
- <a href="/admin/forms" class="dash-card-link">{lang[interfaceLanguage.current].viewAll}</a>
40
42
  </div>
41
43
 
42
44
  {#if !query.ready}
43
- <div class="forms-card-body">
44
- {#each Array(2) as _}
45
- <div class="form-group">
46
- <Skeleton class="h-4 w-24 mb-2" />
47
- <Skeleton class="h-8 w-full" />
48
- <Skeleton class="h-8 w-full mt-1" />
49
- </div>
45
+ <ul class="entries-list">
46
+ {#each Array(4) as _}
47
+ <li class="entry-item">
48
+ <div class="entry-item-link" style="pointer-events:none">
49
+ <div class="entry-item-main">
50
+ <Skeleton class="h-4 w-40" />
51
+ <Skeleton class="h-3 w-24 mt-1" />
52
+ </div>
53
+ </div>
54
+ </li>
50
55
  {/each}
51
- </div>
56
+ </ul>
52
57
  {:else if query.current}
53
- {@const overview = query.current}
54
58
  <div class:opacity-60={query.loading} class="transition-opacity duration-200">
55
- {#if overview.length === 0}
56
- <p class="text-center text-sm py-6" style="color:var(--text-light)">
57
- {lang[interfaceLanguage.current].noSubmissions}
58
- </p>
59
- {:else}
60
- <div class="forms-card-body">
61
- {#each overview as form}
62
- <div class="form-group">
63
- <div class="form-group-header">
64
- <span class="form-group-name">
65
- {getLocalizedLabel(form.label as Localized, interfaceLanguage.current)}
66
- </span>
67
- <span
68
- class="form-group-badge {form.unread > 0 ? 'form-group-badge--unread' : ''}"
69
- aria-label="{form.unread} {interfaceLanguage.current === 'pl' ? 'nieprzeczytanych' : 'unread'}"
70
- >
71
- {form.unread}
72
- </span>
73
- </div>
74
-
75
- {#if form.recent.length > 0}
76
- <ul class="form-submissions-list" aria-label="{getLocalizedLabel(form.label as Localized, interfaceLanguage.current)}">
77
- {#each form.recent.slice(0, 3) as submission}
78
- <li>
79
- <a href="/admin/form-submissions/{submission.id}" class="form-submission-item">
80
- <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true" style="flex-shrink:0; color: {submission.read ? 'var(--text-light)' : 'var(--primary)'}">
81
- <path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"/>
82
- <polyline points="22,6 12,13 2,6"/>
83
- </svg>
84
- <span style="flex:1; min-width:0; font-size:13px; font-weight:{submission.read ? '500' : '700'}; color:{submission.read ? 'var(--muted-foreground)' : 'var(--foreground)'}; overflow:hidden; text-overflow:ellipsis; white-space:nowrap">
85
- {submission.preview || '—'}
86
- </span>
87
- <time style="font-size:11px; color:var(--text-light); white-space:nowrap; flex-shrink:0">
88
- {formatRelativeDate(new Date(submission.createdAt))}
89
- </time>
90
- </a>
91
- </li>
92
- {/each}
93
- </ul>
94
- {:else}
95
- <p style="font-size:13px; color:var(--text-light); padding:4px 10px">
96
- {lang[interfaceLanguage.current].noSubmissions}
97
- </p>
98
- {/if}
99
- </div>
100
- {/each}
101
- </div>
102
- {/if}
59
+ {#if recentSubmissions.length === 0}
60
+ <p class="text-center text-sm py-6" style="color:var(--text-light)">
61
+ {lang[interfaceLanguage.current].noSubmissions}
62
+ </p>
63
+ {:else}
64
+ <ul class="entries-list" aria-label={lang[interfaceLanguage.current].title}>
65
+ {#each recentSubmissions as submission (submission.id)}
66
+ <li class="entry-item">
67
+ <a href="/admin/form-submissions/{submission.id}" class="entry-item-link">
68
+ <span
69
+ aria-hidden="true"
70
+ style="width:7px;height:7px;border-radius:9999px;flex:none;align-self:center;margin-right:8px;background:{submission.read
71
+ ? 'var(--border)'
72
+ : 'var(--primary)'}"
73
+ ></span>
74
+ <div class="entry-item-main">
75
+ <span class="entry-item-title" style={submission.read ? '' : 'font-weight:700'}>
76
+ {submission.preview || '—'}
77
+ {#if !submission.read}<span class="sr-only">({lang[interfaceLanguage.current].unread})</span>{/if}
78
+ </span>
79
+ <span class="entry-item-meta">
80
+ {submission.formLabel} · {formatRelativeDate(new Date(submission.createdAt))}
81
+ </span>
82
+ </div>
83
+ </a>
84
+ </li>
85
+ {/each}
86
+ </ul>
87
+ {/if}
103
88
  </div>
104
89
  {/if}
105
90
  </section>
@@ -1,9 +1,10 @@
1
1
  <script lang="ts">
2
2
  import { useInterfaceLanguage } from '../../state/interface-language.svelte.js';
3
- import { formatRelativeDate as formatRelativeDateUtil } from '../../utils/formatDate.js';
3
+ import { formatRelativeDate as formatRelativeDateUtil } from '../../utils/formatters.js';
4
+ import { getLocalizedLabel } from '../../utils/collectionLabel.js';
4
5
  import Skeleton from '../../../components/ui/skeleton/skeleton.svelte';
5
6
  import { getRemotes } from '../../../sveltekit/index.js';
6
- import type { InterfaceLanguage } from '../../../types/languages.js';
7
+ import type { InterfaceLanguage, Localized } from '../../../types/languages.js';
7
8
 
8
9
  const interfaceLanguage = useInterfaceLanguage();
9
10
  const remotes = getRemotes();
@@ -29,7 +30,9 @@
29
30
  return formatRelativeDateUtil(date, interfaceLanguage.current);
30
31
  }
31
32
 
32
- const query = $derived(remotes.getRecentActivity(10));
33
+ const query = $derived(
34
+ remotes.getRecentActivity({ limit: 10, language: interfaceLanguage.current })
35
+ );
33
36
  </script>
34
37
 
35
38
  <section class="dash-card dash-card--activity" aria-labelledby="activity-heading">
@@ -61,6 +64,10 @@
61
64
  {:else}
62
65
  <ul class="activity-list" aria-label={lang[interfaceLanguage.current].title}>
63
66
  {#each activity as item, i}
67
+ {@const containerName = (
68
+ getLocalizedLabel(item.containerLabel as Localized, interfaceLanguage.current) ??
69
+ item.slug
70
+ ).toLocaleLowerCase(interfaceLanguage.current)}
64
71
  <li class="activity-item">
65
72
  <div class="activity-dot-col">
66
73
  <div class="activity-dot activity-dot--edit" aria-hidden="true"></div>
@@ -70,10 +77,15 @@
70
77
  </div>
71
78
  <a href="/admin/entries/{item.entryId}" class="activity-body" style="text-decoration:none">
72
79
  <p class="activity-text">
73
- {lang[interfaceLanguage.current].edited} „{item.label || item.slug}"
80
+ {#if item.kind === 'single'}
81
+ {lang[interfaceLanguage.current].edited} {containerName}
82
+ {:else}
83
+ {lang[interfaceLanguage.current].edited} {containerName} „{item.label || item.slug}"{#if item.label && item.labelLanguage && item.labelLanguage !== interfaceLanguage.current}<span style="color:var(--text-light);font-weight:400;font-size:0.85em">{' '}({item.labelLanguage})</span>{/if}
84
+ {/if}
74
85
  </p>
75
86
  <p class="activity-meta">
76
- {formatRelativeDate(new Date(item.updatedAt))}
87
+ {(item.editorName ? item.editorName + ' · ' : '') +
88
+ formatRelativeDate(new Date(item.updatedAt))}
77
89
  </p>
78
90
  </a>
79
91
  </li>
@@ -1,6 +1,6 @@
1
1
  <script lang="ts">
2
2
  import { useInterfaceLanguage } from '../../state/interface-language.svelte.js';
3
- import { formatRelativeDate as formatRelativeDateUtil } from '../../utils/formatDate.js';
3
+ import { formatRelativeDate as formatRelativeDateUtil } from '../../utils/formatters.js';
4
4
  import { getLocalizedLabel } from '../../utils/collectionLabel.js';
5
5
  import Skeleton from '../../../components/ui/skeleton/skeleton.svelte';
6
6
  import { getRemotes } from '../../../sveltekit/index.js';
@@ -45,13 +45,12 @@
45
45
  scheduled: '◐'
46
46
  };
47
47
 
48
- const query = $derived(remotes.getRecentEntries(6));
48
+ const query = $derived(remotes.getRecentEntries({ limit: 6, language: interfaceLanguage.current }));
49
49
  </script>
50
50
 
51
51
  <section class="dash-card dash-card--entries" aria-labelledby="entries-heading">
52
52
  <div class="dash-card-header">
53
53
  <h2 class="dash-card-title" id="entries-heading">{lang[interfaceLanguage.current].title}</h2>
54
- <a href="/admin/entries" class="dash-card-link">{lang[interfaceLanguage.current].viewAll}</a>
55
54
  </div>
56
55
 
57
56
  {#if !query.ready}
@@ -77,13 +76,26 @@
77
76
  {:else}
78
77
  <ul class="entries-list" aria-label={lang[interfaceLanguage.current].title}>
79
78
  {#each entries as entry}
79
+ {@const containerName = getLocalizedLabel(
80
+ entry.containerLabel as Localized,
81
+ interfaceLanguage.current
82
+ )}
80
83
  <li class="entry-item">
81
84
  <a href="/admin/entries/{entry.entryId}" class="entry-item-link">
82
85
  <div class="entry-item-main">
83
- <span class="entry-item-title">{entry.label || entry.slug}</span>
84
- <span class="entry-item-meta">
85
- {getLocalizedLabel(entry.collectionLabel as Localized, interfaceLanguage.current)} · {formatRelativeDate(new Date(entry.updatedAt))}
86
- </span>
86
+ {#if entry.kind === 'single'}
87
+ <span class="entry-item-title">{containerName}</span>
88
+ <span class="entry-item-meta">
89
+ {formatRelativeDate(new Date(entry.updatedAt))}
90
+ </span>
91
+ {:else}
92
+ <span class="entry-item-title"
93
+ >{entry.label || entry.slug}{#if entry.label && entry.labelLanguage && entry.labelLanguage !== interfaceLanguage.current}<span style="color:var(--text-light);font-weight:400;font-size:0.85em">{' '}({entry.labelLanguage})</span>{/if}</span
94
+ >
95
+ <span class="entry-item-meta">
96
+ {containerName} · {formatRelativeDate(new Date(entry.updatedAt))}
97
+ </span>
98
+ {/if}
87
99
  </div>
88
100
  <span class="dash-status-badge dash-status-{entry.status}">
89
101
  <span aria-hidden="true">{statusIcon[entry.status] ?? ''}</span>
@@ -0,0 +1,105 @@
1
+ <script lang="ts" module>
2
+ /**
3
+ * @internal
4
+ * Reusable confirmation dialog — wraps bits-ui AlertDialog with destructive
5
+ * default + safe focus (Cancel autofocus) + loading state.
6
+ *
7
+ * Used by entry-page (copy-from-lang, archive), shop-order-detail (cancel
8
+ * shipping), coupons-list (delete), dashboard-page (delete orphaned),
9
+ * form-submissions (bulk delete). S8.
10
+ */
11
+ </script>
12
+
13
+ <script lang="ts">
14
+ import * as AlertDialog from '../../../components/ui/alert-dialog/index.js';
15
+ import { buttonVariants } from '../../../components/ui/button/button.svelte';
16
+ import { useInterfaceLanguage } from '../../state/interface-language.svelte.js';
17
+ import type { InterfaceLanguage } from '../../../types/languages.js';
18
+ import Loader2 from '@tabler/icons-svelte/icons/loader-2';
19
+ import { cn } from '../../../utils.js';
20
+
21
+ type Props = {
22
+ open: boolean;
23
+ title: string;
24
+ description: string;
25
+ confirmLabel?: string;
26
+ cancelLabel?: string;
27
+ variant?: 'destructive' | 'default';
28
+ loading?: boolean;
29
+ onConfirm: () => void | Promise<void>;
30
+ };
31
+
32
+ let {
33
+ open = $bindable(false),
34
+ title,
35
+ description,
36
+ confirmLabel,
37
+ cancelLabel,
38
+ variant = 'destructive',
39
+ loading = false,
40
+ onConfirm
41
+ }: Props = $props();
42
+
43
+ const interfaceLanguage = useInterfaceLanguage();
44
+
45
+ const lang: Record<
46
+ InterfaceLanguage,
47
+ { defaultConfirmDestructive: string; defaultConfirmDefault: string; defaultCancel: string }
48
+ > = {
49
+ pl: {
50
+ defaultConfirmDestructive: 'Usuń',
51
+ defaultConfirmDefault: 'Potwierdź',
52
+ defaultCancel: 'Anuluj'
53
+ },
54
+ en: {
55
+ defaultConfirmDestructive: 'Delete',
56
+ defaultConfirmDefault: 'Confirm',
57
+ defaultCancel: 'Cancel'
58
+ }
59
+ };
60
+
61
+ const resolvedConfirm = $derived(
62
+ confirmLabel ??
63
+ (variant === 'destructive'
64
+ ? lang[interfaceLanguage.current].defaultConfirmDestructive
65
+ : lang[interfaceLanguage.current].defaultConfirmDefault)
66
+ );
67
+ const resolvedCancel = $derived(cancelLabel ?? lang[interfaceLanguage.current].defaultCancel);
68
+
69
+ let cancelRef = $state<HTMLElement | null>(null);
70
+
71
+ $effect(() => {
72
+ if (!open) return;
73
+ // Defer to ensure portal mounted, then focus Cancel for safety.
74
+ queueMicrotask(() => cancelRef?.focus());
75
+ });
76
+
77
+ async function handleAction(event: Event) {
78
+ event.preventDefault();
79
+ if (loading) return;
80
+ await onConfirm();
81
+ open = false;
82
+ }
83
+ </script>
84
+
85
+ <AlertDialog.Root bind:open>
86
+ <AlertDialog.Content>
87
+ <AlertDialog.Title>{title}</AlertDialog.Title>
88
+ <AlertDialog.Description>{description}</AlertDialog.Description>
89
+ <AlertDialog.Footer>
90
+ <AlertDialog.Cancel bind:ref={cancelRef} disabled={loading}>
91
+ {resolvedCancel}
92
+ </AlertDialog.Cancel>
93
+ <AlertDialog.Action
94
+ class={cn(buttonVariants({ variant }), 'inline-flex items-center gap-2')}
95
+ disabled={loading}
96
+ onclick={handleAction}
97
+ >
98
+ {#if loading}
99
+ <Loader2 class="size-4 animate-spin" aria-hidden="true" />
100
+ {/if}
101
+ {resolvedConfirm}
102
+ </AlertDialog.Action>
103
+ </AlertDialog.Footer>
104
+ </AlertDialog.Content>
105
+ </AlertDialog.Root>
@@ -0,0 +1,13 @@
1
+ type Props = {
2
+ open: boolean;
3
+ title: string;
4
+ description: string;
5
+ confirmLabel?: string;
6
+ cancelLabel?: string;
7
+ variant?: 'destructive' | 'default';
8
+ loading?: boolean;
9
+ onConfirm: () => void | Promise<void>;
10
+ };
11
+ declare const ConfirmationDialog: import("svelte").Component<Props, {}, "open">;
12
+ type ConfirmationDialog = ReturnType<typeof ConfirmationDialog>;
13
+ export default ConfirmationDialog;
@@ -62,6 +62,12 @@
62
62
  />
63
63
  </div>
64
64
 
65
+ <div class="sr-only" role="status" aria-live="polite">
66
+ {#if searchQuery.trim()}
67
+ {filteredOptions.length} {pt.noBlocksFound === 'Nie znaleziono bloków' ? 'wyników' : 'results'}
68
+ {/if}
69
+ </div>
70
+
65
71
  <div class="grid max-h-[60vh] grid-cols-2 gap-4 overflow-y-auto">
66
72
  {#each filteredOptions as option (option.slug)}
67
73
  <button
@@ -28,6 +28,7 @@
28
28
  import { droppable, draggable, dndState } from '@thisux/sveltednd';
29
29
  import { flip } from 'svelte/animate';
30
30
  import { arrayMove } from '../../utils/arrayMove.js';
31
+ import { LiveRegion } from '../../../components/ui/live-region/index.js';
31
32
 
32
33
  const contentLanguage = getContentLanguage();
33
34
  const interfaceLanguage = useInterfaceLanguage();
@@ -42,6 +43,18 @@
42
43
  };
43
44
  const bt = $derived(blocksLang[interfaceLanguage.current]);
44
45
 
46
+ const announceLang: Record<InterfaceLanguage, { movedTo: string; added: string; removed: string; duplicated: string }> = {
47
+ pl: { movedTo: 'Przeniesiono na pozycję', added: 'Dodano blok', removed: 'Usunięto blok', duplicated: 'Zduplikowano blok' },
48
+ en: { movedTo: 'Moved to position', added: 'Added block', removed: 'Removed block', duplicated: 'Duplicated block' }
49
+ };
50
+ const at = $derived(announceLang[interfaceLanguage.current]);
51
+ let announcement = $state('');
52
+
53
+ function announce(text: string) {
54
+ announcement = '';
55
+ queueMicrotask(() => { announcement = text; });
56
+ }
57
+
45
58
  function generateId(): string {
46
59
  if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {
47
60
  return crypto.randomUUID();
@@ -111,6 +124,9 @@
111
124
  }
112
125
  ];
113
126
 
127
+ const label = getLocalizedLabel(field.label, interfaceLanguage.current) || field.slug;
128
+ announce(`${at.added}: ${label}`);
129
+
114
130
  openAndCloseOthers($value.length - 1);
115
131
  }
116
132
 
@@ -122,6 +138,9 @@
122
138
  const copy = JSON.parse(JSON.stringify(itemToDuplicate));
123
139
  copy._id = generateId();
124
140
 
141
+ const label = getAccordionLabel(itemToDuplicate) || `${index + 1}`;
142
+ announce(`${at.duplicated}: ${label}`);
143
+
125
144
  $value = [...$value.slice(0, index + 1), copy, ...$value.slice(index + 1)];
126
145
 
127
146
  tick().then(() => {
@@ -131,10 +150,13 @@
131
150
 
132
151
  function moveItemUp(index: number) {
133
152
  if (!$value || index <= 0) return;
153
+ const label = getAccordionLabel($value[index]) || `${index + 1}`;
134
154
  const newValue = [...$value];
135
155
  [newValue[index - 1], newValue[index]] = [newValue[index], newValue[index - 1]];
136
156
  $value = newValue;
137
157
 
158
+ announce(`${label}: ${at.movedTo} ${index}`);
159
+
138
160
  tick().then(() => {
139
161
  openAndCloseOthers(index - 1);
140
162
  });
@@ -142,10 +164,13 @@
142
164
 
143
165
  function moveItemDown(index: number) {
144
166
  if (!$value || index >= $value.length - 1) return;
167
+ const label = getAccordionLabel($value[index]) || `${index + 1}`;
145
168
  const newValue = [...$value];
146
169
  [newValue[index], newValue[index + 1]] = [newValue[index + 1], newValue[index]];
147
170
  $value = newValue;
148
171
 
172
+ announce(`${label}: ${at.movedTo} ${index + 2}`);
173
+
149
174
  tick().then(() => {
150
175
  openAndCloseOthers(index + 1);
151
176
  });
@@ -155,8 +180,11 @@
155
180
 
156
181
  function moveItem(from: number, to: number) {
157
182
  if (!$value || from === to) return;
183
+ const label = getAccordionLabel($value[from]) || `${from + 1}`;
158
184
  $value = arrayMove($value, from, to);
159
185
 
186
+ announce(`${label}: ${at.movedTo} ${to + 1}`);
187
+
160
188
  tick().then(() => {
161
189
  openAndCloseOthers(to);
162
190
  });
@@ -165,8 +193,11 @@
165
193
  function removeItem(index: number) {
166
194
  if (!$value) return;
167
195
 
196
+ const label = getAccordionLabel($value[index]) || `${index + 1}`;
168
197
  accordionOpenState = accordionOpenState.filter((i) => i !== index.toString());
169
198
  $value = $value.filter((_, i) => i !== index);
199
+
200
+ announce(`${at.removed}: ${label}`);
170
201
  }
171
202
 
172
203
  function getAccordionLabel(item: ObjectFieldData) {
@@ -394,7 +425,19 @@
394
425
  {/if}
395
426
  </div>
396
427
  </Accordion.Trigger>
397
- <Accordion.Content class="space-y-4 rounded-b-md border border-t-0 bg-card/80 p-4">
428
+ <!--
429
+ forceMount keeps nested block fields in the DOM when
430
+ closed (so scroll-to-issue can find them and
431
+ activateContainingAccordions can auto-expand them).
432
+ accordion-content.svelte collapses forceMount content
433
+ with a grid-template-rows transition — animated both
434
+ ways, and it holds the collapsed state (the one-shot
435
+ keyframe cannot once the panel stays mounted).
436
+ -->
437
+ <Accordion.Content
438
+ forceMount
439
+ class="space-y-4 rounded-b-md border border-t-0 bg-card/80 p-4"
440
+ >
398
441
  {@const itemPath = joinPath(path, index)}
399
442
  <div data-field-path={itemPath}>
400
443
  <FieldRenderer
@@ -460,3 +503,5 @@
460
503
  </div>
461
504
  {/if}
462
505
  {/if}
506
+
507
+ <LiveRegion message={announcement} />
@@ -43,6 +43,6 @@
43
43
  </span>
44
44
  {/if}
45
45
  </div>
46
- <Switch bind:checked={value} aria-label={label} />
46
+ <Switch bind:checked={value} aria-label={label} {...props} />
47
47
  </div>
48
48
  {/if}
@@ -39,7 +39,9 @@
39
39
  const { value } = formFieldProxy(form, path) as { value: import('svelte/store').Writable<any> };
40
40
 
41
41
  const fieldsWithNoDescription: FieldType[] = ['boolean', 'object', 'blocks', 'seo', 'shop'];
42
- const fieldsWithNoLabel: FieldType[] = ['boolean', 'object', 'blocks', 'seo', 'shop'];
42
+ // 'slug' renders its own label paired with the Auto toggle (flex header),
43
+ // so the field-renderer must not duplicate it.
44
+ const fieldsWithNoLabel: FieldType[] = ['boolean', 'object', 'blocks', 'seo', 'shop', 'slug'];
43
45
 
44
46
  const fieldsWithAlternativeDescription: FieldType[] = ['media', 'object', 'blocks'];
45
47
 
@@ -102,10 +104,10 @@
102
104
  <Form.FieldErrors />
103
105
  </Form.Fieldset>
104
106
  {:else if isTextField(field)}
105
- <Form.Field {form} name={path} class="space-y-0">
106
- <TextFieldWrapper {field} {form} {path} {...props} />
107
- <Form.FieldErrors />
108
- </Form.Field>
107
+ <!-- TextFieldWrapper is self-contained (own Form.Field + Form.FieldErrors).
108
+ Wrapping it again here produced a nested form-item and a duplicated
109
+ error message (QA 5a #1c). -->
110
+ <TextFieldWrapper {field} {form} {path} {...props} />
109
111
  {:else}
110
112
  <Form.Field {form} name={path}>
111
113
  <Form.Control>
@@ -123,46 +125,46 @@
123
125
 
124
126
  {#if field.type === 'media'}
125
127
  {#await import('./media-field.svelte') then { default: MediaField }}
126
- <MediaField {field} bind:value={$value} />
128
+ <MediaField {field} bind:value={$value} {...props} />
127
129
  {/await}
128
130
  {:else if field.type === 'file'}
129
131
  {#await import('./file-field.svelte') then { default: FileField }}
130
- <FileField {field} bind:value={$value} />
132
+ <FileField {field} bind:value={$value} {...props} />
131
133
  {/await}
132
134
  {:else if field.type === 'blocks'}
133
- <LazyField loader={() => import('./blocks-field.svelte')} props={{ field, form, path, focusedPath, flashingPath, depth }} skeletonClass="h-20" />
135
+ <LazyField loader={() => import('./blocks-field.svelte')} props={{ field, form, path, focusedPath, flashingPath, depth, ...props }} skeletonClass="h-20" />
134
136
  {:else if field.type === 'array'}
135
137
  {#await import('./simple-array-field.svelte') then { default: ArrayField }}
136
- <ArrayField {field} bind:value={$value} />
138
+ <ArrayField {field} bind:value={$value} {form} {path} {...props} />
137
139
  {/await}
138
140
  {:else if field.type === 'object'}
139
- <LazyField loader={() => import('./object-field.svelte')} props={{ field, form, path, objectFieldType: distributed ? 'distributed' : objectFieldType, focusedPath, flashingPath, depth }} skeletonClass="h-20" />
141
+ <LazyField loader={() => import('./object-field.svelte')} props={{ field, form, path, objectFieldType: distributed ? 'distributed' : objectFieldType, focusedPath, flashingPath, depth, ...props }} skeletonClass="h-20" />
140
142
  {:else if field.type === 'slug'}
141
- <LazyField loader={() => import('./slug-field.svelte')} props={{ field, form, path }} skeletonClass="h-10" />
143
+ <LazyField loader={() => import('./slug-field.svelte')} props={{ field, form, path, ...props }} skeletonClass="h-10" />
142
144
  {:else if field.type === 'boolean'}
143
- <BooleanField {field} bind:value={$value} />
145
+ <BooleanField {field} bind:value={$value} {...props} />
144
146
  {:else if field.type === 'number'}
145
- <NumberField {field} bind:value={$value} />
147
+ <NumberField {field} bind:value={$value} {...props} />
146
148
  {:else if field.type === 'seo'}
147
- <LazyField loader={() => import('./seo-field.svelte')} props={{ field, form, path }} skeletonClass="h-16" />
149
+ <LazyField loader={() => import('./seo-field.svelte')} props={{ field, form, path, ...props }} skeletonClass="h-16" />
148
150
  {:else if field.type === 'shop'}
149
- <LazyField loader={() => import('./shop-field.svelte')} props={{ field }} skeletonClass="h-40" />
151
+ <LazyField loader={() => import('./shop-field.svelte')} props={{ field, ...props }} skeletonClass="h-40" />
150
152
  {:else if field.type === 'url'}
151
- <UrlFieldWrapper {field} {form} {path} />
153
+ <UrlFieldWrapper {field} {form} {path} {...props} />
152
154
  {:else if field.type === 'relation'}
153
155
  {#await import('./relation-field.svelte') then { default: RelationField }}
154
- <RelationField {field} bind:value={$value} />
156
+ <RelationField {field} bind:value={$value} {...props} />
155
157
  {/await}
156
158
  {:else if field.type === 'date'}
157
- <DateField {field} bind:value={$value} />
159
+ <DateField {field} bind:value={$value} {...props} />
158
160
  {:else if field.type === 'datetime'}
159
- <DateTimeField {field} bind:value={$value} />
161
+ <DateTimeField {field} bind:value={$value} {...props} />
160
162
  {:else if field.type === 'select'}
161
- <SelectField {field} bind:value={$value} />
163
+ <SelectField {field} bind:value={$value} {...props} />
162
164
  {:else if field.type === 'custom'}
163
165
  {@const customDef = customFieldDefs.get(field.fieldType)}
164
166
  {#if customDef}
165
- <LazyField loader={customDef.component} props={{ field, form, path }} skeletonClass="h-20" />
167
+ <LazyField loader={customDef.component} props={{ field, form, path, ...props }} skeletonClass="h-20" />
166
168
  {:else}
167
169
  <p>Nieznany custom field: {field.fieldType}</p>
168
170
  {/if}