@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
@@ -13,14 +13,19 @@ import { ModulesProvider } from "./modules/context.js";
13
13
  import { applyBlockOverrides } from "./modules/overrides.js";
14
14
  import { builtinModules } from "./modules/builtins.js";
15
15
  import { EditorProvider } from "./editor/EditorProvider.js";
16
- import { isDarkColor } from "./theme/color.js";
16
+ import { isDarkColor, tekstOpKleur } from "./theme/color.js";
17
17
  import { SiteSettingsProvider, useSiteSettings, useSiteSettingsLiveSync } from "./settings/useSiteSettings.js";
18
18
  import { mergeThemeTokens } from "./schema/settings.js";
19
19
  import { initAppCheck } from "./firebase/appcheck.js";
20
20
  import { setDemoActive } from "./demo/demoStore.js";
21
+ import { fontStylesheet, isGoogleFontUrl } from "./theme/fonts.js";
22
+ import { fallbackFontFaces, metFallback } from "./theme/fontFallback.js";
23
+ import { preconnect } from "react-dom";
21
24
  import { Theme } from "@astryxdesign/core/theme";
22
25
  import { neutralTheme } from "@astryxdesign/theme-neutral/built";
23
26
  import { LinkProvider } from "@astryxdesign/core/Link";
27
+ import { InternationalizationProvider } from "@astryxdesign/core/i18n";
28
+ import nlNL from "@astryxdesign/core/locales/nl-NL.generated.js";
24
29
  import { ImageProvider } from "./media/ImageContext.js";
25
30
  import { validateSiteConfig } from "./schema/siteConfig.js";
26
31
  import { validateModuleContract } from "./modules/contract.js";
@@ -35,6 +40,7 @@ function warnOnce(message) {
35
40
  function XiCMSProvider({ config, blocks = NO_BLOCKS, modules = NO_MODULES, overrides, astryxTheme, linkComponent, imageComponent, customBlocksData, settingsData, children }) {
36
41
  useEffect(() => {
37
42
  if (!process.env.NEXT_PUBLIC_FIREBASE_APPCHECK_KEY) return;
43
+ if (!/^\/(beheer|login)(\/|$)/.test(window.location.pathname)) return;
38
44
  void initAppCheck();
39
45
  }, []);
40
46
  useEffect(() => {
@@ -85,7 +91,7 @@ function themeCssVars(theme) {
85
91
  "--xicms-bg": ld(theme.background ?? "#ffffff", theme.dark?.background ?? "#0f172a"),
86
92
  "--xicms-fg": ld(theme.foreground ?? "#0f172a", theme.dark?.foreground ?? "#e2e8f0")
87
93
  };
88
- if (theme.fontFamily) cssVars["--xicms-font"] = theme.fontFamily;
94
+ if (theme.fontFamily) cssVars["--xicms-font"] = metFallback(theme.fontFamily);
89
95
  for (const [k, v] of Object.entries(theme.spacing ?? {})) if (v) cssVars[`--xicms-spacing-${k}`] = v;
90
96
  if (theme.radius?.sm) cssVars["--xicms-radius-sm"] = theme.radius.sm;
91
97
  if (theme.radius?.md) cssVars["--xicms-radius"] = theme.radius.md;
@@ -96,7 +102,7 @@ function themeCssVars(theme) {
96
102
  if (theme.dark?.foreground) cssVars["--xicms-fg-dark"] = theme.dark.foreground;
97
103
  if (theme.dark?.primary) cssVars["--xicms-primary-dark"] = theme.dark.primary;
98
104
  cssVars["--color-accent"] = "var(--xicms-primary)";
99
- const onAccent = isDarkColor(theme.primary) ? "#ffffff" : "#0f172a";
105
+ const onAccent = tekstOpKleur(theme.primary) ?? "#0f172a";
100
106
  cssVars["--color-on-accent"] = onAccent;
101
107
  cssVars["--xicms-on-primary"] = onAccent;
102
108
  cssVars["--color-text-accent"] = "var(--xicms-primary)";
@@ -120,7 +126,7 @@ function themeCssVars(theme) {
120
126
  cssVars["--xicms-border"] = "color-mix(in srgb, var(--xicms-fg) 12%, transparent)";
121
127
  cssVars["--xicms-border-strong"] = "color-mix(in srgb, var(--xicms-fg) 22%, transparent)";
122
128
  }
123
- if (theme.headingFont) cssVars["--xicms-font-heading"] = theme.headingFont;
129
+ if (theme.headingFont) cssVars["--xicms-font-heading"] = metFallback(theme.headingFont);
124
130
  if (theme.fontFamily) {
125
131
  cssVars["--font-family-body"] = "var(--xicms-font)";
126
132
  cssVars["--font-family-heading"] = theme.headingFont ? "var(--xicms-font-heading)" : "var(--xicms-font)";
@@ -143,6 +149,10 @@ function ModuleLayer({
143
149
  const { settings } = useSiteSettings();
144
150
  const theme = useMemo(() => mergeThemeTokens(config.theme, settings.theme), [config.theme, settings.theme]);
145
151
  const cssVars = useMemo(() => themeCssVars(theme), [theme]);
152
+ const fontFallbackCss = useMemo(() => fallbackFontFaces([theme.fontFamily, theme.headingFont]), [theme.fontFamily, theme.headingFont]);
153
+ if (theme.fontUrl && !config.selfHostFonts && isGoogleFontUrl(theme.fontUrl)) {
154
+ preconnect("https://fonts.gstatic.com", { crossOrigin: "anonymous" });
155
+ }
146
156
  useEffect(() => {
147
157
  setDemoActive(Boolean(config.demoEditing));
148
158
  }, [config.demoEditing]);
@@ -164,8 +174,10 @@ function ModuleLayer({
164
174
  /* @__PURE__ */ jsx(CustomBlocksSync, { siteId: config.siteId, onData: setCustomBlocks }),
165
175
  /* @__PURE__ */ jsx(SiteSettingsSync, { siteId: config.siteId }),
166
176
  /* @__PURE__ */ jsx(ThemeVarsCtx.Provider, { value: { vars: cssVars, darkAuto: themeDarkMode(theme) === "auto" }, children: /* @__PURE__ */ jsxs(EditorProvider, { children: [
167
- theme.fontUrl && /* @__PURE__ */ jsx("link", { rel: "stylesheet", href: theme.fontUrl }),
168
- /* @__PURE__ */ jsx(Theme, { theme: astryxTheme ?? neutralTheme, mode: themeDarkMode(theme) === "auto" ? "system" : themeDarkMode(theme) === "dark" || isDarkColor(theme.background) ? "dark" : "light", children: /* @__PURE__ */ jsx(LinkProvider, { component: linkComponent ?? "a", children: /* @__PURE__ */ jsx(ImageProvider, { component: imageComponent, children: /* @__PURE__ */ jsx(
177
+ theme.fontUrl && /* @__PURE__ */ jsx("link", { rel: "stylesheet", href: fontStylesheet(theme.fontUrl, config.selfHostFonts) }),
178
+ fontFallbackCss && /* @__PURE__ */ jsx("style", { href: "xicms-font-fallback", precedence: "xicms", children: fontFallbackCss }),
179
+ config.paginaOvergang && /* @__PURE__ */ jsx("style", { href: "xicms-paginaovergang", precedence: "xicms", children: "@view-transition{navigation:auto}" }),
180
+ /* @__PURE__ */ jsx(Theme, { theme: astryxTheme ?? neutralTheme, mode: themeDarkMode(theme) === "auto" ? "system" : themeDarkMode(theme) === "dark" || isDarkColor(theme.background) ? "dark" : "light", children: /* @__PURE__ */ jsx(InternationalizationProvider, { ...astryxLocale(config.lang), children: /* @__PURE__ */ jsx(LinkProvider, { component: linkComponent ?? "a", children: /* @__PURE__ */ jsx(ImageProvider, { component: imageComponent, children: /* @__PURE__ */ jsx(
169
181
  "div",
170
182
  {
171
183
  className: "xicms-root",
@@ -173,7 +185,7 @@ function ModuleLayer({
173
185
  style: cssVars,
174
186
  children
175
187
  }
176
- ) }) }) })
188
+ ) }) }) }) })
177
189
  ] }) })
178
190
  ] }) }) });
179
191
  }
@@ -231,6 +243,10 @@ function CustomBlocksSync({ siteId, onData }) {
231
243
  }, [editing, siteId, onData]);
232
244
  return null;
233
245
  }
246
+ function astryxLocale(lang) {
247
+ const l = (lang ?? "nl").toLowerCase();
248
+ return l === "nl" || l.startsWith("nl-") ? { locale: "nl-NL", messages: { "nl-NL": nlNL } } : { locale: "en" };
249
+ }
234
250
  export {
235
251
  XiCMSProvider,
236
252
  isDarkColor,
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/XiCMSProvider.tsx"],"sourcesContent":["\"use client\";\n\nimport { createContext, useContext, useEffect, useMemo, useState, type ReactNode } from \"react\";\nimport { ConfigProvider } from \"./config\";\nimport { AuthProvider, useAuth } from \"./auth/AuthProvider\";\nimport { canEdit } from \"./auth/roles\";\nimport { RegistryProvider } from \"./blocks/context\";\nimport { createRegistry, mergeRegistry, type BlockDefinition } from \"./blocks/registry\";\nimport { CustomBlockSchema, type CustomBlock as CustomBlockData } from \"./schema/customBlocks\";\nimport { customBlockToDefinition } from \"./blocks/customTemplate/definition\";\nimport { resolveModules } from \"./modules/registry\";\nimport { ModulesProvider } from \"./modules/context\";\nimport { applyBlockOverrides, type BlockOverrides } from \"./modules/overrides\";\nimport { builtinModules } from \"./modules/builtins\";\nimport type { ModuleDefinition, ModulesSiteConfig } from \"./modules/types\";\nimport { EditorProvider } from \"./editor/EditorProvider\";\n// Puur en dependency-vrij; hier alleen nog geherexporteerd zodat de publieke API gelijk blijft.\nimport { isDarkColor } from \"./theme/color\";\nexport { isDarkColor };\nimport { SiteSettingsProvider, useSiteSettings, useSiteSettingsLiveSync } from \"./settings/useSiteSettings\";\nimport { mergeThemeTokens, type ThemeTokens, type PublicSiteSettings } from \"./schema/settings\";\nimport { initAppCheck } from \"./firebase/appcheck\";\nimport { setDemoActive } from \"./demo/demoStore\";\nimport { Theme, type DefinedTheme } from \"@astryxdesign/core/theme\";\nimport { neutralTheme } from \"@astryxdesign/theme-neutral/built\";\nimport { LinkProvider, type LinkComponentType } from \"@astryxdesign/core/Link\";\nimport { ImageProvider, type ImageComponentType } from \"./media/ImageContext\";\nimport { validateSiteConfig, type SiteConfig } from \"./schema/siteConfig\";\nimport { validateModuleContract } from \"./modules/contract\";\n\ninterface ProviderProps {\n config: SiteConfig;\n /** Losse klant-blokken (via `defineBlock`) buiten een module om. Altijd actief. */\n blocks?: BlockDefinition[];\n /**\n * Klant-modules (via `defineModule`) bovenop de ingebouwde. Worden gemerged op `id` (klant wint)\n * en respecteren `config.modules` voor activatie.\n */\n modules?: ModuleDefinition[];\n /**\n * Per-site presentatie-overrides per block-type (`{ gallery: { Render: MijnGalerij } }`). Vervangt\n * alleen het uiterlijk; schema/editor/logica blijven van core. De krachtigste maatwerk-naad.\n */\n overrides?: BlockOverrides;\n /**\n * SSR-startset van custom blocks (5.0): geef het resultaat van `getSiteCustomBlocks(siteId)`\n * (server) door zodat runtime-gedefinieerde blokken al in de server-HTML zitten. Zonder deze\n * prop laadt de provider ze alsnog client-side (werkend, maar pas na hydratie zichtbaar).\n */\n customBlocksData?: CustomBlockData[];\n /**\n * SSR-startset van de publieke site-instellingen: geef het resultaat van\n * `getPublicSiteSettings(siteId)` (server) door zodat klant-thema/nav/footer al in de\n * server-HTML zitten (geen theme-flits bij eerste paint) én publiek geen client-read meer\n * doet — de ISR-gecachte layout ververst de settings per revalidate. Zonder deze prop laadt\n * de provider ze alsnog client-side (werkend, maar met mogelijke flits + 1 read per bezoeker).\n */\n settingsData?: PublicSiteSettings;\n /**\n * Astryx-basistheme voor de hele site (radius-/spacing-/neutralen-karakter). Standaard `neutral`.\n * Een site kan een ander pakket kiezen (`@astryxdesign/theme-butter`, `-stone`, …) of een eigen\n * `defineTheme(...)` doorgeven voor component-overrides — zónder core te forken.\n */\n astryxTheme?: DefinedTheme;\n /**\n * Framework-link-component (bv. Next `Link`) voor soepele client-navigatie + prefetch. Astryx-\n * componenten met een `href` (knoppen/links/tabs) gebruiken 'm dan i.p.v. een rauwe `<a>` (= volledige\n * page-reload). Core importeert `next/link` niet zelf (optionele peer) — geef 'm hier door vanuit de site.\n */\n linkComponent?: LinkComponentType;\n /**\n * Framework-beeldcomponent (bv. Next `Image`) voor automatische beeldoptimalisatie (responsive\n * srcset, AVIF/WebP, geen layout-shift). Core importeert `next/image` niet zelf — geef 'm hier door.\n */\n imageComponent?: ImageComponentType;\n children: ReactNode;\n}\n\n// Stabiele lege defaults: een `= []`-defaultparameter maakt bij ELKE render een nieuwe\n// array-referentie en laat memo's/effects met `modules`/`blocks` in de deps onnodig hervuren.\nconst NO_BLOCKS: BlockDefinition[] = [];\nconst NO_MODULES: ModuleDefinition[] = [];\n\n// Dev-waarschuwingen één keer per boodschap (React strict-mode dubbelt effects; zonder dedupe\n// verschijnt dezelfde config-waarschuwing telkens opnieuw in de console).\nconst warned = new Set<string>();\nfunction warnOnce(message: string) {\n if (warned.has(message)) return;\n warned.add(message);\n console.warn(message);\n}\n\n/**\n * Wikkel de hele site in deze provider (in `app/layout.tsx`). Hij zet:\n * - de SiteConfig-context (siteId, theme, mode) + live publieke settings (footer/nav/modules);\n * - auth + content (Firebase, env-gedreven; werkt ook zonder Firebase);\n * - de block-registry (ingebouwde + klant-blokken) voor de page-renderer;\n * - de themavariabelen als CSS custom properties;\n * - App Check (alleen als geconfigureerd).\n *\n * De ZICHTBARE site-chrome (bewerkbalk, cookiebanner, demo) staat in `<SiteChrome />` en hoort in\n * de layout van je publieke routes — niet hier, anders verschijnt hij ook over /beheer.\n */\nexport function XiCMSProvider({ config, blocks = NO_BLOCKS, modules = NO_MODULES, overrides, astryxTheme, linkComponent, imageComponent, customBlocksData, settingsData, children }: ProviderProps) {\n useEffect(() => {\n // App Check hoort bij het praten mét Firebase; een bezoeker doet dat niet. Alleen aanroepen\n // als er een sleutel is, en de module zelf laadt zijn SDK dynamisch.\n if (!process.env.NEXT_PUBLIC_FIREBASE_APPCHECK_KEY) return;\n void initAppCheck();\n }, []);\n\n // Dev-vangnet: ontbrekende SSR-seeds. Zonder `settingsData` haalt élke bezoeker de publieke\n // settings zelf uit Firestore — één read per bezoeker, én het downloaden van de Firebase-SDK\n // (~680 KB) die anders nooit nodig is. Dat faalt volkomen stil: de site ziet er goed uit.\n // De referentiesite groenhof liep hier maandenlang op, dus: melden zodra het misgaat.\n useEffect(() => {\n if (process.env.NODE_ENV === \"production\") return;\n if (!process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID) return; // geen Firebase → geen client-read\n if (settingsData === undefined) {\n warnOnce(\n \"[xicms] `settingsData` ontbreekt op XiCMSProvider. Elke bezoeker doet daardoor zélf een \" +\n \"Firestore-read voor de site-instellingen en downloadt de Firebase-SDK. Lees ze server-side \" +\n \"in je layout met `getPublicSiteSettings(siteId)` en geef ze door — zie template/app/layout.tsx.\",\n );\n }\n if (customBlocksData === undefined) {\n warnOnce(\n \"[xicms] `customBlocksData` ontbreekt op XiCMSProvider. Custom blocks worden dan pas na \" +\n \"hydratie zichtbaar (SEO-gat + flits). Lees ze server-side met `getSiteCustomBlocks(siteId)`.\",\n );\n }\n }, [settingsData, customBlocksData]);\n\n // Dev-vangnet voor (agent-)geschreven configs: meld config- en module-contractfouten meteen in\n // de console i.p.v. een subtiel kapotte site. In productie geen werk — en er wordt nooit gegooid.\n useEffect(() => {\n if (process.env.NODE_ENV === \"production\") return;\n const configIssues = validateSiteConfig(config);\n if (configIssues.length > 0) {\n warnOnce(`[xicms] site.config.ts bevat problemen:\\n- ${configIssues.join(\"\\n- \")}`);\n }\n if (modules.length > 0) {\n const contractIssues = validateModuleContract(modules);\n if (contractIssues.length > 0) {\n warnOnce(`[xicms] klant-modules voldoen niet aan het module-contract:\\n- ${contractIssues.join(\"\\n- \")}`);\n }\n }\n }, [config, modules]);\n\n return (\n <ConfigProvider config={config}>\n <SiteSettingsProvider siteId={config.siteId} initial={settingsData}>\n <ModuleLayer config={config} blocks={blocks} modules={modules} overrides={overrides} astryxTheme={astryxTheme} linkComponent={linkComponent} imageComponent={imageComponent} customBlocksData={customBlocksData}>\n {children}\n </ModuleLayer>\n </SiteSettingsProvider>\n </ConfigProvider>\n );\n}\n\n/**\n * De berekende theme-tokens, beschikbaar BUITEN `.xicms-root`.\n *\n * De visuele editor rendert als overlay naast die div (EditorProvider staat erboven in de boom),\n * dus zijn canvas erfde de merk-tokens niet: een groene primaire kleur werd daar de globale\n * indigo-fallback, en knoptekst kon zelfs samenvallen met de knopachtergrond. Door dezelfde\n * `cssVars` via context te delen toont het canvas exact wat de bezoeker straks ziet — zonder de\n * mapping te dupliceren of de overlay-structuur te verbouwen.\n */\nconst ThemeVarsCtx = createContext<{ vars: Record<string, string>; darkAuto: boolean }>({ vars: {}, darkAuto: false });\n\n/** Theme-tokens van de live site — voor UI die buiten `.xicms-root` rendert (de editor). */\nexport function useThemeVars() {\n return useContext(ThemeVarsCtx);\n}\n\n/**\n * Theme-tokens → CSS custom properties. Puur; wordt in `ModuleLayer` op het LIVE-gemergde thema\n * toegepast (SiteConfig + `settings/public.theme`), zodat huisstijl-wijzigingen uit /beheer direct\n * op de site verschijnen — net als module-instellingen.\n */\n/**\n * De donkere modus in één plek bepaald, zodat de tokenwaarden en de `data-dark`/`color-scheme` op\n * `.xicms-root` nooit uit elkaar kunnen lopen. `mode` wint; zonder `mode` valt hij terug op de\n * oude boolean, zodat bestaande site-configs (auto: true/false) ongewijzigd blijven werken.\n */\nfunction themeDarkMode(theme: ThemeTokens): \"light\" | \"dark\" | \"auto\" {\n return theme.dark?.mode ?? (theme.dark?.auto ? \"auto\" : \"light\");\n}\n\nfunction themeCssVars(theme: ThemeTokens): Record<string, string> {\n // Dark-auto via light-dark(): deze variabelen staan INLINE op `.xicms-root`, en inline wint\n // altijd van het `@media (prefers-color-scheme: dark)`-blok in styles.css. Alleen dat blok kan\n // een inline lichte waarde dus nooit overrulen — de tokenwaarde zelf moet meeschakelen.\n // (styles.css zet `color-scheme: light dark` op `[data-dark=\"auto\"]`, vereist voor light-dark().)\n // Driestand. `mode` wint; zonder `mode` valt hij terug op de oude boolean, zodat bestaande\n // site-configs (auto: true/false) ongewijzigd blijven werken.\n const donkerModus = themeDarkMode(theme);\n const auto = donkerModus === \"auto\";\n // Bij \"auto\" schakelt de tokenwaarde zélf mee via light-dark(); bij een vaste stand kiezen we hier\n // al. Dat moet op tokenniveau en niet via een @media-blok, want deze variabelen staan INLINE op\n // `.xicms-root` en inline wint altijd van een media-query in styles.css.\n const ld = (light: string, dark: string) =>\n donkerModus === \"auto\" ? `light-dark(${light}, ${dark})` : donkerModus === \"dark\" ? dark : light;\n const cssVars: Record<string, string> = {\n \"--xicms-primary\": theme.dark?.primary ? ld(theme.primary, theme.dark.primary) : theme.primary,\n \"--xicms-accent\": theme.accent ?? theme.primary,\n \"--xicms-bg\": ld(theme.background ?? \"#ffffff\", theme.dark?.background ?? \"#0f172a\"),\n \"--xicms-fg\": ld(theme.foreground ?? \"#0f172a\", theme.dark?.foreground ?? \"#e2e8f0\"),\n };\n if (theme.fontFamily) cssVars[\"--xicms-font\"] = theme.fontFamily;\n // Optionele schalen → CSS-variabelen (alleen gezet als opgegeven; styles.css heeft defaults).\n for (const [k, v] of Object.entries(theme.spacing ?? {})) if (v) cssVars[`--xicms-spacing-${k}`] = v;\n if (theme.radius?.sm) cssVars[\"--xicms-radius-sm\"] = theme.radius.sm;\n if (theme.radius?.md) cssVars[\"--xicms-radius\"] = theme.radius.md;\n if (theme.radius?.lg) cssVars[\"--xicms-radius-lg\"] = theme.radius.lg;\n if (theme.container?.maxWidth) cssVars[\"--xicms-container-max\"] = theme.container.maxWidth;\n if (theme.container?.padding) cssVars[\"--xicms-container-pad\"] = theme.container.padding;\n if (theme.dark?.background) cssVars[\"--xicms-bg-dark\"] = theme.dark.background;\n if (theme.dark?.foreground) cssVars[\"--xicms-fg-dark\"] = theme.dark.foreground;\n if (theme.dark?.primary) cssVars[\"--xicms-primary-dark\"] = theme.dark.primary;\n\n // Astryx-tokens op XiCMS-waarden mappen, zodat de Astryx-componenten elke site z'n eigen merk\n // (kleur/typografie/radius) volgen. Inline op `.xicms-root` → wint over de theme.css-defaults.\n cssVars[\"--color-accent\"] = \"var(--xicms-primary)\";\n // Tekst óp de accentkleur: wit op een donkere merkkleur, donker op een lichte (geel/pastel) —\n // hardcoded wit maakte knop- en bannertekst onleesbaar op lichte primaire kleuren.\n const onAccent = isDarkColor(theme.primary) ? \"#ffffff\" : \"#0f172a\";\n cssVars[\"--color-on-accent\"] = onAccent;\n cssVars[\"--xicms-on-primary\"] = onAccent;\n cssVars[\"--color-text-accent\"] = \"var(--xicms-primary)\";\n cssVars[\"--radius-element\"] = \"var(--xicms-radius-sm, 8px)\";\n cssVars[\"--radius-container\"] = \"var(--xicms-radius, 14px)\";\n cssVars[\"--radius-page\"] = \"var(--xicms-radius-lg, 24px)\";\n // Volledige paletmapping — ALLEEN als de site een eigen achtergrond/tekst kiest. Zo verschilt niet\n // enkel het accent maar de hele sfeer (kaarten, borders, secundaire tekst) per site; een minimale\n // config blijft op de gepolijste neutrale basis (incl. automatische dark-mode via light-dark()).\n if (theme.background) {\n cssVars[\"--color-background-body\"] = \"var(--xicms-bg)\";\n cssVars[\"--color-background-surface\"] = \"color-mix(in srgb, var(--xicms-fg) 4%, var(--xicms-bg))\";\n cssVars[\"--color-background-card\"] = \"color-mix(in srgb, var(--xicms-fg) 3%, var(--xicms-bg))\";\n cssVars[\"--color-background-popover\"] = \"var(--xicms-bg)\";\n cssVars[\"--color-background-muted\"] = \"color-mix(in srgb, var(--xicms-fg) 6%, var(--xicms-bg))\";\n // Ook de XiCMS-oppervlaktetokens meeschakelen: hun defaults in styles.css zijn licht (#fff/zwart-\n // rgba) en het dark-blok vuurt alleen bij `data-dark=\"auto\"`. Zonder deze mapping tonen presets\n // met een vaste donkere achtergrond (donker-modern, luxe-donker) witte kaarten en zwarte borders.\n cssVars[\"--xicms-surface\"] = \"color-mix(in srgb, var(--xicms-fg) 3%, var(--xicms-bg))\";\n cssVars[\"--xicms-muted\"] = \"color-mix(in srgb, var(--xicms-fg) 5%, var(--xicms-bg))\";\n }\n if (theme.foreground) {\n cssVars[\"--color-text-primary\"] = \"var(--xicms-fg)\";\n cssVars[\"--color-text-secondary\"] = \"color-mix(in srgb, var(--xicms-fg) 65%, transparent)\";\n cssVars[\"--color-neutral\"] = \"var(--xicms-fg)\";\n cssVars[\"--color-border\"] = \"color-mix(in srgb, var(--xicms-fg) 14%, transparent)\";\n cssVars[\"--xicms-border\"] = \"color-mix(in srgb, var(--xicms-fg) 12%, transparent)\";\n cssVars[\"--xicms-border-strong\"] = \"color-mix(in srgb, var(--xicms-fg) 22%, transparent)\";\n }\n if (theme.headingFont) cssVars[\"--xicms-font-heading\"] = theme.headingFont;\n if (theme.fontFamily) {\n cssVars[\"--font-family-body\"] = \"var(--xicms-font)\";\n // Koppen volgen een apart display/serif-font als dat is opgegeven, anders het body-font.\n cssVars[\"--font-family-heading\"] = theme.headingFont ? \"var(--xicms-font-heading)\" : \"var(--xicms-font)\";\n } else if (theme.headingFont) {\n cssVars[\"--font-family-heading\"] = \"var(--xicms-font-heading)\";\n }\n\n return cssVars;\n}\n\n/**\n * Binnenlaag: leest de live publieke settings en resolvet daarmee de modules (settings/public.modules\n * legt zich over SiteConfig.modules) én het thema (settings/public.theme over SiteConfig.theme).\n * Zo werken module-aan/uit, -instellingen én huisstijl die de klant in /beheer zet direct door.\n */\nfunction ModuleLayer({\n config,\n blocks = NO_BLOCKS,\n modules = NO_MODULES,\n overrides,\n customBlocksData,\n astryxTheme,\n linkComponent,\n imageComponent,\n children,\n}: ProviderProps) {\n const { settings } = useSiteSettings();\n\n // LIVE thema: wijzigingen uit /beheer (settings/public.theme) winnen per token van SiteConfig.\n const theme = useMemo(() => mergeThemeTokens(config.theme, settings.theme), [config.theme, settings.theme]);\n const cssVars = useMemo(() => themeCssVars(theme), [theme]);\n\n // Demo-bewerkmodus globaal markeren zodat de (Firebase-)dataclients lokaal-only werken.\n // In een effect (niet tijdens render): render-pure + veilig onder concurrent rendering. De\n // demoStore-default is `false`, dus vóór het effect gedraagt alles zich als niet-demo.\n useEffect(() => {\n setDemoActive(Boolean(config.demoEditing));\n }, [config.demoEditing]);\n\n const resolved = useMemo(\n () =>\n resolveModules([...builtinModules, ...modules], {\n modules: config.modules,\n firestoreModules: settings.modules as ModulesSiteConfig | undefined,\n }),\n [config.modules, modules, settings.modules],\n );\n\n // Custom blocks (5.0): runtime-gedefinieerde bloktypes uit sites/{siteId}/customBlocks.\n // Publieke bezoekers krijgen UITSLUITEND de SSR-startset (customBlocksData, server-side gelezen) —\n // géén Firestore-listener per bezoeker (kosten/verbinding). Alleen ingelogde editors krijgen een\n // live sync (CustomBlocksSync, binnen AuthProvider) zodat een nieuw blok uit /beheer of een\n // agent-push zonder redeploy in het toevoeg-menu en op de pagina verschijnt.\n const [customBlocks, setCustomBlocks] = useState<CustomBlockData[]>(customBlocksData ?? []);\n const customDefs = useMemo(() => customBlocks.map(customBlockToDefinition), [customBlocks]);\n\n const registry = useMemo(\n () => applyBlockOverrides(mergeRegistry(mergeRegistry(createRegistry(resolved.blocks), customDefs), blocks), overrides),\n [resolved.blocks, customDefs, blocks, overrides],\n );\n\n return (\n <ModulesProvider value={resolved}>\n <RegistryProvider registry={registry}>\n <AuthProvider siteId={config.siteId} demo={Boolean(config.demoEditing)}>\n <PreviewDraftSync />\n <CustomBlocksSync siteId={config.siteId} onData={setCustomBlocks} />\n <SiteSettingsSync siteId={config.siteId} />\n <ThemeVarsCtx.Provider value={{ vars: cssVars, darkAuto: themeDarkMode(theme) === \"auto\" }}>\n <EditorProvider>\n {/* React 19 hijst <link rel=\"stylesheet\"> automatisch naar <head> → lettertype laadt. */}\n {theme.fontUrl && <link rel=\"stylesheet\" href={theme.fontUrl} />}\n {/* Astryx-thema (Neutral basis) — de XiCMS-token-mapping op `.xicms-root` legt elke\n site z'n eigen merk eroverheen. */}\n <Theme theme={astryxTheme ?? neutralTheme} mode={themeDarkMode(theme) === \"auto\" ? \"system\" : themeDarkMode(theme) === \"dark\" || isDarkColor(theme.background) ? \"dark\" : \"light\"}>\n {/* Framework-router voor Astryx-links/knoppen (soepele client-nav + prefetch);\n zonder `linkComponent` valt het terug op een gewone `<a>` (huidig gedrag). */}\n <LinkProvider component={linkComponent ?? \"a\"}>\n <ImageProvider component={imageComponent}>\n <div\n className=\"xicms-root\"\n // Stuurt `color-scheme` (styles.css): \"auto\" = light dark, \"dark\" = dark.\n data-dark={themeDarkMode(theme) === \"light\" ? undefined : themeDarkMode(theme)}\n style={cssVars as React.CSSProperties}\n >\n {/* De zichtbare site-chrome (demo-balk, bewerkbalk, feedback, cookiebanner) is\n BEWUST geen onderdeel meer van de provider: die hoort bij het site-oppervlak\n en werd zo ook over /beheer heen gerenderd — een cookiebanner en een\n \"Zet live\"-balk bovenop het CMS. Sites renderen nu `<SiteChrome />` in hun\n eigen (site)-layout; zie ./SiteChrome.tsx. */}\n {children}\n </div>\n </ImageProvider>\n </LinkProvider>\n </Theme>\n </EditorProvider>\n </ThemeVarsCtx.Provider>\n </AuthProvider>\n </RegistryProvider>\n </ModulesProvider>\n );\n}\n\n/**\n * Live sync van custom blocks — ALLEEN voor ingelogde editors. Publieke bezoekers krijgen de\n * SSR-startset (customBlocksData) en géén Firestore-listener: dat scheelt een collection-read +\n * open verbinding per bezoeker, conform het getDoc-voor-publiek-patroon van useSiteSettings/News.\n */\n/**\n * Live sync van de publieke site-instellingen — ALLEEN voor ingelogde editors (zelfde patroon als\n * CustomBlocksSync). Zo ziet een editor een /beheer-wijziging (footer/nav/thema) meteen op de site,\n * terwijl publiek op de SSR-seed (settingsData) of de eenmalige getDoc blijft draaien.\n */\n/**\n * Zet Next's Draft Mode aan zodra een editor is ingelogd, zodat de pagina-route de gecommitte\n * content-bundel + de ISR-cache overslaat (server/pages.ts, `opts.skipBundle`) en deze browser\n * altijd de nieuwste GEPUBLICEERDE stand ziet — een publicatie in /beheer komt anders pas via het\n * ISR-vangnet mee.\n *\n * WAAROM EEN FETCH EN GEEN `document.cookie` ZOALS HIERVOOR: de vorige opzet zette zelf een\n * `xicms-preview`-cookie, die een proxy vertaalde naar `?preview=1`. Dat werkte niet: een route\n * die `searchParams` in zijn signatuur heeft merkt Next áltijd als dynamisch — ongeacht of de\n * proxy ooit herschrijft. Gemeten op groenhof: `ƒ (Dynamic)` met\n * `Cache-Control: private, no-cache, no-store` voor élke bezoeker. De cache was dus voor iedereen\n * stuk om een knop te bedienen die alleen de beheerder gebruikt.\n *\n * Draft Mode lost precies dát op: het zet de ondertekende `__prerender_bypass`-cookie die Next\n * VÓÓR de cache controleert, buiten de route om. Gemeten met dezelfde opzet: publiek houdt\n * `● (SSG)` met `s-maxage=300`, terwijl het request mét cookie `private, no-cache, no-store`\n * krijgt en vers rendert.\n *\n * Draagt geen rechten — net als de oude cookie. Er wordt nooit meer getoond dan de al-publieke,\n * gepubliceerde content, dus zelf `/api/draft` aanroepen levert hoogstens een verse blik op iets\n * dat toch al openbaar is. Wat het wél kost is een ongecachte render per request; wil je dat\n * dichttimmeren, laat de route dan een Firebase-ID-token verifiëren voor hij `enable()` doet.\n *\n * Faalt stil en onschadelijk als de site `/api/draft` niet heeft (zie template/): dan blijft de\n * beheerder gewoon op de gecachte stand, precies zoals een site zonder preview.\n */\nfunction PreviewDraftSync() {\n const { role } = useAuth();\n useEffect(() => {\n const gewenst = canEdit(role);\n // Alleen aanroepen als de stand écht moet veranderen. Zonder deze vergelijking zou élke\n // publieke bezoeker bij élke paginaweergave een POST doen om preview \"uit\" te zetten die al\n // uit stond — een serverless-aanroep per bezoeker, precies de kosten die deze hele omzetting\n // moet vermijden.\n //\n // De marker is een SESSIE-cookie, net als Next's `__prerender_bypass`: die laatste is httpOnly\n // en dus onleesbaar voor deze code, dus we houden er zelf een spiegel van bij. Omdat beide\n // met het browservenster verdwijnen lopen ze niet uit de pas — een marker die de cookie\n // overleeft zou preview stilletjes uitgeschakeld laten.\n const gemarkeerd = document.cookie.includes(\"xicms-draft=1\");\n if (gewenst === gemarkeerd) return;\n void fetch(`/api/draft?aan=${gewenst ? \"1\" : \"0\"}`, { method: \"POST\" })\n .then((r) => {\n if (!r.ok) return; // site zonder /api/draft: laat de marker met rust, dan blijft dit stil.\n document.cookie = gewenst ? \"xicms-draft=1; path=/; samesite=lax\" : \"xicms-draft=; path=/; max-age=0\";\n })\n .catch(() => {});\n }, [role]);\n return null;\n}\n\nfunction SiteSettingsSync({ siteId }: { siteId: string }) {\n const { role } = useAuth();\n useSiteSettingsLiveSync(siteId, canEdit(role));\n return null;\n}\n\nfunction CustomBlocksSync({ siteId, onData }: { siteId: string; onData: (defs: CustomBlockData[]) => void }) {\n const { role } = useAuth();\n const editing = canEdit(role);\n useEffect(() => {\n // Alleen editors luisteren mee (kosten + verbinding), en de SDK laadt pas dán.\n if (!editing) return;\n let unsub: (() => void) | undefined;\n let afgebroken = false;\n void (async () => {\n const [{ getDb }, { collection, onSnapshot }] = await Promise.all([\n import(\"./firebase/client\"),\n import(\"firebase/firestore\"),\n ]);\n const db = getDb();\n if (!db || afgebroken) return;\n unsub = onSnapshot(\n collection(db, \"sites\", siteId, \"customBlocks\"),\n (snap) => {\n const defs: CustomBlockData[] = [];\n snap.forEach((d) => {\n const res = CustomBlockSchema.safeParse({ ...(d.data() as Record<string, unknown>), type: (d.data() as { type?: string }).type ?? d.id });\n if (res.success) defs.push(res.data);\n });\n onData(defs);\n },\n () => undefined, // leesfout → SSR-set blijft staan\n );\n })();\n return () => {\n afgebroken = true;\n unsub?.();\n };\n }, [editing, siteId, onData]);\n return null;\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/XiCMSProvider.tsx"],"sourcesContent":["\"use client\";\n\nimport { createContext, useContext, useEffect, useMemo, useState, type ReactNode } from \"react\";\nimport { ConfigProvider } from \"./config\";\nimport { AuthProvider, useAuth } from \"./auth/AuthProvider\";\nimport { canEdit } from \"./auth/roles\";\nimport { RegistryProvider } from \"./blocks/context\";\nimport { createRegistry, mergeRegistry, type BlockDefinition } from \"./blocks/registry\";\nimport { CustomBlockSchema, type CustomBlock as CustomBlockData } from \"./schema/customBlocks\";\nimport { customBlockToDefinition } from \"./blocks/customTemplate/definition\";\nimport { resolveModules } from \"./modules/registry\";\nimport { ModulesProvider } from \"./modules/context\";\nimport { applyBlockOverrides, type BlockOverrides } from \"./modules/overrides\";\nimport { builtinModules } from \"./modules/builtins\";\nimport type { ModuleDefinition, ModulesSiteConfig } from \"./modules/types\";\nimport { EditorProvider } from \"./editor/EditorProvider\";\n// Puur en dependency-vrij; hier alleen nog geherexporteerd zodat de publieke API gelijk blijft.\nimport { isDarkColor, tekstOpKleur } from \"./theme/color\";\nexport { isDarkColor };\nimport { SiteSettingsProvider, useSiteSettings, useSiteSettingsLiveSync } from \"./settings/useSiteSettings\";\nimport { mergeThemeTokens, type ThemeTokens, type PublicSiteSettings } from \"./schema/settings\";\nimport { initAppCheck } from \"./firebase/appcheck\";\nimport { setDemoActive } from \"./demo/demoStore\";\nimport { fontStylesheet, isGoogleFontUrl } from \"./theme/fonts\";\nimport { fallbackFontFaces, metFallback } from \"./theme/fontFallback\";\nimport { preconnect } from \"react-dom\";\nimport { Theme, type DefinedTheme } from \"@astryxdesign/core/theme\";\nimport { neutralTheme } from \"@astryxdesign/theme-neutral/built\";\nimport { LinkProvider, type LinkComponentType } from \"@astryxdesign/core/Link\";\nimport { InternationalizationProvider } from \"@astryxdesign/core/i18n\";\nimport nlNL from \"@astryxdesign/core/locales/nl-NL.generated.js\";\nimport { ImageProvider, type ImageComponentType } from \"./media/ImageContext\";\nimport { validateSiteConfig, type SiteConfig } from \"./schema/siteConfig\";\nimport { validateModuleContract } from \"./modules/contract\";\n\ninterface ProviderProps {\n config: SiteConfig;\n /** Losse klant-blokken (via `defineBlock`) buiten een module om. Altijd actief. */\n blocks?: BlockDefinition[];\n /**\n * Klant-modules (via `defineModule`) bovenop de ingebouwde. Worden gemerged op `id` (klant wint)\n * en respecteren `config.modules` voor activatie.\n */\n modules?: ModuleDefinition[];\n /**\n * Per-site presentatie-overrides per block-type (`{ gallery: { Render: MijnGalerij } }`). Vervangt\n * alleen het uiterlijk; schema/editor/logica blijven van core. De krachtigste maatwerk-naad.\n */\n overrides?: BlockOverrides;\n /**\n * SSR-startset van custom blocks (5.0): geef het resultaat van `getSiteCustomBlocks(siteId)`\n * (server) door zodat runtime-gedefinieerde blokken al in de server-HTML zitten. Zonder deze\n * prop laadt de provider ze alsnog client-side (werkend, maar pas na hydratie zichtbaar).\n */\n customBlocksData?: CustomBlockData[];\n /**\n * SSR-startset van de publieke site-instellingen: geef het resultaat van\n * `getPublicSiteSettings(siteId)` (server) door zodat klant-thema/nav/footer al in de\n * server-HTML zitten (geen theme-flits bij eerste paint) én publiek geen client-read meer\n * doet — de ISR-gecachte layout ververst de settings per revalidate. Zonder deze prop laadt\n * de provider ze alsnog client-side (werkend, maar met mogelijke flits + 1 read per bezoeker).\n */\n settingsData?: PublicSiteSettings;\n /**\n * Astryx-basistheme voor de hele site (radius-/spacing-/neutralen-karakter). Standaard `neutral`.\n * Een site kan een ander pakket kiezen (`@astryxdesign/theme-butter`, `-stone`, …) of een eigen\n * `defineTheme(...)` doorgeven voor component-overrides — zónder core te forken.\n */\n astryxTheme?: DefinedTheme;\n /**\n * Framework-link-component (bv. Next `Link`) voor soepele client-navigatie + prefetch. Astryx-\n * componenten met een `href` (knoppen/links/tabs) gebruiken 'm dan i.p.v. een rauwe `<a>` (= volledige\n * page-reload). Core importeert `next/link` niet zelf (optionele peer) — geef 'm hier door vanuit de site.\n */\n linkComponent?: LinkComponentType;\n /**\n * Framework-beeldcomponent (bv. Next `Image`) voor automatische beeldoptimalisatie (responsive\n * srcset, AVIF/WebP, geen layout-shift). Core importeert `next/image` niet zelf — geef 'm hier door.\n */\n imageComponent?: ImageComponentType;\n children: ReactNode;\n}\n\n// Stabiele lege defaults: een `= []`-defaultparameter maakt bij ELKE render een nieuwe\n// array-referentie en laat memo's/effects met `modules`/`blocks` in de deps onnodig hervuren.\nconst NO_BLOCKS: BlockDefinition[] = [];\nconst NO_MODULES: ModuleDefinition[] = [];\n\n// Dev-waarschuwingen één keer per boodschap (React strict-mode dubbelt effects; zonder dedupe\n// verschijnt dezelfde config-waarschuwing telkens opnieuw in de console).\nconst warned = new Set<string>();\nfunction warnOnce(message: string) {\n if (warned.has(message)) return;\n warned.add(message);\n console.warn(message);\n}\n\n/**\n * Wikkel de hele site in deze provider (in `app/layout.tsx`). Hij zet:\n * - de SiteConfig-context (siteId, theme, mode) + live publieke settings (footer/nav/modules);\n * - auth + content (Firebase, env-gedreven; werkt ook zonder Firebase);\n * - de block-registry (ingebouwde + klant-blokken) voor de page-renderer;\n * - de themavariabelen als CSS custom properties;\n * - App Check (alleen als geconfigureerd).\n *\n * De ZICHTBARE site-chrome (bewerkbalk, cookiebanner, demo) staat in `<SiteChrome />` en hoort in\n * de layout van je publieke routes — niet hier, anders verschijnt hij ook over /beheer.\n */\nexport function XiCMSProvider({ config, blocks = NO_BLOCKS, modules = NO_MODULES, overrides, astryxTheme, linkComponent, imageComponent, customBlocksData, settingsData, children }: ProviderProps) {\n useEffect(() => {\n // App Check hoort bij het praten mét Firebase; een bezoeker doet dat niet. 8.16: op de\n // publieke pagina's nu helemaal niet meer vooraf — reCAPTCHA laadde scripts van Google bij\n // ELKE bezoeker, ook zonder formulier of bestelling. `callable()` start het nu pas vlak vóór\n // een formulier/bestelling, en de AuthProvider zodra iemand inlogt. Alleen het beheer\n // (inlogscherm) start het meteen.\n if (!process.env.NEXT_PUBLIC_FIREBASE_APPCHECK_KEY) return;\n if (!/^\\/(beheer|login)(\\/|$)/.test(window.location.pathname)) return;\n void initAppCheck();\n }, []);\n\n // Dev-vangnet: ontbrekende SSR-seeds. Zonder `settingsData` haalt élke bezoeker de publieke\n // settings zelf uit Firestore — één read per bezoeker, én het downloaden van de Firebase-SDK\n // (~680 KB) die anders nooit nodig is. Dat faalt volkomen stil: de site ziet er goed uit.\n // De referentiesite groenhof liep hier maandenlang op, dus: melden zodra het misgaat.\n useEffect(() => {\n if (process.env.NODE_ENV === \"production\") return;\n if (!process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID) return; // geen Firebase → geen client-read\n if (settingsData === undefined) {\n warnOnce(\n \"[xicms] `settingsData` ontbreekt op XiCMSProvider. Elke bezoeker doet daardoor zélf een \" +\n \"Firestore-read voor de site-instellingen en downloadt de Firebase-SDK. Lees ze server-side \" +\n \"in je layout met `getPublicSiteSettings(siteId)` en geef ze door — zie template/app/layout.tsx.\",\n );\n }\n if (customBlocksData === undefined) {\n warnOnce(\n \"[xicms] `customBlocksData` ontbreekt op XiCMSProvider. Custom blocks worden dan pas na \" +\n \"hydratie zichtbaar (SEO-gat + flits). Lees ze server-side met `getSiteCustomBlocks(siteId)`.\",\n );\n }\n }, [settingsData, customBlocksData]);\n\n // Dev-vangnet voor (agent-)geschreven configs: meld config- en module-contractfouten meteen in\n // de console i.p.v. een subtiel kapotte site. In productie geen werk — en er wordt nooit gegooid.\n useEffect(() => {\n if (process.env.NODE_ENV === \"production\") return;\n const configIssues = validateSiteConfig(config);\n if (configIssues.length > 0) {\n warnOnce(`[xicms] site.config.ts bevat problemen:\\n- ${configIssues.join(\"\\n- \")}`);\n }\n if (modules.length > 0) {\n const contractIssues = validateModuleContract(modules);\n if (contractIssues.length > 0) {\n warnOnce(`[xicms] klant-modules voldoen niet aan het module-contract:\\n- ${contractIssues.join(\"\\n- \")}`);\n }\n }\n }, [config, modules]);\n\n return (\n <ConfigProvider config={config}>\n <SiteSettingsProvider siteId={config.siteId} initial={settingsData}>\n <ModuleLayer config={config} blocks={blocks} modules={modules} overrides={overrides} astryxTheme={astryxTheme} linkComponent={linkComponent} imageComponent={imageComponent} customBlocksData={customBlocksData}>\n {children}\n </ModuleLayer>\n </SiteSettingsProvider>\n </ConfigProvider>\n );\n}\n\n/**\n * De berekende theme-tokens, beschikbaar BUITEN `.xicms-root`.\n *\n * De visuele editor rendert als overlay naast die div (EditorProvider staat erboven in de boom),\n * dus zijn canvas erfde de merk-tokens niet: een groene primaire kleur werd daar de globale\n * indigo-fallback, en knoptekst kon zelfs samenvallen met de knopachtergrond. Door dezelfde\n * `cssVars` via context te delen toont het canvas exact wat de bezoeker straks ziet — zonder de\n * mapping te dupliceren of de overlay-structuur te verbouwen.\n */\nconst ThemeVarsCtx = createContext<{ vars: Record<string, string>; darkAuto: boolean }>({ vars: {}, darkAuto: false });\n\n/** Theme-tokens van de live site — voor UI die buiten `.xicms-root` rendert (de editor). */\nexport function useThemeVars() {\n return useContext(ThemeVarsCtx);\n}\n\n/**\n * Theme-tokens → CSS custom properties. Puur; wordt in `ModuleLayer` op het LIVE-gemergde thema\n * toegepast (SiteConfig + `settings/public.theme`), zodat huisstijl-wijzigingen uit /beheer direct\n * op de site verschijnen — net als module-instellingen.\n */\n/**\n * De donkere modus in één plek bepaald, zodat de tokenwaarden en de `data-dark`/`color-scheme` op\n * `.xicms-root` nooit uit elkaar kunnen lopen. `mode` wint; zonder `mode` valt hij terug op de\n * oude boolean, zodat bestaande site-configs (auto: true/false) ongewijzigd blijven werken.\n */\nfunction themeDarkMode(theme: ThemeTokens): \"light\" | \"dark\" | \"auto\" {\n return theme.dark?.mode ?? (theme.dark?.auto ? \"auto\" : \"light\");\n}\n\nfunction themeCssVars(theme: ThemeTokens): Record<string, string> {\n // Dark-auto via light-dark(): deze variabelen staan INLINE op `.xicms-root`, en inline wint\n // altijd van het `@media (prefers-color-scheme: dark)`-blok in styles.css. Alleen dat blok kan\n // een inline lichte waarde dus nooit overrulen — de tokenwaarde zelf moet meeschakelen.\n // (styles.css zet `color-scheme: light dark` op `[data-dark=\"auto\"]`, vereist voor light-dark().)\n // Driestand. `mode` wint; zonder `mode` valt hij terug op de oude boolean, zodat bestaande\n // site-configs (auto: true/false) ongewijzigd blijven werken.\n const donkerModus = themeDarkMode(theme);\n const auto = donkerModus === \"auto\";\n // Bij \"auto\" schakelt de tokenwaarde zélf mee via light-dark(); bij een vaste stand kiezen we hier\n // al. Dat moet op tokenniveau en niet via een @media-blok, want deze variabelen staan INLINE op\n // `.xicms-root` en inline wint altijd van een media-query in styles.css.\n const ld = (light: string, dark: string) =>\n donkerModus === \"auto\" ? `light-dark(${light}, ${dark})` : donkerModus === \"dark\" ? dark : light;\n const cssVars: Record<string, string> = {\n \"--xicms-primary\": theme.dark?.primary ? ld(theme.primary, theme.dark.primary) : theme.primary,\n \"--xicms-accent\": theme.accent ?? theme.primary,\n \"--xicms-bg\": ld(theme.background ?? \"#ffffff\", theme.dark?.background ?? \"#0f172a\"),\n \"--xicms-fg\": ld(theme.foreground ?? \"#0f172a\", theme.dark?.foreground ?? \"#e2e8f0\"),\n };\n // 8.8: met een reserve-lettertype op maat erachter (geen verspringende tekst bij het laden).\n if (theme.fontFamily) cssVars[\"--xicms-font\"] = metFallback(theme.fontFamily)!;\n // Optionele schalen → CSS-variabelen (alleen gezet als opgegeven; styles.css heeft defaults).\n for (const [k, v] of Object.entries(theme.spacing ?? {})) if (v) cssVars[`--xicms-spacing-${k}`] = v;\n if (theme.radius?.sm) cssVars[\"--xicms-radius-sm\"] = theme.radius.sm;\n if (theme.radius?.md) cssVars[\"--xicms-radius\"] = theme.radius.md;\n if (theme.radius?.lg) cssVars[\"--xicms-radius-lg\"] = theme.radius.lg;\n if (theme.container?.maxWidth) cssVars[\"--xicms-container-max\"] = theme.container.maxWidth;\n if (theme.container?.padding) cssVars[\"--xicms-container-pad\"] = theme.container.padding;\n if (theme.dark?.background) cssVars[\"--xicms-bg-dark\"] = theme.dark.background;\n if (theme.dark?.foreground) cssVars[\"--xicms-fg-dark\"] = theme.dark.foreground;\n if (theme.dark?.primary) cssVars[\"--xicms-primary-dark\"] = theme.dark.primary;\n\n // Astryx-tokens op XiCMS-waarden mappen, zodat de Astryx-componenten elke site z'n eigen merk\n // (kleur/typografie/radius) volgen. Inline op `.xicms-root` → wint over de theme.css-defaults.\n cssVars[\"--color-accent\"] = \"var(--xicms-primary)\";\n // Tekst óp de accentkleur: wit op een donkere merkkleur, donker op een lichte (geel/pastel) —\n // hardcoded wit maakte knop- en bannertekst onleesbaar op lichte primaire kleuren.\n const onAccent = tekstOpKleur(theme.primary) ?? \"#0f172a\";\n cssVars[\"--color-on-accent\"] = onAccent;\n cssVars[\"--xicms-on-primary\"] = onAccent;\n cssVars[\"--color-text-accent\"] = \"var(--xicms-primary)\";\n cssVars[\"--radius-element\"] = \"var(--xicms-radius-sm, 8px)\";\n cssVars[\"--radius-container\"] = \"var(--xicms-radius, 14px)\";\n cssVars[\"--radius-page\"] = \"var(--xicms-radius-lg, 24px)\";\n // Volledige paletmapping — ALLEEN als de site een eigen achtergrond/tekst kiest. Zo verschilt niet\n // enkel het accent maar de hele sfeer (kaarten, borders, secundaire tekst) per site; een minimale\n // config blijft op de gepolijste neutrale basis (incl. automatische dark-mode via light-dark()).\n if (theme.background) {\n cssVars[\"--color-background-body\"] = \"var(--xicms-bg)\";\n cssVars[\"--color-background-surface\"] = \"color-mix(in srgb, var(--xicms-fg) 4%, var(--xicms-bg))\";\n cssVars[\"--color-background-card\"] = \"color-mix(in srgb, var(--xicms-fg) 3%, var(--xicms-bg))\";\n cssVars[\"--color-background-popover\"] = \"var(--xicms-bg)\";\n cssVars[\"--color-background-muted\"] = \"color-mix(in srgb, var(--xicms-fg) 6%, var(--xicms-bg))\";\n // Ook de XiCMS-oppervlaktetokens meeschakelen: hun defaults in styles.css zijn licht (#fff/zwart-\n // rgba) en het dark-blok vuurt alleen bij `data-dark=\"auto\"`. Zonder deze mapping tonen presets\n // met een vaste donkere achtergrond (donker-modern, luxe-donker) witte kaarten en zwarte borders.\n cssVars[\"--xicms-surface\"] = \"color-mix(in srgb, var(--xicms-fg) 3%, var(--xicms-bg))\";\n cssVars[\"--xicms-muted\"] = \"color-mix(in srgb, var(--xicms-fg) 5%, var(--xicms-bg))\";\n }\n if (theme.foreground) {\n cssVars[\"--color-text-primary\"] = \"var(--xicms-fg)\";\n cssVars[\"--color-text-secondary\"] = \"color-mix(in srgb, var(--xicms-fg) 65%, transparent)\";\n cssVars[\"--color-neutral\"] = \"var(--xicms-fg)\";\n cssVars[\"--color-border\"] = \"color-mix(in srgb, var(--xicms-fg) 14%, transparent)\";\n cssVars[\"--xicms-border\"] = \"color-mix(in srgb, var(--xicms-fg) 12%, transparent)\";\n cssVars[\"--xicms-border-strong\"] = \"color-mix(in srgb, var(--xicms-fg) 22%, transparent)\";\n }\n if (theme.headingFont) cssVars[\"--xicms-font-heading\"] = metFallback(theme.headingFont)!;\n if (theme.fontFamily) {\n cssVars[\"--font-family-body\"] = \"var(--xicms-font)\";\n // Koppen volgen een apart display/serif-font als dat is opgegeven, anders het body-font.\n cssVars[\"--font-family-heading\"] = theme.headingFont ? \"var(--xicms-font-heading)\" : \"var(--xicms-font)\";\n } else if (theme.headingFont) {\n cssVars[\"--font-family-heading\"] = \"var(--xicms-font-heading)\";\n }\n\n return cssVars;\n}\n\n/**\n * Binnenlaag: leest de live publieke settings en resolvet daarmee de modules (settings/public.modules\n * legt zich over SiteConfig.modules) én het thema (settings/public.theme over SiteConfig.theme).\n * Zo werken module-aan/uit, -instellingen én huisstijl die de klant in /beheer zet direct door.\n */\nfunction ModuleLayer({\n config,\n blocks = NO_BLOCKS,\n modules = NO_MODULES,\n overrides,\n customBlocksData,\n astryxTheme,\n linkComponent,\n imageComponent,\n children,\n}: ProviderProps) {\n const { settings } = useSiteSettings();\n\n // LIVE thema: wijzigingen uit /beheer (settings/public.theme) winnen per token van SiteConfig.\n const theme = useMemo(() => mergeThemeTokens(config.theme, settings.theme), [config.theme, settings.theme]);\n const cssVars = useMemo(() => themeCssVars(theme), [theme]);\n const fontFallbackCss = useMemo(() => fallbackFontFaces([theme.fontFamily, theme.headingFont]), [theme.fontFamily, theme.headingFont]);\n // 8.8: laadt de site Google Fonts rechtstreeks, open dan alvast de verbinding naar de bestanden.\n if (theme.fontUrl && !config.selfHostFonts && isGoogleFontUrl(theme.fontUrl)) {\n preconnect(\"https://fonts.gstatic.com\", { crossOrigin: \"anonymous\" });\n }\n\n // Demo-bewerkmodus globaal markeren zodat de (Firebase-)dataclients lokaal-only werken.\n // In een effect (niet tijdens render): render-pure + veilig onder concurrent rendering. De\n // demoStore-default is `false`, dus vóór het effect gedraagt alles zich als niet-demo.\n useEffect(() => {\n setDemoActive(Boolean(config.demoEditing));\n }, [config.demoEditing]);\n\n const resolved = useMemo(\n () =>\n resolveModules([...builtinModules, ...modules], {\n modules: config.modules,\n firestoreModules: settings.modules as ModulesSiteConfig | undefined,\n }),\n [config.modules, modules, settings.modules],\n );\n\n // Custom blocks (5.0): runtime-gedefinieerde bloktypes uit sites/{siteId}/customBlocks.\n // Publieke bezoekers krijgen UITSLUITEND de SSR-startset (customBlocksData, server-side gelezen) —\n // géén Firestore-listener per bezoeker (kosten/verbinding). Alleen ingelogde editors krijgen een\n // live sync (CustomBlocksSync, binnen AuthProvider) zodat een nieuw blok uit /beheer of een\n // agent-push zonder redeploy in het toevoeg-menu en op de pagina verschijnt.\n const [customBlocks, setCustomBlocks] = useState<CustomBlockData[]>(customBlocksData ?? []);\n const customDefs = useMemo(() => customBlocks.map(customBlockToDefinition), [customBlocks]);\n\n const registry = useMemo(\n () => applyBlockOverrides(mergeRegistry(mergeRegistry(createRegistry(resolved.blocks), customDefs), blocks), overrides),\n [resolved.blocks, customDefs, blocks, overrides],\n );\n\n return (\n <ModulesProvider value={resolved}>\n <RegistryProvider registry={registry}>\n <AuthProvider siteId={config.siteId} demo={Boolean(config.demoEditing)}>\n <PreviewDraftSync />\n <CustomBlocksSync siteId={config.siteId} onData={setCustomBlocks} />\n <SiteSettingsSync siteId={config.siteId} />\n <ThemeVarsCtx.Provider value={{ vars: cssVars, darkAuto: themeDarkMode(theme) === \"auto\" }}>\n <EditorProvider>\n {/* React 19 hijst <link rel=\"stylesheet\"> automatisch naar <head> → lettertype laadt. */}\n {theme.fontUrl && <link rel=\"stylesheet\" href={fontStylesheet(theme.fontUrl, config.selfHostFonts)} />}\n {/* 8.8: reserve-lettertypen op maat (zie theme/fontFallback.ts); React hijst ze naar <head>. */}\n {fontFallbackCss && (\n <style href=\"xicms-font-fallback\" precedence=\"xicms\">\n {fontFallbackCss}\n </style>\n )}\n {/* 8.8: ook bij een volledige paginaload (gewone <a>, andere tab) een rustige overgang. */}\n {config.paginaOvergang && (\n <style href=\"xicms-paginaovergang\" precedence=\"xicms\">\n {\"@view-transition{navigation:auto}\"}\n </style>\n )}\n {/* Astryx-thema (Neutral basis) — de XiCMS-token-mapping op `.xicms-root` legt elke\n site z'n eigen merk eroverheen. */}\n <Theme theme={astryxTheme ?? neutralTheme} mode={themeDarkMode(theme) === \"auto\" ? \"system\" : themeDarkMode(theme) === \"dark\" || isDarkColor(theme.background) ? \"dark\" : \"light\"}>\n {/* Framework-router voor Astryx-links/knoppen (soepele client-nav + prefetch);\n zonder `linkComponent` valt het terug op een gewone `<a>` (huidig gedrag). */}\n {/* 8.0: Astryx-teksten (o.a. \"Verplicht\"/\"Optioneel\" bij velden, schermlezer-meldingen)\n in de taal van de site. Zonder provider sprak Astryx overal Engels. */}\n <InternationalizationProvider {...astryxLocale(config.lang)}>\n <LinkProvider component={linkComponent ?? \"a\"}>\n <ImageProvider component={imageComponent}>\n <div\n className=\"xicms-root\"\n // Stuurt `color-scheme` (styles.css): \"auto\" = light dark, \"dark\" = dark.\n data-dark={themeDarkMode(theme) === \"light\" ? undefined : themeDarkMode(theme)}\n style={cssVars as React.CSSProperties}\n >\n {/* De zichtbare site-chrome (demo-balk, bewerkbalk, feedback, cookiebanner) is\n BEWUST geen onderdeel meer van de provider: die hoort bij het site-oppervlak\n en werd zo ook over /beheer heen gerenderd — een cookiebanner en een\n \"Zet live\"-balk bovenop het CMS. Sites renderen nu `<SiteChrome />` in hun\n eigen (site)-layout; zie ./SiteChrome.tsx. */}\n {children}\n </div>\n </ImageProvider>\n </LinkProvider>\n </InternationalizationProvider>\n </Theme>\n </EditorProvider>\n </ThemeVarsCtx.Provider>\n </AuthProvider>\n </RegistryProvider>\n </ModulesProvider>\n );\n}\n\n/**\n * Live sync van custom blocks — ALLEEN voor ingelogde editors. Publieke bezoekers krijgen de\n * SSR-startset (customBlocksData) en géén Firestore-listener: dat scheelt een collection-read +\n * open verbinding per bezoeker, conform het getDoc-voor-publiek-patroon van useSiteSettings/News.\n */\n/**\n * Live sync van de publieke site-instellingen — ALLEEN voor ingelogde editors (zelfde patroon als\n * CustomBlocksSync). Zo ziet een editor een /beheer-wijziging (footer/nav/thema) meteen op de site,\n * terwijl publiek op de SSR-seed (settingsData) of de eenmalige getDoc blijft draaien.\n */\n/**\n * Zet Next's Draft Mode aan zodra een editor is ingelogd, zodat de pagina-route de gecommitte\n * content-bundel + de ISR-cache overslaat (server/pages.ts, `opts.skipBundle`) en deze browser\n * altijd de nieuwste GEPUBLICEERDE stand ziet — een publicatie in /beheer komt anders pas via het\n * ISR-vangnet mee.\n *\n * WAAROM EEN FETCH EN GEEN `document.cookie` ZOALS HIERVOOR: de vorige opzet zette zelf een\n * `xicms-preview`-cookie, die een proxy vertaalde naar `?preview=1`. Dat werkte niet: een route\n * die `searchParams` in zijn signatuur heeft merkt Next áltijd als dynamisch — ongeacht of de\n * proxy ooit herschrijft. Gemeten op groenhof: `ƒ (Dynamic)` met\n * `Cache-Control: private, no-cache, no-store` voor élke bezoeker. De cache was dus voor iedereen\n * stuk om een knop te bedienen die alleen de beheerder gebruikt.\n *\n * Draft Mode lost precies dát op: het zet de ondertekende `__prerender_bypass`-cookie die Next\n * VÓÓR de cache controleert, buiten de route om. Gemeten met dezelfde opzet: publiek houdt\n * `● (SSG)` met `s-maxage=300`, terwijl het request mét cookie `private, no-cache, no-store`\n * krijgt en vers rendert.\n *\n * Draagt geen rechten — net als de oude cookie. Er wordt nooit meer getoond dan de al-publieke,\n * gepubliceerde content, dus zelf `/api/draft` aanroepen levert hoogstens een verse blik op iets\n * dat toch al openbaar is. Wat het wél kost is een ongecachte render per request; wil je dat\n * dichttimmeren, laat de route dan een Firebase-ID-token verifiëren voor hij `enable()` doet.\n *\n * Faalt stil en onschadelijk als de site `/api/draft` niet heeft (zie template/): dan blijft de\n * beheerder gewoon op de gecachte stand, precies zoals een site zonder preview.\n */\nfunction PreviewDraftSync() {\n const { role } = useAuth();\n useEffect(() => {\n const gewenst = canEdit(role);\n // Alleen aanroepen als de stand écht moet veranderen. Zonder deze vergelijking zou élke\n // publieke bezoeker bij élke paginaweergave een POST doen om preview \"uit\" te zetten die al\n // uit stond — een serverless-aanroep per bezoeker, precies de kosten die deze hele omzetting\n // moet vermijden.\n //\n // De marker is een SESSIE-cookie, net als Next's `__prerender_bypass`: die laatste is httpOnly\n // en dus onleesbaar voor deze code, dus we houden er zelf een spiegel van bij. Omdat beide\n // met het browservenster verdwijnen lopen ze niet uit de pas — een marker die de cookie\n // overleeft zou preview stilletjes uitgeschakeld laten.\n const gemarkeerd = document.cookie.includes(\"xicms-draft=1\");\n if (gewenst === gemarkeerd) return;\n void fetch(`/api/draft?aan=${gewenst ? \"1\" : \"0\"}`, { method: \"POST\" })\n .then((r) => {\n if (!r.ok) return; // site zonder /api/draft: laat de marker met rust, dan blijft dit stil.\n document.cookie = gewenst ? \"xicms-draft=1; path=/; samesite=lax\" : \"xicms-draft=; path=/; max-age=0\";\n })\n .catch(() => {});\n }, [role]);\n return null;\n}\n\nfunction SiteSettingsSync({ siteId }: { siteId: string }) {\n const { role } = useAuth();\n useSiteSettingsLiveSync(siteId, canEdit(role));\n return null;\n}\n\nfunction CustomBlocksSync({ siteId, onData }: { siteId: string; onData: (defs: CustomBlockData[]) => void }) {\n const { role } = useAuth();\n const editing = canEdit(role);\n useEffect(() => {\n // Alleen editors luisteren mee (kosten + verbinding), en de SDK laadt pas dán.\n if (!editing) return;\n let unsub: (() => void) | undefined;\n let afgebroken = false;\n void (async () => {\n const [{ getDb }, { collection, onSnapshot }] = await Promise.all([\n import(\"./firebase/client\"),\n import(\"firebase/firestore\"),\n ]);\n const db = getDb();\n if (!db || afgebroken) return;\n unsub = onSnapshot(\n collection(db, \"sites\", siteId, \"customBlocks\"),\n (snap) => {\n const defs: CustomBlockData[] = [];\n snap.forEach((d) => {\n const res = CustomBlockSchema.safeParse({ ...(d.data() as Record<string, unknown>), type: (d.data() as { type?: string }).type ?? d.id });\n if (res.success) defs.push(res.data);\n });\n onData(defs);\n },\n () => undefined, // leesfout → SSR-set blijft staan\n );\n })();\n return () => {\n afgebroken = true;\n unsub?.();\n };\n }, [editing, siteId, onData]);\n return null;\n}\n\n/** Astryx-locale bij `SiteConfig.lang`. Alleen Nederlands wordt meegebundeld (~5 KB gzip); andere talen vallen terug op het ingebouwde Engels. */\nfunction astryxLocale(lang: string | undefined): { locale: string; messages?: { \"nl-NL\": typeof nlNL } } {\n const l = (lang ?? \"nl\").toLowerCase();\n return l === \"nl\" || l.startsWith(\"nl-\") ? { locale: \"nl-NL\", messages: { \"nl-NL\": nlNL } } : { locale: \"en\" };\n}\n"],"mappings":"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","names":[]}
@@ -2,7 +2,7 @@
2
2
  import { jsx, jsxs } from "react/jsx-runtime";
3
3
  import { registerBuiltinSchemas } from "../blocks/builtinSchemas.js";
4
4
  registerBuiltinSchemas();
5
- import { useState } from "react";
5
+ import { useCallback, useEffect, useMemo, useRef, useState } from "react";
6
6
  import { useAuth } from "../auth/AuthProvider.js";
7
7
  import { LoginForm } from "../auth/LoginForm.js";
8
8
  import { useSiteConfig } from "../config.js";
@@ -11,16 +11,21 @@ import { canEdit, canManageSite } from "../auth/roles.js";
11
11
  import { Tabs, TabsContent } from "./ui/tabs.js";
12
12
  import * as TabsPrimitive from "@radix-ui/react-tabs";
13
13
  import { ToastProvider } from "./ui/toast.js";
14
- import { ConfirmHost } from "./ui/ConfirmDialog.js";
14
+ import { ConfirmHost, useConfirm } from "./ui/ConfirmDialog.js";
15
+ import { heeftOnopgeslagen, ONOPGESLAGEN_VRAAG, vergeetOnopgeslagen } from "./lib/onopgeslagen.js";
15
16
  import { Button } from "./ui/primitives.js";
17
+ import { Icon } from "./ui/Icon.js";
16
18
  import { PanelIcon } from "./ui/PanelIcon.js";
17
19
  import { builtinPanels } from "./panelRegistry.js";
18
20
  import { AdminNavContext } from "./navContext.js";
19
21
  import { AdminHelp } from "./AdminHelp.js";
22
+ import { ZoekPalet } from "./ZoekPalet.js";
20
23
  import { CoreVersion, WatIsNieuw } from "./CoreVersion.js";
21
24
  function roleAllows(role, min) {
25
+ if (min === "superadmin") return role === "superadmin";
22
26
  return min === "siteadmin" ? canManageSite(role) : canEdit(role);
23
27
  }
28
+ const ROL_NAAM = { superadmin: "Xi Webdesign", siteadmin: "Beheerder", editor: "Redacteur" };
24
29
  function Melding({ children }) {
25
30
  return /* @__PURE__ */ jsx("div", { className: "xicms-admin__midden grid place-items-center p-6", children: /* @__PURE__ */ jsx("div", { className: "w-full max-w-md rounded-xl border border-slate-200 bg-white p-6 text-sm shadow-sm", children }) });
26
31
  }
@@ -36,105 +41,182 @@ function AdminApp({
36
41
  const firstTab = panels[0] && sleutel(panels[0]);
37
42
  const [actief, setActief] = useState(firstTab);
38
43
  const actievePanel = panels.find((p) => sleutel(p) === (actief ?? firstTab));
39
- return /* @__PURE__ */ jsx("div", { className: embedded ? "xicms-admin xicms-admin--ingebed" : "xicms-admin", children: /* @__PURE__ */ jsx(ToastProvider, { children: /* @__PURE__ */ jsx(ConfirmHost, { children: !configured ? /* @__PURE__ */ jsxs(Melding, { children: [
40
- "Firebase is nog niet geconfigureerd. Vul de ",
41
- /* @__PURE__ */ jsx("code", { children: "NEXT_PUBLIC_FIREBASE_*" }),
42
- "-variabelen in om het beheer aan te zetten."
43
- ] }) : loading ? /* @__PURE__ */ jsx(Melding, { children: /* @__PURE__ */ jsx("span", { className: "text-slate-500", children: "Bezig met laden\u2026" }) }) : !user ? /* @__PURE__ */ jsx("div", { className: "xicms-admin__midden grid place-items-center p-6", children: /* @__PURE__ */ jsxs("div", { className: "w-full max-w-sm", children: [
44
- /* @__PURE__ */ jsxs("p", { className: "mb-4 text-center text-sm text-slate-500", children: [
45
- "Beheer \xB7 ",
46
- name
47
- ] }),
48
- /* @__PURE__ */ jsx(LoginForm, { onSuccess: () => {
49
- window.location.replace("/");
50
- } })
51
- ] }) }) : !canEdit(role) ? /* @__PURE__ */ jsxs(Melding, { children: [
52
- "Je bent ingelogd als ",
53
- /* @__PURE__ */ jsx("strong", { children: user.email }),
54
- ", maar hebt geen beheerrechten voor deze site.",
55
- /* @__PURE__ */ jsx("div", { className: "mt-3", children: /* @__PURE__ */ jsx(Button, { variant: "secondary", size: "sm", onClick: () => void signOut(), children: "Uitloggen" }) })
56
- ] }) : panels.length === 0 ? /* @__PURE__ */ jsx(Melding, { children: "Geen actieve beheer-modules voor deze site." }) : /* @__PURE__ */ jsx(AdminNavContext.Provider, { value: setActief, children: /* @__PURE__ */ jsxs(
57
- Tabs,
58
- {
59
- value: actief ?? firstTab,
60
- onValueChange: setActief,
61
- orientation: "vertical",
62
- className: embedded ? "xicms-admin__raster" : "xicms-admin__raster md:grid md:grid-cols-[248px_1fr]",
63
- children: [
64
- /* @__PURE__ */ jsxs(
65
- "div",
66
- {
67
- className: embedded ? "xicms-admin__rail flex flex-row flex-wrap items-center gap-4 border-b border-slate-200 p-2" : "xicms-admin__rail flex flex-col gap-4 border-b border-slate-200 p-4 md:sticky md:top-0 md:h-screen md:border-r md:border-b-0",
68
- style: { background: "var(--admin-sidebar)" },
69
- children: [
70
- /* @__PURE__ */ jsxs("div", { className: "min-w-0 px-2 pt-1", children: [
71
- /* @__PURE__ */ jsx("p", { className: "truncate text-sm font-semibold", children: name }),
72
- /* @__PURE__ */ jsx("p", { className: "text-xs text-slate-500", children: "Beheer" })
73
- ] }),
74
- /* @__PURE__ */ jsx(
75
- TabsPrimitive.List,
76
- {
77
- "aria-label": "Beheer-secties",
78
- className: embedded ? "xicms-admin__lijst -mx-1 flex flex-row gap-1 overflow-x-auto" : "xicms-admin__lijst -mx-1 flex gap-1 overflow-x-auto md:flex-col md:overflow-visible",
79
- children: panels.map((p) => /* @__PURE__ */ jsxs(
80
- TabsPrimitive.Trigger,
44
+ const geldig = (tab) => tab && panels.some((p) => sleutel(p) === tab) ? tab : void 0;
45
+ const panelSleutels = panels.map(sleutel).join(",");
46
+ useEffect(() => {
47
+ const uitHash = decodeURIComponent(window.location.hash.slice(1));
48
+ if (geldig(uitHash)) setActief(uitHash);
49
+ }, [panelSleutels]);
50
+ const bevestigRef = useRef(null);
51
+ const actiefRef = useRef(actief);
52
+ actiefRef.current = actief;
53
+ const gaNaar = useCallback(async (tab, opties = {}) => {
54
+ if (tab === actiefRef.current) return true;
55
+ if (heeftOnopgeslagen() && bevestigRef.current) {
56
+ if (!await bevestigRef.current(ONOPGESLAGEN_VRAAG)) return false;
57
+ vergeetOnopgeslagen();
58
+ }
59
+ setActief(tab);
60
+ if (opties.geschiedenis !== false) window.history.pushState(null, "", `#${encodeURIComponent(tab)}`);
61
+ return true;
62
+ }, []);
63
+ const [zoekOpen, setZoekOpen] = useState(false);
64
+ useEffect(() => {
65
+ const toets = (e) => {
66
+ if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === "k") {
67
+ e.preventDefault();
68
+ setZoekOpen(true);
69
+ }
70
+ };
71
+ window.addEventListener("keydown", toets);
72
+ return () => window.removeEventListener("keydown", toets);
73
+ }, []);
74
+ const zoekPanelen = useMemo(
75
+ () => panels.map((p) => ({ tab: sleutel(p), label: p.label })),
76
+ // eslint-disable-next-line react-hooks/exhaustive-deps
77
+ [panelSleutels]
78
+ );
79
+ useEffect(() => {
80
+ const terug = () => {
81
+ const tab = decodeURIComponent(window.location.hash.slice(1)) || firstTab;
82
+ if (!tab) return;
83
+ void gaNaar(tab, { geschiedenis: false }).then((ok) => {
84
+ if (!ok && actiefRef.current) window.history.pushState(null, "", `#${encodeURIComponent(actiefRef.current)}`);
85
+ });
86
+ };
87
+ window.addEventListener("popstate", terug);
88
+ return () => window.removeEventListener("popstate", terug);
89
+ }, [gaNaar, firstTab]);
90
+ return /* @__PURE__ */ jsx("div", { className: embedded ? "xicms-admin xicms-admin--ingebed" : "xicms-admin", children: /* @__PURE__ */ jsx(ToastProvider, { children: /* @__PURE__ */ jsxs(ConfirmHost, { children: [
91
+ /* @__PURE__ */ jsx(ConfirmBrug, { zet: (c) => {
92
+ bevestigRef.current = c;
93
+ } }),
94
+ !configured ? /* @__PURE__ */ jsxs(Melding, { children: [
95
+ "Firebase is nog niet geconfigureerd. Vul de ",
96
+ /* @__PURE__ */ jsx("code", { children: "NEXT_PUBLIC_FIREBASE_*" }),
97
+ "-variabelen in om het beheer aan te zetten."
98
+ ] }) : loading ? /* @__PURE__ */ jsx(Melding, { children: /* @__PURE__ */ jsx("span", { className: "text-slate-500", children: "Bezig met laden\u2026" }) }) : !user ? /* @__PURE__ */ jsx("div", { className: "xicms-admin__midden grid place-items-center p-6", children: /* @__PURE__ */ jsxs("div", { className: "w-full max-w-sm", children: [
99
+ /* @__PURE__ */ jsxs("p", { className: "mb-4 text-center text-sm text-slate-500", children: [
100
+ "Beheer \xB7 ",
101
+ name
102
+ ] }),
103
+ /* @__PURE__ */ jsx(LoginForm, { onSuccess: () => {
104
+ window.location.replace("/");
105
+ } })
106
+ ] }) }) : !canEdit(role) ? /* @__PURE__ */ jsxs(Melding, { children: [
107
+ "Je bent ingelogd als ",
108
+ /* @__PURE__ */ jsx("strong", { children: user.email }),
109
+ ", maar hebt geen beheerrechten voor deze site.",
110
+ /* @__PURE__ */ jsx("div", { className: "mt-3", children: /* @__PURE__ */ jsx(Button, { variant: "secondary", size: "sm", onClick: () => void signOut(), children: "Uitloggen" }) })
111
+ ] }) : panels.length === 0 ? /* @__PURE__ */ jsx(Melding, { children: "Geen actieve beheer-modules voor deze site." }) : /* @__PURE__ */ jsxs(AdminNavContext.Provider, { value: (tab) => void gaNaar(tab), children: [
112
+ /* @__PURE__ */ jsxs(
113
+ Tabs,
114
+ {
115
+ value: actief ?? firstTab,
116
+ onValueChange: (tab) => void gaNaar(tab),
117
+ orientation: "vertical",
118
+ className: embedded ? "xicms-admin__raster" : "xicms-admin__raster md:grid md:grid-cols-[248px_1fr]",
119
+ children: [
120
+ /* @__PURE__ */ jsxs(
121
+ "div",
122
+ {
123
+ className: embedded ? "xicms-admin__rail flex flex-row flex-wrap items-center gap-4 border-b border-slate-200 p-2" : "xicms-admin__rail flex flex-col gap-4 border-b border-slate-200 p-4 md:sticky md:top-0 md:h-screen md:border-r md:border-b-0",
124
+ style: { background: "var(--admin-sidebar)" },
125
+ children: [
126
+ /* @__PURE__ */ jsxs("div", { className: embedded ? "flex w-full min-w-0 items-center gap-2 px-2 pt-1" : "flex min-w-0 items-start justify-between gap-2 px-2 pt-1", children: [
127
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
128
+ /* @__PURE__ */ jsx("p", { className: "truncate text-sm font-semibold", children: name }),
129
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-slate-500", children: "Beheer" })
130
+ ] }),
131
+ /* @__PURE__ */ jsxs(
132
+ "button",
133
+ {
134
+ type: "button",
135
+ onClick: () => setZoekOpen(true),
136
+ className: "xicms-admin-btn inline-flex shrink-0 items-center gap-1.5 rounded-lg border border-slate-200 bg-white px-2 py-1 text-xs text-slate-600 hover:bg-slate-100",
137
+ "aria-label": "Zoeken in het beheer (Ctrl of Cmd + K)",
138
+ title: "Zoeken (Ctrl/Cmd + K)",
139
+ children: [
140
+ /* @__PURE__ */ jsx(Icon, { naam: "zoek", grootte: 14 }),
141
+ "Zoeken"
142
+ ]
143
+ }
144
+ ),
145
+ embedded && /* @__PURE__ */ jsxs("div", { className: "xicms-admin__voet ml-auto flex min-w-0 items-center gap-3", children: [
146
+ /* @__PURE__ */ jsx("p", { className: "hidden min-w-0 truncate text-xs text-slate-600 sm:block", title: `${user.email ?? ""} \xB7 ${ROL_NAAM[role ?? "editor"] ?? role}`, children: user.email }),
147
+ /* @__PURE__ */ jsx(CoreVersion, { compact: true }),
148
+ /* @__PURE__ */ jsx(Button, { variant: "secondary", size: "sm", onClick: () => void signOut(), children: "Uitloggen" })
149
+ ] })
150
+ ] }),
151
+ /* @__PURE__ */ jsx(
152
+ TabsPrimitive.List,
81
153
  {
82
- value: sleutel(p),
83
- className: "flex shrink-0 items-center gap-2.5 rounded-lg px-3 py-2 text-sm font-medium text-slate-600 hover:bg-slate-200 hover:text-slate-900 focus-visible:ring-2 focus-visible:ring-brand-500 focus-visible:outline-none data-[state=active]:bg-slate-100 data-[state=active]:text-slate-900 data-[state=active]:shadow-[inset_2px_0_0_0_var(--color-brand-500)]",
84
- children: [
85
- /* @__PURE__ */ jsx(PanelIcon, { id: sleutel(p) }),
86
- p.label
87
- ]
88
- },
89
- sleutel(p)
90
- ))
91
- }
92
- ),
93
- /* @__PURE__ */ jsxs(
94
- "div",
95
- {
96
- className: embedded ? "xicms-admin__voet ml-auto flex min-w-0 flex-row items-center gap-3 border-t-0 pt-0" : "xicms-admin__voet mt-auto hidden min-w-0 flex-col gap-3 border-t border-slate-200 pt-3 md:flex",
97
- children: [
154
+ "aria-label": "Beheer-secties",
155
+ className: embedded ? "xicms-admin__lijst -mx-1 flex flex-row gap-1 overflow-x-auto" : "xicms-admin__lijst -mx-1 flex gap-1 overflow-x-auto md:flex-col md:overflow-visible",
156
+ children: panels.map((p) => /* @__PURE__ */ jsxs(
157
+ TabsPrimitive.Trigger,
158
+ {
159
+ value: sleutel(p),
160
+ className: "flex shrink-0 items-center gap-2.5 rounded-lg px-3 py-2 text-sm font-medium text-slate-600 hover:bg-slate-100 hover:text-slate-900 focus-visible:ring-2 focus-visible:ring-brand-500 focus-visible:outline-none data-[state=active]:bg-white data-[state=active]:text-slate-900 data-[state=active]:shadow-[inset_2px_0_0_0_var(--color-brand-500),0_1px_2px_rgba(27,26,23,0.08)]",
161
+ children: [
162
+ /* @__PURE__ */ jsx(PanelIcon, { id: sleutel(p) }),
163
+ p.label
164
+ ]
165
+ },
166
+ sleutel(p)
167
+ ))
168
+ }
169
+ ),
170
+ !embedded && /* @__PURE__ */ jsxs("div", { className: "xicms-admin__voet mt-auto flex min-w-0 flex-row flex-wrap items-center gap-3 border-t border-slate-200 pt-3 md:flex-col md:items-stretch", children: [
98
171
  /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
99
172
  /* @__PURE__ */ jsx("p", { className: "truncate text-xs font-medium text-slate-600", title: user.email ?? void 0, children: user.email }),
100
- /* @__PURE__ */ jsx("p", { className: "text-xs text-slate-400", children: role })
173
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-slate-500", children: ROL_NAAM[role ?? "editor"] ?? role })
101
174
  ] }),
102
175
  /* @__PURE__ */ jsx(CoreVersion, {}),
103
176
  /* @__PURE__ */ jsx(Button, { variant: "secondary", size: "sm", onClick: () => void signOut(), children: "Uitloggen" })
177
+ ] })
178
+ ]
179
+ }
180
+ ),
181
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
182
+ /* @__PURE__ */ jsxs(
183
+ "header",
184
+ {
185
+ className: embedded ? "xicms-admin__kop static z-10 flex items-center justify-between gap-4 border-b border-slate-200 px-4 py-3 md:px-8" : "xicms-admin__kop sticky top-0 z-10 flex items-center justify-between gap-4 border-b border-slate-200 px-4 py-3 md:px-8",
186
+ style: { background: "var(--admin-canvas)" },
187
+ children: [
188
+ /* @__PURE__ */ jsx("h1", { className: "truncate text-lg font-semibold tracking-tight", children: actievePanel?.label ?? "Beheer" }),
189
+ /* @__PURE__ */ jsxs(
190
+ "a",
191
+ {
192
+ className: "inline-flex h-8 shrink-0 items-center gap-1.5 rounded-lg border border-slate-200 bg-white px-3 text-sm hover:bg-slate-100 focus-visible:ring-2 focus-visible:ring-brand-500 focus-visible:outline-none",
193
+ href: "/",
194
+ children: [
195
+ "Bekijk site",
196
+ /* @__PURE__ */ jsx(Icon, { naam: "extern", grootte: 14 })
197
+ ]
198
+ }
199
+ )
104
200
  ]
105
201
  }
106
- )
107
- ]
108
- }
109
- ),
110
- /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
111
- /* @__PURE__ */ jsxs(
112
- "header",
113
- {
114
- className: embedded ? "xicms-admin__kop static z-10 flex items-center justify-between gap-4 border-b border-slate-200 px-4 py-3 md:px-8" : "xicms-admin__kop sticky top-0 z-10 flex items-center justify-between gap-4 border-b border-slate-200 px-4 py-3 md:px-8",
115
- style: { background: "var(--admin-canvas)" },
116
- children: [
117
- /* @__PURE__ */ jsx("h1", { className: "truncate text-base font-semibold", children: actievePanel?.label ?? "Beheer" }),
118
- /* @__PURE__ */ jsx(
119
- "a",
120
- {
121
- className: "inline-flex h-8 shrink-0 items-center rounded-lg border border-slate-200 px-3 text-sm hover:bg-slate-100 focus-visible:ring-2 focus-visible:ring-brand-500 focus-visible:outline-none",
122
- href: "/",
123
- children: "Bekijk site \u2197"
124
- }
125
- )
126
- ]
127
- }
128
- ),
129
- /* @__PURE__ */ jsxs("div", { className: "grid gap-6 p-4 md:p-8", children: [
130
- /* @__PURE__ */ jsx(WatIsNieuw, {}),
131
- panels.map((p) => /* @__PURE__ */ jsx(TabsContent, { value: sleutel(p), className: "pt-0", children: /* @__PURE__ */ jsx(p.Panel, { siteId }) }, sleutel(p))),
132
- /* @__PURE__ */ jsx(AdminHelp, {})
133
- ] })
134
- ] })
135
- ]
136
- }
137
- ) }) }) }) });
202
+ ),
203
+ /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-[minmax(0,1fr)] gap-6 p-4 md:p-8", children: [
204
+ actievePanel?.id === "start" && /* @__PURE__ */ jsx(WatIsNieuw, {}),
205
+ panels.map((p) => /* @__PURE__ */ jsx(TabsContent, { value: sleutel(p), className: "pt-0", children: /* @__PURE__ */ jsx(p.Panel, { siteId }) }, sleutel(p))),
206
+ actievePanel?.id !== "start" && /* @__PURE__ */ jsx(AdminHelp, {})
207
+ ] })
208
+ ] })
209
+ ]
210
+ }
211
+ ),
212
+ /* @__PURE__ */ jsx(ZoekPalet, { siteId, panelen: zoekPanelen, gaNaar: (tab) => void gaNaar(tab), open: zoekOpen, onOpenChange: setZoekOpen })
213
+ ] })
214
+ ] }) }) });
215
+ }
216
+ function ConfirmBrug({ zet }) {
217
+ const confirm = useConfirm();
218
+ useEffect(() => zet(confirm), [confirm, zet]);
219
+ return null;
138
220
  }
139
221
  export {
140
222
  AdminApp