@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
@@ -1,12 +1,12 @@
1
1
  "use client";
2
- import { d as unwrapResponse, l as ApiEnvelopeError, s as ApiRequestError, u as extractApiEnvelopeErrorDetails } from "./previewAuthStore-BxAFlu-j.mjs";
2
+ import { d as unwrapResponse, l as ApiEnvelopeError, s as ApiRequestError, u as extractApiEnvelopeErrorDetails } from "./previewAuthStore-h5IgbSp4.mjs";
3
3
  import * as React$1 from "react";
4
4
  import React, { Component, Fragment, cloneElement, createContext, createElement, createRef, forwardRef, isValidElement, memo, startTransition, useCallback, useContext, useDebugValue, useEffect, useId, useImperativeHandle, useLayoutEffect, useMemo, useReducer, useRef, useState, useSyncExternalStore } from "react";
5
5
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
6
6
  import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
7
+ import { z } from "zod";
7
8
  import * as ReactDOM$1 from "react-dom";
8
9
  import ReactDOM, { createPortal, unstable_batchedUpdates } from "react-dom";
9
- import { z } from "zod";
10
10
  import { createRoot } from "react-dom/client";
11
11
  import deepEqual from "fast-deep-equal";
12
12
  //#region \0rolldown/runtime.js
@@ -1168,9 +1168,20 @@ const knownSocialPlatforms = [
1168
1168
  "instagram",
1169
1169
  "linkedin",
1170
1170
  "tiktok",
1171
+ "whatsapp",
1171
1172
  "x",
1172
1173
  "youtube"
1173
1174
  ];
1175
+ /** How each platform is named wherever people see it (settings, composer, footer link labels). */
1176
+ const knownSocialPlatformLabels = {
1177
+ facebook: "Facebook",
1178
+ instagram: "Instagram",
1179
+ linkedin: "LinkedIn",
1180
+ tiktok: "TikTok",
1181
+ whatsapp: "WhatsApp",
1182
+ x: "X",
1183
+ youtube: "YouTube"
1184
+ };
1174
1185
  function isRecord$29(value) {
1175
1186
  return typeof value === "object" && value !== null && !Array.isArray(value);
1176
1187
  }
@@ -74945,7 +74956,7 @@ function SingleSelectField({ path, backend, config }) {
74945
74956
  })
74946
74957
  });
74947
74958
  }
74948
- function SelectField({ path, backend, config }) {
74959
+ function SelectField$1({ path, backend, config }) {
74949
74960
  if (!config.options || config.options.length === 0) {
74950
74961
  console.warn(`SelectField at path "${path}" has no options defined`);
74951
74962
  return null;
@@ -89598,6 +89609,7 @@ const publicEventLoaderQuerySchemaShape = {
89598
89609
  seriesSlug: z.string().optional(),
89599
89610
  includeOccurrenceId: z.string().optional(),
89600
89611
  readIntent: z.string().optional(),
89612
+ detailAdmission: z.string().optional(),
89601
89613
  detailLevel: z.string().optional(),
89602
89614
  readProfile: z.string().optional()
89603
89615
  };
@@ -89764,11 +89776,11 @@ const publicEventBookingAvailabilitySchema = z.discriminatedUnion("kind", [z.obj
89764
89776
  "series_archived",
89765
89777
  "parent_archived",
89766
89778
  "parent_inconsistent",
89767
- "not_public",
89768
89779
  "already_started",
89769
89780
  "enrollment_closed"
89770
89781
  ])
89771
89782
  })]);
89783
+ const publicEventBookingClosedDetailSchema = z.discriminatedUnion("kind", [z.object({ kind: z.literal("opensSoon") }), z.object({ kind: z.literal("paused") })]);
89772
89784
  const publicRunSessionSchema = z.object({
89773
89785
  occurrenceId: z.string(),
89774
89786
  startsAt: z.string(),
@@ -89813,6 +89825,7 @@ const publicEventBaseSchema = z.object({
89813
89825
  destination: publicEventDestinationSchema,
89814
89826
  requiresRegistration: z.boolean(),
89815
89827
  bookingAvailability: publicEventBookingAvailabilitySchema,
89828
+ bookingClosedDetail: publicEventBookingClosedDetailSchema.optional(),
89816
89829
  deliveryMode: z.enum([
89817
89830
  "in_person",
89818
89831
  "online",
@@ -94227,6 +94240,7 @@ const SOCIAL_ICON_NAMES = [
94227
94240
  "SocialInstagram",
94228
94241
  "SocialLinkedIn",
94229
94242
  "SocialTikTok",
94243
+ "SocialWhatsApp",
94230
94244
  "SocialX",
94231
94245
  "SocialYouTube"
94232
94246
  ];
@@ -94263,6 +94277,7 @@ const socialIcons = {
94263
94277
  /* @__PURE__ */ jsx("path", { d: "M10.5 9v10" })
94264
94278
  ] })),
94265
94279
  SocialTikTok: createIcon("SocialTikTokIcon", /* @__PURE__ */ jsxs(Fragment$1, { 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" })] })),
94280
+ SocialWhatsApp: createIcon("SocialWhatsAppIcon", /* @__PURE__ */ jsxs(Fragment$1, { 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" })] })),
94266
94281
  SocialX: createIcon("SocialXIcon", /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("path", { d: "m5 4 14 16" }), /* @__PURE__ */ jsx("path", { d: "M19 4 5 20" })] })),
94267
94282
  SocialYouTube: createIcon("SocialYouTubeIcon", /* @__PURE__ */ jsxs(Fragment$1, { 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" })] }))
94268
94283
  };
@@ -98081,7 +98096,6 @@ function closedEventBookingLabel(reason) {
98081
98096
  case "series_archived":
98082
98097
  case "parent_archived":
98083
98098
  case "parent_inconsistent":
98084
- case "not_public":
98085
98099
  case "already_started":
98086
98100
  case "enrollment_closed": return "Registration closed";
98087
98101
  default: return assertNever$10(reason);
@@ -122575,6 +122589,12 @@ function withOptionalPhone(fields, includePhone) {
122575
122589
  }
122576
122590
  //#endregion
122577
122591
  //#region ../blocks/src/system/runtime/nodes/newsletter-form.interactive.ts
122592
+ const NEWSLETTER_SIGNUPS_PAUSED_MESSAGE = "We can’t accept signups right now. Please try again later.";
122593
+ function newsletterBlockSubmissionMessage(target) {
122594
+ if (target.tag === "block-source") return target.sourceRef ? null : NEWSLETTER_SIGNUPS_PAUSED_MESSAGE;
122595
+ if (target.tag !== "unpublished-preview") return null;
122596
+ 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.";
122597
+ }
122578
122598
  const newsletterButtonVariantSchema = blockButtonRoleSchema;
122579
122599
  const mailingListContextSchema = z.unknown().transform((value, ctx) => {
122580
122600
  const parsed = parseMailingListRuntimeContext(value);
@@ -122615,6 +122635,11 @@ const mailingListContentVersionIdSchema = z.string().transform((value, ctx) => {
122615
122635
  });
122616
122636
  return z.NEVER;
122617
122637
  });
122638
+ const mailingListSignupBlockSourceRefSchema = z.object({
122639
+ tag: z.literal("block_ref"),
122640
+ blockId: mailingListSignupBlockIdSchema,
122641
+ contentVersionId: mailingListContentVersionIdSchema
122642
+ });
122618
122643
  const signedMailingListSourceTokenSchema = z.string().trim().min(1).transform(parseRequiredMailingListSignedSourceToken);
122619
122644
  const newsletterSourceCommonSchema = z.object({
122620
122645
  siteId: z.string().optional(),
@@ -122629,7 +122654,15 @@ const newsletterSourceSchema = z.discriminatedUnion("source", [
122629
122654
  newsletterSourceCommonSchema.extend({
122630
122655
  source: z.literal("block"),
122631
122656
  blockId: z.string().nullable().optional(),
122632
- contentVersionId: z.string().nullable().optional()
122657
+ newsletterBlockSubmission: z.discriminatedUnion("tag", [
122658
+ z.object({
122659
+ tag: z.literal("ready"),
122660
+ sourceRef: mailingListSignupBlockSourceRefSchema
122661
+ }),
122662
+ z.object({ tag: z.literal("unpublished-form") }),
122663
+ z.object({ tag: z.literal("unpublished-settings") }),
122664
+ z.object({ tag: z.literal("unavailable") })
122665
+ ])
122633
122666
  }),
122634
122667
  newsletterSourceCommonSchema.extend({
122635
122668
  source: z.literal("signed-footer"),
@@ -122658,11 +122691,7 @@ const newsletterHydrationSchema = z.object({
122658
122691
  target: z.discriminatedUnion("tag", [
122659
122692
  z.object({
122660
122693
  tag: z.literal("block-source"),
122661
- sourceRef: z.object({
122662
- tag: z.literal("block_ref"),
122663
- blockId: mailingListSignupBlockIdSchema,
122664
- contentVersionId: mailingListContentVersionIdSchema
122665
- }).nullable()
122694
+ sourceRef: mailingListSignupBlockSourceRefSchema.nullable()
122666
122695
  }),
122667
122696
  z.object({
122668
122697
  tag: z.literal("signed-footer-source"),
@@ -122671,7 +122700,11 @@ const newsletterHydrationSchema = z.object({
122671
122700
  token: signedMailingListSourceTokenSchema
122672
122701
  })
122673
122702
  }),
122674
- z.object({ tag: z.literal("preview") })
122703
+ z.object({ tag: z.literal("preview") }),
122704
+ z.object({
122705
+ tag: z.literal("unpublished-preview"),
122706
+ reason: z.enum(["unpublished-form", "unpublished-settings"])
122707
+ })
122675
122708
  ]),
122676
122709
  setupRevision: z.number().int().positive().nullable(),
122677
122710
  choiceProvider: z.enum([
@@ -122740,16 +122773,21 @@ const newsletterFormBlockRuntime = defineProgressiveBlockRuntime({
122740
122773
  });
122741
122774
  function projectNewsletterFormHydrationTarget(source) {
122742
122775
  switch (source.source) {
122743
- case "block": {
122744
- const sourceRef = buildMailingListSignupBlockSourceRef(source.blockId, source.contentVersionId);
122745
- if (sourceRef?.tag === "block_ref") return {
122776
+ case "block": switch (source.newsletterBlockSubmission.tag) {
122777
+ case "unpublished-form":
122778
+ case "unpublished-settings": return {
122779
+ tag: "unpublished-preview",
122780
+ reason: source.newsletterBlockSubmission.tag
122781
+ };
122782
+ case "ready": return {
122746
122783
  tag: "block-source",
122747
- sourceRef
122784
+ sourceRef: source.newsletterBlockSubmission.sourceRef
122748
122785
  };
122749
- return {
122786
+ case "unavailable": return {
122750
122787
  tag: "block-source",
122751
122788
  sourceRef: null
122752
122789
  };
122790
+ default: return assertNever$10(source.newsletterBlockSubmission);
122753
122791
  }
122754
122792
  case "signed-footer": return {
122755
122793
  tag: "signed-footer-source",
@@ -122818,6 +122856,7 @@ function buildNewsletterFormInteractiveIslandProps(props) {
122818
122856
  const decoded = newsletterFormBlockRuntime.contracts.source.decode(props);
122819
122857
  const source = isDecodeSuccess(decoded) ? decoded.value : {
122820
122858
  ...props,
122859
+ ...props.source === "block" ? { newsletterBlockSubmission: { tag: "unavailable" } } : {},
122821
122860
  mailingList: void 0,
122822
122861
  targeting: { mode: "default" }
122823
122862
  };
@@ -125230,6 +125269,156 @@ function FeedbackMessage({ tone, treatment = "panel", children, className, id, t
125230
125269
  });
125231
125270
  }
125232
125271
  //#endregion
125272
+ //#region ../blocks/src/system/runtime/shared/components/CheckboxChoice.tsx
125273
+ /**
125274
+ * The customer-facing checkbox every block renders. Styling comes from the
125275
+ * theme's input CSS (`.form-check`, `.form-checkbox`), so it follows each
125276
+ * site's input colours, borders and corners.
125277
+ */
125278
+ function CheckboxChoice({ label, presentation = "row", className, ...inputProps }) {
125279
+ return /* @__PURE__ */ jsxs("label", {
125280
+ className: clsx("form-check", presentation === "tile" && "form-check--tile", className),
125281
+ children: [/* @__PURE__ */ jsx("input", {
125282
+ ...inputProps,
125283
+ type: "checkbox",
125284
+ className: "form-checkbox"
125285
+ }), /* @__PURE__ */ jsx("span", {
125286
+ className: "form-check-label",
125287
+ children: label
125288
+ })]
125289
+ });
125290
+ }
125291
+ //#endregion
125292
+ //#region ../blocks/src/system/runtime/nodes/form.fields.tsx
125293
+ function fieldBasics(field) {
125294
+ return {
125295
+ inputId: `f_${field.id}`,
125296
+ label: String(field.label ?? field.id),
125297
+ required: Boolean(field.required)
125298
+ };
125299
+ }
125300
+ function textInputType(type) {
125301
+ return type === "email" || type === "url" || type === "tel" || type === "number" ? type : "text";
125302
+ }
125303
+ function textInputConstraints(field, inputType) {
125304
+ if (inputType === "number") return {
125305
+ ...typeof field.min === "number" ? { min: field.min } : {},
125306
+ ...typeof field.max === "number" ? { max: field.max } : {}
125307
+ };
125308
+ return {
125309
+ ...typeof field.minLength === "number" ? { minLength: field.minLength } : {},
125310
+ ...typeof field.maxLength === "number" ? { maxLength: field.maxLength } : {},
125311
+ ...typeof field.pattern === "string" && field.pattern ? { pattern: field.pattern } : {}
125312
+ };
125313
+ }
125314
+ function LabelledField({ basics, children }) {
125315
+ return /* @__PURE__ */ jsxs("div", {
125316
+ className: "fb-field",
125317
+ children: [/* @__PURE__ */ jsx("label", {
125318
+ htmlFor: basics.inputId,
125319
+ className: "form-label",
125320
+ children: basics.label
125321
+ }), children]
125322
+ });
125323
+ }
125324
+ function TextareaField({ field }) {
125325
+ const basics = fieldBasics(field);
125326
+ return /* @__PURE__ */ jsx(LabelledField, {
125327
+ basics,
125328
+ children: /* @__PURE__ */ jsx("textarea", {
125329
+ id: basics.inputId,
125330
+ name: field.id,
125331
+ required: basics.required,
125332
+ placeholder: field.placeholder,
125333
+ rows: field.rows,
125334
+ className: "form-textarea"
125335
+ })
125336
+ });
125337
+ }
125338
+ function SelectField({ field }) {
125339
+ const basics = fieldBasics(field);
125340
+ const options = field.options ?? [];
125341
+ const multiple = Boolean(field.multiple);
125342
+ return /* @__PURE__ */ jsx(LabelledField, {
125343
+ basics,
125344
+ children: /* @__PURE__ */ jsxs("select", {
125345
+ id: basics.inputId,
125346
+ name: field.id,
125347
+ multiple,
125348
+ required: basics.required,
125349
+ className: "form-select",
125350
+ children: [!multiple && /* @__PURE__ */ jsx("option", {
125351
+ value: "",
125352
+ children: "Select…"
125353
+ }), options.map((opt) => /* @__PURE__ */ jsx("option", {
125354
+ value: opt.value,
125355
+ children: opt.label
125356
+ }, opt.value))]
125357
+ })
125358
+ });
125359
+ }
125360
+ function RadioField({ field }) {
125361
+ const basics = fieldBasics(field);
125362
+ const options = field.options ?? [];
125363
+ return /* @__PURE__ */ jsxs("fieldset", {
125364
+ className: "fb-fieldset",
125365
+ children: [/* @__PURE__ */ jsx("legend", {
125366
+ className: "form-label",
125367
+ children: basics.label
125368
+ }), options.map((opt) => /* @__PURE__ */ jsxs("label", {
125369
+ className: "form-check",
125370
+ children: [/* @__PURE__ */ jsx("input", {
125371
+ type: "radio",
125372
+ name: field.id,
125373
+ value: opt.value,
125374
+ required: basics.required,
125375
+ className: "form-radio"
125376
+ }), /* @__PURE__ */ jsx("span", {
125377
+ className: "form-check-label",
125378
+ children: opt.label
125379
+ })]
125380
+ }, opt.value))]
125381
+ });
125382
+ }
125383
+ function TextInputField({ field, type }) {
125384
+ const basics = fieldBasics(field);
125385
+ const inputType = textInputType(type);
125386
+ return /* @__PURE__ */ jsx(LabelledField, {
125387
+ basics,
125388
+ children: /* @__PURE__ */ jsx("input", {
125389
+ id: basics.inputId,
125390
+ name: field.id,
125391
+ type: inputType,
125392
+ required: basics.required,
125393
+ placeholder: field.placeholder,
125394
+ ...textInputConstraints(field, inputType),
125395
+ className: "form-input"
125396
+ })
125397
+ });
125398
+ }
125399
+ function FormFieldControl({ field }) {
125400
+ const type = String(field.type ?? "text");
125401
+ switch (type) {
125402
+ case "textarea": return /* @__PURE__ */ jsx(TextareaField, { field });
125403
+ case "select": return /* @__PURE__ */ jsx(SelectField, { field });
125404
+ case "radio": return /* @__PURE__ */ jsx(RadioField, { field });
125405
+ case "checkbox":
125406
+ case "consent": {
125407
+ const basics = fieldBasics(field);
125408
+ return /* @__PURE__ */ jsx(CheckboxChoice, {
125409
+ name: field.id,
125410
+ required: basics.required,
125411
+ label: basics.label,
125412
+ presentation: type === "consent" ? "tile" : "row"
125413
+ });
125414
+ }
125415
+ default: return /* @__PURE__ */ jsx(TextInputField, {
125416
+ field,
125417
+ type
125418
+ });
125419
+ }
125420
+ }
125421
+ //#endregion
125233
125422
  //#region ../blocks/src/system/runtime/nodes/form.server.tsx
125234
125423
  const FormNodeSSR = ({ blockId, value, submitLabel, successMessage, className, onSubmit, action = "/api/forms/submit", siteId, apiBaseUrl, spamProtectionEnabled }) => {
125235
125424
  const islandProps = buildFormInteractiveIslandProps({
@@ -125253,107 +125442,7 @@ const FormNodeSSR = ({ blockId, value, submitLabel, successMessage, className, o
125253
125442
  })]
125254
125443
  });
125255
125444
  const groups = display.groups;
125256
- const renderField = (field) => {
125257
- const inputId = `f_${field.id}`;
125258
- const label = String(field.label ?? field.id);
125259
- const required = Boolean(field.required);
125260
- const type = String(field.type ?? "text");
125261
- if (type === "textarea") return /* @__PURE__ */ jsxs("div", {
125262
- className: "fb-field",
125263
- children: [/* @__PURE__ */ jsx("label", {
125264
- htmlFor: inputId,
125265
- className: "form-label",
125266
- children: label
125267
- }), /* @__PURE__ */ jsx("textarea", {
125268
- id: inputId,
125269
- name: field.id,
125270
- required,
125271
- placeholder: field.placeholder,
125272
- rows: field.rows,
125273
- className: "form-textarea"
125274
- })]
125275
- }, field.id);
125276
- if (type === "select") {
125277
- const options = field.options ?? [];
125278
- const multiple = Boolean(field.multiple);
125279
- return /* @__PURE__ */ jsxs("div", {
125280
- className: "fb-field",
125281
- children: [/* @__PURE__ */ jsx("label", {
125282
- htmlFor: inputId,
125283
- className: "form-label",
125284
- children: label
125285
- }), /* @__PURE__ */ jsxs("select", {
125286
- id: inputId,
125287
- name: field.id,
125288
- multiple,
125289
- required,
125290
- className: "form-select",
125291
- children: [!multiple && /* @__PURE__ */ jsx("option", {
125292
- value: "",
125293
- children: "Select…"
125294
- }), options.map((opt) => /* @__PURE__ */ jsx("option", {
125295
- value: opt.value,
125296
- children: opt.label
125297
- }, opt.value))]
125298
- })]
125299
- }, field.id);
125300
- }
125301
- if (type === "radio") {
125302
- const options = field.options ?? [];
125303
- return /* @__PURE__ */ jsxs("fieldset", {
125304
- className: "fb-fieldset",
125305
- children: [/* @__PURE__ */ jsx("legend", {
125306
- className: "form-label",
125307
- children: label
125308
- }), options.map((opt) => /* @__PURE__ */ jsxs("label", {
125309
- className: "fb-inline form-label",
125310
- children: [/* @__PURE__ */ jsx("input", {
125311
- type: "radio",
125312
- name: field.id,
125313
- value: opt.value,
125314
- required,
125315
- className: "form-radio"
125316
- }), /* @__PURE__ */ jsx("span", { children: opt.label })]
125317
- }, opt.value))]
125318
- }, field.id);
125319
- }
125320
- if (type === "checkbox" || type === "consent") return /* @__PURE__ */ jsxs("label", {
125321
- className: "fb-inline form-label",
125322
- children: [/* @__PURE__ */ jsx("input", {
125323
- type: "checkbox",
125324
- name: field.id,
125325
- required,
125326
- className: "form-checkbox"
125327
- }), /* @__PURE__ */ jsx("span", { children: label })]
125328
- }, field.id);
125329
- const inputType = type === "email" || type === "url" || type === "tel" || type === "number" ? type : "text";
125330
- const extra = {};
125331
- if (inputType === "text" || inputType === "email" || inputType === "url" || inputType === "tel") {
125332
- if (typeof field.minLength === "number") extra.minLength = field.minLength;
125333
- if (typeof field.maxLength === "number") extra.maxLength = field.maxLength;
125334
- if (typeof field.pattern === "string" && field.pattern) extra.pattern = field.pattern;
125335
- }
125336
- if (inputType === "number") {
125337
- if (typeof field.min === "number") extra.min = field.min;
125338
- if (typeof field.max === "number") extra.max = field.max;
125339
- }
125340
- return /* @__PURE__ */ jsxs("div", {
125341
- className: "fb-field",
125342
- children: [/* @__PURE__ */ jsx("label", {
125343
- htmlFor: inputId,
125344
- className: "form-label",
125345
- children: label
125346
- }), /* @__PURE__ */ jsx("input", {
125347
- id: inputId,
125348
- name: field.id,
125349
- type: inputType,
125350
- required,
125351
- placeholder: field.placeholder,
125352
- ...extra,
125353
- className: "form-input"
125354
- })]
125355
- }, field.id);
125356
- };
125445
+ const renderField = (field) => /* @__PURE__ */ jsx(FormFieldControl, { field }, field.id);
125357
125446
  return /* @__PURE__ */ jsxs("div", {
125358
125447
  ...getIslandRootProps("form", blockId),
125359
125448
  children: [/* @__PURE__ */ jsx(IslandPropsScript, { value: islandProps }), /* @__PURE__ */ jsxs("form", {
@@ -125399,6 +125488,172 @@ const FormNodeSSR = ({ blockId, value, submitLabel, successMessage, className, o
125399
125488
  });
125400
125489
  };
125401
125490
  //#endregion
125491
+ //#region ../blocks/src/system/runtime/shared/components/FieldValidationMessage.tsx
125492
+ function getFieldValidationControlProps({ message, messageId, describedBy }) {
125493
+ const hasMessage = Boolean(message);
125494
+ const ariaDescribedBy = [describedBy, hasMessage ? messageId : void 0].filter((part) => typeof part === "string" && part.length > 0).join(" ");
125495
+ return {
125496
+ "aria-invalid": hasMessage ? "true" : void 0,
125497
+ "aria-describedby": ariaDescribedBy || void 0
125498
+ };
125499
+ }
125500
+ function FieldValidationMessage({ id, children, className, live = "assertive" }) {
125501
+ return /* @__PURE__ */ jsx("p", {
125502
+ id,
125503
+ className,
125504
+ "data-field-validation-message": true,
125505
+ "data-field-validation-tone": "error",
125506
+ role: "alert",
125507
+ "aria-live": live === "off" ? void 0 : live,
125508
+ children
125509
+ });
125510
+ }
125511
+ //#endregion
125512
+ //#region ../blocks/src/system/runtime/nodes/newsletter-form.parts.tsx
125513
+ /**
125514
+ * Newsletter form pieces shared by the SSR render and the hydrated island, so
125515
+ * both produce the same markup.
125516
+ *
125517
+ * Labels are visually hidden: every field has a placeholder, and a visible
125518
+ * "Email *" label over a single field reads like a generic form. Screen
125519
+ * readers still get the label.
125520
+ */
125521
+ const TOPIC_CHOICE_FIELD_ID = "mailingListChoice";
125522
+ const inputIdFor = (field) => `newsletter_${field.id}`;
125523
+ /** Splits the preset's fields into the email (joined with the button) and the rest. */
125524
+ function partitionNewsletterFields(fields) {
125525
+ const email = fields.find((field) => field.type === "email") ?? null;
125526
+ return {
125527
+ email,
125528
+ extra: fields.filter((field) => field !== email)
125529
+ };
125530
+ }
125531
+ function NewsletterExtraField({ field, disabled, error }) {
125532
+ const inputId = inputIdFor(field);
125533
+ const errorId = `${inputId}-error`;
125534
+ return /* @__PURE__ */ jsxs("div", {
125535
+ className: "fb-field newsletter-field",
125536
+ children: [
125537
+ /* @__PURE__ */ jsx("label", {
125538
+ htmlFor: inputId,
125539
+ className: "rb-sr-only",
125540
+ children: field.label
125541
+ }),
125542
+ /* @__PURE__ */ jsx("input", {
125543
+ id: inputId,
125544
+ name: field.id,
125545
+ type: field.type,
125546
+ required: field.required,
125547
+ placeholder: field.placeholder ?? field.label,
125548
+ className: "form-input",
125549
+ disabled,
125550
+ ...getFieldValidationControlProps({
125551
+ message: error,
125552
+ messageId: errorId
125553
+ })
125554
+ }),
125555
+ error ? /* @__PURE__ */ jsx(FieldValidationMessage, {
125556
+ id: errorId,
125557
+ className: "fb-error",
125558
+ children: error
125559
+ }) : null
125560
+ ]
125561
+ });
125562
+ }
125563
+ /** The email field and submit button sharing one input-styled shell. */
125564
+ function NewsletterEmailEntry({ field, buttonVariant, buttonLabel, disabled, error }) {
125565
+ const inputId = inputIdFor(field);
125566
+ const errorId = `${inputId}-error`;
125567
+ return /* @__PURE__ */ jsxs("div", {
125568
+ className: "newsletter-entry",
125569
+ children: [/* @__PURE__ */ jsxs("div", {
125570
+ className: "form-input-group newsletter-entry-group",
125571
+ children: [
125572
+ /* @__PURE__ */ jsx("label", {
125573
+ htmlFor: inputId,
125574
+ className: "rb-sr-only",
125575
+ children: field.label
125576
+ }),
125577
+ /* @__PURE__ */ jsx("input", {
125578
+ id: inputId,
125579
+ name: field.id,
125580
+ type: "email",
125581
+ required: field.required,
125582
+ placeholder: field.placeholder ?? field.label,
125583
+ className: "form-input-group-field",
125584
+ autoComplete: "email",
125585
+ disabled,
125586
+ ...getFieldValidationControlProps({
125587
+ message: error,
125588
+ messageId: errorId
125589
+ })
125590
+ }),
125591
+ /* @__PURE__ */ jsx(ThemedButton, {
125592
+ type: "submit",
125593
+ variant: buttonVariant,
125594
+ size: "md",
125595
+ disabled,
125596
+ label: buttonLabel
125597
+ })
125598
+ ]
125599
+ }), error ? /* @__PURE__ */ jsx(FieldValidationMessage, {
125600
+ id: errorId,
125601
+ className: "fb-error",
125602
+ children: error
125603
+ }) : null]
125604
+ });
125605
+ }
125606
+ /**
125607
+ * The submit action: joined to the email field when the preset has one
125608
+ * (every current preset does), otherwise a plain themed button.
125609
+ */
125610
+ function NewsletterSubmitRow({ emailField, buttonVariant, buttonLabel, disabled, error }) {
125611
+ if (emailField) return /* @__PURE__ */ jsx(NewsletterEmailEntry, {
125612
+ field: emailField,
125613
+ buttonVariant,
125614
+ buttonLabel,
125615
+ disabled,
125616
+ error
125617
+ });
125618
+ return /* @__PURE__ */ jsx("div", {
125619
+ className: "newsletter-submit",
125620
+ children: /* @__PURE__ */ jsx(ThemedButton, {
125621
+ type: "submit",
125622
+ variant: buttonVariant,
125623
+ size: "md",
125624
+ disabled,
125625
+ label: buttonLabel
125626
+ })
125627
+ });
125628
+ }
125629
+ /** Visitor-chosen topics as toggle chips. Real checkboxes underneath. */
125630
+ function NewsletterTopicChips({ choices, disabled, error }) {
125631
+ const errorId = `newsletter_${TOPIC_CHOICE_FIELD_ID}-error`;
125632
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs("fieldset", {
125633
+ className: "newsletter-topics",
125634
+ "aria-describedby": error ? errorId : void 0,
125635
+ children: [/* @__PURE__ */ jsx("legend", {
125636
+ className: "newsletter-topics-legend",
125637
+ children: "What would you like to hear about?"
125638
+ }), /* @__PURE__ */ jsx("div", {
125639
+ className: "newsletter-topic-chips",
125640
+ children: choices.map((choice) => /* @__PURE__ */ jsxs("label", {
125641
+ className: "newsletter-topic-chip",
125642
+ children: [/* @__PURE__ */ jsx("input", {
125643
+ type: "checkbox",
125644
+ name: TOPIC_CHOICE_FIELD_ID,
125645
+ value: choice.id,
125646
+ disabled
125647
+ }), /* @__PURE__ */ jsx("span", { children: choice.label })]
125648
+ }, choice.id))
125649
+ })]
125650
+ }), error ? /* @__PURE__ */ jsx(FieldValidationMessage, {
125651
+ id: errorId,
125652
+ className: "fb-error",
125653
+ children: error
125654
+ }) : null] });
125655
+ }
125656
+ //#endregion
125402
125657
  //#region ../blocks/src/system/runtime/nodes/newsletter-form.server.tsx
125403
125658
  /**
125404
125659
  * Newsletter Form Server Component
@@ -125419,36 +125674,15 @@ function NewsletterFormSSR(props) {
125419
125674
  });
125420
125675
  const display = islandProps.render.display;
125421
125676
  const fields = display.fields;
125677
+ const submissionMessage = newsletterBlockSubmissionMessage(islandProps.render.hydration.target);
125422
125678
  if (display.availability === "unavailable") return /* @__PURE__ */ jsx("div", {
125423
125679
  className: clsx("newsletter-form-ssr", className),
125424
125680
  children: /* @__PURE__ */ jsx("p", {
125425
125681
  role: "status",
125426
- children: "We can’t accept signups right now. Please try again later."
125682
+ children: NEWSLETTER_SIGNUPS_PAUSED_MESSAGE
125427
125683
  })
125428
125684
  });
125429
- const renderField = (field) => {
125430
- const inputId = `newsletter_${field.id}`;
125431
- return /* @__PURE__ */ jsxs("div", {
125432
- className: "fb-field newsletter-field",
125433
- children: [/* @__PURE__ */ jsxs("label", {
125434
- htmlFor: inputId,
125435
- className: "form-label",
125436
- children: [field.label, field.required && /* @__PURE__ */ jsx("span", {
125437
- className: "newsletter-required",
125438
- "aria-hidden": "true",
125439
- children: "*"
125440
- })]
125441
- }), /* @__PURE__ */ jsx("input", {
125442
- id: inputId,
125443
- name: field.id,
125444
- type: field.type,
125445
- required: field.required,
125446
- placeholder: field.placeholder,
125447
- className: "form-input",
125448
- autoComplete: field.type === "email" ? "email" : void 0
125449
- })]
125450
- }, field.id);
125451
- };
125685
+ const { email: emailField, extra: extraFields } = partitionNewsletterFields(fields);
125452
125686
  return /* @__PURE__ */ jsxs("div", {
125453
125687
  ...getIslandRootProps("newsletter-form", blockId),
125454
125688
  className: clsx("newsletter-form-ssr", className),
@@ -125467,30 +125701,20 @@ function NewsletterFormSSR(props) {
125467
125701
  /* @__PURE__ */ jsxs("div", {
125468
125702
  className: "newsletter-form-fields",
125469
125703
  children: [
125470
- fields.map(renderField),
125471
- islandProps.render.hydration.choicePresentation === "visitor_choice" ? /* @__PURE__ */ jsxs("fieldset", {
125472
- className: "fb-fieldset newsletter-topics",
125473
- children: [/* @__PURE__ */ jsx("legend", {
125474
- className: "form-label",
125475
- children: "What would you like to hear about?"
125476
- }), display.choices.map((choice) => /* @__PURE__ */ jsxs("label", {
125477
- className: "fb-inline form-label newsletter-topic-choice",
125478
- children: [/* @__PURE__ */ jsx("input", {
125479
- type: "checkbox",
125480
- name: "mailingListChoice",
125481
- value: choice.id,
125482
- className: "form-checkbox"
125483
- }), /* @__PURE__ */ jsx("span", { children: choice.label })]
125484
- }, choice.id))]
125704
+ islandProps.render.hydration.choicePresentation === "visitor_choice" ? /* @__PURE__ */ jsx(NewsletterTopicChips, { choices: display.choices }) : null,
125705
+ extraFields.length > 0 ? /* @__PURE__ */ jsx("div", {
125706
+ className: "newsletter-extra-fields",
125707
+ children: extraFields.map((field) => /* @__PURE__ */ jsx(NewsletterExtraField, { field }, field.id))
125485
125708
  }) : null,
125486
- /* @__PURE__ */ jsx("div", {
125487
- className: "newsletter-submit",
125488
- children: /* @__PURE__ */ jsx(ThemedButton, {
125489
- type: "submit",
125490
- variant: display.buttonVariant,
125491
- size: "md",
125492
- label: display.buttonLabel
125493
- })
125709
+ /* @__PURE__ */ jsx(NewsletterSubmitRow, {
125710
+ emailField,
125711
+ buttonVariant: display.buttonVariant,
125712
+ buttonLabel: display.buttonLabel,
125713
+ disabled: submissionMessage !== null
125714
+ }),
125715
+ submissionMessage && /* @__PURE__ */ jsx("p", {
125716
+ role: "status",
125717
+ children: submissionMessage
125494
125718
  })
125495
125719
  ]
125496
125720
  }),
@@ -128881,27 +129105,6 @@ function DiscountCodeDisclosure({ surface, isOpen, code, onOpen, onChange, onRem
128881
129105
  });
128882
129106
  }
128883
129107
  //#endregion
128884
- //#region ../blocks/src/system/runtime/shared/components/FieldValidationMessage.tsx
128885
- function getFieldValidationControlProps({ message, messageId, describedBy }) {
128886
- const hasMessage = Boolean(message);
128887
- const ariaDescribedBy = [describedBy, hasMessage ? messageId : void 0].filter((part) => typeof part === "string" && part.length > 0).join(" ");
128888
- return {
128889
- "aria-invalid": hasMessage ? "true" : void 0,
128890
- "aria-describedby": ariaDescribedBy || void 0
128891
- };
128892
- }
128893
- function FieldValidationMessage({ id, children, className, live = "assertive" }) {
128894
- return /* @__PURE__ */ jsx("p", {
128895
- id,
128896
- className,
128897
- "data-field-validation-message": true,
128898
- "data-field-validation-tone": "error",
128899
- role: "alert",
128900
- "aria-live": live === "off" ? void 0 : live,
128901
- children
128902
- });
128903
- }
128904
- //#endregion
128905
129108
  //#region ../blocks/src/system/runtime/shared/components/BookingConsentAgreement.tsx
128906
129109
  function BookingConsentAgreement({ agreement, showTitle = true, title, titleId }) {
128907
129110
  return /* @__PURE__ */ jsxs(Fragment$1, { children: [showTitle ? /* @__PURE__ */ jsxs("div", {
@@ -129508,7 +129711,7 @@ function DefaultFieldInput({ describedBy, error, errorId, field, onBlur, onChang
129508
129711
  case "radio": return /* @__PURE__ */ jsx("div", {
129509
129712
  className: "rb-space-y-2",
129510
129713
  children: field.field.options?.map((option) => /* @__PURE__ */ jsxs("label", {
129511
- className: "rb-flex rb-items-center rb-gap-2 rb-cursor-pointer",
129714
+ className: "form-check",
129512
129715
  children: [/* @__PURE__ */ jsx("input", {
129513
129716
  type: "radio",
129514
129717
  name: field.id,
@@ -129520,7 +129723,7 @@ function DefaultFieldInput({ describedBy, error, errorId, field, onBlur, onChang
129520
129723
  ...validationProps,
129521
129724
  className: "form-radio"
129522
129725
  }), /* @__PURE__ */ jsx("span", {
129523
- className: "rb-caption",
129726
+ className: "form-check-label",
129524
129727
  children: option.label
129525
129728
  })]
129526
129729
  }, option.value))
@@ -129530,47 +129733,20 @@ function DefaultFieldInput({ describedBy, error, errorId, field, onBlur, onChang
129530
129733
  const checkedValues = toStringArray(value);
129531
129734
  return /* @__PURE__ */ jsx("div", {
129532
129735
  className: "rb-space-y-2",
129533
- children: field.field.options.map((option) => /* @__PURE__ */ jsxs("label", {
129534
- className: "rb-flex rb-items-center rb-gap-2 rb-cursor-pointer",
129535
- children: [/* @__PURE__ */ jsx("input", {
129536
- type: "checkbox",
129537
- name: field.id,
129538
- value: option.value,
129539
- checked: checkedValues.includes(option.value),
129540
- onChange: (event) => {
129541
- onChange(event.target.checked ? [...checkedValues, option.value] : checkedValues.filter((item) => item !== option.value));
129542
- },
129543
- onBlur,
129544
- ...validationProps,
129545
- className: "form-checkbox"
129546
- }), /* @__PURE__ */ jsx("span", {
129547
- className: "rb-caption",
129548
- children: option.label
129549
- })]
129736
+ children: field.field.options.map((option) => /* @__PURE__ */ jsx(CheckboxChoice, {
129737
+ name: field.id,
129738
+ value: option.value,
129739
+ checked: checkedValues.includes(option.value),
129740
+ onChange: (event) => {
129741
+ onChange(event.target.checked ? [...checkedValues, option.value] : checkedValues.filter((item) => item !== option.value));
129742
+ },
129743
+ onBlur,
129744
+ ...validationProps,
129745
+ label: option.label
129550
129746
  }, option.value))
129551
129747
  });
129552
129748
  }
129553
- return /* @__PURE__ */ jsxs("label", {
129554
- className: "rb-flex rb-items-center rb-gap-2 rb-cursor-pointer",
129555
- children: [/* @__PURE__ */ jsx("input", {
129556
- type: "checkbox",
129557
- id: field.inputId,
129558
- name: field.id,
129559
- checked: Boolean(value),
129560
- onChange: (event) => onChange(event.target.checked),
129561
- onBlur,
129562
- required: field.required,
129563
- ...validationProps,
129564
- className: "form-checkbox"
129565
- }), /* @__PURE__ */ jsx("span", {
129566
- className: "rb-caption",
129567
- children: field.field.placeholder || field.label
129568
- })]
129569
- });
129570
- case "booking_requirement_consent": return /* @__PURE__ */ jsxs("label", {
129571
- className: "rb-flex rb-items-start rb-gap-2 rb-cursor-pointer",
129572
- children: [/* @__PURE__ */ jsx("input", {
129573
- type: "checkbox",
129749
+ return /* @__PURE__ */ jsx(CheckboxChoice, {
129574
129750
  id: field.inputId,
129575
129751
  name: field.id,
129576
129752
  checked: Boolean(value),
@@ -129578,11 +129754,18 @@ function DefaultFieldInput({ describedBy, error, errorId, field, onBlur, onChang
129578
129754
  onBlur,
129579
129755
  required: field.required,
129580
129756
  ...validationProps,
129581
- className: "form-checkbox rb-mt-0.5"
129582
- }), /* @__PURE__ */ jsx("span", {
129583
- className: "rb-caption",
129584
- children: field.field.checkboxLabel
129585
- })]
129757
+ label: field.field.placeholder || field.label
129758
+ });
129759
+ case "booking_requirement_consent": return /* @__PURE__ */ jsx(CheckboxChoice, {
129760
+ id: field.inputId,
129761
+ name: field.id,
129762
+ checked: Boolean(value),
129763
+ onChange: (event) => onChange(event.target.checked),
129764
+ onBlur,
129765
+ required: field.required,
129766
+ ...validationProps,
129767
+ label: field.field.checkboxLabel,
129768
+ presentation: "tile"
129586
129769
  });
129587
129770
  case "number": return /* @__PURE__ */ jsx("input", {
129588
129771
  ...commonProps,
@@ -134461,26 +134644,24 @@ function EventConsentField({ consent, error, formData, idBase, onChange }) {
134461
134644
  title: consent.title,
134462
134645
  titleId: `${idBase}-consent-title`
134463
134646
  }),
134464
- /* @__PURE__ */ jsxs("label", {
134465
- className: "er-label rb-flex rb-items-start rb-gap-2 rb-cursor-pointer",
134466
- children: [
134467
- /* @__PURE__ */ jsx("input", {
134468
- "aria-describedby": error ? errorId : void 0,
134469
- className: "form-checkbox rb-mt-0.5",
134470
- checked: formData.consentAccepted === true,
134471
- onChange: (event) => onChange({
134472
- ...formData,
134473
- consentAccepted: event.target.checked
134474
- }),
134475
- type: "checkbox"
134476
- }),
134647
+ /* @__PURE__ */ jsx(CheckboxChoice, {
134648
+ "aria-describedby": error ? errorId : void 0,
134649
+ "aria-invalid": error ? true : void 0,
134650
+ checked: formData.consentAccepted === true,
134651
+ onChange: (event) => onChange({
134652
+ ...formData,
134653
+ consentAccepted: event.target.checked
134654
+ }),
134655
+ label: /* @__PURE__ */ jsxs(Fragment$1, { children: [
134477
134656
  consent.checkboxLabel,
134478
134657
  " ",
134479
134658
  /* @__PURE__ */ jsx("span", {
134480
134659
  className: "er-required",
134481
134660
  children: "*"
134482
134661
  })
134483
- ]
134662
+ ] }),
134663
+ presentation: "tile",
134664
+ className: "er-consent-check"
134484
134665
  }),
134485
134666
  error ? /* @__PURE__ */ jsx(FieldValidationMessage, {
134486
134667
  id: errorId,
@@ -143695,107 +143876,7 @@ const FormNodeClient = ({ render }) => {
143695
143876
  children: "Missing or unknown form."
143696
143877
  });
143697
143878
  const groups = render.display.groups;
143698
- const renderField = (field) => {
143699
- const inputId = `f_${field.id}`;
143700
- const label = String(field.label ?? field.id);
143701
- const required = Boolean(field.required);
143702
- const type = String(field.type ?? "text");
143703
- if (type === "textarea") return /* @__PURE__ */ jsxs("div", {
143704
- className: "fb-field",
143705
- children: [/* @__PURE__ */ jsx("label", {
143706
- htmlFor: inputId,
143707
- className: "form-label",
143708
- children: label
143709
- }), /* @__PURE__ */ jsx("textarea", {
143710
- id: inputId,
143711
- name: field.id,
143712
- required,
143713
- placeholder: field.placeholder,
143714
- rows: field.rows,
143715
- className: "form-textarea"
143716
- })]
143717
- }, field.id);
143718
- if (type === "select") {
143719
- const options = field.options ?? [];
143720
- const multiple = Boolean(field.multiple);
143721
- return /* @__PURE__ */ jsxs("div", {
143722
- className: "fb-field",
143723
- children: [/* @__PURE__ */ jsx("label", {
143724
- htmlFor: inputId,
143725
- className: "form-label",
143726
- children: label
143727
- }), /* @__PURE__ */ jsxs("select", {
143728
- id: inputId,
143729
- name: field.id,
143730
- multiple,
143731
- required,
143732
- className: "form-select",
143733
- children: [!multiple && /* @__PURE__ */ jsx("option", {
143734
- value: "",
143735
- children: "Select…"
143736
- }), options.map((opt) => /* @__PURE__ */ jsx("option", {
143737
- value: opt.value,
143738
- children: opt.label
143739
- }, opt.value))]
143740
- })]
143741
- }, field.id);
143742
- }
143743
- if (type === "radio") {
143744
- const options = field.options ?? [];
143745
- return /* @__PURE__ */ jsxs("fieldset", {
143746
- className: "fb-fieldset",
143747
- children: [/* @__PURE__ */ jsx("legend", {
143748
- className: "form-label",
143749
- children: label
143750
- }), options.map((opt) => /* @__PURE__ */ jsxs("label", {
143751
- className: "fb-inline form-label",
143752
- children: [/* @__PURE__ */ jsx("input", {
143753
- type: "radio",
143754
- name: field.id,
143755
- value: opt.value,
143756
- required,
143757
- className: "form-radio"
143758
- }), /* @__PURE__ */ jsx("span", { children: opt.label })]
143759
- }, opt.value))]
143760
- }, field.id);
143761
- }
143762
- if (type === "checkbox" || type === "consent") return /* @__PURE__ */ jsxs("label", {
143763
- className: "fb-inline form-label",
143764
- children: [/* @__PURE__ */ jsx("input", {
143765
- type: "checkbox",
143766
- name: field.id,
143767
- required,
143768
- className: "form-checkbox"
143769
- }), /* @__PURE__ */ jsx("span", { children: label })]
143770
- }, field.id);
143771
- const inputType = type === "email" || type === "url" || type === "tel" || type === "number" ? type : "text";
143772
- const extra = {};
143773
- if (inputType === "text" || inputType === "email" || inputType === "url" || inputType === "tel") {
143774
- if (typeof field.minLength === "number") extra.minLength = field.minLength;
143775
- if (typeof field.maxLength === "number") extra.maxLength = field.maxLength;
143776
- if (typeof field.pattern === "string" && field.pattern) extra.pattern = field.pattern;
143777
- }
143778
- if (inputType === "number") {
143779
- if (typeof field.min === "number") extra.min = field.min;
143780
- if (typeof field.max === "number") extra.max = field.max;
143781
- }
143782
- return /* @__PURE__ */ jsxs("div", {
143783
- className: "fb-field",
143784
- children: [/* @__PURE__ */ jsx("label", {
143785
- htmlFor: inputId,
143786
- className: "form-label",
143787
- children: label
143788
- }), /* @__PURE__ */ jsx("input", {
143789
- id: inputId,
143790
- name: field.id,
143791
- type: inputType,
143792
- required,
143793
- placeholder: field.placeholder,
143794
- ...extra,
143795
- className: "form-input"
143796
- })]
143797
- }, field.id);
143798
- };
143879
+ const renderField = (field) => /* @__PURE__ */ jsx(FormFieldControl, { field }, field.id);
143799
143880
  const handleSubmit = async (e) => {
143800
143881
  e.preventDefault();
143801
143882
  const formData = new FormData(e.currentTarget);
@@ -144081,6 +144162,10 @@ function resolveNewsletterSubmitTarget(input) {
144081
144162
  tag: "unavailable",
144082
144163
  reason: "preview_only_source"
144083
144164
  };
144165
+ case "unpublished-preview": return {
144166
+ tag: "unavailable",
144167
+ reason: "preview_only_source"
144168
+ };
144084
144169
  default: return assertNever$10(input);
144085
144170
  }
144086
144171
  }
@@ -144100,6 +144185,7 @@ function readSubmittedText(value) {
144100
144185
  //#endregion
144101
144186
  //#region ../blocks/src/system/runtime/nodes/newsletter-form.client.tsx
144102
144187
  function NewsletterFormClient({ render }) {
144188
+ const submissionMessage = newsletterBlockSubmissionMessage(render.hydration.target);
144103
144189
  const api = useBlockApi();
144104
144190
  const [submissionState, dispatchSubmission] = useReducer(newsletterFormSubmissionReducer, initialNewsletterFormSubmissionState);
144105
144191
  const [altchaSolution, setAltchaSolution] = useState(null);
@@ -144109,7 +144195,6 @@ function NewsletterFormClient({ render }) {
144109
144195
  if (succeeded) successRef.current?.focus();
144110
144196
  }, [succeeded]);
144111
144197
  const showSpamProtection = render.hydration.spamProtectionEnabled ?? isSpamProtectionEnabled();
144112
- const fields = render.display.fields;
144113
144198
  const handleSubmit = async (e) => {
144114
144199
  e.preventDefault();
144115
144200
  const formData = new FormData(e.currentTarget);
@@ -144141,7 +144226,7 @@ function NewsletterFormClient({ render }) {
144141
144226
  reportNewsletterSignupRefusal(submitTarget.reason, { target: render.hydration.target });
144142
144227
  dispatchSubmission({
144143
144228
  type: "failed",
144144
- error: newsletterFormError(SIGNUPS_PAUSED_MESSAGE)
144229
+ error: newsletterFormError(NEWSLETTER_SIGNUPS_PAUSED_MESSAGE)
144145
144230
  });
144146
144231
  return;
144147
144232
  }
@@ -144149,7 +144234,7 @@ function NewsletterFormClient({ render }) {
144149
144234
  reportNewsletterSignupRefusal("setup_not_configured");
144150
144235
  dispatchSubmission({
144151
144236
  type: "failed",
144152
- error: newsletterFormError(SIGNUPS_PAUSED_MESSAGE)
144237
+ error: newsletterFormError(NEWSLETTER_SIGNUPS_PAUSED_MESSAGE)
144153
144238
  });
144154
144239
  return;
144155
144240
  }
@@ -144157,7 +144242,7 @@ function NewsletterFormClient({ render }) {
144157
144242
  reportNewsletterSignupRefusal("destination_unavailable", { setupRevision: render.hydration.setupRevision });
144158
144243
  dispatchSubmission({
144159
144244
  type: "failed",
144160
- error: newsletterFormError(SIGNUPS_PAUSED_MESSAGE)
144245
+ error: newsletterFormError(NEWSLETTER_SIGNUPS_PAUSED_MESSAGE)
144161
144246
  });
144162
144247
  return;
144163
144248
  }
@@ -144232,43 +144317,14 @@ function NewsletterFormClient({ render }) {
144232
144317
  autoComplete: "off",
144233
144318
  "aria-hidden": "true"
144234
144319
  }),
144235
- /* @__PURE__ */ jsxs("div", {
144236
- className: "newsletter-form-fields",
144237
- children: [
144238
- fields.map((field) => /* @__PURE__ */ jsx(NewsletterField, {
144239
- field,
144240
- submitting,
144241
- error: getNewsletterSubmissionFieldError(submissionState, field.id)
144242
- }, field.id)),
144243
- render.hydration.choicePresentation === "visitor_choice" ? /* @__PURE__ */ jsx(NewsletterTopicChoices, {
144244
- choices: render.display.choices,
144245
- submitting,
144246
- error: getNewsletterSubmissionFieldError(submissionState, TOPIC_CHOICE_FIELD_ID)
144247
- }) : null,
144248
- showSpamProtection && /* @__PURE__ */ jsx("div", {
144249
- className: "newsletter-altcha",
144250
- children: /* @__PURE__ */ jsx(AltchaWidget, {
144251
- challengeUrl: getChallengeUrl(),
144252
- onSolutionChange: setAltchaSolution
144253
- })
144254
- }),
144255
- formError && /* @__PURE__ */ jsx(FeedbackMessage, {
144256
- tone: "error",
144257
- className: "fb-error",
144258
- role: "alert",
144259
- children: formError
144260
- }),
144261
- /* @__PURE__ */ jsx("div", {
144262
- className: "newsletter-submit",
144263
- children: /* @__PURE__ */ jsx(ThemedButton, {
144264
- type: "submit",
144265
- variant: render.display.buttonVariant,
144266
- size: "md",
144267
- disabled: submitting,
144268
- label: submitting ? "Subscribing..." : render.display.buttonLabel
144269
- })
144270
- })
144271
- ]
144320
+ /* @__PURE__ */ jsx(NewsletterFormFields, {
144321
+ render,
144322
+ submissionState,
144323
+ submitting,
144324
+ submissionMessage,
144325
+ formError,
144326
+ showSpamProtection,
144327
+ onAltchaSolution: setAltchaSolution
144272
144328
  }),
144273
144329
  render.display.privacyNote && /* @__PURE__ */ jsx("p", {
144274
144330
  className: "newsletter-privacy-note",
@@ -144278,67 +144334,52 @@ function NewsletterFormClient({ render }) {
144278
144334
  })
144279
144335
  });
144280
144336
  }
144281
- function NewsletterField({ field, submitting, error }) {
144282
- const inputId = `newsletter_${field.id}`;
144283
- const errorId = `${inputId}-error`;
144337
+ function NewsletterFormFields({ render, submissionState, submitting, submissionMessage, formError, showSpamProtection, onAltchaSolution }) {
144338
+ const { email: emailField, extra: extraFields } = partitionNewsletterFields(render.display.fields);
144339
+ const fieldError = (id) => getNewsletterSubmissionFieldError(submissionState, id);
144284
144340
  return /* @__PURE__ */ jsxs("div", {
144285
- className: "fb-field newsletter-field",
144341
+ className: "newsletter-form-fields",
144286
144342
  children: [
144287
- /* @__PURE__ */ jsxs("label", {
144288
- htmlFor: inputId,
144289
- className: "form-label",
144290
- children: [field.label, field.required && /* @__PURE__ */ jsx("span", {
144291
- className: "newsletter-required",
144292
- "aria-hidden": "true",
144293
- children: "*"
144294
- })]
144295
- }),
144296
- /* @__PURE__ */ jsx("input", {
144297
- id: inputId,
144298
- name: field.id,
144299
- type: field.type,
144300
- required: field.required,
144301
- placeholder: field.placeholder,
144302
- className: "form-input",
144303
- autoComplete: field.type === "email" ? "email" : void 0,
144343
+ render.hydration.choicePresentation === "visitor_choice" ? /* @__PURE__ */ jsx(NewsletterTopicChips, {
144344
+ choices: render.display.choices,
144304
144345
  disabled: submitting,
144305
- ...getFieldValidationControlProps({
144306
- message: error,
144307
- messageId: errorId
144346
+ error: fieldError(TOPIC_CHOICE_FIELD_ID)
144347
+ }) : null,
144348
+ extraFields.length > 0 ? /* @__PURE__ */ jsx("div", {
144349
+ className: "newsletter-extra-fields",
144350
+ children: extraFields.map((field) => /* @__PURE__ */ jsx(NewsletterExtraField, {
144351
+ field,
144352
+ disabled: submitting,
144353
+ error: fieldError(field.id)
144354
+ }, field.id))
144355
+ }) : null,
144356
+ showSpamProtection && /* @__PURE__ */ jsx("div", {
144357
+ className: "newsletter-altcha",
144358
+ children: /* @__PURE__ */ jsx(AltchaWidget, {
144359
+ challengeUrl: getChallengeUrl(),
144360
+ onSolutionChange: onAltchaSolution
144308
144361
  })
144309
144362
  }),
144310
- error && /* @__PURE__ */ jsx(FieldValidationMessage, {
144311
- id: errorId,
144363
+ formError && /* @__PURE__ */ jsx(FeedbackMessage, {
144364
+ tone: "error",
144312
144365
  className: "fb-error",
144313
- children: error
144366
+ role: "alert",
144367
+ children: formError
144368
+ }),
144369
+ /* @__PURE__ */ jsx(NewsletterSubmitRow, {
144370
+ emailField,
144371
+ buttonVariant: render.display.buttonVariant,
144372
+ buttonLabel: submitting ? "Subscribing..." : render.display.buttonLabel,
144373
+ disabled: submitting || submissionMessage !== null,
144374
+ error: emailField ? fieldError(emailField.id) : null
144375
+ }),
144376
+ submissionMessage && /* @__PURE__ */ jsx("p", {
144377
+ role: "status",
144378
+ children: submissionMessage
144314
144379
  })
144315
144380
  ]
144316
144381
  });
144317
144382
  }
144318
- function NewsletterTopicChoices({ choices, submitting, error }) {
144319
- const errorId = `newsletter_${TOPIC_CHOICE_FIELD_ID}-error`;
144320
- return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs("fieldset", {
144321
- className: "fb-fieldset newsletter-topics",
144322
- "aria-describedby": error ? errorId : void 0,
144323
- children: [/* @__PURE__ */ jsx("legend", {
144324
- className: "form-label",
144325
- children: "What would you like to hear about?"
144326
- }), choices.map((choice) => /* @__PURE__ */ jsxs("label", {
144327
- className: "fb-inline form-label newsletter-topic-choice",
144328
- children: [/* @__PURE__ */ jsx("input", {
144329
- type: "checkbox",
144330
- name: TOPIC_CHOICE_FIELD_ID,
144331
- value: choice.id,
144332
- className: "form-checkbox",
144333
- disabled: submitting
144334
- }), /* @__PURE__ */ jsx("span", { children: choice.label })]
144335
- }, choice.id))]
144336
- }), error && /* @__PURE__ */ jsx(FieldValidationMessage, {
144337
- id: errorId,
144338
- className: "fb-error",
144339
- children: error
144340
- })] });
144341
- }
144342
144383
  function UnavailableNewsletterForm({ className }) {
144343
144384
  return /* @__PURE__ */ jsx("div", {
144344
144385
  className: clsx("newsletter-form", className ?? void 0),
@@ -144346,13 +144387,10 @@ function UnavailableNewsletterForm({ className }) {
144346
144387
  tone: "error",
144347
144388
  className: "fb-error",
144348
144389
  role: "status",
144349
- children: SIGNUPS_PAUSED_MESSAGE
144390
+ children: NEWSLETTER_SIGNUPS_PAUSED_MESSAGE
144350
144391
  })
144351
144392
  });
144352
144393
  }
144353
- const TOPIC_CHOICE_FIELD_ID = "mailingListChoice";
144354
- /** The site's setup is broken or missing: nothing the visitor does will help. */
144355
- const SIGNUPS_PAUSED_MESSAGE = "We can’t accept signups right now. Please try again later.";
144356
144394
  /** The provider did not answer in time or at all: worth another go shortly. */
144357
144395
  const RETRY_SHORTLY_MESSAGE = "We couldn’t confirm your signup. Please try again in a little while.";
144358
144396
  const TOO_MANY_ATTEMPTS_MESSAGE = "There have been too many signup attempts. Please wait a moment and try again.";
@@ -144372,7 +144410,7 @@ function transportFailureMessage(err) {
144372
144410
  function visitorSelectionError(selection) {
144373
144411
  switch (selection.tag) {
144374
144412
  case "nothing_chosen": return newsletterFieldError(TOPIC_CHOICE_FIELD_ID, "Choose at least one email topic.");
144375
- case "unusable": return newsletterFormError(SIGNUPS_PAUSED_MESSAGE);
144413
+ case "unusable": return newsletterFormError(NEWSLETTER_SIGNUPS_PAUSED_MESSAGE);
144376
144414
  case "not_offered":
144377
144415
  case "chosen": return null;
144378
144416
  }
@@ -144404,7 +144442,7 @@ function publicSignupError(outcome) {
144404
144442
  case "unavailable": switch (outcome.reason) {
144405
144443
  case "configuration_unavailable":
144406
144444
  case "authentication_failed":
144407
- case "target_unavailable": return SIGNUPS_PAUSED_MESSAGE;
144445
+ case "target_unavailable": return NEWSLETTER_SIGNUPS_PAUSED_MESSAGE;
144408
144446
  case "stale_configuration": return "This signup form has changed. Refresh the page, then try again.";
144409
144447
  case "rate_limited": return TOO_MANY_ATTEMPTS_MESSAGE;
144410
144448
  case "temporarily_unavailable": return RETRY_SHORTLY_MESSAGE;
@@ -148715,7 +148753,7 @@ const RENDERER_METADATA_PROP_KEYS = /* @__PURE__ */ new Set([
148715
148753
  "blockContent",
148716
148754
  "fragmentRegistry",
148717
148755
  "previewAuthoring",
148718
- "contentVersionId",
148756
+ "newsletterBlockSubmission",
148719
148757
  "imageResolveContext"
148720
148758
  ]);
148721
148759
  function omitRendererMetadataProps(props) {
@@ -148771,7 +148809,7 @@ function resolveNodeMetadata(nodeType, context) {
148771
148809
  pathBase: context.pathBase,
148772
148810
  fragmentRegistry: context.fragmentRegistry
148773
148811
  } : {},
148774
- ...normalizedType === "newsletter-form" ? { contentVersionId: context.contentVersionId } : {},
148812
+ ...normalizedType === "newsletter-form" ? { newsletterBlockSubmission: context.newsletterBlockSubmission } : {},
148775
148813
  ...normalizedType === "media" && context.imageResolveContext ? { imageResolveContext: context.imageResolveContext } : {}
148776
148814
  };
148777
148815
  }
@@ -149382,6 +149420,270 @@ function generateHoverEffects(axes, _space) {
149382
149420
  };
149383
149421
  }
149384
149422
  //#endregion
149423
+ //#region ../theme-core/src/inputs/checkable.ts
149424
+ /**
149425
+ * Checkbox and radio CSS shared by the full theme generator and the SDK
149426
+ * theme bridge, so both render the same customer-facing controls.
149427
+ *
149428
+ * Emits:
149429
+ * - .form-checkbox / .form-radio: the controls themselves. The tick and dot
149430
+ * are drawn with ::before so their colour comes from theme tokens rather
149431
+ * than a baked-in SVG.
149432
+ * - .form-check: a label row holding a control and its text. The control
149433
+ * lines up with the first line of text, so long labels wrap cleanly.
149434
+ * - .form-check--tile: a bordered, fully clickable panel for agreements
149435
+ * (booking consent, consent fields) that tints when ticked.
149436
+ */
149437
+ const CHECKABLE_SIZE = "1.375rem";
149438
+ /** Never fully round: a round checkbox reads as a radio. */
149439
+ const CHECKBOX_RADIUS = {
149440
+ square: "0",
149441
+ soft: "0.25rem",
149442
+ rounded: "0.375rem",
149443
+ pill: "0.375rem"
149444
+ };
149445
+ /** Tiles hold wrapping text, so pill themes get a generous radius, not a capsule. */
149446
+ const TILE_RADIUS = {
149447
+ square: "0",
149448
+ soft: "0.5rem",
149449
+ rounded: "0.75rem",
149450
+ pill: "1rem"
149451
+ };
149452
+ const ON_ACCENT_TOKENS = {
149453
+ primary: "onPrimary",
149454
+ secondary: "onSecondary",
149455
+ accent: "onAccent"
149456
+ };
149457
+ /**
149458
+ * Colour for the tick/dot drawn on top of the accent fill. Uses the palette's
149459
+ * matching "on" token where there is one, falling back to white.
149460
+ */
149461
+ /** The accent at full strength: `primary/70` becomes `primary`. */
149462
+ function solidAccentToken(accentToken) {
149463
+ const parsed = parseColorTokenParts(accentToken);
149464
+ return parsed.kind === "token" ? parsed.token : accentToken;
149465
+ }
149466
+ function checkableMarkColor(accentToken) {
149467
+ const parsed = parseColorTokenParts(accentToken);
149468
+ const onToken = parsed.kind === "token" ? ON_ACCENT_TOKENS[parsed.token] : void 0;
149469
+ return onToken ? `rgb(var(--tb-${onToken}, 255 255 255))` : "rgb(255 255 255)";
149470
+ }
149471
+ function checkableSelectors(root) {
149472
+ return {
149473
+ checkbox: `${root} .form-checkbox`,
149474
+ radio: `${root} .form-radio`,
149475
+ check: `${root} .form-check`,
149476
+ tile: `${root} .form-check--tile`
149477
+ };
149478
+ }
149479
+ /** The box and circle themselves, unchecked. */
149480
+ function controlBaseCss(sel, input) {
149481
+ const border = input.borderWidth === "0" ? "1px" : input.borderWidth;
149482
+ return [
149483
+ `${sel.checkbox},
149484
+ ${sel.radio} {
149485
+ appearance: none;
149486
+ display: inline-grid;
149487
+ place-content: center;
149488
+ width: ${CHECKABLE_SIZE};
149489
+ height: ${CHECKABLE_SIZE};
149490
+ margin: 0;
149491
+ flex-shrink: 0;
149492
+ border: ${border} solid ${input.borderColor};
149493
+ background-color: ${input.background};
149494
+ color: inherit;
149495
+ cursor: pointer;
149496
+ transition: background-color 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease;
149497
+ }`,
149498
+ `${sel.checkbox} {
149499
+ border-radius: ${CHECKBOX_RADIUS[input.corners]};
149500
+ }`,
149501
+ `${sel.radio} {
149502
+ border-radius: 9999px;
149503
+ }`
149504
+ ];
149505
+ }
149506
+ /** The tick and dot, drawn with ::before so their colour is a theme token. */
149507
+ function controlMarkCss(sel, accentToken) {
149508
+ return [
149509
+ `${sel.checkbox}::before,
149510
+ ${sel.radio}::before {
149511
+ content: "";
149512
+ background-color: ${checkableMarkColor(accentToken)};
149513
+ transform: scale(0);
149514
+ transition: transform 0.12s ease;
149515
+ }`,
149516
+ `${sel.checkbox}::before {
149517
+ width: 0.75rem;
149518
+ height: 0.75rem;
149519
+ clip-path: polygon(14% 52%, 0 67%, 38% 100%, 100% 22%, 85% 8%, 37% 70%);
149520
+ }`,
149521
+ `${sel.radio}::before {
149522
+ width: 0.5rem;
149523
+ height: 0.5rem;
149524
+ border-radius: 9999px;
149525
+ }`
149526
+ ];
149527
+ }
149528
+ function controlStateCss(sel, input) {
149529
+ const accent = rgbColorValue(solidAccentToken(input.accentToken));
149530
+ return [
149531
+ `${sel.checkbox}:hover,
149532
+ ${sel.radio}:hover,
149533
+ ${sel.check}:hover > .form-checkbox,
149534
+ ${sel.check}:hover > .form-radio {
149535
+ border-color: ${accent};
149536
+ }`,
149537
+ `${sel.checkbox}:checked,
149538
+ ${sel.radio}:checked {
149539
+ background-color: ${accent};
149540
+ border-color: ${accent};
149541
+ }`,
149542
+ `${sel.checkbox}:checked::before,
149543
+ ${sel.radio}:checked::before {
149544
+ transform: scale(1);
149545
+ }`,
149546
+ `${sel.checkbox}:focus-visible,
149547
+ ${sel.radio}:focus-visible {
149548
+ outline: 2px solid ${accent};
149549
+ outline-offset: 2px;
149550
+ }`,
149551
+ `${sel.checkbox}:disabled,
149552
+ ${sel.radio}:disabled {
149553
+ opacity: 0.5;
149554
+ cursor: not-allowed;
149555
+ }`
149556
+ ];
149557
+ }
149558
+ /** Label row: control lined up with the first line of wrapping text. */
149559
+ function checkRowCss(sel) {
149560
+ return [
149561
+ `${sel.check} {
149562
+ display: flex;
149563
+ align-items: flex-start;
149564
+ gap: 0.75rem;
149565
+ line-height: 1.5;
149566
+ cursor: pointer;
149567
+ }`,
149568
+ `${sel.check} > .form-checkbox,
149569
+ ${sel.check} > .form-radio {
149570
+ margin-top: 0.0625rem;
149571
+ margin-top: max(0px, calc((1lh - ${CHECKABLE_SIZE}) / 2));
149572
+ }`,
149573
+ `${sel.check}:has(> :disabled) {
149574
+ cursor: not-allowed;
149575
+ }`
149576
+ ];
149577
+ }
149578
+ function agreementTileCss(sel, input) {
149579
+ const accent = rgbColorValue(solidAccentToken(input.accentToken));
149580
+ return [
149581
+ `${sel.tile} {
149582
+ padding: 0.875rem 1rem;
149583
+ border: 1px solid color-mix(in srgb, currentColor 22%, transparent);
149584
+ border-radius: ${TILE_RADIUS[input.corners]};
149585
+ transition: border-color 0.15s ease, background-color 0.15s ease;
149586
+ }`,
149587
+ `${sel.tile}:hover {
149588
+ border-color: color-mix(in srgb, ${accent} 55%, transparent);
149589
+ }`,
149590
+ `${sel.tile}:has(> .form-checkbox:checked) {
149591
+ border-color: ${accent};
149592
+ background-color: color-mix(in srgb, ${accent} 7%, transparent);
149593
+ }`,
149594
+ `${sel.tile}:has(> .form-checkbox[aria-invalid="true"]) {
149595
+ border-color: ${input.errorColor};
149596
+ }`
149597
+ ];
149598
+ }
149599
+ function checkableMediaCss(sel) {
149600
+ return [`@media (prefers-reduced-motion: reduce) {
149601
+ ${sel.checkbox}, ${sel.radio}, ${sel.checkbox}::before, ${sel.radio}::before, ${sel.tile} {
149602
+ transition: none;
149603
+ }
149604
+ }`, `@media (forced-colors: active) {
149605
+ ${sel.checkbox}::before,
149606
+ ${sel.radio}::before {
149607
+ background-color: CanvasText;
149608
+ }
149609
+ }`];
149610
+ }
149611
+ /**
149612
+ * Exposes the accent and mark colours so other choice controls (newsletter
149613
+ * topic chips) match the checkboxes without re-deriving the theme tokens.
149614
+ */
149615
+ function checkableVarsCss(input) {
149616
+ return [`${input.root} {
149617
+ --rb-check-accent: ${rgbColorValue(solidAccentToken(input.accentToken))};
149618
+ --rb-check-mark: ${checkableMarkColor(input.accentToken)};
149619
+ }`];
149620
+ }
149621
+ function generateCheckableCss(input) {
149622
+ const sel = checkableSelectors(input.root);
149623
+ return [
149624
+ ...checkableVarsCss(input),
149625
+ ...controlBaseCss(sel, input),
149626
+ ...controlMarkCss(sel, input.accentToken),
149627
+ ...controlStateCss(sel, input),
149628
+ ...checkRowCss(sel),
149629
+ ...agreementTileCss(sel, input),
149630
+ ...checkableMediaCss(sel)
149631
+ ].join("\n\n");
149632
+ }
149633
+ //#endregion
149634
+ //#region ../theme-core/src/inputs/inputGroup.ts
149635
+ /**
149636
+ * Input group: a field and an action (usually a themed button) sharing one
149637
+ * input-styled shell, e.g. the newsletter email + Sign up row.
149638
+ *
149639
+ * The shell `.form-input-group` takes the theme's `.form-input` rules (the
149640
+ * generators add it to that selector list, plus focus and error), so it
149641
+ * follows the site's input background, border, corners and shadow. This file
149642
+ * only adds the layout overrides and the borderless inner field.
149643
+ */
149644
+ const INPUT_GROUP_SELECTOR = ".form-input-group";
149645
+ /** Shell focus ring follows the field only, not the button beside it. */
149646
+ const INPUT_GROUP_FOCUS_SELECTOR = ".form-input-group:has(> .form-input-group-field:focus-visible)";
149647
+ const INPUT_GROUP_ERROR_SELECTOR = ".form-input-group:has(> .form-input-group-field[aria-invalid=\"true\"])";
149648
+ const GROUP_INSET = "0.25rem";
149649
+ /**
149650
+ * @param root - scoped root selector
149651
+ * @param padding - the theme's input padding shorthand (`block inline`), so the
149652
+ * inner field's text sits where a plain input's text would.
149653
+ */
149654
+ function generateInputGroupCss(root, padding) {
149655
+ const [block = padding, inline = block] = padding.trim().split(/\s+/);
149656
+ return `${root} .form-input-group {
149657
+ display: flex;
149658
+ align-items: stretch;
149659
+ gap: ${GROUP_INSET};
149660
+ padding: ${GROUP_INSET};
149661
+ }
149662
+
149663
+ ${root} .form-input-group-field {
149664
+ flex: 1 1 auto;
149665
+ min-width: 0;
149666
+ margin: 0;
149667
+ border: 0;
149668
+ border-radius: 0;
149669
+ background: transparent;
149670
+ box-shadow: none;
149671
+ outline: none;
149672
+ color: inherit;
149673
+ font: inherit;
149674
+ padding: calc(${block} - ${GROUP_INSET}) calc(${inline} - ${GROUP_INSET});
149675
+ }
149676
+
149677
+ ${root} .form-input-group-field::placeholder {
149678
+ color: inherit;
149679
+ opacity: 0.6;
149680
+ }
149681
+
149682
+ ${root} .form-input-group > :not(.form-input-group-field) {
149683
+ flex-shrink: 0;
149684
+ }`;
149685
+ }
149686
+ //#endregion
149385
149687
  //#region ../theme-core/src/inputs/generateInputCss.ts
149386
149688
  /**
149387
149689
  * Corner radius map (reused from other systems)
@@ -149392,6 +149694,9 @@ const CORNER_MAP$1 = {
149392
149694
  rounded: "1rem",
149393
149695
  pill: "9999px"
149394
149696
  };
149697
+ function inputBackgroundValue(background) {
149698
+ return background.type === "transparent" ? "transparent" : rgbColorValue(background.colorToken);
149699
+ }
149395
149700
  /**
149396
149701
  * Generate CSS for form input styling based on theme configuration
149397
149702
  *
@@ -149409,8 +149714,7 @@ const CORNER_MAP$1 = {
149409
149714
  function generateInputCss({ themeId, theme, inputSystem }) {
149410
149715
  const rootSelector = `:where([data-theme-scope="${themeId}"])`;
149411
149716
  const baseInputRules = [];
149412
- if (inputSystem.base.background.type === "transparent") baseInputRules.push("background-color: transparent");
149413
- else baseInputRules.push(`background-color: ${rgbColorValue(inputSystem.base.background.colorToken)}`);
149717
+ baseInputRules.push(`background-color: ${inputBackgroundValue(inputSystem.base.background)}`);
149414
149718
  baseInputRules.push(`color: ${rgbColorValue(inputSystem.base.textColorToken)}`);
149415
149719
  const borderPx = parseBorderWidth(inputSystem.base.border.widthClass);
149416
149720
  const borderStyle = inputSystem.base.border.style ?? "all";
@@ -149466,7 +149770,8 @@ function generateInputCss({ themeId, theme, inputSystem }) {
149466
149770
  const focusSelectors = [
149467
149771
  `${inputSelector}:focus-visible`,
149468
149772
  `${textareaSelector}:focus-visible`,
149469
- `${selectSelector}:focus-visible`
149773
+ `${selectSelector}:focus-visible`,
149774
+ `${rootSelector} ${INPUT_GROUP_FOCUS_SELECTOR}`
149470
149775
  ];
149471
149776
  const focusRules = [];
149472
149777
  focusRules.push("outline: none");
@@ -149475,7 +149780,8 @@ function generateInputCss({ themeId, theme, inputSystem }) {
149475
149780
  const errorSelectors = [
149476
149781
  `${inputSelector}[aria-invalid="true"]`,
149477
149782
  `${textareaSelector}[aria-invalid="true"]`,
149478
- `${selectSelector}[aria-invalid="true"]`
149783
+ `${selectSelector}[aria-invalid="true"]`,
149784
+ `${rootSelector} ${INPUT_GROUP_ERROR_SELECTOR}`
149479
149785
  ];
149480
149786
  const errorRules = [];
149481
149787
  errorRules.push(`border-color: ${rgbColorValue(inputSystem.error.borderColorToken)}`);
@@ -149490,53 +149796,25 @@ function generateInputCss({ themeId, theme, inputSystem }) {
149490
149796
  disabledRules.push(`color: ${rgbColorValue(inputSystem.disabled.textColorToken)}`);
149491
149797
  disabledRules.push(`opacity: ${inputSystem.disabled.opacity}`);
149492
149798
  disabledRules.push("cursor: not-allowed");
149493
- const checkboxSelector = `${rootSelector} .form-checkbox`;
149494
- const radioSelector = `${rootSelector} .form-radio`;
149495
- const checkableRules = [];
149496
- checkableRules.push("appearance: none");
149497
- checkableRules.push("width: 1.125rem");
149498
- checkableRules.push("height: 1.125rem");
149499
- checkableRules.push("flex-shrink: 0");
149500
- checkableRules.push(`border: ${borderPx} solid ${rgbColorValue(inputSystem.base.border.colorToken)}`);
149501
- if (inputSystem.base.background.type === "transparent") checkableRules.push("background-color: transparent");
149502
- else checkableRules.push(`background-color: ${rgbColorValue(inputSystem.base.background.colorToken)}`);
149503
- checkableRules.push("cursor: pointer");
149504
- checkableRules.push("transition: background-color 0.2s ease, border-color 0.2s ease");
149505
- const checkboxSpecificRules = [...checkableRules];
149506
- checkboxSpecificRules.push(`border-radius: ${CORNER_MAP$1.soft}`);
149507
- const radioSpecificRules = [...checkableRules];
149508
- radioSpecificRules.push("border-radius: 9999px");
149509
- const checkboxCheckedSelector = `${checkboxSelector}:checked`;
149510
- const checkboxCheckedRules = [];
149511
- checkboxCheckedRules.push(`background-color: ${rgbColorValue(inputSystem.focus.ringColorToken)}`);
149512
- checkboxCheckedRules.push(`border-color: ${rgbColorValue(inputSystem.focus.ringColorToken)}`);
149513
- 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\")");
149514
- checkboxCheckedRules.push("background-size: 100% 100%");
149515
- checkboxCheckedRules.push("background-position: center");
149516
- checkboxCheckedRules.push("background-repeat: no-repeat");
149517
- const radioCheckedSelector = `${radioSelector}:checked`;
149518
- const radioCheckedRules = [];
149519
- radioCheckedRules.push(`background-color: ${rgbColorValue(inputSystem.focus.ringColorToken)}`);
149520
- radioCheckedRules.push(`border-color: ${rgbColorValue(inputSystem.focus.ringColorToken)}`);
149521
- radioCheckedRules.push("background-image: radial-gradient(circle, white 40%, transparent 40%)");
149522
- const checkboxFocusSelector = `${checkboxSelector}:focus-visible`;
149523
- const radioFocusSelector = `${radioSelector}:focus-visible`;
149524
- const checkableFocusRules = [];
149525
- checkableFocusRules.push("outline: none");
149526
- checkableFocusRules.push(`box-shadow: 0 0 0 ${inputSystem.focus.ringWidth}px ${rgbColorValue(inputSystem.focus.ringColorToken)}`);
149799
+ const checkableCss = generateCheckableCss({
149800
+ root: rootSelector,
149801
+ borderWidth: borderPx,
149802
+ borderColor: rgbColorValue(inputSystem.base.border.colorToken),
149803
+ background: inputBackgroundValue(inputSystem.base.background),
149804
+ corners: inputSystem.base.corners ?? theme.corners,
149805
+ accentToken: inputSystem.focus.borderColorToken ?? inputSystem.focus.ringColorToken,
149806
+ errorColor: rgbColorValue(inputSystem.error.borderColorToken)
149807
+ });
149527
149808
  const cssBlocks = [];
149528
149809
  cssBlocks.push(`${labelSelector} {\n ${labelRules.join(";\n ")};\n}`);
149529
- cssBlocks.push(`${inputSelector} {\n ${inputRules.join(";\n ")};\n}`);
149810
+ cssBlocks.push(`${inputSelector},\n${rootSelector} ${INPUT_GROUP_SELECTOR} {\n ${inputRules.join(";\n ")};\n}`);
149530
149811
  cssBlocks.push(`${textareaSelector} {\n ${textareaRules.join(";\n ")};\n}`);
149531
149812
  cssBlocks.push(`${selectSelector} {\n ${selectRules.join(";\n ")};\n}`);
149532
149813
  cssBlocks.push(`${focusSelectors.join(",\n")} {\n ${focusRules.join(";\n ")};\n}`);
149533
149814
  cssBlocks.push(`${errorSelectors.join(",\n")} {\n ${errorRules.join(";\n ")};\n}`);
149534
149815
  cssBlocks.push(`${disabledSelectors.join(",\n")} {\n ${disabledRules.join(";\n ")};\n}`);
149535
- cssBlocks.push(`${checkboxSelector} {\n ${checkboxSpecificRules.join(";\n ")};\n}`);
149536
- cssBlocks.push(`${radioSelector} {\n ${radioSpecificRules.join(";\n ")};\n}`);
149537
- cssBlocks.push(`${checkboxCheckedSelector} {\n ${checkboxCheckedRules.join(";\n ")};\n}`);
149538
- cssBlocks.push(`${radioCheckedSelector} {\n ${radioCheckedRules.join(";\n ")};\n}`);
149539
- cssBlocks.push(`${checkboxFocusSelector},\n${radioFocusSelector} {\n ${checkableFocusRules.join(";\n ")};\n}`);
149816
+ cssBlocks.push(generateInputGroupCss(rootSelector, padding));
149817
+ cssBlocks.push(checkableCss);
149540
149818
  return cssBlocks.join("\n\n");
149541
149819
  }
149542
149820
  //#endregion
@@ -154726,13 +155004,13 @@ const hours = stack({
154726
155004
  as: "p",
154727
155005
  className: "rb-caption rb-opacity-70"
154728
155006
  }, bind$1("module.timeZone"), when("module.timeZone"))], when("module.kind", { equals: "opening-hours" }));
154729
- const socials = inline({ className: "rb-flex rb-flex-wrap rb-gap-x-5 rb-gap-y-3" }, [link({
155007
+ const socials = inline({ className: "rb-footer-socials" }, [link({
154730
155008
  href: { $bind: { from: "social.href" } },
154731
155009
  target: "_blank",
154732
155010
  rel: "noreferrer noopener",
154733
155011
  "aria-label": { $bind: { from: "social.label" } },
154734
- className: "rb-nav-text transition-theme-standard"
154735
- }, [icon({ className: "rb-h-5 rb-w-5" }, bind$1("social.icon"), when("social.icon")), text({ as: "span" }, bind$1("social.label"), when("social.icon", { equals: null }))], repeat("module.socialLinks", "social"))], when("module.kind", { equals: "social-links" }));
155012
+ className: "rb-footer-social-link rb-nav-text transition-theme-standard"
155013
+ }, [icon({ className: "rb-footer-social-icon" }, bind$1("social.icon"), when("social.icon")), text({ as: "span" }, bind$1("social.label"), when("social.icon", { equals: null }))], repeat("module.socialLinks", "social"))], when("module.kind", { equals: "social-links" }));
154736
155014
  const authoredCopy = richText({
154737
155015
  className: "rb-prose rb-prose-sm rb-max-w-none",
154738
155016
  style: textColorStyle("text/80")
@@ -160952,43 +161230,53 @@ function collectNestedPreviewFieldConstraintEntries(field, path) {
160952
161230
  default: return assertNever$10(field);
160953
161231
  }
160954
161232
  }
161233
+ function prepareDefaultBlockRender(manifest, props) {
161234
+ if (!props.theme) throw new Error("Block rendering requires theme tokens; none were provided to makeDefaultBlockComponent");
161235
+ if (!props.registry) throw new Error("Block rendering requires a component registry; none was provided");
161236
+ const content = props.content;
161237
+ const layout = resolveBlockLayout(manifest, content);
161238
+ if (!layout) throw new Error(`Block manifest "${manifest.name}" requires a layout definition`);
161239
+ const mergedContent = mergeContentWithBlockStyleOverrides(content, props.themeConfig, props.blockKind ?? manifest.name);
161240
+ return {
161241
+ registry: props.registry,
161242
+ layout,
161243
+ mergedContent,
161244
+ fieldConstraints: buildPreviewFieldConstraints(manifest),
161245
+ viewModel: buildBlockViewModel({
161246
+ mergedContent,
161247
+ data: props.data,
161248
+ resolvedThemeConfig: resolveThemeConfigForBindings(props.themeConfig),
161249
+ viewModelOverrides: props.viewModelOverrides
161250
+ }),
161251
+ themeForTransforms: withButtonSystem(props.theme, props.themeConfig)
161252
+ };
161253
+ }
160955
161254
  function makeDefaultBlockComponent(args) {
160956
- const { manifest } = args;
160957
- return function DefaultBlockComponent({ content, data, registry, theme, themeConfig, transforms, viewModelOverrides, pathBase, blockId, contentVersionId, blockKind, blockBindings, editableRouteMetadataFieldIds, fragmentRegistry, imageResolveContext, previewAuthoring }) {
161255
+ return function DefaultBlockComponent(props) {
160958
161256
  const perf = beginBlockRenderMeasurement();
160959
- if (!theme) throw new Error("Block rendering requires theme tokens; none were provided to makeDefaultBlockComponent");
160960
- if (!registry) throw new Error("Block rendering requires a component registry; none was provided");
160961
- const layout = resolveBlockLayout(manifest, content);
160962
- if (!layout) throw new Error(`Block manifest "${manifest.name}" requires a layout definition`);
160963
- const fieldConstraints = buildPreviewFieldConstraints(manifest);
160964
- const mergedContent = mergeContentWithBlockStyleOverrides(content, themeConfig, blockKind ?? manifest.name);
160965
- const result = resolveTree(layout, {
160966
- registry,
160967
- viewModel: buildBlockViewModel({
160968
- mergedContent,
160969
- data,
160970
- resolvedThemeConfig: resolveThemeConfigForBindings(themeConfig),
160971
- viewModelOverrides
160972
- }),
160973
- transforms,
160974
- theme: withButtonSystem(theme, themeConfig),
160975
- pathBase,
160976
- blockId,
160977
- contentVersionId,
160978
- blockKind,
160979
- blockContent: mergedContent,
160980
- blockBindings,
160981
- editableRouteMetadataFieldIds,
160982
- fragmentRegistry,
160983
- fieldConstraints,
160984
- imageResolveContext,
160985
- previewAuthoring
161257
+ const prepared = prepareDefaultBlockRender(args.manifest, props);
161258
+ const result = resolveTree(prepared.layout, {
161259
+ registry: prepared.registry,
161260
+ viewModel: prepared.viewModel,
161261
+ transforms: props.transforms,
161262
+ theme: prepared.themeForTransforms,
161263
+ pathBase: props.pathBase,
161264
+ blockId: props.blockId,
161265
+ newsletterBlockSubmission: props.newsletterBlockSubmission,
161266
+ blockKind: props.blockKind,
161267
+ blockContent: prepared.mergedContent,
161268
+ blockBindings: props.blockBindings,
161269
+ editableRouteMetadataFieldIds: props.editableRouteMetadataFieldIds,
161270
+ fragmentRegistry: props.fragmentRegistry,
161271
+ fieldConstraints: prepared.fieldConstraints,
161272
+ imageResolveContext: props.imageResolveContext,
161273
+ previewAuthoring: props.previewAuthoring
160986
161274
  });
160987
161275
  reportSlowBlockRender(perf, {
160988
- content,
160989
- blockId,
160990
- blockKind: blockKind ?? manifest.name,
160991
- manifestName: manifest.name
161276
+ content: props.content,
161277
+ blockId: props.blockId,
161278
+ blockKind: props.blockKind ?? args.manifest.name,
161279
+ manifestName: args.manifest.name
160992
161280
  });
160993
161281
  return result;
160994
161282
  };
@@ -162585,6 +162873,9 @@ const containerResponsiveThemeCss = `/*
162585
162873
  .rb-h-4 {
162586
162874
  height: 1rem;
162587
162875
  }
162876
+ .rb-h-5 {
162877
+ height: 1.25rem;
162878
+ }
162588
162879
  .rb-h-8 {
162589
162880
  height: 2rem;
162590
162881
  }
@@ -166550,6 +166841,10 @@ const containerResponsiveThemeCss = `/*
166550
166841
  margin-bottom: 0.25rem;
166551
166842
  }
166552
166843
 
166844
+ :where(.theme-scope) :where([data-block='event-registration']) .er-consent-check {
166845
+ margin-top: 0.75rem;
166846
+ }
166847
+
166553
166848
  :where(.theme-scope) :where([data-block='event-registration']) .er-required {
166554
166849
  color: var(--er-required);
166555
166850
  }
@@ -171269,13 +171564,6 @@ const containerResponsiveThemeCss = `/*
171269
171564
  margin: 0;
171270
171565
  }
171271
171566
 
171272
- /* Inline field (checkbox, radio with label) */
171273
- :where(.theme-scope) :where([data-block="form"]) .fb-inline {
171274
- display: flex;
171275
- align-items: center;
171276
- gap: 0.5rem;
171277
- }
171278
-
171279
171567
  /* Success state */
171280
171568
  :where(.theme-scope) :where([data-block="form"]) .fb-success {
171281
171569
  background-color: var(--fb-success-bg);
@@ -173392,9 +173680,11 @@ const containerResponsiveThemeCss = `/*
173392
173680
  */
173393
173681
 
173394
173682
  /* Newsletter copy styling */
173683
+ /* Size only: weight, family and colour come from the theme's heading styles */
173395
173684
  :where(.theme-scope) :where([data-block="newsletter-signup"]) .newsletter-copy-title {
173396
- font-size: 1.5rem;
173397
- font-weight: 600;
173685
+ font-size: clamp(1.75rem, 1.35rem + 1.6vw, 2.5rem);
173686
+ line-height: 1.15;
173687
+ text-wrap: balance;
173398
173688
  }
173399
173689
 
173400
173690
  :where(.theme-scope) :where([data-block="newsletter-signup"]) .newsletter-copy-subtitle {
@@ -173418,37 +173708,150 @@ const containerResponsiveThemeCss = `/*
173418
173708
  gap: var(--rb-gap-sm, 0.75rem);
173419
173709
  }
173420
173710
 
173421
- /* Individual field styling */
173711
+ /* Extra preset fields (name, company...). Labels are visually hidden, so
173712
+ these sit in a row above the email entry. */
173713
+ :where(.theme-scope) .newsletter-extra-fields {
173714
+ display: grid;
173715
+ grid-template-columns: repeat(auto-fit, minmax(min(12rem, 100%), 1fr));
173716
+ gap: 0.5rem;
173717
+ }
173718
+
173422
173719
  :where(.theme-scope) .newsletter-field {
173423
173720
  display: flex;
173424
173721
  flex-direction: column;
173425
173722
  gap: 0.25rem;
173723
+ text-align: left;
173426
173724
  }
173427
173725
 
173428
- /* Topic choices (visitor picks what to hear about). Same treatment as the
173429
- form block's .fb-fieldset / .fb-inline, defined here because the newsletter
173430
- form also renders inside contact-newsletter and the site footer. */
173431
- :where(.theme-scope) .newsletter-topics {
173726
+ /* Email entry: the email field and the themed submit button share one shell.
173727
+ The shell's look (background, border, corners, focus ring) comes from the
173728
+ theme's input system via .form-input-group; this only handles layout. */
173729
+ :where(.theme-scope) .newsletter-entry {
173730
+ container-type: inline-size;
173432
173731
  display: flex;
173433
173732
  flex-direction: column;
173434
- gap: 0.5rem;
173733
+ gap: 0.375rem;
173734
+ text-align: left;
173735
+ }
173736
+
173737
+ :where(.theme-scope) .newsletter-entry-group > button {
173738
+ white-space: nowrap;
173739
+ }
173740
+
173741
+ /* Too narrow for field and button side by side (phones, footer columns):
173742
+ stack them inside the shell and keep pill themes from turning the taller
173743
+ shell into a capsule. */
173744
+ @container (max-width: 22rem) {
173745
+ :where(.theme-scope) .newsletter-entry .newsletter-entry-group {
173746
+ flex-direction: column;
173747
+ border-radius: min(var(--rb-input-radius, 0.5rem), 1rem);
173748
+ }
173749
+
173750
+ :where(.theme-scope) .newsletter-entry .newsletter-entry-group > button {
173751
+ width: 100%;
173752
+ justify-content: center;
173753
+ }
173754
+ }
173755
+
173756
+ /* Topic choices (visitor picks what to hear about) as toggle chips. Each chip
173757
+ is a real checkbox underneath; the chip is its visible face. */
173758
+ :where(.theme-scope) .newsletter-topics {
173435
173759
  border: none;
173436
173760
  padding: 0;
173437
173761
  margin: 0;
173438
173762
  min-width: 0;
173439
173763
  }
173440
173764
 
173441
- :where(.theme-scope) .newsletter-topics > legend {
173765
+ :where(.theme-scope) .newsletter-topics-legend {
173442
173766
  padding: 0;
173443
- margin-bottom: 0.25rem;
173767
+ margin-bottom: 0.625rem;
173768
+ font-size: 0.9375rem;
173769
+ color: var(--rb-surface-text-color, rgb(var(--tb-text, 17 24 39)));
173444
173770
  }
173445
173771
 
173446
- :where(.theme-scope) .newsletter-topic-choice {
173772
+ :where(.theme-scope) .newsletter-topic-chips {
173447
173773
  display: flex;
173448
- align-items: center;
173774
+ flex-wrap: wrap;
173449
173775
  gap: 0.5rem;
173450
173776
  }
173451
173777
 
173778
+ :where(.theme-scope) .newsletter-stacked .newsletter-topics-legend {
173779
+ width: 100%;
173780
+ }
173781
+
173782
+ :where(.theme-scope) .newsletter-stacked .newsletter-topic-chips {
173783
+ justify-content: center;
173784
+ }
173785
+
173786
+ :where(.theme-scope) .newsletter-topic-chip {
173787
+ position: relative;
173788
+ display: inline-flex;
173789
+ }
173790
+
173791
+ :where(.theme-scope) .newsletter-topic-chip > input {
173792
+ position: absolute;
173793
+ inset: 0;
173794
+ width: 100%;
173795
+ height: 100%;
173796
+ margin: 0;
173797
+ opacity: 0;
173798
+ cursor: pointer;
173799
+ }
173800
+
173801
+ :where(.theme-scope) .newsletter-topic-chip > span {
173802
+ display: inline-flex;
173803
+ align-items: center;
173804
+ gap: 0.375rem;
173805
+ padding: 0.4375rem 0.9375rem;
173806
+ border: 1px solid color-mix(in srgb, currentColor 35%, transparent);
173807
+ border-radius: var(--rb-button-radius, var(--rb-input-radius, 9999px));
173808
+ font-size: 0.9375rem;
173809
+ line-height: 1.3;
173810
+ color: var(--rb-surface-text-color, rgb(var(--tb-text, 17 24 39)));
173811
+ transition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease;
173812
+ }
173813
+
173814
+ /* Tick that grows in when the chip is on */
173815
+ :where(.theme-scope) .newsletter-topic-chip > span::before {
173816
+ content: "";
173817
+ width: 0;
173818
+ height: 0.7em;
173819
+ background-color: currentColor;
173820
+ clip-path: polygon(14% 52%, 0 67%, 38% 100%, 100% 22%, 85% 8%, 37% 70%);
173821
+ transition: width 0.15s ease;
173822
+ }
173823
+
173824
+ :where(.theme-scope) .newsletter-topic-chip:hover > span {
173825
+ border-color: currentColor;
173826
+ }
173827
+
173828
+ /* Same accent and mark colours as the theme's checkboxes */
173829
+ :where(.theme-scope) .newsletter-topic-chip > input:checked + span {
173830
+ background-color: var(--rb-check-accent, rgb(var(--tb-primary)));
173831
+ border-color: var(--rb-check-accent, rgb(var(--tb-primary)));
173832
+ color: var(--rb-check-mark, rgb(var(--tb-onPrimary, 255 255 255)));
173833
+ }
173834
+
173835
+ :where(.theme-scope) .newsletter-topic-chip > input:checked + span::before {
173836
+ width: 0.7em;
173837
+ }
173838
+
173839
+ :where(.theme-scope) .newsletter-topic-chip > input:focus-visible + span {
173840
+ outline: 2px solid var(--rb-check-accent, rgb(var(--tb-primary)));
173841
+ outline-offset: 2px;
173842
+ }
173843
+
173844
+ :where(.theme-scope) .newsletter-topic-chip > input:disabled + span {
173845
+ opacity: 0.6;
173846
+ }
173847
+
173848
+ @media (prefers-reduced-motion: reduce) {
173849
+ :where(.theme-scope) .newsletter-topic-chip > span,
173850
+ :where(.theme-scope) .newsletter-topic-chip > span::before {
173851
+ transition: none;
173852
+ }
173853
+ }
173854
+
173452
173855
  /* Error panel and field notes. The form block scopes these to its own
173453
173856
  data-block, so the newsletter form (which also renders in the footer)
173454
173857
  needs its own copy of the treatment. */
@@ -173466,13 +173869,7 @@ const containerResponsiveThemeCss = `/*
173466
173869
  color: var(--fb-error-text);
173467
173870
  }
173468
173871
 
173469
- /* Required indicator */
173470
- :where(.theme-scope) .newsletter-required {
173471
- color: rgb(var(--tb-primary));
173472
- margin-left: 0.125rem;
173473
- }
173474
-
173475
- /* Submit button container */
173872
+ /* Submit button container (only when a preset has no email field) */
173476
173873
  :where(.theme-scope) .newsletter-submit {
173477
173874
  margin-top: 0.5rem;
173478
173875
  }
@@ -173484,52 +173881,29 @@ const containerResponsiveThemeCss = `/*
173484
173881
  justify-content: center;
173485
173882
  }
173486
173883
 
173487
- /* Privacy note */
173884
+ /* Privacy note: quieter than the intro so the entry row leads */
173488
173885
  :where(.theme-scope) .newsletter-privacy-note {
173489
173886
  margin-top: 0.75rem;
173490
- font-size: 1rem;
173491
- line-height: 1.6;
173492
- color: var(--rb-surface-text-color, rgb(var(--tb-text, 17 24 39)));
173887
+ font-size: 0.8125rem;
173888
+ line-height: 1.5;
173889
+ color: var(--rb-surface-supporting-color, var(--rb-surface-text-color, rgb(var(--tb-text, 17 24 39))));
173890
+ opacity: 0.85;
173493
173891
  text-align: center;
173494
173892
  }
173495
173893
 
173496
173894
  /* =============================================================================
173497
- * Inline Variant - Horizontal layout
173895
+ * Inline Variant - left-aligned, wider entry row
173498
173896
  * =============================================================================
173499
173897
  */
173500
173898
 
173501
- :where(.theme-scope) .newsletter-inline .newsletter-form-fields {
173502
- flex-direction: row;
173503
- align-items: flex-end;
173504
- flex-wrap: wrap;
173505
- gap: var(--rb-gap-sm, 0.75rem);
173506
- }
173507
-
173508
- :where(.theme-scope) .newsletter-inline .newsletter-field {
173509
- flex: 1 1 auto;
173510
- min-width: 10rem;
173511
- }
173512
-
173513
- :where(.theme-scope) .newsletter-inline .newsletter-submit {
173514
- margin-top: 0;
173515
- flex-shrink: 0;
173516
- }
173517
-
173518
- :where(.theme-scope) .newsletter-inline .newsletter-topics {
173519
- flex-basis: 100%;
173899
+ :where(.theme-scope) .newsletter-inline .newsletter-form {
173900
+ max-width: 40rem;
173901
+ margin-left: 0;
173902
+ margin-right: 0;
173520
173903
  }
173521
173904
 
173522
- /* Mobile fallback for inline variant */
173523
- @container rb-site (max-width: 640px) {
173524
- @scope ([data-rb-responsive-mode="container"]) to (:scope [data-rb-responsive-mode]) {
173525
- :where(.theme-scope) .newsletter-inline .newsletter-form-fields {
173526
- flex-direction: column;
173527
- }
173528
-
173529
- :where(.theme-scope) .newsletter-inline .newsletter-field {
173530
- min-width: 100%;
173531
- }
173532
- }
173905
+ :where(.theme-scope) .newsletter-inline .newsletter-privacy-note {
173906
+ text-align: left;
173533
173907
  }
173534
173908
 
173535
173909
  /* =============================================================================
@@ -173667,12 +174041,6 @@ const containerResponsiveThemeCss = `/*
173667
174041
  margin: 0;
173668
174042
  }
173669
174043
 
173670
- :where(.theme-scope) :where([data-block="contact-newsletter"]) .fb-inline {
173671
- display: flex;
173672
- align-items: center;
173673
- gap: 0.5rem;
173674
- }
173675
-
173676
174044
  :where(.theme-scope) :where([data-block="contact-newsletter"]) .fb-success,
173677
174045
  :where(.theme-scope) :where([data-block="contact-newsletter"]) .fb-error,
173678
174046
  :where(.theme-scope) :where([data-block="contact-newsletter"]) .fb-empty {
@@ -175569,6 +175937,44 @@ const containerResponsiveThemeCss = `/*
175569
175937
  flex: 0 0 auto;
175570
175938
  }
175571
175939
  }
175940
+ }
175941
+
175942
+ /* =============================================================================
175943
+ * Site footer: social links
175944
+ *
175945
+ * Icon links get a 40px tap target with a hairline ring drawn from the link's
175946
+ * own colour, so it follows the footer's text colour on any surface. Links
175947
+ * without an icon (unknown platforms) stay plain text.
175948
+ * =============================================================================
175949
+ */
175950
+
175951
+ :where(.theme-scope) .rb-footer-socials {
175952
+ display: flex;
175953
+ flex-wrap: wrap;
175954
+ align-items: center;
175955
+ gap: 0.75rem 1.25rem;
175956
+ }
175957
+
175958
+ :where(.theme-scope) .rb-footer-social-link:has(> .rb-footer-social-icon) {
175959
+ display: inline-grid;
175960
+ place-items: center;
175961
+ width: 2.5rem;
175962
+ height: 2.5rem;
175963
+ border: 1px solid color-mix(in srgb, currentColor 22%, transparent);
175964
+ border-radius: 9999px;
175965
+ }
175966
+
175967
+ :where(.theme-scope) .rb-footer-socials:has(.rb-footer-social-icon) {
175968
+ gap: 0.5rem;
175969
+ }
175970
+
175971
+ :where(.theme-scope) .rb-footer-social-link:has(> .rb-footer-social-icon):hover {
175972
+ border-color: currentColor;
175973
+ }
175974
+
175975
+ :where(.theme-scope) .rb-footer-social-icon {
175976
+ width: 1.5rem;
175977
+ height: 1.5rem;
175572
175978
  }`;
175573
175979
  //#endregion
175574
175980
  //#region ../theme-core/src/ThemeScopeCore.tsx
@@ -187655,6 +188061,28 @@ z.discriminatedUnion("requirementId", [z.object({ requirementId: z.literal("revi
187655
188061
  })]);
187656
188062
  z.object({ acceptExtraSiteCharge: z.boolean().optional() });
187657
188063
  //#endregion
188064
+ //#region ../api/src/launchRequirementPriority.ts
188065
+ const REQUIREMENT_PRIORITIES = {
188066
+ confirm_email: "required",
188067
+ review_generated_site: "required",
188068
+ configure_appointments: "required",
188069
+ configure_events: "required",
188070
+ configure_courses: "recommended",
188071
+ connect_payments: "required",
188072
+ connect_custom_domain: "optional",
188073
+ add_first_offering: "recommended",
188074
+ add_cover_image: "recommended",
188075
+ add_public_contact: "recommended"
188076
+ };
188077
+ /** A booking page can go live with bookings setup still unfinished. */
188078
+ const HOSTED_BOOKING_PRIORITIES = {
188079
+ configure_appointments: "recommended",
188080
+ configure_events: "recommended"
188081
+ };
188082
+ function requirementPriorityFor(id, publicExperience = "website") {
188083
+ return (publicExperience === "hosted_booking" ? HOSTED_BOOKING_PRIORITIES[id] : void 0) ?? REQUIREMENT_PRIORITIES[id];
188084
+ }
188085
+ //#endregion
187658
188086
  //#region ../api/src/launchReadiness.ts
187659
188087
  const DEFAULT_LAUNCH_READINESS_INPUT = {
187660
188088
  siteId: null,
@@ -187665,6 +188093,9 @@ const DEFAULT_LAUNCH_READINESS_INPUT = {
187665
188093
  courses: { kind: "not_applicable" },
187666
188094
  payments: { kind: "not_applicable" },
187667
188095
  customDomain: { kind: "pending_setup" },
188096
+ offerings: { kind: "none" },
188097
+ coverImage: { kind: "missing" },
188098
+ publicContact: { kind: "missing" },
187668
188099
  overrides: []
187669
188100
  };
187670
188101
  function makeDashboardPath(siteId, path) {
@@ -187698,8 +188129,34 @@ function evidenceFromDerivedState(state) {
187698
188129
  reason: "pending_setup"
187699
188130
  };
187700
188131
  }
187701
- function requirement(input) {
187702
- return input;
188132
+ function requirement(publicExperience, input) {
188133
+ return {
188134
+ ...input,
188135
+ priority: requirementPriorityFor(input.id, publicExperience)
188136
+ };
188137
+ }
188138
+ /** The shared fields of a requirement derived from a done/not-done fact. */
188139
+ function derivedFields(context, spec) {
188140
+ const state = spec.complete ? "complete" : "pending";
188141
+ const [title, description] = spec.copy[state];
188142
+ return {
188143
+ packId: spec.packId,
188144
+ owner: "admin",
188145
+ title,
188146
+ description,
188147
+ action: openDashboardPathAction(context.siteId, spec.path, spec.actionLabel),
188148
+ evidence: evidenceFromDerivedState(state)
188149
+ };
188150
+ }
188151
+ function derivedRequirement(context, spec) {
188152
+ return requirement(context.publicExperience, {
188153
+ ...derivedFields(context, spec),
188154
+ id: spec.id,
188155
+ state: spec.complete ? "complete" : "pending"
188156
+ });
188157
+ }
188158
+ function onlyForBookingPages(context, build) {
188159
+ return context.publicExperience === "hosted_booking" ? [build()] : [];
187703
188160
  }
187704
188161
  function buildGoLiveDecision(requirements) {
187705
188162
  const pendingRequiredRequirements = requirements.filter((item) => item.priority === "required" && item.state === "pending");
@@ -187726,10 +188183,9 @@ function deriveLaunchDomainRequirement(siteId, domainState) {
187726
188183
  check_unavailable: ["Domain connection check unavailable", "We couldn’t check your domain connection. Open Domains to check again."]
187727
188184
  }[domainState.kind];
187728
188185
  const state = domainState.kind === "connected" ? "complete" : "pending";
187729
- return requirement({
188186
+ return requirement("website", {
187730
188187
  id: "connect_custom_domain",
187731
188188
  packId: "domain",
187732
- priority: "optional",
187733
188189
  owner: "admin",
187734
188190
  state,
187735
188191
  title,
@@ -187741,13 +188197,28 @@ function deriveLaunchDomainRequirement(siteId, domainState) {
187741
188197
  } : evidenceFromDerivedState(state)
187742
188198
  });
187743
188199
  }
187744
- function generatedSiteReviewRequirements(input) {
187745
- if (input.publicExperience === "hosted_booking") return [];
187746
- const isGeneratedSiteReviewed = input.reviewGeneratedSite.kind === "reviewed";
187747
- return [requirement({
188200
+ function customDomainRequirements(context, domainState) {
188201
+ return context.publicExperience === "hosted_booking" ? [] : [deriveLaunchDomainRequirement(context.siteId, domainState)];
188202
+ }
188203
+ function confirmEmailRequirement(context, email) {
188204
+ const state = email.kind === "confirmed" ? "complete" : "pending";
188205
+ return requirement(context.publicExperience, {
188206
+ id: "confirm_email",
188207
+ packId: "core",
188208
+ state,
188209
+ owner: "either",
188210
+ title: "Confirm your email",
188211
+ description: state === "complete" ? "Email confirmed. Your dashboard and launch path are unlocked." : "Confirm your email before the site can go live.",
188212
+ action: informationalAction("Confirm your email"),
188213
+ evidence: evidenceFromDerivedState(state)
188214
+ });
188215
+ }
188216
+ function generatedSiteReviewRequirements(context, reviewGeneratedSite) {
188217
+ if (context.publicExperience === "hosted_booking") return [];
188218
+ const isGeneratedSiteReviewed = reviewGeneratedSite.kind === "reviewed";
188219
+ return [requirement(context.publicExperience, {
187748
188220
  id: "review_generated_site",
187749
188221
  packId: "core",
187750
- priority: "required",
187751
188222
  state: isGeneratedSiteReviewed ? "complete" : "pending",
187752
188223
  owner: "admin",
187753
188224
  title: "Check your pages",
@@ -187760,102 +188231,214 @@ function generatedSiteReviewRequirements(input) {
187760
188231
  },
187761
188232
  evidence: isGeneratedSiteReviewed ? {
187762
188233
  kind: "acknowledged",
187763
- acknowledgedAt: input.reviewGeneratedSite.reviewedAt,
187764
- acknowledgedBy: input.reviewGeneratedSite.reviewedBy
188234
+ acknowledgedAt: reviewGeneratedSite.reviewedAt,
188235
+ acknowledgedBy: reviewGeneratedSite.reviewedBy
187765
188236
  } : {
187766
188237
  kind: "deferred",
187767
188238
  reason: "pending_acknowledgement"
187768
188239
  }
187769
188240
  })];
187770
188241
  }
187771
- function deriveLaunchReadiness(input) {
187772
- const siteId = input.siteId ?? null;
187773
- const overrides = input.overrides ?? [];
187774
- const appointmentOverrideDefinition = LAUNCH_REQUIREMENT_OVERRIDE_DEFINITIONS.configure_appointments;
187775
- const requirements = [];
187776
- const confirmEmailState = input.email.kind === "confirmed" ? "complete" : "pending";
187777
- requirements.push(requirement({
187778
- id: "confirm_email",
187779
- packId: "core",
187780
- priority: "required",
187781
- state: confirmEmailState,
187782
- owner: "either",
187783
- title: "Confirm your email",
187784
- description: confirmEmailState === "complete" ? "Email confirmed. Your dashboard and launch path are unlocked." : "Confirm your email before the site can go live.",
187785
- action: informationalAction("Confirm your email"),
187786
- evidence: evidenceFromDerivedState(confirmEmailState)
187787
- }));
187788
- requirements.push(...generatedSiteReviewRequirements(input));
187789
- if (input.appointments.kind !== "disabled") {
187790
- const appointmentsOverride = input.appointments.kind === "pending_setup" ? findLaunchOverride(overrides, appointmentOverrideDefinition.requirementId) : null;
187791
- requirements.push(requirement({
187792
- id: "configure_appointments",
187793
- packId: "bookings_appointments",
187794
- priority: "required",
187795
- state: input.appointments.kind === "ready" ? "complete" : "pending",
187796
- owner: "admin",
187797
- title: "Configure appointments",
187798
- description: input.appointments.kind === "ready" ? "Appointments have at least one bookable service with a practitioner and availability." : appointmentsOverride ? "Appointment setup is still unfinished. You chose to launch anyway and finish it later." : "Finish appointment setup so customers can book at least one service before launch, or launch anyway and come back later.",
187799
- action: openDashboardPathAction(siteId, input.appointments.kind === "pending_setup" ? appendQueryString("/bookings/appointments/setup", {
187800
- step: input.appointments.targetStep,
187801
- returnTo: "launch"
187802
- }) : "/bookings/services", "Set up appointments"),
187803
- secondaryAction: input.appointments.kind === "pending_setup" ? appointmentsOverride ? informationalAction("Launch override saved") : {
187804
- kind: "acknowledge_requirement",
187805
- label: "Launch anyway",
187806
- requirementId: appointmentOverrideDefinition.requirementId,
187807
- acknowledgementKind: "override",
187808
- overrideReason: appointmentOverrideDefinition.reason
187809
- } : null,
187810
- evidence: appointmentsOverride ? {
187811
- kind: "overridden",
187812
- reason: appointmentsOverride.reason,
187813
- acknowledgedAt: appointmentsOverride.acknowledgedAt,
187814
- acknowledgedBy: appointmentsOverride.acknowledgedBy
187815
- } : evidenceFromDerivedState(input.appointments.kind === "ready" ? "complete" : "pending")
187816
- }));
187817
- }
187818
- if (input.events.kind !== "disabled") requirements.push(requirement({
187819
- id: "configure_events",
187820
- packId: "bookings_events",
187821
- priority: "required",
187822
- state: input.events.kind === "ready" ? "complete" : "pending",
188242
+ /** Booking pages have no "launch anyway": appointments never block them. */
188243
+ function appointmentsOverrideFor(context, input) {
188244
+ if (context.publicExperience === "hosted_booking" || input.appointments.kind !== "pending_setup") return null;
188245
+ return findLaunchOverride(input.overrides ?? [], LAUNCH_REQUIREMENT_OVERRIDE_DEFINITIONS.configure_appointments.requirementId);
188246
+ }
188247
+ function appointmentsSecondaryAction(context, appointments, override) {
188248
+ if (appointments.kind !== "pending_setup" || context.publicExperience === "hosted_booking") return null;
188249
+ if (override) return informationalAction("Launch override saved");
188250
+ const definition = LAUNCH_REQUIREMENT_OVERRIDE_DEFINITIONS.configure_appointments;
188251
+ return {
188252
+ kind: "acknowledge_requirement",
188253
+ label: "Launch anyway",
188254
+ requirementId: definition.requirementId,
188255
+ acknowledgementKind: "override",
188256
+ overrideReason: definition.reason
188257
+ };
188258
+ }
188259
+ function appointmentsDescription(appointments, override) {
188260
+ if (appointments.kind === "ready") return "Appointments have at least one bookable service with a practitioner and availability.";
188261
+ return override ? "Appointment setup is still unfinished. You chose to launch anyway and finish it later." : "Finish appointment setup so customers can book at least one service before launch, or launch anyway and come back later.";
188262
+ }
188263
+ function appointmentsRequirements(context, input) {
188264
+ const appointments = input.appointments;
188265
+ if (appointments.kind === "disabled") return [];
188266
+ const override = appointmentsOverrideFor(context, input);
188267
+ const state = appointments.kind === "ready" ? "complete" : "pending";
188268
+ const path = appointments.kind === "pending_setup" ? appendQueryString("/bookings/appointments/setup", {
188269
+ step: appointments.targetStep,
188270
+ returnTo: "launch"
188271
+ }) : "/bookings/services";
188272
+ const evidence = override ? {
188273
+ kind: "overridden",
188274
+ reason: override.reason,
188275
+ acknowledgedAt: override.acknowledgedAt,
188276
+ acknowledgedBy: override.acknowledgedBy
188277
+ } : evidenceFromDerivedState(state);
188278
+ const fields = {
188279
+ packId: "bookings_appointments",
187823
188280
  owner: "admin",
187824
- title: "Configure events",
187825
- description: input.events.kind === "ready" ? "Events already include at least one future-dated offering." : "Create at least one future-dated event offering before launch.",
187826
- action: openDashboardPathAction(siteId, "/bookings/events/new", "Create an event"),
187827
- evidence: evidenceFromDerivedState(input.events.kind === "ready" ? "complete" : "pending")
187828
- }));
187829
- if (input.courses.kind !== "not_applicable") requirements.push(requirement({
188281
+ title: "Configure appointments",
188282
+ description: appointmentsDescription(appointments, override),
188283
+ action: openDashboardPathAction(context.siteId, path, "Set up appointments"),
188284
+ secondaryAction: appointmentsSecondaryAction(context, appointments, override),
188285
+ evidence
188286
+ };
188287
+ return [requirement(context.publicExperience, appointments.kind === "pending_setup" ? {
188288
+ ...fields,
188289
+ id: "configure_appointments",
188290
+ state: "pending",
188291
+ detail: {
188292
+ kind: "appointments_gap",
188293
+ missing: appointments.missing
188294
+ }
188295
+ } : {
188296
+ ...fields,
188297
+ id: "configure_appointments",
188298
+ state: "complete"
188299
+ })];
188300
+ }
188301
+ function eventsRequirements(context, events) {
188302
+ if (events.kind === "disabled") return [];
188303
+ const fields = derivedFields(context, {
188304
+ packId: "bookings_events",
188305
+ complete: events.kind === "ready",
188306
+ copy: {
188307
+ complete: ["Configure events", "Events already include at least one future-dated offering."],
188308
+ pending: ["Configure events", "Create at least one future-dated event offering before launch."]
188309
+ },
188310
+ path: "/bookings/events/new",
188311
+ actionLabel: "Create an event"
188312
+ });
188313
+ return [requirement(context.publicExperience, events.kind === "pending_setup" ? {
188314
+ ...fields,
188315
+ id: "configure_events",
188316
+ state: "pending",
188317
+ detail: {
188318
+ kind: "event_kinds",
188319
+ offeredKinds: events.offeredKinds
188320
+ }
188321
+ } : {
188322
+ ...fields,
188323
+ id: "configure_events",
188324
+ state: "complete"
188325
+ })];
188326
+ }
188327
+ function coursesRequirements(context, courses) {
188328
+ if (courses.kind === "not_applicable") return [];
188329
+ return [derivedRequirement(context, {
187830
188330
  id: "configure_courses",
187831
188331
  packId: "bookings_courses",
187832
- priority: "recommended",
187833
- state: input.courses.kind === "ready" ? "complete" : "pending",
187834
- owner: "admin",
187835
- title: "Configure courses",
187836
- description: input.courses.kind === "ready" ? "Courses already include at least one real course run." : "You chose courses during setup. Add your first course when you're ready so the dashboard reflects that plan.",
187837
- action: openDashboardPathAction(siteId, "/bookings/events/new/course", "Create a course"),
187838
- evidence: evidenceFromDerivedState(input.courses.kind === "ready" ? "complete" : "pending")
187839
- }));
187840
- if (input.payments.kind !== "not_applicable") requirements.push(requirement({
187841
- id: "connect_payments",
188332
+ complete: courses.kind === "ready",
188333
+ copy: {
188334
+ complete: ["Configure courses", "Courses already include at least one real course run."],
188335
+ pending: ["Configure courses", "You chose courses during setup. Add your first course when you're ready so the dashboard reflects that plan."]
188336
+ },
188337
+ path: "/bookings/events/new/course",
188338
+ actionLabel: "Create a course"
188339
+ })];
188340
+ }
188341
+ function paymentsRequirements(context, payments) {
188342
+ if (payments.kind === "not_applicable") return [];
188343
+ const fields = derivedFields(context, {
187842
188344
  packId: "payments",
187843
- priority: "required",
187844
- state: input.payments.kind === "ready" ? "complete" : "pending",
187845
- owner: "admin",
187846
- title: "Connect payments",
187847
- description: input.payments.kind === "ready" ? "Stripe is connected and ready for paid bookings." : "Connect Stripe before visitors can pay for paid bookings online.",
187848
- action: openDashboardPathAction(siteId, "/money/settings", "Connect payments"),
187849
- evidence: evidenceFromDerivedState(input.payments.kind === "ready" ? "complete" : "pending")
188345
+ complete: payments.kind === "ready",
188346
+ copy: {
188347
+ complete: ["Connect payments", "Stripe is connected and ready for paid bookings."],
188348
+ pending: ["Connect payments", "Connect Stripe before visitors can pay for paid bookings online."]
188349
+ },
188350
+ path: "/money/settings",
188351
+ actionLabel: "Connect payments"
188352
+ });
188353
+ return [requirement(context.publicExperience, payments.kind === "ready" ? {
188354
+ ...fields,
188355
+ id: "connect_payments",
188356
+ state: "complete"
188357
+ } : {
188358
+ ...fields,
188359
+ id: "connect_payments",
188360
+ state: "pending",
188361
+ detail: {
188362
+ kind: "payments_gap",
188363
+ stage: payments.kind
188364
+ }
188365
+ })];
188366
+ }
188367
+ function firstOfferingRequirements(context, offerings) {
188368
+ return onlyForBookingPages(context, () => derivedRequirement(context, {
188369
+ id: "add_first_offering",
188370
+ packId: "offerings",
188371
+ complete: offerings.kind === "has_offerings",
188372
+ copy: {
188373
+ complete: ["First offering added", "Your page has something people can book."],
188374
+ pending: ["Add your first offering", "Your page is ready for something people can book: a class, a course or a private session."]
188375
+ },
188376
+ path: "/bookings",
188377
+ actionLabel: "Add an offering"
187850
188378
  }));
187851
- requirements.push(deriveLaunchDomainRequirement(siteId, input.customDomain));
187852
- const goLiveDecision = buildGoLiveDecision(requirements);
188379
+ }
188380
+ function publicContactRequirements(context, publicContact) {
188381
+ return onlyForBookingPages(context, () => derivedRequirement(context, {
188382
+ id: "add_public_contact",
188383
+ packId: "presence",
188384
+ complete: publicContact.kind === "published",
188385
+ copy: {
188386
+ complete: ["Contact details added", "Your page shows a way to reach you."],
188387
+ pending: ["Add a way to reach you", "Your page doesn't show an email or phone number yet, so people can't ask a question before they book."]
188388
+ },
188389
+ path: "/settings/business",
188390
+ actionLabel: "Add contact details"
188391
+ }));
188392
+ }
188393
+ function coverImageRequirements(context, coverImage) {
188394
+ return onlyForBookingPages(context, () => derivedRequirement(context, {
188395
+ id: "add_cover_image",
188396
+ packId: "presence",
188397
+ complete: coverImage.kind === "set",
188398
+ copy: {
188399
+ complete: ["Cover photo added", "Your page has a cover photo."],
188400
+ pending: ["Add a cover photo", "A photo of your space or your work sits at the top of your page. It works without one, but a photo makes it feel like yours."]
188401
+ },
188402
+ path: "/settings/general",
188403
+ actionLabel: "Add a photo"
188404
+ }));
188405
+ }
188406
+ /**
188407
+ * While a booking page has nothing to offer, "Add your first offering" stands
188408
+ * in for the per-kind setup items, so a new owner sees one place to start.
188409
+ * Lives here, not in a presentation, so every count agrees with the list.
188410
+ */
188411
+ function isSupersededByFirstOffering(input, id) {
188412
+ if (input.publicExperience !== "hosted_booking" || input.offerings.kind !== "none") return false;
188413
+ if (id === "configure_events" || id === "configure_courses") return true;
188414
+ return id === "configure_appointments" && input.appointments.kind === "pending_setup" && input.appointments.missing === "not_started";
188415
+ }
188416
+ function countPending(requirements, priority) {
188417
+ return requirements.filter((item) => item.priority === priority && item.state === "pending").length;
188418
+ }
188419
+ function deriveLaunchReadiness(input) {
188420
+ const context = {
188421
+ siteId: input.siteId ?? null,
188422
+ publicExperience: input.publicExperience ?? "website"
188423
+ };
188424
+ const requirements = [
188425
+ confirmEmailRequirement(context, input.email),
188426
+ ...generatedSiteReviewRequirements(context, input.reviewGeneratedSite),
188427
+ ...firstOfferingRequirements(context, input.offerings),
188428
+ ...appointmentsRequirements(context, input),
188429
+ ...eventsRequirements(context, input.events),
188430
+ ...coursesRequirements(context, input.courses),
188431
+ ...paymentsRequirements(context, input.payments),
188432
+ ...publicContactRequirements(context, input.publicContact),
188433
+ ...coverImageRequirements(context, input.coverImage),
188434
+ ...customDomainRequirements(context, input.customDomain)
188435
+ ].filter((item) => !isSupersededByFirstOffering(input, item.id));
187853
188436
  return {
187854
188437
  requirements,
187855
- pendingRequiredCount: requirements.filter((item) => item.priority === "required" && item.state === "pending").length,
187856
- pendingRecommendedCount: requirements.filter((item) => item.priority === "recommended" && item.state === "pending").length,
187857
- pendingOptionalCount: requirements.filter((item) => item.priority === "optional" && item.state === "pending").length,
187858
- goLiveDecision
188438
+ pendingRequiredCount: countPending(requirements, "required"),
188439
+ pendingRecommendedCount: countPending(requirements, "recommended"),
188440
+ pendingOptionalCount: countPending(requirements, "optional"),
188441
+ goLiveDecision: buildGoLiveDecision(requirements)
187859
188442
  };
187860
188443
  }
187861
188444
  //#endregion
@@ -188874,6 +189457,7 @@ async function updateRouteMetadata(apiClient, { siteId, routeId, body, options }
188874
189457
  return normalizeApiError(error, "Failed to update route metadata");
188875
189458
  }
188876
189459
  }
189460
+ z.enum(["public", "unlisted"], { error: "visibility must be 'public' or 'unlisted'" });
188877
189461
  //#endregion
188878
189462
  //#region ../api/src/bookingPaymentTermSchemas.ts
188879
189463
  const bookingDepositRefundPolicySchema = z.enum(["refundable", "non_refundable"]);
@@ -192399,7 +192983,7 @@ const WIDGET_COMPONENTS = {
192399
192983
  text: TextField$1,
192400
192984
  inlineText: InlineTextField$1,
192401
192985
  number: NumberField,
192402
- select: SelectField,
192986
+ select: SelectField$1,
192403
192987
  sdkSelect: SdkSelectField,
192404
192988
  boolean: BooleanField,
192405
192989
  group: GroupField,
@@ -195694,6 +196278,23 @@ function assertNever$1(value, message) {
195694
196278
  throw new Error(message ?? `Unexpected value: ${String(value)}`);
195695
196279
  }
195696
196280
  //#endregion
196281
+ //#region ../content-editor/src/ui/editorBlockEquality.ts
196282
+ function sameBlockIdentity(left, right) {
196283
+ return left.id === right.id && left.draftContentId === right.draftContentId && left.publishedContentId === right.publishedContentId && left.kind === right.kind && left.orderIndex === right.orderIndex && left.purpose === right.purpose && left.optimisticHash === right.optimisticHash;
196284
+ }
196285
+ function sameBlockValues(left, right) {
196286
+ return recordsEqual(left.content, right.content) && recordsEqual(left.draftContent, right.draftContent) && recordsEqual(left.publishedContent, right.publishedContent) && recordsEqual(left.bindings, right.bindings);
196287
+ }
196288
+ function normalizedBlockEqual(left, right) {
196289
+ return sameBlockIdentity(left, right) && sameBlockValues(left, right);
196290
+ }
196291
+ function normalizedBlocksEqual(left, right) {
196292
+ return left.length === right.length && left.every((block, index) => {
196293
+ const other = right[index];
196294
+ return other !== void 0 && normalizedBlockEqual(block, other);
196295
+ });
196296
+ }
196297
+ //#endregion
195697
196298
  //#region ../content-editor/src/ui/editorSnapshot.ts
195698
196299
  function deriveEditorValuePublicationState(snapshot) {
195699
196300
  const current = snapshot.current ?? snapshot.baseline;
@@ -195947,7 +196548,8 @@ function normalizeEditorBlockId(value) {
195947
196548
  function normalizeEditorBlock(block) {
195948
196549
  return {
195949
196550
  id: normalizeEditorBlockId(block.id),
195950
- contentVersionId: block.contentVersionId ?? null,
196551
+ draftContentId: block.draftContentId ?? null,
196552
+ publishedContentId: block.publishedContentId ?? null,
195951
196553
  kind: block.kind,
195952
196554
  content: cloneBlockValues(block.content ?? null),
195953
196555
  orderIndex: block.orderIndex ?? null,
@@ -195961,35 +196563,13 @@ function normalizeEditorBlock(block) {
195961
196563
  function normalizeEditorBlockList(blocks) {
195962
196564
  return blocks.map((block) => normalizeEditorBlock(block));
195963
196565
  }
195964
- function normalizedBlocksEqual(left, right) {
195965
- if (left.length !== right.length) return false;
195966
- for (let index = 0; index < left.length; index += 1) {
195967
- const leftBlock = left[index];
195968
- const rightBlock = right[index];
195969
- if (!leftBlock || !rightBlock) return false;
195970
- if (leftBlock.id !== rightBlock.id) return false;
195971
- if (leftBlock.contentVersionId !== rightBlock.contentVersionId) return false;
195972
- if (leftBlock.kind !== rightBlock.kind) return false;
195973
- if (leftBlock.orderIndex !== rightBlock.orderIndex) return false;
195974
- if (leftBlock.purpose !== rightBlock.purpose) return false;
195975
- if (!recordsEqual(leftBlock.content, rightBlock.content)) return false;
195976
- if (!recordsEqual(leftBlock.draftContent, rightBlock.draftContent)) return false;
195977
- if (!recordsEqual(leftBlock.publishedContent, rightBlock.publishedContent)) return false;
195978
- if (!recordsEqual(leftBlock.bindings, rightBlock.bindings)) return false;
195979
- if (leftBlock.optimisticHash !== rightBlock.optimisticHash) return false;
195980
- }
195981
- return true;
195982
- }
195983
196566
  function updatePersistedBlockInList(blockList, blockId, updater) {
195984
- let changed = false;
195985
196567
  const nextBlockList = blockList.map((block) => {
195986
196568
  if (block.id !== blockId || !isPersistedBlock(block)) return block;
195987
196569
  const nextBlock = updater(block);
195988
- if (nextBlock.kind === block.kind && nextBlock.orderIndex === block.orderIndex && nextBlock.purpose === block.purpose && recordsEqual(nextBlock.content, block.content) && recordsEqual(nextBlock.draftContent, block.draftContent) && recordsEqual(nextBlock.publishedContent, block.publishedContent) && recordsEqual(nextBlock.bindings, block.bindings) && nextBlock.optimisticHash === block.optimisticHash) return block;
195989
- changed = true;
195990
- return nextBlock;
196570
+ return normalizedBlockEqual(nextBlock, block) ? block : nextBlock;
195991
196571
  });
195992
- return changed ? nextBlockList : blockList;
196572
+ return nextBlockList.every((block, index) => block === blockList[index]) ? blockList : nextBlockList;
195993
196573
  }
195994
196574
  function editorBlockListsEqual(left, right) {
195995
196575
  return normalizedBlocksEqual(normalizeEditorBlockList(left), normalizeEditorBlockList(right));
@@ -199049,15 +199629,23 @@ function EnhancedBlockPickerDialog({ open, onOpenChange, creatingBlockName, desc
199049
199629
  }
199050
199630
  //#endregion
199051
199631
  //#region ../editor-blocks/src/block-editor/EmptyState.tsx
199052
- const EmptyState = ({ onAdd }) => /* @__PURE__ */ jsx(EmptyState$2, {
199053
- title: "No blocks yet",
199054
- description: "Add your first block to start building this page.",
199632
+ const DEFAULT_BLOCK_CREATION_COPY = {
199633
+ emptyTitle: "No blocks yet",
199634
+ emptyDescription: "Add your first block to start building this page.",
199635
+ addLabel: "Add block"
199636
+ };
199637
+ function addBlockLabel(copy) {
199638
+ return (copy ?? DEFAULT_BLOCK_CREATION_COPY).addLabel;
199639
+ }
199640
+ const EmptyState = ({ onAdd, copy = DEFAULT_BLOCK_CREATION_COPY }) => /* @__PURE__ */ jsx(EmptyState$2, {
199641
+ title: copy.emptyTitle,
199642
+ description: copy.emptyDescription,
199055
199643
  className: "p-6",
199056
199644
  action: /* @__PURE__ */ jsxs(Button$1, {
199057
199645
  type: "button",
199058
199646
  variant: "secondary",
199059
199647
  onClick: onAdd,
199060
- children: [/* @__PURE__ */ jsx(Plus, { className: "mr-2 h-4 w-4" }), "Add block"]
199648
+ children: [/* @__PURE__ */ jsx(Plus, { className: "mr-2 h-4 w-4" }), copy.addLabel]
199061
199649
  })
199062
199650
  });
199063
199651
  //#endregion
@@ -199200,14 +199788,22 @@ const reindexBlockList = (items) => items.map((block, index) => ({
199200
199788
  function toEditorBlockValues(value) {
199201
199789
  return value ? unsafeAsEditorBlockValues(value) : null;
199202
199790
  }
199791
+ function insertBlockContent(block, draftContent, publishedContent) {
199792
+ return {
199793
+ baseline: draftContent ?? block.draftContent ?? block.content ?? null,
199794
+ published: publishedContent ?? block.publishedContent ?? null
199795
+ };
199796
+ }
199203
199797
  function buildInsertBlockHistoryCommand({ block, index, draftContent, publishedContent }) {
199204
199798
  if (!block.id) return null;
199205
199799
  const blockId = unsafeAsEditorBlockId(block.id);
199206
- const purpose = typeof block.purpose === "string" ? block.purpose ?? null : "content";
199207
- const baseline = draftContent ?? block.draftContent ?? block.content ?? null;
199208
- const nextPublishedContent = publishedContent ?? block.publishedContent ?? null;
199800
+ const purpose = block.purpose ?? "content";
199801
+ const { draftContentId = null, publishedContentId = null } = block;
199802
+ const { baseline, published: nextPublishedContent } = insertBlockContent(block, draftContent, publishedContent);
199209
199803
  return createEditorInsertBlockCommand({
199210
199804
  id: blockId,
199805
+ draftContentId,
199806
+ publishedContentId,
199211
199807
  kind: block.kind,
199212
199808
  content: toEditorBlockValues(block.content ?? null),
199213
199809
  orderIndex: index,
@@ -201618,7 +202214,7 @@ function getGeneratedIconSetErrorMessage(error) {
201618
202214
  const message = getApiRequestErrorMessage(error);
201619
202215
  return message === "Internal server error" || /^Request to .+ failed with status \d+$/u.test(message) ? GENERATED_ICON_SET_FRIENDLY_ERROR : message;
201620
202216
  }
201621
- const BlockEditor = forwardRef(function BlockEditor({ siteId, dashboardBaseUrl, owner, blocks, recoveryConflictBlockIds = [], recoveryConflictReviewRequestId = null, apiClient, uiStore, enableReordering = true, enableCreation = true, enableDeletion = true, onBlockSave, onBlocksChange, onStructuralRevisionChange, theme, widgetOverrides, headerLeftSlot, hideThemeV2RawStyleFields = false, pageDesignEditorModel = null, enabledContentTypes = [], sdkConfig = null, customBlocks = [], allowedBlockKinds = null, emptyUnavailableMessage = "No blocks available for this page.", initialCollapsed = true, reorderControlMode = DEFAULT_REORDER_CONTROL_MODE, actionPresentation = DEFAULT_BLOCK_ACTION_PRESENTATION }, ref) {
202217
+ const BlockEditor = forwardRef(function BlockEditor({ siteId, dashboardBaseUrl, owner, blocks, recoveryConflictBlockIds = [], recoveryConflictReviewRequestId = null, apiClient, uiStore, enableReordering = true, enableCreation = true, enableDeletion = true, onBlockSave, onBlocksChange, onStructuralRevisionChange, theme, widgetOverrides, headerLeftSlot, hideThemeV2RawStyleFields = false, pageDesignEditorModel = null, enabledContentTypes = [], sdkConfig = null, customBlocks = [], allowedBlockKinds = null, emptyUnavailableMessage = "No blocks available for this page.", creationCopy, initialCollapsed = true, reorderControlMode = DEFAULT_REORDER_CONTROL_MODE, actionPresentation = DEFAULT_BLOCK_ACTION_PRESENTATION }, ref) {
201622
202218
  const [blockList, setBlockList] = useState(() => normalizeBlockListInitial(blocks));
201623
202219
  const [errorMessage, setErrorMessage] = useState(null);
201624
202220
  const [highlightedBlockId, setHighlightedBlockId] = useState(null);
@@ -202110,7 +202706,10 @@ const BlockEditor = forwardRef(function BlockEditor({ siteId, dashboardBaseUrl,
202110
202706
  }) : hasBlocks ? /* @__PURE__ */ jsx("div", {
202111
202707
  className: "rounded-md border border-dashed px-4 py-6 text-center text-sm text-muted-foreground",
202112
202708
  children: "Loading block editor..."
202113
- }) : canCreateBlocks ? /* @__PURE__ */ jsx(EmptyState, { onAdd: () => openPicker(0) }) : /* @__PURE__ */ jsx("div", {
202709
+ }) : canCreateBlocks ? /* @__PURE__ */ jsx(EmptyState, {
202710
+ onAdd: () => openPicker(0),
202711
+ copy: creationCopy
202712
+ }) : /* @__PURE__ */ jsx("div", {
202114
202713
  className: "rounded-md border border-dashed px-4 py-6 text-center text-sm text-muted-foreground",
202115
202714
  children: emptyUnavailableMessage
202116
202715
  }),
@@ -202120,7 +202719,7 @@ const BlockEditor = forwardRef(function BlockEditor({ siteId, dashboardBaseUrl,
202120
202719
  type: "button",
202121
202720
  variant: "secondary",
202122
202721
  onClick: () => openPicker(blockList.length),
202123
- children: [/* @__PURE__ */ jsx(Plus, { className: "mr-2 h-4 w-4" }), "Add block"]
202722
+ children: [/* @__PURE__ */ jsx(Plus, { className: "mr-2 h-4 w-4" }), addBlockLabel(creationCopy)]
202124
202723
  })
202125
202724
  }) : null,
202126
202725
  canCreateBlocks ? /* @__PURE__ */ jsx(EnhancedBlockPickerDialog, {
@@ -227596,6 +228195,7 @@ function ContentFieldsForm({ siteId, manifest, form: formSpec, initialValues: _i
227596
228195
  children: formContent
227597
228196
  }) : formContent;
227598
228197
  }
228198
+ const PREVIEW_EDITABLE_OUTLINE = `1px dashed rgba(156, 163, 175, 0.75)`;
227599
228199
  //#endregion
227600
228200
  //#region ../content-editor/src/primitives/shared/storeBinding.ts
227601
228201
  const AI_OVERLAY_VERSION_MULTIPLIER = 1048576;
@@ -227795,7 +228395,7 @@ function PreviewTextEditor(props) {
227795
228395
  [data-rb-preview-text-editor]:hover,
227796
228396
  [data-rb-preview-text-editor][data-rb-preview-text-linked-focus="true"],
227797
228397
  [data-rb-preview-text-editor]:focus-visible {
227798
- outline: 1px dashed rgba(156, 163, 175, 0.75) !important;
228398
+ outline: ${PREVIEW_EDITABLE_OUTLINE} !important;
227799
228399
  outline-offset: 2px;
227800
228400
  }
227801
228401
  [data-rb-preview-text-editor][data-rb-preview-text-empty="true"]::before {
@@ -227991,7 +228591,6 @@ const PreviewRichTextEditorInner = ({ path, linkedEntryField, onLinkedEntryField
227991
228591
  version,
227992
228592
  lastSyncedVersion
227993
228593
  ]);
227994
- const previewBorderColor = "rgba(156, 163, 175, 0.75)";
227995
228594
  const showAffordance = isHovered || isFocused || isLinkedSidebarFocus;
227996
228595
  const resolvedClassName = className?.trim() || "rb-prose rb-max-w-none";
227997
228596
  return /* @__PURE__ */ jsxs(Comp, {
@@ -228036,7 +228635,7 @@ const PreviewRichTextEditorInner = ({ path, linkedEntryField, onLinkedEntryField
228036
228635
  "data-rb-preview-richtext-affordance": showAffordance ? "true" : void 0,
228037
228636
  className: `relative rounded cursor-text ${isEmpty ? "min-h-[30px]" : ""} ${showAffordance ? "bg-white/5" : "bg-transparent"}`,
228038
228637
  style: showAffordance ? {
228039
- outline: `1px dashed ${previewBorderColor}`,
228638
+ outline: PREVIEW_EDITABLE_OUTLINE,
228040
228639
  outlineOffset: "2px"
228041
228640
  } : void 0,
228042
228641
  children: content
@@ -229006,13 +229605,14 @@ const socialPlatformIcons = {
229006
229605
  instagram: "SocialInstagram",
229007
229606
  linkedin: "SocialLinkedIn",
229008
229607
  tiktok: "SocialTikTok",
229608
+ whatsapp: "SocialWhatsApp",
229009
229609
  x: "SocialX",
229010
229610
  youtube: "SocialYouTube"
229011
229611
  };
229012
229612
  function socialLinks(profile) {
229013
229613
  return profile.socialLinks.map((item) => ({
229014
229614
  href: item.url,
229015
- label: item.kind === "known" ? item.platform.replace(/^x$/u, "X") : item.label,
229615
+ label: item.kind === "known" ? knownSocialPlatformLabels[item.platform] : item.label,
229016
229616
  icon: item.kind === "known" ? socialPlatformIcons[item.platform] : null
229017
229617
  }));
229018
229618
  }
@@ -230100,14 +230700,10 @@ function SocialLinksEditor({ profile, onChange }) {
230100
230700
  ...item,
230101
230701
  platform: event.target.value
230102
230702
  } : item)),
230103
- children: [
230104
- "facebook",
230105
- "instagram",
230106
- "linkedin",
230107
- "tiktok",
230108
- "x",
230109
- "youtube"
230110
- ].map((platform) => /* @__PURE__ */ jsx("option", { children: platform }, platform))
230703
+ children: knownSocialPlatforms.map((platform) => /* @__PURE__ */ jsx("option", {
230704
+ value: platform,
230705
+ children: knownSocialPlatformLabels[platform]
230706
+ }, platform))
230111
230707
  }) : /* @__PURE__ */ jsx("input", {
230112
230708
  id,
230113
230709
  className: inputClass,
@@ -233074,4 +233670,4 @@ function useSiteChromeCustomizeOptional() {
233074
233670
  return useContext(SiteChromeCustomizeContext);
233075
233671
  }
233076
233672
  //#endregion
233077
- export { FooterComposerPanel as $, Tablet as $a, attachRenderableMediaAssetFields as $i, LINKED_CONTENT_ENTRY_META_KEY as $n, ctaButton as $r, useMultiAutosave as $t, markApplySaving as A, DialogContent as Aa, corners as Ai, containerResponsiveThemeCss as An, surfaceResolutionContextFromTheme as Ar, RichTextField as At, setPaletteColors as B, DropdownMenuContent as Ba, resolveButtonStyleSelection as Bi, compileManifestContentContract as Bn, autoDesignChoice as Br, getBlockManifestFromSdkConfig as Bt, cancelPreview as C, PopoverTrigger as Ca, BlockApiProvider as Ci, deriveLaunchReadiness as Cn, expectParsedBrandedId as Co, formatSiteChromeBackgroundTokenLabel as Cr, ButtonVariantField as Ct, isPreviewingChange as D, TabsList as Da, bookingConsentCarrierSchema as Di, useApiMediaUploader as Dn, curatedSiteStyles as Dr, ReferenceField as Dt, dismissWarnings as E, TabsContent as Ea, eventCalendarListLayoutOptions as Ei, useMediaEditorOptional as En, __exportAll as Eo, componentRuntimeRulesForTheme as Er, MediaField as Et, previewFooterLook as F, Collapsible as Fa, assertNever$7 as Fi, SITE_CHROME_VISIBLE_HEADER_SELECTOR as Fn, GRADIENT_PRESETS as Fr, LinkWidgetProvider as Ft, confirmAutosaveBatch as G, Primitive as Ga, defaultThemeTokens as Gi, escapeStyleContent as Gn, boundaryTreatmentForBoundaryOptionId as Gr, canRedoHistory as Gt, syncStyleConfiguratorState as H, DropdownMenuLabel as Ha, updateButtonStyleSelectionChoice as Hi, buildThemeRuntime as Hn, boundaryLayout as Hr, useEditorUiStore as Ht, previewHeaderLayout as I, CollapsibleContent as Ia, makeBoundaryId as Ii, SITE_OVERLAY_HEADER_CLEARANCE_CSS_VAR as In, GRADIENT_PRESET_IDS as Ir, BlockEditor as It, idleEditorTransactionQueueState as J, cn$2 as Ja, VARIANT_ROLES as Ji, getDefaultComponentRegistry as Jn, sectionTransitionFamilyForBoundaryOptionId as Jr, pushHistoryEntry as Jt, deriveTransactionCapabilities as K, Button$1 as Ka, parseThemeForPersistence as Ki, mergeContentWithBlockStyleOverrides as Kn, defaultSectionTransitionVariantForFamily as Kr, canUndoHistory as Kt, previewHeaderStyle as L, CollapsibleTrigger as La, buttonStyleHoverPreferenceValue as Li, planSiteOverlayHeaderClearance as Ln, getGradientPreset as Lr, hideThemeV2RawStyleFields as Lt, palettePreviewProjection as M, DialogFooter as Ma, pageDesignEditorBackgroundOverrideOwner as Mi, makeDefaultBlockComponent as Mn, getHeaderLayout as Mr, EditorProvider as Mt, previewButtonStyle as N, DialogHeader as Na, stripStaleTransitionStyleGroup as Ni, getBlockDefinition as Nn, getHeaderStyle as Nr, useEditor$1 as Nt, markApplyFailed as O, TabsTrigger as Oa, isObjectRecord$1 as Oi, isSupportedLoaderEndpoint as On, designRuntimeRulesForTheme as Or, ReferenceWidgetProvider as Ot, previewCuratedPalette as P, DialogTitle as Pa, asDesignBlockId as Pi, projectRecurringSchedule as Pn, gradientToCss as Pr, LinkField as Pt, resolvePreviewSidebarTab as Q, TriangleAlert as Qa, resolveSdkFooterMode as Qi, resolveRouteTarget as Qn, parseBackgroundAppearanceColorToken as Qr, recordsEqual as Qt, previewSiteStyle as R, Surface as Ra, buttonStyleSelectionParameterValue as Ri, visibleHeaderClearancePx as Rn, parseGradientPresetId as Rr, prepareBlockEditorManifest as Rt, applyTypographyDraftPatch as S, PopoverContent as Sa, siblingPath$1 as Si, DEFAULT_LAUNCH_READINESS_INPUT as Sn, assertNever$10 as So, compileEditorModelRuntime as Sr, EntryPickerWidgetProvider as St, deriveStyleConfiguratorCapabilities as T, Tabs as Ta, eventCalendarListLayoutCompatibleDisplayModeValues as Ti, MediaEditorContextProvider as Tn, parseSiteId as To, resolvePageDesignEditorBoundaryForChoice as Tr, FileField as Tt, toggleRow as U, DropdownMenuSeparator as Ua, buttonStyleSelectionKey as Ui, DEFAULT_THEME_RESPONSIVE_MODE as Un, composeBoundary as Ur, useEditorUiStoreInstance as Ut, styleConfiguratorHistoryEntryForPersistedSelection as V, DropdownMenuItem as Va, updateButtonStyleHoverPreference as Vi, validateManifestDraft as Vn, userPinnedDesignChoice as Vr, classifyHistoryShortcut as Vt, beginAutosaveBatch as W, DropdownMenuTrigger as Wa, textColorStyle as Wi, getResponsiveScopeSpec as Wn, sectionFactsForContent as Wr, useOptionalEditorUiStoreInstance as Wt, resolveStyleConfiguratorInitialSnapshot as X, Upload as Xa, paletteColorsSchema as Xi, resolveEntryRouteTarget as Xn, backgroundAppearanceColorTokenNames as Xr, undoHistory as Xt, rejectAutosaveBatch as Y, X as Ya, paletteColorEntries as Yi, defaultTransforms as Yn, sectionTransitionVariantForBoundaryOptionId as Yr, redoHistory as Yt, createOptimisticActionRunner as Z, Undo2 as Za, paletteModeSchema as Zi, resolvePageRouteTarget as Zn, backgroundAppearanceQuickColorTokenNames as Zr, unsafeAsLinkedContentEntryId as Zt, reportPreviewDesignError as _, SelectValue as _a, getCurrentResolveImageUrlContext as _i, MediaEditor as _n, ChevronDown as _o, ctaRowFragment as _r, loadMailingListAuthoringContext as _t, previewDesignHistoryDomainForCommand as a, mapCurrentValueForSelect as aa, parseBlockIconValue as ai, parseReferenceKind as an, Pencil as ao, headingFragment as ar, useUISelector as at, planSiteChromeSelection as b, SearchInput as ba, SECTION_BACKGROUND_MIN_SOURCE_WIDTH as bi, listEntryPageContentSlots as bn, unsafeAsEditorBlockId as bo, defineFragment as br, IconPickerField as bt, selectionSnapshotFromApplySiteStyleSelectionResponse as c, FieldFrame as ca, ThemedButtonSpecimen as ci, resolveContentTitle as cn, Monitor as co, faqHeadingFragment as cr, useEntryController as ct, PreviewDesignCoordinatorProvider as d, TooltipContent as da, coerceInlineTextWithFallback as di, ManifestForm as dn, Image as do, formEmbedFragment as dr, createSiteOptionWidgetAdapters as dt, getFieldIntent as ea, bindingSchema as ei, useDebouncedLatestSave as en, Sparkles as eo, coerceLinkedContentEntriesPayload as er, renderSiteChromeBlock as et, usePreviewDesignCoordinator as f, TooltipTrigger as fa, inlineTextToPlainText as fi, createManifestFormAdapter as fn, GripVertical as fo, formCopyFragment as fr, SiteOptionPickerField as ft, PREVIEW_DESIGN_SAVE_ERROR_MESSAGE as g, SelectTrigger as ga, buildResolveImageUrlContext as gi, createStoreBackend as gn, ChevronLeft as go, heroCtaRowFragment as gr, MailingListTargetingField as gt, PREVIEW_DESIGN_LOAD_ERROR_MESSAGE as h, SelectItem as ha, RichText as hi, evaluateVisibility as hn, ChevronRight as ho, ctaCopyFragment as hr, OfferingsPreviewWidgetProvider as ht, usePreviewDesignHistoryOrder as i, hasEmptyOption as ia, runTransforms as ii, isAdapterReferenceKind as in, Redo2 as io, richTextFragment as ir, ContentFieldsForm as it, openRow as j, DialogDescription as ja, isThemeV2NormalEditorRawStyleFieldName as ji, createCustomBlockRegistry as jn, findFooterLook as jr, RichTextWidgetProvider as jt, markApplySaved as k, Dialog as ka, isRecord$18 as ki, ThemeScope as kn, getCuratedSiteStyle as kr, useRichTextImagePicker as kt, deriveSiteStylePreviewUpdate as l, useField as la, renderInlineText as li, PaletteProvider as ln, Maximize2 as lo, blogFeaturedPostFragment as lr, useEntryEditorController as lt, usePreviewThemeOverlay as m, SelectContent as ma, Text$2 as mi, FormRenderer as mn, EllipsisVertical as mo, testimonialsHeadingFragment as mr, OfferingsPreviewGroupOrderField as mt, useSiteChromeCustomizeOptional as n, SdkConfigProvider as na, planSiteChromePlacement as ni, createSnapshotFromPageRecord as nn, SlidersHorizontal as no, clientComponentRegistry as nr, PreviewInlineTextEditor as nt, selectPreviewDesignHistoryDomain as o, mapOptionValueForSelect as oa, parseGeneratedIconAssetId as oi, deriveRouteMetadataPresentation as on, PenLine as oo, cardFragment as or, EditableBlockProvider as ot, PreviewThemeOverlayProvider as p, Select$1 as pa, isInlineTextEmpty as pi, createManifestValidation as pn, Eye as po, testimonialsCarouselFragment as pr, SiteOptionWidgetProvider as pt, enqueueTransaction as q, cva as qa, ORDINARY_TEXT_MIN_CONTRAST_RATIO as qi, readBlockComposition as qn, sectionTransitionFamilies as qr, createHistoryState as qt, PreviewDesignHistoryOrderProvider as r, useSdkConfig as ra, parseBackgroundContent as ri, BUILT_IN_REFERENCE_KINDS as rn, RotateCcw as ro, ImageResolveContextProvider as rr, PreviewTextEditor as rt, buildApplySiteStyleSelectionBody as s, unmapValueFromSelect as sa, parseGeneratedIconSetId as si, resolvePageRouteSlug as sn, Palette as so, faqAccordionFragment as sr, EntryControllerProvider as st, SiteChromeCustomizeProvider as t, isHeaderField as ta, EDITABLE_SURFACE_FORWARDING_PROP as ti, createRoutingHelpers as tn, Smartphone as to, getLinkedContentEntryMeta as tr, PreviewRichTextEditor as tt, planConfiguratorPreview as u, Tooltip as ua, logger$1 as ui, usePalette as un, LoaderCircle as uo, singleButtonFragment as ur, createSiteOptionApiLoader as ut, buildSiteChromeSelectionModels as v, Callout as va, resolveImageUrlWithContext as vi, applyPageDesignEditorAction as vn, Check as vo, heroCopyFragment as vr, MailingListTargetingProvider as vt, createStyleConfiguratorState as w, Input as wa, calendarWindowQuerySchema as wi, AMBIENT_BACKGROUND_ROLES as wn, parseMediaAssetId as wo, planPageDesignLayoutLookCompatibility as wr, ButtonWidgetProvider as wt, applyResolvedSelections as x, Popover as xa, getAtPath as xi, decodePublicProductCategorySelectorQuery as xn, unsafeAsEditorBlockValues as xo, applyCompiledRuntimeFieldsToContent as xr, EntryPickerField as xt, cycleSiteChromeSelectionId as y, CalloutDescription as ya, setContextResolveImageUrlContext as yi, getPageDesignEditorState as yn, parseFooterModuleId as yo, bodyCopyFragment as yr, InlineTextField as yt, resetTypographyToSaved as z, DropdownMenu as za, findButtonStyleRecipe as zi, resolveVariantKey as zn, curatedPalettes as zr, stripTopLevelRoutingUi as zt };
233673
+ export { FooterComposerPanel as $, TriangleAlert as $a, resolveSdkFooterMode as $i, resolveRouteTarget as $n, parseBackgroundAppearanceColorToken as $r, recordsEqual as $t, markApplySaving as A, Dialog as Aa, isRecord$18 as Ai, ThemeScope as An, __exportAll as Ao, getCuratedSiteStyle as Ar, useRichTextImagePicker as At, setPaletteColors as B, DropdownMenu as Ba, findButtonStyleRecipe as Bi, resolveVariantKey as Bn, curatedPalettes as Br, stripTopLevelRoutingUi as Bt, cancelPreview as C, PopoverContent as Ca, siblingPath$1 as Ci, DEFAULT_LAUNCH_READINESS_INPUT as Cn, parseMailingListPlacementTargeting as Co, compileEditorModelRuntime as Cr, EntryPickerWidgetProvider as Ct, isPreviewingChange as D, TabsContent as Da, eventCalendarListLayoutOptions as Di, useMediaEditorOptional as Dn, expectParsedBrandedId as Do, componentRuntimeRulesForTheme as Dr, MediaField as Dt, dismissWarnings as E, Tabs as Ea, eventCalendarListLayoutCompatibleDisplayModeValues as Ei, MediaEditorContextProvider as En, assertNever$10 as Eo, resolvePageDesignEditorBoundaryForChoice as Er, FileField as Et, previewFooterLook as F, DialogTitle as Fa, asDesignBlockId as Fi, projectRecurringSchedule as Fn, gradientToCss as Fr, LinkField as Ft, confirmAutosaveBatch as G, DropdownMenuTrigger as Ga, textColorStyle as Gi, getResponsiveScopeSpec as Gn, sectionFactsForContent as Gr, useOptionalEditorUiStoreInstance as Gt, syncStyleConfiguratorState as H, DropdownMenuItem as Ha, updateButtonStyleHoverPreference as Hi, validateManifestDraft as Hn, userPinnedDesignChoice as Hr, classifyHistoryShortcut as Ht, previewHeaderLayout as I, Collapsible as Ia, assertNever$7 as Ii, SITE_CHROME_VISIBLE_HEADER_SELECTOR as In, GRADIENT_PRESETS as Ir, LinkWidgetProvider as It, idleEditorTransactionQueueState as J, cva as Ja, ORDINARY_TEXT_MIN_CONTRAST_RATIO as Ji, readBlockComposition as Jn, sectionTransitionFamilies as Jr, createHistoryState as Jt, deriveTransactionCapabilities as K, Primitive as Ka, defaultThemeTokens as Ki, escapeStyleContent as Kn, boundaryTreatmentForBoundaryOptionId as Kr, canRedoHistory as Kt, previewHeaderStyle as L, CollapsibleContent as La, makeBoundaryId as Li, SITE_OVERLAY_HEADER_CLEARANCE_CSS_VAR as Ln, GRADIENT_PRESET_IDS as Lr, BlockEditor as Lt, palettePreviewProjection as M, DialogDescription as Ma, isThemeV2NormalEditorRawStyleFieldName as Mi, createCustomBlockRegistry as Mn, findFooterLook as Mr, RichTextWidgetProvider as Mt, previewButtonStyle as N, DialogFooter as Na, pageDesignEditorBackgroundOverrideOwner as Ni, makeDefaultBlockComponent as Nn, getHeaderLayout as Nr, EditorProvider as Nt, markApplyFailed as O, TabsList as Oa, bookingConsentCarrierSchema as Oi, useApiMediaUploader as On, parseMediaAssetId as Oo, curatedSiteStyles as Or, ReferenceField as Ot, previewCuratedPalette as P, DialogHeader as Pa, stripStaleTransitionStyleGroup as Pi, getBlockDefinition as Pn, getHeaderStyle as Pr, useEditor$1 as Pt, resolvePreviewSidebarTab as Q, Undo2 as Qa, paletteModeSchema as Qi, resolvePageRouteTarget as Qn, backgroundAppearanceQuickColorTokenNames as Qr, unsafeAsLinkedContentEntryId as Qt, previewSiteStyle as R, CollapsibleTrigger as Ra, buttonStyleHoverPreferenceValue as Ri, planSiteOverlayHeaderClearance as Rn, getGradientPreset as Rr, hideThemeV2RawStyleFields as Rt, applyTypographyDraftPatch as S, Popover as Sa, getAtPath as Si, decodePublicProductCategorySelectorQuery as Sn, parseFooterModuleId as So, applyCompiledRuntimeFieldsToContent as Sr, EntryPickerField as St, deriveStyleConfiguratorCapabilities as T, Input as Ta, calendarWindowQuerySchema as Ti, AMBIENT_BACKGROUND_ROLES as Tn, unsafeAsEditorBlockValues as To, planPageDesignLayoutLookCompatibility as Tr, ButtonWidgetProvider as Tt, toggleRow as U, DropdownMenuLabel as Ua, updateButtonStyleSelectionChoice as Ui, buildThemeRuntime as Un, boundaryLayout as Ur, useEditorUiStore as Ut, styleConfiguratorHistoryEntryForPersistedSelection as V, DropdownMenuContent as Va, resolveButtonStyleSelection as Vi, compileManifestContentContract as Vn, autoDesignChoice as Vr, getBlockManifestFromSdkConfig as Vt, beginAutosaveBatch as W, DropdownMenuSeparator as Wa, buttonStyleSelectionKey as Wi, DEFAULT_THEME_RESPONSIVE_MODE as Wn, composeBoundary as Wr, useEditorUiStoreInstance as Wt, resolveStyleConfiguratorInitialSnapshot as X, X as Xa, paletteColorEntries as Xi, defaultTransforms as Xn, sectionTransitionVariantForBoundaryOptionId as Xr, redoHistory as Xt, rejectAutosaveBatch as Y, cn$2 as Ya, VARIANT_ROLES as Yi, getDefaultComponentRegistry as Yn, sectionTransitionFamilyForBoundaryOptionId as Yr, pushHistoryEntry as Yt, createOptimisticActionRunner as Z, Upload as Za, paletteColorsSchema as Zi, resolveEntryRouteTarget as Zn, backgroundAppearanceColorTokenNames as Zr, undoHistory as Zt, reportPreviewDesignError as _, SelectTrigger as _a, buildResolveImageUrlContext as _i, createStoreBackend as _n, ChevronLeft as _o, heroCtaRowFragment as _r, MailingListTargetingField as _t, previewDesignHistoryDomainForCommand as a, hasEmptyOption as aa, runTransforms as ai, isAdapterReferenceKind as an, Redo2 as ao, richTextFragment as ar, ContentFieldsForm as at, planSiteChromeSelection as b, CalloutDescription as ba, setContextResolveImageUrlContext as bi, getPageDesignEditorState as bn, buildMailingListSignupBlockSourceRef as bo, bodyCopyFragment as br, InlineTextField as bt, selectionSnapshotFromApplySiteStyleSelectionResponse as c, unmapValueFromSelect as ca, parseGeneratedIconSetId as ci, resolvePageRouteSlug as cn, Palette as co, faqAccordionFragment as cr, EntryControllerProvider as ct, PreviewDesignCoordinatorProvider as d, Tooltip as da, logger$1 as di, usePalette as dn, LoaderCircle as do, singleButtonFragment as dr, createSiteOptionApiLoader as dt, attachRenderableMediaAssetFields as ea, ctaButton as ei, useMultiAutosave as en, Tablet as eo, LINKED_CONTENT_ENTRY_META_KEY as er, renderSiteChromeBlock as et, usePreviewDesignCoordinator as f, TooltipContent as fa, coerceInlineTextWithFallback as fi, ManifestForm as fn, Image as fo, formEmbedFragment as fr, createSiteOptionWidgetAdapters as ft, PREVIEW_DESIGN_SAVE_ERROR_MESSAGE as g, SelectItem as ga, RichText as gi, evaluateVisibility as gn, ChevronRight as go, ctaCopyFragment as gr, OfferingsPreviewWidgetProvider as gt, PREVIEW_DESIGN_LOAD_ERROR_MESSAGE as h, SelectContent as ha, Text$2 as hi, FormRenderer as hn, EllipsisVertical as ho, testimonialsHeadingFragment as hr, OfferingsPreviewGroupOrderField as ht, usePreviewDesignHistoryOrder as i, useSdkConfig as ia, parseBackgroundContent as ii, BUILT_IN_REFERENCE_KINDS as in, RotateCcw as io, ImageResolveContextProvider as ir, PREVIEW_EDITABLE_OUTLINE as it, openRow as j, DialogContent as ja, corners as ji, containerResponsiveThemeCss as jn, surfaceResolutionContextFromTheme as jr, RichTextField as jt, markApplySaved as k, TabsTrigger as ka, isObjectRecord$1 as ki, isSupportedLoaderEndpoint as kn, parseSiteId as ko, designRuntimeRulesForTheme as kr, ReferenceWidgetProvider as kt, deriveSiteStylePreviewUpdate as l, FieldFrame as la, ThemedButtonSpecimen as li, resolveContentTitle as ln, Monitor as lo, faqHeadingFragment as lr, useEntryController as lt, usePreviewThemeOverlay as m, Select$1 as ma, isInlineTextEmpty as mi, createManifestValidation as mn, Eye as mo, testimonialsCarouselFragment as mr, SiteOptionWidgetProvider as mt, useSiteChromeCustomizeOptional as n, isHeaderField as na, EDITABLE_SURFACE_FORWARDING_PROP as ni, createRoutingHelpers as nn, Smartphone as no, getLinkedContentEntryMeta as nr, PreviewInlineTextEditor as nt, selectPreviewDesignHistoryDomain as o, mapCurrentValueForSelect as oa, parseBlockIconValue as oi, parseReferenceKind as on, Pencil as oo, headingFragment as or, useUISelector as ot, PreviewThemeOverlayProvider as p, TooltipTrigger as pa, inlineTextToPlainText as pi, createManifestFormAdapter as pn, GripVertical as po, formCopyFragment as pr, SiteOptionPickerField as pt, enqueueTransaction as q, Button$1 as qa, parseThemeForPersistence as qi, mergeContentWithBlockStyleOverrides as qn, defaultSectionTransitionVariantForFamily as qr, canUndoHistory as qt, PreviewDesignHistoryOrderProvider as r, SdkConfigProvider as ra, planSiteChromePlacement as ri, createSnapshotFromPageRecord as rn, SlidersHorizontal as ro, clientComponentRegistry as rr, PreviewTextEditor as rt, buildApplySiteStyleSelectionBody as s, mapOptionValueForSelect as sa, parseGeneratedIconAssetId as si, deriveRouteMetadataPresentation as sn, PenLine as so, cardFragment as sr, EditableBlockProvider as st, SiteChromeCustomizeProvider as t, getFieldIntent as ta, bindingSchema as ti, useDebouncedLatestSave as tn, Sparkles as to, coerceLinkedContentEntriesPayload as tr, PreviewRichTextEditor as tt, planConfiguratorPreview as u, useField as ua, renderInlineText as ui, PaletteProvider as un, Maximize2 as uo, blogFeaturedPostFragment as ur, useEntryEditorController as ut, buildSiteChromeSelectionModels as v, SelectValue as va, getCurrentResolveImageUrlContext as vi, MediaEditor as vn, ChevronDown as vo, ctaRowFragment as vr, loadMailingListAuthoringContext as vt, createStyleConfiguratorState as w, PopoverTrigger as wa, BlockApiProvider as wi, deriveLaunchReadiness as wn, unsafeAsEditorBlockId as wo, formatSiteChromeBackgroundTokenLabel as wr, ButtonVariantField as wt, applyResolvedSelections as x, SearchInput as xa, SECTION_BACKGROUND_MIN_SOURCE_WIDTH as xi, listEntryPageContentSlots as xn, sameMailingListPlacementTargeting as xo, defineFragment as xr, IconPickerField as xt, cycleSiteChromeSelectionId as y, Callout as ya, resolveImageUrlWithContext as yi, applyPageDesignEditorAction as yn, Check as yo, heroCopyFragment as yr, MailingListTargetingProvider as yt, resetTypographyToSaved as z, Surface as za, buttonStyleSelectionParameterValue as zi, visibleHeaderClearancePx as zn, parseGradientPresetId as zr, prepareBlockEditorManifest as zt };