@xiwebdesign/xicms-core 7.13.0 → 7.15.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 (280) hide show
  1. package/dist/admin/lib/mediaUsage.d.ts +17 -0
  2. package/dist/admin/lib/mediaUsage.js +32 -1
  3. package/dist/admin/lib/mediaUsage.js.map +1 -1
  4. package/dist/admin/media/MediaManager.js +74 -17
  5. package/dist/admin/media/MediaManager.js.map +1 -1
  6. package/dist/admin/visual/VisualEditor.js +37 -3
  7. package/dist/admin/visual/VisualEditor.js.map +1 -1
  8. package/dist/blocks/BlockErrorBoundary.d.ts +1 -0
  9. package/dist/blocks/BlockErrorBoundary.js +4 -0
  10. package/dist/blocks/BlockErrorBoundary.js.map +1 -1
  11. package/dist/blocks/BlockRenderer.js +1 -1
  12. package/dist/blocks/BlockRenderer.js.map +1 -1
  13. package/dist/blocks/builtins/Accordion.d.ts +1 -2
  14. package/dist/blocks/builtins/Accordion.js +2 -39
  15. package/dist/blocks/builtins/Accordion.js.map +1 -1
  16. package/dist/blocks/builtins/AccordionRender.d.ts +7 -0
  17. package/dist/blocks/builtins/AccordionRender.js +42 -0
  18. package/dist/blocks/builtins/AccordionRender.js.map +1 -0
  19. package/dist/blocks/builtins/Agenda.d.ts +1 -29
  20. package/dist/blocks/builtins/Agenda.js +3 -94
  21. package/dist/blocks/builtins/Agenda.js.map +1 -1
  22. package/dist/blocks/builtins/AgendaRender.d.ts +34 -0
  23. package/dist/blocks/builtins/AgendaRender.js +96 -0
  24. package/dist/blocks/builtins/AgendaRender.js.map +1 -0
  25. package/dist/blocks/builtins/Banner.d.ts +1 -2
  26. package/dist/blocks/builtins/Banner.js +2 -32
  27. package/dist/blocks/builtins/Banner.js.map +1 -1
  28. package/dist/blocks/builtins/BannerRender.d.ts +11 -0
  29. package/dist/blocks/builtins/BannerRender.js +35 -0
  30. package/dist/blocks/builtins/BannerRender.js.map +1 -0
  31. package/dist/blocks/builtins/BeforeAfter.d.ts +1 -2
  32. package/dist/blocks/builtins/BeforeAfter.js +2 -31
  33. package/dist/blocks/builtins/BeforeAfter.js.map +1 -1
  34. package/dist/blocks/builtins/BeforeAfterRender.d.ts +11 -0
  35. package/dist/blocks/builtins/BeforeAfterRender.js +34 -0
  36. package/dist/blocks/builtins/BeforeAfterRender.js.map +1 -0
  37. package/dist/blocks/builtins/Booking.d.ts +1 -2
  38. package/dist/blocks/builtins/Booking.js +2 -14
  39. package/dist/blocks/builtins/Booking.js.map +1 -1
  40. package/dist/blocks/builtins/BookingRender.d.ts +8 -0
  41. package/dist/blocks/builtins/BookingRender.js +17 -0
  42. package/dist/blocks/builtins/BookingRender.js.map +1 -0
  43. package/dist/blocks/builtins/Breadcrumbs.d.ts +1 -10
  44. package/dist/blocks/builtins/Breadcrumbs.js +3 -69
  45. package/dist/blocks/builtins/Breadcrumbs.js.map +1 -1
  46. package/dist/blocks/builtins/BreadcrumbsRender.d.ts +18 -0
  47. package/dist/blocks/builtins/BreadcrumbsRender.js +71 -0
  48. package/dist/blocks/builtins/BreadcrumbsRender.js.map +1 -0
  49. package/dist/blocks/builtins/Cards.d.ts +1 -2
  50. package/dist/blocks/builtins/Cards.js +2 -74
  51. package/dist/blocks/builtins/Cards.js.map +1 -1
  52. package/dist/blocks/builtins/CardsRender.d.ts +7 -0
  53. package/dist/blocks/builtins/CardsRender.js +77 -0
  54. package/dist/blocks/builtins/CardsRender.js.map +1 -0
  55. package/dist/blocks/builtins/Columns.d.ts +1 -2
  56. package/dist/blocks/builtins/Columns.js +2 -9
  57. package/dist/blocks/builtins/Columns.js.map +1 -1
  58. package/dist/blocks/builtins/ColumnsRender.d.ts +6 -0
  59. package/dist/blocks/builtins/ColumnsRender.js +12 -0
  60. package/dist/blocks/builtins/ColumnsRender.js.map +1 -0
  61. package/dist/blocks/builtins/Contact.d.ts +2 -7
  62. package/dist/blocks/builtins/Contact.js +3 -102
  63. package/dist/blocks/builtins/Contact.js.map +1 -1
  64. package/dist/blocks/builtins/ContactRender.d.ts +9 -0
  65. package/dist/blocks/builtins/ContactRender.js +105 -0
  66. package/dist/blocks/builtins/ContactRender.js.map +1 -0
  67. package/dist/blocks/builtins/Countdown.d.ts +1 -18
  68. package/dist/blocks/builtins/Countdown.js +3 -53
  69. package/dist/blocks/builtins/Countdown.js.map +1 -1
  70. package/dist/blocks/builtins/CountdownRender.d.ts +22 -0
  71. package/dist/blocks/builtins/CountdownRender.js +55 -0
  72. package/dist/blocks/builtins/CountdownRender.js.map +1 -0
  73. package/dist/blocks/builtins/Cta.d.ts +1 -2
  74. package/dist/blocks/builtins/Cta.js +2 -39
  75. package/dist/blocks/builtins/Cta.js.map +1 -1
  76. package/dist/blocks/builtins/CtaRender.d.ts +6 -0
  77. package/dist/blocks/builtins/CtaRender.js +42 -0
  78. package/dist/blocks/builtins/CtaRender.js.map +1 -0
  79. package/dist/blocks/builtins/Downloads.d.ts +1 -2
  80. package/dist/blocks/builtins/Downloads.js +2 -16
  81. package/dist/blocks/builtins/Downloads.js.map +1 -1
  82. package/dist/blocks/builtins/DownloadsRender.d.ts +7 -0
  83. package/dist/blocks/builtins/DownloadsRender.js +19 -0
  84. package/dist/blocks/builtins/DownloadsRender.js.map +1 -0
  85. package/dist/blocks/builtins/Elements.d.ts +3 -4
  86. package/dist/blocks/builtins/Elements.js +4 -38
  87. package/dist/blocks/builtins/Elements.js.map +1 -1
  88. package/dist/blocks/builtins/ElementsRender.d.ts +10 -0
  89. package/dist/blocks/builtins/ElementsRender.js +41 -0
  90. package/dist/blocks/builtins/ElementsRender.js.map +1 -0
  91. package/dist/blocks/builtins/Embed.d.ts +1 -2
  92. package/dist/blocks/builtins/Embed.js +2 -19
  93. package/dist/blocks/builtins/Embed.js.map +1 -1
  94. package/dist/blocks/builtins/EmbedRender.d.ts +7 -0
  95. package/dist/blocks/builtins/EmbedRender.js +22 -0
  96. package/dist/blocks/builtins/EmbedRender.js.map +1 -0
  97. package/dist/blocks/builtins/Faq.d.ts +1 -6
  98. package/dist/blocks/builtins/Faq.js +3 -103
  99. package/dist/blocks/builtins/Faq.js.map +1 -1
  100. package/dist/blocks/builtins/FaqRender.d.ts +10 -0
  101. package/dist/blocks/builtins/FaqRender.js +105 -0
  102. package/dist/blocks/builtins/FaqRender.js.map +1 -0
  103. package/dist/blocks/builtins/FormBlock.d.ts +1 -2
  104. package/dist/blocks/builtins/FormBlock.js +2 -222
  105. package/dist/blocks/builtins/FormBlock.js.map +1 -1
  106. package/dist/blocks/builtins/FormBlockRender.d.ts +6 -0
  107. package/dist/blocks/builtins/FormBlockRender.js +225 -0
  108. package/dist/blocks/builtins/FormBlockRender.js.map +1 -0
  109. package/dist/blocks/builtins/Gallery.d.ts +1 -23
  110. package/dist/blocks/builtins/Gallery.js +2 -164
  111. package/dist/blocks/builtins/Gallery.js.map +1 -1
  112. package/dist/blocks/builtins/GalleryRender.d.ts +25 -0
  113. package/dist/blocks/builtins/GalleryRender.js +167 -0
  114. package/dist/blocks/builtins/GalleryRender.js.map +1 -0
  115. package/dist/blocks/builtins/Hero.d.ts +1 -2
  116. package/dist/blocks/builtins/Hero.js +2 -73
  117. package/dist/blocks/builtins/Hero.js.map +1 -1
  118. package/dist/blocks/builtins/HeroRender.d.ts +6 -0
  119. package/dist/blocks/builtins/HeroRender.js +76 -0
  120. package/dist/blocks/builtins/HeroRender.js.map +1 -0
  121. package/dist/blocks/builtins/ImageBlock.d.ts +1 -2
  122. package/dist/blocks/builtins/ImageBlock.js +2 -22
  123. package/dist/blocks/builtins/ImageBlock.js.map +1 -1
  124. package/dist/blocks/builtins/ImageBlockRender.d.ts +6 -0
  125. package/dist/blocks/builtins/ImageBlockRender.js +25 -0
  126. package/dist/blocks/builtins/ImageBlockRender.js.map +1 -0
  127. package/dist/blocks/builtins/Jobs.d.ts +1 -15
  128. package/dist/blocks/builtins/Jobs.js +3 -69
  129. package/dist/blocks/builtins/Jobs.js.map +1 -1
  130. package/dist/blocks/builtins/JobsRender.d.ts +17 -0
  131. package/dist/blocks/builtins/JobsRender.js +71 -0
  132. package/dist/blocks/builtins/JobsRender.js.map +1 -0
  133. package/dist/blocks/builtins/Layout.d.ts +2 -3
  134. package/dist/blocks/builtins/Layout.js +3 -39
  135. package/dist/blocks/builtins/Layout.js.map +1 -1
  136. package/dist/blocks/builtins/LayoutRender.d.ts +8 -0
  137. package/dist/blocks/builtins/LayoutRender.js +42 -0
  138. package/dist/blocks/builtins/LayoutRender.js.map +1 -0
  139. package/dist/blocks/builtins/MapBlock.d.ts +1 -2
  140. package/dist/blocks/builtins/MapBlock.js +2 -45
  141. package/dist/blocks/builtins/MapBlock.js.map +1 -1
  142. package/dist/blocks/builtins/MapBlockRender.d.ts +6 -0
  143. package/dist/blocks/builtins/MapBlockRender.js +48 -0
  144. package/dist/blocks/builtins/MapBlockRender.js.map +1 -0
  145. package/dist/blocks/builtins/NewsListBlock.d.ts +1 -2
  146. package/dist/blocks/builtins/NewsListBlock.js +2 -11
  147. package/dist/blocks/builtins/NewsListBlock.js.map +1 -1
  148. package/dist/blocks/builtins/NewsListBlockRender.d.ts +6 -0
  149. package/dist/blocks/builtins/NewsListBlockRender.js +14 -0
  150. package/dist/blocks/builtins/NewsListBlockRender.js.map +1 -0
  151. package/dist/blocks/builtins/Newsletter.d.ts +1 -2
  152. package/dist/blocks/builtins/Newsletter.js +2 -89
  153. package/dist/blocks/builtins/Newsletter.js.map +1 -1
  154. package/dist/blocks/builtins/NewsletterRender.d.ts +13 -0
  155. package/dist/blocks/builtins/NewsletterRender.js +92 -0
  156. package/dist/blocks/builtins/NewsletterRender.js.map +1 -0
  157. package/dist/blocks/builtins/OpeningHours.d.ts +1 -2
  158. package/dist/blocks/builtins/OpeningHours.js +2 -28
  159. package/dist/blocks/builtins/OpeningHours.js.map +1 -1
  160. package/dist/blocks/builtins/OpeningHoursRender.d.ts +7 -0
  161. package/dist/blocks/builtins/OpeningHoursRender.js +31 -0
  162. package/dist/blocks/builtins/OpeningHoursRender.js.map +1 -0
  163. package/dist/blocks/builtins/PdfBlock.d.ts +1 -2
  164. package/dist/blocks/builtins/PdfBlock.js +2 -76
  165. package/dist/blocks/builtins/PdfBlock.js.map +1 -1
  166. package/dist/blocks/builtins/PdfBlockRender.d.ts +11 -0
  167. package/dist/blocks/builtins/PdfBlockRender.js +79 -0
  168. package/dist/blocks/builtins/PdfBlockRender.js.map +1 -0
  169. package/dist/blocks/builtins/Portfolio.d.ts +1 -2
  170. package/dist/blocks/builtins/Portfolio.js +2 -75
  171. package/dist/blocks/builtins/Portfolio.js.map +1 -1
  172. package/dist/blocks/builtins/PortfolioRender.d.ts +7 -0
  173. package/dist/blocks/builtins/PortfolioRender.js +78 -0
  174. package/dist/blocks/builtins/PortfolioRender.js.map +1 -0
  175. package/dist/blocks/builtins/Pricing.d.ts +1 -8
  176. package/dist/blocks/builtins/Pricing.js +3 -73
  177. package/dist/blocks/builtins/Pricing.js.map +1 -1
  178. package/dist/blocks/builtins/PricingRender.d.ts +10 -0
  179. package/dist/blocks/builtins/PricingRender.js +75 -0
  180. package/dist/blocks/builtins/PricingRender.js.map +1 -0
  181. package/dist/blocks/builtins/RichTextBlock.d.ts +1 -2
  182. package/dist/blocks/builtins/RichTextBlock.js +2 -5
  183. package/dist/blocks/builtins/RichTextBlock.js.map +1 -1
  184. package/dist/blocks/builtins/RichTextBlockRender.d.ts +6 -0
  185. package/dist/blocks/builtins/RichTextBlockRender.js +8 -0
  186. package/dist/blocks/builtins/RichTextBlockRender.js.map +1 -0
  187. package/dist/blocks/builtins/Search.d.ts +1 -2
  188. package/dist/blocks/builtins/Search.js +2 -80
  189. package/dist/blocks/builtins/Search.js.map +1 -1
  190. package/dist/blocks/builtins/SearchRender.d.ts +7 -0
  191. package/dist/blocks/builtins/SearchRender.js +83 -0
  192. package/dist/blocks/builtins/SearchRender.js.map +1 -0
  193. package/dist/blocks/builtins/Sections.d.ts +4 -5
  194. package/dist/blocks/builtins/Sections.js +5 -142
  195. package/dist/blocks/builtins/Sections.js.map +1 -1
  196. package/dist/blocks/builtins/SectionsRender.d.ts +12 -0
  197. package/dist/blocks/builtins/SectionsRender.js +145 -0
  198. package/dist/blocks/builtins/SectionsRender.js.map +1 -0
  199. package/dist/blocks/builtins/Slider.d.ts +1 -2
  200. package/dist/blocks/builtins/Slider.js +2 -134
  201. package/dist/blocks/builtins/Slider.js.map +1 -1
  202. package/dist/blocks/builtins/SliderRender.d.ts +7 -0
  203. package/dist/blocks/builtins/SliderRender.js +137 -0
  204. package/dist/blocks/builtins/SliderRender.js.map +1 -0
  205. package/dist/blocks/builtins/Spacer.d.ts +1 -2
  206. package/dist/blocks/builtins/Spacer.js +2 -6
  207. package/dist/blocks/builtins/Spacer.js.map +1 -1
  208. package/dist/blocks/builtins/SpacerRender.d.ts +6 -0
  209. package/dist/blocks/builtins/SpacerRender.js +9 -0
  210. package/dist/blocks/builtins/SpacerRender.js.map +1 -0
  211. package/dist/blocks/builtins/SymbolRef.d.ts +1 -2
  212. package/dist/blocks/builtins/SymbolRef.js +2 -76
  213. package/dist/blocks/builtins/SymbolRef.js.map +1 -1
  214. package/dist/blocks/builtins/SymbolRefRender.d.ts +13 -0
  215. package/dist/blocks/builtins/SymbolRefRender.js +79 -0
  216. package/dist/blocks/builtins/SymbolRefRender.js.map +1 -0
  217. package/dist/blocks/builtins/Team.d.ts +1 -2
  218. package/dist/blocks/builtins/Team.js +2 -55
  219. package/dist/blocks/builtins/Team.js.map +1 -1
  220. package/dist/blocks/builtins/TeamRender.d.ts +7 -0
  221. package/dist/blocks/builtins/TeamRender.js +58 -0
  222. package/dist/blocks/builtins/TeamRender.js.map +1 -0
  223. package/dist/blocks/builtins/Testimonials.d.ts +1 -8
  224. package/dist/blocks/builtins/Testimonials.js +2 -69
  225. package/dist/blocks/builtins/Testimonials.js.map +1 -1
  226. package/dist/blocks/builtins/TestimonialsRender.d.ts +10 -0
  227. package/dist/blocks/builtins/TestimonialsRender.js +72 -0
  228. package/dist/blocks/builtins/TestimonialsRender.js.map +1 -0
  229. package/dist/blocks/builtins/Video.d.ts +1 -9
  230. package/dist/blocks/builtins/Video.js +2 -64
  231. package/dist/blocks/builtins/Video.js.map +1 -1
  232. package/dist/blocks/builtins/VideoRender.d.ts +10 -0
  233. package/dist/blocks/builtins/VideoRender.js +67 -0
  234. package/dist/blocks/builtins/VideoRender.js.map +1 -0
  235. package/dist/blocks/builtins/WhatsappChat.d.ts +1 -8
  236. package/dist/blocks/builtins/WhatsappChat.js +2 -37
  237. package/dist/blocks/builtins/WhatsappChat.js.map +1 -1
  238. package/dist/blocks/builtins/WhatsappChatRender.d.ts +17 -0
  239. package/dist/blocks/builtins/WhatsappChatRender.js +40 -0
  240. package/dist/blocks/builtins/WhatsappChatRender.js.map +1 -0
  241. package/dist/blocks/builtins/Widgets.d.ts +12 -13
  242. package/dist/blocks/builtins/Widgets.js +13 -175
  243. package/dist/blocks/builtins/Widgets.js.map +1 -1
  244. package/dist/blocks/builtins/WidgetsRender.d.ts +34 -0
  245. package/dist/blocks/builtins/WidgetsRender.js +178 -0
  246. package/dist/blocks/builtins/WidgetsRender.js.map +1 -0
  247. package/dist/blocks/reportRenderFout.d.ts +13 -0
  248. package/dist/blocks/reportRenderFout.js +31 -0
  249. package/dist/blocks/reportRenderFout.js.map +1 -0
  250. package/dist/modules/contract.js +2 -1
  251. package/dist/modules/contract.js.map +1 -1
  252. package/dist/modules/shop/blocks/Cart.js +1 -2
  253. package/dist/modules/shop/blocks/Cart.js.map +1 -1
  254. package/dist/modules/shop/blocks/Checkout.js +1 -2
  255. package/dist/modules/shop/blocks/Checkout.js.map +1 -1
  256. package/dist/modules/shop/blocks/Donation.js +1 -2
  257. package/dist/modules/shop/blocks/Donation.js.map +1 -1
  258. package/dist/modules/shop/blocks/OrderStatus.js +0 -2
  259. package/dist/modules/shop/blocks/OrderStatus.js.map +1 -1
  260. package/dist/modules/shop/blocks/ProductDetail.js +1 -7
  261. package/dist/modules/shop/blocks/ProductDetail.js.map +1 -1
  262. package/dist/modules/shop/blocks/ProductGrid.js +1 -2
  263. package/dist/modules/shop/blocks/ProductGrid.js.map +1 -1
  264. package/dist/modules/shop/blocks/ShopCategories.js +0 -2
  265. package/dist/modules/shop/blocks/ShopCategories.js.map +1 -1
  266. package/dist/modules/shop/module.js +1 -0
  267. package/dist/modules/shop/module.js.map +1 -1
  268. package/dist/modules/shop/schemas.d.ts +1 -0
  269. package/dist/modules/shop/schemas.js +32 -0
  270. package/dist/modules/shop/schemas.js.map +1 -0
  271. package/dist/modules/types.d.ts +6 -0
  272. package/dist/schema/shop.d.ts +1 -11
  273. package/dist/schema/shop.js +1 -20
  274. package/dist/schema/shop.js.map +1 -1
  275. package/dist/schema/shopGeld.d.ts +18 -0
  276. package/dist/schema/shopGeld.js +27 -0
  277. package/dist/schema/shopGeld.js.map +1 -0
  278. package/dist/styles.css +17 -0
  279. package/dist/version.js +1 -1
  280. package/package.json +1 -1
@@ -0,0 +1,225 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { useEffect, useState } from "react";
4
+ import { useBlockData } from "../context.js";
5
+ import { submitFormValues } from "./lib/submitForm.js";
6
+ import { isDemoActive, getDemoForm } from "../../demo/demoStore.js";
7
+ import { useSiteConfig } from "../../config.js";
8
+ import { TextInput } from "@astryxdesign/core/TextInput";
9
+ import { TextArea } from "@astryxdesign/core/TextArea";
10
+ import { Selector } from "@astryxdesign/core/Selector";
11
+ import { CheckboxInput } from "@astryxdesign/core/CheckboxInput";
12
+ import { Spinner } from "@astryxdesign/core/Spinner";
13
+ import { Button } from "@astryxdesign/core/Button";
14
+ import { VStack, Card, Heading, Text } from "../ui/index.js";
15
+ const DEMO_FALLBACK_FORM = {
16
+ name: "Contact",
17
+ submitLabel: "Versturen",
18
+ successMessage: "Bedankt! Dit is een demo \u2014 je bericht is niet echt verstuurd.",
19
+ fields: [
20
+ { name: "naam", label: "Naam", type: "text", required: true },
21
+ { name: "email", label: "E-mail", type: "email", required: true },
22
+ { name: "bericht", label: "Bericht", type: "textarea", required: false, placeholder: "Waarmee kunnen we je helpen?" }
23
+ ]
24
+ };
25
+ function FormRender({ block, siteId, mode }) {
26
+ const siteMode = useSiteConfig().mode;
27
+ const serverForms = useBlockData("forms");
28
+ const serverDef = serverForms?.[block.formId] ?? null;
29
+ const [def, setDef] = useState(serverDef);
30
+ const [unavailable, setUnavailable] = useState(false);
31
+ const [values, setValues] = useState({});
32
+ const [hp, setHp] = useState("");
33
+ const [status, setStatus] = useState("idle");
34
+ const [error, setError] = useState(null);
35
+ const demo = isDemoActive();
36
+ const [localOnly, setLocalOnly] = useState(demo);
37
+ useEffect(() => {
38
+ if (demo) {
39
+ setDef(getDemoForm(siteId, block.formId) ?? DEMO_FALLBACK_FORM);
40
+ setLocalOnly(true);
41
+ return;
42
+ }
43
+ if (serverDef) return;
44
+ void (async () => {
45
+ const [{ getDb }, { doc, getDoc }] = await Promise.all([
46
+ import("../../firebase/client.js"),
47
+ import("firebase/firestore")
48
+ ]);
49
+ const db = getDb();
50
+ if (!db) {
51
+ const reg = getDemoForm(siteId, block.formId) ?? (siteMode === "demo" ? DEMO_FALLBACK_FORM : null);
52
+ if (reg) {
53
+ setDef(reg);
54
+ setLocalOnly(true);
55
+ } else {
56
+ setUnavailable(true);
57
+ }
58
+ return;
59
+ }
60
+ try {
61
+ const snap = await getDoc(doc(db, "sites", siteId, "forms", block.formId));
62
+ if (snap.exists()) setDef(snap.data());
63
+ else setUnavailable(true);
64
+ } catch {
65
+ setUnavailable(true);
66
+ }
67
+ })();
68
+ }, [demo, siteId, block.formId, siteMode, serverDef]);
69
+ if (unavailable) {
70
+ return /* @__PURE__ */ jsx(Card, { padding: 4, variant: "muted", children: /* @__PURE__ */ jsxs(Text, { children: [
71
+ block.heading ? `${block.heading}: ` : "",
72
+ "neem contact met ons op \u2014 we reageren snel."
73
+ ] }) });
74
+ }
75
+ if (!def) {
76
+ return /* @__PURE__ */ jsx("div", { style: { display: "grid", placeItems: "center", minHeight: 120 }, children: /* @__PURE__ */ jsx(Spinner, { label: "Formulier laden\u2026" }) });
77
+ }
78
+ async function submit(e) {
79
+ e.preventDefault();
80
+ if (mode === "preview") return;
81
+ if (localOnly) {
82
+ setStatus("ok");
83
+ setValues({});
84
+ return;
85
+ }
86
+ setStatus("busy");
87
+ setError(null);
88
+ try {
89
+ await submitFormValues(siteId, block.formId, values, hp);
90
+ if (def?.successRedirect) {
91
+ window.location.assign(def.successRedirect);
92
+ return;
93
+ }
94
+ setStatus("ok");
95
+ setValues({});
96
+ } catch {
97
+ setStatus("error");
98
+ setError("Versturen mislukt. Probeer het later opnieuw.");
99
+ }
100
+ }
101
+ if (status === "ok") {
102
+ return (
103
+ // role="status": screenreaders melden de succesboodschap wanneer het formulier verdwijnt.
104
+ /* @__PURE__ */ jsx(Card, { padding: 4, variant: "muted", role: "status", children: /* @__PURE__ */ jsx(Text, { children: def.successMessage }) })
105
+ );
106
+ }
107
+ const setVal = (name, v) => setValues((prev) => ({ ...prev, [name]: v }));
108
+ return /* @__PURE__ */ jsx("form", { className: "xicms-form", onSubmit: submit, children: /* @__PURE__ */ jsxs(VStack, { gap: 3, children: [
109
+ block.heading && /* @__PURE__ */ jsx(Heading, { level: 2, "data-xicms-edit": "heading", children: block.heading }),
110
+ def.fields.map((f) => {
111
+ const sv = values[f.name] ?? "";
112
+ if (f.type === "textarea") {
113
+ return /* @__PURE__ */ jsx(
114
+ TextArea,
115
+ {
116
+ label: f.label,
117
+ isRequired: f.required,
118
+ placeholder: f.placeholder,
119
+ rows: 4,
120
+ value: sv,
121
+ onChange: (v) => setVal(f.name, v)
122
+ },
123
+ f.name
124
+ );
125
+ }
126
+ if (f.type === "select") {
127
+ return /* @__PURE__ */ jsx(
128
+ Selector,
129
+ {
130
+ label: f.label,
131
+ isRequired: f.required,
132
+ placeholder: "Kies\u2026",
133
+ options: f.options ?? [],
134
+ value: sv,
135
+ onChange: (v) => setVal(f.name, v ?? "")
136
+ },
137
+ f.name
138
+ );
139
+ }
140
+ if (f.type === "checkbox") {
141
+ return /* @__PURE__ */ jsx(
142
+ CheckboxInput,
143
+ {
144
+ label: f.label,
145
+ isRequired: f.required,
146
+ value: Boolean(values[f.name]),
147
+ onChange: (checked) => setVal(f.name, checked)
148
+ },
149
+ f.name
150
+ );
151
+ }
152
+ if (f.type === "radio") {
153
+ return /* @__PURE__ */ jsxs("fieldset", { className: "xicms-form__radios", children: [
154
+ /* @__PURE__ */ jsxs("legend", { children: [
155
+ f.label,
156
+ f.required && " *"
157
+ ] }),
158
+ (f.options ?? []).map((opt) => /* @__PURE__ */ jsxs("label", { className: "xicms-form__radio", children: [
159
+ /* @__PURE__ */ jsx(
160
+ "input",
161
+ {
162
+ type: "radio",
163
+ name: f.name,
164
+ value: opt,
165
+ required: f.required,
166
+ checked: sv === opt,
167
+ onChange: () => setVal(f.name, opt)
168
+ }
169
+ ),
170
+ opt
171
+ ] }, opt))
172
+ ] }, f.name);
173
+ }
174
+ if (f.type === "date" || f.type === "number") {
175
+ return /* @__PURE__ */ jsxs("label", { className: "xicms-form__native", children: [
176
+ /* @__PURE__ */ jsxs("span", { className: "xicms-form__native-label", children: [
177
+ f.label,
178
+ f.required && " *"
179
+ ] }),
180
+ /* @__PURE__ */ jsx(
181
+ "input",
182
+ {
183
+ className: "xicms-input",
184
+ type: f.type,
185
+ required: f.required,
186
+ placeholder: f.placeholder,
187
+ value: sv,
188
+ onChange: (e) => setVal(f.name, e.target.value)
189
+ }
190
+ )
191
+ ] }, f.name);
192
+ }
193
+ return /* @__PURE__ */ jsx(
194
+ TextInput,
195
+ {
196
+ label: f.label,
197
+ type: f.type === "email" ? "email" : "text",
198
+ isRequired: f.required,
199
+ placeholder: f.placeholder,
200
+ value: sv,
201
+ onChange: (v) => setVal(f.name, v)
202
+ },
203
+ f.name
204
+ );
205
+ }),
206
+ /* @__PURE__ */ jsx(
207
+ "input",
208
+ {
209
+ type: "text",
210
+ tabIndex: -1,
211
+ autoComplete: "off",
212
+ value: hp,
213
+ onChange: (e) => setHp(e.target.value),
214
+ style: { position: "absolute", left: "-9999px", width: 1, height: 1 },
215
+ "aria-hidden": true
216
+ }
217
+ ),
218
+ error && /* @__PURE__ */ jsx(Text, { role: "alert", style: { color: "var(--color-error, #c0392b)" }, children: error }),
219
+ /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(Button, { label: status === "busy" ? "Versturen\u2026" : def.submitLabel, variant: "primary", size: "lg", type: "submit", isLoading: status === "busy" }) })
220
+ ] }) });
221
+ }
222
+ export {
223
+ FormRender
224
+ };
225
+ //# sourceMappingURL=FormBlockRender.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/blocks/builtins/FormBlockRender.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useState, type FormEvent } from \"react\";\nimport type { z } from \"zod\";\nimport type { FormBlockSchema } from \"../../schema/blocks\";\nimport type { FormDefinition } from \"../../schema/forms\";\nimport type { BlockRenderProps } from \"../registry\";\nimport { useBlockData } from \"../context\";\nimport { submitFormValues } from \"./lib/submitForm\";\nimport { isDemoActive, getDemoForm } from \"../../demo/demoStore\";\nimport { useSiteConfig } from \"../../config\";\nimport { TextInput } from \"@astryxdesign/core/TextInput\";\nimport { TextArea } from \"@astryxdesign/core/TextArea\";\nimport { Selector } from \"@astryxdesign/core/Selector\";\nimport { CheckboxInput } from \"@astryxdesign/core/CheckboxInput\";\nimport { Spinner } from \"@astryxdesign/core/Spinner\";\nimport { Button } from \"@astryxdesign/core/Button\";\nimport { VStack, Card, Heading, Text } from \"../ui\";\n\ntype FormBlk = z.infer<typeof FormBlockSchema>;\n\n/** Voorbeeldformulier voor de demo wanneer er geen specifieke definitie is geregistreerd. */\nconst DEMO_FALLBACK_FORM: FormDefinition = {\n name: \"Contact\",\n submitLabel: \"Versturen\",\n successMessage: \"Bedankt! Dit is een demo — je bericht is niet echt verstuurd.\",\n fields: [\n { name: \"naam\", label: \"Naam\", type: \"text\", required: true },\n { name: \"email\", label: \"E-mail\", type: \"email\", required: true },\n { name: \"bericht\", label: \"Bericht\", type: \"textarea\", required: false, placeholder: \"Waarmee kunnen we je helpen?\" },\n ],\n};\n\nexport function FormRender({ block, siteId, mode }: BlockRenderProps<FormBlk>) {\n const siteMode = useSiteConfig().mode;\n // Server-seed (7.12): de route leest formulierdefinities server-side (getPageBlockData) en\n // geeft ze mee als blockData. Het formulier staat dan al in de SSR-HTML en de per-bezoeker\n // `getDoc` hieronder vervalt. Zonder seed (oudere site, admin-preview) werkt het oude pad.\n const serverForms = useBlockData<Record<string, FormDefinition>>(\"forms\");\n const serverDef = serverForms?.[block.formId] ?? null;\n const [def, setDef] = useState<FormDefinition | null>(serverDef);\n const [unavailable, setUnavailable] = useState(false);\n const [values, setValues] = useState<Record<string, string | boolean>>({});\n const [hp, setHp] = useState(\"\");\n const [status, setStatus] = useState<\"idle\" | \"busy\" | \"ok\" | \"error\">(\"idle\");\n const [error, setError] = useState<string | null>(null);\n\n const demo = isDemoActive();\n // \"Lokaal\" inzenden (geen Firebase-call) bij demo OF wanneer er geen Firebase is maar wél een\n // geregistreerd voorbeeldformulier — zo werkt een statische referentiesite z'n formulier ook.\n const [localOnly, setLocalOnly] = useState(demo);\n\n useEffect(() => {\n if (demo) {\n setDef(getDemoForm(siteId, block.formId) ?? DEMO_FALLBACK_FORM);\n setLocalOnly(true);\n return;\n }\n if (serverDef) return; // definitie kwam al server-side mee\n // Firestore dynamisch: alleen een pagina die écht een formulier toont haalt de SDK binnen.\n void (async () => {\n const [{ getDb }, { doc, getDoc }] = await Promise.all([\n import(\"../../firebase/client\"),\n import(\"firebase/firestore\"),\n ]);\n const db = getDb();\n if (!db) {\n // Geen Firebase: val terug op een geregistreerd formulier, of (op een mode:\"demo\"-site) op\n // het ingebouwde voorbeeld; beide zenden lokaal in. Anders een nette \"niet beschikbaar\".\n const reg = getDemoForm(siteId, block.formId) ?? (siteMode === \"demo\" ? DEMO_FALLBACK_FORM : null);\n if (reg) { setDef(reg); setLocalOnly(true); } else { setUnavailable(true); }\n return;\n }\n try {\n const snap = await getDoc(doc(db, \"sites\", siteId, \"forms\", block.formId));\n if (snap.exists()) setDef(snap.data() as FormDefinition);\n else setUnavailable(true);\n } catch {\n setUnavailable(true);\n }\n })();\n }, [demo, siteId, block.formId, siteMode, serverDef]);\n\n if (unavailable) {\n return (\n <Card padding={4} variant=\"muted\">\n <Text>{block.heading ? `${block.heading}: ` : \"\"}neem contact met ons op — we reageren snel.</Text>\n </Card>\n );\n }\n if (!def) {\n return (\n <div style={{ display: \"grid\", placeItems: \"center\", minHeight: 120 }}>\n <Spinner label=\"Formulier laden…\" />\n </div>\n );\n }\n\n async function submit(e: FormEvent) {\n e.preventDefault();\n if (mode === \"preview\") return;\n if (localOnly) {\n // Lokaal (demo / geen backend): niets versturen, alleen de successtaat tonen.\n setStatus(\"ok\");\n setValues({});\n return;\n }\n setStatus(\"busy\");\n setError(null);\n try {\n await submitFormValues(siteId, block.formId, values, hp);\n // Optioneel doorsturen naar een bedankt-pagina (conversiemeting/advertenties).\n if (def?.successRedirect) {\n window.location.assign(def.successRedirect);\n return;\n }\n setStatus(\"ok\");\n setValues({});\n } catch {\n setStatus(\"error\");\n setError(\"Versturen mislukt. Probeer het later opnieuw.\");\n }\n }\n\n if (status === \"ok\") {\n return (\n // role=\"status\": screenreaders melden de succesboodschap wanneer het formulier verdwijnt.\n <Card padding={4} variant=\"muted\" role=\"status\">\n <Text>{def.successMessage}</Text>\n </Card>\n );\n }\n\n const setVal = (name: string, v: string | boolean) => setValues((prev) => ({ ...prev, [name]: v }));\n\n return (\n <form className=\"xicms-form\" onSubmit={submit}>\n <VStack gap={3}>\n {block.heading && <Heading level={2} data-xicms-edit=\"heading\">{block.heading}</Heading>}\n {def.fields.map((f) => {\n const sv = (values[f.name] as string) ?? \"\";\n if (f.type === \"textarea\") {\n return (\n <TextArea key={f.name} label={f.label} isRequired={f.required} placeholder={f.placeholder} rows={4}\n value={sv} onChange={(v) => setVal(f.name, v)} />\n );\n }\n if (f.type === \"select\") {\n return (\n <Selector key={f.name} label={f.label} isRequired={f.required} placeholder=\"Kies…\"\n options={f.options ?? []} value={sv} onChange={(v) => setVal(f.name, (v as string) ?? \"\")} />\n );\n }\n if (f.type === \"checkbox\") {\n return (\n <CheckboxInput key={f.name} label={f.label} isRequired={f.required}\n value={Boolean(values[f.name])} onChange={(checked) => setVal(f.name, checked)} />\n );\n }\n if (f.type === \"radio\") {\n return (\n <fieldset key={f.name} className=\"xicms-form__radios\">\n <legend>{f.label}{f.required && \" *\"}</legend>\n {(f.options ?? []).map((opt) => (\n <label key={opt} className=\"xicms-form__radio\">\n <input\n type=\"radio\"\n name={f.name}\n value={opt}\n required={f.required}\n checked={sv === opt}\n onChange={() => setVal(f.name, opt)}\n />\n {opt}\n </label>\n ))}\n </fieldset>\n );\n }\n if (f.type === \"date\" || f.type === \"number\") {\n // Astryx TextInput kent geen date/number → native input in dezelfde stijl.\n return (\n <label key={f.name} className=\"xicms-form__native\">\n <span className=\"xicms-form__native-label\">{f.label}{f.required && \" *\"}</span>\n <input\n className=\"xicms-input\"\n type={f.type}\n required={f.required}\n placeholder={f.placeholder}\n value={sv}\n onChange={(e) => setVal(f.name, e.target.value)}\n />\n </label>\n );\n }\n return (\n <TextInput key={f.name} label={f.label} type={f.type === \"email\" ? \"email\" : \"text\"}\n isRequired={f.required} placeholder={f.placeholder}\n value={sv} onChange={(v) => setVal(f.name, v)} />\n );\n })}\n {/* Honeypot — verborgen voor mensen, bots vullen 'm vaak wel in. */}\n <input\n type=\"text\"\n tabIndex={-1}\n autoComplete=\"off\"\n value={hp}\n onChange={(e) => setHp(e.target.value)}\n style={{ position: \"absolute\", left: \"-9999px\", width: 1, height: 1 }}\n aria-hidden\n />\n {error && <Text role=\"alert\" style={{ color: \"var(--color-error, #c0392b)\" }}>{error}</Text>}\n <div>\n <Button label={status === \"busy\" ? \"Versturen…\" : def.submitLabel} variant=\"primary\" size=\"lg\" type=\"submit\" isLoading={status === \"busy\"} />\n </div>\n </VStack>\n </form>\n );\n}\n"],"mappings":"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","names":[]}
@@ -1,23 +1 @@
1
- import type { z } from "zod";
2
- import type { GalleryBlockSchema } from "../../schema/blocks.js";
3
- type Gallery = z.infer<typeof GalleryBlockSchema>;
4
- type Item = Gallery["items"][number];
5
- /** Per-site instelbaar via `modules.gallery.config` (door de agent of in /beheer). */
6
- export interface GallerySettings {
7
- columns?: number;
8
- lightbox?: boolean;
9
- }
10
- /**
11
- * Eigen lightbox-overlay: rendert via een portal naar `document.body` (zo raakt geen enkele
12
- * ancestor-transform — bv. de scroll-reveal — de full-screen positionering). Sluit op klik náást
13
- * de foto én op Escape; vorige/volgende met teller; herstelt focus zónder de pagina te laten
14
- * verspringen (`preventScroll`) en zet de body-scroll vast zolang hij open is.
15
- */
16
- export declare function LightboxOverlay({ items, index, onIndex, onClose, }: {
17
- items: Item[];
18
- index: number;
19
- onIndex: (i: number) => void;
20
- onClose: () => void;
21
- }): import("react").ReactPortal | null;
22
- export declare const galleryBlock: import("../index.js").BlockDefinition<z.core.$ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>>;
23
- export {};
1
+ export declare const galleryBlock: import("../index.js").BlockDefinition<import("zod/v4/core").$ZodType<unknown, unknown, import("zod/v4/core").$ZodTypeInternals<unknown, unknown>>>;
@@ -1,175 +1,13 @@
1
- "use client";
2
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
- import { useCallback, useEffect, useRef, useState } from "react";
4
- import { createPortal } from "react-dom";
1
+ import dynamic from "next/dynamic";
5
2
  import { defineBlock } from "../registry.js";
6
- import { useModuleSettings } from "../../modules/context.js";
7
- import { Grid } from "../ui/index.js";
8
- import { Img } from "../../media/ImageContext.js";
9
- function LightboxOverlay({
10
- items,
11
- index,
12
- onIndex,
13
- onClose
14
- }) {
15
- const it = items[index];
16
- const total = items.length;
17
- const overlayRef = useRef(null);
18
- const prev = useCallback(() => onIndex((index - 1 + total) % total), [index, total, onIndex]);
19
- const next = useCallback(() => onIndex((index + 1) % total), [index, total, onIndex]);
20
- const swipeStart = useRef(null);
21
- const onPointerDown = (e) => {
22
- swipeStart.current = e.clientX;
23
- };
24
- const onPointerUp = (e) => {
25
- if (swipeStart.current === null || total < 2) return;
26
- const dx = e.clientX - swipeStart.current;
27
- swipeStart.current = null;
28
- if (dx > 40) prev();
29
- else if (dx < -40) next();
30
- };
31
- useEffect(() => {
32
- const onKey = (e) => {
33
- if (e.key === "Escape") onClose();
34
- else if (e.key === "ArrowLeft") prev();
35
- else if (e.key === "ArrowRight") next();
36
- else if (e.key === "Tab") {
37
- const el = overlayRef.current;
38
- const focusables = el ? [...el.querySelectorAll("button, a[href]")] : [];
39
- if (focusables.length === 0) return;
40
- const first = focusables[0];
41
- const last = focusables[focusables.length - 1];
42
- const active = document.activeElement;
43
- if (e.shiftKey && (active === first || !el?.contains(active))) {
44
- e.preventDefault();
45
- last.focus();
46
- } else if (!e.shiftKey && (active === last || !el?.contains(active))) {
47
- e.preventDefault();
48
- first.focus();
49
- }
50
- }
51
- };
52
- document.addEventListener("keydown", onKey);
53
- const prevOverflow = document.body.style.overflow;
54
- document.body.style.overflow = "hidden";
55
- overlayRef.current?.querySelector(".xicms-lightbox__close")?.focus({ preventScroll: true });
56
- return () => {
57
- document.removeEventListener("keydown", onKey);
58
- document.body.style.overflow = prevOverflow;
59
- };
60
- }, [onClose, prev, next]);
61
- if (typeof document === "undefined") return null;
62
- return createPortal(
63
- /* @__PURE__ */ jsxs(
64
- "div",
65
- {
66
- ref: overlayRef,
67
- className: "xicms-lightbox",
68
- role: "dialog",
69
- "aria-modal": "true",
70
- "aria-label": it.alt || it.caption || "Foto",
71
- onClick: onClose,
72
- children: [
73
- /* @__PURE__ */ jsx("button", { type: "button", className: "xicms-lightbox__close", "aria-label": "Sluiten", onClick: onClose, children: "\u2715" }),
74
- total > 1 && /* @__PURE__ */ jsxs(Fragment, { children: [
75
- /* @__PURE__ */ jsx("button", { type: "button", className: "xicms-lightbox__nav xicms-lightbox__nav--prev", "aria-label": "Vorige", onClick: (e) => {
76
- e.stopPropagation();
77
- prev();
78
- }, children: "\u2039" }),
79
- /* @__PURE__ */ jsx("button", { type: "button", className: "xicms-lightbox__nav xicms-lightbox__nav--next", "aria-label": "Volgende", onClick: (e) => {
80
- e.stopPropagation();
81
- next();
82
- }, children: "\u203A" }),
83
- /* @__PURE__ */ jsxs("span", { className: "xicms-lightbox__counter", children: [
84
- index + 1,
85
- " / ",
86
- total
87
- ] })
88
- ] }),
89
- /* @__PURE__ */ jsxs(
90
- "figure",
91
- {
92
- className: "xicms-lightbox__figure",
93
- onClick: (e) => e.stopPropagation(),
94
- onPointerDown,
95
- onPointerUp,
96
- style: { touchAction: "pan-y" },
97
- children: [
98
- /* @__PURE__ */ jsx("img", { src: it.url, alt: it.alt ?? "" }),
99
- it.caption && /* @__PURE__ */ jsx("figcaption", { children: it.caption })
100
- ]
101
- }
102
- )
103
- ]
104
- }
105
- ),
106
- document.body
107
- );
108
- }
109
- function GalleryRender({ block }) {
110
- const settings = useModuleSettings("gallery");
111
- const allItems = (block.items ?? []).map((it, _i) => ({ ...it, _i })).filter((i) => i.url);
112
- const [open, setOpen] = useState(false);
113
- const [index, setIndex] = useState(0);
114
- const [activeTag, setActiveTag] = useState(null);
115
- const triggerRef = useRef(null);
116
- const tags = block.showFilter ? [...new Set(allItems.map((i) => i.tag).filter((t) => Boolean(t)))] : [];
117
- const items = activeTag ? allItems.filter((i) => i.tag === activeTag) : allItems;
118
- if (allItems.length === 0) return null;
119
- const cols = block.columns && block.columns > 0 ? block.columns : settings.columns ?? 3;
120
- const lightbox = block.lightbox === "on" ? true : block.lightbox === "off" ? false : settings.lightbox ?? true;
121
- const ar = block.aspectRatio ?? "1/1";
122
- const imgStyle = {
123
- width: "100%",
124
- aspectRatio: ar === "auto" ? void 0 : ar.replace("/", " / "),
125
- objectFit: "cover",
126
- borderRadius: "var(--radius-element)",
127
- display: "block"
128
- };
129
- const close = () => {
130
- setOpen(false);
131
- triggerRef.current?.focus({ preventScroll: true });
132
- };
133
- return /* @__PURE__ */ jsxs("div", { className: "xicms-gallery", children: [
134
- tags.length > 0 && /* @__PURE__ */ jsxs("div", { className: "xicms-gallery__filter", role: "group", "aria-label": "Filter op categorie", children: [
135
- /* @__PURE__ */ jsx("button", { type: "button", className: "xicms-gallery__filterbtn", "aria-pressed": activeTag === null, "data-active": activeTag === null ? "1" : "0", onClick: () => {
136
- setActiveTag(null);
137
- setIndex(0);
138
- }, children: "Alles" }),
139
- tags.map((t) => /* @__PURE__ */ jsx("button", { type: "button", className: "xicms-gallery__filterbtn", "aria-pressed": activeTag === t, "data-active": activeTag === t ? "1" : "0", onClick: () => {
140
- setActiveTag(t);
141
- setIndex(0);
142
- }, children: t }, t))
143
- ] }),
144
- /* @__PURE__ */ jsx(Grid, { columns: { minWidth: 160, max: Math.min(cols, 6) }, gap: 2, children: items.map((i, idx) => /* @__PURE__ */ jsxs("figure", { style: { margin: 0 }, className: "xicms-gallery__item", children: [
145
- lightbox ? /* @__PURE__ */ jsx(
146
- "button",
147
- {
148
- type: "button",
149
- onClick: (e) => {
150
- triggerRef.current = e.currentTarget;
151
- setIndex(idx);
152
- setOpen(true);
153
- },
154
- "aria-label": i.alt || i.caption || `Foto ${idx + 1} vergroten`,
155
- style: { display: "block", width: "100%", padding: 0, border: 0, background: "none", cursor: "zoom-in" },
156
- children: /* @__PURE__ */ jsx(Img, { src: i.url, alt: i.alt ?? "", width: 600, height: 600, sizes: "(max-width: 640px) 50vw, 280px", style: imgStyle })
157
- }
158
- ) : /* @__PURE__ */ jsx(Img, { src: i.url, alt: i.alt ?? "", width: 600, height: 600, sizes: "(max-width: 640px) 50vw, 280px", style: imgStyle }),
159
- i.caption && /* @__PURE__ */ jsx("figcaption", { className: "xicms-gallery__caption", "data-xicms-edit": `items.${i._i}.caption`, style: { marginTop: "0.4rem", fontSize: "0.85rem", color: "var(--color-text-secondary)" }, children: i.caption })
160
- ] }, idx)) }),
161
- lightbox && open && /* @__PURE__ */ jsx(LightboxOverlay, { items, index, onIndex: setIndex, onClose: close })
162
- ] });
163
- }
164
3
  const galleryBlock = defineBlock({
165
4
  type: "gallery",
166
- Render: GalleryRender,
5
+ Render: dynamic(() => import("./GalleryRender.js").then((m) => m.GalleryRender)),
167
6
  label: "Galerij",
168
7
  icon: "\u{1F5BC}",
169
8
  defaults: () => ({ items: [], columns: 0, lightbox: "inherit", aspectRatio: "1/1" })
170
9
  });
171
10
  export {
172
- LightboxOverlay,
173
11
  galleryBlock
174
12
  };
175
13
  //# sourceMappingURL=Gallery.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/blocks/builtins/Gallery.tsx"],"sourcesContent":["\"use client\";\n\nimport { useCallback, useEffect, useRef, useState } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport type { z } from \"zod\";\nimport type { GalleryBlockSchema } from \"../../schema/blocks\";\nimport { defineBlock, type BlockRenderProps } from \"../registry\";\nimport { useModuleSettings } from \"../../modules/context\";\nimport { Grid } from \"../ui\";\nimport { Img } from \"../../media/ImageContext\";\n\ntype Gallery = z.infer<typeof GalleryBlockSchema>;\ntype Item = Gallery[\"items\"][number];\n\n/** Per-site instelbaar via `modules.gallery.config` (door de agent of in /beheer). */\nexport interface GallerySettings {\n columns?: number;\n lightbox?: boolean;\n}\n\n/**\n * Eigen lightbox-overlay: rendert via een portal naar `document.body` (zo raakt geen enkele\n * ancestor-transform — bv. de scroll-reveal — de full-screen positionering). Sluit op klik náást\n * de foto én op Escape; vorige/volgende met teller; herstelt focus zónder de pagina te laten\n * verspringen (`preventScroll`) en zet de body-scroll vast zolang hij open is.\n */\nexport function LightboxOverlay({\n items,\n index,\n onIndex,\n onClose,\n}: {\n items: Item[];\n index: number;\n onIndex: (i: number) => void;\n onClose: () => void;\n}) {\n const it = items[index];\n const total = items.length;\n const overlayRef = useRef<HTMLDivElement | null>(null);\n const prev = useCallback(() => onIndex((index - 1 + total) % total), [index, total, onIndex]);\n const next = useCallback(() => onIndex((index + 1) % total), [index, total, onIndex]);\n // Swipe (pointer events, werkt voor touch én muis-sleep): horizontaal > 40px = vorige/volgende.\n const swipeStart = useRef<number | null>(null);\n const onPointerDown = (e: React.PointerEvent) => {\n swipeStart.current = e.clientX;\n };\n const onPointerUp = (e: React.PointerEvent) => {\n if (swipeStart.current === null || total < 2) return;\n const dx = e.clientX - swipeStart.current;\n swipeStart.current = null;\n if (dx > 40) prev();\n else if (dx < -40) next();\n };\n\n useEffect(() => {\n const onKey = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") onClose();\n else if (e.key === \"ArrowLeft\") prev();\n else if (e.key === \"ArrowRight\") next();\n else if (e.key === \"Tab\") {\n // Focus-trap (aria-modal): Tab cirkelt binnen de dialog i.p.v. naar de pagina eronder.\n const el = overlayRef.current;\n const focusables = el ? [...el.querySelectorAll<HTMLElement>(\"button, a[href]\")] : [];\n if (focusables.length === 0) return;\n const first = focusables[0];\n const last = focusables[focusables.length - 1];\n const active = document.activeElement;\n if (e.shiftKey && (active === first || !el?.contains(active))) {\n e.preventDefault();\n last.focus();\n } else if (!e.shiftKey && (active === last || !el?.contains(active))) {\n e.preventDefault();\n first.focus();\n }\n }\n };\n document.addEventListener(\"keydown\", onKey);\n const prevOverflow = document.body.style.overflow;\n document.body.style.overflow = \"hidden\"; // scroll-lock terwijl open\n // Initiële focus in de dialog (dialog-conventie; toetsenbord/screenreader landt niet \"achter\" de overlay).\n overlayRef.current?.querySelector<HTMLElement>(\".xicms-lightbox__close\")?.focus({ preventScroll: true });\n return () => {\n document.removeEventListener(\"keydown\", onKey);\n document.body.style.overflow = prevOverflow;\n };\n }, [onClose, prev, next]);\n\n if (typeof document === \"undefined\") return null;\n return createPortal(\n <div\n ref={overlayRef}\n className=\"xicms-lightbox\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={it.alt || it.caption || \"Foto\"}\n onClick={onClose}\n >\n <button type=\"button\" className=\"xicms-lightbox__close\" aria-label=\"Sluiten\" onClick={onClose}>✕</button>\n {total > 1 && (\n <>\n <button type=\"button\" className=\"xicms-lightbox__nav xicms-lightbox__nav--prev\" aria-label=\"Vorige\" onClick={(e) => { e.stopPropagation(); prev(); }}>‹</button>\n <button type=\"button\" className=\"xicms-lightbox__nav xicms-lightbox__nav--next\" aria-label=\"Volgende\" onClick={(e) => { e.stopPropagation(); next(); }}>›</button>\n <span className=\"xicms-lightbox__counter\">{index + 1} / {total}</span>\n </>\n )}\n {/* Klik op de foto/onderschrift sluit NIET (stopPropagation); klik op de rand wel.\n touchAction pan-y: verticaal scrollen blijft van de browser, horizontaal is swipen. */}\n <figure\n className=\"xicms-lightbox__figure\"\n onClick={(e) => e.stopPropagation()}\n onPointerDown={onPointerDown}\n onPointerUp={onPointerUp}\n style={{ touchAction: \"pan-y\" }}\n >\n {/* eslint-disable-next-line @next/next/no-img-element */}\n <img src={it.url} alt={it.alt ?? \"\"} />\n {it.caption && <figcaption>{it.caption}</figcaption>}\n </figure>\n </div>,\n document.body,\n );\n}\n\n/** Galerij — responsive grid met instelbare beeldverhouding en optionele lightbox. */\nfunction GalleryRender({ block }: BlockRenderProps<Gallery>) {\n const settings = useModuleSettings<GallerySettings>(\"gallery\");\n // `_i` = de index in block.items (vóór url-/tagfilters): het inline-edit-pad\n // (`items.<_i>.caption`) moet naar het ORIGINELE array-item wijzen, niet naar de filterpositie.\n const allItems = (block.items ?? []).map((it, _i) => ({ ...it, _i })).filter((i) => i.url);\n const [open, setOpen] = useState(false);\n const [index, setIndex] = useState(0);\n const [activeTag, setActiveTag] = useState<string | null>(null);\n const triggerRef = useRef<HTMLButtonElement | null>(null);\n\n // Filterbalk op item-tags (opt-in): lightbox-navigatie volgt de gefilterde lijst.\n const tags = block.showFilter ? [...new Set(allItems.map((i) => i.tag).filter((t): t is string => Boolean(t)))] : [];\n const items = activeTag ? allItems.filter((i) => i.tag === activeTag) : allItems;\n\n if (allItems.length === 0) return null;\n\n const cols = block.columns && block.columns > 0 ? block.columns : settings.columns ?? 3;\n const lightbox =\n block.lightbox === \"on\" ? true : block.lightbox === \"off\" ? false : settings.lightbox ?? true;\n const ar = block.aspectRatio ?? \"1/1\";\n\n const imgStyle = {\n width: \"100%\",\n aspectRatio: ar === \"auto\" ? undefined : ar.replace(\"/\", \" / \"),\n objectFit: \"cover\" as const,\n borderRadius: \"var(--radius-element)\",\n display: \"block\",\n };\n\n const close = () => {\n setOpen(false);\n triggerRef.current?.focus({ preventScroll: true }); // geen page-jump bij sluiten\n };\n\n return (\n <div className=\"xicms-gallery\">\n {tags.length > 0 && (\n <div className=\"xicms-gallery__filter\" role=\"group\" aria-label=\"Filter op categorie\">\n <button type=\"button\" className=\"xicms-gallery__filterbtn\" aria-pressed={activeTag === null} data-active={activeTag === null ? \"1\" : \"0\"} onClick={() => { setActiveTag(null); setIndex(0); }}>\n Alles\n </button>\n {tags.map((t) => (\n <button key={t} type=\"button\" className=\"xicms-gallery__filterbtn\" aria-pressed={activeTag === t} data-active={activeTag === t ? \"1\" : \"0\"} onClick={() => { setActiveTag(t); setIndex(0); }}>\n {t}\n </button>\n ))}\n </div>\n )}\n <Grid columns={{ minWidth: 160, max: Math.min(cols, 6) }} gap={2}>\n {items.map((i, idx) => (\n <figure key={idx} style={{ margin: 0 }} className=\"xicms-gallery__item\">\n {lightbox ? (\n <button\n type=\"button\"\n onClick={(e) => { triggerRef.current = e.currentTarget; setIndex(idx); setOpen(true); }}\n aria-label={i.alt || i.caption || `Foto ${idx + 1} vergroten`}\n style={{ display: \"block\", width: \"100%\", padding: 0, border: 0, background: \"none\", cursor: \"zoom-in\" }}\n >\n <Img src={i.url as string} alt={i.alt ?? \"\"} width={600} height={600} sizes=\"(max-width: 640px) 50vw, 280px\" style={imgStyle} />\n </button>\n ) : (\n <Img src={i.url as string} alt={i.alt ?? \"\"} width={600} height={600} sizes=\"(max-width: 640px) 50vw, 280px\" style={imgStyle} />\n )}\n {i.caption && (\n <figcaption className=\"xicms-gallery__caption\" data-xicms-edit={`items.${i._i}.caption`} style={{ marginTop: \"0.4rem\", fontSize: \"0.85rem\", color: \"var(--color-text-secondary)\" }}>\n {i.caption}\n </figcaption>\n )}\n </figure>\n ))}\n </Grid>\n\n {lightbox && open && (\n <LightboxOverlay items={items} index={index} onIndex={setIndex} onClose={close} />\n )}\n </div>\n );\n}\n\nexport const galleryBlock = defineBlock({\n type: \"gallery\",\n Render: GalleryRender,\n label: \"Galerij\",\n icon: \"🖼\",\n defaults: () => ({ items: [], columns: 0, lightbox: \"inherit\", aspectRatio: \"1/1\" }),\n});\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../src/blocks/builtins/Gallery.tsx"],"sourcesContent":["import dynamic from \"next/dynamic\";\nimport { defineBlock } from \"../registry\";\n\nexport const galleryBlock = defineBlock({\n type: \"gallery\",\n Render: dynamic(() => import(\"./GalleryRender\").then((m) => m.GalleryRender)),\n label: \"Galerij\",\n icon: \"🖼\",\n defaults: () => ({ items: [], columns: 0, lightbox: \"inherit\", aspectRatio: \"1/1\" }),\n});\n"],"mappings":"AAAA,OAAO,aAAa;AACpB,SAAS,mBAAmB;AAErB,MAAM,eAAe,YAAY;AAAA,EACtC,MAAM;AAAA,EACN,QAAQ,QAAQ,MAAM,OAAO,iBAAiB,EAAE,KAAK,CAAC,MAAM,EAAE,aAAa,CAAC;AAAA,EAC5E,OAAO;AAAA,EACP,MAAM;AAAA,EACN,UAAU,OAAO,EAAE,OAAO,CAAC,GAAG,SAAS,GAAG,UAAU,WAAW,aAAa,MAAM;AACpF,CAAC;","names":[]}
@@ -0,0 +1,25 @@
1
+ import type { z } from "zod";
2
+ import type { GalleryBlockSchema } from "../../schema/blocks.js";
3
+ import type { BlockRenderProps } from "../registry.js";
4
+ type Gallery = z.infer<typeof GalleryBlockSchema>;
5
+ type Item = Gallery["items"][number];
6
+ /** Per-site instelbaar via `modules.gallery.config` (door de agent of in /beheer). */
7
+ export interface GallerySettings {
8
+ columns?: number;
9
+ lightbox?: boolean;
10
+ }
11
+ /**
12
+ * Eigen lightbox-overlay: rendert via een portal naar `document.body` (zo raakt geen enkele
13
+ * ancestor-transform — bv. de scroll-reveal — de full-screen positionering). Sluit op klik náást
14
+ * de foto én op Escape; vorige/volgende met teller; herstelt focus zónder de pagina te laten
15
+ * verspringen (`preventScroll`) en zet de body-scroll vast zolang hij open is.
16
+ */
17
+ export declare function LightboxOverlay({ items, index, onIndex, onClose, }: {
18
+ items: Item[];
19
+ index: number;
20
+ onIndex: (i: number) => void;
21
+ onClose: () => void;
22
+ }): import("react").ReactPortal | null;
23
+ /** Galerij — responsive grid met instelbare beeldverhouding en optionele lightbox. */
24
+ export declare function GalleryRender({ block }: BlockRenderProps<Gallery>): import("react").JSX.Element | null;
25
+ export {};