@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
@@ -961,6 +961,27 @@ function formError(field) {
961
961
  field
962
962
  });
963
963
  }
964
+ //#endregion
965
+ //#region ../core/src/mailing-list-targeting.ts
966
+ function sameMailingListPlacementTargeting(left, right) {
967
+ if (left.mode !== right.mode) return false;
968
+ if (left.mode === "default" || right.mode === "default") return true;
969
+ if (left.provider !== right.provider || left.selection.tag !== right.selection.tag) return false;
970
+ if (left.provider === "mailchimp" && (right.provider !== "mailchimp" || left.audienceId !== right.audienceId)) return false;
971
+ return sameIds(targetingSelectionIds(left), targetingSelectionIds(right));
972
+ }
973
+ function targetingSelectionIds(targeting) {
974
+ switch (targeting.provider) {
975
+ case "native": return targeting.selection.tag === "fixed" ? targeting.selection.topicIds : targeting.selection.offeredTopicIds;
976
+ case "brevo": return targeting.selection.tag === "fixed" ? targeting.selection.listIds : targeting.selection.offeredListIds;
977
+ case "mailchimp": return targeting.selection.tag === "fixed" ? targeting.selection.interestIds : targeting.selection.offeredInterestIds;
978
+ }
979
+ }
980
+ function sameIds(left, right) {
981
+ const leftIds = new Set(left);
982
+ const rightIds = new Set(right);
983
+ return leftIds.size === left.length && rightIds.size === right.length && leftIds.size === rightIds.size && [...leftIds].every((id) => rightIds.has(id));
984
+ }
964
985
  function planMailingListChoicePresentation(targeting) {
965
986
  if (targeting.mode === "default" || targeting.selection.tag === "fixed") return { tag: "hidden" };
966
987
  switch (targeting.provider) {
@@ -28372,6 +28393,7 @@ const publicEventLoaderQuerySchemaShape = {
28372
28393
  seriesSlug: z$1.string().optional(),
28373
28394
  includeOccurrenceId: z$1.string().optional(),
28374
28395
  readIntent: z$1.string().optional(),
28396
+ detailAdmission: z$1.string().optional(),
28375
28397
  detailLevel: z$1.string().optional(),
28376
28398
  readProfile: z$1.string().optional()
28377
28399
  };
@@ -28538,11 +28560,11 @@ const publicEventBookingAvailabilitySchema = z$1.discriminatedUnion("kind", [z$1
28538
28560
  "series_archived",
28539
28561
  "parent_archived",
28540
28562
  "parent_inconsistent",
28541
- "not_public",
28542
28563
  "already_started",
28543
28564
  "enrollment_closed"
28544
28565
  ])
28545
28566
  })]);
28567
+ const publicEventBookingClosedDetailSchema = z$1.discriminatedUnion("kind", [z$1.object({ kind: z$1.literal("opensSoon") }), z$1.object({ kind: z$1.literal("paused") })]);
28546
28568
  const publicRunSessionSchema = z$1.object({
28547
28569
  occurrenceId: z$1.string(),
28548
28570
  startsAt: z$1.string(),
@@ -28587,6 +28609,7 @@ const publicEventBaseSchema = z$1.object({
28587
28609
  destination: publicEventDestinationSchema,
28588
28610
  requiresRegistration: z$1.boolean(),
28589
28611
  bookingAvailability: publicEventBookingAvailabilitySchema,
28612
+ bookingClosedDetail: publicEventBookingClosedDetailSchema.optional(),
28590
28613
  deliveryMode: z$1.enum([
28591
28614
  "in_person",
28592
28615
  "online",
@@ -30522,6 +30545,7 @@ const SOCIAL_ICON_NAMES = [
30522
30545
  "SocialInstagram",
30523
30546
  "SocialLinkedIn",
30524
30547
  "SocialTikTok",
30548
+ "SocialWhatsApp",
30525
30549
  "SocialX",
30526
30550
  "SocialYouTube"
30527
30551
  ];
@@ -30558,6 +30582,7 @@ const socialIcons = {
30558
30582
  /* @__PURE__ */ jsx("path", { d: "M10.5 9v10" })
30559
30583
  ] })),
30560
30584
  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" })] })),
30585
+ 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" })] })),
30561
30586
  SocialX: createIcon("SocialXIcon", /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("path", { d: "m5 4 14 16" }), /* @__PURE__ */ jsx("path", { d: "M19 4 5 20" })] })),
30562
30587
  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" })] }))
30563
30588
  };
@@ -33449,7 +33474,6 @@ function closedEventBookingLabel(reason) {
33449
33474
  case "series_archived":
33450
33475
  case "parent_archived":
33451
33476
  case "parent_inconsistent":
33452
- case "not_public":
33453
33477
  case "already_started":
33454
33478
  case "enrollment_closed": return "Registration closed";
33455
33479
  default: return assertNever$21(reason);
@@ -41306,6 +41330,12 @@ function withOptionalPhone(fields, includePhone) {
41306
41330
  }
41307
41331
  //#endregion
41308
41332
  //#region ../blocks/src/system/runtime/nodes/newsletter-form.interactive.ts
41333
+ const NEWSLETTER_SIGNUPS_PAUSED_MESSAGE = "We can’t accept signups right now. Please try again later.";
41334
+ function newsletterBlockSubmissionMessage(target) {
41335
+ if (target.tag === "block-source") return target.sourceRef ? null : NEWSLETTER_SIGNUPS_PAUSED_MESSAGE;
41336
+ if (target.tag !== "unpublished-preview") return null;
41337
+ 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.";
41338
+ }
41309
41339
  const newsletterButtonVariantSchema = blockButtonRoleSchema;
41310
41340
  const mailingListContextSchema = z$1.unknown().transform((value, ctx) => {
41311
41341
  const parsed = parseMailingListRuntimeContext(value);
@@ -41346,6 +41376,11 @@ const mailingListContentVersionIdSchema = z$1.string().transform((value, ctx) =>
41346
41376
  });
41347
41377
  return z$1.NEVER;
41348
41378
  });
41379
+ const mailingListSignupBlockSourceRefSchema = z$1.object({
41380
+ tag: z$1.literal("block_ref"),
41381
+ blockId: mailingListSignupBlockIdSchema,
41382
+ contentVersionId: mailingListContentVersionIdSchema
41383
+ });
41349
41384
  const signedMailingListSourceTokenSchema = z$1.string().trim().min(1).transform(parseRequiredMailingListSignedSourceToken);
41350
41385
  const newsletterSourceCommonSchema = z$1.object({
41351
41386
  siteId: z$1.string().optional(),
@@ -41360,7 +41395,15 @@ const newsletterSourceSchema = z$1.discriminatedUnion("source", [
41360
41395
  newsletterSourceCommonSchema.extend({
41361
41396
  source: z$1.literal("block"),
41362
41397
  blockId: z$1.string().nullable().optional(),
41363
- contentVersionId: z$1.string().nullable().optional()
41398
+ newsletterBlockSubmission: z$1.discriminatedUnion("tag", [
41399
+ z$1.object({
41400
+ tag: z$1.literal("ready"),
41401
+ sourceRef: mailingListSignupBlockSourceRefSchema
41402
+ }),
41403
+ z$1.object({ tag: z$1.literal("unpublished-form") }),
41404
+ z$1.object({ tag: z$1.literal("unpublished-settings") }),
41405
+ z$1.object({ tag: z$1.literal("unavailable") })
41406
+ ])
41364
41407
  }),
41365
41408
  newsletterSourceCommonSchema.extend({
41366
41409
  source: z$1.literal("signed-footer"),
@@ -41389,11 +41432,7 @@ const newsletterHydrationSchema = z$1.object({
41389
41432
  target: z$1.discriminatedUnion("tag", [
41390
41433
  z$1.object({
41391
41434
  tag: z$1.literal("block-source"),
41392
- sourceRef: z$1.object({
41393
- tag: z$1.literal("block_ref"),
41394
- blockId: mailingListSignupBlockIdSchema,
41395
- contentVersionId: mailingListContentVersionIdSchema
41396
- }).nullable()
41435
+ sourceRef: mailingListSignupBlockSourceRefSchema.nullable()
41397
41436
  }),
41398
41437
  z$1.object({
41399
41438
  tag: z$1.literal("signed-footer-source"),
@@ -41402,7 +41441,11 @@ const newsletterHydrationSchema = z$1.object({
41402
41441
  token: signedMailingListSourceTokenSchema
41403
41442
  })
41404
41443
  }),
41405
- z$1.object({ tag: z$1.literal("preview") })
41444
+ z$1.object({ tag: z$1.literal("preview") }),
41445
+ z$1.object({
41446
+ tag: z$1.literal("unpublished-preview"),
41447
+ reason: z$1.enum(["unpublished-form", "unpublished-settings"])
41448
+ })
41406
41449
  ]),
41407
41450
  setupRevision: z$1.number().int().positive().nullable(),
41408
41451
  choiceProvider: z$1.enum([
@@ -41471,16 +41514,21 @@ const newsletterFormBlockRuntime = defineProgressiveBlockRuntime({
41471
41514
  });
41472
41515
  function projectNewsletterFormHydrationTarget(source) {
41473
41516
  switch (source.source) {
41474
- case "block": {
41475
- const sourceRef = buildMailingListSignupBlockSourceRef(source.blockId, source.contentVersionId);
41476
- if (sourceRef?.tag === "block_ref") return {
41517
+ case "block": switch (source.newsletterBlockSubmission.tag) {
41518
+ case "unpublished-form":
41519
+ case "unpublished-settings": return {
41520
+ tag: "unpublished-preview",
41521
+ reason: source.newsletterBlockSubmission.tag
41522
+ };
41523
+ case "ready": return {
41477
41524
  tag: "block-source",
41478
- sourceRef
41525
+ sourceRef: source.newsletterBlockSubmission.sourceRef
41479
41526
  };
41480
- return {
41527
+ case "unavailable": return {
41481
41528
  tag: "block-source",
41482
41529
  sourceRef: null
41483
41530
  };
41531
+ default: return assertNever$21(source.newsletterBlockSubmission);
41484
41532
  }
41485
41533
  case "signed-footer": return {
41486
41534
  tag: "signed-footer-source",
@@ -41549,6 +41597,7 @@ function buildNewsletterFormInteractiveIslandProps(props) {
41549
41597
  const decoded = newsletterFormBlockRuntime.contracts.source.decode(props);
41550
41598
  const source = isDecodeSuccess(decoded) ? decoded.value : {
41551
41599
  ...props,
41600
+ ...props.source === "block" ? { newsletterBlockSubmission: { tag: "unavailable" } } : {},
41552
41601
  mailingList: void 0,
41553
41602
  targeting: { mode: "default" }
41554
41603
  };
@@ -43963,6 +44012,156 @@ function FeedbackMessage({ tone, treatment = "panel", children, className, id, t
43963
44012
  });
43964
44013
  }
43965
44014
  //#endregion
44015
+ //#region ../blocks/src/system/runtime/shared/components/CheckboxChoice.tsx
44016
+ /**
44017
+ * The customer-facing checkbox every block renders. Styling comes from the
44018
+ * theme's input CSS (`.form-check`, `.form-checkbox`), so it follows each
44019
+ * site's input colours, borders and corners.
44020
+ */
44021
+ function CheckboxChoice({ label, presentation = "row", className, ...inputProps }) {
44022
+ return /* @__PURE__ */ jsxs("label", {
44023
+ className: clsx("form-check", presentation === "tile" && "form-check--tile", className),
44024
+ children: [/* @__PURE__ */ jsx("input", {
44025
+ ...inputProps,
44026
+ type: "checkbox",
44027
+ className: "form-checkbox"
44028
+ }), /* @__PURE__ */ jsx("span", {
44029
+ className: "form-check-label",
44030
+ children: label
44031
+ })]
44032
+ });
44033
+ }
44034
+ //#endregion
44035
+ //#region ../blocks/src/system/runtime/nodes/form.fields.tsx
44036
+ function fieldBasics(field) {
44037
+ return {
44038
+ inputId: `f_${field.id}`,
44039
+ label: String(field.label ?? field.id),
44040
+ required: Boolean(field.required)
44041
+ };
44042
+ }
44043
+ function textInputType(type) {
44044
+ return type === "email" || type === "url" || type === "tel" || type === "number" ? type : "text";
44045
+ }
44046
+ function textInputConstraints(field, inputType) {
44047
+ if (inputType === "number") return {
44048
+ ...typeof field.min === "number" ? { min: field.min } : {},
44049
+ ...typeof field.max === "number" ? { max: field.max } : {}
44050
+ };
44051
+ return {
44052
+ ...typeof field.minLength === "number" ? { minLength: field.minLength } : {},
44053
+ ...typeof field.maxLength === "number" ? { maxLength: field.maxLength } : {},
44054
+ ...typeof field.pattern === "string" && field.pattern ? { pattern: field.pattern } : {}
44055
+ };
44056
+ }
44057
+ function LabelledField({ basics, children }) {
44058
+ return /* @__PURE__ */ jsxs("div", {
44059
+ className: "fb-field",
44060
+ children: [/* @__PURE__ */ jsx("label", {
44061
+ htmlFor: basics.inputId,
44062
+ className: "form-label",
44063
+ children: basics.label
44064
+ }), children]
44065
+ });
44066
+ }
44067
+ function TextareaField({ field }) {
44068
+ const basics = fieldBasics(field);
44069
+ return /* @__PURE__ */ jsx(LabelledField, {
44070
+ basics,
44071
+ children: /* @__PURE__ */ jsx("textarea", {
44072
+ id: basics.inputId,
44073
+ name: field.id,
44074
+ required: basics.required,
44075
+ placeholder: field.placeholder,
44076
+ rows: field.rows,
44077
+ className: "form-textarea"
44078
+ })
44079
+ });
44080
+ }
44081
+ function SelectField({ field }) {
44082
+ const basics = fieldBasics(field);
44083
+ const options = field.options ?? [];
44084
+ const multiple = Boolean(field.multiple);
44085
+ return /* @__PURE__ */ jsx(LabelledField, {
44086
+ basics,
44087
+ children: /* @__PURE__ */ jsxs("select", {
44088
+ id: basics.inputId,
44089
+ name: field.id,
44090
+ multiple,
44091
+ required: basics.required,
44092
+ className: "form-select",
44093
+ children: [!multiple && /* @__PURE__ */ jsx("option", {
44094
+ value: "",
44095
+ children: "Select…"
44096
+ }), options.map((opt) => /* @__PURE__ */ jsx("option", {
44097
+ value: opt.value,
44098
+ children: opt.label
44099
+ }, opt.value))]
44100
+ })
44101
+ });
44102
+ }
44103
+ function RadioField({ field }) {
44104
+ const basics = fieldBasics(field);
44105
+ const options = field.options ?? [];
44106
+ return /* @__PURE__ */ jsxs("fieldset", {
44107
+ className: "fb-fieldset",
44108
+ children: [/* @__PURE__ */ jsx("legend", {
44109
+ className: "form-label",
44110
+ children: basics.label
44111
+ }), options.map((opt) => /* @__PURE__ */ jsxs("label", {
44112
+ className: "form-check",
44113
+ children: [/* @__PURE__ */ jsx("input", {
44114
+ type: "radio",
44115
+ name: field.id,
44116
+ value: opt.value,
44117
+ required: basics.required,
44118
+ className: "form-radio"
44119
+ }), /* @__PURE__ */ jsx("span", {
44120
+ className: "form-check-label",
44121
+ children: opt.label
44122
+ })]
44123
+ }, opt.value))]
44124
+ });
44125
+ }
44126
+ function TextInputField({ field, type }) {
44127
+ const basics = fieldBasics(field);
44128
+ const inputType = textInputType(type);
44129
+ return /* @__PURE__ */ jsx(LabelledField, {
44130
+ basics,
44131
+ children: /* @__PURE__ */ jsx("input", {
44132
+ id: basics.inputId,
44133
+ name: field.id,
44134
+ type: inputType,
44135
+ required: basics.required,
44136
+ placeholder: field.placeholder,
44137
+ ...textInputConstraints(field, inputType),
44138
+ className: "form-input"
44139
+ })
44140
+ });
44141
+ }
44142
+ function FormFieldControl({ field }) {
44143
+ const type = String(field.type ?? "text");
44144
+ switch (type) {
44145
+ case "textarea": return /* @__PURE__ */ jsx(TextareaField, { field });
44146
+ case "select": return /* @__PURE__ */ jsx(SelectField, { field });
44147
+ case "radio": return /* @__PURE__ */ jsx(RadioField, { field });
44148
+ case "checkbox":
44149
+ case "consent": {
44150
+ const basics = fieldBasics(field);
44151
+ return /* @__PURE__ */ jsx(CheckboxChoice, {
44152
+ name: field.id,
44153
+ required: basics.required,
44154
+ label: basics.label,
44155
+ presentation: type === "consent" ? "tile" : "row"
44156
+ });
44157
+ }
44158
+ default: return /* @__PURE__ */ jsx(TextInputField, {
44159
+ field,
44160
+ type
44161
+ });
44162
+ }
44163
+ }
44164
+ //#endregion
43966
44165
  //#region ../blocks/src/system/runtime/nodes/form.server.tsx
43967
44166
  const FormNodeSSR = ({ blockId, value, submitLabel, successMessage, className, onSubmit, action = "/api/forms/submit", siteId, apiBaseUrl, spamProtectionEnabled }) => {
43968
44167
  const islandProps = buildFormInteractiveIslandProps({
@@ -43986,107 +44185,7 @@ const FormNodeSSR = ({ blockId, value, submitLabel, successMessage, className, o
43986
44185
  })]
43987
44186
  });
43988
44187
  const groups = display.groups;
43989
- const renderField = (field) => {
43990
- const inputId = `f_${field.id}`;
43991
- const label = String(field.label ?? field.id);
43992
- const required = Boolean(field.required);
43993
- const type = String(field.type ?? "text");
43994
- if (type === "textarea") return /* @__PURE__ */ jsxs("div", {
43995
- className: "fb-field",
43996
- children: [/* @__PURE__ */ jsx("label", {
43997
- htmlFor: inputId,
43998
- className: "form-label",
43999
- children: label
44000
- }), /* @__PURE__ */ jsx("textarea", {
44001
- id: inputId,
44002
- name: field.id,
44003
- required,
44004
- placeholder: field.placeholder,
44005
- rows: field.rows,
44006
- className: "form-textarea"
44007
- })]
44008
- }, field.id);
44009
- if (type === "select") {
44010
- const options = field.options ?? [];
44011
- const multiple = Boolean(field.multiple);
44012
- return /* @__PURE__ */ jsxs("div", {
44013
- className: "fb-field",
44014
- children: [/* @__PURE__ */ jsx("label", {
44015
- htmlFor: inputId,
44016
- className: "form-label",
44017
- children: label
44018
- }), /* @__PURE__ */ jsxs("select", {
44019
- id: inputId,
44020
- name: field.id,
44021
- multiple,
44022
- required,
44023
- className: "form-select",
44024
- children: [!multiple && /* @__PURE__ */ jsx("option", {
44025
- value: "",
44026
- children: "Select…"
44027
- }), options.map((opt) => /* @__PURE__ */ jsx("option", {
44028
- value: opt.value,
44029
- children: opt.label
44030
- }, opt.value))]
44031
- })]
44032
- }, field.id);
44033
- }
44034
- if (type === "radio") {
44035
- const options = field.options ?? [];
44036
- return /* @__PURE__ */ jsxs("fieldset", {
44037
- className: "fb-fieldset",
44038
- children: [/* @__PURE__ */ jsx("legend", {
44039
- className: "form-label",
44040
- children: label
44041
- }), options.map((opt) => /* @__PURE__ */ jsxs("label", {
44042
- className: "fb-inline form-label",
44043
- children: [/* @__PURE__ */ jsx("input", {
44044
- type: "radio",
44045
- name: field.id,
44046
- value: opt.value,
44047
- required,
44048
- className: "form-radio"
44049
- }), /* @__PURE__ */ jsx("span", { children: opt.label })]
44050
- }, opt.value))]
44051
- }, field.id);
44052
- }
44053
- if (type === "checkbox" || type === "consent") return /* @__PURE__ */ jsxs("label", {
44054
- className: "fb-inline form-label",
44055
- children: [/* @__PURE__ */ jsx("input", {
44056
- type: "checkbox",
44057
- name: field.id,
44058
- required,
44059
- className: "form-checkbox"
44060
- }), /* @__PURE__ */ jsx("span", { children: label })]
44061
- }, field.id);
44062
- const inputType = type === "email" || type === "url" || type === "tel" || type === "number" ? type : "text";
44063
- const extra = {};
44064
- if (inputType === "text" || inputType === "email" || inputType === "url" || inputType === "tel") {
44065
- if (typeof field.minLength === "number") extra.minLength = field.minLength;
44066
- if (typeof field.maxLength === "number") extra.maxLength = field.maxLength;
44067
- if (typeof field.pattern === "string" && field.pattern) extra.pattern = field.pattern;
44068
- }
44069
- if (inputType === "number") {
44070
- if (typeof field.min === "number") extra.min = field.min;
44071
- if (typeof field.max === "number") extra.max = field.max;
44072
- }
44073
- return /* @__PURE__ */ jsxs("div", {
44074
- className: "fb-field",
44075
- children: [/* @__PURE__ */ jsx("label", {
44076
- htmlFor: inputId,
44077
- className: "form-label",
44078
- children: label
44079
- }), /* @__PURE__ */ jsx("input", {
44080
- id: inputId,
44081
- name: field.id,
44082
- type: inputType,
44083
- required,
44084
- placeholder: field.placeholder,
44085
- ...extra,
44086
- className: "form-input"
44087
- })]
44088
- }, field.id);
44089
- };
44188
+ const renderField = (field) => /* @__PURE__ */ jsx(FormFieldControl, { field }, field.id);
44090
44189
  return /* @__PURE__ */ jsxs("div", {
44091
44190
  ...getIslandRootProps("form", blockId),
44092
44191
  children: [/* @__PURE__ */ jsx(IslandPropsScript, { value: islandProps }), /* @__PURE__ */ jsxs("form", {
@@ -44132,6 +44231,172 @@ const FormNodeSSR = ({ blockId, value, submitLabel, successMessage, className, o
44132
44231
  });
44133
44232
  };
44134
44233
  //#endregion
44234
+ //#region ../blocks/src/system/runtime/shared/components/FieldValidationMessage.tsx
44235
+ function getFieldValidationControlProps({ message, messageId, describedBy }) {
44236
+ const hasMessage = Boolean(message);
44237
+ const ariaDescribedBy = [describedBy, hasMessage ? messageId : void 0].filter((part) => typeof part === "string" && part.length > 0).join(" ");
44238
+ return {
44239
+ "aria-invalid": hasMessage ? "true" : void 0,
44240
+ "aria-describedby": ariaDescribedBy || void 0
44241
+ };
44242
+ }
44243
+ function FieldValidationMessage({ id, children, className, live = "assertive" }) {
44244
+ return /* @__PURE__ */ jsx("p", {
44245
+ id,
44246
+ className,
44247
+ "data-field-validation-message": true,
44248
+ "data-field-validation-tone": "error",
44249
+ role: "alert",
44250
+ "aria-live": live === "off" ? void 0 : live,
44251
+ children
44252
+ });
44253
+ }
44254
+ //#endregion
44255
+ //#region ../blocks/src/system/runtime/nodes/newsletter-form.parts.tsx
44256
+ /**
44257
+ * Newsletter form pieces shared by the SSR render and the hydrated island, so
44258
+ * both produce the same markup.
44259
+ *
44260
+ * Labels are visually hidden: every field has a placeholder, and a visible
44261
+ * "Email *" label over a single field reads like a generic form. Screen
44262
+ * readers still get the label.
44263
+ */
44264
+ const TOPIC_CHOICE_FIELD_ID = "mailingListChoice";
44265
+ const inputIdFor = (field) => `newsletter_${field.id}`;
44266
+ /** Splits the preset's fields into the email (joined with the button) and the rest. */
44267
+ function partitionNewsletterFields(fields) {
44268
+ const email = fields.find((field) => field.type === "email") ?? null;
44269
+ return {
44270
+ email,
44271
+ extra: fields.filter((field) => field !== email)
44272
+ };
44273
+ }
44274
+ function NewsletterExtraField({ field, disabled, error }) {
44275
+ const inputId = inputIdFor(field);
44276
+ const errorId = `${inputId}-error`;
44277
+ return /* @__PURE__ */ jsxs("div", {
44278
+ className: "fb-field newsletter-field",
44279
+ children: [
44280
+ /* @__PURE__ */ jsx("label", {
44281
+ htmlFor: inputId,
44282
+ className: "rb-sr-only",
44283
+ children: field.label
44284
+ }),
44285
+ /* @__PURE__ */ jsx("input", {
44286
+ id: inputId,
44287
+ name: field.id,
44288
+ type: field.type,
44289
+ required: field.required,
44290
+ placeholder: field.placeholder ?? field.label,
44291
+ className: "form-input",
44292
+ disabled,
44293
+ ...getFieldValidationControlProps({
44294
+ message: error,
44295
+ messageId: errorId
44296
+ })
44297
+ }),
44298
+ error ? /* @__PURE__ */ jsx(FieldValidationMessage, {
44299
+ id: errorId,
44300
+ className: "fb-error",
44301
+ children: error
44302
+ }) : null
44303
+ ]
44304
+ });
44305
+ }
44306
+ /** The email field and submit button sharing one input-styled shell. */
44307
+ function NewsletterEmailEntry({ field, buttonVariant, buttonLabel, disabled, error }) {
44308
+ const inputId = inputIdFor(field);
44309
+ const errorId = `${inputId}-error`;
44310
+ return /* @__PURE__ */ jsxs("div", {
44311
+ className: "newsletter-entry",
44312
+ children: [/* @__PURE__ */ jsxs("div", {
44313
+ className: "form-input-group newsletter-entry-group",
44314
+ children: [
44315
+ /* @__PURE__ */ jsx("label", {
44316
+ htmlFor: inputId,
44317
+ className: "rb-sr-only",
44318
+ children: field.label
44319
+ }),
44320
+ /* @__PURE__ */ jsx("input", {
44321
+ id: inputId,
44322
+ name: field.id,
44323
+ type: "email",
44324
+ required: field.required,
44325
+ placeholder: field.placeholder ?? field.label,
44326
+ className: "form-input-group-field",
44327
+ autoComplete: "email",
44328
+ disabled,
44329
+ ...getFieldValidationControlProps({
44330
+ message: error,
44331
+ messageId: errorId
44332
+ })
44333
+ }),
44334
+ /* @__PURE__ */ jsx(ThemedButton, {
44335
+ type: "submit",
44336
+ variant: buttonVariant,
44337
+ size: "md",
44338
+ disabled,
44339
+ label: buttonLabel
44340
+ })
44341
+ ]
44342
+ }), error ? /* @__PURE__ */ jsx(FieldValidationMessage, {
44343
+ id: errorId,
44344
+ className: "fb-error",
44345
+ children: error
44346
+ }) : null]
44347
+ });
44348
+ }
44349
+ /**
44350
+ * The submit action: joined to the email field when the preset has one
44351
+ * (every current preset does), otherwise a plain themed button.
44352
+ */
44353
+ function NewsletterSubmitRow({ emailField, buttonVariant, buttonLabel, disabled, error }) {
44354
+ if (emailField) return /* @__PURE__ */ jsx(NewsletterEmailEntry, {
44355
+ field: emailField,
44356
+ buttonVariant,
44357
+ buttonLabel,
44358
+ disabled,
44359
+ error
44360
+ });
44361
+ return /* @__PURE__ */ jsx("div", {
44362
+ className: "newsletter-submit",
44363
+ children: /* @__PURE__ */ jsx(ThemedButton, {
44364
+ type: "submit",
44365
+ variant: buttonVariant,
44366
+ size: "md",
44367
+ disabled,
44368
+ label: buttonLabel
44369
+ })
44370
+ });
44371
+ }
44372
+ /** Visitor-chosen topics as toggle chips. Real checkboxes underneath. */
44373
+ function NewsletterTopicChips({ choices, disabled, error }) {
44374
+ const errorId = `newsletter_${TOPIC_CHOICE_FIELD_ID}-error`;
44375
+ return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs("fieldset", {
44376
+ className: "newsletter-topics",
44377
+ "aria-describedby": error ? errorId : void 0,
44378
+ children: [/* @__PURE__ */ jsx("legend", {
44379
+ className: "newsletter-topics-legend",
44380
+ children: "What would you like to hear about?"
44381
+ }), /* @__PURE__ */ jsx("div", {
44382
+ className: "newsletter-topic-chips",
44383
+ children: choices.map((choice) => /* @__PURE__ */ jsxs("label", {
44384
+ className: "newsletter-topic-chip",
44385
+ children: [/* @__PURE__ */ jsx("input", {
44386
+ type: "checkbox",
44387
+ name: TOPIC_CHOICE_FIELD_ID,
44388
+ value: choice.id,
44389
+ disabled
44390
+ }), /* @__PURE__ */ jsx("span", { children: choice.label })]
44391
+ }, choice.id))
44392
+ })]
44393
+ }), error ? /* @__PURE__ */ jsx(FieldValidationMessage, {
44394
+ id: errorId,
44395
+ className: "fb-error",
44396
+ children: error
44397
+ }) : null] });
44398
+ }
44399
+ //#endregion
44135
44400
  //#region ../blocks/src/system/runtime/nodes/newsletter-form.server.tsx
44136
44401
  /**
44137
44402
  * Newsletter Form Server Component
@@ -44152,36 +44417,15 @@ function NewsletterFormSSR(props) {
44152
44417
  });
44153
44418
  const display = islandProps.render.display;
44154
44419
  const fields = display.fields;
44420
+ const submissionMessage = newsletterBlockSubmissionMessage(islandProps.render.hydration.target);
44155
44421
  if (display.availability === "unavailable") return /* @__PURE__ */ jsx("div", {
44156
44422
  className: clsx("newsletter-form-ssr", className),
44157
44423
  children: /* @__PURE__ */ jsx("p", {
44158
44424
  role: "status",
44159
- children: "We can’t accept signups right now. Please try again later."
44425
+ children: NEWSLETTER_SIGNUPS_PAUSED_MESSAGE
44160
44426
  })
44161
44427
  });
44162
- const renderField = (field) => {
44163
- const inputId = `newsletter_${field.id}`;
44164
- return /* @__PURE__ */ jsxs("div", {
44165
- className: "fb-field newsletter-field",
44166
- children: [/* @__PURE__ */ jsxs("label", {
44167
- htmlFor: inputId,
44168
- className: "form-label",
44169
- children: [field.label, field.required && /* @__PURE__ */ jsx("span", {
44170
- className: "newsletter-required",
44171
- "aria-hidden": "true",
44172
- children: "*"
44173
- })]
44174
- }), /* @__PURE__ */ jsx("input", {
44175
- id: inputId,
44176
- name: field.id,
44177
- type: field.type,
44178
- required: field.required,
44179
- placeholder: field.placeholder,
44180
- className: "form-input",
44181
- autoComplete: field.type === "email" ? "email" : void 0
44182
- })]
44183
- }, field.id);
44184
- };
44428
+ const { email: emailField, extra: extraFields } = partitionNewsletterFields(fields);
44185
44429
  return /* @__PURE__ */ jsxs("div", {
44186
44430
  ...getIslandRootProps("newsletter-form", blockId),
44187
44431
  className: clsx("newsletter-form-ssr", className),
@@ -44200,30 +44444,20 @@ function NewsletterFormSSR(props) {
44200
44444
  /* @__PURE__ */ jsxs("div", {
44201
44445
  className: "newsletter-form-fields",
44202
44446
  children: [
44203
- fields.map(renderField),
44204
- islandProps.render.hydration.choicePresentation === "visitor_choice" ? /* @__PURE__ */ jsxs("fieldset", {
44205
- className: "fb-fieldset newsletter-topics",
44206
- children: [/* @__PURE__ */ jsx("legend", {
44207
- className: "form-label",
44208
- children: "What would you like to hear about?"
44209
- }), display.choices.map((choice) => /* @__PURE__ */ jsxs("label", {
44210
- className: "fb-inline form-label newsletter-topic-choice",
44211
- children: [/* @__PURE__ */ jsx("input", {
44212
- type: "checkbox",
44213
- name: "mailingListChoice",
44214
- value: choice.id,
44215
- className: "form-checkbox"
44216
- }), /* @__PURE__ */ jsx("span", { children: choice.label })]
44217
- }, choice.id))]
44447
+ islandProps.render.hydration.choicePresentation === "visitor_choice" ? /* @__PURE__ */ jsx(NewsletterTopicChips, { choices: display.choices }) : null,
44448
+ extraFields.length > 0 ? /* @__PURE__ */ jsx("div", {
44449
+ className: "newsletter-extra-fields",
44450
+ children: extraFields.map((field) => /* @__PURE__ */ jsx(NewsletterExtraField, { field }, field.id))
44218
44451
  }) : null,
44219
- /* @__PURE__ */ jsx("div", {
44220
- className: "newsletter-submit",
44221
- children: /* @__PURE__ */ jsx(ThemedButton, {
44222
- type: "submit",
44223
- variant: display.buttonVariant,
44224
- size: "md",
44225
- label: display.buttonLabel
44226
- })
44452
+ /* @__PURE__ */ jsx(NewsletterSubmitRow, {
44453
+ emailField,
44454
+ buttonVariant: display.buttonVariant,
44455
+ buttonLabel: display.buttonLabel,
44456
+ disabled: submissionMessage !== null
44457
+ }),
44458
+ submissionMessage && /* @__PURE__ */ jsx("p", {
44459
+ role: "status",
44460
+ children: submissionMessage
44227
44461
  })
44228
44462
  ]
44229
44463
  }),
@@ -45204,7 +45438,7 @@ const RENDERER_METADATA_PROP_KEYS = /* @__PURE__ */ new Set([
45204
45438
  "blockContent",
45205
45439
  "fragmentRegistry",
45206
45440
  "previewAuthoring",
45207
- "contentVersionId",
45441
+ "newsletterBlockSubmission",
45208
45442
  "imageResolveContext"
45209
45443
  ]);
45210
45444
  function omitRendererMetadataProps(props) {
@@ -45260,7 +45494,7 @@ function resolveNodeMetadata(nodeType, context) {
45260
45494
  pathBase: context.pathBase,
45261
45495
  fragmentRegistry: context.fragmentRegistry
45262
45496
  } : {},
45263
- ...normalizedType === "newsletter-form" ? { contentVersionId: context.contentVersionId } : {},
45497
+ ...normalizedType === "newsletter-form" ? { newsletterBlockSubmission: context.newsletterBlockSubmission } : {},
45264
45498
  ...normalizedType === "media" && context.imageResolveContext ? { imageResolveContext: context.imageResolveContext } : {}
45265
45499
  };
45266
45500
  }
@@ -45871,6 +46105,270 @@ function generateHoverEffects(axes, _space) {
45871
46105
  };
45872
46106
  }
45873
46107
  //#endregion
46108
+ //#region ../theme-core/src/inputs/checkable.ts
46109
+ /**
46110
+ * Checkbox and radio CSS shared by the full theme generator and the SDK
46111
+ * theme bridge, so both render the same customer-facing controls.
46112
+ *
46113
+ * Emits:
46114
+ * - .form-checkbox / .form-radio: the controls themselves. The tick and dot
46115
+ * are drawn with ::before so their colour comes from theme tokens rather
46116
+ * than a baked-in SVG.
46117
+ * - .form-check: a label row holding a control and its text. The control
46118
+ * lines up with the first line of text, so long labels wrap cleanly.
46119
+ * - .form-check--tile: a bordered, fully clickable panel for agreements
46120
+ * (booking consent, consent fields) that tints when ticked.
46121
+ */
46122
+ const CHECKABLE_SIZE = "1.375rem";
46123
+ /** Never fully round: a round checkbox reads as a radio. */
46124
+ const CHECKBOX_RADIUS = {
46125
+ square: "0",
46126
+ soft: "0.25rem",
46127
+ rounded: "0.375rem",
46128
+ pill: "0.375rem"
46129
+ };
46130
+ /** Tiles hold wrapping text, so pill themes get a generous radius, not a capsule. */
46131
+ const TILE_RADIUS = {
46132
+ square: "0",
46133
+ soft: "0.5rem",
46134
+ rounded: "0.75rem",
46135
+ pill: "1rem"
46136
+ };
46137
+ const ON_ACCENT_TOKENS = {
46138
+ primary: "onPrimary",
46139
+ secondary: "onSecondary",
46140
+ accent: "onAccent"
46141
+ };
46142
+ /**
46143
+ * Colour for the tick/dot drawn on top of the accent fill. Uses the palette's
46144
+ * matching "on" token where there is one, falling back to white.
46145
+ */
46146
+ /** The accent at full strength: `primary/70` becomes `primary`. */
46147
+ function solidAccentToken(accentToken) {
46148
+ const parsed = parseColorTokenParts(accentToken);
46149
+ return parsed.kind === "token" ? parsed.token : accentToken;
46150
+ }
46151
+ function checkableMarkColor(accentToken) {
46152
+ const parsed = parseColorTokenParts(accentToken);
46153
+ const onToken = parsed.kind === "token" ? ON_ACCENT_TOKENS[parsed.token] : void 0;
46154
+ return onToken ? `rgb(var(--tb-${onToken}, 255 255 255))` : "rgb(255 255 255)";
46155
+ }
46156
+ function checkableSelectors(root) {
46157
+ return {
46158
+ checkbox: `${root} .form-checkbox`,
46159
+ radio: `${root} .form-radio`,
46160
+ check: `${root} .form-check`,
46161
+ tile: `${root} .form-check--tile`
46162
+ };
46163
+ }
46164
+ /** The box and circle themselves, unchecked. */
46165
+ function controlBaseCss(sel, input) {
46166
+ const border = input.borderWidth === "0" ? "1px" : input.borderWidth;
46167
+ return [
46168
+ `${sel.checkbox},
46169
+ ${sel.radio} {
46170
+ appearance: none;
46171
+ display: inline-grid;
46172
+ place-content: center;
46173
+ width: ${CHECKABLE_SIZE};
46174
+ height: ${CHECKABLE_SIZE};
46175
+ margin: 0;
46176
+ flex-shrink: 0;
46177
+ border: ${border} solid ${input.borderColor};
46178
+ background-color: ${input.background};
46179
+ color: inherit;
46180
+ cursor: pointer;
46181
+ transition: background-color 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease;
46182
+ }`,
46183
+ `${sel.checkbox} {
46184
+ border-radius: ${CHECKBOX_RADIUS[input.corners]};
46185
+ }`,
46186
+ `${sel.radio} {
46187
+ border-radius: 9999px;
46188
+ }`
46189
+ ];
46190
+ }
46191
+ /** The tick and dot, drawn with ::before so their colour is a theme token. */
46192
+ function controlMarkCss(sel, accentToken) {
46193
+ return [
46194
+ `${sel.checkbox}::before,
46195
+ ${sel.radio}::before {
46196
+ content: "";
46197
+ background-color: ${checkableMarkColor(accentToken)};
46198
+ transform: scale(0);
46199
+ transition: transform 0.12s ease;
46200
+ }`,
46201
+ `${sel.checkbox}::before {
46202
+ width: 0.75rem;
46203
+ height: 0.75rem;
46204
+ clip-path: polygon(14% 52%, 0 67%, 38% 100%, 100% 22%, 85% 8%, 37% 70%);
46205
+ }`,
46206
+ `${sel.radio}::before {
46207
+ width: 0.5rem;
46208
+ height: 0.5rem;
46209
+ border-radius: 9999px;
46210
+ }`
46211
+ ];
46212
+ }
46213
+ function controlStateCss(sel, input) {
46214
+ const accent = rgbColorValue(solidAccentToken(input.accentToken));
46215
+ return [
46216
+ `${sel.checkbox}:hover,
46217
+ ${sel.radio}:hover,
46218
+ ${sel.check}:hover > .form-checkbox,
46219
+ ${sel.check}:hover > .form-radio {
46220
+ border-color: ${accent};
46221
+ }`,
46222
+ `${sel.checkbox}:checked,
46223
+ ${sel.radio}:checked {
46224
+ background-color: ${accent};
46225
+ border-color: ${accent};
46226
+ }`,
46227
+ `${sel.checkbox}:checked::before,
46228
+ ${sel.radio}:checked::before {
46229
+ transform: scale(1);
46230
+ }`,
46231
+ `${sel.checkbox}:focus-visible,
46232
+ ${sel.radio}:focus-visible {
46233
+ outline: 2px solid ${accent};
46234
+ outline-offset: 2px;
46235
+ }`,
46236
+ `${sel.checkbox}:disabled,
46237
+ ${sel.radio}:disabled {
46238
+ opacity: 0.5;
46239
+ cursor: not-allowed;
46240
+ }`
46241
+ ];
46242
+ }
46243
+ /** Label row: control lined up with the first line of wrapping text. */
46244
+ function checkRowCss(sel) {
46245
+ return [
46246
+ `${sel.check} {
46247
+ display: flex;
46248
+ align-items: flex-start;
46249
+ gap: 0.75rem;
46250
+ line-height: 1.5;
46251
+ cursor: pointer;
46252
+ }`,
46253
+ `${sel.check} > .form-checkbox,
46254
+ ${sel.check} > .form-radio {
46255
+ margin-top: 0.0625rem;
46256
+ margin-top: max(0px, calc((1lh - ${CHECKABLE_SIZE}) / 2));
46257
+ }`,
46258
+ `${sel.check}:has(> :disabled) {
46259
+ cursor: not-allowed;
46260
+ }`
46261
+ ];
46262
+ }
46263
+ function agreementTileCss(sel, input) {
46264
+ const accent = rgbColorValue(solidAccentToken(input.accentToken));
46265
+ return [
46266
+ `${sel.tile} {
46267
+ padding: 0.875rem 1rem;
46268
+ border: 1px solid color-mix(in srgb, currentColor 22%, transparent);
46269
+ border-radius: ${TILE_RADIUS[input.corners]};
46270
+ transition: border-color 0.15s ease, background-color 0.15s ease;
46271
+ }`,
46272
+ `${sel.tile}:hover {
46273
+ border-color: color-mix(in srgb, ${accent} 55%, transparent);
46274
+ }`,
46275
+ `${sel.tile}:has(> .form-checkbox:checked) {
46276
+ border-color: ${accent};
46277
+ background-color: color-mix(in srgb, ${accent} 7%, transparent);
46278
+ }`,
46279
+ `${sel.tile}:has(> .form-checkbox[aria-invalid="true"]) {
46280
+ border-color: ${input.errorColor};
46281
+ }`
46282
+ ];
46283
+ }
46284
+ function checkableMediaCss(sel) {
46285
+ return [`@media (prefers-reduced-motion: reduce) {
46286
+ ${sel.checkbox}, ${sel.radio}, ${sel.checkbox}::before, ${sel.radio}::before, ${sel.tile} {
46287
+ transition: none;
46288
+ }
46289
+ }`, `@media (forced-colors: active) {
46290
+ ${sel.checkbox}::before,
46291
+ ${sel.radio}::before {
46292
+ background-color: CanvasText;
46293
+ }
46294
+ }`];
46295
+ }
46296
+ /**
46297
+ * Exposes the accent and mark colours so other choice controls (newsletter
46298
+ * topic chips) match the checkboxes without re-deriving the theme tokens.
46299
+ */
46300
+ function checkableVarsCss(input) {
46301
+ return [`${input.root} {
46302
+ --rb-check-accent: ${rgbColorValue(solidAccentToken(input.accentToken))};
46303
+ --rb-check-mark: ${checkableMarkColor(input.accentToken)};
46304
+ }`];
46305
+ }
46306
+ function generateCheckableCss(input) {
46307
+ const sel = checkableSelectors(input.root);
46308
+ return [
46309
+ ...checkableVarsCss(input),
46310
+ ...controlBaseCss(sel, input),
46311
+ ...controlMarkCss(sel, input.accentToken),
46312
+ ...controlStateCss(sel, input),
46313
+ ...checkRowCss(sel),
46314
+ ...agreementTileCss(sel, input),
46315
+ ...checkableMediaCss(sel)
46316
+ ].join("\n\n");
46317
+ }
46318
+ //#endregion
46319
+ //#region ../theme-core/src/inputs/inputGroup.ts
46320
+ /**
46321
+ * Input group: a field and an action (usually a themed button) sharing one
46322
+ * input-styled shell, e.g. the newsletter email + Sign up row.
46323
+ *
46324
+ * The shell `.form-input-group` takes the theme's `.form-input` rules (the
46325
+ * generators add it to that selector list, plus focus and error), so it
46326
+ * follows the site's input background, border, corners and shadow. This file
46327
+ * only adds the layout overrides and the borderless inner field.
46328
+ */
46329
+ const INPUT_GROUP_SELECTOR = ".form-input-group";
46330
+ /** Shell focus ring follows the field only, not the button beside it. */
46331
+ const INPUT_GROUP_FOCUS_SELECTOR = ".form-input-group:has(> .form-input-group-field:focus-visible)";
46332
+ const INPUT_GROUP_ERROR_SELECTOR = ".form-input-group:has(> .form-input-group-field[aria-invalid=\"true\"])";
46333
+ const GROUP_INSET = "0.25rem";
46334
+ /**
46335
+ * @param root - scoped root selector
46336
+ * @param padding - the theme's input padding shorthand (`block inline`), so the
46337
+ * inner field's text sits where a plain input's text would.
46338
+ */
46339
+ function generateInputGroupCss(root, padding) {
46340
+ const [block = padding, inline = block] = padding.trim().split(/\s+/);
46341
+ return `${root} .form-input-group {
46342
+ display: flex;
46343
+ align-items: stretch;
46344
+ gap: ${GROUP_INSET};
46345
+ padding: ${GROUP_INSET};
46346
+ }
46347
+
46348
+ ${root} .form-input-group-field {
46349
+ flex: 1 1 auto;
46350
+ min-width: 0;
46351
+ margin: 0;
46352
+ border: 0;
46353
+ border-radius: 0;
46354
+ background: transparent;
46355
+ box-shadow: none;
46356
+ outline: none;
46357
+ color: inherit;
46358
+ font: inherit;
46359
+ padding: calc(${block} - ${GROUP_INSET}) calc(${inline} - ${GROUP_INSET});
46360
+ }
46361
+
46362
+ ${root} .form-input-group-field::placeholder {
46363
+ color: inherit;
46364
+ opacity: 0.6;
46365
+ }
46366
+
46367
+ ${root} .form-input-group > :not(.form-input-group-field) {
46368
+ flex-shrink: 0;
46369
+ }`;
46370
+ }
46371
+ //#endregion
45874
46372
  //#region ../theme-core/src/inputs/generateInputCss.ts
45875
46373
  /**
45876
46374
  * Corner radius map (reused from other systems)
@@ -45881,6 +46379,9 @@ const CORNER_MAP$1 = {
45881
46379
  rounded: "1rem",
45882
46380
  pill: "9999px"
45883
46381
  };
46382
+ function inputBackgroundValue(background) {
46383
+ return background.type === "transparent" ? "transparent" : rgbColorValue(background.colorToken);
46384
+ }
45884
46385
  /**
45885
46386
  * Generate CSS for form input styling based on theme configuration
45886
46387
  *
@@ -45898,8 +46399,7 @@ const CORNER_MAP$1 = {
45898
46399
  function generateInputCss({ themeId, theme, inputSystem }) {
45899
46400
  const rootSelector = `:where([data-theme-scope="${themeId}"])`;
45900
46401
  const baseInputRules = [];
45901
- if (inputSystem.base.background.type === "transparent") baseInputRules.push("background-color: transparent");
45902
- else baseInputRules.push(`background-color: ${rgbColorValue(inputSystem.base.background.colorToken)}`);
46402
+ baseInputRules.push(`background-color: ${inputBackgroundValue(inputSystem.base.background)}`);
45903
46403
  baseInputRules.push(`color: ${rgbColorValue(inputSystem.base.textColorToken)}`);
45904
46404
  const borderPx = parseBorderWidth(inputSystem.base.border.widthClass);
45905
46405
  const borderStyle = inputSystem.base.border.style ?? "all";
@@ -45955,7 +46455,8 @@ function generateInputCss({ themeId, theme, inputSystem }) {
45955
46455
  const focusSelectors = [
45956
46456
  `${inputSelector}:focus-visible`,
45957
46457
  `${textareaSelector}:focus-visible`,
45958
- `${selectSelector}:focus-visible`
46458
+ `${selectSelector}:focus-visible`,
46459
+ `${rootSelector} ${INPUT_GROUP_FOCUS_SELECTOR}`
45959
46460
  ];
45960
46461
  const focusRules = [];
45961
46462
  focusRules.push("outline: none");
@@ -45964,7 +46465,8 @@ function generateInputCss({ themeId, theme, inputSystem }) {
45964
46465
  const errorSelectors = [
45965
46466
  `${inputSelector}[aria-invalid="true"]`,
45966
46467
  `${textareaSelector}[aria-invalid="true"]`,
45967
- `${selectSelector}[aria-invalid="true"]`
46468
+ `${selectSelector}[aria-invalid="true"]`,
46469
+ `${rootSelector} ${INPUT_GROUP_ERROR_SELECTOR}`
45968
46470
  ];
45969
46471
  const errorRules = [];
45970
46472
  errorRules.push(`border-color: ${rgbColorValue(inputSystem.error.borderColorToken)}`);
@@ -45979,53 +46481,25 @@ function generateInputCss({ themeId, theme, inputSystem }) {
45979
46481
  disabledRules.push(`color: ${rgbColorValue(inputSystem.disabled.textColorToken)}`);
45980
46482
  disabledRules.push(`opacity: ${inputSystem.disabled.opacity}`);
45981
46483
  disabledRules.push("cursor: not-allowed");
45982
- const checkboxSelector = `${rootSelector} .form-checkbox`;
45983
- const radioSelector = `${rootSelector} .form-radio`;
45984
- const checkableRules = [];
45985
- checkableRules.push("appearance: none");
45986
- checkableRules.push("width: 1.125rem");
45987
- checkableRules.push("height: 1.125rem");
45988
- checkableRules.push("flex-shrink: 0");
45989
- checkableRules.push(`border: ${borderPx} solid ${rgbColorValue(inputSystem.base.border.colorToken)}`);
45990
- if (inputSystem.base.background.type === "transparent") checkableRules.push("background-color: transparent");
45991
- else checkableRules.push(`background-color: ${rgbColorValue(inputSystem.base.background.colorToken)}`);
45992
- checkableRules.push("cursor: pointer");
45993
- checkableRules.push("transition: background-color 0.2s ease, border-color 0.2s ease");
45994
- const checkboxSpecificRules = [...checkableRules];
45995
- checkboxSpecificRules.push(`border-radius: ${CORNER_MAP$1.soft}`);
45996
- const radioSpecificRules = [...checkableRules];
45997
- radioSpecificRules.push("border-radius: 9999px");
45998
- const checkboxCheckedSelector = `${checkboxSelector}:checked`;
45999
- const checkboxCheckedRules = [];
46000
- checkboxCheckedRules.push(`background-color: ${rgbColorValue(inputSystem.focus.ringColorToken)}`);
46001
- checkboxCheckedRules.push(`border-color: ${rgbColorValue(inputSystem.focus.ringColorToken)}`);
46002
- 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\")");
46003
- checkboxCheckedRules.push("background-size: 100% 100%");
46004
- checkboxCheckedRules.push("background-position: center");
46005
- checkboxCheckedRules.push("background-repeat: no-repeat");
46006
- const radioCheckedSelector = `${radioSelector}:checked`;
46007
- const radioCheckedRules = [];
46008
- radioCheckedRules.push(`background-color: ${rgbColorValue(inputSystem.focus.ringColorToken)}`);
46009
- radioCheckedRules.push(`border-color: ${rgbColorValue(inputSystem.focus.ringColorToken)}`);
46010
- radioCheckedRules.push("background-image: radial-gradient(circle, white 40%, transparent 40%)");
46011
- const checkboxFocusSelector = `${checkboxSelector}:focus-visible`;
46012
- const radioFocusSelector = `${radioSelector}:focus-visible`;
46013
- const checkableFocusRules = [];
46014
- checkableFocusRules.push("outline: none");
46015
- checkableFocusRules.push(`box-shadow: 0 0 0 ${inputSystem.focus.ringWidth}px ${rgbColorValue(inputSystem.focus.ringColorToken)}`);
46484
+ const checkableCss = generateCheckableCss({
46485
+ root: rootSelector,
46486
+ borderWidth: borderPx,
46487
+ borderColor: rgbColorValue(inputSystem.base.border.colorToken),
46488
+ background: inputBackgroundValue(inputSystem.base.background),
46489
+ corners: inputSystem.base.corners ?? theme.corners,
46490
+ accentToken: inputSystem.focus.borderColorToken ?? inputSystem.focus.ringColorToken,
46491
+ errorColor: rgbColorValue(inputSystem.error.borderColorToken)
46492
+ });
46016
46493
  const cssBlocks = [];
46017
46494
  cssBlocks.push(`${labelSelector} {\n ${labelRules.join(";\n ")};\n}`);
46018
- cssBlocks.push(`${inputSelector} {\n ${inputRules.join(";\n ")};\n}`);
46495
+ cssBlocks.push(`${inputSelector},\n${rootSelector} ${INPUT_GROUP_SELECTOR} {\n ${inputRules.join(";\n ")};\n}`);
46019
46496
  cssBlocks.push(`${textareaSelector} {\n ${textareaRules.join(";\n ")};\n}`);
46020
46497
  cssBlocks.push(`${selectSelector} {\n ${selectRules.join(";\n ")};\n}`);
46021
46498
  cssBlocks.push(`${focusSelectors.join(",\n")} {\n ${focusRules.join(";\n ")};\n}`);
46022
46499
  cssBlocks.push(`${errorSelectors.join(",\n")} {\n ${errorRules.join(";\n ")};\n}`);
46023
46500
  cssBlocks.push(`${disabledSelectors.join(",\n")} {\n ${disabledRules.join(";\n ")};\n}`);
46024
- cssBlocks.push(`${checkboxSelector} {\n ${checkboxSpecificRules.join(";\n ")};\n}`);
46025
- cssBlocks.push(`${radioSelector} {\n ${radioSpecificRules.join(";\n ")};\n}`);
46026
- cssBlocks.push(`${checkboxCheckedSelector} {\n ${checkboxCheckedRules.join(";\n ")};\n}`);
46027
- cssBlocks.push(`${radioCheckedSelector} {\n ${radioCheckedRules.join(";\n ")};\n}`);
46028
- cssBlocks.push(`${checkboxFocusSelector},\n${radioFocusSelector} {\n ${checkableFocusRules.join(";\n ")};\n}`);
46501
+ cssBlocks.push(generateInputGroupCss(rootSelector, padding));
46502
+ cssBlocks.push(checkableCss);
46029
46503
  return cssBlocks.join("\n\n");
46030
46504
  }
46031
46505
  //#endregion
@@ -52467,13 +52941,13 @@ const hours = stack({
52467
52941
  as: "p",
52468
52942
  className: "rb-caption rb-opacity-70"
52469
52943
  }, bind("module.timeZone"), when("module.timeZone"))], when("module.kind", { equals: "opening-hours" }));
52470
- const socials = inline({ className: "rb-flex rb-flex-wrap rb-gap-x-5 rb-gap-y-3" }, [link({
52944
+ const socials = inline({ className: "rb-footer-socials" }, [link({
52471
52945
  href: { $bind: { from: "social.href" } },
52472
52946
  target: "_blank",
52473
52947
  rel: "noreferrer noopener",
52474
52948
  "aria-label": { $bind: { from: "social.label" } },
52475
- className: "rb-nav-text transition-theme-standard"
52476
- }, [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" }));
52949
+ className: "rb-footer-social-link rb-nav-text transition-theme-standard"
52950
+ }, [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" }));
52477
52951
  const authoredCopy = richText({
52478
52952
  className: "rb-prose rb-prose-sm rb-max-w-none",
52479
52953
  style: textColorStyle("text/80")
@@ -58451,43 +58925,53 @@ function collectNestedPreviewFieldConstraintEntries(field, path) {
58451
58925
  default: return assertNever$21(field);
58452
58926
  }
58453
58927
  }
58928
+ function prepareDefaultBlockRender(manifest, props) {
58929
+ if (!props.theme) throw new Error("Block rendering requires theme tokens; none were provided to makeDefaultBlockComponent");
58930
+ if (!props.registry) throw new Error("Block rendering requires a component registry; none was provided");
58931
+ const content = props.content;
58932
+ const layout = resolveBlockLayout(manifest, content);
58933
+ if (!layout) throw new Error(`Block manifest "${manifest.name}" requires a layout definition`);
58934
+ const mergedContent = mergeContentWithBlockStyleOverrides(content, props.themeConfig, props.blockKind ?? manifest.name);
58935
+ return {
58936
+ registry: props.registry,
58937
+ layout,
58938
+ mergedContent,
58939
+ fieldConstraints: buildPreviewFieldConstraints(manifest),
58940
+ viewModel: buildBlockViewModel({
58941
+ mergedContent,
58942
+ data: props.data,
58943
+ resolvedThemeConfig: resolveThemeConfigForBindings(props.themeConfig),
58944
+ viewModelOverrides: props.viewModelOverrides
58945
+ }),
58946
+ themeForTransforms: withButtonSystem(props.theme, props.themeConfig)
58947
+ };
58948
+ }
58454
58949
  function makeDefaultBlockComponent(args) {
58455
- const { manifest } = args;
58456
- return function DefaultBlockComponent({ content, data, registry, theme, themeConfig, transforms, viewModelOverrides, pathBase, blockId, contentVersionId, blockKind, blockBindings, editableRouteMetadataFieldIds, fragmentRegistry, imageResolveContext, previewAuthoring }) {
58950
+ return function DefaultBlockComponent(props) {
58457
58951
  const perf = beginBlockRenderMeasurement();
58458
- if (!theme) throw new Error("Block rendering requires theme tokens; none were provided to makeDefaultBlockComponent");
58459
- if (!registry) throw new Error("Block rendering requires a component registry; none was provided");
58460
- const layout = resolveBlockLayout(manifest, content);
58461
- if (!layout) throw new Error(`Block manifest "${manifest.name}" requires a layout definition`);
58462
- const fieldConstraints = buildPreviewFieldConstraints(manifest);
58463
- const mergedContent = mergeContentWithBlockStyleOverrides(content, themeConfig, blockKind ?? manifest.name);
58464
- const result = resolveTree(layout, {
58465
- registry,
58466
- viewModel: buildBlockViewModel({
58467
- mergedContent,
58468
- data,
58469
- resolvedThemeConfig: resolveThemeConfigForBindings(themeConfig),
58470
- viewModelOverrides
58471
- }),
58472
- transforms,
58473
- theme: withButtonSystem(theme, themeConfig),
58474
- pathBase,
58475
- blockId,
58476
- contentVersionId,
58477
- blockKind,
58478
- blockContent: mergedContent,
58479
- blockBindings,
58480
- editableRouteMetadataFieldIds,
58481
- fragmentRegistry,
58482
- fieldConstraints,
58483
- imageResolveContext,
58484
- previewAuthoring
58952
+ const prepared = prepareDefaultBlockRender(args.manifest, props);
58953
+ const result = resolveTree(prepared.layout, {
58954
+ registry: prepared.registry,
58955
+ viewModel: prepared.viewModel,
58956
+ transforms: props.transforms,
58957
+ theme: prepared.themeForTransforms,
58958
+ pathBase: props.pathBase,
58959
+ blockId: props.blockId,
58960
+ newsletterBlockSubmission: props.newsletterBlockSubmission,
58961
+ blockKind: props.blockKind,
58962
+ blockContent: prepared.mergedContent,
58963
+ blockBindings: props.blockBindings,
58964
+ editableRouteMetadataFieldIds: props.editableRouteMetadataFieldIds,
58965
+ fragmentRegistry: props.fragmentRegistry,
58966
+ fieldConstraints: prepared.fieldConstraints,
58967
+ imageResolveContext: props.imageResolveContext,
58968
+ previewAuthoring: props.previewAuthoring
58485
58969
  });
58486
58970
  reportSlowBlockRender(perf, {
58487
- content,
58488
- blockId,
58489
- blockKind: blockKind ?? manifest.name,
58490
- manifestName: manifest.name
58971
+ content: props.content,
58972
+ blockId: props.blockId,
58973
+ blockKind: props.blockKind ?? args.manifest.name,
58974
+ manifestName: args.manifest.name
58491
58975
  });
58492
58976
  return result;
58493
58977
  };
@@ -59089,6 +59573,39 @@ function resolveBlockData$1(blockId, dataLoaders, dataContext, routes) {
59089
59573
  return dataLoaders && typeof dataLoaders === "object" && Object.keys(dataLoaders).length > 0 ? {} : void 0;
59090
59574
  }
59091
59575
  //#endregion
59576
+ //#region ../blocks/src/system/runtime/nodes/newsletter-form.block-submission.ts
59577
+ /** Authorise one block source for both public and preview rendering. */
59578
+ function planNewsletterBlockSubmission(placement) {
59579
+ if (placement.stage === "published") {
59580
+ const sourceRef = buildMailingListSignupBlockSourceRef(placement.blockId, placement.selectedContentVersionId);
59581
+ return sourceRef ? {
59582
+ tag: "ready",
59583
+ sourceRef
59584
+ } : { tag: "unavailable" };
59585
+ }
59586
+ if (placement.publishedPlacement) return planNewsletterPreviewSubmission({
59587
+ blockId: placement.blockId,
59588
+ publishedContentId: placement.publishedPlacement.id,
59589
+ renderedContent: placement.renderedContent,
59590
+ publishedContent: placement.publishedPlacement.content
59591
+ });
59592
+ if (placement.stage === "preview") return { tag: "unpublished-form" };
59593
+ return { tag: "unavailable" };
59594
+ }
59595
+ /** Decide whether the visible draft can safely cite the published placement. */
59596
+ function planNewsletterPreviewSubmission(placement) {
59597
+ if (!placement.publishedContentId) return { tag: "unpublished-form" };
59598
+ if (!placement.publishedContent) return { tag: "unpublished-settings" };
59599
+ const draft = parseMailingListPlacementTargeting(placement.renderedContent.targeting ?? { mode: "default" });
59600
+ const published = parseMailingListPlacementTargeting(placement.publishedContent.targeting);
59601
+ if (!draft.ok || !published.ok || !sameMailingListPlacementTargeting(draft.value, published.value)) return { tag: "unpublished-settings" };
59602
+ const sourceRef = buildMailingListSignupBlockSourceRef(placement.blockId, placement.publishedContentId);
59603
+ return sourceRef ? {
59604
+ tag: "ready",
59605
+ sourceRef
59606
+ } : { tag: "unpublished-settings" };
59607
+ }
59608
+ //#endregion
59092
59609
  //#region ../blocks/src/pageRenderPreparation.ts
59093
59610
  /**
59094
59611
  * Stage two of the render plan.
@@ -59217,9 +59734,20 @@ function buildBlockOverrideProps(input) {
59217
59734
  imageResolveContext: input.imageResolveContext,
59218
59735
  blockId: block.id ?? null,
59219
59736
  contentVersionId: block.contentVersionId ?? null,
59737
+ ...newsletterBlockProps(block, input.content, dataContext?.previewStage),
59220
59738
  blockKind: block.kind
59221
59739
  };
59222
59740
  }
59741
+ function newsletterBlockProps(block, renderedContent, stage) {
59742
+ if (block.kind !== "block.newsletter-signup") return {};
59743
+ return { newsletterBlockSubmission: planNewsletterBlockSubmission({
59744
+ blockId: block.id,
59745
+ selectedContentVersionId: block.contentVersionId ?? null,
59746
+ publishedPlacement: block.publishedPlacement ?? null,
59747
+ renderedContent,
59748
+ stage
59749
+ }) };
59750
+ }
59223
59751
  /** Site, transport and session context a block needs to call back to the API. */
59224
59752
  function blockSessionProps(dataContext) {
59225
59753
  return {
@@ -59309,6 +59837,15 @@ function createBlockErrorBoundary() {
59309
59837
  const BlockErrorBoundary = createBlockErrorBoundary();
59310
59838
  //#endregion
59311
59839
  //#region ../blocks/src/pageRenderAdmission.ts
59840
+ /** Pair a published version with the content it authorises at the render boundary. */
59841
+ function readPublishedBlockPlacement(id, content) {
59842
+ if (id == null && content == null) return null;
59843
+ if (id == null || content == null) throw new Error("Published block placement requires both an ID and content");
59844
+ return {
59845
+ id,
59846
+ content
59847
+ };
59848
+ }
59312
59849
  function toPresentationPage(page) {
59313
59850
  if (!page) return null;
59314
59851
  return {
@@ -59319,6 +59856,8 @@ function toPresentationPage(page) {
59319
59856
  kind: block.kind,
59320
59857
  purpose: block.purpose,
59321
59858
  ...block.contentVersionId ? { contentVersionId: block.contentVersionId } : {},
59859
+ ...block.draftContentId !== void 0 ? { draftContentId: block.draftContentId } : {},
59860
+ ...block.publishedPlacement !== void 0 ? { publishedPlacement: block.publishedPlacement } : {},
59322
59861
  ...block.bindings ? { bindings: block.bindings } : {}
59323
59862
  };
59324
59863
  return block.admission.kind === "renderable" ? {
@@ -60046,6 +60585,9 @@ const containerResponsiveThemeCss = `/*
60046
60585
  .rb-h-4 {
60047
60586
  height: 1rem;
60048
60587
  }
60588
+ .rb-h-5 {
60589
+ height: 1.25rem;
60590
+ }
60049
60591
  .rb-h-8 {
60050
60592
  height: 2rem;
60051
60593
  }
@@ -64011,6 +64553,10 @@ const containerResponsiveThemeCss = `/*
64011
64553
  margin-bottom: 0.25rem;
64012
64554
  }
64013
64555
 
64556
+ :where(.theme-scope) :where([data-block='event-registration']) .er-consent-check {
64557
+ margin-top: 0.75rem;
64558
+ }
64559
+
64014
64560
  :where(.theme-scope) :where([data-block='event-registration']) .er-required {
64015
64561
  color: var(--er-required);
64016
64562
  }
@@ -68730,13 +69276,6 @@ const containerResponsiveThemeCss = `/*
68730
69276
  margin: 0;
68731
69277
  }
68732
69278
 
68733
- /* Inline field (checkbox, radio with label) */
68734
- :where(.theme-scope) :where([data-block="form"]) .fb-inline {
68735
- display: flex;
68736
- align-items: center;
68737
- gap: 0.5rem;
68738
- }
68739
-
68740
69279
  /* Success state */
68741
69280
  :where(.theme-scope) :where([data-block="form"]) .fb-success {
68742
69281
  background-color: var(--fb-success-bg);
@@ -70853,9 +71392,11 @@ const containerResponsiveThemeCss = `/*
70853
71392
  */
70854
71393
 
70855
71394
  /* Newsletter copy styling */
71395
+ /* Size only: weight, family and colour come from the theme's heading styles */
70856
71396
  :where(.theme-scope) :where([data-block="newsletter-signup"]) .newsletter-copy-title {
70857
- font-size: 1.5rem;
70858
- font-weight: 600;
71397
+ font-size: clamp(1.75rem, 1.35rem + 1.6vw, 2.5rem);
71398
+ line-height: 1.15;
71399
+ text-wrap: balance;
70859
71400
  }
70860
71401
 
70861
71402
  :where(.theme-scope) :where([data-block="newsletter-signup"]) .newsletter-copy-subtitle {
@@ -70879,37 +71420,150 @@ const containerResponsiveThemeCss = `/*
70879
71420
  gap: var(--rb-gap-sm, 0.75rem);
70880
71421
  }
70881
71422
 
70882
- /* Individual field styling */
71423
+ /* Extra preset fields (name, company...). Labels are visually hidden, so
71424
+ these sit in a row above the email entry. */
71425
+ :where(.theme-scope) .newsletter-extra-fields {
71426
+ display: grid;
71427
+ grid-template-columns: repeat(auto-fit, minmax(min(12rem, 100%), 1fr));
71428
+ gap: 0.5rem;
71429
+ }
71430
+
70883
71431
  :where(.theme-scope) .newsletter-field {
70884
71432
  display: flex;
70885
71433
  flex-direction: column;
70886
71434
  gap: 0.25rem;
71435
+ text-align: left;
70887
71436
  }
70888
71437
 
70889
- /* Topic choices (visitor picks what to hear about). Same treatment as the
70890
- form block's .fb-fieldset / .fb-inline, defined here because the newsletter
70891
- form also renders inside contact-newsletter and the site footer. */
70892
- :where(.theme-scope) .newsletter-topics {
71438
+ /* Email entry: the email field and the themed submit button share one shell.
71439
+ The shell's look (background, border, corners, focus ring) comes from the
71440
+ theme's input system via .form-input-group; this only handles layout. */
71441
+ :where(.theme-scope) .newsletter-entry {
71442
+ container-type: inline-size;
70893
71443
  display: flex;
70894
71444
  flex-direction: column;
70895
- gap: 0.5rem;
71445
+ gap: 0.375rem;
71446
+ text-align: left;
71447
+ }
71448
+
71449
+ :where(.theme-scope) .newsletter-entry-group > button {
71450
+ white-space: nowrap;
71451
+ }
71452
+
71453
+ /* Too narrow for field and button side by side (phones, footer columns):
71454
+ stack them inside the shell and keep pill themes from turning the taller
71455
+ shell into a capsule. */
71456
+ @container (max-width: 22rem) {
71457
+ :where(.theme-scope) .newsletter-entry .newsletter-entry-group {
71458
+ flex-direction: column;
71459
+ border-radius: min(var(--rb-input-radius, 0.5rem), 1rem);
71460
+ }
71461
+
71462
+ :where(.theme-scope) .newsletter-entry .newsletter-entry-group > button {
71463
+ width: 100%;
71464
+ justify-content: center;
71465
+ }
71466
+ }
71467
+
71468
+ /* Topic choices (visitor picks what to hear about) as toggle chips. Each chip
71469
+ is a real checkbox underneath; the chip is its visible face. */
71470
+ :where(.theme-scope) .newsletter-topics {
70896
71471
  border: none;
70897
71472
  padding: 0;
70898
71473
  margin: 0;
70899
71474
  min-width: 0;
70900
71475
  }
70901
71476
 
70902
- :where(.theme-scope) .newsletter-topics > legend {
71477
+ :where(.theme-scope) .newsletter-topics-legend {
70903
71478
  padding: 0;
70904
- margin-bottom: 0.25rem;
71479
+ margin-bottom: 0.625rem;
71480
+ font-size: 0.9375rem;
71481
+ color: var(--rb-surface-text-color, rgb(var(--tb-text, 17 24 39)));
70905
71482
  }
70906
71483
 
70907
- :where(.theme-scope) .newsletter-topic-choice {
71484
+ :where(.theme-scope) .newsletter-topic-chips {
70908
71485
  display: flex;
70909
- align-items: center;
71486
+ flex-wrap: wrap;
70910
71487
  gap: 0.5rem;
70911
71488
  }
70912
71489
 
71490
+ :where(.theme-scope) .newsletter-stacked .newsletter-topics-legend {
71491
+ width: 100%;
71492
+ }
71493
+
71494
+ :where(.theme-scope) .newsletter-stacked .newsletter-topic-chips {
71495
+ justify-content: center;
71496
+ }
71497
+
71498
+ :where(.theme-scope) .newsletter-topic-chip {
71499
+ position: relative;
71500
+ display: inline-flex;
71501
+ }
71502
+
71503
+ :where(.theme-scope) .newsletter-topic-chip > input {
71504
+ position: absolute;
71505
+ inset: 0;
71506
+ width: 100%;
71507
+ height: 100%;
71508
+ margin: 0;
71509
+ opacity: 0;
71510
+ cursor: pointer;
71511
+ }
71512
+
71513
+ :where(.theme-scope) .newsletter-topic-chip > span {
71514
+ display: inline-flex;
71515
+ align-items: center;
71516
+ gap: 0.375rem;
71517
+ padding: 0.4375rem 0.9375rem;
71518
+ border: 1px solid color-mix(in srgb, currentColor 35%, transparent);
71519
+ border-radius: var(--rb-button-radius, var(--rb-input-radius, 9999px));
71520
+ font-size: 0.9375rem;
71521
+ line-height: 1.3;
71522
+ color: var(--rb-surface-text-color, rgb(var(--tb-text, 17 24 39)));
71523
+ transition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease;
71524
+ }
71525
+
71526
+ /* Tick that grows in when the chip is on */
71527
+ :where(.theme-scope) .newsletter-topic-chip > span::before {
71528
+ content: "";
71529
+ width: 0;
71530
+ height: 0.7em;
71531
+ background-color: currentColor;
71532
+ clip-path: polygon(14% 52%, 0 67%, 38% 100%, 100% 22%, 85% 8%, 37% 70%);
71533
+ transition: width 0.15s ease;
71534
+ }
71535
+
71536
+ :where(.theme-scope) .newsletter-topic-chip:hover > span {
71537
+ border-color: currentColor;
71538
+ }
71539
+
71540
+ /* Same accent and mark colours as the theme's checkboxes */
71541
+ :where(.theme-scope) .newsletter-topic-chip > input:checked + span {
71542
+ background-color: var(--rb-check-accent, rgb(var(--tb-primary)));
71543
+ border-color: var(--rb-check-accent, rgb(var(--tb-primary)));
71544
+ color: var(--rb-check-mark, rgb(var(--tb-onPrimary, 255 255 255)));
71545
+ }
71546
+
71547
+ :where(.theme-scope) .newsletter-topic-chip > input:checked + span::before {
71548
+ width: 0.7em;
71549
+ }
71550
+
71551
+ :where(.theme-scope) .newsletter-topic-chip > input:focus-visible + span {
71552
+ outline: 2px solid var(--rb-check-accent, rgb(var(--tb-primary)));
71553
+ outline-offset: 2px;
71554
+ }
71555
+
71556
+ :where(.theme-scope) .newsletter-topic-chip > input:disabled + span {
71557
+ opacity: 0.6;
71558
+ }
71559
+
71560
+ @media (prefers-reduced-motion: reduce) {
71561
+ :where(.theme-scope) .newsletter-topic-chip > span,
71562
+ :where(.theme-scope) .newsletter-topic-chip > span::before {
71563
+ transition: none;
71564
+ }
71565
+ }
71566
+
70913
71567
  /* Error panel and field notes. The form block scopes these to its own
70914
71568
  data-block, so the newsletter form (which also renders in the footer)
70915
71569
  needs its own copy of the treatment. */
@@ -70927,13 +71581,7 @@ const containerResponsiveThemeCss = `/*
70927
71581
  color: var(--fb-error-text);
70928
71582
  }
70929
71583
 
70930
- /* Required indicator */
70931
- :where(.theme-scope) .newsletter-required {
70932
- color: rgb(var(--tb-primary));
70933
- margin-left: 0.125rem;
70934
- }
70935
-
70936
- /* Submit button container */
71584
+ /* Submit button container (only when a preset has no email field) */
70937
71585
  :where(.theme-scope) .newsletter-submit {
70938
71586
  margin-top: 0.5rem;
70939
71587
  }
@@ -70945,52 +71593,29 @@ const containerResponsiveThemeCss = `/*
70945
71593
  justify-content: center;
70946
71594
  }
70947
71595
 
70948
- /* Privacy note */
71596
+ /* Privacy note: quieter than the intro so the entry row leads */
70949
71597
  :where(.theme-scope) .newsletter-privacy-note {
70950
71598
  margin-top: 0.75rem;
70951
- font-size: 1rem;
70952
- line-height: 1.6;
70953
- color: var(--rb-surface-text-color, rgb(var(--tb-text, 17 24 39)));
71599
+ font-size: 0.8125rem;
71600
+ line-height: 1.5;
71601
+ color: var(--rb-surface-supporting-color, var(--rb-surface-text-color, rgb(var(--tb-text, 17 24 39))));
71602
+ opacity: 0.85;
70954
71603
  text-align: center;
70955
71604
  }
70956
71605
 
70957
71606
  /* =============================================================================
70958
- * Inline Variant - Horizontal layout
71607
+ * Inline Variant - left-aligned, wider entry row
70959
71608
  * =============================================================================
70960
71609
  */
70961
71610
 
70962
- :where(.theme-scope) .newsletter-inline .newsletter-form-fields {
70963
- flex-direction: row;
70964
- align-items: flex-end;
70965
- flex-wrap: wrap;
70966
- gap: var(--rb-gap-sm, 0.75rem);
70967
- }
70968
-
70969
- :where(.theme-scope) .newsletter-inline .newsletter-field {
70970
- flex: 1 1 auto;
70971
- min-width: 10rem;
70972
- }
70973
-
70974
- :where(.theme-scope) .newsletter-inline .newsletter-submit {
70975
- margin-top: 0;
70976
- flex-shrink: 0;
70977
- }
70978
-
70979
- :where(.theme-scope) .newsletter-inline .newsletter-topics {
70980
- flex-basis: 100%;
71611
+ :where(.theme-scope) .newsletter-inline .newsletter-form {
71612
+ max-width: 40rem;
71613
+ margin-left: 0;
71614
+ margin-right: 0;
70981
71615
  }
70982
71616
 
70983
- /* Mobile fallback for inline variant */
70984
- @container rb-site (max-width: 640px) {
70985
- @scope ([data-rb-responsive-mode="container"]) to (:scope [data-rb-responsive-mode]) {
70986
- :where(.theme-scope) .newsletter-inline .newsletter-form-fields {
70987
- flex-direction: column;
70988
- }
70989
-
70990
- :where(.theme-scope) .newsletter-inline .newsletter-field {
70991
- min-width: 100%;
70992
- }
70993
- }
71617
+ :where(.theme-scope) .newsletter-inline .newsletter-privacy-note {
71618
+ text-align: left;
70994
71619
  }
70995
71620
 
70996
71621
  /* =============================================================================
@@ -71128,12 +71753,6 @@ const containerResponsiveThemeCss = `/*
71128
71753
  margin: 0;
71129
71754
  }
71130
71755
 
71131
- :where(.theme-scope) :where([data-block="contact-newsletter"]) .fb-inline {
71132
- display: flex;
71133
- align-items: center;
71134
- gap: 0.5rem;
71135
- }
71136
-
71137
71756
  :where(.theme-scope) :where([data-block="contact-newsletter"]) .fb-success,
71138
71757
  :where(.theme-scope) :where([data-block="contact-newsletter"]) .fb-error,
71139
71758
  :where(.theme-scope) :where([data-block="contact-newsletter"]) .fb-empty {
@@ -73030,6 +73649,44 @@ const containerResponsiveThemeCss = `/*
73030
73649
  flex: 0 0 auto;
73031
73650
  }
73032
73651
  }
73652
+ }
73653
+
73654
+ /* =============================================================================
73655
+ * Site footer: social links
73656
+ *
73657
+ * Icon links get a 40px tap target with a hairline ring drawn from the link's
73658
+ * own colour, so it follows the footer's text colour on any surface. Links
73659
+ * without an icon (unknown platforms) stay plain text.
73660
+ * =============================================================================
73661
+ */
73662
+
73663
+ :where(.theme-scope) .rb-footer-socials {
73664
+ display: flex;
73665
+ flex-wrap: wrap;
73666
+ align-items: center;
73667
+ gap: 0.75rem 1.25rem;
73668
+ }
73669
+
73670
+ :where(.theme-scope) .rb-footer-social-link:has(> .rb-footer-social-icon) {
73671
+ display: inline-grid;
73672
+ place-items: center;
73673
+ width: 2.5rem;
73674
+ height: 2.5rem;
73675
+ border: 1px solid color-mix(in srgb, currentColor 22%, transparent);
73676
+ border-radius: 9999px;
73677
+ }
73678
+
73679
+ :where(.theme-scope) .rb-footer-socials:has(.rb-footer-social-icon) {
73680
+ gap: 0.5rem;
73681
+ }
73682
+
73683
+ :where(.theme-scope) .rb-footer-social-link:has(> .rb-footer-social-icon):hover {
73684
+ border-color: currentColor;
73685
+ }
73686
+
73687
+ :where(.theme-scope) .rb-footer-social-icon {
73688
+ width: 1.5rem;
73689
+ height: 1.5rem;
73033
73690
  }`;
73034
73691
  //#endregion
73035
73692
  //#region ../theme-core/src/ThemeScopeCore.tsx
@@ -73330,7 +73987,7 @@ function toBlocksCommonProps(props) {
73330
73987
  return {
73331
73988
  page: props.page,
73332
73989
  runtimeJoins: props.runtimeJoins,
73333
- dataContext: props.dataContext ? toBlocksPageRendererDataContext(props.dataContext) : void 0,
73990
+ dataContext: toBlocksPageRendererDataContext(props.dataContext),
73334
73991
  routeMap: props.routeMap,
73335
73992
  wrapBlock: props.wrapBlock,
73336
73993
  registry: props.registry,
@@ -73428,14 +74085,14 @@ function resolveSdkBookingTimeZone(timeZone) {
73428
74085
  }
73429
74086
  function buildPageRouteRenderContext(dataContext) {
73430
74087
  return {
73431
- pathname: dataContext?.pathname,
73432
- occurrenceContext: dataContext?.occurrenceContext ?? null,
73433
- entrySubrouteContext: dataContext?.entrySubrouteContext ?? null,
73434
- contentEntry: dataContext?.contentEntry ?? null,
73435
- pageSurface: dataContext?.pageSurface ?? null,
73436
- subject: dataContext?.subject ?? null,
73437
- editableRouteMetadataFieldIds: dataContext?.editableRouteMetadataFieldIds ?? null,
73438
- previewStage: dataContext?.previewStage
74088
+ pathname: dataContext.pathname,
74089
+ occurrenceContext: dataContext.occurrenceContext ?? null,
74090
+ entrySubrouteContext: dataContext.entrySubrouteContext ?? null,
74091
+ contentEntry: dataContext.contentEntry ?? null,
74092
+ pageSurface: dataContext.pageSurface ?? null,
74093
+ subject: dataContext.subject ?? null,
74094
+ editableRouteMetadataFieldIds: dataContext.editableRouteMetadataFieldIds ?? null,
74095
+ previewStage: dataContext.previewStage
73439
74096
  };
73440
74097
  }
73441
74098
  function PageContent(props) {
@@ -73449,10 +74106,10 @@ function PageContent(props) {
73449
74106
  apiBaseUrl,
73450
74107
  portalToken,
73451
74108
  previewToken,
73452
- readAuthority: readAuthority ?? dataContext?.readAuthority,
74109
+ readAuthority: readAuthority ?? dataContext.readAuthority,
73453
74110
  resolvedData,
73454
74111
  bookingOfferingPresets: bookingOfferingPresets ?? [],
73455
- mailingList: mailingList ?? dataContext?.mailingList,
74112
+ mailingList: mailingList ?? dataContext.mailingList,
73456
74113
  bookingTimeZone: resolveSdkBookingTimeZone(bookingTimeZone),
73457
74114
  routes: routeMap,
73458
74115
  pagesByIdentifier,
@@ -75325,21 +75982,39 @@ function resolveSiteCustomBlocks(site) {
75325
75982
  const sdkBlocks = site.sdkConfig?.customBlocks;
75326
75983
  if (Array.isArray(sdkBlocks) && sdkBlocks.length > 0) return sdkBlocks;
75327
75984
  }
75328
- function convertPageResponseBlock(block) {
75985
+ function readBlockContentId(value, name) {
75986
+ if (value === null || value === void 0) return null;
75987
+ if (typeof value === "string") return value;
75988
+ throw new Error(`Invalid ${name} in page: expected string or null`);
75989
+ }
75990
+ function readTransportedBlockIdentity(block, kind, stage) {
75991
+ return {
75992
+ draftContentId: readBlockContentId(block.draftContentId, "draft content id"),
75993
+ publishedPlacement: stage === "preview" ? readPublishedBlockPlacement(readBlockContentId(block.publishedContentId, "published content id"), sanitizeNullableSdkRuntimeBlockContent(kind, readNestedContentRecord(block.publishedContent))) : null
75994
+ };
75995
+ }
75996
+ function convertPageResponseBlock(block, stage) {
75329
75997
  if (!isRecord$8(block)) throw new Error("Invalid block format in page API response");
75998
+ const header = readTransportedBlockHeader(block);
75999
+ const admission = readInvalidBlockAdmission(block.admission);
76000
+ return {
76001
+ ...header,
76002
+ ...readTransportedBlockIdentity(block, header.kind, stage),
76003
+ content: sanitizeSdkRuntimeBlockContent(header.kind, readContentRecord(block.content) ?? {}),
76004
+ draftContent: sanitizeNullableSdkRuntimeBlockContent(header.kind, readNestedContentRecord(block.draftContent)),
76005
+ ...admission ? { admission } : {}
76006
+ };
76007
+ }
76008
+ function readTransportedBlockHeader(block) {
75330
76009
  if (typeof block.id !== "string" && block.id !== null) throw new Error(`Invalid block id in page: expected string or null, got ${typeof block.id}`);
75331
76010
  if (typeof block.kind !== "string") throw new Error(`Invalid block kind in page: expected string, got ${typeof block.kind}`);
75332
76011
  if (typeof block.purpose !== "string") throw new Error(`Invalid block purpose in page: expected string, got ${typeof block.purpose}`);
75333
76012
  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}`);
75334
- const admission = readInvalidBlockAdmission(block.admission);
75335
76013
  return {
75336
76014
  id: block.id,
75337
76015
  ...block.contentVersionId !== void 0 ? { contentVersionId: block.contentVersionId } : {},
75338
76016
  kind: block.kind,
75339
- purpose: block.purpose,
75340
- content: sanitizeSdkRuntimeBlockContent(block.kind, readContentRecord(block.content) ?? {}),
75341
- draftContent: sanitizeNullableSdkRuntimeBlockContent(block.kind, readNestedContentRecord(block.draftContent)),
75342
- ...admission ? { admission } : {}
76017
+ purpose: block.purpose
75343
76018
  };
75344
76019
  }
75345
76020
  function readInvalidBlockAdmission(value) {
@@ -75352,7 +76027,7 @@ function buildPageOutline(input) {
75352
76027
  name: input.name,
75353
76028
  path: input.path ?? input.fallbackPath,
75354
76029
  purpose: input.purpose,
75355
- blocks: input.blocks.map(convertPageResponseBlock)
76030
+ blocks: input.blocks.map((block) => convertPageResponseBlock(block, input.previewStage))
75356
76031
  };
75357
76032
  }
75358
76033
  function buildRenderablePageOutline(input) {
@@ -75365,6 +76040,8 @@ function buildRenderablePageOutline(input) {
75365
76040
  function admitSdkRuntimePageBlock(block, customBlocks) {
75366
76041
  const base = {
75367
76042
  id: block.id,
76043
+ draftContentId: block.draftContentId,
76044
+ publishedPlacement: block.publishedPlacement,
75368
76045
  ...block.contentVersionId !== void 0 ? { contentVersionId: block.contentVersionId } : {},
75369
76046
  kind: block.kind,
75370
76047
  purpose: block.purpose,
@@ -75435,6 +76112,7 @@ function buildFooterRenderablePageOutline(siteData, blocks) {
75435
76112
  fallbackPath: "/__footer",
75436
76113
  purpose: "footer",
75437
76114
  blocks,
76115
+ previewStage: "published",
75438
76116
  customBlocks: resolveSiteCustomBlocks(siteData)
75439
76117
  });
75440
76118
  }
@@ -76677,6 +77355,13 @@ const EVENT_SERIES_REGISTRATION_ENDPOINT_DEFINITIONS = defineEndpointDefinitions
76677
77355
  errors: [],
76678
77356
  responseKind: "blob"
76679
77357
  },
77358
+ exportEventOfferingRegistrationsCsv: {
77359
+ path: "/sites/{siteId}/bookings/event-offerings/{eventOfferingId}/registrations/export.csv",
77360
+ method: "GET",
77361
+ auth: "user",
77362
+ errors: [],
77363
+ responseKind: "blob"
77364
+ },
76680
77365
  updateEventSeriesRegistration: {
76681
77366
  path: "/sites/{siteId}/bookings/event-series/{seriesId}/registrations/{registrationId}",
76682
77367
  method: "PATCH",
@@ -76687,6 +77372,19 @@ const EVENT_SERIES_REGISTRATION_ENDPOINT_DEFINITIONS = defineEndpointDefinitions
76687
77372
  "resource:not_found",
76688
77373
  "server:internal_error"
76689
77374
  ]
77375
+ },
77376
+ saveEventSeriesRegistrationAnswers: {
77377
+ path: "/sites/{siteId}/bookings/event-series/{seriesId}/registrations/{registrationId}/answers",
77378
+ method: "PUT",
77379
+ auth: "user",
77380
+ responseKind: "json",
77381
+ errors: [
77382
+ "validation:invalid_input",
77383
+ "auth:forbidden",
77384
+ "resource:not_found",
77385
+ "resource:conflict",
77386
+ "server:internal_error"
77387
+ ]
76690
77388
  }
76691
77389
  });
76692
77390
  //#endregion
@@ -77107,6 +77805,30 @@ const NEWSLETTER_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
77107
77805
  responseKind: "json",
77108
77806
  demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN
77109
77807
  },
77808
+ scheduleNewsletterCampaign: {
77809
+ path: "/sites/{siteId}/newsletter/campaigns/{campaignId}/schedule",
77810
+ method: "POST",
77811
+ tags: [TAG_TEMPLATES.site, TAG_TEMPLATES.siteNewsletter],
77812
+ auth: "user",
77813
+ responseKind: "json",
77814
+ demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN
77815
+ },
77816
+ unscheduleNewsletterCampaign: {
77817
+ path: "/sites/{siteId}/newsletter/campaigns/{campaignId}/unschedule",
77818
+ method: "POST",
77819
+ tags: [TAG_TEMPLATES.site, TAG_TEMPLATES.siteNewsletter],
77820
+ auth: "user",
77821
+ responseKind: "json",
77822
+ demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN
77823
+ },
77824
+ stopNewsletterCampaign: {
77825
+ path: "/sites/{siteId}/newsletter/campaigns/{campaignId}/stop",
77826
+ method: "POST",
77827
+ tags: [TAG_TEMPLATES.site, TAG_TEMPLATES.siteNewsletter],
77828
+ auth: "user",
77829
+ responseKind: "json",
77830
+ demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN
77831
+ },
77110
77832
  testSendNewsletterCampaign: {
77111
77833
  path: "/sites/{siteId}/newsletter/campaigns/{campaignId}/test-send",
77112
77834
  method: "POST",
@@ -77117,6 +77839,154 @@ const NEWSLETTER_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
77117
77839
  }
77118
77840
  });
77119
77841
  //#endregion
77842
+ //#region ../api/src/sdkEventEndpointDefinitions.ts
77843
+ /**
77844
+ * The SDK's Event graph: the Events themselves and the occurrences of one run.
77845
+ * Extracted from `endpoints.ts` so this family can be read, and added to, on
77846
+ * its own. New entries here must declare `errors`; the
77847
+ * require-api-endpoint-errors lint enforces that here as in endpoints.ts.
77848
+ */
77849
+ const SDK_EVENT_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
77850
+ sdkListEvents: {
77851
+ path: "/sdk/{siteId}/events",
77852
+ method: "GET",
77853
+ auth: "service",
77854
+ responseKind: "json"
77855
+ },
77856
+ sdkUpsertEvent: {
77857
+ path: "/sdk/{siteId}/events",
77858
+ method: "POST",
77859
+ auth: "service",
77860
+ responseKind: "json",
77861
+ errors: [
77862
+ "validation:invalid_input",
77863
+ "resource:not_found",
77864
+ "resource:conflict",
77865
+ "billing:plan_limit_exceeded",
77866
+ "server:internal_error"
77867
+ ]
77868
+ },
77869
+ sdkGetEvent: {
77870
+ path: "/sdk/{siteId}/events/{identifier}",
77871
+ method: "GET",
77872
+ auth: "service",
77873
+ responseKind: "json"
77874
+ },
77875
+ sdkDeleteEvent: {
77876
+ path: "/sdk/{siteId}/events/{identifier}",
77877
+ method: "DELETE",
77878
+ auth: "service",
77879
+ responseKind: "json",
77880
+ errors: [
77881
+ "resource:not_found",
77882
+ "resource:conflict",
77883
+ "server:internal_error"
77884
+ ]
77885
+ },
77886
+ sdkTakeEventOffline: {
77887
+ path: "/sdk/{siteId}/events/{identifier}/lifecycle",
77888
+ method: "POST",
77889
+ auth: "service",
77890
+ responseKind: "json",
77891
+ errors: [
77892
+ "resource:not_found",
77893
+ "validation:invalid_input",
77894
+ "resource:conflict",
77895
+ "server:internal_error"
77896
+ ]
77897
+ },
77898
+ sdkListEventOccurrences: {
77899
+ path: "/sdk/{siteId}/events/{identifier}/runs/{runIdentifier}/occurrences",
77900
+ method: "GET",
77901
+ auth: "service",
77902
+ responseKind: "json",
77903
+ errors: [
77904
+ "resource:not_found",
77905
+ "validation:invalid_input",
77906
+ "server:internal_error"
77907
+ ]
77908
+ },
77909
+ sdkAddEventOccurrence: {
77910
+ path: "/sdk/{siteId}/events/{identifier}/runs/{runIdentifier}/occurrences",
77911
+ method: "POST",
77912
+ auth: "service",
77913
+ responseKind: "json",
77914
+ errors: [
77915
+ "resource:not_found",
77916
+ "validation:invalid_input",
77917
+ "resource:conflict",
77918
+ "server:internal_error"
77919
+ ]
77920
+ },
77921
+ sdkUpdateEventOccurrence: {
77922
+ path: "/sdk/{siteId}/events/{identifier}/runs/{runIdentifier}/occurrences/{occurrenceId}",
77923
+ method: "PATCH",
77924
+ auth: "service",
77925
+ responseKind: "json",
77926
+ errors: [
77927
+ "resource:not_found",
77928
+ "validation:invalid_input",
77929
+ "resource:conflict",
77930
+ "server:internal_error"
77931
+ ]
77932
+ },
77933
+ sdkCancelEventOccurrence: {
77934
+ path: "/sdk/{siteId}/events/{identifier}/runs/{runIdentifier}/occurrences/{occurrenceId}/cancel",
77935
+ method: "POST",
77936
+ auth: "service",
77937
+ responseKind: "json",
77938
+ errors: [
77939
+ "resource:not_found",
77940
+ "resource:conflict",
77941
+ "server:internal_error"
77942
+ ]
77943
+ },
77944
+ sdkDeleteEventOccurrence: {
77945
+ path: "/sdk/{siteId}/events/{identifier}/runs/{runIdentifier}/occurrences/{occurrenceId}",
77946
+ method: "DELETE",
77947
+ auth: "service",
77948
+ responseKind: "json",
77949
+ errors: [
77950
+ "resource:not_found",
77951
+ "resource:conflict",
77952
+ "server:internal_error"
77953
+ ]
77954
+ }
77955
+ });
77956
+ //#endregion
77957
+ //#region ../api/src/sdkPageDesignEndpointDefinitions.ts
77958
+ /**
77959
+ * SDK management endpoints for a page's draft design (issue 1497), spread into
77960
+ * `ENDPOINT_DEFINITIONS` like the other endpoint-definition modules. New
77961
+ * entries here must declare `errors`, which the require-api-endpoint-errors
77962
+ * lint enforces.
77963
+ */
77964
+ const SDK_PAGE_DESIGN_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
77965
+ sdkGetPageDesign: {
77966
+ path: "/sdk/{siteId}/pages/{identifier}/design",
77967
+ method: "GET",
77968
+ auth: "service",
77969
+ responseKind: "json",
77970
+ errors: [
77971
+ "resource:not_found",
77972
+ "validation:invalid_input",
77973
+ "server:internal_error"
77974
+ ]
77975
+ },
77976
+ sdkSavePageDesign: {
77977
+ path: "/sdk/{siteId}/pages/{identifier}/design",
77978
+ method: "POST",
77979
+ auth: "service",
77980
+ responseKind: "json",
77981
+ errors: [
77982
+ "resource:not_found",
77983
+ "validation:invalid_input",
77984
+ "resource:conflict",
77985
+ "server:internal_error"
77986
+ ]
77987
+ }
77988
+ });
77989
+ //#endregion
77120
77990
  //#region ../api/src/publicEventEndpointDefinitions.ts
77121
77991
  const PUBLIC_EVENT_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
77122
77992
  checkPublicEventRegistrationNextStep: {
@@ -77361,6 +78231,45 @@ const SITE_API_KEY_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
77361
78231
  }
77362
78232
  });
77363
78233
  //#endregion
78234
+ //#region ../api/src/siteManagementEndpointDefinitions.ts
78235
+ const SITE_MANAGEMENT_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
78236
+ createSite: {
78237
+ path: "/sites/manage",
78238
+ method: "POST",
78239
+ tags: ["site"],
78240
+ auth: "user",
78241
+ responseKind: "json"
78242
+ },
78243
+ updateSite: {
78244
+ path: "/sites/manage",
78245
+ method: "PUT",
78246
+ tags: ["site"],
78247
+ auth: "user",
78248
+ responseKind: "json"
78249
+ },
78250
+ changeSiteAddress: {
78251
+ path: "/sites/{siteId}/address",
78252
+ method: "PUT",
78253
+ auth: "user",
78254
+ responseKind: "json",
78255
+ demoMutation: DEMO_MUTATION_BLOCKED_DISABLED
78256
+ },
78257
+ getSiteAddressAvailability: {
78258
+ path: "/sites/{siteId}/address/availability",
78259
+ method: "GET",
78260
+ auth: "user",
78261
+ responseKind: "json"
78262
+ },
78263
+ deleteSite: {
78264
+ path: "/sites/{siteId}",
78265
+ method: "DELETE",
78266
+ tags: ["site", "site-{siteId}"],
78267
+ auth: "user",
78268
+ responseKind: "json",
78269
+ demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN
78270
+ }
78271
+ });
78272
+ //#endregion
77364
78273
  //#region ../api/src/eventManagementEndpointDefinitions.ts
77365
78274
  const EVENT_MANAGEMENT_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
77366
78275
  listEvents: {
@@ -77408,6 +78317,28 @@ const EVENT_MANAGEMENT_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
77408
78317
  "server:internal_error"
77409
78318
  ]
77410
78319
  },
78320
+ /**
78321
+ * The web address of an event's own page. A course page belongs to the
78322
+ * event itself, so its address is written here rather than through a run.
78323
+ */
78324
+ updateEventAddress: {
78325
+ path: "/sites/{siteId}/bookings/events/{eventId}/address",
78326
+ method: "PATCH",
78327
+ tags: [
78328
+ "site-{siteId}",
78329
+ "event-series-{siteId}",
78330
+ TAG_TEMPLATES.siteRoutableContent,
78331
+ TAG_TEMPLATES.siteRedirects
78332
+ ],
78333
+ auth: "user",
78334
+ responseKind: "json",
78335
+ errors: [
78336
+ "validation:invalid_input",
78337
+ "resource:not_found",
78338
+ "resource:conflict",
78339
+ "server:internal_error"
78340
+ ]
78341
+ },
77411
78342
  createWholeSeriesRun: {
77412
78343
  path: "/sites/{siteId}/bookings/events/{eventId}/runs",
77413
78344
  method: "POST",
@@ -77434,6 +78365,20 @@ const EVENT_MANAGEMENT_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
77434
78365
  "server:internal_error"
77435
78366
  ]
77436
78367
  },
78368
+ updateCourseBookingSettings: {
78369
+ path: "/sites/{siteId}/bookings/events/{eventId}/booking-settings",
78370
+ method: "PATCH",
78371
+ tags: ["site-{siteId}", "event-series-{siteId}"],
78372
+ auth: "user",
78373
+ responseKind: "json",
78374
+ errors: [
78375
+ "validation:invalid_input",
78376
+ "auth:forbidden",
78377
+ "resource:not_found",
78378
+ "resource:conflict",
78379
+ "server:internal_error"
78380
+ ]
78381
+ },
77437
78382
  cancelWholeSeriesRun: {
77438
78383
  path: "/sites/{siteId}/bookings/events/{eventId}/runs/{runId}/cancellation",
77439
78384
  method: "POST",
@@ -77446,6 +78391,28 @@ const EVENT_MANAGEMENT_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
77446
78391
  "resource:conflict",
77447
78392
  "server:internal_error"
77448
78393
  ]
78394
+ },
78395
+ /**
78396
+ * The Content tab's one write: the short introduction, image and
78397
+ * description of an event's page, published without its layout.
78398
+ */
78399
+ saveEventPageWords: {
78400
+ path: "/sites/{siteId}/page-surfaces/{pageSurfaceId}/words",
78401
+ method: "PUT",
78402
+ tags: [
78403
+ TAG_TEMPLATES.siteCollection,
78404
+ TAG_TEMPLATES.siteRoutableContent,
78405
+ TAG_TEMPLATES.pageSurfaceById
78406
+ ],
78407
+ auth: "user",
78408
+ responseKind: "json",
78409
+ errors: [
78410
+ "auth:forbidden",
78411
+ "validation:invalid_input",
78412
+ "resource:not_found",
78413
+ "resource:conflict",
78414
+ "server:internal_error"
78415
+ ]
77449
78416
  }
77450
78417
  });
77451
78418
  //#endregion
@@ -77878,19 +78845,56 @@ const BILLING_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
77878
78845
  responseKind: "json"
77879
78846
  }
77880
78847
  });
78848
+ //#endregion
78849
+ //#region ../api/src/clientErrorReporting.ts
78850
+ const CLIENT_ERROR_REPORT_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({ reportClientError: {
78851
+ path: "/client/error-report",
78852
+ method: "POST",
78853
+ auth: "user",
78854
+ errors: [],
78855
+ responseKind: "json"
78856
+ } });
78857
+ const CLIENT_ERROR_REPORT_LIMITS = {
78858
+ pathname: 1024,
78859
+ name: 120,
78860
+ message: 2e3,
78861
+ stack: 8e3,
78862
+ digest: 128,
78863
+ componentStack: 8e3,
78864
+ sourceLocation: 1024
78865
+ };
78866
+ const clientErrorEventSchema = z$1.enum([
78867
+ "dashboard:route-error",
78868
+ "dashboard:app-error",
78869
+ "client:error-boundary",
78870
+ "client:window-error",
78871
+ "client:unhandled-rejection"
78872
+ ]);
78873
+ z$1.object({
78874
+ event: clientErrorEventSchema,
78875
+ pathname: z$1.string().startsWith("/").max(CLIENT_ERROR_REPORT_LIMITS.pathname),
78876
+ name: z$1.string().max(CLIENT_ERROR_REPORT_LIMITS.name),
78877
+ message: z$1.string().max(CLIENT_ERROR_REPORT_LIMITS.message),
78878
+ stack: z$1.string().max(CLIENT_ERROR_REPORT_LIMITS.stack).nullable(),
78879
+ digest: z$1.string().max(CLIENT_ERROR_REPORT_LIMITS.digest).nullable(),
78880
+ componentStack: z$1.string().max(CLIENT_ERROR_REPORT_LIMITS.componentStack).nullable(),
78881
+ sourceLocation: z$1.string().max(CLIENT_ERROR_REPORT_LIMITS.sourceLocation).nullable()
78882
+ }).strict();
77881
78883
  ({
78884
+ ...CLIENT_ERROR_REPORT_ENDPOINT_DEFINITIONS,
77882
78885
  ...PUBLIC_NEWSLETTER_ENDPOINT_DEFINITIONS,
77883
78886
  ...ACCOUNT_ENDPOINT_DEFINITIONS,
77884
78887
  ...PUBLIC_ONBOARDING_ATTEMPT_ENDPOINT_DEFINITIONS,
77885
78888
  ...PUBLIC_EVENT_ENDPOINT_DEFINITIONS,
77886
78889
  ...GIFTING_ENDPOINT_DEFINITIONS,
77887
78890
  ...PUBLIC_READ_ENDPOINT_DEFINITIONS,
77888
- ...BILLING_ENDPOINT_DEFINITIONS
78891
+ ...BILLING_ENDPOINT_DEFINITIONS,
78892
+ ...SITE_MANAGEMENT_ENDPOINT_DEFINITIONS
77889
78893
  }), TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteTheme, TAG_TEMPLATES.siteCollection, { ...SITE_API_KEY_ENDPOINT_DEFINITIONS }, TAG_TEMPLATES.site, TAG_TEMPLATES.siteBookingSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteBookingSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteEmailSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteEmailSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteEmailSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteEmailSettings, {
77890
78894
  ...NEWSLETTER_ENDPOINT_DEFINITIONS,
77891
78895
  ...APPOINTMENT_ENDPOINT_DEFINITIONS,
77892
78896
  ...EVENT_SERIES_REGISTRATION_ENDPOINT_DEFINITIONS
77893
- }, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteById, TAG_TEMPLATES.siteBySlug, TAG_TEMPLATES.siteByDomain, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteById, TAG_TEMPLATES.siteBySlug, TAG_TEMPLATES.siteByDomain, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.pageSurfaceById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.pageSurfaceById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageSurfaceById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageSurfaceById, TAG_TEMPLATES.workflowRunById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.routeById, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.site, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteNavigation, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteNavigation, TAG_TEMPLATES.navigationMenuById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteNavigation, TAG_TEMPLATES.navigationMenuById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteNavigation, TAG_TEMPLATES.navigationMenuById, TAG_TEMPLATES.navigationItemById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteNavigation, TAG_TEMPLATES.navigationMenuById, TAG_TEMPLATES.navigationItemById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteNavigation, TAG_TEMPLATES.navigationMenuById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.publicEvents, TAG_TEMPLATES.publicBookingServices, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteTheme, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteTheme, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteTheme, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.pageSurfaceById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.pageSurfaceById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.pageSurfaceById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.pageSurfaceById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.siteRedirects, TAG_TEMPLATES.siteRouteOutcomes, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.siteRedirects, TAG_TEMPLATES.siteRouteOutcomes, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.siteForms, TAG_TEMPLATES.siteForms, TAG_TEMPLATES.siteForms, TAG_TEMPLATES.siteForms, TAG_TEMPLATES.siteForms, TAG_TEMPLATES.siteForms, TAG_TEMPLATES.formSubmissionsBySlug, TAG_TEMPLATES.siteForms, TAG_TEMPLATES.formSubmissionsBySlug, TAG_TEMPLATES.siteForms, TAG_TEMPLATES.formSubmissionsBySlug, TAG_TEMPLATES.siteForms, { ...PUBLIC_BOOKING_AVAILABILITY_ENDPOINT_DEFINITIONS }, TAG_TEMPLATES.publicEventFilters, TAG_TEMPLATES.publicEvents, TAG_TEMPLATES.publicShop, TAG_TEMPLATES.publicCheckout, TAG_TEMPLATES.siteRoutableContent, { ...PUBLIC_EVENT_CHECKOUT_ENDPOINT_DEFINITIONS }, TAG_TEMPLATES.publicEvents, TAG_TEMPLATES.publicEvents, { ...EVENT_MANAGEMENT_ENDPOINT_DEFINITIONS }, { ...SDK_MEDIA_ENDPOINT_DEFINITIONS }, { ...SDK_ENDPOINT_DEFINITIONS }, { ...SDK_ENTRY_READ_ENDPOINTS };
78897
+ }, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteById, TAG_TEMPLATES.siteBySlug, TAG_TEMPLATES.siteByDomain, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteById, TAG_TEMPLATES.siteBySlug, TAG_TEMPLATES.siteByDomain, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.pageSurfaceById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.pageSurfaceById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageSurfaceById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageSurfaceById, TAG_TEMPLATES.workflowRunById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.routeById, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.site, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteNavigation, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteNavigation, TAG_TEMPLATES.navigationMenuById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteNavigation, TAG_TEMPLATES.navigationMenuById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteNavigation, TAG_TEMPLATES.navigationMenuById, TAG_TEMPLATES.navigationItemById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteNavigation, TAG_TEMPLATES.navigationMenuById, TAG_TEMPLATES.navigationItemById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteNavigation, TAG_TEMPLATES.navigationMenuById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.publicEvents, TAG_TEMPLATES.publicBookingServices, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteTheme, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteTheme, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteTheme, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.pageSurfaceById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.pageSurfaceById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.pageSurfaceById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.pageSurfaceById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.siteRedirects, TAG_TEMPLATES.siteRouteOutcomes, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.siteRedirects, TAG_TEMPLATES.siteRouteOutcomes, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.siteForms, TAG_TEMPLATES.siteForms, TAG_TEMPLATES.siteForms, TAG_TEMPLATES.siteForms, TAG_TEMPLATES.siteForms, TAG_TEMPLATES.siteForms, TAG_TEMPLATES.formSubmissionsBySlug, TAG_TEMPLATES.siteForms, TAG_TEMPLATES.formSubmissionsBySlug, TAG_TEMPLATES.siteForms, TAG_TEMPLATES.formSubmissionsBySlug, TAG_TEMPLATES.siteForms, { ...PUBLIC_BOOKING_AVAILABILITY_ENDPOINT_DEFINITIONS }, TAG_TEMPLATES.publicEventFilters, TAG_TEMPLATES.publicEvents, TAG_TEMPLATES.publicShop, TAG_TEMPLATES.publicCheckout, TAG_TEMPLATES.siteRoutableContent, { ...PUBLIC_EVENT_CHECKOUT_ENDPOINT_DEFINITIONS }, TAG_TEMPLATES.publicEvents, TAG_TEMPLATES.publicEvents, { ...EVENT_MANAGEMENT_ENDPOINT_DEFINITIONS }, { ...SDK_MEDIA_ENDPOINT_DEFINITIONS }, { ...SDK_ENDPOINT_DEFINITIONS }, { ...SDK_PAGE_DESIGN_ENDPOINT_DEFINITIONS }, { ...SDK_EVENT_ENDPOINT_DEFINITIONS }, { ...SDK_ENTRY_READ_ENDPOINTS };
77894
78898
  z$1.object({ refreshToken: z$1.string().min(1).max(4096) }).strict();
77895
78899
  z$1.object({
77896
78900
  accessToken: z$1.string().min(1).max(4096),
@@ -78496,6 +79500,46 @@ z$1.object({ acceptExtraSiteCharge: z$1.boolean().optional() });
78496
79500
  //#region ../surfaces/src/index.ts
78497
79501
  const SURFACE_IDS = ["core", "macadamia"];
78498
79502
  const DEFAULT_SURFACE_ID = "core";
79503
+ /**
79504
+ * Root hosts for each surface, keyed by deployment tier. The tier-keyed shape
79505
+ * makes it impossible to mis-order entries: callers like
79506
+ * `buildSurfaceAwareDashboardOriginForSurfaceId` look up by tier directly
79507
+ * rather than relying on positional alignment between arrays.
79508
+ */
79509
+ const SURFACE_ROOT_HOSTS = {
79510
+ core: {
79511
+ local: "localhost",
79512
+ prod: "riverbankcms.com"
79513
+ },
79514
+ macadamia: {
79515
+ local: "macadamia.localhost",
79516
+ prod: "macadamia.studio"
79517
+ }
79518
+ };
79519
+ const SURFACE_SITE_ROOT_HOSTS = {
79520
+ core: {
79521
+ local: "localhost",
79522
+ prod: "riverbanksites.com"
79523
+ },
79524
+ macadamia: {
79525
+ local: "macadamia.localhost",
79526
+ prod: "macadamia.studio"
79527
+ }
79528
+ };
79529
+ const SURFACE_SITE_ROOT_HOST_ALIASES = { core: { prod: ["preview.riverbanksites.com"] } };
79530
+ function surfaceHostTableValues(table) {
79531
+ return Object.values(table).flatMap((byTier) => Object.values(byTier).flat());
79532
+ }
79533
+ function siteSlugLabelUnderRoot(host, siteRootHost) {
79534
+ if (!host.endsWith(`.${siteRootHost}`)) return [];
79535
+ return host.slice(0, host.length - siteRootHost.length - 1).split(".").slice(-1);
79536
+ }
79537
+ function deriveSurfaceOwnedSiteSlugs() {
79538
+ const siteRootHosts = [...surfaceHostTableValues(SURFACE_SITE_ROOT_HOSTS), ...surfaceHostTableValues(SURFACE_SITE_ROOT_HOST_ALIASES)];
79539
+ const labels = [...surfaceHostTableValues(SURFACE_ROOT_HOSTS), ...siteRootHosts].flatMap((host) => siteRootHosts.flatMap((root) => siteSlugLabelUnderRoot(host, root)));
79540
+ return [...new Set(labels)].sort();
79541
+ }
79542
+ deriveSurfaceOwnedSiteSlugs();
78499
79543
  [...SURFACE_IDS.filter((surfaceId) => surfaceId !== DEFAULT_SURFACE_ID)];
78500
79544
  //#endregion
78501
79545
  //#region ../api/src/accountApi.ts
@@ -79100,6 +80144,7 @@ function stableSerialize(value) {
79100
80144
  if (isRecord$5(value)) return `{${Object.entries(value).filter(([, entryValue]) => entryValue !== void 0).sort(([left], [right]) => left.localeCompare(right)).map(([key, entryValue]) => `${JSON.stringify(key)}:${stableSerialize(entryValue)}`).join(",")}}`;
79101
80145
  return JSON.stringify(value);
79102
80146
  }
80147
+ z$1.enum(["public", "unlisted"], { error: "visibility must be 'public' or 'unlisted'" });
79103
80148
  //#endregion
79104
80149
  //#region ../api/src/bookingPaymentTermSchemas.ts
79105
80150
  const bookingDepositRefundPolicySchema = z$1.enum(["refundable", "non_refundable"]);