@riverbankcms/sdk 0.145.0 → 0.146.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 (159) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/dist/{PreviewEditorSidebar-O-V6Pl5a.mjs → PreviewEditorSidebar-kg2r2Fyi.mjs} +4 -4
  3. package/dist/{PreviewEditorUI-1UlX_9cw.mjs → PreviewEditorUI-sWMLp5dT.mjs} +3 -3
  4. package/dist/{PreviewQueryProvider-BxGwdOCV.mjs → PreviewQueryProvider-Cg51xq1w.mjs} +1 -1
  5. package/dist/{SdkPreviewModeRuntime-DYbA_4iv.mjs → SdkPreviewModeRuntime-h2ti3Hch.mjs} +280 -182
  6. package/dist/{SiteChromeCustomizeContext-CNTKQ9nx.mjs → SiteChromeCustomizeContext-DEACFH9m.mjs} +1330 -734
  7. package/dist/_dts/ai/src/contracts/proposals.d.ts +924 -0
  8. package/dist/_dts/ai/src/contracts/siteStyleProposalSchemas.d.ts +84 -0
  9. package/dist/_dts/api/src/bookingConfig.d.ts +8 -1
  10. package/dist/_dts/api/src/bookingManagementEndpoints.d.ts +8 -14
  11. package/dist/_dts/api/src/bookingManagementEventEndpointTypes.d.ts +45 -1
  12. package/dist/_dts/api/src/clientErrorReporting.d.ts +50 -0
  13. package/dist/_dts/api/src/communications.d.ts +20 -4
  14. package/dist/_dts/api/src/contentRuntime.d.ts +3 -7
  15. package/dist/_dts/api/src/endpoints.d.ts +223 -88
  16. package/dist/_dts/api/src/event-visibility.d.ts +20 -0
  17. package/dist/_dts/api/src/eventManagementContracts.d.ts +56 -3
  18. package/dist/_dts/api/src/eventManagementEndpointDefinitions.d.ts +24 -0
  19. package/dist/_dts/api/src/eventPageWords.d.ts +19 -0
  20. package/dist/_dts/api/src/eventSeriesRegistrationEndpointDefinitions.d.ts +14 -0
  21. package/dist/_dts/api/src/index.d.ts +7 -1
  22. package/dist/_dts/api/src/indexCoreTypes.d.ts +1 -1
  23. package/dist/_dts/api/src/indexExtendedTypes.d.ts +1 -1
  24. package/dist/_dts/api/src/launchReadiness.d.ts +20 -2
  25. package/dist/_dts/api/src/launchRequirementPriority.d.ts +3 -0
  26. package/dist/_dts/api/src/newsletterCampaignCommandEndpoints.d.ts +13 -0
  27. package/dist/_dts/api/src/newsletterEndpointDefinitions.d.ts +42 -0
  28. package/dist/_dts/api/src/occurrenceScheduling.d.ts +10 -0
  29. package/dist/_dts/api/src/pageSurfaceEndpoints.d.ts +44 -0
  30. package/dist/_dts/api/src/participantMessaging.d.ts +11 -1
  31. package/dist/_dts/api/src/sdk-event-upsert.d.ts +40 -1
  32. package/dist/_dts/api/src/sdkContracts.d.ts +3 -42
  33. package/dist/_dts/api/src/sdkCourseBooking.d.ts +30 -0
  34. package/dist/_dts/api/src/sdkEventEndpointDefinitions.d.ts +76 -0
  35. package/dist/_dts/api/src/sdkEventLifecycle.d.ts +37 -0
  36. package/dist/_dts/api/src/sdkManagedEventContracts.d.ts +18 -0
  37. package/dist/_dts/api/src/sdkPageDesign.d.ts +388 -0
  38. package/dist/_dts/api/src/sdkPageDesignEndpointDefinitions.d.ts +22 -0
  39. package/dist/_dts/api/src/sdkPullEventContracts.d.ts +46 -0
  40. package/dist/_dts/api/src/siteAddressEndpoints.d.ts +29 -0
  41. package/dist/_dts/api/src/siteManagementEndpointDefinitions.d.ts +49 -0
  42. package/dist/_dts/api/src/siteManagementEndpoints.d.ts +2 -32
  43. package/dist/_dts/api/src/siteOnboarding.d.ts +75 -9
  44. package/dist/_dts/api/src/sitePlatformEndpoints.d.ts +1 -1
  45. package/dist/_dts/api/src/types.d.ts +7 -1
  46. package/dist/_dts/api/src/wholeSeriesRuns.d.ts +14 -0
  47. package/dist/_dts/blocks/src/index.d.ts +2 -0
  48. package/dist/_dts/blocks/src/pageRenderAdmission.d.ts +10 -0
  49. package/dist/_dts/blocks/src/pageRendererContracts.d.ts +3 -1
  50. package/dist/_dts/blocks/src/system/blocks/events/shared/schemas.d.ts +27 -5
  51. package/dist/_dts/blocks/src/system/blocks/events/shared/types.d.ts +14 -1
  52. package/dist/_dts/blocks/src/system/icons/social.d.ts +1 -1
  53. package/dist/_dts/blocks/src/system/registry.d.ts +1 -1
  54. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/eventSourceRecovery.d.ts +1 -0
  55. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/eventCollectionContract.d.ts +20 -4
  56. package/dist/_dts/blocks/src/system/runtime/nodes/form.fields.d.ts +5 -0
  57. package/dist/_dts/blocks/src/system/runtime/nodes/newsletter-form.block-submission.d.ts +36 -0
  58. package/dist/_dts/blocks/src/system/runtime/nodes/newsletter-form.client.d.ts +1 -1
  59. package/dist/_dts/blocks/src/system/runtime/nodes/newsletter-form.interactive.d.ts +6 -1
  60. package/dist/_dts/blocks/src/system/runtime/nodes/newsletter-form.parts.d.ts +46 -0
  61. package/dist/_dts/blocks/src/system/runtime/nodes/newsletter-form.types.d.ts +2 -1
  62. package/dist/_dts/blocks/src/system/runtime/resolver.d.ts +2 -1
  63. package/dist/_dts/blocks/src/system/runtime/shared/components/CheckboxChoice.d.ts +18 -0
  64. package/dist/_dts/blocks/src/system/runtime/shared/components/index.d.ts +1 -0
  65. package/dist/_dts/content-editor/src/index.d.ts +1 -0
  66. package/dist/_dts/content-editor/src/primitives/previewEditableOutline.d.ts +2 -0
  67. package/dist/_dts/content-editor/src/ui/editorBlockEquality.d.ts +3 -0
  68. package/dist/_dts/content-editor/src/ui/editorSnapshot.d.ts +3 -5
  69. package/dist/_dts/core/src/block-content-identity.d.ts +5 -0
  70. package/dist/_dts/core/src/editor-state.d.ts +2 -7
  71. package/dist/_dts/core/src/index.d.ts +1 -0
  72. package/dist/_dts/core/src/mailing-list-submission.d.ts +3 -1
  73. package/dist/_dts/core/src/public-event-booking-availability.d.ts +20 -1
  74. package/dist/_dts/core/src/public-profile.d.ts +3 -1
  75. package/dist/_dts/db/src/generated/supabase/database.types.d.ts +49 -2
  76. package/dist/_dts/editor-blocks/src/BlockEditor.d.ts +3 -0
  77. package/dist/_dts/editor-blocks/src/block-editor/EmptyState.d.ts +13 -1
  78. package/dist/_dts/editor-blocks/src/block-editor/types.d.ts +2 -8
  79. package/dist/_dts/editor-blocks/src/index.d.ts +1 -0
  80. package/dist/_dts/preview-next/src/client/blocks/composer/types.d.ts +3 -4
  81. package/dist/_dts/preview-next/src/client/preview/PreviewEntryControllerProvider.d.ts +1 -2
  82. package/dist/_dts/sdk/src/next/renderSdkContent.d.ts +0 -1
  83. package/dist/_dts/sdk/src/rendering/blocks-page-renderer.d.ts +2 -2
  84. package/dist/_dts/sdk/src/rendering/components/pageShared.d.ts +2 -2
  85. package/dist/_dts/sdk/src/rendering/helpers/loadContent.d.ts +6 -1
  86. package/dist/_dts/sdk/src/rendering/helpers/loadPage.d.ts +5 -2
  87. package/dist/_dts/sdk/src/rendering/helpers/pageRuntimeSupport.d.ts +6 -1
  88. package/dist/_dts/sdk/src/rendering/helpers/templateContent.d.ts +2 -0
  89. package/dist/_dts/sdk/src/rendering/hooks/useContent.d.ts +5 -1
  90. package/dist/_dts/sdk/src/rendering/hooks/usePage.d.ts +5 -1
  91. package/dist/_dts/sdk/src/version.d.ts +1 -1
  92. package/dist/_dts/surfaces/src/index.d.ts +9 -0
  93. package/dist/_dts/theme-core/src/generated/containerResponsiveThemeCss.d.ts +1 -1
  94. package/dist/_dts/theme-core/src/inputs/checkable.d.ts +42 -0
  95. package/dist/_dts/theme-core/src/inputs/inputGroup.d.ts +19 -0
  96. package/dist/_dts/ui/src/navigation-tabs.d.ts +2 -1
  97. package/dist/client/{BookingConsentAgreement-DlVOmpW4.mjs → BookingConsentAgreement-BQKL045f.mjs} +2 -2
  98. package/dist/client/CheckboxChoice--W2n6yKs.mjs +24 -0
  99. package/dist/client/{DiscountCodeDisclosure-T9q623PQ.mjs → DiscountCodeDisclosure-CsOtjFY7.mjs} +1 -1
  100. package/dist/client/{EventCombined.client-DnsUeONl.mjs → EventCombined.client-BdRjVbhH.mjs} +6 -6
  101. package/dist/client/{EventListing.client-CNBFqJS4.mjs → EventListing.client-DBxC6xOU.mjs} +2 -2
  102. package/dist/client/{LeafletStaticMap-C7higg52.mjs → LeafletStaticMap-mHEJKrTs.mjs} +1 -1
  103. package/dist/client/{ThemedButton-LAJTNrS8.mjs → ThemedButton-CE5KYT6z.mjs} +1 -1
  104. package/dist/client/{accordion-BcNF9TjX.mjs → accordion-BEQNSptH.mjs} +1 -1
  105. package/dist/client/{bookingForm-BUaQ3S03.mjs → bookingForm-AMr-s5vw.mjs} +33 -52
  106. package/dist/client/bookings.mjs +48 -46
  107. package/dist/client/{carousel-CTdF6e0V.mjs → carousel-Bbt_QgJy.mjs} +1 -1
  108. package/dist/client/{cart-pGtyf_XU.mjs → cart-CnWi30zJ.mjs} +3 -3
  109. package/dist/client/{checkout-Da9WSn7Y.mjs → checkout-f3nkWgd4.mjs} +3 -3
  110. package/dist/client/client.mjs +1611 -815
  111. package/dist/client/{context-BFeY_Wbm.mjs → context-Bc8T6pCe.mjs} +1 -1
  112. package/dist/client/{dates-BhwVSxDg.mjs → dates-DUsCEzLb.mjs} +2 -3
  113. package/dist/client/{eventCalendar-BAtdnR4s.mjs → eventCalendar-CKwgXui5.mjs} +9 -9
  114. package/dist/client/{eventCombined-RksA3tRC.mjs → eventCombined-CBAOSTGR.mjs} +4 -4
  115. package/dist/client/{eventDetails-BB9hB4wR.mjs → eventDetails-Dh-_WiBD.mjs} +4 -4
  116. package/dist/client/{eventListing-BpJBkviM.mjs → eventListing-CA3frIH5.mjs} +4 -4
  117. package/dist/client/{eventRegistration-B18jFq_o.mjs → eventRegistration-BHtsgdcg.mjs} +21 -22
  118. package/dist/client/{form-Dodt8Y8t.mjs → form-C2h3YAcg.mjs} +135 -104
  119. package/dist/client/{headerSection-B0qj9ttg.mjs → headerSection-lwMuMTH9.mjs} +3 -3
  120. package/dist/client/hooks.mjs +489 -65
  121. package/dist/client/{locationMap-gn-iMk7a.mjs → locationMap-DJ2bLODV.mjs} +3 -3
  122. package/dist/client/{newsletterForm-oByLdFkr.mjs → newsletterForm-8Pu5K32g.mjs} +203 -101
  123. package/dist/client/{pricing-BOU0_Hai.mjs → pricing-HHx3IgBz.mjs} +1 -1
  124. package/dist/client/{productDetail-D9v1zH2j.mjs → productDetail-C_1odnAf.mjs} +3 -3
  125. package/dist/client/{productList-D-mItx1n.mjs → productList-CtCv-Nmx.mjs} +3 -3
  126. package/dist/client/{propsDecoder-C3TP_z4x.mjs → propsDecoder-Dcgsncxb.mjs} +40 -23
  127. package/dist/client/rendering/client.mjs +490 -457
  128. package/dist/client/rendering/islands.mjs +17 -17
  129. package/dist/client/rendering.mjs +1515 -628
  130. package/dist/client/{routeIslandApiConfig-DzN1W0sq.mjs → routeIslandApiConfig-CWLP7wu3.mjs} +1 -1
  131. package/dist/client/{scrollToBlock-CWs8EIdo.mjs → scrollToBlock-BNgaEUpo.mjs} +1 -1
  132. package/dist/client/{shop-Dufw7N7o.mjs → shop-DQXrQ8kJ.mjs} +7 -7
  133. package/dist/client/{shop-commerce-gklw_hLF.mjs → shop-commerce-B88zmWWo.mjs} +6 -6
  134. package/dist/client/{shop-commerce-store-Sf1eyTaZ.mjs → shop-commerce-store-DtSfkKuX.mjs} +1 -1
  135. package/dist/client/{shopShared-B5nyA41S.mjs → shopShared-cuaONpkJ.mjs} +4 -4
  136. package/dist/client/{useEventFilters-CLL829vy.mjs → useEventFilters-Bukew6Gb.mjs} +6 -6
  137. package/dist/preview-next/before-render.mjs +368 -103
  138. package/dist/preview-next/client/runtime.mjs +4 -4
  139. package/dist/preview-next/editor-base.css +11 -0
  140. package/dist/preview-next/keepAlive.mjs +328 -103
  141. package/dist/preview-next/middleware.mjs +329 -103
  142. package/dist/{previewAuthStore-BxAFlu-j.mjs → previewAuthStore-h5IgbSp4.mjs} +353 -103
  143. package/dist/{sdk-runtime-D0uZFev7.mjs → sdk-runtime-DTc1uIXn.mjs} +2 -2
  144. package/dist/{separator-EvdCAn4V.mjs → separator-BpHS1KZK.mjs} +1 -1
  145. package/dist/server/components.mjs +1376 -331
  146. package/dist/server/config-validation.mjs +405 -27
  147. package/dist/server/config.mjs +405 -27
  148. package/dist/server/data.mjs +405 -27
  149. package/dist/server/index.mjs +370 -104
  150. package/dist/server/next.mjs +1430 -463
  151. package/dist/server/page-converter.mjs +36 -25
  152. package/dist/server/prebuild.mjs +1 -1
  153. package/dist/server/rendering/server.mjs +1374 -331
  154. package/dist/server/rendering.mjs +1436 -364
  155. package/dist/server/routing.mjs +476 -43
  156. package/dist/server/server.mjs +504 -169
  157. package/dist/server/theme-bridge.mjs +467 -111
  158. package/dist/styles/index.css +186 -65
  159. package/package.json +1 -1
@@ -2049,6 +2049,27 @@ function formError(field) {
2049
2049
  field
2050
2050
  });
2051
2051
  }
2052
+ //#endregion
2053
+ //#region ../core/src/mailing-list-targeting.ts
2054
+ function sameMailingListPlacementTargeting(left, right) {
2055
+ if (left.mode !== right.mode) return false;
2056
+ if (left.mode === "default" || right.mode === "default") return true;
2057
+ if (left.provider !== right.provider || left.selection.tag !== right.selection.tag) return false;
2058
+ if (left.provider === "mailchimp" && (right.provider !== "mailchimp" || left.audienceId !== right.audienceId)) return false;
2059
+ return sameIds(targetingSelectionIds(left), targetingSelectionIds(right));
2060
+ }
2061
+ function targetingSelectionIds(targeting) {
2062
+ switch (targeting.provider) {
2063
+ case "native": return targeting.selection.tag === "fixed" ? targeting.selection.topicIds : targeting.selection.offeredTopicIds;
2064
+ case "brevo": return targeting.selection.tag === "fixed" ? targeting.selection.listIds : targeting.selection.offeredListIds;
2065
+ case "mailchimp": return targeting.selection.tag === "fixed" ? targeting.selection.interestIds : targeting.selection.offeredInterestIds;
2066
+ }
2067
+ }
2068
+ function sameIds(left, right) {
2069
+ const leftIds = new Set(left);
2070
+ const rightIds = new Set(right);
2071
+ return leftIds.size === left.length && rightIds.size === right.length && leftIds.size === rightIds.size && [...leftIds].every((id) => rightIds.has(id));
2072
+ }
2052
2073
  function planMailingListChoicePresentation(targeting) {
2053
2074
  if (targeting.mode === "default" || targeting.selection.tag === "fixed") return { tag: "hidden" };
2054
2075
  switch (targeting.provider) {
@@ -13217,6 +13238,7 @@ const publicEventLoaderQuerySchemaShape = {
13217
13238
  seriesSlug: z$1.string().optional(),
13218
13239
  includeOccurrenceId: z$1.string().optional(),
13219
13240
  readIntent: z$1.string().optional(),
13241
+ detailAdmission: z$1.string().optional(),
13220
13242
  detailLevel: z$1.string().optional(),
13221
13243
  readProfile: z$1.string().optional()
13222
13244
  };
@@ -13383,11 +13405,11 @@ const publicEventBookingAvailabilitySchema = z$1.discriminatedUnion("kind", [z$1
13383
13405
  "series_archived",
13384
13406
  "parent_archived",
13385
13407
  "parent_inconsistent",
13386
- "not_public",
13387
13408
  "already_started",
13388
13409
  "enrollment_closed"
13389
13410
  ])
13390
13411
  })]);
13412
+ const publicEventBookingClosedDetailSchema = z$1.discriminatedUnion("kind", [z$1.object({ kind: z$1.literal("opensSoon") }), z$1.object({ kind: z$1.literal("paused") })]);
13391
13413
  const publicRunSessionSchema = z$1.object({
13392
13414
  occurrenceId: z$1.string(),
13393
13415
  startsAt: z$1.string(),
@@ -13432,6 +13454,7 @@ const publicEventBaseSchema = z$1.object({
13432
13454
  destination: publicEventDestinationSchema,
13433
13455
  requiresRegistration: z$1.boolean(),
13434
13456
  bookingAvailability: publicEventBookingAvailabilitySchema,
13457
+ bookingClosedDetail: publicEventBookingClosedDetailSchema.optional(),
13435
13458
  deliveryMode: z$1.enum([
13436
13459
  "in_person",
13437
13460
  "online",
@@ -28643,7 +28666,6 @@ function closedEventBookingLabel(reason) {
28643
28666
  case "series_archived":
28644
28667
  case "parent_archived":
28645
28668
  case "parent_inconsistent":
28646
- case "not_public":
28647
28669
  case "already_started":
28648
28670
  case "enrollment_closed": return "Registration closed";
28649
28671
  default: return assertNever$20(reason);
@@ -31405,6 +31427,7 @@ const SOCIAL_ICON_NAMES = [
31405
31427
  "SocialInstagram",
31406
31428
  "SocialLinkedIn",
31407
31429
  "SocialTikTok",
31430
+ "SocialWhatsApp",
31408
31431
  "SocialX",
31409
31432
  "SocialYouTube"
31410
31433
  ];
@@ -31441,6 +31464,7 @@ const socialIcons = {
31441
31464
  /* @__PURE__ */ jsx("path", { d: "M10.5 9v10" })
31442
31465
  ] })),
31443
31466
  SocialTikTok: createIcon("SocialTikTokIcon", /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("path", { d: "M14 4v11.5a4.5 4.5 0 1 1-4-4.47" }), /* @__PURE__ */ jsx("path", { d: "M14 4c.7 3 2.4 4.5 5 4.5" })] })),
31467
+ SocialWhatsApp: createIcon("SocialWhatsAppIcon", /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("path", { d: "M3.5 20.5 4.8 16.4A8.5 8.5 0 1 1 8 19.3Z" }), /* @__PURE__ */ jsx("path", { d: "M9.2 8.2c.2-.5.9-.6 1.2-.1l.8 1.4c.2.3.1.7-.2 1l-.5.5c.5 1.1 1.4 2 2.5 2.5l.5-.5c.3-.3.7-.4 1-.2l1.4.8c.5.3.4 1-.1 1.2-2.9 1.1-7.7-3.7-6.6-6.6Z" })] })),
31444
31468
  SocialX: createIcon("SocialXIcon", /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("path", { d: "m5 4 14 16" }), /* @__PURE__ */ jsx("path", { d: "M19 4 5 20" })] })),
31445
31469
  SocialYouTube: createIcon("SocialYouTubeIcon", /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("path", { d: "M21 12c0 3.5-.5 5.5-1.3 6.3S16.5 19.5 12 19.5s-6.9-.4-7.7-1.2S3 15.5 3 12s.5-5.5 1.3-6.3S7.5 4.5 12 4.5s6.9.4 7.7 1.2S21 8.5 21 12Z" }), /* @__PURE__ */ jsx("path", { d: "m10 9 5 3-5 3Z" })] }))
31446
31470
  };
@@ -33340,6 +33364,12 @@ function withOptionalPhone(fields, includePhone) {
33340
33364
  }
33341
33365
  //#endregion
33342
33366
  //#region ../blocks/src/system/runtime/nodes/newsletter-form.interactive.ts
33367
+ const NEWSLETTER_SIGNUPS_PAUSED_MESSAGE = "We can’t accept signups right now. Please try again later.";
33368
+ function newsletterBlockSubmissionMessage(target) {
33369
+ if (target.tag === "block-source") return target.sourceRef ? null : NEWSLETTER_SIGNUPS_PAUSED_MESSAGE;
33370
+ if (target.tag !== "unpublished-preview") return null;
33371
+ return target.reason === "unpublished-form" ? "Publish this form to test a signup here." : "This form's signup settings are unpublished. Publish it to test a signup here.";
33372
+ }
33343
33373
  const newsletterButtonVariantSchema = blockButtonRoleSchema;
33344
33374
  const mailingListContextSchema = z$1.unknown().transform((value, ctx) => {
33345
33375
  const parsed = parseMailingListRuntimeContext(value);
@@ -33380,6 +33410,11 @@ const mailingListContentVersionIdSchema = z$1.string().transform((value, ctx) =>
33380
33410
  });
33381
33411
  return z$1.NEVER;
33382
33412
  });
33413
+ const mailingListSignupBlockSourceRefSchema = z$1.object({
33414
+ tag: z$1.literal("block_ref"),
33415
+ blockId: mailingListSignupBlockIdSchema,
33416
+ contentVersionId: mailingListContentVersionIdSchema
33417
+ });
33383
33418
  const signedMailingListSourceTokenSchema = z$1.string().trim().min(1).transform(parseRequiredMailingListSignedSourceToken);
33384
33419
  const newsletterSourceCommonSchema = z$1.object({
33385
33420
  siteId: z$1.string().optional(),
@@ -33394,7 +33429,15 @@ const newsletterSourceSchema = z$1.discriminatedUnion("source", [
33394
33429
  newsletterSourceCommonSchema.extend({
33395
33430
  source: z$1.literal("block"),
33396
33431
  blockId: z$1.string().nullable().optional(),
33397
- contentVersionId: z$1.string().nullable().optional()
33432
+ newsletterBlockSubmission: z$1.discriminatedUnion("tag", [
33433
+ z$1.object({
33434
+ tag: z$1.literal("ready"),
33435
+ sourceRef: mailingListSignupBlockSourceRefSchema
33436
+ }),
33437
+ z$1.object({ tag: z$1.literal("unpublished-form") }),
33438
+ z$1.object({ tag: z$1.literal("unpublished-settings") }),
33439
+ z$1.object({ tag: z$1.literal("unavailable") })
33440
+ ])
33398
33441
  }),
33399
33442
  newsletterSourceCommonSchema.extend({
33400
33443
  source: z$1.literal("signed-footer"),
@@ -33423,11 +33466,7 @@ const newsletterHydrationSchema = z$1.object({
33423
33466
  target: z$1.discriminatedUnion("tag", [
33424
33467
  z$1.object({
33425
33468
  tag: z$1.literal("block-source"),
33426
- sourceRef: z$1.object({
33427
- tag: z$1.literal("block_ref"),
33428
- blockId: mailingListSignupBlockIdSchema,
33429
- contentVersionId: mailingListContentVersionIdSchema
33430
- }).nullable()
33469
+ sourceRef: mailingListSignupBlockSourceRefSchema.nullable()
33431
33470
  }),
33432
33471
  z$1.object({
33433
33472
  tag: z$1.literal("signed-footer-source"),
@@ -33436,7 +33475,11 @@ const newsletterHydrationSchema = z$1.object({
33436
33475
  token: signedMailingListSourceTokenSchema
33437
33476
  })
33438
33477
  }),
33439
- z$1.object({ tag: z$1.literal("preview") })
33478
+ z$1.object({ tag: z$1.literal("preview") }),
33479
+ z$1.object({
33480
+ tag: z$1.literal("unpublished-preview"),
33481
+ reason: z$1.enum(["unpublished-form", "unpublished-settings"])
33482
+ })
33440
33483
  ]),
33441
33484
  setupRevision: z$1.number().int().positive().nullable(),
33442
33485
  choiceProvider: z$1.enum([
@@ -33505,16 +33548,21 @@ const newsletterFormBlockRuntime = defineProgressiveBlockRuntime({
33505
33548
  });
33506
33549
  function projectNewsletterFormHydrationTarget(source) {
33507
33550
  switch (source.source) {
33508
- case "block": {
33509
- const sourceRef = buildMailingListSignupBlockSourceRef(source.blockId, source.contentVersionId);
33510
- if (sourceRef?.tag === "block_ref") return {
33551
+ case "block": switch (source.newsletterBlockSubmission.tag) {
33552
+ case "unpublished-form":
33553
+ case "unpublished-settings": return {
33554
+ tag: "unpublished-preview",
33555
+ reason: source.newsletterBlockSubmission.tag
33556
+ };
33557
+ case "ready": return {
33511
33558
  tag: "block-source",
33512
- sourceRef
33559
+ sourceRef: source.newsletterBlockSubmission.sourceRef
33513
33560
  };
33514
- return {
33561
+ case "unavailable": return {
33515
33562
  tag: "block-source",
33516
33563
  sourceRef: null
33517
33564
  };
33565
+ default: return assertNever$20(source.newsletterBlockSubmission);
33518
33566
  }
33519
33567
  case "signed-footer": return {
33520
33568
  tag: "signed-footer-source",
@@ -33583,6 +33631,7 @@ function buildNewsletterFormInteractiveIslandProps(props) {
33583
33631
  const decoded = newsletterFormBlockRuntime.contracts.source.decode(props);
33584
33632
  const source = isDecodeSuccess(decoded) ? decoded.value : {
33585
33633
  ...props,
33634
+ ...props.source === "block" ? { newsletterBlockSubmission: { tag: "unavailable" } } : {},
33586
33635
  mailingList: void 0,
33587
33636
  targeting: { mode: "default" }
33588
33637
  };
@@ -35336,6 +35385,13 @@ const EVENT_SERIES_REGISTRATION_ENDPOINT_DEFINITIONS = defineEndpointDefinitions
35336
35385
  errors: [],
35337
35386
  responseKind: "blob"
35338
35387
  },
35388
+ exportEventOfferingRegistrationsCsv: {
35389
+ path: "/sites/{siteId}/bookings/event-offerings/{eventOfferingId}/registrations/export.csv",
35390
+ method: "GET",
35391
+ auth: "user",
35392
+ errors: [],
35393
+ responseKind: "blob"
35394
+ },
35339
35395
  updateEventSeriesRegistration: {
35340
35396
  path: "/sites/{siteId}/bookings/event-series/{seriesId}/registrations/{registrationId}",
35341
35397
  method: "PATCH",
@@ -35346,6 +35402,19 @@ const EVENT_SERIES_REGISTRATION_ENDPOINT_DEFINITIONS = defineEndpointDefinitions
35346
35402
  "resource:not_found",
35347
35403
  "server:internal_error"
35348
35404
  ]
35405
+ },
35406
+ saveEventSeriesRegistrationAnswers: {
35407
+ path: "/sites/{siteId}/bookings/event-series/{seriesId}/registrations/{registrationId}/answers",
35408
+ method: "PUT",
35409
+ auth: "user",
35410
+ responseKind: "json",
35411
+ errors: [
35412
+ "validation:invalid_input",
35413
+ "auth:forbidden",
35414
+ "resource:not_found",
35415
+ "resource:conflict",
35416
+ "server:internal_error"
35417
+ ]
35349
35418
  }
35350
35419
  });
35351
35420
  //#endregion
@@ -35766,6 +35835,30 @@ const NEWSLETTER_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
35766
35835
  responseKind: "json",
35767
35836
  demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN
35768
35837
  },
35838
+ scheduleNewsletterCampaign: {
35839
+ path: "/sites/{siteId}/newsletter/campaigns/{campaignId}/schedule",
35840
+ method: "POST",
35841
+ tags: [TAG_TEMPLATES.site, TAG_TEMPLATES.siteNewsletter],
35842
+ auth: "user",
35843
+ responseKind: "json",
35844
+ demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN
35845
+ },
35846
+ unscheduleNewsletterCampaign: {
35847
+ path: "/sites/{siteId}/newsletter/campaigns/{campaignId}/unschedule",
35848
+ method: "POST",
35849
+ tags: [TAG_TEMPLATES.site, TAG_TEMPLATES.siteNewsletter],
35850
+ auth: "user",
35851
+ responseKind: "json",
35852
+ demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN
35853
+ },
35854
+ stopNewsletterCampaign: {
35855
+ path: "/sites/{siteId}/newsletter/campaigns/{campaignId}/stop",
35856
+ method: "POST",
35857
+ tags: [TAG_TEMPLATES.site, TAG_TEMPLATES.siteNewsletter],
35858
+ auth: "user",
35859
+ responseKind: "json",
35860
+ demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN
35861
+ },
35769
35862
  testSendNewsletterCampaign: {
35770
35863
  path: "/sites/{siteId}/newsletter/campaigns/{campaignId}/test-send",
35771
35864
  method: "POST",
@@ -35776,6 +35869,154 @@ const NEWSLETTER_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
35776
35869
  }
35777
35870
  });
35778
35871
  //#endregion
35872
+ //#region ../api/src/sdkEventEndpointDefinitions.ts
35873
+ /**
35874
+ * The SDK's Event graph: the Events themselves and the occurrences of one run.
35875
+ * Extracted from `endpoints.ts` so this family can be read, and added to, on
35876
+ * its own. New entries here must declare `errors`; the
35877
+ * require-api-endpoint-errors lint enforces that here as in endpoints.ts.
35878
+ */
35879
+ const SDK_EVENT_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
35880
+ sdkListEvents: {
35881
+ path: "/sdk/{siteId}/events",
35882
+ method: "GET",
35883
+ auth: "service",
35884
+ responseKind: "json"
35885
+ },
35886
+ sdkUpsertEvent: {
35887
+ path: "/sdk/{siteId}/events",
35888
+ method: "POST",
35889
+ auth: "service",
35890
+ responseKind: "json",
35891
+ errors: [
35892
+ "validation:invalid_input",
35893
+ "resource:not_found",
35894
+ "resource:conflict",
35895
+ "billing:plan_limit_exceeded",
35896
+ "server:internal_error"
35897
+ ]
35898
+ },
35899
+ sdkGetEvent: {
35900
+ path: "/sdk/{siteId}/events/{identifier}",
35901
+ method: "GET",
35902
+ auth: "service",
35903
+ responseKind: "json"
35904
+ },
35905
+ sdkDeleteEvent: {
35906
+ path: "/sdk/{siteId}/events/{identifier}",
35907
+ method: "DELETE",
35908
+ auth: "service",
35909
+ responseKind: "json",
35910
+ errors: [
35911
+ "resource:not_found",
35912
+ "resource:conflict",
35913
+ "server:internal_error"
35914
+ ]
35915
+ },
35916
+ sdkTakeEventOffline: {
35917
+ path: "/sdk/{siteId}/events/{identifier}/lifecycle",
35918
+ method: "POST",
35919
+ auth: "service",
35920
+ responseKind: "json",
35921
+ errors: [
35922
+ "resource:not_found",
35923
+ "validation:invalid_input",
35924
+ "resource:conflict",
35925
+ "server:internal_error"
35926
+ ]
35927
+ },
35928
+ sdkListEventOccurrences: {
35929
+ path: "/sdk/{siteId}/events/{identifier}/runs/{runIdentifier}/occurrences",
35930
+ method: "GET",
35931
+ auth: "service",
35932
+ responseKind: "json",
35933
+ errors: [
35934
+ "resource:not_found",
35935
+ "validation:invalid_input",
35936
+ "server:internal_error"
35937
+ ]
35938
+ },
35939
+ sdkAddEventOccurrence: {
35940
+ path: "/sdk/{siteId}/events/{identifier}/runs/{runIdentifier}/occurrences",
35941
+ method: "POST",
35942
+ auth: "service",
35943
+ responseKind: "json",
35944
+ errors: [
35945
+ "resource:not_found",
35946
+ "validation:invalid_input",
35947
+ "resource:conflict",
35948
+ "server:internal_error"
35949
+ ]
35950
+ },
35951
+ sdkUpdateEventOccurrence: {
35952
+ path: "/sdk/{siteId}/events/{identifier}/runs/{runIdentifier}/occurrences/{occurrenceId}",
35953
+ method: "PATCH",
35954
+ auth: "service",
35955
+ responseKind: "json",
35956
+ errors: [
35957
+ "resource:not_found",
35958
+ "validation:invalid_input",
35959
+ "resource:conflict",
35960
+ "server:internal_error"
35961
+ ]
35962
+ },
35963
+ sdkCancelEventOccurrence: {
35964
+ path: "/sdk/{siteId}/events/{identifier}/runs/{runIdentifier}/occurrences/{occurrenceId}/cancel",
35965
+ method: "POST",
35966
+ auth: "service",
35967
+ responseKind: "json",
35968
+ errors: [
35969
+ "resource:not_found",
35970
+ "resource:conflict",
35971
+ "server:internal_error"
35972
+ ]
35973
+ },
35974
+ sdkDeleteEventOccurrence: {
35975
+ path: "/sdk/{siteId}/events/{identifier}/runs/{runIdentifier}/occurrences/{occurrenceId}",
35976
+ method: "DELETE",
35977
+ auth: "service",
35978
+ responseKind: "json",
35979
+ errors: [
35980
+ "resource:not_found",
35981
+ "resource:conflict",
35982
+ "server:internal_error"
35983
+ ]
35984
+ }
35985
+ });
35986
+ //#endregion
35987
+ //#region ../api/src/sdkPageDesignEndpointDefinitions.ts
35988
+ /**
35989
+ * SDK management endpoints for a page's draft design (issue 1497), spread into
35990
+ * `ENDPOINT_DEFINITIONS` like the other endpoint-definition modules. New
35991
+ * entries here must declare `errors`, which the require-api-endpoint-errors
35992
+ * lint enforces.
35993
+ */
35994
+ const SDK_PAGE_DESIGN_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
35995
+ sdkGetPageDesign: {
35996
+ path: "/sdk/{siteId}/pages/{identifier}/design",
35997
+ method: "GET",
35998
+ auth: "service",
35999
+ responseKind: "json",
36000
+ errors: [
36001
+ "resource:not_found",
36002
+ "validation:invalid_input",
36003
+ "server:internal_error"
36004
+ ]
36005
+ },
36006
+ sdkSavePageDesign: {
36007
+ path: "/sdk/{siteId}/pages/{identifier}/design",
36008
+ method: "POST",
36009
+ auth: "service",
36010
+ responseKind: "json",
36011
+ errors: [
36012
+ "resource:not_found",
36013
+ "validation:invalid_input",
36014
+ "resource:conflict",
36015
+ "server:internal_error"
36016
+ ]
36017
+ }
36018
+ });
36019
+ //#endregion
35779
36020
  //#region ../api/src/publicEventEndpointDefinitions.ts
35780
36021
  const PUBLIC_EVENT_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
35781
36022
  checkPublicEventRegistrationNextStep: {
@@ -36020,6 +36261,45 @@ const SITE_API_KEY_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
36020
36261
  }
36021
36262
  });
36022
36263
  //#endregion
36264
+ //#region ../api/src/siteManagementEndpointDefinitions.ts
36265
+ const SITE_MANAGEMENT_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
36266
+ createSite: {
36267
+ path: "/sites/manage",
36268
+ method: "POST",
36269
+ tags: ["site"],
36270
+ auth: "user",
36271
+ responseKind: "json"
36272
+ },
36273
+ updateSite: {
36274
+ path: "/sites/manage",
36275
+ method: "PUT",
36276
+ tags: ["site"],
36277
+ auth: "user",
36278
+ responseKind: "json"
36279
+ },
36280
+ changeSiteAddress: {
36281
+ path: "/sites/{siteId}/address",
36282
+ method: "PUT",
36283
+ auth: "user",
36284
+ responseKind: "json",
36285
+ demoMutation: DEMO_MUTATION_BLOCKED_DISABLED
36286
+ },
36287
+ getSiteAddressAvailability: {
36288
+ path: "/sites/{siteId}/address/availability",
36289
+ method: "GET",
36290
+ auth: "user",
36291
+ responseKind: "json"
36292
+ },
36293
+ deleteSite: {
36294
+ path: "/sites/{siteId}",
36295
+ method: "DELETE",
36296
+ tags: ["site", "site-{siteId}"],
36297
+ auth: "user",
36298
+ responseKind: "json",
36299
+ demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN
36300
+ }
36301
+ });
36302
+ //#endregion
36023
36303
  //#region ../api/src/eventManagementEndpointDefinitions.ts
36024
36304
  const EVENT_MANAGEMENT_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
36025
36305
  listEvents: {
@@ -36067,6 +36347,28 @@ const EVENT_MANAGEMENT_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
36067
36347
  "server:internal_error"
36068
36348
  ]
36069
36349
  },
36350
+ /**
36351
+ * The web address of an event's own page. A course page belongs to the
36352
+ * event itself, so its address is written here rather than through a run.
36353
+ */
36354
+ updateEventAddress: {
36355
+ path: "/sites/{siteId}/bookings/events/{eventId}/address",
36356
+ method: "PATCH",
36357
+ tags: [
36358
+ "site-{siteId}",
36359
+ "event-series-{siteId}",
36360
+ TAG_TEMPLATES.siteRoutableContent,
36361
+ TAG_TEMPLATES.siteRedirects
36362
+ ],
36363
+ auth: "user",
36364
+ responseKind: "json",
36365
+ errors: [
36366
+ "validation:invalid_input",
36367
+ "resource:not_found",
36368
+ "resource:conflict",
36369
+ "server:internal_error"
36370
+ ]
36371
+ },
36070
36372
  createWholeSeriesRun: {
36071
36373
  path: "/sites/{siteId}/bookings/events/{eventId}/runs",
36072
36374
  method: "POST",
@@ -36093,6 +36395,20 @@ const EVENT_MANAGEMENT_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
36093
36395
  "server:internal_error"
36094
36396
  ]
36095
36397
  },
36398
+ updateCourseBookingSettings: {
36399
+ path: "/sites/{siteId}/bookings/events/{eventId}/booking-settings",
36400
+ method: "PATCH",
36401
+ tags: ["site-{siteId}", "event-series-{siteId}"],
36402
+ auth: "user",
36403
+ responseKind: "json",
36404
+ errors: [
36405
+ "validation:invalid_input",
36406
+ "auth:forbidden",
36407
+ "resource:not_found",
36408
+ "resource:conflict",
36409
+ "server:internal_error"
36410
+ ]
36411
+ },
36096
36412
  cancelWholeSeriesRun: {
36097
36413
  path: "/sites/{siteId}/bookings/events/{eventId}/runs/{runId}/cancellation",
36098
36414
  method: "POST",
@@ -36105,6 +36421,28 @@ const EVENT_MANAGEMENT_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
36105
36421
  "resource:conflict",
36106
36422
  "server:internal_error"
36107
36423
  ]
36424
+ },
36425
+ /**
36426
+ * The Content tab's one write: the short introduction, image and
36427
+ * description of an event's page, published without its layout.
36428
+ */
36429
+ saveEventPageWords: {
36430
+ path: "/sites/{siteId}/page-surfaces/{pageSurfaceId}/words",
36431
+ method: "PUT",
36432
+ tags: [
36433
+ TAG_TEMPLATES.siteCollection,
36434
+ TAG_TEMPLATES.siteRoutableContent,
36435
+ TAG_TEMPLATES.pageSurfaceById
36436
+ ],
36437
+ auth: "user",
36438
+ responseKind: "json",
36439
+ errors: [
36440
+ "auth:forbidden",
36441
+ "validation:invalid_input",
36442
+ "resource:not_found",
36443
+ "resource:conflict",
36444
+ "server:internal_error"
36445
+ ]
36108
36446
  }
36109
36447
  });
36110
36448
  //#endregion
@@ -36537,7 +36875,43 @@ const BILLING_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
36537
36875
  responseKind: "json"
36538
36876
  }
36539
36877
  });
36878
+ //#endregion
36879
+ //#region ../api/src/clientErrorReporting.ts
36880
+ const CLIENT_ERROR_REPORT_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({ reportClientError: {
36881
+ path: "/client/error-report",
36882
+ method: "POST",
36883
+ auth: "user",
36884
+ errors: [],
36885
+ responseKind: "json"
36886
+ } });
36887
+ const CLIENT_ERROR_REPORT_LIMITS = {
36888
+ pathname: 1024,
36889
+ name: 120,
36890
+ message: 2e3,
36891
+ stack: 8e3,
36892
+ digest: 128,
36893
+ componentStack: 8e3,
36894
+ sourceLocation: 1024
36895
+ };
36896
+ const clientErrorEventSchema = z$1.enum([
36897
+ "dashboard:route-error",
36898
+ "dashboard:app-error",
36899
+ "client:error-boundary",
36900
+ "client:window-error",
36901
+ "client:unhandled-rejection"
36902
+ ]);
36903
+ z$1.object({
36904
+ event: clientErrorEventSchema,
36905
+ pathname: z$1.string().startsWith("/").max(CLIENT_ERROR_REPORT_LIMITS.pathname),
36906
+ name: z$1.string().max(CLIENT_ERROR_REPORT_LIMITS.name),
36907
+ message: z$1.string().max(CLIENT_ERROR_REPORT_LIMITS.message),
36908
+ stack: z$1.string().max(CLIENT_ERROR_REPORT_LIMITS.stack).nullable(),
36909
+ digest: z$1.string().max(CLIENT_ERROR_REPORT_LIMITS.digest).nullable(),
36910
+ componentStack: z$1.string().max(CLIENT_ERROR_REPORT_LIMITS.componentStack).nullable(),
36911
+ sourceLocation: z$1.string().max(CLIENT_ERROR_REPORT_LIMITS.sourceLocation).nullable()
36912
+ }).strict();
36540
36913
  const API_ENDPOINTS$1 = {
36914
+ ...CLIENT_ERROR_REPORT_ENDPOINT_DEFINITIONS,
36541
36915
  ...PUBLIC_NEWSLETTER_ENDPOINT_DEFINITIONS,
36542
36916
  ...ACCOUNT_ENDPOINT_DEFINITIONS,
36543
36917
  ...PUBLIC_ONBOARDING_ATTEMPT_ENDPOINT_DEFINITIONS,
@@ -36545,6 +36919,7 @@ const API_ENDPOINTS$1 = {
36545
36919
  ...GIFTING_ENDPOINT_DEFINITIONS,
36546
36920
  ...PUBLIC_READ_ENDPOINT_DEFINITIONS,
36547
36921
  ...BILLING_ENDPOINT_DEFINITIONS,
36922
+ ...SITE_MANAGEMENT_ENDPOINT_DEFINITIONS,
36548
36923
  aiContentUpdateChat: {
36549
36924
  path: "/ai/content-update-chat",
36550
36925
  method: "POST",
@@ -37071,13 +37446,6 @@ const API_ENDPOINTS$1 = {
37071
37446
  auth: "user",
37072
37447
  responseKind: "json"
37073
37448
  },
37074
- createSite: {
37075
- path: "/sites/manage",
37076
- method: "POST",
37077
- tags: ["site"],
37078
- auth: "user",
37079
- responseKind: "json"
37080
- },
37081
37449
  createSiteManual: {
37082
37450
  path: "/sites/manual",
37083
37451
  method: "POST",
@@ -37085,21 +37453,6 @@ const API_ENDPOINTS$1 = {
37085
37453
  auth: "user",
37086
37454
  responseKind: "json"
37087
37455
  },
37088
- updateSite: {
37089
- path: "/sites/manage",
37090
- method: "PUT",
37091
- tags: ["site"],
37092
- auth: "user",
37093
- responseKind: "json"
37094
- },
37095
- deleteSite: {
37096
- path: "/sites/{siteId}",
37097
- method: "DELETE",
37098
- tags: ["site", "site-{siteId}"],
37099
- auth: "user",
37100
- responseKind: "json",
37101
- demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN
37102
- },
37103
37456
  listSiteMembers: {
37104
37457
  path: "/sites/{siteId}/members",
37105
37458
  method: "GET",
@@ -41332,6 +41685,7 @@ const API_ENDPOINTS$1 = {
41332
41685
  auth: "service",
41333
41686
  responseKind: "json"
41334
41687
  },
41688
+ ...SDK_PAGE_DESIGN_ENDPOINT_DEFINITIONS,
41335
41689
  sdkUpsertPageBlock: {
41336
41690
  path: "/sdk/{siteId}/pages/{identifier}/blocks",
41337
41691
  method: "POST",
@@ -41454,87 +41808,7 @@ const API_ENDPOINTS$1 = {
41454
41808
  auth: "service",
41455
41809
  responseKind: "json"
41456
41810
  },
41457
- sdkListEvents: {
41458
- path: "/sdk/{siteId}/events",
41459
- method: "GET",
41460
- auth: "service",
41461
- responseKind: "json"
41462
- },
41463
- sdkUpsertEvent: {
41464
- path: "/sdk/{siteId}/events",
41465
- method: "POST",
41466
- auth: "service",
41467
- responseKind: "json"
41468
- },
41469
- sdkGetEvent: {
41470
- path: "/sdk/{siteId}/events/{identifier}",
41471
- method: "GET",
41472
- auth: "service",
41473
- responseKind: "json"
41474
- },
41475
- sdkDeleteEvent: {
41476
- path: "/sdk/{siteId}/events/{identifier}",
41477
- method: "DELETE",
41478
- auth: "service",
41479
- responseKind: "json"
41480
- },
41481
- sdkListEventOccurrences: {
41482
- path: "/sdk/{siteId}/events/{identifier}/runs/{runIdentifier}/occurrences",
41483
- method: "GET",
41484
- auth: "service",
41485
- responseKind: "json",
41486
- errors: [
41487
- "resource:not_found",
41488
- "validation:invalid_input",
41489
- "server:internal_error"
41490
- ]
41491
- },
41492
- sdkAddEventOccurrence: {
41493
- path: "/sdk/{siteId}/events/{identifier}/runs/{runIdentifier}/occurrences",
41494
- method: "POST",
41495
- auth: "service",
41496
- responseKind: "json",
41497
- errors: [
41498
- "resource:not_found",
41499
- "validation:invalid_input",
41500
- "resource:conflict",
41501
- "server:internal_error"
41502
- ]
41503
- },
41504
- sdkUpdateEventOccurrence: {
41505
- path: "/sdk/{siteId}/events/{identifier}/runs/{runIdentifier}/occurrences/{occurrenceId}",
41506
- method: "PATCH",
41507
- auth: "service",
41508
- responseKind: "json",
41509
- errors: [
41510
- "resource:not_found",
41511
- "validation:invalid_input",
41512
- "resource:conflict",
41513
- "server:internal_error"
41514
- ]
41515
- },
41516
- sdkCancelEventOccurrence: {
41517
- path: "/sdk/{siteId}/events/{identifier}/runs/{runIdentifier}/occurrences/{occurrenceId}/cancel",
41518
- method: "POST",
41519
- auth: "service",
41520
- responseKind: "json",
41521
- errors: [
41522
- "resource:not_found",
41523
- "resource:conflict",
41524
- "server:internal_error"
41525
- ]
41526
- },
41527
- sdkDeleteEventOccurrence: {
41528
- path: "/sdk/{siteId}/events/{identifier}/runs/{runIdentifier}/occurrences/{occurrenceId}",
41529
- method: "DELETE",
41530
- auth: "service",
41531
- responseKind: "json",
41532
- errors: [
41533
- "resource:not_found",
41534
- "resource:conflict",
41535
- "server:internal_error"
41536
- ]
41537
- },
41811
+ ...SDK_EVENT_ENDPOINT_DEFINITIONS,
41538
41812
  sdkUpsertEntry: {
41539
41813
  path: "/sdk/{siteId}/entries",
41540
41814
  method: "POST",
@@ -52957,6 +53231,156 @@ function FeedbackMessage({ tone, treatment = "panel", children, className, id, t
52957
53231
  });
52958
53232
  }
52959
53233
  //#endregion
53234
+ //#region ../blocks/src/system/runtime/shared/components/CheckboxChoice.tsx
53235
+ /**
53236
+ * The customer-facing checkbox every block renders. Styling comes from the
53237
+ * theme's input CSS (`.form-check`, `.form-checkbox`), so it follows each
53238
+ * site's input colours, borders and corners.
53239
+ */
53240
+ function CheckboxChoice({ label, presentation = "row", className, ...inputProps }) {
53241
+ return /* @__PURE__ */ jsxs("label", {
53242
+ className: clsx("form-check", presentation === "tile" && "form-check--tile", className),
53243
+ children: [/* @__PURE__ */ jsx("input", {
53244
+ ...inputProps,
53245
+ type: "checkbox",
53246
+ className: "form-checkbox"
53247
+ }), /* @__PURE__ */ jsx("span", {
53248
+ className: "form-check-label",
53249
+ children: label
53250
+ })]
53251
+ });
53252
+ }
53253
+ //#endregion
53254
+ //#region ../blocks/src/system/runtime/nodes/form.fields.tsx
53255
+ function fieldBasics(field) {
53256
+ return {
53257
+ inputId: `f_${field.id}`,
53258
+ label: String(field.label ?? field.id),
53259
+ required: Boolean(field.required)
53260
+ };
53261
+ }
53262
+ function textInputType(type) {
53263
+ return type === "email" || type === "url" || type === "tel" || type === "number" ? type : "text";
53264
+ }
53265
+ function textInputConstraints(field, inputType) {
53266
+ if (inputType === "number") return {
53267
+ ...typeof field.min === "number" ? { min: field.min } : {},
53268
+ ...typeof field.max === "number" ? { max: field.max } : {}
53269
+ };
53270
+ return {
53271
+ ...typeof field.minLength === "number" ? { minLength: field.minLength } : {},
53272
+ ...typeof field.maxLength === "number" ? { maxLength: field.maxLength } : {},
53273
+ ...typeof field.pattern === "string" && field.pattern ? { pattern: field.pattern } : {}
53274
+ };
53275
+ }
53276
+ function LabelledField({ basics, children }) {
53277
+ return /* @__PURE__ */ jsxs("div", {
53278
+ className: "fb-field",
53279
+ children: [/* @__PURE__ */ jsx("label", {
53280
+ htmlFor: basics.inputId,
53281
+ className: "form-label",
53282
+ children: basics.label
53283
+ }), children]
53284
+ });
53285
+ }
53286
+ function TextareaField({ field }) {
53287
+ const basics = fieldBasics(field);
53288
+ return /* @__PURE__ */ jsx(LabelledField, {
53289
+ basics,
53290
+ children: /* @__PURE__ */ jsx("textarea", {
53291
+ id: basics.inputId,
53292
+ name: field.id,
53293
+ required: basics.required,
53294
+ placeholder: field.placeholder,
53295
+ rows: field.rows,
53296
+ className: "form-textarea"
53297
+ })
53298
+ });
53299
+ }
53300
+ function SelectField({ field }) {
53301
+ const basics = fieldBasics(field);
53302
+ const options = field.options ?? [];
53303
+ const multiple = Boolean(field.multiple);
53304
+ return /* @__PURE__ */ jsx(LabelledField, {
53305
+ basics,
53306
+ children: /* @__PURE__ */ jsxs("select", {
53307
+ id: basics.inputId,
53308
+ name: field.id,
53309
+ multiple,
53310
+ required: basics.required,
53311
+ className: "form-select",
53312
+ children: [!multiple && /* @__PURE__ */ jsx("option", {
53313
+ value: "",
53314
+ children: "Select…"
53315
+ }), options.map((opt) => /* @__PURE__ */ jsx("option", {
53316
+ value: opt.value,
53317
+ children: opt.label
53318
+ }, opt.value))]
53319
+ })
53320
+ });
53321
+ }
53322
+ function RadioField({ field }) {
53323
+ const basics = fieldBasics(field);
53324
+ const options = field.options ?? [];
53325
+ return /* @__PURE__ */ jsxs("fieldset", {
53326
+ className: "fb-fieldset",
53327
+ children: [/* @__PURE__ */ jsx("legend", {
53328
+ className: "form-label",
53329
+ children: basics.label
53330
+ }), options.map((opt) => /* @__PURE__ */ jsxs("label", {
53331
+ className: "form-check",
53332
+ children: [/* @__PURE__ */ jsx("input", {
53333
+ type: "radio",
53334
+ name: field.id,
53335
+ value: opt.value,
53336
+ required: basics.required,
53337
+ className: "form-radio"
53338
+ }), /* @__PURE__ */ jsx("span", {
53339
+ className: "form-check-label",
53340
+ children: opt.label
53341
+ })]
53342
+ }, opt.value))]
53343
+ });
53344
+ }
53345
+ function TextInputField({ field, type }) {
53346
+ const basics = fieldBasics(field);
53347
+ const inputType = textInputType(type);
53348
+ return /* @__PURE__ */ jsx(LabelledField, {
53349
+ basics,
53350
+ children: /* @__PURE__ */ jsx("input", {
53351
+ id: basics.inputId,
53352
+ name: field.id,
53353
+ type: inputType,
53354
+ required: basics.required,
53355
+ placeholder: field.placeholder,
53356
+ ...textInputConstraints(field, inputType),
53357
+ className: "form-input"
53358
+ })
53359
+ });
53360
+ }
53361
+ function FormFieldControl({ field }) {
53362
+ const type = String(field.type ?? "text");
53363
+ switch (type) {
53364
+ case "textarea": return /* @__PURE__ */ jsx(TextareaField, { field });
53365
+ case "select": return /* @__PURE__ */ jsx(SelectField, { field });
53366
+ case "radio": return /* @__PURE__ */ jsx(RadioField, { field });
53367
+ case "checkbox":
53368
+ case "consent": {
53369
+ const basics = fieldBasics(field);
53370
+ return /* @__PURE__ */ jsx(CheckboxChoice, {
53371
+ name: field.id,
53372
+ required: basics.required,
53373
+ label: basics.label,
53374
+ presentation: type === "consent" ? "tile" : "row"
53375
+ });
53376
+ }
53377
+ default: return /* @__PURE__ */ jsx(TextInputField, {
53378
+ field,
53379
+ type
53380
+ });
53381
+ }
53382
+ }
53383
+ //#endregion
52960
53384
  //#region ../blocks/src/system/runtime/nodes/form.server.tsx
52961
53385
  const FormNodeSSR = ({ blockId, value, submitLabel, successMessage, className, onSubmit, action = "/api/forms/submit", siteId, apiBaseUrl, spamProtectionEnabled }) => {
52962
53386
  const islandProps = buildFormInteractiveIslandProps({
@@ -52980,107 +53404,7 @@ const FormNodeSSR = ({ blockId, value, submitLabel, successMessage, className, o
52980
53404
  })]
52981
53405
  });
52982
53406
  const groups = display.groups;
52983
- const renderField = (field) => {
52984
- const inputId = `f_${field.id}`;
52985
- const label = String(field.label ?? field.id);
52986
- const required = Boolean(field.required);
52987
- const type = String(field.type ?? "text");
52988
- if (type === "textarea") return /* @__PURE__ */ jsxs("div", {
52989
- className: "fb-field",
52990
- children: [/* @__PURE__ */ jsx("label", {
52991
- htmlFor: inputId,
52992
- className: "form-label",
52993
- children: label
52994
- }), /* @__PURE__ */ jsx("textarea", {
52995
- id: inputId,
52996
- name: field.id,
52997
- required,
52998
- placeholder: field.placeholder,
52999
- rows: field.rows,
53000
- className: "form-textarea"
53001
- })]
53002
- }, field.id);
53003
- if (type === "select") {
53004
- const options = field.options ?? [];
53005
- const multiple = Boolean(field.multiple);
53006
- return /* @__PURE__ */ jsxs("div", {
53007
- className: "fb-field",
53008
- children: [/* @__PURE__ */ jsx("label", {
53009
- htmlFor: inputId,
53010
- className: "form-label",
53011
- children: label
53012
- }), /* @__PURE__ */ jsxs("select", {
53013
- id: inputId,
53014
- name: field.id,
53015
- multiple,
53016
- required,
53017
- className: "form-select",
53018
- children: [!multiple && /* @__PURE__ */ jsx("option", {
53019
- value: "",
53020
- children: "Select…"
53021
- }), options.map((opt) => /* @__PURE__ */ jsx("option", {
53022
- value: opt.value,
53023
- children: opt.label
53024
- }, opt.value))]
53025
- })]
53026
- }, field.id);
53027
- }
53028
- if (type === "radio") {
53029
- const options = field.options ?? [];
53030
- return /* @__PURE__ */ jsxs("fieldset", {
53031
- className: "fb-fieldset",
53032
- children: [/* @__PURE__ */ jsx("legend", {
53033
- className: "form-label",
53034
- children: label
53035
- }), options.map((opt) => /* @__PURE__ */ jsxs("label", {
53036
- className: "fb-inline form-label",
53037
- children: [/* @__PURE__ */ jsx("input", {
53038
- type: "radio",
53039
- name: field.id,
53040
- value: opt.value,
53041
- required,
53042
- className: "form-radio"
53043
- }), /* @__PURE__ */ jsx("span", { children: opt.label })]
53044
- }, opt.value))]
53045
- }, field.id);
53046
- }
53047
- if (type === "checkbox" || type === "consent") return /* @__PURE__ */ jsxs("label", {
53048
- className: "fb-inline form-label",
53049
- children: [/* @__PURE__ */ jsx("input", {
53050
- type: "checkbox",
53051
- name: field.id,
53052
- required,
53053
- className: "form-checkbox"
53054
- }), /* @__PURE__ */ jsx("span", { children: label })]
53055
- }, field.id);
53056
- const inputType = type === "email" || type === "url" || type === "tel" || type === "number" ? type : "text";
53057
- const extra = {};
53058
- if (inputType === "text" || inputType === "email" || inputType === "url" || inputType === "tel") {
53059
- if (typeof field.minLength === "number") extra.minLength = field.minLength;
53060
- if (typeof field.maxLength === "number") extra.maxLength = field.maxLength;
53061
- if (typeof field.pattern === "string" && field.pattern) extra.pattern = field.pattern;
53062
- }
53063
- if (inputType === "number") {
53064
- if (typeof field.min === "number") extra.min = field.min;
53065
- if (typeof field.max === "number") extra.max = field.max;
53066
- }
53067
- return /* @__PURE__ */ jsxs("div", {
53068
- className: "fb-field",
53069
- children: [/* @__PURE__ */ jsx("label", {
53070
- htmlFor: inputId,
53071
- className: "form-label",
53072
- children: label
53073
- }), /* @__PURE__ */ jsx("input", {
53074
- id: inputId,
53075
- name: field.id,
53076
- type: inputType,
53077
- required,
53078
- placeholder: field.placeholder,
53079
- ...extra,
53080
- className: "form-input"
53081
- })]
53082
- }, field.id);
53083
- };
53407
+ const renderField = (field) => /* @__PURE__ */ jsx(FormFieldControl, { field }, field.id);
53084
53408
  return /* @__PURE__ */ jsxs("div", {
53085
53409
  ...getIslandRootProps("form", blockId),
53086
53410
  children: [/* @__PURE__ */ jsx(IslandPropsScript, { value: islandProps }), /* @__PURE__ */ jsxs("form", {
@@ -53126,6 +53450,172 @@ const FormNodeSSR = ({ blockId, value, submitLabel, successMessage, className, o
53126
53450
  });
53127
53451
  };
53128
53452
  //#endregion
53453
+ //#region ../blocks/src/system/runtime/shared/components/FieldValidationMessage.tsx
53454
+ function getFieldValidationControlProps({ message, messageId, describedBy }) {
53455
+ const hasMessage = Boolean(message);
53456
+ const ariaDescribedBy = [describedBy, hasMessage ? messageId : void 0].filter((part) => typeof part === "string" && part.length > 0).join(" ");
53457
+ return {
53458
+ "aria-invalid": hasMessage ? "true" : void 0,
53459
+ "aria-describedby": ariaDescribedBy || void 0
53460
+ };
53461
+ }
53462
+ function FieldValidationMessage({ id, children, className, live = "assertive" }) {
53463
+ return /* @__PURE__ */ jsx("p", {
53464
+ id,
53465
+ className,
53466
+ "data-field-validation-message": true,
53467
+ "data-field-validation-tone": "error",
53468
+ role: "alert",
53469
+ "aria-live": live === "off" ? void 0 : live,
53470
+ children
53471
+ });
53472
+ }
53473
+ //#endregion
53474
+ //#region ../blocks/src/system/runtime/nodes/newsletter-form.parts.tsx
53475
+ /**
53476
+ * Newsletter form pieces shared by the SSR render and the hydrated island, so
53477
+ * both produce the same markup.
53478
+ *
53479
+ * Labels are visually hidden: every field has a placeholder, and a visible
53480
+ * "Email *" label over a single field reads like a generic form. Screen
53481
+ * readers still get the label.
53482
+ */
53483
+ const TOPIC_CHOICE_FIELD_ID = "mailingListChoice";
53484
+ const inputIdFor = (field) => `newsletter_${field.id}`;
53485
+ /** Splits the preset's fields into the email (joined with the button) and the rest. */
53486
+ function partitionNewsletterFields(fields) {
53487
+ const email = fields.find((field) => field.type === "email") ?? null;
53488
+ return {
53489
+ email,
53490
+ extra: fields.filter((field) => field !== email)
53491
+ };
53492
+ }
53493
+ function NewsletterExtraField({ field, disabled, error }) {
53494
+ const inputId = inputIdFor(field);
53495
+ const errorId = `${inputId}-error`;
53496
+ return /* @__PURE__ */ jsxs("div", {
53497
+ className: "fb-field newsletter-field",
53498
+ children: [
53499
+ /* @__PURE__ */ jsx("label", {
53500
+ htmlFor: inputId,
53501
+ className: "rb-sr-only",
53502
+ children: field.label
53503
+ }),
53504
+ /* @__PURE__ */ jsx("input", {
53505
+ id: inputId,
53506
+ name: field.id,
53507
+ type: field.type,
53508
+ required: field.required,
53509
+ placeholder: field.placeholder ?? field.label,
53510
+ className: "form-input",
53511
+ disabled,
53512
+ ...getFieldValidationControlProps({
53513
+ message: error,
53514
+ messageId: errorId
53515
+ })
53516
+ }),
53517
+ error ? /* @__PURE__ */ jsx(FieldValidationMessage, {
53518
+ id: errorId,
53519
+ className: "fb-error",
53520
+ children: error
53521
+ }) : null
53522
+ ]
53523
+ });
53524
+ }
53525
+ /** The email field and submit button sharing one input-styled shell. */
53526
+ function NewsletterEmailEntry({ field, buttonVariant, buttonLabel, disabled, error }) {
53527
+ const inputId = inputIdFor(field);
53528
+ const errorId = `${inputId}-error`;
53529
+ return /* @__PURE__ */ jsxs("div", {
53530
+ className: "newsletter-entry",
53531
+ children: [/* @__PURE__ */ jsxs("div", {
53532
+ className: "form-input-group newsletter-entry-group",
53533
+ children: [
53534
+ /* @__PURE__ */ jsx("label", {
53535
+ htmlFor: inputId,
53536
+ className: "rb-sr-only",
53537
+ children: field.label
53538
+ }),
53539
+ /* @__PURE__ */ jsx("input", {
53540
+ id: inputId,
53541
+ name: field.id,
53542
+ type: "email",
53543
+ required: field.required,
53544
+ placeholder: field.placeholder ?? field.label,
53545
+ className: "form-input-group-field",
53546
+ autoComplete: "email",
53547
+ disabled,
53548
+ ...getFieldValidationControlProps({
53549
+ message: error,
53550
+ messageId: errorId
53551
+ })
53552
+ }),
53553
+ /* @__PURE__ */ jsx(ThemedButton, {
53554
+ type: "submit",
53555
+ variant: buttonVariant,
53556
+ size: "md",
53557
+ disabled,
53558
+ label: buttonLabel
53559
+ })
53560
+ ]
53561
+ }), error ? /* @__PURE__ */ jsx(FieldValidationMessage, {
53562
+ id: errorId,
53563
+ className: "fb-error",
53564
+ children: error
53565
+ }) : null]
53566
+ });
53567
+ }
53568
+ /**
53569
+ * The submit action: joined to the email field when the preset has one
53570
+ * (every current preset does), otherwise a plain themed button.
53571
+ */
53572
+ function NewsletterSubmitRow({ emailField, buttonVariant, buttonLabel, disabled, error }) {
53573
+ if (emailField) return /* @__PURE__ */ jsx(NewsletterEmailEntry, {
53574
+ field: emailField,
53575
+ buttonVariant,
53576
+ buttonLabel,
53577
+ disabled,
53578
+ error
53579
+ });
53580
+ return /* @__PURE__ */ jsx("div", {
53581
+ className: "newsletter-submit",
53582
+ children: /* @__PURE__ */ jsx(ThemedButton, {
53583
+ type: "submit",
53584
+ variant: buttonVariant,
53585
+ size: "md",
53586
+ disabled,
53587
+ label: buttonLabel
53588
+ })
53589
+ });
53590
+ }
53591
+ /** Visitor-chosen topics as toggle chips. Real checkboxes underneath. */
53592
+ function NewsletterTopicChips({ choices, disabled, error }) {
53593
+ const errorId = `newsletter_${TOPIC_CHOICE_FIELD_ID}-error`;
53594
+ return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs("fieldset", {
53595
+ className: "newsletter-topics",
53596
+ "aria-describedby": error ? errorId : void 0,
53597
+ children: [/* @__PURE__ */ jsx("legend", {
53598
+ className: "newsletter-topics-legend",
53599
+ children: "What would you like to hear about?"
53600
+ }), /* @__PURE__ */ jsx("div", {
53601
+ className: "newsletter-topic-chips",
53602
+ children: choices.map((choice) => /* @__PURE__ */ jsxs("label", {
53603
+ className: "newsletter-topic-chip",
53604
+ children: [/* @__PURE__ */ jsx("input", {
53605
+ type: "checkbox",
53606
+ name: TOPIC_CHOICE_FIELD_ID,
53607
+ value: choice.id,
53608
+ disabled
53609
+ }), /* @__PURE__ */ jsx("span", { children: choice.label })]
53610
+ }, choice.id))
53611
+ })]
53612
+ }), error ? /* @__PURE__ */ jsx(FieldValidationMessage, {
53613
+ id: errorId,
53614
+ className: "fb-error",
53615
+ children: error
53616
+ }) : null] });
53617
+ }
53618
+ //#endregion
53129
53619
  //#region ../blocks/src/system/runtime/nodes/newsletter-form.server.tsx
53130
53620
  /**
53131
53621
  * Newsletter Form Server Component
@@ -53146,36 +53636,15 @@ function NewsletterFormSSR(props) {
53146
53636
  });
53147
53637
  const display = islandProps.render.display;
53148
53638
  const fields = display.fields;
53639
+ const submissionMessage = newsletterBlockSubmissionMessage(islandProps.render.hydration.target);
53149
53640
  if (display.availability === "unavailable") return /* @__PURE__ */ jsx("div", {
53150
53641
  className: clsx("newsletter-form-ssr", className),
53151
53642
  children: /* @__PURE__ */ jsx("p", {
53152
53643
  role: "status",
53153
- children: "We can’t accept signups right now. Please try again later."
53644
+ children: NEWSLETTER_SIGNUPS_PAUSED_MESSAGE
53154
53645
  })
53155
53646
  });
53156
- const renderField = (field) => {
53157
- const inputId = `newsletter_${field.id}`;
53158
- return /* @__PURE__ */ jsxs("div", {
53159
- className: "fb-field newsletter-field",
53160
- children: [/* @__PURE__ */ jsxs("label", {
53161
- htmlFor: inputId,
53162
- className: "form-label",
53163
- children: [field.label, field.required && /* @__PURE__ */ jsx("span", {
53164
- className: "newsletter-required",
53165
- "aria-hidden": "true",
53166
- children: "*"
53167
- })]
53168
- }), /* @__PURE__ */ jsx("input", {
53169
- id: inputId,
53170
- name: field.id,
53171
- type: field.type,
53172
- required: field.required,
53173
- placeholder: field.placeholder,
53174
- className: "form-input",
53175
- autoComplete: field.type === "email" ? "email" : void 0
53176
- })]
53177
- }, field.id);
53178
- };
53647
+ const { email: emailField, extra: extraFields } = partitionNewsletterFields(fields);
53179
53648
  return /* @__PURE__ */ jsxs("div", {
53180
53649
  ...getIslandRootProps("newsletter-form", blockId),
53181
53650
  className: clsx("newsletter-form-ssr", className),
@@ -53194,30 +53663,20 @@ function NewsletterFormSSR(props) {
53194
53663
  /* @__PURE__ */ jsxs("div", {
53195
53664
  className: "newsletter-form-fields",
53196
53665
  children: [
53197
- fields.map(renderField),
53198
- islandProps.render.hydration.choicePresentation === "visitor_choice" ? /* @__PURE__ */ jsxs("fieldset", {
53199
- className: "fb-fieldset newsletter-topics",
53200
- children: [/* @__PURE__ */ jsx("legend", {
53201
- className: "form-label",
53202
- children: "What would you like to hear about?"
53203
- }), display.choices.map((choice) => /* @__PURE__ */ jsxs("label", {
53204
- className: "fb-inline form-label newsletter-topic-choice",
53205
- children: [/* @__PURE__ */ jsx("input", {
53206
- type: "checkbox",
53207
- name: "mailingListChoice",
53208
- value: choice.id,
53209
- className: "form-checkbox"
53210
- }), /* @__PURE__ */ jsx("span", { children: choice.label })]
53211
- }, choice.id))]
53666
+ islandProps.render.hydration.choicePresentation === "visitor_choice" ? /* @__PURE__ */ jsx(NewsletterTopicChips, { choices: display.choices }) : null,
53667
+ extraFields.length > 0 ? /* @__PURE__ */ jsx("div", {
53668
+ className: "newsletter-extra-fields",
53669
+ children: extraFields.map((field) => /* @__PURE__ */ jsx(NewsletterExtraField, { field }, field.id))
53212
53670
  }) : null,
53213
- /* @__PURE__ */ jsx("div", {
53214
- className: "newsletter-submit",
53215
- children: /* @__PURE__ */ jsx(ThemedButton, {
53216
- type: "submit",
53217
- variant: display.buttonVariant,
53218
- size: "md",
53219
- label: display.buttonLabel
53220
- })
53671
+ /* @__PURE__ */ jsx(NewsletterSubmitRow, {
53672
+ emailField,
53673
+ buttonVariant: display.buttonVariant,
53674
+ buttonLabel: display.buttonLabel,
53675
+ disabled: submissionMessage !== null
53676
+ }),
53677
+ submissionMessage && /* @__PURE__ */ jsx("p", {
53678
+ role: "status",
53679
+ children: submissionMessage
53221
53680
  })
53222
53681
  ]
53223
53682
  }),
@@ -54198,7 +54657,7 @@ const RENDERER_METADATA_PROP_KEYS = /* @__PURE__ */ new Set([
54198
54657
  "blockContent",
54199
54658
  "fragmentRegistry",
54200
54659
  "previewAuthoring",
54201
- "contentVersionId",
54660
+ "newsletterBlockSubmission",
54202
54661
  "imageResolveContext"
54203
54662
  ]);
54204
54663
  function omitRendererMetadataProps(props) {
@@ -54254,7 +54713,7 @@ function resolveNodeMetadata(nodeType, context) {
54254
54713
  pathBase: context.pathBase,
54255
54714
  fragmentRegistry: context.fragmentRegistry
54256
54715
  } : {},
54257
- ...normalizedType === "newsletter-form" ? { contentVersionId: context.contentVersionId } : {},
54716
+ ...normalizedType === "newsletter-form" ? { newsletterBlockSubmission: context.newsletterBlockSubmission } : {},
54258
54717
  ...normalizedType === "media" && context.imageResolveContext ? { imageResolveContext: context.imageResolveContext } : {}
54259
54718
  };
54260
54719
  }
@@ -54865,6 +55324,270 @@ function generateHoverEffects(axes, _space) {
54865
55324
  };
54866
55325
  }
54867
55326
  //#endregion
55327
+ //#region ../theme-core/src/inputs/checkable.ts
55328
+ /**
55329
+ * Checkbox and radio CSS shared by the full theme generator and the SDK
55330
+ * theme bridge, so both render the same customer-facing controls.
55331
+ *
55332
+ * Emits:
55333
+ * - .form-checkbox / .form-radio: the controls themselves. The tick and dot
55334
+ * are drawn with ::before so their colour comes from theme tokens rather
55335
+ * than a baked-in SVG.
55336
+ * - .form-check: a label row holding a control and its text. The control
55337
+ * lines up with the first line of text, so long labels wrap cleanly.
55338
+ * - .form-check--tile: a bordered, fully clickable panel for agreements
55339
+ * (booking consent, consent fields) that tints when ticked.
55340
+ */
55341
+ const CHECKABLE_SIZE = "1.375rem";
55342
+ /** Never fully round: a round checkbox reads as a radio. */
55343
+ const CHECKBOX_RADIUS = {
55344
+ square: "0",
55345
+ soft: "0.25rem",
55346
+ rounded: "0.375rem",
55347
+ pill: "0.375rem"
55348
+ };
55349
+ /** Tiles hold wrapping text, so pill themes get a generous radius, not a capsule. */
55350
+ const TILE_RADIUS = {
55351
+ square: "0",
55352
+ soft: "0.5rem",
55353
+ rounded: "0.75rem",
55354
+ pill: "1rem"
55355
+ };
55356
+ const ON_ACCENT_TOKENS = {
55357
+ primary: "onPrimary",
55358
+ secondary: "onSecondary",
55359
+ accent: "onAccent"
55360
+ };
55361
+ /**
55362
+ * Colour for the tick/dot drawn on top of the accent fill. Uses the palette's
55363
+ * matching "on" token where there is one, falling back to white.
55364
+ */
55365
+ /** The accent at full strength: `primary/70` becomes `primary`. */
55366
+ function solidAccentToken(accentToken) {
55367
+ const parsed = parseColorTokenParts(accentToken);
55368
+ return parsed.kind === "token" ? parsed.token : accentToken;
55369
+ }
55370
+ function checkableMarkColor(accentToken) {
55371
+ const parsed = parseColorTokenParts(accentToken);
55372
+ const onToken = parsed.kind === "token" ? ON_ACCENT_TOKENS[parsed.token] : void 0;
55373
+ return onToken ? `rgb(var(--tb-${onToken}, 255 255 255))` : "rgb(255 255 255)";
55374
+ }
55375
+ function checkableSelectors(root) {
55376
+ return {
55377
+ checkbox: `${root} .form-checkbox`,
55378
+ radio: `${root} .form-radio`,
55379
+ check: `${root} .form-check`,
55380
+ tile: `${root} .form-check--tile`
55381
+ };
55382
+ }
55383
+ /** The box and circle themselves, unchecked. */
55384
+ function controlBaseCss(sel, input) {
55385
+ const border = input.borderWidth === "0" ? "1px" : input.borderWidth;
55386
+ return [
55387
+ `${sel.checkbox},
55388
+ ${sel.radio} {
55389
+ appearance: none;
55390
+ display: inline-grid;
55391
+ place-content: center;
55392
+ width: ${CHECKABLE_SIZE};
55393
+ height: ${CHECKABLE_SIZE};
55394
+ margin: 0;
55395
+ flex-shrink: 0;
55396
+ border: ${border} solid ${input.borderColor};
55397
+ background-color: ${input.background};
55398
+ color: inherit;
55399
+ cursor: pointer;
55400
+ transition: background-color 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease;
55401
+ }`,
55402
+ `${sel.checkbox} {
55403
+ border-radius: ${CHECKBOX_RADIUS[input.corners]};
55404
+ }`,
55405
+ `${sel.radio} {
55406
+ border-radius: 9999px;
55407
+ }`
55408
+ ];
55409
+ }
55410
+ /** The tick and dot, drawn with ::before so their colour is a theme token. */
55411
+ function controlMarkCss(sel, accentToken) {
55412
+ return [
55413
+ `${sel.checkbox}::before,
55414
+ ${sel.radio}::before {
55415
+ content: "";
55416
+ background-color: ${checkableMarkColor(accentToken)};
55417
+ transform: scale(0);
55418
+ transition: transform 0.12s ease;
55419
+ }`,
55420
+ `${sel.checkbox}::before {
55421
+ width: 0.75rem;
55422
+ height: 0.75rem;
55423
+ clip-path: polygon(14% 52%, 0 67%, 38% 100%, 100% 22%, 85% 8%, 37% 70%);
55424
+ }`,
55425
+ `${sel.radio}::before {
55426
+ width: 0.5rem;
55427
+ height: 0.5rem;
55428
+ border-radius: 9999px;
55429
+ }`
55430
+ ];
55431
+ }
55432
+ function controlStateCss(sel, input) {
55433
+ const accent = rgbColorValue(solidAccentToken(input.accentToken));
55434
+ return [
55435
+ `${sel.checkbox}:hover,
55436
+ ${sel.radio}:hover,
55437
+ ${sel.check}:hover > .form-checkbox,
55438
+ ${sel.check}:hover > .form-radio {
55439
+ border-color: ${accent};
55440
+ }`,
55441
+ `${sel.checkbox}:checked,
55442
+ ${sel.radio}:checked {
55443
+ background-color: ${accent};
55444
+ border-color: ${accent};
55445
+ }`,
55446
+ `${sel.checkbox}:checked::before,
55447
+ ${sel.radio}:checked::before {
55448
+ transform: scale(1);
55449
+ }`,
55450
+ `${sel.checkbox}:focus-visible,
55451
+ ${sel.radio}:focus-visible {
55452
+ outline: 2px solid ${accent};
55453
+ outline-offset: 2px;
55454
+ }`,
55455
+ `${sel.checkbox}:disabled,
55456
+ ${sel.radio}:disabled {
55457
+ opacity: 0.5;
55458
+ cursor: not-allowed;
55459
+ }`
55460
+ ];
55461
+ }
55462
+ /** Label row: control lined up with the first line of wrapping text. */
55463
+ function checkRowCss(sel) {
55464
+ return [
55465
+ `${sel.check} {
55466
+ display: flex;
55467
+ align-items: flex-start;
55468
+ gap: 0.75rem;
55469
+ line-height: 1.5;
55470
+ cursor: pointer;
55471
+ }`,
55472
+ `${sel.check} > .form-checkbox,
55473
+ ${sel.check} > .form-radio {
55474
+ margin-top: 0.0625rem;
55475
+ margin-top: max(0px, calc((1lh - ${CHECKABLE_SIZE}) / 2));
55476
+ }`,
55477
+ `${sel.check}:has(> :disabled) {
55478
+ cursor: not-allowed;
55479
+ }`
55480
+ ];
55481
+ }
55482
+ function agreementTileCss(sel, input) {
55483
+ const accent = rgbColorValue(solidAccentToken(input.accentToken));
55484
+ return [
55485
+ `${sel.tile} {
55486
+ padding: 0.875rem 1rem;
55487
+ border: 1px solid color-mix(in srgb, currentColor 22%, transparent);
55488
+ border-radius: ${TILE_RADIUS[input.corners]};
55489
+ transition: border-color 0.15s ease, background-color 0.15s ease;
55490
+ }`,
55491
+ `${sel.tile}:hover {
55492
+ border-color: color-mix(in srgb, ${accent} 55%, transparent);
55493
+ }`,
55494
+ `${sel.tile}:has(> .form-checkbox:checked) {
55495
+ border-color: ${accent};
55496
+ background-color: color-mix(in srgb, ${accent} 7%, transparent);
55497
+ }`,
55498
+ `${sel.tile}:has(> .form-checkbox[aria-invalid="true"]) {
55499
+ border-color: ${input.errorColor};
55500
+ }`
55501
+ ];
55502
+ }
55503
+ function checkableMediaCss(sel) {
55504
+ return [`@media (prefers-reduced-motion: reduce) {
55505
+ ${sel.checkbox}, ${sel.radio}, ${sel.checkbox}::before, ${sel.radio}::before, ${sel.tile} {
55506
+ transition: none;
55507
+ }
55508
+ }`, `@media (forced-colors: active) {
55509
+ ${sel.checkbox}::before,
55510
+ ${sel.radio}::before {
55511
+ background-color: CanvasText;
55512
+ }
55513
+ }`];
55514
+ }
55515
+ /**
55516
+ * Exposes the accent and mark colours so other choice controls (newsletter
55517
+ * topic chips) match the checkboxes without re-deriving the theme tokens.
55518
+ */
55519
+ function checkableVarsCss(input) {
55520
+ return [`${input.root} {
55521
+ --rb-check-accent: ${rgbColorValue(solidAccentToken(input.accentToken))};
55522
+ --rb-check-mark: ${checkableMarkColor(input.accentToken)};
55523
+ }`];
55524
+ }
55525
+ function generateCheckableCss(input) {
55526
+ const sel = checkableSelectors(input.root);
55527
+ return [
55528
+ ...checkableVarsCss(input),
55529
+ ...controlBaseCss(sel, input),
55530
+ ...controlMarkCss(sel, input.accentToken),
55531
+ ...controlStateCss(sel, input),
55532
+ ...checkRowCss(sel),
55533
+ ...agreementTileCss(sel, input),
55534
+ ...checkableMediaCss(sel)
55535
+ ].join("\n\n");
55536
+ }
55537
+ //#endregion
55538
+ //#region ../theme-core/src/inputs/inputGroup.ts
55539
+ /**
55540
+ * Input group: a field and an action (usually a themed button) sharing one
55541
+ * input-styled shell, e.g. the newsletter email + Sign up row.
55542
+ *
55543
+ * The shell `.form-input-group` takes the theme's `.form-input` rules (the
55544
+ * generators add it to that selector list, plus focus and error), so it
55545
+ * follows the site's input background, border, corners and shadow. This file
55546
+ * only adds the layout overrides and the borderless inner field.
55547
+ */
55548
+ const INPUT_GROUP_SELECTOR = ".form-input-group";
55549
+ /** Shell focus ring follows the field only, not the button beside it. */
55550
+ const INPUT_GROUP_FOCUS_SELECTOR = ".form-input-group:has(> .form-input-group-field:focus-visible)";
55551
+ const INPUT_GROUP_ERROR_SELECTOR = ".form-input-group:has(> .form-input-group-field[aria-invalid=\"true\"])";
55552
+ const GROUP_INSET = "0.25rem";
55553
+ /**
55554
+ * @param root - scoped root selector
55555
+ * @param padding - the theme's input padding shorthand (`block inline`), so the
55556
+ * inner field's text sits where a plain input's text would.
55557
+ */
55558
+ function generateInputGroupCss(root, padding) {
55559
+ const [block = padding, inline = block] = padding.trim().split(/\s+/);
55560
+ return `${root} .form-input-group {
55561
+ display: flex;
55562
+ align-items: stretch;
55563
+ gap: ${GROUP_INSET};
55564
+ padding: ${GROUP_INSET};
55565
+ }
55566
+
55567
+ ${root} .form-input-group-field {
55568
+ flex: 1 1 auto;
55569
+ min-width: 0;
55570
+ margin: 0;
55571
+ border: 0;
55572
+ border-radius: 0;
55573
+ background: transparent;
55574
+ box-shadow: none;
55575
+ outline: none;
55576
+ color: inherit;
55577
+ font: inherit;
55578
+ padding: calc(${block} - ${GROUP_INSET}) calc(${inline} - ${GROUP_INSET});
55579
+ }
55580
+
55581
+ ${root} .form-input-group-field::placeholder {
55582
+ color: inherit;
55583
+ opacity: 0.6;
55584
+ }
55585
+
55586
+ ${root} .form-input-group > :not(.form-input-group-field) {
55587
+ flex-shrink: 0;
55588
+ }`;
55589
+ }
55590
+ //#endregion
54868
55591
  //#region ../theme-core/src/inputs/generateInputCss.ts
54869
55592
  /**
54870
55593
  * Corner radius map (reused from other systems)
@@ -54875,6 +55598,9 @@ const CORNER_MAP$1 = {
54875
55598
  rounded: "1rem",
54876
55599
  pill: "9999px"
54877
55600
  };
55601
+ function inputBackgroundValue(background) {
55602
+ return background.type === "transparent" ? "transparent" : rgbColorValue(background.colorToken);
55603
+ }
54878
55604
  /**
54879
55605
  * Generate CSS for form input styling based on theme configuration
54880
55606
  *
@@ -54892,8 +55618,7 @@ const CORNER_MAP$1 = {
54892
55618
  function generateInputCss({ themeId, theme, inputSystem }) {
54893
55619
  const rootSelector = `:where([data-theme-scope="${themeId}"])`;
54894
55620
  const baseInputRules = [];
54895
- if (inputSystem.base.background.type === "transparent") baseInputRules.push("background-color: transparent");
54896
- else baseInputRules.push(`background-color: ${rgbColorValue(inputSystem.base.background.colorToken)}`);
55621
+ baseInputRules.push(`background-color: ${inputBackgroundValue(inputSystem.base.background)}`);
54897
55622
  baseInputRules.push(`color: ${rgbColorValue(inputSystem.base.textColorToken)}`);
54898
55623
  const borderPx = parseBorderWidth(inputSystem.base.border.widthClass);
54899
55624
  const borderStyle = inputSystem.base.border.style ?? "all";
@@ -54949,7 +55674,8 @@ function generateInputCss({ themeId, theme, inputSystem }) {
54949
55674
  const focusSelectors = [
54950
55675
  `${inputSelector}:focus-visible`,
54951
55676
  `${textareaSelector}:focus-visible`,
54952
- `${selectSelector}:focus-visible`
55677
+ `${selectSelector}:focus-visible`,
55678
+ `${rootSelector} ${INPUT_GROUP_FOCUS_SELECTOR}`
54953
55679
  ];
54954
55680
  const focusRules = [];
54955
55681
  focusRules.push("outline: none");
@@ -54958,7 +55684,8 @@ function generateInputCss({ themeId, theme, inputSystem }) {
54958
55684
  const errorSelectors = [
54959
55685
  `${inputSelector}[aria-invalid="true"]`,
54960
55686
  `${textareaSelector}[aria-invalid="true"]`,
54961
- `${selectSelector}[aria-invalid="true"]`
55687
+ `${selectSelector}[aria-invalid="true"]`,
55688
+ `${rootSelector} ${INPUT_GROUP_ERROR_SELECTOR}`
54962
55689
  ];
54963
55690
  const errorRules = [];
54964
55691
  errorRules.push(`border-color: ${rgbColorValue(inputSystem.error.borderColorToken)}`);
@@ -54973,53 +55700,25 @@ function generateInputCss({ themeId, theme, inputSystem }) {
54973
55700
  disabledRules.push(`color: ${rgbColorValue(inputSystem.disabled.textColorToken)}`);
54974
55701
  disabledRules.push(`opacity: ${inputSystem.disabled.opacity}`);
54975
55702
  disabledRules.push("cursor: not-allowed");
54976
- const checkboxSelector = `${rootSelector} .form-checkbox`;
54977
- const radioSelector = `${rootSelector} .form-radio`;
54978
- const checkableRules = [];
54979
- checkableRules.push("appearance: none");
54980
- checkableRules.push("width: 1.125rem");
54981
- checkableRules.push("height: 1.125rem");
54982
- checkableRules.push("flex-shrink: 0");
54983
- checkableRules.push(`border: ${borderPx} solid ${rgbColorValue(inputSystem.base.border.colorToken)}`);
54984
- if (inputSystem.base.background.type === "transparent") checkableRules.push("background-color: transparent");
54985
- else checkableRules.push(`background-color: ${rgbColorValue(inputSystem.base.background.colorToken)}`);
54986
- checkableRules.push("cursor: pointer");
54987
- checkableRules.push("transition: background-color 0.2s ease, border-color 0.2s ease");
54988
- const checkboxSpecificRules = [...checkableRules];
54989
- checkboxSpecificRules.push(`border-radius: ${CORNER_MAP$1.soft}`);
54990
- const radioSpecificRules = [...checkableRules];
54991
- radioSpecificRules.push("border-radius: 9999px");
54992
- const checkboxCheckedSelector = `${checkboxSelector}:checked`;
54993
- const checkboxCheckedRules = [];
54994
- checkboxCheckedRules.push(`background-color: ${rgbColorValue(inputSystem.focus.ringColorToken)}`);
54995
- checkboxCheckedRules.push(`border-color: ${rgbColorValue(inputSystem.focus.ringColorToken)}`);
54996
- checkboxCheckedRules.push("background-image: url(\"data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M12.207 4.793a1 1 0 010 1.414l-5 5a1 1 0 01-1.414 0l-2-2a1 1 0 011.414-1.414L6.5 9.086l4.293-4.293a1 1 0 011.414 0z'/%3e%3c/svg%3e\")");
54997
- checkboxCheckedRules.push("background-size: 100% 100%");
54998
- checkboxCheckedRules.push("background-position: center");
54999
- checkboxCheckedRules.push("background-repeat: no-repeat");
55000
- const radioCheckedSelector = `${radioSelector}:checked`;
55001
- const radioCheckedRules = [];
55002
- radioCheckedRules.push(`background-color: ${rgbColorValue(inputSystem.focus.ringColorToken)}`);
55003
- radioCheckedRules.push(`border-color: ${rgbColorValue(inputSystem.focus.ringColorToken)}`);
55004
- radioCheckedRules.push("background-image: radial-gradient(circle, white 40%, transparent 40%)");
55005
- const checkboxFocusSelector = `${checkboxSelector}:focus-visible`;
55006
- const radioFocusSelector = `${radioSelector}:focus-visible`;
55007
- const checkableFocusRules = [];
55008
- checkableFocusRules.push("outline: none");
55009
- checkableFocusRules.push(`box-shadow: 0 0 0 ${inputSystem.focus.ringWidth}px ${rgbColorValue(inputSystem.focus.ringColorToken)}`);
55703
+ const checkableCss = generateCheckableCss({
55704
+ root: rootSelector,
55705
+ borderWidth: borderPx,
55706
+ borderColor: rgbColorValue(inputSystem.base.border.colorToken),
55707
+ background: inputBackgroundValue(inputSystem.base.background),
55708
+ corners: inputSystem.base.corners ?? theme.corners,
55709
+ accentToken: inputSystem.focus.borderColorToken ?? inputSystem.focus.ringColorToken,
55710
+ errorColor: rgbColorValue(inputSystem.error.borderColorToken)
55711
+ });
55010
55712
  const cssBlocks = [];
55011
55713
  cssBlocks.push(`${labelSelector} {\n ${labelRules.join(";\n ")};\n}`);
55012
- cssBlocks.push(`${inputSelector} {\n ${inputRules.join(";\n ")};\n}`);
55714
+ cssBlocks.push(`${inputSelector},\n${rootSelector} ${INPUT_GROUP_SELECTOR} {\n ${inputRules.join(";\n ")};\n}`);
55013
55715
  cssBlocks.push(`${textareaSelector} {\n ${textareaRules.join(";\n ")};\n}`);
55014
55716
  cssBlocks.push(`${selectSelector} {\n ${selectRules.join(";\n ")};\n}`);
55015
55717
  cssBlocks.push(`${focusSelectors.join(",\n")} {\n ${focusRules.join(";\n ")};\n}`);
55016
55718
  cssBlocks.push(`${errorSelectors.join(",\n")} {\n ${errorRules.join(";\n ")};\n}`);
55017
55719
  cssBlocks.push(`${disabledSelectors.join(",\n")} {\n ${disabledRules.join(";\n ")};\n}`);
55018
- cssBlocks.push(`${checkboxSelector} {\n ${checkboxSpecificRules.join(";\n ")};\n}`);
55019
- cssBlocks.push(`${radioSelector} {\n ${radioSpecificRules.join(";\n ")};\n}`);
55020
- cssBlocks.push(`${checkboxCheckedSelector} {\n ${checkboxCheckedRules.join(";\n ")};\n}`);
55021
- cssBlocks.push(`${radioCheckedSelector} {\n ${radioCheckedRules.join(";\n ")};\n}`);
55022
- cssBlocks.push(`${checkboxFocusSelector},\n${radioFocusSelector} {\n ${checkableFocusRules.join(";\n ")};\n}`);
55720
+ cssBlocks.push(generateInputGroupCss(rootSelector, padding));
55721
+ cssBlocks.push(checkableCss);
55023
55722
  return cssBlocks.join("\n\n");
55024
55723
  }
55025
55724
  //#endregion
@@ -61398,13 +62097,13 @@ const hours = stack({
61398
62097
  as: "p",
61399
62098
  className: "rb-caption rb-opacity-70"
61400
62099
  }, bind("module.timeZone"), when("module.timeZone"))], when("module.kind", { equals: "opening-hours" }));
61401
- const socials = inline({ className: "rb-flex rb-flex-wrap rb-gap-x-5 rb-gap-y-3" }, [link({
62100
+ const socials = inline({ className: "rb-footer-socials" }, [link({
61402
62101
  href: { $bind: { from: "social.href" } },
61403
62102
  target: "_blank",
61404
62103
  rel: "noreferrer noopener",
61405
62104
  "aria-label": { $bind: { from: "social.label" } },
61406
- className: "rb-nav-text transition-theme-standard"
61407
- }, [icon({ className: "rb-h-5 rb-w-5" }, bind("social.icon"), when("social.icon")), text({ as: "span" }, bind("social.label"), when("social.icon", { equals: null }))], repeat("module.socialLinks", "social"))], when("module.kind", { equals: "social-links" }));
62105
+ className: "rb-footer-social-link rb-nav-text transition-theme-standard"
62106
+ }, [icon({ className: "rb-footer-social-icon" }, bind("social.icon"), when("social.icon")), text({ as: "span" }, bind("social.label"), when("social.icon", { equals: null }))], repeat("module.socialLinks", "social"))], when("module.kind", { equals: "social-links" }));
61408
62107
  const authoredCopy = richText({
61409
62108
  className: "rb-prose rb-prose-sm rb-max-w-none",
61410
62109
  style: textColorStyle("text/80")
@@ -67357,43 +68056,53 @@ function collectNestedPreviewFieldConstraintEntries(field, path) {
67357
68056
  default: return assertNever$20(field);
67358
68057
  }
67359
68058
  }
68059
+ function prepareDefaultBlockRender(manifest, props) {
68060
+ if (!props.theme) throw new Error("Block rendering requires theme tokens; none were provided to makeDefaultBlockComponent");
68061
+ if (!props.registry) throw new Error("Block rendering requires a component registry; none was provided");
68062
+ const content = props.content;
68063
+ const layout = resolveBlockLayout(manifest, content);
68064
+ if (!layout) throw new Error(`Block manifest "${manifest.name}" requires a layout definition`);
68065
+ const mergedContent = mergeContentWithBlockStyleOverrides(content, props.themeConfig, props.blockKind ?? manifest.name);
68066
+ return {
68067
+ registry: props.registry,
68068
+ layout,
68069
+ mergedContent,
68070
+ fieldConstraints: buildPreviewFieldConstraints(manifest),
68071
+ viewModel: buildBlockViewModel({
68072
+ mergedContent,
68073
+ data: props.data,
68074
+ resolvedThemeConfig: resolveThemeConfigForBindings(props.themeConfig),
68075
+ viewModelOverrides: props.viewModelOverrides
68076
+ }),
68077
+ themeForTransforms: withButtonSystem(props.theme, props.themeConfig)
68078
+ };
68079
+ }
67360
68080
  function makeDefaultBlockComponent(args) {
67361
- const { manifest } = args;
67362
- return function DefaultBlockComponent({ content, data, registry, theme, themeConfig, transforms, viewModelOverrides, pathBase, blockId, contentVersionId, blockKind, blockBindings, editableRouteMetadataFieldIds, fragmentRegistry, imageResolveContext, previewAuthoring }) {
68081
+ return function DefaultBlockComponent(props) {
67363
68082
  const perf = beginBlockRenderMeasurement();
67364
- if (!theme) throw new Error("Block rendering requires theme tokens; none were provided to makeDefaultBlockComponent");
67365
- if (!registry) throw new Error("Block rendering requires a component registry; none was provided");
67366
- const layout = resolveBlockLayout(manifest, content);
67367
- if (!layout) throw new Error(`Block manifest "${manifest.name}" requires a layout definition`);
67368
- const fieldConstraints = buildPreviewFieldConstraints(manifest);
67369
- const mergedContent = mergeContentWithBlockStyleOverrides(content, themeConfig, blockKind ?? manifest.name);
67370
- const result = resolveTree(layout, {
67371
- registry,
67372
- viewModel: buildBlockViewModel({
67373
- mergedContent,
67374
- data,
67375
- resolvedThemeConfig: resolveThemeConfigForBindings(themeConfig),
67376
- viewModelOverrides
67377
- }),
67378
- transforms,
67379
- theme: withButtonSystem(theme, themeConfig),
67380
- pathBase,
67381
- blockId,
67382
- contentVersionId,
67383
- blockKind,
67384
- blockContent: mergedContent,
67385
- blockBindings,
67386
- editableRouteMetadataFieldIds,
67387
- fragmentRegistry,
67388
- fieldConstraints,
67389
- imageResolveContext,
67390
- previewAuthoring
68083
+ const prepared = prepareDefaultBlockRender(args.manifest, props);
68084
+ const result = resolveTree(prepared.layout, {
68085
+ registry: prepared.registry,
68086
+ viewModel: prepared.viewModel,
68087
+ transforms: props.transforms,
68088
+ theme: prepared.themeForTransforms,
68089
+ pathBase: props.pathBase,
68090
+ blockId: props.blockId,
68091
+ newsletterBlockSubmission: props.newsletterBlockSubmission,
68092
+ blockKind: props.blockKind,
68093
+ blockContent: prepared.mergedContent,
68094
+ blockBindings: props.blockBindings,
68095
+ editableRouteMetadataFieldIds: props.editableRouteMetadataFieldIds,
68096
+ fragmentRegistry: props.fragmentRegistry,
68097
+ fieldConstraints: prepared.fieldConstraints,
68098
+ imageResolveContext: props.imageResolveContext,
68099
+ previewAuthoring: props.previewAuthoring
67391
68100
  });
67392
68101
  reportSlowBlockRender(perf, {
67393
- content,
67394
- blockId,
67395
- blockKind: blockKind ?? manifest.name,
67396
- manifestName: manifest.name
68102
+ content: props.content,
68103
+ blockId: props.blockId,
68104
+ blockKind: props.blockKind ?? args.manifest.name,
68105
+ manifestName: args.manifest.name
67397
68106
  });
67398
68107
  return result;
67399
68108
  };
@@ -67956,6 +68665,39 @@ function resolveBlockData$1(blockId, dataLoaders, dataContext, routes) {
67956
68665
  return dataLoaders && typeof dataLoaders === "object" && Object.keys(dataLoaders).length > 0 ? {} : void 0;
67957
68666
  }
67958
68667
  //#endregion
68668
+ //#region ../blocks/src/system/runtime/nodes/newsletter-form.block-submission.ts
68669
+ /** Authorise one block source for both public and preview rendering. */
68670
+ function planNewsletterBlockSubmission(placement) {
68671
+ if (placement.stage === "published") {
68672
+ const sourceRef = buildMailingListSignupBlockSourceRef(placement.blockId, placement.selectedContentVersionId);
68673
+ return sourceRef ? {
68674
+ tag: "ready",
68675
+ sourceRef
68676
+ } : { tag: "unavailable" };
68677
+ }
68678
+ if (placement.publishedPlacement) return planNewsletterPreviewSubmission({
68679
+ blockId: placement.blockId,
68680
+ publishedContentId: placement.publishedPlacement.id,
68681
+ renderedContent: placement.renderedContent,
68682
+ publishedContent: placement.publishedPlacement.content
68683
+ });
68684
+ if (placement.stage === "preview") return { tag: "unpublished-form" };
68685
+ return { tag: "unavailable" };
68686
+ }
68687
+ /** Decide whether the visible draft can safely cite the published placement. */
68688
+ function planNewsletterPreviewSubmission(placement) {
68689
+ if (!placement.publishedContentId) return { tag: "unpublished-form" };
68690
+ if (!placement.publishedContent) return { tag: "unpublished-settings" };
68691
+ const draft = parseMailingListPlacementTargeting(placement.renderedContent.targeting ?? { mode: "default" });
68692
+ const published = parseMailingListPlacementTargeting(placement.publishedContent.targeting);
68693
+ if (!draft.ok || !published.ok || !sameMailingListPlacementTargeting(draft.value, published.value)) return { tag: "unpublished-settings" };
68694
+ const sourceRef = buildMailingListSignupBlockSourceRef(placement.blockId, placement.publishedContentId);
68695
+ return sourceRef ? {
68696
+ tag: "ready",
68697
+ sourceRef
68698
+ } : { tag: "unpublished-settings" };
68699
+ }
68700
+ //#endregion
67959
68701
  //#region ../blocks/src/pageRenderPreparation.ts
67960
68702
  /**
67961
68703
  * Stage two of the render plan.
@@ -68084,9 +68826,20 @@ function buildBlockOverrideProps(input) {
68084
68826
  imageResolveContext: input.imageResolveContext,
68085
68827
  blockId: block.id ?? null,
68086
68828
  contentVersionId: block.contentVersionId ?? null,
68829
+ ...newsletterBlockProps(block, input.content, dataContext?.previewStage),
68087
68830
  blockKind: block.kind
68088
68831
  };
68089
68832
  }
68833
+ function newsletterBlockProps(block, renderedContent, stage) {
68834
+ if (block.kind !== "block.newsletter-signup") return {};
68835
+ return { newsletterBlockSubmission: planNewsletterBlockSubmission({
68836
+ blockId: block.id,
68837
+ selectedContentVersionId: block.contentVersionId ?? null,
68838
+ publishedPlacement: block.publishedPlacement ?? null,
68839
+ renderedContent,
68840
+ stage
68841
+ }) };
68842
+ }
68090
68843
  /** Site, transport and session context a block needs to call back to the API. */
68091
68844
  function blockSessionProps(dataContext) {
68092
68845
  return {
@@ -68176,6 +68929,15 @@ function createBlockErrorBoundary() {
68176
68929
  const BlockErrorBoundary = createBlockErrorBoundary();
68177
68930
  //#endregion
68178
68931
  //#region ../blocks/src/pageRenderAdmission.ts
68932
+ /** Pair a published version with the content it authorises at the render boundary. */
68933
+ function readPublishedBlockPlacement(id, content) {
68934
+ if (id == null && content == null) return null;
68935
+ if (id == null || content == null) throw new Error("Published block placement requires both an ID and content");
68936
+ return {
68937
+ id,
68938
+ content
68939
+ };
68940
+ }
68179
68941
  function toPresentationPage(page) {
68180
68942
  if (!page) return null;
68181
68943
  return {
@@ -68186,6 +68948,8 @@ function toPresentationPage(page) {
68186
68948
  kind: block.kind,
68187
68949
  purpose: block.purpose,
68188
68950
  ...block.contentVersionId ? { contentVersionId: block.contentVersionId } : {},
68951
+ ...block.draftContentId !== void 0 ? { draftContentId: block.draftContentId } : {},
68952
+ ...block.publishedPlacement !== void 0 ? { publishedPlacement: block.publishedPlacement } : {},
68189
68953
  ...block.bindings ? { bindings: block.bindings } : {}
68190
68954
  };
68191
68955
  return block.admission.kind === "renderable" ? {
@@ -69961,6 +70725,9 @@ const containerResponsiveThemeCss = `/*
69961
70725
  .rb-h-4 {
69962
70726
  height: 1rem;
69963
70727
  }
70728
+ .rb-h-5 {
70729
+ height: 1.25rem;
70730
+ }
69964
70731
  .rb-h-8 {
69965
70732
  height: 2rem;
69966
70733
  }
@@ -73926,6 +74693,10 @@ const containerResponsiveThemeCss = `/*
73926
74693
  margin-bottom: 0.25rem;
73927
74694
  }
73928
74695
 
74696
+ :where(.theme-scope) :where([data-block='event-registration']) .er-consent-check {
74697
+ margin-top: 0.75rem;
74698
+ }
74699
+
73929
74700
  :where(.theme-scope) :where([data-block='event-registration']) .er-required {
73930
74701
  color: var(--er-required);
73931
74702
  }
@@ -78645,13 +79416,6 @@ const containerResponsiveThemeCss = `/*
78645
79416
  margin: 0;
78646
79417
  }
78647
79418
 
78648
- /* Inline field (checkbox, radio with label) */
78649
- :where(.theme-scope) :where([data-block="form"]) .fb-inline {
78650
- display: flex;
78651
- align-items: center;
78652
- gap: 0.5rem;
78653
- }
78654
-
78655
79419
  /* Success state */
78656
79420
  :where(.theme-scope) :where([data-block="form"]) .fb-success {
78657
79421
  background-color: var(--fb-success-bg);
@@ -80768,9 +81532,11 @@ const containerResponsiveThemeCss = `/*
80768
81532
  */
80769
81533
 
80770
81534
  /* Newsletter copy styling */
81535
+ /* Size only: weight, family and colour come from the theme's heading styles */
80771
81536
  :where(.theme-scope) :where([data-block="newsletter-signup"]) .newsletter-copy-title {
80772
- font-size: 1.5rem;
80773
- font-weight: 600;
81537
+ font-size: clamp(1.75rem, 1.35rem + 1.6vw, 2.5rem);
81538
+ line-height: 1.15;
81539
+ text-wrap: balance;
80774
81540
  }
80775
81541
 
80776
81542
  :where(.theme-scope) :where([data-block="newsletter-signup"]) .newsletter-copy-subtitle {
@@ -80794,37 +81560,150 @@ const containerResponsiveThemeCss = `/*
80794
81560
  gap: var(--rb-gap-sm, 0.75rem);
80795
81561
  }
80796
81562
 
80797
- /* Individual field styling */
81563
+ /* Extra preset fields (name, company...). Labels are visually hidden, so
81564
+ these sit in a row above the email entry. */
81565
+ :where(.theme-scope) .newsletter-extra-fields {
81566
+ display: grid;
81567
+ grid-template-columns: repeat(auto-fit, minmax(min(12rem, 100%), 1fr));
81568
+ gap: 0.5rem;
81569
+ }
81570
+
80798
81571
  :where(.theme-scope) .newsletter-field {
80799
81572
  display: flex;
80800
81573
  flex-direction: column;
80801
81574
  gap: 0.25rem;
81575
+ text-align: left;
80802
81576
  }
80803
81577
 
80804
- /* Topic choices (visitor picks what to hear about). Same treatment as the
80805
- form block's .fb-fieldset / .fb-inline, defined here because the newsletter
80806
- form also renders inside contact-newsletter and the site footer. */
80807
- :where(.theme-scope) .newsletter-topics {
81578
+ /* Email entry: the email field and the themed submit button share one shell.
81579
+ The shell's look (background, border, corners, focus ring) comes from the
81580
+ theme's input system via .form-input-group; this only handles layout. */
81581
+ :where(.theme-scope) .newsletter-entry {
81582
+ container-type: inline-size;
80808
81583
  display: flex;
80809
81584
  flex-direction: column;
80810
- gap: 0.5rem;
81585
+ gap: 0.375rem;
81586
+ text-align: left;
81587
+ }
81588
+
81589
+ :where(.theme-scope) .newsletter-entry-group > button {
81590
+ white-space: nowrap;
81591
+ }
81592
+
81593
+ /* Too narrow for field and button side by side (phones, footer columns):
81594
+ stack them inside the shell and keep pill themes from turning the taller
81595
+ shell into a capsule. */
81596
+ @container (max-width: 22rem) {
81597
+ :where(.theme-scope) .newsletter-entry .newsletter-entry-group {
81598
+ flex-direction: column;
81599
+ border-radius: min(var(--rb-input-radius, 0.5rem), 1rem);
81600
+ }
81601
+
81602
+ :where(.theme-scope) .newsletter-entry .newsletter-entry-group > button {
81603
+ width: 100%;
81604
+ justify-content: center;
81605
+ }
81606
+ }
81607
+
81608
+ /* Topic choices (visitor picks what to hear about) as toggle chips. Each chip
81609
+ is a real checkbox underneath; the chip is its visible face. */
81610
+ :where(.theme-scope) .newsletter-topics {
80811
81611
  border: none;
80812
81612
  padding: 0;
80813
81613
  margin: 0;
80814
81614
  min-width: 0;
80815
81615
  }
80816
81616
 
80817
- :where(.theme-scope) .newsletter-topics > legend {
81617
+ :where(.theme-scope) .newsletter-topics-legend {
80818
81618
  padding: 0;
80819
- margin-bottom: 0.25rem;
81619
+ margin-bottom: 0.625rem;
81620
+ font-size: 0.9375rem;
81621
+ color: var(--rb-surface-text-color, rgb(var(--tb-text, 17 24 39)));
80820
81622
  }
80821
81623
 
80822
- :where(.theme-scope) .newsletter-topic-choice {
81624
+ :where(.theme-scope) .newsletter-topic-chips {
80823
81625
  display: flex;
80824
- align-items: center;
81626
+ flex-wrap: wrap;
80825
81627
  gap: 0.5rem;
80826
81628
  }
80827
81629
 
81630
+ :where(.theme-scope) .newsletter-stacked .newsletter-topics-legend {
81631
+ width: 100%;
81632
+ }
81633
+
81634
+ :where(.theme-scope) .newsletter-stacked .newsletter-topic-chips {
81635
+ justify-content: center;
81636
+ }
81637
+
81638
+ :where(.theme-scope) .newsletter-topic-chip {
81639
+ position: relative;
81640
+ display: inline-flex;
81641
+ }
81642
+
81643
+ :where(.theme-scope) .newsletter-topic-chip > input {
81644
+ position: absolute;
81645
+ inset: 0;
81646
+ width: 100%;
81647
+ height: 100%;
81648
+ margin: 0;
81649
+ opacity: 0;
81650
+ cursor: pointer;
81651
+ }
81652
+
81653
+ :where(.theme-scope) .newsletter-topic-chip > span {
81654
+ display: inline-flex;
81655
+ align-items: center;
81656
+ gap: 0.375rem;
81657
+ padding: 0.4375rem 0.9375rem;
81658
+ border: 1px solid color-mix(in srgb, currentColor 35%, transparent);
81659
+ border-radius: var(--rb-button-radius, var(--rb-input-radius, 9999px));
81660
+ font-size: 0.9375rem;
81661
+ line-height: 1.3;
81662
+ color: var(--rb-surface-text-color, rgb(var(--tb-text, 17 24 39)));
81663
+ transition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease;
81664
+ }
81665
+
81666
+ /* Tick that grows in when the chip is on */
81667
+ :where(.theme-scope) .newsletter-topic-chip > span::before {
81668
+ content: "";
81669
+ width: 0;
81670
+ height: 0.7em;
81671
+ background-color: currentColor;
81672
+ clip-path: polygon(14% 52%, 0 67%, 38% 100%, 100% 22%, 85% 8%, 37% 70%);
81673
+ transition: width 0.15s ease;
81674
+ }
81675
+
81676
+ :where(.theme-scope) .newsletter-topic-chip:hover > span {
81677
+ border-color: currentColor;
81678
+ }
81679
+
81680
+ /* Same accent and mark colours as the theme's checkboxes */
81681
+ :where(.theme-scope) .newsletter-topic-chip > input:checked + span {
81682
+ background-color: var(--rb-check-accent, rgb(var(--tb-primary)));
81683
+ border-color: var(--rb-check-accent, rgb(var(--tb-primary)));
81684
+ color: var(--rb-check-mark, rgb(var(--tb-onPrimary, 255 255 255)));
81685
+ }
81686
+
81687
+ :where(.theme-scope) .newsletter-topic-chip > input:checked + span::before {
81688
+ width: 0.7em;
81689
+ }
81690
+
81691
+ :where(.theme-scope) .newsletter-topic-chip > input:focus-visible + span {
81692
+ outline: 2px solid var(--rb-check-accent, rgb(var(--tb-primary)));
81693
+ outline-offset: 2px;
81694
+ }
81695
+
81696
+ :where(.theme-scope) .newsletter-topic-chip > input:disabled + span {
81697
+ opacity: 0.6;
81698
+ }
81699
+
81700
+ @media (prefers-reduced-motion: reduce) {
81701
+ :where(.theme-scope) .newsletter-topic-chip > span,
81702
+ :where(.theme-scope) .newsletter-topic-chip > span::before {
81703
+ transition: none;
81704
+ }
81705
+ }
81706
+
80828
81707
  /* Error panel and field notes. The form block scopes these to its own
80829
81708
  data-block, so the newsletter form (which also renders in the footer)
80830
81709
  needs its own copy of the treatment. */
@@ -80842,13 +81721,7 @@ const containerResponsiveThemeCss = `/*
80842
81721
  color: var(--fb-error-text);
80843
81722
  }
80844
81723
 
80845
- /* Required indicator */
80846
- :where(.theme-scope) .newsletter-required {
80847
- color: rgb(var(--tb-primary));
80848
- margin-left: 0.125rem;
80849
- }
80850
-
80851
- /* Submit button container */
81724
+ /* Submit button container (only when a preset has no email field) */
80852
81725
  :where(.theme-scope) .newsletter-submit {
80853
81726
  margin-top: 0.5rem;
80854
81727
  }
@@ -80860,52 +81733,29 @@ const containerResponsiveThemeCss = `/*
80860
81733
  justify-content: center;
80861
81734
  }
80862
81735
 
80863
- /* Privacy note */
81736
+ /* Privacy note: quieter than the intro so the entry row leads */
80864
81737
  :where(.theme-scope) .newsletter-privacy-note {
80865
81738
  margin-top: 0.75rem;
80866
- font-size: 1rem;
80867
- line-height: 1.6;
80868
- color: var(--rb-surface-text-color, rgb(var(--tb-text, 17 24 39)));
81739
+ font-size: 0.8125rem;
81740
+ line-height: 1.5;
81741
+ color: var(--rb-surface-supporting-color, var(--rb-surface-text-color, rgb(var(--tb-text, 17 24 39))));
81742
+ opacity: 0.85;
80869
81743
  text-align: center;
80870
81744
  }
80871
81745
 
80872
81746
  /* =============================================================================
80873
- * Inline Variant - Horizontal layout
81747
+ * Inline Variant - left-aligned, wider entry row
80874
81748
  * =============================================================================
80875
81749
  */
80876
81750
 
80877
- :where(.theme-scope) .newsletter-inline .newsletter-form-fields {
80878
- flex-direction: row;
80879
- align-items: flex-end;
80880
- flex-wrap: wrap;
80881
- gap: var(--rb-gap-sm, 0.75rem);
80882
- }
80883
-
80884
- :where(.theme-scope) .newsletter-inline .newsletter-field {
80885
- flex: 1 1 auto;
80886
- min-width: 10rem;
80887
- }
80888
-
80889
- :where(.theme-scope) .newsletter-inline .newsletter-submit {
80890
- margin-top: 0;
80891
- flex-shrink: 0;
80892
- }
80893
-
80894
- :where(.theme-scope) .newsletter-inline .newsletter-topics {
80895
- flex-basis: 100%;
81751
+ :where(.theme-scope) .newsletter-inline .newsletter-form {
81752
+ max-width: 40rem;
81753
+ margin-left: 0;
81754
+ margin-right: 0;
80896
81755
  }
80897
81756
 
80898
- /* Mobile fallback for inline variant */
80899
- @container rb-site (max-width: 640px) {
80900
- @scope ([data-rb-responsive-mode="container"]) to (:scope [data-rb-responsive-mode]) {
80901
- :where(.theme-scope) .newsletter-inline .newsletter-form-fields {
80902
- flex-direction: column;
80903
- }
80904
-
80905
- :where(.theme-scope) .newsletter-inline .newsletter-field {
80906
- min-width: 100%;
80907
- }
80908
- }
81757
+ :where(.theme-scope) .newsletter-inline .newsletter-privacy-note {
81758
+ text-align: left;
80909
81759
  }
80910
81760
 
80911
81761
  /* =============================================================================
@@ -81043,12 +81893,6 @@ const containerResponsiveThemeCss = `/*
81043
81893
  margin: 0;
81044
81894
  }
81045
81895
 
81046
- :where(.theme-scope) :where([data-block="contact-newsletter"]) .fb-inline {
81047
- display: flex;
81048
- align-items: center;
81049
- gap: 0.5rem;
81050
- }
81051
-
81052
81896
  :where(.theme-scope) :where([data-block="contact-newsletter"]) .fb-success,
81053
81897
  :where(.theme-scope) :where([data-block="contact-newsletter"]) .fb-error,
81054
81898
  :where(.theme-scope) :where([data-block="contact-newsletter"]) .fb-empty {
@@ -82945,6 +83789,44 @@ const containerResponsiveThemeCss = `/*
82945
83789
  flex: 0 0 auto;
82946
83790
  }
82947
83791
  }
83792
+ }
83793
+
83794
+ /* =============================================================================
83795
+ * Site footer: social links
83796
+ *
83797
+ * Icon links get a 40px tap target with a hairline ring drawn from the link's
83798
+ * own colour, so it follows the footer's text colour on any surface. Links
83799
+ * without an icon (unknown platforms) stay plain text.
83800
+ * =============================================================================
83801
+ */
83802
+
83803
+ :where(.theme-scope) .rb-footer-socials {
83804
+ display: flex;
83805
+ flex-wrap: wrap;
83806
+ align-items: center;
83807
+ gap: 0.75rem 1.25rem;
83808
+ }
83809
+
83810
+ :where(.theme-scope) .rb-footer-social-link:has(> .rb-footer-social-icon) {
83811
+ display: inline-grid;
83812
+ place-items: center;
83813
+ width: 2.5rem;
83814
+ height: 2.5rem;
83815
+ border: 1px solid color-mix(in srgb, currentColor 22%, transparent);
83816
+ border-radius: 9999px;
83817
+ }
83818
+
83819
+ :where(.theme-scope) .rb-footer-socials:has(.rb-footer-social-icon) {
83820
+ gap: 0.5rem;
83821
+ }
83822
+
83823
+ :where(.theme-scope) .rb-footer-social-link:has(> .rb-footer-social-icon):hover {
83824
+ border-color: currentColor;
83825
+ }
83826
+
83827
+ :where(.theme-scope) .rb-footer-social-icon {
83828
+ width: 1.5rem;
83829
+ height: 1.5rem;
82948
83830
  }`;
82949
83831
  //#endregion
82950
83832
  //#region ../theme-core/src/ThemeScopeCore.tsx
@@ -83957,6 +84839,46 @@ z$1.object({ acceptExtraSiteCharge: z$1.boolean().optional() });
83957
84839
  //#region ../surfaces/src/index.ts
83958
84840
  const SURFACE_IDS = ["core", "macadamia"];
83959
84841
  const DEFAULT_SURFACE_ID = "core";
84842
+ /**
84843
+ * Root hosts for each surface, keyed by deployment tier. The tier-keyed shape
84844
+ * makes it impossible to mis-order entries: callers like
84845
+ * `buildSurfaceAwareDashboardOriginForSurfaceId` look up by tier directly
84846
+ * rather than relying on positional alignment between arrays.
84847
+ */
84848
+ const SURFACE_ROOT_HOSTS = {
84849
+ core: {
84850
+ local: "localhost",
84851
+ prod: "riverbankcms.com"
84852
+ },
84853
+ macadamia: {
84854
+ local: "macadamia.localhost",
84855
+ prod: "macadamia.studio"
84856
+ }
84857
+ };
84858
+ const SURFACE_SITE_ROOT_HOSTS = {
84859
+ core: {
84860
+ local: "localhost",
84861
+ prod: "riverbanksites.com"
84862
+ },
84863
+ macadamia: {
84864
+ local: "macadamia.localhost",
84865
+ prod: "macadamia.studio"
84866
+ }
84867
+ };
84868
+ const SURFACE_SITE_ROOT_HOST_ALIASES = { core: { prod: ["preview.riverbanksites.com"] } };
84869
+ function surfaceHostTableValues(table) {
84870
+ return Object.values(table).flatMap((byTier) => Object.values(byTier).flat());
84871
+ }
84872
+ function siteSlugLabelUnderRoot(host, siteRootHost) {
84873
+ if (!host.endsWith(`.${siteRootHost}`)) return [];
84874
+ return host.slice(0, host.length - siteRootHost.length - 1).split(".").slice(-1);
84875
+ }
84876
+ function deriveSurfaceOwnedSiteSlugs() {
84877
+ const siteRootHosts = [...surfaceHostTableValues(SURFACE_SITE_ROOT_HOSTS), ...surfaceHostTableValues(SURFACE_SITE_ROOT_HOST_ALIASES)];
84878
+ const labels = [...surfaceHostTableValues(SURFACE_ROOT_HOSTS), ...siteRootHosts].flatMap((host) => siteRootHosts.flatMap((root) => siteSlugLabelUnderRoot(host, root)));
84879
+ return [...new Set(labels)].sort();
84880
+ }
84881
+ deriveSurfaceOwnedSiteSlugs();
83960
84882
  [...SURFACE_IDS.filter((surfaceId) => surfaceId !== DEFAULT_SURFACE_ID)];
83961
84883
  //#endregion
83962
84884
  //#region ../api/src/url.ts
@@ -85003,6 +85925,7 @@ function parsePublicProductCategorySelector(value) {
85003
85925
  productCategoryEntryId: record.productCategoryEntryId
85004
85926
  };
85005
85927
  }
85928
+ z$1.enum(["public", "unlisted"], { error: "visibility must be 'public' or 'unlisted'" });
85006
85929
  //#endregion
85007
85930
  //#region ../api/src/bookingPaymentTermSchemas.ts
85008
85931
  const bookingDepositRefundPolicySchema = z$1.enum(["refundable", "non_refundable"]);
@@ -85674,21 +86597,39 @@ function buildSiteRenderSupport(site, mediaAssets) {
85674
86597
  function collectMediaAssetSidecar(mediaAssets) {
85675
86598
  return Array.isArray(mediaAssets) && mediaAssets.length > 0 ? mediaAssets : void 0;
85676
86599
  }
85677
- function convertPageResponseBlock(block) {
86600
+ function readBlockContentId(value, name) {
86601
+ if (value === null || value === void 0) return null;
86602
+ if (typeof value === "string") return value;
86603
+ throw new Error(`Invalid ${name} in page: expected string or null`);
86604
+ }
86605
+ function readTransportedBlockIdentity(block, kind, stage) {
86606
+ return {
86607
+ draftContentId: readBlockContentId(block.draftContentId, "draft content id"),
86608
+ publishedPlacement: stage === "preview" ? readPublishedBlockPlacement(readBlockContentId(block.publishedContentId, "published content id"), sanitizeNullableSdkRuntimeBlockContent(kind, readNestedContentRecord(block.publishedContent))) : null
86609
+ };
86610
+ }
86611
+ function convertPageResponseBlock(block, stage) {
85678
86612
  if (!isRecord$5(block)) throw new Error("Invalid block format in page API response");
86613
+ const header = readTransportedBlockHeader(block);
86614
+ const admission = readInvalidBlockAdmission(block.admission);
86615
+ return {
86616
+ ...header,
86617
+ ...readTransportedBlockIdentity(block, header.kind, stage),
86618
+ content: sanitizeSdkRuntimeBlockContent(header.kind, readContentRecord(block.content) ?? {}),
86619
+ draftContent: sanitizeNullableSdkRuntimeBlockContent(header.kind, readNestedContentRecord(block.draftContent)),
86620
+ ...admission ? { admission } : {}
86621
+ };
86622
+ }
86623
+ function readTransportedBlockHeader(block) {
85679
86624
  if (typeof block.id !== "string" && block.id !== null) throw new Error(`Invalid block id in page: expected string or null, got ${typeof block.id}`);
85680
86625
  if (typeof block.kind !== "string") throw new Error(`Invalid block kind in page: expected string, got ${typeof block.kind}`);
85681
86626
  if (typeof block.purpose !== "string") throw new Error(`Invalid block purpose in page: expected string, got ${typeof block.purpose}`);
85682
86627
  if (block.contentVersionId !== void 0 && block.contentVersionId !== null && typeof block.contentVersionId !== "string") throw new Error(`Invalid content version id in page: expected string or null, got ${typeof block.contentVersionId}`);
85683
- const admission = readInvalidBlockAdmission(block.admission);
85684
86628
  return {
85685
86629
  id: block.id,
85686
86630
  ...block.contentVersionId !== void 0 ? { contentVersionId: block.contentVersionId } : {},
85687
86631
  kind: block.kind,
85688
- purpose: block.purpose,
85689
- content: sanitizeSdkRuntimeBlockContent(block.kind, readContentRecord(block.content) ?? {}),
85690
- draftContent: sanitizeNullableSdkRuntimeBlockContent(block.kind, readNestedContentRecord(block.draftContent)),
85691
- ...admission ? { admission } : {}
86632
+ purpose: block.purpose
85692
86633
  };
85693
86634
  }
85694
86635
  function readInvalidBlockAdmission(value) {
@@ -85701,7 +86642,7 @@ function buildPageOutline(input) {
85701
86642
  name: input.name,
85702
86643
  path: input.path ?? input.fallbackPath,
85703
86644
  purpose: input.purpose,
85704
- blocks: input.blocks.map(convertPageResponseBlock)
86645
+ blocks: input.blocks.map((block) => convertPageResponseBlock(block, input.previewStage))
85705
86646
  };
85706
86647
  }
85707
86648
  function buildRenderablePageOutline(input) {
@@ -85727,6 +86668,8 @@ function projectRenderablePageOutline(page) {
85727
86668
  function admitSdkRuntimePageBlock(block, customBlocks) {
85728
86669
  const base = {
85729
86670
  id: block.id,
86671
+ draftContentId: block.draftContentId,
86672
+ publishedPlacement: block.publishedPlacement,
85730
86673
  ...block.contentVersionId !== void 0 ? { contentVersionId: block.contentVersionId } : {},
85731
86674
  kind: block.kind,
85732
86675
  purpose: block.purpose,
@@ -88320,7 +89263,8 @@ async function processTemplatePage(input) {
88320
89263
  block,
88321
89264
  bindingContext: input.bindingContext,
88322
89265
  slotContent: input.slotContent,
88323
- customBlocks: input.customBlocks
89266
+ customBlocks: input.customBlocks,
89267
+ previewStage: input.previewStage
88324
89268
  }));
88325
89269
  if (blocks.length === 0) return {
88326
89270
  templatePage: null,
@@ -88351,7 +89295,7 @@ function resolveTemplateBlockSequence(input) {
88351
89295
  if (slotKey) return selectBlocksForDeclaredEntrySlot({
88352
89296
  declaredSlotKey: slotKey,
88353
89297
  entrySlots: input.slotContent ?? []
88354
- }).map((slotBlock) => admitEntrySlotBlock(slotBlock, input.customBlocks));
89298
+ }).map((slotBlock) => admitEntrySlotBlock(slotBlock, input.customBlocks, input.previewStage));
88355
89299
  if (block.blockKind === "system.entry-slot") return [];
88356
89300
  return [resolveTemplateBlock(block, input.bindingContext, input.customBlocks)];
88357
89301
  }
@@ -88385,10 +89329,11 @@ function readEntrySlotKey(block) {
88385
89329
  const parsed = parseSlotKey(block.content?.slotKey);
88386
89330
  return parsed.ok ? parsed.value : null;
88387
89331
  }
88388
- function admitEntrySlotBlock(block, customBlocks) {
89332
+ function admitEntrySlotBlock(block, customBlocks, previewStage) {
88389
89333
  const base = {
88390
89334
  id: block.id ?? block.blockId ?? null,
88391
89335
  contentVersionId: block.contentVersionId,
89336
+ ...entrySlotBlockIdentity(block, previewStage),
88392
89337
  kind: block.kind,
88393
89338
  purpose: block.purpose,
88394
89339
  ...isRecord$1(block.bindings) ? { bindings: block.bindings } : {}
@@ -88409,6 +89354,12 @@ function admitEntrySlotBlock(block, customBlocks) {
88409
89354
  error: renderable.error
88410
89355
  });
88411
89356
  }
89357
+ function entrySlotBlockIdentity(block, previewStage) {
89358
+ return {
89359
+ draftContentId: block.draftContentId ?? null,
89360
+ publishedPlacement: previewStage === "preview" ? readPublishedBlockPlacement(block.publishedContentId, isRecord$1(block.publishedContent) && isRecord$1(block.publishedContent.data) ? block.publishedContent.data : null) : null
89361
+ };
89362
+ }
88412
89363
  //#endregion
88413
89364
  //#region src/rendering/helpers/loadContent.ts
88414
89365
  /**
@@ -88580,15 +89531,18 @@ async function loadContentFromContentResponseWithDeps(deps, params) {
88580
89531
  entry,
88581
89532
  templatePage,
88582
89533
  resolvedData,
88583
- dataContext: { contentEntry: {
88584
- ...entry.content ?? {},
88585
- id: entry.id,
88586
- slug: entry.slug,
88587
- contentTypeSlug: entry.type,
88588
- _entryId: entry.id,
88589
- _entrySlug: entry.slug,
88590
- _contentTypeSlug: entry.type
88591
- } },
89534
+ dataContext: {
89535
+ previewStage,
89536
+ contentEntry: {
89537
+ ...entry.content ?? {},
89538
+ id: entry.id,
89539
+ slug: entry.slug,
89540
+ contentTypeSlug: entry.type,
89541
+ _entryId: entry.id,
89542
+ _entrySlug: entry.slug,
89543
+ _contentTypeSlug: entry.type
89544
+ }
89545
+ },
88592
89546
  ...templateContentSupport
88593
89547
  };
88594
89548
  }
@@ -88649,6 +89603,7 @@ async function loadContentFromContentResponseWithDeps(deps, params) {
88649
89603
  templatePage,
88650
89604
  resolvedData,
88651
89605
  dataContext: {
89606
+ previewStage,
88652
89607
  pageSurface: {
88653
89608
  ...pageSurface.content ?? {},
88654
89609
  id: pageSurface.id,
@@ -88665,13 +89620,13 @@ async function loadContentFromContentResponseWithDeps(deps, params) {
88665
89620
  const { page: pageData } = contentResponse;
88666
89621
  const pageRecord = pageData;
88667
89622
  const canonicalPagePath = pageData.path ?? pageRecord.path ?? "/";
88668
- const draftPagePath = pageRecord.draftPath ?? pageRecord.path ?? canonicalPagePath;
88669
89623
  const pageOutline = buildRenderablePageOutline({
88670
89624
  name: pageData.name,
88671
89625
  path: canonicalPagePath,
88672
89626
  fallbackPath: "/",
88673
89627
  purpose: pageData.purpose,
88674
89628
  blocks: pageData.blocks,
89629
+ previewStage,
88675
89630
  customBlocks: support.customBlocks
88676
89631
  });
88677
89632
  const resolvedData = await resolveBlockDataWithDeps(deps, {
@@ -88690,26 +89645,14 @@ async function loadContentFromContentResponseWithDeps(deps, params) {
88690
89645
  type: "page",
88691
89646
  pageId: pageRecord.id,
88692
89647
  routeId: pageRecord.routeId ?? null,
88693
- pageMetadata: {
88694
- draftTitle: pageRecord.draftTitle ?? pageRecord.name ?? pageData.name,
88695
- draftPath: draftPagePath,
88696
- draftStatus: pageRecord.draftStatus ?? pageRecord.status ?? "draft",
88697
- title: pageRecord.name ?? pageData.name,
88698
- path: canonicalPagePath,
88699
- status: pageRecord.status ?? pageRecord.draftStatus ?? "draft",
88700
- publishedAt: pageRecord.publishedAt ?? null,
88701
- draftMetaTitle: pageRecord.draftMetaTitle ?? null,
88702
- draftMetaDescription: pageRecord.draftMetaDescription ?? null,
88703
- publishedMetaTitle: pageRecord.publishedMetaTitle ?? null,
88704
- publishedMetaDescription: pageRecord.publishedMetaDescription ?? null,
88705
- ogImageId: pageRecord.ogImageId ?? null
88706
- },
89648
+ pageMetadata: projectPagePreviewMetadata(pageRecord, pageData.name, canonicalPagePath),
88707
89649
  page: pageOutline,
88708
89650
  runtimeJoins: pageData.runtimeJoins,
88709
89651
  theme: support.theme,
88710
89652
  siteId,
88711
89653
  ...support.customBlocks ? { customBlocks: support.customBlocks } : {},
88712
89654
  resolvedData,
89655
+ dataContext: { previewStage },
88713
89656
  bookingOfferingPresets: support.bookingOfferingPresets,
88714
89657
  mailingList: support.mailingList,
88715
89658
  bookingTimeZone: support.bookingTimeZone,
@@ -88722,6 +89665,32 @@ async function loadContentFromContentResponseWithDeps(deps, params) {
88722
89665
  ...support.mediaAssets ? { mediaAssets: support.mediaAssets } : {}
88723
89666
  };
88724
89667
  }
89668
+ function projectPagePreviewMetadata(page, pageName, canonicalPath) {
89669
+ return {
89670
+ ...projectDraftPageMetadata(page, pageName, canonicalPath),
89671
+ ...projectPublishedPageMetadata(page, pageName, canonicalPath)
89672
+ };
89673
+ }
89674
+ function projectDraftPageMetadata(page, pageName, canonicalPath) {
89675
+ return {
89676
+ draftTitle: page.draftTitle ?? page.name ?? pageName,
89677
+ draftPath: page.draftPath ?? page.path ?? canonicalPath,
89678
+ draftStatus: page.draftStatus ?? page.status ?? "draft",
89679
+ draftMetaTitle: page.draftMetaTitle ?? null,
89680
+ draftMetaDescription: page.draftMetaDescription ?? null
89681
+ };
89682
+ }
89683
+ function projectPublishedPageMetadata(page, pageName, canonicalPath) {
89684
+ return {
89685
+ title: page.name ?? pageName,
89686
+ path: canonicalPath,
89687
+ status: page.status ?? page.draftStatus ?? "draft",
89688
+ publishedAt: page.publishedAt ?? null,
89689
+ publishedMetaTitle: page.publishedMetaTitle ?? null,
89690
+ publishedMetaDescription: page.publishedMetaDescription ?? null,
89691
+ ogImageId: page.ogImageId ?? null
89692
+ };
89693
+ }
88725
89694
  /**
88726
89695
  * Type guard to check if API response is an entry
88727
89696
  */
@@ -88801,7 +89770,7 @@ function toBlocksCommonProps(props) {
88801
89770
  return {
88802
89771
  page: props.page,
88803
89772
  runtimeJoins: props.runtimeJoins,
88804
- dataContext: props.dataContext ? toBlocksPageRendererDataContext(props.dataContext) : void 0,
89773
+ dataContext: toBlocksPageRendererDataContext(props.dataContext),
88805
89774
  routeMap: props.routeMap,
88806
89775
  wrapBlock: props.wrapBlock,
88807
89776
  registry: props.registry,
@@ -88888,14 +89857,14 @@ function resolveSdkBookingTimeZone(timeZone) {
88888
89857
  }
88889
89858
  function buildPageRouteRenderContext(dataContext) {
88890
89859
  return {
88891
- pathname: dataContext?.pathname,
88892
- occurrenceContext: dataContext?.occurrenceContext ?? null,
88893
- entrySubrouteContext: dataContext?.entrySubrouteContext ?? null,
88894
- contentEntry: dataContext?.contentEntry ?? null,
88895
- pageSurface: dataContext?.pageSurface ?? null,
88896
- subject: dataContext?.subject ?? null,
88897
- editableRouteMetadataFieldIds: dataContext?.editableRouteMetadataFieldIds ?? null,
88898
- previewStage: dataContext?.previewStage
89860
+ pathname: dataContext.pathname,
89861
+ occurrenceContext: dataContext.occurrenceContext ?? null,
89862
+ entrySubrouteContext: dataContext.entrySubrouteContext ?? null,
89863
+ contentEntry: dataContext.contentEntry ?? null,
89864
+ pageSurface: dataContext.pageSurface ?? null,
89865
+ subject: dataContext.subject ?? null,
89866
+ editableRouteMetadataFieldIds: dataContext.editableRouteMetadataFieldIds ?? null,
89867
+ previewStage: dataContext.previewStage
88899
89868
  };
88900
89869
  }
88901
89870
  function PageContent(props) {
@@ -88909,10 +89878,10 @@ function PageContent(props) {
88909
89878
  apiBaseUrl,
88910
89879
  portalToken,
88911
89880
  previewToken,
88912
- readAuthority: readAuthority ?? dataContext?.readAuthority,
89881
+ readAuthority: readAuthority ?? dataContext.readAuthority,
88913
89882
  resolvedData,
88914
89883
  bookingOfferingPresets: bookingOfferingPresets ?? [],
88915
- mailingList: mailingList ?? dataContext?.mailingList,
89884
+ mailingList: mailingList ?? dataContext.mailingList,
88916
89885
  bookingTimeZone: resolveSdkBookingTimeZone(bookingTimeZone),
88917
89886
  routes: routeMap,
88918
89887
  pagesByIdentifier,
@@ -90117,7 +91086,7 @@ var CircuitOpenError = class extends Error {
90117
91086
  * 1. This constant
90118
91087
  * 2. The "version" field in package.json
90119
91088
  */
90120
- const SDK_VERSION = "0.145.0";
91089
+ const SDK_VERSION = "0.146.0";
90121
91090
  //#endregion
90122
91091
  //#region src/next/content-load-failure.ts
90123
91092
  const SdkContentLoadError = RiverbankContentLoadError;
@@ -90401,7 +91370,7 @@ async function renderPage(input, page, dataContext) {
90401
91370
  });
90402
91371
  }
90403
91372
  async function renderSdkContent(input) {
90404
- const previewStage = input.preview ? "preview" : "published";
91373
+ const previewStage = input.content.dataContext.previewStage;
90405
91374
  const occurrenceContext = input.entrySubrouteContext?.kind === "event-occurrence" ? input.entrySubrouteContext.occurrence : null;
90406
91375
  const render = (page, dataContext) => renderPage(input, page, dataContext);
90407
91376
  if (isPageContent(input.content)) return {
@@ -90650,13 +91619,11 @@ async function renderResolvedCatchAllPage(runtime, input) {
90650
91619
  ...commonRenderInput,
90651
91620
  blockOverrides: runtime.options.blockOverrides,
90652
91621
  kind: "overrides-only",
90653
- preview: runtime.preview,
90654
91622
  rendering: admission.rendering
90655
91623
  }) : await renderSdkContent({
90656
91624
  ...commonRenderInput,
90657
91625
  blockOverrides: runtime.options.blockOverrides,
90658
91626
  kind: "themed",
90659
- preview: runtime.preview,
90660
91627
  theme: admission.theme,
90661
91628
  themeRuntime: runtime.themeRuntime
90662
91629
  });