@xiwebdesign/xicms-core 7.31.0 → 8.16.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 (482) hide show
  1. package/dist/XiCMSProvider.js +23 -7
  2. package/dist/XiCMSProvider.js.map +1 -1
  3. package/dist/admin/AdminApp.js +175 -93
  4. package/dist/admin/AdminApp.js.map +1 -1
  5. package/dist/admin/AdminHelp.d.ts +1 -1
  6. package/dist/admin/AdminHelp.js +44 -36
  7. package/dist/admin/AdminHelp.js.map +1 -1
  8. package/dist/admin/CoreVersion.d.ts +6 -3
  9. package/dist/admin/CoreVersion.js +60 -24
  10. package/dist/admin/CoreVersion.js.map +1 -1
  11. package/dist/admin/NewsEditor.d.ts +7 -0
  12. package/dist/admin/NewsEditor.js +117 -75
  13. package/dist/admin/NewsEditor.js.map +1 -1
  14. package/dist/admin/SuperadminPanel.js +1 -1
  15. package/dist/admin/SuperadminPanel.js.map +1 -1
  16. package/dist/admin/ZoekPalet.d.ts +15 -0
  17. package/dist/admin/ZoekPalet.js +123 -0
  18. package/dist/admin/ZoekPalet.js.map +1 -0
  19. package/dist/admin/blockEditors/GenericEditor.js +36 -18
  20. package/dist/admin/blockEditors/GenericEditor.js.map +1 -1
  21. package/dist/admin/blockEditors/StyleEditor.js +37 -3
  22. package/dist/admin/blockEditors/StyleEditor.js.map +1 -1
  23. package/dist/admin/blockEditors/SymbolRefEditor.js +44 -2
  24. package/dist/admin/blockEditors/SymbolRefEditor.js.map +1 -1
  25. package/dist/admin/blockEditors/index.js +154 -73
  26. package/dist/admin/blockEditors/index.js.map +1 -1
  27. package/dist/admin/customBlocks/CustomBlocksPanel.js +18 -7
  28. package/dist/admin/customBlocks/CustomBlocksPanel.js.map +1 -1
  29. package/dist/admin/dashboard/DashboardPanel.js +26 -16
  30. package/dist/admin/dashboard/DashboardPanel.js.map +1 -1
  31. package/dist/admin/editors/RichTextEditor.d.ts +4 -3
  32. package/dist/admin/editors/RichTextEditor.js +19 -60
  33. package/dist/admin/editors/RichTextEditor.js.map +1 -1
  34. package/dist/admin/editors/fontSizeExtension.js +7 -1
  35. package/dist/admin/editors/fontSizeExtension.js.map +1 -1
  36. package/dist/admin/editors/slashMenu.d.ts +18 -0
  37. package/dist/admin/editors/slashMenu.js +34 -0
  38. package/dist/admin/editors/slashMenu.js.map +1 -0
  39. package/dist/admin/editors/useRijkeTekst.d.ts +48 -0
  40. package/dist/admin/editors/useRijkeTekst.js +310 -0
  41. package/dist/admin/editors/useRijkeTekst.js.map +1 -0
  42. package/dist/admin/forms/FormsPanel.d.ts +11 -2
  43. package/dist/admin/forms/FormsPanel.js +218 -65
  44. package/dist/admin/forms/FormsPanel.js.map +1 -1
  45. package/dist/admin/lib/blokInfo.d.ts +17 -0
  46. package/dist/admin/lib/blokInfo.js +80 -0
  47. package/dist/admin/lib/blokInfo.js.map +1 -0
  48. package/dist/admin/lib/foutNaarMens.d.ts +1 -0
  49. package/dist/admin/lib/foutNaarMens.js +22 -0
  50. package/dist/admin/lib/foutNaarMens.js.map +1 -0
  51. package/dist/admin/lib/gewisteVelden.d.ts +13 -0
  52. package/dist/admin/lib/gewisteVelden.js +31 -0
  53. package/dist/admin/lib/gewisteVelden.js.map +1 -0
  54. package/dist/admin/lib/heroHulp.d.ts +11 -0
  55. package/dist/admin/lib/heroHulp.js +18 -0
  56. package/dist/admin/lib/heroHulp.js.map +1 -0
  57. package/dist/admin/lib/kleur.js +2 -3
  58. package/dist/admin/lib/kleur.js.map +1 -1
  59. package/dist/admin/lib/leesbaarheid.d.ts +34 -0
  60. package/dist/admin/lib/leesbaarheid.js +82 -0
  61. package/dist/admin/lib/leesbaarheid.js.map +1 -0
  62. package/dist/admin/lib/lengteAdvies.d.ts +1 -0
  63. package/dist/admin/lib/lengteAdvies.js +16 -0
  64. package/dist/admin/lib/lengteAdvies.js.map +1 -0
  65. package/dist/admin/lib/mediaLijst.d.ts +26 -0
  66. package/dist/admin/lib/mediaLijst.js +42 -0
  67. package/dist/admin/lib/mediaLijst.js.map +1 -0
  68. package/dist/admin/lib/mediaUsage.d.ts +12 -1
  69. package/dist/admin/lib/mediaUsage.js +43 -33
  70. package/dist/admin/lib/mediaUsage.js.map +1 -1
  71. package/dist/admin/lib/menuHulp.d.ts +16 -0
  72. package/dist/admin/lib/menuHulp.js +41 -0
  73. package/dist/admin/lib/menuHulp.js.map +1 -0
  74. package/dist/admin/lib/onopgeslagen.d.ts +10 -0
  75. package/dist/admin/lib/onopgeslagen.js +35 -0
  76. package/dist/admin/lib/onopgeslagen.js.map +1 -0
  77. package/dist/admin/lib/pagesClient.d.ts +55 -2
  78. package/dist/admin/lib/pagesClient.js +126 -28
  79. package/dist/admin/lib/pagesClient.js.map +1 -1
  80. package/dist/admin/lib/paginaGebruik.d.ts +56 -0
  81. package/dist/admin/lib/paginaGebruik.js +109 -0
  82. package/dist/admin/lib/paginaGebruik.js.map +1 -0
  83. package/dist/admin/lib/publicatieCheck.d.ts +25 -0
  84. package/dist/admin/lib/publicatieCheck.js +114 -0
  85. package/dist/admin/lib/publicatieCheck.js.map +1 -0
  86. package/dist/admin/lib/scrollNaarDetail.d.ts +6 -0
  87. package/dist/admin/lib/scrollNaarDetail.js +20 -0
  88. package/dist/admin/lib/scrollNaarDetail.js.map +1 -0
  89. package/dist/admin/lib/symbolsClient.d.ts +10 -0
  90. package/dist/admin/lib/symbolsClient.js +14 -1
  91. package/dist/admin/lib/symbolsClient.js.map +1 -1
  92. package/dist/admin/lib/tekstVeld.d.ts +8 -0
  93. package/dist/admin/lib/tekstVeld.js +10 -0
  94. package/dist/admin/lib/tekstVeld.js.map +1 -0
  95. package/dist/admin/lib/useIsSuperadmin.d.ts +2 -0
  96. package/dist/admin/lib/useIsSuperadmin.js +13 -0
  97. package/dist/admin/lib/useIsSuperadmin.js.map +1 -0
  98. package/dist/admin/lib/veldTaal.d.ts +14 -0
  99. package/dist/admin/lib/veldTaal.js +248 -0
  100. package/dist/admin/lib/veldTaal.js.map +1 -0
  101. package/dist/admin/lib/versieVergelijk.d.ts +17 -0
  102. package/dist/admin/lib/versieVergelijk.js +24 -0
  103. package/dist/admin/lib/versieVergelijk.js.map +1 -0
  104. package/dist/admin/lib/zodFields.js +22 -4
  105. package/dist/admin/lib/zodFields.js.map +1 -1
  106. package/dist/admin/lib/zodFout.d.ts +9 -0
  107. package/dist/admin/lib/zodFout.js +63 -0
  108. package/dist/admin/lib/zodFout.js.map +1 -0
  109. package/dist/admin/media/MediaManager.js +162 -32
  110. package/dist/admin/media/MediaManager.js.map +1 -1
  111. package/dist/admin/media/MediaPicker.d.ts +3 -0
  112. package/dist/admin/media/MediaPicker.js +84 -31
  113. package/dist/admin/media/MediaPicker.js.map +1 -1
  114. package/dist/admin/menu/MenuPanel.js +144 -83
  115. package/dist/admin/menu/MenuPanel.js.map +1 -1
  116. package/dist/admin/navContext.d.ts +3 -0
  117. package/dist/admin/navContext.js +13 -1
  118. package/dist/admin/navContext.js.map +1 -1
  119. package/dist/admin/pages/PageEditor.js +146 -30
  120. package/dist/admin/pages/PageEditor.js.map +1 -1
  121. package/dist/admin/pages/PagesPanel.js +215 -61
  122. package/dist/admin/pages/PagesPanel.js.map +1 -1
  123. package/dist/admin/pages/StarterKiezer.d.ts +12 -0
  124. package/dist/admin/pages/StarterKiezer.js +113 -0
  125. package/dist/admin/pages/StarterKiezer.js.map +1 -0
  126. package/dist/admin/panelRegistry.d.ts +1 -1
  127. package/dist/admin/panelRegistry.js +2 -1
  128. package/dist/admin/panelRegistry.js.map +1 -1
  129. package/dist/admin/patterns/PatternInserter.js +1 -1
  130. package/dist/admin/patterns/PatternInserter.js.map +1 -1
  131. package/dist/admin/settings/BedrijfInstellingen.d.ts +20 -0
  132. package/dist/admin/settings/BedrijfInstellingen.js +159 -0
  133. package/dist/admin/settings/BedrijfInstellingen.js.map +1 -0
  134. package/dist/admin/settings/MailTemplates.js +5 -4
  135. package/dist/admin/settings/MailTemplates.js.map +1 -1
  136. package/dist/admin/settings/SettingsPanel.js +120 -78
  137. package/dist/admin/settings/SettingsPanel.js.map +1 -1
  138. package/dist/admin/settings/SnapshotsCard.js +4 -4
  139. package/dist/admin/settings/SnapshotsCard.js.map +1 -1
  140. package/dist/admin/settings/VorigeTerugzetten.d.ts +15 -0
  141. package/dist/admin/settings/VorigeTerugzetten.js +89 -0
  142. package/dist/admin/settings/VorigeTerugzetten.js.map +1 -0
  143. package/dist/admin/shop/CategoriesTab.js +6 -4
  144. package/dist/admin/shop/CategoriesTab.js.map +1 -1
  145. package/dist/admin/shop/DiscountsTab.js +4 -2
  146. package/dist/admin/shop/DiscountsTab.js.map +1 -1
  147. package/dist/admin/shop/OrdersTab.js +57 -19
  148. package/dist/admin/shop/OrdersTab.js.map +1 -1
  149. package/dist/admin/shop/ProductPaneel.js +2 -1
  150. package/dist/admin/shop/ProductPaneel.js.map +1 -1
  151. package/dist/admin/shop/ProductsTab.js +40 -19
  152. package/dist/admin/shop/ProductsTab.js.map +1 -1
  153. package/dist/admin/shop/ShopPanel.js +13 -1
  154. package/dist/admin/shop/ShopPanel.js.map +1 -1
  155. package/dist/admin/shop/ShopSettingsTab.js +56 -17
  156. package/dist/admin/shop/ShopSettingsTab.js.map +1 -1
  157. package/dist/admin/shop/productClient.js +7 -3
  158. package/dist/admin/shop/productClient.js.map +1 -1
  159. package/dist/admin/stats/NietGevonden.d.ts +10 -0
  160. package/dist/admin/stats/NietGevonden.js +78 -0
  161. package/dist/admin/stats/NietGevonden.js.map +1 -0
  162. package/dist/admin/stats/StatsPanel.js +6 -1
  163. package/dist/admin/stats/StatsPanel.js.map +1 -1
  164. package/dist/admin/stats/lib.d.ts +2 -0
  165. package/dist/admin/stats/lib.js.map +1 -1
  166. package/dist/admin/ui/ConfirmDialog.js +10 -1
  167. package/dist/admin/ui/ConfirmDialog.js.map +1 -1
  168. package/dist/admin/ui/Icon.d.ts +34 -0
  169. package/dist/admin/ui/Icon.js +44 -0
  170. package/dist/admin/ui/Icon.js.map +1 -0
  171. package/dist/admin/ui/ImageField.d.ts +15 -0
  172. package/dist/admin/ui/ImageField.js +67 -0
  173. package/dist/admin/ui/ImageField.js.map +1 -0
  174. package/dist/admin/ui/KleurVeld.d.ts +25 -0
  175. package/dist/admin/ui/KleurVeld.js +76 -0
  176. package/dist/admin/ui/KleurVeld.js.map +1 -0
  177. package/dist/admin/ui/LaadStaat.d.ts +21 -0
  178. package/dist/admin/ui/LaadStaat.js +43 -0
  179. package/dist/admin/ui/LaadStaat.js.map +1 -0
  180. package/dist/admin/ui/LeesbaarheidPaneel.d.ts +10 -0
  181. package/dist/admin/ui/LeesbaarheidPaneel.js +68 -0
  182. package/dist/admin/ui/LeesbaarheidPaneel.js.map +1 -0
  183. package/dist/admin/ui/LinkDialog.d.ts +22 -0
  184. package/dist/admin/ui/LinkDialog.js +131 -0
  185. package/dist/admin/ui/LinkDialog.js.map +1 -0
  186. package/dist/admin/ui/LinkVeld.d.ts +14 -0
  187. package/dist/admin/ui/LinkVeld.js +49 -0
  188. package/dist/admin/ui/LinkVeld.js.map +1 -0
  189. package/dist/admin/ui/PreviewLinkResultaat.d.ts +14 -0
  190. package/dist/admin/ui/PreviewLinkResultaat.js +52 -0
  191. package/dist/admin/ui/PreviewLinkResultaat.js.map +1 -0
  192. package/dist/admin/ui/charts.js +5 -5
  193. package/dist/admin/ui/charts.js.map +1 -1
  194. package/dist/admin/ui/primitives.d.ts +16 -6
  195. package/dist/admin/ui/primitives.js +98 -26
  196. package/dist/admin/ui/primitives.js.map +1 -1
  197. package/dist/admin/ui/select.js +5 -2
  198. package/dist/admin/ui/select.js.map +1 -1
  199. package/dist/admin/ui/switch.d.ts +3 -1
  200. package/dist/admin/ui/switch.js +6 -3
  201. package/dist/admin/ui/switch.js.map +1 -1
  202. package/dist/admin/ui/toast.d.ts +2 -1
  203. package/dist/admin/ui/toast.js +17 -11
  204. package/dist/admin/ui/toast.js.map +1 -1
  205. package/dist/admin/visual/BlokKiezer.d.ts +34 -0
  206. package/dist/admin/visual/BlokKiezer.js +225 -0
  207. package/dist/admin/visual/BlokKiezer.js.map +1 -0
  208. package/dist/admin/visual/InlineGereedschap.d.ts +52 -0
  209. package/dist/admin/visual/InlineGereedschap.js +356 -0
  210. package/dist/admin/visual/InlineGereedschap.js.map +1 -0
  211. package/dist/admin/visual/InlineRijkeTekst.d.ts +23 -0
  212. package/dist/admin/visual/InlineRijkeTekst.js +152 -0
  213. package/dist/admin/visual/InlineRijkeTekst.js.map +1 -0
  214. package/dist/admin/visual/VisualEditor.js +273 -125
  215. package/dist/admin/visual/VisualEditor.js.map +1 -1
  216. package/dist/admin.css +1 -1
  217. package/dist/auth/AuthProvider.js +1 -0
  218. package/dist/auth/AuthProvider.js.map +1 -1
  219. package/dist/bedrijf/bedrijf.d.ts +44 -0
  220. package/dist/bedrijf/bedrijf.js +125 -0
  221. package/dist/bedrijf/bedrijf.js.map +1 -0
  222. package/dist/blocks/BlockRenderer.js +11 -1
  223. package/dist/blocks/BlockRenderer.js.map +1 -1
  224. package/dist/blocks/blockStyle.d.ts +7 -0
  225. package/dist/blocks/blockStyle.js +16 -3
  226. package/dist/blocks/blockStyle.js.map +1 -1
  227. package/dist/blocks/builtinSchemas.js +6 -0
  228. package/dist/blocks/builtinSchemas.js.map +1 -1
  229. package/dist/blocks/builtins/AgendaRender.d.ts +22 -0
  230. package/dist/blocks/builtins/AgendaRender.js +69 -9
  231. package/dist/blocks/builtins/AgendaRender.js.map +1 -1
  232. package/dist/blocks/builtins/Availability.d.ts +1 -0
  233. package/dist/blocks/builtins/Availability.js +23 -0
  234. package/dist/blocks/builtins/Availability.js.map +1 -0
  235. package/dist/blocks/builtins/AvailabilityRender.d.ts +12 -0
  236. package/dist/blocks/builtins/AvailabilityRender.js +105 -0
  237. package/dist/blocks/builtins/AvailabilityRender.js.map +1 -0
  238. package/dist/blocks/builtins/BeforeAfterRender.js +4 -3
  239. package/dist/blocks/builtins/BeforeAfterRender.js.map +1 -1
  240. package/dist/blocks/builtins/Booking.js +1 -1
  241. package/dist/blocks/builtins/Booking.js.map +1 -1
  242. package/dist/blocks/builtins/BreadcrumbsRender.d.ts +4 -3
  243. package/dist/blocks/builtins/BreadcrumbsRender.js +14 -8
  244. package/dist/blocks/builtins/BreadcrumbsRender.js.map +1 -1
  245. package/dist/blocks/builtins/ColumnsRender.d.ts +1 -1
  246. package/dist/blocks/builtins/ColumnsRender.js +3 -1
  247. package/dist/blocks/builtins/ColumnsRender.js.map +1 -1
  248. package/dist/blocks/builtins/Contact.js +1 -1
  249. package/dist/blocks/builtins/Contact.js.map +1 -1
  250. package/dist/blocks/builtins/ContactRender.d.ts +1 -1
  251. package/dist/blocks/builtins/ContactRender.js +37 -8
  252. package/dist/blocks/builtins/ContactRender.js.map +1 -1
  253. package/dist/blocks/builtins/Cta.js +1 -1
  254. package/dist/blocks/builtins/Cta.js.map +1 -1
  255. package/dist/blocks/builtins/CtaRender.d.ts +1 -1
  256. package/dist/blocks/builtins/CtaRender.js +5 -4
  257. package/dist/blocks/builtins/CtaRender.js.map +1 -1
  258. package/dist/blocks/builtins/Embed.js +1 -1
  259. package/dist/blocks/builtins/Embed.js.map +1 -1
  260. package/dist/blocks/builtins/FormBlock.js +1 -0
  261. package/dist/blocks/builtins/FormBlock.js.map +1 -1
  262. package/dist/blocks/builtins/FormBlockRender.d.ts +6 -0
  263. package/dist/blocks/builtins/FormBlockRender.js +88 -16
  264. package/dist/blocks/builtins/FormBlockRender.js.map +1 -1
  265. package/dist/blocks/builtins/GalleryRender.js +3 -2
  266. package/dist/blocks/builtins/GalleryRender.js.map +1 -1
  267. package/dist/blocks/builtins/Hero.js +1 -1
  268. package/dist/blocks/builtins/Hero.js.map +1 -1
  269. package/dist/blocks/builtins/HeroRender.js +7 -3
  270. package/dist/blocks/builtins/HeroRender.js.map +1 -1
  271. package/dist/blocks/builtins/OpenNowBadge.d.ts +4 -2
  272. package/dist/blocks/builtins/OpenNowBadge.js +6 -6
  273. package/dist/blocks/builtins/OpenNowBadge.js.map +1 -1
  274. package/dist/blocks/builtins/OpeningHoursRender.d.ts +8 -2
  275. package/dist/blocks/builtins/OpeningHoursRender.js +27 -6
  276. package/dist/blocks/builtins/OpeningHoursRender.js.map +1 -1
  277. package/dist/blocks/builtins/PriceList.d.ts +1 -0
  278. package/dist/blocks/builtins/PriceList.js +25 -0
  279. package/dist/blocks/builtins/PriceList.js.map +1 -0
  280. package/dist/blocks/builtins/PriceListRender.d.ts +17 -0
  281. package/dist/blocks/builtins/PriceListRender.js +87 -0
  282. package/dist/blocks/builtins/PriceListRender.js.map +1 -0
  283. package/dist/blocks/builtins/RichTextBlockRender.js +6 -1
  284. package/dist/blocks/builtins/RichTextBlockRender.js.map +1 -1
  285. package/dist/blocks/builtins/SectionHeading.d.ts +1 -0
  286. package/dist/blocks/builtins/SectionHeading.js +14 -0
  287. package/dist/blocks/builtins/SectionHeading.js.map +1 -0
  288. package/dist/blocks/builtins/SectionHeadingRender.d.ts +7 -0
  289. package/dist/blocks/builtins/SectionHeadingRender.js +14 -0
  290. package/dist/blocks/builtins/SectionHeadingRender.js.map +1 -0
  291. package/dist/blocks/builtins/SliderRender.js +3 -2
  292. package/dist/blocks/builtins/SliderRender.js.map +1 -1
  293. package/dist/blocks/builtins/SymbolRef.js +1 -1
  294. package/dist/blocks/builtins/SymbolRef.js.map +1 -1
  295. package/dist/blocks/builtins/TeamRender.js +6 -1
  296. package/dist/blocks/builtins/TeamRender.js.map +1 -1
  297. package/dist/blocks/builtins/Testimonials.js +3 -1
  298. package/dist/blocks/builtins/Testimonials.js.map +1 -1
  299. package/dist/blocks/builtins/TestimonialsRender.js +4 -0
  300. package/dist/blocks/builtins/TestimonialsRender.js.map +1 -1
  301. package/dist/blocks/builtins/WhatsappChatRender.d.ts +1 -1
  302. package/dist/blocks/builtins/WhatsappChatRender.js +3 -1
  303. package/dist/blocks/builtins/WhatsappChatRender.js.map +1 -1
  304. package/dist/blocks/builtins/Widgets.js +2 -2
  305. package/dist/blocks/builtins/Widgets.js.map +1 -1
  306. package/dist/blocks/builtins/WidgetsRender.js +3 -1
  307. package/dist/blocks/builtins/WidgetsRender.js.map +1 -1
  308. package/dist/blocks/builtins/consentEmbed.js +26 -9
  309. package/dist/blocks/builtins/consentEmbed.js.map +1 -1
  310. package/dist/blocks/builtins/index.d.ts +3 -0
  311. package/dist/blocks/builtins/index.js +6 -0
  312. package/dist/blocks/builtins/index.js.map +1 -1
  313. package/dist/blocks/builtins/lib/autoComplete.d.ts +7 -0
  314. package/dist/blocks/builtins/lib/autoComplete.js +20 -0
  315. package/dist/blocks/builtins/lib/autoComplete.js.map +1 -0
  316. package/dist/blocks/builtins/lib/bookingUrl.d.ts +2 -2
  317. package/dist/blocks/builtins/lib/bookingUrl.js +1 -1
  318. package/dist/blocks/builtins/lib/bookingUrl.js.map +1 -1
  319. package/dist/blocks/builtins/lib/ical.d.ts +24 -0
  320. package/dist/blocks/builtins/lib/ical.js +82 -0
  321. package/dist/blocks/builtins/lib/ical.js.map +1 -0
  322. package/dist/blocks/builtins/lib/vandaag.d.ts +8 -0
  323. package/dist/blocks/builtins/lib/vandaag.js +22 -0
  324. package/dist/blocks/builtins/lib/vandaag.js.map +1 -0
  325. package/dist/blocks/registry.d.ts +6 -0
  326. package/dist/blocks/registry.js.map +1 -1
  327. package/dist/blocks/ui/index.js +1 -0
  328. package/dist/blocks/ui/index.js.map +1 -1
  329. package/dist/components/EditBar.js +2 -4
  330. package/dist/components/EditBar.js.map +1 -1
  331. package/dist/components/News.js +26 -18
  332. package/dist/components/News.js.map +1 -1
  333. package/dist/components/PageView.d.ts +7 -1
  334. package/dist/components/PageView.js +17 -0
  335. package/dist/components/PageView.js.map +1 -1
  336. package/dist/components/ResponsiveImage.js +18 -20
  337. package/dist/components/ResponsiveImage.js.map +1 -1
  338. package/dist/components/onderOffset.d.ts +13 -0
  339. package/dist/components/onderOffset.js +74 -0
  340. package/dist/components/onderOffset.js.map +1 -0
  341. package/dist/components/site/Bedrijfsnummers.d.ts +9 -0
  342. package/dist/components/site/Bedrijfsnummers.js +12 -0
  343. package/dist/components/site/Bedrijfsnummers.js.map +1 -0
  344. package/dist/components/site/SiteFooter.d.ts +6 -1
  345. package/dist/components/site/SiteFooter.js +62 -9
  346. package/dist/components/site/SiteFooter.js.map +1 -1
  347. package/dist/components/site/SiteHeader.d.ts +15 -0
  348. package/dist/components/site/SiteHeader.js +70 -0
  349. package/dist/components/site/SiteHeader.js.map +1 -0
  350. package/dist/components/site/SiteNav.d.ts +2 -0
  351. package/dist/components/site/SiteNav.js +29 -5
  352. package/dist/components/site/SiteNav.js.map +1 -1
  353. package/dist/demo/DemoStudio.js +2 -2
  354. package/dist/demo/DemoStudio.js.map +1 -1
  355. package/dist/demo/demoStore.d.ts +13 -0
  356. package/dist/demo/demoStore.js +36 -0
  357. package/dist/demo/demoStore.js.map +1 -1
  358. package/dist/editor/EditorProvider.js +15 -4
  359. package/dist/editor/EditorProvider.js.map +1 -1
  360. package/dist/firebase/functionsClient.js +5 -1
  361. package/dist/firebase/functionsClient.js.map +1 -1
  362. package/dist/index.d.ts +5 -1
  363. package/dist/index.js +20 -1
  364. package/dist/index.js.map +1 -1
  365. package/dist/media/ImageContext.d.ts +17 -0
  366. package/dist/media/ImageContext.js +65 -20
  367. package/dist/media/ImageContext.js.map +1 -1
  368. package/dist/media/altInHtml.d.ts +9 -0
  369. package/dist/media/altInHtml.js +17 -0
  370. package/dist/media/altInHtml.js.map +1 -0
  371. package/dist/media/srcset.d.ts +12 -0
  372. package/dist/media/srcset.js +13 -0
  373. package/dist/media/srcset.js.map +1 -0
  374. package/dist/modules/builtins.d.ts +1 -0
  375. package/dist/modules/builtins.js +22 -9
  376. package/dist/modules/builtins.js.map +1 -1
  377. package/dist/modules/consent/ConsentBanner.d.ts +5 -0
  378. package/dist/modules/consent/ConsentBanner.js +8 -7
  379. package/dist/modules/consent/ConsentBanner.js.map +1 -1
  380. package/dist/modules/consent/standaard.d.ts +12 -0
  381. package/dist/modules/consent/standaard.js +10 -0
  382. package/dist/modules/consent/standaard.js.map +1 -0
  383. package/dist/modules/consent/useConsent.d.ts +4 -0
  384. package/dist/modules/consent/useConsent.js +30 -1
  385. package/dist/modules/consent/useConsent.js.map +1 -1
  386. package/dist/modules/shop/blocks/Cart.js +5 -3
  387. package/dist/modules/shop/blocks/Cart.js.map +1 -1
  388. package/dist/modules/shop/blocks/Checkout.js +56 -35
  389. package/dist/modules/shop/blocks/Checkout.js.map +1 -1
  390. package/dist/modules/shop/blocks/Donation.js +4 -4
  391. package/dist/modules/shop/blocks/Donation.js.map +1 -1
  392. package/dist/modules/shop/blocks/ProductDetail.js +19 -3
  393. package/dist/modules/shop/blocks/ProductDetail.js.map +1 -1
  394. package/dist/modules/shop/blocks/ProductGrid.d.ts +3 -1
  395. package/dist/modules/shop/blocks/ProductGrid.js +8 -4
  396. package/dist/modules/shop/blocks/ProductGrid.js.map +1 -1
  397. package/dist/modules/shop/blocks/ShopCategories.js +4 -3
  398. package/dist/modules/shop/blocks/ShopCategories.js.map +1 -1
  399. package/dist/modules/shop/lib.d.ts +4 -0
  400. package/dist/modules/shop/lib.js +14 -0
  401. package/dist/modules/shop/lib.js.map +1 -1
  402. package/dist/modules/shop/settings.d.ts +3 -0
  403. package/dist/modules/shop/settings.js +14 -0
  404. package/dist/modules/shop/settings.js.map +1 -1
  405. package/dist/modules/shop/strings.d.ts +4 -0
  406. package/dist/modules/shop/strings.js +8 -0
  407. package/dist/modules/shop/strings.js.map +1 -1
  408. package/dist/next/envCheck.d.ts +42 -0
  409. package/dist/next/envCheck.js +106 -0
  410. package/dist/next/envCheck.js.map +1 -0
  411. package/dist/next/index.cjs +185 -2
  412. package/dist/next/index.d.ts +2 -0
  413. package/dist/next/index.js +8 -1
  414. package/dist/next/index.js.map +1 -1
  415. package/dist/next/securityHeaders.d.ts +36 -0
  416. package/dist/next/securityHeaders.js +74 -0
  417. package/dist/next/securityHeaders.js.map +1 -0
  418. package/dist/patterns/builtins.d.ts +7 -0
  419. package/dist/patterns/builtins.js +138 -3
  420. package/dist/patterns/builtins.js.map +1 -1
  421. package/dist/releaseNotes.js +148 -0
  422. package/dist/releaseNotes.js.map +1 -1
  423. package/dist/render/PublishedPage.d.ts +2 -1
  424. package/dist/render/PublishedPage.js +10 -4
  425. package/dist/render/PublishedPage.js.map +1 -1
  426. package/dist/schema/blocks.d.ts +473 -0
  427. package/dist/schema/blocks.js +105 -5
  428. package/dist/schema/blocks.js.map +1 -1
  429. package/dist/schema/business.d.ts +118 -0
  430. package/dist/schema/business.js +75 -0
  431. package/dist/schema/business.js.map +1 -0
  432. package/dist/schema/fields.d.ts +2 -1
  433. package/dist/schema/fields.js.map +1 -1
  434. package/dist/schema/forms.d.ts +18 -0
  435. package/dist/schema/forms.js +18 -3
  436. package/dist/schema/forms.js.map +1 -1
  437. package/dist/schema/mail.d.ts +10 -0
  438. package/dist/schema/mail.js +7 -0
  439. package/dist/schema/mail.js.map +1 -1
  440. package/dist/schema/settings.d.ts +103 -0
  441. package/dist/schema/settings.js +24 -3
  442. package/dist/schema/settings.js.map +1 -1
  443. package/dist/schema/shop.d.ts +2 -0
  444. package/dist/schema/shop.js +4 -0
  445. package/dist/schema/shop.js.map +1 -1
  446. package/dist/schema/shopGeld.d.ts +1 -0
  447. package/dist/schema/shopGeld.js +1 -0
  448. package/dist/schema/shopGeld.js.map +1 -1
  449. package/dist/schema/siteConfig.d.ts +69 -1
  450. package/dist/schema/siteConfig.js +7 -2
  451. package/dist/schema/siteConfig.js.map +1 -1
  452. package/dist/server/blockData.d.ts +1 -1
  453. package/dist/server/blockData.js +74 -18
  454. package/dist/server/blockData.js.map +1 -1
  455. package/dist/server/cspRapport.d.ts +20 -0
  456. package/dist/server/cspRapport.js +56 -0
  457. package/dist/server/cspRapport.js.map +1 -0
  458. package/dist/server/fonts.d.ts +3 -0
  459. package/dist/server/fonts.js +39 -0
  460. package/dist/server/fonts.js.map +1 -0
  461. package/dist/server/index.d.ts +3 -0
  462. package/dist/server/index.js +8 -0
  463. package/dist/server/index.js.map +1 -1
  464. package/dist/server/sanitize.js +2 -0
  465. package/dist/server/sanitize.js.map +1 -1
  466. package/dist/settings/useSiteSettings.js +4 -1
  467. package/dist/settings/useSiteSettings.js.map +1 -1
  468. package/dist/starters/starters.d.ts +69 -0
  469. package/dist/starters/starters.js +171 -0
  470. package/dist/starters/starters.js.map +1 -0
  471. package/dist/styles.css +1181 -212
  472. package/dist/theme/color.d.ts +10 -0
  473. package/dist/theme/color.js +17 -1
  474. package/dist/theme/color.js.map +1 -1
  475. package/dist/theme/fontFallback.d.ts +23 -0
  476. package/dist/theme/fontFallback.js +58 -0
  477. package/dist/theme/fontFallback.js.map +1 -0
  478. package/dist/theme/fonts.d.ts +11 -0
  479. package/dist/theme/fonts.js +16 -0
  480. package/dist/theme/fonts.js.map +1 -0
  481. package/dist/version.js +1 -1
  482. package/package.json +5 -4
@@ -0,0 +1,24 @@
1
+ import { bepaalWijzigingen } from "../visual/wijzigingen.js";
2
+ function vergelijkVersie(huidig, versie, labelVoor) {
3
+ const uit = [];
4
+ if ((versie.title ?? "") !== (huidig.title ?? "")) uit.push(`Titel wordt \u201C${versie.title ?? ""}\u201D (nu \u201C${huidig.title ?? ""}\u201D).`);
5
+ if ((versie.path ?? "") !== (huidig.path ?? "")) uit.push(`Adres wordt ${versie.path} (nu ${huidig.path}).`);
6
+ if ((versie.seo?.description ?? "") !== (huidig.seo?.description ?? "")) uit.push("De omschrijving voor Google is anders.");
7
+ const v = versie.blocks ?? [];
8
+ const h = huidig.blocks ?? [];
9
+ const w = bepaalWijzigingen(v, h);
10
+ const anders = v.filter((b) => w.blokken.has(String(b._key ?? "")) || w.velden.has(String(b._key ?? "")));
11
+ if (anders.length > 0) {
12
+ const namen = [...new Set(anders.map((b) => labelVoor(String(b._type ?? ""))))];
13
+ uit.push(`${anders.length === 1 ? "1 blok is" : `${anders.length} blokken zijn`} anders: ${namen.slice(0, 6).join(", ")}${namen.length > 6 ? " \u2026" : ""}.`);
14
+ }
15
+ if (w.verwijderd > 0) {
16
+ uit.push(w.verwijderd === 1 ? "1 blok dat er nu staat, verdwijnt." : `${w.verwijderd} blokken die er nu staan, verdwijnen.`);
17
+ }
18
+ if (uit.length === 0) uit.push("Deze versie is gelijk aan je huidige werkversie.");
19
+ return uit;
20
+ }
21
+ export {
22
+ vergelijkVersie
23
+ };
24
+ //# sourceMappingURL=versieVergelijk.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/admin/lib/versieVergelijk.ts"],"sourcesContent":["import { bepaalWijzigingen } from \"../visual/wijzigingen\";\n\ntype Blok = { _key?: unknown; _type?: unknown } & Record<string, unknown>;\ninterface Versie {\n title?: string;\n path?: string;\n blocks?: unknown[];\n seo?: { title?: string; description?: string };\n}\n\n/**\n * \"Wat verandert er als ik deze versie terugzet?\" (8.4) — in zinnen, vóór je op Herstellen drukt.\n * Eerst was herstellen blind: je zag alleen een datum. Bouwt op dezelfde blokvergelijking als de\n * rode markeringen in de editor (`bepaalWijzigingen`), met de versie als \"werk\" en de huidige\n * werkversie als maatstaf.\n */\nexport function vergelijkVersie(huidig: Versie, versie: Versie, labelVoor: (type: string) => string): string[] {\n const uit: string[] = [];\n if ((versie.title ?? \"\") !== (huidig.title ?? \"\")) uit.push(`Titel wordt “${versie.title ?? \"\"}” (nu “${huidig.title ?? \"\"}”).`);\n if ((versie.path ?? \"\") !== (huidig.path ?? \"\")) uit.push(`Adres wordt ${versie.path} (nu ${huidig.path}).`);\n if ((versie.seo?.description ?? \"\") !== (huidig.seo?.description ?? \"\")) uit.push(\"De omschrijving voor Google is anders.\");\n\n const v = (versie.blocks ?? []) as Blok[];\n const h = (huidig.blocks ?? []) as Blok[];\n const w = bepaalWijzigingen(v, h);\n const anders = v.filter((b) => w.blokken.has(String(b._key ?? \"\")) || w.velden.has(String(b._key ?? \"\")));\n if (anders.length > 0) {\n const namen = [...new Set(anders.map((b) => labelVoor(String(b._type ?? \"\"))))];\n uit.push(`${anders.length === 1 ? \"1 blok is\" : `${anders.length} blokken zijn`} anders: ${namen.slice(0, 6).join(\", \")}${namen.length > 6 ? \" …\" : \"\"}.`);\n }\n if (w.verwijderd > 0) {\n uit.push(w.verwijderd === 1 ? \"1 blok dat er nu staat, verdwijnt.\" : `${w.verwijderd} blokken die er nu staan, verdwijnen.`);\n }\n if (uit.length === 0) uit.push(\"Deze versie is gelijk aan je huidige werkversie.\");\n return uit;\n}\n"],"mappings":"AAAA,SAAS,yBAAyB;AAgB3B,SAAS,gBAAgB,QAAgB,QAAgB,WAA+C;AAC7G,QAAM,MAAgB,CAAC;AACvB,OAAK,OAAO,SAAS,SAAS,OAAO,SAAS,IAAK,KAAI,KAAK,qBAAgB,OAAO,SAAS,EAAE,oBAAU,OAAO,SAAS,EAAE,UAAK;AAC/H,OAAK,OAAO,QAAQ,SAAS,OAAO,QAAQ,IAAK,KAAI,KAAK,eAAe,OAAO,IAAI,QAAQ,OAAO,IAAI,IAAI;AAC3G,OAAK,OAAO,KAAK,eAAe,SAAS,OAAO,KAAK,eAAe,IAAK,KAAI,KAAK,wCAAwC;AAE1H,QAAM,IAAK,OAAO,UAAU,CAAC;AAC7B,QAAM,IAAK,OAAO,UAAU,CAAC;AAC7B,QAAM,IAAI,kBAAkB,GAAG,CAAC;AAChC,QAAM,SAAS,EAAE,OAAO,CAAC,MAAM,EAAE,QAAQ,IAAI,OAAO,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,OAAO,IAAI,OAAO,EAAE,QAAQ,EAAE,CAAC,CAAC;AACxG,MAAI,OAAO,SAAS,GAAG;AACrB,UAAM,QAAQ,CAAC,GAAG,IAAI,IAAI,OAAO,IAAI,CAAC,MAAM,UAAU,OAAO,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,CAAC;AAC9E,QAAI,KAAK,GAAG,OAAO,WAAW,IAAI,cAAc,GAAG,OAAO,MAAM,eAAe,YAAY,MAAM,MAAM,GAAG,CAAC,EAAE,KAAK,IAAI,CAAC,GAAG,MAAM,SAAS,IAAI,YAAO,EAAE,GAAG;AAAA,EAC3J;AACA,MAAI,EAAE,aAAa,GAAG;AACpB,QAAI,KAAK,EAAE,eAAe,IAAI,uCAAuC,GAAG,EAAE,UAAU,uCAAuC;AAAA,EAC7H;AACA,MAAI,IAAI,WAAW,EAAG,KAAI,KAAK,kDAAkD;AACjF,SAAO;AACT;","names":[]}
@@ -7,6 +7,15 @@ function maxLengthOf(def) {
7
7
  }
8
8
  return void 0;
9
9
  }
10
+ function grenzenVan(def) {
11
+ const uit = {};
12
+ for (const c of def?.checks ?? []) {
13
+ const rule = c?._zod?.def;
14
+ if (rule?.check === "greater_than" && typeof rule.value === "number") uit.min = rule.value;
15
+ if (rule?.check === "less_than" && typeof rule.value === "number") uit.max = rule.value;
16
+ }
17
+ return uit;
18
+ }
10
19
  const valuesOf = (def) => Object.values(def?.entries ?? {});
11
20
  function shapeOf(schema) {
12
21
  const def = defOf(schema);
@@ -20,13 +29,22 @@ function describedAs(s) {
20
29
  function unwrap(schema) {
21
30
  let s = schema;
22
31
  let description = describedAs(s);
32
+ let standaard;
23
33
  for (; ; ) {
24
34
  const def = defOf(s);
25
35
  if (def?.type !== "default" && def?.type !== "optional" && def?.type !== "nullable") break;
36
+ if (def.type === "default" && standaard === void 0) {
37
+ const d = def.defaultValue;
38
+ try {
39
+ standaard = typeof d === "function" ? d() : d;
40
+ } catch {
41
+ standaard = void 0;
42
+ }
43
+ }
26
44
  s = def.innerType;
27
45
  description = description ?? describedAs(s);
28
46
  }
29
- return { def: defOf(s), description, inner: s };
47
+ return { def: defOf(s), description, inner: s, standaard };
30
48
  }
31
49
  function introspectObjectSchema(schema) {
32
50
  if (!schema) return [];
@@ -72,20 +90,20 @@ function introspectToFields(schema, hints, prefix = "") {
72
90
  const out = [];
73
91
  for (const [key, raw] of Object.entries(shape)) {
74
92
  if (key.startsWith("_")) continue;
75
- const { def: inner, description, inner: innerSchema } = unwrap(raw);
93
+ const { def: inner, description, inner: innerSchema, standaard } = unwrap(raw);
76
94
  const label = description ?? key;
77
95
  const path = prefix ? `${prefix}.${key}` : key;
78
96
  const hint = hints?.[path];
79
97
  const push = (f) => out.push({ ...f, ...hint, key, label: hint?.label ?? label });
80
98
  switch (inner?.type) {
81
99
  case "number":
82
- push({ key, label, type: "number" });
100
+ push({ key, label, type: "number", ...grenzenVan(inner) });
83
101
  break;
84
102
  case "boolean":
85
103
  push({ key, label, type: "switch" });
86
104
  break;
87
105
  case "enum":
88
- push({ key, label, type: "select", options: valuesOf(inner).map((v) => ({ value: v, label: v })) });
106
+ push({ key, label, type: "select", options: valuesOf(inner).map((v) => ({ value: v, label: v })), standaard: typeof standaard === "string" ? standaard : void 0 });
89
107
  break;
90
108
  case "string": {
91
109
  const max = maxLengthOf(inner);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/admin/lib/zodFields.ts"],"sourcesContent":["/**\n * Zod-introspectie voor automatisch gegenereerde formulieren. Gedeeld door:\n * - de `GenericEditor` (fallback-editor voor blokken zonder eigen `Editor`), en\n * - het `ModuleSettingsForm` (instellingen van een module in /beheer).\n *\n * Twee lagen:\n * - `introspectObjectSchema` (legacy, plat): simpele kinds — blijft bestaan voor module-settings.\n * - `introspectToFields` (5.0): levert de rijke **Field-IR** (schema/fields.ts, primo-port) met\n * échte repeaters/groepen (recursief), richtext-/image-/link-detectie en optionele per-block\n * hints (`defineBlock({ fields })`). De GenericEditor 2.0 rendert deze IR.\n *\n * Een veld krijgt zijn label uit `.describe(\"…\")` op het schema; zonder beschrijving valt het\n * terug op de veldsleutel. Puur (geen React) — apart testbaar.\n */\nimport { globalRegistry } from \"zod/mini\";\nimport type { $ZodType as ZodTypeAny } from \"zod/v4/core\";\nimport type { Field } from \"../../schema/fields\";\n\nexport interface SchemaField {\n key: string;\n kind: \"number\" | \"boolean\" | \"string\" | \"enum\" | \"json\";\n /** Leesbaar label: `.describe()` van het schema, anders de veldsleutel. */\n label: string;\n options?: string[];\n /** Max-lengte van een string (bepaalt Input vs Textarea in de UI). */\n maxLength?: number;\n /** Het volledige veld-schema — voor validatie van json-velden vóór commit. */\n schema: ZodTypeAny;\n}\n\n/**\n * Zod 4-interne vorm. In Zod 3 heette dit `_def.typeName` (\"ZodObject\") met `shape` als FUNCTIE en\n * de beschrijving op `_def.description`; sinds Zod 4 is het `_def.type` (\"object\") met `shape` als\n * gewoon object, staat de beschrijving op de schema-instantie, dragen enums hun waarden in\n * `entries`, en zit een string-check achter `checks[i]._zod.def` als\n * `{ check: \"max_length\", maximum: n }`.\n *\n * Dit blijft leunen op interne velden — er is geen publieke introspectie-API in Zod. De\n * Field-IR-tests (fields.test.ts) zijn daarom het vangnet: die vallen om zodra Zod zijn interne\n * vorm opnieuw wijzigt, in plaats van dat de GenericEditor stilletjes lege formulieren toont.\n */\ntype ZodKind =\n | \"object\" | \"string\" | \"number\" | \"boolean\" | \"enum\" | \"array\" | \"record\"\n | \"default\" | \"optional\" | \"nullable\" | \"literal\" | (string & {});\n\ninterface AnyDef {\n type?: ZodKind;\n innerType?: unknown;\n entries?: Record<string, string>;\n element?: unknown;\n checks?: { _zod?: { def?: { check?: string; maximum?: number } } }[];\n shape?: Record<string, unknown>;\n}\n\n/**\n * De interne definitie van een schema.\n *\n * LET OP: `_def` is een alias die alléén de classic-façade aanbiedt — `zod/mini` (waar core op\n * draait) heeft hem niet en zet alles op `_zod.def`. Lees dus `_zod.def` eerst, met `_def` als\n * terugval voor classic-schema's uit een klantrepo. Zonder die volgorde levert introspectie\n * stilletjes niets op en toont de GenericEditor lege formulieren.\n */\nconst defOf = (schema: unknown): AnyDef | undefined =>\n (schema as { _zod?: { def?: AnyDef } })?._zod?.def ?? (schema as { _def?: AnyDef })?._def;\n\n/** Max-lengte van een string-schema (Zod 4: checks dragen hun regel onder `_zod.def`). */\nfunction maxLengthOf(def: AnyDef | undefined): number | undefined {\n for (const c of def?.checks ?? []) {\n const rule = c?._zod?.def;\n if (rule?.check === \"max_length\") return rule.maximum;\n }\n return undefined;\n}\n\n/** Waarden van een enum (Zod 4 levert een entries-map i.p.v. een values-array). */\nconst valuesOf = (def: AnyDef | undefined): string[] => Object.values(def?.entries ?? {});\n\n/** De velden van een objectschema; leeg als het geen object is. */\nfunction shapeOf(schema: unknown): Record<string, unknown> | null {\n const def = defOf(schema);\n if (def?.type !== \"object\" || !def.shape || typeof def.shape !== \"object\") return null;\n return def.shape;\n}\n\n/**\n * De beschrijving van een schema — de bron van de veldlabels in /beheer.\n *\n * `zod/mini` heeft géén `.description`-getter (die hoort bij de classic-façade), maar `.describe()`\n * en `.register()` schrijven allebei naar dezelfde `globalRegistry`. Die lezen we hier dus direct,\n * met de getter als terugval zodat een classic-schema uit een klantrepo blijft werken.\n */\nfunction describedAs(s: unknown): string | undefined {\n const uitRegister = globalRegistry.get(s as never)?.description;\n return uitRegister ?? (s as { description?: string } | null)?.description;\n}\n\n/** Pakt het binnenste type uit default/optional/nullable; bewaart de buitenste beschrijving. */\nfunction unwrap(schema: unknown): { def?: AnyDef; description?: string; inner?: unknown } {\n let s: unknown = schema;\n let description = describedAs(s);\n for (;;) {\n const def = defOf(s);\n if (def?.type !== \"default\" && def?.type !== \"optional\" && def?.type !== \"nullable\") break;\n s = def.innerType;\n description = description ?? describedAs(s);\n }\n return { def: defOf(s), description, inner: s };\n}\n\n/**\n * Leidt een formulier-beschrijving af uit een Zod-objectschema. Interne velden (`_key`/`_type`/\n * `_style`) worden overgeslagen — die beheren de editor-chrome en de StyleEditor. Complexe velden\n * (array/object/record) worden als `json` teruggegeven zodat een fallback-editor ze tóch kan\n * aanbieden; een aanroeper die alleen simpele velden wil, filtert op `kind !== \"json\"`.\n */\nexport function introspectObjectSchema(schema: ZodTypeAny | undefined): SchemaField[] {\n if (!schema) return [];\n const shape = shapeOf(schema);\n if (!shape) return [];\n const out: SchemaField[] = [];\n for (const [key, field] of Object.entries(shape)) {\n if (key.startsWith(\"_\")) continue;\n const { def: inner, description } = unwrap(field);\n const label = description ?? key;\n const fieldSchema = field as ZodTypeAny;\n switch (inner?.type) {\n case \"number\":\n out.push({ key, kind: \"number\", label, schema: fieldSchema });\n break;\n case \"boolean\":\n out.push({ key, kind: \"boolean\", label, schema: fieldSchema });\n break;\n case \"enum\":\n out.push({ key, kind: \"enum\", label, options: valuesOf(inner), schema: fieldSchema });\n break;\n case \"string\": {\n out.push({ key, kind: \"string\", label, maxLength: maxLengthOf(inner), schema: fieldSchema });\n break;\n }\n case \"array\":\n case \"object\":\n case \"record\":\n out.push({ key, kind: \"json\", label, schema: fieldSchema });\n break;\n default:\n // ZodLiteral (bv. _type), unions e.d.: geen zinvol generiek veld.\n break;\n }\n }\n return out;\n}\n\nexport type { FieldHints } from \"../../schema/fields\";\nimport type { FieldHints } from \"../../schema/fields\";\n\n/** Herkent een beeld-URL-veld aan de sleutelnaam (zelfde heuristiek als de oude GenericEditor). */\nconst IMAGE_KEY = /image|photo|foto|logo|cover|avatar|poster/i;\n/** Herkent een URL-veld aan de sleutelnaam. */\nconst URL_KEY = /^(href|url|link)$|Url$|Href$/;\n\n/**\n * Leidt de rijke Field-IR af uit een Zod-objectschema (5.0). Verschillen met de platte laag:\n * - `z.array(z.object)` → **repeater** met recursief geïntrospecteerde subvelden;\n * - genest `z.object` → **group** (of **link** als de vorm exact `{label, href}` is);\n * - stringvelden `html`/`*Html` → **richtext**, beeld-sleutels → **image**, URL-sleutels → **url**;\n * - al het overige (records, scalar-arrays, unions) → **json** (laatste redmiddel).\n * `hints` verfijnt per (dotted) sleutel: type-overrides (date/slider/…) en `showIf`.\n */\nexport function introspectToFields(schema: ZodTypeAny | undefined, hints?: FieldHints, prefix = \"\"): Field[] {\n // Lazy schema's (7.13): vóór registerBuiltinSchemas kan een def nog geen schema hebben —\n // dan geen velden i.p.v. een crash (komt in de praktijk alleen in tests/randgevallen voor).\n if (!schema) return [];\n const shape = shapeOf(schema);\n if (!shape) return [];\n const out: Field[] = [];\n for (const [key, raw] of Object.entries(shape)) {\n if (key.startsWith(\"_\")) continue;\n const { def: inner, description, inner: innerSchema } = unwrap(raw);\n const label = description ?? key;\n const path = prefix ? `${prefix}.${key}` : key;\n const hint = hints?.[path];\n const push = (f: Field) => out.push({ ...f, ...(hint as Partial<Field>), key, label: (hint?.label as string) ?? label } as Field);\n switch (inner?.type) {\n case \"number\":\n push({ key, label, type: \"number\" });\n break;\n case \"boolean\":\n push({ key, label, type: \"switch\" });\n break;\n case \"enum\":\n push({ key, label, type: \"select\", options: valuesOf(inner).map((v) => ({ value: v, label: v })) });\n break;\n case \"string\": {\n const max = maxLengthOf(inner);\n if (key === \"html\" || key.endsWith(\"Html\")) push({ key, label, type: \"richtext\" });\n else if (IMAGE_KEY.test(key)) push({ key, label, type: \"image\" });\n else if (URL_KEY.test(key)) push({ key, label, type: \"url\" });\n else if ((max ?? 0) > 500) push({ key, label, type: \"textarea\", maxLength: max });\n else push({ key, label, type: \"text\", maxLength: max });\n break;\n }\n case \"object\": {\n const sub = introspectToFields(innerSchema as ZodTypeAny, hints, path);\n const isLink = sub.length === 2 && sub.some((f) => f.key === \"label\") && sub.some((f) => f.key === \"href\");\n if (isLink) push({ key, label, type: \"link\" });\n else if (sub.length > 0) push({ key, label, type: \"group\", fields: sub });\n else push({ key, label, type: \"json\" });\n break;\n }\n case \"array\": {\n const { def: elDef, inner: elSchema } = unwrap(inner?.element);\n if (elDef?.type === \"object\") {\n const sub = introspectToFields(elSchema as ZodTypeAny, hints, path);\n if (sub.length > 0) {\n push({ key, label, type: \"repeater\", fields: sub });\n break;\n }\n }\n push({ key, label, type: \"json\" });\n break;\n }\n case \"record\":\n push({ key, label, type: \"json\" });\n break;\n default:\n break;\n }\n }\n return out;\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../src/admin/lib/zodFields.ts"],"sourcesContent":["/**\n * Zod-introspectie voor automatisch gegenereerde formulieren. Gedeeld door:\n * - de `GenericEditor` (fallback-editor voor blokken zonder eigen `Editor`), en\n * - het `ModuleSettingsForm` (instellingen van een module in /beheer).\n *\n * Twee lagen:\n * - `introspectObjectSchema` (legacy, plat): simpele kinds — blijft bestaan voor module-settings.\n * - `introspectToFields` (5.0): levert de rijke **Field-IR** (schema/fields.ts, primo-port) met\n * échte repeaters/groepen (recursief), richtext-/image-/link-detectie en optionele per-block\n * hints (`defineBlock({ fields })`). De GenericEditor 2.0 rendert deze IR.\n *\n * Een veld krijgt zijn label uit `.describe(\"…\")` op het schema; zonder beschrijving valt het\n * terug op de veldsleutel. Puur (geen React) — apart testbaar.\n */\nimport { globalRegistry } from \"zod/mini\";\nimport type { $ZodType as ZodTypeAny } from \"zod/v4/core\";\nimport type { Field } from \"../../schema/fields\";\n\nexport interface SchemaField {\n key: string;\n kind: \"number\" | \"boolean\" | \"string\" | \"enum\" | \"json\";\n /** Leesbaar label: `.describe()` van het schema, anders de veldsleutel. */\n label: string;\n options?: string[];\n /** Max-lengte van een string (bepaalt Input vs Textarea in de UI). */\n maxLength?: number;\n /** Het volledige veld-schema — voor validatie van json-velden vóór commit. */\n schema: ZodTypeAny;\n}\n\n/**\n * Zod 4-interne vorm. In Zod 3 heette dit `_def.typeName` (\"ZodObject\") met `shape` als FUNCTIE en\n * de beschrijving op `_def.description`; sinds Zod 4 is het `_def.type` (\"object\") met `shape` als\n * gewoon object, staat de beschrijving op de schema-instantie, dragen enums hun waarden in\n * `entries`, en zit een string-check achter `checks[i]._zod.def` als\n * `{ check: \"max_length\", maximum: n }`.\n *\n * Dit blijft leunen op interne velden — er is geen publieke introspectie-API in Zod. De\n * Field-IR-tests (fields.test.ts) zijn daarom het vangnet: die vallen om zodra Zod zijn interne\n * vorm opnieuw wijzigt, in plaats van dat de GenericEditor stilletjes lege formulieren toont.\n */\ntype ZodKind =\n | \"object\" | \"string\" | \"number\" | \"boolean\" | \"enum\" | \"array\" | \"record\"\n | \"default\" | \"optional\" | \"nullable\" | \"literal\" | (string & {});\n\ninterface AnyDef {\n type?: ZodKind;\n innerType?: unknown;\n entries?: Record<string, string>;\n element?: unknown;\n checks?: { _zod?: { def?: { check?: string; maximum?: number } } }[];\n shape?: Record<string, unknown>;\n}\n\n/**\n * De interne definitie van een schema.\n *\n * LET OP: `_def` is een alias die alléén de classic-façade aanbiedt — `zod/mini` (waar core op\n * draait) heeft hem niet en zet alles op `_zod.def`. Lees dus `_zod.def` eerst, met `_def` als\n * terugval voor classic-schema's uit een klantrepo. Zonder die volgorde levert introspectie\n * stilletjes niets op en toont de GenericEditor lege formulieren.\n */\nconst defOf = (schema: unknown): AnyDef | undefined =>\n (schema as { _zod?: { def?: AnyDef } })?._zod?.def ?? (schema as { _def?: AnyDef })?._def;\n\n/** Max-lengte van een string-schema (Zod 4: checks dragen hun regel onder `_zod.def`). */\nfunction maxLengthOf(def: AnyDef | undefined): number | undefined {\n for (const c of def?.checks ?? []) {\n const rule = c?._zod?.def;\n if (rule?.check === \"max_length\") return rule.maximum;\n }\n return undefined;\n}\n\n/** Onder- en bovengrens van een getal (`z.minimum`/`z.maximum`), voor een knoppenrij i.p.v. een vrij veld. */\nfunction grenzenVan(def: AnyDef | undefined): { min?: number; max?: number } {\n const uit: { min?: number; max?: number } = {};\n for (const c of def?.checks ?? []) {\n const rule = c?._zod?.def as { check?: string; value?: unknown } | undefined;\n if (rule?.check === \"greater_than\" && typeof rule.value === \"number\") uit.min = rule.value;\n if (rule?.check === \"less_than\" && typeof rule.value === \"number\") uit.max = rule.value;\n }\n return uit;\n}\n\n/** Waarden van een enum (Zod 4 levert een entries-map i.p.v. een values-array). */\nconst valuesOf = (def: AnyDef | undefined): string[] => Object.values(def?.entries ?? {});\n\n/** De velden van een objectschema; leeg als het geen object is. */\nfunction shapeOf(schema: unknown): Record<string, unknown> | null {\n const def = defOf(schema);\n if (def?.type !== \"object\" || !def.shape || typeof def.shape !== \"object\") return null;\n return def.shape;\n}\n\n/**\n * De beschrijving van een schema — de bron van de veldlabels in /beheer.\n *\n * `zod/mini` heeft géén `.description`-getter (die hoort bij de classic-façade), maar `.describe()`\n * en `.register()` schrijven allebei naar dezelfde `globalRegistry`. Die lezen we hier dus direct,\n * met de getter als terugval zodat een classic-schema uit een klantrepo blijft werken.\n */\nfunction describedAs(s: unknown): string | undefined {\n const uitRegister = globalRegistry.get(s as never)?.description;\n return uitRegister ?? (s as { description?: string } | null)?.description;\n}\n\n/** Pakt het binnenste type uit default/optional/nullable; bewaart de buitenste beschrijving. */\nfunction unwrap(schema: unknown): { def?: AnyDef; description?: string; inner?: unknown; standaard?: unknown } {\n let s: unknown = schema;\n let description = describedAs(s);\n let standaard: unknown;\n for (;;) {\n const def = defOf(s);\n if (def?.type !== \"default\" && def?.type !== \"optional\" && def?.type !== \"nullable\") break;\n if (def.type === \"default\" && standaard === undefined) {\n // 8.10: de default meenemen — een keuzelijst toont dan wat er echt gerenderd wordt.\n const d = (def as { defaultValue?: unknown }).defaultValue;\n try {\n standaard = typeof d === \"function\" ? (d as () => unknown)() : d;\n } catch {\n standaard = undefined;\n }\n }\n s = def.innerType;\n description = description ?? describedAs(s);\n }\n return { def: defOf(s), description, inner: s, standaard };\n}\n\n/**\n * Leidt een formulier-beschrijving af uit een Zod-objectschema. Interne velden (`_key`/`_type`/\n * `_style`) worden overgeslagen — die beheren de editor-chrome en de StyleEditor. Complexe velden\n * (array/object/record) worden als `json` teruggegeven zodat een fallback-editor ze tóch kan\n * aanbieden; een aanroeper die alleen simpele velden wil, filtert op `kind !== \"json\"`.\n */\nexport function introspectObjectSchema(schema: ZodTypeAny | undefined): SchemaField[] {\n if (!schema) return [];\n const shape = shapeOf(schema);\n if (!shape) return [];\n const out: SchemaField[] = [];\n for (const [key, field] of Object.entries(shape)) {\n if (key.startsWith(\"_\")) continue;\n const { def: inner, description } = unwrap(field);\n const label = description ?? key;\n const fieldSchema = field as ZodTypeAny;\n switch (inner?.type) {\n case \"number\":\n out.push({ key, kind: \"number\", label, schema: fieldSchema });\n break;\n case \"boolean\":\n out.push({ key, kind: \"boolean\", label, schema: fieldSchema });\n break;\n case \"enum\":\n out.push({ key, kind: \"enum\", label, options: valuesOf(inner), schema: fieldSchema });\n break;\n case \"string\": {\n out.push({ key, kind: \"string\", label, maxLength: maxLengthOf(inner), schema: fieldSchema });\n break;\n }\n case \"array\":\n case \"object\":\n case \"record\":\n out.push({ key, kind: \"json\", label, schema: fieldSchema });\n break;\n default:\n // ZodLiteral (bv. _type), unions e.d.: geen zinvol generiek veld.\n break;\n }\n }\n return out;\n}\n\nexport type { FieldHints } from \"../../schema/fields\";\nimport type { FieldHints } from \"../../schema/fields\";\n\n/** Herkent een beeld-URL-veld aan de sleutelnaam (zelfde heuristiek als de oude GenericEditor). */\nconst IMAGE_KEY = /image|photo|foto|logo|cover|avatar|poster/i;\n/** Herkent een URL-veld aan de sleutelnaam. */\nconst URL_KEY = /^(href|url|link)$|Url$|Href$/;\n\n/**\n * Leidt de rijke Field-IR af uit een Zod-objectschema (5.0). Verschillen met de platte laag:\n * - `z.array(z.object)` → **repeater** met recursief geïntrospecteerde subvelden;\n * - genest `z.object` → **group** (of **link** als de vorm exact `{label, href}` is);\n * - stringvelden `html`/`*Html` → **richtext**, beeld-sleutels → **image**, URL-sleutels → **url**;\n * - al het overige (records, scalar-arrays, unions) → **json** (laatste redmiddel).\n * `hints` verfijnt per (dotted) sleutel: type-overrides (date/slider/…) en `showIf`.\n */\nexport function introspectToFields(schema: ZodTypeAny | undefined, hints?: FieldHints, prefix = \"\"): Field[] {\n // Lazy schema's (7.13): vóór registerBuiltinSchemas kan een def nog geen schema hebben —\n // dan geen velden i.p.v. een crash (komt in de praktijk alleen in tests/randgevallen voor).\n if (!schema) return [];\n const shape = shapeOf(schema);\n if (!shape) return [];\n const out: Field[] = [];\n for (const [key, raw] of Object.entries(shape)) {\n if (key.startsWith(\"_\")) continue;\n const { def: inner, description, inner: innerSchema, standaard } = unwrap(raw);\n const label = description ?? key;\n const path = prefix ? `${prefix}.${key}` : key;\n const hint = hints?.[path];\n const push = (f: Field) => out.push({ ...f, ...(hint as Partial<Field>), key, label: (hint?.label as string) ?? label } as Field);\n switch (inner?.type) {\n case \"number\":\n push({ key, label, type: \"number\", ...grenzenVan(inner) });\n break;\n case \"boolean\":\n push({ key, label, type: \"switch\" });\n break;\n case \"enum\":\n push({ key, label, type: \"select\", options: valuesOf(inner).map((v) => ({ value: v, label: v })), standaard: typeof standaard === \"string\" ? standaard : undefined });\n break;\n case \"string\": {\n const max = maxLengthOf(inner);\n if (key === \"html\" || key.endsWith(\"Html\")) push({ key, label, type: \"richtext\" });\n else if (IMAGE_KEY.test(key)) push({ key, label, type: \"image\" });\n else if (URL_KEY.test(key)) push({ key, label, type: \"url\" });\n else if ((max ?? 0) > 500) push({ key, label, type: \"textarea\", maxLength: max });\n else push({ key, label, type: \"text\", maxLength: max });\n break;\n }\n case \"object\": {\n const sub = introspectToFields(innerSchema as ZodTypeAny, hints, path);\n const isLink = sub.length === 2 && sub.some((f) => f.key === \"label\") && sub.some((f) => f.key === \"href\");\n if (isLink) push({ key, label, type: \"link\" });\n else if (sub.length > 0) push({ key, label, type: \"group\", fields: sub });\n else push({ key, label, type: \"json\" });\n break;\n }\n case \"array\": {\n const { def: elDef, inner: elSchema } = unwrap(inner?.element);\n if (elDef?.type === \"object\") {\n const sub = introspectToFields(elSchema as ZodTypeAny, hints, path);\n if (sub.length > 0) {\n push({ key, label, type: \"repeater\", fields: sub });\n break;\n }\n }\n push({ key, label, type: \"json\" });\n break;\n }\n case \"record\":\n push({ key, label, type: \"json\" });\n break;\n default:\n break;\n }\n }\n return out;\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,9 @@
1
+ interface Issue {
2
+ path?: PropertyKey[];
3
+ code?: string;
4
+ message?: string;
5
+ origin?: string;
6
+ format?: string;
7
+ }
8
+ export declare function zodFoutTekst(issue: Issue | undefined): string;
9
+ export {};
@@ -0,0 +1,63 @@
1
+ const NAMEN = {
2
+ name: "Sitenaam",
3
+ contactEmail: "Contact-e-mail",
4
+ domain: "Domein",
5
+ nav: "Menu",
6
+ children: "submenu",
7
+ footer: "Footer",
8
+ columns: "kolom",
9
+ links: "link",
10
+ social: "social-link",
11
+ copyright: "copyright",
12
+ heading: "kop",
13
+ label: "tekst",
14
+ href: "adres",
15
+ platform: "naam",
16
+ redirects: "Doorverwijzing",
17
+ from: "van",
18
+ to: "naar",
19
+ theme: "Huisstijl",
20
+ primary: "merkkleur",
21
+ accent: "accentkleur",
22
+ background: "achtergrondkleur",
23
+ foreground: "tekstkleur",
24
+ seoDefaults: "SEO",
25
+ description: "omschrijving",
26
+ forms: "Formulieren",
27
+ title: "titel",
28
+ slug: "adres",
29
+ price: "prijs",
30
+ priceCents: "prijs",
31
+ fields: "veld",
32
+ options: "keuze",
33
+ code: "code",
34
+ percent: "percentage",
35
+ stock: "voorraad",
36
+ variants: "variant"
37
+ };
38
+ function zodFoutTekst(issue) {
39
+ if (!issue) return "Onbekende fout.";
40
+ const delen = [];
41
+ for (const p of issue.path ?? []) {
42
+ if (typeof p === "number") {
43
+ if (delen.length) delen[delen.length - 1] += ` ${p + 1}`;
44
+ else delen.push(`item ${p + 1}`);
45
+ } else {
46
+ delen.push(NAMEN[String(p)] ?? String(p));
47
+ }
48
+ }
49
+ const waar = delen.join(", ");
50
+ let wat;
51
+ if (issue.code === "too_small" && issue.origin === "string") wat = "is leeg";
52
+ else if (issue.code === "too_small") wat = "is te klein of te kort";
53
+ else if (issue.code === "too_big") wat = "is te lang";
54
+ else if (issue.code === "invalid_format" && issue.format === "email") wat = "is geen geldig e-mailadres";
55
+ else if (issue.code === "invalid_format") wat = "heeft een ongeldige vorm";
56
+ else if (issue.code === "invalid_type") wat = "ontbreekt of heeft een verkeerde waarde";
57
+ else wat = issue.message ?? "klopt niet";
58
+ return waar ? `${waar[0].toUpperCase()}${waar.slice(1)}: ${wat}.` : `${wat[0].toUpperCase()}${wat.slice(1)}.`;
59
+ }
60
+ export {
61
+ zodFoutTekst
62
+ };
63
+ //# sourceMappingURL=zodFout.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/admin/lib/zodFout.ts"],"sourcesContent":["/**\n * Een zod-fout in mensentaal (8.10).\n *\n * Bij opslaan van de instellingen kreeg de klant \"Too small: expected string to have >=1\n * characters\" — Engels, zonder te zeggen wélk veld. Dit maakt er \"Footer, kolom 2, link 1: de tekst\n * is leeg\" van. Onbekende velden krijgen hun sleutel; dat is nog altijd beter dan niets.\n */\nconst NAMEN: Record<string, string> = {\n name: \"Sitenaam\",\n contactEmail: \"Contact-e-mail\",\n domain: \"Domein\",\n nav: \"Menu\",\n children: \"submenu\",\n footer: \"Footer\",\n columns: \"kolom\",\n links: \"link\",\n social: \"social-link\",\n copyright: \"copyright\",\n heading: \"kop\",\n label: \"tekst\",\n href: \"adres\",\n platform: \"naam\",\n redirects: \"Doorverwijzing\",\n from: \"van\",\n to: \"naar\",\n theme: \"Huisstijl\",\n primary: \"merkkleur\",\n accent: \"accentkleur\",\n background: \"achtergrondkleur\",\n foreground: \"tekstkleur\",\n seoDefaults: \"SEO\",\n description: \"omschrijving\",\n forms: \"Formulieren\",\n title: \"titel\",\n slug: \"adres\",\n price: \"prijs\",\n priceCents: \"prijs\",\n fields: \"veld\",\n options: \"keuze\",\n code: \"code\",\n percent: \"percentage\",\n stock: \"voorraad\",\n variants: \"variant\",\n};\n\ninterface Issue {\n path?: PropertyKey[];\n code?: string;\n message?: string;\n origin?: string;\n format?: string;\n}\n\nexport function zodFoutTekst(issue: Issue | undefined): string {\n if (!issue) return \"Onbekende fout.\";\n const delen: string[] = [];\n for (const p of issue.path ?? []) {\n if (typeof p === \"number\") {\n if (delen.length) delen[delen.length - 1] += ` ${p + 1}`;\n else delen.push(`item ${p + 1}`);\n } else {\n delen.push(NAMEN[String(p)] ?? String(p));\n }\n }\n const waar = delen.join(\", \");\n let wat: string;\n if (issue.code === \"too_small\" && issue.origin === \"string\") wat = \"is leeg\";\n else if (issue.code === \"too_small\") wat = \"is te klein of te kort\";\n else if (issue.code === \"too_big\") wat = \"is te lang\";\n else if (issue.code === \"invalid_format\" && issue.format === \"email\") wat = \"is geen geldig e-mailadres\";\n else if (issue.code === \"invalid_format\") wat = \"heeft een ongeldige vorm\";\n else if (issue.code === \"invalid_type\") wat = \"ontbreekt of heeft een verkeerde waarde\";\n else wat = issue.message ?? \"klopt niet\";\n return waar ? `${waar[0].toUpperCase()}${waar.slice(1)}: ${wat}.` : `${wat[0].toUpperCase()}${wat.slice(1)}.`;\n}\n"],"mappings":"AAOA,MAAM,QAAgC;AAAA,EACpC,MAAM;AAAA,EACN,cAAc;AAAA,EACd,QAAQ;AAAA,EACR,KAAK;AAAA,EACL,UAAU;AAAA,EACV,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,WAAW;AAAA,EACX,SAAS;AAAA,EACT,OAAO;AAAA,EACP,MAAM;AAAA,EACN,UAAU;AAAA,EACV,WAAW;AAAA,EACX,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,YAAY;AAAA,EACZ,YAAY;AAAA,EACZ,aAAa;AAAA,EACb,aAAa;AAAA,EACb,OAAO;AAAA,EACP,OAAO;AAAA,EACP,MAAM;AAAA,EACN,OAAO;AAAA,EACP,YAAY;AAAA,EACZ,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,MAAM;AAAA,EACN,SAAS;AAAA,EACT,OAAO;AAAA,EACP,UAAU;AACZ;AAUO,SAAS,aAAa,OAAkC;AAC7D,MAAI,CAAC,MAAO,QAAO;AACnB,QAAM,QAAkB,CAAC;AACzB,aAAW,KAAK,MAAM,QAAQ,CAAC,GAAG;AAChC,QAAI,OAAO,MAAM,UAAU;AACzB,UAAI,MAAM,OAAQ,OAAM,MAAM,SAAS,CAAC,KAAK,IAAI,IAAI,CAAC;AAAA,UACjD,OAAM,KAAK,QAAQ,IAAI,CAAC,EAAE;AAAA,IACjC,OAAO;AACL,YAAM,KAAK,MAAM,OAAO,CAAC,CAAC,KAAK,OAAO,CAAC,CAAC;AAAA,IAC1C;AAAA,EACF;AACA,QAAM,OAAO,MAAM,KAAK,IAAI;AAC5B,MAAI;AACJ,MAAI,MAAM,SAAS,eAAe,MAAM,WAAW,SAAU,OAAM;AAAA,WAC1D,MAAM,SAAS,YAAa,OAAM;AAAA,WAClC,MAAM,SAAS,UAAW,OAAM;AAAA,WAChC,MAAM,SAAS,oBAAoB,MAAM,WAAW,QAAS,OAAM;AAAA,WACnE,MAAM,SAAS,iBAAkB,OAAM;AAAA,WACvC,MAAM,SAAS,eAAgB,OAAM;AAAA,MACzC,OAAM,MAAM,WAAW;AAC5B,SAAO,OAAO,GAAG,KAAK,CAAC,EAAE,YAAY,CAAC,GAAG,KAAK,MAAM,CAAC,CAAC,KAAK,GAAG,MAAM,GAAG,IAAI,CAAC,EAAE,YAAY,CAAC,GAAG,IAAI,MAAM,CAAC,CAAC;AAC5G;","names":[]}
@@ -14,12 +14,15 @@ import {
14
14
  } from "firebase/firestore";
15
15
  import { deleteObject, ref as storageRef } from "firebase/storage";
16
16
  import { getBucket, getDb } from "../../firebase/client.js";
17
- import { DEMO_EVENT, isDemoActive, listDemoMediaAll } from "../../demo/demoStore.js";
18
- import { Button, Card, Badge, Input } from "../ui/primitives.js";
17
+ import { DEMO_EVENT, isDemoActive, listDemoMediaAll, removeDemoMedia } from "../../demo/demoStore.js";
18
+ import { Button, Card, Badge, Input, LegeStaat } from "../ui/primitives.js";
19
19
  import { useToast } from "../ui/toast.js";
20
+ import { Switch } from "../ui/switch.js";
20
21
  import { useConfirm } from "../ui/ConfirmDialog.js";
21
22
  import { uploadImage } from "../lib/upload.js";
22
23
  import { findMediaUsage, findUnusedMedia } from "../lib/mediaUsage.js";
24
+ import { korteDatum, leesbareGrootte, MEDIA_SORTERINGEN, sorteerMedia } from "../lib/mediaLijst.js";
25
+ import { Select } from "../ui/select.js";
23
26
  const PAGE_SIZE = 48;
24
27
  function MediaManager({ siteId }) {
25
28
  const { toast } = useToast();
@@ -32,7 +35,10 @@ function MediaManager({ siteId }) {
32
35
  const [hasMore, setHasMore] = useState(false);
33
36
  const inputRef = useRef(null);
34
37
  const [zoek, setZoek] = useState("");
38
+ const [zonderAlt, setZonderAlt] = useState(false);
35
39
  const [sleepOver, setSleepOver] = useState(false);
40
+ const [sortering, setSortering] = useState("nieuw");
41
+ const [geselecteerd, setGeselecteerd] = useState(() => /* @__PURE__ */ new Set());
36
42
  useEffect(() => {
37
43
  if (isDemoActive()) {
38
44
  const sync = () => setItems(listDemoMediaAll(siteId));
@@ -92,14 +98,13 @@ function MediaManager({ siteId }) {
92
98
  }
93
99
  }
94
100
  async function remove(item) {
95
- const db = getDb();
96
- const bucket = getBucket();
97
- if (!db) return;
98
- const usedOn = await findMediaUsage(siteId, item);
101
+ const demo = isDemoActive();
102
+ if (!demo && !getDb()) return;
103
+ const usedOn = demo ? [] : await findMediaUsage(siteId, item);
99
104
  const ok = await confirm({
100
105
  title: "Afbeelding verwijderen?",
101
- description: usedOn.length > 0 ? `Let op: deze afbeelding wordt gebruikt op ${usedOn.length} gepubliceerde pagina('s) (${usedOn.join(", ")}). Daar verschijnt dan een gebroken afbeelding.` : "De afbeelding wordt definitief verwijderd.",
102
- confirmLabel: "Verwijderen",
106
+ description: usedOn === null ? "Er kon niet worden nagegaan of deze afbeelding nog ergens gebruikt wordt. Wordt hij dat wel, dan verschijnt daar een gebroken afbeelding." : usedOn.length > 0 ? `Let op: deze afbeelding wordt nog gebruikt (${usedOn.slice(0, 5).join(", ")}${usedOn.length > 5 ? " \u2026" : ""}). Daar verschijnt dan een gebroken afbeelding.` : "De afbeelding wordt nergens gebruikt en wordt definitief verwijderd.",
107
+ confirmLabel: usedOn && usedOn.length > 0 ? "Toch verwijderen" : "Verwijderen",
103
108
  tone: "danger"
104
109
  });
105
110
  if (!ok) return;
@@ -110,7 +115,67 @@ function MediaManager({ siteId }) {
110
115
  toast({ title: "Verwijderen mislukt", description: e.message, tone: "error" });
111
116
  }
112
117
  }
118
+ async function verwijderSelectie() {
119
+ const doelen = items.filter((it) => geselecteerd.has(it.id));
120
+ if (doelen.length === 0) return;
121
+ setBusy(true);
122
+ let inGebruik = isDemoActive() ? 0 : null;
123
+ try {
124
+ if (!isDemoActive()) {
125
+ const vrij = new Set(await findUnusedMedia(siteId, doelen));
126
+ inGebruik = doelen.filter((d) => !vrij.has(d.id)).length;
127
+ }
128
+ } catch {
129
+ inGebruik = null;
130
+ }
131
+ setBusy(false);
132
+ const ok = await confirm({
133
+ title: `${doelen.length} foto('s) verwijderen?`,
134
+ description: inGebruik === null ? "Kon niet nagaan of deze foto's nog op de site staan. Waar ze gebruikt worden, verschijnt dan een gebroken afbeelding." : inGebruik > 0 ? `Let op: ${inGebruik} hiervan ${inGebruik === 1 ? "wordt" : "worden"} nog gebruikt (of ${inGebruik === 1 ? "is" : "zijn"} net ge\xFCpload). Daar verschijnt dan een gebroken afbeelding.` : "Geen van deze foto's wordt nog gebruikt. Ze worden definitief verwijderd.",
135
+ confirmLabel: "Verwijderen",
136
+ tone: "danger"
137
+ });
138
+ if (!ok) return;
139
+ setBusy(true);
140
+ let gelukt = 0;
141
+ const fouten = [];
142
+ for (const it of doelen) {
143
+ try {
144
+ await verwijderItem(it);
145
+ gelukt++;
146
+ } catch (e) {
147
+ fouten.push(`${it.name}: ${e.message}`);
148
+ }
149
+ }
150
+ setGeselecteerd(/* @__PURE__ */ new Set());
151
+ setBusy(false);
152
+ if (gelukt) toast({ title: `${gelukt} foto('s) verwijderd`, tone: "success" });
153
+ if (fouten.length) toast({ title: "Niet alles kon weg", description: fouten.join(" \xB7 "), tone: "error" });
154
+ }
155
+ async function download(item) {
156
+ try {
157
+ const res = await fetch(item.url);
158
+ if (!res.ok) throw new Error(String(res.status));
159
+ const url = URL.createObjectURL(await res.blob());
160
+ const a = document.createElement("a");
161
+ a.href = url;
162
+ a.download = item.name || "foto";
163
+ a.click();
164
+ setTimeout(() => URL.revokeObjectURL(url), 1e3);
165
+ } catch {
166
+ window.open(item.url, "_blank", "noopener");
167
+ }
168
+ }
169
+ function wisselSelectie(id) {
170
+ setGeselecteerd((s) => {
171
+ const n = new Set(s);
172
+ if (n.has(id)) n.delete(id);
173
+ else n.add(id);
174
+ return n;
175
+ });
176
+ }
113
177
  async function verwijderItem(item) {
178
+ if (isDemoActive()) return removeDemoMedia(siteId, item.id);
114
179
  const db = getDb();
115
180
  const bucket = getBucket();
116
181
  if (!db) throw new Error("Geen databaseverbinding.");
@@ -169,7 +234,13 @@ function MediaManager({ siteId }) {
169
234
  if (fouten.length) toast({ title: "Niet alles kon weg", description: fouten.join(" \xB7 "), tone: "error" });
170
235
  }
171
236
  const term = zoek.trim().toLowerCase();
172
- const getoond = term ? items.filter((m) => `${m.name ?? ""} ${m.alt ?? ""}`.toLowerCase().includes(term)) : items;
237
+ const aantalZonderAlt = items.filter((m) => !m.alt?.trim()).length;
238
+ const getoond = sorteerMedia(
239
+ items.filter((m) => !zonderAlt || !m.alt?.trim()).filter((m) => !term || `${m.name ?? ""} ${m.alt ?? ""}`.toLowerCase().includes(term)),
240
+ sortering
241
+ );
242
+ const aantalGeselecteerd = items.filter((m) => geselecteerd.has(m.id)).length;
243
+ const allesGetoondGeselecteerd = getoond.length > 0 && getoond.every((m) => geselecteerd.has(m.id));
173
244
  return /* @__PURE__ */ jsxs(
174
245
  "div",
175
246
  {
@@ -205,7 +276,48 @@ function MediaManager({ siteId }) {
205
276
  /* @__PURE__ */ jsx("strong", { children: "focuspunt" }),
206
277
  " te kiezen: dat deel blijft in beeld als de foto wordt bijgesneden (bijvoorbeeld een brede kopfoto op een telefoon)."
207
278
  ] }),
208
- items.length > 8 && /* @__PURE__ */ jsx("div", { className: "mt-3 max-w-xs", children: /* @__PURE__ */ jsx(Input, { value: zoek, onChange: (e) => setZoek(e.target.value), placeholder: "Zoek op naam of alt-tekst\u2026", "aria-label": "Zoek in mediabibliotheek" }) }),
279
+ /* @__PURE__ */ jsxs("div", { className: "mt-3 flex flex-wrap items-center gap-3", children: [
280
+ items.length > 8 && /* @__PURE__ */ jsx("div", { className: "w-full max-w-xs", children: /* @__PURE__ */ jsx(Input, { value: zoek, onChange: (e) => setZoek(e.target.value), placeholder: "Zoek op naam of beschrijving\u2026", "aria-label": "Zoek in mediabibliotheek" }) }),
281
+ (aantalZonderAlt > 0 || zonderAlt) && /* @__PURE__ */ jsx(
282
+ Switch,
283
+ {
284
+ checked: zonderAlt,
285
+ onCheckedChange: setZonderAlt,
286
+ label: `Alleen zonder beschrijving (${aantalZonderAlt})`
287
+ }
288
+ ),
289
+ items.length > 1 && /* @__PURE__ */ jsx("div", { className: "w-48", children: /* @__PURE__ */ jsx(
290
+ Select,
291
+ {
292
+ value: sortering,
293
+ onValueChange: (v) => setSortering(v || "nieuw"),
294
+ options: MEDIA_SORTERINGEN,
295
+ placeholder: "Sorteren"
296
+ }
297
+ ) })
298
+ ] }),
299
+ aantalGeselecteerd > 0 && /* @__PURE__ */ jsxs(
300
+ "div",
301
+ {
302
+ role: "region",
303
+ "aria-label": "Selectie",
304
+ className: "sticky top-2 z-10 mt-3 flex flex-wrap items-center gap-2 rounded-lg border border-brand-500/40 bg-brand-50 px-3 py-2 text-sm shadow-sm",
305
+ children: [
306
+ /* @__PURE__ */ jsxs("strong", { children: [
307
+ aantalGeselecteerd,
308
+ " geselecteerd"
309
+ ] }),
310
+ !allesGetoondGeselecteerd && /* @__PURE__ */ jsxs(Button, { variant: "ghost", size: "sm", onClick: () => setGeselecteerd(/* @__PURE__ */ new Set([...geselecteerd, ...getoond.map((m) => m.id)])), children: [
311
+ "Alles selecteren (",
312
+ getoond.length,
313
+ ")"
314
+ ] }),
315
+ /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", onClick: () => setGeselecteerd(/* @__PURE__ */ new Set()), children: "Selectie wissen" }),
316
+ /* @__PURE__ */ jsx("span", { className: "flex-1" }),
317
+ /* @__PURE__ */ jsx(Button, { loading: busy, variant: "danger", size: "sm", disabled: busy, onClick: () => void verwijderSelectie(), children: `Verwijderen (${aantalGeselecteerd})` })
318
+ ]
319
+ }
320
+ ),
209
321
  /* @__PURE__ */ jsx(
210
322
  "input",
211
323
  {
@@ -222,32 +334,49 @@ function MediaManager({ siteId }) {
222
334
  )
223
335
  ] }),
224
336
  /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-3 sm:grid-cols-3 lg:grid-cols-4", children: [
225
- getoond.map((m) => /* @__PURE__ */ jsxs(Card, { className: "p-3", children: [
226
- /* @__PURE__ */ jsx(FocusFoto, { item: m, onFocus: (f) => void zetFocus(m, f) }),
337
+ getoond.map((m) => /* @__PURE__ */ jsxs(Card, { className: `p-3 ${geselecteerd.has(m.id) ? "ring-2 ring-brand-500" : ""}`, children: [
338
+ /* @__PURE__ */ jsxs("div", { className: "relative", children: [
339
+ /* @__PURE__ */ jsx(FocusFoto, { item: m, onFocus: (f) => void zetFocus(m, f) }),
340
+ /* @__PURE__ */ jsx("label", { className: "absolute top-1.5 left-1.5 flex h-7 w-7 cursor-pointer items-center justify-center rounded-md bg-white/90 shadow", children: /* @__PURE__ */ jsx(
341
+ "input",
342
+ {
343
+ type: "checkbox",
344
+ className: "h-4 w-4 cursor-pointer accent-brand-600",
345
+ checked: geselecteerd.has(m.id),
346
+ onChange: () => wisselSelectie(m.id),
347
+ "aria-label": `Selecteer ${m.name ?? "foto"}`
348
+ }
349
+ ) })
350
+ ] }),
227
351
  /* @__PURE__ */ jsxs("div", { className: "mb-2 flex items-center justify-between gap-1", children: [
228
- /* @__PURE__ */ jsxs("span", { className: "truncate text-xs text-slate-500", children: [
229
- m.name,
230
- m.width && /* @__PURE__ */ jsxs("span", { className: "text-slate-400", children: [
231
- " \xB7 ",
232
- m.width,
233
- "\xD7",
234
- m.height
235
- ] })
352
+ /* @__PURE__ */ jsxs("span", { className: "min-w-0 text-xs text-slate-500", children: [
353
+ /* @__PURE__ */ jsx("span", { className: "block truncate", title: m.name, children: m.name }),
354
+ /* @__PURE__ */ jsx("span", { className: "block truncate", children: [
355
+ m.width && m.height ? `${m.width}\xD7${m.height}` : "",
356
+ leesbareGrootte(m.size),
357
+ korteDatum(m.createdAt)
358
+ ].filter(Boolean).join(" \xB7 ") })
236
359
  ] }),
237
360
  m.status === "processing" ? /* @__PURE__ */ jsx(Badge, { tone: "amber", children: "verwerken" }) : ongebruikt?.includes(m.id) ? /* @__PURE__ */ jsx(Badge, { tone: "amber", children: "ongebruikt" }) : /* @__PURE__ */ jsx(Badge, { tone: "green", children: "klaar" })
238
361
  ] }),
239
362
  /* @__PURE__ */ jsx(AltInput, { item: m, onSave: saveAlt }),
240
- /* @__PURE__ */ jsxs("div", { className: "flex gap-1", children: [
241
- /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", className: "text-xs", onClick: () => void navigator.clipboard?.writeText(m.url), children: "Kopieer URL" }),
242
- /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", className: "text-xs", onClick: () => void remove(m), children: "Verwijder" })
363
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-1", children: [
364
+ /* @__PURE__ */ jsx(
365
+ Button,
366
+ {
367
+ variant: "ghost",
368
+ size: "sm",
369
+ className: "text-xs",
370
+ onClick: () => void navigator.clipboard?.writeText(m.url).then(() => toast({ title: "Adres gekopieerd", tone: "success" })).catch(() => toast({ title: "Kopi\xEBren lukte niet", description: m.url, tone: "error" })),
371
+ children: "Kopieer adres"
372
+ }
373
+ ),
374
+ /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", className: "text-xs", onClick: () => void download(m), children: "Download" }),
375
+ /* @__PURE__ */ jsx(Button, { variant: "dangerGhost", size: "sm", className: "text-xs", onClick: () => void remove(m), children: "Verwijderen" })
243
376
  ] })
244
377
  ] }, m.id)),
245
- items.length === 0 && /* @__PURE__ */ jsx("p", { className: "text-sm text-slate-500", children: "Nog geen media." }),
246
- items.length > 0 && getoond.length === 0 && /* @__PURE__ */ jsxs("p", { className: "text-sm text-slate-500", children: [
247
- "Geen foto's gevonden voor \u201C",
248
- zoek,
249
- "\u201D."
250
- ] })
378
+ items.length === 0 && /* @__PURE__ */ jsx(LegeStaat, { titel: "Nog geen foto's", tekst: "Sleep foto's hierheen of gebruik Uploaden. Ze worden vanzelf verkleind en in meerdere formaten klaargezet." }),
379
+ items.length > 0 && getoond.length === 0 && /* @__PURE__ */ jsx("p", { className: "text-sm text-slate-500", children: zonderAlt && !term ? "Alle foto's hebben een beschrijving." : `Geen foto's gevonden voor \u201C${zoek}\u201D.` })
251
380
  ] }),
252
381
  hasMore && /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(Button, { variant: "secondary", size: "sm", onClick: () => setPageCount((c) => c + 1), children: "Meer laden\u2026" }) })
253
382
  ]
@@ -264,13 +393,14 @@ function AltInput({ item, onSave }) {
264
393
  Input,
265
394
  {
266
395
  value,
267
- placeholder: "Alt-tekst",
268
- className: "mb-2 h-8 text-xs",
396
+ placeholder: "Beschrijving (alt-tekst)",
397
+ "aria-label": `Beschrijving van ${item.name ?? "de foto"} voor schermlezers en Google`,
398
+ className: "mb-2 text-xs",
269
399
  onChange: (e) => setValue(e.target.value),
270
400
  onFocus: () => setFocused(true),
271
401
  onBlur: () => {
272
402
  setFocused(false);
273
- void onSave(item, value);
403
+ if (value !== (item.alt ?? "")) void onSave(item, value);
274
404
  }
275
405
  }
276
406
  );