@xiwebdesign/xicms-core 7.12.1 → 7.14.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 (164) hide show
  1. package/dist/admin/AdminApp.js +2 -0
  2. package/dist/admin/AdminApp.js.map +1 -1
  3. package/dist/admin/lib/mediaUsage.d.ts +17 -0
  4. package/dist/admin/lib/mediaUsage.js +32 -1
  5. package/dist/admin/lib/mediaUsage.js.map +1 -1
  6. package/dist/admin/lib/zodFields.d.ts +2 -2
  7. package/dist/admin/lib/zodFields.js +2 -0
  8. package/dist/admin/lib/zodFields.js.map +1 -1
  9. package/dist/admin/media/MediaManager.js +74 -17
  10. package/dist/admin/media/MediaManager.js.map +1 -1
  11. package/dist/admin/ui/toast.d.ts +4 -0
  12. package/dist/admin/ui/toast.js +9 -3
  13. package/dist/admin/ui/toast.js.map +1 -1
  14. package/dist/admin/visual/VisualEditor.js +69 -5
  15. package/dist/admin/visual/VisualEditor.js.map +1 -1
  16. package/dist/blocks/BlockErrorBoundary.d.ts +1 -0
  17. package/dist/blocks/BlockErrorBoundary.js +4 -0
  18. package/dist/blocks/BlockErrorBoundary.js.map +1 -1
  19. package/dist/blocks/BlockRenderer.js +1 -1
  20. package/dist/blocks/BlockRenderer.js.map +1 -1
  21. package/dist/blocks/builtinSchemas.d.ts +23 -0
  22. package/dist/blocks/builtinSchemas.js +138 -0
  23. package/dist/blocks/builtinSchemas.js.map +1 -0
  24. package/dist/blocks/builtins/Accordion.js +0 -2
  25. package/dist/blocks/builtins/Accordion.js.map +1 -1
  26. package/dist/blocks/builtins/Agenda.js +0 -2
  27. package/dist/blocks/builtins/Agenda.js.map +1 -1
  28. package/dist/blocks/builtins/Banner.js +0 -2
  29. package/dist/blocks/builtins/Banner.js.map +1 -1
  30. package/dist/blocks/builtins/BeforeAfter.js +0 -2
  31. package/dist/blocks/builtins/BeforeAfter.js.map +1 -1
  32. package/dist/blocks/builtins/Booking.js +0 -2
  33. package/dist/blocks/builtins/Booking.js.map +1 -1
  34. package/dist/blocks/builtins/Breadcrumbs.js +0 -2
  35. package/dist/blocks/builtins/Breadcrumbs.js.map +1 -1
  36. package/dist/blocks/builtins/Cards.js +0 -2
  37. package/dist/blocks/builtins/Cards.js.map +1 -1
  38. package/dist/blocks/builtins/Columns.js +0 -2
  39. package/dist/blocks/builtins/Columns.js.map +1 -1
  40. package/dist/blocks/builtins/Contact.d.ts +1 -1
  41. package/dist/blocks/builtins/Contact.js +0 -3
  42. package/dist/blocks/builtins/Contact.js.map +1 -1
  43. package/dist/blocks/builtins/Countdown.js +0 -2
  44. package/dist/blocks/builtins/Countdown.js.map +1 -1
  45. package/dist/blocks/builtins/Cta.js +0 -2
  46. package/dist/blocks/builtins/Cta.js.map +1 -1
  47. package/dist/blocks/builtins/Downloads.js +0 -2
  48. package/dist/blocks/builtins/Downloads.js.map +1 -1
  49. package/dist/blocks/builtins/Elements.js +0 -4
  50. package/dist/blocks/builtins/Elements.js.map +1 -1
  51. package/dist/blocks/builtins/Embed.js +0 -2
  52. package/dist/blocks/builtins/Embed.js.map +1 -1
  53. package/dist/blocks/builtins/Faq.js +0 -2
  54. package/dist/blocks/builtins/Faq.js.map +1 -1
  55. package/dist/blocks/builtins/FormBlock.js +0 -2
  56. package/dist/blocks/builtins/FormBlock.js.map +1 -1
  57. package/dist/blocks/builtins/Gallery.d.ts +1 -1
  58. package/dist/blocks/builtins/Gallery.js +0 -2
  59. package/dist/blocks/builtins/Gallery.js.map +1 -1
  60. package/dist/blocks/builtins/Hero.js +0 -2
  61. package/dist/blocks/builtins/Hero.js.map +1 -1
  62. package/dist/blocks/builtins/ImageBlock.js +0 -2
  63. package/dist/blocks/builtins/ImageBlock.js.map +1 -1
  64. package/dist/blocks/builtins/Jobs.d.ts +1 -1
  65. package/dist/blocks/builtins/Jobs.js +0 -2
  66. package/dist/blocks/builtins/Jobs.js.map +1 -1
  67. package/dist/blocks/builtins/Layout.js +0 -3
  68. package/dist/blocks/builtins/Layout.js.map +1 -1
  69. package/dist/blocks/builtins/MapBlock.js +0 -2
  70. package/dist/blocks/builtins/MapBlock.js.map +1 -1
  71. package/dist/blocks/builtins/NewsListBlock.js +0 -2
  72. package/dist/blocks/builtins/NewsListBlock.js.map +1 -1
  73. package/dist/blocks/builtins/Newsletter.js +0 -2
  74. package/dist/blocks/builtins/Newsletter.js.map +1 -1
  75. package/dist/blocks/builtins/OpeningHours.js +0 -2
  76. package/dist/blocks/builtins/OpeningHours.js.map +1 -1
  77. package/dist/blocks/builtins/PdfBlock.js +0 -2
  78. package/dist/blocks/builtins/PdfBlock.js.map +1 -1
  79. package/dist/blocks/builtins/Portfolio.js +0 -2
  80. package/dist/blocks/builtins/Portfolio.js.map +1 -1
  81. package/dist/blocks/builtins/Pricing.d.ts +1 -1
  82. package/dist/blocks/builtins/Pricing.js +0 -2
  83. package/dist/blocks/builtins/Pricing.js.map +1 -1
  84. package/dist/blocks/builtins/RichTextBlock.js +0 -2
  85. package/dist/blocks/builtins/RichTextBlock.js.map +1 -1
  86. package/dist/blocks/builtins/Search.js +0 -2
  87. package/dist/blocks/builtins/Search.js.map +1 -1
  88. package/dist/blocks/builtins/Sections.js +0 -10
  89. package/dist/blocks/builtins/Sections.js.map +1 -1
  90. package/dist/blocks/builtins/Slider.js +0 -2
  91. package/dist/blocks/builtins/Slider.js.map +1 -1
  92. package/dist/blocks/builtins/Spacer.js +0 -2
  93. package/dist/blocks/builtins/Spacer.js.map +1 -1
  94. package/dist/blocks/builtins/SymbolRef.js +3 -5
  95. package/dist/blocks/builtins/SymbolRef.js.map +1 -1
  96. package/dist/blocks/builtins/Team.js +0 -2
  97. package/dist/blocks/builtins/Team.js.map +1 -1
  98. package/dist/blocks/builtins/Testimonials.d.ts +1 -1
  99. package/dist/blocks/builtins/Testimonials.js +0 -2
  100. package/dist/blocks/builtins/Testimonials.js.map +1 -1
  101. package/dist/blocks/builtins/Video.d.ts +1 -1
  102. package/dist/blocks/builtins/Video.js +0 -2
  103. package/dist/blocks/builtins/Video.js.map +1 -1
  104. package/dist/blocks/builtins/WhatsappChat.js +0 -2
  105. package/dist/blocks/builtins/WhatsappChat.js.map +1 -1
  106. package/dist/blocks/builtins/Widgets.js +0 -26
  107. package/dist/blocks/builtins/Widgets.js.map +1 -1
  108. package/dist/blocks/customTemplate/definition.js +1 -1
  109. package/dist/blocks/customTemplate/definition.js.map +1 -1
  110. package/dist/blocks/registry.d.ts +24 -13
  111. package/dist/blocks/registry.js +15 -4
  112. package/dist/blocks/registry.js.map +1 -1
  113. package/dist/blocks/reportRenderFout.d.ts +13 -0
  114. package/dist/blocks/reportRenderFout.js +31 -0
  115. package/dist/blocks/reportRenderFout.js.map +1 -0
  116. package/dist/media/ImageContext.js +24 -1
  117. package/dist/media/ImageContext.js.map +1 -1
  118. package/dist/modules/shop/blocks/Cart.js +1 -2
  119. package/dist/modules/shop/blocks/Cart.js.map +1 -1
  120. package/dist/modules/shop/blocks/Checkout.js +1 -2
  121. package/dist/modules/shop/blocks/Checkout.js.map +1 -1
  122. package/dist/modules/shop/blocks/Donation.js +1 -2
  123. package/dist/modules/shop/blocks/Donation.js.map +1 -1
  124. package/dist/modules/shop/blocks/OrderStatus.js +0 -2
  125. package/dist/modules/shop/blocks/OrderStatus.js.map +1 -1
  126. package/dist/modules/shop/blocks/ProductDetail.js +1 -7
  127. package/dist/modules/shop/blocks/ProductDetail.js.map +1 -1
  128. package/dist/modules/shop/blocks/ProductGrid.js +1 -2
  129. package/dist/modules/shop/blocks/ProductGrid.js.map +1 -1
  130. package/dist/modules/shop/blocks/ShopCategories.js +0 -2
  131. package/dist/modules/shop/blocks/ShopCategories.js.map +1 -1
  132. package/dist/modules/shop/module.js +1 -0
  133. package/dist/modules/shop/module.js.map +1 -1
  134. package/dist/modules/shop/schemas.d.ts +1 -0
  135. package/dist/modules/shop/schemas.js +32 -0
  136. package/dist/modules/shop/schemas.js.map +1 -0
  137. package/dist/modules/types.d.ts +6 -0
  138. package/dist/schema/blockBase.d.ts +99 -0
  139. package/dist/schema/blockBase.js +22 -0
  140. package/dist/schema/blockBase.js.map +1 -0
  141. package/dist/schema/blocks.d.ts +1 -91
  142. package/dist/schema/blocks.js +64 -77
  143. package/dist/schema/blocks.js.map +1 -1
  144. package/dist/schema/pages.js +1 -1
  145. package/dist/schema/pages.js.map +1 -1
  146. package/dist/schema/shop.d.ts +1 -11
  147. package/dist/schema/shop.js +2 -21
  148. package/dist/schema/shop.js.map +1 -1
  149. package/dist/schema/shopGeld.d.ts +18 -0
  150. package/dist/schema/shopGeld.js +27 -0
  151. package/dist/schema/shopGeld.js.map +1 -0
  152. package/dist/schema/symbols.js +1 -1
  153. package/dist/schema/symbols.js.map +1 -1
  154. package/dist/server/blockData.js +14 -1
  155. package/dist/server/blockData.js.map +1 -1
  156. package/dist/server/index.d.ts +1 -1
  157. package/dist/server/index.js +2 -1
  158. package/dist/server/index.js.map +1 -1
  159. package/dist/server/pages.d.ts +16 -0
  160. package/dist/server/pages.js +9 -0
  161. package/dist/server/pages.js.map +1 -1
  162. package/dist/styles.css +62 -0
  163. package/dist/version.js +1 -1
  164. package/package.json +1 -1
@@ -17,6 +17,7 @@ interface Props {
17
17
  mode: "view" | "preview";
18
18
  type: string;
19
19
  blockKey: string;
20
+ siteId?: string;
20
21
  children: ReactNode;
21
22
  }
22
23
  interface State {
@@ -1,6 +1,7 @@
1
1
  "use client";
2
2
  import { jsx, jsxs } from "react/jsx-runtime";
3
3
  import { Component } from "react";
4
+ import { reportRenderFout } from "./reportRenderFout.js";
4
5
  class BlockErrorBoundary extends Component {
5
6
  state = { error: null };
6
7
  static getDerivedStateFromError(error) {
@@ -10,6 +11,9 @@ class BlockErrorBoundary extends Component {
10
11
  if (typeof console !== "undefined") {
11
12
  console.error(`[xicms] block "${this.props.type}" gaf een renderfout:`, error, info);
12
13
  }
14
+ if (this.props.mode === "view" && this.props.siteId) {
15
+ reportRenderFout(this.props.siteId, this.props.type, error?.message ?? String(error));
16
+ }
13
17
  }
14
18
  componentDidUpdate(prev) {
15
19
  if (this.state.error && (prev.blockKey !== this.props.blockKey || prev.type !== this.props.type)) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/blocks/BlockErrorBoundary.tsx"],"sourcesContent":["\"use client\";\n\nimport { Component, type ErrorInfo, type ReactNode } from \"react\";\n\n/**\n * Vangt een fout in één block-Render op zodat één kapot block nooit de hele pagina sloopt\n * (foolproof: een editor kan geen content maken die de live site breekt).\n *\n * - `mode=\"view\"` (publiek): faalt stil — rendert niets, layout blijft intact.\n * - `mode=\"preview\"` (editor): toont een zichtbare foutkaart zodat de bewerker de breuk ziet.\n *\n * Let op de RSC-grens: een error-boundary is per definitie client (`componentDidCatch`). Daarom is\n * dit een client-leaf die per block om de Render heen wordt gezet; `BlockRenderer` zelf blijft\n * server-importeerbaar. Een fout die al tijdens server-rendering wordt gegooid valt buiten een\n * client-boundary — maar `validateBlocks` haalt schema-ongeldige content er server-side al uit, en\n * de meeste runtime-render-fouten (kapotte URL, client-hook) gebeuren client-side en worden hier\n * dus wél gevangen.\n */\ninterface Props {\n mode: \"view\" | \"preview\";\n type: string;\n blockKey: string;\n children: ReactNode;\n}\ninterface State {\n error: Error | null;\n}\n\nexport class BlockErrorBoundary extends Component<Props, State> {\n state: State = { error: null };\n\n static getDerivedStateFromError(error: Error): State {\n return { error };\n }\n\n componentDidCatch(error: Error, info: ErrorInfo): void {\n if (typeof console !== \"undefined\") {\n console.error(`[xicms] block \"${this.props.type}\" gaf een renderfout:`, error, info);\n }\n }\n\n componentDidUpdate(prev: Props): void {\n // Reset na een fix (ander block of ander type) zodat het block opnieuw probeert te renderen.\n if (this.state.error && (prev.blockKey !== this.props.blockKey || prev.type !== this.props.type)) {\n this.setState({ error: null });\n }\n }\n\n render(): ReactNode {\n if (this.state.error) {\n if (this.props.mode === \"preview\") {\n return (\n <div className=\"xicms-block-error\" role=\"alert\">\n <strong>Blok “{this.props.type}” kon niet worden weergegeven.</strong>\n <span>{this.state.error.message}</span>\n </div>\n );\n }\n // Publiek: stil falen, geen layout-verstoring.\n return null;\n }\n return this.props.children;\n }\n}\n"],"mappings":";AAqDY,SACA,KADA;AAnDZ,SAAS,iBAAiD;AA0BnD,MAAM,2BAA2B,UAAwB;AAAA,EAC9D,QAAe,EAAE,OAAO,KAAK;AAAA,EAE7B,OAAO,yBAAyB,OAAqB;AACnD,WAAO,EAAE,MAAM;AAAA,EACjB;AAAA,EAEA,kBAAkB,OAAc,MAAuB;AACrD,QAAI,OAAO,YAAY,aAAa;AAClC,cAAQ,MAAM,kBAAkB,KAAK,MAAM,IAAI,yBAAyB,OAAO,IAAI;AAAA,IACrF;AAAA,EACF;AAAA,EAEA,mBAAmB,MAAmB;AAEpC,QAAI,KAAK,MAAM,UAAU,KAAK,aAAa,KAAK,MAAM,YAAY,KAAK,SAAS,KAAK,MAAM,OAAO;AAChG,WAAK,SAAS,EAAE,OAAO,KAAK,CAAC;AAAA,IAC/B;AAAA,EACF;AAAA,EAEA,SAAoB;AAClB,QAAI,KAAK,MAAM,OAAO;AACpB,UAAI,KAAK,MAAM,SAAS,WAAW;AACjC,eACE,qBAAC,SAAI,WAAU,qBAAoB,MAAK,SACtC;AAAA,+BAAC,YAAO;AAAA;AAAA,YAAO,KAAK,MAAM;AAAA,YAAK;AAAA,aAA8B;AAAA,UAC7D,oBAAC,UAAM,eAAK,MAAM,MAAM,SAAQ;AAAA,WAClC;AAAA,MAEJ;AAEA,aAAO;AAAA,IACT;AACA,WAAO,KAAK,MAAM;AAAA,EACpB;AACF;","names":[]}
1
+ {"version":3,"sources":["../../src/blocks/BlockErrorBoundary.tsx"],"sourcesContent":["\"use client\";\n\nimport { Component, type ErrorInfo, type ReactNode } from \"react\";\nimport { reportRenderFout } from \"./reportRenderFout\";\n\n/**\n * Vangt een fout in één block-Render op zodat één kapot block nooit de hele pagina sloopt\n * (foolproof: een editor kan geen content maken die de live site breekt).\n *\n * - `mode=\"view\"` (publiek): faalt stil — rendert niets, layout blijft intact.\n * - `mode=\"preview\"` (editor): toont een zichtbare foutkaart zodat de bewerker de breuk ziet.\n *\n * Let op de RSC-grens: een error-boundary is per definitie client (`componentDidCatch`). Daarom is\n * dit een client-leaf die per block om de Render heen wordt gezet; `BlockRenderer` zelf blijft\n * server-importeerbaar. Een fout die al tijdens server-rendering wordt gegooid valt buiten een\n * client-boundary — maar `validateBlocks` haalt schema-ongeldige content er server-side al uit, en\n * de meeste runtime-render-fouten (kapotte URL, client-hook) gebeuren client-side en worden hier\n * dus wél gevangen.\n */\ninterface Props {\n mode: \"view\" | \"preview\";\n type: string;\n blockKey: string;\n siteId?: string;\n children: ReactNode;\n}\ninterface State {\n error: Error | null;\n}\n\nexport class BlockErrorBoundary extends Component<Props, State> {\n state: State = { error: null };\n\n static getDerivedStateFromError(error: Error): State {\n return { error };\n }\n\n componentDidCatch(error: Error, info: ErrorInfo): void {\n if (typeof console !== \"undefined\") {\n console.error(`[xicms] block \"${this.props.type}\" gaf een renderfout:`, error, info);\n }\n // Publiek (mode=\"view\"): meld de fout aan de backend — de bezoeker ziet niets (dat is de\n // belofte van deze boundary), maar wij horen het via Cloud Logging/Monitoring. In de editor\n // niet: daar stáát de bewerker naar de foutkaart te kijken.\n if (this.props.mode === \"view\" && this.props.siteId) {\n reportRenderFout(this.props.siteId, this.props.type, error?.message ?? String(error));\n }\n }\n\n componentDidUpdate(prev: Props): void {\n // Reset na een fix (ander block of ander type) zodat het block opnieuw probeert te renderen.\n if (this.state.error && (prev.blockKey !== this.props.blockKey || prev.type !== this.props.type)) {\n this.setState({ error: null });\n }\n }\n\n render(): ReactNode {\n if (this.state.error) {\n if (this.props.mode === \"preview\") {\n return (\n <div className=\"xicms-block-error\" role=\"alert\">\n <strong>Blok “{this.props.type}” kon niet worden weergegeven.</strong>\n <span>{this.state.error.message}</span>\n </div>\n );\n }\n // Publiek: stil falen, geen layout-verstoring.\n return null;\n }\n return this.props.children;\n }\n}\n"],"mappings":";AA6DY,SACA,KADA;AA3DZ,SAAS,iBAAiD;AAC1D,SAAS,wBAAwB;AA2B1B,MAAM,2BAA2B,UAAwB;AAAA,EAC9D,QAAe,EAAE,OAAO,KAAK;AAAA,EAE7B,OAAO,yBAAyB,OAAqB;AACnD,WAAO,EAAE,MAAM;AAAA,EACjB;AAAA,EAEA,kBAAkB,OAAc,MAAuB;AACrD,QAAI,OAAO,YAAY,aAAa;AAClC,cAAQ,MAAM,kBAAkB,KAAK,MAAM,IAAI,yBAAyB,OAAO,IAAI;AAAA,IACrF;AAIA,QAAI,KAAK,MAAM,SAAS,UAAU,KAAK,MAAM,QAAQ;AACnD,uBAAiB,KAAK,MAAM,QAAQ,KAAK,MAAM,MAAM,OAAO,WAAW,OAAO,KAAK,CAAC;AAAA,IACtF;AAAA,EACF;AAAA,EAEA,mBAAmB,MAAmB;AAEpC,QAAI,KAAK,MAAM,UAAU,KAAK,aAAa,KAAK,MAAM,YAAY,KAAK,SAAS,KAAK,MAAM,OAAO;AAChG,WAAK,SAAS,EAAE,OAAO,KAAK,CAAC;AAAA,IAC/B;AAAA,EACF;AAAA,EAEA,SAAoB;AAClB,QAAI,KAAK,MAAM,OAAO;AACpB,UAAI,KAAK,MAAM,SAAS,WAAW;AACjC,eACE,qBAAC,SAAI,WAAU,qBAAoB,MAAK,SACtC;AAAA,+BAAC,YAAO;AAAA;AAAA,YAAO,KAAK,MAAM;AAAA,YAAK;AAAA,aAA8B;AAAA,UAC7D,oBAAC,UAAM,eAAK,MAAM,MAAM,SAAQ;AAAA,WAClC;AAAA,MAEJ;AAEA,aAAO;AAAA,IACT;AACA,WAAO,KAAK,MAAM;AAAA,EACpB;AACF;","names":[]}
@@ -15,7 +15,7 @@ function BlockRenderer({
15
15
  const Render = def.Render;
16
16
  const attrs = blockStyleAttrs(b._style);
17
17
  const rendered = /* @__PURE__ */ jsx(Render, { block: b, siteId, mode });
18
- return /* @__PURE__ */ jsx(BlockErrorBoundary, { mode, type: b._type, blockKey: b._key, children: attrs ? /* @__PURE__ */ jsx(
18
+ return /* @__PURE__ */ jsx(BlockErrorBoundary, { mode, type: b._type, blockKey: b._key, siteId, children: attrs ? /* @__PURE__ */ jsx(
19
19
  "div",
20
20
  {
21
21
  id: attrs.id,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/blocks/BlockRenderer.tsx"],"sourcesContent":["import { validateBlocks, type BlockRegistry } from \"./registry\";\nimport { BlockErrorBoundary } from \"./BlockErrorBoundary\";\nimport { blockStyleAttrs } from \"./blockStyle\";\nimport type { BlockStyle } from \"../schema/blocks\";\n\n/**\n * Rendert een blocks-array via de registry. Server-safe (geen \"use client\"): bruikbaar in\n * React Server Components én client. Geef de registry expliciet mee (zo werkt server-rendering);\n * client-componenten kunnen `useRegistry()` gebruiken om hem te verkrijgen.\n *\n * Elk block wordt in een `BlockErrorBoundary` gewikkeld zodat één kapot block nooit de hele\n * pagina sloopt (foolproof).\n */\nexport function BlockRenderer({\n blocks,\n registry,\n siteId,\n mode = \"view\",\n}: {\n blocks: unknown[] | undefined;\n registry: BlockRegistry;\n siteId: string;\n mode?: \"view\" | \"preview\";\n}) {\n const valid = validateBlocks(blocks, registry);\n return (\n <>\n {valid.map((b) => {\n const def = registry.get(b._type);\n if (!def) return null;\n const Render = def.Render;\n // Gedeelde blokstijl (ruimte/achtergrond/breedte/uitlijning/anker) centraal toepassen.\n const attrs = blockStyleAttrs((b as { _style?: BlockStyle })._style);\n const rendered = <Render block={b} siteId={siteId} mode={mode} />;\n // Altijd een DOM-wrapper met een stabiele block-identifier, zodat het feedback-widget\n // (en andere tooling) een onderdeel op de pagina kan aanwijzen via\n // `closest('[data-xicms-block]')`. Zonder eigen blokstijl gebruiken we `display:contents`\n // zodat de wrapper layout-neutraal is (hij traverseert wél mee in `closest()`).\n return (\n <BlockErrorBoundary key={b._key} mode={mode} type={b._type} blockKey={b._key}>\n {attrs ? (\n <div\n id={attrs.id}\n className={attrs.className}\n style={attrs.style}\n data-xicms-animate={attrs.dataAnimate}\n data-xicms-block={b._key}\n data-xicms-block-type={b._type}\n >\n {rendered}\n </div>\n ) : (\n <div style={{ display: \"contents\" }} data-xicms-block={b._key} data-xicms-block-type={b._type}>\n {rendered}\n </div>\n )}\n </BlockErrorBoundary>\n );\n })}\n </>\n );\n}\n"],"mappings":"AA0BI,mBAOqB,WAPrB;AA1BJ,SAAS,sBAA0C;AACnD,SAAS,0BAA0B;AACnC,SAAS,uBAAuB;AAWzB,SAAS,cAAc;AAAA,EAC5B;AAAA,EACA;AAAA,EACA;AAAA,EACA,OAAO;AACT,GAKG;AACD,QAAM,QAAQ,eAAe,QAAQ,QAAQ;AAC7C,SACE,gCACG,gBAAM,IAAI,CAAC,MAAM;AAChB,UAAM,MAAM,SAAS,IAAI,EAAE,KAAK;AAChC,QAAI,CAAC,IAAK,QAAO;AACjB,UAAM,SAAS,IAAI;AAEnB,UAAM,QAAQ,gBAAiB,EAA8B,MAAM;AACnE,UAAM,WAAW,oBAAC,UAAO,OAAO,GAAG,QAAgB,MAAY;AAK/D,WACE,oBAAC,sBAAgC,MAAY,MAAM,EAAE,OAAO,UAAU,EAAE,MACrE,kBACC;AAAA,MAAC;AAAA;AAAA,QACC,IAAI,MAAM;AAAA,QACV,WAAW,MAAM;AAAA,QACjB,OAAO,MAAM;AAAA,QACb,sBAAoB,MAAM;AAAA,QAC1B,oBAAkB,EAAE;AAAA,QACpB,yBAAuB,EAAE;AAAA,QAExB;AAAA;AAAA,IACH,IAEA,oBAAC,SAAI,OAAO,EAAE,SAAS,WAAW,GAAG,oBAAkB,EAAE,MAAM,yBAAuB,EAAE,OACrF,oBACH,KAfqB,EAAE,IAiB3B;AAAA,EAEJ,CAAC,GACH;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../../src/blocks/BlockRenderer.tsx"],"sourcesContent":["import { validateBlocks, type BlockRegistry } from \"./registry\";\nimport { BlockErrorBoundary } from \"./BlockErrorBoundary\";\nimport { blockStyleAttrs } from \"./blockStyle\";\nimport type { BlockStyle } from \"../schema/blocks\";\n\n/**\n * Rendert een blocks-array via de registry. Server-safe (geen \"use client\"): bruikbaar in\n * React Server Components én client. Geef de registry expliciet mee (zo werkt server-rendering);\n * client-componenten kunnen `useRegistry()` gebruiken om hem te verkrijgen.\n *\n * Elk block wordt in een `BlockErrorBoundary` gewikkeld zodat één kapot block nooit de hele\n * pagina sloopt (foolproof).\n */\nexport function BlockRenderer({\n blocks,\n registry,\n siteId,\n mode = \"view\",\n}: {\n blocks: unknown[] | undefined;\n registry: BlockRegistry;\n siteId: string;\n mode?: \"view\" | \"preview\";\n}) {\n const valid = validateBlocks(blocks, registry);\n return (\n <>\n {valid.map((b) => {\n const def = registry.get(b._type);\n if (!def) return null;\n const Render = def.Render;\n // Gedeelde blokstijl (ruimte/achtergrond/breedte/uitlijning/anker) centraal toepassen.\n const attrs = blockStyleAttrs((b as { _style?: BlockStyle })._style);\n const rendered = <Render block={b} siteId={siteId} mode={mode} />;\n // Altijd een DOM-wrapper met een stabiele block-identifier, zodat het feedback-widget\n // (en andere tooling) een onderdeel op de pagina kan aanwijzen via\n // `closest('[data-xicms-block]')`. Zonder eigen blokstijl gebruiken we `display:contents`\n // zodat de wrapper layout-neutraal is (hij traverseert wél mee in `closest()`).\n return (\n <BlockErrorBoundary key={b._key} mode={mode} type={b._type} blockKey={b._key} siteId={siteId}>\n {attrs ? (\n <div\n id={attrs.id}\n className={attrs.className}\n style={attrs.style}\n data-xicms-animate={attrs.dataAnimate}\n data-xicms-block={b._key}\n data-xicms-block-type={b._type}\n >\n {rendered}\n </div>\n ) : (\n <div style={{ display: \"contents\" }} data-xicms-block={b._key} data-xicms-block-type={b._type}>\n {rendered}\n </div>\n )}\n </BlockErrorBoundary>\n );\n })}\n </>\n );\n}\n"],"mappings":"AA0BI,mBAOqB,WAPrB;AA1BJ,SAAS,sBAA0C;AACnD,SAAS,0BAA0B;AACnC,SAAS,uBAAuB;AAWzB,SAAS,cAAc;AAAA,EAC5B;AAAA,EACA;AAAA,EACA;AAAA,EACA,OAAO;AACT,GAKG;AACD,QAAM,QAAQ,eAAe,QAAQ,QAAQ;AAC7C,SACE,gCACG,gBAAM,IAAI,CAAC,MAAM;AAChB,UAAM,MAAM,SAAS,IAAI,EAAE,KAAK;AAChC,QAAI,CAAC,IAAK,QAAO;AACjB,UAAM,SAAS,IAAI;AAEnB,UAAM,QAAQ,gBAAiB,EAA8B,MAAM;AACnE,UAAM,WAAW,oBAAC,UAAO,OAAO,GAAG,QAAgB,MAAY;AAK/D,WACE,oBAAC,sBAAgC,MAAY,MAAM,EAAE,OAAO,UAAU,EAAE,MAAM,QAC3E,kBACC;AAAA,MAAC;AAAA;AAAA,QACC,IAAI,MAAM;AAAA,QACV,WAAW,MAAM;AAAA,QACjB,OAAO,MAAM;AAAA,QACb,sBAAoB,MAAM;AAAA,QAC1B,oBAAkB,EAAE;AAAA,QACpB,yBAAuB,EAAE;AAAA,QAExB;AAAA;AAAA,IACH,IAEA,oBAAC,SAAI,OAAO,EAAE,SAAS,WAAW,GAAG,oBAAkB,EAAE,MAAM,yBAAuB,EAAE,OACrF,oBACH,KAfqB,EAAE,IAiB3B;AAAA,EAEJ,CAAC,GACH;AAEJ;","names":[]}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Lazy schema-registratie voor de ingebouwde blokken (7.13).
3
+ *
4
+ * De schema's zijn EDITOR-kennis: het formulier in het zijpaneel, de inline-veldlabels, de
5
+ * vertaal-overlay en de validatie bij bewerken komen eruit voort. Een publieke bezoeker heeft
6
+ * er niets aan — en toch reisden alle schema's plus de zod-runtime (±73 KB gzip) mee in élke
7
+ * paginabundel, omdat elk blok zijn schema in zijn eigen client-module droeg.
8
+ *
9
+ * Dit bestand is de enige plek die de schema's nog als WAARDE importeert, en het wordt alleen
10
+ * geladen door de admin/editor-chunks (AdminApp, VisualEditor) — die waren al lazy. Het plugt
11
+ * ook de zod-parser in de registry (`setSchemaParser`), zodat validatie weer volledig is zodra
12
+ * er bewerkt wordt; publiek volstaat de lichte vormcheck (zie registry.validateBlocks).
13
+ *
14
+ * NIEUW BLOK? `npm test` bewaakt dat elk ingebouwd blok hier een schema heeft (builtinSchemas.test).
15
+ */
16
+ import { type $ZodType } from "zod/v4/core";
17
+ /** type → schema, voor elk ingebouwd blok. */
18
+ export declare const builtinBlockSchemas: Record<string, $ZodType>;
19
+ /**
20
+ * Hangt de schema's aan de (module-singleton) builtin-defs en plugt de zod-parser in.
21
+ * Idempotent; aan te roepen vanuit elke admin/editor-ingang.
22
+ */
23
+ export declare function registerBuiltinSchemas(): void;
@@ -0,0 +1,138 @@
1
+ import { safeParse } from "zod/v4/core";
2
+ import {
3
+ AccordionBlockSchema,
4
+ AgendaBlockSchema,
5
+ AgendaWidgetSchema,
6
+ BannerBlockSchema,
7
+ BeforeAfterBlockSchema,
8
+ BookingBlockSchema,
9
+ BreadcrumbsBlockSchema,
10
+ ButtonsBlockSchema,
11
+ CardsBlockSchema,
12
+ CardsWidgetSchema,
13
+ ColumnsBlockSchema,
14
+ ContactBlockSchema,
15
+ ContactWidgetSchema,
16
+ CountdownBlockSchema,
17
+ CountdownWidgetSchema,
18
+ CountersBlockSchema,
19
+ CtaBlockSchema,
20
+ CtaWidgetSchema,
21
+ DividerBlockSchema,
22
+ DownloadsBlockSchema,
23
+ DownloadsWidgetSchema,
24
+ EmbedBlockSchema,
25
+ FaqBlockSchema,
26
+ FeatureBlockSchema,
27
+ FormBlockSchema,
28
+ GalleryBlockSchema,
29
+ GalleryWidgetSchema,
30
+ HeroBlockSchema,
31
+ ImageBlockSchema,
32
+ JobsBlockSchema,
33
+ LogosBlockSchema,
34
+ MapBlockSchema,
35
+ NewsListBlockSchema,
36
+ NewsWidgetSchema,
37
+ NewsletterBlockSchema,
38
+ NewsletterWidgetSchema,
39
+ OpeningHoursBlockSchema,
40
+ OpeningHoursWidgetSchema,
41
+ PdfBlockSchema,
42
+ PortfolioBlockSchema,
43
+ PricingBlockSchema,
44
+ QuoteBlockSchema,
45
+ RichTextBlockSchema,
46
+ SearchBlockSchema,
47
+ SliderBlockSchema,
48
+ SocialBlockSchema,
49
+ SocialWidgetSchema,
50
+ SpacerBlockSchema,
51
+ SymbolRefBlockSchema,
52
+ TabsBlockSchema,
53
+ TeamBlockSchema,
54
+ TestimonialsBlockSchema,
55
+ TestimonialsWidgetSchema,
56
+ TimelineBlockSchema,
57
+ VideoBlockSchema,
58
+ WhatsappChatBlockSchema,
59
+ WithSidebarBlockSchema
60
+ } from "../schema/blocks.js";
61
+ import { setSchemaParser } from "./registry.js";
62
+ import { builtinBlocks } from "./builtins/index.js";
63
+ const builtinBlockSchemas = {
64
+ accordion: AccordionBlockSchema,
65
+ agenda: AgendaBlockSchema,
66
+ agendaWidget: AgendaWidgetSchema,
67
+ banner: BannerBlockSchema,
68
+ beforeAfter: BeforeAfterBlockSchema,
69
+ booking: BookingBlockSchema,
70
+ breadcrumbs: BreadcrumbsBlockSchema,
71
+ buttons: ButtonsBlockSchema,
72
+ cards: CardsBlockSchema,
73
+ cardsWidget: CardsWidgetSchema,
74
+ columns: ColumnsBlockSchema,
75
+ contact: ContactBlockSchema,
76
+ contactWidget: ContactWidgetSchema,
77
+ countdown: CountdownBlockSchema,
78
+ countdownWidget: CountdownWidgetSchema,
79
+ counters: CountersBlockSchema,
80
+ cta: CtaBlockSchema,
81
+ ctaWidget: CtaWidgetSchema,
82
+ divider: DividerBlockSchema,
83
+ downloads: DownloadsBlockSchema,
84
+ downloadsWidget: DownloadsWidgetSchema,
85
+ embed: EmbedBlockSchema,
86
+ faq: FaqBlockSchema,
87
+ feature: FeatureBlockSchema,
88
+ form: FormBlockSchema,
89
+ gallery: GalleryBlockSchema,
90
+ galleryWidget: GalleryWidgetSchema,
91
+ hero: HeroBlockSchema,
92
+ image: ImageBlockSchema,
93
+ jobs: JobsBlockSchema,
94
+ logos: LogosBlockSchema,
95
+ map: MapBlockSchema,
96
+ newsList: NewsListBlockSchema,
97
+ newsWidget: NewsWidgetSchema,
98
+ newsletter: NewsletterBlockSchema,
99
+ newsletterWidget: NewsletterWidgetSchema,
100
+ openingHours: OpeningHoursBlockSchema,
101
+ openingHoursWidget: OpeningHoursWidgetSchema,
102
+ pdf: PdfBlockSchema,
103
+ portfolio: PortfolioBlockSchema,
104
+ pricing: PricingBlockSchema,
105
+ quote: QuoteBlockSchema,
106
+ richText: RichTextBlockSchema,
107
+ search: SearchBlockSchema,
108
+ slider: SliderBlockSchema,
109
+ social: SocialBlockSchema,
110
+ socialWidget: SocialWidgetSchema,
111
+ spacer: SpacerBlockSchema,
112
+ symbolRef: SymbolRefBlockSchema,
113
+ tabs: TabsBlockSchema,
114
+ team: TeamBlockSchema,
115
+ testimonials: TestimonialsBlockSchema,
116
+ testimonialsWidget: TestimonialsWidgetSchema,
117
+ timeline: TimelineBlockSchema,
118
+ video: VideoBlockSchema,
119
+ whatsappChat: WhatsappChatBlockSchema,
120
+ withSidebar: WithSidebarBlockSchema
121
+ };
122
+ let geregistreerd = false;
123
+ function registerBuiltinSchemas() {
124
+ if (geregistreerd) return;
125
+ geregistreerd = true;
126
+ setSchemaParser((schema, raw) => {
127
+ const res = safeParse(schema, raw);
128
+ return res.success ? { success: true, data: res.data } : { success: false, issues: res.error.issues };
129
+ });
130
+ for (const def of builtinBlocks) {
131
+ if (!def.schema && builtinBlockSchemas[def.type]) def.schema = builtinBlockSchemas[def.type];
132
+ }
133
+ }
134
+ export {
135
+ builtinBlockSchemas,
136
+ registerBuiltinSchemas
137
+ };
138
+ //# sourceMappingURL=builtinSchemas.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/blocks/builtinSchemas.ts"],"sourcesContent":["/**\n * Lazy schema-registratie voor de ingebouwde blokken (7.13).\n *\n * De schema's zijn EDITOR-kennis: het formulier in het zijpaneel, de inline-veldlabels, de\n * vertaal-overlay en de validatie bij bewerken komen eruit voort. Een publieke bezoeker heeft\n * er niets aan — en toch reisden alle schema's plus de zod-runtime (±73 KB gzip) mee in élke\n * paginabundel, omdat elk blok zijn schema in zijn eigen client-module droeg.\n *\n * Dit bestand is de enige plek die de schema's nog als WAARDE importeert, en het wordt alleen\n * geladen door de admin/editor-chunks (AdminApp, VisualEditor) — die waren al lazy. Het plugt\n * ook de zod-parser in de registry (`setSchemaParser`), zodat validatie weer volledig is zodra\n * er bewerkt wordt; publiek volstaat de lichte vormcheck (zie registry.validateBlocks).\n *\n * NIEUW BLOK? `npm test` bewaakt dat elk ingebouwd blok hier een schema heeft (builtinSchemas.test).\n */\nimport { safeParse, type $ZodType } from \"zod/v4/core\";\nimport {\n AccordionBlockSchema,\n AgendaBlockSchema,\n AgendaWidgetSchema,\n BannerBlockSchema,\n BeforeAfterBlockSchema,\n BookingBlockSchema,\n BreadcrumbsBlockSchema,\n ButtonsBlockSchema,\n CardsBlockSchema,\n CardsWidgetSchema,\n ColumnsBlockSchema,\n ContactBlockSchema,\n ContactWidgetSchema,\n CountdownBlockSchema,\n CountdownWidgetSchema,\n CountersBlockSchema,\n CtaBlockSchema,\n CtaWidgetSchema,\n DividerBlockSchema,\n DownloadsBlockSchema,\n DownloadsWidgetSchema,\n EmbedBlockSchema,\n FaqBlockSchema,\n FeatureBlockSchema,\n FormBlockSchema,\n GalleryBlockSchema,\n GalleryWidgetSchema,\n HeroBlockSchema,\n ImageBlockSchema,\n JobsBlockSchema,\n LogosBlockSchema,\n MapBlockSchema,\n NewsListBlockSchema,\n NewsWidgetSchema,\n NewsletterBlockSchema,\n NewsletterWidgetSchema,\n OpeningHoursBlockSchema,\n OpeningHoursWidgetSchema,\n PdfBlockSchema,\n PortfolioBlockSchema,\n PricingBlockSchema,\n QuoteBlockSchema,\n RichTextBlockSchema,\n SearchBlockSchema,\n SliderBlockSchema,\n SocialBlockSchema,\n SocialWidgetSchema,\n SpacerBlockSchema,\n SymbolRefBlockSchema,\n TabsBlockSchema,\n TeamBlockSchema,\n TestimonialsBlockSchema,\n TestimonialsWidgetSchema,\n TimelineBlockSchema,\n VideoBlockSchema,\n WhatsappChatBlockSchema,\n WithSidebarBlockSchema,\n} from \"../schema/blocks\";\nimport { setSchemaParser, type BlockDefinition } from \"./registry\";\nimport { builtinBlocks } from \"./builtins/index\";\n\n/** type → schema, voor elk ingebouwd blok. */\nexport const builtinBlockSchemas: Record<string, $ZodType> = {\n accordion: AccordionBlockSchema,\n agenda: AgendaBlockSchema,\n agendaWidget: AgendaWidgetSchema,\n banner: BannerBlockSchema,\n beforeAfter: BeforeAfterBlockSchema,\n booking: BookingBlockSchema,\n breadcrumbs: BreadcrumbsBlockSchema,\n buttons: ButtonsBlockSchema,\n cards: CardsBlockSchema,\n cardsWidget: CardsWidgetSchema,\n columns: ColumnsBlockSchema,\n contact: ContactBlockSchema,\n contactWidget: ContactWidgetSchema,\n countdown: CountdownBlockSchema,\n countdownWidget: CountdownWidgetSchema,\n counters: CountersBlockSchema,\n cta: CtaBlockSchema,\n ctaWidget: CtaWidgetSchema,\n divider: DividerBlockSchema,\n downloads: DownloadsBlockSchema,\n downloadsWidget: DownloadsWidgetSchema,\n embed: EmbedBlockSchema,\n faq: FaqBlockSchema,\n feature: FeatureBlockSchema,\n form: FormBlockSchema,\n gallery: GalleryBlockSchema,\n galleryWidget: GalleryWidgetSchema,\n hero: HeroBlockSchema,\n image: ImageBlockSchema,\n jobs: JobsBlockSchema,\n logos: LogosBlockSchema,\n map: MapBlockSchema,\n newsList: NewsListBlockSchema,\n newsWidget: NewsWidgetSchema,\n newsletter: NewsletterBlockSchema,\n newsletterWidget: NewsletterWidgetSchema,\n openingHours: OpeningHoursBlockSchema,\n openingHoursWidget: OpeningHoursWidgetSchema,\n pdf: PdfBlockSchema,\n portfolio: PortfolioBlockSchema,\n pricing: PricingBlockSchema,\n quote: QuoteBlockSchema,\n richText: RichTextBlockSchema,\n search: SearchBlockSchema,\n slider: SliderBlockSchema,\n social: SocialBlockSchema,\n socialWidget: SocialWidgetSchema,\n spacer: SpacerBlockSchema,\n symbolRef: SymbolRefBlockSchema,\n tabs: TabsBlockSchema,\n team: TeamBlockSchema,\n testimonials: TestimonialsBlockSchema,\n testimonialsWidget: TestimonialsWidgetSchema,\n timeline: TimelineBlockSchema,\n video: VideoBlockSchema,\n whatsappChat: WhatsappChatBlockSchema,\n withSidebar: WithSidebarBlockSchema,\n};\n\nlet geregistreerd = false;\n\n/**\n * Hangt de schema's aan de (module-singleton) builtin-defs en plugt de zod-parser in.\n * Idempotent; aan te roepen vanuit elke admin/editor-ingang.\n */\nexport function registerBuiltinSchemas(): void {\n if (geregistreerd) return;\n geregistreerd = true;\n setSchemaParser((schema, raw) => {\n const res = safeParse(schema, raw);\n return res.success ? { success: true, data: res.data } : { success: false, issues: res.error.issues };\n });\n for (const def of builtinBlocks as Array<BlockDefinition & { schema?: unknown }>) {\n if (!def.schema && builtinBlockSchemas[def.type]) def.schema = builtinBlockSchemas[def.type];\n }\n}\n"],"mappings":"AAeA,SAAS,iBAAgC;AACzC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,uBAA6C;AACtD,SAAS,qBAAqB;AAGvB,MAAM,sBAAgD;AAAA,EAC3D,WAAW;AAAA,EACX,QAAQ;AAAA,EACR,cAAc;AAAA,EACd,QAAQ;AAAA,EACR,aAAa;AAAA,EACb,SAAS;AAAA,EACT,aAAa;AAAA,EACb,SAAS;AAAA,EACT,OAAO;AAAA,EACP,aAAa;AAAA,EACb,SAAS;AAAA,EACT,SAAS;AAAA,EACT,eAAe;AAAA,EACf,WAAW;AAAA,EACX,iBAAiB;AAAA,EACjB,UAAU;AAAA,EACV,KAAK;AAAA,EACL,WAAW;AAAA,EACX,SAAS;AAAA,EACT,WAAW;AAAA,EACX,iBAAiB;AAAA,EACjB,OAAO;AAAA,EACP,KAAK;AAAA,EACL,SAAS;AAAA,EACT,MAAM;AAAA,EACN,SAAS;AAAA,EACT,eAAe;AAAA,EACf,MAAM;AAAA,EACN,OAAO;AAAA,EACP,MAAM;AAAA,EACN,OAAO;AAAA,EACP,KAAK;AAAA,EACL,UAAU;AAAA,EACV,YAAY;AAAA,EACZ,YAAY;AAAA,EACZ,kBAAkB;AAAA,EAClB,cAAc;AAAA,EACd,oBAAoB;AAAA,EACpB,KAAK;AAAA,EACL,WAAW;AAAA,EACX,SAAS;AAAA,EACT,OAAO;AAAA,EACP,UAAU;AAAA,EACV,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,cAAc;AAAA,EACd,QAAQ;AAAA,EACR,WAAW;AAAA,EACX,MAAM;AAAA,EACN,MAAM;AAAA,EACN,cAAc;AAAA,EACd,oBAAoB;AAAA,EACpB,UAAU;AAAA,EACV,OAAO;AAAA,EACP,cAAc;AAAA,EACd,aAAa;AACf;AAEA,IAAI,gBAAgB;AAMb,SAAS,yBAA+B;AAC7C,MAAI,cAAe;AACnB,kBAAgB;AAChB,kBAAgB,CAAC,QAAQ,QAAQ;AAC/B,UAAM,MAAM,UAAU,QAAQ,GAAG;AACjC,WAAO,IAAI,UAAU,EAAE,SAAS,MAAM,MAAM,IAAI,KAAK,IAAI,EAAE,SAAS,OAAO,QAAQ,IAAI,MAAM,OAAO;AAAA,EACtG,CAAC;AACD,aAAW,OAAO,eAAgE;AAChF,QAAI,CAAC,IAAI,UAAU,oBAAoB,IAAI,IAAI,EAAG,KAAI,SAAS,oBAAoB,IAAI,IAAI;AAAA,EAC7F;AACF;","names":[]}
@@ -1,7 +1,6 @@
1
1
  "use client";
2
2
  import { jsx, jsxs } from "react/jsx-runtime";
3
3
  import { useState } from "react";
4
- import { AccordionBlockSchema } from "../../schema/blocks.js";
5
4
  import { defineBlock } from "../registry.js";
6
5
  import { Collapsible } from "@astryxdesign/core/Collapsible";
7
6
  import { VStack, Heading, Text } from "../ui/index.js";
@@ -40,7 +39,6 @@ function AccordionRender({ block }) {
40
39
  }
41
40
  const accordionBlock = defineBlock({
42
41
  type: "accordion",
43
- schema: AccordionBlockSchema,
44
42
  Render: AccordionRender,
45
43
  label: "Accordeon",
46
44
  icon: "\u{1FA97}",
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/blocks/builtins/Accordion.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState } from \"react\";\nimport type { z } from \"zod\";\nimport { AccordionBlockSchema } from \"../../schema/blocks\";\nimport { defineBlock, type BlockRenderProps } from \"../registry\";\nimport { Collapsible } from \"@astryxdesign/core/Collapsible\";\nimport { VStack, Heading, Text } from \"../ui\";\n\ntype Accordion = z.infer<typeof AccordionBlockSchema>;\n\n/** Accordeon op Astryx Collapsible. Bij `multiple: false` is er max. één paneel tegelijk open. */\nfunction AccordionRender({ block }: BlockRenderProps<Accordion>) {\n const items = (block.items ?? []).filter((i) => i.title);\n const [openIdx, setOpenIdx] = useState<number | null>(null);\n if (items.length === 0) return null;\n return (\n <VStack gap={3} as=\"section\" className=\"xicms-accordion\">\n {block.heading && <Heading level={2} data-xicms-edit=\"heading\">{block.heading}</Heading>}\n <VStack gap={1.5}>\n {items.map((it, i) => {\n const body = it.bodyHtml ? (\n // Server-side gesanitized bij publiceren (*Html-velden) — zie functions/lib/sanitize.\n // eslint-disable-next-line react/no-danger\n <div\n className=\"xicms-richtext\"\n data-xicms-edit={`items.${i}.bodyHtml`}\n dangerouslySetInnerHTML={{ __html: it.bodyHtml }}\n />\n ) : (\n <Text color=\"secondary\" data-xicms-edit={`items.${i}.body`}>{it.body}</Text>\n );\n const trigger = <Text weight=\"bold\" data-xicms-edit={`items.${i}.title`}>{it.title}</Text>;\n return block.multiple ? (\n <Collapsible key={i} trigger={trigger} defaultIsOpen={false}>{body}</Collapsible>\n ) : (\n <Collapsible\n key={i}\n trigger={trigger}\n isOpen={openIdx === i}\n onOpenChange={(o) => setOpenIdx(o ? i : null)}\n >\n {body}\n </Collapsible>\n );\n })}\n </VStack>\n </VStack>\n );\n}\n\nexport const accordionBlock = defineBlock({\n type: \"accordion\",\n schema: AccordionBlockSchema,\n Render: AccordionRender,\n label: \"Accordeon\",\n icon: \"🪗\",\n defaults: () => ({ items: [{ title: \"Titel\", body: \"Inhoud…\" }], multiple: false }),\n});\n"],"mappings":";AAiBI,SACoB,KADpB;AAfJ,SAAS,gBAAgB;AAEzB,SAAS,4BAA4B;AACrC,SAAS,mBAA0C;AACnD,SAAS,mBAAmB;AAC5B,SAAS,QAAQ,SAAS,YAAY;AAKtC,SAAS,gBAAgB,EAAE,MAAM,GAAgC;AAC/D,QAAM,SAAS,MAAM,SAAS,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,KAAK;AACvD,QAAM,CAAC,SAAS,UAAU,IAAI,SAAwB,IAAI;AAC1D,MAAI,MAAM,WAAW,EAAG,QAAO;AAC/B,SACE,qBAAC,UAAO,KAAK,GAAG,IAAG,WAAU,WAAU,mBACpC;AAAA,UAAM,WAAW,oBAAC,WAAQ,OAAO,GAAG,mBAAgB,WAAW,gBAAM,SAAQ;AAAA,IAC9E,oBAAC,UAAO,KAAK,KACV,gBAAM,IAAI,CAAC,IAAI,MAAM;AACpB,YAAM,OAAO,GAAG;AAAA;AAAA;AAAA,QAGd;AAAA,UAAC;AAAA;AAAA,YACC,WAAU;AAAA,YACV,mBAAiB,SAAS,CAAC;AAAA,YAC3B,yBAAyB,EAAE,QAAQ,GAAG,SAAS;AAAA;AAAA,QACjD;AAAA,UAEA,oBAAC,QAAK,OAAM,aAAY,mBAAiB,SAAS,CAAC,SAAU,aAAG,MAAK;AAEvE,YAAM,UAAU,oBAAC,QAAK,QAAO,QAAO,mBAAiB,SAAS,CAAC,UAAW,aAAG,OAAM;AACnF,aAAO,MAAM,WACX,oBAAC,eAAoB,SAAkB,eAAe,OAAQ,kBAA5C,CAAiD,IAEnE;AAAA,QAAC;AAAA;AAAA,UAEC;AAAA,UACA,QAAQ,YAAY;AAAA,UACpB,cAAc,CAAC,MAAM,WAAW,IAAI,IAAI,IAAI;AAAA,UAE3C;AAAA;AAAA,QALI;AAAA,MAMP;AAAA,IAEJ,CAAC,GACH;AAAA,KACF;AAEJ;AAEO,MAAM,iBAAiB,YAAY;AAAA,EACxC,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,MAAM;AAAA,EACN,UAAU,OAAO,EAAE,OAAO,CAAC,EAAE,OAAO,SAAS,MAAM,eAAU,CAAC,GAAG,UAAU,MAAM;AACnF,CAAC;","names":[]}
1
+ {"version":3,"sources":["../../../src/blocks/builtins/Accordion.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState } from \"react\";\nimport type { z } from \"zod\";\nimport type { AccordionBlockSchema } from \"../../schema/blocks\";\nimport { defineBlock, type BlockRenderProps } from \"../registry\";\nimport { Collapsible } from \"@astryxdesign/core/Collapsible\";\nimport { VStack, Heading, Text } from \"../ui\";\n\ntype Accordion = z.infer<typeof AccordionBlockSchema>;\n\n/** Accordeon op Astryx Collapsible. Bij `multiple: false` is er max. één paneel tegelijk open. */\nfunction AccordionRender({ block }: BlockRenderProps<Accordion>) {\n const items = (block.items ?? []).filter((i) => i.title);\n const [openIdx, setOpenIdx] = useState<number | null>(null);\n if (items.length === 0) return null;\n return (\n <VStack gap={3} as=\"section\" className=\"xicms-accordion\">\n {block.heading && <Heading level={2} data-xicms-edit=\"heading\">{block.heading}</Heading>}\n <VStack gap={1.5}>\n {items.map((it, i) => {\n const body = it.bodyHtml ? (\n // Server-side gesanitized bij publiceren (*Html-velden) — zie functions/lib/sanitize.\n // eslint-disable-next-line react/no-danger\n <div\n className=\"xicms-richtext\"\n data-xicms-edit={`items.${i}.bodyHtml`}\n dangerouslySetInnerHTML={{ __html: it.bodyHtml }}\n />\n ) : (\n <Text color=\"secondary\" data-xicms-edit={`items.${i}.body`}>{it.body}</Text>\n );\n const trigger = <Text weight=\"bold\" data-xicms-edit={`items.${i}.title`}>{it.title}</Text>;\n return block.multiple ? (\n <Collapsible key={i} trigger={trigger} defaultIsOpen={false}>{body}</Collapsible>\n ) : (\n <Collapsible\n key={i}\n trigger={trigger}\n isOpen={openIdx === i}\n onOpenChange={(o) => setOpenIdx(o ? i : null)}\n >\n {body}\n </Collapsible>\n );\n })}\n </VStack>\n </VStack>\n );\n}\n\nexport const accordionBlock = defineBlock({\n type: \"accordion\",\n Render: AccordionRender,\n label: \"Accordeon\",\n icon: \"🪗\",\n defaults: () => ({ items: [{ title: \"Titel\", body: \"Inhoud…\" }], multiple: false }),\n});\n"],"mappings":";AAiBI,SACoB,KADpB;AAfJ,SAAS,gBAAgB;AAGzB,SAAS,mBAA0C;AACnD,SAAS,mBAAmB;AAC5B,SAAS,QAAQ,SAAS,YAAY;AAKtC,SAAS,gBAAgB,EAAE,MAAM,GAAgC;AAC/D,QAAM,SAAS,MAAM,SAAS,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,KAAK;AACvD,QAAM,CAAC,SAAS,UAAU,IAAI,SAAwB,IAAI;AAC1D,MAAI,MAAM,WAAW,EAAG,QAAO;AAC/B,SACE,qBAAC,UAAO,KAAK,GAAG,IAAG,WAAU,WAAU,mBACpC;AAAA,UAAM,WAAW,oBAAC,WAAQ,OAAO,GAAG,mBAAgB,WAAW,gBAAM,SAAQ;AAAA,IAC9E,oBAAC,UAAO,KAAK,KACV,gBAAM,IAAI,CAAC,IAAI,MAAM;AACpB,YAAM,OAAO,GAAG;AAAA;AAAA;AAAA,QAGd;AAAA,UAAC;AAAA;AAAA,YACC,WAAU;AAAA,YACV,mBAAiB,SAAS,CAAC;AAAA,YAC3B,yBAAyB,EAAE,QAAQ,GAAG,SAAS;AAAA;AAAA,QACjD;AAAA,UAEA,oBAAC,QAAK,OAAM,aAAY,mBAAiB,SAAS,CAAC,SAAU,aAAG,MAAK;AAEvE,YAAM,UAAU,oBAAC,QAAK,QAAO,QAAO,mBAAiB,SAAS,CAAC,UAAW,aAAG,OAAM;AACnF,aAAO,MAAM,WACX,oBAAC,eAAoB,SAAkB,eAAe,OAAQ,kBAA5C,CAAiD,IAEnE;AAAA,QAAC;AAAA;AAAA,UAEC;AAAA,UACA,QAAQ,YAAY;AAAA,UACpB,cAAc,CAAC,MAAM,WAAW,IAAI,IAAI,IAAI;AAAA,UAE3C;AAAA;AAAA,QALI;AAAA,MAMP;AAAA,IAEJ,CAAC,GACH;AAAA,KACF;AAEJ;AAEO,MAAM,iBAAiB,YAAY;AAAA,EACxC,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,MAAM;AAAA,EACN,UAAU,OAAO,EAAE,OAAO,CAAC,EAAE,OAAO,SAAS,MAAM,eAAU,CAAC,GAAG,UAAU,MAAM;AACnF,CAAC;","names":[]}
@@ -1,6 +1,5 @@
1
1
  import { jsx, jsxs } from "react/jsx-runtime";
2
2
  import { jsonLdHtml } from "./jsonld.js";
3
- import { AgendaBlockSchema } from "../../schema/blocks.js";
4
3
  import { defineBlock } from "../registry.js";
5
4
  import { Heading } from "../ui/index.js";
6
5
  import { icsDataUrl } from "./lib/ics.js";
@@ -91,7 +90,6 @@ function AgendaRender({ block }) {
91
90
  }
92
91
  const agendaBlock = defineBlock({
93
92
  type: "agenda",
94
- schema: AgendaBlockSchema,
95
93
  Render: AgendaRender,
96
94
  label: "Agenda",
97
95
  icon: "\u{1F4C5}",
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/blocks/builtins/Agenda.tsx"],"sourcesContent":["import type { z } from \"zod\";\nimport { jsonLdHtml } from \"./jsonld\";\nimport { AgendaBlockSchema } from \"../../schema/blocks\";\nimport { defineBlock, type BlockRenderProps } from \"../registry\";\nimport { Heading } from \"../ui\";\nimport { icsDataUrl } from \"./lib/ics\";\n\ntype Agenda = z.infer<typeof AgendaBlockSchema>;\n\n/** Eén event zoals zowel het Agenda-blok als de Agenda-widget het kennen. */\nexport interface AgendaEvent {\n title: string;\n start: string;\n end?: string;\n location?: string;\n description?: string;\n url?: string;\n}\n\n/**\n * Parseert een event-datum als LOKALE tijd. Cruciaal voor datum-zonder-tijd: `new Date(\"2026-08-01\")`\n * is per spec UTC-middernacht, waardoor west-van-UTC-bezoekers \"31 juli\" te zien kregen (en de\n * server/client bij hydration konden verschillen). \"2026-08-01\" is hier gewoon 1 augustus, overal.\n */\nexport function parseEventDate(value: string): Date {\n const m = /^(\\d{4})-(\\d{2})-(\\d{2})$/.exec(value.trim());\n if (m) return new Date(Number(m[1]), Number(m[2]) - 1, Number(m[3]));\n return new Date(value);\n}\n\n/** Toont een datum leesbaar (nl-NL). Valt terug op de ruwe string bij ongeldige invoer. */\nexport function formatEventDate(value: string): string {\n if (!value) return \"\";\n const d = parseEventDate(value);\n if (Number.isNaN(d.getTime())) return value;\n const hasTime = value.includes(\"T\");\n return d.toLocaleDateString(\"nl-NL\", {\n weekday: \"short\",\n day: \"numeric\",\n month: \"long\",\n year: \"numeric\",\n ...(hasTime ? { hour: \"2-digit\", minute: \"2-digit\" } : {}),\n });\n}\n\n/**\n * Selecteert de te tonen events: filtert lege titels, optioneel verlopen events, sorteert\n * chronologisch (events zonder geldige datum achteraan, in invoervolgorde) en limiteert. Gedeeld\n * door het volwaardige Agenda-blok en de compacte Agenda-widget — zo \"haalt\" de widget alles\n * uit dezelfde logica als de volledige versie.\n */\nexport function selectAgendaEvents<T extends AgendaEvent>(\n events: T[] | undefined,\n opts: { hidePast?: boolean; limit?: number } = {},\n): T[] {\n let list = (events ?? []).filter((e) => e.title);\n if (opts.hidePast) {\n const today = new Date();\n today.setHours(0, 0, 0, 0);\n list = list.filter((e) => {\n const d = parseEventDate(e.end || e.start);\n return Number.isNaN(d.getTime()) || d >= today;\n });\n }\n list = [...list].sort((a, b) => {\n const ta = parseEventDate(a.start).getTime();\n const tb = parseEventDate(b.start).getTime();\n if (Number.isNaN(ta) && Number.isNaN(tb)) return 0;\n if (Number.isNaN(ta)) return 1;\n if (Number.isNaN(tb)) return -1;\n return ta - tb;\n });\n return typeof opts.limit === \"number\" ? list.slice(0, opts.limit) : list;\n}\n\nfunction eventJsonLd(events: Agenda[\"events\"]): Record<string, unknown> {\n return {\n \"@context\": \"https://schema.org\",\n \"@type\": \"ItemList\",\n // Google vereist `location` voor Event-rich-results: events zonder locatie renderen wel op\n // de pagina, maar blijven uit de JSON-LD (voorkomt gegarandeerde Search-Console-errors).\n itemListElement: events\n .filter((e) => e.title && e.start && e.location)\n .map((e, i) => ({\n \"@type\": \"ListItem\",\n position: i + 1,\n item: {\n \"@type\": \"Event\",\n name: e.title,\n startDate: e.start,\n ...(e.end ? { endDate: e.end } : {}),\n location: { \"@type\": \"Place\", name: e.location },\n ...(e.description ? { description: e.description } : {}),\n ...(e.url ? { url: e.url } : {}),\n },\n })),\n };\n}\n\n/** Agenda/evenementen. Server-safe (geen client-state); `hidePast` filtert verlopen events. */\nfunction AgendaRender({ block }: BlockRenderProps<Agenda>) {\n const events = selectAgendaEvents((block.events ?? []).map((e, i) => ({ ...e, _i: i })), { hidePast: block.hidePast });\n if (events.length === 0) return null;\n\n return (\n <section className=\"xicms-agenda\">\n {block.heading && <Heading level={2} data-xicms-edit=\"heading\">{block.heading}</Heading>}\n <ul className=\"xicms-agenda__list\">\n {events.map((e) => (\n <li key={e._i} className=\"xicms-agenda__item\">\n <time className=\"xicms-agenda__date\" dateTime={e.start}>\n {formatEventDate(e.start)}\n </time>\n <div className=\"xicms-agenda__body\">\n <strong className=\"xicms-agenda__title\">\n {e.url\n ? <a href={e.url} data-xicms-edit={`events.${e._i}.title`}>{e.title}</a>\n : <span data-xicms-edit={`events.${e._i}.title`}>{e.title}</span>}\n </strong>\n {e.location && <span className=\"xicms-agenda__location\" data-xicms-edit={`events.${e._i}.location`}>{e.location}</span>}\n {e.description && <p className=\"xicms-agenda__desc\" data-xicms-edit={`events.${e._i}.description`}>{e.description}</p>}\n {(() => {\n const ics = icsDataUrl(e);\n return ics ? (\n <a className=\"xicms-agenda__ics\" href={ics} download={`${(e.title || \"evenement\").toLowerCase().replace(/\\s+/g, \"-\").slice(0, 40)}.ics`}>\n 📅 Zet in agenda\n </a>\n ) : null;\n })()}\n </div>\n </li>\n ))}\n </ul>\n {block.jsonLd && (\n <script\n type=\"application/ld+json\"\n // eslint-disable-next-line react/no-danger\n dangerouslySetInnerHTML={{ __html: jsonLdHtml(eventJsonLd(events)) }}\n />\n )}\n </section>\n );\n}\n\nexport const agendaBlock = defineBlock({\n type: \"agenda\",\n schema: AgendaBlockSchema,\n Render: AgendaRender,\n label: \"Agenda\",\n icon: \"📅\",\n defaults: () => ({\n heading: \"Agenda\",\n events: [{ title: \"Evenement\", start: \"\" }],\n hidePast: true,\n jsonLd: true,\n }),\n});\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../src/blocks/builtins/Agenda.tsx"],"sourcesContent":["import type { z } from \"zod\";\nimport { jsonLdHtml } from \"./jsonld\";\nimport type { AgendaBlockSchema } from \"../../schema/blocks\";\nimport { defineBlock, type BlockRenderProps } from \"../registry\";\nimport { Heading } from \"../ui\";\nimport { icsDataUrl } from \"./lib/ics\";\n\ntype Agenda = z.infer<typeof AgendaBlockSchema>;\n\n/** Eén event zoals zowel het Agenda-blok als de Agenda-widget het kennen. */\nexport interface AgendaEvent {\n title: string;\n start: string;\n end?: string;\n location?: string;\n description?: string;\n url?: string;\n}\n\n/**\n * Parseert een event-datum als LOKALE tijd. Cruciaal voor datum-zonder-tijd: `new Date(\"2026-08-01\")`\n * is per spec UTC-middernacht, waardoor west-van-UTC-bezoekers \"31 juli\" te zien kregen (en de\n * server/client bij hydration konden verschillen). \"2026-08-01\" is hier gewoon 1 augustus, overal.\n */\nexport function parseEventDate(value: string): Date {\n const m = /^(\\d{4})-(\\d{2})-(\\d{2})$/.exec(value.trim());\n if (m) return new Date(Number(m[1]), Number(m[2]) - 1, Number(m[3]));\n return new Date(value);\n}\n\n/** Toont een datum leesbaar (nl-NL). Valt terug op de ruwe string bij ongeldige invoer. */\nexport function formatEventDate(value: string): string {\n if (!value) return \"\";\n const d = parseEventDate(value);\n if (Number.isNaN(d.getTime())) return value;\n const hasTime = value.includes(\"T\");\n return d.toLocaleDateString(\"nl-NL\", {\n weekday: \"short\",\n day: \"numeric\",\n month: \"long\",\n year: \"numeric\",\n ...(hasTime ? { hour: \"2-digit\", minute: \"2-digit\" } : {}),\n });\n}\n\n/**\n * Selecteert de te tonen events: filtert lege titels, optioneel verlopen events, sorteert\n * chronologisch (events zonder geldige datum achteraan, in invoervolgorde) en limiteert. Gedeeld\n * door het volwaardige Agenda-blok en de compacte Agenda-widget — zo \"haalt\" de widget alles\n * uit dezelfde logica als de volledige versie.\n */\nexport function selectAgendaEvents<T extends AgendaEvent>(\n events: T[] | undefined,\n opts: { hidePast?: boolean; limit?: number } = {},\n): T[] {\n let list = (events ?? []).filter((e) => e.title);\n if (opts.hidePast) {\n const today = new Date();\n today.setHours(0, 0, 0, 0);\n list = list.filter((e) => {\n const d = parseEventDate(e.end || e.start);\n return Number.isNaN(d.getTime()) || d >= today;\n });\n }\n list = [...list].sort((a, b) => {\n const ta = parseEventDate(a.start).getTime();\n const tb = parseEventDate(b.start).getTime();\n if (Number.isNaN(ta) && Number.isNaN(tb)) return 0;\n if (Number.isNaN(ta)) return 1;\n if (Number.isNaN(tb)) return -1;\n return ta - tb;\n });\n return typeof opts.limit === \"number\" ? list.slice(0, opts.limit) : list;\n}\n\nfunction eventJsonLd(events: Agenda[\"events\"]): Record<string, unknown> {\n return {\n \"@context\": \"https://schema.org\",\n \"@type\": \"ItemList\",\n // Google vereist `location` voor Event-rich-results: events zonder locatie renderen wel op\n // de pagina, maar blijven uit de JSON-LD (voorkomt gegarandeerde Search-Console-errors).\n itemListElement: events\n .filter((e) => e.title && e.start && e.location)\n .map((e, i) => ({\n \"@type\": \"ListItem\",\n position: i + 1,\n item: {\n \"@type\": \"Event\",\n name: e.title,\n startDate: e.start,\n ...(e.end ? { endDate: e.end } : {}),\n location: { \"@type\": \"Place\", name: e.location },\n ...(e.description ? { description: e.description } : {}),\n ...(e.url ? { url: e.url } : {}),\n },\n })),\n };\n}\n\n/** Agenda/evenementen. Server-safe (geen client-state); `hidePast` filtert verlopen events. */\nfunction AgendaRender({ block }: BlockRenderProps<Agenda>) {\n const events = selectAgendaEvents((block.events ?? []).map((e, i) => ({ ...e, _i: i })), { hidePast: block.hidePast });\n if (events.length === 0) return null;\n\n return (\n <section className=\"xicms-agenda\">\n {block.heading && <Heading level={2} data-xicms-edit=\"heading\">{block.heading}</Heading>}\n <ul className=\"xicms-agenda__list\">\n {events.map((e) => (\n <li key={e._i} className=\"xicms-agenda__item\">\n <time className=\"xicms-agenda__date\" dateTime={e.start}>\n {formatEventDate(e.start)}\n </time>\n <div className=\"xicms-agenda__body\">\n <strong className=\"xicms-agenda__title\">\n {e.url\n ? <a href={e.url} data-xicms-edit={`events.${e._i}.title`}>{e.title}</a>\n : <span data-xicms-edit={`events.${e._i}.title`}>{e.title}</span>}\n </strong>\n {e.location && <span className=\"xicms-agenda__location\" data-xicms-edit={`events.${e._i}.location`}>{e.location}</span>}\n {e.description && <p className=\"xicms-agenda__desc\" data-xicms-edit={`events.${e._i}.description`}>{e.description}</p>}\n {(() => {\n const ics = icsDataUrl(e);\n return ics ? (\n <a className=\"xicms-agenda__ics\" href={ics} download={`${(e.title || \"evenement\").toLowerCase().replace(/\\s+/g, \"-\").slice(0, 40)}.ics`}>\n 📅 Zet in agenda\n </a>\n ) : null;\n })()}\n </div>\n </li>\n ))}\n </ul>\n {block.jsonLd && (\n <script\n type=\"application/ld+json\"\n // eslint-disable-next-line react/no-danger\n dangerouslySetInnerHTML={{ __html: jsonLdHtml(eventJsonLd(events)) }}\n />\n )}\n </section>\n );\n}\n\nexport const agendaBlock = defineBlock({\n type: \"agenda\",\n Render: AgendaRender,\n label: \"Agenda\",\n icon: \"📅\",\n defaults: () => ({\n heading: \"Agenda\",\n events: [{ title: \"Evenement\", start: \"\" }],\n hidePast: true,\n jsonLd: true,\n }),\n});\n"],"mappings":"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","names":[]}
@@ -1,7 +1,6 @@
1
1
  "use client";
2
2
  import { jsx, jsxs } from "react/jsx-runtime";
3
3
  import { useEffect, useState } from "react";
4
- import { BannerBlockSchema } from "../../schema/blocks.js";
5
4
  import { defineBlock } from "../registry.js";
6
5
  function storageKey(block) {
7
6
  return `xicms-banner:${block._key}${block.dismissVersion ? `:${block.dismissVersion}` : ""}`;
@@ -33,7 +32,6 @@ function BannerRender({ block, mode }) {
33
32
  }
34
33
  const bannerBlock = defineBlock({
35
34
  type: "banner",
36
- schema: BannerBlockSchema,
37
35
  Render: BannerRender,
38
36
  label: "Aankondiging",
39
37
  icon: "\u{1F4E2}",
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/blocks/builtins/Banner.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useState } from \"react\";\nimport type { z } from \"zod\";\nimport { BannerBlockSchema } from \"../../schema/blocks\";\nimport { defineBlock, type BlockRenderProps } from \"../registry\";\n\ntype Banner = z.infer<typeof BannerBlockSchema>;\n\n/** Sleutel per blok (+ optionele versie): wegklikken onthouden we per banner-inhoud. */\nfunction storageKey(block: Banner): string {\n return `xicms-banner:${block._key}${block.dismissVersion ? `:${block.dismissVersion}` : \"\"}`;\n}\n\n/**\n * Aankondigingsbalk, optioneel sluitbaar. Wegklikken wordt in localStorage onthouden (per blok +\n * `dismissVersion`), zodat de balk niet bij elke paginaweergave terugkomt. In de editor-preview\n * tonen we hem altijd (anders kan een editor zijn eigen weggeklikte banner niet meer bewerken).\n */\nfunction BannerRender({ block, mode }: BlockRenderProps<Banner>) {\n const [closed, setClosed] = useState(false);\n\n // localStorage pas na mount lezen (SSR-veilig; voorkomt hydration-mismatch).\n useEffect(() => {\n if (mode === \"preview\" || !block.dismissible) return;\n try {\n if (window.localStorage.getItem(storageKey(block)) === \"1\") setClosed(true);\n } catch {\n /* opslag onbeschikbaar: banner gewoon tonen */\n }\n }, [block, mode]);\n\n const dismiss = () => {\n setClosed(true);\n try {\n window.localStorage.setItem(storageKey(block), \"1\");\n } catch {\n /* opslag geweigerd: sluiten geldt dan alleen voor deze weergave */\n }\n };\n\n if (!block.text || (closed && mode !== \"preview\")) return null;\n return (\n <div className=\"xicms-banner\" data-tone={block.tone} role=\"region\" aria-label=\"Aankondiging\">\n <span>\n <span data-xicms-edit=\"text\">{block.text}</span>\n {block.href && (\n <a className=\"xicms-banner__link\" href={block.href} data-xicms-edit=\"linkLabel\">\n {block.linkLabel ?? \"Meer\"}\n </a>\n )}\n </span>\n {block.dismissible && (\n <button type=\"button\" className=\"xicms-banner__close\" aria-label=\"Sluiten\" onClick={dismiss}>\n ✕\n </button>\n )}\n </div>\n );\n}\n\nexport const bannerBlock = defineBlock({\n type: \"banner\",\n schema: BannerBlockSchema,\n Render: BannerRender,\n label: \"Aankondiging\",\n icon: \"📢\",\n defaults: () => ({ text: \"Nieuw: …\", tone: \"info\", dismissible: true }),\n});\n"],"mappings":";AA4CM,SACE,KADF;AA1CN,SAAS,WAAW,gBAAgB;AAEpC,SAAS,yBAAyB;AAClC,SAAS,mBAA0C;AAKnD,SAAS,WAAW,OAAuB;AACzC,SAAO,gBAAgB,MAAM,IAAI,GAAG,MAAM,iBAAiB,IAAI,MAAM,cAAc,KAAK,EAAE;AAC5F;AAOA,SAAS,aAAa,EAAE,OAAO,KAAK,GAA6B;AAC/D,QAAM,CAAC,QAAQ,SAAS,IAAI,SAAS,KAAK;AAG1C,YAAU,MAAM;AACd,QAAI,SAAS,aAAa,CAAC,MAAM,YAAa;AAC9C,QAAI;AACF,UAAI,OAAO,aAAa,QAAQ,WAAW,KAAK,CAAC,MAAM,IAAK,WAAU,IAAI;AAAA,IAC5E,QAAQ;AAAA,IAER;AAAA,EACF,GAAG,CAAC,OAAO,IAAI,CAAC;AAEhB,QAAM,UAAU,MAAM;AACpB,cAAU,IAAI;AACd,QAAI;AACF,aAAO,aAAa,QAAQ,WAAW,KAAK,GAAG,GAAG;AAAA,IACpD,QAAQ;AAAA,IAER;AAAA,EACF;AAEA,MAAI,CAAC,MAAM,QAAS,UAAU,SAAS,UAAY,QAAO;AAC1D,SACE,qBAAC,SAAI,WAAU,gBAAe,aAAW,MAAM,MAAM,MAAK,UAAS,cAAW,gBAC5E;AAAA,yBAAC,UACC;AAAA,0BAAC,UAAK,mBAAgB,QAAQ,gBAAM,MAAK;AAAA,MACxC,MAAM,QACL,oBAAC,OAAE,WAAU,sBAAqB,MAAM,MAAM,MAAM,mBAAgB,aACjE,gBAAM,aAAa,QACtB;AAAA,OAEJ;AAAA,IACC,MAAM,eACL,oBAAC,YAAO,MAAK,UAAS,WAAU,uBAAsB,cAAW,WAAU,SAAS,SAAS,oBAE7F;AAAA,KAEJ;AAEJ;AAEO,MAAM,cAAc,YAAY;AAAA,EACrC,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,MAAM;AAAA,EACN,UAAU,OAAO,EAAE,MAAM,iBAAY,MAAM,QAAQ,aAAa,KAAK;AACvE,CAAC;","names":[]}
1
+ {"version":3,"sources":["../../../src/blocks/builtins/Banner.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useState } from \"react\";\nimport type { z } from \"zod\";\nimport type { BannerBlockSchema } from \"../../schema/blocks\";\nimport { defineBlock, type BlockRenderProps } from \"../registry\";\n\ntype Banner = z.infer<typeof BannerBlockSchema>;\n\n/** Sleutel per blok (+ optionele versie): wegklikken onthouden we per banner-inhoud. */\nfunction storageKey(block: Banner): string {\n return `xicms-banner:${block._key}${block.dismissVersion ? `:${block.dismissVersion}` : \"\"}`;\n}\n\n/**\n * Aankondigingsbalk, optioneel sluitbaar. Wegklikken wordt in localStorage onthouden (per blok +\n * `dismissVersion`), zodat de balk niet bij elke paginaweergave terugkomt. In de editor-preview\n * tonen we hem altijd (anders kan een editor zijn eigen weggeklikte banner niet meer bewerken).\n */\nfunction BannerRender({ block, mode }: BlockRenderProps<Banner>) {\n const [closed, setClosed] = useState(false);\n\n // localStorage pas na mount lezen (SSR-veilig; voorkomt hydration-mismatch).\n useEffect(() => {\n if (mode === \"preview\" || !block.dismissible) return;\n try {\n if (window.localStorage.getItem(storageKey(block)) === \"1\") setClosed(true);\n } catch {\n /* opslag onbeschikbaar: banner gewoon tonen */\n }\n }, [block, mode]);\n\n const dismiss = () => {\n setClosed(true);\n try {\n window.localStorage.setItem(storageKey(block), \"1\");\n } catch {\n /* opslag geweigerd: sluiten geldt dan alleen voor deze weergave */\n }\n };\n\n if (!block.text || (closed && mode !== \"preview\")) return null;\n return (\n <div className=\"xicms-banner\" data-tone={block.tone} role=\"region\" aria-label=\"Aankondiging\">\n <span>\n <span data-xicms-edit=\"text\">{block.text}</span>\n {block.href && (\n <a className=\"xicms-banner__link\" href={block.href} data-xicms-edit=\"linkLabel\">\n {block.linkLabel ?? \"Meer\"}\n </a>\n )}\n </span>\n {block.dismissible && (\n <button type=\"button\" className=\"xicms-banner__close\" aria-label=\"Sluiten\" onClick={dismiss}>\n ✕\n </button>\n )}\n </div>\n );\n}\n\nexport const bannerBlock = defineBlock({\n type: \"banner\",\n Render: BannerRender,\n label: \"Aankondiging\",\n icon: \"📢\",\n defaults: () => ({ text: \"Nieuw: …\", tone: \"info\", dismissible: true }),\n});\n"],"mappings":";AA4CM,SACE,KADF;AA1CN,SAAS,WAAW,gBAAgB;AAGpC,SAAS,mBAA0C;AAKnD,SAAS,WAAW,OAAuB;AACzC,SAAO,gBAAgB,MAAM,IAAI,GAAG,MAAM,iBAAiB,IAAI,MAAM,cAAc,KAAK,EAAE;AAC5F;AAOA,SAAS,aAAa,EAAE,OAAO,KAAK,GAA6B;AAC/D,QAAM,CAAC,QAAQ,SAAS,IAAI,SAAS,KAAK;AAG1C,YAAU,MAAM;AACd,QAAI,SAAS,aAAa,CAAC,MAAM,YAAa;AAC9C,QAAI;AACF,UAAI,OAAO,aAAa,QAAQ,WAAW,KAAK,CAAC,MAAM,IAAK,WAAU,IAAI;AAAA,IAC5E,QAAQ;AAAA,IAER;AAAA,EACF,GAAG,CAAC,OAAO,IAAI,CAAC;AAEhB,QAAM,UAAU,MAAM;AACpB,cAAU,IAAI;AACd,QAAI;AACF,aAAO,aAAa,QAAQ,WAAW,KAAK,GAAG,GAAG;AAAA,IACpD,QAAQ;AAAA,IAER;AAAA,EACF;AAEA,MAAI,CAAC,MAAM,QAAS,UAAU,SAAS,UAAY,QAAO;AAC1D,SACE,qBAAC,SAAI,WAAU,gBAAe,aAAW,MAAM,MAAM,MAAK,UAAS,cAAW,gBAC5E;AAAA,yBAAC,UACC;AAAA,0BAAC,UAAK,mBAAgB,QAAQ,gBAAM,MAAK;AAAA,MACxC,MAAM,QACL,oBAAC,OAAE,WAAU,sBAAqB,MAAM,MAAM,MAAM,mBAAgB,aACjE,gBAAM,aAAa,QACtB;AAAA,OAEJ;AAAA,IACC,MAAM,eACL,oBAAC,YAAO,MAAK,UAAS,WAAU,uBAAsB,cAAW,WAAU,SAAS,SAAS,oBAE7F;AAAA,KAEJ;AAEJ;AAEO,MAAM,cAAc,YAAY;AAAA,EACrC,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,MAAM;AAAA,EACN,UAAU,OAAO,EAAE,MAAM,iBAAY,MAAM,QAAQ,aAAa,KAAK;AACvE,CAAC;","names":[]}
@@ -1,7 +1,6 @@
1
1
  "use client";
2
2
  import { jsx, jsxs } from "react/jsx-runtime";
3
3
  import { useState } from "react";
4
- import { BeforeAfterBlockSchema } from "../../schema/blocks.js";
5
4
  import { defineBlock } from "../registry.js";
6
5
  function BeforeAfterRender({ block }) {
7
6
  const [pos, setPos] = useState(50);
@@ -33,7 +32,6 @@ function BeforeAfterRender({ block }) {
33
32
  const beforeAfterBlock = defineBlock({
34
33
  type: "beforeAfter",
35
34
  fields: { beforeUrl: { type: "image" }, afterUrl: { type: "image" } },
36
- schema: BeforeAfterBlockSchema,
37
35
  Render: BeforeAfterRender,
38
36
  label: "Voor / na",
39
37
  icon: "\u{1F500}",
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/blocks/builtins/BeforeAfter.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState } from \"react\";\nimport type { z } from \"zod\";\nimport { BeforeAfterBlockSchema } from \"../../schema/blocks\";\nimport { defineBlock, type BlockRenderProps } from \"../registry\";\n\ntype BeforeAfter = z.infer<typeof BeforeAfterBlockSchema>;\n\n/**\n * Voor/na-vergelijker: het \"na\"-beeld wordt geclipt op de sleppositie. De greep is een échte\n * range-input (over de hele breedte, transparant) — slepen, klikken én pijltjestoetsen werken\n * daarmee gratis en toegankelijk (aria-label + waarde in %).\n */\nfunction BeforeAfterRender({ block }: BlockRenderProps<BeforeAfter>) {\n const [pos, setPos] = useState(50);\n if (!block.beforeUrl || !block.afterUrl) return null;\n return (\n <figure className=\"xicms-beforeafter\" style={{ aspectRatio: block.aspectRatio.replace(\"/\", \" / \") }}>\n {block.heading && <figcaption className=\"xicms-beforeafter__heading\" data-xicms-edit=\"heading\">{block.heading}</figcaption>}\n <div className=\"xicms-beforeafter__stage\">\n {/* eslint-disable-next-line @next/next/no-img-element */}\n <img className=\"xicms-beforeafter__img\" src={block.beforeUrl} alt={block.alt || block.beforeLabel} loading=\"lazy\" />\n <div className=\"xicms-beforeafter__clip\" style={{ clipPath: `inset(0 0 0 ${pos}%)` }} aria-hidden>\n {/* eslint-disable-next-line @next/next/no-img-element */}\n <img className=\"xicms-beforeafter__img\" src={block.afterUrl} alt=\"\" loading=\"lazy\" />\n </div>\n <div className=\"xicms-beforeafter__divider\" style={{ left: `${pos}%` }} aria-hidden>\n <span className=\"xicms-beforeafter__handle\">⟨⟩</span>\n </div>\n <span className=\"xicms-beforeafter__badge xicms-beforeafter__badge--before\" data-xicms-edit=\"beforeLabel\">{block.beforeLabel}</span>\n <span className=\"xicms-beforeafter__badge xicms-beforeafter__badge--after\" data-xicms-edit=\"afterLabel\">{block.afterLabel}</span>\n <input\n className=\"xicms-beforeafter__range\"\n type=\"range\"\n min={0}\n max={100}\n value={pos}\n onChange={(e) => setPos(Number(e.target.value))}\n aria-label={`Vergelijk ${block.beforeLabel} en ${block.afterLabel}`}\n aria-valuetext={`${pos}% ${block.afterLabel}`}\n />\n </div>\n </figure>\n );\n}\n\nexport const beforeAfterBlock = defineBlock({\n type: \"beforeAfter\",\n fields: { beforeUrl: { type: \"image\" }, afterUrl: { type: \"image\" } },\n schema: BeforeAfterBlockSchema,\n Render: BeforeAfterRender,\n label: \"Voor / na\",\n icon: \"🔀\",\n defaults: () => ({ beforeUrl: \"\", afterUrl: \"\", beforeLabel: \"Voor\", afterLabel: \"Na\", aspectRatio: \"4/3\" }),\n});\n"],"mappings":";AAmBwB,cAClB,YADkB;AAjBxB,SAAS,gBAAgB;AAEzB,SAAS,8BAA8B;AACvC,SAAS,mBAA0C;AASnD,SAAS,kBAAkB,EAAE,MAAM,GAAkC;AACnE,QAAM,CAAC,KAAK,MAAM,IAAI,SAAS,EAAE;AACjC,MAAI,CAAC,MAAM,aAAa,CAAC,MAAM,SAAU,QAAO;AAChD,SACE,qBAAC,YAAO,WAAU,qBAAoB,OAAO,EAAE,aAAa,MAAM,YAAY,QAAQ,KAAK,KAAK,EAAE,GAC/F;AAAA,UAAM,WAAW,oBAAC,gBAAW,WAAU,8BAA6B,mBAAgB,WAAW,gBAAM,SAAQ;AAAA,IAC9G,qBAAC,SAAI,WAAU,4BAEb;AAAA,0BAAC,SAAI,WAAU,0BAAyB,KAAK,MAAM,WAAW,KAAK,MAAM,OAAO,MAAM,aAAa,SAAQ,QAAO;AAAA,MAClH,oBAAC,SAAI,WAAU,2BAA0B,OAAO,EAAE,UAAU,eAAe,GAAG,KAAK,GAAG,eAAW,MAE/F,8BAAC,SAAI,WAAU,0BAAyB,KAAK,MAAM,UAAU,KAAI,IAAG,SAAQ,QAAO,GACrF;AAAA,MACA,oBAAC,SAAI,WAAU,8BAA6B,OAAO,EAAE,MAAM,GAAG,GAAG,IAAI,GAAG,eAAW,MACjF,8BAAC,UAAK,WAAU,6BAA4B,0BAAE,GAChD;AAAA,MACA,oBAAC,UAAK,WAAU,6DAA4D,mBAAgB,eAAe,gBAAM,aAAY;AAAA,MAC7H,oBAAC,UAAK,WAAU,4DAA2D,mBAAgB,cAAc,gBAAM,YAAW;AAAA,MAC1H;AAAA,QAAC;AAAA;AAAA,UACC,WAAU;AAAA,UACV,MAAK;AAAA,UACL,KAAK;AAAA,UACL,KAAK;AAAA,UACL,OAAO;AAAA,UACP,UAAU,CAAC,MAAM,OAAO,OAAO,EAAE,OAAO,KAAK,CAAC;AAAA,UAC9C,cAAY,aAAa,MAAM,WAAW,OAAO,MAAM,UAAU;AAAA,UACjE,kBAAgB,GAAG,GAAG,KAAK,MAAM,UAAU;AAAA;AAAA,MAC7C;AAAA,OACF;AAAA,KACF;AAEJ;AAEO,MAAM,mBAAmB,YAAY;AAAA,EAC1C,MAAM;AAAA,EACN,QAAQ,EAAE,WAAW,EAAE,MAAM,QAAQ,GAAG,UAAU,EAAE,MAAM,QAAQ,EAAE;AAAA,EACpE,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,MAAM;AAAA,EACN,UAAU,OAAO,EAAE,WAAW,IAAI,UAAU,IAAI,aAAa,QAAQ,YAAY,MAAM,aAAa,MAAM;AAC5G,CAAC;","names":[]}
1
+ {"version":3,"sources":["../../../src/blocks/builtins/BeforeAfter.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState } from \"react\";\nimport type { z } from \"zod\";\nimport type { BeforeAfterBlockSchema } from \"../../schema/blocks\";\nimport { defineBlock, type BlockRenderProps } from \"../registry\";\n\ntype BeforeAfter = z.infer<typeof BeforeAfterBlockSchema>;\n\n/**\n * Voor/na-vergelijker: het \"na\"-beeld wordt geclipt op de sleppositie. De greep is een échte\n * range-input (over de hele breedte, transparant) — slepen, klikken én pijltjestoetsen werken\n * daarmee gratis en toegankelijk (aria-label + waarde in %).\n */\nfunction BeforeAfterRender({ block }: BlockRenderProps<BeforeAfter>) {\n const [pos, setPos] = useState(50);\n if (!block.beforeUrl || !block.afterUrl) return null;\n return (\n <figure className=\"xicms-beforeafter\" style={{ aspectRatio: block.aspectRatio.replace(\"/\", \" / \") }}>\n {block.heading && <figcaption className=\"xicms-beforeafter__heading\" data-xicms-edit=\"heading\">{block.heading}</figcaption>}\n <div className=\"xicms-beforeafter__stage\">\n {/* eslint-disable-next-line @next/next/no-img-element */}\n <img className=\"xicms-beforeafter__img\" src={block.beforeUrl} alt={block.alt || block.beforeLabel} loading=\"lazy\" />\n <div className=\"xicms-beforeafter__clip\" style={{ clipPath: `inset(0 0 0 ${pos}%)` }} aria-hidden>\n {/* eslint-disable-next-line @next/next/no-img-element */}\n <img className=\"xicms-beforeafter__img\" src={block.afterUrl} alt=\"\" loading=\"lazy\" />\n </div>\n <div className=\"xicms-beforeafter__divider\" style={{ left: `${pos}%` }} aria-hidden>\n <span className=\"xicms-beforeafter__handle\">⟨⟩</span>\n </div>\n <span className=\"xicms-beforeafter__badge xicms-beforeafter__badge--before\" data-xicms-edit=\"beforeLabel\">{block.beforeLabel}</span>\n <span className=\"xicms-beforeafter__badge xicms-beforeafter__badge--after\" data-xicms-edit=\"afterLabel\">{block.afterLabel}</span>\n <input\n className=\"xicms-beforeafter__range\"\n type=\"range\"\n min={0}\n max={100}\n value={pos}\n onChange={(e) => setPos(Number(e.target.value))}\n aria-label={`Vergelijk ${block.beforeLabel} en ${block.afterLabel}`}\n aria-valuetext={`${pos}% ${block.afterLabel}`}\n />\n </div>\n </figure>\n );\n}\n\nexport const beforeAfterBlock = defineBlock({\n type: \"beforeAfter\",\n fields: { beforeUrl: { type: \"image\" }, afterUrl: { type: \"image\" } },\n Render: BeforeAfterRender,\n label: \"Voor / na\",\n icon: \"🔀\",\n defaults: () => ({ beforeUrl: \"\", afterUrl: \"\", beforeLabel: \"Voor\", afterLabel: \"Na\", aspectRatio: \"4/3\" }),\n});\n"],"mappings":";AAmBwB,cAClB,YADkB;AAjBxB,SAAS,gBAAgB;AAGzB,SAAS,mBAA0C;AASnD,SAAS,kBAAkB,EAAE,MAAM,GAAkC;AACnE,QAAM,CAAC,KAAK,MAAM,IAAI,SAAS,EAAE;AACjC,MAAI,CAAC,MAAM,aAAa,CAAC,MAAM,SAAU,QAAO;AAChD,SACE,qBAAC,YAAO,WAAU,qBAAoB,OAAO,EAAE,aAAa,MAAM,YAAY,QAAQ,KAAK,KAAK,EAAE,GAC/F;AAAA,UAAM,WAAW,oBAAC,gBAAW,WAAU,8BAA6B,mBAAgB,WAAW,gBAAM,SAAQ;AAAA,IAC9G,qBAAC,SAAI,WAAU,4BAEb;AAAA,0BAAC,SAAI,WAAU,0BAAyB,KAAK,MAAM,WAAW,KAAK,MAAM,OAAO,MAAM,aAAa,SAAQ,QAAO;AAAA,MAClH,oBAAC,SAAI,WAAU,2BAA0B,OAAO,EAAE,UAAU,eAAe,GAAG,KAAK,GAAG,eAAW,MAE/F,8BAAC,SAAI,WAAU,0BAAyB,KAAK,MAAM,UAAU,KAAI,IAAG,SAAQ,QAAO,GACrF;AAAA,MACA,oBAAC,SAAI,WAAU,8BAA6B,OAAO,EAAE,MAAM,GAAG,GAAG,IAAI,GAAG,eAAW,MACjF,8BAAC,UAAK,WAAU,6BAA4B,0BAAE,GAChD;AAAA,MACA,oBAAC,UAAK,WAAU,6DAA4D,mBAAgB,eAAe,gBAAM,aAAY;AAAA,MAC7H,oBAAC,UAAK,WAAU,4DAA2D,mBAAgB,cAAc,gBAAM,YAAW;AAAA,MAC1H;AAAA,QAAC;AAAA;AAAA,UACC,WAAU;AAAA,UACV,MAAK;AAAA,UACL,KAAK;AAAA,UACL,KAAK;AAAA,UACL,OAAO;AAAA,UACP,UAAU,CAAC,MAAM,OAAO,OAAO,EAAE,OAAO,KAAK,CAAC;AAAA,UAC9C,cAAY,aAAa,MAAM,WAAW,OAAO,MAAM,UAAU;AAAA,UACjE,kBAAgB,GAAG,GAAG,KAAK,MAAM,UAAU;AAAA;AAAA,MAC7C;AAAA,OACF;AAAA,KACF;AAEJ;AAEO,MAAM,mBAAmB,YAAY;AAAA,EAC1C,MAAM;AAAA,EACN,QAAQ,EAAE,WAAW,EAAE,MAAM,QAAQ,GAAG,UAAU,EAAE,MAAM,QAAQ,EAAE;AAAA,EACpE,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,MAAM;AAAA,EACN,UAAU,OAAO,EAAE,WAAW,IAAI,UAAU,IAAI,aAAa,QAAQ,YAAY,MAAM,aAAa,MAAM;AAC5G,CAAC;","names":[]}
@@ -1,6 +1,5 @@
1
1
  "use client";
2
2
  import { jsx, jsxs } from "react/jsx-runtime";
3
- import { BookingBlockSchema } from "../../schema/blocks.js";
4
3
  import { defineBlock } from "../registry.js";
5
4
  import { Heading } from "../ui/index.js";
6
5
  import { ConsentEmbed } from "./consentEmbed.js";
@@ -15,7 +14,6 @@ function BookingRender({ block, mode }) {
15
14
  }
16
15
  const bookingBlock = defineBlock({
17
16
  type: "booking",
18
- schema: BookingBlockSchema,
19
17
  Render: BookingRender,
20
18
  label: "Afspraak/booking",
21
19
  icon: "\u{1F4C6}",
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/blocks/builtins/Booking.tsx"],"sourcesContent":["\"use client\";\n\nimport type { z } from \"zod\";\nimport { BookingBlockSchema } from \"../../schema/blocks\";\nimport { defineBlock, type BlockRenderProps } from \"../registry\";\nimport { Heading } from \"../ui\";\nimport { ConsentEmbed } from \"./consentEmbed\";\nimport { buildBookingUrl, type BookingProvider } from \"./lib/bookingUrl\";\n\ntype Booking = z.infer<typeof BookingBlockSchema>;\n\n/** Boekings-/afspraak-embed (bv. Calendly). Consent-gated by default. De provider-keuze bouwt de\n * volledige embed-URL uit een geplakte link óf een kale slug/id (buildBookingUrl). */\nfunction BookingRender({ block, mode }: BlockRenderProps<Booking>) {\n const src = buildBookingUrl((block.provider ?? \"custom\") as BookingProvider, block.embedUrl);\n if (!src) return null;\n return (\n <section className=\"xicms-booking\">\n {block.heading && <Heading level={2} data-xicms-edit=\"heading\">{block.heading}</Heading>}\n <div className=\"xicms-booking__frame\" style={{ height: `${block.height}px` }}>\n <ConsentEmbed gated={block.consentGated} preview={mode === \"preview\"} label=\"Afspraak/booking\">\n <iframe src={src} title={block.heading ?? \"Afspraak maken\"} loading=\"lazy\" referrerPolicy=\"no-referrer-when-downgrade\" sandbox=\"allow-scripts allow-same-origin allow-forms allow-popups\" style={{ border: 0, width: \"100%\", height: \"100%\" }} />\n </ConsentEmbed>\n </div>\n </section>\n );\n}\n\nexport const bookingBlock = defineBlock({\n type: \"booking\",\n schema: BookingBlockSchema,\n Render: BookingRender,\n label: \"Afspraak/booking\",\n icon: \"📆\",\n defaults: () => ({ embedUrl: \"\", height: 630, consentGated: true }),\n});\n"],"mappings":";AAiBI,SACoB,KADpB;AAdJ,SAAS,0BAA0B;AACnC,SAAS,mBAA0C;AACnD,SAAS,eAAe;AACxB,SAAS,oBAAoB;AAC7B,SAAS,uBAA6C;AAMtD,SAAS,cAAc,EAAE,OAAO,KAAK,GAA8B;AACjE,QAAM,MAAM,gBAAiB,MAAM,YAAY,UAA8B,MAAM,QAAQ;AAC3F,MAAI,CAAC,IAAK,QAAO;AACjB,SACE,qBAAC,aAAQ,WAAU,iBAChB;AAAA,UAAM,WAAW,oBAAC,WAAQ,OAAO,GAAG,mBAAgB,WAAW,gBAAM,SAAQ;AAAA,IAC9E,oBAAC,SAAI,WAAU,wBAAuB,OAAO,EAAE,QAAQ,GAAG,MAAM,MAAM,KAAK,GACzE,8BAAC,gBAAa,OAAO,MAAM,cAAc,SAAS,SAAS,WAAW,OAAM,oBAC1E,8BAAC,YAAO,KAAU,OAAO,MAAM,WAAW,kBAAkB,SAAQ,QAAO,gBAAe,8BAA6B,SAAQ,4DAA2D,OAAO,EAAE,QAAQ,GAAG,OAAO,QAAQ,QAAQ,OAAO,GAAG,GACjP,GACF;AAAA,KACF;AAEJ;AAEO,MAAM,eAAe,YAAY;AAAA,EACtC,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,MAAM;AAAA,EACN,UAAU,OAAO,EAAE,UAAU,IAAI,QAAQ,KAAK,cAAc,KAAK;AACnE,CAAC;","names":[]}
1
+ {"version":3,"sources":["../../../src/blocks/builtins/Booking.tsx"],"sourcesContent":["\"use client\";\n\nimport type { z } from \"zod\";\nimport type { BookingBlockSchema } from \"../../schema/blocks\";\nimport { defineBlock, type BlockRenderProps } from \"../registry\";\nimport { Heading } from \"../ui\";\nimport { ConsentEmbed } from \"./consentEmbed\";\nimport { buildBookingUrl, type BookingProvider } from \"./lib/bookingUrl\";\n\ntype Booking = z.infer<typeof BookingBlockSchema>;\n\n/** Boekings-/afspraak-embed (bv. Calendly). Consent-gated by default. De provider-keuze bouwt de\n * volledige embed-URL uit een geplakte link óf een kale slug/id (buildBookingUrl). */\nfunction BookingRender({ block, mode }: BlockRenderProps<Booking>) {\n const src = buildBookingUrl((block.provider ?? \"custom\") as BookingProvider, block.embedUrl);\n if (!src) return null;\n return (\n <section className=\"xicms-booking\">\n {block.heading && <Heading level={2} data-xicms-edit=\"heading\">{block.heading}</Heading>}\n <div className=\"xicms-booking__frame\" style={{ height: `${block.height}px` }}>\n <ConsentEmbed gated={block.consentGated} preview={mode === \"preview\"} label=\"Afspraak/booking\">\n <iframe src={src} title={block.heading ?? \"Afspraak maken\"} loading=\"lazy\" referrerPolicy=\"no-referrer-when-downgrade\" sandbox=\"allow-scripts allow-same-origin allow-forms allow-popups\" style={{ border: 0, width: \"100%\", height: \"100%\" }} />\n </ConsentEmbed>\n </div>\n </section>\n );\n}\n\nexport const bookingBlock = defineBlock({\n type: \"booking\",\n Render: BookingRender,\n label: \"Afspraak/booking\",\n icon: \"📆\",\n defaults: () => ({ embedUrl: \"\", height: 630, consentGated: true }),\n});\n"],"mappings":";AAiBI,SACoB,KADpB;AAbJ,SAAS,mBAA0C;AACnD,SAAS,eAAe;AACxB,SAAS,oBAAoB;AAC7B,SAAS,uBAA6C;AAMtD,SAAS,cAAc,EAAE,OAAO,KAAK,GAA8B;AACjE,QAAM,MAAM,gBAAiB,MAAM,YAAY,UAA8B,MAAM,QAAQ;AAC3F,MAAI,CAAC,IAAK,QAAO;AACjB,SACE,qBAAC,aAAQ,WAAU,iBAChB;AAAA,UAAM,WAAW,oBAAC,WAAQ,OAAO,GAAG,mBAAgB,WAAW,gBAAM,SAAQ;AAAA,IAC9E,oBAAC,SAAI,WAAU,wBAAuB,OAAO,EAAE,QAAQ,GAAG,MAAM,MAAM,KAAK,GACzE,8BAAC,gBAAa,OAAO,MAAM,cAAc,SAAS,SAAS,WAAW,OAAM,oBAC1E,8BAAC,YAAO,KAAU,OAAO,MAAM,WAAW,kBAAkB,SAAQ,QAAO,gBAAe,8BAA6B,SAAQ,4DAA2D,OAAO,EAAE,QAAQ,GAAG,OAAO,QAAQ,QAAQ,OAAO,GAAG,GACjP,GACF;AAAA,KACF;AAEJ;AAEO,MAAM,eAAe,YAAY;AAAA,EACtC,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,MAAM;AAAA,EACN,UAAU,OAAO,EAAE,UAAU,IAAI,QAAQ,KAAK,cAAc,KAAK;AACnE,CAAC;","names":[]}
@@ -1,7 +1,6 @@
1
1
  "use client";
2
2
  import { jsx, jsxs } from "react/jsx-runtime";
3
3
  import { useEffect, useState } from "react";
4
- import { BreadcrumbsBlockSchema } from "../../schema/blocks.js";
5
4
  import { defineBlock } from "../registry.js";
6
5
  import { useLinkComponent } from "@astryxdesign/core/Link";
7
6
  import { jsonLdHtml } from "./jsonld.js";
@@ -67,7 +66,6 @@ function BreadcrumbsRender({ block, mode }) {
67
66
  }
68
67
  const breadcrumbsBlock = defineBlock({
69
68
  type: "breadcrumbs",
70
- schema: BreadcrumbsBlockSchema,
71
69
  Render: BreadcrumbsRender,
72
70
  label: "Kruimelpad",
73
71
  icon: "\u{1F9ED}",
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/blocks/builtins/Breadcrumbs.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useState } from \"react\";\nimport type { z } from \"zod\";\nimport { BreadcrumbsBlockSchema } from \"../../schema/blocks\";\nimport { defineBlock, type BlockRenderProps } from \"../registry\";\nimport { useLinkComponent } from \"@astryxdesign/core/Link\";\nimport { jsonLdHtml } from \"./jsonld\";\n\ntype Breadcrumbs = z.infer<typeof BreadcrumbsBlockSchema>;\n\nexport interface Crumb {\n label: string;\n href: string;\n}\n\n/** Kruimels uit een pad: \"/diensten/tuinaanleg\" → Home / Diensten / Tuinaanleg. Puur en getest. */\nexport function crumbsFromPath(path: string, homeLabel = \"Home\"): Crumb[] {\n const segments = path.split(\"/\").filter(Boolean);\n const crumbs: Crumb[] = [{ label: homeLabel, href: \"/\" }];\n let href = \"\";\n for (const seg of segments) {\n href += `/${seg}`;\n // decodeURIComponent gooit op misvormde percent-encoding (\"%E0%A4%A\") — dan het rauwe segment.\n let decoded = seg;\n try {\n decoded = decodeURIComponent(seg);\n } catch {\n /* rauw segment als label */\n }\n const label = decoded.replace(/[-_]+/g, \" \").replace(/^./, (c) => c.toUpperCase());\n crumbs.push({ label, href });\n }\n return crumbs;\n}\n\n/** BreadcrumbList-JSON-LD. Puur en getest. */\nexport function breadcrumbsJsonLd(crumbs: Crumb[]): Record<string, unknown> {\n return {\n \"@context\": \"https://schema.org\",\n \"@type\": \"BreadcrumbList\",\n itemListElement: crumbs.map((c, i) => ({\n \"@type\": \"ListItem\",\n position: i + 1,\n name: c.label,\n item: c.href,\n })),\n };\n}\n\n/**\n * Kruimelpad, afgeleid van de URL (client, ná mount — hydration-veilig). Op de homepage\n * (alleen \"Home\") wordt niets getoond.\n */\nfunction BreadcrumbsRender({ block, mode }: BlockRenderProps<Breadcrumbs>) {\n const LinkC = useLinkComponent();\n const [path, setPath] = useState<string | null>(null);\n useEffect(() => {\n setPath(window.location.pathname);\n }, []);\n\n if (mode === \"preview\" && (path === null || path === \"/\")) {\n return <nav className=\"xicms-breadcrumbs\" aria-label=\"Kruimelpad\"><span data-xicms-edit=\"homeLabel\">{block.homeLabel}</span> / Voorbeeldpagina</nav>;\n }\n if (path === null || path === \"/\") return null;\n const crumbs = crumbsFromPath(path, block.homeLabel);\n\n return (\n <nav className=\"xicms-breadcrumbs\" aria-label=\"Kruimelpad\">\n <ol className=\"xicms-breadcrumbs__list\">\n {crumbs.map((c, i) => (\n <li key={c.href} className=\"xicms-breadcrumbs__item\">\n {i < crumbs.length - 1 ? (\n // De eerste kruimel ís `homeLabel`; de rest komt uit het pad en is dus geen blokveld.\n <LinkC href={c.href}>{i === 0 ? <span data-xicms-edit=\"homeLabel\">{c.label}</span> : c.label}</LinkC>\n ) : (\n <span aria-current=\"page\">{c.label}</span>\n )}\n </li>\n ))}\n </ol>\n {block.jsonLd && (\n <script\n type=\"application/ld+json\"\n // eslint-disable-next-line react/no-danger\n // Absolute URL's: Google wil volledige item-URL's in BreadcrumbList (dit rendert\n // client-side ná mount, dus window.location.origin is beschikbaar).\n dangerouslySetInnerHTML={{\n __html: jsonLdHtml(\n breadcrumbsJsonLd(crumbs.map((c) => ({ ...c, href: `${window.location.origin}${c.href}` }))),\n ),\n }}\n />\n )}\n </nav>\n );\n}\n\nexport const breadcrumbsBlock = defineBlock({\n type: \"breadcrumbs\",\n schema: BreadcrumbsBlockSchema,\n Render: BreadcrumbsRender,\n label: \"Kruimelpad\",\n icon: \"🧭\",\n defaults: () => ({ homeLabel: \"Home\", jsonLd: true }),\n});\n"],"mappings":";AA8DW,SAA2D,KAA3D;AA5DX,SAAS,WAAW,gBAAgB;AAEpC,SAAS,8BAA8B;AACvC,SAAS,mBAA0C;AACnD,SAAS,wBAAwB;AACjC,SAAS,kBAAkB;AAUpB,SAAS,eAAe,MAAc,YAAY,QAAiB;AACxE,QAAM,WAAW,KAAK,MAAM,GAAG,EAAE,OAAO,OAAO;AAC/C,QAAM,SAAkB,CAAC,EAAE,OAAO,WAAW,MAAM,IAAI,CAAC;AACxD,MAAI,OAAO;AACX,aAAW,OAAO,UAAU;AAC1B,YAAQ,IAAI,GAAG;AAEf,QAAI,UAAU;AACd,QAAI;AACF,gBAAU,mBAAmB,GAAG;AAAA,IAClC,QAAQ;AAAA,IAER;AACA,UAAM,QAAQ,QAAQ,QAAQ,UAAU,GAAG,EAAE,QAAQ,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC;AACjF,WAAO,KAAK,EAAE,OAAO,KAAK,CAAC;AAAA,EAC7B;AACA,SAAO;AACT;AAGO,SAAS,kBAAkB,QAA0C;AAC1E,SAAO;AAAA,IACL,YAAY;AAAA,IACZ,SAAS;AAAA,IACT,iBAAiB,OAAO,IAAI,CAAC,GAAG,OAAO;AAAA,MACrC,SAAS;AAAA,MACT,UAAU,IAAI;AAAA,MACd,MAAM,EAAE;AAAA,MACR,MAAM,EAAE;AAAA,IACV,EAAE;AAAA,EACJ;AACF;AAMA,SAAS,kBAAkB,EAAE,OAAO,KAAK,GAAkC;AACzE,QAAM,QAAQ,iBAAiB;AAC/B,QAAM,CAAC,MAAM,OAAO,IAAI,SAAwB,IAAI;AACpD,YAAU,MAAM;AACd,YAAQ,OAAO,SAAS,QAAQ;AAAA,EAClC,GAAG,CAAC,CAAC;AAEL,MAAI,SAAS,cAAc,SAAS,QAAQ,SAAS,MAAM;AACzD,WAAO,qBAAC,SAAI,WAAU,qBAAoB,cAAW,cAAa;AAAA,0BAAC,UAAK,mBAAgB,aAAa,gBAAM,WAAU;AAAA,MAAO;AAAA,OAAkB;AAAA,EAChJ;AACA,MAAI,SAAS,QAAQ,SAAS,IAAK,QAAO;AAC1C,QAAM,SAAS,eAAe,MAAM,MAAM,SAAS;AAEnD,SACE,qBAAC,SAAI,WAAU,qBAAoB,cAAW,cAC5C;AAAA,wBAAC,QAAG,WAAU,2BACX,iBAAO,IAAI,CAAC,GAAG,MACd,oBAAC,QAAgB,WAAU,2BACxB,cAAI,OAAO,SAAS;AAAA;AAAA,MAEnB,oBAAC,SAAM,MAAM,EAAE,MAAO,gBAAM,IAAI,oBAAC,UAAK,mBAAgB,aAAa,YAAE,OAAM,IAAU,EAAE,OAAM;AAAA,QAE7F,oBAAC,UAAK,gBAAa,QAAQ,YAAE,OAAM,KAL9B,EAAE,IAOX,CACD,GACH;AAAA,IACC,MAAM,UACL;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QAIL,yBAAyB;AAAA,UACvB,QAAQ;AAAA,YACN,kBAAkB,OAAO,IAAI,CAAC,OAAO,EAAE,GAAG,GAAG,MAAM,GAAG,OAAO,SAAS,MAAM,GAAG,EAAE,IAAI,GAAG,EAAE,CAAC;AAAA,UAC7F;AAAA,QACF;AAAA;AAAA,IACF;AAAA,KAEJ;AAEJ;AAEO,MAAM,mBAAmB,YAAY;AAAA,EAC1C,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,MAAM;AAAA,EACN,UAAU,OAAO,EAAE,WAAW,QAAQ,QAAQ,KAAK;AACrD,CAAC;","names":[]}
1
+ {"version":3,"sources":["../../../src/blocks/builtins/Breadcrumbs.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useState } from \"react\";\nimport type { z } from \"zod\";\nimport type { BreadcrumbsBlockSchema } from \"../../schema/blocks\";\nimport { defineBlock, type BlockRenderProps } from \"../registry\";\nimport { useLinkComponent } from \"@astryxdesign/core/Link\";\nimport { jsonLdHtml } from \"./jsonld\";\n\ntype Breadcrumbs = z.infer<typeof BreadcrumbsBlockSchema>;\n\nexport interface Crumb {\n label: string;\n href: string;\n}\n\n/** Kruimels uit een pad: \"/diensten/tuinaanleg\" → Home / Diensten / Tuinaanleg. Puur en getest. */\nexport function crumbsFromPath(path: string, homeLabel = \"Home\"): Crumb[] {\n const segments = path.split(\"/\").filter(Boolean);\n const crumbs: Crumb[] = [{ label: homeLabel, href: \"/\" }];\n let href = \"\";\n for (const seg of segments) {\n href += `/${seg}`;\n // decodeURIComponent gooit op misvormde percent-encoding (\"%E0%A4%A\") — dan het rauwe segment.\n let decoded = seg;\n try {\n decoded = decodeURIComponent(seg);\n } catch {\n /* rauw segment als label */\n }\n const label = decoded.replace(/[-_]+/g, \" \").replace(/^./, (c) => c.toUpperCase());\n crumbs.push({ label, href });\n }\n return crumbs;\n}\n\n/** BreadcrumbList-JSON-LD. Puur en getest. */\nexport function breadcrumbsJsonLd(crumbs: Crumb[]): Record<string, unknown> {\n return {\n \"@context\": \"https://schema.org\",\n \"@type\": \"BreadcrumbList\",\n itemListElement: crumbs.map((c, i) => ({\n \"@type\": \"ListItem\",\n position: i + 1,\n name: c.label,\n item: c.href,\n })),\n };\n}\n\n/**\n * Kruimelpad, afgeleid van de URL (client, ná mount — hydration-veilig). Op de homepage\n * (alleen \"Home\") wordt niets getoond.\n */\nfunction BreadcrumbsRender({ block, mode }: BlockRenderProps<Breadcrumbs>) {\n const LinkC = useLinkComponent();\n const [path, setPath] = useState<string | null>(null);\n useEffect(() => {\n setPath(window.location.pathname);\n }, []);\n\n if (mode === \"preview\" && (path === null || path === \"/\")) {\n return <nav className=\"xicms-breadcrumbs\" aria-label=\"Kruimelpad\"><span data-xicms-edit=\"homeLabel\">{block.homeLabel}</span> / Voorbeeldpagina</nav>;\n }\n if (path === null || path === \"/\") return null;\n const crumbs = crumbsFromPath(path, block.homeLabel);\n\n return (\n <nav className=\"xicms-breadcrumbs\" aria-label=\"Kruimelpad\">\n <ol className=\"xicms-breadcrumbs__list\">\n {crumbs.map((c, i) => (\n <li key={c.href} className=\"xicms-breadcrumbs__item\">\n {i < crumbs.length - 1 ? (\n // De eerste kruimel ís `homeLabel`; de rest komt uit het pad en is dus geen blokveld.\n <LinkC href={c.href}>{i === 0 ? <span data-xicms-edit=\"homeLabel\">{c.label}</span> : c.label}</LinkC>\n ) : (\n <span aria-current=\"page\">{c.label}</span>\n )}\n </li>\n ))}\n </ol>\n {block.jsonLd && (\n <script\n type=\"application/ld+json\"\n // eslint-disable-next-line react/no-danger\n // Absolute URL's: Google wil volledige item-URL's in BreadcrumbList (dit rendert\n // client-side ná mount, dus window.location.origin is beschikbaar).\n dangerouslySetInnerHTML={{\n __html: jsonLdHtml(\n breadcrumbsJsonLd(crumbs.map((c) => ({ ...c, href: `${window.location.origin}${c.href}` }))),\n ),\n }}\n />\n )}\n </nav>\n );\n}\n\nexport const breadcrumbsBlock = defineBlock({\n type: \"breadcrumbs\",\n Render: BreadcrumbsRender,\n label: \"Kruimelpad\",\n icon: \"🧭\",\n defaults: () => ({ homeLabel: \"Home\", jsonLd: true }),\n});\n"],"mappings":";AA8DW,SAA2D,KAA3D;AA5DX,SAAS,WAAW,gBAAgB;AAGpC,SAAS,mBAA0C;AACnD,SAAS,wBAAwB;AACjC,SAAS,kBAAkB;AAUpB,SAAS,eAAe,MAAc,YAAY,QAAiB;AACxE,QAAM,WAAW,KAAK,MAAM,GAAG,EAAE,OAAO,OAAO;AAC/C,QAAM,SAAkB,CAAC,EAAE,OAAO,WAAW,MAAM,IAAI,CAAC;AACxD,MAAI,OAAO;AACX,aAAW,OAAO,UAAU;AAC1B,YAAQ,IAAI,GAAG;AAEf,QAAI,UAAU;AACd,QAAI;AACF,gBAAU,mBAAmB,GAAG;AAAA,IAClC,QAAQ;AAAA,IAER;AACA,UAAM,QAAQ,QAAQ,QAAQ,UAAU,GAAG,EAAE,QAAQ,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC;AACjF,WAAO,KAAK,EAAE,OAAO,KAAK,CAAC;AAAA,EAC7B;AACA,SAAO;AACT;AAGO,SAAS,kBAAkB,QAA0C;AAC1E,SAAO;AAAA,IACL,YAAY;AAAA,IACZ,SAAS;AAAA,IACT,iBAAiB,OAAO,IAAI,CAAC,GAAG,OAAO;AAAA,MACrC,SAAS;AAAA,MACT,UAAU,IAAI;AAAA,MACd,MAAM,EAAE;AAAA,MACR,MAAM,EAAE;AAAA,IACV,EAAE;AAAA,EACJ;AACF;AAMA,SAAS,kBAAkB,EAAE,OAAO,KAAK,GAAkC;AACzE,QAAM,QAAQ,iBAAiB;AAC/B,QAAM,CAAC,MAAM,OAAO,IAAI,SAAwB,IAAI;AACpD,YAAU,MAAM;AACd,YAAQ,OAAO,SAAS,QAAQ;AAAA,EAClC,GAAG,CAAC,CAAC;AAEL,MAAI,SAAS,cAAc,SAAS,QAAQ,SAAS,MAAM;AACzD,WAAO,qBAAC,SAAI,WAAU,qBAAoB,cAAW,cAAa;AAAA,0BAAC,UAAK,mBAAgB,aAAa,gBAAM,WAAU;AAAA,MAAO;AAAA,OAAkB;AAAA,EAChJ;AACA,MAAI,SAAS,QAAQ,SAAS,IAAK,QAAO;AAC1C,QAAM,SAAS,eAAe,MAAM,MAAM,SAAS;AAEnD,SACE,qBAAC,SAAI,WAAU,qBAAoB,cAAW,cAC5C;AAAA,wBAAC,QAAG,WAAU,2BACX,iBAAO,IAAI,CAAC,GAAG,MACd,oBAAC,QAAgB,WAAU,2BACxB,cAAI,OAAO,SAAS;AAAA;AAAA,MAEnB,oBAAC,SAAM,MAAM,EAAE,MAAO,gBAAM,IAAI,oBAAC,UAAK,mBAAgB,aAAa,YAAE,OAAM,IAAU,EAAE,OAAM;AAAA,QAE7F,oBAAC,UAAK,gBAAa,QAAQ,YAAE,OAAM,KAL9B,EAAE,IAOX,CACD,GACH;AAAA,IACC,MAAM,UACL;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QAIL,yBAAyB;AAAA,UACvB,QAAQ;AAAA,YACN,kBAAkB,OAAO,IAAI,CAAC,OAAO,EAAE,GAAG,GAAG,MAAM,GAAG,OAAO,SAAS,MAAM,GAAG,EAAE,IAAI,GAAG,EAAE,CAAC;AAAA,UAC7F;AAAA,QACF;AAAA;AAAA,IACF;AAAA,KAEJ;AAEJ;AAEO,MAAM,mBAAmB,YAAY;AAAA,EAC1C,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,MAAM;AAAA,EACN,UAAU,OAAO,EAAE,WAAW,QAAQ,QAAQ,KAAK;AACrD,CAAC;","names":[]}
@@ -1,6 +1,5 @@
1
1
  "use client";
2
2
  import { jsx, jsxs } from "react/jsx-runtime";
3
- import { CardsBlockSchema } from "../../schema/blocks.js";
4
3
  import { defineBlock } from "../registry.js";
5
4
  import { VStack, Grid, Card, Heading, Text } from "../ui/index.js";
6
5
  import { useLinkComponent } from "@astryxdesign/core/Link";
@@ -76,7 +75,6 @@ function CardsRender({ block }) {
76
75
  const cardsBlock = defineBlock({
77
76
  type: "cards",
78
77
  fields: { "items.icon": { type: "icon" } },
79
- schema: CardsBlockSchema,
80
78
  Render: CardsRender,
81
79
  label: "Diensten / kaarten",
82
80
  icon: "\u{1F9E9}",
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/blocks/builtins/Cards.tsx"],"sourcesContent":["\"use client\";\n\nimport type { z } from \"zod\";\nimport { CardsBlockSchema } from \"../../schema/blocks\";\nimport { defineBlock, type BlockRenderProps } from \"../registry\";\nimport { VStack, Grid, Card, Heading, Text } from \"../ui\";\nimport { useLinkComponent } from \"@astryxdesign/core/Link\";\nimport { Img } from \"../../media/ImageContext\";\n\ntype Cards = z.infer<typeof CardsBlockSchema>;\n\n/** Diensten/uitgelichte kaarten in een responsive grid (Astryx). */\nfunction CardsRender({ block }: BlockRenderProps<Cards>) {\n const LinkC = useLinkComponent();\n // _i = index in de OORSPRONKELIJKE array — inline-edit-paden moeten naar de ongefilterde\n // items wijzen, anders schrijft bewerken naar het verkeerde (weggefilterde) item.\n const items = (block.items ?? []).map((c, i) => ({ ...c, _i: i })).filter((c) => c.title || c.text || c.imageUrl);\n if (items.length === 0 && !block.heading) return null;\n return (\n <VStack gap={4} as=\"section\" className=\"xicms-cards\">\n {(block.heading || block.intro) && (\n <VStack gap={1} hAlign=\"center\" style={{ textAlign: \"center\" }}>\n {block.heading && <Heading level={2} data-xicms-edit=\"heading\">{block.heading}</Heading>}\n {block.intro && <Text type=\"large\" color=\"secondary\" data-xicms-edit=\"intro\">{block.intro}</Text>}\n </VStack>\n )}\n <Grid columns={{ minWidth: 240, max: block.columns }} gap={4}>\n {items.map((c) => {\n const i = c._i;\n const cover = block.imageStyle === \"cover\" && Boolean(c.imageUrl);\n const body = (\n <VStack gap={2} style={cover ? { padding: \"1.1rem 1.25rem 1.25rem\" } : undefined}>\n {c.title && <Heading level={3} className=\"xicms-cards__title\" data-xicms-edit={`items.${i}.title`}>{c.title}</Heading>}\n {c.text && <Text color=\"secondary\" className=\"xicms-cards__text\" data-xicms-edit={`items.${i}.text`}>{c.text}</Text>}\n {c.href && c.linkLabel && (\n <Text type=\"label\" style={{ color: \"var(--color-accent)\" }}><span data-xicms-edit={`items.${i}.linkLabel`}>{c.linkLabel}</span> →</Text>\n )}\n </VStack>\n );\n const inner = cover ? (\n <VStack gap={0} style={{ height: \"100%\" }}>\n {/* Beeld edge-to-edge bovenaan (postkaart-stijl); tekst hieronder gepad. */}\n <Img src={c.imageUrl as string} alt={c.title ?? \"\"} width={600} height={360}\n sizes=\"(max-width: 720px) 100vw, 33vw\" editField={`items.${i}.imageUrl`}\n style={{ width: \"100%\", aspectRatio: \"16 / 10\", objectFit: \"cover\", display: \"block\" }} />\n {body}\n </VStack>\n ) : (\n <VStack gap={2}>\n {c.imageUrl ? (\n <Img src={c.imageUrl} alt={c.title ?? \"\"} width={480} height={300}\n sizes=\"(max-width: 720px) 100vw, 33vw\" editField={`items.${i}.imageUrl`}\n style={{ width: \"100%\", height: 160, objectFit: \"cover\", borderRadius: \"var(--radius-element)\" }} />\n ) : c.icon ? (\n <div aria-hidden=\"true\" style={{ fontSize: \"2rem\", lineHeight: 1 }}>{c.icon}</div>\n ) : null}\n {c.title && <Heading level={3} className=\"xicms-cards__title\" data-xicms-edit={`items.${i}.title`}>{c.title}</Heading>}\n {c.text && <Text color=\"secondary\" className=\"xicms-cards__text\" data-xicms-edit={`items.${i}.text`}>{c.text}</Text>}\n {c.href && c.linkLabel && (\n <Text type=\"label\" style={{ color: \"var(--color-accent)\" }}><span data-xicms-edit={`items.${i}.linkLabel`}>{c.linkLabel}</span> →</Text>\n )}\n </VStack>\n );\n const card = (\n <Card\n padding={cover ? 0 : 4}\n height=\"100%\"\n className={`xicms-cards__card${c.featured ? \" xicms-cards__card--featured\" : \"\"}`}\n style={cover ? { overflow: \"hidden\" } : undefined}\n >\n {inner}\n </Card>\n );\n return c.href ? (\n <LinkC key={i} href={c.href} style={{ textDecoration: \"none\", color: \"inherit\", display: \"block\" }}>\n {card}\n </LinkC>\n ) : (\n <div key={i}>{card}</div>\n );\n })}\n </Grid>\n </VStack>\n );\n}\n\nexport const cardsBlock = defineBlock({\n type: \"cards\",\n fields: { \"items.icon\": { type: \"icon\" } },\n schema: CardsBlockSchema,\n Render: CardsRender,\n label: \"Diensten / kaarten\",\n icon: \"🧩\",\n defaults: () => ({\n heading: \"Onze diensten\",\n columns: 3,\n items: [\n { icon: \"⭐\", title: \"Dienst één\", text: \"Korte omschrijving van wat je biedt.\" },\n { icon: \"⚡\", title: \"Dienst twee\", text: \"Korte omschrijving van wat je biedt.\" },\n { icon: \"💬\", title: \"Dienst drie\", text: \"Korte omschrijving van wat je biedt.\" },\n ],\n }),\n});\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../src/blocks/builtins/Cards.tsx"],"sourcesContent":["\"use client\";\n\nimport type { z } from \"zod\";\nimport type { CardsBlockSchema } from \"../../schema/blocks\";\nimport { defineBlock, type BlockRenderProps } from \"../registry\";\nimport { VStack, Grid, Card, Heading, Text } from \"../ui\";\nimport { useLinkComponent } from \"@astryxdesign/core/Link\";\nimport { Img } from \"../../media/ImageContext\";\n\ntype Cards = z.infer<typeof CardsBlockSchema>;\n\n/** Diensten/uitgelichte kaarten in een responsive grid (Astryx). */\nfunction CardsRender({ block }: BlockRenderProps<Cards>) {\n const LinkC = useLinkComponent();\n // _i = index in de OORSPRONKELIJKE array — inline-edit-paden moeten naar de ongefilterde\n // items wijzen, anders schrijft bewerken naar het verkeerde (weggefilterde) item.\n const items = (block.items ?? []).map((c, i) => ({ ...c, _i: i })).filter((c) => c.title || c.text || c.imageUrl);\n if (items.length === 0 && !block.heading) return null;\n return (\n <VStack gap={4} as=\"section\" className=\"xicms-cards\">\n {(block.heading || block.intro) && (\n <VStack gap={1} hAlign=\"center\" style={{ textAlign: \"center\" }}>\n {block.heading && <Heading level={2} data-xicms-edit=\"heading\">{block.heading}</Heading>}\n {block.intro && <Text type=\"large\" color=\"secondary\" data-xicms-edit=\"intro\">{block.intro}</Text>}\n </VStack>\n )}\n <Grid columns={{ minWidth: 240, max: block.columns }} gap={4}>\n {items.map((c) => {\n const i = c._i;\n const cover = block.imageStyle === \"cover\" && Boolean(c.imageUrl);\n const body = (\n <VStack gap={2} style={cover ? { padding: \"1.1rem 1.25rem 1.25rem\" } : undefined}>\n {c.title && <Heading level={3} className=\"xicms-cards__title\" data-xicms-edit={`items.${i}.title`}>{c.title}</Heading>}\n {c.text && <Text color=\"secondary\" className=\"xicms-cards__text\" data-xicms-edit={`items.${i}.text`}>{c.text}</Text>}\n {c.href && c.linkLabel && (\n <Text type=\"label\" style={{ color: \"var(--color-accent)\" }}><span data-xicms-edit={`items.${i}.linkLabel`}>{c.linkLabel}</span> →</Text>\n )}\n </VStack>\n );\n const inner = cover ? (\n <VStack gap={0} style={{ height: \"100%\" }}>\n {/* Beeld edge-to-edge bovenaan (postkaart-stijl); tekst hieronder gepad. */}\n <Img src={c.imageUrl as string} alt={c.title ?? \"\"} width={600} height={360}\n sizes=\"(max-width: 720px) 100vw, 33vw\" editField={`items.${i}.imageUrl`}\n style={{ width: \"100%\", aspectRatio: \"16 / 10\", objectFit: \"cover\", display: \"block\" }} />\n {body}\n </VStack>\n ) : (\n <VStack gap={2}>\n {c.imageUrl ? (\n <Img src={c.imageUrl} alt={c.title ?? \"\"} width={480} height={300}\n sizes=\"(max-width: 720px) 100vw, 33vw\" editField={`items.${i}.imageUrl`}\n style={{ width: \"100%\", height: 160, objectFit: \"cover\", borderRadius: \"var(--radius-element)\" }} />\n ) : c.icon ? (\n <div aria-hidden=\"true\" style={{ fontSize: \"2rem\", lineHeight: 1 }}>{c.icon}</div>\n ) : null}\n {c.title && <Heading level={3} className=\"xicms-cards__title\" data-xicms-edit={`items.${i}.title`}>{c.title}</Heading>}\n {c.text && <Text color=\"secondary\" className=\"xicms-cards__text\" data-xicms-edit={`items.${i}.text`}>{c.text}</Text>}\n {c.href && c.linkLabel && (\n <Text type=\"label\" style={{ color: \"var(--color-accent)\" }}><span data-xicms-edit={`items.${i}.linkLabel`}>{c.linkLabel}</span> →</Text>\n )}\n </VStack>\n );\n const card = (\n <Card\n padding={cover ? 0 : 4}\n height=\"100%\"\n className={`xicms-cards__card${c.featured ? \" xicms-cards__card--featured\" : \"\"}`}\n style={cover ? { overflow: \"hidden\" } : undefined}\n >\n {inner}\n </Card>\n );\n return c.href ? (\n <LinkC key={i} href={c.href} style={{ textDecoration: \"none\", color: \"inherit\", display: \"block\" }}>\n {card}\n </LinkC>\n ) : (\n <div key={i}>{card}</div>\n );\n })}\n </Grid>\n </VStack>\n );\n}\n\nexport const cardsBlock = defineBlock({\n type: \"cards\",\n fields: { \"items.icon\": { type: \"icon\" } },\n Render: CardsRender,\n label: \"Diensten / kaarten\",\n icon: \"🧩\",\n defaults: () => ({\n heading: \"Onze diensten\",\n columns: 3,\n items: [\n { icon: \"⭐\", title: \"Dienst één\", text: \"Korte omschrijving van wat je biedt.\" },\n { icon: \"⚡\", title: \"Dienst twee\", text: \"Korte omschrijving van wat je biedt.\" },\n { icon: \"💬\", title: \"Dienst drie\", text: \"Korte omschrijving van wat je biedt.\" },\n ],\n }),\n});\n"],"mappings":"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","names":[]}
@@ -1,6 +1,5 @@
1
1
  "use client";
2
2
  import { jsx } from "react/jsx-runtime";
3
- import { ColumnsBlockSchema } from "../../schema/blocks.js";
4
3
  import { defineBlock } from "../registry.js";
5
4
  import { BlockRenderer } from "../BlockRenderer.js";
6
5
  import { useRegistry } from "../context.js";
@@ -10,7 +9,6 @@ function ColumnsRender({ block, siteId, mode }) {
10
9
  }
11
10
  const columnsBlock = defineBlock({
12
11
  type: "columns",
13
- schema: ColumnsBlockSchema,
14
12
  Render: ColumnsRender,
15
13
  label: "Kolommen",
16
14
  icon: "\u25A5",
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/blocks/builtins/Columns.tsx"],"sourcesContent":["\"use client\";\n\nimport type { z } from \"zod\";\nimport { ColumnsBlockSchema } from \"../../schema/blocks\";\nimport { defineBlock, type BlockRenderProps } from \"../registry\";\nimport { BlockRenderer } from \"../BlockRenderer\";\nimport { useRegistry } from \"../context\";\n\ntype Columns = z.infer<typeof ColumnsBlockSchema>;\n\nfunction ColumnsRender({ block, siteId, mode }: BlockRenderProps<Columns>) {\n const registry = useRegistry();\n return (\n <div className=\"xicms-columns\" data-cols={block.columns.length} style={{ gridTemplateColumns: `repeat(${block.columns.length}, 1fr)` }}>\n {block.columns.map((col, idx) => (\n <div key={idx} className=\"xicms-column\">\n <BlockRenderer blocks={col.blocks} registry={registry} siteId={siteId} mode={mode} />\n </div>\n ))}\n </div>\n );\n}\n\nexport const columnsBlock = defineBlock({\n type: \"columns\",\n schema: ColumnsBlockSchema,\n Render: ColumnsRender,\n label: \"Kolommen\",\n icon: \"▥\",\n defaults: () => ({ columns: [{ blocks: [] }, { blocks: [] }] }),\n});\n"],"mappings":";AAgBU;AAbV,SAAS,0BAA0B;AACnC,SAAS,mBAA0C;AACnD,SAAS,qBAAqB;AAC9B,SAAS,mBAAmB;AAI5B,SAAS,cAAc,EAAE,OAAO,QAAQ,KAAK,GAA8B;AACzE,QAAM,WAAW,YAAY;AAC7B,SACE,oBAAC,SAAI,WAAU,iBAAgB,aAAW,MAAM,QAAQ,QAAQ,OAAO,EAAE,qBAAqB,UAAU,MAAM,QAAQ,MAAM,SAAS,GAClI,gBAAM,QAAQ,IAAI,CAAC,KAAK,QACvB,oBAAC,SAAc,WAAU,gBACvB,8BAAC,iBAAc,QAAQ,IAAI,QAAQ,UAAoB,QAAgB,MAAY,KAD3E,GAEV,CACD,GACH;AAEJ;AAEO,MAAM,eAAe,YAAY;AAAA,EACtC,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,MAAM;AAAA,EACN,UAAU,OAAO,EAAE,SAAS,CAAC,EAAE,QAAQ,CAAC,EAAE,GAAG,EAAE,QAAQ,CAAC,EAAE,CAAC,EAAE;AAC/D,CAAC;","names":[]}
1
+ {"version":3,"sources":["../../../src/blocks/builtins/Columns.tsx"],"sourcesContent":["\"use client\";\n\nimport type { z } from \"zod\";\nimport type { ColumnsBlockSchema } from \"../../schema/blocks\";\nimport { defineBlock, type BlockRenderProps } from \"../registry\";\nimport { BlockRenderer } from \"../BlockRenderer\";\nimport { useRegistry } from \"../context\";\n\ntype Columns = z.infer<typeof ColumnsBlockSchema>;\n\nfunction ColumnsRender({ block, siteId, mode }: BlockRenderProps<Columns>) {\n const registry = useRegistry();\n return (\n <div className=\"xicms-columns\" data-cols={block.columns.length} style={{ gridTemplateColumns: `repeat(${block.columns.length}, 1fr)` }}>\n {block.columns.map((col, idx) => (\n <div key={idx} className=\"xicms-column\">\n <BlockRenderer blocks={col.blocks} registry={registry} siteId={siteId} mode={mode} />\n </div>\n ))}\n </div>\n );\n}\n\nexport const columnsBlock = defineBlock({\n type: \"columns\",\n Render: ColumnsRender,\n label: \"Kolommen\",\n icon: \"▥\",\n defaults: () => ({ columns: [{ blocks: [] }, { blocks: [] }] }),\n});\n"],"mappings":";AAgBU;AAZV,SAAS,mBAA0C;AACnD,SAAS,qBAAqB;AAC9B,SAAS,mBAAmB;AAI5B,SAAS,cAAc,EAAE,OAAO,QAAQ,KAAK,GAA8B;AACzE,QAAM,WAAW,YAAY;AAC7B,SACE,oBAAC,SAAI,WAAU,iBAAgB,aAAW,MAAM,QAAQ,QAAQ,OAAO,EAAE,qBAAqB,UAAU,MAAM,QAAQ,MAAM,SAAS,GAClI,gBAAM,QAAQ,IAAI,CAAC,KAAK,QACvB,oBAAC,SAAc,WAAU,gBACvB,8BAAC,iBAAc,QAAQ,IAAI,QAAQ,UAAoB,QAAgB,MAAY,KAD3E,GAEV,CACD,GACH;AAEJ;AAEO,MAAM,eAAe,YAAY;AAAA,EACtC,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,MAAM;AAAA,EACN,UAAU,OAAO,EAAE,SAAS,CAAC,EAAE,QAAQ,CAAC,EAAE,GAAG,EAAE,QAAQ,CAAC,EAAE,CAAC,EAAE;AAC/D,CAAC;","names":[]}