@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
@@ -220,7 +220,7 @@ function formatEventPricing(pricing, options = {}) {
220
220
  //#endregion
221
221
  //#region ../core/src/event-page-surface-subject.ts
222
222
  function parseEventPageSurfaceSubject(value) {
223
- if (!isRecord$36(value)) return err$3({ kind: "notObject" });
223
+ if (!isRecord$38(value)) return err$3({ kind: "notObject" });
224
224
  switch (value.kind) {
225
225
  case "eventSeries": {
226
226
  const eventSeriesId = parseEventSeriesId(value.eventSeriesId);
@@ -263,7 +263,7 @@ function parseEventPageSurfaceSubject(value) {
263
263
  });
264
264
  }
265
265
  }
266
- function isRecord$36(value) {
266
+ function isRecord$38(value) {
267
267
  return typeof value === "object" && value !== null && !Array.isArray(value);
268
268
  }
269
269
  //#endregion
@@ -497,7 +497,7 @@ function toLocationCoordinates(value) {
497
497
  }
498
498
  //#endregion
499
499
  //#region ../core/src/rich-text.ts
500
- function isRecord$34(value) {
500
+ function isRecord$36(value) {
501
501
  return typeof value === "object" && value !== null && !Array.isArray(value);
502
502
  }
503
503
  function hasOnlyKeys(value, allowed) {
@@ -516,13 +516,16 @@ function isDenseArrayOf(value, predicate) {
516
516
  return true;
517
517
  }
518
518
  function isTipTapMark(value) {
519
- return isRecord$34(value) && hasOnlyKeys(value, markKeys) && typeof value.type === "string" && value.type.length > 0 && (value.attrs === void 0 || isRecord$34(value.attrs));
519
+ return isRecord$36(value) && hasOnlyKeys(value, markKeys) && typeof value.type === "string" && value.type.length > 0 && (value.attrs === void 0 || isRecord$36(value.attrs));
520
520
  }
521
521
  function isTipTapNode(value) {
522
- if (!isRecord$34(value) || !hasOnlyKeys(value, nodeKeys) || typeof value.type !== "string" || value.type.length === 0 || value.type === "doc" || value.attrs !== void 0 && !isRecord$34(value.attrs) || value.marks !== void 0 && (!Array.isArray(value.marks) || !isDenseArrayOf(value.marks, isTipTapMark)) || value.content !== void 0 && (!Array.isArray(value.content) || !isDenseArrayOf(value.content, isTipTapNode))) return false;
522
+ if (!isRecord$36(value) || !hasOnlyKeys(value, nodeKeys) || typeof value.type !== "string" || value.type.length === 0 || value.type === "doc" || value.attrs !== void 0 && !isRecord$36(value.attrs) || value.marks !== void 0 && (!Array.isArray(value.marks) || !isDenseArrayOf(value.marks, isTipTapMark)) || value.content !== void 0 && (!Array.isArray(value.content) || !isDenseArrayOf(value.content, isTipTapNode))) return false;
523
523
  if (value.type === "text") return typeof value.text === "string" && value.text.length > 0 && value.content === void 0;
524
524
  return value.text === void 0;
525
525
  }
526
+ function parseNewsletterSignupDestinationProvider(value) {
527
+ return value === "riverbank" || value === "mailchimp" ? value : null;
528
+ }
526
529
  new Map([
527
530
  "brand",
528
531
  "supporting-text",
@@ -531,6 +534,7 @@ new Map([
531
534
  "business-address",
532
535
  "contact",
533
536
  "opening-hours",
537
+ "engagement",
534
538
  "legal-navigation",
535
539
  "legal"
536
540
  ].map((kind, index) => [kind, index]));
@@ -568,9 +572,9 @@ function resolvePlanningDateInput(input = {}) {
568
572
  }
569
573
  //#endregion
570
574
  //#region ../media-core/src/fileSafety.ts
571
- const CONTROL_CHARACTER_PATTERN$1 = /[\u0000-\u001f\u007f]/u;
575
+ const CONTROL_CHARACTER_PATTERN = /[\u0000-\u001f\u007f]/u;
572
576
  function containsUnsafePathSegmentCharacter(value) {
573
- return value.includes("/") || value.includes("\\") || CONTROL_CHARACTER_PATTERN$1.test(value);
577
+ return value.includes("/") || value.includes("\\") || CONTROL_CHARACTER_PATTERN.test(value);
574
578
  }
575
579
  function isReservedPathSegment(value) {
576
580
  return value === "." || value === "..";
@@ -17282,10 +17286,16 @@ function getHeaderPaintTargets(variant, themeId, state = "base") {
17282
17286
  ownerSelector: desktopOwner,
17283
17287
  selector: `${desktopOwner}::before`,
17284
17288
  mediaQuery: MQ_MD_UP,
17285
- topExtension: {
17286
- customProperty: "--rb-header-floating-top-gap",
17287
- value: "1rem",
17288
- ownerProperty: "top"
17289
+ extent: {
17290
+ top: {
17291
+ customProperty: "--rb-header-floating-top-gap",
17292
+ value: "1rem",
17293
+ ownerProperty: "top"
17294
+ },
17295
+ bottom: {
17296
+ customProperty: "--rb-header-floating-bottom-extension",
17297
+ value: "0.75rem"
17298
+ }
17289
17299
  },
17290
17300
  ownerNeedsPositioning: false
17291
17301
  }, {
@@ -17294,10 +17304,16 @@ function getHeaderPaintTargets(variant, themeId, state = "base") {
17294
17304
  ownerSelector: mobileOwner,
17295
17305
  selector: `${mobileOwner}::before`,
17296
17306
  mediaQuery: MQ_MD_DOWN,
17297
- topExtension: {
17298
- customProperty: "--rb-header-floating-top-gap",
17299
- value: "0.75rem",
17300
- ownerProperty: "margin-top"
17307
+ extent: {
17308
+ top: {
17309
+ customProperty: "--rb-header-floating-top-gap",
17310
+ value: "0.75rem",
17311
+ ownerProperty: "margin-top"
17312
+ },
17313
+ bottom: {
17314
+ customProperty: "--rb-header-floating-bottom-extension",
17315
+ value: "0.75rem"
17316
+ }
17301
17317
  },
17302
17318
  ownerNeedsPositioning: true
17303
17319
  }];
@@ -17338,10 +17354,11 @@ function renderHeaderPaintTargetRule(target, rules) {
17338
17354
  return `${target.selector} {\n ${[...pseudoElementSetup, ...rules].join("\n ")}\n}`;
17339
17355
  }
17340
17356
  case "viewport-band": {
17341
- const gap = target.topExtension;
17357
+ const { top, bottom } = target.extent;
17342
17358
  const ownerRules = [
17343
- `${gap.customProperty}: ${gap.value};`,
17344
- `${gap.ownerProperty}: var(${gap.customProperty});`,
17359
+ `${top.customProperty}: ${top.value};`,
17360
+ `${bottom.customProperty}: ${bottom.value};`,
17361
+ `${top.ownerProperty}: var(${top.customProperty});`,
17345
17362
  ...target.ownerNeedsPositioning ? ["position: relative;"] : [],
17346
17363
  "isolation: isolate;",
17347
17364
  "background: none;",
@@ -17353,8 +17370,8 @@ function renderHeaderPaintTargetRule(target, rules) {
17353
17370
  const bandRules = [
17354
17371
  "content: \"\";",
17355
17372
  "position: absolute;",
17356
- `top: calc(-1 * var(${gap.customProperty}));`,
17357
- "bottom: 0;",
17373
+ `top: calc(-1 * var(${top.customProperty}));`,
17374
+ `bottom: calc(-1 * var(${bottom.customProperty}));`,
17358
17375
  "left: 50%;",
17359
17376
  "width: 100vw;",
17360
17377
  "transform: translateX(-50%);",
@@ -17373,6 +17390,7 @@ const headerScrollTreatmentSchema = z$1.discriminatedUnion("kind", [z$1.object({
17373
17390
  kind: z$1.literal("contrast-glass"),
17374
17391
  backgroundTone: z$1.enum(["light", "dark"])
17375
17392
  })]).optional();
17393
+ const CONTRAST_GLASS_BLUR = "blur(12px)";
17376
17394
  function generateMobileOverlayBackdropFilterFix(themeId, variant) {
17377
17395
  const root = `:where([data-theme-scope="${themeId}"]) .header-root:has([data-nav-mobile-overlay][aria-hidden="false"])`;
17378
17396
  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`;
@@ -17382,7 +17400,12 @@ function generateHeaderScrollTreatmentStyles(treatment, themeId, variant, surfac
17382
17400
  switch (treatment.kind) {
17383
17401
  case "contrast-glass": {
17384
17402
  const backgroundChannels = treatment.backgroundTone === "dark" ? "0 0 0" : "255 255 255";
17385
- return renderHeaderPaintTargetRules(getHeaderPaintTargets(variant, themeId, "scrolled"), [`background-color: rgb(${backgroundChannels} / 0.60);`, ...surfaceRules]);
17403
+ return renderHeaderPaintTargetRules(getHeaderPaintTargets(variant, themeId, "scrolled"), [
17404
+ `background-color: rgb(${backgroundChannels} / 0.60);`,
17405
+ `backdrop-filter: ${CONTRAST_GLASS_BLUR};`,
17406
+ `-webkit-backdrop-filter: ${CONTRAST_GLASS_BLUR};`,
17407
+ ...surfaceRules
17408
+ ]);
17386
17409
  }
17387
17410
  }
17388
17411
  }
@@ -25709,6 +25732,7 @@ const newsletterFormFragment = defineFragment({
25709
25732
  }
25710
25733
  ],
25711
25734
  layout: [el("newsletter-form", withApiBindings({
25735
+ source: "block",
25712
25736
  destinationProvider: { $bind: { from: "destinationProvider" } },
25713
25737
  listId: { $bind: { from: "listId" } },
25714
25738
  preset: { $bind: { from: "preset" } },
@@ -27231,6 +27255,7 @@ const contactNewsletterLayout = styledSection({
27231
27255
  as: "h2",
27232
27256
  className: "newsletter-copy-title"
27233
27257
  }, when("newsletterTitle"), bind("newsletterTitle")), richText({ className: "newsletter-copy-subtitle rb-prose rb-max-w-none" }, when("newsletterSubtitle"), bind("newsletterSubtitle"))]), el("newsletter-form", withApiBindings({
27258
+ source: "block",
27234
27259
  listId: { $bind: { from: "listId" } },
27235
27260
  preset: { $bind: { from: "preset" } },
27236
27261
  includePhone: { $bind: { from: "includePhone" } },
@@ -29229,6 +29254,22 @@ const footerNavGroupsLayout = stack({
29229
29254
  }, [text({ as: "span" }, bind("entry.label"))], repeat("group.children", "entry"))])], repeat("footerMenu.groups", "group"))], whenCollectionHasItems("footerMenu.groups"));
29230
29255
  //#endregion
29231
29256
  //#region ../blocks/src/system/blocks/site-footer.ts
29257
+ const footerStandardContactBindings = {
29258
+ value: { $bind: { from: "module.engagement.runtime.value" } },
29259
+ submitLabel: { $bind: { from: "module.engagement.runtime.submitLabel" } },
29260
+ successMessage: { $bind: { from: "module.engagement.runtime.successMessage" } }
29261
+ };
29262
+ const footerMailingListBindings = {
29263
+ source: { $bind: { from: "module.engagement.runtime.source" } },
29264
+ destinationRef: { $bind: { from: "module.engagement.runtime.destinationRef" } },
29265
+ listId: { $bind: { from: "module.engagement.runtime.listId" } },
29266
+ preset: { $bind: { from: "module.engagement.runtime.preset" } },
29267
+ includePhone: { $bind: { from: "module.engagement.runtime.includePhone" } },
29268
+ buttonLabel: { $bind: { from: "module.engagement.runtime.buttonLabel" } },
29269
+ successMessage: { $bind: { from: "module.engagement.runtime.successMessage" } },
29270
+ privacyNote: { $bind: { from: "module.engagement.runtime.privacyNote" } }
29271
+ };
29272
+ const footerSpamProtectionBinding = { spamProtectionEnabled: { $bind: { from: "$root.spamProtectionEnabled" } } };
29232
29273
  const brandLogo = link({
29233
29274
  href: "/",
29234
29275
  className: { $bind: {
@@ -29306,6 +29347,23 @@ const authoredCopy = richText({
29306
29347
  id: "content.interpolateRichTextTokens",
29307
29348
  options: { tokens: ["year", "site_name"] }
29308
29349
  }] }));
29350
+ const footerEngagement = stack({
29351
+ gap: "md",
29352
+ className: "rb-w-full"
29353
+ }, [
29354
+ text({
29355
+ as: "p",
29356
+ className: "rb-body rb-opacity-80"
29357
+ }, bind("module.engagement.intro"), when("module.engagement.intro")),
29358
+ form(withApiBindings({
29359
+ ...footerStandardContactBindings,
29360
+ ...footerSpamProtectionBinding
29361
+ }), [], when("module.engagement.kind", { equals: "standard-contact" })),
29362
+ el("newsletter-form", withApiBindings({
29363
+ ...footerMailingListBindings,
29364
+ ...footerSpamProtectionBinding
29365
+ }), [], when("module.engagement.kind", { equals: "mailing-list" }))
29366
+ ], when("module.kind", { equals: "engagement" }));
29309
29367
  const footerGroup = stack({
29310
29368
  gap: "md",
29311
29369
  align: "stretch",
@@ -29331,6 +29389,7 @@ const footerGroup = stack({
29331
29389
  contact,
29332
29390
  hours,
29333
29391
  socials,
29392
+ footerEngagement,
29334
29393
  stack({ className: "rb-w-full" }, [authoredCopy], when("module.kind", { equals: "supporting-text" })),
29335
29394
  stack({ className: "rb-w-full rb-lg-col-span-3" }, [authoredCopy], when("module.kind", { equals: "legal" }))
29336
29395
  ], repeat("group.modules", "module"))], repeat("region.groups", "group"));
@@ -29338,6 +29397,10 @@ const footerMainRegion = stack({
29338
29397
  className: { $bind: { from: "region.className" } },
29339
29398
  "data-footer-region": { $bind: { from: "region.kind" } }
29340
29399
  }, [footerGroup], when("region.kind", { equals: "main" }), repeat("content.footerRuntime.regions", "region"));
29400
+ const footerEngagementRegion = stack({
29401
+ className: { $bind: { from: "region.className" } },
29402
+ "data-footer-region": "engagement-row"
29403
+ }, [footerGroup], when("region.kind", { equals: "engagement-row" }), repeat("content.footerRuntime.regions", "region"));
29341
29404
  const footerBottomRegion = stack({ className: { $bind: {
29342
29405
  from: "$root.theme.footer",
29343
29406
  transforms: [{ id: "layout.footerBottomBarContainerClass" }],
@@ -29373,7 +29436,11 @@ const siteFooterManifest = createBlockManifest({
29373
29436
  fallback: mergeStyles(backgroundColorStyle("surface"), surfaceForegroundStyle({ text: "rgb(var(--tb-text))" }), borderColorStyle("border"))
29374
29437
  } },
29375
29438
  "data-footer-membership": { $bind: { from: "content.footerRuntime.membershipKey" } }
29376
- }, [footerMainRegion, footerBottomRegion]),
29439
+ }, [
29440
+ footerEngagementRegion,
29441
+ footerMainRegion,
29442
+ footerBottomRegion
29443
+ ]),
29377
29444
  description: "Site-wide composed footer with canonical shared details.",
29378
29445
  styleTokens: { spacing: "md" },
29379
29446
  paletteHidden: true
@@ -31957,7 +32024,7 @@ const publicMembershipProductCollectionSchema = z$1.object({ memberships: z$1.ar
31957
32024
  * Kept in a shared module so the block definition and runtime contracts can
31958
32025
  * depend on the same schema without creating an initialization cycle.
31959
32026
  */
31960
- const occurrenceContextSchema$1 = z$1.object({
32027
+ const occurrenceContextSchema = z$1.object({
31961
32028
  id: z$1.string(),
31962
32029
  seriesId: z$1.string(),
31963
32030
  startsAt: z$1.string(),
@@ -32357,28 +32424,37 @@ const EVENT_REGISTRATION_SHELL_STEP_LABELS = [
32357
32424
  "Payment"
32358
32425
  ];
32359
32426
  const eventRegistrationPublicEventSchema = z$1.preprocess(normalizeEventRegistrationEventInput, publicEventSchema);
32360
- const eventRegistrationSourceSchema = z$1.object({
32361
- siteId: z$1.string().optional(),
32362
- apiBaseUrl: z$1.string().optional(),
32363
- portalToken: z$1.string().nullable().optional(),
32364
- previewToken: z$1.string().nullable().optional(),
32365
- occurrenceContext: occurrenceContextSchema$1.optional(),
32427
+ const eventRegistrationHydrationSchemaShape = {
32428
+ occurrenceContext: occurrenceContextSchema.optional(),
32366
32429
  subject: eventRegistrationPageSurfaceSubjectSchema.nullable().optional(),
32367
32430
  events: z$1.array(eventRegistrationPublicEventSchema).nullable().optional(),
32368
- className: z$1.string().nullable().optional(),
32369
- buttonText: z$1.string().nullable().optional(),
32370
- maxTickets: z$1.string().nullable().optional(),
32431
+ wholeSeriesOfferings: publicCoursesArraySchema.nullable().optional(),
32432
+ wholeSeriesOffering: publicCourseSchema.nullable().optional(),
32433
+ maxTickets: z$1.string().optional(),
32371
32434
  showVenue: z$1.boolean().optional(),
32372
32435
  showCapacity: z$1.boolean().optional(),
32436
+ showSessions: z$1.boolean().optional(),
32437
+ showPrice: z$1.boolean().optional(),
32373
32438
  successMessage: z$1.string().optional(),
32374
32439
  waitlistMessage: z$1.string().optional(),
32440
+ membershipMessage: z$1.string().optional(),
32375
32441
  buttonVariant: registrationButtonVariantSchema.optional(),
32376
32442
  overlayEnabled: z$1.boolean().optional(),
32377
32443
  spamProtectionEnabled: z$1.boolean().optional(),
32378
- stage: previewStageSchema.optional(),
32379
32444
  supportEmail: z$1.string().optional(),
32380
32445
  sitePasses: publicPassProductCollectionSchema.nullable().optional(),
32381
32446
  siteMemberships: publicMembershipProductCollectionSchema.nullable().optional()
32447
+ };
32448
+ const eventRegistrationSourceSchema = z$1.object({
32449
+ siteId: z$1.string().optional(),
32450
+ apiBaseUrl: z$1.string().optional(),
32451
+ portalToken: z$1.string().nullable().optional(),
32452
+ previewToken: z$1.string().nullable().optional(),
32453
+ ...eventRegistrationHydrationSchemaShape,
32454
+ className: z$1.string().nullable().optional(),
32455
+ buttonText: z$1.string().nullable().optional(),
32456
+ maxTickets: z$1.string().nullable().optional(),
32457
+ stage: previewStageSchema.optional()
32382
32458
  });
32383
32459
  const eventRegistrationDisplaySchema = z$1.object({
32384
32460
  kind: z$1.literal("event-registration"),
@@ -32389,22 +32465,7 @@ const eventRegistrationDisplaySchema = z$1.object({
32389
32465
  stepLabels: z$1.array(z$1.enum(EVENT_REGISTRATION_SHELL_STEP_LABELS)).min(1),
32390
32466
  summaryButtonText: z$1.string()
32391
32467
  });
32392
- const eventRegistrationHydrationSchema = z$1.object({
32393
- occurrenceContext: occurrenceContextSchema$1.optional(),
32394
- subject: eventRegistrationPageSurfaceSubjectSchema.nullable().optional(),
32395
- events: z$1.array(eventRegistrationPublicEventSchema).nullable().optional(),
32396
- maxTickets: z$1.string().optional(),
32397
- showVenue: z$1.boolean().optional(),
32398
- showCapacity: z$1.boolean().optional(),
32399
- successMessage: z$1.string().optional(),
32400
- waitlistMessage: z$1.string().optional(),
32401
- buttonVariant: registrationButtonVariantSchema.optional(),
32402
- overlayEnabled: z$1.boolean().optional(),
32403
- spamProtectionEnabled: z$1.boolean().optional(),
32404
- supportEmail: z$1.string().optional(),
32405
- sitePasses: publicPassProductCollectionSchema.nullable().optional(),
32406
- siteMemberships: publicMembershipProductCollectionSchema.nullable().optional()
32407
- });
32468
+ const eventRegistrationHydrationSchema = z$1.object(eventRegistrationHydrationSchemaShape);
32408
32469
  const eventRegistrationRenderSchema = z$1.object({
32409
32470
  display: eventRegistrationDisplaySchema,
32410
32471
  hydration: eventRegistrationHydrationSchema
@@ -32484,11 +32545,16 @@ const eventRegistrationBlockRuntime = defineClientOwnedBlockRuntime({
32484
32545
  occurrenceContext: source.occurrenceContext ?? null,
32485
32546
  subject: source.subject ?? null,
32486
32547
  events: source.events ?? null,
32548
+ wholeSeriesOfferings: source.wholeSeriesOfferings ?? null,
32549
+ wholeSeriesOffering: source.wholeSeriesOffering ?? null,
32487
32550
  maxTickets: source.maxTickets ?? void 0,
32488
32551
  showVenue: source.showVenue,
32489
32552
  showCapacity: source.showCapacity,
32553
+ showSessions: source.showSessions,
32554
+ showPrice: source.showPrice,
32490
32555
  successMessage: source.successMessage,
32491
32556
  waitlistMessage: source.waitlistMessage,
32557
+ membershipMessage: source.membershipMessage,
32492
32558
  buttonVariant: source.buttonVariant,
32493
32559
  overlayEnabled: source.overlayEnabled,
32494
32560
  spamProtectionEnabled: source.spamProtectionEnabled,
@@ -32523,6 +32589,159 @@ function buildEventRegistrationInteractiveIslandProps(props) {
32523
32589
  source: props
32524
32590
  });
32525
32591
  }
32592
+ //#endregion
32593
+ //#region ../blocks/src/system/blocks/courses/shared/pricing.ts
32594
+ function isSaleWindowOpen(option, now) {
32595
+ if (!option.isActive) return false;
32596
+ if (option.saleStartsAt && new Date(option.saleStartsAt) > now) return false;
32597
+ if (option.saleEndsAt && new Date(option.saleEndsAt) < now) return false;
32598
+ return true;
32599
+ }
32600
+ function toExactOrFreeDisplay(amount, currency) {
32601
+ if (amount <= 0) return {
32602
+ kind: "free",
32603
+ currency
32604
+ };
32605
+ return {
32606
+ kind: "exact",
32607
+ amount,
32608
+ currency
32609
+ };
32610
+ }
32611
+ function getSelectableCoursePricingOptionsForNow(course, now) {
32612
+ if (course.pricing.pricingStrategy !== "tiered") return [];
32613
+ return [...course.pricing.options].filter((option) => isSaleWindowOpen(option, now)).sort((left, right) => {
32614
+ if (left.sortOrder !== right.sortOrder) return left.sortOrder - right.sortOrder;
32615
+ if (left.priceAmount !== right.priceAmount) return left.priceAmount - right.priceAmount;
32616
+ return left.name.localeCompare(right.name);
32617
+ });
32618
+ }
32619
+ function resolveCoursePricingState(course, selectedPricingOptionId, selectedSlidingAmountOrNowInput, nowInput = {}) {
32620
+ const selectedSlidingAmount = typeof selectedSlidingAmountOrNowInput === "number" || selectedSlidingAmountOrNowInput === null ? selectedSlidingAmountOrNowInput : null;
32621
+ const effectiveNowInput = typeof selectedSlidingAmountOrNowInput === "object" && selectedSlidingAmountOrNowInput !== null ? selectedSlidingAmountOrNowInput : nowInput;
32622
+ const currency = course.pricing.currency;
32623
+ switch (course.pricing.pricingStrategy) {
32624
+ case "free": return {
32625
+ currency,
32626
+ display: {
32627
+ kind: "free",
32628
+ currency
32629
+ },
32630
+ selectableOptions: [],
32631
+ requiresSelection: false,
32632
+ selectedOption: null,
32633
+ slidingScale: null,
32634
+ selectedSlidingAmount: null,
32635
+ selectedPriceAmount: 0,
32636
+ selectedRequiresPayment: false,
32637
+ hasPaidSelection: false,
32638
+ hasFreeSelection: true
32639
+ };
32640
+ case "single": {
32641
+ const amount = course.pricing.singlePriceAmount ?? 0;
32642
+ return {
32643
+ currency,
32644
+ display: toExactOrFreeDisplay(amount, currency),
32645
+ selectableOptions: [],
32646
+ requiresSelection: false,
32647
+ selectedOption: null,
32648
+ slidingScale: null,
32649
+ selectedSlidingAmount: null,
32650
+ selectedPriceAmount: amount,
32651
+ selectedRequiresPayment: amount > 0,
32652
+ hasPaidSelection: amount > 0,
32653
+ hasFreeSelection: amount <= 0
32654
+ };
32655
+ }
32656
+ case "tiered": {
32657
+ const selectableOptions = getSelectableCoursePricingOptionsForNow(course, resolvePlanningDateInput(effectiveNowInput));
32658
+ const selectedOption = (selectedPricingOptionId ? selectableOptions.find((option) => option.id === selectedPricingOptionId) : null) ?? (selectableOptions.length === 1 ? selectableOptions[0] ?? null : null);
32659
+ const lowestAmount = selectableOptions.reduce((lowest, option) => {
32660
+ if (lowest === null || option.priceAmount < lowest) return option.priceAmount;
32661
+ return lowest;
32662
+ }, null);
32663
+ return {
32664
+ currency,
32665
+ display: lowestAmount === null ? {
32666
+ kind: "unavailable",
32667
+ currency
32668
+ } : selectableOptions.length > 1 && lowestAmount > 0 ? {
32669
+ kind: "from",
32670
+ amount: lowestAmount,
32671
+ currency
32672
+ } : toExactOrFreeDisplay(lowestAmount, currency),
32673
+ selectableOptions,
32674
+ requiresSelection: selectableOptions.length > 1,
32675
+ selectedOption,
32676
+ slidingScale: null,
32677
+ selectedSlidingAmount: null,
32678
+ selectedPriceAmount: selectedOption?.priceAmount ?? null,
32679
+ selectedRequiresPayment: (selectedOption?.priceAmount ?? 0) > 0,
32680
+ hasPaidSelection: selectableOptions.some((option) => option.priceAmount > 0),
32681
+ hasFreeSelection: selectableOptions.some((option) => option.priceAmount === 0)
32682
+ };
32683
+ }
32684
+ case "sliding_scale": {
32685
+ const minAmount = course.pricing.slidingMinAmount ?? null;
32686
+ const maxAmount = course.pricing.slidingMaxAmount ?? null;
32687
+ if (minAmount === null || maxAmount === null || minAmount < 0 || maxAmount < minAmount) return {
32688
+ currency,
32689
+ display: {
32690
+ kind: "unavailable",
32691
+ currency
32692
+ },
32693
+ selectableOptions: [],
32694
+ requiresSelection: true,
32695
+ selectedOption: null,
32696
+ slidingScale: null,
32697
+ selectedSlidingAmount: null,
32698
+ selectedPriceAmount: null,
32699
+ selectedRequiresPayment: false,
32700
+ hasPaidSelection: false,
32701
+ hasFreeSelection: false
32702
+ };
32703
+ const normalizedSelectedAmount = typeof selectedSlidingAmount === "number" && Number.isFinite(selectedSlidingAmount) ? selectedSlidingAmount : null;
32704
+ return {
32705
+ currency,
32706
+ display: {
32707
+ kind: "range",
32708
+ minAmount,
32709
+ maxAmount,
32710
+ currency
32711
+ },
32712
+ selectableOptions: [],
32713
+ requiresSelection: normalizedSelectedAmount === null,
32714
+ selectedOption: null,
32715
+ slidingScale: {
32716
+ minAmount,
32717
+ maxAmount,
32718
+ suggestedAmount: course.pricing.slidingSuggestedAmount ?? null
32719
+ },
32720
+ selectedSlidingAmount: normalizedSelectedAmount,
32721
+ selectedPriceAmount: normalizedSelectedAmount,
32722
+ selectedRequiresPayment: (normalizedSelectedAmount ?? 0) > 0,
32723
+ hasPaidSelection: maxAmount > 0,
32724
+ hasFreeSelection: minAmount === 0
32725
+ };
32726
+ }
32727
+ }
32728
+ }
32729
+ function formatCoursePriceDisplay(display, locale) {
32730
+ return formatBookingPriceDisplay(display, {
32731
+ decimals: "exact",
32732
+ locale
32733
+ });
32734
+ }
32735
+ function formatCoursePriceAmount(amount, currency, locale) {
32736
+ return formatCoursePriceDisplay(amount > 0 ? {
32737
+ kind: "exact",
32738
+ amount,
32739
+ currency
32740
+ } : {
32741
+ kind: "free",
32742
+ currency
32743
+ }, locale);
32744
+ }
32526
32745
  const eventRegistrationBlockDefinition = {
32527
32746
  manifest: createBlockManifest({
32528
32747
  id: "block.event-registration",
@@ -32618,6 +32837,24 @@ const eventRegistrationBlockDefinition = {
32618
32837
  defaultValue: true,
32619
32838
  ui: { intent: "display" }
32620
32839
  },
32840
+ {
32841
+ id: "showSessions",
32842
+ type: "boolean",
32843
+ label: "Show complete schedule",
32844
+ description: "Display every session for whole-series registrations",
32845
+ required: false,
32846
+ defaultValue: true,
32847
+ ui: { intent: "display" }
32848
+ },
32849
+ {
32850
+ id: "showPrice",
32851
+ type: "boolean",
32852
+ label: "Show price",
32853
+ description: "Display the whole-series price",
32854
+ required: false,
32855
+ defaultValue: true,
32856
+ ui: { intent: "display" }
32857
+ },
32621
32858
  {
32622
32859
  id: "successMessage",
32623
32860
  type: "text",
@@ -32628,6 +32865,26 @@ const eventRegistrationBlockDefinition = {
32628
32865
  defaultValue: "Thank you for registering! Check your email for confirmation details.",
32629
32866
  maxLength: 500
32630
32867
  },
32868
+ {
32869
+ id: "waitlistMessage",
32870
+ type: "text",
32871
+ label: "Waitlist message",
32872
+ description: "Message shown after joining a whole-series waitlist",
32873
+ required: false,
32874
+ multiline: true,
32875
+ defaultValue: "You've been added to the waitlist. We'll email you if a place becomes available.",
32876
+ maxLength: 500
32877
+ },
32878
+ {
32879
+ id: "membershipMessage",
32880
+ type: "text",
32881
+ label: "Membership registration message",
32882
+ description: "Message shown when a whole-series place is covered by membership",
32883
+ required: false,
32884
+ multiline: true,
32885
+ defaultValue: "Registered using your membership. Check your email for session details.",
32886
+ maxLength: 500
32887
+ },
32631
32888
  {
32632
32889
  id: "buttonText",
32633
32890
  type: "text",
@@ -32659,8 +32916,11 @@ const eventRegistrationBlockDefinition = {
32659
32916
  } },
32660
32917
  showVenue: { $bind: { from: "content.showVenue" } },
32661
32918
  showCapacity: { $bind: { from: "content.showCapacity" } },
32919
+ showSessions: { $bind: { from: "content.showSessions" } },
32920
+ showPrice: { $bind: { from: "content.showPrice" } },
32662
32921
  successMessage: { $bind: { from: "content.successMessage" } },
32663
32922
  waitlistMessage: { $bind: { from: "content.waitlistMessage" } },
32923
+ membershipMessage: { $bind: { from: "content.membershipMessage" } },
32664
32924
  buttonText: { $bind: {
32665
32925
  from: "content.buttonText",
32666
32926
  fallback: "Complete Registration"
@@ -32674,6 +32934,7 @@ const eventRegistrationBlockDefinition = {
32674
32934
  fallback: false
32675
32935
  } },
32676
32936
  events: { $bind: { from: "data.events" } },
32937
+ wholeSeriesOffering: { $bind: { from: "data.wholeSeriesOffering.offering" } },
32677
32938
  sitePasses: { $bind: { from: "data.sitePasses" } },
32678
32939
  siteMemberships: { $bind: { from: "data.siteMemberships" } },
32679
32940
  stage: { $bind: {
@@ -32687,9 +32948,10 @@ const eventRegistrationBlockDefinition = {
32687
32948
  runtime: eventRegistrationBlockRuntime,
32688
32949
  dataSchemas: {
32689
32950
  events: publicEventsArraySchema.optional(),
32951
+ wholeSeriesOffering: z$1.object({ offering: publicCourseSchema }).optional(),
32690
32952
  sitePasses: publicPassProductCollectionSchema.optional(),
32691
32953
  siteMemberships: publicMembershipProductCollectionSchema.optional(),
32692
- occurrenceContext: occurrenceContextSchema$1.optional()
32954
+ occurrenceContext: occurrenceContextSchema.optional()
32693
32955
  },
32694
32956
  dataLoaders: {
32695
32957
  events: {
@@ -32702,11 +32964,23 @@ const eventRegistrationBlockDefinition = {
32702
32964
  fallback: "published"
32703
32965
  } },
32704
32966
  readProfile: "registration",
32705
- seriesId: { $bind: { from: "$root.occurrenceContext.seriesId" } },
32967
+ seriesId: { $bind: { from: "$root.subject.eventSeriesId" } },
32706
32968
  includeOccurrenceId: { $bind: { from: "$root.occurrenceContext.id" } }
32707
32969
  },
32708
32970
  mode: "server"
32709
32971
  },
32972
+ wholeSeriesOffering: {
32973
+ endpoint: "getPublicWholeSeriesOffering",
32974
+ params: {
32975
+ siteId: { $bind: { from: "$root.siteId" } },
32976
+ eventSeriesId: { $bind: { from: "$root.subject.eventSeriesId" } },
32977
+ stage: { $bind: {
32978
+ from: "$root.previewStage",
32979
+ fallback: "published"
32980
+ } }
32981
+ },
32982
+ mode: "server"
32983
+ },
32710
32984
  sitePasses: {
32711
32985
  endpoint: "listPublicPasses",
32712
32986
  params: { siteId: { $bind: { from: "$root.siteId" } } },
@@ -32720,159 +32994,6 @@ const eventRegistrationBlockDefinition = {
32720
32994
  }
32721
32995
  };
32722
32996
  //#endregion
32723
- //#region ../blocks/src/system/blocks/courses/shared/pricing.ts
32724
- function isSaleWindowOpen(option, now) {
32725
- if (!option.isActive) return false;
32726
- if (option.saleStartsAt && new Date(option.saleStartsAt) > now) return false;
32727
- if (option.saleEndsAt && new Date(option.saleEndsAt) < now) return false;
32728
- return true;
32729
- }
32730
- function toExactOrFreeDisplay(amount, currency) {
32731
- if (amount <= 0) return {
32732
- kind: "free",
32733
- currency
32734
- };
32735
- return {
32736
- kind: "exact",
32737
- amount,
32738
- currency
32739
- };
32740
- }
32741
- function getSelectableCoursePricingOptionsForNow(course, now) {
32742
- if (course.pricing.pricingStrategy !== "tiered") return [];
32743
- return [...course.pricing.options].filter((option) => isSaleWindowOpen(option, now)).sort((left, right) => {
32744
- if (left.sortOrder !== right.sortOrder) return left.sortOrder - right.sortOrder;
32745
- if (left.priceAmount !== right.priceAmount) return left.priceAmount - right.priceAmount;
32746
- return left.name.localeCompare(right.name);
32747
- });
32748
- }
32749
- function resolveCoursePricingState(course, selectedPricingOptionId, selectedSlidingAmountOrNowInput, nowInput = {}) {
32750
- const selectedSlidingAmount = typeof selectedSlidingAmountOrNowInput === "number" || selectedSlidingAmountOrNowInput === null ? selectedSlidingAmountOrNowInput : null;
32751
- const effectiveNowInput = typeof selectedSlidingAmountOrNowInput === "object" && selectedSlidingAmountOrNowInput !== null ? selectedSlidingAmountOrNowInput : nowInput;
32752
- const currency = course.pricing.currency;
32753
- switch (course.pricing.pricingStrategy) {
32754
- case "free": return {
32755
- currency,
32756
- display: {
32757
- kind: "free",
32758
- currency
32759
- },
32760
- selectableOptions: [],
32761
- requiresSelection: false,
32762
- selectedOption: null,
32763
- slidingScale: null,
32764
- selectedSlidingAmount: null,
32765
- selectedPriceAmount: 0,
32766
- selectedRequiresPayment: false,
32767
- hasPaidSelection: false,
32768
- hasFreeSelection: true
32769
- };
32770
- case "single": {
32771
- const amount = course.pricing.singlePriceAmount ?? 0;
32772
- return {
32773
- currency,
32774
- display: toExactOrFreeDisplay(amount, currency),
32775
- selectableOptions: [],
32776
- requiresSelection: false,
32777
- selectedOption: null,
32778
- slidingScale: null,
32779
- selectedSlidingAmount: null,
32780
- selectedPriceAmount: amount,
32781
- selectedRequiresPayment: amount > 0,
32782
- hasPaidSelection: amount > 0,
32783
- hasFreeSelection: amount <= 0
32784
- };
32785
- }
32786
- case "tiered": {
32787
- const selectableOptions = getSelectableCoursePricingOptionsForNow(course, resolvePlanningDateInput(effectiveNowInput));
32788
- const selectedOption = (selectedPricingOptionId ? selectableOptions.find((option) => option.id === selectedPricingOptionId) : null) ?? (selectableOptions.length === 1 ? selectableOptions[0] ?? null : null);
32789
- const lowestAmount = selectableOptions.reduce((lowest, option) => {
32790
- if (lowest === null || option.priceAmount < lowest) return option.priceAmount;
32791
- return lowest;
32792
- }, null);
32793
- return {
32794
- currency,
32795
- display: lowestAmount === null ? {
32796
- kind: "unavailable",
32797
- currency
32798
- } : selectableOptions.length > 1 && lowestAmount > 0 ? {
32799
- kind: "from",
32800
- amount: lowestAmount,
32801
- currency
32802
- } : toExactOrFreeDisplay(lowestAmount, currency),
32803
- selectableOptions,
32804
- requiresSelection: selectableOptions.length > 1,
32805
- selectedOption,
32806
- slidingScale: null,
32807
- selectedSlidingAmount: null,
32808
- selectedPriceAmount: selectedOption?.priceAmount ?? null,
32809
- selectedRequiresPayment: (selectedOption?.priceAmount ?? 0) > 0,
32810
- hasPaidSelection: selectableOptions.some((option) => option.priceAmount > 0),
32811
- hasFreeSelection: selectableOptions.some((option) => option.priceAmount === 0)
32812
- };
32813
- }
32814
- case "sliding_scale": {
32815
- const minAmount = course.pricing.slidingMinAmount ?? null;
32816
- const maxAmount = course.pricing.slidingMaxAmount ?? null;
32817
- if (minAmount === null || maxAmount === null || minAmount < 0 || maxAmount < minAmount) return {
32818
- currency,
32819
- display: {
32820
- kind: "unavailable",
32821
- currency
32822
- },
32823
- selectableOptions: [],
32824
- requiresSelection: true,
32825
- selectedOption: null,
32826
- slidingScale: null,
32827
- selectedSlidingAmount: null,
32828
- selectedPriceAmount: null,
32829
- selectedRequiresPayment: false,
32830
- hasPaidSelection: false,
32831
- hasFreeSelection: false
32832
- };
32833
- const normalizedSelectedAmount = typeof selectedSlidingAmount === "number" && Number.isFinite(selectedSlidingAmount) ? selectedSlidingAmount : null;
32834
- return {
32835
- currency,
32836
- display: {
32837
- kind: "range",
32838
- minAmount,
32839
- maxAmount,
32840
- currency
32841
- },
32842
- selectableOptions: [],
32843
- requiresSelection: normalizedSelectedAmount === null,
32844
- selectedOption: null,
32845
- slidingScale: {
32846
- minAmount,
32847
- maxAmount,
32848
- suggestedAmount: course.pricing.slidingSuggestedAmount ?? null
32849
- },
32850
- selectedSlidingAmount: normalizedSelectedAmount,
32851
- selectedPriceAmount: normalizedSelectedAmount,
32852
- selectedRequiresPayment: (normalizedSelectedAmount ?? 0) > 0,
32853
- hasPaidSelection: maxAmount > 0,
32854
- hasFreeSelection: minAmount === 0
32855
- };
32856
- }
32857
- }
32858
- }
32859
- function formatCoursePriceDisplay(display, locale) {
32860
- return formatBookingPriceDisplay(display, {
32861
- decimals: "exact",
32862
- locale
32863
- });
32864
- }
32865
- function formatCoursePriceAmount(amount, currency, locale) {
32866
- return formatCoursePriceDisplay(amount > 0 ? {
32867
- kind: "exact",
32868
- amount,
32869
- currency
32870
- } : {
32871
- kind: "free",
32872
- currency
32873
- }, locale);
32874
- }
32875
- //#endregion
32876
32997
  //#region ../blocks/src/system/runtime/nodes/course-registration.interactive.ts
32877
32998
  const courseRegistrationSourceSchema = z$1.object({
32878
32999
  siteId: z$1.string().optional(),
@@ -33307,15 +33428,6 @@ const eventDetailsManifest = createBlockManifest({
33307
33428
  })], { gap: "lg" })
33308
33429
  })]
33309
33430
  });
33310
- const occurrenceContextSchema = z$1.object({
33311
- id: z$1.string(),
33312
- seriesId: z$1.string(),
33313
- startsAt: z$1.string(),
33314
- endsAt: z$1.string(),
33315
- timeZone: z$1.string(),
33316
- capacityOverride: z$1.number().nullable().optional(),
33317
- overrides: z$1.record(z$1.string(), z$1.unknown()).nullable().optional()
33318
- }).nullable();
33319
33431
  const eventAutoApplyDiscountPreviewBaseSchema = z$1.object({
33320
33432
  id: z$1.string(),
33321
33433
  publicLabel: z$1.string(),
@@ -33350,8 +33462,9 @@ const eventDetailsBlockDefinition = {
33350
33462
  from: "$root.previewStage",
33351
33463
  fallback: "published"
33352
33464
  } },
33353
- limit: "25",
33354
- seriesId: { $bind: { from: "$root.occurrenceContext.seriesId" } },
33465
+ limit: "100",
33466
+ readProfile: "details",
33467
+ seriesId: { $bind: { from: "$root.subject.eventSeriesId" } },
33355
33468
  includeOccurrenceId: { $bind: { from: "$root.occurrenceContext.id" } }
33356
33469
  },
33357
33470
  mode: "server"
@@ -42141,9 +42254,6 @@ function parseSignedNewsletterDestinationRef(value) {
42141
42254
  const trimmed = parseTrimmedString$1(value);
42142
42255
  return trimmed && SIGNED_DESTINATION_REF_PATTERN.test(trimmed) ? trimmed : null;
42143
42256
  }
42144
- function parseNewsletterSignupDestinationProvider(value) {
42145
- return value === "riverbank" || value === "mailchimp" ? value : null;
42146
- }
42147
42257
  function buildNewsletterSignupBlockRef(blockId) {
42148
42258
  const parsed = parseNewsletterSignupBlockId(blockId);
42149
42259
  return parsed ? {
@@ -42310,19 +42420,9 @@ const newsletterFieldSchema = z$1.object({
42310
42420
  });
42311
42421
  const newsletterSignupBlockIdSchema = z$1.string().trim().min(1).transform(parseRequiredNewsletterSignupBlockId);
42312
42422
  const signedNewsletterDestinationRefSchema = z$1.string().trim().min(1).transform(parseRequiredSignedNewsletterDestinationRef);
42313
- const newsletterPublicDestinationRefSchema = z$1.discriminatedUnion("tag", [z$1.object({
42314
- tag: z$1.literal("block_ref"),
42315
- blockId: newsletterSignupBlockIdSchema
42316
- }), z$1.object({
42317
- tag: z$1.literal("signed_destination_ref"),
42318
- token: signedNewsletterDestinationRefSchema
42319
- })]);
42320
- const newsletterSourceSchema = z$1.object({
42321
- blockId: z$1.string().nullable().optional(),
42423
+ const newsletterSourceCommonSchema = z$1.object({
42322
42424
  siteId: z$1.string().optional(),
42323
42425
  apiBaseUrl: z$1.string().optional(),
42324
- listId: z$1.string().nullable().optional(),
42325
- destinationProvider: newsletterDestinationProviderSchema.nullable().optional(),
42326
42426
  preset: newsletterPresetSchema.optional(),
42327
42427
  includePhone: z$1.boolean().optional(),
42328
42428
  buttonLabel: z$1.string().nullable().optional(),
@@ -42333,6 +42433,25 @@ const newsletterSourceSchema = z$1.object({
42333
42433
  spamProtectionEnabled: z$1.boolean().optional(),
42334
42434
  className: z$1.string().nullable().optional()
42335
42435
  });
42436
+ const newsletterSourceSchema = z$1.discriminatedUnion("source", [
42437
+ newsletterSourceCommonSchema.extend({
42438
+ source: z$1.literal("block"),
42439
+ blockId: z$1.string().nullable().optional(),
42440
+ listId: z$1.string().nullable().optional(),
42441
+ destinationProvider: newsletterDestinationProviderSchema.nullable().optional()
42442
+ }),
42443
+ newsletterSourceCommonSchema.extend({
42444
+ source: z$1.literal("signed-footer"),
42445
+ destinationRef: z$1.object({
42446
+ tag: z$1.literal("signed_destination_ref"),
42447
+ token: signedNewsletterDestinationRefSchema
42448
+ })
42449
+ }),
42450
+ newsletterSourceCommonSchema.extend({
42451
+ source: z$1.literal("legacy-direct-list"),
42452
+ listId: z$1.string().nullable()
42453
+ })
42454
+ ]);
42336
42455
  const newsletterDisplaySchema = z$1.object({
42337
42456
  kind: z$1.literal("newsletter-form"),
42338
42457
  className: z$1.string().nullable(),
@@ -42343,8 +42462,26 @@ const newsletterDisplaySchema = z$1.object({
42343
42462
  fields: z$1.array(newsletterFieldSchema)
42344
42463
  });
42345
42464
  const newsletterHydrationSchema = z$1.object({
42346
- destinationRef: newsletterPublicDestinationRefSchema.nullable().optional(),
42347
- listId: z$1.string().nullable().optional(),
42465
+ target: z$1.discriminatedUnion("tag", [
42466
+ z$1.object({
42467
+ tag: z$1.literal("block-source"),
42468
+ destinationRef: z$1.object({
42469
+ tag: z$1.literal("block_ref"),
42470
+ blockId: newsletterSignupBlockIdSchema
42471
+ }).nullable()
42472
+ }),
42473
+ z$1.object({
42474
+ tag: z$1.literal("signed-footer-source"),
42475
+ destinationRef: z$1.object({
42476
+ tag: z$1.literal("signed_destination_ref"),
42477
+ token: signedNewsletterDestinationRefSchema
42478
+ })
42479
+ }),
42480
+ z$1.object({
42481
+ tag: z$1.literal("legacy-direct-list"),
42482
+ listId: z$1.string().nullable()
42483
+ })
42484
+ ]),
42348
42485
  preset: newsletterPresetSchema,
42349
42486
  includePhone: z$1.boolean(),
42350
42487
  tags: z$1.string().nullable().optional(),
@@ -42378,20 +42515,43 @@ const newsletterFormBlockRuntime = defineProgressiveBlockRuntime({
42378
42515
  render: createZodCodec(newsletterRenderSchema)
42379
42516
  },
42380
42517
  buildRender: (source) => {
42381
- const runtimeSource = deriveNewsletterSignupRuntimeSource(source);
42518
+ const runtimeSource = source.source === "block" ? deriveNewsletterSignupRuntimeSource(source) : null;
42382
42519
  return {
42383
42520
  display: buildNewsletterDisplay(source),
42384
42521
  hydration: {
42385
- destinationRef: buildNewsletterSignupBlockRef(source.blockId),
42386
- listId: runtimeSource.listId,
42522
+ target: projectNewsletterFormHydrationTarget(source),
42387
42523
  preset: source.preset ?? "emailOnly",
42388
42524
  includePhone: source.includePhone ?? false,
42389
- tags: runtimeSource.tags,
42525
+ tags: runtimeSource ? runtimeSource.tags : source.tags,
42390
42526
  spamProtectionEnabled: source.spamProtectionEnabled
42391
42527
  }
42392
42528
  };
42393
42529
  }
42394
42530
  });
42531
+ function projectNewsletterFormHydrationTarget(source) {
42532
+ switch (source.source) {
42533
+ case "block": {
42534
+ const destinationRef = buildNewsletterSignupBlockRef(source.blockId);
42535
+ if (destinationRef?.tag === "block_ref") return {
42536
+ tag: "block-source",
42537
+ destinationRef
42538
+ };
42539
+ return {
42540
+ tag: "legacy-direct-list",
42541
+ listId: source.listId ?? null
42542
+ };
42543
+ }
42544
+ case "signed-footer": return {
42545
+ tag: "signed-footer-source",
42546
+ destinationRef: source.destinationRef
42547
+ };
42548
+ case "legacy-direct-list": return {
42549
+ tag: "legacy-direct-list",
42550
+ listId: source.listId
42551
+ };
42552
+ default: return assertNever$24(source);
42553
+ }
42554
+ }
42395
42555
  function buildNewsletterFormInteractiveIslandProps(props) {
42396
42556
  return buildInteractiveIslandProps({
42397
42557
  runtime: newsletterFormBlockRuntime,
@@ -46790,6 +46950,33 @@ function uniqByOccurrenceId(events) {
46790
46950
  }
46791
46951
  return out;
46792
46952
  }
46953
+ function selectFromOccurrenceContext(events, occurrenceContext) {
46954
+ if (!occurrenceContext) return null;
46955
+ const byId = events.find((event) => event.occurrenceId === occurrenceContext.id || event.id === occurrenceContext.id);
46956
+ if (byId) return byId;
46957
+ const contextDate = getBookingLocalDateKey(toScheduledBookingDateTime({
46958
+ startsAt: occurrenceContext.startsAt,
46959
+ timeZone: occurrenceContext.timeZone
46960
+ }));
46961
+ return events.find((event) => getBookingLocalDateKey(toScheduledBookingDateTime({
46962
+ startsAt: event.startsAt,
46963
+ timeZone: event.timeZone
46964
+ })) === contextDate) ?? null;
46965
+ }
46966
+ function selectNextUpcoming(events, nowIso) {
46967
+ return [...events].filter((event) => isFutureOrNow(event.startsAt, nowIso)).sort((left, right) => Date.parse(left.startsAt) - Date.parse(right.startsAt))[0] ?? null;
46968
+ }
46969
+ function selectCompletedWholeSeries(events) {
46970
+ if (events.length === 0 || !events.every((event) => event.bookingScope === "whole_series")) return null;
46971
+ return [...events].sort((left, right) => Date.parse(right.startsAt) - Date.parse(left.startsAt))[0] ?? null;
46972
+ }
46973
+ function selectRelatedDates(input) {
46974
+ if (!input.seriesId) return [];
46975
+ const isWholeSeries = input.selected?.bookingScope === "whole_series";
46976
+ const selectedOccurrenceId = input.selected ? input.selected.occurrenceId || input.selected.id : null;
46977
+ 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));
46978
+ return isWholeSeries ? dates : dates.slice(0, input.limit);
46979
+ }
46793
46980
  function selectEventDetails(args) {
46794
46981
  const all = uniqByOccurrenceId(resolveEventRegistrationScopedEvents((args.events ?? []).filter(Boolean), {
46795
46982
  occurrenceContext: args.occurrenceContext,
@@ -46797,37 +46984,22 @@ function selectEventDetails(args) {
46797
46984
  }));
46798
46985
  const occurrenceContext = args.occurrenceContext ?? null;
46799
46986
  const otherLimit = parseLimit$1(args.otherDatesLimit, 5);
46800
- const selectedFromContext = (() => {
46801
- if (!occurrenceContext) return null;
46802
- const byId = all.find((e) => e.occurrenceId === occurrenceContext.id || e.id === occurrenceContext.id) ?? null;
46803
- if (byId) return byId;
46804
- const ctxDate = getBookingLocalDateKey(toScheduledBookingDateTime({
46805
- startsAt: occurrenceContext.startsAt,
46806
- timeZone: occurrenceContext.timeZone
46807
- }));
46808
- return all.find((e) => getBookingLocalDateKey(toScheduledBookingDateTime({
46809
- startsAt: e.startsAt,
46810
- timeZone: e.timeZone
46811
- })) === ctxDate) ?? null;
46812
- })();
46813
- const nextUpcoming = (() => {
46814
- const upcoming = all.filter((e) => isFutureOrNow(e.startsAt, args.nowIso));
46815
- upcoming.sort((a, b) => Date.parse(a.startsAt) - Date.parse(b.startsAt));
46816
- return upcoming[0] ?? null;
46817
- })();
46818
- const mode = selectedFromContext ? "selected" : "next";
46819
- const selected = selectedFromContext ?? nextUpcoming;
46987
+ const selectedFromContext = selectFromOccurrenceContext(all, occurrenceContext);
46988
+ const nextUpcoming = selectNextUpcoming(all, args.nowIso);
46989
+ const completedWholeSeries = selectCompletedWholeSeries(all);
46990
+ const selected = selectedFromContext ?? nextUpcoming ?? completedWholeSeries;
46991
+ const mode = selectedFromContext ? "selected" : nextUpcoming ? "next" : completedWholeSeries ? "completed" : "next";
46820
46992
  const timeZone = toBookingTimeZone(selected?.timeZone ?? all[0]?.timeZone ?? null);
46821
- const seriesId = occurrenceContext?.seriesId ?? selected?.seriesId ?? all[0]?.seriesId ?? null;
46822
- const selectedOccurrenceId = selected?.occurrenceId ?? null;
46823
46993
  return {
46824
46994
  mode,
46825
46995
  selected,
46826
- otherDates: seriesId ? all.filter((e) => e.seriesId === seriesId).filter((e) => isFutureOrNow(e.startsAt, args.nowIso)).filter((e) => {
46827
- const occId = e.occurrenceId || e.id;
46828
- if (selectedOccurrenceId && occId === selectedOccurrenceId) return false;
46829
- return true;
46830
- }).slice(0, otherLimit) : [],
46996
+ otherDates: selectRelatedDates({
46997
+ events: all,
46998
+ seriesId: occurrenceContext?.seriesId ?? selected?.seriesId ?? all[0]?.seriesId ?? null,
46999
+ selected,
47000
+ nowIso: args.nowIso,
47001
+ limit: otherLimit
47002
+ }),
46831
47003
  timeZone
46832
47004
  };
46833
47005
  }
@@ -46949,7 +47121,7 @@ function EventFacts({ selection, selected, venue, teamMembers, pricing }) {
46949
47121
  /* @__PURE__ */ jsxs("div", { children: [
46950
47122
  /* @__PURE__ */ jsx("div", {
46951
47123
  className: "rb-label rb-mb-2",
46952
- children: selection.mode === "next" ? "Next date" : "Date"
47124
+ children: selected.bookingScope === "whole_series" ? selection.mode === "next" ? "Next session" : "Selected session" : selection.mode === "next" ? "Next date" : "Date"
46953
47125
  }),
46954
47126
  /* @__PURE__ */ jsx("p", { children: /* @__PURE__ */ jsx("strong", { children: date }) }),
46955
47127
  /* @__PURE__ */ jsx("p", {
@@ -46987,18 +47159,27 @@ function EventFacts({ selection, selected, venue, teamMembers, pricing }) {
46987
47159
  }) : null] }, member.id))
46988
47160
  })]
46989
47161
  }) : null,
46990
- pricing
47162
+ pricing,
47163
+ selected.bookingScope === "whole_series" ? /* @__PURE__ */ jsxs("div", {
47164
+ className: "rb-mt-6",
47165
+ children: [/* @__PURE__ */ jsx("div", {
47166
+ className: "rb-label rb-mb-2",
47167
+ children: "Registration"
47168
+ }), /* @__PURE__ */ jsx("p", { children: /* @__PURE__ */ jsx("strong", { children: selected.wholeSeries?.enrollmentOpen ? "Open" : "Closed" }) })]
47169
+ }) : null
46991
47170
  ]
46992
47171
  });
46993
47172
  }
46994
47173
  function OtherEventDates({ selection }) {
46995
- if (selection.otherDates.length === 0) return null;
47174
+ const isWholeSeries = selection.selected?.bookingScope === "whole_series";
47175
+ const dates = isWholeSeries && selection.selected ? [selection.selected, ...selection.otherDates].sort((left, right) => Date.parse(left.startsAt) - Date.parse(right.startsAt)) : selection.otherDates;
47176
+ if (dates.length === 0) return null;
46996
47177
  return /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("div", {
46997
47178
  className: "rb-label",
46998
- children: "Other dates"
47179
+ children: isWholeSeries ? "Session schedule" : "Other dates"
46999
47180
  }), /* @__PURE__ */ jsx("div", {
47000
47181
  className: "rb-mt-2 rb-tiles-grid",
47001
- children: selection.otherDates.map((event) => /* @__PURE__ */ jsx("a", {
47182
+ children: dates.map((event) => /* @__PURE__ */ jsx("a", {
47002
47183
  className: "rb-tile rb-tile--interactive",
47003
47184
  ...resolveEventLinkProps(event),
47004
47185
  children: /* @__PURE__ */ jsx(DateTimeTile, {
@@ -50197,13 +50378,13 @@ const FormNodeSSR = ({ blockId, value, submitLabel, successMessage, className, o
50197
50378
  * Renders the newsletter signup form for SSR with hydration support.
50198
50379
  * Uses the islands architecture pattern to hydrate on the client.
50199
50380
  */
50200
- function NewsletterFormSSR({ blockId, siteId, apiBaseUrl, listId, destinationProvider, preset = "emailOnly", includePhone, buttonLabel = "Subscribe", buttonVariant = "primary", successMessage, privacyNote, tags, spamProtectionEnabled, className }) {
50381
+ function NewsletterFormSSR(props) {
50382
+ const { siteId, apiBaseUrl, preset = "emailOnly", includePhone, buttonLabel = "Subscribe", buttonVariant = "primary", successMessage, privacyNote, tags, spamProtectionEnabled, className } = props;
50383
+ const blockId = props.source === "block" ? props.blockId : null;
50201
50384
  const islandProps = buildNewsletterFormInteractiveIslandProps({
50202
- blockId,
50385
+ ...props,
50203
50386
  siteId,
50204
50387
  apiBaseUrl,
50205
- listId,
50206
- destinationProvider,
50207
50388
  preset,
50208
50389
  includePhone,
50209
50390
  buttonLabel,
@@ -51870,6 +52051,213 @@ function collectConstrainedVideoMediaValues(options) {
51870
52051
  return values;
51871
52052
  }
51872
52053
  //#endregion
52054
+ //#region ../blocks/src/system/manifest/hydrateLinks.ts
52055
+ /**
52056
+ * Hydrates link objects within block content using the provided route map. Returns
52057
+ * the original content reference when no mutations are required to avoid unnecessary renders.
52058
+ */
52059
+ function hydrateManifestLinks(manifest, content, routes, pagesByIdentifier, entriesByIdentifier) {
52060
+ if (!routes || !manifest?.fields?.length) return content;
52061
+ return hydrateValue(content, {
52062
+ routes,
52063
+ pagesByIdentifier,
52064
+ entriesByIdentifier
52065
+ });
52066
+ }
52067
+ function hydrateValue(value, context) {
52068
+ try {
52069
+ if (Array.isArray(value)) {
52070
+ const resolvedItems = value.map((item) => hydrateValue(item, context));
52071
+ return resolvedItems.every((item, index) => item === value[index]) ? value : resolvedItems;
52072
+ }
52073
+ if (isRecord$27(value)) {
52074
+ if (isInternalLink$1(value)) return hydrateInternalLink(value, context.routes);
52075
+ if (isPageLink$1(value)) return hydratePageLink(value, context);
52076
+ if (isEntryLink$1(value)) return hydrateEntryLink(value, context);
52077
+ const resolvedEntries = Object.entries(value).map(([key, entry]) => [key, hydrateValue(entry, context)]);
52078
+ return resolvedEntries.every(([key, entry]) => entry === value[key]) ? value : Object.fromEntries(resolvedEntries);
52079
+ }
52080
+ return value;
52081
+ } catch (err) {
52082
+ console.error("[hydrateLinks] Error hydrating value:", err, value);
52083
+ return value;
52084
+ }
52085
+ }
52086
+ function hydrateInternalLink(link, routes) {
52087
+ const resolved = resolveRouteTarget(link.routeId, routes);
52088
+ if (!resolved) return link;
52089
+ const nextHref = resolved.href;
52090
+ const currentHref = typeof link.href === "string" && link.href.length > 0 ? link.href : null;
52091
+ const nextUpdatedAt = resolved.updatedAt;
52092
+ const updates = {};
52093
+ if (nextHref && nextHref !== currentHref) updates.href = nextHref;
52094
+ if (nextUpdatedAt && link.updatedAt !== nextUpdatedAt) updates.updatedAt = nextUpdatedAt;
52095
+ return Object.keys(updates).length > 0 ? {
52096
+ ...link,
52097
+ ...updates
52098
+ } : link;
52099
+ }
52100
+ function isInternalLink$1(value) {
52101
+ if (value.kind !== "internal") return false;
52102
+ if (typeof value.routeId !== "string" || value.routeId.length === 0) return false;
52103
+ return true;
52104
+ }
52105
+ function isPageLink$1(value) {
52106
+ if (value.kind !== "page") return false;
52107
+ if (typeof value.identifier !== "string" || value.identifier.length === 0) return false;
52108
+ return true;
52109
+ }
52110
+ function hydratePageLink(link, context) {
52111
+ const resolved = resolvePageRouteTarget(link, context);
52112
+ if (!resolved) return link;
52113
+ return {
52114
+ ...link,
52115
+ href: resolved.href,
52116
+ routeId: resolved.routeId
52117
+ };
52118
+ }
52119
+ function isEntryLink$1(value) {
52120
+ if (value.kind !== "entry") return false;
52121
+ if (typeof value.contentType !== "string" || value.contentType.length === 0) return false;
52122
+ if (typeof value.identifier !== "string" || value.identifier.length === 0) return false;
52123
+ return true;
52124
+ }
52125
+ function hydrateEntryLink(link, context) {
52126
+ const resolved = resolveEntryRouteTarget(link, context);
52127
+ if (!resolved) return link;
52128
+ return {
52129
+ ...link,
52130
+ href: resolved.href,
52131
+ routeId: resolved.routeId
52132
+ };
52133
+ }
52134
+ //#endregion
52135
+ //#region ../blocks/src/sdkBlockTransform.ts
52136
+ /**
52137
+ * Transforms an SDK custom block into a BlockManifest.
52138
+ *
52139
+ * If the block has a `layout`, it can be rendered declaratively without React code.
52140
+ * If no layout, the block MUST use blockOverrides for rendering.
52141
+ */
52142
+ function transformSdkBlockToManifest(sdkBlock) {
52143
+ const hasLayout = Boolean(sdkBlock.layout) || Boolean(sdkBlock.variants && Object.keys(sdkBlock.variants).length > 0);
52144
+ return augmentManifest({
52145
+ name: sdkBlock.id,
52146
+ version: "1.0.0",
52147
+ title: sdkBlock.title,
52148
+ titleSource: sdkBlock.titleSource,
52149
+ description: sdkBlock.description,
52150
+ component: sdkBlock.id,
52151
+ fields: sdkBlock.fields,
52152
+ slots: [],
52153
+ category: sdkBlock.category,
52154
+ tags: sdkBlock.tags,
52155
+ icon: sdkBlock.icon,
52156
+ layout: sdkBlock.layout,
52157
+ variants: sdkBlock.variants,
52158
+ defaultVariant: sdkBlock.defaultVariant,
52159
+ variantOptions: sdkBlock.variantOptions,
52160
+ previewCustomize: sdkBlock.previewCustomize,
52161
+ behaviours: {
52162
+ supportsThemeSwitching: true,
52163
+ inlineEditing: hasLayout,
52164
+ animation: hasLayout,
52165
+ paletteHidden: false
52166
+ }
52167
+ });
52168
+ }
52169
+ /**
52170
+ * Transforms an SDK custom block into a SystemBlockDefinition.
52171
+ *
52172
+ * This creates a minimal definition with just the manifest - no data loaders
52173
+ * or content normalizers since SDK blocks handle their own rendering.
52174
+ */
52175
+ function transformSdkBlockToDefinition(sdkBlock) {
52176
+ return {
52177
+ manifest: transformSdkBlockToManifest(sdkBlock),
52178
+ dataLoaders: sdkBlock.dataLoaders
52179
+ };
52180
+ }
52181
+ //#endregion
52182
+ //#region ../blocks/src/customBlockRegistry.ts
52183
+ const defaultCustomBlockSourcePolicy = { kind: "canonical-db-fallback-sdk" };
52184
+ function isCustomBlockKind(blockKind) {
52185
+ return blockKind.startsWith("custom.");
52186
+ }
52187
+ function transformToBlockDescriptor(sdkBlock, source = "sdk") {
52188
+ return {
52189
+ name: sdkBlock.id,
52190
+ title: sdkBlock.title,
52191
+ description: sdkBlock.description,
52192
+ category: sdkBlock.category,
52193
+ tags: sdkBlock.tags,
52194
+ icon: sdkBlock.icon,
52195
+ definition: transformSdkBlockToDefinition(sdkBlock),
52196
+ source
52197
+ };
52198
+ }
52199
+ function toResolvedCustomBlock(manifest, source) {
52200
+ return {
52201
+ blockKind: manifest.id,
52202
+ manifest: transformSdkBlockToManifest(manifest),
52203
+ source,
52204
+ descriptor: transformToBlockDescriptor(manifest, source.kind === "managed-database" ? "database" : "sdk")
52205
+ };
52206
+ }
52207
+ function planCustomBlockRegistryResolution({ sdkConfig, customBlocks = [], policy = defaultCustomBlockSourcePolicy }) {
52208
+ switch (policy.kind) {
52209
+ case "canonical-db-fallback-sdk": {
52210
+ const entriesByKind = /* @__PURE__ */ new Map();
52211
+ const conflicts = [];
52212
+ for (const customBlock of customBlocks) entriesByKind.set(customBlock.manifest.id, toResolvedCustomBlock(customBlock.manifest, customBlock.source));
52213
+ for (const sdkBlock of sdkConfig?.customBlocks ?? []) {
52214
+ const existing = entriesByKind.get(sdkBlock.id);
52215
+ if (existing) {
52216
+ conflicts.push({
52217
+ kind: "conflict",
52218
+ blockKind: existing.blockKind,
52219
+ winner: existing.source,
52220
+ loser: { kind: "sdk-config" },
52221
+ reason: "db-canonical-sdk-fallback"
52222
+ });
52223
+ continue;
52224
+ }
52225
+ entriesByKind.set(sdkBlock.id, toResolvedCustomBlock(sdkBlock, { kind: "sdk-config" }));
52226
+ }
52227
+ return {
52228
+ policy,
52229
+ entries: Array.from(entriesByKind.values()),
52230
+ conflicts
52231
+ };
52232
+ }
52233
+ }
52234
+ }
52235
+ function createCustomBlockRegistry({ sdkConfig, customBlocks = [], policy = defaultCustomBlockSourcePolicy, onConflict }) {
52236
+ const plan = planCustomBlockRegistryResolution({
52237
+ sdkConfig,
52238
+ customBlocks,
52239
+ policy
52240
+ });
52241
+ const entriesByKind = new Map(plan.entries.map((entry) => [entry.blockKind, entry]));
52242
+ for (const conflict of plan.conflicts) onConflict?.(`Using ${sourceLabel(conflict.winner)} custom block "${conflict.blockKind}" - ${sourceLabel(conflict.loser)} block is fallback only`);
52243
+ return {
52244
+ entries: plan.entries,
52245
+ conflicts: plan.conflicts,
52246
+ findManifest: (blockKind) => {
52247
+ if (!isCustomBlockKind(blockKind)) return void 0;
52248
+ return entriesByKind.get(blockKind);
52249
+ }
52250
+ };
52251
+ }
52252
+ function sourceLabel(source) {
52253
+ switch (source.kind) {
52254
+ case "managed-database": return "DB";
52255
+ case "sdk-synced": return "SDK-synced DB";
52256
+ case "sdk-config": return "SDK config";
52257
+ default: return assertNever$24(source);
52258
+ }
52259
+ }
52260
+ //#endregion
51873
52261
  //#region ../theme-core/src/runtime/fontFamily.ts
51874
52262
  /**
51875
52263
  * Font Family Formatting Utilities
@@ -52544,30 +52932,24 @@ const NAV_DROPDOWN_CONTAINER_RAIL_CSS_RULES = [
52544
52932
  ];
52545
52933
  //#endregion
52546
52934
  //#region ../theme-core/src/header/surfaceRules.ts
52547
- /** Compile the visual surface declarations independently of paint geometry. */
52548
- function buildHeaderSurfaceRules(header, tokens, blur) {
52935
+ /** Compile the at-rest surface independently of scroll treatment and paint geometry. */
52936
+ function buildHeaderSurfaceRules(header, tokens) {
52549
52937
  const base = [];
52550
- const scrolled = [];
52551
52938
  const background = header.background;
52552
52939
  if (background.type === "color") base.push(`background-color: ${tokens.getColor(background.color || "surface")};`);
52553
52940
  else if (background.type === "gradient" && background.gradient) {
52554
52941
  const stops = background.gradient.stops.map((stop) => tokens.getColor(stop.color)).join(", ");
52555
52942
  base.push(`background-image: linear-gradient(${background.gradient.angle ?? 180}deg, ${stops});`);
52556
52943
  }
52557
- const blurRules = [`backdrop-filter: ${blur};`, `-webkit-backdrop-filter: ${blur};`];
52558
- base.push(...blurRules);
52559
- scrolled.push(...blurRules);
52560
52944
  const borderWidth = getComponentBorderWidthPx(header.border?.width ?? "none");
52561
52945
  if (!header.border || borderWidth === "0") return {
52562
52946
  base,
52563
- scrolled,
52564
52947
  border: []
52565
52948
  };
52566
52949
  const color = rgbColorValue(header.border.colorToken?.trim() || "border");
52567
52950
  const style = header.border.style === "dashed" ? "dashed" : "solid";
52568
52951
  return {
52569
52952
  base,
52570
- scrolled,
52571
52953
  border: header.border.position === "both" ? [`border-top: ${borderWidth} ${style} ${color};`, `border-bottom: ${borderWidth} ${style} ${color};`] : [`border-${header.border.position}: ${borderWidth} ${style} ${color};`]
52572
52954
  };
52573
52955
  }
@@ -52877,13 +53259,12 @@ function generateHeaderRootStyles(header, themeId, tokens) {
52877
53259
  rules.push("isolation: isolate;");
52878
53260
  const surfaceRules = isContainedNav ? {
52879
53261
  base: [],
52880
- scrolled: [],
52881
53262
  border: []
52882
- } : buildHeaderSurfaceRules(header, tokens, HEADER_BLUR);
53263
+ } : buildHeaderSurfaceRules(header, tokens);
52883
53264
  const floatingSurfaceBorder = header.variant === "floating";
52884
53265
  if (!floatingSurfaceBorder) rules.push(...surfaceRules.border);
52885
53266
  const basePaintRules = floatingSurfaceBorder ? [...surfaceRules.base, ...surfaceRules.border] : surfaceRules.base;
52886
- const scrolledPaintRules = floatingSurfaceBorder ? [...surfaceRules.scrolled, ...surfaceRules.border] : surfaceRules.scrolled;
53267
+ const scrolledPaintRules = floatingSurfaceBorder ? surfaceRules.border : [];
52887
53268
  if (header.positioning === "sticky" || header.positioning === "fixed") {
52888
53269
  const shadowVar = getComponentShadowVar(header.shadow?.elevation ?? "none");
52889
53270
  if (shadowVar) rules.push(`box-shadow: ${shadowVar};`);
@@ -55614,215 +55995,115 @@ function mapFontStyle(italic) {
55614
55995
  return italic ? "italic" : "normal";
55615
55996
  }
55616
55997
  //#endregion
55617
- //#region ../blocks/src/system/manifest/hydrateLinks.ts
55618
- /**
55619
- * Hydrates link objects within block content using the provided route map. Returns
55620
- * the original content reference when no mutations are required to avoid unnecessary renders.
55621
- */
55622
- function hydrateManifestLinks(manifest, content, routes, pagesByIdentifier, entriesByIdentifier) {
55623
- if (!routes || !manifest?.fields?.length) return content;
55624
- return hydrateValue(content, {
55625
- routes,
55626
- pagesByIdentifier,
55627
- entriesByIdentifier
55628
- });
55629
- }
55630
- function hydrateValue(value, context) {
55631
- try {
55632
- if (Array.isArray(value)) {
55633
- const resolvedItems = value.map((item) => hydrateValue(item, context));
55634
- return resolvedItems.every((item, index) => item === value[index]) ? value : resolvedItems;
55635
- }
55636
- if (isRecord$27(value)) {
55637
- if (isInternalLink$1(value)) return hydrateInternalLink(value, context.routes);
55638
- if (isPageLink$1(value)) return hydratePageLink(value, context);
55639
- if (isEntryLink$1(value)) return hydrateEntryLink(value, context);
55640
- const resolvedEntries = Object.entries(value).map(([key, entry]) => [key, hydrateValue(entry, context)]);
55641
- return resolvedEntries.every(([key, entry]) => entry === value[key]) ? value : Object.fromEntries(resolvedEntries);
55642
- }
55643
- return value;
55644
- } catch (err) {
55645
- console.error("[hydrateLinks] Error hydrating value:", err, value);
55646
- return value;
55998
+ //#region ../blocks/src/pageRenderingMode.ts
55999
+ var MissingBlockOverrideError$1 = class extends Error {
56000
+ constructor(blockKind) {
56001
+ super(`Override-only rendering requires an override for block kind "${blockKind}".`);
56002
+ this.blockKind = blockKind;
56003
+ this.code = "missing_block_override";
56004
+ this.name = "MissingBlockOverrideError";
55647
56005
  }
56006
+ };
56007
+ function isOverrideOnlyResourceInput(props) {
56008
+ return props.rendering?.kind === "overrides-only";
55648
56009
  }
55649
- function hydrateInternalLink(link, routes) {
55650
- const resolved = resolveRouteTarget(link.routeId, routes);
55651
- if (!resolved) return link;
55652
- const nextHref = resolved.href;
55653
- const currentHref = typeof link.href === "string" && link.href.length > 0 ? link.href : null;
55654
- const nextUpdatedAt = resolved.updatedAt;
55655
- const updates = {};
55656
- if (nextHref && nextHref !== currentHref) updates.href = nextHref;
55657
- if (nextUpdatedAt && link.updatedAt !== nextUpdatedAt) updates.updatedAt = nextUpdatedAt;
55658
- return Object.keys(updates).length > 0 ? {
55659
- ...link,
55660
- ...updates
55661
- } : link;
55662
- }
55663
- function isInternalLink$1(value) {
55664
- if (value.kind !== "internal") return false;
55665
- if (typeof value.routeId !== "string" || value.routeId.length === 0) return false;
55666
- return true;
55667
- }
55668
- function isPageLink$1(value) {
55669
- if (value.kind !== "page") return false;
55670
- if (typeof value.identifier !== "string" || value.identifier.length === 0) return false;
55671
- return true;
55672
- }
55673
- function hydratePageLink(link, context) {
55674
- const resolved = resolvePageRouteTarget(link, context);
55675
- if (!resolved) return link;
56010
+ function resolvePageThemeResources(props) {
56011
+ if (isOverrideOnlyResourceInput(props)) return { kind: "unavailable" };
55676
56012
  return {
55677
- ...link,
55678
- href: resolved.href,
55679
- routeId: resolved.routeId
56013
+ kind: "available",
56014
+ tokens: props.themeTokens ?? buildThemeRuntime$1(props.theme).tokens,
56015
+ config: props.theme
55680
56016
  };
55681
56017
  }
55682
- function isEntryLink$1(value) {
55683
- if (value.kind !== "entry") return false;
55684
- if (typeof value.contentType !== "string" || value.contentType.length === 0) return false;
55685
- if (typeof value.identifier !== "string" || value.identifier.length === 0) return false;
55686
- return true;
56018
+ function requireBlockOverride(resources, override, blockKind) {
56019
+ if (resources.kind === "unavailable" && !override) throw new MissingBlockOverrideError$1(blockKind);
55687
56020
  }
55688
- function hydrateEntryLink(link, context) {
55689
- const resolved = resolveEntryRouteTarget(link, context);
55690
- if (!resolved) return link;
55691
- return {
55692
- ...link,
55693
- href: resolved.href,
55694
- routeId: resolved.routeId
55695
- };
56021
+ function overrideThemeProps(resources) {
56022
+ return resources.kind === "available" ? {
56023
+ theme: resources.tokens,
56024
+ themeConfig: resources.config
56025
+ } : {};
56026
+ }
56027
+ function requireThemeResources(resources, blockKind) {
56028
+ if (resources.kind === "unavailable") throw new MissingBlockOverrideError$1(blockKind);
56029
+ return resources;
55696
56030
  }
55697
56031
  //#endregion
55698
- //#region ../blocks/src/sdkBlockTransform.ts
55699
- /**
55700
- * Transforms an SDK custom block into a BlockManifest.
55701
- *
55702
- * If the block has a `layout`, it can be rendered declaratively without React code.
55703
- * If no layout, the block MUST use blockOverrides for rendering.
55704
- */
55705
- function transformSdkBlockToManifest(sdkBlock) {
55706
- const hasLayout = Boolean(sdkBlock.layout) || Boolean(sdkBlock.variants && Object.keys(sdkBlock.variants).length > 0);
55707
- return augmentManifest({
55708
- name: sdkBlock.id,
55709
- version: "1.0.0",
55710
- title: sdkBlock.title,
55711
- titleSource: sdkBlock.titleSource,
55712
- description: sdkBlock.description,
55713
- component: sdkBlock.id,
55714
- fields: sdkBlock.fields,
55715
- slots: [],
55716
- category: sdkBlock.category,
55717
- tags: sdkBlock.tags,
55718
- icon: sdkBlock.icon,
55719
- layout: sdkBlock.layout,
55720
- variants: sdkBlock.variants,
55721
- defaultVariant: sdkBlock.defaultVariant,
55722
- variantOptions: sdkBlock.variantOptions,
55723
- previewCustomize: sdkBlock.previewCustomize,
55724
- behaviours: {
55725
- supportsThemeSwitching: true,
55726
- inlineEditing: hasLayout,
55727
- animation: hasLayout,
55728
- paletteHidden: false
55729
- }
55730
- });
56032
+ //#region ../blocks/src/pageRendererBoundaries.tsx
56033
+ const boundaryKey = (previousBlockId, nextBlockId) => `${previousBlockId}\u0000${nextBlockId}`;
56034
+ function isSiteStyleTransitionStyleGroup(value) {
56035
+ return value?.startsWith("site-style-transition-") === true;
55731
56036
  }
55732
- /**
55733
- * Transforms an SDK custom block into a SystemBlockDefinition.
55734
- *
55735
- * This creates a minimal definition with just the manifest - no data loaders
55736
- * or content normalizers since SDK blocks handle their own rendering.
55737
- */
55738
- function transformSdkBlockToDefinition(sdkBlock) {
55739
- return {
55740
- manifest: transformSdkBlockToManifest(sdkBlock),
55741
- dataLoaders: sdkBlock.dataLoaders
55742
- };
56037
+ function boundaryMapForAdjacentBlockIds(boundaries) {
56038
+ return new Map(boundaries.map((boundary) => [boundaryKey(boundary.previousBlockId, boundary.nextBlockId), boundary]));
55743
56039
  }
55744
- //#endregion
55745
- //#region ../blocks/src/customBlockRegistry.ts
55746
- const defaultCustomBlockSourcePolicy = { kind: "canonical-db-fallback-sdk" };
55747
- function isCustomBlockKind(blockKind) {
55748
- return blockKind.startsWith("custom.");
56040
+ function boundaryBetweenBlocks(previousBlock, nextBlock, boundaries) {
56041
+ const previousBlockId = previousBlock?.id ?? null;
56042
+ const nextBlockId = nextBlock?.id ?? null;
56043
+ if (!previousBlockId || !nextBlockId) return null;
56044
+ return boundaries.get(boundaryKey(previousBlockId, nextBlockId)) ?? null;
55749
56045
  }
55750
- function transformToBlockDescriptor(sdkBlock, source = "sdk") {
56046
+ function renderBoundaryAfterBlock(input) {
56047
+ const previousBlockId = input.block.id;
56048
+ const nextBlockId = input.nextBlock?.id ?? null;
56049
+ if (!previousBlockId || !nextBlockId) return null;
56050
+ const boundary = input.boundaryByAdjacentBlockIds.get(boundaryKey(previousBlockId, nextBlockId));
56051
+ if (!boundary) return null;
56052
+ const rendered = /* @__PURE__ */ jsx("div", {
56053
+ "aria-hidden": "true",
56054
+ "data-block-boundary": "",
56055
+ "data-boundary-id": boundary.boundaryId,
56056
+ "data-boundary-previous-block-id": boundary.previousBlockId,
56057
+ "data-boundary-next-block-id": boundary.nextBlockId,
56058
+ "data-style-group": boundary.styleGroup,
56059
+ style: boundaryCssVarsStyle(boundary)
56060
+ }, `${input.blockKey}:boundary`);
56061
+ return input.wrapBoundary ? input.wrapBoundary(boundary, rendered) : rendered;
56062
+ }
56063
+ function boundaryCssVarsStyle(boundary) {
55751
56064
  return {
55752
- name: sdkBlock.id,
55753
- title: sdkBlock.title,
55754
- description: sdkBlock.description,
55755
- category: sdkBlock.category,
55756
- tags: sdkBlock.tags,
55757
- icon: sdkBlock.icon,
55758
- definition: transformSdkBlockToDefinition(sdkBlock),
55759
- source
56065
+ "--site-style-transition-from": boundary.cssVars.from,
56066
+ "--site-style-transition-to": boundary.cssVars.to
55760
56067
  };
55761
56068
  }
55762
- function toResolvedCustomBlock(manifest, source) {
56069
+ function boundaryReserveCssVarsStyle(input) {
56070
+ const before = input.before?.metrics.reserveCss ?? null;
56071
+ const after = input.after?.metrics.reserveCss ?? null;
56072
+ if (!before && !after) return void 0;
55763
56073
  return {
55764
- blockKind: manifest.id,
55765
- manifest: transformSdkBlockToManifest(manifest),
55766
- source,
55767
- descriptor: transformToBlockDescriptor(manifest, source.kind === "managed-database" ? "database" : "sdk")
56074
+ ...before ? { "--site-style-boundary-before-reserve": before } : {},
56075
+ ...after ? { "--site-style-boundary-after-reserve": after } : {}
55768
56076
  };
55769
56077
  }
55770
- function planCustomBlockRegistryResolution({ sdkConfig, customBlocks = [], policy = defaultCustomBlockSourcePolicy }) {
55771
- switch (policy.kind) {
55772
- case "canonical-db-fallback-sdk": {
55773
- const entriesByKind = /* @__PURE__ */ new Map();
55774
- const conflicts = [];
55775
- for (const customBlock of customBlocks) entriesByKind.set(customBlock.manifest.id, toResolvedCustomBlock(customBlock.manifest, customBlock.source));
55776
- for (const sdkBlock of sdkConfig?.customBlocks ?? []) {
55777
- const existing = entriesByKind.get(sdkBlock.id);
55778
- if (existing) {
55779
- conflicts.push({
55780
- kind: "conflict",
55781
- blockKind: existing.blockKind,
55782
- winner: existing.source,
55783
- loser: { kind: "sdk-config" },
55784
- reason: "db-canonical-sdk-fallback"
55785
- });
55786
- continue;
55787
- }
55788
- entriesByKind.set(sdkBlock.id, toResolvedCustomBlock(sdkBlock, { kind: "sdk-config" }));
55789
- }
55790
- return {
55791
- policy,
55792
- entries: Array.from(entriesByKind.values()),
55793
- conflicts
55794
- };
55795
- }
55796
- }
56078
+ function transitionCssVarsStyle(content) {
56079
+ const transitionStyles = isObjectRecord$1(content._transitionStyles) ? content._transitionStyles : null;
56080
+ const cssVars = isObjectRecord$1(transitionStyles?.cssVars) ? transitionStyles.cssVars : null;
56081
+ const from = typeof cssVars?.from === "string" ? cssVars.from : null;
56082
+ const to = typeof cssVars?.to === "string" ? cssVars.to : null;
56083
+ if (!from && !to) return void 0;
56084
+ return {
56085
+ ...from ? { "--site-style-transition-from": from } : {},
56086
+ ...to ? { "--site-style-transition-to": to } : {}
56087
+ };
55797
56088
  }
55798
- function createCustomBlockRegistry({ sdkConfig, customBlocks = [], policy = defaultCustomBlockSourcePolicy, onConflict }) {
55799
- const plan = planCustomBlockRegistryResolution({
55800
- sdkConfig,
55801
- customBlocks,
55802
- policy
55803
- });
55804
- const entriesByKind = new Map(plan.entries.map((entry) => [entry.blockKind, entry]));
55805
- for (const conflict of plan.conflicts) onConflict?.(`Using ${sourceLabel(conflict.winner)} custom block "${conflict.blockKind}" - ${sourceLabel(conflict.loser)} block is fallback only`);
56089
+ function mergeStyleObjects(left, right) {
56090
+ if (!left) return right;
56091
+ if (!right) return left;
55806
56092
  return {
55807
- entries: plan.entries,
55808
- conflicts: plan.conflicts,
55809
- findManifest: (blockKind) => {
55810
- if (!isCustomBlockKind(blockKind)) return void 0;
55811
- return entriesByKind.get(blockKind);
55812
- }
56093
+ ...left,
56094
+ ...right
55813
56095
  };
55814
56096
  }
55815
- function sourceLabel(source) {
55816
- switch (source.kind) {
55817
- case "managed-database": return "DB";
55818
- case "sdk-synced": return "SDK-synced DB";
55819
- case "sdk-config": return "SDK config";
55820
- default: return assertNever$24(source);
55821
- }
56097
+ function pageBlockPosition(index, blockCount) {
56098
+ if (blockCount <= 1) return "only";
56099
+ if (index === 0) return "first";
56100
+ if (index === blockCount - 1) return "last";
56101
+ return "middle";
55822
56102
  }
55823
56103
  //#endregion
55824
56104
  //#region ../blocks/src/PageRenderer.tsx
55825
- function PageRenderer$1({ theme, page, runtimeBoundaries, usePlaceholders = false, dataContext, wrapBlock, wrapBoundary, registry, themeTokens: providedThemeTokens, routeMap, blockOverrides, sdkConfig, customBlocks, previewAuthoring }) {
56105
+ function PageRenderer$1(props) {
56106
+ const { page, runtimeBoundaries, usePlaceholders = false, dataContext, wrapBlock, wrapBoundary, registry, routeMap, blockOverrides, sdkConfig, customBlocks, previewAuthoring } = props;
55826
56107
  const imageResolveContext = React$1.useMemo(() => resolvePageRendererImageResolveContext(dataContext), [
55827
56108
  dataContext?.imageResolveContext,
55828
56109
  dataContext?.mediaAssets,
@@ -55831,12 +56112,16 @@ function PageRenderer$1({ theme, page, runtimeBoundaries, usePlaceholders = fals
55831
56112
  ]);
55832
56113
  const boundaryByAdjacentBlockIds = React$1.useMemo(() => boundaryMapForAdjacentBlockIds(runtimeBoundaries ?? []), [runtimeBoundaries]);
55833
56114
  const usesRuntimeBoundaries = runtimeBoundaries !== void 0;
56115
+ const themeResources = React$1.useMemo(() => resolvePageThemeResources(props), [
56116
+ props.rendering,
56117
+ props.theme,
56118
+ props.themeTokens
56119
+ ]);
55834
56120
  if (!page || page.blocks.length === 0) return /* @__PURE__ */ jsx("div", {
55835
56121
  className: "rb-p-6 rb-caption",
55836
56122
  style: textColorStyle("mutedText"),
55837
56123
  children: "No blocks found."
55838
56124
  });
55839
- const themeTokens = providedThemeTokens ?? buildThemeRuntime$1(theme).tokens;
55840
56125
  const resolvedRegistry = registry ?? getDefaultComponentRegistry();
55841
56126
  setContextResolveImageUrlContext(imageResolveContext);
55842
56127
  return /* @__PURE__ */ jsx("div", { children: page.blocks.map((block, index) => {
@@ -55859,22 +56144,14 @@ function PageRenderer$1({ theme, page, runtimeBoundaries, usePlaceholders = fals
55859
56144
  const renderableContent = getRenderableContent(block, dataContext?.previewStage);
55860
56145
  const variantKey = definition?.manifest ? resolveVariantKey(definition.manifest, renderableContent) : null;
55861
56146
  const shouldUseWrapper = !managesOwnWrapper || Boolean(wrapBlock);
55862
- const blockSectionProps = {
55863
- themeTokens,
55864
- themeConfig: theme,
56147
+ const blockSectionProps = buildBlockSectionProps({
56148
+ props,
56149
+ themeResources,
55865
56150
  block,
55866
- usePlaceholders,
55867
- dataContext,
55868
56151
  blockKey,
55869
- registry: resolvedRegistry,
55870
- routeMap,
55871
- wrapBlock,
55872
- blockOverrides,
55873
- sdkConfig,
55874
- customBlocks,
55875
56152
  imageResolveContext,
55876
- previewAuthoring
55877
- };
56153
+ registry: resolvedRegistry
56154
+ });
55878
56155
  if (!shouldUseWrapper) {
55879
56156
  const rendered = /* @__PURE__ */ jsx(MemoBlockSection, { ...blockSectionProps }, `${blockKey}:block`);
55880
56157
  return boundaryElement ? /* @__PURE__ */ jsxs(React$1.Fragment, { children: [rendered, boundaryElement] }, blockKey) : rendered;
@@ -55916,81 +56193,6 @@ function PageRenderer$1({ theme, page, runtimeBoundaries, usePlaceholders = fals
55916
56193
  })] }, blockKey);
55917
56194
  }) });
55918
56195
  }
55919
- function isSiteStyleTransitionStyleGroup(value) {
55920
- return value?.startsWith("site-style-transition-") === true;
55921
- }
55922
- function boundaryMapForAdjacentBlockIds(boundaries) {
55923
- return new Map(boundaries.map((boundary) => [boundaryKey(boundary.previousBlockId, boundary.nextBlockId), boundary]));
55924
- }
55925
- function boundaryKey(previousBlockId, nextBlockId) {
55926
- return `${previousBlockId}\u0000${nextBlockId}`;
55927
- }
55928
- function boundaryBetweenBlocks(previousBlock, nextBlock, boundaryByAdjacentBlockIds) {
55929
- const previousBlockId = previousBlock?.id ?? null;
55930
- const nextBlockId = nextBlock?.id ?? null;
55931
- if (!previousBlockId || !nextBlockId) return null;
55932
- return boundaryByAdjacentBlockIds.get(boundaryKey(previousBlockId, nextBlockId)) ?? null;
55933
- }
55934
- function renderBoundaryAfterBlock(input) {
55935
- const previousBlockId = input.block.id;
55936
- const nextBlockId = input.nextBlock?.id ?? null;
55937
- if (!previousBlockId || !nextBlockId) return null;
55938
- const boundary = input.boundaryByAdjacentBlockIds.get(boundaryKey(previousBlockId, nextBlockId));
55939
- if (!boundary) return null;
55940
- const rendered = /* @__PURE__ */ jsx("div", {
55941
- "aria-hidden": "true",
55942
- "data-block-boundary": "",
55943
- "data-boundary-id": boundary.boundaryId,
55944
- "data-boundary-previous-block-id": boundary.previousBlockId,
55945
- "data-boundary-next-block-id": boundary.nextBlockId,
55946
- "data-style-group": boundary.styleGroup,
55947
- style: boundaryCssVarsStyle(boundary)
55948
- }, `${input.blockKey}:boundary`);
55949
- return input.wrapBoundary ? input.wrapBoundary(boundary, rendered) : rendered;
55950
- }
55951
- function boundaryCssVarsStyle(boundary) {
55952
- return {
55953
- "--site-style-transition-from": boundary.cssVars.from,
55954
- "--site-style-transition-to": boundary.cssVars.to
55955
- };
55956
- }
55957
- function boundaryReserveCssVarsStyle(input) {
55958
- const before = input.before ? boundaryReserveValueForTreatment(input.before) : null;
55959
- const after = input.after ? boundaryReserveValueForTreatment(input.after) : null;
55960
- if (!before && !after) return void 0;
55961
- return {
55962
- ...before ? { "--site-style-boundary-before-reserve": before } : {},
55963
- ...after ? { "--site-style-boundary-after-reserve": after } : {}
55964
- };
55965
- }
55966
- function boundaryReserveValueForTreatment(boundary) {
55967
- return boundary.metrics.reserveCss;
55968
- }
55969
- function transitionCssVarsStyle(content) {
55970
- const transitionStyles = isObjectRecord$1(content._transitionStyles) ? content._transitionStyles : null;
55971
- const cssVars = isObjectRecord$1(transitionStyles?.cssVars) ? transitionStyles.cssVars : null;
55972
- const from = typeof cssVars?.from === "string" ? cssVars.from : null;
55973
- const to = typeof cssVars?.to === "string" ? cssVars.to : null;
55974
- if (!from && !to) return void 0;
55975
- return {
55976
- ...from ? { "--site-style-transition-from": from } : {},
55977
- ...to ? { "--site-style-transition-to": to } : {}
55978
- };
55979
- }
55980
- function mergeStyleObjects(left, right) {
55981
- if (!left) return right;
55982
- if (!right) return left;
55983
- return {
55984
- ...left,
55985
- ...right
55986
- };
55987
- }
55988
- function pageBlockPosition(index, blockCount) {
55989
- if (blockCount <= 1) return "only";
55990
- if (index === 0) return "first";
55991
- if (index === blockCount - 1) return "last";
55992
- return "middle";
55993
- }
55994
56196
  function resolvePageRendererImageResolveContext(dataContext) {
55995
56197
  const input = dataContext?.imageResolveContext;
55996
56198
  return buildResolveImageUrlContext({
@@ -56000,6 +56202,23 @@ function resolvePageRendererImageResolveContext(dataContext) {
56000
56202
  mediaAssets: input?.mediaAssets ?? dataContext?.mediaAssets
56001
56203
  });
56002
56204
  }
56205
+ function buildBlockSectionProps(input) {
56206
+ return {
56207
+ themeResources: input.themeResources,
56208
+ block: input.block,
56209
+ usePlaceholders: input.props.usePlaceholders ?? false,
56210
+ dataContext: input.props.dataContext,
56211
+ blockKey: input.blockKey,
56212
+ registry: input.registry,
56213
+ routeMap: input.props.routeMap,
56214
+ wrapBlock: input.props.wrapBlock,
56215
+ blockOverrides: input.props.blockOverrides,
56216
+ sdkConfig: input.props.sdkConfig,
56217
+ customBlocks: input.props.customBlocks,
56218
+ imageResolveContext: input.imageResolveContext,
56219
+ previewAuthoring: input.props.previewAuthoring
56220
+ };
56221
+ }
56003
56222
  /**
56004
56223
  * Look up a block override component by block kind.
56005
56224
  * Supports both full ("block.hero") and short ("hero") keys.
@@ -56066,7 +56285,7 @@ function getCachedValidator(manifest, flavour) {
56066
56285
  * referential equality of all props that affect rendering. Standard React.memo
56067
56286
  * wouldn't catch all the render triggers from the editor store.
56068
56287
  */
56069
- const MemoBlockSection = React$1.memo(function MemoBlockSection({ themeTokens, themeConfig, block, usePlaceholders, dataContext, registry, routeMap, wrapBlock, blockOverrides, sdkConfig, customBlocks, imageResolveContext, previewAuthoring }) {
56288
+ const MemoBlockSection = React$1.memo(function MemoBlockSection({ themeResources, block, usePlaceholders, dataContext, registry, routeMap, wrapBlock, blockOverrides, sdkConfig, customBlocks, imageResolveContext, previewAuthoring }) {
56070
56289
  const perfStart = globalThis.process?.env?.DEBUG_PERF === "1" && typeof window === "undefined" ? Date.now() : 0;
56071
56290
  const fallbackImageResolveContext = getCurrentResolveImageUrlContext();
56072
56291
  const resolvedImageResolveContext = imageResolveContext ?? fallbackImageResolveContext;
@@ -56087,6 +56306,7 @@ const MemoBlockSection = React$1.memo(function MemoBlockSection({ themeTokens, t
56087
56306
  return node;
56088
56307
  }
56089
56308
  const OverrideComponent = getBlockOverride(block.kind, blockOverrides);
56309
+ requireBlockOverride(themeResources, OverrideComponent, block.kind);
56090
56310
  let definition = getBlockDefinition(block.kind);
56091
56311
  if (!definition && block.kind.startsWith("custom.")) definition = createCustomBlockRegistry({
56092
56312
  sdkConfig,
@@ -56099,8 +56319,7 @@ const MemoBlockSection = React$1.memo(function MemoBlockSection({ themeTokens, t
56099
56319
  if (OverrideComponent) {
56100
56320
  const rendered = /* @__PURE__ */ jsx(OverrideComponent, {
56101
56321
  content: getRenderableContent(block, dataContext?.previewStage),
56102
- theme: themeTokens,
56103
- themeConfig,
56322
+ ...overrideThemeProps(themeResources),
56104
56323
  data: void 0,
56105
56324
  siteId: dataContext?.siteId,
56106
56325
  apiBaseUrl: dataContext?.apiBaseUrl,
@@ -56199,8 +56418,7 @@ const MemoBlockSection = React$1.memo(function MemoBlockSection({ themeTokens, t
56199
56418
  const hasResolvedData = !!resolved && typeof resolved === "object" && Object.keys(resolved).length > 0;
56200
56419
  const baseProps = {
56201
56420
  content: hydratedContent,
56202
- theme: themeTokens,
56203
- themeConfig,
56421
+ ...overrideThemeProps(themeResources),
56204
56422
  data: resolved,
56205
56423
  siteId: dataContext?.siteId,
56206
56424
  apiBaseUrl: dataContext?.apiBaseUrl,
@@ -56220,6 +56438,7 @@ const MemoBlockSection = React$1.memo(function MemoBlockSection({ themeTokens, t
56220
56438
  let rendered;
56221
56439
  if (OverrideComponent) rendered = /* @__PURE__ */ jsx(OverrideComponent, { ...baseProps });
56222
56440
  else {
56441
+ requireThemeResources(themeResources, block.kind);
56223
56442
  const BlockComponent = getCachedBlockComponent(definition.manifest);
56224
56443
  const pathBase = typeof block.id === "string" && block.id.length > 0 ? `blocks.${block.id}.` : void 0;
56225
56444
  const rootContext = { $root: {
@@ -56269,7 +56488,7 @@ const MemoBlockSection = React$1.memo(function MemoBlockSection({ themeTokens, t
56269
56488
  });
56270
56489
  }
56271
56490
  }, (prev, next) => {
56272
- 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;
56491
+ 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;
56273
56492
  });
56274
56493
  function fallback(message) {
56275
56494
  return /* @__PURE__ */ jsx("div", {
@@ -69486,6 +69705,10 @@ function toBlocksImageResolveContextInput(context) {
69486
69705
  }
69487
69706
  //#endregion
69488
69707
  //#region src/rendering/blocks-page-renderer.ts
69708
+ const MissingBlockOverrideError = MissingBlockOverrideError$1;
69709
+ function isOverrideOnlyPageRenderer(props) {
69710
+ return props.rendering?.kind === "overrides-only";
69711
+ }
69489
69712
  function normalizeSdkCustomBlocks(customBlocks) {
69490
69713
  if (!customBlocks) return void 0;
69491
69714
  return customBlocks.map((block) => {
@@ -69507,8 +69730,7 @@ function toBlocksBlockOverrides(overrides) {
69507
69730
  };
69508
69731
  return result;
69509
69732
  }
69510
- function toBlocksDataContext(dataContext) {
69511
- if (!dataContext) return void 0;
69733
+ function toBlocksPageRendererDataContext(dataContext) {
69512
69734
  return {
69513
69735
  ...dataContext,
69514
69736
  mediaAssets: toBlocksMediaAssets(dataContext.mediaAssets),
@@ -69517,15 +69739,23 @@ function toBlocksDataContext(dataContext) {
69517
69739
  }
69518
69740
  function PageRenderer(props) {
69519
69741
  const blocksSdkConfig = props.sdkConfig ? { customBlocks: normalizeSdkCustomBlocks(props.sdkConfig.customBlocks) } : props.sdkConfig;
69520
- const blocksTheme = parseBlocksTheme(props.theme);
69521
- const blocksProps = {
69522
- ...props,
69523
- theme: blocksTheme,
69524
- dataContext: toBlocksDataContext(props.dataContext),
69742
+ const { rendering: _rendering, theme: _theme, themeTokens: _themeTokens, ...commonProps } = props;
69743
+ const commonBlocksProps = {
69744
+ ...commonProps,
69745
+ dataContext: props.dataContext ? toBlocksPageRendererDataContext(props.dataContext) : void 0,
69525
69746
  blockOverrides: toBlocksBlockOverrides(props.blockOverrides),
69526
69747
  sdkConfig: blocksSdkConfig,
69527
69748
  customBlocks: normalizeSdkCustomBlocks(props.customBlocks)
69528
69749
  };
69750
+ const blocksProps = isOverrideOnlyPageRenderer(props) ? {
69751
+ ...commonBlocksProps,
69752
+ rendering: { kind: "overrides-only" },
69753
+ blockOverrides: toBlocksBlockOverrides(props.blockOverrides) ?? {}
69754
+ } : {
69755
+ ...commonBlocksProps,
69756
+ theme: parseBlocksTheme(props.theme),
69757
+ themeTokens: props.themeTokens
69758
+ };
69529
69759
  return React$1.createElement(PageRenderer$1, blocksProps);
69530
69760
  }
69531
69761
  //#endregion
@@ -69567,8 +69797,31 @@ function renderWithSdkThemeRuntime({ themeRuntime, theme, children }) {
69567
69797
  default: return assertNever$24(themeRuntime);
69568
69798
  }
69569
69799
  }
69800
+ function renderWithOverrideOnlyRuntime({ runtime, children }) {
69801
+ switch (runtime.kind) {
69802
+ case "responsive-only": return /* @__PURE__ */ jsx(ResponsiveScope, {
69803
+ responsiveMode: runtime.responsiveMode,
69804
+ children
69805
+ });
69806
+ case "none": return /* @__PURE__ */ jsx(Fragment, { children });
69807
+ default: return assertNever$24(runtime);
69808
+ }
69809
+ }
69570
69810
  //#endregion
69571
69811
  //#region src/rendering/components/pageShared.tsx
69812
+ function isOverrideOnlyPage(props) {
69813
+ return props.rendering?.kind === "overrides-only";
69814
+ }
69815
+ function resolvePageThemeTokens(props) {
69816
+ const baseTokens = props.themeTokens ?? buildThemeRuntime(props.theme).tokens;
69817
+ return props.sdkConfig?.theme?.palette ? {
69818
+ ...baseTokens,
69819
+ palette: {
69820
+ ...baseTokens.palette,
69821
+ ...props.sdkConfig.theme.palette
69822
+ }
69823
+ } : baseTokens;
69824
+ }
69572
69825
  function toPageHydrationBootstrapConfig(props) {
69573
69826
  return {
69574
69827
  siteId: props.siteId,
@@ -69576,55 +69829,60 @@ function toPageHydrationBootstrapConfig(props) {
69576
69829
  mediaAssets: props.mediaAssets
69577
69830
  };
69578
69831
  }
69579
- 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 }) {
69580
- const baseTokens = providedTokens ?? buildThemeRuntime(theme).tokens;
69581
- return renderWithSdkThemeRuntime({
69582
- themeRuntime,
69583
- theme,
69584
- children: /* @__PURE__ */ jsx(PageRenderer, {
69585
- theme,
69586
- page,
69587
- runtimeBoundaries,
69588
- themeTokens: sdkConfig?.theme?.palette ? {
69589
- ...baseTokens,
69590
- palette: {
69591
- ...baseTokens.palette,
69592
- ...sdkConfig.theme.palette
69593
- }
69594
- } : baseTokens,
69595
- usePlaceholders,
69596
- dataContext: {
69832
+ function PageContent(props) {
69833
+ const { page, runtimeBoundaries, siteId, resolvedData, bookingOfferingPresets, routeMap, pagesByIdentifier, entriesByIdentifier, wrapBlock, registry, usePlaceholders = false, blockOverrides, sdkConfig, customBlocks, supabaseUrl, mediaAssets, apiBaseUrl, portalToken, previewToken, dataContext } = props;
69834
+ const rendererCommonProps = {
69835
+ page,
69836
+ runtimeBoundaries,
69837
+ usePlaceholders,
69838
+ dataContext: {
69839
+ siteId,
69840
+ apiBaseUrl,
69841
+ portalToken,
69842
+ previewToken,
69843
+ resolvedData,
69844
+ bookingOfferingPresets: bookingOfferingPresets ?? [],
69845
+ routes: routeMap,
69846
+ pagesByIdentifier,
69847
+ entriesByIdentifier,
69848
+ occurrenceContext: dataContext?.occurrenceContext ?? null,
69849
+ entrySubrouteContext: dataContext?.entrySubrouteContext ?? null,
69850
+ contentEntry: dataContext?.contentEntry ?? null,
69851
+ pageSurface: dataContext?.pageSurface ?? null,
69852
+ subject: dataContext?.subject ?? null,
69853
+ editableRouteMetadataFieldIds: dataContext?.editableRouteMetadataFieldIds ?? null,
69854
+ previewStage: dataContext?.previewStage,
69855
+ supabaseUrl,
69856
+ mediaAssets,
69857
+ imageResolveContext: {
69597
69858
  siteId,
69598
- apiBaseUrl,
69599
- portalToken,
69600
- previewToken,
69601
- resolvedData,
69602
- bookingOfferingPresets: bookingOfferingPresets ?? [],
69603
- routes: routeMap,
69604
- pagesByIdentifier,
69605
- entriesByIdentifier,
69606
- occurrenceContext: dataContext?.occurrenceContext ?? null,
69607
- entrySubrouteContext: dataContext?.entrySubrouteContext ?? null,
69608
- contentEntry: dataContext?.contentEntry ?? null,
69609
- pageSurface: dataContext?.pageSurface ?? null,
69610
- subject: dataContext?.subject ?? null,
69611
- editableRouteMetadataFieldIds: dataContext?.editableRouteMetadataFieldIds ?? null,
69612
- previewStage: dataContext?.previewStage,
69613
69859
  supabaseUrl,
69614
- mediaAssets,
69615
- imageResolveContext: {
69616
- siteId,
69617
- supabaseUrl,
69618
- mediaAssets
69619
- }
69620
- },
69621
- routeMap,
69622
- wrapBlock,
69623
- registry,
69624
- blockOverrides,
69625
- sdkConfig: sdkConfig ? { customBlocks: sdkConfig.customBlocks } : null,
69626
- customBlocks
69627
- })
69860
+ mediaAssets
69861
+ }
69862
+ },
69863
+ routeMap,
69864
+ wrapBlock,
69865
+ registry,
69866
+ sdkConfig: sdkConfig ? { customBlocks: sdkConfig.customBlocks } : null,
69867
+ customBlocks
69868
+ };
69869
+ const content = isOverrideOnlyPage(props) ? /* @__PURE__ */ jsx(PageRenderer, {
69870
+ ...rendererCommonProps,
69871
+ rendering: { kind: "overrides-only" },
69872
+ blockOverrides: props.blockOverrides
69873
+ }) : /* @__PURE__ */ jsx(PageRenderer, {
69874
+ ...rendererCommonProps,
69875
+ theme: props.theme,
69876
+ themeTokens: resolvePageThemeTokens(props),
69877
+ blockOverrides
69878
+ });
69879
+ return isOverrideOnlyPage(props) ? renderWithOverrideOnlyRuntime({
69880
+ runtime: props.rendering.runtime,
69881
+ children: content
69882
+ }) : renderWithSdkThemeRuntime({
69883
+ themeRuntime: props.themeRuntime ?? defaultPageThemeRuntime,
69884
+ theme: props.theme,
69885
+ children: content
69628
69886
  });
69629
69887
  }
69630
69888
  //#endregion
@@ -70147,12 +70405,48 @@ function buildLogo(logo, fallbackAlt) {
70147
70405
  return result;
70148
70406
  }
70149
70407
  //#endregion
70408
+ //#region src/rendering/renderingMode.ts
70409
+ const defaultOverrideOnlyRuntime = { kind: "responsive-only" };
70410
+ //#endregion
70150
70411
  //#region src/rendering/components/Layout.tsx
70151
70412
  /**
70152
70413
  * Layout component with header and footer
70153
70414
  *
70154
70415
  * Renders site header and footer around content. Fetches site data if not provided.
70155
70416
  */
70417
+ function isOverrideOnlyLayout(props) {
70418
+ return props.rendering?.kind === "overrides-only";
70419
+ }
70420
+ var UnsupportedOverrideOnlyLayoutChromeError = class extends Error {
70421
+ constructor(surface) {
70422
+ super(`Override-only Layout requires a custom or disabled ${surface}; SDK default chrome is unavailable.`);
70423
+ this.surface = surface;
70424
+ this.code = "unsupported_override_only_layout_chrome";
70425
+ this.name = "UnsupportedOverrideOnlyLayoutChromeError";
70426
+ }
70427
+ };
70428
+ async function resolveLayoutSiteData(props) {
70429
+ if (props.siteData) return props.siteData;
70430
+ if (!props.client) throw new Error("Layout: must provide either siteData or client");
70431
+ if (!props.siteId && !props.slug && !props.domain) throw new Error("Layout: must provide siteId, slug, or domain when using client");
70432
+ return props.client.getSite({
70433
+ id: props.siteId,
70434
+ slug: props.slug,
70435
+ domain: props.domain
70436
+ });
70437
+ }
70438
+ function renderOverrideOnlyLayout(props, data) {
70439
+ if (data.header === true) throw new UnsupportedOverrideOnlyLayoutChromeError("header");
70440
+ if (data.footer === true) throw new UnsupportedOverrideOnlyLayoutChromeError("footer");
70441
+ return renderWithOverrideOnlyRuntime({
70442
+ runtime: props.rendering.runtime ?? defaultOverrideOnlyRuntime,
70443
+ children: /* @__PURE__ */ jsxs(Fragment, { children: [
70444
+ typeof props.header === "function" ? props.header(data.headerData) : null,
70445
+ props.children,
70446
+ typeof props.footer === "function" ? props.footer(data.footerData) : null
70447
+ ] })
70448
+ });
70449
+ }
70156
70450
  /**
70157
70451
  * Layout component that wraps content with site header and footer.
70158
70452
  *
@@ -70188,20 +70482,13 @@ function buildLogo(logo, fallbackAlt) {
70188
70482
  * </Layout>
70189
70483
  * ```
70190
70484
  */
70191
- async function Layout({ siteData: providedSiteData, client, siteId, slug, domain, children, header = true, footer = true, headerVariant, hasPortalSession = false, previewStage = "published", themeRuntime }) {
70192
- let siteData = providedSiteData;
70193
- if (!siteData) {
70194
- if (!client) throw new Error("Layout: must provide either siteData or client");
70195
- if (!siteId && !slug && !domain) throw new Error("Layout: must provide siteId, slug, or domain when using client");
70196
- siteData = await client.getSite({
70197
- id: siteId,
70198
- slug,
70199
- domain
70200
- });
70201
- }
70202
- const { site, theme, navigation, layout, routes } = siteData;
70485
+ async function Layout(props) {
70486
+ const { children, hasPortalSession = false, previewStage = "published" } = props;
70487
+ const header = props.header ?? true;
70488
+ const footer = props.footer ?? true;
70489
+ const siteData = await resolveLayoutSiteData(props);
70490
+ const { site, navigation, layout, routes } = siteData;
70203
70491
  const footerBlocks = siteData.footerBlocks ?? [];
70204
- const builtThemeRuntime = buildThemeRuntime(theme);
70205
70492
  const navigationOptions = {
70206
70493
  hasPortalSession,
70207
70494
  previewStage,
@@ -70215,22 +70502,38 @@ async function Layout({ siteData: providedSiteData, client, siteId, slug, domain
70215
70502
  const footerMenuViewModel = buildFooterMenu(navigation, routes, navigationOptions);
70216
70503
  const legalFooterMenuViewModel = buildFooterMenuForRole(navigation, routes, "legal-policy", navigationOptions);
70217
70504
  const logoViewModel = buildLogo(layout.logo ?? null, site.title);
70218
- const headerData = {
70505
+ const customHeaderData = {
70219
70506
  menu: menuViewModel,
70220
70507
  logo: logoViewModel,
70221
70508
  site,
70222
- theme,
70223
70509
  routes
70224
70510
  };
70225
- const footerData = {
70511
+ const customFooterData = {
70226
70512
  menu: menuViewModel,
70227
70513
  footerMenu: footerMenuViewModel,
70228
70514
  legalFooterMenu: legalFooterMenuViewModel,
70229
70515
  logo: logoViewModel,
70230
70516
  site,
70231
- theme,
70232
70517
  routes
70233
70518
  };
70519
+ if (isOverrideOnlyLayout(props)) return renderOverrideOnlyLayout(props, {
70520
+ header: props.header ?? true,
70521
+ footer: props.footer ?? true,
70522
+ headerData: customHeaderData,
70523
+ footerData: customFooterData
70524
+ });
70525
+ const { theme } = siteData;
70526
+ const builtThemeRuntime = buildThemeRuntime(theme);
70527
+ const headerVariant = props.headerVariant;
70528
+ const themeRuntime = props.themeRuntime;
70529
+ const headerData = {
70530
+ ...customHeaderData,
70531
+ theme
70532
+ };
70533
+ const footerData = {
70534
+ ...customFooterData,
70535
+ theme
70536
+ };
70234
70537
  const headerContent = headerVariant ? {
70235
70538
  ...layout.header,
70236
70539
  variant: headerVariant
@@ -70248,7 +70551,7 @@ async function Layout({ siteData: providedSiteData, client, siteId, slug, domain
70248
70551
  try {
70249
70552
  apiBaseUrl = getRiverbankEnv().baseUrl;
70250
70553
  } catch {}
70251
- const viewModelOverrides = {
70554
+ const sharedViewModelOverrides = {
70252
70555
  $root: {
70253
70556
  siteId: site.id,
70254
70557
  apiBaseUrl,
@@ -70261,14 +70564,24 @@ async function Layout({ siteData: providedSiteData, client, siteId, slug, domain
70261
70564
  site,
70262
70565
  menu: menuViewModel,
70263
70566
  footerMenu: footerMenuViewModel,
70264
- legalFooterMenu: legalFooterMenuViewModel,
70567
+ legalFooterMenu: legalFooterMenuViewModel
70568
+ };
70569
+ const headerViewModelOverrides = {
70570
+ ...sharedViewModelOverrides,
70265
70571
  content: { logo: logoViewModel }
70266
70572
  };
70573
+ const footerViewModelOverrides = {
70574
+ ...sharedViewModelOverrides,
70575
+ content: {
70576
+ ...layout.footer,
70577
+ logo: logoViewModel
70578
+ }
70579
+ };
70267
70580
  let headerElement = null;
70268
70581
  if (header === true) headerElement = renderBlock(siteHeaderManifest, headerContent, {
70269
70582
  theme: builtThemeRuntime.tokens,
70270
70583
  themeConfig: blocksThemeWithVariant,
70271
- viewModelOverrides
70584
+ viewModelOverrides: headerViewModelOverrides
70272
70585
  });
70273
70586
  else if (typeof header === "function") headerElement = header(headerData);
70274
70587
  let footerElement = null;
@@ -70303,7 +70616,7 @@ async function Layout({ siteData: providedSiteData, client, siteId, slug, domain
70303
70616
  const defaultFooterElement = footerPlan.renderDefaultFooter ? renderBlock(siteFooterManifest, layout.footer, {
70304
70617
  theme: builtThemeRuntime.tokens,
70305
70618
  themeConfig: blocksTheme,
70306
- viewModelOverrides
70619
+ viewModelOverrides: footerViewModelOverrides
70307
70620
  }) : null;
70308
70621
  footerElement = footerPlan.mode === "default+blocks" ? /* @__PURE__ */ jsxs(Fragment, { children: [footerBlocksElement, defaultFooterElement] }) : footerPlan.mode === "blocks" ? footerBlocksElement : footerPlan.mode === "none" ? null : defaultFooterElement;
70309
70622
  } else if (typeof footer === "function") footerElement = footer(footerData);
@@ -70631,6 +70944,7 @@ const SUPPORTED_LOADER_ENDPOINTS$1 = [
70631
70944
  "listPublicRecurringSchedule",
70632
70945
  "getPublicEventDetails",
70633
70946
  "listPublicWholeSeriesOfferings",
70947
+ "getPublicWholeSeriesOffering",
70634
70948
  "listPublicRouteCandidates",
70635
70949
  "listPublicTeamMembers",
70636
70950
  "listPublicProducts",
@@ -73366,6 +73680,7 @@ const loaderAdapters = {
73366
73680
  listPublicEvents,
73367
73681
  listPublicRecurringSchedule,
73368
73682
  getPublicEventDetails,
73683
+ getPublicWholeSeriesOffering,
73369
73684
  listPublicRouteCandidates,
73370
73685
  listPublicTeamMembers,
73371
73686
  listPublicProducts,
@@ -73460,6 +73775,13 @@ async function listPublicEvents({ client, params }) {
73460
73775
  async function listPublicRecurringSchedule(input) {
73461
73776
  return projectRecurringSchedule(await listPublicEvents(input));
73462
73777
  }
73778
+ async function getPublicWholeSeriesOffering({ client, params }) {
73779
+ return await client.getPublicWholeSeriesOffering({
73780
+ siteId: requireStringParam(params, "siteId", "getPublicWholeSeriesOffering"),
73781
+ eventSeriesId: requireStringParam(params, "eventSeriesId", "getPublicWholeSeriesOffering"),
73782
+ stage: readStringParam(params, "stage")
73783
+ });
73784
+ }
73463
73785
  async function getPublicEventDetails({ client, params }) {
73464
73786
  return await client.getPublicEventDetails({
73465
73787
  siteId: requireStringParam(params, "siteId", "getPublicEventDetails"),
@@ -73611,6 +73933,17 @@ async function prefetchBlockDataWithDeps(deps, page, context, client, options) {
73611
73933
  * hydration; the strict `@riverbankcms/sdk/rendering/server` surface exports it
73612
73934
  * directly.
73613
73935
  */
73936
+ function isOverrideOnlyBlock(props) {
73937
+ return props.rendering?.kind === "overrides-only";
73938
+ }
73939
+ var MissingStandaloneBlockOverrideError = class extends Error {
73940
+ constructor(blockKind) {
73941
+ super(`Override-only standalone rendering requires an override for block kind "${blockKind}".`);
73942
+ this.blockKind = blockKind;
73943
+ this.code = "missing_standalone_block_override";
73944
+ this.name = "MissingStandaloneBlockOverrideError";
73945
+ }
73946
+ };
73614
73947
  function toBlockHydrationBootstrapConfig(props) {
73615
73948
  return {
73616
73949
  siteId: props.siteId,
@@ -73680,14 +74013,16 @@ function buildStandaloneBlockViewModel({ siteId, pageId, previewStage, apiBaseUr
73680
74013
  function renderBlockOverride({ OverrideComponent, props, runtime, resolvedData }) {
73681
74014
  return /* @__PURE__ */ jsx(OverrideComponent, {
73682
74015
  content: props.content,
73683
- theme: runtime.themeRuntime.tokens,
73684
- themeConfig: props.theme,
74016
+ ...runtime && "theme" in props ? {
74017
+ theme: runtime.themeRuntime.tokens,
74018
+ themeConfig: props.theme
74019
+ } : {},
73685
74020
  data: resolvedData,
73686
74021
  siteId: props.siteId,
73687
74022
  apiBaseUrl: props.apiBaseUrl,
73688
74023
  portalToken: props.portalToken ?? null,
73689
74024
  supabaseUrl: props.supabaseUrl,
73690
- imageResolveContext: runtime.imageResolveContext,
74025
+ imageResolveContext: runtime?.imageResolveContext,
73691
74026
  blockId: props.blockId ?? null,
73692
74027
  blockKind: props.blockKind
73693
74028
  });
@@ -73716,8 +74051,8 @@ function renderManifestBlock({ definition, props, runtime, resolvedData }) {
73716
74051
  async function BlockContent(props) {
73717
74052
  const definition = getBlockDefinition(props.blockKind);
73718
74053
  const OverrideComponent = props.override;
74054
+ if (isOverrideOnlyBlock(props) && !OverrideComponent) throw new MissingStandaloneBlockOverrideError(props.blockKind);
73719
74055
  if (!definition && !OverrideComponent) return renderUnknownBlock(props.blockKind);
73720
- const runtime = buildBlockContentRuntime(props);
73721
74056
  const resolvedData = await loadStandaloneBlockData({
73722
74057
  ...props,
73723
74058
  hasDefinition: Boolean(definition)
@@ -73725,13 +74060,14 @@ async function BlockContent(props) {
73725
74060
  if (OverrideComponent) return renderBlockOverride({
73726
74061
  OverrideComponent,
73727
74062
  props,
73728
- runtime,
74063
+ runtime: isOverrideOnlyBlock(props) ? void 0 : buildBlockContentRuntime(props),
73729
74064
  resolvedData
73730
74065
  });
74066
+ if (isOverrideOnlyBlock(props)) throw new MissingStandaloneBlockOverrideError(props.blockKind);
73731
74067
  return renderManifestBlock({
73732
74068
  definition,
73733
74069
  props,
73734
- runtime,
74070
+ runtime: buildBlockContentRuntime(props),
73735
74071
  resolvedData
73736
74072
  });
73737
74073
  }
@@ -77536,4 +77872,4 @@ function defineBlockOverrideRegistrations(registrations) {
77536
77872
  * ```
77537
77873
  */
77538
77874
  //#endregion
77539
- export { Block, ImagePresets, Layout, Page, PageRenderer, RichText, ThemeScope, buildThemeRuntime, defineBlockOverrideRegistrations, defineBlockOverrides, defineLazyBlockOverride, isEntryContent, isPageContent, isPageSurfaceContent, loadContent, loadPage, resolveImageSourceSetWithContext, resolveImageUrl, resolveImageUrlWithContext };
77875
+ export { Block, ImagePresets, Layout, MissingBlockOverrideError, Page, PageRenderer, RichText, ThemeScope, UnsupportedOverrideOnlyLayoutChromeError, buildThemeRuntime, defineBlockOverrideRegistrations, defineBlockOverrides, defineLazyBlockOverride, isEntryContent, isPageContent, isPageSurfaceContent, loadContent, loadPage, resolveImageSourceSetWithContext, resolveImageUrl, resolveImageUrlWithContext, toBlocksImageResolveContextInput, toBlocksMediaAssets, toBlocksPageRendererDataContext };