@riverbankcms/sdk 0.127.0 → 0.129.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (178) hide show
  1. package/README.md +33 -0
  2. package/dist/{PreviewEditorSidebar-BXtfF7tp.mjs → PreviewEditorSidebar-B43CJ0g_.mjs} +9 -33
  3. package/dist/{PreviewEditorUI-Dou73Q0K.mjs → PreviewEditorUI-DHirVkeM.mjs} +3 -3
  4. package/dist/{PreviewQueryProvider-DgFDIwvK.mjs → PreviewQueryProvider-B1kbhaJD.mjs} +1 -1
  5. package/dist/SdkPreviewModeRuntime-BJumZy1B.mjs +11209 -0
  6. package/dist/{SiteChromeCustomizeContext-DZiDBAYu.mjs → SiteChromeCustomizeContext-D9SlpwEj.mjs} +31757 -1621
  7. package/dist/_dts/ai/src/contracts/proposals.d.ts +288 -36
  8. package/dist/_dts/api/src/bookingClosures.d.ts +19 -3
  9. package/dist/_dts/api/src/bookingManagementEndpoints.d.ts +4 -3
  10. package/dist/_dts/api/src/bookingRecords.d.ts +0 -13
  11. package/dist/_dts/api/src/commercePortalEndpoints.d.ts +2 -2
  12. package/dist/_dts/api/src/communications.d.ts +2 -1
  13. package/dist/_dts/api/src/contactFormSummary.d.ts +15 -0
  14. package/dist/_dts/api/src/contentRuntime.d.ts +2 -5
  15. package/dist/_dts/api/src/endpoints.d.ts +1 -1
  16. package/dist/_dts/api/src/footerSettings.d.ts +11 -0
  17. package/dist/_dts/api/src/index.d.ts +2 -1
  18. package/dist/_dts/api/src/occurrenceScheduling.d.ts +48 -0
  19. package/dist/_dts/api/src/participantMessaging.d.ts +5 -3
  20. package/dist/_dts/api/src/publicExperience/siteEndpoints.d.ts +7 -0
  21. package/dist/_dts/api/src/sdkContracts.d.ts +7 -5
  22. package/dist/_dts/api/src/siteOperations.d.ts +12 -3
  23. package/dist/_dts/api/src/sitePlatformEndpoints.d.ts +3 -2
  24. package/dist/_dts/blocks/src/PageRenderer.d.ts +20 -10
  25. package/dist/_dts/blocks/src/client/form.d.ts +1 -0
  26. package/dist/_dts/blocks/src/client/newsletter-form.d.ts +1 -0
  27. package/dist/_dts/blocks/src/client/site-chrome.d.ts +1 -0
  28. package/dist/_dts/blocks/src/contracts/proof-block-islands.d.ts +4 -8
  29. package/dist/_dts/blocks/src/index.d.ts +2 -1
  30. package/dist/_dts/blocks/src/pageRendererBoundaries.d.ts +30 -0
  31. package/dist/_dts/blocks/src/pageRenderingMode.d.ts +37 -0
  32. package/dist/_dts/blocks/src/rendering/server.d.ts +1 -1
  33. package/dist/_dts/blocks/src/server.d.ts +1 -1
  34. package/dist/_dts/blocks/src/system/blocks/event-registration.d.ts +41 -0
  35. package/dist/_dts/blocks/src/system/blocks/newsletter-signup-destination.d.ts +14 -23
  36. package/dist/_dts/blocks/src/system/blocks/newsletter-signup.d.ts +1 -1
  37. package/dist/_dts/blocks/src/system/blocks/site-footer-runtime.d.ts +109 -23
  38. package/dist/_dts/blocks/src/system/data/loaderEndpoints.d.ts +1 -1
  39. package/dist/_dts/blocks/src/system/runtime/components/registry.client.d.ts +42 -108
  40. package/dist/_dts/blocks/src/system/runtime/components/runtime-backed-blocks.d.ts +21 -54
  41. package/dist/_dts/blocks/src/system/runtime/nodes/event-details/logic.d.ts +1 -1
  42. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/registrationSurface.d.ts +26 -0
  43. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/types.d.ts +8 -0
  44. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration.interactive.d.ts +21 -0
  45. package/dist/_dts/blocks/src/system/runtime/nodes/newsletter-form.interactive.d.ts +29 -78
  46. package/dist/_dts/blocks/src/system/runtime/nodes/newsletter-form.server.d.ts +1 -1
  47. package/dist/_dts/blocks/src/system/runtime/nodes/newsletter-form.submission.d.ts +3 -6
  48. package/dist/_dts/blocks/src/system/runtime/nodes/newsletter-form.types.d.ts +27 -8
  49. package/dist/_dts/content-editor/src/FooterComposerOverview.d.ts +21 -0
  50. package/dist/_dts/content-editor/src/FooterComposerPanel.d.ts +3 -1
  51. package/dist/_dts/content-editor/src/FooterEngagementEditorFields.d.ts +31 -0
  52. package/dist/_dts/content-editor/src/FooterEngagementEditorPanel.d.ts +17 -0
  53. package/dist/_dts/content-editor/src/footerComposer.d.ts +3 -0
  54. package/dist/_dts/content-editor/src/footerEngagementDraft.d.ts +57 -0
  55. package/dist/_dts/content-editor/src/footerEngagementEditor.d.ts +11 -0
  56. package/dist/_dts/content-editor/src/footerPreviewRuntime.d.ts +13 -0
  57. package/dist/_dts/content-editor/src/index.d.ts +1 -0
  58. package/dist/_dts/content-editor/src/useFooterComposerState.d.ts +35 -0
  59. package/dist/_dts/core/src/footer-arrangement.d.ts +2 -0
  60. package/dist/_dts/core/src/footer-composition-types.d.ts +118 -0
  61. package/dist/_dts/core/src/footer-composition.d.ts +7 -116
  62. package/dist/_dts/core/src/footer-engagement.d.ts +30 -0
  63. package/dist/_dts/core/src/index.d.ts +4 -0
  64. package/dist/_dts/core/src/newsletter-signup-destination.d.ts +38 -0
  65. package/dist/_dts/db/src/generated/supabase/database.types.d.ts +73 -6
  66. package/dist/_dts/db/src/index.d.ts +1 -0
  67. package/dist/_dts/db/src/schemas/forms.d.ts +72 -2
  68. package/dist/_dts/db/src/schemas/standard-contact.d.ts +114 -0
  69. package/dist/_dts/preview-next/src/client/blocks/pageDesignRuntimePreview.d.ts +2 -0
  70. package/dist/_dts/preview-next/src/client/blocks/previewBatchLoaderParams.d.ts +6 -0
  71. package/dist/_dts/preview-next/src/client/index.d.ts +47 -47
  72. package/dist/_dts/preview-next/src/client/preview/EntryEditorPanel.d.ts +2 -5
  73. package/dist/_dts/preview-next/src/client/preview/EntrySlotBlockEditorPanel.d.ts +2 -5
  74. package/dist/_dts/preview-next/src/client/preview/PageBlockEditorPanel.d.ts +2 -5
  75. package/dist/_dts/preview-next/src/client/preview/PreviewEditorSidebar.d.ts +2 -4
  76. package/dist/_dts/preview-next/src/client/preview/PreviewShell.d.ts +19 -7
  77. package/dist/_dts/preview-next/src/client/preview/PreviewShellLayout.d.ts +30 -23
  78. package/dist/_dts/preview-next/src/client/preview/PreviewThemedSiteDocument.d.ts +18 -5
  79. package/dist/_dts/preview-next/src/client/preview/themeRuntime.d.ts +9 -0
  80. package/dist/_dts/preview-next/src/client/sdk/SdkPreviewMode.d.ts +21 -6
  81. package/dist/_dts/preview-next/src/client/sdk-runtime.d.ts +8 -8
  82. package/dist/_dts/preview-next/src/client/widgets/widgetOverrides.d.ts +6 -5
  83. package/dist/_dts/sdk/src/cli/commands/push/execute/footer.d.ts +9 -0
  84. package/dist/_dts/sdk/src/cli/content/footerFile.d.ts +10 -0
  85. package/dist/_dts/sdk/src/cli/content/reader.d.ts +3 -5
  86. package/dist/_dts/sdk/src/cli/site-commands/footerCommands.d.ts +15 -3
  87. package/dist/_dts/sdk/src/client/combineAbortSignals.d.ts +2 -0
  88. package/dist/_dts/sdk/src/client/management/types.d.ts +6 -15
  89. package/dist/_dts/sdk/src/client/types.d.ts +10 -2
  90. package/dist/_dts/sdk/src/client/wholeSeriesReadOperations.d.ts +11 -0
  91. package/dist/_dts/sdk/src/config/types.d.ts +1 -1
  92. package/dist/_dts/sdk/src/config/validation.d.ts +3 -0
  93. package/dist/_dts/sdk/src/contracts/event-registration-content.d.ts +16 -0
  94. package/dist/_dts/sdk/src/contracts/system-block-content.d.ts +4 -15
  95. package/dist/_dts/sdk/src/next/catch-all.d.ts +6 -0
  96. package/dist/_dts/sdk/src/next/index.d.ts +2 -1
  97. package/dist/_dts/sdk/src/next/renderSdkContent.d.ts +33 -0
  98. package/dist/_dts/sdk/src/next/types.d.ts +23 -9
  99. package/dist/_dts/sdk/src/preview-next/before-render.d.ts +4 -6
  100. package/dist/_dts/sdk/src/preview-next/client/index.d.ts +3 -3
  101. package/dist/_dts/sdk/src/preview-next/client/runtime.d.ts +1 -1
  102. package/dist/_dts/sdk/src/public-api/contracts.d.ts +4 -18
  103. package/dist/_dts/sdk/src/public-api/teamMemberContracts.d.ts +17 -0
  104. package/dist/_dts/sdk/src/public-api/wholeSeriesContracts.d.ts +2 -0
  105. package/dist/_dts/sdk/src/rendering/blocks-page-renderer.d.ts +32 -3
  106. package/dist/_dts/sdk/src/rendering/components/Block.shared.d.ts +13 -2
  107. package/dist/_dts/sdk/src/rendering/components/Layout.d.ts +31 -18
  108. package/dist/_dts/sdk/src/rendering/components/pageShared.d.ts +20 -9
  109. package/dist/_dts/sdk/src/rendering/index.d.ts +8 -4
  110. package/dist/_dts/sdk/src/rendering/mediaAssets.d.ts +8 -2
  111. package/dist/_dts/sdk/src/rendering/renderingMode.d.ts +23 -0
  112. package/dist/_dts/sdk/src/rendering/server.d.ts +5 -3
  113. package/dist/_dts/sdk/src/rendering/themeRuntime.d.ts +6 -0
  114. package/dist/_dts/sdk/src/version.d.ts +1 -1
  115. package/dist/_dts/site-commands/src/commandContract.d.ts +8 -1
  116. package/dist/_dts/site-commands/src/commands.d.ts +16 -2
  117. package/dist/_dts/theme-core/src/header/paintTargets.d.ts +10 -4
  118. package/dist/_dts/theme-core/src/header/surfaceRules.d.ts +2 -3
  119. package/dist/cli/index.mjs +5535 -4835
  120. package/dist/cli/init-docs/content/workflow-preview-mode.md +24 -11
  121. package/dist/client/{courseRegistration-DTEYWL6Z.mjs → CourseRegistrationWizard-xRmA7REV.mjs} +329 -49
  122. package/dist/client/{DiscountCodeDisclosure-BDFRp8Y7.mjs → DiscountCodeDisclosure-B9vriL5C.mjs} +1 -1
  123. package/dist/client/{EventCombined.client-DJgF1_lf.mjs → EventCombined.client-BgVnVTlz.mjs} +2 -2
  124. package/dist/client/{EventListing.client-CnWGNjOr.mjs → EventListing.client-CqdsO7jO.mjs} +2 -2
  125. package/dist/client/{LeafletStaticMap-BISs9Bl7.mjs → LeafletStaticMap-CKPxot9M.mjs} +1 -1
  126. package/dist/client/{StepIndicator-D8gVYkK-.mjs → StepIndicator-DGCYuBJ1.mjs} +2 -2
  127. package/dist/client/{accordion-DFDajgDz.mjs → accordion-BfN5Eqd-.mjs} +1 -1
  128. package/dist/client/{bookingForm-Bdqj9-52.mjs → bookingForm-DOvCpBFP.mjs} +5 -5
  129. package/dist/client/{carousel-Cvqf-kN8.mjs → carousel-DPNmiH0f.mjs} +1 -1
  130. package/dist/client/{cart-CuH2TJXP.mjs → cart--egVXlrR.mjs} +3 -3
  131. package/dist/client/{checkout-CMNPpejZ.mjs → checkout-DywWtMcq.mjs} +3 -3
  132. package/dist/client/client.mjs +5324 -4942
  133. package/dist/client/courseRegistration-Dk9qFVwt.mjs +46 -0
  134. package/dist/client/{eventCalendar-BW-XoxZ0.mjs → eventCalendar-Bkz2HjlS.mjs} +4 -4
  135. package/dist/client/{eventCombined-Bpn7s0y9.mjs → eventCombined-D4kipYWg.mjs} +2 -2
  136. package/dist/client/{eventDetails-D2uUSTMH.mjs → eventDetails-Dz_5ix2Q.mjs} +56 -35
  137. package/dist/client/{eventListing-CVr1c094.mjs → eventListing-D0vm-zST.mjs} +2 -2
  138. package/dist/client/{eventRegistration-Dv4AvkMw.mjs → eventRegistration-Cw1E4Q4p.mjs} +58 -6
  139. package/dist/client/{form-DxdKf9fs.mjs → form-C2Zf1n3K.mjs} +1 -1
  140. package/dist/client/{headerSection-BaXI5Sro.mjs → headerSection-CP05gzdc.mjs} +2 -2
  141. package/dist/client/hooks.mjs +212 -61
  142. package/dist/client/{locationMap-BEtW2fKz.mjs → locationMap-Cl3x9PYJ.mjs} +2 -2
  143. package/dist/client/{newsletterForm-BKKs0S4R.mjs → newsletterForm-DyEJoClm.mjs} +26 -20
  144. package/dist/client/{pricing-ClkqcElA.mjs → pricing-DGuNR1W4.mjs} +1 -1
  145. package/dist/client/{productDetail-H-ru8dyy.mjs → productDetail-Cq-HrGew.mjs} +3 -3
  146. package/dist/client/{productList-Buyi5c0C.mjs → productList-DbB3jwqd.mjs} +3 -3
  147. package/dist/client/{propsDecoder-BF7i6Ijg.mjs → propsDecoder-CiTuhUwY.mjs} +130 -87
  148. package/dist/client/rendering/client.mjs +416 -208
  149. package/dist/client/rendering/islands.mjs +18 -18
  150. package/dist/client/rendering.mjs +6026 -5596
  151. package/dist/client/{scrollToBlock-D_7t8yWb.mjs → scrollToBlock-CShkRqab.mjs} +1 -1
  152. package/dist/client/{shop-CF7SZQNX.mjs → shop-Cu4Ib-ZA.mjs} +5 -5
  153. package/dist/client/{shop-commerce-DA7_Rq5p.mjs → shop-commerce-BzpsOdh7.mjs} +4 -4
  154. package/dist/client/{shop-commerce-store-BmLqW7Gh.mjs → shop-commerce-store-DaE7Fhj8.mjs} +1 -1
  155. package/dist/client/{shopShared-WL-E1znM.mjs → shopShared-cF0c20vB.mjs} +2 -2
  156. package/dist/client/{useEventFilters-rc8VLeLV.mjs → useEventFilters-QZ3HMgaJ.mjs} +2 -2
  157. package/dist/client/{usePolling-1ncrfd4S.mjs → usePolling-BKf0GcE-.mjs} +2 -2
  158. package/dist/preview-next/before-render.mjs +11 -4
  159. package/dist/preview-next/client/runtime.mjs +4 -4
  160. package/dist/preview-next/middleware.mjs +1 -1
  161. package/dist/{previewAuthStore-Dev9CdG9.mjs → previewAuthStore-BesgU5Xu.mjs} +1 -1
  162. package/dist/{sdk-runtime-BnrCCFJq.mjs → sdk-runtime-CfZd5pAm.mjs} +2 -2
  163. package/dist/{separator-CFvBx2yl.mjs → separator-DkTe68HE.mjs} +1 -1
  164. package/dist/server/components.mjs +950 -639
  165. package/dist/server/config-validation.mjs +209 -61
  166. package/dist/server/config.mjs +209 -61
  167. package/dist/server/data.mjs +212 -61
  168. package/dist/server/index.mjs +40 -16
  169. package/dist/server/next.mjs +1181 -835
  170. package/dist/server/page-converter.mjs +211 -64
  171. package/dist/server/prebuild.mjs +1 -1
  172. package/dist/server/rendering/server.mjs +974 -637
  173. package/dist/server/rendering.mjs +980 -644
  174. package/dist/server/routing.mjs +254 -80
  175. package/dist/server/server.mjs +252 -77
  176. package/package.json +1 -1
  177. package/dist/SdkPreviewModeRuntime-B0HPXr-l.mjs +0 -39546
  178. package/dist/client/MagicLinkForm-b5E_HoG9.mjs +0 -327
@@ -498,6 +498,11 @@ function toLocationCoordinates(value) {
498
498
  };
499
499
  }
500
500
  //#endregion
501
+ //#region ../core/src/newsletter-signup-destination.ts
502
+ function parseNewsletterSignupDestinationProvider(value) {
503
+ return value === "riverbank" || value === "mailchimp" ? value : null;
504
+ }
505
+ //#endregion
501
506
  //#region ../core/src/planner.ts
502
507
  /** Default clock for production callers that do not inject time explicitly. */
503
508
  const systemPlanningClock = { now: () => Date.now() };
@@ -16634,10 +16639,16 @@ function getHeaderPaintTargets(variant, themeId, state = "base") {
16634
16639
  ownerSelector: desktopOwner,
16635
16640
  selector: `${desktopOwner}::before`,
16636
16641
  mediaQuery: MQ_MD_UP,
16637
- topExtension: {
16638
- customProperty: "--rb-header-floating-top-gap",
16639
- value: "1rem",
16640
- ownerProperty: "top"
16642
+ extent: {
16643
+ top: {
16644
+ customProperty: "--rb-header-floating-top-gap",
16645
+ value: "1rem",
16646
+ ownerProperty: "top"
16647
+ },
16648
+ bottom: {
16649
+ customProperty: "--rb-header-floating-bottom-extension",
16650
+ value: "0.75rem"
16651
+ }
16641
16652
  },
16642
16653
  ownerNeedsPositioning: false
16643
16654
  }, {
@@ -16646,10 +16657,16 @@ function getHeaderPaintTargets(variant, themeId, state = "base") {
16646
16657
  ownerSelector: mobileOwner,
16647
16658
  selector: `${mobileOwner}::before`,
16648
16659
  mediaQuery: MQ_MD_DOWN,
16649
- topExtension: {
16650
- customProperty: "--rb-header-floating-top-gap",
16651
- value: "0.75rem",
16652
- ownerProperty: "margin-top"
16660
+ extent: {
16661
+ top: {
16662
+ customProperty: "--rb-header-floating-top-gap",
16663
+ value: "0.75rem",
16664
+ ownerProperty: "margin-top"
16665
+ },
16666
+ bottom: {
16667
+ customProperty: "--rb-header-floating-bottom-extension",
16668
+ value: "0.75rem"
16669
+ }
16653
16670
  },
16654
16671
  ownerNeedsPositioning: true
16655
16672
  }];
@@ -16690,10 +16707,11 @@ function renderHeaderPaintTargetRule(target, rules) {
16690
16707
  return `${target.selector} {\n ${[...pseudoElementSetup, ...rules].join("\n ")}\n}`;
16691
16708
  }
16692
16709
  case "viewport-band": {
16693
- const gap = target.topExtension;
16710
+ const { top, bottom } = target.extent;
16694
16711
  const ownerRules = [
16695
- `${gap.customProperty}: ${gap.value};`,
16696
- `${gap.ownerProperty}: var(${gap.customProperty});`,
16712
+ `${top.customProperty}: ${top.value};`,
16713
+ `${bottom.customProperty}: ${bottom.value};`,
16714
+ `${top.ownerProperty}: var(${top.customProperty});`,
16697
16715
  ...target.ownerNeedsPositioning ? ["position: relative;"] : [],
16698
16716
  "isolation: isolate;",
16699
16717
  "background: none;",
@@ -16705,8 +16723,8 @@ function renderHeaderPaintTargetRule(target, rules) {
16705
16723
  const bandRules = [
16706
16724
  "content: \"\";",
16707
16725
  "position: absolute;",
16708
- `top: calc(-1 * var(${gap.customProperty}));`,
16709
- "bottom: 0;",
16726
+ `top: calc(-1 * var(${top.customProperty}));`,
16727
+ `bottom: calc(-1 * var(${bottom.customProperty}));`,
16710
16728
  "left: 50%;",
16711
16729
  "width: 100vw;",
16712
16730
  "transform: translateX(-50%);",
@@ -16725,6 +16743,7 @@ const headerScrollTreatmentSchema = z$1.discriminatedUnion("kind", [z$1.object({
16725
16743
  kind: z$1.literal("contrast-glass"),
16726
16744
  backgroundTone: z$1.enum(["light", "dark"])
16727
16745
  })]).optional();
16746
+ const CONTRAST_GLASS_BLUR = "blur(12px)";
16728
16747
  function generateMobileOverlayBackdropFilterFix(themeId, variant) {
16729
16748
  const root = `:where([data-theme-scope="${themeId}"]) .header-root:has([data-nav-mobile-overlay][aria-hidden="false"])`;
16730
16749
  return `\n${(variant === "floating" ? [`${root} .header-mobile-bar`, `${root} .header-mobile-bar::before`] : [`${root}::before`]).join(",\n")} {\n backdrop-filter: none !important;\n -webkit-backdrop-filter: none !important;\n}\n`;
@@ -16734,7 +16753,12 @@ function generateHeaderScrollTreatmentStyles(treatment, themeId, variant, surfac
16734
16753
  switch (treatment.kind) {
16735
16754
  case "contrast-glass": {
16736
16755
  const backgroundChannels = treatment.backgroundTone === "dark" ? "0 0 0" : "255 255 255";
16737
- return renderHeaderPaintTargetRules(getHeaderPaintTargets(variant, themeId, "scrolled"), [`background-color: rgb(${backgroundChannels} / 0.60);`, ...surfaceRules]);
16756
+ return renderHeaderPaintTargetRules(getHeaderPaintTargets(variant, themeId, "scrolled"), [
16757
+ `background-color: rgb(${backgroundChannels} / 0.60);`,
16758
+ `backdrop-filter: ${CONTRAST_GLASS_BLUR};`,
16759
+ `-webkit-backdrop-filter: ${CONTRAST_GLASS_BLUR};`,
16760
+ ...surfaceRules
16761
+ ]);
16738
16762
  }
16739
16763
  }
16740
16764
  }
@@ -24364,6 +24388,7 @@ const newsletterFormFragment = defineFragment({
24364
24388
  }
24365
24389
  ],
24366
24390
  layout: [el("newsletter-form", withApiBindings({
24391
+ source: "block",
24367
24392
  destinationProvider: { $bind: { from: "destinationProvider" } },
24368
24393
  listId: { $bind: { from: "listId" } },
24369
24394
  preset: { $bind: { from: "preset" } },
@@ -26308,6 +26333,7 @@ const contactNewsletterLayout = styledSection({
26308
26333
  as: "h2",
26309
26334
  className: "newsletter-copy-title"
26310
26335
  }, when("newsletterTitle"), bind("newsletterTitle")), richText({ className: "newsletter-copy-subtitle rb-prose rb-max-w-none" }, when("newsletterSubtitle"), bind("newsletterSubtitle"))]), el("newsletter-form", withApiBindings({
26336
+ source: "block",
26311
26337
  listId: { $bind: { from: "listId" } },
26312
26338
  preset: { $bind: { from: "preset" } },
26313
26339
  includePhone: { $bind: { from: "includePhone" } },
@@ -28318,6 +28344,22 @@ const footerNavGroupsLayout = stack({
28318
28344
  }, [text({ as: "span" }, bind("entry.label"))], repeat("group.children", "entry"))])], repeat("footerMenu.groups", "group"))], whenCollectionHasItems("footerMenu.groups"));
28319
28345
  //#endregion
28320
28346
  //#region ../blocks/src/system/blocks/site-footer.ts
28347
+ const footerStandardContactBindings = {
28348
+ value: { $bind: { from: "module.engagement.runtime.value" } },
28349
+ submitLabel: { $bind: { from: "module.engagement.runtime.submitLabel" } },
28350
+ successMessage: { $bind: { from: "module.engagement.runtime.successMessage" } }
28351
+ };
28352
+ const footerMailingListBindings = {
28353
+ source: { $bind: { from: "module.engagement.runtime.source" } },
28354
+ destinationRef: { $bind: { from: "module.engagement.runtime.destinationRef" } },
28355
+ listId: { $bind: { from: "module.engagement.runtime.listId" } },
28356
+ preset: { $bind: { from: "module.engagement.runtime.preset" } },
28357
+ includePhone: { $bind: { from: "module.engagement.runtime.includePhone" } },
28358
+ buttonLabel: { $bind: { from: "module.engagement.runtime.buttonLabel" } },
28359
+ successMessage: { $bind: { from: "module.engagement.runtime.successMessage" } },
28360
+ privacyNote: { $bind: { from: "module.engagement.runtime.privacyNote" } }
28361
+ };
28362
+ const footerSpamProtectionBinding = { spamProtectionEnabled: { $bind: { from: "$root.spamProtectionEnabled" } } };
28321
28363
  const brandLogo = link({
28322
28364
  href: "/",
28323
28365
  className: { $bind: {
@@ -28395,6 +28437,23 @@ const authoredCopy = richText({
28395
28437
  id: "content.interpolateRichTextTokens",
28396
28438
  options: { tokens: ["year", "site_name"] }
28397
28439
  }] }));
28440
+ const footerEngagement = stack({
28441
+ gap: "md",
28442
+ className: "rb-w-full"
28443
+ }, [
28444
+ text({
28445
+ as: "p",
28446
+ className: "rb-body rb-opacity-80"
28447
+ }, bind("module.engagement.intro"), when("module.engagement.intro")),
28448
+ form(withApiBindings({
28449
+ ...footerStandardContactBindings,
28450
+ ...footerSpamProtectionBinding
28451
+ }), [], when("module.engagement.kind", { equals: "standard-contact" })),
28452
+ el("newsletter-form", withApiBindings({
28453
+ ...footerMailingListBindings,
28454
+ ...footerSpamProtectionBinding
28455
+ }), [], when("module.engagement.kind", { equals: "mailing-list" }))
28456
+ ], when("module.kind", { equals: "engagement" }));
28398
28457
  const footerGroup = stack({
28399
28458
  gap: "md",
28400
28459
  align: "stretch",
@@ -28420,6 +28479,7 @@ const footerGroup = stack({
28420
28479
  contact,
28421
28480
  hours,
28422
28481
  socials,
28482
+ footerEngagement,
28423
28483
  stack({ className: "rb-w-full" }, [authoredCopy], when("module.kind", { equals: "supporting-text" })),
28424
28484
  stack({ className: "rb-w-full rb-lg-col-span-3" }, [authoredCopy], when("module.kind", { equals: "legal" }))
28425
28485
  ], repeat("group.modules", "module"))], repeat("region.groups", "group"));
@@ -28427,6 +28487,10 @@ const footerMainRegion = stack({
28427
28487
  className: { $bind: { from: "region.className" } },
28428
28488
  "data-footer-region": { $bind: { from: "region.kind" } }
28429
28489
  }, [footerGroup], when("region.kind", { equals: "main" }), repeat("content.footerRuntime.regions", "region"));
28490
+ const footerEngagementRegion = stack({
28491
+ className: { $bind: { from: "region.className" } },
28492
+ "data-footer-region": "engagement-row"
28493
+ }, [footerGroup], when("region.kind", { equals: "engagement-row" }), repeat("content.footerRuntime.regions", "region"));
28430
28494
  const footerBottomRegion = stack({ className: { $bind: {
28431
28495
  from: "$root.theme.footer",
28432
28496
  transforms: [{ id: "layout.footerBottomBarContainerClass" }],
@@ -28462,7 +28526,11 @@ const siteFooterManifest = createBlockManifest({
28462
28526
  fallback: mergeStyles(backgroundColorStyle("surface"), surfaceForegroundStyle({ text: "rgb(var(--tb-text))" }), borderColorStyle("border"))
28463
28527
  } },
28464
28528
  "data-footer-membership": { $bind: { from: "content.footerRuntime.membershipKey" } }
28465
- }, [footerMainRegion, footerBottomRegion]),
28529
+ }, [
28530
+ footerEngagementRegion,
28531
+ footerMainRegion,
28532
+ footerBottomRegion
28533
+ ]),
28466
28534
  description: "Site-wide composed footer with canonical shared details.",
28467
28535
  styleTokens: { spacing: "md" },
28468
28536
  paletteHidden: true
@@ -31036,7 +31104,7 @@ const publicMembershipProductCollectionSchema = z$1.object({ memberships: z$1.ar
31036
31104
  * Kept in a shared module so the block definition and runtime contracts can
31037
31105
  * depend on the same schema without creating an initialization cycle.
31038
31106
  */
31039
- const occurrenceContextSchema$1 = z$1.object({
31107
+ const occurrenceContextSchema = z$1.object({
31040
31108
  id: z$1.string(),
31041
31109
  seriesId: z$1.string(),
31042
31110
  startsAt: z$1.string(),
@@ -31439,28 +31507,37 @@ const EVENT_REGISTRATION_SHELL_STEP_LABELS = [
31439
31507
  "Payment"
31440
31508
  ];
31441
31509
  const eventRegistrationPublicEventSchema = z$1.preprocess(normalizeEventRegistrationEventInput, publicEventSchema);
31442
- const eventRegistrationSourceSchema = z$1.object({
31443
- siteId: z$1.string().optional(),
31444
- apiBaseUrl: z$1.string().optional(),
31445
- portalToken: z$1.string().nullable().optional(),
31446
- previewToken: z$1.string().nullable().optional(),
31447
- occurrenceContext: occurrenceContextSchema$1.optional(),
31510
+ const eventRegistrationHydrationSchemaShape = {
31511
+ occurrenceContext: occurrenceContextSchema.optional(),
31448
31512
  subject: eventRegistrationPageSurfaceSubjectSchema.nullable().optional(),
31449
31513
  events: z$1.array(eventRegistrationPublicEventSchema).nullable().optional(),
31450
- className: z$1.string().nullable().optional(),
31451
- buttonText: z$1.string().nullable().optional(),
31452
- maxTickets: z$1.string().nullable().optional(),
31514
+ wholeSeriesOfferings: publicCoursesArraySchema.nullable().optional(),
31515
+ wholeSeriesOffering: publicCourseSchema.nullable().optional(),
31516
+ maxTickets: z$1.string().optional(),
31453
31517
  showVenue: z$1.boolean().optional(),
31454
31518
  showCapacity: z$1.boolean().optional(),
31519
+ showSessions: z$1.boolean().optional(),
31520
+ showPrice: z$1.boolean().optional(),
31455
31521
  successMessage: z$1.string().optional(),
31456
31522
  waitlistMessage: z$1.string().optional(),
31523
+ membershipMessage: z$1.string().optional(),
31457
31524
  buttonVariant: registrationButtonVariantSchema.optional(),
31458
31525
  overlayEnabled: z$1.boolean().optional(),
31459
31526
  spamProtectionEnabled: z$1.boolean().optional(),
31460
- stage: previewStageSchema.optional(),
31461
31527
  supportEmail: z$1.string().optional(),
31462
31528
  sitePasses: publicPassProductCollectionSchema.nullable().optional(),
31463
31529
  siteMemberships: publicMembershipProductCollectionSchema.nullable().optional()
31530
+ };
31531
+ const eventRegistrationSourceSchema = z$1.object({
31532
+ siteId: z$1.string().optional(),
31533
+ apiBaseUrl: z$1.string().optional(),
31534
+ portalToken: z$1.string().nullable().optional(),
31535
+ previewToken: z$1.string().nullable().optional(),
31536
+ ...eventRegistrationHydrationSchemaShape,
31537
+ className: z$1.string().nullable().optional(),
31538
+ buttonText: z$1.string().nullable().optional(),
31539
+ maxTickets: z$1.string().nullable().optional(),
31540
+ stage: previewStageSchema.optional()
31464
31541
  });
31465
31542
  const eventRegistrationDisplaySchema = z$1.object({
31466
31543
  kind: z$1.literal("event-registration"),
@@ -31471,22 +31548,7 @@ const eventRegistrationDisplaySchema = z$1.object({
31471
31548
  stepLabels: z$1.array(z$1.enum(EVENT_REGISTRATION_SHELL_STEP_LABELS)).min(1),
31472
31549
  summaryButtonText: z$1.string()
31473
31550
  });
31474
- const eventRegistrationHydrationSchema = z$1.object({
31475
- occurrenceContext: occurrenceContextSchema$1.optional(),
31476
- subject: eventRegistrationPageSurfaceSubjectSchema.nullable().optional(),
31477
- events: z$1.array(eventRegistrationPublicEventSchema).nullable().optional(),
31478
- maxTickets: z$1.string().optional(),
31479
- showVenue: z$1.boolean().optional(),
31480
- showCapacity: z$1.boolean().optional(),
31481
- successMessage: z$1.string().optional(),
31482
- waitlistMessage: z$1.string().optional(),
31483
- buttonVariant: registrationButtonVariantSchema.optional(),
31484
- overlayEnabled: z$1.boolean().optional(),
31485
- spamProtectionEnabled: z$1.boolean().optional(),
31486
- supportEmail: z$1.string().optional(),
31487
- sitePasses: publicPassProductCollectionSchema.nullable().optional(),
31488
- siteMemberships: publicMembershipProductCollectionSchema.nullable().optional()
31489
- });
31551
+ const eventRegistrationHydrationSchema = z$1.object(eventRegistrationHydrationSchemaShape);
31490
31552
  const eventRegistrationRenderSchema = z$1.object({
31491
31553
  display: eventRegistrationDisplaySchema,
31492
31554
  hydration: eventRegistrationHydrationSchema
@@ -31566,11 +31628,16 @@ const eventRegistrationBlockRuntime = defineClientOwnedBlockRuntime({
31566
31628
  occurrenceContext: source.occurrenceContext ?? null,
31567
31629
  subject: source.subject ?? null,
31568
31630
  events: source.events ?? null,
31631
+ wholeSeriesOfferings: source.wholeSeriesOfferings ?? null,
31632
+ wholeSeriesOffering: source.wholeSeriesOffering ?? null,
31569
31633
  maxTickets: source.maxTickets ?? void 0,
31570
31634
  showVenue: source.showVenue,
31571
31635
  showCapacity: source.showCapacity,
31636
+ showSessions: source.showSessions,
31637
+ showPrice: source.showPrice,
31572
31638
  successMessage: source.successMessage,
31573
31639
  waitlistMessage: source.waitlistMessage,
31640
+ membershipMessage: source.membershipMessage,
31574
31641
  buttonVariant: source.buttonVariant,
31575
31642
  overlayEnabled: source.overlayEnabled,
31576
31643
  spamProtectionEnabled: source.spamProtectionEnabled,
@@ -31605,6 +31672,159 @@ function buildEventRegistrationInteractiveIslandProps(props) {
31605
31672
  source: props
31606
31673
  });
31607
31674
  }
31675
+ //#endregion
31676
+ //#region ../blocks/src/system/blocks/courses/shared/pricing.ts
31677
+ function isSaleWindowOpen(option, now) {
31678
+ if (!option.isActive) return false;
31679
+ if (option.saleStartsAt && new Date(option.saleStartsAt) > now) return false;
31680
+ if (option.saleEndsAt && new Date(option.saleEndsAt) < now) return false;
31681
+ return true;
31682
+ }
31683
+ function toExactOrFreeDisplay(amount, currency) {
31684
+ if (amount <= 0) return {
31685
+ kind: "free",
31686
+ currency
31687
+ };
31688
+ return {
31689
+ kind: "exact",
31690
+ amount,
31691
+ currency
31692
+ };
31693
+ }
31694
+ function getSelectableCoursePricingOptionsForNow(course, now) {
31695
+ if (course.pricing.pricingStrategy !== "tiered") return [];
31696
+ return [...course.pricing.options].filter((option) => isSaleWindowOpen(option, now)).sort((left, right) => {
31697
+ if (left.sortOrder !== right.sortOrder) return left.sortOrder - right.sortOrder;
31698
+ if (left.priceAmount !== right.priceAmount) return left.priceAmount - right.priceAmount;
31699
+ return left.name.localeCompare(right.name);
31700
+ });
31701
+ }
31702
+ function resolveCoursePricingState(course, selectedPricingOptionId, selectedSlidingAmountOrNowInput, nowInput = {}) {
31703
+ const selectedSlidingAmount = typeof selectedSlidingAmountOrNowInput === "number" || selectedSlidingAmountOrNowInput === null ? selectedSlidingAmountOrNowInput : null;
31704
+ const effectiveNowInput = typeof selectedSlidingAmountOrNowInput === "object" && selectedSlidingAmountOrNowInput !== null ? selectedSlidingAmountOrNowInput : nowInput;
31705
+ const currency = course.pricing.currency;
31706
+ switch (course.pricing.pricingStrategy) {
31707
+ case "free": return {
31708
+ currency,
31709
+ display: {
31710
+ kind: "free",
31711
+ currency
31712
+ },
31713
+ selectableOptions: [],
31714
+ requiresSelection: false,
31715
+ selectedOption: null,
31716
+ slidingScale: null,
31717
+ selectedSlidingAmount: null,
31718
+ selectedPriceAmount: 0,
31719
+ selectedRequiresPayment: false,
31720
+ hasPaidSelection: false,
31721
+ hasFreeSelection: true
31722
+ };
31723
+ case "single": {
31724
+ const amount = course.pricing.singlePriceAmount ?? 0;
31725
+ return {
31726
+ currency,
31727
+ display: toExactOrFreeDisplay(amount, currency),
31728
+ selectableOptions: [],
31729
+ requiresSelection: false,
31730
+ selectedOption: null,
31731
+ slidingScale: null,
31732
+ selectedSlidingAmount: null,
31733
+ selectedPriceAmount: amount,
31734
+ selectedRequiresPayment: amount > 0,
31735
+ hasPaidSelection: amount > 0,
31736
+ hasFreeSelection: amount <= 0
31737
+ };
31738
+ }
31739
+ case "tiered": {
31740
+ const selectableOptions = getSelectableCoursePricingOptionsForNow(course, resolvePlanningDateInput(effectiveNowInput));
31741
+ const selectedOption = (selectedPricingOptionId ? selectableOptions.find((option) => option.id === selectedPricingOptionId) : null) ?? (selectableOptions.length === 1 ? selectableOptions[0] ?? null : null);
31742
+ const lowestAmount = selectableOptions.reduce((lowest, option) => {
31743
+ if (lowest === null || option.priceAmount < lowest) return option.priceAmount;
31744
+ return lowest;
31745
+ }, null);
31746
+ return {
31747
+ currency,
31748
+ display: lowestAmount === null ? {
31749
+ kind: "unavailable",
31750
+ currency
31751
+ } : selectableOptions.length > 1 && lowestAmount > 0 ? {
31752
+ kind: "from",
31753
+ amount: lowestAmount,
31754
+ currency
31755
+ } : toExactOrFreeDisplay(lowestAmount, currency),
31756
+ selectableOptions,
31757
+ requiresSelection: selectableOptions.length > 1,
31758
+ selectedOption,
31759
+ slidingScale: null,
31760
+ selectedSlidingAmount: null,
31761
+ selectedPriceAmount: selectedOption?.priceAmount ?? null,
31762
+ selectedRequiresPayment: (selectedOption?.priceAmount ?? 0) > 0,
31763
+ hasPaidSelection: selectableOptions.some((option) => option.priceAmount > 0),
31764
+ hasFreeSelection: selectableOptions.some((option) => option.priceAmount === 0)
31765
+ };
31766
+ }
31767
+ case "sliding_scale": {
31768
+ const minAmount = course.pricing.slidingMinAmount ?? null;
31769
+ const maxAmount = course.pricing.slidingMaxAmount ?? null;
31770
+ if (minAmount === null || maxAmount === null || minAmount < 0 || maxAmount < minAmount) return {
31771
+ currency,
31772
+ display: {
31773
+ kind: "unavailable",
31774
+ currency
31775
+ },
31776
+ selectableOptions: [],
31777
+ requiresSelection: true,
31778
+ selectedOption: null,
31779
+ slidingScale: null,
31780
+ selectedSlidingAmount: null,
31781
+ selectedPriceAmount: null,
31782
+ selectedRequiresPayment: false,
31783
+ hasPaidSelection: false,
31784
+ hasFreeSelection: false
31785
+ };
31786
+ const normalizedSelectedAmount = typeof selectedSlidingAmount === "number" && Number.isFinite(selectedSlidingAmount) ? selectedSlidingAmount : null;
31787
+ return {
31788
+ currency,
31789
+ display: {
31790
+ kind: "range",
31791
+ minAmount,
31792
+ maxAmount,
31793
+ currency
31794
+ },
31795
+ selectableOptions: [],
31796
+ requiresSelection: normalizedSelectedAmount === null,
31797
+ selectedOption: null,
31798
+ slidingScale: {
31799
+ minAmount,
31800
+ maxAmount,
31801
+ suggestedAmount: course.pricing.slidingSuggestedAmount ?? null
31802
+ },
31803
+ selectedSlidingAmount: normalizedSelectedAmount,
31804
+ selectedPriceAmount: normalizedSelectedAmount,
31805
+ selectedRequiresPayment: (normalizedSelectedAmount ?? 0) > 0,
31806
+ hasPaidSelection: maxAmount > 0,
31807
+ hasFreeSelection: minAmount === 0
31808
+ };
31809
+ }
31810
+ }
31811
+ }
31812
+ function formatCoursePriceDisplay(display, locale) {
31813
+ return formatBookingPriceDisplay(display, {
31814
+ decimals: "exact",
31815
+ locale
31816
+ });
31817
+ }
31818
+ function formatCoursePriceAmount(amount, currency, locale) {
31819
+ return formatCoursePriceDisplay(amount > 0 ? {
31820
+ kind: "exact",
31821
+ amount,
31822
+ currency
31823
+ } : {
31824
+ kind: "free",
31825
+ currency
31826
+ }, locale);
31827
+ }
31608
31828
  const eventRegistrationBlockDefinition = {
31609
31829
  manifest: createBlockManifest({
31610
31830
  id: "block.event-registration",
@@ -31700,6 +31920,24 @@ const eventRegistrationBlockDefinition = {
31700
31920
  defaultValue: true,
31701
31921
  ui: { intent: "display" }
31702
31922
  },
31923
+ {
31924
+ id: "showSessions",
31925
+ type: "boolean",
31926
+ label: "Show complete schedule",
31927
+ description: "Display every session for whole-series registrations",
31928
+ required: false,
31929
+ defaultValue: true,
31930
+ ui: { intent: "display" }
31931
+ },
31932
+ {
31933
+ id: "showPrice",
31934
+ type: "boolean",
31935
+ label: "Show price",
31936
+ description: "Display the whole-series price",
31937
+ required: false,
31938
+ defaultValue: true,
31939
+ ui: { intent: "display" }
31940
+ },
31703
31941
  {
31704
31942
  id: "successMessage",
31705
31943
  type: "text",
@@ -31710,6 +31948,26 @@ const eventRegistrationBlockDefinition = {
31710
31948
  defaultValue: "Thank you for registering! Check your email for confirmation details.",
31711
31949
  maxLength: 500
31712
31950
  },
31951
+ {
31952
+ id: "waitlistMessage",
31953
+ type: "text",
31954
+ label: "Waitlist message",
31955
+ description: "Message shown after joining a whole-series waitlist",
31956
+ required: false,
31957
+ multiline: true,
31958
+ defaultValue: "You've been added to the waitlist. We'll email you if a place becomes available.",
31959
+ maxLength: 500
31960
+ },
31961
+ {
31962
+ id: "membershipMessage",
31963
+ type: "text",
31964
+ label: "Membership registration message",
31965
+ description: "Message shown when a whole-series place is covered by membership",
31966
+ required: false,
31967
+ multiline: true,
31968
+ defaultValue: "Registered using your membership. Check your email for session details.",
31969
+ maxLength: 500
31970
+ },
31713
31971
  {
31714
31972
  id: "buttonText",
31715
31973
  type: "text",
@@ -31741,8 +31999,11 @@ const eventRegistrationBlockDefinition = {
31741
31999
  } },
31742
32000
  showVenue: { $bind: { from: "content.showVenue" } },
31743
32001
  showCapacity: { $bind: { from: "content.showCapacity" } },
32002
+ showSessions: { $bind: { from: "content.showSessions" } },
32003
+ showPrice: { $bind: { from: "content.showPrice" } },
31744
32004
  successMessage: { $bind: { from: "content.successMessage" } },
31745
32005
  waitlistMessage: { $bind: { from: "content.waitlistMessage" } },
32006
+ membershipMessage: { $bind: { from: "content.membershipMessage" } },
31746
32007
  buttonText: { $bind: {
31747
32008
  from: "content.buttonText",
31748
32009
  fallback: "Complete Registration"
@@ -31756,6 +32017,7 @@ const eventRegistrationBlockDefinition = {
31756
32017
  fallback: false
31757
32018
  } },
31758
32019
  events: { $bind: { from: "data.events" } },
32020
+ wholeSeriesOffering: { $bind: { from: "data.wholeSeriesOffering.offering" } },
31759
32021
  sitePasses: { $bind: { from: "data.sitePasses" } },
31760
32022
  siteMemberships: { $bind: { from: "data.siteMemberships" } },
31761
32023
  stage: { $bind: {
@@ -31769,9 +32031,10 @@ const eventRegistrationBlockDefinition = {
31769
32031
  runtime: eventRegistrationBlockRuntime,
31770
32032
  dataSchemas: {
31771
32033
  events: publicEventsArraySchema.optional(),
32034
+ wholeSeriesOffering: z$1.object({ offering: publicCourseSchema }).optional(),
31772
32035
  sitePasses: publicPassProductCollectionSchema.optional(),
31773
32036
  siteMemberships: publicMembershipProductCollectionSchema.optional(),
31774
- occurrenceContext: occurrenceContextSchema$1.optional()
32037
+ occurrenceContext: occurrenceContextSchema.optional()
31775
32038
  },
31776
32039
  dataLoaders: {
31777
32040
  events: {
@@ -31784,11 +32047,23 @@ const eventRegistrationBlockDefinition = {
31784
32047
  fallback: "published"
31785
32048
  } },
31786
32049
  readProfile: "registration",
31787
- seriesId: { $bind: { from: "$root.occurrenceContext.seriesId" } },
32050
+ seriesId: { $bind: { from: "$root.subject.eventSeriesId" } },
31788
32051
  includeOccurrenceId: { $bind: { from: "$root.occurrenceContext.id" } }
31789
32052
  },
31790
32053
  mode: "server"
31791
32054
  },
32055
+ wholeSeriesOffering: {
32056
+ endpoint: "getPublicWholeSeriesOffering",
32057
+ params: {
32058
+ siteId: { $bind: { from: "$root.siteId" } },
32059
+ eventSeriesId: { $bind: { from: "$root.subject.eventSeriesId" } },
32060
+ stage: { $bind: {
32061
+ from: "$root.previewStage",
32062
+ fallback: "published"
32063
+ } }
32064
+ },
32065
+ mode: "server"
32066
+ },
31792
32067
  sitePasses: {
31793
32068
  endpoint: "listPublicPasses",
31794
32069
  params: { siteId: { $bind: { from: "$root.siteId" } } },
@@ -31802,159 +32077,6 @@ const eventRegistrationBlockDefinition = {
31802
32077
  }
31803
32078
  };
31804
32079
  //#endregion
31805
- //#region ../blocks/src/system/blocks/courses/shared/pricing.ts
31806
- function isSaleWindowOpen(option, now) {
31807
- if (!option.isActive) return false;
31808
- if (option.saleStartsAt && new Date(option.saleStartsAt) > now) return false;
31809
- if (option.saleEndsAt && new Date(option.saleEndsAt) < now) return false;
31810
- return true;
31811
- }
31812
- function toExactOrFreeDisplay(amount, currency) {
31813
- if (amount <= 0) return {
31814
- kind: "free",
31815
- currency
31816
- };
31817
- return {
31818
- kind: "exact",
31819
- amount,
31820
- currency
31821
- };
31822
- }
31823
- function getSelectableCoursePricingOptionsForNow(course, now) {
31824
- if (course.pricing.pricingStrategy !== "tiered") return [];
31825
- return [...course.pricing.options].filter((option) => isSaleWindowOpen(option, now)).sort((left, right) => {
31826
- if (left.sortOrder !== right.sortOrder) return left.sortOrder - right.sortOrder;
31827
- if (left.priceAmount !== right.priceAmount) return left.priceAmount - right.priceAmount;
31828
- return left.name.localeCompare(right.name);
31829
- });
31830
- }
31831
- function resolveCoursePricingState(course, selectedPricingOptionId, selectedSlidingAmountOrNowInput, nowInput = {}) {
31832
- const selectedSlidingAmount = typeof selectedSlidingAmountOrNowInput === "number" || selectedSlidingAmountOrNowInput === null ? selectedSlidingAmountOrNowInput : null;
31833
- const effectiveNowInput = typeof selectedSlidingAmountOrNowInput === "object" && selectedSlidingAmountOrNowInput !== null ? selectedSlidingAmountOrNowInput : nowInput;
31834
- const currency = course.pricing.currency;
31835
- switch (course.pricing.pricingStrategy) {
31836
- case "free": return {
31837
- currency,
31838
- display: {
31839
- kind: "free",
31840
- currency
31841
- },
31842
- selectableOptions: [],
31843
- requiresSelection: false,
31844
- selectedOption: null,
31845
- slidingScale: null,
31846
- selectedSlidingAmount: null,
31847
- selectedPriceAmount: 0,
31848
- selectedRequiresPayment: false,
31849
- hasPaidSelection: false,
31850
- hasFreeSelection: true
31851
- };
31852
- case "single": {
31853
- const amount = course.pricing.singlePriceAmount ?? 0;
31854
- return {
31855
- currency,
31856
- display: toExactOrFreeDisplay(amount, currency),
31857
- selectableOptions: [],
31858
- requiresSelection: false,
31859
- selectedOption: null,
31860
- slidingScale: null,
31861
- selectedSlidingAmount: null,
31862
- selectedPriceAmount: amount,
31863
- selectedRequiresPayment: amount > 0,
31864
- hasPaidSelection: amount > 0,
31865
- hasFreeSelection: amount <= 0
31866
- };
31867
- }
31868
- case "tiered": {
31869
- const selectableOptions = getSelectableCoursePricingOptionsForNow(course, resolvePlanningDateInput(effectiveNowInput));
31870
- const selectedOption = (selectedPricingOptionId ? selectableOptions.find((option) => option.id === selectedPricingOptionId) : null) ?? (selectableOptions.length === 1 ? selectableOptions[0] ?? null : null);
31871
- const lowestAmount = selectableOptions.reduce((lowest, option) => {
31872
- if (lowest === null || option.priceAmount < lowest) return option.priceAmount;
31873
- return lowest;
31874
- }, null);
31875
- return {
31876
- currency,
31877
- display: lowestAmount === null ? {
31878
- kind: "unavailable",
31879
- currency
31880
- } : selectableOptions.length > 1 && lowestAmount > 0 ? {
31881
- kind: "from",
31882
- amount: lowestAmount,
31883
- currency
31884
- } : toExactOrFreeDisplay(lowestAmount, currency),
31885
- selectableOptions,
31886
- requiresSelection: selectableOptions.length > 1,
31887
- selectedOption,
31888
- slidingScale: null,
31889
- selectedSlidingAmount: null,
31890
- selectedPriceAmount: selectedOption?.priceAmount ?? null,
31891
- selectedRequiresPayment: (selectedOption?.priceAmount ?? 0) > 0,
31892
- hasPaidSelection: selectableOptions.some((option) => option.priceAmount > 0),
31893
- hasFreeSelection: selectableOptions.some((option) => option.priceAmount === 0)
31894
- };
31895
- }
31896
- case "sliding_scale": {
31897
- const minAmount = course.pricing.slidingMinAmount ?? null;
31898
- const maxAmount = course.pricing.slidingMaxAmount ?? null;
31899
- if (minAmount === null || maxAmount === null || minAmount < 0 || maxAmount < minAmount) return {
31900
- currency,
31901
- display: {
31902
- kind: "unavailable",
31903
- currency
31904
- },
31905
- selectableOptions: [],
31906
- requiresSelection: true,
31907
- selectedOption: null,
31908
- slidingScale: null,
31909
- selectedSlidingAmount: null,
31910
- selectedPriceAmount: null,
31911
- selectedRequiresPayment: false,
31912
- hasPaidSelection: false,
31913
- hasFreeSelection: false
31914
- };
31915
- const normalizedSelectedAmount = typeof selectedSlidingAmount === "number" && Number.isFinite(selectedSlidingAmount) ? selectedSlidingAmount : null;
31916
- return {
31917
- currency,
31918
- display: {
31919
- kind: "range",
31920
- minAmount,
31921
- maxAmount,
31922
- currency
31923
- },
31924
- selectableOptions: [],
31925
- requiresSelection: normalizedSelectedAmount === null,
31926
- selectedOption: null,
31927
- slidingScale: {
31928
- minAmount,
31929
- maxAmount,
31930
- suggestedAmount: course.pricing.slidingSuggestedAmount ?? null
31931
- },
31932
- selectedSlidingAmount: normalizedSelectedAmount,
31933
- selectedPriceAmount: normalizedSelectedAmount,
31934
- selectedRequiresPayment: (normalizedSelectedAmount ?? 0) > 0,
31935
- hasPaidSelection: maxAmount > 0,
31936
- hasFreeSelection: minAmount === 0
31937
- };
31938
- }
31939
- }
31940
- }
31941
- function formatCoursePriceDisplay(display, locale) {
31942
- return formatBookingPriceDisplay(display, {
31943
- decimals: "exact",
31944
- locale
31945
- });
31946
- }
31947
- function formatCoursePriceAmount(amount, currency, locale) {
31948
- return formatCoursePriceDisplay(amount > 0 ? {
31949
- kind: "exact",
31950
- amount,
31951
- currency
31952
- } : {
31953
- kind: "free",
31954
- currency
31955
- }, locale);
31956
- }
31957
- //#endregion
31958
32080
  //#region ../blocks/src/system/runtime/nodes/course-registration.interactive.ts
31959
32081
  const courseRegistrationSourceSchema = z$1.object({
31960
32082
  siteId: z$1.string().optional(),
@@ -32389,15 +32511,6 @@ const eventDetailsManifest = createBlockManifest({
32389
32511
  })], { gap: "lg" })
32390
32512
  })]
32391
32513
  });
32392
- const occurrenceContextSchema = z$1.object({
32393
- id: z$1.string(),
32394
- seriesId: z$1.string(),
32395
- startsAt: z$1.string(),
32396
- endsAt: z$1.string(),
32397
- timeZone: z$1.string(),
32398
- capacityOverride: z$1.number().nullable().optional(),
32399
- overrides: z$1.record(z$1.string(), z$1.unknown()).nullable().optional()
32400
- }).nullable();
32401
32514
  const eventAutoApplyDiscountPreviewBaseSchema = z$1.object({
32402
32515
  id: z$1.string(),
32403
32516
  publicLabel: z$1.string(),
@@ -32432,8 +32545,9 @@ const eventDetailsBlockDefinition = {
32432
32545
  from: "$root.previewStage",
32433
32546
  fallback: "published"
32434
32547
  } },
32435
- limit: "25",
32436
- seriesId: { $bind: { from: "$root.occurrenceContext.seriesId" } },
32548
+ limit: "100",
32549
+ readProfile: "details",
32550
+ seriesId: { $bind: { from: "$root.subject.eventSeriesId" } },
32437
32551
  includeOccurrenceId: { $bind: { from: "$root.occurrenceContext.id" } }
32438
32552
  },
32439
32553
  mode: "server"
@@ -41170,9 +41284,6 @@ function parseSignedNewsletterDestinationRef(value) {
41170
41284
  const trimmed = parseTrimmedString(value);
41171
41285
  return trimmed && SIGNED_DESTINATION_REF_PATTERN.test(trimmed) ? trimmed : null;
41172
41286
  }
41173
- function parseNewsletterSignupDestinationProvider(value) {
41174
- return value === "riverbank" || value === "mailchimp" ? value : null;
41175
- }
41176
41287
  function buildNewsletterSignupBlockRef(blockId) {
41177
41288
  const parsed = parseNewsletterSignupBlockId(blockId);
41178
41289
  return parsed ? {
@@ -41319,19 +41430,9 @@ const newsletterFieldSchema = z$1.object({
41319
41430
  });
41320
41431
  const newsletterSignupBlockIdSchema = z$1.string().trim().min(1).transform(parseRequiredNewsletterSignupBlockId);
41321
41432
  const signedNewsletterDestinationRefSchema = z$1.string().trim().min(1).transform(parseRequiredSignedNewsletterDestinationRef);
41322
- const newsletterPublicDestinationRefSchema = z$1.discriminatedUnion("tag", [z$1.object({
41323
- tag: z$1.literal("block_ref"),
41324
- blockId: newsletterSignupBlockIdSchema
41325
- }), z$1.object({
41326
- tag: z$1.literal("signed_destination_ref"),
41327
- token: signedNewsletterDestinationRefSchema
41328
- })]);
41329
- const newsletterSourceSchema = z$1.object({
41330
- blockId: z$1.string().nullable().optional(),
41433
+ const newsletterSourceCommonSchema = z$1.object({
41331
41434
  siteId: z$1.string().optional(),
41332
41435
  apiBaseUrl: z$1.string().optional(),
41333
- listId: z$1.string().nullable().optional(),
41334
- destinationProvider: newsletterDestinationProviderSchema.nullable().optional(),
41335
41436
  preset: newsletterPresetSchema.optional(),
41336
41437
  includePhone: z$1.boolean().optional(),
41337
41438
  buttonLabel: z$1.string().nullable().optional(),
@@ -41342,6 +41443,25 @@ const newsletterSourceSchema = z$1.object({
41342
41443
  spamProtectionEnabled: z$1.boolean().optional(),
41343
41444
  className: z$1.string().nullable().optional()
41344
41445
  });
41446
+ const newsletterSourceSchema = z$1.discriminatedUnion("source", [
41447
+ newsletterSourceCommonSchema.extend({
41448
+ source: z$1.literal("block"),
41449
+ blockId: z$1.string().nullable().optional(),
41450
+ listId: z$1.string().nullable().optional(),
41451
+ destinationProvider: newsletterDestinationProviderSchema.nullable().optional()
41452
+ }),
41453
+ newsletterSourceCommonSchema.extend({
41454
+ source: z$1.literal("signed-footer"),
41455
+ destinationRef: z$1.object({
41456
+ tag: z$1.literal("signed_destination_ref"),
41457
+ token: signedNewsletterDestinationRefSchema
41458
+ })
41459
+ }),
41460
+ newsletterSourceCommonSchema.extend({
41461
+ source: z$1.literal("legacy-direct-list"),
41462
+ listId: z$1.string().nullable()
41463
+ })
41464
+ ]);
41345
41465
  const newsletterDisplaySchema = z$1.object({
41346
41466
  kind: z$1.literal("newsletter-form"),
41347
41467
  className: z$1.string().nullable(),
@@ -41352,8 +41472,26 @@ const newsletterDisplaySchema = z$1.object({
41352
41472
  fields: z$1.array(newsletterFieldSchema)
41353
41473
  });
41354
41474
  const newsletterHydrationSchema = z$1.object({
41355
- destinationRef: newsletterPublicDestinationRefSchema.nullable().optional(),
41356
- listId: z$1.string().nullable().optional(),
41475
+ target: z$1.discriminatedUnion("tag", [
41476
+ z$1.object({
41477
+ tag: z$1.literal("block-source"),
41478
+ destinationRef: z$1.object({
41479
+ tag: z$1.literal("block_ref"),
41480
+ blockId: newsletterSignupBlockIdSchema
41481
+ }).nullable()
41482
+ }),
41483
+ z$1.object({
41484
+ tag: z$1.literal("signed-footer-source"),
41485
+ destinationRef: z$1.object({
41486
+ tag: z$1.literal("signed_destination_ref"),
41487
+ token: signedNewsletterDestinationRefSchema
41488
+ })
41489
+ }),
41490
+ z$1.object({
41491
+ tag: z$1.literal("legacy-direct-list"),
41492
+ listId: z$1.string().nullable()
41493
+ })
41494
+ ]),
41357
41495
  preset: newsletterPresetSchema,
41358
41496
  includePhone: z$1.boolean(),
41359
41497
  tags: z$1.string().nullable().optional(),
@@ -41387,20 +41525,43 @@ const newsletterFormBlockRuntime = defineProgressiveBlockRuntime({
41387
41525
  render: createZodCodec(newsletterRenderSchema)
41388
41526
  },
41389
41527
  buildRender: (source) => {
41390
- const runtimeSource = deriveNewsletterSignupRuntimeSource(source);
41528
+ const runtimeSource = source.source === "block" ? deriveNewsletterSignupRuntimeSource(source) : null;
41391
41529
  return {
41392
41530
  display: buildNewsletterDisplay(source),
41393
41531
  hydration: {
41394
- destinationRef: buildNewsletterSignupBlockRef(source.blockId),
41395
- listId: runtimeSource.listId,
41532
+ target: projectNewsletterFormHydrationTarget(source),
41396
41533
  preset: source.preset ?? "emailOnly",
41397
41534
  includePhone: source.includePhone ?? false,
41398
- tags: runtimeSource.tags,
41535
+ tags: runtimeSource ? runtimeSource.tags : source.tags,
41399
41536
  spamProtectionEnabled: source.spamProtectionEnabled
41400
41537
  }
41401
41538
  };
41402
41539
  }
41403
41540
  });
41541
+ function projectNewsletterFormHydrationTarget(source) {
41542
+ switch (source.source) {
41543
+ case "block": {
41544
+ const destinationRef = buildNewsletterSignupBlockRef(source.blockId);
41545
+ if (destinationRef?.tag === "block_ref") return {
41546
+ tag: "block-source",
41547
+ destinationRef
41548
+ };
41549
+ return {
41550
+ tag: "legacy-direct-list",
41551
+ listId: source.listId ?? null
41552
+ };
41553
+ }
41554
+ case "signed-footer": return {
41555
+ tag: "signed-footer-source",
41556
+ destinationRef: source.destinationRef
41557
+ };
41558
+ case "legacy-direct-list": return {
41559
+ tag: "legacy-direct-list",
41560
+ listId: source.listId
41561
+ };
41562
+ default: return assertNever$4(source);
41563
+ }
41564
+ }
41404
41565
  function buildNewsletterFormInteractiveIslandProps(props) {
41405
41566
  return buildInteractiveIslandProps({
41406
41567
  runtime: newsletterFormBlockRuntime,
@@ -45785,6 +45946,33 @@ function uniqByOccurrenceId(events) {
45785
45946
  }
45786
45947
  return out;
45787
45948
  }
45949
+ function selectFromOccurrenceContext(events, occurrenceContext) {
45950
+ if (!occurrenceContext) return null;
45951
+ const byId = events.find((event) => event.occurrenceId === occurrenceContext.id || event.id === occurrenceContext.id);
45952
+ if (byId) return byId;
45953
+ const contextDate = getBookingLocalDateKey(toScheduledBookingDateTime({
45954
+ startsAt: occurrenceContext.startsAt,
45955
+ timeZone: occurrenceContext.timeZone
45956
+ }));
45957
+ return events.find((event) => getBookingLocalDateKey(toScheduledBookingDateTime({
45958
+ startsAt: event.startsAt,
45959
+ timeZone: event.timeZone
45960
+ })) === contextDate) ?? null;
45961
+ }
45962
+ function selectNextUpcoming(events, nowIso) {
45963
+ return [...events].filter((event) => isFutureOrNow(event.startsAt, nowIso)).sort((left, right) => Date.parse(left.startsAt) - Date.parse(right.startsAt))[0] ?? null;
45964
+ }
45965
+ function selectCompletedWholeSeries(events) {
45966
+ if (events.length === 0 || !events.every((event) => event.bookingScope === "whole_series")) return null;
45967
+ return [...events].sort((left, right) => Date.parse(right.startsAt) - Date.parse(left.startsAt))[0] ?? null;
45968
+ }
45969
+ function selectRelatedDates(input) {
45970
+ if (!input.seriesId) return [];
45971
+ const isWholeSeries = input.selected?.bookingScope === "whole_series";
45972
+ const selectedOccurrenceId = input.selected ? input.selected.occurrenceId || input.selected.id : null;
45973
+ const dates = input.events.filter((event) => event.seriesId === input.seriesId).filter((event) => isWholeSeries || isFutureOrNow(event.startsAt, input.nowIso)).filter((event) => !selectedOccurrenceId || (event.occurrenceId || event.id) !== selectedOccurrenceId).sort((left, right) => Date.parse(left.startsAt) - Date.parse(right.startsAt));
45974
+ return isWholeSeries ? dates : dates.slice(0, input.limit);
45975
+ }
45788
45976
  function selectEventDetails(args) {
45789
45977
  const all = uniqByOccurrenceId(resolveEventRegistrationScopedEvents((args.events ?? []).filter(Boolean), {
45790
45978
  occurrenceContext: args.occurrenceContext,
@@ -45792,37 +45980,22 @@ function selectEventDetails(args) {
45792
45980
  }));
45793
45981
  const occurrenceContext = args.occurrenceContext ?? null;
45794
45982
  const otherLimit = parseLimit$1(args.otherDatesLimit, 5);
45795
- const selectedFromContext = (() => {
45796
- if (!occurrenceContext) return null;
45797
- const byId = all.find((e) => e.occurrenceId === occurrenceContext.id || e.id === occurrenceContext.id) ?? null;
45798
- if (byId) return byId;
45799
- const ctxDate = getBookingLocalDateKey(toScheduledBookingDateTime({
45800
- startsAt: occurrenceContext.startsAt,
45801
- timeZone: occurrenceContext.timeZone
45802
- }));
45803
- return all.find((e) => getBookingLocalDateKey(toScheduledBookingDateTime({
45804
- startsAt: e.startsAt,
45805
- timeZone: e.timeZone
45806
- })) === ctxDate) ?? null;
45807
- })();
45808
- const nextUpcoming = (() => {
45809
- const upcoming = all.filter((e) => isFutureOrNow(e.startsAt, args.nowIso));
45810
- upcoming.sort((a, b) => Date.parse(a.startsAt) - Date.parse(b.startsAt));
45811
- return upcoming[0] ?? null;
45812
- })();
45813
- const mode = selectedFromContext ? "selected" : "next";
45814
- const selected = selectedFromContext ?? nextUpcoming;
45983
+ const selectedFromContext = selectFromOccurrenceContext(all, occurrenceContext);
45984
+ const nextUpcoming = selectNextUpcoming(all, args.nowIso);
45985
+ const completedWholeSeries = selectCompletedWholeSeries(all);
45986
+ const selected = selectedFromContext ?? nextUpcoming ?? completedWholeSeries;
45987
+ const mode = selectedFromContext ? "selected" : nextUpcoming ? "next" : completedWholeSeries ? "completed" : "next";
45815
45988
  const timeZone = toBookingTimeZone(selected?.timeZone ?? all[0]?.timeZone ?? null);
45816
- const seriesId = occurrenceContext?.seriesId ?? selected?.seriesId ?? all[0]?.seriesId ?? null;
45817
- const selectedOccurrenceId = selected?.occurrenceId ?? null;
45818
45989
  return {
45819
45990
  mode,
45820
45991
  selected,
45821
- otherDates: seriesId ? all.filter((e) => e.seriesId === seriesId).filter((e) => isFutureOrNow(e.startsAt, args.nowIso)).filter((e) => {
45822
- const occId = e.occurrenceId || e.id;
45823
- if (selectedOccurrenceId && occId === selectedOccurrenceId) return false;
45824
- return true;
45825
- }).slice(0, otherLimit) : [],
45992
+ otherDates: selectRelatedDates({
45993
+ events: all,
45994
+ seriesId: occurrenceContext?.seriesId ?? selected?.seriesId ?? all[0]?.seriesId ?? null,
45995
+ selected,
45996
+ nowIso: args.nowIso,
45997
+ limit: otherLimit
45998
+ }),
45826
45999
  timeZone
45827
46000
  };
45828
46001
  }
@@ -45967,7 +46140,7 @@ function EventFacts({ selection, selected, venue, teamMembers, pricing }) {
45967
46140
  /* @__PURE__ */ jsxs("div", { children: [
45968
46141
  /* @__PURE__ */ jsx("div", {
45969
46142
  className: "rb-label rb-mb-2",
45970
- children: selection.mode === "next" ? "Next date" : "Date"
46143
+ children: selected.bookingScope === "whole_series" ? selection.mode === "next" ? "Next session" : "Selected session" : selection.mode === "next" ? "Next date" : "Date"
45971
46144
  }),
45972
46145
  /* @__PURE__ */ jsx("p", { children: /* @__PURE__ */ jsx("strong", { children: date }) }),
45973
46146
  /* @__PURE__ */ jsx("p", {
@@ -46005,18 +46178,27 @@ function EventFacts({ selection, selected, venue, teamMembers, pricing }) {
46005
46178
  }) : null] }, member.id))
46006
46179
  })]
46007
46180
  }) : null,
46008
- pricing
46181
+ pricing,
46182
+ selected.bookingScope === "whole_series" ? /* @__PURE__ */ jsxs("div", {
46183
+ className: "rb-mt-6",
46184
+ children: [/* @__PURE__ */ jsx("div", {
46185
+ className: "rb-label rb-mb-2",
46186
+ children: "Registration"
46187
+ }), /* @__PURE__ */ jsx("p", { children: /* @__PURE__ */ jsx("strong", { children: selected.wholeSeries?.enrollmentOpen ? "Open" : "Closed" }) })]
46188
+ }) : null
46009
46189
  ]
46010
46190
  });
46011
46191
  }
46012
46192
  function OtherEventDates({ selection }) {
46013
- if (selection.otherDates.length === 0) return null;
46193
+ const isWholeSeries = selection.selected?.bookingScope === "whole_series";
46194
+ const dates = isWholeSeries && selection.selected ? [selection.selected, ...selection.otherDates].sort((left, right) => Date.parse(left.startsAt) - Date.parse(right.startsAt)) : selection.otherDates;
46195
+ if (dates.length === 0) return null;
46014
46196
  return /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("div", {
46015
46197
  className: "rb-label",
46016
- children: "Other dates"
46198
+ children: isWholeSeries ? "Session schedule" : "Other dates"
46017
46199
  }), /* @__PURE__ */ jsx("div", {
46018
46200
  className: "rb-mt-2 rb-tiles-grid",
46019
- children: selection.otherDates.map((event) => /* @__PURE__ */ jsx("a", {
46201
+ children: dates.map((event) => /* @__PURE__ */ jsx("a", {
46020
46202
  className: "rb-tile rb-tile--interactive",
46021
46203
  ...resolveEventLinkProps(event),
46022
46204
  children: /* @__PURE__ */ jsx(DateTimeTile, {
@@ -49215,13 +49397,13 @@ const FormNodeSSR = ({ blockId, value, submitLabel, successMessage, className, o
49215
49397
  * Renders the newsletter signup form for SSR with hydration support.
49216
49398
  * Uses the islands architecture pattern to hydrate on the client.
49217
49399
  */
49218
- function NewsletterFormSSR({ blockId, siteId, apiBaseUrl, listId, destinationProvider, preset = "emailOnly", includePhone, buttonLabel = "Subscribe", buttonVariant = "primary", successMessage, privacyNote, tags, spamProtectionEnabled, className }) {
49400
+ function NewsletterFormSSR(props) {
49401
+ const { siteId, apiBaseUrl, preset = "emailOnly", includePhone, buttonLabel = "Subscribe", buttonVariant = "primary", successMessage, privacyNote, tags, spamProtectionEnabled, className } = props;
49402
+ const blockId = props.source === "block" ? props.blockId : null;
49219
49403
  const islandProps = buildNewsletterFormInteractiveIslandProps({
49220
- blockId,
49404
+ ...props,
49221
49405
  siteId,
49222
49406
  apiBaseUrl,
49223
- listId,
49224
- destinationProvider,
49225
49407
  preset,
49226
49408
  includePhone,
49227
49409
  buttonLabel,
@@ -50803,6 +50985,213 @@ function renderBlock(manifest, content, options = {}) {
50803
50985
  }, componentElement);
50804
50986
  }
50805
50987
  //#endregion
50988
+ //#region ../blocks/src/system/manifest/hydrateLinks.ts
50989
+ /**
50990
+ * Hydrates link objects within block content using the provided route map. Returns
50991
+ * the original content reference when no mutations are required to avoid unnecessary renders.
50992
+ */
50993
+ function hydrateManifestLinks(manifest, content, routes, pagesByIdentifier, entriesByIdentifier) {
50994
+ if (!routes || !manifest?.fields?.length) return content;
50995
+ return hydrateValue(content, {
50996
+ routes,
50997
+ pagesByIdentifier,
50998
+ entriesByIdentifier
50999
+ });
51000
+ }
51001
+ function hydrateValue(value, context) {
51002
+ try {
51003
+ if (Array.isArray(value)) {
51004
+ const resolvedItems = value.map((item) => hydrateValue(item, context));
51005
+ return resolvedItems.every((item, index) => item === value[index]) ? value : resolvedItems;
51006
+ }
51007
+ if (isRecord$13(value)) {
51008
+ if (isInternalLink(value)) return hydrateInternalLink(value, context.routes);
51009
+ if (isPageLink(value)) return hydratePageLink(value, context);
51010
+ if (isEntryLink(value)) return hydrateEntryLink(value, context);
51011
+ const resolvedEntries = Object.entries(value).map(([key, entry]) => [key, hydrateValue(entry, context)]);
51012
+ return resolvedEntries.every(([key, entry]) => entry === value[key]) ? value : Object.fromEntries(resolvedEntries);
51013
+ }
51014
+ return value;
51015
+ } catch (err) {
51016
+ console.error("[hydrateLinks] Error hydrating value:", err, value);
51017
+ return value;
51018
+ }
51019
+ }
51020
+ function hydrateInternalLink(link, routes) {
51021
+ const resolved = resolveRouteTarget(link.routeId, routes);
51022
+ if (!resolved) return link;
51023
+ const nextHref = resolved.href;
51024
+ const currentHref = typeof link.href === "string" && link.href.length > 0 ? link.href : null;
51025
+ const nextUpdatedAt = resolved.updatedAt;
51026
+ const updates = {};
51027
+ if (nextHref && nextHref !== currentHref) updates.href = nextHref;
51028
+ if (nextUpdatedAt && link.updatedAt !== nextUpdatedAt) updates.updatedAt = nextUpdatedAt;
51029
+ return Object.keys(updates).length > 0 ? {
51030
+ ...link,
51031
+ ...updates
51032
+ } : link;
51033
+ }
51034
+ function isInternalLink(value) {
51035
+ if (value.kind !== "internal") return false;
51036
+ if (typeof value.routeId !== "string" || value.routeId.length === 0) return false;
51037
+ return true;
51038
+ }
51039
+ function isPageLink(value) {
51040
+ if (value.kind !== "page") return false;
51041
+ if (typeof value.identifier !== "string" || value.identifier.length === 0) return false;
51042
+ return true;
51043
+ }
51044
+ function hydratePageLink(link, context) {
51045
+ const resolved = resolvePageRouteTarget(link, context);
51046
+ if (!resolved) return link;
51047
+ return {
51048
+ ...link,
51049
+ href: resolved.href,
51050
+ routeId: resolved.routeId
51051
+ };
51052
+ }
51053
+ function isEntryLink(value) {
51054
+ if (value.kind !== "entry") return false;
51055
+ if (typeof value.contentType !== "string" || value.contentType.length === 0) return false;
51056
+ if (typeof value.identifier !== "string" || value.identifier.length === 0) return false;
51057
+ return true;
51058
+ }
51059
+ function hydrateEntryLink(link, context) {
51060
+ const resolved = resolveEntryRouteTarget(link, context);
51061
+ if (!resolved) return link;
51062
+ return {
51063
+ ...link,
51064
+ href: resolved.href,
51065
+ routeId: resolved.routeId
51066
+ };
51067
+ }
51068
+ //#endregion
51069
+ //#region ../blocks/src/sdkBlockTransform.ts
51070
+ /**
51071
+ * Transforms an SDK custom block into a BlockManifest.
51072
+ *
51073
+ * If the block has a `layout`, it can be rendered declaratively without React code.
51074
+ * If no layout, the block MUST use blockOverrides for rendering.
51075
+ */
51076
+ function transformSdkBlockToManifest(sdkBlock) {
51077
+ const hasLayout = Boolean(sdkBlock.layout) || Boolean(sdkBlock.variants && Object.keys(sdkBlock.variants).length > 0);
51078
+ return augmentManifest({
51079
+ name: sdkBlock.id,
51080
+ version: "1.0.0",
51081
+ title: sdkBlock.title,
51082
+ titleSource: sdkBlock.titleSource,
51083
+ description: sdkBlock.description,
51084
+ component: sdkBlock.id,
51085
+ fields: sdkBlock.fields,
51086
+ slots: [],
51087
+ category: sdkBlock.category,
51088
+ tags: sdkBlock.tags,
51089
+ icon: sdkBlock.icon,
51090
+ layout: sdkBlock.layout,
51091
+ variants: sdkBlock.variants,
51092
+ defaultVariant: sdkBlock.defaultVariant,
51093
+ variantOptions: sdkBlock.variantOptions,
51094
+ previewCustomize: sdkBlock.previewCustomize,
51095
+ behaviours: {
51096
+ supportsThemeSwitching: true,
51097
+ inlineEditing: hasLayout,
51098
+ animation: hasLayout,
51099
+ paletteHidden: false
51100
+ }
51101
+ });
51102
+ }
51103
+ /**
51104
+ * Transforms an SDK custom block into a SystemBlockDefinition.
51105
+ *
51106
+ * This creates a minimal definition with just the manifest - no data loaders
51107
+ * or content normalizers since SDK blocks handle their own rendering.
51108
+ */
51109
+ function transformSdkBlockToDefinition(sdkBlock) {
51110
+ return {
51111
+ manifest: transformSdkBlockToManifest(sdkBlock),
51112
+ dataLoaders: sdkBlock.dataLoaders
51113
+ };
51114
+ }
51115
+ //#endregion
51116
+ //#region ../blocks/src/customBlockRegistry.ts
51117
+ const defaultCustomBlockSourcePolicy = { kind: "canonical-db-fallback-sdk" };
51118
+ function isCustomBlockKind(blockKind) {
51119
+ return blockKind.startsWith("custom.");
51120
+ }
51121
+ function transformToBlockDescriptor(sdkBlock, source = "sdk") {
51122
+ return {
51123
+ name: sdkBlock.id,
51124
+ title: sdkBlock.title,
51125
+ description: sdkBlock.description,
51126
+ category: sdkBlock.category,
51127
+ tags: sdkBlock.tags,
51128
+ icon: sdkBlock.icon,
51129
+ definition: transformSdkBlockToDefinition(sdkBlock),
51130
+ source
51131
+ };
51132
+ }
51133
+ function toResolvedCustomBlock(manifest, source) {
51134
+ return {
51135
+ blockKind: manifest.id,
51136
+ manifest: transformSdkBlockToManifest(manifest),
51137
+ source,
51138
+ descriptor: transformToBlockDescriptor(manifest, source.kind === "managed-database" ? "database" : "sdk")
51139
+ };
51140
+ }
51141
+ function planCustomBlockRegistryResolution({ sdkConfig, customBlocks = [], policy = defaultCustomBlockSourcePolicy }) {
51142
+ switch (policy.kind) {
51143
+ case "canonical-db-fallback-sdk": {
51144
+ const entriesByKind = /* @__PURE__ */ new Map();
51145
+ const conflicts = [];
51146
+ for (const customBlock of customBlocks) entriesByKind.set(customBlock.manifest.id, toResolvedCustomBlock(customBlock.manifest, customBlock.source));
51147
+ for (const sdkBlock of sdkConfig?.customBlocks ?? []) {
51148
+ const existing = entriesByKind.get(sdkBlock.id);
51149
+ if (existing) {
51150
+ conflicts.push({
51151
+ kind: "conflict",
51152
+ blockKind: existing.blockKind,
51153
+ winner: existing.source,
51154
+ loser: { kind: "sdk-config" },
51155
+ reason: "db-canonical-sdk-fallback"
51156
+ });
51157
+ continue;
51158
+ }
51159
+ entriesByKind.set(sdkBlock.id, toResolvedCustomBlock(sdkBlock, { kind: "sdk-config" }));
51160
+ }
51161
+ return {
51162
+ policy,
51163
+ entries: Array.from(entriesByKind.values()),
51164
+ conflicts
51165
+ };
51166
+ }
51167
+ }
51168
+ }
51169
+ function createCustomBlockRegistry({ sdkConfig, customBlocks = [], policy = defaultCustomBlockSourcePolicy, onConflict }) {
51170
+ const plan = planCustomBlockRegistryResolution({
51171
+ sdkConfig,
51172
+ customBlocks,
51173
+ policy
51174
+ });
51175
+ const entriesByKind = new Map(plan.entries.map((entry) => [entry.blockKind, entry]));
51176
+ for (const conflict of plan.conflicts) onConflict?.(`Using ${sourceLabel(conflict.winner)} custom block "${conflict.blockKind}" - ${sourceLabel(conflict.loser)} block is fallback only`);
51177
+ return {
51178
+ entries: plan.entries,
51179
+ conflicts: plan.conflicts,
51180
+ findManifest: (blockKind) => {
51181
+ if (!isCustomBlockKind(blockKind)) return void 0;
51182
+ return entriesByKind.get(blockKind);
51183
+ }
51184
+ };
51185
+ }
51186
+ function sourceLabel(source) {
51187
+ switch (source.kind) {
51188
+ case "managed-database": return "DB";
51189
+ case "sdk-synced": return "SDK-synced DB";
51190
+ case "sdk-config": return "SDK config";
51191
+ default: return assertNever$4(source);
51192
+ }
51193
+ }
51194
+ //#endregion
50806
51195
  //#region ../theme-core/src/runtime/fontFamily.ts
50807
51196
  /**
50808
51197
  * Font Family Formatting Utilities
@@ -51477,30 +51866,24 @@ const NAV_DROPDOWN_CONTAINER_RAIL_CSS_RULES = [
51477
51866
  ];
51478
51867
  //#endregion
51479
51868
  //#region ../theme-core/src/header/surfaceRules.ts
51480
- /** Compile the visual surface declarations independently of paint geometry. */
51481
- function buildHeaderSurfaceRules(header, tokens, blur) {
51869
+ /** Compile the at-rest surface independently of scroll treatment and paint geometry. */
51870
+ function buildHeaderSurfaceRules(header, tokens) {
51482
51871
  const base = [];
51483
- const scrolled = [];
51484
51872
  const background = header.background;
51485
51873
  if (background.type === "color") base.push(`background-color: ${tokens.getColor(background.color || "surface")};`);
51486
51874
  else if (background.type === "gradient" && background.gradient) {
51487
51875
  const stops = background.gradient.stops.map((stop) => tokens.getColor(stop.color)).join(", ");
51488
51876
  base.push(`background-image: linear-gradient(${background.gradient.angle ?? 180}deg, ${stops});`);
51489
51877
  }
51490
- const blurRules = [`backdrop-filter: ${blur};`, `-webkit-backdrop-filter: ${blur};`];
51491
- base.push(...blurRules);
51492
- scrolled.push(...blurRules);
51493
51878
  const borderWidth = getComponentBorderWidthPx(header.border?.width ?? "none");
51494
51879
  if (!header.border || borderWidth === "0") return {
51495
51880
  base,
51496
- scrolled,
51497
51881
  border: []
51498
51882
  };
51499
51883
  const color = rgbColorValue(header.border.colorToken?.trim() || "border");
51500
51884
  const style = header.border.style === "dashed" ? "dashed" : "solid";
51501
51885
  return {
51502
51886
  base,
51503
- scrolled,
51504
51887
  border: header.border.position === "both" ? [`border-top: ${borderWidth} ${style} ${color};`, `border-bottom: ${borderWidth} ${style} ${color};`] : [`border-${header.border.position}: ${borderWidth} ${style} ${color};`]
51505
51888
  };
51506
51889
  }
@@ -51810,13 +52193,12 @@ function generateHeaderRootStyles(header, themeId, tokens) {
51810
52193
  rules.push("isolation: isolate;");
51811
52194
  const surfaceRules = isContainedNav ? {
51812
52195
  base: [],
51813
- scrolled: [],
51814
52196
  border: []
51815
- } : buildHeaderSurfaceRules(header, tokens, HEADER_BLUR);
52197
+ } : buildHeaderSurfaceRules(header, tokens);
51816
52198
  const floatingSurfaceBorder = header.variant === "floating";
51817
52199
  if (!floatingSurfaceBorder) rules.push(...surfaceRules.border);
51818
52200
  const basePaintRules = floatingSurfaceBorder ? [...surfaceRules.base, ...surfaceRules.border] : surfaceRules.base;
51819
- const scrolledPaintRules = floatingSurfaceBorder ? [...surfaceRules.scrolled, ...surfaceRules.border] : surfaceRules.scrolled;
52201
+ const scrolledPaintRules = floatingSurfaceBorder ? surfaceRules.border : [];
51820
52202
  if (header.positioning === "sticky" || header.positioning === "fixed") {
51821
52203
  const shadowVar = getComponentShadowVar(header.shadow?.elevation ?? "none");
51822
52204
  if (shadowVar) rules.push(`box-shadow: ${shadowVar};`);
@@ -54547,215 +54929,115 @@ function mapFontStyle(italic) {
54547
54929
  return italic ? "italic" : "normal";
54548
54930
  }
54549
54931
  //#endregion
54550
- //#region ../blocks/src/system/manifest/hydrateLinks.ts
54551
- /**
54552
- * Hydrates link objects within block content using the provided route map. Returns
54553
- * the original content reference when no mutations are required to avoid unnecessary renders.
54554
- */
54555
- function hydrateManifestLinks(manifest, content, routes, pagesByIdentifier, entriesByIdentifier) {
54556
- if (!routes || !manifest?.fields?.length) return content;
54557
- return hydrateValue(content, {
54558
- routes,
54559
- pagesByIdentifier,
54560
- entriesByIdentifier
54561
- });
54562
- }
54563
- function hydrateValue(value, context) {
54564
- try {
54565
- if (Array.isArray(value)) {
54566
- const resolvedItems = value.map((item) => hydrateValue(item, context));
54567
- return resolvedItems.every((item, index) => item === value[index]) ? value : resolvedItems;
54568
- }
54569
- if (isRecord$13(value)) {
54570
- if (isInternalLink(value)) return hydrateInternalLink(value, context.routes);
54571
- if (isPageLink(value)) return hydratePageLink(value, context);
54572
- if (isEntryLink(value)) return hydrateEntryLink(value, context);
54573
- const resolvedEntries = Object.entries(value).map(([key, entry]) => [key, hydrateValue(entry, context)]);
54574
- return resolvedEntries.every(([key, entry]) => entry === value[key]) ? value : Object.fromEntries(resolvedEntries);
54575
- }
54576
- return value;
54577
- } catch (err) {
54578
- console.error("[hydrateLinks] Error hydrating value:", err, value);
54579
- return value;
54932
+ //#region ../blocks/src/pageRenderingMode.ts
54933
+ var MissingBlockOverrideError$1 = class extends Error {
54934
+ constructor(blockKind) {
54935
+ super(`Override-only rendering requires an override for block kind "${blockKind}".`);
54936
+ this.blockKind = blockKind;
54937
+ this.code = "missing_block_override";
54938
+ this.name = "MissingBlockOverrideError";
54580
54939
  }
54940
+ };
54941
+ function isOverrideOnlyResourceInput(props) {
54942
+ return props.rendering?.kind === "overrides-only";
54581
54943
  }
54582
- function hydrateInternalLink(link, routes) {
54583
- const resolved = resolveRouteTarget(link.routeId, routes);
54584
- if (!resolved) return link;
54585
- const nextHref = resolved.href;
54586
- const currentHref = typeof link.href === "string" && link.href.length > 0 ? link.href : null;
54587
- const nextUpdatedAt = resolved.updatedAt;
54588
- const updates = {};
54589
- if (nextHref && nextHref !== currentHref) updates.href = nextHref;
54590
- if (nextUpdatedAt && link.updatedAt !== nextUpdatedAt) updates.updatedAt = nextUpdatedAt;
54591
- return Object.keys(updates).length > 0 ? {
54592
- ...link,
54593
- ...updates
54594
- } : link;
54595
- }
54596
- function isInternalLink(value) {
54597
- if (value.kind !== "internal") return false;
54598
- if (typeof value.routeId !== "string" || value.routeId.length === 0) return false;
54599
- return true;
54600
- }
54601
- function isPageLink(value) {
54602
- if (value.kind !== "page") return false;
54603
- if (typeof value.identifier !== "string" || value.identifier.length === 0) return false;
54604
- return true;
54605
- }
54606
- function hydratePageLink(link, context) {
54607
- const resolved = resolvePageRouteTarget(link, context);
54608
- if (!resolved) return link;
54944
+ function resolvePageThemeResources(props) {
54945
+ if (isOverrideOnlyResourceInput(props)) return { kind: "unavailable" };
54609
54946
  return {
54610
- ...link,
54611
- href: resolved.href,
54612
- routeId: resolved.routeId
54947
+ kind: "available",
54948
+ tokens: props.themeTokens ?? buildThemeRuntime$1(props.theme).tokens,
54949
+ config: props.theme
54613
54950
  };
54614
54951
  }
54615
- function isEntryLink(value) {
54616
- if (value.kind !== "entry") return false;
54617
- if (typeof value.contentType !== "string" || value.contentType.length === 0) return false;
54618
- if (typeof value.identifier !== "string" || value.identifier.length === 0) return false;
54619
- return true;
54952
+ function requireBlockOverride(resources, override, blockKind) {
54953
+ if (resources.kind === "unavailable" && !override) throw new MissingBlockOverrideError$1(blockKind);
54620
54954
  }
54621
- function hydrateEntryLink(link, context) {
54622
- const resolved = resolveEntryRouteTarget(link, context);
54623
- if (!resolved) return link;
54624
- return {
54625
- ...link,
54626
- href: resolved.href,
54627
- routeId: resolved.routeId
54628
- };
54955
+ function overrideThemeProps(resources) {
54956
+ return resources.kind === "available" ? {
54957
+ theme: resources.tokens,
54958
+ themeConfig: resources.config
54959
+ } : {};
54960
+ }
54961
+ function requireThemeResources(resources, blockKind) {
54962
+ if (resources.kind === "unavailable") throw new MissingBlockOverrideError$1(blockKind);
54963
+ return resources;
54629
54964
  }
54630
54965
  //#endregion
54631
- //#region ../blocks/src/sdkBlockTransform.ts
54632
- /**
54633
- * Transforms an SDK custom block into a BlockManifest.
54634
- *
54635
- * If the block has a `layout`, it can be rendered declaratively without React code.
54636
- * If no layout, the block MUST use blockOverrides for rendering.
54637
- */
54638
- function transformSdkBlockToManifest(sdkBlock) {
54639
- const hasLayout = Boolean(sdkBlock.layout) || Boolean(sdkBlock.variants && Object.keys(sdkBlock.variants).length > 0);
54640
- return augmentManifest({
54641
- name: sdkBlock.id,
54642
- version: "1.0.0",
54643
- title: sdkBlock.title,
54644
- titleSource: sdkBlock.titleSource,
54645
- description: sdkBlock.description,
54646
- component: sdkBlock.id,
54647
- fields: sdkBlock.fields,
54648
- slots: [],
54649
- category: sdkBlock.category,
54650
- tags: sdkBlock.tags,
54651
- icon: sdkBlock.icon,
54652
- layout: sdkBlock.layout,
54653
- variants: sdkBlock.variants,
54654
- defaultVariant: sdkBlock.defaultVariant,
54655
- variantOptions: sdkBlock.variantOptions,
54656
- previewCustomize: sdkBlock.previewCustomize,
54657
- behaviours: {
54658
- supportsThemeSwitching: true,
54659
- inlineEditing: hasLayout,
54660
- animation: hasLayout,
54661
- paletteHidden: false
54662
- }
54663
- });
54966
+ //#region ../blocks/src/pageRendererBoundaries.tsx
54967
+ const boundaryKey = (previousBlockId, nextBlockId) => `${previousBlockId}\u0000${nextBlockId}`;
54968
+ function isSiteStyleTransitionStyleGroup(value) {
54969
+ return value?.startsWith("site-style-transition-") === true;
54664
54970
  }
54665
- /**
54666
- * Transforms an SDK custom block into a SystemBlockDefinition.
54667
- *
54668
- * This creates a minimal definition with just the manifest - no data loaders
54669
- * or content normalizers since SDK blocks handle their own rendering.
54670
- */
54671
- function transformSdkBlockToDefinition(sdkBlock) {
54672
- return {
54673
- manifest: transformSdkBlockToManifest(sdkBlock),
54674
- dataLoaders: sdkBlock.dataLoaders
54675
- };
54971
+ function boundaryMapForAdjacentBlockIds(boundaries) {
54972
+ return new Map(boundaries.map((boundary) => [boundaryKey(boundary.previousBlockId, boundary.nextBlockId), boundary]));
54676
54973
  }
54677
- //#endregion
54678
- //#region ../blocks/src/customBlockRegistry.ts
54679
- const defaultCustomBlockSourcePolicy = { kind: "canonical-db-fallback-sdk" };
54680
- function isCustomBlockKind(blockKind) {
54681
- return blockKind.startsWith("custom.");
54974
+ function boundaryBetweenBlocks(previousBlock, nextBlock, boundaries) {
54975
+ const previousBlockId = previousBlock?.id ?? null;
54976
+ const nextBlockId = nextBlock?.id ?? null;
54977
+ if (!previousBlockId || !nextBlockId) return null;
54978
+ return boundaries.get(boundaryKey(previousBlockId, nextBlockId)) ?? null;
54682
54979
  }
54683
- function transformToBlockDescriptor(sdkBlock, source = "sdk") {
54980
+ function renderBoundaryAfterBlock(input) {
54981
+ const previousBlockId = input.block.id;
54982
+ const nextBlockId = input.nextBlock?.id ?? null;
54983
+ if (!previousBlockId || !nextBlockId) return null;
54984
+ const boundary = input.boundaryByAdjacentBlockIds.get(boundaryKey(previousBlockId, nextBlockId));
54985
+ if (!boundary) return null;
54986
+ const rendered = /* @__PURE__ */ jsx("div", {
54987
+ "aria-hidden": "true",
54988
+ "data-block-boundary": "",
54989
+ "data-boundary-id": boundary.boundaryId,
54990
+ "data-boundary-previous-block-id": boundary.previousBlockId,
54991
+ "data-boundary-next-block-id": boundary.nextBlockId,
54992
+ "data-style-group": boundary.styleGroup,
54993
+ style: boundaryCssVarsStyle(boundary)
54994
+ }, `${input.blockKey}:boundary`);
54995
+ return input.wrapBoundary ? input.wrapBoundary(boundary, rendered) : rendered;
54996
+ }
54997
+ function boundaryCssVarsStyle(boundary) {
54684
54998
  return {
54685
- name: sdkBlock.id,
54686
- title: sdkBlock.title,
54687
- description: sdkBlock.description,
54688
- category: sdkBlock.category,
54689
- tags: sdkBlock.tags,
54690
- icon: sdkBlock.icon,
54691
- definition: transformSdkBlockToDefinition(sdkBlock),
54692
- source
54999
+ "--site-style-transition-from": boundary.cssVars.from,
55000
+ "--site-style-transition-to": boundary.cssVars.to
54693
55001
  };
54694
55002
  }
54695
- function toResolvedCustomBlock(manifest, source) {
55003
+ function boundaryReserveCssVarsStyle(input) {
55004
+ const before = input.before?.metrics.reserveCss ?? null;
55005
+ const after = input.after?.metrics.reserveCss ?? null;
55006
+ if (!before && !after) return void 0;
54696
55007
  return {
54697
- blockKind: manifest.id,
54698
- manifest: transformSdkBlockToManifest(manifest),
54699
- source,
54700
- descriptor: transformToBlockDescriptor(manifest, source.kind === "managed-database" ? "database" : "sdk")
55008
+ ...before ? { "--site-style-boundary-before-reserve": before } : {},
55009
+ ...after ? { "--site-style-boundary-after-reserve": after } : {}
54701
55010
  };
54702
55011
  }
54703
- function planCustomBlockRegistryResolution({ sdkConfig, customBlocks = [], policy = defaultCustomBlockSourcePolicy }) {
54704
- switch (policy.kind) {
54705
- case "canonical-db-fallback-sdk": {
54706
- const entriesByKind = /* @__PURE__ */ new Map();
54707
- const conflicts = [];
54708
- for (const customBlock of customBlocks) entriesByKind.set(customBlock.manifest.id, toResolvedCustomBlock(customBlock.manifest, customBlock.source));
54709
- for (const sdkBlock of sdkConfig?.customBlocks ?? []) {
54710
- const existing = entriesByKind.get(sdkBlock.id);
54711
- if (existing) {
54712
- conflicts.push({
54713
- kind: "conflict",
54714
- blockKind: existing.blockKind,
54715
- winner: existing.source,
54716
- loser: { kind: "sdk-config" },
54717
- reason: "db-canonical-sdk-fallback"
54718
- });
54719
- continue;
54720
- }
54721
- entriesByKind.set(sdkBlock.id, toResolvedCustomBlock(sdkBlock, { kind: "sdk-config" }));
54722
- }
54723
- return {
54724
- policy,
54725
- entries: Array.from(entriesByKind.values()),
54726
- conflicts
54727
- };
54728
- }
54729
- }
55012
+ function transitionCssVarsStyle(content) {
55013
+ const transitionStyles = isObjectRecord$1(content._transitionStyles) ? content._transitionStyles : null;
55014
+ const cssVars = isObjectRecord$1(transitionStyles?.cssVars) ? transitionStyles.cssVars : null;
55015
+ const from = typeof cssVars?.from === "string" ? cssVars.from : null;
55016
+ const to = typeof cssVars?.to === "string" ? cssVars.to : null;
55017
+ if (!from && !to) return void 0;
55018
+ return {
55019
+ ...from ? { "--site-style-transition-from": from } : {},
55020
+ ...to ? { "--site-style-transition-to": to } : {}
55021
+ };
54730
55022
  }
54731
- function createCustomBlockRegistry({ sdkConfig, customBlocks = [], policy = defaultCustomBlockSourcePolicy, onConflict }) {
54732
- const plan = planCustomBlockRegistryResolution({
54733
- sdkConfig,
54734
- customBlocks,
54735
- policy
54736
- });
54737
- const entriesByKind = new Map(plan.entries.map((entry) => [entry.blockKind, entry]));
54738
- for (const conflict of plan.conflicts) onConflict?.(`Using ${sourceLabel(conflict.winner)} custom block "${conflict.blockKind}" - ${sourceLabel(conflict.loser)} block is fallback only`);
55023
+ function mergeStyleObjects(left, right) {
55024
+ if (!left) return right;
55025
+ if (!right) return left;
54739
55026
  return {
54740
- entries: plan.entries,
54741
- conflicts: plan.conflicts,
54742
- findManifest: (blockKind) => {
54743
- if (!isCustomBlockKind(blockKind)) return void 0;
54744
- return entriesByKind.get(blockKind);
54745
- }
55027
+ ...left,
55028
+ ...right
54746
55029
  };
54747
55030
  }
54748
- function sourceLabel(source) {
54749
- switch (source.kind) {
54750
- case "managed-database": return "DB";
54751
- case "sdk-synced": return "SDK-synced DB";
54752
- case "sdk-config": return "SDK config";
54753
- default: return assertNever$4(source);
54754
- }
55031
+ function pageBlockPosition(index, blockCount) {
55032
+ if (blockCount <= 1) return "only";
55033
+ if (index === 0) return "first";
55034
+ if (index === blockCount - 1) return "last";
55035
+ return "middle";
54755
55036
  }
54756
55037
  //#endregion
54757
55038
  //#region ../blocks/src/PageRenderer.tsx
54758
- function PageRenderer$1({ theme, page, runtimeBoundaries, usePlaceholders = false, dataContext, wrapBlock, wrapBoundary, registry, themeTokens: providedThemeTokens, routeMap, blockOverrides, sdkConfig, customBlocks, previewAuthoring }) {
55039
+ function PageRenderer$1(props) {
55040
+ const { page, runtimeBoundaries, usePlaceholders = false, dataContext, wrapBlock, wrapBoundary, registry, routeMap, blockOverrides, sdkConfig, customBlocks, previewAuthoring } = props;
54759
55041
  const imageResolveContext = React$1.useMemo(() => resolvePageRendererImageResolveContext(dataContext), [
54760
55042
  dataContext?.imageResolveContext,
54761
55043
  dataContext?.mediaAssets,
@@ -54764,12 +55046,16 @@ function PageRenderer$1({ theme, page, runtimeBoundaries, usePlaceholders = fals
54764
55046
  ]);
54765
55047
  const boundaryByAdjacentBlockIds = React$1.useMemo(() => boundaryMapForAdjacentBlockIds(runtimeBoundaries ?? []), [runtimeBoundaries]);
54766
55048
  const usesRuntimeBoundaries = runtimeBoundaries !== void 0;
55049
+ const themeResources = React$1.useMemo(() => resolvePageThemeResources(props), [
55050
+ props.rendering,
55051
+ props.theme,
55052
+ props.themeTokens
55053
+ ]);
54767
55054
  if (!page || page.blocks.length === 0) return /* @__PURE__ */ jsx("div", {
54768
55055
  className: "rb-p-6 rb-caption",
54769
55056
  style: textColorStyle("mutedText"),
54770
55057
  children: "No blocks found."
54771
55058
  });
54772
- const themeTokens = providedThemeTokens ?? buildThemeRuntime$1(theme).tokens;
54773
55059
  const resolvedRegistry = registry ?? getDefaultComponentRegistry();
54774
55060
  setContextResolveImageUrlContext(imageResolveContext);
54775
55061
  return /* @__PURE__ */ jsx("div", { children: page.blocks.map((block, index) => {
@@ -54792,22 +55078,14 @@ function PageRenderer$1({ theme, page, runtimeBoundaries, usePlaceholders = fals
54792
55078
  const renderableContent = getRenderableContent(block, dataContext?.previewStage);
54793
55079
  const variantKey = definition?.manifest ? resolveVariantKey(definition.manifest, renderableContent) : null;
54794
55080
  const shouldUseWrapper = !managesOwnWrapper || Boolean(wrapBlock);
54795
- const blockSectionProps = {
54796
- themeTokens,
54797
- themeConfig: theme,
55081
+ const blockSectionProps = buildBlockSectionProps({
55082
+ props,
55083
+ themeResources,
54798
55084
  block,
54799
- usePlaceholders,
54800
- dataContext,
54801
55085
  blockKey,
54802
- registry: resolvedRegistry,
54803
- routeMap,
54804
- wrapBlock,
54805
- blockOverrides,
54806
- sdkConfig,
54807
- customBlocks,
54808
55086
  imageResolveContext,
54809
- previewAuthoring
54810
- };
55087
+ registry: resolvedRegistry
55088
+ });
54811
55089
  if (!shouldUseWrapper) {
54812
55090
  const rendered = /* @__PURE__ */ jsx(MemoBlockSection, { ...blockSectionProps }, `${blockKey}:block`);
54813
55091
  return boundaryElement ? /* @__PURE__ */ jsxs(React$1.Fragment, { children: [rendered, boundaryElement] }, blockKey) : rendered;
@@ -54849,81 +55127,6 @@ function PageRenderer$1({ theme, page, runtimeBoundaries, usePlaceholders = fals
54849
55127
  })] }, blockKey);
54850
55128
  }) });
54851
55129
  }
54852
- function isSiteStyleTransitionStyleGroup(value) {
54853
- return value?.startsWith("site-style-transition-") === true;
54854
- }
54855
- function boundaryMapForAdjacentBlockIds(boundaries) {
54856
- return new Map(boundaries.map((boundary) => [boundaryKey(boundary.previousBlockId, boundary.nextBlockId), boundary]));
54857
- }
54858
- function boundaryKey(previousBlockId, nextBlockId) {
54859
- return `${previousBlockId}\u0000${nextBlockId}`;
54860
- }
54861
- function boundaryBetweenBlocks(previousBlock, nextBlock, boundaryByAdjacentBlockIds) {
54862
- const previousBlockId = previousBlock?.id ?? null;
54863
- const nextBlockId = nextBlock?.id ?? null;
54864
- if (!previousBlockId || !nextBlockId) return null;
54865
- return boundaryByAdjacentBlockIds.get(boundaryKey(previousBlockId, nextBlockId)) ?? null;
54866
- }
54867
- function renderBoundaryAfterBlock(input) {
54868
- const previousBlockId = input.block.id;
54869
- const nextBlockId = input.nextBlock?.id ?? null;
54870
- if (!previousBlockId || !nextBlockId) return null;
54871
- const boundary = input.boundaryByAdjacentBlockIds.get(boundaryKey(previousBlockId, nextBlockId));
54872
- if (!boundary) return null;
54873
- const rendered = /* @__PURE__ */ jsx("div", {
54874
- "aria-hidden": "true",
54875
- "data-block-boundary": "",
54876
- "data-boundary-id": boundary.boundaryId,
54877
- "data-boundary-previous-block-id": boundary.previousBlockId,
54878
- "data-boundary-next-block-id": boundary.nextBlockId,
54879
- "data-style-group": boundary.styleGroup,
54880
- style: boundaryCssVarsStyle(boundary)
54881
- }, `${input.blockKey}:boundary`);
54882
- return input.wrapBoundary ? input.wrapBoundary(boundary, rendered) : rendered;
54883
- }
54884
- function boundaryCssVarsStyle(boundary) {
54885
- return {
54886
- "--site-style-transition-from": boundary.cssVars.from,
54887
- "--site-style-transition-to": boundary.cssVars.to
54888
- };
54889
- }
54890
- function boundaryReserveCssVarsStyle(input) {
54891
- const before = input.before ? boundaryReserveValueForTreatment(input.before) : null;
54892
- const after = input.after ? boundaryReserveValueForTreatment(input.after) : null;
54893
- if (!before && !after) return void 0;
54894
- return {
54895
- ...before ? { "--site-style-boundary-before-reserve": before } : {},
54896
- ...after ? { "--site-style-boundary-after-reserve": after } : {}
54897
- };
54898
- }
54899
- function boundaryReserveValueForTreatment(boundary) {
54900
- return boundary.metrics.reserveCss;
54901
- }
54902
- function transitionCssVarsStyle(content) {
54903
- const transitionStyles = isObjectRecord$1(content._transitionStyles) ? content._transitionStyles : null;
54904
- const cssVars = isObjectRecord$1(transitionStyles?.cssVars) ? transitionStyles.cssVars : null;
54905
- const from = typeof cssVars?.from === "string" ? cssVars.from : null;
54906
- const to = typeof cssVars?.to === "string" ? cssVars.to : null;
54907
- if (!from && !to) return void 0;
54908
- return {
54909
- ...from ? { "--site-style-transition-from": from } : {},
54910
- ...to ? { "--site-style-transition-to": to } : {}
54911
- };
54912
- }
54913
- function mergeStyleObjects(left, right) {
54914
- if (!left) return right;
54915
- if (!right) return left;
54916
- return {
54917
- ...left,
54918
- ...right
54919
- };
54920
- }
54921
- function pageBlockPosition(index, blockCount) {
54922
- if (blockCount <= 1) return "only";
54923
- if (index === 0) return "first";
54924
- if (index === blockCount - 1) return "last";
54925
- return "middle";
54926
- }
54927
55130
  function resolvePageRendererImageResolveContext(dataContext) {
54928
55131
  const input = dataContext?.imageResolveContext;
54929
55132
  return buildResolveImageUrlContext({
@@ -54933,6 +55136,23 @@ function resolvePageRendererImageResolveContext(dataContext) {
54933
55136
  mediaAssets: input?.mediaAssets ?? dataContext?.mediaAssets
54934
55137
  });
54935
55138
  }
55139
+ function buildBlockSectionProps(input) {
55140
+ return {
55141
+ themeResources: input.themeResources,
55142
+ block: input.block,
55143
+ usePlaceholders: input.props.usePlaceholders ?? false,
55144
+ dataContext: input.props.dataContext,
55145
+ blockKey: input.blockKey,
55146
+ registry: input.registry,
55147
+ routeMap: input.props.routeMap,
55148
+ wrapBlock: input.props.wrapBlock,
55149
+ blockOverrides: input.props.blockOverrides,
55150
+ sdkConfig: input.props.sdkConfig,
55151
+ customBlocks: input.props.customBlocks,
55152
+ imageResolveContext: input.imageResolveContext,
55153
+ previewAuthoring: input.props.previewAuthoring
55154
+ };
55155
+ }
54936
55156
  /**
54937
55157
  * Look up a block override component by block kind.
54938
55158
  * Supports both full ("block.hero") and short ("hero") keys.
@@ -54999,7 +55219,7 @@ function getCachedValidator(manifest, flavour) {
54999
55219
  * referential equality of all props that affect rendering. Standard React.memo
55000
55220
  * wouldn't catch all the render triggers from the editor store.
55001
55221
  */
55002
- const MemoBlockSection = React$1.memo(function MemoBlockSection({ themeTokens, themeConfig, block, usePlaceholders, dataContext, registry, routeMap, wrapBlock, blockOverrides, sdkConfig, customBlocks, imageResolveContext, previewAuthoring }) {
55222
+ const MemoBlockSection = React$1.memo(function MemoBlockSection({ themeResources, block, usePlaceholders, dataContext, registry, routeMap, wrapBlock, blockOverrides, sdkConfig, customBlocks, imageResolveContext, previewAuthoring }) {
55003
55223
  const perfStart = globalThis.process?.env?.DEBUG_PERF === "1" && typeof window === "undefined" ? Date.now() : 0;
55004
55224
  const fallbackImageResolveContext = getCurrentResolveImageUrlContext();
55005
55225
  const resolvedImageResolveContext = imageResolveContext ?? fallbackImageResolveContext;
@@ -55020,6 +55240,7 @@ const MemoBlockSection = React$1.memo(function MemoBlockSection({ themeTokens, t
55020
55240
  return node;
55021
55241
  }
55022
55242
  const OverrideComponent = getBlockOverride(block.kind, blockOverrides);
55243
+ requireBlockOverride(themeResources, OverrideComponent, block.kind);
55023
55244
  let definition = getBlockDefinition(block.kind);
55024
55245
  if (!definition && block.kind.startsWith("custom.")) definition = createCustomBlockRegistry({
55025
55246
  sdkConfig,
@@ -55032,8 +55253,7 @@ const MemoBlockSection = React$1.memo(function MemoBlockSection({ themeTokens, t
55032
55253
  if (OverrideComponent) {
55033
55254
  const rendered = /* @__PURE__ */ jsx(OverrideComponent, {
55034
55255
  content: getRenderableContent(block, dataContext?.previewStage),
55035
- theme: themeTokens,
55036
- themeConfig,
55256
+ ...overrideThemeProps(themeResources),
55037
55257
  data: void 0,
55038
55258
  siteId: dataContext?.siteId,
55039
55259
  apiBaseUrl: dataContext?.apiBaseUrl,
@@ -55132,8 +55352,7 @@ const MemoBlockSection = React$1.memo(function MemoBlockSection({ themeTokens, t
55132
55352
  const hasResolvedData = !!resolved && typeof resolved === "object" && Object.keys(resolved).length > 0;
55133
55353
  const baseProps = {
55134
55354
  content: hydratedContent,
55135
- theme: themeTokens,
55136
- themeConfig,
55355
+ ...overrideThemeProps(themeResources),
55137
55356
  data: resolved,
55138
55357
  siteId: dataContext?.siteId,
55139
55358
  apiBaseUrl: dataContext?.apiBaseUrl,
@@ -55153,6 +55372,7 @@ const MemoBlockSection = React$1.memo(function MemoBlockSection({ themeTokens, t
55153
55372
  let rendered;
55154
55373
  if (OverrideComponent) rendered = /* @__PURE__ */ jsx(OverrideComponent, { ...baseProps });
55155
55374
  else {
55375
+ requireThemeResources(themeResources, block.kind);
55156
55376
  const BlockComponent = getCachedBlockComponent(definition.manifest);
55157
55377
  const pathBase = typeof block.id === "string" && block.id.length > 0 ? `blocks.${block.id}.` : void 0;
55158
55378
  const rootContext = { $root: {
@@ -55202,7 +55422,7 @@ const MemoBlockSection = React$1.memo(function MemoBlockSection({ themeTokens, t
55202
55422
  });
55203
55423
  }
55204
55424
  }, (prev, next) => {
55205
- return prev.block === next.block && prev.registry === next.registry && prev.dataContext === next.dataContext && prev.themeTokens === next.themeTokens && prev.themeConfig === next.themeConfig && prev.routeMap === next.routeMap && prev.usePlaceholders === next.usePlaceholders && prev.wrapBlock === next.wrapBlock && prev.blockOverrides === next.blockOverrides && prev.sdkConfig === next.sdkConfig && prev.customBlocks === next.customBlocks && prev.imageResolveContext === next.imageResolveContext && prev.previewAuthoring === next.previewAuthoring;
55425
+ return prev.block === next.block && prev.registry === next.registry && prev.dataContext === next.dataContext && prev.themeResources === next.themeResources && prev.routeMap === next.routeMap && prev.usePlaceholders === next.usePlaceholders && prev.wrapBlock === next.wrapBlock && prev.blockOverrides === next.blockOverrides && prev.sdkConfig === next.sdkConfig && prev.customBlocks === next.customBlocks && prev.imageResolveContext === next.imageResolveContext && prev.previewAuthoring === next.previewAuthoring;
55206
55426
  });
55207
55427
  function fallback(message) {
55208
55428
  return /* @__PURE__ */ jsx("div", {
@@ -68421,6 +68641,10 @@ function toBlocksImageResolveContextInput(context) {
68421
68641
  }
68422
68642
  //#endregion
68423
68643
  //#region src/rendering/blocks-page-renderer.ts
68644
+ const MissingBlockOverrideError = MissingBlockOverrideError$1;
68645
+ function isOverrideOnlyPageRenderer(props) {
68646
+ return props.rendering?.kind === "overrides-only";
68647
+ }
68424
68648
  function normalizeSdkCustomBlocks(customBlocks) {
68425
68649
  if (!customBlocks) return void 0;
68426
68650
  return customBlocks.map((block) => {
@@ -68442,8 +68666,7 @@ function toBlocksBlockOverrides(overrides) {
68442
68666
  };
68443
68667
  return result;
68444
68668
  }
68445
- function toBlocksDataContext(dataContext) {
68446
- if (!dataContext) return void 0;
68669
+ function toBlocksPageRendererDataContext(dataContext) {
68447
68670
  return {
68448
68671
  ...dataContext,
68449
68672
  mediaAssets: toBlocksMediaAssets(dataContext.mediaAssets),
@@ -68452,15 +68675,23 @@ function toBlocksDataContext(dataContext) {
68452
68675
  }
68453
68676
  function PageRenderer(props) {
68454
68677
  const blocksSdkConfig = props.sdkConfig ? { customBlocks: normalizeSdkCustomBlocks(props.sdkConfig.customBlocks) } : props.sdkConfig;
68455
- const blocksTheme = parseBlocksTheme(props.theme);
68456
- const blocksProps = {
68457
- ...props,
68458
- theme: blocksTheme,
68459
- dataContext: toBlocksDataContext(props.dataContext),
68678
+ const { rendering: _rendering, theme: _theme, themeTokens: _themeTokens, ...commonProps } = props;
68679
+ const commonBlocksProps = {
68680
+ ...commonProps,
68681
+ dataContext: props.dataContext ? toBlocksPageRendererDataContext(props.dataContext) : void 0,
68460
68682
  blockOverrides: toBlocksBlockOverrides(props.blockOverrides),
68461
68683
  sdkConfig: blocksSdkConfig,
68462
68684
  customBlocks: normalizeSdkCustomBlocks(props.customBlocks)
68463
68685
  };
68686
+ const blocksProps = isOverrideOnlyPageRenderer(props) ? {
68687
+ ...commonBlocksProps,
68688
+ rendering: { kind: "overrides-only" },
68689
+ blockOverrides: toBlocksBlockOverrides(props.blockOverrides) ?? {}
68690
+ } : {
68691
+ ...commonBlocksProps,
68692
+ theme: parseBlocksTheme(props.theme),
68693
+ themeTokens: props.themeTokens
68694
+ };
68464
68695
  return React$1.createElement(PageRenderer$1, blocksProps);
68465
68696
  }
68466
68697
  //#endregion
@@ -68502,57 +68733,85 @@ function renderWithSdkThemeRuntime({ themeRuntime, theme, children }) {
68502
68733
  default: return assertNever$4(themeRuntime);
68503
68734
  }
68504
68735
  }
68736
+ function renderWithOverrideOnlyRuntime({ runtime, children }) {
68737
+ switch (runtime.kind) {
68738
+ case "responsive-only": return /* @__PURE__ */ jsx(ResponsiveScope, {
68739
+ responsiveMode: runtime.responsiveMode,
68740
+ children
68741
+ });
68742
+ case "none": return /* @__PURE__ */ jsx(Fragment, { children });
68743
+ default: return assertNever$4(runtime);
68744
+ }
68745
+ }
68505
68746
  //#endregion
68506
68747
  //#region src/rendering/components/pageShared.tsx
68507
- function PageContent({ page, runtimeBoundaries, theme, themeTokens: providedTokens, siteId, resolvedData, bookingOfferingPresets, routeMap, pagesByIdentifier, entriesByIdentifier, wrapBlock, registry, usePlaceholders = false, blockOverrides, sdkConfig, customBlocks, supabaseUrl, mediaAssets, apiBaseUrl, portalToken, previewToken, dataContext, themeRuntime = defaultPageThemeRuntime }) {
68508
- const baseTokens = providedTokens ?? buildThemeRuntime(theme).tokens;
68509
- return renderWithSdkThemeRuntime({
68510
- themeRuntime,
68511
- theme,
68512
- children: /* @__PURE__ */ jsx(PageRenderer, {
68513
- theme,
68514
- page,
68515
- runtimeBoundaries,
68516
- themeTokens: sdkConfig?.theme?.palette ? {
68517
- ...baseTokens,
68518
- palette: {
68519
- ...baseTokens.palette,
68520
- ...sdkConfig.theme.palette
68521
- }
68522
- } : baseTokens,
68523
- usePlaceholders,
68524
- dataContext: {
68748
+ function isOverrideOnlyPage(props) {
68749
+ return props.rendering?.kind === "overrides-only";
68750
+ }
68751
+ function resolvePageThemeTokens(props) {
68752
+ const baseTokens = props.themeTokens ?? buildThemeRuntime(props.theme).tokens;
68753
+ return props.sdkConfig?.theme?.palette ? {
68754
+ ...baseTokens,
68755
+ palette: {
68756
+ ...baseTokens.palette,
68757
+ ...props.sdkConfig.theme.palette
68758
+ }
68759
+ } : baseTokens;
68760
+ }
68761
+ function PageContent(props) {
68762
+ const { page, runtimeBoundaries, siteId, resolvedData, bookingOfferingPresets, routeMap, pagesByIdentifier, entriesByIdentifier, wrapBlock, registry, usePlaceholders = false, blockOverrides, sdkConfig, customBlocks, supabaseUrl, mediaAssets, apiBaseUrl, portalToken, previewToken, dataContext } = props;
68763
+ const rendererCommonProps = {
68764
+ page,
68765
+ runtimeBoundaries,
68766
+ usePlaceholders,
68767
+ dataContext: {
68768
+ siteId,
68769
+ apiBaseUrl,
68770
+ portalToken,
68771
+ previewToken,
68772
+ resolvedData,
68773
+ bookingOfferingPresets: bookingOfferingPresets ?? [],
68774
+ routes: routeMap,
68775
+ pagesByIdentifier,
68776
+ entriesByIdentifier,
68777
+ occurrenceContext: dataContext?.occurrenceContext ?? null,
68778
+ entrySubrouteContext: dataContext?.entrySubrouteContext ?? null,
68779
+ contentEntry: dataContext?.contentEntry ?? null,
68780
+ pageSurface: dataContext?.pageSurface ?? null,
68781
+ subject: dataContext?.subject ?? null,
68782
+ editableRouteMetadataFieldIds: dataContext?.editableRouteMetadataFieldIds ?? null,
68783
+ previewStage: dataContext?.previewStage,
68784
+ supabaseUrl,
68785
+ mediaAssets,
68786
+ imageResolveContext: {
68525
68787
  siteId,
68526
- apiBaseUrl,
68527
- portalToken,
68528
- previewToken,
68529
- resolvedData,
68530
- bookingOfferingPresets: bookingOfferingPresets ?? [],
68531
- routes: routeMap,
68532
- pagesByIdentifier,
68533
- entriesByIdentifier,
68534
- occurrenceContext: dataContext?.occurrenceContext ?? null,
68535
- entrySubrouteContext: dataContext?.entrySubrouteContext ?? null,
68536
- contentEntry: dataContext?.contentEntry ?? null,
68537
- pageSurface: dataContext?.pageSurface ?? null,
68538
- subject: dataContext?.subject ?? null,
68539
- editableRouteMetadataFieldIds: dataContext?.editableRouteMetadataFieldIds ?? null,
68540
- previewStage: dataContext?.previewStage,
68541
68788
  supabaseUrl,
68542
- mediaAssets,
68543
- imageResolveContext: {
68544
- siteId,
68545
- supabaseUrl,
68546
- mediaAssets
68547
- }
68548
- },
68549
- routeMap,
68550
- wrapBlock,
68551
- registry,
68552
- blockOverrides,
68553
- sdkConfig: sdkConfig ? { customBlocks: sdkConfig.customBlocks } : null,
68554
- customBlocks
68555
- })
68789
+ mediaAssets
68790
+ }
68791
+ },
68792
+ routeMap,
68793
+ wrapBlock,
68794
+ registry,
68795
+ sdkConfig: sdkConfig ? { customBlocks: sdkConfig.customBlocks } : null,
68796
+ customBlocks
68797
+ };
68798
+ const content = isOverrideOnlyPage(props) ? /* @__PURE__ */ jsx(PageRenderer, {
68799
+ ...rendererCommonProps,
68800
+ rendering: { kind: "overrides-only" },
68801
+ blockOverrides: props.blockOverrides
68802
+ }) : /* @__PURE__ */ jsx(PageRenderer, {
68803
+ ...rendererCommonProps,
68804
+ theme: props.theme,
68805
+ themeTokens: resolvePageThemeTokens(props),
68806
+ blockOverrides
68807
+ });
68808
+ return isOverrideOnlyPage(props) ? renderWithOverrideOnlyRuntime({
68809
+ runtime: props.rendering.runtime,
68810
+ children: content
68811
+ }) : renderWithSdkThemeRuntime({
68812
+ themeRuntime: props.themeRuntime ?? defaultPageThemeRuntime,
68813
+ theme: props.theme,
68814
+ children: content
68556
68815
  });
68557
68816
  }
68558
68817
  //#endregion
@@ -69031,12 +69290,48 @@ function buildLogo(logo, fallbackAlt) {
69031
69290
  return result;
69032
69291
  }
69033
69292
  //#endregion
69293
+ //#region src/rendering/renderingMode.ts
69294
+ const defaultOverrideOnlyRuntime = { kind: "responsive-only" };
69295
+ //#endregion
69034
69296
  //#region src/rendering/components/Layout.tsx
69035
69297
  /**
69036
69298
  * Layout component with header and footer
69037
69299
  *
69038
69300
  * Renders site header and footer around content. Fetches site data if not provided.
69039
69301
  */
69302
+ function isOverrideOnlyLayout(props) {
69303
+ return props.rendering?.kind === "overrides-only";
69304
+ }
69305
+ var UnsupportedOverrideOnlyLayoutChromeError = class extends Error {
69306
+ constructor(surface) {
69307
+ super(`Override-only Layout requires a custom or disabled ${surface}; SDK default chrome is unavailable.`);
69308
+ this.surface = surface;
69309
+ this.code = "unsupported_override_only_layout_chrome";
69310
+ this.name = "UnsupportedOverrideOnlyLayoutChromeError";
69311
+ }
69312
+ };
69313
+ async function resolveLayoutSiteData(props) {
69314
+ if (props.siteData) return props.siteData;
69315
+ if (!props.client) throw new Error("Layout: must provide either siteData or client");
69316
+ if (!props.siteId && !props.slug && !props.domain) throw new Error("Layout: must provide siteId, slug, or domain when using client");
69317
+ return props.client.getSite({
69318
+ id: props.siteId,
69319
+ slug: props.slug,
69320
+ domain: props.domain
69321
+ });
69322
+ }
69323
+ function renderOverrideOnlyLayout(props, data) {
69324
+ if (data.header === true) throw new UnsupportedOverrideOnlyLayoutChromeError("header");
69325
+ if (data.footer === true) throw new UnsupportedOverrideOnlyLayoutChromeError("footer");
69326
+ return renderWithOverrideOnlyRuntime({
69327
+ runtime: props.rendering.runtime ?? defaultOverrideOnlyRuntime,
69328
+ children: /* @__PURE__ */ jsxs(Fragment, { children: [
69329
+ typeof props.header === "function" ? props.header(data.headerData) : null,
69330
+ props.children,
69331
+ typeof props.footer === "function" ? props.footer(data.footerData) : null
69332
+ ] })
69333
+ });
69334
+ }
69040
69335
  /**
69041
69336
  * Layout component that wraps content with site header and footer.
69042
69337
  *
@@ -69072,20 +69367,13 @@ function buildLogo(logo, fallbackAlt) {
69072
69367
  * </Layout>
69073
69368
  * ```
69074
69369
  */
69075
- async function Layout({ siteData: providedSiteData, client, siteId, slug, domain, children, header = true, footer = true, headerVariant, hasPortalSession = false, previewStage = "published", themeRuntime }) {
69076
- let siteData = providedSiteData;
69077
- if (!siteData) {
69078
- if (!client) throw new Error("Layout: must provide either siteData or client");
69079
- if (!siteId && !slug && !domain) throw new Error("Layout: must provide siteId, slug, or domain when using client");
69080
- siteData = await client.getSite({
69081
- id: siteId,
69082
- slug,
69083
- domain
69084
- });
69085
- }
69086
- const { site, theme, navigation, layout, routes } = siteData;
69370
+ async function Layout(props) {
69371
+ const { children, hasPortalSession = false, previewStage = "published" } = props;
69372
+ const header = props.header ?? true;
69373
+ const footer = props.footer ?? true;
69374
+ const siteData = await resolveLayoutSiteData(props);
69375
+ const { site, navigation, layout, routes } = siteData;
69087
69376
  const footerBlocks = siteData.footerBlocks ?? [];
69088
- const builtThemeRuntime = buildThemeRuntime(theme);
69089
69377
  const navigationOptions = {
69090
69378
  hasPortalSession,
69091
69379
  previewStage,
@@ -69099,22 +69387,38 @@ async function Layout({ siteData: providedSiteData, client, siteId, slug, domain
69099
69387
  const footerMenuViewModel = buildFooterMenu(navigation, routes, navigationOptions);
69100
69388
  const legalFooterMenuViewModel = buildFooterMenuForRole(navigation, routes, "legal-policy", navigationOptions);
69101
69389
  const logoViewModel = buildLogo(layout.logo ?? null, site.title);
69102
- const headerData = {
69390
+ const customHeaderData = {
69103
69391
  menu: menuViewModel,
69104
69392
  logo: logoViewModel,
69105
69393
  site,
69106
- theme,
69107
69394
  routes
69108
69395
  };
69109
- const footerData = {
69396
+ const customFooterData = {
69110
69397
  menu: menuViewModel,
69111
69398
  footerMenu: footerMenuViewModel,
69112
69399
  legalFooterMenu: legalFooterMenuViewModel,
69113
69400
  logo: logoViewModel,
69114
69401
  site,
69115
- theme,
69116
69402
  routes
69117
69403
  };
69404
+ if (isOverrideOnlyLayout(props)) return renderOverrideOnlyLayout(props, {
69405
+ header: props.header ?? true,
69406
+ footer: props.footer ?? true,
69407
+ headerData: customHeaderData,
69408
+ footerData: customFooterData
69409
+ });
69410
+ const { theme } = siteData;
69411
+ const builtThemeRuntime = buildThemeRuntime(theme);
69412
+ const headerVariant = props.headerVariant;
69413
+ const themeRuntime = props.themeRuntime;
69414
+ const headerData = {
69415
+ ...customHeaderData,
69416
+ theme
69417
+ };
69418
+ const footerData = {
69419
+ ...customFooterData,
69420
+ theme
69421
+ };
69118
69422
  const headerContent = headerVariant ? {
69119
69423
  ...layout.header,
69120
69424
  variant: headerVariant
@@ -69132,7 +69436,7 @@ async function Layout({ siteData: providedSiteData, client, siteId, slug, domain
69132
69436
  try {
69133
69437
  apiBaseUrl = getRiverbankEnv().baseUrl;
69134
69438
  } catch {}
69135
- const viewModelOverrides = {
69439
+ const sharedViewModelOverrides = {
69136
69440
  $root: {
69137
69441
  siteId: site.id,
69138
69442
  apiBaseUrl,
@@ -69145,14 +69449,24 @@ async function Layout({ siteData: providedSiteData, client, siteId, slug, domain
69145
69449
  site,
69146
69450
  menu: menuViewModel,
69147
69451
  footerMenu: footerMenuViewModel,
69148
- legalFooterMenu: legalFooterMenuViewModel,
69452
+ legalFooterMenu: legalFooterMenuViewModel
69453
+ };
69454
+ const headerViewModelOverrides = {
69455
+ ...sharedViewModelOverrides,
69149
69456
  content: { logo: logoViewModel }
69150
69457
  };
69458
+ const footerViewModelOverrides = {
69459
+ ...sharedViewModelOverrides,
69460
+ content: {
69461
+ ...layout.footer,
69462
+ logo: logoViewModel
69463
+ }
69464
+ };
69151
69465
  let headerElement = null;
69152
69466
  if (header === true) headerElement = renderBlock(siteHeaderManifest, headerContent, {
69153
69467
  theme: builtThemeRuntime.tokens,
69154
69468
  themeConfig: blocksThemeWithVariant,
69155
- viewModelOverrides
69469
+ viewModelOverrides: headerViewModelOverrides
69156
69470
  });
69157
69471
  else if (typeof header === "function") headerElement = header(headerData);
69158
69472
  let footerElement = null;
@@ -69187,7 +69501,7 @@ async function Layout({ siteData: providedSiteData, client, siteId, slug, domain
69187
69501
  const defaultFooterElement = footerPlan.renderDefaultFooter ? renderBlock(siteFooterManifest, layout.footer, {
69188
69502
  theme: builtThemeRuntime.tokens,
69189
69503
  themeConfig: blocksTheme,
69190
- viewModelOverrides
69504
+ viewModelOverrides: footerViewModelOverrides
69191
69505
  }) : null;
69192
69506
  footerElement = footerPlan.mode === "default+blocks" ? /* @__PURE__ */ jsxs(Fragment, { children: [footerBlocksElement, defaultFooterElement] }) : footerPlan.mode === "blocks" ? footerBlocksElement : footerPlan.mode === "none" ? null : defaultFooterElement;
69193
69507
  } else if (typeof footer === "function") footerElement = footer(footerData);
@@ -69497,6 +69811,7 @@ const SUPPORTED_LOADER_ENDPOINTS$1 = [
69497
69811
  "listPublicRecurringSchedule",
69498
69812
  "getPublicEventDetails",
69499
69813
  "listPublicWholeSeriesOfferings",
69814
+ "getPublicWholeSeriesOffering",
69500
69815
  "listPublicRouteCandidates",
69501
69816
  "listPublicTeamMembers",
69502
69817
  "listPublicProducts",
@@ -71922,6 +72237,7 @@ const loaderAdapters = {
71922
72237
  listPublicEvents,
71923
72238
  listPublicRecurringSchedule,
71924
72239
  getPublicEventDetails,
72240
+ getPublicWholeSeriesOffering,
71925
72241
  listPublicRouteCandidates,
71926
72242
  listPublicTeamMembers,
71927
72243
  listPublicProducts,
@@ -72016,6 +72332,13 @@ async function listPublicEvents({ client, params }) {
72016
72332
  async function listPublicRecurringSchedule(input) {
72017
72333
  return projectRecurringSchedule(await listPublicEvents(input));
72018
72334
  }
72335
+ async function getPublicWholeSeriesOffering({ client, params }) {
72336
+ return await client.getPublicWholeSeriesOffering({
72337
+ siteId: requireStringParam(params, "siteId", "getPublicWholeSeriesOffering"),
72338
+ eventSeriesId: requireStringParam(params, "eventSeriesId", "getPublicWholeSeriesOffering"),
72339
+ stage: readStringParam(params, "stage")
72340
+ });
72341
+ }
72019
72342
  async function getPublicEventDetails({ client, params }) {
72020
72343
  return await client.getPublicEventDetails({
72021
72344
  siteId: requireStringParam(params, "siteId", "getPublicEventDetails"),
@@ -72160,6 +72483,17 @@ async function prefetchBlockDataWithDeps(deps, page, context, client, options) {
72160
72483
  }
72161
72484
  //#endregion
72162
72485
  //#region src/rendering/components/Block.shared.tsx
72486
+ function isOverrideOnlyBlock(props) {
72487
+ return props.rendering?.kind === "overrides-only";
72488
+ }
72489
+ var MissingStandaloneBlockOverrideError = class extends Error {
72490
+ constructor(blockKind) {
72491
+ super(`Override-only standalone rendering requires an override for block kind "${blockKind}".`);
72492
+ this.blockKind = blockKind;
72493
+ this.code = "missing_standalone_block_override";
72494
+ this.name = "MissingStandaloneBlockOverrideError";
72495
+ }
72496
+ };
72163
72497
  function renderUnknownBlock(blockKind) {
72164
72498
  return /* @__PURE__ */ jsx("div", {
72165
72499
  className: "p-4 border border-red-300 bg-red-50 rounded",
@@ -72222,14 +72556,16 @@ function buildStandaloneBlockViewModel({ siteId, pageId, previewStage, apiBaseUr
72222
72556
  function renderBlockOverride({ OverrideComponent, props, runtime, resolvedData }) {
72223
72557
  return /* @__PURE__ */ jsx(OverrideComponent, {
72224
72558
  content: props.content,
72225
- theme: runtime.themeRuntime.tokens,
72226
- themeConfig: props.theme,
72559
+ ...runtime && "theme" in props ? {
72560
+ theme: runtime.themeRuntime.tokens,
72561
+ themeConfig: props.theme
72562
+ } : {},
72227
72563
  data: resolvedData,
72228
72564
  siteId: props.siteId,
72229
72565
  apiBaseUrl: props.apiBaseUrl,
72230
72566
  portalToken: props.portalToken ?? null,
72231
72567
  supabaseUrl: props.supabaseUrl,
72232
- imageResolveContext: runtime.imageResolveContext,
72568
+ imageResolveContext: runtime?.imageResolveContext,
72233
72569
  blockId: props.blockId ?? null,
72234
72570
  blockKind: props.blockKind
72235
72571
  });
@@ -72258,8 +72594,8 @@ function renderManifestBlock({ definition, props, runtime, resolvedData }) {
72258
72594
  async function BlockContent(props) {
72259
72595
  const definition = getBlockDefinition(props.blockKind);
72260
72596
  const OverrideComponent = props.override;
72597
+ if (isOverrideOnlyBlock(props) && !OverrideComponent) throw new MissingStandaloneBlockOverrideError(props.blockKind);
72261
72598
  if (!definition && !OverrideComponent) return renderUnknownBlock(props.blockKind);
72262
- const runtime = buildBlockContentRuntime(props);
72263
72599
  const resolvedData = await loadStandaloneBlockData({
72264
72600
  ...props,
72265
72601
  hasDefinition: Boolean(definition)
@@ -72267,13 +72603,14 @@ async function BlockContent(props) {
72267
72603
  if (OverrideComponent) return renderBlockOverride({
72268
72604
  OverrideComponent,
72269
72605
  props,
72270
- runtime,
72606
+ runtime: isOverrideOnlyBlock(props) ? void 0 : buildBlockContentRuntime(props),
72271
72607
  resolvedData
72272
72608
  });
72609
+ if (isOverrideOnlyBlock(props)) throw new MissingStandaloneBlockOverrideError(props.blockKind);
72273
72610
  return renderManifestBlock({
72274
72611
  definition,
72275
72612
  props,
72276
- runtime,
72613
+ runtime: buildBlockContentRuntime(props),
72277
72614
  resolvedData
72278
72615
  });
72279
72616
  }
@@ -72390,4 +72727,4 @@ async function resolveBlockOverridesForPage(registrations, page) {
72390
72727
  return resolved;
72391
72728
  }
72392
72729
  //#endregion
72393
- export { Block, Layout, Page, buildPageBlockKindIndex, collectUsedBlockKindsFromPageOutline, defineBlockOverrideRegistrations, defineBlockOverrides, defineLazyBlockOverride, resolveBlockOverridesForPage };
72730
+ export { Block, Layout, MissingBlockOverrideError, Page, UnsupportedOverrideOnlyLayoutChromeError, buildPageBlockKindIndex, collectUsedBlockKindsFromPageOutline, defineBlockOverrideRegistrations, defineBlockOverrides, defineLazyBlockOverride, resolveBlockOverridesForPage };