@xiwebdesign/xicms-core 7.14.0 → 7.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (263) hide show
  1. package/dist/admin/AdminApp.js +4 -3
  2. package/dist/admin/AdminApp.js.map +1 -1
  3. package/dist/admin/dashboard/DashboardPanel.d.ts +3 -0
  4. package/dist/admin/dashboard/DashboardPanel.js +316 -0
  5. package/dist/admin/dashboard/DashboardPanel.js.map +1 -0
  6. package/dist/admin/navContext.d.ts +14 -0
  7. package/dist/admin/navContext.js +12 -0
  8. package/dist/admin/navContext.js.map +1 -0
  9. package/dist/admin/pages/PagesPanel.js +38 -12
  10. package/dist/admin/pages/PagesPanel.js.map +1 -1
  11. package/dist/admin/panelRegistry.js +4 -0
  12. package/dist/admin/panelRegistry.js.map +1 -1
  13. package/dist/admin/ui/PanelIcon.js +5 -0
  14. package/dist/admin/ui/PanelIcon.js.map +1 -1
  15. package/dist/admin/visual/VisualEditor.js +56 -20
  16. package/dist/admin/visual/VisualEditor.js.map +1 -1
  17. package/dist/admin.css +1 -1
  18. package/dist/auth/AuthProvider.js +8 -1
  19. package/dist/auth/AuthProvider.js.map +1 -1
  20. package/dist/blocks/builtins/Accordion.d.ts +1 -2
  21. package/dist/blocks/builtins/Accordion.js +2 -39
  22. package/dist/blocks/builtins/Accordion.js.map +1 -1
  23. package/dist/blocks/builtins/AccordionRender.d.ts +7 -0
  24. package/dist/blocks/builtins/AccordionRender.js +42 -0
  25. package/dist/blocks/builtins/AccordionRender.js.map +1 -0
  26. package/dist/blocks/builtins/Agenda.d.ts +1 -29
  27. package/dist/blocks/builtins/Agenda.js +3 -94
  28. package/dist/blocks/builtins/Agenda.js.map +1 -1
  29. package/dist/blocks/builtins/AgendaRender.d.ts +34 -0
  30. package/dist/blocks/builtins/AgendaRender.js +96 -0
  31. package/dist/blocks/builtins/AgendaRender.js.map +1 -0
  32. package/dist/blocks/builtins/Banner.d.ts +1 -2
  33. package/dist/blocks/builtins/Banner.js +2 -32
  34. package/dist/blocks/builtins/Banner.js.map +1 -1
  35. package/dist/blocks/builtins/BannerRender.d.ts +11 -0
  36. package/dist/blocks/builtins/BannerRender.js +35 -0
  37. package/dist/blocks/builtins/BannerRender.js.map +1 -0
  38. package/dist/blocks/builtins/BeforeAfter.d.ts +1 -2
  39. package/dist/blocks/builtins/BeforeAfter.js +2 -31
  40. package/dist/blocks/builtins/BeforeAfter.js.map +1 -1
  41. package/dist/blocks/builtins/BeforeAfterRender.d.ts +11 -0
  42. package/dist/blocks/builtins/BeforeAfterRender.js +34 -0
  43. package/dist/blocks/builtins/BeforeAfterRender.js.map +1 -0
  44. package/dist/blocks/builtins/Booking.d.ts +1 -2
  45. package/dist/blocks/builtins/Booking.js +2 -14
  46. package/dist/blocks/builtins/Booking.js.map +1 -1
  47. package/dist/blocks/builtins/BookingRender.d.ts +8 -0
  48. package/dist/blocks/builtins/BookingRender.js +17 -0
  49. package/dist/blocks/builtins/BookingRender.js.map +1 -0
  50. package/dist/blocks/builtins/Breadcrumbs.d.ts +1 -10
  51. package/dist/blocks/builtins/Breadcrumbs.js +3 -69
  52. package/dist/blocks/builtins/Breadcrumbs.js.map +1 -1
  53. package/dist/blocks/builtins/BreadcrumbsRender.d.ts +18 -0
  54. package/dist/blocks/builtins/BreadcrumbsRender.js +71 -0
  55. package/dist/blocks/builtins/BreadcrumbsRender.js.map +1 -0
  56. package/dist/blocks/builtins/Cards.d.ts +1 -2
  57. package/dist/blocks/builtins/Cards.js +2 -74
  58. package/dist/blocks/builtins/Cards.js.map +1 -1
  59. package/dist/blocks/builtins/CardsRender.d.ts +7 -0
  60. package/dist/blocks/builtins/CardsRender.js +77 -0
  61. package/dist/blocks/builtins/CardsRender.js.map +1 -0
  62. package/dist/blocks/builtins/Columns.d.ts +1 -2
  63. package/dist/blocks/builtins/Columns.js +2 -9
  64. package/dist/blocks/builtins/Columns.js.map +1 -1
  65. package/dist/blocks/builtins/ColumnsRender.d.ts +6 -0
  66. package/dist/blocks/builtins/ColumnsRender.js +12 -0
  67. package/dist/blocks/builtins/ColumnsRender.js.map +1 -0
  68. package/dist/blocks/builtins/Contact.d.ts +2 -7
  69. package/dist/blocks/builtins/Contact.js +3 -102
  70. package/dist/blocks/builtins/Contact.js.map +1 -1
  71. package/dist/blocks/builtins/ContactRender.d.ts +9 -0
  72. package/dist/blocks/builtins/ContactRender.js +105 -0
  73. package/dist/blocks/builtins/ContactRender.js.map +1 -0
  74. package/dist/blocks/builtins/Countdown.d.ts +1 -18
  75. package/dist/blocks/builtins/Countdown.js +3 -53
  76. package/dist/blocks/builtins/Countdown.js.map +1 -1
  77. package/dist/blocks/builtins/CountdownRender.d.ts +22 -0
  78. package/dist/blocks/builtins/CountdownRender.js +61 -0
  79. package/dist/blocks/builtins/CountdownRender.js.map +1 -0
  80. package/dist/blocks/builtins/Cta.d.ts +1 -2
  81. package/dist/blocks/builtins/Cta.js +2 -39
  82. package/dist/blocks/builtins/Cta.js.map +1 -1
  83. package/dist/blocks/builtins/CtaRender.d.ts +6 -0
  84. package/dist/blocks/builtins/CtaRender.js +42 -0
  85. package/dist/blocks/builtins/CtaRender.js.map +1 -0
  86. package/dist/blocks/builtins/Downloads.d.ts +1 -2
  87. package/dist/blocks/builtins/Downloads.js +2 -16
  88. package/dist/blocks/builtins/Downloads.js.map +1 -1
  89. package/dist/blocks/builtins/DownloadsRender.d.ts +7 -0
  90. package/dist/blocks/builtins/DownloadsRender.js +19 -0
  91. package/dist/blocks/builtins/DownloadsRender.js.map +1 -0
  92. package/dist/blocks/builtins/Elements.d.ts +3 -4
  93. package/dist/blocks/builtins/Elements.js +4 -38
  94. package/dist/blocks/builtins/Elements.js.map +1 -1
  95. package/dist/blocks/builtins/ElementsRender.d.ts +10 -0
  96. package/dist/blocks/builtins/ElementsRender.js +41 -0
  97. package/dist/blocks/builtins/ElementsRender.js.map +1 -0
  98. package/dist/blocks/builtins/Embed.d.ts +1 -2
  99. package/dist/blocks/builtins/Embed.js +2 -19
  100. package/dist/blocks/builtins/Embed.js.map +1 -1
  101. package/dist/blocks/builtins/EmbedRender.d.ts +7 -0
  102. package/dist/blocks/builtins/EmbedRender.js +22 -0
  103. package/dist/blocks/builtins/EmbedRender.js.map +1 -0
  104. package/dist/blocks/builtins/Faq.d.ts +1 -6
  105. package/dist/blocks/builtins/Faq.js +3 -103
  106. package/dist/blocks/builtins/Faq.js.map +1 -1
  107. package/dist/blocks/builtins/FaqRender.d.ts +10 -0
  108. package/dist/blocks/builtins/FaqRender.js +105 -0
  109. package/dist/blocks/builtins/FaqRender.js.map +1 -0
  110. package/dist/blocks/builtins/FormBlock.d.ts +1 -2
  111. package/dist/blocks/builtins/FormBlock.js +2 -222
  112. package/dist/blocks/builtins/FormBlock.js.map +1 -1
  113. package/dist/blocks/builtins/FormBlockRender.d.ts +6 -0
  114. package/dist/blocks/builtins/FormBlockRender.js +225 -0
  115. package/dist/blocks/builtins/FormBlockRender.js.map +1 -0
  116. package/dist/blocks/builtins/Gallery.d.ts +1 -23
  117. package/dist/blocks/builtins/Gallery.js +2 -164
  118. package/dist/blocks/builtins/Gallery.js.map +1 -1
  119. package/dist/blocks/builtins/GalleryRender.d.ts +25 -0
  120. package/dist/blocks/builtins/GalleryRender.js +167 -0
  121. package/dist/blocks/builtins/GalleryRender.js.map +1 -0
  122. package/dist/blocks/builtins/Hero.d.ts +1 -2
  123. package/dist/blocks/builtins/Hero.js +2 -73
  124. package/dist/blocks/builtins/Hero.js.map +1 -1
  125. package/dist/blocks/builtins/HeroRender.d.ts +6 -0
  126. package/dist/blocks/builtins/HeroRender.js +76 -0
  127. package/dist/blocks/builtins/HeroRender.js.map +1 -0
  128. package/dist/blocks/builtins/ImageBlock.d.ts +1 -2
  129. package/dist/blocks/builtins/ImageBlock.js +2 -22
  130. package/dist/blocks/builtins/ImageBlock.js.map +1 -1
  131. package/dist/blocks/builtins/ImageBlockRender.d.ts +6 -0
  132. package/dist/blocks/builtins/ImageBlockRender.js +25 -0
  133. package/dist/blocks/builtins/ImageBlockRender.js.map +1 -0
  134. package/dist/blocks/builtins/Jobs.d.ts +1 -15
  135. package/dist/blocks/builtins/Jobs.js +3 -69
  136. package/dist/blocks/builtins/Jobs.js.map +1 -1
  137. package/dist/blocks/builtins/JobsRender.d.ts +17 -0
  138. package/dist/blocks/builtins/JobsRender.js +71 -0
  139. package/dist/blocks/builtins/JobsRender.js.map +1 -0
  140. package/dist/blocks/builtins/Layout.d.ts +2 -3
  141. package/dist/blocks/builtins/Layout.js +3 -39
  142. package/dist/blocks/builtins/Layout.js.map +1 -1
  143. package/dist/blocks/builtins/LayoutRender.d.ts +8 -0
  144. package/dist/blocks/builtins/LayoutRender.js +42 -0
  145. package/dist/blocks/builtins/LayoutRender.js.map +1 -0
  146. package/dist/blocks/builtins/MapBlock.d.ts +1 -2
  147. package/dist/blocks/builtins/MapBlock.js +2 -45
  148. package/dist/blocks/builtins/MapBlock.js.map +1 -1
  149. package/dist/blocks/builtins/MapBlockRender.d.ts +6 -0
  150. package/dist/blocks/builtins/MapBlockRender.js +48 -0
  151. package/dist/blocks/builtins/MapBlockRender.js.map +1 -0
  152. package/dist/blocks/builtins/NewsListBlock.d.ts +1 -2
  153. package/dist/blocks/builtins/NewsListBlock.js +2 -11
  154. package/dist/blocks/builtins/NewsListBlock.js.map +1 -1
  155. package/dist/blocks/builtins/NewsListBlockRender.d.ts +6 -0
  156. package/dist/blocks/builtins/NewsListBlockRender.js +14 -0
  157. package/dist/blocks/builtins/NewsListBlockRender.js.map +1 -0
  158. package/dist/blocks/builtins/Newsletter.d.ts +1 -2
  159. package/dist/blocks/builtins/Newsletter.js +2 -89
  160. package/dist/blocks/builtins/Newsletter.js.map +1 -1
  161. package/dist/blocks/builtins/NewsletterRender.d.ts +13 -0
  162. package/dist/blocks/builtins/NewsletterRender.js +92 -0
  163. package/dist/blocks/builtins/NewsletterRender.js.map +1 -0
  164. package/dist/blocks/builtins/OpeningHours.d.ts +1 -2
  165. package/dist/blocks/builtins/OpeningHours.js +2 -28
  166. package/dist/blocks/builtins/OpeningHours.js.map +1 -1
  167. package/dist/blocks/builtins/OpeningHoursRender.d.ts +7 -0
  168. package/dist/blocks/builtins/OpeningHoursRender.js +31 -0
  169. package/dist/blocks/builtins/OpeningHoursRender.js.map +1 -0
  170. package/dist/blocks/builtins/PdfBlock.d.ts +1 -2
  171. package/dist/blocks/builtins/PdfBlock.js +2 -76
  172. package/dist/blocks/builtins/PdfBlock.js.map +1 -1
  173. package/dist/blocks/builtins/PdfBlockRender.d.ts +11 -0
  174. package/dist/blocks/builtins/PdfBlockRender.js +79 -0
  175. package/dist/blocks/builtins/PdfBlockRender.js.map +1 -0
  176. package/dist/blocks/builtins/Portfolio.d.ts +1 -2
  177. package/dist/blocks/builtins/Portfolio.js +2 -75
  178. package/dist/blocks/builtins/Portfolio.js.map +1 -1
  179. package/dist/blocks/builtins/PortfolioRender.d.ts +7 -0
  180. package/dist/blocks/builtins/PortfolioRender.js +78 -0
  181. package/dist/blocks/builtins/PortfolioRender.js.map +1 -0
  182. package/dist/blocks/builtins/Pricing.d.ts +1 -8
  183. package/dist/blocks/builtins/Pricing.js +3 -73
  184. package/dist/blocks/builtins/Pricing.js.map +1 -1
  185. package/dist/blocks/builtins/PricingRender.d.ts +10 -0
  186. package/dist/blocks/builtins/PricingRender.js +75 -0
  187. package/dist/blocks/builtins/PricingRender.js.map +1 -0
  188. package/dist/blocks/builtins/RichTextBlock.d.ts +1 -2
  189. package/dist/blocks/builtins/RichTextBlock.js +2 -5
  190. package/dist/blocks/builtins/RichTextBlock.js.map +1 -1
  191. package/dist/blocks/builtins/RichTextBlockRender.d.ts +6 -0
  192. package/dist/blocks/builtins/RichTextBlockRender.js +8 -0
  193. package/dist/blocks/builtins/RichTextBlockRender.js.map +1 -0
  194. package/dist/blocks/builtins/Search.d.ts +1 -2
  195. package/dist/blocks/builtins/Search.js +2 -80
  196. package/dist/blocks/builtins/Search.js.map +1 -1
  197. package/dist/blocks/builtins/SearchRender.d.ts +7 -0
  198. package/dist/blocks/builtins/SearchRender.js +83 -0
  199. package/dist/blocks/builtins/SearchRender.js.map +1 -0
  200. package/dist/blocks/builtins/Sections.d.ts +4 -5
  201. package/dist/blocks/builtins/Sections.js +5 -142
  202. package/dist/blocks/builtins/Sections.js.map +1 -1
  203. package/dist/blocks/builtins/SectionsRender.d.ts +12 -0
  204. package/dist/blocks/builtins/SectionsRender.js +145 -0
  205. package/dist/blocks/builtins/SectionsRender.js.map +1 -0
  206. package/dist/blocks/builtins/Slider.d.ts +1 -2
  207. package/dist/blocks/builtins/Slider.js +2 -134
  208. package/dist/blocks/builtins/Slider.js.map +1 -1
  209. package/dist/blocks/builtins/SliderRender.d.ts +7 -0
  210. package/dist/blocks/builtins/SliderRender.js +137 -0
  211. package/dist/blocks/builtins/SliderRender.js.map +1 -0
  212. package/dist/blocks/builtins/Spacer.d.ts +1 -2
  213. package/dist/blocks/builtins/Spacer.js +2 -6
  214. package/dist/blocks/builtins/Spacer.js.map +1 -1
  215. package/dist/blocks/builtins/SpacerRender.d.ts +6 -0
  216. package/dist/blocks/builtins/SpacerRender.js +9 -0
  217. package/dist/blocks/builtins/SpacerRender.js.map +1 -0
  218. package/dist/blocks/builtins/SymbolRef.d.ts +1 -2
  219. package/dist/blocks/builtins/SymbolRef.js +2 -76
  220. package/dist/blocks/builtins/SymbolRef.js.map +1 -1
  221. package/dist/blocks/builtins/SymbolRefRender.d.ts +13 -0
  222. package/dist/blocks/builtins/SymbolRefRender.js +79 -0
  223. package/dist/blocks/builtins/SymbolRefRender.js.map +1 -0
  224. package/dist/blocks/builtins/Team.d.ts +1 -2
  225. package/dist/blocks/builtins/Team.js +2 -55
  226. package/dist/blocks/builtins/Team.js.map +1 -1
  227. package/dist/blocks/builtins/TeamRender.d.ts +7 -0
  228. package/dist/blocks/builtins/TeamRender.js +58 -0
  229. package/dist/blocks/builtins/TeamRender.js.map +1 -0
  230. package/dist/blocks/builtins/Testimonials.d.ts +1 -8
  231. package/dist/blocks/builtins/Testimonials.js +2 -69
  232. package/dist/blocks/builtins/Testimonials.js.map +1 -1
  233. package/dist/blocks/builtins/TestimonialsRender.d.ts +10 -0
  234. package/dist/blocks/builtins/TestimonialsRender.js +72 -0
  235. package/dist/blocks/builtins/TestimonialsRender.js.map +1 -0
  236. package/dist/blocks/builtins/Video.d.ts +1 -9
  237. package/dist/blocks/builtins/Video.js +2 -64
  238. package/dist/blocks/builtins/Video.js.map +1 -1
  239. package/dist/blocks/builtins/VideoRender.d.ts +10 -0
  240. package/dist/blocks/builtins/VideoRender.js +67 -0
  241. package/dist/blocks/builtins/VideoRender.js.map +1 -0
  242. package/dist/blocks/builtins/WhatsappChat.d.ts +1 -8
  243. package/dist/blocks/builtins/WhatsappChat.js +2 -37
  244. package/dist/blocks/builtins/WhatsappChat.js.map +1 -1
  245. package/dist/blocks/builtins/WhatsappChatRender.d.ts +17 -0
  246. package/dist/blocks/builtins/WhatsappChatRender.js +40 -0
  247. package/dist/blocks/builtins/WhatsappChatRender.js.map +1 -0
  248. package/dist/blocks/builtins/Widgets.d.ts +12 -13
  249. package/dist/blocks/builtins/Widgets.js +13 -175
  250. package/dist/blocks/builtins/Widgets.js.map +1 -1
  251. package/dist/blocks/builtins/WidgetsRender.d.ts +34 -0
  252. package/dist/blocks/builtins/WidgetsRender.js +178 -0
  253. package/dist/blocks/builtins/WidgetsRender.js.map +1 -0
  254. package/dist/components/barOffset.js +1 -1
  255. package/dist/components/barOffset.js.map +1 -1
  256. package/dist/modules/contract.js +2 -1
  257. package/dist/modules/contract.js.map +1 -1
  258. package/dist/schema/settings.d.ts +4 -0
  259. package/dist/schema/settings.js +10 -1
  260. package/dist/schema/settings.js.map +1 -1
  261. package/dist/styles.css +93 -19
  262. package/dist/version.js +1 -1
  263. package/package.json +1 -1
@@ -1,57 +1,23 @@
1
- "use client";
2
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
1
+ import dynamic from "next/dynamic";
3
2
  import { defineBlock } from "../registry.js";
4
- import { HStack, VStack, Card, Text, Btn, Divider } from "../ui/index.js";
5
- function ButtonsRender({ block }) {
6
- const items = (block.items ?? []).map((b, i) => ({ ...b, _i: i })).filter((b) => b.label);
7
- if (items.length === 0) return null;
8
- const hAlign = block.align === "center" ? "center" : block.align === "right" ? "end" : "start";
9
- return /* @__PURE__ */ jsx(HStack, { gap: 2, hAlign, style: { flexWrap: "wrap" }, children: items.map((b) => /* @__PURE__ */ jsx(Btn, { label: b.label, href: b.href, variant: b.variant, editField: `items.${b._i}.label` }, b._i)) });
10
- }
11
3
  const buttonsBlock = defineBlock({
12
4
  type: "buttons",
13
5
  fields: { "items.variant": { type: "select", options: [{ value: "primary", label: "Primair" }, { value: "secondary", label: "Secundair" }, { value: "outline", label: "Outline" }] } },
14
- Render: ButtonsRender,
6
+ Render: dynamic(() => import("./ElementsRender.js").then((m) => m.ButtonsRender)),
15
7
  label: "Knoppen",
16
8
  icon: "\u{1F518}",
17
9
  defaults: () => ({ align: "left", items: [{ label: "Knop", href: "#", variant: "primary" }] })
18
10
  });
19
- function QuoteRender({ block }) {
20
- if (!block.text) return null;
21
- return /* @__PURE__ */ jsx(Card, { padding: 5, variant: "muted", children: /* @__PURE__ */ jsxs(VStack, { gap: 2, as: "figure", style: { margin: 0 }, children: [
22
- /* @__PURE__ */ jsxs(Text, { type: "large", as: "p", style: { fontStyle: "italic" }, children: [
23
- "\u201C",
24
- /* @__PURE__ */ jsx("span", { "data-xicms-edit": "text", children: block.text }),
25
- "\u201D"
26
- ] }),
27
- (block.author || block.role) && /* @__PURE__ */ jsxs(Text, { as: "label", color: "secondary", children: [
28
- "\u2014 ",
29
- /* @__PURE__ */ jsx("span", { "data-xicms-edit": "author", children: block.author }),
30
- block.role ? /* @__PURE__ */ jsxs(Fragment, { children: [
31
- " \xB7 ",
32
- /* @__PURE__ */ jsx("span", { "data-xicms-edit": "role", children: block.role })
33
- ] }) : ""
34
- ] })
35
- ] }) });
36
- }
37
11
  const quoteBlock = defineBlock({
38
12
  type: "quote",
39
- Render: QuoteRender,
13
+ Render: dynamic(() => import("./ElementsRender.js").then((m) => m.QuoteRender)),
40
14
  label: "Uitspraak",
41
15
  icon: "\u275D",
42
16
  defaults: () => ({ text: "Een krachtige uitspraak.", author: "" })
43
17
  });
44
- function DividerRender({ block }) {
45
- const pad = block.spacing === "sm" ? "0.75rem" : block.spacing === "lg" ? "3rem" : "1.5rem";
46
- if (block.variant === "space") return /* @__PURE__ */ jsx("div", { style: { height: pad }, "aria-hidden": "true" });
47
- if (block.variant === "dots") {
48
- return /* @__PURE__ */ jsx("div", { style: { textAlign: "center", padding: `${pad} 0`, color: "var(--color-text-secondary)", letterSpacing: "0.5em" }, "aria-hidden": "true", children: "\u2022 \u2022 \u2022" });
49
- }
50
- return /* @__PURE__ */ jsx("div", { style: { padding: `${pad} 0` }, children: /* @__PURE__ */ jsx(Divider, { variant: "subtle" }) });
51
- }
52
18
  const dividerBlock = defineBlock({
53
19
  type: "divider",
54
- Render: DividerRender,
20
+ Render: dynamic(() => import("./ElementsRender.js").then((m) => m.DividerRender)),
55
21
  label: "Scheiding",
56
22
  icon: "\u2796",
57
23
  defaults: () => ({ variant: "line", spacing: "md" })
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/blocks/builtins/Elements.tsx"],"sourcesContent":["\"use client\";\n\nimport type { z } from \"zod\";\nimport type { ButtonsBlockSchema, QuoteBlockSchema, DividerBlockSchema } from \"../../schema/blocks\";\nimport { defineBlock, type BlockRenderProps } from \"../registry\";\nimport { HStack, VStack, Card, Text, Btn, Divider } from \"../ui\";\n\n/* ── Buttons (knopgroep) ─────────────────────────────────────────────────── */\ntype Buttons = z.infer<typeof ButtonsBlockSchema>;\nfunction ButtonsRender({ block }: BlockRenderProps<Buttons>) {\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((b, i) => ({ ...b, _i: i })).filter((b) => b.label);\n if (items.length === 0) return null;\n const hAlign = block.align === \"center\" ? \"center\" : block.align === \"right\" ? \"end\" : \"start\";\n return (\n <HStack gap={2} hAlign={hAlign} style={{ flexWrap: \"wrap\" }}>\n {items.map((b) => (\n <Btn key={b._i} label={b.label} href={b.href} variant={b.variant} editField={`items.${b._i}.label`} />\n ))}\n </HStack>\n );\n}\nexport const buttonsBlock = defineBlock({\n type: \"buttons\",\n fields: { \"items.variant\": { type: \"select\", options: [{ value: \"primary\", label: \"Primair\" }, { value: \"secondary\", label: \"Secundair\" }, { value: \"outline\", label: \"Outline\" }] } },\n Render: ButtonsRender,\n label: \"Knoppen\",\n icon: \"🔘\",\n defaults: () => ({ align: \"left\", items: [{ label: \"Knop\", href: \"#\", variant: \"primary\" }] }),\n});\n\n/* ── Quote (uitspraak) ───────────────────────────────────────────────────── */\ntype Quote = z.infer<typeof QuoteBlockSchema>;\nfunction QuoteRender({ block }: BlockRenderProps<Quote>) {\n if (!block.text) return null;\n return (\n <Card padding={5} variant=\"muted\">\n <VStack gap={2} as=\"figure\" style={{ margin: 0 }}>\n <Text type=\"large\" as=\"p\" style={{ fontStyle: \"italic\" }}>“<span data-xicms-edit=\"text\">{block.text}</span>”</Text>\n {(block.author || block.role) && (\n <Text as=\"label\" color=\"secondary\">\n — <span data-xicms-edit=\"author\">{block.author}</span>\n {block.role ? <> · <span data-xicms-edit=\"role\">{block.role}</span></> : \"\"}\n </Text>\n )}\n </VStack>\n </Card>\n );\n}\nexport const quoteBlock = defineBlock({\n type: \"quote\",\n Render: QuoteRender,\n label: \"Uitspraak\",\n icon: \"❝\",\n defaults: () => ({ text: \"Een krachtige uitspraak.\", author: \"\" }),\n});\n\n/* ── Divider (scheiding) ─────────────────────────────────────────────────── */\ntype DividerBlk = z.infer<typeof DividerBlockSchema>;\nfunction DividerRender({ block }: BlockRenderProps<DividerBlk>) {\n const pad = block.spacing === \"sm\" ? \"0.75rem\" : block.spacing === \"lg\" ? \"3rem\" : \"1.5rem\";\n if (block.variant === \"space\") return <div style={{ height: pad }} aria-hidden=\"true\" />;\n if (block.variant === \"dots\") {\n return (\n <div style={{ textAlign: \"center\", padding: `${pad} 0`, color: \"var(--color-text-secondary)\", letterSpacing: \"0.5em\" }} aria-hidden=\"true\">\n • • •\n </div>\n );\n }\n return <div style={{ padding: `${pad} 0` }}><Divider variant=\"subtle\" /></div>;\n}\nexport const dividerBlock = defineBlock({\n type: \"divider\",\n Render: DividerRender,\n label: \"Scheiding\",\n icon: \"➖\",\n defaults: () => ({ variant: \"line\", spacing: \"md\" }),\n});\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../src/blocks/builtins/Elements.tsx"],"sourcesContent":["import dynamic from \"next/dynamic\";\nimport { defineBlock } from \"../registry\";\n\nexport const buttonsBlock = defineBlock({\n type: \"buttons\",\n fields: { \"items.variant\": { type: \"select\", options: [{ value: \"primary\", label: \"Primair\" }, { value: \"secondary\", label: \"Secundair\" }, { value: \"outline\", label: \"Outline\" }] } },\n Render: dynamic(() => import(\"./ElementsRender\").then((m) => m.ButtonsRender)),\n label: \"Knoppen\",\n icon: \"🔘\",\n defaults: () => ({ align: \"left\", items: [{ label: \"Knop\", href: \"#\", variant: \"primary\" }] }),\n});\n\nexport const quoteBlock = defineBlock({\n type: \"quote\",\n Render: dynamic(() => import(\"./ElementsRender\").then((m) => m.QuoteRender)),\n label: \"Uitspraak\",\n icon: \"❝\",\n defaults: () => ({ text: \"Een krachtige uitspraak.\", author: \"\" }),\n});\n\nexport const dividerBlock = defineBlock({\n type: \"divider\",\n Render: dynamic(() => import(\"./ElementsRender\").then((m) => m.DividerRender)),\n label: \"Scheiding\",\n icon: \"➖\",\n defaults: () => ({ variant: \"line\", spacing: \"md\" }),\n});\n"],"mappings":"AAAA,OAAO,aAAa;AACpB,SAAS,mBAAmB;AAErB,MAAM,eAAe,YAAY;AAAA,EACtC,MAAM;AAAA,EACN,QAAQ,EAAE,iBAAiB,EAAE,MAAM,UAAU,SAAS,CAAC,EAAE,OAAO,WAAW,OAAO,UAAU,GAAG,EAAE,OAAO,aAAa,OAAO,YAAY,GAAG,EAAE,OAAO,WAAW,OAAO,UAAU,CAAC,EAAE,EAAE;AAAA,EACrL,QAAQ,QAAQ,MAAM,OAAO,kBAAkB,EAAE,KAAK,CAAC,MAAM,EAAE,aAAa,CAAC;AAAA,EAC7E,OAAO;AAAA,EACP,MAAM;AAAA,EACN,UAAU,OAAO,EAAE,OAAO,QAAQ,OAAO,CAAC,EAAE,OAAO,QAAQ,MAAM,KAAK,SAAS,UAAU,CAAC,EAAE;AAC9F,CAAC;AAEM,MAAM,aAAa,YAAY;AAAA,EACpC,MAAM;AAAA,EACN,QAAQ,QAAQ,MAAM,OAAO,kBAAkB,EAAE,KAAK,CAAC,MAAM,EAAE,WAAW,CAAC;AAAA,EAC3E,OAAO;AAAA,EACP,MAAM;AAAA,EACN,UAAU,OAAO,EAAE,MAAM,4BAA4B,QAAQ,GAAG;AAClE,CAAC;AAEM,MAAM,eAAe,YAAY;AAAA,EACtC,MAAM;AAAA,EACN,QAAQ,QAAQ,MAAM,OAAO,kBAAkB,EAAE,KAAK,CAAC,MAAM,EAAE,aAAa,CAAC;AAAA,EAC7E,OAAO;AAAA,EACP,MAAM;AAAA,EACN,UAAU,OAAO,EAAE,SAAS,QAAQ,SAAS,KAAK;AACpD,CAAC;","names":[]}
@@ -0,0 +1,10 @@
1
+ import type { z } from "zod";
2
+ import type { ButtonsBlockSchema, QuoteBlockSchema, DividerBlockSchema } from "../../schema/blocks.js";
3
+ import type { BlockRenderProps } from "../registry.js";
4
+ type Buttons = z.infer<typeof ButtonsBlockSchema>;
5
+ export declare function ButtonsRender({ block }: BlockRenderProps<Buttons>): import("react").JSX.Element | null;
6
+ type Quote = z.infer<typeof QuoteBlockSchema>;
7
+ export declare function QuoteRender({ block }: BlockRenderProps<Quote>): import("react").JSX.Element | null;
8
+ type DividerBlk = z.infer<typeof DividerBlockSchema>;
9
+ export declare function DividerRender({ block }: BlockRenderProps<DividerBlk>): import("react").JSX.Element;
10
+ export {};
@@ -0,0 +1,41 @@
1
+ "use client";
2
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
+ import { HStack, VStack, Card, Text, Btn, Divider } from "../ui/index.js";
4
+ function ButtonsRender({ block }) {
5
+ const items = (block.items ?? []).map((b, i) => ({ ...b, _i: i })).filter((b) => b.label);
6
+ if (items.length === 0) return null;
7
+ const hAlign = block.align === "center" ? "center" : block.align === "right" ? "end" : "start";
8
+ return /* @__PURE__ */ jsx(HStack, { gap: 2, hAlign, style: { flexWrap: "wrap" }, children: items.map((b) => /* @__PURE__ */ jsx(Btn, { label: b.label, href: b.href, variant: b.variant, editField: `items.${b._i}.label` }, b._i)) });
9
+ }
10
+ function QuoteRender({ block }) {
11
+ if (!block.text) return null;
12
+ return /* @__PURE__ */ jsx(Card, { padding: 5, variant: "muted", children: /* @__PURE__ */ jsxs(VStack, { gap: 2, as: "figure", style: { margin: 0 }, children: [
13
+ /* @__PURE__ */ jsxs(Text, { type: "large", as: "p", style: { fontStyle: "italic" }, children: [
14
+ "\u201C",
15
+ /* @__PURE__ */ jsx("span", { "data-xicms-edit": "text", children: block.text }),
16
+ "\u201D"
17
+ ] }),
18
+ (block.author || block.role) && /* @__PURE__ */ jsxs(Text, { as: "label", color: "secondary", children: [
19
+ "\u2014 ",
20
+ /* @__PURE__ */ jsx("span", { "data-xicms-edit": "author", children: block.author }),
21
+ block.role ? /* @__PURE__ */ jsxs(Fragment, { children: [
22
+ " \xB7 ",
23
+ /* @__PURE__ */ jsx("span", { "data-xicms-edit": "role", children: block.role })
24
+ ] }) : ""
25
+ ] })
26
+ ] }) });
27
+ }
28
+ function DividerRender({ block }) {
29
+ const pad = block.spacing === "sm" ? "0.75rem" : block.spacing === "lg" ? "3rem" : "1.5rem";
30
+ if (block.variant === "space") return /* @__PURE__ */ jsx("div", { style: { height: pad }, "aria-hidden": "true" });
31
+ if (block.variant === "dots") {
32
+ return /* @__PURE__ */ jsx("div", { style: { textAlign: "center", padding: `${pad} 0`, color: "var(--color-text-secondary)", letterSpacing: "0.5em" }, "aria-hidden": "true", children: "\u2022 \u2022 \u2022" });
33
+ }
34
+ return /* @__PURE__ */ jsx("div", { style: { padding: `${pad} 0` }, children: /* @__PURE__ */ jsx(Divider, { variant: "subtle" }) });
35
+ }
36
+ export {
37
+ ButtonsRender,
38
+ DividerRender,
39
+ QuoteRender
40
+ };
41
+ //# sourceMappingURL=ElementsRender.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/blocks/builtins/ElementsRender.tsx"],"sourcesContent":["\"use client\";\n\nimport type { z } from \"zod\";\nimport type { ButtonsBlockSchema, QuoteBlockSchema, DividerBlockSchema } from \"../../schema/blocks\";\nimport type { BlockRenderProps } from \"../registry\";\nimport { HStack, VStack, Card, Text, Btn, Divider } from \"../ui\";\n\n/* ── Buttons (knopgroep) ─────────────────────────────────────────────────── */\ntype Buttons = z.infer<typeof ButtonsBlockSchema>;\nexport function ButtonsRender({ block }: BlockRenderProps<Buttons>) {\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((b, i) => ({ ...b, _i: i })).filter((b) => b.label);\n if (items.length === 0) return null;\n const hAlign = block.align === \"center\" ? \"center\" : block.align === \"right\" ? \"end\" : \"start\";\n return (\n <HStack gap={2} hAlign={hAlign} style={{ flexWrap: \"wrap\" }}>\n {items.map((b) => (\n <Btn key={b._i} label={b.label} href={b.href} variant={b.variant} editField={`items.${b._i}.label`} />\n ))}\n </HStack>\n );\n}\n/* ── Quote (uitspraak) ───────────────────────────────────────────────────── */\ntype Quote = z.infer<typeof QuoteBlockSchema>;\nexport function QuoteRender({ block }: BlockRenderProps<Quote>) {\n if (!block.text) return null;\n return (\n <Card padding={5} variant=\"muted\">\n <VStack gap={2} as=\"figure\" style={{ margin: 0 }}>\n <Text type=\"large\" as=\"p\" style={{ fontStyle: \"italic\" }}>“<span data-xicms-edit=\"text\">{block.text}</span>”</Text>\n {(block.author || block.role) && (\n <Text as=\"label\" color=\"secondary\">\n — <span data-xicms-edit=\"author\">{block.author}</span>\n {block.role ? <> · <span data-xicms-edit=\"role\">{block.role}</span></> : \"\"}\n </Text>\n )}\n </VStack>\n </Card>\n );\n}\n/* ── Divider (scheiding) ─────────────────────────────────────────────────── */\ntype DividerBlk = z.infer<typeof DividerBlockSchema>;\nexport function DividerRender({ block }: BlockRenderProps<DividerBlk>) {\n const pad = block.spacing === \"sm\" ? \"0.75rem\" : block.spacing === \"lg\" ? \"3rem\" : \"1.5rem\";\n if (block.variant === \"space\") return <div style={{ height: pad }} aria-hidden=\"true\" />;\n if (block.variant === \"dots\") {\n return (\n <div style={{ textAlign: \"center\", padding: `${pad} 0`, color: \"var(--color-text-secondary)\", letterSpacing: \"0.5em\" }} aria-hidden=\"true\">\n • • •\n </div>\n );\n }\n return <div style={{ padding: `${pad} 0` }}><Divider variant=\"subtle\" /></div>;\n}\n"],"mappings":";AAkBQ,SAgBkB,UAhBlB,KAYA,YAZA;AAbR,SAAS,QAAQ,QAAQ,MAAM,MAAM,KAAK,eAAe;AAIlD,SAAS,cAAc,EAAE,MAAM,GAA8B;AAGlE,QAAM,SAAS,MAAM,SAAS,CAAC,GAAG,IAAI,CAAC,GAAG,OAAO,EAAE,GAAG,GAAG,IAAI,EAAE,EAAE,EAAE,OAAO,CAAC,MAAM,EAAE,KAAK;AACxF,MAAI,MAAM,WAAW,EAAG,QAAO;AAC/B,QAAM,SAAS,MAAM,UAAU,WAAW,WAAW,MAAM,UAAU,UAAU,QAAQ;AACvF,SACE,oBAAC,UAAO,KAAK,GAAG,QAAgB,OAAO,EAAE,UAAU,OAAO,GACvD,gBAAM,IAAI,CAAC,MACV,oBAAC,OAAe,OAAO,EAAE,OAAO,MAAM,EAAE,MAAM,SAAS,EAAE,SAAS,WAAW,SAAS,EAAE,EAAE,YAAhF,EAAE,EAAwF,CACrG,GACH;AAEJ;AAGO,SAAS,YAAY,EAAE,MAAM,GAA4B;AAC9D,MAAI,CAAC,MAAM,KAAM,QAAO;AACxB,SACE,oBAAC,QAAK,SAAS,GAAG,SAAQ,SACxB,+BAAC,UAAO,KAAK,GAAG,IAAG,UAAS,OAAO,EAAE,QAAQ,EAAE,GAC7C;AAAA,yBAAC,QAAK,MAAK,SAAQ,IAAG,KAAI,OAAO,EAAE,WAAW,SAAS,GAAG;AAAA;AAAA,MAAC,oBAAC,UAAK,mBAAgB,QAAQ,gBAAM,MAAK;AAAA,MAAO;AAAA,OAAC;AAAA,KAC1G,MAAM,UAAU,MAAM,SACtB,qBAAC,QAAK,IAAG,SAAQ,OAAM,aAAY;AAAA;AAAA,MAC/B,oBAAC,UAAK,mBAAgB,UAAU,gBAAM,QAAO;AAAA,MAC9C,MAAM,OAAO,iCAAE;AAAA;AAAA,QAAG,oBAAC,UAAK,mBAAgB,QAAQ,gBAAM,MAAK;AAAA,SAAO,IAAM;AAAA,OAC3E;AAAA,KAEJ,GACF;AAEJ;AAGO,SAAS,cAAc,EAAE,MAAM,GAAiC;AACrE,QAAM,MAAM,MAAM,YAAY,OAAO,YAAY,MAAM,YAAY,OAAO,SAAS;AACnF,MAAI,MAAM,YAAY,QAAS,QAAO,oBAAC,SAAI,OAAO,EAAE,QAAQ,IAAI,GAAG,eAAY,QAAO;AACtF,MAAI,MAAM,YAAY,QAAQ;AAC5B,WACE,oBAAC,SAAI,OAAO,EAAE,WAAW,UAAU,SAAS,GAAG,GAAG,MAAM,OAAO,+BAA+B,eAAe,QAAQ,GAAG,eAAY,QAAO,kCAE3I;AAAA,EAEJ;AACA,SAAO,oBAAC,SAAI,OAAO,EAAE,SAAS,GAAG,GAAG,KAAK,GAAG,8BAAC,WAAQ,SAAQ,UAAS,GAAE;AAC1E;","names":[]}
@@ -1,2 +1 @@
1
- import type { z } from "zod";
2
- export declare const embedBlock: import("../index.js").BlockDefinition<z.core.$ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>>;
1
+ export declare const embedBlock: import("../index.js").BlockDefinition<import("zod/v4/core").$ZodType<unknown, unknown, import("zod/v4/core").$ZodTypeInternals<unknown, unknown>>>;
@@ -1,25 +1,8 @@
1
- "use client";
2
- import { jsx } from "react/jsx-runtime";
1
+ import dynamic from "next/dynamic";
3
2
  import { defineBlock } from "../registry.js";
4
- import { ConsentEmbed } from "./consentEmbed.js";
5
- function EmbedRender({ block, mode }) {
6
- if (!block.url) return null;
7
- const sizing = block.aspectRatio && block.aspectRatio !== "fixed" ? { aspectRatio: block.aspectRatio.replace("/", " / ") } : { height: `${block.height}px` };
8
- return /* @__PURE__ */ jsx("div", { className: "xicms-embed", style: sizing, children: /* @__PURE__ */ jsx(ConsentEmbed, { gated: block.consentGated, preview: mode === "preview", label: block.title ?? "Embed", children: /* @__PURE__ */ jsx(
9
- "iframe",
10
- {
11
- src: block.url,
12
- title: block.title ?? "Embed",
13
- loading: "lazy",
14
- referrerPolicy: "no-referrer-when-downgrade",
15
- sandbox: "allow-scripts allow-same-origin allow-forms allow-popups",
16
- style: { border: 0, width: "100%", height: "100%" }
17
- }
18
- ) }) });
19
- }
20
3
  const embedBlock = defineBlock({
21
4
  type: "embed",
22
- Render: EmbedRender,
5
+ Render: dynamic(() => import("./EmbedRender.js").then((m) => m.EmbedRender)),
23
6
  label: "Embed (iframe)",
24
7
  icon: "\u{1F9E9}",
25
8
  defaults: () => ({ url: "", height: 420, consentGated: true })
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/blocks/builtins/Embed.tsx"],"sourcesContent":["\"use client\";\n\nimport type { z } from \"zod\";\nimport type { EmbedBlockSchema } from \"../../schema/blocks\";\nimport { defineBlock, type BlockRenderProps } from \"../registry\";\nimport { ConsentEmbed } from \"./consentEmbed\";\n\ntype Embed = z.infer<typeof EmbedBlockSchema>;\n\n/** Generieke responsive iframe-embed (consent-gated by default) — voor wat dan ook met een URL. */\nfunction EmbedRender({ block, mode }: BlockRenderProps<Embed>) {\n if (!block.url) return null;\n // \"fixed\" = vaste hoogte (bestaand gedrag); anders schaalt de embed mee met de beeldverhouding.\n const sizing =\n block.aspectRatio && block.aspectRatio !== \"fixed\"\n ? { aspectRatio: block.aspectRatio.replace(\"/\", \" / \") }\n : { height: `${block.height}px` };\n return (\n <div className=\"xicms-embed\" style={sizing}>\n <ConsentEmbed gated={block.consentGated} preview={mode === \"preview\"} label={block.title ?? \"Embed\"}>\n <iframe\n src={block.url}\n title={block.title ?? \"Embed\"}\n loading=\"lazy\"\n referrerPolicy=\"no-referrer-when-downgrade\"\n sandbox=\"allow-scripts allow-same-origin allow-forms allow-popups\"\n style={{ border: 0, width: \"100%\", height: \"100%\" }}\n />\n </ConsentEmbed>\n </div>\n );\n}\n\nexport const embedBlock = defineBlock({\n type: \"embed\",\n Render: EmbedRender,\n label: \"Embed (iframe)\",\n icon: \"🧩\",\n defaults: () => ({ url: \"\", height: 420, consentGated: true }),\n});\n"],"mappings":";AAoBQ;AAhBR,SAAS,mBAA0C;AACnD,SAAS,oBAAoB;AAK7B,SAAS,YAAY,EAAE,OAAO,KAAK,GAA4B;AAC7D,MAAI,CAAC,MAAM,IAAK,QAAO;AAEvB,QAAM,SACJ,MAAM,eAAe,MAAM,gBAAgB,UACvC,EAAE,aAAa,MAAM,YAAY,QAAQ,KAAK,KAAK,EAAE,IACrD,EAAE,QAAQ,GAAG,MAAM,MAAM,KAAK;AACpC,SACE,oBAAC,SAAI,WAAU,eAAc,OAAO,QAClC,8BAAC,gBAAa,OAAO,MAAM,cAAc,SAAS,SAAS,WAAW,OAAO,MAAM,SAAS,SAC1F;AAAA,IAAC;AAAA;AAAA,MACC,KAAK,MAAM;AAAA,MACX,OAAO,MAAM,SAAS;AAAA,MACtB,SAAQ;AAAA,MACR,gBAAe;AAAA,MACf,SAAQ;AAAA,MACR,OAAO,EAAE,QAAQ,GAAG,OAAO,QAAQ,QAAQ,OAAO;AAAA;AAAA,EACpD,GACF,GACF;AAEJ;AAEO,MAAM,aAAa,YAAY;AAAA,EACpC,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,MAAM;AAAA,EACN,UAAU,OAAO,EAAE,KAAK,IAAI,QAAQ,KAAK,cAAc,KAAK;AAC9D,CAAC;","names":[]}
1
+ {"version":3,"sources":["../../../src/blocks/builtins/Embed.tsx"],"sourcesContent":["import dynamic from \"next/dynamic\";\nimport { defineBlock } from \"../registry\";\n\nexport const embedBlock = defineBlock({\n type: \"embed\",\n Render: dynamic(() => import(\"./EmbedRender\").then((m) => m.EmbedRender)),\n label: \"Embed (iframe)\",\n icon: \"🧩\",\n defaults: () => ({ url: \"\", height: 420, consentGated: true }),\n});\n"],"mappings":"AAAA,OAAO,aAAa;AACpB,SAAS,mBAAmB;AAErB,MAAM,aAAa,YAAY;AAAA,EACpC,MAAM;AAAA,EACN,QAAQ,QAAQ,MAAM,OAAO,eAAe,EAAE,KAAK,CAAC,MAAM,EAAE,WAAW,CAAC;AAAA,EACxE,OAAO;AAAA,EACP,MAAM;AAAA,EACN,UAAU,OAAO,EAAE,KAAK,IAAI,QAAQ,KAAK,cAAc,KAAK;AAC9D,CAAC;","names":[]}
@@ -0,0 +1,7 @@
1
+ import type { z } from "zod";
2
+ import type { EmbedBlockSchema } from "../../schema/blocks.js";
3
+ import type { BlockRenderProps } from "../registry.js";
4
+ type Embed = z.infer<typeof EmbedBlockSchema>;
5
+ /** Generieke responsive iframe-embed (consent-gated by default) — voor wat dan ook met een URL. */
6
+ export declare function EmbedRender({ block, mode }: BlockRenderProps<Embed>): import("react").JSX.Element | null;
7
+ export {};
@@ -0,0 +1,22 @@
1
+ "use client";
2
+ import { jsx } from "react/jsx-runtime";
3
+ import { ConsentEmbed } from "./consentEmbed.js";
4
+ function EmbedRender({ block, mode }) {
5
+ if (!block.url) return null;
6
+ const sizing = block.aspectRatio && block.aspectRatio !== "fixed" ? { aspectRatio: block.aspectRatio.replace("/", " / ") } : { height: `${block.height}px` };
7
+ return /* @__PURE__ */ jsx("div", { className: "xicms-embed", style: sizing, children: /* @__PURE__ */ jsx(ConsentEmbed, { gated: block.consentGated, preview: mode === "preview", label: block.title ?? "Embed", children: /* @__PURE__ */ jsx(
8
+ "iframe",
9
+ {
10
+ src: block.url,
11
+ title: block.title ?? "Embed",
12
+ loading: "lazy",
13
+ referrerPolicy: "no-referrer-when-downgrade",
14
+ sandbox: "allow-scripts allow-same-origin allow-forms allow-popups",
15
+ style: { border: 0, width: "100%", height: "100%" }
16
+ }
17
+ ) }) });
18
+ }
19
+ export {
20
+ EmbedRender
21
+ };
22
+ //# sourceMappingURL=EmbedRender.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/blocks/builtins/EmbedRender.tsx"],"sourcesContent":["\"use client\";\n\nimport type { z } from \"zod\";\nimport type { EmbedBlockSchema } from \"../../schema/blocks\";\nimport type { BlockRenderProps } from \"../registry\";\nimport { ConsentEmbed } from \"./consentEmbed\";\n\ntype Embed = z.infer<typeof EmbedBlockSchema>;\n\n/** Generieke responsive iframe-embed (consent-gated by default) — voor wat dan ook met een URL. */\nexport function EmbedRender({ block, mode }: BlockRenderProps<Embed>) {\n if (!block.url) return null;\n // \"fixed\" = vaste hoogte (bestaand gedrag); anders schaalt de embed mee met de beeldverhouding.\n const sizing =\n block.aspectRatio && block.aspectRatio !== \"fixed\"\n ? { aspectRatio: block.aspectRatio.replace(\"/\", \" / \") }\n : { height: `${block.height}px` };\n return (\n <div className=\"xicms-embed\" style={sizing}>\n <ConsentEmbed gated={block.consentGated} preview={mode === \"preview\"} label={block.title ?? \"Embed\"}>\n <iframe\n src={block.url}\n title={block.title ?? \"Embed\"}\n loading=\"lazy\"\n referrerPolicy=\"no-referrer-when-downgrade\"\n sandbox=\"allow-scripts allow-same-origin allow-forms allow-popups\"\n style={{ border: 0, width: \"100%\", height: \"100%\" }}\n />\n </ConsentEmbed>\n </div>\n );\n}\n"],"mappings":";AAoBQ;AAfR,SAAS,oBAAoB;AAKtB,SAAS,YAAY,EAAE,OAAO,KAAK,GAA4B;AACpE,MAAI,CAAC,MAAM,IAAK,QAAO;AAEvB,QAAM,SACJ,MAAM,eAAe,MAAM,gBAAgB,UACvC,EAAE,aAAa,MAAM,YAAY,QAAQ,KAAK,KAAK,EAAE,IACrD,EAAE,QAAQ,GAAG,MAAM,MAAM,KAAK;AACpC,SACE,oBAAC,SAAI,WAAU,eAAc,OAAO,QAClC,8BAAC,gBAAa,OAAO,MAAM,cAAc,SAAS,SAAS,WAAW,OAAO,MAAM,SAAS,SAC1F;AAAA,IAAC;AAAA;AAAA,MACC,KAAK,MAAM;AAAA,MACX,OAAO,MAAM,SAAS;AAAA,MACtB,SAAQ;AAAA,MACR,gBAAe;AAAA,MACf,SAAQ;AAAA,MACR,OAAO,EAAE,QAAQ,GAAG,OAAO,QAAQ,QAAQ,OAAO;AAAA;AAAA,EACpD,GACF,GACF;AAEJ;","names":[]}
@@ -1,6 +1 @@
1
- import type { z } from "zod";
2
- /** Anker-id voor een vraag (deep-link: /faq#hoe-werkt-het). */
3
- export declare function questionSlug(q: string): string;
4
- /** Unieke anker-ids voor een vragenlijst: identieke vragen krijgen -2, -3, … (ids moeten uniek zijn). */
5
- export declare function questionSlugs(questions: string[]): string[];
6
- export declare const faqBlock: import("../index.js").BlockDefinition<z.core.$ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>>;
1
+ export declare const faqBlock: import("../index.js").BlockDefinition<import("zod/v4/core").$ZodType<unknown, unknown, import("zod/v4/core").$ZodTypeInternals<unknown, unknown>>>;
@@ -1,106 +1,8 @@
1
- "use client";
2
- import { jsx, jsxs } from "react/jsx-runtime";
3
- import { useEffect, useMemo, useState } from "react";
1
+ import dynamic from "next/dynamic";
4
2
  import { defineBlock } from "../registry.js";
5
- import { Collapsible } from "@astryxdesign/core/Collapsible";
6
- import { TextInput } from "@astryxdesign/core/TextInput";
7
- import { VStack, Heading, Text } from "../ui/index.js";
8
- import { jsonLdHtml } from "./jsonld.js";
9
- function questionSlug(q) {
10
- return q.toLowerCase().normalize("NFD").replace(/[̀-ͯ]/g, "").replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 60);
11
- }
12
- function questionSlugs(questions) {
13
- const seen = /* @__PURE__ */ new Map();
14
- return questions.map((q) => {
15
- const base = questionSlug(q);
16
- if (!base) return "";
17
- const n = (seen.get(base) ?? 0) + 1;
18
- seen.set(base, n);
19
- return n === 1 ? base : `${base}-${n}`;
20
- });
21
- }
22
- function faqJsonLd(items) {
23
- return {
24
- "@context": "https://schema.org",
25
- "@type": "FAQPage",
26
- mainEntity: items.filter((it) => it.q && (it.a || it.aHtml)).map((it) => ({
27
- "@type": "Question",
28
- name: it.q,
29
- acceptedAnswer: { "@type": "Answer", text: it.aHtml ? it.aHtml.replace(/<[^>]*>/g, " ").trim() : it.a }
30
- }))
31
- };
32
- }
33
- function FaqRender({ block }) {
34
- const items = block.items ?? [];
35
- const [q, setQ] = useState("");
36
- const withSlugs = useMemo(() => {
37
- const slugs = questionSlugs(items.map((it) => it.q));
38
- return items.map((it, i) => ({ it, slug: slugs[i], idx: i }));
39
- }, [items]);
40
- const [openSlug, setOpenSlug] = useState(null);
41
- useEffect(() => {
42
- const hash = window.location.hash.slice(1);
43
- if (hash && withSlugs.some(({ slug }) => slug === hash)) {
44
- setOpenSlug(hash);
45
- document.getElementById(hash)?.scrollIntoView({ block: "start" });
46
- }
47
- }, []);
48
- const filtered = useMemo(() => {
49
- if (!block.searchable || !q.trim()) return withSlugs;
50
- const needle = q.toLowerCase();
51
- return withSlugs.filter(({ it }) => (it.q + " " + it.a + " " + (it.aHtml ?? "")).toLowerCase().includes(needle));
52
- }, [withSlugs, q, block.searchable]);
53
- return /* @__PURE__ */ jsxs(VStack, { gap: 3, as: "section", className: "xicms-faq", children: [
54
- block.heading && /* @__PURE__ */ jsx(Heading, { level: 2, "data-xicms-edit": "heading", children: block.heading }),
55
- block.searchable && /* @__PURE__ */ jsx("div", { style: { maxWidth: 360 }, children: /* @__PURE__ */ jsx(
56
- TextInput,
57
- {
58
- label: "Zoek in veelgestelde vragen",
59
- isLabelHidden: true,
60
- placeholder: "Zoek in vragen\u2026",
61
- value: q,
62
- onChange: setQ
63
- }
64
- ) }),
65
- /* @__PURE__ */ jsxs(VStack, { gap: 1.5, children: [
66
- filtered.map(({ it, slug, idx }, i) => {
67
- return /* @__PURE__ */ jsx("div", { id: slug || void 0, children: /* @__PURE__ */ jsx(
68
- Collapsible,
69
- {
70
- trigger: /* @__PURE__ */ jsx(Text, { weight: "bold", className: "xicms-faq__question", "data-xicms-edit": `items.${idx}.q`, children: it.q }),
71
- defaultIsOpen: block.defaultOpen || slug !== "" && slug === openSlug,
72
- children: it.aHtml ? (
73
- // Server-side gesanitized bij publiceren (velden op *Html) — zie functions/lib/sanitize.
74
- // Inline bewerkbaar MET opmaak: `data-xicms-edit` wijst naar het eigen veld, zodat
75
- // de editor hier niet naar een niet-bestaand "html" schrijft.
76
- // eslint-disable-next-line react/no-danger
77
- /* @__PURE__ */ jsx(
78
- "div",
79
- {
80
- className: "xicms-richtext xicms-faq__answer",
81
- "data-xicms-edit": `items.${idx}.aHtml`,
82
- dangerouslySetInnerHTML: { __html: it.aHtml }
83
- }
84
- )
85
- ) : /* @__PURE__ */ jsx(Text, { color: "secondary", className: "xicms-faq__answer", "data-xicms-edit": `items.${idx}.a`, children: it.a })
86
- },
87
- `${i}-${slug === openSlug ? "open" : "dicht"}`
88
- ) }, i);
89
- }),
90
- filtered.length === 0 && /* @__PURE__ */ jsx(Text, { color: "secondary", children: "Geen vragen gevonden." })
91
- ] }),
92
- block.jsonLd && /* @__PURE__ */ jsx(
93
- "script",
94
- {
95
- type: "application/ld+json",
96
- dangerouslySetInnerHTML: { __html: jsonLdHtml(faqJsonLd(items)) }
97
- }
98
- )
99
- ] });
100
- }
101
3
  const faqBlock = defineBlock({
102
4
  type: "faq",
103
- Render: FaqRender,
5
+ Render: dynamic(() => import("./FaqRender.js").then((m) => m.FaqRender)),
104
6
  label: "Veelgestelde vragen",
105
7
  icon: "\u2753",
106
8
  defaults: () => ({
@@ -111,8 +13,6 @@ const faqBlock = defineBlock({
111
13
  })
112
14
  });
113
15
  export {
114
- faqBlock,
115
- questionSlug,
116
- questionSlugs
16
+ faqBlock
117
17
  };
118
18
  //# sourceMappingURL=Faq.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/blocks/builtins/Faq.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useMemo, useState } from \"react\";\nimport type { z } from \"zod\";\nimport type { FaqBlockSchema } from \"../../schema/blocks\";\nimport { defineBlock, type BlockRenderProps } from \"../registry\";\nimport { Collapsible } from \"@astryxdesign/core/Collapsible\";\nimport { TextInput } from \"@astryxdesign/core/TextInput\";\nimport { VStack, Heading, Text } from \"../ui\";\nimport { jsonLdHtml } from \"./jsonld\";\n\ntype Faq = z.infer<typeof FaqBlockSchema>;\n\n/** Anker-id voor een vraag (deep-link: /faq#hoe-werkt-het). */\nexport function questionSlug(q: string): string {\n return q\n .toLowerCase()\n .normalize(\"NFD\")\n .replace(/[̀-ͯ]/g, \"\")\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\")\n .slice(0, 60);\n}\n\n/** Unieke anker-ids voor een vragenlijst: identieke vragen krijgen -2, -3, … (ids moeten uniek zijn). */\nexport function questionSlugs(questions: string[]): string[] {\n const seen = new Map<string, number>();\n return questions.map((q) => {\n const base = questionSlug(q);\n if (!base) return \"\";\n const n = (seen.get(base) ?? 0) + 1;\n seen.set(base, n);\n return n === 1 ? base : `${base}-${n}`;\n });\n}\n\nfunction faqJsonLd(items: { q: string; a: string; aHtml?: string }[]): Record<string, unknown> {\n return {\n \"@context\": \"https://schema.org\",\n \"@type\": \"FAQPage\",\n mainEntity: items\n .filter((it) => it.q && (it.a || it.aHtml))\n .map((it) => ({\n \"@type\": \"Question\",\n name: it.q,\n acceptedAnswer: { \"@type\": \"Answer\", text: it.aHtml ? it.aHtml.replace(/<[^>]*>/g, \" \").trim() : it.a },\n })),\n };\n}\n\nfunction FaqRender({ block }: BlockRenderProps<Faq>) {\n const items = block.items ?? [];\n const [q, setQ] = useState(\"\");\n // Slug per item vooraf berekenen (met dedupe), zodat dubbele vragen geen dubbele ids opleveren\n // en de hash-match precies één vraag opent.\n const withSlugs = useMemo(() => {\n const slugs = questionSlugs(items.map((it) => it.q));\n // idx = originele index in block.items — nodig voor de inline-edit-paden, want `filtered`\n // kan bij een actieve zoekterm een deelverzameling met verschoven indexen zijn.\n return items.map((it, i) => ({ it, slug: slugs[i], idx: i }));\n }, [items]);\n // Deep-link: bij laden met #<vraag-slug> die vraag openen (en ernaartoe scrollen).\n const [openSlug, setOpenSlug] = useState<string | null>(null);\n useEffect(() => {\n const hash = window.location.hash.slice(1);\n if (hash && withSlugs.some(({ slug }) => slug === hash)) {\n setOpenSlug(hash);\n document.getElementById(hash)?.scrollIntoView({ block: \"start\" });\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n const filtered = useMemo(() => {\n if (!block.searchable || !q.trim()) return withSlugs;\n const needle = q.toLowerCase();\n return withSlugs.filter(({ it }) => (it.q + \" \" + it.a + \" \" + (it.aHtml ?? \"\")).toLowerCase().includes(needle));\n }, [withSlugs, q, block.searchable]);\n\n return (\n <VStack gap={3} as=\"section\" className=\"xicms-faq\">\n {block.heading && <Heading level={2} data-xicms-edit=\"heading\">{block.heading}</Heading>}\n {block.searchable && (\n <div style={{ maxWidth: 360 }}>\n <TextInput\n label=\"Zoek in veelgestelde vragen\"\n isLabelHidden\n placeholder=\"Zoek in vragen…\"\n value={q}\n onChange={setQ}\n />\n </div>\n )}\n <VStack gap={1.5}>\n {filtered.map(({ it, slug, idx }, i) => {\n return (\n <div key={i} id={slug || undefined}>\n <Collapsible\n // key wisselt zodra de hash-match binnenkomt (effect ná mount) → remount met open staat.\n key={`${i}-${slug === openSlug ? \"open\" : \"dicht\"}`}\n trigger={<Text weight=\"bold\" className=\"xicms-faq__question\" data-xicms-edit={`items.${idx}.q`}>{it.q}</Text>}\n defaultIsOpen={block.defaultOpen || (slug !== \"\" && slug === openSlug)}\n >\n {it.aHtml ? (\n // Server-side gesanitized bij publiceren (velden op *Html) — zie functions/lib/sanitize.\n // Inline bewerkbaar MET opmaak: `data-xicms-edit` wijst naar het eigen veld, zodat\n // de editor hier niet naar een niet-bestaand \"html\" schrijft.\n // eslint-disable-next-line react/no-danger\n <div\n className=\"xicms-richtext xicms-faq__answer\"\n data-xicms-edit={`items.${idx}.aHtml`}\n dangerouslySetInnerHTML={{ __html: it.aHtml }}\n />\n ) : (\n <Text color=\"secondary\" className=\"xicms-faq__answer\" data-xicms-edit={`items.${idx}.a`}>{it.a}</Text>\n )}\n </Collapsible>\n </div>\n );\n })}\n {filtered.length === 0 && <Text color=\"secondary\">Geen vragen gevonden.</Text>}\n </VStack>\n {block.jsonLd && (\n <script\n type=\"application/ld+json\"\n // eslint-disable-next-line react/no-danger\n dangerouslySetInnerHTML={{ __html: jsonLdHtml(faqJsonLd(items)) }}\n />\n )}\n </VStack>\n );\n}\n\nexport const faqBlock = defineBlock({\n type: \"faq\",\n Render: FaqRender,\n label: \"Veelgestelde vragen\",\n icon: \"❓\",\n defaults: () => ({\n heading: \"Veelgestelde vragen\",\n items: [{ q: \"Een vraag?\", a: \"Het antwoord.\" }],\n searchable: false,\n jsonLd: true,\n }),\n});\n"],"mappings":";AA+EwB,cAYlB,YAZkB;AA7ExB,SAAS,WAAW,SAAS,gBAAgB;AAG7C,SAAS,mBAA0C;AACnD,SAAS,mBAAmB;AAC5B,SAAS,iBAAiB;AAC1B,SAAS,QAAQ,SAAS,YAAY;AACtC,SAAS,kBAAkB;AAKpB,SAAS,aAAa,GAAmB;AAC9C,SAAO,EACJ,YAAY,EACZ,UAAU,KAAK,EACf,QAAQ,UAAU,EAAE,EACpB,QAAQ,eAAe,GAAG,EAC1B,QAAQ,YAAY,EAAE,EACtB,MAAM,GAAG,EAAE;AAChB;AAGO,SAAS,cAAc,WAA+B;AAC3D,QAAM,OAAO,oBAAI,IAAoB;AACrC,SAAO,UAAU,IAAI,CAAC,MAAM;AAC1B,UAAM,OAAO,aAAa,CAAC;AAC3B,QAAI,CAAC,KAAM,QAAO;AAClB,UAAM,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK;AAClC,SAAK,IAAI,MAAM,CAAC;AAChB,WAAO,MAAM,IAAI,OAAO,GAAG,IAAI,IAAI,CAAC;AAAA,EACtC,CAAC;AACH;AAEA,SAAS,UAAU,OAA4E;AAC7F,SAAO;AAAA,IACL,YAAY;AAAA,IACZ,SAAS;AAAA,IACT,YAAY,MACT,OAAO,CAAC,OAAO,GAAG,MAAM,GAAG,KAAK,GAAG,MAAM,EACzC,IAAI,CAAC,QAAQ;AAAA,MACZ,SAAS;AAAA,MACT,MAAM,GAAG;AAAA,MACT,gBAAgB,EAAE,SAAS,UAAU,MAAM,GAAG,QAAQ,GAAG,MAAM,QAAQ,YAAY,GAAG,EAAE,KAAK,IAAI,GAAG,EAAE;AAAA,IACxG,EAAE;AAAA,EACN;AACF;AAEA,SAAS,UAAU,EAAE,MAAM,GAA0B;AACnD,QAAM,QAAQ,MAAM,SAAS,CAAC;AAC9B,QAAM,CAAC,GAAG,IAAI,IAAI,SAAS,EAAE;AAG7B,QAAM,YAAY,QAAQ,MAAM;AAC9B,UAAM,QAAQ,cAAc,MAAM,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC;AAGnD,WAAO,MAAM,IAAI,CAAC,IAAI,OAAO,EAAE,IAAI,MAAM,MAAM,CAAC,GAAG,KAAK,EAAE,EAAE;AAAA,EAC9D,GAAG,CAAC,KAAK,CAAC;AAEV,QAAM,CAAC,UAAU,WAAW,IAAI,SAAwB,IAAI;AAC5D,YAAU,MAAM;AACd,UAAM,OAAO,OAAO,SAAS,KAAK,MAAM,CAAC;AACzC,QAAI,QAAQ,UAAU,KAAK,CAAC,EAAE,KAAK,MAAM,SAAS,IAAI,GAAG;AACvD,kBAAY,IAAI;AAChB,eAAS,eAAe,IAAI,GAAG,eAAe,EAAE,OAAO,QAAQ,CAAC;AAAA,IAClE;AAAA,EAEF,GAAG,CAAC,CAAC;AACL,QAAM,WAAW,QAAQ,MAAM;AAC7B,QAAI,CAAC,MAAM,cAAc,CAAC,EAAE,KAAK,EAAG,QAAO;AAC3C,UAAM,SAAS,EAAE,YAAY;AAC7B,WAAO,UAAU,OAAO,CAAC,EAAE,GAAG,OAAO,GAAG,IAAI,MAAM,GAAG,IAAI,OAAO,GAAG,SAAS,KAAK,YAAY,EAAE,SAAS,MAAM,CAAC;AAAA,EACjH,GAAG,CAAC,WAAW,GAAG,MAAM,UAAU,CAAC;AAEnC,SACE,qBAAC,UAAO,KAAK,GAAG,IAAG,WAAU,WAAU,aACpC;AAAA,UAAM,WAAW,oBAAC,WAAQ,OAAO,GAAG,mBAAgB,WAAW,gBAAM,SAAQ;AAAA,IAC7E,MAAM,cACL,oBAAC,SAAI,OAAO,EAAE,UAAU,IAAI,GAC1B;AAAA,MAAC;AAAA;AAAA,QACC,OAAM;AAAA,QACN,eAAa;AAAA,QACb,aAAY;AAAA,QACZ,OAAO;AAAA,QACP,UAAU;AAAA;AAAA,IACZ,GACF;AAAA,IAEF,qBAAC,UAAO,KAAK,KACV;AAAA,eAAS,IAAI,CAAC,EAAE,IAAI,MAAM,IAAI,GAAG,MAAM;AACtC,eACE,oBAAC,SAAY,IAAI,QAAQ,QACvB;AAAA,UAAC;AAAA;AAAA,YAGC,SAAS,oBAAC,QAAK,QAAO,QAAO,WAAU,uBAAsB,mBAAiB,SAAS,GAAG,MAAO,aAAG,GAAE;AAAA,YACtG,eAAe,MAAM,eAAgB,SAAS,MAAM,SAAS;AAAA,YAE5D,aAAG;AAAA;AAAA;AAAA;AAAA;AAAA,cAKF;AAAA,gBAAC;AAAA;AAAA,kBACC,WAAU;AAAA,kBACV,mBAAiB,SAAS,GAAG;AAAA,kBAC7B,yBAAyB,EAAE,QAAQ,GAAG,MAAM;AAAA;AAAA,cAC9C;AAAA,gBAEA,oBAAC,QAAK,OAAM,aAAY,WAAU,qBAAoB,mBAAiB,SAAS,GAAG,MAAO,aAAG,GAAE;AAAA;AAAA,UAf5F,GAAG,CAAC,IAAI,SAAS,WAAW,SAAS,OAAO;AAAA,QAiBnD,KApBQ,CAqBV;AAAA,MAEJ,CAAC;AAAA,MACA,SAAS,WAAW,KAAK,oBAAC,QAAK,OAAM,aAAY,mCAAqB;AAAA,OACzE;AAAA,IACC,MAAM,UACL;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QAEL,yBAAyB,EAAE,QAAQ,WAAW,UAAU,KAAK,CAAC,EAAE;AAAA;AAAA,IAClE;AAAA,KAEJ;AAEJ;AAEO,MAAM,WAAW,YAAY;AAAA,EAClC,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,MAAM;AAAA,EACN,UAAU,OAAO;AAAA,IACf,SAAS;AAAA,IACT,OAAO,CAAC,EAAE,GAAG,cAAc,GAAG,gBAAgB,CAAC;AAAA,IAC/C,YAAY;AAAA,IACZ,QAAQ;AAAA,EACV;AACF,CAAC;","names":[]}
1
+ {"version":3,"sources":["../../../src/blocks/builtins/Faq.tsx"],"sourcesContent":["import dynamic from \"next/dynamic\";\nimport { defineBlock } from \"../registry\";\n\nexport const faqBlock = defineBlock({\n type: \"faq\",\n Render: dynamic(() => import(\"./FaqRender\").then((m) => m.FaqRender)),\n label: \"Veelgestelde vragen\",\n icon: \"❓\",\n defaults: () => ({\n heading: \"Veelgestelde vragen\",\n items: [{ q: \"Een vraag?\", a: \"Het antwoord.\" }],\n searchable: false,\n jsonLd: true,\n }),\n});\n"],"mappings":"AAAA,OAAO,aAAa;AACpB,SAAS,mBAAmB;AAErB,MAAM,WAAW,YAAY;AAAA,EAClC,MAAM;AAAA,EACN,QAAQ,QAAQ,MAAM,OAAO,aAAa,EAAE,KAAK,CAAC,MAAM,EAAE,SAAS,CAAC;AAAA,EACpE,OAAO;AAAA,EACP,MAAM;AAAA,EACN,UAAU,OAAO;AAAA,IACf,SAAS;AAAA,IACT,OAAO,CAAC,EAAE,GAAG,cAAc,GAAG,gBAAgB,CAAC;AAAA,IAC/C,YAAY;AAAA,IACZ,QAAQ;AAAA,EACV;AACF,CAAC;","names":[]}
@@ -0,0 +1,10 @@
1
+ import type { z } from "zod";
2
+ import type { FaqBlockSchema } from "../../schema/blocks.js";
3
+ import type { BlockRenderProps } from "../registry.js";
4
+ type Faq = z.infer<typeof FaqBlockSchema>;
5
+ /** Anker-id voor een vraag (deep-link: /faq#hoe-werkt-het). */
6
+ export declare function questionSlug(q: string): string;
7
+ /** Unieke anker-ids voor een vragenlijst: identieke vragen krijgen -2, -3, … (ids moeten uniek zijn). */
8
+ export declare function questionSlugs(questions: string[]): string[];
9
+ export declare function FaqRender({ block }: BlockRenderProps<Faq>): import("react").JSX.Element;
10
+ export {};
@@ -0,0 +1,105 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { useEffect, useMemo, useState } from "react";
4
+ import { Collapsible } from "@astryxdesign/core/Collapsible";
5
+ import { TextInput } from "@astryxdesign/core/TextInput";
6
+ import { VStack, Heading, Text } from "../ui/index.js";
7
+ import { jsonLdHtml } from "./jsonld.js";
8
+ function questionSlug(q) {
9
+ return q.toLowerCase().normalize("NFD").replace(/[̀-ͯ]/g, "").replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 60);
10
+ }
11
+ function questionSlugs(questions) {
12
+ const seen = /* @__PURE__ */ new Map();
13
+ return questions.map((q) => {
14
+ const base = questionSlug(q);
15
+ if (!base) return "";
16
+ const n = (seen.get(base) ?? 0) + 1;
17
+ seen.set(base, n);
18
+ return n === 1 ? base : `${base}-${n}`;
19
+ });
20
+ }
21
+ function faqJsonLd(items) {
22
+ return {
23
+ "@context": "https://schema.org",
24
+ "@type": "FAQPage",
25
+ mainEntity: items.filter((it) => it.q && (it.a || it.aHtml)).map((it) => ({
26
+ "@type": "Question",
27
+ name: it.q,
28
+ acceptedAnswer: { "@type": "Answer", text: it.aHtml ? it.aHtml.replace(/<[^>]*>/g, " ").trim() : it.a }
29
+ }))
30
+ };
31
+ }
32
+ function FaqRender({ block }) {
33
+ const items = block.items ?? [];
34
+ const [q, setQ] = useState("");
35
+ const withSlugs = useMemo(() => {
36
+ const slugs = questionSlugs(items.map((it) => it.q));
37
+ return items.map((it, i) => ({ it, slug: slugs[i], idx: i }));
38
+ }, [items]);
39
+ const [openSlug, setOpenSlug] = useState(null);
40
+ useEffect(() => {
41
+ const hash = window.location.hash.slice(1);
42
+ if (hash && withSlugs.some(({ slug }) => slug === hash)) {
43
+ setOpenSlug(hash);
44
+ document.getElementById(hash)?.scrollIntoView({ block: "start" });
45
+ }
46
+ }, []);
47
+ const filtered = useMemo(() => {
48
+ if (!block.searchable || !q.trim()) return withSlugs;
49
+ const needle = q.toLowerCase();
50
+ return withSlugs.filter(({ it }) => (it.q + " " + it.a + " " + (it.aHtml ?? "")).toLowerCase().includes(needle));
51
+ }, [withSlugs, q, block.searchable]);
52
+ return /* @__PURE__ */ jsxs(VStack, { gap: 3, as: "section", className: "xicms-faq", children: [
53
+ block.heading && /* @__PURE__ */ jsx(Heading, { level: 2, "data-xicms-edit": "heading", children: block.heading }),
54
+ block.searchable && /* @__PURE__ */ jsx("div", { style: { maxWidth: 360 }, children: /* @__PURE__ */ jsx(
55
+ TextInput,
56
+ {
57
+ label: "Zoek in veelgestelde vragen",
58
+ isLabelHidden: true,
59
+ placeholder: "Zoek in vragen\u2026",
60
+ value: q,
61
+ onChange: setQ
62
+ }
63
+ ) }),
64
+ /* @__PURE__ */ jsxs(VStack, { gap: 1.5, children: [
65
+ filtered.map(({ it, slug, idx }, i) => {
66
+ return /* @__PURE__ */ jsx("div", { id: slug || void 0, children: /* @__PURE__ */ jsx(
67
+ Collapsible,
68
+ {
69
+ trigger: /* @__PURE__ */ jsx(Text, { weight: "bold", className: "xicms-faq__question", "data-xicms-edit": `items.${idx}.q`, children: it.q }),
70
+ defaultIsOpen: block.defaultOpen || slug !== "" && slug === openSlug,
71
+ children: it.aHtml ? (
72
+ // Server-side gesanitized bij publiceren (velden op *Html) — zie functions/lib/sanitize.
73
+ // Inline bewerkbaar MET opmaak: `data-xicms-edit` wijst naar het eigen veld, zodat
74
+ // de editor hier niet naar een niet-bestaand "html" schrijft.
75
+ // eslint-disable-next-line react/no-danger
76
+ /* @__PURE__ */ jsx(
77
+ "div",
78
+ {
79
+ className: "xicms-richtext xicms-faq__answer",
80
+ "data-xicms-edit": `items.${idx}.aHtml`,
81
+ dangerouslySetInnerHTML: { __html: it.aHtml }
82
+ }
83
+ )
84
+ ) : /* @__PURE__ */ jsx(Text, { color: "secondary", className: "xicms-faq__answer", "data-xicms-edit": `items.${idx}.a`, children: it.a })
85
+ },
86
+ `${i}-${slug === openSlug ? "open" : "dicht"}`
87
+ ) }, i);
88
+ }),
89
+ filtered.length === 0 && /* @__PURE__ */ jsx(Text, { color: "secondary", children: "Geen vragen gevonden." })
90
+ ] }),
91
+ block.jsonLd && /* @__PURE__ */ jsx(
92
+ "script",
93
+ {
94
+ type: "application/ld+json",
95
+ dangerouslySetInnerHTML: { __html: jsonLdHtml(faqJsonLd(items)) }
96
+ }
97
+ )
98
+ ] });
99
+ }
100
+ export {
101
+ FaqRender,
102
+ questionSlug,
103
+ questionSlugs
104
+ };
105
+ //# sourceMappingURL=FaqRender.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/blocks/builtins/FaqRender.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useMemo, useState } from \"react\";\nimport type { z } from \"zod\";\nimport type { FaqBlockSchema } from \"../../schema/blocks\";\nimport type { BlockRenderProps } from \"../registry\";\nimport { Collapsible } from \"@astryxdesign/core/Collapsible\";\nimport { TextInput } from \"@astryxdesign/core/TextInput\";\nimport { VStack, Heading, Text } from \"../ui\";\nimport { jsonLdHtml } from \"./jsonld\";\n\ntype Faq = z.infer<typeof FaqBlockSchema>;\n\n/** Anker-id voor een vraag (deep-link: /faq#hoe-werkt-het). */\nexport function questionSlug(q: string): string {\n return q\n .toLowerCase()\n .normalize(\"NFD\")\n .replace(/[̀-ͯ]/g, \"\")\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\")\n .slice(0, 60);\n}\n\n/** Unieke anker-ids voor een vragenlijst: identieke vragen krijgen -2, -3, … (ids moeten uniek zijn). */\nexport function questionSlugs(questions: string[]): string[] {\n const seen = new Map<string, number>();\n return questions.map((q) => {\n const base = questionSlug(q);\n if (!base) return \"\";\n const n = (seen.get(base) ?? 0) + 1;\n seen.set(base, n);\n return n === 1 ? base : `${base}-${n}`;\n });\n}\n\nfunction faqJsonLd(items: { q: string; a: string; aHtml?: string }[]): Record<string, unknown> {\n return {\n \"@context\": \"https://schema.org\",\n \"@type\": \"FAQPage\",\n mainEntity: items\n .filter((it) => it.q && (it.a || it.aHtml))\n .map((it) => ({\n \"@type\": \"Question\",\n name: it.q,\n acceptedAnswer: { \"@type\": \"Answer\", text: it.aHtml ? it.aHtml.replace(/<[^>]*>/g, \" \").trim() : it.a },\n })),\n };\n}\n\nexport function FaqRender({ block }: BlockRenderProps<Faq>) {\n const items = block.items ?? [];\n const [q, setQ] = useState(\"\");\n // Slug per item vooraf berekenen (met dedupe), zodat dubbele vragen geen dubbele ids opleveren\n // en de hash-match precies één vraag opent.\n const withSlugs = useMemo(() => {\n const slugs = questionSlugs(items.map((it) => it.q));\n // idx = originele index in block.items — nodig voor de inline-edit-paden, want `filtered`\n // kan bij een actieve zoekterm een deelverzameling met verschoven indexen zijn.\n return items.map((it, i) => ({ it, slug: slugs[i], idx: i }));\n }, [items]);\n // Deep-link: bij laden met #<vraag-slug> die vraag openen (en ernaartoe scrollen).\n const [openSlug, setOpenSlug] = useState<string | null>(null);\n useEffect(() => {\n const hash = window.location.hash.slice(1);\n if (hash && withSlugs.some(({ slug }) => slug === hash)) {\n setOpenSlug(hash);\n document.getElementById(hash)?.scrollIntoView({ block: \"start\" });\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n const filtered = useMemo(() => {\n if (!block.searchable || !q.trim()) return withSlugs;\n const needle = q.toLowerCase();\n return withSlugs.filter(({ it }) => (it.q + \" \" + it.a + \" \" + (it.aHtml ?? \"\")).toLowerCase().includes(needle));\n }, [withSlugs, q, block.searchable]);\n\n return (\n <VStack gap={3} as=\"section\" className=\"xicms-faq\">\n {block.heading && <Heading level={2} data-xicms-edit=\"heading\">{block.heading}</Heading>}\n {block.searchable && (\n <div style={{ maxWidth: 360 }}>\n <TextInput\n label=\"Zoek in veelgestelde vragen\"\n isLabelHidden\n placeholder=\"Zoek in vragen…\"\n value={q}\n onChange={setQ}\n />\n </div>\n )}\n <VStack gap={1.5}>\n {filtered.map(({ it, slug, idx }, i) => {\n return (\n <div key={i} id={slug || undefined}>\n <Collapsible\n // key wisselt zodra de hash-match binnenkomt (effect ná mount) → remount met open staat.\n key={`${i}-${slug === openSlug ? \"open\" : \"dicht\"}`}\n trigger={<Text weight=\"bold\" className=\"xicms-faq__question\" data-xicms-edit={`items.${idx}.q`}>{it.q}</Text>}\n defaultIsOpen={block.defaultOpen || (slug !== \"\" && slug === openSlug)}\n >\n {it.aHtml ? (\n // Server-side gesanitized bij publiceren (velden op *Html) — zie functions/lib/sanitize.\n // Inline bewerkbaar MET opmaak: `data-xicms-edit` wijst naar het eigen veld, zodat\n // de editor hier niet naar een niet-bestaand \"html\" schrijft.\n // eslint-disable-next-line react/no-danger\n <div\n className=\"xicms-richtext xicms-faq__answer\"\n data-xicms-edit={`items.${idx}.aHtml`}\n dangerouslySetInnerHTML={{ __html: it.aHtml }}\n />\n ) : (\n <Text color=\"secondary\" className=\"xicms-faq__answer\" data-xicms-edit={`items.${idx}.a`}>{it.a}</Text>\n )}\n </Collapsible>\n </div>\n );\n })}\n {filtered.length === 0 && <Text color=\"secondary\">Geen vragen gevonden.</Text>}\n </VStack>\n {block.jsonLd && (\n <script\n type=\"application/ld+json\"\n // eslint-disable-next-line react/no-danger\n dangerouslySetInnerHTML={{ __html: jsonLdHtml(faqJsonLd(items)) }}\n />\n )}\n </VStack>\n );\n}\n"],"mappings":"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","names":[]}
@@ -1,2 +1 @@
1
- import type { z } from "zod";
2
- export declare const formBlock: import("../index.js").BlockDefinition<z.core.$ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>>;
1
+ export declare const formBlock: import("../index.js").BlockDefinition<import("zod/v4/core").$ZodType<unknown, unknown, import("zod/v4/core").$ZodTypeInternals<unknown, unknown>>>;