@xiwebdesign/xicms-core 7.30.0 → 8.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.
- package/dist/XiCMSProvider.js +22 -7
- package/dist/XiCMSProvider.js.map +1 -1
- package/dist/admin/AdminApp.js +175 -93
- package/dist/admin/AdminApp.js.map +1 -1
- package/dist/admin/AdminHelp.d.ts +1 -1
- package/dist/admin/AdminHelp.js +44 -36
- package/dist/admin/AdminHelp.js.map +1 -1
- package/dist/admin/CoreVersion.d.ts +6 -3
- package/dist/admin/CoreVersion.js +60 -24
- package/dist/admin/CoreVersion.js.map +1 -1
- package/dist/admin/NewsEditor.d.ts +7 -0
- package/dist/admin/NewsEditor.js +117 -75
- package/dist/admin/NewsEditor.js.map +1 -1
- package/dist/admin/SuperadminPanel.js +1 -1
- package/dist/admin/SuperadminPanel.js.map +1 -1
- package/dist/admin/ZoekPalet.d.ts +15 -0
- package/dist/admin/ZoekPalet.js +123 -0
- package/dist/admin/ZoekPalet.js.map +1 -0
- package/dist/admin/blockEditors/GenericEditor.js +36 -18
- package/dist/admin/blockEditors/GenericEditor.js.map +1 -1
- package/dist/admin/blockEditors/StyleEditor.js +37 -3
- package/dist/admin/blockEditors/StyleEditor.js.map +1 -1
- package/dist/admin/blockEditors/SymbolRefEditor.js +44 -2
- package/dist/admin/blockEditors/SymbolRefEditor.js.map +1 -1
- package/dist/admin/blockEditors/index.js +154 -73
- package/dist/admin/blockEditors/index.js.map +1 -1
- package/dist/admin/customBlocks/CustomBlocksPanel.js +18 -7
- package/dist/admin/customBlocks/CustomBlocksPanel.js.map +1 -1
- package/dist/admin/dashboard/DashboardPanel.js +26 -16
- package/dist/admin/dashboard/DashboardPanel.js.map +1 -1
- package/dist/admin/editors/RichTextEditor.d.ts +4 -3
- package/dist/admin/editors/RichTextEditor.js +19 -56
- package/dist/admin/editors/RichTextEditor.js.map +1 -1
- package/dist/admin/editors/fontSizeExtension.js +7 -1
- package/dist/admin/editors/fontSizeExtension.js.map +1 -1
- package/dist/admin/editors/slashMenu.d.ts +18 -0
- package/dist/admin/editors/slashMenu.js +34 -0
- package/dist/admin/editors/slashMenu.js.map +1 -0
- package/dist/admin/editors/useRijkeTekst.d.ts +48 -0
- package/dist/admin/editors/useRijkeTekst.js +310 -0
- package/dist/admin/editors/useRijkeTekst.js.map +1 -0
- package/dist/admin/forms/FormsPanel.d.ts +11 -2
- package/dist/admin/forms/FormsPanel.js +218 -65
- package/dist/admin/forms/FormsPanel.js.map +1 -1
- package/dist/admin/lib/blokInfo.d.ts +17 -0
- package/dist/admin/lib/blokInfo.js +80 -0
- package/dist/admin/lib/blokInfo.js.map +1 -0
- package/dist/admin/lib/foutNaarMens.d.ts +1 -0
- package/dist/admin/lib/foutNaarMens.js +22 -0
- package/dist/admin/lib/foutNaarMens.js.map +1 -0
- package/dist/admin/lib/gewisteVelden.d.ts +13 -0
- package/dist/admin/lib/gewisteVelden.js +31 -0
- package/dist/admin/lib/gewisteVelden.js.map +1 -0
- package/dist/admin/lib/heroHulp.d.ts +11 -0
- package/dist/admin/lib/heroHulp.js +18 -0
- package/dist/admin/lib/heroHulp.js.map +1 -0
- package/dist/admin/lib/kleur.js +2 -3
- package/dist/admin/lib/kleur.js.map +1 -1
- package/dist/admin/lib/leesbaarheid.d.ts +34 -0
- package/dist/admin/lib/leesbaarheid.js +82 -0
- package/dist/admin/lib/leesbaarheid.js.map +1 -0
- package/dist/admin/lib/lengteAdvies.d.ts +1 -0
- package/dist/admin/lib/lengteAdvies.js +16 -0
- package/dist/admin/lib/lengteAdvies.js.map +1 -0
- package/dist/admin/lib/mediaLijst.d.ts +26 -0
- package/dist/admin/lib/mediaLijst.js +42 -0
- package/dist/admin/lib/mediaLijst.js.map +1 -0
- package/dist/admin/lib/mediaUsage.d.ts +12 -1
- package/dist/admin/lib/mediaUsage.js +43 -33
- package/dist/admin/lib/mediaUsage.js.map +1 -1
- package/dist/admin/lib/menuHulp.d.ts +16 -0
- package/dist/admin/lib/menuHulp.js +41 -0
- package/dist/admin/lib/menuHulp.js.map +1 -0
- package/dist/admin/lib/onopgeslagen.d.ts +10 -0
- package/dist/admin/lib/onopgeslagen.js +35 -0
- package/dist/admin/lib/onopgeslagen.js.map +1 -0
- package/dist/admin/lib/pagesClient.d.ts +55 -2
- package/dist/admin/lib/pagesClient.js +126 -28
- package/dist/admin/lib/pagesClient.js.map +1 -1
- package/dist/admin/lib/paginaGebruik.d.ts +56 -0
- package/dist/admin/lib/paginaGebruik.js +109 -0
- package/dist/admin/lib/paginaGebruik.js.map +1 -0
- package/dist/admin/lib/publicatieCheck.d.ts +25 -0
- package/dist/admin/lib/publicatieCheck.js +114 -0
- package/dist/admin/lib/publicatieCheck.js.map +1 -0
- package/dist/admin/lib/scrollNaarDetail.d.ts +6 -0
- package/dist/admin/lib/scrollNaarDetail.js +20 -0
- package/dist/admin/lib/scrollNaarDetail.js.map +1 -0
- package/dist/admin/lib/symbolsClient.d.ts +10 -0
- package/dist/admin/lib/symbolsClient.js +14 -1
- package/dist/admin/lib/symbolsClient.js.map +1 -1
- package/dist/admin/lib/tekstVeld.d.ts +8 -0
- package/dist/admin/lib/tekstVeld.js +10 -0
- package/dist/admin/lib/tekstVeld.js.map +1 -0
- package/dist/admin/lib/useIsSuperadmin.d.ts +2 -0
- package/dist/admin/lib/useIsSuperadmin.js +13 -0
- package/dist/admin/lib/useIsSuperadmin.js.map +1 -0
- package/dist/admin/lib/veldTaal.d.ts +14 -0
- package/dist/admin/lib/veldTaal.js +247 -0
- package/dist/admin/lib/veldTaal.js.map +1 -0
- package/dist/admin/lib/versieVergelijk.d.ts +17 -0
- package/dist/admin/lib/versieVergelijk.js +24 -0
- package/dist/admin/lib/versieVergelijk.js.map +1 -0
- package/dist/admin/lib/zodFields.js +22 -4
- package/dist/admin/lib/zodFields.js.map +1 -1
- package/dist/admin/lib/zodFout.d.ts +9 -0
- package/dist/admin/lib/zodFout.js +63 -0
- package/dist/admin/lib/zodFout.js.map +1 -0
- package/dist/admin/media/MediaManager.js +162 -32
- package/dist/admin/media/MediaManager.js.map +1 -1
- package/dist/admin/media/MediaPicker.d.ts +3 -0
- package/dist/admin/media/MediaPicker.js +84 -31
- package/dist/admin/media/MediaPicker.js.map +1 -1
- package/dist/admin/menu/MenuPanel.js +144 -83
- package/dist/admin/menu/MenuPanel.js.map +1 -1
- package/dist/admin/navContext.d.ts +3 -0
- package/dist/admin/navContext.js +13 -1
- package/dist/admin/navContext.js.map +1 -1
- package/dist/admin/pages/PageEditor.js +146 -30
- package/dist/admin/pages/PageEditor.js.map +1 -1
- package/dist/admin/pages/PagesPanel.js +215 -61
- package/dist/admin/pages/PagesPanel.js.map +1 -1
- package/dist/admin/pages/StarterKiezer.d.ts +12 -0
- package/dist/admin/pages/StarterKiezer.js +113 -0
- package/dist/admin/pages/StarterKiezer.js.map +1 -0
- package/dist/admin/panelRegistry.d.ts +1 -1
- package/dist/admin/panelRegistry.js +2 -1
- package/dist/admin/panelRegistry.js.map +1 -1
- package/dist/admin/patterns/PatternInserter.js +1 -1
- package/dist/admin/patterns/PatternInserter.js.map +1 -1
- package/dist/admin/settings/BedrijfInstellingen.d.ts +20 -0
- package/dist/admin/settings/BedrijfInstellingen.js +144 -0
- package/dist/admin/settings/BedrijfInstellingen.js.map +1 -0
- package/dist/admin/settings/MailSettings.js +2 -2
- package/dist/admin/settings/MailSettings.js.map +1 -1
- package/dist/admin/settings/MailTemplates.js +5 -4
- package/dist/admin/settings/MailTemplates.js.map +1 -1
- package/dist/admin/settings/SettingsPanel.js +120 -78
- package/dist/admin/settings/SettingsPanel.js.map +1 -1
- package/dist/admin/settings/SnapshotsCard.js +4 -4
- package/dist/admin/settings/SnapshotsCard.js.map +1 -1
- package/dist/admin/settings/VorigeTerugzetten.d.ts +15 -0
- package/dist/admin/settings/VorigeTerugzetten.js +89 -0
- package/dist/admin/settings/VorigeTerugzetten.js.map +1 -0
- package/dist/admin/shop/CategoriesTab.js +6 -4
- package/dist/admin/shop/CategoriesTab.js.map +1 -1
- package/dist/admin/shop/DiscountsTab.js +4 -2
- package/dist/admin/shop/DiscountsTab.js.map +1 -1
- package/dist/admin/shop/OrdersTab.js +57 -19
- package/dist/admin/shop/OrdersTab.js.map +1 -1
- package/dist/admin/shop/ProductPaneel.js +2 -1
- package/dist/admin/shop/ProductPaneel.js.map +1 -1
- package/dist/admin/shop/ProductsTab.js +40 -19
- package/dist/admin/shop/ProductsTab.js.map +1 -1
- package/dist/admin/shop/ShopPanel.js +13 -1
- package/dist/admin/shop/ShopPanel.js.map +1 -1
- package/dist/admin/shop/ShopSettingsTab.js +27 -1
- package/dist/admin/shop/ShopSettingsTab.js.map +1 -1
- package/dist/admin/shop/productClient.js +7 -3
- package/dist/admin/shop/productClient.js.map +1 -1
- package/dist/admin/stats/NietGevonden.d.ts +10 -0
- package/dist/admin/stats/NietGevonden.js +78 -0
- package/dist/admin/stats/NietGevonden.js.map +1 -0
- package/dist/admin/stats/StatsPanel.js +6 -1
- package/dist/admin/stats/StatsPanel.js.map +1 -1
- package/dist/admin/stats/lib.d.ts +2 -0
- package/dist/admin/stats/lib.js.map +1 -1
- package/dist/admin/ui/ConfirmDialog.js +10 -1
- package/dist/admin/ui/ConfirmDialog.js.map +1 -1
- package/dist/admin/ui/Icon.d.ts +34 -0
- package/dist/admin/ui/Icon.js +44 -0
- package/dist/admin/ui/Icon.js.map +1 -0
- package/dist/admin/ui/ImageField.d.ts +15 -0
- package/dist/admin/ui/ImageField.js +67 -0
- package/dist/admin/ui/ImageField.js.map +1 -0
- package/dist/admin/ui/KleurVeld.d.ts +25 -0
- package/dist/admin/ui/KleurVeld.js +76 -0
- package/dist/admin/ui/KleurVeld.js.map +1 -0
- package/dist/admin/ui/LaadStaat.d.ts +21 -0
- package/dist/admin/ui/LaadStaat.js +43 -0
- package/dist/admin/ui/LaadStaat.js.map +1 -0
- package/dist/admin/ui/LeesbaarheidPaneel.d.ts +10 -0
- package/dist/admin/ui/LeesbaarheidPaneel.js +68 -0
- package/dist/admin/ui/LeesbaarheidPaneel.js.map +1 -0
- package/dist/admin/ui/LinkDialog.d.ts +22 -0
- package/dist/admin/ui/LinkDialog.js +131 -0
- package/dist/admin/ui/LinkDialog.js.map +1 -0
- package/dist/admin/ui/LinkVeld.d.ts +14 -0
- package/dist/admin/ui/LinkVeld.js +49 -0
- package/dist/admin/ui/LinkVeld.js.map +1 -0
- package/dist/admin/ui/PreviewLinkResultaat.d.ts +14 -0
- package/dist/admin/ui/PreviewLinkResultaat.js +52 -0
- package/dist/admin/ui/PreviewLinkResultaat.js.map +1 -0
- package/dist/admin/ui/charts.js +5 -5
- package/dist/admin/ui/charts.js.map +1 -1
- package/dist/admin/ui/primitives.d.ts +16 -6
- package/dist/admin/ui/primitives.js +98 -26
- package/dist/admin/ui/primitives.js.map +1 -1
- package/dist/admin/ui/select.js +5 -2
- package/dist/admin/ui/select.js.map +1 -1
- package/dist/admin/ui/switch.d.ts +3 -1
- package/dist/admin/ui/switch.js +6 -3
- package/dist/admin/ui/switch.js.map +1 -1
- package/dist/admin/ui/toast.d.ts +2 -1
- package/dist/admin/ui/toast.js +17 -11
- package/dist/admin/ui/toast.js.map +1 -1
- package/dist/admin/visual/BlokKiezer.d.ts +34 -0
- package/dist/admin/visual/BlokKiezer.js +225 -0
- package/dist/admin/visual/BlokKiezer.js.map +1 -0
- package/dist/admin/visual/InlineGereedschap.d.ts +52 -0
- package/dist/admin/visual/InlineGereedschap.js +356 -0
- package/dist/admin/visual/InlineGereedschap.js.map +1 -0
- package/dist/admin/visual/InlineRijkeTekst.d.ts +23 -0
- package/dist/admin/visual/InlineRijkeTekst.js +152 -0
- package/dist/admin/visual/InlineRijkeTekst.js.map +1 -0
- package/dist/admin/visual/VisualEditor.js +273 -125
- package/dist/admin/visual/VisualEditor.js.map +1 -1
- package/dist/admin.css +1 -1
- package/dist/bedrijf/bedrijf.d.ts +36 -0
- package/dist/bedrijf/bedrijf.js +110 -0
- package/dist/bedrijf/bedrijf.js.map +1 -0
- package/dist/blocks/BlockRenderer.js +11 -1
- package/dist/blocks/BlockRenderer.js.map +1 -1
- package/dist/blocks/blockStyle.d.ts +7 -0
- package/dist/blocks/blockStyle.js +16 -3
- package/dist/blocks/blockStyle.js.map +1 -1
- package/dist/blocks/builtinSchemas.js +6 -0
- package/dist/blocks/builtinSchemas.js.map +1 -1
- package/dist/blocks/builtins/AgendaRender.d.ts +22 -0
- package/dist/blocks/builtins/AgendaRender.js +69 -9
- package/dist/blocks/builtins/AgendaRender.js.map +1 -1
- package/dist/blocks/builtins/Availability.d.ts +1 -0
- package/dist/blocks/builtins/Availability.js +23 -0
- package/dist/blocks/builtins/Availability.js.map +1 -0
- package/dist/blocks/builtins/AvailabilityRender.d.ts +12 -0
- package/dist/blocks/builtins/AvailabilityRender.js +105 -0
- package/dist/blocks/builtins/AvailabilityRender.js.map +1 -0
- package/dist/blocks/builtins/BeforeAfterRender.js +4 -3
- package/dist/blocks/builtins/BeforeAfterRender.js.map +1 -1
- package/dist/blocks/builtins/Booking.js +1 -1
- package/dist/blocks/builtins/Booking.js.map +1 -1
- package/dist/blocks/builtins/BreadcrumbsRender.d.ts +4 -3
- package/dist/blocks/builtins/BreadcrumbsRender.js +14 -8
- package/dist/blocks/builtins/BreadcrumbsRender.js.map +1 -1
- package/dist/blocks/builtins/ColumnsRender.d.ts +1 -1
- package/dist/blocks/builtins/ColumnsRender.js +3 -1
- package/dist/blocks/builtins/ColumnsRender.js.map +1 -1
- package/dist/blocks/builtins/Contact.js +1 -1
- package/dist/blocks/builtins/Contact.js.map +1 -1
- package/dist/blocks/builtins/ContactRender.d.ts +1 -1
- package/dist/blocks/builtins/ContactRender.js +29 -8
- package/dist/blocks/builtins/ContactRender.js.map +1 -1
- package/dist/blocks/builtins/Cta.js +1 -1
- package/dist/blocks/builtins/Cta.js.map +1 -1
- package/dist/blocks/builtins/CtaRender.d.ts +1 -1
- package/dist/blocks/builtins/CtaRender.js +5 -4
- package/dist/blocks/builtins/CtaRender.js.map +1 -1
- package/dist/blocks/builtins/Embed.js +1 -1
- package/dist/blocks/builtins/Embed.js.map +1 -1
- package/dist/blocks/builtins/FormBlock.js +1 -0
- package/dist/blocks/builtins/FormBlock.js.map +1 -1
- package/dist/blocks/builtins/FormBlockRender.d.ts +6 -0
- package/dist/blocks/builtins/FormBlockRender.js +88 -16
- package/dist/blocks/builtins/FormBlockRender.js.map +1 -1
- package/dist/blocks/builtins/GalleryRender.js +3 -2
- package/dist/blocks/builtins/GalleryRender.js.map +1 -1
- package/dist/blocks/builtins/Hero.js +1 -1
- package/dist/blocks/builtins/Hero.js.map +1 -1
- package/dist/blocks/builtins/HeroRender.js +7 -3
- package/dist/blocks/builtins/HeroRender.js.map +1 -1
- package/dist/blocks/builtins/OpenNowBadge.d.ts +4 -2
- package/dist/blocks/builtins/OpenNowBadge.js +6 -6
- package/dist/blocks/builtins/OpenNowBadge.js.map +1 -1
- package/dist/blocks/builtins/OpeningHoursRender.d.ts +8 -2
- package/dist/blocks/builtins/OpeningHoursRender.js +27 -6
- package/dist/blocks/builtins/OpeningHoursRender.js.map +1 -1
- package/dist/blocks/builtins/PriceList.d.ts +1 -0
- package/dist/blocks/builtins/PriceList.js +25 -0
- package/dist/blocks/builtins/PriceList.js.map +1 -0
- package/dist/blocks/builtins/PriceListRender.d.ts +17 -0
- package/dist/blocks/builtins/PriceListRender.js +87 -0
- package/dist/blocks/builtins/PriceListRender.js.map +1 -0
- package/dist/blocks/builtins/RichTextBlockRender.js +6 -1
- package/dist/blocks/builtins/RichTextBlockRender.js.map +1 -1
- package/dist/blocks/builtins/SectionHeading.d.ts +1 -0
- package/dist/blocks/builtins/SectionHeading.js +14 -0
- package/dist/blocks/builtins/SectionHeading.js.map +1 -0
- package/dist/blocks/builtins/SectionHeadingRender.d.ts +7 -0
- package/dist/blocks/builtins/SectionHeadingRender.js +14 -0
- package/dist/blocks/builtins/SectionHeadingRender.js.map +1 -0
- package/dist/blocks/builtins/SliderRender.js +3 -2
- package/dist/blocks/builtins/SliderRender.js.map +1 -1
- package/dist/blocks/builtins/SymbolRef.js +1 -1
- package/dist/blocks/builtins/SymbolRef.js.map +1 -1
- package/dist/blocks/builtins/TeamRender.js +6 -1
- package/dist/blocks/builtins/TeamRender.js.map +1 -1
- package/dist/blocks/builtins/Testimonials.js +3 -1
- package/dist/blocks/builtins/Testimonials.js.map +1 -1
- package/dist/blocks/builtins/TestimonialsRender.js +4 -0
- package/dist/blocks/builtins/TestimonialsRender.js.map +1 -1
- package/dist/blocks/builtins/WhatsappChatRender.d.ts +1 -1
- package/dist/blocks/builtins/WhatsappChatRender.js +1 -1
- package/dist/blocks/builtins/WhatsappChatRender.js.map +1 -1
- package/dist/blocks/builtins/Widgets.js +2 -2
- package/dist/blocks/builtins/Widgets.js.map +1 -1
- package/dist/blocks/builtins/WidgetsRender.js +3 -1
- package/dist/blocks/builtins/WidgetsRender.js.map +1 -1
- package/dist/blocks/builtins/index.d.ts +3 -0
- package/dist/blocks/builtins/index.js +6 -0
- package/dist/blocks/builtins/index.js.map +1 -1
- package/dist/blocks/builtins/lib/autoComplete.d.ts +7 -0
- package/dist/blocks/builtins/lib/autoComplete.js +20 -0
- package/dist/blocks/builtins/lib/autoComplete.js.map +1 -0
- package/dist/blocks/builtins/lib/bookingUrl.d.ts +2 -2
- package/dist/blocks/builtins/lib/bookingUrl.js +1 -1
- package/dist/blocks/builtins/lib/bookingUrl.js.map +1 -1
- package/dist/blocks/builtins/lib/ical.d.ts +24 -0
- package/dist/blocks/builtins/lib/ical.js +82 -0
- package/dist/blocks/builtins/lib/ical.js.map +1 -0
- package/dist/blocks/builtins/lib/vandaag.d.ts +8 -0
- package/dist/blocks/builtins/lib/vandaag.js +22 -0
- package/dist/blocks/builtins/lib/vandaag.js.map +1 -0
- package/dist/blocks/registry.d.ts +6 -0
- package/dist/blocks/registry.js.map +1 -1
- package/dist/blocks/ui/index.js +1 -0
- package/dist/blocks/ui/index.js.map +1 -1
- package/dist/components/EditBar.js +2 -4
- package/dist/components/EditBar.js.map +1 -1
- package/dist/components/News.js +26 -18
- package/dist/components/News.js.map +1 -1
- package/dist/components/PageView.d.ts +7 -1
- package/dist/components/PageView.js +17 -0
- package/dist/components/PageView.js.map +1 -1
- package/dist/components/ResponsiveImage.js +18 -20
- package/dist/components/ResponsiveImage.js.map +1 -1
- package/dist/components/site/SiteFooter.d.ts +6 -1
- package/dist/components/site/SiteFooter.js +61 -9
- package/dist/components/site/SiteFooter.js.map +1 -1
- package/dist/components/site/SiteHeader.d.ts +15 -0
- package/dist/components/site/SiteHeader.js +70 -0
- package/dist/components/site/SiteHeader.js.map +1 -0
- package/dist/components/site/SiteNav.d.ts +2 -0
- package/dist/components/site/SiteNav.js +29 -5
- package/dist/components/site/SiteNav.js.map +1 -1
- package/dist/demo/DemoStudio.js +2 -2
- package/dist/demo/DemoStudio.js.map +1 -1
- package/dist/demo/demoStore.d.ts +13 -0
- package/dist/demo/demoStore.js +36 -0
- package/dist/demo/demoStore.js.map +1 -1
- package/dist/editor/EditorProvider.js +15 -4
- package/dist/editor/EditorProvider.js.map +1 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.js +16 -1
- package/dist/index.js.map +1 -1
- package/dist/media/ImageContext.d.ts +17 -0
- package/dist/media/ImageContext.js +65 -20
- package/dist/media/ImageContext.js.map +1 -1
- package/dist/media/altInHtml.d.ts +9 -0
- package/dist/media/altInHtml.js +17 -0
- package/dist/media/altInHtml.js.map +1 -0
- package/dist/media/srcset.d.ts +12 -0
- package/dist/media/srcset.js +13 -0
- package/dist/media/srcset.js.map +1 -0
- package/dist/modules/builtins.d.ts +1 -0
- package/dist/modules/builtins.js +16 -3
- package/dist/modules/builtins.js.map +1 -1
- package/dist/modules/shop/blocks/Cart.js +5 -3
- package/dist/modules/shop/blocks/Cart.js.map +1 -1
- package/dist/modules/shop/blocks/Checkout.js +56 -35
- package/dist/modules/shop/blocks/Checkout.js.map +1 -1
- package/dist/modules/shop/blocks/Donation.js +4 -4
- package/dist/modules/shop/blocks/Donation.js.map +1 -1
- package/dist/modules/shop/blocks/ProductDetail.js +19 -3
- package/dist/modules/shop/blocks/ProductDetail.js.map +1 -1
- package/dist/modules/shop/blocks/ProductGrid.d.ts +3 -1
- package/dist/modules/shop/blocks/ProductGrid.js +8 -4
- package/dist/modules/shop/blocks/ProductGrid.js.map +1 -1
- package/dist/modules/shop/blocks/ShopCategories.js +4 -3
- package/dist/modules/shop/blocks/ShopCategories.js.map +1 -1
- package/dist/modules/shop/lib.d.ts +4 -0
- package/dist/modules/shop/lib.js +14 -0
- package/dist/modules/shop/lib.js.map +1 -1
- package/dist/modules/shop/settings.d.ts +3 -0
- package/dist/modules/shop/settings.js +14 -0
- package/dist/modules/shop/settings.js.map +1 -1
- package/dist/modules/shop/strings.d.ts +4 -0
- package/dist/modules/shop/strings.js +8 -0
- package/dist/modules/shop/strings.js.map +1 -1
- package/dist/next/envCheck.d.ts +42 -0
- package/dist/next/envCheck.js +106 -0
- package/dist/next/envCheck.js.map +1 -0
- package/dist/next/index.cjs +185 -2
- package/dist/next/index.d.ts +2 -0
- package/dist/next/index.js +8 -1
- package/dist/next/index.js.map +1 -1
- package/dist/next/securityHeaders.d.ts +36 -0
- package/dist/next/securityHeaders.js +74 -0
- package/dist/next/securityHeaders.js.map +1 -0
- package/dist/patterns/builtins.d.ts +7 -0
- package/dist/patterns/builtins.js +138 -3
- package/dist/patterns/builtins.js.map +1 -1
- package/dist/releaseNotes.js +140 -0
- package/dist/releaseNotes.js.map +1 -1
- package/dist/render/PublishedPage.d.ts +2 -1
- package/dist/render/PublishedPage.js +10 -4
- package/dist/render/PublishedPage.js.map +1 -1
- package/dist/schema/blocks.d.ts +470 -0
- package/dist/schema/blocks.js +102 -4
- package/dist/schema/blocks.js.map +1 -1
- package/dist/schema/business.d.ts +117 -0
- package/dist/schema/business.js +73 -0
- package/dist/schema/business.js.map +1 -0
- package/dist/schema/fields.d.ts +2 -1
- package/dist/schema/fields.js.map +1 -1
- package/dist/schema/forms.d.ts +18 -0
- package/dist/schema/forms.js +18 -3
- package/dist/schema/forms.js.map +1 -1
- package/dist/schema/mail.d.ts +10 -0
- package/dist/schema/mail.js +7 -0
- package/dist/schema/mail.js.map +1 -1
- package/dist/schema/settings.d.ts +101 -0
- package/dist/schema/settings.js +24 -3
- package/dist/schema/settings.js.map +1 -1
- package/dist/schema/shop.d.ts +2 -0
- package/dist/schema/shop.js +4 -0
- package/dist/schema/shop.js.map +1 -1
- package/dist/schema/shopGeld.d.ts +1 -0
- package/dist/schema/shopGeld.js +1 -0
- package/dist/schema/shopGeld.js.map +1 -1
- package/dist/schema/siteConfig.d.ts +68 -1
- package/dist/schema/siteConfig.js +7 -2
- package/dist/schema/siteConfig.js.map +1 -1
- package/dist/server/blockData.d.ts +1 -1
- package/dist/server/blockData.js +74 -18
- package/dist/server/blockData.js.map +1 -1
- package/dist/server/cspRapport.d.ts +20 -0
- package/dist/server/cspRapport.js +56 -0
- package/dist/server/cspRapport.js.map +1 -0
- package/dist/server/fonts.d.ts +3 -0
- package/dist/server/fonts.js +39 -0
- package/dist/server/fonts.js.map +1 -0
- package/dist/server/index.d.ts +3 -0
- package/dist/server/index.js +8 -0
- package/dist/server/index.js.map +1 -1
- package/dist/server/sanitize.js +15 -2
- package/dist/server/sanitize.js.map +1 -1
- package/dist/settings/useSiteSettings.js +4 -1
- package/dist/settings/useSiteSettings.js.map +1 -1
- package/dist/starters/starters.d.ts +69 -0
- package/dist/starters/starters.js +171 -0
- package/dist/starters/starters.js.map +1 -0
- package/dist/styles.css +1149 -208
- package/dist/theme/color.d.ts +10 -0
- package/dist/theme/color.js +17 -1
- package/dist/theme/color.js.map +1 -1
- package/dist/theme/fontFallback.d.ts +23 -0
- package/dist/theme/fontFallback.js +58 -0
- package/dist/theme/fontFallback.js.map +1 -0
- package/dist/theme/fonts.d.ts +11 -0
- package/dist/theme/fonts.js +16 -0
- package/dist/theme/fonts.js.map +1 -0
- package/dist/version.js +1 -1
- package/package.json +6 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/demo/demoStore.ts"],"sourcesContent":["\"use client\";\n\nimport type { Page } from \"../schema/pages\";\nimport type { MediaItem, NewsArticle } from \"../content/types\";\nimport type { FormDefinition } from \"../schema/forms\";\n\n/**\n * Lokale opslag voor de DEMO-bewerkmodus (`config.demoEditing`). Alle \"bewerkingen\" van een\n * bezoeker (teksten, blokken, publiceren) blijven UITSLUITEND in de browser van die bezoeker\n * (localStorage) — er gaat niets naar Firebase. Zo kunnen eindgebruikers het beheer veilig\n * uitproberen zonder dat er echt iets verandert. Een \"Reset\" wist alles weer.\n *\n * Bewust GEEN onderdeel van de echte (Firebase-)opslag: pagesClient en AuthProvider takken hier\n * alleen naartoe als de demo-modus actief is, en die staat alleen aan op een demo-site.\n */\n\nconst DRAFT_PREFIX = \"xicms-demo-draft\";\nconst MEDIA_PREFIX = \"xicms-demo-media\";\nconst SESSION_KEY = \"xicms-demo-session\";\nexport const DEMO_EVENT = \"xicms:demo\";\n\nlet active = false;\nconst seeds = new Map<string, Page>();\nconst newsSeeds = new Map<string, NewsArticle[]>();\nconst formSeeds = new Map<string, FormDefinition>();\nconst mediaSeeds = new Map<string, MediaItem[]>();\n\n/** Zet de demo-bewerkmodus aan/uit (door de provider, op basis van config.demoEditing). */\nexport function setDemoActive(on: boolean) {\n active = on;\n}\nexport function isDemoActive(): boolean {\n return active;\n}\n\n/** Stabiel, deterministisch draft-id per pad, zodat pagina + editor naar dezelfde opslag wijzen. */\nexport function demoIdForPath(path: string): string {\n return `demo:${path || \"/\"}`;\n}\n\n/** De omkering: uit een demo-draft-id het pad terug. `null` voor een niet-demo-id. */\nexport function demoPathForId(id: string): string | null {\n return id.startsWith(\"demo:\") ? id.slice(\"demo:\".length) : null;\n}\n\nfunction emit() {\n if (typeof window !== \"undefined\") window.dispatchEvent(new Event(DEMO_EVENT));\n}\n\n// ── Pseudo-login (sessie) ──────────────────────────────────────────────────\n// In sessionStorage: verdwijnt als het tabblad sluit — benadrukt het tijdelijke karakter.\nexport function isDemoLoggedIn(): boolean {\n if (typeof window === \"undefined\") return false;\n try {\n return window.sessionStorage.getItem(SESSION_KEY) === \"1\";\n } catch {\n return false;\n }\n}\nexport function setDemoLoggedIn(on: boolean) {\n if (typeof window === \"undefined\") return;\n try {\n if (on) window.sessionStorage.setItem(SESSION_KEY, \"1\");\n else window.sessionStorage.removeItem(SESSION_KEY);\n } catch {\n /* opslag geweigerd — login geldt dan alleen voor deze render */\n }\n emit();\n}\n\n// ── Seed-pagina's (de oorspronkelijke inhoud waar een bezoeker op verder bewerkt) ──\n/**\n * De EERSTE registratie wint. Een seed is per definitie het origineel, en het origineel verandert\n * niet tijdens een sessie. Zonder deze regel vervuilde de seed zichzelf: een demo-route registreert\n * bij module-load de zuivere pagina, maar `PublishedPage` registreert in een effect de pagina die\n * hij TOONT — en dat is in de demo seed+draft. De bewerkte tekst werd zo het \"origineel\", waarmee\n * de wijzigingen-teller schoon leek en \"blok verwerpen\" terugzette naar precies de tekst die je\n * wilde verwerpen. (De seeds leven in het geheugen van één pageload, dus \"eerste\" is per bezoek.)\n */\nexport function registerSeed(siteId: string, path: string, page: Page) {\n const key = `${siteId}::${path}`;\n if (!seeds.has(key)) seeds.set(key, page);\n}\nexport function getSeed(siteId: string, path: string): Page | null {\n return seeds.get(`${siteId}::${path}`) ?? null;\n}\n\n// ── Demo-nieuws (zodat nieuws-blokken/widgets ook in de demo gevuld zijn, zonder Firebase) ──\nexport function registerDemoNews(siteId: string, articles: NewsArticle[]) {\n newsSeeds.set(siteId, articles);\n}\nexport function getDemoNews(siteId: string): NewsArticle[] {\n return newsSeeds.get(siteId) ?? [];\n}\n\n// ── Demo-formulieren (zodat het form-blok werkt zonder Firebase; inzenden doet lokaal niets) ──\nexport function registerDemoForm(siteId: string, formId: string, def: FormDefinition) {\n formSeeds.set(`${siteId}::${formId}`, def);\n}\nexport function getDemoForm(siteId: string, formId: string): FormDefinition | null {\n return formSeeds.get(`${siteId}::${formId}`) ?? null;\n}\n\n// ── Demo-media (bibliotheek + upload zonder Firebase) ─────────────────────\n// Geseede items (bv. de foto's van de demo-site zelf) + lokale \"uploads\" als data-URL in\n// localStorage. Zo werken kiezen, uploaden en vervangen in de demo écht — alles blijft lokaal.\n\n/** Seed de mediabibliotheek van de demo (curated set; alt = zoektekst in de kiezer). */\nexport function registerDemoMedia(siteId: string, items: Array<Pick<MediaItem, \"url\" | \"name\" | \"alt\">>) {\n mediaSeeds.set(\n siteId,\n items.map((m, i) => ({ id: `demo-seed-${i}`, url: m.url, path: \"demo\", name: m.name, alt: m.alt ?? \"\" })),\n );\n}\n\nfunction mediaKey(siteId: string) {\n return `${MEDIA_PREFIX}:${siteId}`;\n}\n\nfunction loadLocalDemoMedia(siteId: string): MediaItem[] {\n if (typeof window === \"undefined\") return [];\n try {\n const raw = window.localStorage.getItem(mediaKey(siteId));\n return raw ? (JSON.parse(raw) as MediaItem[]) : [];\n } catch {\n return [];\n }\n}\n\n/** Bibliotheek in demo-modus: lokale uploads (nieuwste eerst) + de geseede set. */\nexport function listDemoMedia(siteId: string): MediaItem[] {\n return [...loadLocalDemoMedia(siteId), ...(mediaSeeds.get(siteId) ?? [])];\n}\n\n/**\n * \"Upload\" in demo-modus: bewaar de (gecomprimeerde) afbeelding als data-URL in localStorage.\n * localStorage is beperkt (~5 MB) — we houden maximaal 10 lokale uploads aan en laten bij een\n * volle opslag het item alleen voor deze sessie in het geheugen bestaan (zelfde vangnet als drafts).\n */\nconst memoryOnlyMedia = new Map<string, MediaItem[]>();\nexport function addDemoMedia(siteId: string, item: { url: string; name: string }): MediaItem {\n const media: MediaItem = {\n id: `demo-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,\n url: item.url,\n path: \"demo\",\n name: item.name,\n alt: \"\",\n };\n const next = [media, ...loadLocalDemoMedia(siteId)].slice(0, 10);\n try {\n window.localStorage.setItem(mediaKey(siteId), JSON.stringify(next));\n } catch {\n memoryOnlyMedia.set(siteId, [media, ...(memoryOnlyMedia.get(siteId) ?? [])]);\n }\n emit();\n return media;\n}\n\n/** Inclusief geheugen-only items (opslag-vol-vangnet) — gebruikt door de kiezer. */\nexport function listDemoMediaAll(siteId: string): MediaItem[] {\n return [...(memoryOnlyMedia.get(siteId) ?? []), ...listDemoMedia(siteId)];\n}\n\n// ── Lokale drafts (de bewerkingen) ─────────────────────────────────────────\nfunction draftKey(siteId: string, id: string) {\n return `${DRAFT_PREFIX}:${siteId}:${id}`;\n}\n\nexport function loadDemoDraft(siteId: string, id: string): Partial<Page> | null {\n if (typeof window === \"undefined\") return null;\n try {\n const raw = window.localStorage.getItem(draftKey(siteId, id));\n return raw ? (JSON.parse(raw) as Partial<Page>) : null;\n } catch {\n return null;\n }\n}\n\nexport function saveDemoDraft(siteId: string, id: string, patch: Partial<Page>) {\n if (typeof window === \"undefined\") return;\n try {\n const current = loadDemoDraft(siteId, id) ?? {};\n window.localStorage.setItem(draftKey(siteId, id), JSON.stringify({ ...current, ...patch }));\n } catch {\n /* opslag vol/geweigerd — bewerking geldt dan alleen voor deze sessie in het geheugen */\n }\n emit();\n}\n\n/** Verwijdert alle lokale demo-bewerkingen + login voor deze site (de \"Reset\"-knop). */\nexport function resetDemo(siteId: string) {\n if (typeof window === \"undefined\") return;\n try {\n const toRemove: string[] = [];\n for (let i = 0; i < window.localStorage.length; i++) {\n const k = window.localStorage.key(i);\n if (k && k.startsWith(`${DRAFT_PREFIX}:${siteId}:`)) toRemove.push(k);\n }\n toRemove.forEach((k) => window.localStorage.removeItem(k));\n window.localStorage.removeItem(mediaKey(siteId));\n memoryOnlyMedia.delete(siteId);\n window.sessionStorage.removeItem(SESSION_KEY);\n } catch {\n /* negeren */\n }\n emit();\n}\n\n/**\n * De effectieve demo-pagina = seed met lokale bewerkingen eroverheen. Gebruikt door de demo-pagina\n * om de wijzigingen van de bezoeker direct te tonen (ook na sluiten van de editor).\n */\nexport function resolveDemoPage(siteId: string, path: string): Page | null {\n const seed = getSeed(siteId, path);\n if (!seed) return null;\n const draft = loadDemoDraft(siteId, demoIdForPath(path));\n return draft ? ({ ...seed, ...draft } as Page) : seed;\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/demo/demoStore.ts"],"sourcesContent":["\"use client\";\n\nimport type { Page } from \"../schema/pages\";\nimport type { MediaItem, NewsArticle } from \"../content/types\";\nimport type { FormDefinition } from \"../schema/forms\";\n\n/**\n * Lokale opslag voor de DEMO-bewerkmodus (`config.demoEditing`). Alle \"bewerkingen\" van een\n * bezoeker (teksten, blokken, publiceren) blijven UITSLUITEND in de browser van die bezoeker\n * (localStorage) — er gaat niets naar Firebase. Zo kunnen eindgebruikers het beheer veilig\n * uitproberen zonder dat er echt iets verandert. Een \"Reset\" wist alles weer.\n *\n * Bewust GEEN onderdeel van de echte (Firebase-)opslag: pagesClient en AuthProvider takken hier\n * alleen naartoe als de demo-modus actief is, en die staat alleen aan op een demo-site.\n */\n\nconst DRAFT_PREFIX = \"xicms-demo-draft\";\nconst MEDIA_PREFIX = \"xicms-demo-media\";\nconst SESSION_KEY = \"xicms-demo-session\";\nexport const DEMO_EVENT = \"xicms:demo\";\n\nlet active = false;\nconst seeds = new Map<string, Page>();\nconst newsSeeds = new Map<string, NewsArticle[]>();\nconst formSeeds = new Map<string, FormDefinition>();\nconst mediaSeeds = new Map<string, MediaItem[]>();\n\n/** Zet de demo-bewerkmodus aan/uit (door de provider, op basis van config.demoEditing). */\nexport function setDemoActive(on: boolean) {\n active = on;\n}\nexport function isDemoActive(): boolean {\n return active;\n}\n\n/** Stabiel, deterministisch draft-id per pad, zodat pagina + editor naar dezelfde opslag wijzen. */\nexport function demoIdForPath(path: string): string {\n return `demo:${path || \"/\"}`;\n}\n\n/** De omkering: uit een demo-draft-id het pad terug. `null` voor een niet-demo-id. */\nexport function demoPathForId(id: string): string | null {\n return id.startsWith(\"demo:\") ? id.slice(\"demo:\".length) : null;\n}\n\nfunction emit() {\n if (typeof window !== \"undefined\") window.dispatchEvent(new Event(DEMO_EVENT));\n}\n\n// ── Pseudo-login (sessie) ──────────────────────────────────────────────────\n// In sessionStorage: verdwijnt als het tabblad sluit — benadrukt het tijdelijke karakter.\nexport function isDemoLoggedIn(): boolean {\n if (typeof window === \"undefined\") return false;\n try {\n return window.sessionStorage.getItem(SESSION_KEY) === \"1\";\n } catch {\n return false;\n }\n}\nexport function setDemoLoggedIn(on: boolean) {\n if (typeof window === \"undefined\") return;\n try {\n if (on) window.sessionStorage.setItem(SESSION_KEY, \"1\");\n else window.sessionStorage.removeItem(SESSION_KEY);\n } catch {\n /* opslag geweigerd — login geldt dan alleen voor deze render */\n }\n emit();\n}\n\n// ── Seed-pagina's (de oorspronkelijke inhoud waar een bezoeker op verder bewerkt) ──\n/**\n * De EERSTE registratie wint. Een seed is per definitie het origineel, en het origineel verandert\n * niet tijdens een sessie. Zonder deze regel vervuilde de seed zichzelf: een demo-route registreert\n * bij module-load de zuivere pagina, maar `PublishedPage` registreert in een effect de pagina die\n * hij TOONT — en dat is in de demo seed+draft. De bewerkte tekst werd zo het \"origineel\", waarmee\n * de wijzigingen-teller schoon leek en \"blok verwerpen\" terugzette naar precies de tekst die je\n * wilde verwerpen. (De seeds leven in het geheugen van één pageload, dus \"eerste\" is per bezoek.)\n */\nexport function registerSeed(siteId: string, path: string, page: Page) {\n const key = `${siteId}::${path}`;\n if (!seeds.has(key)) seeds.set(key, page);\n}\nexport function getSeed(siteId: string, path: string): Page | null {\n return seeds.get(`${siteId}::${path}`) ?? null;\n}\n\n// ── Demo-nieuws (zodat nieuws-blokken/widgets ook in de demo gevuld zijn, zonder Firebase) ──\nexport function registerDemoNews(siteId: string, articles: NewsArticle[]) {\n newsSeeds.set(siteId, articles);\n}\nexport function getDemoNews(siteId: string): NewsArticle[] {\n return newsSeeds.get(siteId) ?? [];\n}\n\n// ── Demo-formulieren (zodat het form-blok werkt zonder Firebase; inzenden doet lokaal niets) ──\nexport function registerDemoForm(siteId: string, formId: string, def: FormDefinition) {\n formSeeds.set(`${siteId}::${formId}`, def);\n}\nexport function getDemoForm(siteId: string, formId: string): FormDefinition | null {\n return formSeeds.get(`${siteId}::${formId}`) ?? null;\n}\n\n// ── Demo-media (bibliotheek + upload zonder Firebase) ─────────────────────\n// Geseede items (bv. de foto's van de demo-site zelf) + lokale \"uploads\" als data-URL in\n// localStorage. Zo werken kiezen, uploaden en vervangen in de demo écht — alles blijft lokaal.\n\n/** Seed de mediabibliotheek van de demo (curated set; alt = zoektekst in de kiezer). */\nexport function registerDemoMedia(siteId: string, items: Array<Pick<MediaItem, \"url\" | \"name\" | \"alt\">>) {\n mediaSeeds.set(\n siteId,\n items.map((m, i) => ({ id: `demo-seed-${i}`, url: m.url, path: \"demo\", name: m.name, alt: m.alt ?? \"\" })),\n );\n}\n\nfunction mediaKey(siteId: string) {\n return `${MEDIA_PREFIX}:${siteId}`;\n}\n\nfunction loadLocalDemoMedia(siteId: string): MediaItem[] {\n if (typeof window === \"undefined\") return [];\n try {\n const raw = window.localStorage.getItem(mediaKey(siteId));\n return raw ? (JSON.parse(raw) as MediaItem[]) : [];\n } catch {\n return [];\n }\n}\n\n/** Bibliotheek in demo-modus: lokale uploads (nieuwste eerst) + de geseede set. */\nexport function listDemoMedia(siteId: string): MediaItem[] {\n return [...loadLocalDemoMedia(siteId), ...(mediaSeeds.get(siteId) ?? [])];\n}\n\n/**\n * \"Upload\" in demo-modus: bewaar de (gecomprimeerde) afbeelding als data-URL in localStorage.\n * localStorage is beperkt (~5 MB) — we houden maximaal 10 lokale uploads aan en laten bij een\n * volle opslag het item alleen voor deze sessie in het geheugen bestaan (zelfde vangnet als drafts).\n */\nconst memoryOnlyMedia = new Map<string, MediaItem[]>();\nexport function addDemoMedia(siteId: string, item: { url: string; name: string }): MediaItem {\n const media: MediaItem = {\n id: `demo-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,\n url: item.url,\n path: \"demo\",\n name: item.name,\n alt: \"\",\n };\n const next = [media, ...loadLocalDemoMedia(siteId)].slice(0, 10);\n try {\n window.localStorage.setItem(mediaKey(siteId), JSON.stringify(next));\n } catch {\n memoryOnlyMedia.set(siteId, [media, ...(memoryOnlyMedia.get(siteId) ?? [])]);\n }\n emit();\n return media;\n}\n\n/**\n * Verwijderen in demo-modus (8.5): lokale uploads echt weg; een geseed item wordt alleen voor\n * deze sessie verborgen (de seed komt bij herladen terug, zoals de rest van de demo).\n */\nexport function removeDemoMedia(siteId: string, id: string) {\n const lokaal = loadLocalDemoMedia(siteId);\n if (lokaal.some((m) => m.id === id)) {\n try {\n window.localStorage.setItem(mediaKey(siteId), JSON.stringify(lokaal.filter((m) => m.id !== id)));\n } catch {\n /* opslag niet beschikbaar */\n }\n }\n memoryOnlyMedia.set(siteId, (memoryOnlyMedia.get(siteId) ?? []).filter((m) => m.id !== id));\n mediaSeeds.set(siteId, (mediaSeeds.get(siteId) ?? []).filter((m) => m.id !== id));\n emit();\n}\n\n/** Inclusief geheugen-only items (opslag-vol-vangnet) — gebruikt door de kiezer. */\nexport function listDemoMediaAll(siteId: string): MediaItem[] {\n return [...(memoryOnlyMedia.get(siteId) ?? []), ...listDemoMedia(siteId)];\n}\n\n// ── Lokale drafts (de bewerkingen) ─────────────────────────────────────────\nfunction draftKey(siteId: string, id: string) {\n return `${DRAFT_PREFIX}:${siteId}:${id}`;\n}\n\nexport function loadDemoDraft(siteId: string, id: string): Partial<Page> | null {\n if (typeof window === \"undefined\") return null;\n try {\n const raw = window.localStorage.getItem(draftKey(siteId, id));\n return raw ? (JSON.parse(raw) as Partial<Page>) : null;\n } catch {\n return null;\n }\n}\n\nexport function saveDemoDraft(siteId: string, id: string, patch: Partial<Page>) {\n if (typeof window === \"undefined\") return;\n try {\n const current = loadDemoDraft(siteId, id) ?? {};\n window.localStorage.setItem(draftKey(siteId, id), JSON.stringify({ ...current, ...patch }));\n } catch {\n /* opslag vol/geweigerd — bewerking geldt dan alleen voor deze sessie in het geheugen */\n }\n emit();\n}\n\n/**\n * Alle pagina's die de demo kent (8.6): geseede pagina's plus lokaal aangemaakte/bewerkte, met de\n * lokale bewerking eroverheen. Voor het paginaoverzicht in het beheer — dat wachtte eerst op een\n * rechtenfout van de echte database en toonde dan niets.\n */\nexport function listDemoPages(siteId: string): Array<Page & { id: string }> {\n const paden = new Set<string>();\n for (const k of seeds.keys()) if (k.startsWith(`${siteId}::`)) paden.add(k.slice(siteId.length + 2));\n if (typeof window !== \"undefined\") {\n try {\n const prefix = `${DRAFT_PREFIX}:${siteId}:`;\n for (let i = 0; i < window.localStorage.length; i++) {\n const k = window.localStorage.key(i);\n const pad = k?.startsWith(prefix) ? demoPathForId(k.slice(prefix.length)) : null;\n if (pad) paden.add(pad);\n }\n } catch {\n /* opslag geweigerd */\n }\n }\n const lijst: Array<Page & { id: string }> = [];\n for (const pad of paden) {\n const id = demoIdForPath(pad);\n const page = (resolveDemoPage(siteId, pad) ?? loadDemoDraft(siteId, id)) as Page | null;\n if (page) lijst.push({ ...page, path: page.path ?? pad, id });\n }\n return lijst.sort((a, b) => (a.path === \"/\" ? -1 : b.path === \"/\" ? 1 : (a.order ?? 0) - (b.order ?? 0)));\n}\n\n/** Verwijdert alle lokale demo-bewerkingen + login voor deze site (de \"Reset\"-knop). */\nexport function resetDemo(siteId: string) {\n if (typeof window === \"undefined\") return;\n try {\n const toRemove: string[] = [];\n for (let i = 0; i < window.localStorage.length; i++) {\n const k = window.localStorage.key(i);\n if (k && k.startsWith(`${DRAFT_PREFIX}:${siteId}:`)) toRemove.push(k);\n }\n toRemove.forEach((k) => window.localStorage.removeItem(k));\n window.localStorage.removeItem(mediaKey(siteId));\n memoryOnlyMedia.delete(siteId);\n window.sessionStorage.removeItem(SESSION_KEY);\n } catch {\n /* negeren */\n }\n emit();\n}\n\n/**\n * De effectieve demo-pagina = seed met lokale bewerkingen eroverheen. Gebruikt door de demo-pagina\n * om de wijzigingen van de bezoeker direct te tonen (ook na sluiten van de editor).\n */\nexport function resolveDemoPage(siteId: string, path: string): Page | null {\n const seed = getSeed(siteId, path);\n if (!seed) return null;\n const draft = loadDemoDraft(siteId, demoIdForPath(path));\n return draft ? ({ ...seed, ...draft } as Page) : seed;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { createContext, useCallback, useContext, useEffect, useMemo, useState } from "react";
|
|
4
4
|
let visualEditorModule = null;
|
|
5
5
|
const OPSLAGSLEUTEL = "xicms-bewerkmodus";
|
|
@@ -26,6 +26,8 @@ const Ctx = createContext({
|
|
|
26
26
|
function EditorProvider({ children }) {
|
|
27
27
|
const [modus, setModusState] = useState("live");
|
|
28
28
|
const [VisualEditor, setVisualEditor] = useState(() => visualEditorModule);
|
|
29
|
+
const [laadFout, setLaadFout] = useState(false);
|
|
30
|
+
const [laadPoging, setLaadPoging] = useState(0);
|
|
29
31
|
const [draft, setDraft] = useState(null);
|
|
30
32
|
const [publishedOverride, setPublishedOverride] = useState(null);
|
|
31
33
|
const [fotoVervanger, setFotoVervanger] = useState(null);
|
|
@@ -41,14 +43,18 @@ function EditorProvider({ children }) {
|
|
|
41
43
|
useEffect(() => {
|
|
42
44
|
if (modus !== "bewerken" || VisualEditor) return;
|
|
43
45
|
let losgekoppeld = false;
|
|
44
|
-
|
|
46
|
+
setLaadFout(false);
|
|
47
|
+
import("../admin/visual/VisualEditor.js").then((m) => {
|
|
45
48
|
visualEditorModule = m.default;
|
|
46
49
|
if (!losgekoppeld) setVisualEditor(() => m.default);
|
|
50
|
+
}).catch((e) => {
|
|
51
|
+
console.error("[xicms] editor laden mislukt:", e);
|
|
52
|
+
if (!losgekoppeld) setLaadFout(true);
|
|
47
53
|
});
|
|
48
54
|
return () => {
|
|
49
55
|
losgekoppeld = true;
|
|
50
56
|
};
|
|
51
|
-
}, [modus, VisualEditor]);
|
|
57
|
+
}, [modus, VisualEditor, laadPoging]);
|
|
52
58
|
const zetModus = useCallback((next) => {
|
|
53
59
|
setModusState(next);
|
|
54
60
|
try {
|
|
@@ -80,7 +86,12 @@ function EditorProvider({ children }) {
|
|
|
80
86
|
}), [modus, draft, zetModus, publishDraft, publishedOverride, bevestigPublicatie, fotoVervanger, zetFotoVervanger]);
|
|
81
87
|
return /* @__PURE__ */ jsxs(Ctx.Provider, { value, children: [
|
|
82
88
|
children,
|
|
83
|
-
modus === "bewerken" && VisualEditor && /* @__PURE__ */ jsx(VisualEditor, { onClose: () => zetModus("live") })
|
|
89
|
+
modus === "bewerken" && VisualEditor && /* @__PURE__ */ jsx(VisualEditor, { onClose: () => zetModus("live") }),
|
|
90
|
+
modus === "bewerken" && !VisualEditor && /* @__PURE__ */ jsx("div", { className: "xicms-editor-laden", role: laadFout ? "alert" : "status", "aria-live": "polite", "data-xicms-tooling": "", children: laadFout ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
91
|
+
/* @__PURE__ */ jsx("span", { children: "De editor kon niet geladen worden." }),
|
|
92
|
+
/* @__PURE__ */ jsx("button", { type: "button", onClick: () => setLaadPoging((n) => n + 1), children: "Opnieuw proberen" }),
|
|
93
|
+
/* @__PURE__ */ jsx("button", { type: "button", onClick: () => zetModus("live"), children: "Sluiten" })
|
|
94
|
+
] }) : /* @__PURE__ */ jsx("span", { children: "Editor laden\u2026" }) })
|
|
84
95
|
] });
|
|
85
96
|
}
|
|
86
97
|
function useEditor() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/editor/EditorProvider.tsx"],"sourcesContent":["\"use client\";\n\nimport { createContext, useCallback, useContext, useEffect, useMemo, useState, type ComponentType, type ReactNode } from \"react\";\n// Het bloktype van de PAGINA zelf, zodat wat hier langskomt per definitie past in wat\n// `PublishedPage` rendert. Een eigen definitie zou hier stil uit de pas kunnen lopen.\nimport type { Page } from \"../schema/pages\";\n\ntype PaginaBlokken = Page[\"blocks\"];\n\n/**\n * Lichte runtime-context voor het inline (visuele) bewerken op de live pagina. De echte editor\n * (TipTap/Radix, zwaar) wordt PAS geladen als een editor hem opent — publieke bezoekers downloaden\n * hem nooit. De editor leeft in de admin-entry; we laden 'm via een dynamische import (eigen chunk).\n *\n * ── WAAROM DE BLOKKEN HIER LANGSKOMEN ─────────────────────────────────────────────────────\n *\n * De editor tekende de pagina vroeger zélf, in een eigen canvas binnen een schermvullende overlay.\n * Je klikte \"Pagina bewerken\" en je site verdween achter een donker paneel met een nabootsing erin.\n * Dat voelde niet als je site bewerken maar als een ander programma openen.\n *\n * Nu blijft de PAGINA de pagina en wordt alleen de DATA vervangen: de editor laadt de werkversie en\n * zet die hier neer, waarna `PublishedPage` de werkversie rendert in plaats van de gepubliceerde\n * blokken. Dezelfde componenten, dezelfde huisstijl, dezelfde layout — alleen andere inhoud.\n *\n * Die omweg via de data is wezenlijk, geen implementatiedetail. Alleen potloodjes over de live\n * pagina leggen zou betekenen dat je de WERKVERSIE bewerkt terwijl je de GEPUBLICEERDE tekst ziet.\n * Zodra je iets wijzigt en nog niet publiceert, lopen die twee uit elkaar en bewerk je iets anders\n * dan er staat. Wat je ziet moet zijn wat je bewerkt.\n *\n * `editPath` hoort erbij: een site kan meerdere gerenderde pagina's in beeld hebben (een\n * ingekaderde pagina, een preview). Alleen het pad dat de editor open heeft mag zijn blokken\n * verwisselen.\n *\n * ── WAAROM DE MODUS EEN REFRESH MOET OVERLEVEN (7.8) ──────────────────────────────────────\n *\n * Bewerken was een toestand die alleen in het geheugen van één render-boom bestond. Een per ongeluk\n * ingedrukte F5 — of een klik op een link in je eigen site, want dat is een volledige navigatie —\n * zette je terug op de live site. Je wijzigingen waren niet weg (die staan in de werkversie in\n * Firestore), maar je zág ze niet meer, en dat is niet te onderscheiden van kwijt zijn.\n *\n * Daarom staat de modus in `sessionStorage`: hij overleeft een refresh en het navigeren door de\n * site, en verdwijnt vanzelf zodra het tabblad dichtgaat. Bewust niet `localStorage` — dan zit je\n * morgen in een nieuw venster nog steeds in de bewerkmodus zonder dat je erom vroeg.\n */\n/**\n * BEWUST GEEN `lazy()` + `<Suspense>`. De chunk-splitsing is dezelfde (de dynamische import\n * hieronder maakt zijn eigen chunk), maar Suspense heeft een gedraging die ons hier de kop kostte:\n * als de boom suspendt, koppelt React de al-gemonteerde children tijdelijk los en weer vast\n * (disconnect/reconnect van de passive effects). In dat her-aansluitpad draaide Astryx'\n * `useScrollLock`-effect dubbel zonder tussenliggende cleanup, waardoor zijn module-brede teller\n * nooit meer op nul kwam — en een teller boven nul betekent: `body { position: fixed }`. De hele\n * site stond stil: niet meer scrollen, dus ook geen bewerkknoppen bij blokken onder de vouw.\n * Zelf laden in een effect en pas renderen als de module er is, heeft dat Suspense-pad niet.\n */\ntype VisualEditorComponent = ComponentType<{ onClose: () => void }>;\nlet visualEditorModule: VisualEditorComponent | null = null;\n\n/** \"live\" = precies wat een bezoeker ziet. \"bewerken\" = dezelfde pagina, met werkversie en gereedschap. */\nexport type Bewerkmodus = \"live\" | \"bewerken\";\n\nconst OPSLAGSLEUTEL = \"xicms-bewerkmodus\";\n\ninterface EditorCtx {\n modus: Bewerkmodus;\n /** Blijft bestaan naast `modus` omdat het door de hele codebase heen gelezen wordt. */\n open: boolean;\n zetModus: (modus: Bewerkmodus) => void;\n openEditor: () => void;\n closeEditor: () => void;\n /** De blokken van de werkversie die de pagina moet tonen; `null` = toon gewoon het gepubliceerde. */\n draftBlocks: PaginaBlokken | null;\n /** Het pad waarvoor `draftBlocks` geldt. */\n editPath: string | null;\n /** Door de editor aangeroepen zodra de werkversie laadt of wijzigt. */\n publishDraft: (path: string, blocks: PaginaBlokken | null) => void;\n /**\n * Net gepubliceerde blokken voor `path` — `PublishedPage` gebruikt dit als het TERUGVALT op de\n * `page`-prop (bewerkmodus dicht/nog niet aan), zodat \"Live site\" bekijken vlak na publiceren\n * niet de VEROUDERDE server-props laat zien (die zijn maar één keer geladen, bij het openen van\n * de pagina, en publiceren ververst ze niet). Zie `bevestigPublicatie`.\n */\n publishedOverride: { path: string; blocks: PaginaBlokken } | null;\n /** Door de editor aangeroepen direct na een geslaagde `publishPage`-call. */\n bevestigPublicatie: (path: string, blocks: PaginaBlokken) => void;\n /**\n * \"Vervang de foto in veld X van blok Y\" — gezet door de VisualEditor zolang hij open is.\n *\n * De 📷-knopjes op de foto's zitten in de RENDER van de pagina (Img), de mediakiezer zit in de\n * EDITOR. Die twee delen geen boom meer sinds het canvas weg is; dit is de brug. `null` buiten\n * de bewerkmodus, en dan tekent Img geen knopjes.\n */\n fotoVervanger: ((field: string, blockKey?: string) => void) | null;\n zetFotoVervanger: (fn: ((field: string, blockKey?: string) => void) | null) => void;\n}\n\nconst Ctx = createContext<EditorCtx>({\n modus: \"live\",\n open: false,\n zetModus: () => {},\n openEditor: () => {},\n closeEditor: () => {},\n draftBlocks: null,\n editPath: null,\n publishDraft: () => {},\n publishedOverride: null,\n bevestigPublicatie: () => {},\n fotoVervanger: null,\n zetFotoVervanger: () => {},\n});\n\nexport function EditorProvider({ children }: { children: ReactNode }) {\n /**\n * Start altijd op \"live\", ook als de opslag iets anders zegt.\n *\n * De server rendert deze boom zonder toegang tot `sessionStorage`. Zou de eerste client-render\n * meteen \"bewerken\" teruggeven, dan wijkt hij af van de HTML die er al staat en gooit React de\n * boom weg (hydration mismatch). Vandaar: eerst hetzelfde als de server, daarna in een effect\n * bijstellen. Eén frame \"live\" is niet zichtbaar; een kapotte hydration wel.\n */\n const [modus, setModusState] = useState<Bewerkmodus>(\"live\");\n // De editor-component zodra zijn chunk binnen is; module-cache zodat een tweede keer openen\n // (of een andere pagina in dezelfde sessie) niet opnieuw op het netwerk wacht.\n const [VisualEditor, setVisualEditor] = useState<VisualEditorComponent | null>(() => visualEditorModule);\n const [draft, setDraft] = useState<{ path: string; blocks: PaginaBlokken } | null>(null);\n const [publishedOverride, setPublishedOverride] = useState<{ path: string; blocks: PaginaBlokken } | null>(null);\n const [fotoVervanger, setFotoVervanger] = useState<((field: string, blockKey?: string) => void) | null>(null);\n // In state gewikkeld: een functie rechtstreeks aan een setState geven zou hem AANROEPEN\n // (functionele updater) in plaats van opslaan.\n const zetFotoVervanger = useCallback((fn: ((field: string, blockKey?: string) => void) | null) => {\n setFotoVervanger(() => fn);\n }, []);\n\n useEffect(() => {\n try {\n if (sessionStorage.getItem(OPSLAGSLEUTEL) === \"bewerken\") setModusState(\"bewerken\");\n } catch {\n /* privémodus of geblokkeerde opslag: dan gewoon op de live site beginnen */\n }\n }, []);\n\n // De editor-chunk laden zodra de bewerkmodus aangaat (zie het commentaar bij\n // `visualEditorModule` waarom dit met de hand gebeurt en niet via lazy/Suspense).\n useEffect(() => {\n if (modus !== \"bewerken\" || VisualEditor) return;\n let losgekoppeld = false;\n void import(\"../admin/visual/VisualEditor\").then((m) => {\n visualEditorModule = m.default;\n if (!losgekoppeld) setVisualEditor(() => m.default);\n });\n return () => {\n losgekoppeld = true;\n };\n }, [modus, VisualEditor]);\n\n const zetModus = useCallback((next: Bewerkmodus) => {\n setModusState(next);\n try {\n if (next === \"bewerken\") sessionStorage.setItem(OPSLAGSLEUTEL, \"bewerken\");\n else sessionStorage.removeItem(OPSLAGSLEUTEL);\n } catch {\n /* de modus werkt ook zonder opslag; alleen een refresh valt dan terug op live */\n }\n // De werkversie hoort bij de bewerkmodus. Blijft hij staan na het sluiten, dan ziet de bezoeker\n // ongepubliceerde tekst terwijl het gereedschap weg is — een pagina die iets toont wat niet\n // live is. De werkversie zelf blijft in Firestore staan; alleen deze weergave stopt.\n if (next === \"live\") setDraft(null);\n }, []);\n\n const publishDraft = useCallback((path: string, blocks: PaginaBlokken | null) => {\n setDraft(blocks ? { path, blocks } : null);\n }, []);\n\n const bevestigPublicatie = useCallback((path: string, blocks: PaginaBlokken) => {\n setPublishedOverride({ path, blocks });\n }, []);\n\n const value = useMemo<EditorCtx>(() => ({\n modus,\n open: modus === \"bewerken\",\n zetModus,\n openEditor: () => zetModus(\"bewerken\"),\n closeEditor: () => zetModus(\"live\"),\n draftBlocks: draft?.blocks ?? null,\n editPath: draft?.path ?? null,\n publishDraft,\n publishedOverride,\n bevestigPublicatie,\n fotoVervanger,\n zetFotoVervanger,\n }), [modus, draft, zetModus, publishDraft, publishedOverride, bevestigPublicatie, fotoVervanger, zetFotoVervanger]);\n\n return (\n <Ctx.Provider value={value}>\n {children}\n {modus === \"bewerken\" && VisualEditor && <VisualEditor onClose={() => zetModus(\"live\")} />}\n </Ctx.Provider>\n );\n}\n\n/** Open/sluit de visuele pagina-editor. */\nexport function useEditor(): EditorCtx {\n return useContext(Ctx);\n}\n"],"mappings":";AAgMI,SAE2C,KAF3C;AA9LJ,SAAS,eAAe,aAAa,YAAY,WAAW,SAAS,gBAAoD;AAqDzH,IAAI,qBAAmD;AAKvD,MAAM,gBAAgB;AAmCtB,MAAM,MAAM,cAAyB;AAAA,EACnC,OAAO;AAAA,EACP,MAAM;AAAA,EACN,UAAU,MAAM;AAAA,EAAC;AAAA,EACjB,YAAY,MAAM;AAAA,EAAC;AAAA,EACnB,aAAa,MAAM;AAAA,EAAC;AAAA,EACpB,aAAa;AAAA,EACb,UAAU;AAAA,EACV,cAAc,MAAM;AAAA,EAAC;AAAA,EACrB,mBAAmB;AAAA,EACnB,oBAAoB,MAAM;AAAA,EAAC;AAAA,EAC3B,eAAe;AAAA,EACf,kBAAkB,MAAM;AAAA,EAAC;AAC3B,CAAC;AAEM,SAAS,eAAe,EAAE,SAAS,GAA4B;AASpE,QAAM,CAAC,OAAO,aAAa,IAAI,SAAsB,MAAM;AAG3D,QAAM,CAAC,cAAc,eAAe,IAAI,SAAuC,MAAM,kBAAkB;AACvG,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAyD,IAAI;AACvF,QAAM,CAAC,mBAAmB,oBAAoB,IAAI,SAAyD,IAAI;AAC/G,QAAM,CAAC,eAAe,gBAAgB,IAAI,SAA8D,IAAI;AAG5G,QAAM,mBAAmB,YAAY,CAAC,OAA4D;AAChG,qBAAiB,MAAM,EAAE;AAAA,EAC3B,GAAG,CAAC,CAAC;AAEL,YAAU,MAAM;AACd,QAAI;AACF,UAAI,eAAe,QAAQ,aAAa,MAAM,WAAY,eAAc,UAAU;AAAA,IACpF,QAAQ;AAAA,IAER;AAAA,EACF,GAAG,CAAC,CAAC;AAIL,YAAU,MAAM;AACd,QAAI,UAAU,cAAc,aAAc;AAC1C,QAAI,eAAe;AACnB,SAAK,OAAO,8BAA8B,EAAE,KAAK,CAAC,MAAM;AACtD,2BAAqB,EAAE;AACvB,UAAI,CAAC,aAAc,iBAAgB,MAAM,EAAE,OAAO;AAAA,IACpD,CAAC;AACD,WAAO,MAAM;AACX,qBAAe;AAAA,IACjB;AAAA,EACF,GAAG,CAAC,OAAO,YAAY,CAAC;AAExB,QAAM,WAAW,YAAY,CAAC,SAAsB;AAClD,kBAAc,IAAI;AAClB,QAAI;AACF,UAAI,SAAS,WAAY,gBAAe,QAAQ,eAAe,UAAU;AAAA,UACpE,gBAAe,WAAW,aAAa;AAAA,IAC9C,QAAQ;AAAA,IAER;AAIA,QAAI,SAAS,OAAQ,UAAS,IAAI;AAAA,EACpC,GAAG,CAAC,CAAC;AAEL,QAAM,eAAe,YAAY,CAAC,MAAc,WAAiC;AAC/E,aAAS,SAAS,EAAE,MAAM,OAAO,IAAI,IAAI;AAAA,EAC3C,GAAG,CAAC,CAAC;AAEL,QAAM,qBAAqB,YAAY,CAAC,MAAc,WAA0B;AAC9E,yBAAqB,EAAE,MAAM,OAAO,CAAC;AAAA,EACvC,GAAG,CAAC,CAAC;AAEL,QAAM,QAAQ,QAAmB,OAAO;AAAA,IACtC;AAAA,IACA,MAAM,UAAU;AAAA,IAChB;AAAA,IACA,YAAY,MAAM,SAAS,UAAU;AAAA,IACrC,aAAa,MAAM,SAAS,MAAM;AAAA,IAClC,aAAa,OAAO,UAAU;AAAA,IAC9B,UAAU,OAAO,QAAQ;AAAA,IACzB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI,CAAC,OAAO,OAAO,UAAU,cAAc,mBAAmB,oBAAoB,eAAe,gBAAgB,CAAC;AAElH,SACE,qBAAC,IAAI,UAAJ,EAAa,OACX;AAAA;AAAA,IACA,UAAU,cAAc,gBAAgB,oBAAC,gBAAa,SAAS,MAAM,SAAS,MAAM,GAAG;AAAA,KAC1F;AAEJ;AAGO,SAAS,YAAuB;AACrC,SAAO,WAAW,GAAG;AACvB;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/editor/EditorProvider.tsx"],"sourcesContent":["\"use client\";\n\nimport { createContext, useCallback, useContext, useEffect, useMemo, useState, type ComponentType, type ReactNode } from \"react\";\n// Het bloktype van de PAGINA zelf, zodat wat hier langskomt per definitie past in wat\n// `PublishedPage` rendert. Een eigen definitie zou hier stil uit de pas kunnen lopen.\nimport type { Page } from \"../schema/pages\";\n\ntype PaginaBlokken = Page[\"blocks\"];\n\n/**\n * Lichte runtime-context voor het inline (visuele) bewerken op de live pagina. De echte editor\n * (TipTap/Radix, zwaar) wordt PAS geladen als een editor hem opent — publieke bezoekers downloaden\n * hem nooit. De editor leeft in de admin-entry; we laden 'm via een dynamische import (eigen chunk).\n *\n * ── WAAROM DE BLOKKEN HIER LANGSKOMEN ─────────────────────────────────────────────────────\n *\n * De editor tekende de pagina vroeger zélf, in een eigen canvas binnen een schermvullende overlay.\n * Je klikte \"Pagina bewerken\" en je site verdween achter een donker paneel met een nabootsing erin.\n * Dat voelde niet als je site bewerken maar als een ander programma openen.\n *\n * Nu blijft de PAGINA de pagina en wordt alleen de DATA vervangen: de editor laadt de werkversie en\n * zet die hier neer, waarna `PublishedPage` de werkversie rendert in plaats van de gepubliceerde\n * blokken. Dezelfde componenten, dezelfde huisstijl, dezelfde layout — alleen andere inhoud.\n *\n * Die omweg via de data is wezenlijk, geen implementatiedetail. Alleen potloodjes over de live\n * pagina leggen zou betekenen dat je de WERKVERSIE bewerkt terwijl je de GEPUBLICEERDE tekst ziet.\n * Zodra je iets wijzigt en nog niet publiceert, lopen die twee uit elkaar en bewerk je iets anders\n * dan er staat. Wat je ziet moet zijn wat je bewerkt.\n *\n * `editPath` hoort erbij: een site kan meerdere gerenderde pagina's in beeld hebben (een\n * ingekaderde pagina, een preview). Alleen het pad dat de editor open heeft mag zijn blokken\n * verwisselen.\n *\n * ── WAAROM DE MODUS EEN REFRESH MOET OVERLEVEN (7.8) ──────────────────────────────────────\n *\n * Bewerken was een toestand die alleen in het geheugen van één render-boom bestond. Een per ongeluk\n * ingedrukte F5 — of een klik op een link in je eigen site, want dat is een volledige navigatie —\n * zette je terug op de live site. Je wijzigingen waren niet weg (die staan in de werkversie in\n * Firestore), maar je zág ze niet meer, en dat is niet te onderscheiden van kwijt zijn.\n *\n * Daarom staat de modus in `sessionStorage`: hij overleeft een refresh en het navigeren door de\n * site, en verdwijnt vanzelf zodra het tabblad dichtgaat. Bewust niet `localStorage` — dan zit je\n * morgen in een nieuw venster nog steeds in de bewerkmodus zonder dat je erom vroeg.\n */\n/**\n * BEWUST GEEN `lazy()` + `<Suspense>`. De chunk-splitsing is dezelfde (de dynamische import\n * hieronder maakt zijn eigen chunk), maar Suspense heeft een gedraging die ons hier de kop kostte:\n * als de boom suspendt, koppelt React de al-gemonteerde children tijdelijk los en weer vast\n * (disconnect/reconnect van de passive effects). In dat her-aansluitpad draaide Astryx'\n * `useScrollLock`-effect dubbel zonder tussenliggende cleanup, waardoor zijn module-brede teller\n * nooit meer op nul kwam — en een teller boven nul betekent: `body { position: fixed }`. De hele\n * site stond stil: niet meer scrollen, dus ook geen bewerkknoppen bij blokken onder de vouw.\n * Zelf laden in een effect en pas renderen als de module er is, heeft dat Suspense-pad niet.\n */\ntype VisualEditorComponent = ComponentType<{ onClose: () => void }>;\nlet visualEditorModule: VisualEditorComponent | null = null;\n\n/** \"live\" = precies wat een bezoeker ziet. \"bewerken\" = dezelfde pagina, met werkversie en gereedschap. */\nexport type Bewerkmodus = \"live\" | \"bewerken\";\n\nconst OPSLAGSLEUTEL = \"xicms-bewerkmodus\";\n\ninterface EditorCtx {\n modus: Bewerkmodus;\n /** Blijft bestaan naast `modus` omdat het door de hele codebase heen gelezen wordt. */\n open: boolean;\n zetModus: (modus: Bewerkmodus) => void;\n openEditor: () => void;\n closeEditor: () => void;\n /** De blokken van de werkversie die de pagina moet tonen; `null` = toon gewoon het gepubliceerde. */\n draftBlocks: PaginaBlokken | null;\n /** Het pad waarvoor `draftBlocks` geldt. */\n editPath: string | null;\n /** Door de editor aangeroepen zodra de werkversie laadt of wijzigt. */\n publishDraft: (path: string, blocks: PaginaBlokken | null) => void;\n /**\n * Net gepubliceerde blokken voor `path` — `PublishedPage` gebruikt dit als het TERUGVALT op de\n * `page`-prop (bewerkmodus dicht/nog niet aan), zodat \"Live site\" bekijken vlak na publiceren\n * niet de VEROUDERDE server-props laat zien (die zijn maar één keer geladen, bij het openen van\n * de pagina, en publiceren ververst ze niet). Zie `bevestigPublicatie`.\n */\n publishedOverride: { path: string; blocks: PaginaBlokken } | null;\n /** Door de editor aangeroepen direct na een geslaagde `publishPage`-call. */\n bevestigPublicatie: (path: string, blocks: PaginaBlokken) => void;\n /**\n * \"Vervang de foto in veld X van blok Y\" — gezet door de VisualEditor zolang hij open is.\n *\n * De 📷-knopjes op de foto's zitten in de RENDER van de pagina (Img), de mediakiezer zit in de\n * EDITOR. Die twee delen geen boom meer sinds het canvas weg is; dit is de brug. `null` buiten\n * de bewerkmodus, en dan tekent Img geen knopjes.\n */\n fotoVervanger: ((field: string, blockKey?: string) => void) | null;\n zetFotoVervanger: (fn: ((field: string, blockKey?: string) => void) | null) => void;\n}\n\nconst Ctx = createContext<EditorCtx>({\n modus: \"live\",\n open: false,\n zetModus: () => {},\n openEditor: () => {},\n closeEditor: () => {},\n draftBlocks: null,\n editPath: null,\n publishDraft: () => {},\n publishedOverride: null,\n bevestigPublicatie: () => {},\n fotoVervanger: null,\n zetFotoVervanger: () => {},\n});\n\nexport function EditorProvider({ children }: { children: ReactNode }) {\n /**\n * Start altijd op \"live\", ook als de opslag iets anders zegt.\n *\n * De server rendert deze boom zonder toegang tot `sessionStorage`. Zou de eerste client-render\n * meteen \"bewerken\" teruggeven, dan wijkt hij af van de HTML die er al staat en gooit React de\n * boom weg (hydration mismatch). Vandaar: eerst hetzelfde als de server, daarna in een effect\n * bijstellen. Eén frame \"live\" is niet zichtbaar; een kapotte hydration wel.\n */\n const [modus, setModusState] = useState<Bewerkmodus>(\"live\");\n // De editor-component zodra zijn chunk binnen is; module-cache zodat een tweede keer openen\n // (of een andere pagina in dezelfde sessie) niet opnieuw op het netwerk wacht.\n const [VisualEditor, setVisualEditor] = useState<VisualEditorComponent | null>(() => visualEditorModule);\n /** 8.2: mislukt het laden van de editor-chunk (slechte verbinding, nieuwe deploy), zeg dat dan. */\n const [laadFout, setLaadFout] = useState(false);\n const [laadPoging, setLaadPoging] = useState(0);\n const [draft, setDraft] = useState<{ path: string; blocks: PaginaBlokken } | null>(null);\n const [publishedOverride, setPublishedOverride] = useState<{ path: string; blocks: PaginaBlokken } | null>(null);\n const [fotoVervanger, setFotoVervanger] = useState<((field: string, blockKey?: string) => void) | null>(null);\n // In state gewikkeld: een functie rechtstreeks aan een setState geven zou hem AANROEPEN\n // (functionele updater) in plaats van opslaan.\n const zetFotoVervanger = useCallback((fn: ((field: string, blockKey?: string) => void) | null) => {\n setFotoVervanger(() => fn);\n }, []);\n\n useEffect(() => {\n try {\n if (sessionStorage.getItem(OPSLAGSLEUTEL) === \"bewerken\") setModusState(\"bewerken\");\n } catch {\n /* privémodus of geblokkeerde opslag: dan gewoon op de live site beginnen */\n }\n }, []);\n\n // De editor-chunk laden zodra de bewerkmodus aangaat (zie het commentaar bij\n // `visualEditorModule` waarom dit met de hand gebeurt en niet via lazy/Suspense).\n useEffect(() => {\n if (modus !== \"bewerken\" || VisualEditor) return;\n let losgekoppeld = false;\n setLaadFout(false);\n import(\"../admin/visual/VisualEditor\")\n .then((m) => {\n visualEditorModule = m.default;\n if (!losgekoppeld) setVisualEditor(() => m.default);\n })\n .catch((e) => {\n console.error(\"[xicms] editor laden mislukt:\", e);\n if (!losgekoppeld) setLaadFout(true);\n });\n return () => {\n losgekoppeld = true;\n };\n }, [modus, VisualEditor, laadPoging]);\n\n const zetModus = useCallback((next: Bewerkmodus) => {\n setModusState(next);\n try {\n if (next === \"bewerken\") sessionStorage.setItem(OPSLAGSLEUTEL, \"bewerken\");\n else sessionStorage.removeItem(OPSLAGSLEUTEL);\n } catch {\n /* de modus werkt ook zonder opslag; alleen een refresh valt dan terug op live */\n }\n // De werkversie hoort bij de bewerkmodus. Blijft hij staan na het sluiten, dan ziet de bezoeker\n // ongepubliceerde tekst terwijl het gereedschap weg is — een pagina die iets toont wat niet\n // live is. De werkversie zelf blijft in Firestore staan; alleen deze weergave stopt.\n if (next === \"live\") setDraft(null);\n }, []);\n\n const publishDraft = useCallback((path: string, blocks: PaginaBlokken | null) => {\n setDraft(blocks ? { path, blocks } : null);\n }, []);\n\n const bevestigPublicatie = useCallback((path: string, blocks: PaginaBlokken) => {\n setPublishedOverride({ path, blocks });\n }, []);\n\n const value = useMemo<EditorCtx>(() => ({\n modus,\n open: modus === \"bewerken\",\n zetModus,\n openEditor: () => zetModus(\"bewerken\"),\n closeEditor: () => zetModus(\"live\"),\n draftBlocks: draft?.blocks ?? null,\n editPath: draft?.path ?? null,\n publishDraft,\n publishedOverride,\n bevestigPublicatie,\n fotoVervanger,\n zetFotoVervanger,\n }), [modus, draft, zetModus, publishDraft, publishedOverride, bevestigPublicatie, fotoVervanger, zetFotoVervanger]);\n\n return (\n <Ctx.Provider value={value}>\n {children}\n {modus === \"bewerken\" && VisualEditor && <VisualEditor onClose={() => zetModus(\"live\")} />}\n {modus === \"bewerken\" && !VisualEditor && (\n <div className=\"xicms-editor-laden\" role={laadFout ? \"alert\" : \"status\"} aria-live=\"polite\" data-xicms-tooling=\"\">\n {laadFout ? (\n <>\n <span>De editor kon niet geladen worden.</span>\n <button type=\"button\" onClick={() => setLaadPoging((n) => n + 1)}>Opnieuw proberen</button>\n <button type=\"button\" onClick={() => zetModus(\"live\")}>Sluiten</button>\n </>\n ) : (\n <span>Editor laden…</span>\n )}\n </div>\n )}\n </Ctx.Provider>\n );\n}\n\n/** Open/sluit de visuele pagina-editor. */\nexport function useEditor(): EditorCtx {\n return useContext(Ctx);\n}\n"],"mappings":";AA2M+C,SAInC,UAJmC,KAInC,YAJmC;AAzM/C,SAAS,eAAe,aAAa,YAAY,WAAW,SAAS,gBAAoD;AAqDzH,IAAI,qBAAmD;AAKvD,MAAM,gBAAgB;AAmCtB,MAAM,MAAM,cAAyB;AAAA,EACnC,OAAO;AAAA,EACP,MAAM;AAAA,EACN,UAAU,MAAM;AAAA,EAAC;AAAA,EACjB,YAAY,MAAM;AAAA,EAAC;AAAA,EACnB,aAAa,MAAM;AAAA,EAAC;AAAA,EACpB,aAAa;AAAA,EACb,UAAU;AAAA,EACV,cAAc,MAAM;AAAA,EAAC;AAAA,EACrB,mBAAmB;AAAA,EACnB,oBAAoB,MAAM;AAAA,EAAC;AAAA,EAC3B,eAAe;AAAA,EACf,kBAAkB,MAAM;AAAA,EAAC;AAC3B,CAAC;AAEM,SAAS,eAAe,EAAE,SAAS,GAA4B;AASpE,QAAM,CAAC,OAAO,aAAa,IAAI,SAAsB,MAAM;AAG3D,QAAM,CAAC,cAAc,eAAe,IAAI,SAAuC,MAAM,kBAAkB;AAEvG,QAAM,CAAC,UAAU,WAAW,IAAI,SAAS,KAAK;AAC9C,QAAM,CAAC,YAAY,aAAa,IAAI,SAAS,CAAC;AAC9C,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAyD,IAAI;AACvF,QAAM,CAAC,mBAAmB,oBAAoB,IAAI,SAAyD,IAAI;AAC/G,QAAM,CAAC,eAAe,gBAAgB,IAAI,SAA8D,IAAI;AAG5G,QAAM,mBAAmB,YAAY,CAAC,OAA4D;AAChG,qBAAiB,MAAM,EAAE;AAAA,EAC3B,GAAG,CAAC,CAAC;AAEL,YAAU,MAAM;AACd,QAAI;AACF,UAAI,eAAe,QAAQ,aAAa,MAAM,WAAY,eAAc,UAAU;AAAA,IACpF,QAAQ;AAAA,IAER;AAAA,EACF,GAAG,CAAC,CAAC;AAIL,YAAU,MAAM;AACd,QAAI,UAAU,cAAc,aAAc;AAC1C,QAAI,eAAe;AACnB,gBAAY,KAAK;AACjB,WAAO,8BAA8B,EAClC,KAAK,CAAC,MAAM;AACX,2BAAqB,EAAE;AACvB,UAAI,CAAC,aAAc,iBAAgB,MAAM,EAAE,OAAO;AAAA,IACpD,CAAC,EACA,MAAM,CAAC,MAAM;AACZ,cAAQ,MAAM,iCAAiC,CAAC;AAChD,UAAI,CAAC,aAAc,aAAY,IAAI;AAAA,IACrC,CAAC;AACH,WAAO,MAAM;AACX,qBAAe;AAAA,IACjB;AAAA,EACF,GAAG,CAAC,OAAO,cAAc,UAAU,CAAC;AAEpC,QAAM,WAAW,YAAY,CAAC,SAAsB;AAClD,kBAAc,IAAI;AAClB,QAAI;AACF,UAAI,SAAS,WAAY,gBAAe,QAAQ,eAAe,UAAU;AAAA,UACpE,gBAAe,WAAW,aAAa;AAAA,IAC9C,QAAQ;AAAA,IAER;AAIA,QAAI,SAAS,OAAQ,UAAS,IAAI;AAAA,EACpC,GAAG,CAAC,CAAC;AAEL,QAAM,eAAe,YAAY,CAAC,MAAc,WAAiC;AAC/E,aAAS,SAAS,EAAE,MAAM,OAAO,IAAI,IAAI;AAAA,EAC3C,GAAG,CAAC,CAAC;AAEL,QAAM,qBAAqB,YAAY,CAAC,MAAc,WAA0B;AAC9E,yBAAqB,EAAE,MAAM,OAAO,CAAC;AAAA,EACvC,GAAG,CAAC,CAAC;AAEL,QAAM,QAAQ,QAAmB,OAAO;AAAA,IACtC;AAAA,IACA,MAAM,UAAU;AAAA,IAChB;AAAA,IACA,YAAY,MAAM,SAAS,UAAU;AAAA,IACrC,aAAa,MAAM,SAAS,MAAM;AAAA,IAClC,aAAa,OAAO,UAAU;AAAA,IAC9B,UAAU,OAAO,QAAQ;AAAA,IACzB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI,CAAC,OAAO,OAAO,UAAU,cAAc,mBAAmB,oBAAoB,eAAe,gBAAgB,CAAC;AAElH,SACE,qBAAC,IAAI,UAAJ,EAAa,OACX;AAAA;AAAA,IACA,UAAU,cAAc,gBAAgB,oBAAC,gBAAa,SAAS,MAAM,SAAS,MAAM,GAAG;AAAA,IACvF,UAAU,cAAc,CAAC,gBACxB,oBAAC,SAAI,WAAU,sBAAqB,MAAM,WAAW,UAAU,UAAU,aAAU,UAAS,sBAAmB,IAC5G,qBACC,iCACE;AAAA,0BAAC,UAAK,gDAAkC;AAAA,MACxC,oBAAC,YAAO,MAAK,UAAS,SAAS,MAAM,cAAc,CAAC,MAAM,IAAI,CAAC,GAAG,8BAAgB;AAAA,MAClF,oBAAC,YAAO,MAAK,UAAS,SAAS,MAAM,SAAS,MAAM,GAAG,qBAAO;AAAA,OAChE,IAEA,oBAAC,UAAK,gCAAa,GAEvB;AAAA,KAEJ;AAEJ;AAGO,SAAS,YAAuB;AACrC,SAAO,WAAW,GAAG;AACvB;","names":[]}
|
package/dist/index.d.ts
CHANGED
|
@@ -16,6 +16,7 @@ export * from "./blocks/ui/index.js";
|
|
|
16
16
|
export { SiteSettingsProvider, useSiteSettings, useMergedSiteConfig, } from "./settings/useSiteSettings.js";
|
|
17
17
|
export { SiteFooter } from "./components/site/SiteFooter.js";
|
|
18
18
|
export { SiteNav } from "./components/site/SiteNav.js";
|
|
19
|
+
export { SiteHeader } from "./components/site/SiteHeader.js";
|
|
19
20
|
export { EditorProvider, useEditor } from "./editor/EditorProvider.js";
|
|
20
21
|
export { definePattern, instantiatePattern, collectPatternTypes, builtinPatterns, type Pattern, type PatternBlock, } from "./patterns/index.js";
|
|
21
22
|
export { builtinThemePresets, type ThemePreset } from "./theme/presets.js";
|
|
@@ -34,6 +35,8 @@ export type { Translations, LocaleConfig } from "./i18n/overlay.js";
|
|
|
34
35
|
export type { ThemeTokens, NavItem, NavLeaf, Redirect, SiteSettings, PublicSiteSettings, FormsSender } from "./schema/settings.js";
|
|
35
36
|
export { zoekRedirect, normaliseerPad, navHref, isExterneLink } from "./schema/settings.js";
|
|
36
37
|
export type { Seo } from "./schema/seo.js";
|
|
38
|
+
export { BusinessSchema, BEDRIJFSTYPES, type Business, type BusinessException } from "./schema/business.js";
|
|
39
|
+
export { adresRegels, telLink, routeLink, afwijkingOp, komendeAfwijkingen, afwijkingDatumTekst, isOpenNuMetAfwijkingen, heeftProfiel } from "./bedrijf/bedrijf.js";
|
|
37
40
|
export type { Page, PageStatus } from "./schema/pages.js";
|
|
38
41
|
export type { FormDefinition, FormField } from "./schema/forms.js";
|
|
39
42
|
export { AuthProvider, useAuth } from "./auth/AuthProvider.js";
|
|
@@ -43,7 +46,7 @@ export type { NewsArticle, MediaItem, MediaVariant } from "./content/types.js";
|
|
|
43
46
|
export { EditBar } from "./components/EditBar.js";
|
|
44
47
|
export { ExternEmbed } from "./components/ExternEmbed.js";
|
|
45
48
|
export { ResponsiveImage } from "./components/ResponsiveImage.js";
|
|
46
|
-
export { PageView } from "./components/PageView.js";
|
|
49
|
+
export { PageView, NietGevondenMelder } from "./components/PageView.js";
|
|
47
50
|
export { NewsList, NewsArticleView, useNews } from "./components/News.js";
|
|
48
51
|
export { defineBlock, createRegistry, mergeRegistry, validateBlocks, buildBlockAddOptions, type BlockDefinition, type BlockRegistry, type BlockRenderProps, type BlockEditorProps, type BlockCategory, } from "./blocks/registry.js";
|
|
49
52
|
export { BlockRenderer } from "./blocks/BlockRenderer.js";
|
package/dist/index.js
CHANGED
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
} from "./settings/useSiteSettings.js";
|
|
12
12
|
import { SiteFooter } from "./components/site/SiteFooter.js";
|
|
13
13
|
import { SiteNav } from "./components/site/SiteNav.js";
|
|
14
|
+
import { SiteHeader } from "./components/site/SiteHeader.js";
|
|
14
15
|
import { EditorProvider, useEditor } from "./editor/EditorProvider.js";
|
|
15
16
|
import {
|
|
16
17
|
definePattern,
|
|
@@ -35,6 +36,8 @@ import {
|
|
|
35
36
|
TranslationsSchema
|
|
36
37
|
} from "./i18n/overlay.js";
|
|
37
38
|
import { zoekRedirect, normaliseerPad, navHref, isExterneLink } from "./schema/settings.js";
|
|
39
|
+
import { BusinessSchema, BEDRIJFSTYPES } from "./schema/business.js";
|
|
40
|
+
import { adresRegels, telLink, routeLink, afwijkingOp, komendeAfwijkingen, afwijkingDatumTekst, isOpenNuMetAfwijkingen, heeftProfiel } from "./bedrijf/bedrijf.js";
|
|
38
41
|
import { AuthProvider, useAuth } from "./auth/AuthProvider.js";
|
|
39
42
|
import { LoginForm } from "./auth/LoginForm.js";
|
|
40
43
|
import {
|
|
@@ -46,7 +49,7 @@ import {
|
|
|
46
49
|
import { EditBar } from "./components/EditBar.js";
|
|
47
50
|
import { ExternEmbed } from "./components/ExternEmbed.js";
|
|
48
51
|
import { ResponsiveImage } from "./components/ResponsiveImage.js";
|
|
49
|
-
import { PageView } from "./components/PageView.js";
|
|
52
|
+
import { PageView, NietGevondenMelder } from "./components/PageView.js";
|
|
50
53
|
import { NewsList, NewsArticleView, useNews } from "./components/News.js";
|
|
51
54
|
import {
|
|
52
55
|
defineBlock,
|
|
@@ -91,8 +94,10 @@ import { SiteChrome } from "./SiteChrome.js";
|
|
|
91
94
|
import { CORE_VERSION, CORE_PACKAGE, isNieuwer } from "./version.js";
|
|
92
95
|
export {
|
|
93
96
|
AuthProvider,
|
|
97
|
+
BEDRIJFSTYPES,
|
|
94
98
|
BlockDataProvider,
|
|
95
99
|
BlockRenderer,
|
|
100
|
+
BusinessSchema,
|
|
96
101
|
CORE_PACKAGE,
|
|
97
102
|
CORE_VERSION,
|
|
98
103
|
ConsentBanner,
|
|
@@ -114,6 +119,7 @@ export {
|
|
|
114
119
|
ModulesProvider,
|
|
115
120
|
NewsArticleView,
|
|
116
121
|
NewsList,
|
|
122
|
+
NietGevondenMelder,
|
|
117
123
|
PageRenderer,
|
|
118
124
|
PageView,
|
|
119
125
|
PublishedPage,
|
|
@@ -121,11 +127,15 @@ export {
|
|
|
121
127
|
ResponsiveImage,
|
|
122
128
|
SiteChrome,
|
|
123
129
|
SiteFooter,
|
|
130
|
+
SiteHeader,
|
|
124
131
|
SiteNav,
|
|
125
132
|
SiteSettingsProvider,
|
|
126
133
|
SymbolSchema,
|
|
127
134
|
TranslationsSchema,
|
|
128
135
|
XiCMSProvider,
|
|
136
|
+
adresRegels,
|
|
137
|
+
afwijkingDatumTekst,
|
|
138
|
+
afwijkingOp,
|
|
129
139
|
applyBlockOverrides,
|
|
130
140
|
assertModuleContract,
|
|
131
141
|
buildBlockAddOptions,
|
|
@@ -149,6 +159,7 @@ export {
|
|
|
149
159
|
getDb,
|
|
150
160
|
getFirebaseApp,
|
|
151
161
|
getFirebaseAuth,
|
|
162
|
+
heeftProfiel,
|
|
152
163
|
initAppCheck,
|
|
153
164
|
instantiatePattern,
|
|
154
165
|
interpretTemplate,
|
|
@@ -157,8 +168,10 @@ export {
|
|
|
157
168
|
isFirebaseConfigured,
|
|
158
169
|
isModuleActive,
|
|
159
170
|
isNieuwer,
|
|
171
|
+
isOpenNuMetAfwijkingen,
|
|
160
172
|
isRichTextKey,
|
|
161
173
|
isSuperadmin,
|
|
174
|
+
komendeAfwijkingen,
|
|
162
175
|
localizeBlocks,
|
|
163
176
|
localizePage,
|
|
164
177
|
localizedPath,
|
|
@@ -170,8 +183,10 @@ export {
|
|
|
170
183
|
pruneTranslations,
|
|
171
184
|
resolveModules,
|
|
172
185
|
roleForSite,
|
|
186
|
+
routeLink,
|
|
173
187
|
scopeCss,
|
|
174
188
|
siteLocales,
|
|
189
|
+
telLink,
|
|
175
190
|
useAuth,
|
|
176
191
|
useBlockData,
|
|
177
192
|
useConsent,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * Publieke runtime-API van @xiwebdesign/xicms-core (lichte client/runtime laag).\n * - Admin (TipTap/Radix) zit in \"@xiwebdesign/xicms-core/admin\".\n * - Server-only code (firebase-admin, sanitize, SEO) zit in \"@xiwebdesign/xicms-core/server\".\n * - Pure schema's in \"@xiwebdesign/xicms-core/schema\".\n */\n\n// Provider & config\nexport { XiCMSProvider } from \"./XiCMSProvider\";\nexport { useSiteConfig } from \"./config\";\n\n// Theming & design-primitieven (maatwerk zonder core te forken).\n// - `defineTheme` maakt een eigen Astryx-thema (tokens + component-overrides) → geef door als\n// XiCMSProvider `astryxTheme`-prop.\n// - De `ui`-primitieven (Card/Stack/Grid/Heading/Text/Btn…) zijn de bouwstenen waarop de ingebouwde\n// blokken draaien; gebruik ze in eigen blokken voor een consistent maar te herstijlen uiterlijk.\nexport { defineTheme, useTheme } from \"@astryxdesign/core/theme\";\nexport type { DefinedTheme } from \"@astryxdesign/core/theme\";\n// Framework-router-integratie: geef `next/link` door als XiCMSProvider `linkComponent`-prop\n// (soepele client-nav + prefetch op alle Astryx-knoppen/links). `useLinkComponent` voor eigen blokken.\nexport { LinkProvider, useLinkComponent } from \"@astryxdesign/core/Link\";\nexport type { LinkComponentType } from \"@astryxdesign/core/Link\";\n// Beeldoptimalisatie: geef `next/image` door als XiCMSProvider `imageComponent`-prop. `Img` is de\n// wrapper die de blokken gebruiken; `useImageComponent` voor eigen blokken.\nexport { Img, ImageProvider, useImageComponent, InlineImageEditProvider } from \"./media/ImageContext\";\nexport type { ImageComponentType, ImgProps } from \"./media/ImageContext\";\nexport * from \"./blocks/ui\";\nexport {\n SiteSettingsProvider,\n useSiteSettings,\n useMergedSiteConfig,\n} from \"./settings/useSiteSettings\";\nexport { SiteFooter } from \"./components/site/SiteFooter\";\n// 7.24: de beheerde hoofdnavigatie — de enige plek die `settings.nav` leest. Zie SiteNav.tsx.\nexport { SiteNav } from \"./components/site/SiteNav\";\nexport { EditorProvider, useEditor } from \"./editor/EditorProvider\";\nexport {\n definePattern,\n instantiatePattern,\n collectPatternTypes,\n builtinPatterns,\n type Pattern,\n type PatternBlock,\n} from \"./patterns\";\nexport { builtinThemePresets, type ThemePreset } from \"./theme/presets\";\nexport { defineSiteConfig } from \"./schema/siteConfig\";\nexport type { SiteConfig, SiteMode } from \"./schema/siteConfig\";\n// 5.0: Field-IR (primo-port), symbolen en custom blocks.\nexport { FieldSchema, FieldsSchema, fieldsToZod, fieldsDefaults, isFieldVisible, isRichTextKey } from \"./schema/fields\";\nexport type { Field, FieldHints, ShowIf } from \"./schema/fields\";\nexport { SymbolSchema } from \"./schema/symbols\";\nexport type { SymbolDefinition, StoredSymbol } from \"./schema/symbols\";\nexport { CustomBlockSchema } from \"./schema/customBlocks\";\nexport type { CustomBlock, CustomBlock as CustomBlockData } from \"./schema/customBlocks\";\nexport { customBlockToDefinition } from \"./blocks/customTemplate/definition\";\nexport { interpretTemplate, scopeCss } from \"./blocks/customTemplate/interpret\";\n// 5.0: localisatie — overlay-model (primo's locale-per-waarde, additief vertaald).\nexport {\n siteLocales,\n parseLocaleSlugs,\n localizedPath,\n localizePage,\n localizeBlocks,\n pruneTranslations,\n TranslationsSchema,\n} from \"./i18n/overlay\";\nexport type { Translations, LocaleConfig } from \"./i18n/overlay\";\nexport type { ThemeTokens, NavItem, NavLeaf, Redirect, SiteSettings, PublicSiteSettings, FormsSender } from \"./schema/settings\";\nexport { zoekRedirect, normaliseerPad, navHref, isExterneLink } from \"./schema/settings\";\nexport type { Seo } from \"./schema/seo\";\nexport type { Page, PageStatus } from \"./schema/pages\";\nexport type { FormDefinition, FormField } from \"./schema/forms\";\n\n// Auth\nexport { AuthProvider, useAuth } from \"./auth/AuthProvider\";\nexport { LoginForm } from \"./auth/LoginForm\";\nexport {\n roleForSite,\n canEdit,\n canManageSite,\n isSuperadmin,\n type Role,\n type XiClaims,\n} from \"./auth/roles\";\n\n// De legacy inline-laag (ContentProvider/useContent + EditableText/EditableRichText/EditableImage,\n// het v1 platte `cms/content`-model) is in 5.0 VERWIJDERD, zoals bij de deprecatie aangekondigd.\n// Inline bewerken loopt via het block-model: markeer tekstvelden met `data-xicms-edit` in de Render.\nexport type { NewsArticle, MediaItem, MediaVariant } from \"./content/types\";\n\nexport { EditBar } from \"./components/EditBar\";\nexport { ExternEmbed } from \"./components/ExternEmbed\";\nexport { ResponsiveImage } from \"./components/ResponsiveImage\";\nexport { PageView } from \"./components/PageView\";\nexport { NewsList, NewsArticleView, useNews } from \"./components/News\";\n\n// Block-systeem (runtime: registry + renderer; editors zitten in /admin)\nexport {\n defineBlock,\n createRegistry,\n mergeRegistry,\n validateBlocks,\n buildBlockAddOptions,\n type BlockDefinition,\n type BlockRegistry,\n type BlockRenderProps,\n type BlockEditorProps,\n type BlockCategory,\n} from \"./blocks/registry\";\nexport { BlockRenderer } from \"./blocks/BlockRenderer\";\nexport { RegistryProvider, useRegistry, BlockDataProvider, useBlockData } from \"./blocks/context\";\nexport { builtinBlocks, ConsentEmbed } from \"./blocks/builtins\";\nexport { PageRenderer } from \"./render/PageRenderer\";\nexport { PublishedPage } from \"./render/PublishedPage\";\n\n// Module-systeem (XiCMS 3.0): modules bundelen blocks + instellingen; per site aan/uit + te stylen.\nexport {\n defineModule,\n resolveModules,\n isModuleActive,\n ModulesProvider,\n useModules,\n useModuleActive,\n useModuleSettings,\n applyBlockOverrides,\n moduleIdForBlockType,\n builtinModules,\n validateModuleContract,\n assertModuleContract,\n useConsent,\n ConsentBanner,\n ConsentGate,\n ConsentReopenLink,\n type ConsentState,\n type ConsentSettings,\n type ConsentCategory,\n type ModuleDefinition,\n type ModuleSiteSetting,\n type ModulesSiteConfig,\n type Capability,\n type ResolvedModules,\n type BlockOverride,\n type BlockOverrides,\n} from \"./modules\";\n\n// Demo-lock\nexport { DemoLock } from \"./lock/DemoLock\";\n\n// Demo-bewerkmodus (lokaal-only) leeft op het subpad `@xiwebdesign/xicms-core/demo` — dit zijn\n// demo-store-internals die niet in de publieke runtime-API thuishoren (klantsites gebruiken ze nooit;\n// alleen de XiCMS.nl-showcase). DemoStudio wordt intern door XiCMSProvider gerenderd.\n\n// Firebase (client)\nexport {\n getFirebaseApp,\n getFirebaseAuth,\n getDb,\n getBucket,\n isFirebaseConfigured,\n} from \"./firebase/client\";\nexport { initAppCheck } from \"./firebase/appcheck\";\nexport { SiteChrome } from \"./SiteChrome\";\nexport { CORE_VERSION, CORE_PACKAGE, isNieuwer } from \"./version\";\n"],"mappings":"AAQA,SAAS,qBAAqB;AAC9B,SAAS,qBAAqB;AAO9B,SAAS,aAAa,gBAAgB;AAItC,SAAS,cAAc,wBAAwB;AAI/C,SAAS,KAAK,eAAe,mBAAmB,+BAA+B;AAE/E,cAAc;AACd;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,kBAAkB;AAE3B,SAAS,eAAe;
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * Publieke runtime-API van @xiwebdesign/xicms-core (lichte client/runtime laag).\n * - Admin (TipTap/Radix) zit in \"@xiwebdesign/xicms-core/admin\".\n * - Server-only code (firebase-admin, sanitize, SEO) zit in \"@xiwebdesign/xicms-core/server\".\n * - Pure schema's in \"@xiwebdesign/xicms-core/schema\".\n */\n\n// Provider & config\nexport { XiCMSProvider } from \"./XiCMSProvider\";\nexport { useSiteConfig } from \"./config\";\n\n// Theming & design-primitieven (maatwerk zonder core te forken).\n// - `defineTheme` maakt een eigen Astryx-thema (tokens + component-overrides) → geef door als\n// XiCMSProvider `astryxTheme`-prop.\n// - De `ui`-primitieven (Card/Stack/Grid/Heading/Text/Btn…) zijn de bouwstenen waarop de ingebouwde\n// blokken draaien; gebruik ze in eigen blokken voor een consistent maar te herstijlen uiterlijk.\nexport { defineTheme, useTheme } from \"@astryxdesign/core/theme\";\nexport type { DefinedTheme } from \"@astryxdesign/core/theme\";\n// Framework-router-integratie: geef `next/link` door als XiCMSProvider `linkComponent`-prop\n// (soepele client-nav + prefetch op alle Astryx-knoppen/links). `useLinkComponent` voor eigen blokken.\nexport { LinkProvider, useLinkComponent } from \"@astryxdesign/core/Link\";\nexport type { LinkComponentType } from \"@astryxdesign/core/Link\";\n// Beeldoptimalisatie: geef `next/image` door als XiCMSProvider `imageComponent`-prop. `Img` is de\n// wrapper die de blokken gebruiken; `useImageComponent` voor eigen blokken.\nexport { Img, ImageProvider, useImageComponent, InlineImageEditProvider } from \"./media/ImageContext\";\nexport type { ImageComponentType, ImgProps } from \"./media/ImageContext\";\nexport * from \"./blocks/ui\";\nexport {\n SiteSettingsProvider,\n useSiteSettings,\n useMergedSiteConfig,\n} from \"./settings/useSiteSettings\";\nexport { SiteFooter } from \"./components/site/SiteFooter\";\n// 7.24: de beheerde hoofdnavigatie — de enige plek die `settings.nav` leest. Zie SiteNav.tsx.\nexport { SiteNav } from \"./components/site/SiteNav\";\n// 8.13: kop met logo, menu, actieknop, hamburgermenu en mobiele belbalk. Zie SiteHeader.tsx.\nexport { SiteHeader } from \"./components/site/SiteHeader\";\nexport { EditorProvider, useEditor } from \"./editor/EditorProvider\";\nexport {\n definePattern,\n instantiatePattern,\n collectPatternTypes,\n builtinPatterns,\n type Pattern,\n type PatternBlock,\n} from \"./patterns\";\nexport { builtinThemePresets, type ThemePreset } from \"./theme/presets\";\nexport { defineSiteConfig } from \"./schema/siteConfig\";\nexport type { SiteConfig, SiteMode } from \"./schema/siteConfig\";\n// 5.0: Field-IR (primo-port), symbolen en custom blocks.\nexport { FieldSchema, FieldsSchema, fieldsToZod, fieldsDefaults, isFieldVisible, isRichTextKey } from \"./schema/fields\";\nexport type { Field, FieldHints, ShowIf } from \"./schema/fields\";\nexport { SymbolSchema } from \"./schema/symbols\";\nexport type { SymbolDefinition, StoredSymbol } from \"./schema/symbols\";\nexport { CustomBlockSchema } from \"./schema/customBlocks\";\nexport type { CustomBlock, CustomBlock as CustomBlockData } from \"./schema/customBlocks\";\nexport { customBlockToDefinition } from \"./blocks/customTemplate/definition\";\nexport { interpretTemplate, scopeCss } from \"./blocks/customTemplate/interpret\";\n// 5.0: localisatie — overlay-model (primo's locale-per-waarde, additief vertaald).\nexport {\n siteLocales,\n parseLocaleSlugs,\n localizedPath,\n localizePage,\n localizeBlocks,\n pruneTranslations,\n TranslationsSchema,\n} from \"./i18n/overlay\";\nexport type { Translations, LocaleConfig } from \"./i18n/overlay\";\nexport type { ThemeTokens, NavItem, NavLeaf, Redirect, SiteSettings, PublicSiteSettings, FormsSender } from \"./schema/settings\";\nexport { zoekRedirect, normaliseerPad, navHref, isExterneLink } from \"./schema/settings\";\nexport type { Seo } from \"./schema/seo\";\n// 8.13: bedrijfsprofiel (adres, telefoon, openingstijden) + hulpjes voor eigen headers/footers.\nexport { BusinessSchema, BEDRIJFSTYPES, type Business, type BusinessException } from \"./schema/business\";\nexport { adresRegels, telLink, routeLink, afwijkingOp, komendeAfwijkingen, afwijkingDatumTekst, isOpenNuMetAfwijkingen, heeftProfiel } from \"./bedrijf/bedrijf\";\nexport type { Page, PageStatus } from \"./schema/pages\";\nexport type { FormDefinition, FormField } from \"./schema/forms\";\n\n// Auth\nexport { AuthProvider, useAuth } from \"./auth/AuthProvider\";\nexport { LoginForm } from \"./auth/LoginForm\";\nexport {\n roleForSite,\n canEdit,\n canManageSite,\n isSuperadmin,\n type Role,\n type XiClaims,\n} from \"./auth/roles\";\n\n// De legacy inline-laag (ContentProvider/useContent + EditableText/EditableRichText/EditableImage,\n// het v1 platte `cms/content`-model) is in 5.0 VERWIJDERD, zoals bij de deprecatie aangekondigd.\n// Inline bewerken loopt via het block-model: markeer tekstvelden met `data-xicms-edit` in de Render.\nexport type { NewsArticle, MediaItem, MediaVariant } from \"./content/types\";\n\nexport { EditBar } from \"./components/EditBar\";\nexport { ExternEmbed } from \"./components/ExternEmbed\";\nexport { ResponsiveImage } from \"./components/ResponsiveImage\";\nexport { PageView, NietGevondenMelder } from \"./components/PageView\";\nexport { NewsList, NewsArticleView, useNews } from \"./components/News\";\n\n// Block-systeem (runtime: registry + renderer; editors zitten in /admin)\nexport {\n defineBlock,\n createRegistry,\n mergeRegistry,\n validateBlocks,\n buildBlockAddOptions,\n type BlockDefinition,\n type BlockRegistry,\n type BlockRenderProps,\n type BlockEditorProps,\n type BlockCategory,\n} from \"./blocks/registry\";\nexport { BlockRenderer } from \"./blocks/BlockRenderer\";\nexport { RegistryProvider, useRegistry, BlockDataProvider, useBlockData } from \"./blocks/context\";\nexport { builtinBlocks, ConsentEmbed } from \"./blocks/builtins\";\nexport { PageRenderer } from \"./render/PageRenderer\";\nexport { PublishedPage } from \"./render/PublishedPage\";\n\n// Module-systeem (XiCMS 3.0): modules bundelen blocks + instellingen; per site aan/uit + te stylen.\nexport {\n defineModule,\n resolveModules,\n isModuleActive,\n ModulesProvider,\n useModules,\n useModuleActive,\n useModuleSettings,\n applyBlockOverrides,\n moduleIdForBlockType,\n builtinModules,\n validateModuleContract,\n assertModuleContract,\n useConsent,\n ConsentBanner,\n ConsentGate,\n ConsentReopenLink,\n type ConsentState,\n type ConsentSettings,\n type ConsentCategory,\n type ModuleDefinition,\n type ModuleSiteSetting,\n type ModulesSiteConfig,\n type Capability,\n type ResolvedModules,\n type BlockOverride,\n type BlockOverrides,\n} from \"./modules\";\n\n// Demo-lock\nexport { DemoLock } from \"./lock/DemoLock\";\n\n// Demo-bewerkmodus (lokaal-only) leeft op het subpad `@xiwebdesign/xicms-core/demo` — dit zijn\n// demo-store-internals die niet in de publieke runtime-API thuishoren (klantsites gebruiken ze nooit;\n// alleen de XiCMS.nl-showcase). DemoStudio wordt intern door XiCMSProvider gerenderd.\n\n// Firebase (client)\nexport {\n getFirebaseApp,\n getFirebaseAuth,\n getDb,\n getBucket,\n isFirebaseConfigured,\n} from \"./firebase/client\";\nexport { initAppCheck } from \"./firebase/appcheck\";\nexport { SiteChrome } from \"./SiteChrome\";\nexport { CORE_VERSION, CORE_PACKAGE, isNieuwer } from \"./version\";\n"],"mappings":"AAQA,SAAS,qBAAqB;AAC9B,SAAS,qBAAqB;AAO9B,SAAS,aAAa,gBAAgB;AAItC,SAAS,cAAc,wBAAwB;AAI/C,SAAS,KAAK,eAAe,mBAAmB,+BAA+B;AAE/E,cAAc;AACd;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,kBAAkB;AAE3B,SAAS,eAAe;AAExB,SAAS,kBAAkB;AAC3B,SAAS,gBAAgB,iBAAiB;AAC1C;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAGK;AACP,SAAS,2BAA6C;AACtD,SAAS,wBAAwB;AAGjC,SAAS,aAAa,cAAc,aAAa,gBAAgB,gBAAgB,qBAAqB;AAEtG,SAAS,oBAAoB;AAE7B,SAAS,yBAAyB;AAElC,SAAS,+BAA+B;AACxC,SAAS,mBAAmB,gBAAgB;AAE5C;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAGP,SAAS,cAAc,gBAAgB,SAAS,qBAAqB;AAGrE,SAAS,gBAAgB,qBAA4D;AACrF,SAAS,aAAa,SAAS,WAAW,aAAa,oBAAoB,qBAAqB,wBAAwB,oBAAoB;AAK5I,SAAS,cAAc,eAAe;AACtC,SAAS,iBAAiB;AAC1B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAGK;AAOP,SAAS,eAAe;AACxB,SAAS,mBAAmB;AAC5B,SAAS,uBAAuB;AAChC,SAAS,UAAU,0BAA0B;AAC7C,SAAS,UAAU,iBAAiB,eAAe;AAGnD;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAMK;AACP,SAAS,qBAAqB;AAC9B,SAAS,kBAAkB,aAAa,mBAAmB,oBAAoB;AAC/E,SAAS,eAAe,oBAAoB;AAC5C,SAAS,oBAAoB;AAC7B,SAAS,qBAAqB;AAG9B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAWK;AAGP,SAAS,gBAAgB;AAOzB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,oBAAoB;AAC7B,SAAS,kBAAkB;AAC3B,SAAS,cAAc,cAAc,iBAAiB;","names":[]}
|
|
@@ -34,3 +34,20 @@ export interface ImgProps {
|
|
|
34
34
|
editFill?: boolean;
|
|
35
35
|
}
|
|
36
36
|
export declare function Img({ src, alt, width, height, sizes, priority, className, style: styleProp, editField, editFill }: ImgProps): import("react").JSX.Element;
|
|
37
|
+
/**
|
|
38
|
+
* Lichte beeldtag voor plekken waar `Img` te veel is (productkaarten, winkelwagen, voor/na,
|
|
39
|
+
* lightbox) — 8.3. Gebruikt de ladder uit de media-seed als die er is, en is anders precies de
|
|
40
|
+
* kale `<img>` die er al stond: géén next/image-terugval, dus geen betaalde transformaties.
|
|
41
|
+
*/
|
|
42
|
+
export declare function SeedImg({ src, alt, sizes, className, style, priority, }: {
|
|
43
|
+
src: string;
|
|
44
|
+
alt: string;
|
|
45
|
+
sizes?: string;
|
|
46
|
+
className?: string;
|
|
47
|
+
style?: CSSProperties;
|
|
48
|
+
priority?: boolean;
|
|
49
|
+
}): import("react").JSX.Element;
|
|
50
|
+
/** De kleinste variant die minstens `minBreedte` breed is (bv. een avatar van 96px op 2x). */
|
|
51
|
+
export declare function useVariantVoor(src: string | undefined, minBreedte: number): string | undefined;
|
|
52
|
+
/** De grootste beschikbare versie (lightbox): volle WebP, anders de hoogste trede, anders het origineel. */
|
|
53
|
+
export declare function useGrootsteVariant(src: string): string;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { bronSet } from "./srcset.js";
|
|
3
4
|
import { createContext, useContext } from "react";
|
|
4
5
|
import { useBlockData } from "../blocks/context.js";
|
|
5
6
|
const ImageContext = createContext(null);
|
|
@@ -24,30 +25,28 @@ function Img({ src, alt, width, height, sizes, priority, className, style: style
|
|
|
24
25
|
const onReplace = useContext(InlineImageEditContext);
|
|
25
26
|
const mediaSeed = useBlockData("media");
|
|
26
27
|
const eigenLadder = mediaSeed?.[src];
|
|
28
|
+
alt = alt || eigenLadder?.alt || "";
|
|
27
29
|
const ladder = eigenLadder?.variants?.sizes ?? [];
|
|
28
30
|
const webp = eigenLadder?.variants?.webp;
|
|
29
31
|
const focal = eigenLadder?.focal;
|
|
30
32
|
const style = focal && !style_heeftPositie(styleProp) ? { ...styleProp, objectPosition: `${Math.round(focal.x * 100)}% ${Math.round(focal.y * 100)}%` } : styleProp;
|
|
31
33
|
const editHook = editField ? { "data-xicms-edit": editField } : void 0;
|
|
32
|
-
const imageEl = ladder.length > 0 ? /* @__PURE__ */
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
}
|
|
49
|
-
)
|
|
50
|
-
] }) : ImageComponent ? /* @__PURE__ */ jsx(
|
|
34
|
+
const imageEl = ladder.length > 0 ? /* @__PURE__ */ jsx("picture", { ...editHook, children: /* @__PURE__ */ jsx(
|
|
35
|
+
"img",
|
|
36
|
+
{
|
|
37
|
+
src,
|
|
38
|
+
srcSet: bronSet(ladder, webp),
|
|
39
|
+
sizes,
|
|
40
|
+
alt,
|
|
41
|
+
width: eigenLadder?.width ?? width,
|
|
42
|
+
height: eigenLadder?.height ?? height,
|
|
43
|
+
loading: priority ? "eager" : "lazy",
|
|
44
|
+
fetchPriority: priority ? "high" : void 0,
|
|
45
|
+
decoding: "async",
|
|
46
|
+
className,
|
|
47
|
+
style
|
|
48
|
+
}
|
|
49
|
+
) }) : ImageComponent ? /* @__PURE__ */ jsx(
|
|
51
50
|
ImageComponent,
|
|
52
51
|
{
|
|
53
52
|
src,
|
|
@@ -98,10 +97,56 @@ function Img({ src, alt, width, height, sizes, priority, className, style: style
|
|
|
98
97
|
}
|
|
99
98
|
return imageEl;
|
|
100
99
|
}
|
|
100
|
+
function SeedImg({
|
|
101
|
+
src,
|
|
102
|
+
alt,
|
|
103
|
+
sizes,
|
|
104
|
+
className,
|
|
105
|
+
style,
|
|
106
|
+
priority
|
|
107
|
+
}) {
|
|
108
|
+
const seed = useBlockData("media")?.[src];
|
|
109
|
+
const srcSet = seed ? bronSet(seed.variants?.sizes, seed.variants?.webp) : void 0;
|
|
110
|
+
const focal = seed?.focal;
|
|
111
|
+
const stijl = focal && !style_heeftPositie(style) ? { ...style, objectPosition: `${Math.round(focal.x * 100)}% ${Math.round(focal.y * 100)}%` } : style;
|
|
112
|
+
return (
|
|
113
|
+
// eslint-disable-next-line @next/next/no-img-element
|
|
114
|
+
/* @__PURE__ */ jsx(
|
|
115
|
+
"img",
|
|
116
|
+
{
|
|
117
|
+
src,
|
|
118
|
+
srcSet,
|
|
119
|
+
sizes: srcSet ? sizes : void 0,
|
|
120
|
+
alt: alt || seed?.alt || "",
|
|
121
|
+
width: seed?.width,
|
|
122
|
+
height: seed?.height,
|
|
123
|
+
loading: priority ? "eager" : "lazy",
|
|
124
|
+
decoding: "async",
|
|
125
|
+
className,
|
|
126
|
+
style: stijl
|
|
127
|
+
}
|
|
128
|
+
)
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
function useVariantVoor(src, minBreedte) {
|
|
132
|
+
const seed = useBlockData("media");
|
|
133
|
+
if (!src) return src;
|
|
134
|
+
const ladder = [...seed?.[src]?.variants?.sizes ?? []].sort((a, b) => a.width - b.width);
|
|
135
|
+
return ladder.find((v) => v.width >= minBreedte)?.url ?? src;
|
|
136
|
+
}
|
|
137
|
+
function useGrootsteVariant(src) {
|
|
138
|
+
const v = useBlockData("media")?.[src]?.variants;
|
|
139
|
+
if (v?.webp?.url) return v.webp.url;
|
|
140
|
+
const ladder = [...v?.sizes ?? []].sort((a, b) => b.width - a.width);
|
|
141
|
+
return ladder[0]?.url ?? src;
|
|
142
|
+
}
|
|
101
143
|
export {
|
|
102
144
|
ImageProvider,
|
|
103
145
|
Img,
|
|
104
146
|
InlineImageEditProvider,
|
|
105
|
-
|
|
147
|
+
SeedImg,
|
|
148
|
+
useGrootsteVariant,
|
|
149
|
+
useImageComponent,
|
|
150
|
+
useVariantVoor
|
|
106
151
|
};
|
|
107
152
|
//# sourceMappingURL=ImageContext.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/media/ImageContext.tsx"],"sourcesContent":["\"use client\";\n\nimport { createContext, useContext, type CSSProperties, type ElementType, type ReactNode } from \"react\";\nimport { useBlockData } from \"../blocks/context\";\nimport type { MediaItem } from \"../content/types\";\n\n/**\n * Optionele framework-beeldcomponent (bv. Next `Image`) voor automatische optimalisatie: responsive\n * `srcset`, moderne formaten (AVIF/WebP), correcte `width/height` (geen layout-shift), lazy-loading.\n * Core importeert `next/image` niet zelf (optionele peer) — de site injecteert 'm via de\n * `imageComponent`-prop op `XiCMSProvider`, net als `linkComponent`. Zonder injectie valt alles terug\n * op een gewone `<img>` (huidig gedrag, werkt overal).\n */\nexport type ImageComponentType = ElementType;\n\nconst ImageContext = createContext<ImageComponentType | null>(null);\n\nexport function ImageProvider({ component, children }: { component?: ImageComponentType; children: ReactNode }) {\n return <ImageContext.Provider value={component ?? null}>{children}</ImageContext.Provider>;\n}\n\nexport function useImageComponent(): ImageComponentType | null {\n return useContext(ImageContext);\n}\n\n/**\n * Inline beeld-bewerken: de visuele editor levert via deze context een `onReplace(field)`-callback\n * voor het GESELECTEERDE blok. Is die actief én geeft een `<Img>` een `editField` mee, dan toont het\n * beeld een vervang-icoontje. Buiten de editor (context = null) rendert `<Img>` exact als voorheen.\n */\n/**\n * `blockKey` komt sinds 7.9 uit de DOM, niet uit een per-blok provider.\n *\n * Tot 7.4 wikkelde de editor élk blok in zijn canvas apart in deze provider, met de blok-key in de\n * closure. Dat canvas is weg — de pagina van de klant ís de editor — en één provider om de hele\n * pagina weet niet meer bij welk blok een foto hoort. De knop lost dat op het moment van klikken\n * op: elk blok draagt al `data-xicms-block` (BlockRenderer), dus `closest()` vanaf de knop is\n * betrouwbaar en kost niets zolang er niemand klikt.\n */\nconst InlineImageEditContext = createContext<((field: string, blockKey?: string) => void) | null>(null);\n\nexport function InlineImageEditProvider({\n onReplace,\n children,\n}: {\n onReplace: ((field: string, blockKey?: string) => void) | null;\n children: ReactNode;\n}) {\n return <InlineImageEditContext.Provider value={onReplace}>{children}</InlineImageEditContext.Provider>;\n}\n\nexport interface ImgProps {\n src: string;\n alt: string;\n /** Intrinsieke breedte/hoogte (verhouding) → nodig voor next/image én tegen CLS. */\n width: number;\n height: number;\n /** Hint voor responsive selectie, bv. \"(max-width: 720px) 100vw, 33vw\". */\n sizes?: string;\n /** Above-the-fold (hero): eager + hoge prioriteit voor LCP. */\n priority?: boolean;\n className?: string;\n style?: CSSProperties;\n /** Blokveld (pad) met de URL — schakelt inline vervangen in de visuele editor in (bv. \"imageUrl\"). */\n editField?: string;\n /** Beeld vult absoluut z'n parent (bv. hero-achtergrond): geen wrapper-box, knop absoluut t.o.v. het blok. */\n editFill?: boolean;\n}\n\n/**\n * Eén beeld-wrapper voor alle blokken. Gebruikt de geïnjecteerde `imageComponent` (next/image) als\n * die er is, anders een gewone `<img>`. De display-grootte regel je met CSS (`style`/`className`,\n * bv. `width:100%;height:100%;object-fit:cover`); `width`/`height` zijn de verhouding.\n */\nfunction style_heeftPositie(style?: CSSProperties): boolean {\n return Boolean(style && \"objectPosition\" in style && style.objectPosition);\n}\n\nexport function Img({ src, alt, width, height, sizes, priority, className, style: styleProp, editField, editFill }: ImgProps) {\n const ImageComponent = useImageComponent();\n const onReplace = useContext(InlineImageEditContext);\n /**\n * Eigen srcset-ladder vóór next/image (7.13). De upload-pipeline (onMediaUpload, sharp) maakt\n * bij élke upload al webp + een maten-ladder; next/image liet dat werk links liggen en\n * transformeerde dezelfde beelden nóg een keer bij Vercel — betaalde image-transformations,\n * plus transformatie-latency op de eerste hit. De route levert daarom per pagina een\n * `media`-seed (url → varianten, zie server/blockData.ts); staat de URL van dit beeld daarin,\n * dan renderen we een kale <picture> met de eigen ladder en blijft Vercel er helemaal buiten.\n * Geen seed (editor, oudere site, extern beeld zoals Unsplash) → het bestaande pad.\n */\n const mediaSeed = useBlockData<Record<string, Pick<MediaItem, \"variants\" | \"width\" | \"height\" | \"focal\">>>(\"media\");\n const eigenLadder = mediaSeed?.[src];\n const ladder = eigenLadder?.variants?.sizes ?? [];\n const webp = eigenLadder?.variants?.webp;\n // Focuspunt (7.24): staat er in het beheer een focuspunt op deze foto, dan snijdt `object-fit:\n // cover` rond dát punt bij in plaats van rond het midden. Alleen als het blok zelf geen\n // object-position zet — een blok dat bewust \"top\" wil, wint.\n const focal = eigenLadder?.focal;\n const style = focal && !style_heeftPositie(styleProp)\n ? { ...styleProp, objectPosition: `${Math.round(focal.x * 100)}% ${Math.round(focal.y * 100)}%` }\n : styleProp;\n // De rode wijzigings-highlight (visuele editor) zoekt op `data-xicms-edit=\"<veld>\"` binnen het\n // geselecteerde blok — voor foto's stond dat hook er nergens op (alleen tekstvelden hadden 'm),\n // dus een vervangen foto bleef onopgemerkt tussen de andere, wél gemarkeerde wijzigingen. Eén\n // plek hier lost het voor elk blok met een `<Img editField=…>` tegelijk op.\n const editHook = editField ? { \"data-xicms-edit\": editField } : undefined;\n const imageEl = ladder.length > 0 ? (\n <picture {...editHook}>\n {webp && <source type=\"image/webp\" srcSet={`${webp.url} ${webp.width}w`} sizes={sizes} />}\n {/* eslint-disable-next-line @next/next/no-img-element */}\n <img\n src={src}\n srcSet={ladder.map((v) => `${v.url} ${v.width}w`).join(\", \")}\n sizes={sizes}\n alt={alt}\n width={eigenLadder?.width ?? width}\n height={eigenLadder?.height ?? height}\n loading={priority ? \"eager\" : \"lazy\"}\n fetchPriority={priority ? \"high\" : undefined}\n decoding=\"async\"\n className={className}\n style={style}\n />\n </picture>\n ) : ImageComponent ? (\n <ImageComponent\n src={src}\n alt={alt}\n width={width}\n height={height}\n sizes={sizes}\n priority={priority || undefined}\n className={className}\n style={style}\n {...editHook}\n />\n ) : (\n // eslint-disable-next-line @next/next/no-img-element\n <img\n src={src}\n alt={alt}\n width={width}\n height={height}\n sizes={sizes}\n loading={priority ? \"eager\" : \"lazy\"}\n fetchPriority={priority ? \"high\" : undefined}\n className={className}\n style={style}\n {...editHook}\n />\n );\n\n // In de visuele editor (geselecteerd blok): toon een vervang-icoontje over het beeld. We wijzigen\n // alleen de URL → de grootte/stijl blijft (die komt uit het blok), dus blok én beeld behouden hun maat.\n if (onReplace && editField) {\n const replace = (e: { preventDefault: () => void; stopPropagation: () => void; currentTarget?: unknown }) => {\n e.preventDefault();\n e.stopPropagation();\n const el = e.currentTarget as HTMLElement | undefined;\n const key = el?.closest?.(\"[data-xicms-block]\")?.getAttribute(\"data-xicms-block\") ?? undefined;\n onReplace(editField, key);\n };\n const btn = (\n <button type=\"button\" className={`xicms-ve-img__btn${editFill ? \" xicms-ve-img__btn--fill\" : \"\"}`} title=\"Klik om de foto te wijzigen\" onClick={replace}>\n 📷 Foto wijzigen\n </button>\n );\n // Vullend (hero-achtergrond): geen wrapper-box (zou het absoluut gepositioneerde beeld breken);\n // de knop is absoluut t.o.v. het blok-element zelf (dat is `position:relative`).\n if (editFill) return (<>{imageEl}{btn}</>);\n // In-flow beeld: hele beeld klikbaar (duidelijke affordance) + knop rechtsboven.\n return (\n <span className=\"xicms-ve-img\" style={{ position: \"relative\", display: \"block\" }} title=\"Klik om de foto te wijzigen\" onClick={replace}>\n {imageEl}\n {btn}\n </span>\n );\n }\n return imageEl;\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/media/ImageContext.tsx"],"sourcesContent":["\"use client\";\n\nimport { bronSet } from \"./srcset\";\nimport { createContext, useContext, type CSSProperties, type ElementType, type ReactNode } from \"react\";\nimport { useBlockData } from \"../blocks/context\";\nimport type { MediaItem } from \"../content/types\";\n\n/**\n * Optionele framework-beeldcomponent (bv. Next `Image`) voor automatische optimalisatie: responsive\n * `srcset`, moderne formaten (AVIF/WebP), correcte `width/height` (geen layout-shift), lazy-loading.\n * Core importeert `next/image` niet zelf (optionele peer) — de site injecteert 'm via de\n * `imageComponent`-prop op `XiCMSProvider`, net als `linkComponent`. Zonder injectie valt alles terug\n * op een gewone `<img>` (huidig gedrag, werkt overal).\n */\nexport type ImageComponentType = ElementType;\n\nconst ImageContext = createContext<ImageComponentType | null>(null);\n\nexport function ImageProvider({ component, children }: { component?: ImageComponentType; children: ReactNode }) {\n return <ImageContext.Provider value={component ?? null}>{children}</ImageContext.Provider>;\n}\n\nexport function useImageComponent(): ImageComponentType | null {\n return useContext(ImageContext);\n}\n\n/**\n * Inline beeld-bewerken: de visuele editor levert via deze context een `onReplace(field)`-callback\n * voor het GESELECTEERDE blok. Is die actief én geeft een `<Img>` een `editField` mee, dan toont het\n * beeld een vervang-icoontje. Buiten de editor (context = null) rendert `<Img>` exact als voorheen.\n */\n/**\n * `blockKey` komt sinds 7.9 uit de DOM, niet uit een per-blok provider.\n *\n * Tot 7.4 wikkelde de editor élk blok in zijn canvas apart in deze provider, met de blok-key in de\n * closure. Dat canvas is weg — de pagina van de klant ís de editor — en één provider om de hele\n * pagina weet niet meer bij welk blok een foto hoort. De knop lost dat op het moment van klikken\n * op: elk blok draagt al `data-xicms-block` (BlockRenderer), dus `closest()` vanaf de knop is\n * betrouwbaar en kost niets zolang er niemand klikt.\n */\nconst InlineImageEditContext = createContext<((field: string, blockKey?: string) => void) | null>(null);\n\nexport function InlineImageEditProvider({\n onReplace,\n children,\n}: {\n onReplace: ((field: string, blockKey?: string) => void) | null;\n children: ReactNode;\n}) {\n return <InlineImageEditContext.Provider value={onReplace}>{children}</InlineImageEditContext.Provider>;\n}\n\nexport interface ImgProps {\n src: string;\n alt: string;\n /** Intrinsieke breedte/hoogte (verhouding) → nodig voor next/image én tegen CLS. */\n width: number;\n height: number;\n /** Hint voor responsive selectie, bv. \"(max-width: 720px) 100vw, 33vw\". */\n sizes?: string;\n /** Above-the-fold (hero): eager + hoge prioriteit voor LCP. */\n priority?: boolean;\n className?: string;\n style?: CSSProperties;\n /** Blokveld (pad) met de URL — schakelt inline vervangen in de visuele editor in (bv. \"imageUrl\"). */\n editField?: string;\n /** Beeld vult absoluut z'n parent (bv. hero-achtergrond): geen wrapper-box, knop absoluut t.o.v. het blok. */\n editFill?: boolean;\n}\n\n/**\n * Eén beeld-wrapper voor alle blokken. Gebruikt de geïnjecteerde `imageComponent` (next/image) als\n * die er is, anders een gewone `<img>`. De display-grootte regel je met CSS (`style`/`className`,\n * bv. `width:100%;height:100%;object-fit:cover`); `width`/`height` zijn de verhouding.\n */\nfunction style_heeftPositie(style?: CSSProperties): boolean {\n return Boolean(style && \"objectPosition\" in style && style.objectPosition);\n}\n\nexport function Img({ src, alt, width, height, sizes, priority, className, style: styleProp, editField, editFill }: ImgProps) {\n const ImageComponent = useImageComponent();\n const onReplace = useContext(InlineImageEditContext);\n /**\n * Eigen srcset-ladder vóór next/image (7.13). De upload-pipeline (onMediaUpload, sharp) maakt\n * bij élke upload al webp + een maten-ladder; next/image liet dat werk links liggen en\n * transformeerde dezelfde beelden nóg een keer bij Vercel — betaalde image-transformations,\n * plus transformatie-latency op de eerste hit. De route levert daarom per pagina een\n * `media`-seed (url → varianten, zie server/blockData.ts); staat de URL van dit beeld daarin,\n * dan renderen we een kale <picture> met de eigen ladder en blijft Vercel er helemaal buiten.\n * Geen seed (editor, oudere site, extern beeld zoals Unsplash) → het bestaande pad.\n */\n const mediaSeed = useBlockData<Record<string, Pick<MediaItem, \"variants\" | \"width\" | \"height\" | \"focal\" | \"alt\">>>(\"media\");\n const eigenLadder = mediaSeed?.[src];\n // 8.4: geen alt in het blok? Dan de beschrijving uit de mediabibliotheek (als die er is).\n alt = alt || eigenLadder?.alt || \"\";\n const ladder = eigenLadder?.variants?.sizes ?? [];\n const webp = eigenLadder?.variants?.webp;\n // Focuspunt (7.24): staat er in het beheer een focuspunt op deze foto, dan snijdt `object-fit:\n // cover` rond dát punt bij in plaats van rond het midden. Alleen als het blok zelf geen\n // object-position zet — een blok dat bewust \"top\" wil, wint.\n const focal = eigenLadder?.focal;\n const style = focal && !style_heeftPositie(styleProp)\n ? { ...styleProp, objectPosition: `${Math.round(focal.x * 100)}% ${Math.round(focal.y * 100)}%` }\n : styleProp;\n // De rode wijzigings-highlight (visuele editor) zoekt op `data-xicms-edit=\"<veld>\"` binnen het\n // geselecteerde blok — voor foto's stond dat hook er nergens op (alleen tekstvelden hadden 'm),\n // dus een vervangen foto bleef onopgemerkt tussen de andere, wél gemarkeerde wijzigingen. Eén\n // plek hier lost het voor elk blok met een `<Img editField=…>` tegelijk op.\n const editHook = editField ? { \"data-xicms-edit\": editField } : undefined;\n const imageEl = ladder.length > 0 ? (\n <picture {...editHook}>\n {/* 8.3: geen losse <source> meer — die liet de browser altijd de volle WebP kiezen. */}\n {/* eslint-disable-next-line @next/next/no-img-element */}\n <img\n src={src}\n srcSet={bronSet(ladder, webp)}\n sizes={sizes}\n alt={alt}\n width={eigenLadder?.width ?? width}\n height={eigenLadder?.height ?? height}\n loading={priority ? \"eager\" : \"lazy\"}\n fetchPriority={priority ? \"high\" : undefined}\n decoding=\"async\"\n className={className}\n style={style}\n />\n </picture>\n ) : ImageComponent ? (\n <ImageComponent\n src={src}\n alt={alt}\n width={width}\n height={height}\n sizes={sizes}\n priority={priority || undefined}\n className={className}\n style={style}\n {...editHook}\n />\n ) : (\n // eslint-disable-next-line @next/next/no-img-element\n <img\n src={src}\n alt={alt}\n width={width}\n height={height}\n sizes={sizes}\n loading={priority ? \"eager\" : \"lazy\"}\n fetchPriority={priority ? \"high\" : undefined}\n className={className}\n style={style}\n {...editHook}\n />\n );\n\n // In de visuele editor (geselecteerd blok): toon een vervang-icoontje over het beeld. We wijzigen\n // alleen de URL → de grootte/stijl blijft (die komt uit het blok), dus blok én beeld behouden hun maat.\n if (onReplace && editField) {\n const replace = (e: { preventDefault: () => void; stopPropagation: () => void; currentTarget?: unknown }) => {\n e.preventDefault();\n e.stopPropagation();\n const el = e.currentTarget as HTMLElement | undefined;\n const key = el?.closest?.(\"[data-xicms-block]\")?.getAttribute(\"data-xicms-block\") ?? undefined;\n onReplace(editField, key);\n };\n const btn = (\n <button type=\"button\" className={`xicms-ve-img__btn${editFill ? \" xicms-ve-img__btn--fill\" : \"\"}`} title=\"Klik om de foto te wijzigen\" onClick={replace}>\n 📷 Foto wijzigen\n </button>\n );\n // Vullend (hero-achtergrond): geen wrapper-box (zou het absoluut gepositioneerde beeld breken);\n // de knop is absoluut t.o.v. het blok-element zelf (dat is `position:relative`).\n if (editFill) return (<>{imageEl}{btn}</>);\n // In-flow beeld: hele beeld klikbaar (duidelijke affordance) + knop rechtsboven.\n return (\n <span className=\"xicms-ve-img\" style={{ position: \"relative\", display: \"block\" }} title=\"Klik om de foto te wijzigen\" onClick={replace}>\n {imageEl}\n {btn}\n </span>\n );\n }\n return imageEl;\n}\n\ntype MediaSeed = Record<string, Pick<MediaItem, \"variants\" | \"width\" | \"height\" | \"focal\" | \"alt\">>;\n\n/**\n * Lichte beeldtag voor plekken waar `Img` te veel is (productkaarten, winkelwagen, voor/na,\n * lightbox) — 8.3. Gebruikt de ladder uit de media-seed als die er is, en is anders precies de\n * kale `<img>` die er al stond: géén next/image-terugval, dus geen betaalde transformaties.\n */\nexport function SeedImg({\n src,\n alt,\n sizes,\n className,\n style,\n priority,\n}: {\n src: string;\n alt: string;\n sizes?: string;\n className?: string;\n style?: CSSProperties;\n priority?: boolean;\n}) {\n const seed = useBlockData<MediaSeed>(\"media\")?.[src];\n const srcSet = seed ? bronSet(seed.variants?.sizes, seed.variants?.webp) : undefined;\n const focal = seed?.focal;\n const stijl = focal && !style_heeftPositie(style)\n ? { ...style, objectPosition: `${Math.round(focal.x * 100)}% ${Math.round(focal.y * 100)}%` }\n : style;\n return (\n // eslint-disable-next-line @next/next/no-img-element\n <img\n src={src}\n srcSet={srcSet}\n sizes={srcSet ? sizes : undefined}\n alt={alt || seed?.alt || \"\"}\n width={seed?.width}\n height={seed?.height}\n loading={priority ? \"eager\" : \"lazy\"}\n decoding=\"async\"\n className={className}\n style={stijl}\n />\n );\n}\n\n/** De kleinste variant die minstens `minBreedte` breed is (bv. een avatar van 96px op 2x). */\nexport function useVariantVoor(src: string | undefined, minBreedte: number): string | undefined {\n const seed = useBlockData<MediaSeed>(\"media\");\n if (!src) return src;\n const ladder = [...(seed?.[src]?.variants?.sizes ?? [])].sort((a, b) => a.width - b.width);\n return ladder.find((v) => v.width >= minBreedte)?.url ?? src;\n}\n\n/** De grootste beschikbare versie (lightbox): volle WebP, anders de hoogste trede, anders het origineel. */\nexport function useGrootsteVariant(src: string): string {\n const v = useBlockData<MediaSeed>(\"media\")?.[src]?.variants;\n if (v?.webp?.url) return v.webp.url;\n const ladder = [...(v?.sizes ?? [])].sort((a, b) => b.width - a.width);\n return ladder[0]?.url ?? src;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Alt-tekst uit de mediabibliotheek invullen in rich text (8.10).
|
|
3
|
+
*
|
|
4
|
+
* Een foto die je in een tekstblok plakt of sleept krijgt `alt=""` in de HTML, en de melding zei
|
|
5
|
+
* "geef hem in Media een beschrijving". Dat hielp niet: de beschrijving in Media kwam nooit in die
|
|
6
|
+
* HTML terecht. Nu wel, bij het tonen: een `<img>` zonder alt krijgt de beschrijving uit de
|
|
7
|
+
* bibliotheek (dezelfde media-seed die blokken al gebruiken). Een eigen alt wint altijd.
|
|
8
|
+
*/
|
|
9
|
+
export declare function vulAltIn(html: string, altVoor: (src: string) => string | undefined): string;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
function vulAltIn(html, altVoor) {
|
|
2
|
+
if (!html || !html.includes("<img")) return html;
|
|
3
|
+
return html.replace(/<img\b[^>]*>/gi, (tag) => {
|
|
4
|
+
const src = /\ssrc\s*=\s*"([^"]*)"/i.exec(tag)?.[1];
|
|
5
|
+
if (!src) return tag;
|
|
6
|
+
const huidig = /\salt\s*=\s*"([^"]*)"/i.exec(tag);
|
|
7
|
+
if (huidig && huidig[1].trim()) return tag;
|
|
8
|
+
const alt = altVoor(src.replace(/&/g, "&"));
|
|
9
|
+
if (!alt) return tag;
|
|
10
|
+
const veilig = alt.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
|
|
11
|
+
return huidig ? tag.replace(huidig[0], ` alt="${veilig}"`) : tag.replace(/<img\b/i, `<img alt="${veilig}"`);
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
export {
|
|
15
|
+
vulAltIn
|
|
16
|
+
};
|
|
17
|
+
//# sourceMappingURL=altInHtml.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/media/altInHtml.ts"],"sourcesContent":["/**\n * Alt-tekst uit de mediabibliotheek invullen in rich text (8.10).\n *\n * Een foto die je in een tekstblok plakt of sleept krijgt `alt=\"\"` in de HTML, en de melding zei\n * \"geef hem in Media een beschrijving\". Dat hielp niet: de beschrijving in Media kwam nooit in die\n * HTML terecht. Nu wel, bij het tonen: een `<img>` zonder alt krijgt de beschrijving uit de\n * bibliotheek (dezelfde media-seed die blokken al gebruiken). Een eigen alt wint altijd.\n */\nexport function vulAltIn(html: string, altVoor: (src: string) => string | undefined): string {\n if (!html || !html.includes(\"<img\")) return html;\n return html.replace(/<img\\b[^>]*>/gi, (tag) => {\n const src = /\\ssrc\\s*=\\s*\"([^\"]*)\"/i.exec(tag)?.[1];\n if (!src) return tag;\n const huidig = /\\salt\\s*=\\s*\"([^\"]*)\"/i.exec(tag);\n if (huidig && huidig[1].trim()) return tag;\n const alt = altVoor(src.replace(/&/g, \"&\"));\n if (!alt) return tag;\n const veilig = alt.replace(/&/g, \"&\").replace(/\"/g, \""\").replace(/</g, \"<\").replace(/>/g, \">\");\n return huidig ? tag.replace(huidig[0], ` alt=\"${veilig}\"`) : tag.replace(/<img\\b/i, `<img alt=\"${veilig}\"`);\n });\n}\n"],"mappings":"AAQO,SAAS,SAAS,MAAc,SAAsD;AAC3F,MAAI,CAAC,QAAQ,CAAC,KAAK,SAAS,MAAM,EAAG,QAAO;AAC5C,SAAO,KAAK,QAAQ,kBAAkB,CAAC,QAAQ;AAC7C,UAAM,MAAM,yBAAyB,KAAK,GAAG,IAAI,CAAC;AAClD,QAAI,CAAC,IAAK,QAAO;AACjB,UAAM,SAAS,yBAAyB,KAAK,GAAG;AAChD,QAAI,UAAU,OAAO,CAAC,EAAE,KAAK,EAAG,QAAO;AACvC,UAAM,MAAM,QAAQ,IAAI,QAAQ,UAAU,GAAG,CAAC;AAC9C,QAAI,CAAC,IAAK,QAAO;AACjB,UAAM,SAAS,IAAI,QAAQ,MAAM,OAAO,EAAE,QAAQ,MAAM,QAAQ,EAAE,QAAQ,MAAM,MAAM,EAAE,QAAQ,MAAM,MAAM;AAC5G,WAAO,SAAS,IAAI,QAAQ,OAAO,CAAC,GAAG,SAAS,MAAM,GAAG,IAAI,IAAI,QAAQ,WAAW,aAAa,MAAM,GAAG;AAAA,EAC5G,CAAC;AACH;","names":[]}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* De srcset voor een geüpload beeld (8.3). De upload-pipeline maakt een WebP-ladder (320…1280) én
|
|
3
|
+
* een volle WebP (tot 2048). Tot 8.3 stond die volle WebP als enige kandidaat in een
|
|
4
|
+
* `<source type="image/webp">` — en elke moderne browser kiest de `<source>`, dus de ladder op de
|
|
5
|
+
* `<img>` werd nooit gebruikt: een telefoon downloadde het 2048-beeld voor een kaartje van 300px.
|
|
6
|
+
* Nu één srcset met de hele ladder plus de volle versie als grootste trede; de browser kiest zelf.
|
|
7
|
+
*/
|
|
8
|
+
export interface Variant {
|
|
9
|
+
url: string;
|
|
10
|
+
width: number;
|
|
11
|
+
}
|
|
12
|
+
export declare function bronSet(ladder: Variant[] | undefined, volle?: Variant | null): string | undefined;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
function bronSet(ladder, volle) {
|
|
2
|
+
const treden = [...ladder ?? []].filter((v) => v.url && v.width > 0);
|
|
3
|
+
const grootste = treden.reduce((m, v) => Math.max(m, v.width), 0);
|
|
4
|
+
if (volle?.url && volle.width > grootste) treden.push(volle);
|
|
5
|
+
if (treden.length === 0) return void 0;
|
|
6
|
+
const uniek = /* @__PURE__ */ new Map();
|
|
7
|
+
for (const v of treden) if (!uniek.has(v.width)) uniek.set(v.width, v);
|
|
8
|
+
return [...uniek.values()].sort((a, b) => a.width - b.width).map((v) => `${v.url} ${v.width}w`).join(", ");
|
|
9
|
+
}
|
|
10
|
+
export {
|
|
11
|
+
bronSet
|
|
12
|
+
};
|
|
13
|
+
//# sourceMappingURL=srcset.js.map
|