@riverbankcms/sdk 0.144.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 (228) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/dist/{PreviewEditorSidebar-CQZNnFiM.mjs → PreviewEditorSidebar-kg2r2Fyi.mjs} +4 -4
  3. package/dist/{PreviewEditorUI-DCNxnmI0.mjs → PreviewEditorUI-sWMLp5dT.mjs} +3 -3
  4. package/dist/{PreviewQueryProvider-BCYICImX.mjs → PreviewQueryProvider-Cg51xq1w.mjs} +1 -1
  5. package/dist/{SdkPreviewModeRuntime-BJolUbr1.mjs → SdkPreviewModeRuntime-h2ti3Hch.mjs} +688 -519
  6. package/dist/{SiteChromeCustomizeContext-CKgEpoxi.mjs → SiteChromeCustomizeContext-DEACFH9m.mjs} +3381 -2017
  7. package/dist/_dts/ai/src/contracts/proposals.d.ts +5643 -66
  8. package/dist/_dts/ai/src/contracts/siteStyleProposalSchemas.d.ts +513 -6
  9. package/dist/_dts/api/src/appointmentEndpointDefinitions.d.ts +49 -0
  10. package/dist/_dts/api/src/appointmentServiceCategoryEndpoints.d.ts +75 -0
  11. package/dist/_dts/api/src/appointmentServiceContracts.d.ts +80 -0
  12. package/dist/_dts/api/src/appointmentSetup.d.ts +8 -1
  13. package/dist/_dts/api/src/bookingConfig.d.ts +8 -1
  14. package/dist/_dts/api/src/bookingManagementEndpoints.d.ts +10 -26
  15. package/dist/_dts/api/src/bookingManagementEventEndpointTypes.d.ts +45 -1
  16. package/dist/_dts/api/src/clientErrorReporting.d.ts +50 -0
  17. package/dist/_dts/api/src/communications.d.ts +32 -24
  18. package/dist/_dts/api/src/contentRuntime.d.ts +3 -5
  19. package/dist/_dts/api/src/endpoints.d.ts +316 -134
  20. package/dist/_dts/api/src/event-visibility.d.ts +20 -0
  21. package/dist/_dts/api/src/eventManagementContracts.d.ts +56 -3
  22. package/dist/_dts/api/src/eventManagementEndpointDefinitions.d.ts +24 -0
  23. package/dist/_dts/api/src/eventPageWords.d.ts +19 -0
  24. package/dist/_dts/api/src/eventSeriesRegistrationEndpointDefinitions.d.ts +14 -0
  25. package/dist/_dts/api/src/index.d.ts +7 -1
  26. package/dist/_dts/api/src/indexCoreTypes.d.ts +1 -1
  27. package/dist/_dts/api/src/indexExtendedTypes.d.ts +1 -1
  28. package/dist/_dts/api/src/launchReadiness.d.ts +22 -2
  29. package/dist/_dts/api/src/launchRequirementPriority.d.ts +3 -0
  30. package/dist/_dts/api/src/newsletterCampaignCommandEndpoints.d.ts +13 -0
  31. package/dist/_dts/api/src/newsletterEndpointDefinitions.d.ts +30 -11
  32. package/dist/_dts/api/src/occurrenceScheduling.d.ts +10 -0
  33. package/dist/_dts/api/src/onboarding/confirmationResend.d.ts +3 -0
  34. package/dist/_dts/api/src/pageSurfaceEndpoints.d.ts +44 -0
  35. package/dist/_dts/api/src/participantMessaging.d.ts +11 -1
  36. package/dist/_dts/api/src/publicBookingService.d.ts +35 -1
  37. package/dist/_dts/api/src/publicExperience/newsletterEndpoints.d.ts +13 -0
  38. package/dist/_dts/api/src/publicNewsletterEndpointDefinitions.d.ts +58 -0
  39. package/dist/_dts/api/src/schemas/admin-observability-logs.d.ts +3 -3
  40. package/dist/_dts/api/src/sdk-event-upsert.d.ts +40 -1
  41. package/dist/_dts/api/src/sdkContracts.d.ts +3 -42
  42. package/dist/_dts/api/src/sdkCourseBooking.d.ts +30 -0
  43. package/dist/_dts/api/src/sdkEventEndpointDefinitions.d.ts +76 -0
  44. package/dist/_dts/api/src/sdkEventLifecycle.d.ts +37 -0
  45. package/dist/_dts/api/src/sdkManagedEventContracts.d.ts +18 -0
  46. package/dist/_dts/api/src/sdkPageDesign.d.ts +388 -0
  47. package/dist/_dts/api/src/sdkPageDesignEndpointDefinitions.d.ts +22 -0
  48. package/dist/_dts/api/src/sdkPullEventContracts.d.ts +46 -0
  49. package/dist/_dts/api/src/siteAddressEndpoints.d.ts +29 -0
  50. package/dist/_dts/api/src/siteManagementEndpointDefinitions.d.ts +49 -0
  51. package/dist/_dts/api/src/siteManagementEndpoints.d.ts +4 -38
  52. package/dist/_dts/api/src/siteOnboarding.d.ts +75 -9
  53. package/dist/_dts/api/src/sitePlatformEndpoints.d.ts +1 -1
  54. package/dist/_dts/api/src/types.d.ts +8 -1
  55. package/dist/_dts/api/src/wholeSeriesRuns.d.ts +14 -0
  56. package/dist/_dts/blocks/src/PageRenderer.d.ts +4 -4
  57. package/dist/_dts/blocks/src/bindings/index.d.ts +2 -2
  58. package/dist/_dts/blocks/src/contracts/proof-block-islands.d.ts +24 -0
  59. package/dist/_dts/blocks/src/index.d.ts +3 -1
  60. package/dist/_dts/blocks/src/pageRenderAdmission.d.ts +10 -0
  61. package/dist/_dts/blocks/src/pageRenderJoins.d.ts +68 -0
  62. package/dist/_dts/blocks/src/pageRenderPlan.d.ts +8 -27
  63. package/dist/_dts/blocks/src/pageRenderPreparation.d.ts +7 -4
  64. package/dist/_dts/blocks/src/pageRendererBoundaries.d.ts +40 -23
  65. package/dist/_dts/blocks/src/pageRendererContracts.d.ts +3 -1
  66. package/dist/_dts/blocks/src/server.d.ts +1 -1
  67. package/dist/_dts/blocks/src/system/blocks/appointment-services.d.ts +2 -0
  68. package/dist/_dts/blocks/src/system/blocks/events/eventSelectionFields.d.ts +2 -2
  69. package/dist/_dts/blocks/src/system/blocks/events/shared/calendarWindow.d.ts +1 -1
  70. package/dist/_dts/blocks/src/system/blocks/events/shared/schemas.d.ts +27 -5
  71. package/dist/_dts/blocks/src/system/blocks/events/shared/types.d.ts +14 -1
  72. package/dist/_dts/blocks/src/system/blocks/location-map.d.ts +2 -2
  73. package/dist/_dts/blocks/src/system/blocks/media-text.d.ts +47 -47
  74. package/dist/_dts/blocks/src/system/icons/social.d.ts +1 -1
  75. package/dist/_dts/blocks/src/system/manifest/schema.d.ts +29 -3
  76. package/dist/_dts/blocks/src/system/registry.d.ts +1 -1
  77. package/dist/_dts/blocks/src/system/runtime/hooks/useHeadlessBookingFlow.d.ts +8 -1
  78. package/dist/_dts/blocks/src/system/runtime/nodes/appointment-services.d.ts +22 -2
  79. package/dist/_dts/blocks/src/system/runtime/nodes/booking-form.headless.state.d.ts +3 -1
  80. package/dist/_dts/blocks/src/system/runtime/nodes/booking-form.interactive.d.ts +57 -2
  81. package/dist/_dts/blocks/src/system/runtime/nodes/booking-form.service-categories.d.ts +29 -0
  82. package/dist/_dts/blocks/src/system/runtime/nodes/booking-form.service-choices.d.ts +13 -0
  83. package/dist/_dts/blocks/src/system/runtime/nodes/booking-form.state.d.ts +3 -3
  84. package/dist/_dts/blocks/src/system/runtime/nodes/booking-runtime-sources.d.ts +13 -1
  85. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/eventSourceRecovery.d.ts +2 -1
  86. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/eventCollectionContract.d.ts +23 -7
  87. package/dist/_dts/blocks/src/system/runtime/nodes/form.fields.d.ts +5 -0
  88. package/dist/_dts/blocks/src/system/runtime/nodes/newsletter-form.block-submission.d.ts +36 -0
  89. package/dist/_dts/blocks/src/system/runtime/nodes/newsletter-form.client.d.ts +1 -1
  90. package/dist/_dts/blocks/src/system/runtime/nodes/newsletter-form.interactive.d.ts +6 -1
  91. package/dist/_dts/blocks/src/system/runtime/nodes/newsletter-form.parts.d.ts +46 -0
  92. package/dist/_dts/blocks/src/system/runtime/nodes/newsletter-form.submission.d.ts +20 -1
  93. package/dist/_dts/blocks/src/system/runtime/nodes/newsletter-form.types.d.ts +2 -1
  94. package/dist/_dts/blocks/src/system/runtime/resolver.d.ts +2 -1
  95. package/dist/_dts/blocks/src/system/runtime/shared/components/CheckboxChoice.d.ts +18 -0
  96. package/dist/_dts/blocks/src/system/runtime/shared/components/index.d.ts +1 -0
  97. package/dist/_dts/content-editor/src/index.d.ts +1 -0
  98. package/dist/_dts/content-editor/src/primitives/previewEditableOutline.d.ts +2 -0
  99. package/dist/_dts/content-editor/src/ui/editorBlockEquality.d.ts +3 -0
  100. package/dist/_dts/content-editor/src/ui/editorSnapshot.d.ts +3 -3
  101. package/dist/_dts/content-model/src/content-types/schema.d.ts +1 -1
  102. package/dist/_dts/core/src/appointment-service-categories.d.ts +108 -0
  103. package/dist/_dts/core/src/block-content-identity.d.ts +5 -0
  104. package/dist/_dts/core/src/editor-state.d.ts +2 -1
  105. package/dist/_dts/core/src/index.d.ts +2 -0
  106. package/dist/_dts/core/src/mailing-list-submission.d.ts +3 -1
  107. package/dist/_dts/core/src/public-event-booking-availability.d.ts +20 -1
  108. package/dist/_dts/core/src/public-profile.d.ts +12 -1
  109. package/dist/_dts/db/src/generated/supabase/database.types.d.ts +711 -242
  110. package/dist/_dts/editor-blocks/src/BlockEditor.d.ts +3 -0
  111. package/dist/_dts/editor-blocks/src/block-editor/EmptyState.d.ts +13 -1
  112. package/dist/_dts/editor-blocks/src/block-editor/types.d.ts +2 -2
  113. package/dist/_dts/editor-blocks/src/index.d.ts +1 -0
  114. package/dist/_dts/editor-blocks/src/widgets/site-option-picker/loaders.d.ts +16 -1
  115. package/dist/_dts/editor-blocks/src/widgets/site-option-picker/types.d.ts +13 -0
  116. package/dist/_dts/editor-blocks/src/widgets/site-option-picker/utils.d.ts +29 -0
  117. package/dist/_dts/preview-next/src/client/blocks/BoundaryControl.d.ts +7 -2
  118. package/dist/_dts/preview-next/src/client/blocks/composer/mergeDrafts.d.ts +1 -1
  119. package/dist/_dts/preview-next/src/client/blocks/composer/types.d.ts +3 -3
  120. package/dist/_dts/preview-next/src/client/blocks/previewProjection/applyPreviewProjections.d.ts +1 -3
  121. package/dist/_dts/preview-next/src/client/blocks/previewProjection/runtimeContentDecoration.d.ts +2 -2
  122. package/dist/_dts/preview-next/src/client/blocks/previewProjection/types.d.ts +2 -2
  123. package/dist/_dts/preview-next/src/client/preview/PreviewEntryControllerProvider.d.ts +1 -1
  124. package/dist/_dts/sdk/src/client/runtimeCacheKeys.d.ts +8 -0
  125. package/dist/_dts/sdk/src/client/types.d.ts +1 -1
  126. package/dist/_dts/sdk/src/contracts/index.d.ts +1 -1
  127. package/dist/_dts/sdk/src/contracts/page.d.ts +7 -2
  128. package/dist/_dts/sdk/src/contracts/system-block-content.d.ts +5 -0
  129. package/dist/_dts/sdk/src/manifest/passes/pass1-fields.d.ts +2 -2
  130. package/dist/_dts/sdk/src/next/renderSdkContent.d.ts +0 -1
  131. package/dist/_dts/sdk/src/public-api/contracts.d.ts +6 -8
  132. package/dist/_dts/sdk/src/rendering/blocks-page-renderer.d.ts +4 -4
  133. package/dist/_dts/sdk/src/rendering/components/pageShared.d.ts +4 -4
  134. package/dist/_dts/sdk/src/rendering/helpers/loadContent.d.ts +7 -2
  135. package/dist/_dts/sdk/src/rendering/helpers/loadPage.d.ts +5 -2
  136. package/dist/_dts/sdk/src/rendering/helpers/pageRuntimeSupport.d.ts +6 -1
  137. package/dist/_dts/sdk/src/rendering/helpers/templateContent.d.ts +2 -0
  138. package/dist/_dts/sdk/src/rendering/hooks/useContent.d.ts +6 -2
  139. package/dist/_dts/sdk/src/rendering/hooks/usePage.d.ts +5 -1
  140. package/dist/_dts/sdk/src/version.d.ts +1 -1
  141. package/dist/_dts/surfaces/src/index.d.ts +10 -0
  142. package/dist/_dts/theme-core/src/generated/containerResponsiveThemeCss.d.ts +1 -1
  143. package/dist/_dts/theme-core/src/inputs/checkable.d.ts +42 -0
  144. package/dist/_dts/theme-core/src/inputs/inputGroup.d.ts +19 -0
  145. package/dist/_dts/theme-core/src/layout/boundaryCss.d.ts +3 -0
  146. package/dist/_dts/theme-core/src/site-styles/compositionBudget.d.ts +8 -0
  147. package/dist/_dts/theme-core/src/site-styles/contentTemplateRuntimeCompiler.d.ts +3 -2
  148. package/dist/_dts/theme-core/src/site-styles/designState.d.ts +1 -3
  149. package/dist/_dts/theme-core/src/site-styles/generatedDesignPipeline.d.ts +3 -0
  150. package/dist/_dts/theme-core/src/site-styles/index.d.ts +3 -0
  151. package/dist/_dts/theme-core/src/site-styles/joinTreatment.d.ts +132 -0
  152. package/dist/_dts/theme-core/src/site-styles/pageDesignEditorBoundaries.d.ts +31 -0
  153. package/dist/_dts/theme-core/src/site-styles/pageDesignEditorModel.d.ts +33 -29
  154. package/dist/_dts/theme-core/src/site-styles/pageDesignIntent.d.ts +4 -4
  155. package/dist/_dts/theme-core/src/site-styles/pageFlowPresets.d.ts +36 -0
  156. package/dist/_dts/theme-core/src/site-styles/previewCompiler.d.ts +4 -10
  157. package/dist/_dts/theme-core/src/site-styles/rawStyleFields.d.ts +17 -4
  158. package/dist/_dts/theme-core/src/site-styles/runtimeCompiler.d.ts +20 -74
  159. package/dist/_dts/theme-core/src/site-styles/sectionBoundaryComposition.d.ts +95 -0
  160. package/dist/_dts/theme-core/src/site-styles/sectionTransitions.d.ts +80 -518
  161. package/dist/_dts/theme-core/src/site-styles/siteStyleBlockPolicies.d.ts +9 -4
  162. package/dist/_dts/theme-core/src/site-styles/transitionCatalogue.d.ts +320 -0
  163. package/dist/_dts/theme-core/src/site-styles/types.d.ts +3 -18
  164. package/dist/_dts/ui/src/navigation-tabs.d.ts +2 -1
  165. package/dist/client/{BookingConsentAgreement-DoAILrkN.mjs → BookingConsentAgreement-BQKL045f.mjs} +2 -2
  166. package/dist/client/CheckboxChoice--W2n6yKs.mjs +24 -0
  167. package/dist/client/{DiscountCodeDisclosure-X528hUTf.mjs → DiscountCodeDisclosure-CsOtjFY7.mjs} +1 -1
  168. package/dist/client/{EventCombined.client-DSBVwq5m.mjs → EventCombined.client-BdRjVbhH.mjs} +6 -6
  169. package/dist/client/{EventListing.client-DmFAX7Vb.mjs → EventListing.client-DBxC6xOU.mjs} +2 -2
  170. package/dist/client/{LeafletStaticMap-BAqXdfhq.mjs → LeafletStaticMap-mHEJKrTs.mjs} +1 -1
  171. package/dist/client/{ThemedButton-BwNFVwi4.mjs → ThemedButton-CE5KYT6z.mjs} +1 -1
  172. package/dist/client/{accordion-DRhMdkbd.mjs → accordion-BEQNSptH.mjs} +1 -1
  173. package/dist/client/{bookingForm-iJ_nCsNF.mjs → bookingForm-AMr-s5vw.mjs} +168 -95
  174. package/dist/client/bookings.mjs +239 -110
  175. package/dist/client/{carousel-D8zuffZr.mjs → carousel-Bbt_QgJy.mjs} +1 -1
  176. package/dist/client/{cart-DeMGJViN.mjs → cart-CnWi30zJ.mjs} +3 -3
  177. package/dist/client/{checkout-DXc06Km2.mjs → checkout-f3nkWgd4.mjs} +3 -3
  178. package/dist/client/client.mjs +3222 -1612
  179. package/dist/client/{context-CDLCfDep.mjs → context-Bc8T6pCe.mjs} +1 -1
  180. package/dist/client/{dates-ClFx7Epy.mjs → dates-DUsCEzLb.mjs} +2 -3
  181. package/dist/client/{eventCalendar-BaGpnOGN.mjs → eventCalendar-CKwgXui5.mjs} +9 -9
  182. package/dist/client/{eventCombined-ywONOx2m.mjs → eventCombined-CBAOSTGR.mjs} +4 -4
  183. package/dist/client/{eventDetails-B2LlOTYY.mjs → eventDetails-Dh-_WiBD.mjs} +4 -4
  184. package/dist/client/{eventListing-CMgxWpqP.mjs → eventListing-CA3frIH5.mjs} +4 -4
  185. package/dist/client/{eventRegistration-BarLDNHR.mjs → eventRegistration-BHtsgdcg.mjs} +21 -22
  186. package/dist/client/{form-BjqKaBJ7.mjs → form-C2h3YAcg.mjs} +135 -104
  187. package/dist/client/{headerSection-CP4XDwz1.mjs → headerSection-lwMuMTH9.mjs} +3 -3
  188. package/dist/client/hooks.mjs +1023 -148
  189. package/dist/client/{locationMap-C5gW-d-w.mjs → locationMap-DJ2bLODV.mjs} +3 -3
  190. package/dist/client/{newsletterForm-afXlVSA0.mjs → newsletterForm-8Pu5K32g.mjs} +225 -102
  191. package/dist/client/{pricing-Bl1CAl28.mjs → pricing-HHx3IgBz.mjs} +1 -1
  192. package/dist/client/{productDetail-CvQ3jWQe.mjs → productDetail-C_1odnAf.mjs} +3 -3
  193. package/dist/client/{productList-U874PGO7.mjs → productList-CtCv-Nmx.mjs} +3 -3
  194. package/dist/client/{propsDecoder-DPXtCZWP.mjs → propsDecoder-Dcgsncxb.mjs} +111 -55
  195. package/dist/client/rendering/client.mjs +1389 -722
  196. package/dist/client/rendering/islands.mjs +17 -17
  197. package/dist/client/rendering.mjs +3136 -1400
  198. package/dist/client/{routeIslandApiConfig-NGYiUWXu.mjs → routeIslandApiConfig-CWLP7wu3.mjs} +1 -1
  199. package/dist/client/{scrollToBlock-0-C3DVhK.mjs → scrollToBlock-BNgaEUpo.mjs} +1 -1
  200. package/dist/client/{shop-BXjXhM9P.mjs → shop-DQXrQ8kJ.mjs} +7 -7
  201. package/dist/client/{shop-commerce-BZ6UlWJ7.mjs → shop-commerce-B88zmWWo.mjs} +6 -6
  202. package/dist/client/{shop-commerce-store-DlSBXb3D.mjs → shop-commerce-store-DtSfkKuX.mjs} +1 -1
  203. package/dist/client/{shopShared-kkEOiLPA.mjs → shopShared-cuaONpkJ.mjs} +4 -4
  204. package/dist/client/{useEventFilters-zvnnE1ro.mjs → useEventFilters-Bukew6Gb.mjs} +6 -6
  205. package/dist/preview-next/before-render.mjs +500 -165
  206. package/dist/preview-next/client/runtime.mjs +4 -4
  207. package/dist/preview-next/editor-base.css +11 -0
  208. package/dist/preview-next/keepAlive.mjs +460 -165
  209. package/dist/preview-next/middleware.mjs +461 -165
  210. package/dist/{previewAuthStore-JA6-I_sL.mjs → previewAuthStore-h5IgbSp4.mjs} +485 -165
  211. package/dist/{sdk-runtime-DFJlQt3q.mjs → sdk-runtime-DTc1uIXn.mjs} +2 -2
  212. package/dist/{separator-o8GHb1xh.mjs → separator-BpHS1KZK.mjs} +1 -1
  213. package/dist/server/components.mjs +3088 -1307
  214. package/dist/server/config-validation.mjs +927 -109
  215. package/dist/server/config.mjs +927 -109
  216. package/dist/server/data.mjs +939 -110
  217. package/dist/server/index.mjs +513 -169
  218. package/dist/server/next.mjs +2874 -1195
  219. package/dist/server/page-converter.mjs +420 -79
  220. package/dist/server/prebuild.mjs +1 -1
  221. package/dist/server/rendering/server.mjs +3071 -1289
  222. package/dist/server/rendering.mjs +3169 -1350
  223. package/dist/server/routing.mjs +1085 -159
  224. package/dist/server/server.mjs +1042 -291
  225. package/dist/server/theme-bridge.mjs +1658 -137
  226. package/dist/server/theme.mjs +6 -4
  227. package/dist/styles/index.css +186 -65
  228. package/package.json +2 -1
@@ -1,12 +1,12 @@
1
1
  "use client";
2
- import { $i as mapCurrentValueForSelect, $n as coerceLinkedContentEntriesPayload, $r as runTransforms, Ai as makeBoundaryId, An as containerResponsiveThemeCss, Ar as compileTransitionRuntime, At as RichTextField, Ba as Button, Bi as parseThemeForPersistence, Bn as compileManifestContentContract, Bt as getBlockManifestFromSdkConfig, Ca as Dialog, Ci as isObjectRecord, Cn as deriveLaunchReadiness, Cr as retargetCompiledRuntimeFieldsForContentAdjacency, Ct as ButtonVariantField, Da as DialogHeader, Di as pageDesignEditorBackgroundOverrideOwner, Dn as useApiMediaUploader, Dt as ReferenceField, Ea as DialogFooter, Ei as isThemeV2NormalEditorRawStyleFieldName, En as useMediaEditorOptional, Er as componentRuntimeRulesForTheme, Et as MediaField, Fn as SITE_CHROME_VISIBLE_HEADER_SELECTOR, Fr as gradientToCss, Ft as LinkWidgetProvider, G as confirmAutosaveBatch, Gi as paletteModeSchema, Gn as escapeStyleContent, Gr as backgroundAppearanceColorTokenNames, Gt as canRedoHistory, Ha as cn, Hn as buildThemeRuntime, Hr as sectionTransitionFamilies, Ht as useEditorUiStore, In as SITE_OVERLAY_HEADER_CLEARANCE_CSS_VAR, Ir as GRADIENT_PRESETS, J as idleEditorTransactionQueueState, Ji as getFieldIntent, Jn as defaultTransforms, Jr as ctaButton, Jt as pushHistoryEntry, K as deriveTransactionCapabilities, Ki as resolveSdkFooterMode, Kn as readBlockComposition, Kr as backgroundAppearanceQuickColorTokenNames, Kt as canUndoHistory, Ln as planSiteOverlayHeaderClearance, Lr as GRADIENT_PRESET_IDS, Lt as hideThemeV2RawStyleFields, Mn as makeDefaultBlockComponent, Mt as EditorProvider, Nn as getBlockDefinition, Nt as useEditor, Oa as DialogTitle, Oi as asDesignBlockId, On as isSupportedLoaderEndpoint, Or as designRuntimeRulesForTheme, Ot as ReferenceWidgetProvider, Pn as projectRecurringSchedule, Pt as LinkField, Q as resolvePreviewSidebarTab, Qi as hasEmptyOption, Qn as LINKED_CONTENT_ENTRY_META_KEY, Qr as parseBackgroundContent, Qt as recordsEqual, Ri as textColorStyle, Rn as visibleHeaderClearancePx, Rr as getGradientPreset, Rt as prepareBlockEditorManifest, Sa as TabsTrigger, Si as bookingConsentCarrierSchema, Sn as DEFAULT_LAUNCH_READINESS_INPUT, Sr as retargetCompiledBoundaryRuntimeForContentAdjacency, St as EntryPickerWidgetProvider, Ta as DialogDescription, Ti as corners, Tn as MediaEditorContextProvider, Tr as planPageDesignLayoutLookCompatibility, Tt as FileField, Ua as X, Un as DEFAULT_THEME_RESPONSIVE_MODE, Ur as sectionTransitionFamilyForBoundaryOptionId, Ut as useEditorUiStoreInstance, Vi as ORDINARY_TEXT_MIN_CONTRAST_RATIO, Vn as validateManifestDraft, Vr as defaultSectionTransitionVariantForFamily, W as beginAutosaveBatch, Wa as Upload, Wi as paletteColorsSchema, Wn as getResponsiveScopeSpec, Wr as sectionTransitionVariantForBoundaryOptionId, Wt as useOptionalEditorUiStoreInstance, Xi as SdkConfigProvider, Xn as resolvePageRouteTarget, Xt as undoHistory, Y as rejectAutosaveBatch, Yi as isHeaderField, Yn as resolveEntryRouteTarget, Yr as bindingSchema, Yt as redoHistory, Za as RotateCcw, Zi as useSdkConfig, Zn as resolveRouteTarget, Zr as planSiteChromePlacement, Zt as unsafeAsLinkedContentEntryId, _ as reportPreviewDesignError, _i as siblingPath, _n as MediaEditor, _o as expectParsedBrandedId, _r as heroCopyFragment, _t as loadMailingListAuthoringContext, ai as logger, an as parseReferenceKind, ao as Image, ar as cardFragment, at as useUISelector, ba as TabsContent, bi as eventCalendarListLayoutCompatibleDisplayModeValues, bo as __exportAll, br as applyCompiledRuntimeFieldsToContent, bt as IconPickerField, ca as SelectContent, ci as isInlineTextEmpty, cr as blogFeaturedPostFragment, d as PreviewDesignCoordinatorProvider, da as SelectValue, di as buildResolveImageUrlContext, dr as formCopyFragment, dt as createSiteOptionWidgetAdapters, ea as mapOptionValueForSelect, ei as parseBlockIconValue, en as useDebouncedLatestSave, er as getLinkedContentEntryMeta, et as renderSiteChromeBlock, fi as getCurrentResolveImageUrlContext, fn as createManifestFormAdapter, fr as testimonialsCarouselFragment, ft as SiteOptionPickerField, g as PREVIEW_DESIGN_SAVE_ERROR_MESSAGE, gi as getAtPath, gn as createStoreBackend, go as assertNever$2, gr as ctaRowFragment, gt as MailingListTargetingField, h as PREVIEW_DESIGN_LOAD_ERROR_MESSAGE, hi as SECTION_BACKGROUND_MIN_SOURCE_WIDTH, hn as evaluateVisibility, ho as unsafeAsEditorBlockValues, hr as heroCtaRowFragment, ht as OfferingsPreviewWidgetProvider, i as usePreviewDesignHistoryOrder, ii as renderInlineText, ir as headingFragment, jn as createCustomBlockRegistry, jr as surfaceResolutionContextFromTheme, jt as RichTextWidgetProvider, ki as assertNever$1, kn as ThemeScope, kt as useRichTextImagePicker, la as SelectItem, li as Text$1, ln as PaletteProvider, lo as ChevronRight, lr as singleButtonFragment, lt as useEntryEditorController, m as usePreviewThemeOverlay, mi as setContextResolveImageUrlContext, mn as FormRenderer, mo as unsafeAsEditorBlockId, mr as ctaCopyFragment, mt as OfferingsPreviewGroupOrderField, n as useSiteChromeCustomizeOptional, na as FieldFrame, ni as parseGeneratedIconSetId, nn as createSnapshotFromPageRecord, nr as ImageResolveContextProvider, nt as PreviewInlineTextEditor, oi as coerceInlineTextWithFallback, oo as GripVertical, or as faqAccordionFragment, ot as EditableBlockProvider, p as PreviewThemeOverlayProvider, pi as resolveImageUrlWithContext, po as parseFooterModuleId, pr as testimonialsHeadingFragment, pt as SiteOptionWidgetProvider, q as enqueueTransaction, qi as attachRenderableMediaAssetFields, qn as getDefaultComponentRegistry, qr as parseBackgroundAppearanceColorToken, qt as createHistoryState, r as PreviewDesignHistoryOrderProvider, ra as useField, rn as BUILT_IN_REFERENCE_KINDS, rr as richTextFragment, rt as PreviewTextEditor, sa as Select, si as inlineTextToPlainText, sr as faqHeadingFragment, st as EntryControllerProvider, t as SiteChromeCustomizeProvider, ta as unmapValueFromSelect, ti as parseGeneratedIconAssetId, tn as createRoutingHelpers, tr as clientComponentRegistry, tt as PreviewRichTextEditor, ua as SelectTrigger, ui as RichText$1, un as usePalette, uo as ChevronLeft, ur as formEmbedFragment, ut as createSiteOptionApiLoader, vi as BlockApiProvider, vn as applyPageDesignEditorAction, vo as parseMediaAssetId, vr as bodyCopyFragment, vt as MailingListTargetingProvider, wa as DialogContent, wi as isRecord$13, wn as AMBIENT_BACKGROUND_ROLES, wr as formatSiteChromeBackgroundTokenLabel, wt as ButtonWidgetProvider, xa as TabsList, xi as eventCalendarListLayoutOptions, xn as decodePublicProductCategorySelectorQuery, xr as compileEditorModelRuntime, xt as EntryPickerField, ya as Tabs, yi as calendarWindowQuerySchema, yn as getPageDesignEditorState, yo as parseSiteId, yr as defineFragment, yt as InlineTextField, zi as defaultThemeTokens, zn as resolveVariantKey, zr as parseGradientPresetId, zt as stripTopLevelRoutingUi } from "./SiteChromeCustomizeContext-CKgEpoxi.mjs";
3
- import { i as useOptionalPreviewLayout, t as PreviewQueryProvider } from "./PreviewQueryProvider-BCYICImX.mjs";
4
- import { _ as API_ENDPOINTS, a as usePreviewToken, c as createBearerAPIClient, d as unwrapResponse, g as resolveSurfaceDocumentAttributes, h as SURFACE_IDS, i as usePreviewAuthFetch, m as SURFACE_DOCUMENT_DATA_ATTRIBUTE, n as markPreviewAuthExpired, o as isPreviewRuntimeSessionEditable, r as usePreviewAuth, s as ApiRequestError, t as initPreviewAuth } from "./previewAuthStore-JA6-I_sL.mjs";
2
+ import { $i as resolveSdkFooterMode, $n as resolveRouteTarget, $r as parseBackgroundAppearanceColorToken, $t as recordsEqual, Aa as Dialog, Ai as isRecord$11, An as ThemeScope, Ao as __exportAll, At as useRichTextImagePicker, Bn as resolveVariantKey, Bt as stripTopLevelRoutingUi, Ci as siblingPath, Cn as DEFAULT_LAUNCH_READINESS_INPUT, Co as parseMailingListPlacementTargeting, Cr as compileEditorModelRuntime, Ct as EntryPickerWidgetProvider, Da as TabsContent, Di as eventCalendarListLayoutOptions, Dn as useMediaEditorOptional, Do as expectParsedBrandedId, Dr as componentRuntimeRulesForTheme, Dt as MediaField, Ea as Tabs, Ei as eventCalendarListLayoutCompatibleDisplayModeValues, En as MediaEditorContextProvider, Eo as assertNever$2, Er as resolvePageDesignEditorBoundaryForChoice, Et as FileField, Fa as DialogTitle, Fi as asDesignBlockId, Fn as projectRecurringSchedule, Fr as gradientToCss, Ft as LinkField, G as confirmAutosaveBatch, Gi as textColorStyle, Gn as getResponsiveScopeSpec, Gr as sectionFactsForContent, Gt as useOptionalEditorUiStoreInstance, Hn as validateManifestDraft, Hr as userPinnedDesignChoice, Ii as assertNever$1, In as SITE_CHROME_VISIBLE_HEADER_SELECTOR, Ir as GRADIENT_PRESETS, It as LinkWidgetProvider, J as idleEditorTransactionQueueState, Ji as ORDINARY_TEXT_MIN_CONTRAST_RATIO, Jn as readBlockComposition, Jr as sectionTransitionFamilies, Jt as createHistoryState, K as deriveTransactionCapabilities, Ki as defaultThemeTokens, Kn as escapeStyleContent, Kr as boundaryTreatmentForBoundaryOptionId, Kt as canRedoHistory, Li as makeBoundaryId, Ln as SITE_OVERLAY_HEADER_CLEARANCE_CSS_VAR, Lr as GRADIENT_PRESET_IDS, Ma as DialogDescription, Mi as isThemeV2NormalEditorRawStyleFieldName, Mn as createCustomBlockRegistry, Mt as RichTextWidgetProvider, Na as DialogFooter, Ni as pageDesignEditorBackgroundOverrideOwner, Nn as makeDefaultBlockComponent, Nt as EditorProvider, Oa as TabsList, Oi as bookingConsentCarrierSchema, On as useApiMediaUploader, Oo as parseMediaAssetId, Ot as ReferenceField, Pa as DialogHeader, Pi as stripStaleTransitionStyleGroup, Pn as getBlockDefinition, Pt as useEditor, Q as resolvePreviewSidebarTab, Qi as paletteModeSchema, Qn as resolvePageRouteTarget, Qr as backgroundAppearanceQuickColorTokenNames, Qt as unsafeAsLinkedContentEntryId, Rn as planSiteOverlayHeaderClearance, Rr as getGradientPreset, Rt as hideThemeV2RawStyleFields, Si as getAtPath, Sn as decodePublicProductCategorySelectorQuery, So as parseFooterModuleId, Sr as applyCompiledRuntimeFieldsToContent, St as EntryPickerField, Ti as calendarWindowQuerySchema, Tn as AMBIENT_BACKGROUND_ROLES, To as unsafeAsEditorBlockValues, Tr as planPageDesignLayoutLookCompatibility, Tt as ButtonWidgetProvider, Un as buildThemeRuntime, Ur as boundaryLayout, Ut as useEditorUiStore, Vn as compileManifestContentContract, Vr as autoDesignChoice, Vt as getBlockManifestFromSdkConfig, W as beginAutosaveBatch, Wn as DEFAULT_THEME_RESPONSIVE_MODE, Wr as composeBoundary, Wt as useEditorUiStoreInstance, Xa as X, Xn as defaultTransforms, Xr as sectionTransitionVariantForBoundaryOptionId, Xt as redoHistory, Y as rejectAutosaveBatch, Ya as cn, Yn as getDefaultComponentRegistry, Yr as sectionTransitionFamilyForBoundaryOptionId, Yt as pushHistoryEntry, Za as Upload, Zi as paletteColorsSchema, Zn as resolveEntryRouteTarget, Zr as backgroundAppearanceColorTokenNames, Zt as undoHistory, _ as reportPreviewDesignError, _a as SelectTrigger, _i as buildResolveImageUrlContext, _n as createStoreBackend, _o as ChevronLeft, _r as heroCtaRowFragment, _t as MailingListTargetingField, aa as hasEmptyOption, ai as runTransforms, ar as richTextFragment, bi as setContextResolveImageUrlContext, bn as getPageDesignEditorState, bo as buildMailingListSignupBlockSourceRef, br as bodyCopyFragment, bt as InlineTextField, ca as unmapValueFromSelect, ci as parseGeneratedIconSetId, cr as faqAccordionFragment, ct as EntryControllerProvider, d as PreviewDesignCoordinatorProvider, di as logger, dn as usePalette, dr as singleButtonFragment, dt as createSiteOptionApiLoader, ea as attachRenderableMediaAssetFields, ei as ctaButton, er as LINKED_CONTENT_ENTRY_META_KEY, et as renderSiteChromeBlock, fi as coerceInlineTextWithFallback, fo as Image, fr as formEmbedFragment, ft as createSiteOptionWidgetAdapters, g as PREVIEW_DESIGN_SAVE_ERROR_MESSAGE, ga as SelectItem, gi as RichText$1, gn as evaluateVisibility, go as ChevronRight, gr as ctaCopyFragment, gt as OfferingsPreviewWidgetProvider, h as PREVIEW_DESIGN_LOAD_ERROR_MESSAGE, ha as SelectContent, hi as Text$1, hn as FormRenderer, hr as testimonialsHeadingFragment, ht as OfferingsPreviewGroupOrderField, i as usePreviewDesignHistoryOrder, ia as useSdkConfig, ii as parseBackgroundContent, in as BUILT_IN_REFERENCE_KINDS, io as RotateCcw, ir as ImageResolveContextProvider, it as PREVIEW_EDITABLE_OUTLINE, ja as DialogContent, ji as corners, jn as containerResponsiveThemeCss, jr as surfaceResolutionContextFromTheme, jt as RichTextField, ka as TabsTrigger, ki as isObjectRecord, kn as isSupportedLoaderEndpoint, ko as parseSiteId, kr as designRuntimeRulesForTheme, kt as ReferenceWidgetProvider, la as FieldFrame, lr as faqHeadingFragment, m as usePreviewThemeOverlay, ma as Select, mi as isInlineTextEmpty, mr as testimonialsCarouselFragment, mt as SiteOptionWidgetProvider, n as useSiteChromeCustomizeOptional, na as isHeaderField, nn as createRoutingHelpers, nr as getLinkedContentEntryMeta, nt as PreviewInlineTextEditor, oa as mapCurrentValueForSelect, oi as parseBlockIconValue, on as parseReferenceKind, or as headingFragment, ot as useUISelector, p as PreviewThemeOverlayProvider, pi as inlineTextToPlainText, pn as createManifestFormAdapter, po as GripVertical, pr as formCopyFragment, pt as SiteOptionPickerField, q as enqueueTransaction, qa as Button, qi as parseThemeForPersistence, qn as mergeContentWithBlockStyleOverrides, qr as defaultSectionTransitionVariantForFamily, qt as canUndoHistory, r as PreviewDesignHistoryOrderProvider, ra as SdkConfigProvider, ri as planSiteChromePlacement, rn as createSnapshotFromPageRecord, rr as clientComponentRegistry, rt as PreviewTextEditor, sa as mapOptionValueForSelect, si as parseGeneratedIconAssetId, sr as cardFragment, st as EditableBlockProvider, t as SiteChromeCustomizeProvider, ta as getFieldIntent, ti as bindingSchema, tn as useDebouncedLatestSave, tr as coerceLinkedContentEntriesPayload, tt as PreviewRichTextEditor, ua as useField, ui as renderInlineText, un as PaletteProvider, ur as blogFeaturedPostFragment, ut as useEntryEditorController, va as SelectValue, vi as getCurrentResolveImageUrlContext, vn as MediaEditor, vr as ctaRowFragment, vt as loadMailingListAuthoringContext, wi as BlockApiProvider, wn as deriveLaunchReadiness, wo as unsafeAsEditorBlockId, wr as formatSiteChromeBackgroundTokenLabel, wt as ButtonVariantField, xi as SECTION_BACKGROUND_MIN_SOURCE_WIDTH, xo as sameMailingListPlacementTargeting, xr as defineFragment, xt as IconPickerField, yi as resolveImageUrlWithContext, yn as applyPageDesignEditorAction, yr as heroCopyFragment, yt as MailingListTargetingProvider, zn as visibleHeaderClearancePx, zr as parseGradientPresetId, zt as prepareBlockEditorManifest } from "./SiteChromeCustomizeContext-DEACFH9m.mjs";
3
+ import { i as useOptionalPreviewLayout, t as PreviewQueryProvider } from "./PreviewQueryProvider-Cg51xq1w.mjs";
4
+ import { _ as API_ENDPOINTS, a as usePreviewToken, c as createBearerAPIClient, d as unwrapResponse, g as resolveSurfaceDocumentAttributes, h as SURFACE_IDS, i as usePreviewAuthFetch, m as SURFACE_DOCUMENT_DATA_ATTRIBUTE, n as markPreviewAuthExpired, o as isPreviewRuntimeSessionEditable, r as usePreviewAuth, s as ApiRequestError, t as initPreviewAuth } from "./previewAuthStore-h5IgbSp4.mjs";
5
5
  import * as React$1 from "react";
6
6
  import React, { Children, Fragment, cloneElement, createContext, isValidElement, useCallback, useContext, useEffect, useId, useLayoutEffect, useMemo, useReducer, useRef, useState } from "react";
7
7
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
8
- import { createPortal } from "react-dom";
9
8
  import { z } from "zod";
9
+ import { createPortal } from "react-dom";
10
10
  //#region ../ui/src/fixed-bottom-surface.tsx
11
11
  const SURFACE_CLASS_BY_VARIANT = {
12
12
  light: "z-40 border-t border-border bg-editor-chrome-surface text-foreground",
@@ -175,7 +175,7 @@ function ResizableSplitPane({ left, right, defaultSplit = 40, minLeftWidth = 300
175
175
  }
176
176
  //#endregion
177
177
  //#region ../blocks/src/system/icons/generatedAssets.ts
178
- function isRecord$12(value) {
178
+ function isRecord$10(value) {
179
179
  return typeof value === "object" && value !== null && !Array.isArray(value);
180
180
  }
181
181
  function generatedIconAssetRefKey(ref) {
@@ -185,11 +185,11 @@ function collectGeneratedIconAssetRefs(page) {
185
185
  const blocks = [];
186
186
  for (const block of page.blocks) {
187
187
  if (block.kind !== "block.feature-cards" || typeof block.id !== "string") continue;
188
- const content = isRecord$12(block.draftContent) ? block.draftContent : isRecord$12(block.content) ? block.content : null;
188
+ const content = isRecord$10(block.draftContent) ? block.draftContent : isRecord$10(block.content) ? block.content : null;
189
189
  const cards = Array.isArray(content?.cards) ? content.cards : [];
190
190
  const refs = /* @__PURE__ */ new Map();
191
191
  for (const card of cards) {
192
- if (!isRecord$12(card)) continue;
192
+ if (!isRecord$10(card)) continue;
193
193
  const icon = parseBlockIconValue(card.icon);
194
194
  if (icon.kind !== "generated") continue;
195
195
  const ref = {
@@ -386,70 +386,171 @@ function requireThemeResources(resources, blockKind) {
386
386
  return resources;
387
387
  }
388
388
  //#endregion
389
- //#region ../blocks/src/pageRendererBoundaries.tsx
390
- const boundaryKey = (previousBlockId, nextBlockId) => `${previousBlockId}\u0000${nextBlockId}`;
391
- function isSiteStyleTransitionStyleGroup(value) {
392
- return value?.startsWith("site-style-transition-") === true;
389
+ //#region ../blocks/src/pageRenderJoins.ts
390
+ /**
391
+ * Re-points joins across omitted blocks. Pure over joins.
392
+ *
393
+ * Joins are keyed by adjacent block-id pairs, so dropping B from [A, B, C]
394
+ * removes the A→C join as well as B's own, because no A→C join was ever
395
+ * resolved. For each surviving pair the original join is kept when the pair
396
+ * was already adjacent. Across a gap, the treatment comes from the join
397
+ * entering the omitted run (A→first omitted), falling back to the one leaving
398
+ * it (last omitted→C). Nothing visual is carried: the survivors are composed
399
+ * from their own content afterwards.
400
+ *
401
+ * `survivors` are compared by identity against `originalBlocks`.
402
+ */
403
+ function retargetJoinsAcrossOmissions(input) {
404
+ const { joins, originalBlocks, survivingBlocks } = input;
405
+ if (joins.length === 0) return joins;
406
+ if (originalBlocks.every((block) => survivingBlocks.has(block))) return joins;
407
+ const byPair = joinsByPair(joins);
408
+ const retargeted = [];
409
+ let previousSurvivor = null;
410
+ let run = [];
411
+ for (const block of originalBlocks) {
412
+ if (!survivingBlocks.has(block)) {
413
+ run.push(block);
414
+ continue;
415
+ }
416
+ if (previousSurvivor?.id && block.id) {
417
+ const join = run.length === 0 ? byPair.get(pairKey(previousSurvivor.id, block.id)) : joinAcrossRun(byPair, previousSurvivor.id, block.id, run);
418
+ if (join) retargeted.push(join);
419
+ }
420
+ previousSurvivor = block;
421
+ run = [];
422
+ }
423
+ return retargeted;
393
424
  }
394
- function boundaryMapForAdjacentBlockIds(boundaries) {
395
- return new Map(boundaries.map((boundary) => [boundaryKey(boundary.previousBlockId, boundary.nextBlockId), boundary]));
425
+ function joinAcrossRun(byPair, previousBlockId, nextBlockId, run) {
426
+ const firstOmittedId = run[0]?.id;
427
+ const lastOmittedId = run[run.length - 1]?.id;
428
+ const entering = firstOmittedId ? byPair.get(pairKey(previousBlockId, firstOmittedId)) : void 0;
429
+ const exiting = lastOmittedId ? byPair.get(pairKey(lastOmittedId, nextBlockId)) : void 0;
430
+ const donor = entering ?? exiting;
431
+ return donor ? {
432
+ previousBlockId,
433
+ nextBlockId,
434
+ treatment: donor.treatment
435
+ } : void 0;
396
436
  }
397
- function boundaryBetweenBlocks(previousBlock, nextBlock, boundaries) {
398
- const previousBlockId = previousBlock?.id ?? null;
399
- const nextBlockId = nextBlock?.id ?? null;
400
- if (!previousBlockId || !nextBlockId) return null;
401
- return boundaries.get(boundaryKey(previousBlockId, nextBlockId)) ?? null;
437
+ /**
438
+ * The single composition site. For every adjacent pair of survivors with ids,
439
+ * finds its join and composes it from both survivors' final content: what
440
+ * each paints with and the frame each draws.
441
+ */
442
+ function composePageJoins(input) {
443
+ const byPair = joinsByPair(input.joins);
444
+ return input.survivors.flatMap((previous, index) => {
445
+ const next = input.survivors[index + 1];
446
+ if (!next || !previous.id || !next.id) return [];
447
+ const join = byPair.get(pairKey(previous.id, next.id));
448
+ return [{
449
+ previousBlockId: previous.id,
450
+ nextBlockId: next.id,
451
+ join: join ? composeJoin(join, previous, next) : null
452
+ }];
453
+ });
454
+ }
455
+ function composeJoin(join, previous, next) {
456
+ return {
457
+ boundaryId: pairKey(join.previousBlockId, join.nextBlockId),
458
+ previousBlockId: join.previousBlockId,
459
+ nextBlockId: join.nextBlockId,
460
+ treatment: join.treatment,
461
+ outcome: composeBoundary(sectionFactsForContent(previous.content), sectionFactsForContent(next.content))
462
+ };
463
+ }
464
+ /** Placement, reserves and paint for a join that draws; null otherwise. */
465
+ function renderedJoinLayout(join) {
466
+ if (!join || join.outcome.kind !== "shown") return null;
467
+ return boundaryLayout(join.treatment, join.outcome.composition);
468
+ }
469
+ /** Joins with a missing id on either side cannot sit between two blocks. */
470
+ function joinsByPair(joins) {
471
+ return new Map(joins.flatMap((join) => join.previousBlockId && join.nextBlockId ? [[pairKey(join.previousBlockId, join.nextBlockId), join]] : []));
472
+ }
473
+ /** Slot lookup key for an adjacent pair, in the one boundary-id scheme. */
474
+ function joinSlotKey(previousBlockId, nextBlockId) {
475
+ return pairKey(previousBlockId, nextBlockId);
476
+ }
477
+ function pairKey(previousBlockId, nextBlockId) {
478
+ return makeBoundaryId(asDesignBlockId(previousBlockId), asDesignBlockId(nextBlockId));
479
+ }
480
+ //#endregion
481
+ //#region ../blocks/src/pageRendererBoundaries.tsx
482
+ function joinSlotsByPair(slots) {
483
+ return new Map(slots.map((slot) => [joinSlotKey(slot.previousBlockId, slot.nextBlockId), slot]));
402
484
  }
403
- function renderBoundaryAfterBlock(input) {
404
- const previousBlockId = input.block.id;
405
- const nextBlockId = input.nextBlock?.id ?? null;
485
+ function joinSlotBetween(previousBlockId, nextBlockId, slots) {
406
486
  if (!previousBlockId || !nextBlockId) return null;
407
- const boundary = input.boundaryByAdjacentBlockIds.get(boundaryKey(previousBlockId, nextBlockId));
408
- if (!boundary) return null;
409
- const rendered = /* @__PURE__ */ jsx("div", {
487
+ return slots.get(joinSlotKey(previousBlockId, nextBlockId)) ?? null;
488
+ }
489
+ /**
490
+ * The markup at one join: the painted boundary element when the join draws,
491
+ * then whatever `renderJoin` adds. Null when there is nothing to render.
492
+ */
493
+ function renderJoinSlot(input) {
494
+ const { slot } = input;
495
+ if (!slot) return null;
496
+ const layout = renderedJoinLayout(slot.join);
497
+ const painted = slot.join && layout ? /* @__PURE__ */ jsx("div", {
410
498
  "aria-hidden": "true",
411
499
  "data-block-boundary": "",
412
- "data-boundary-id": boundary.boundaryId,
413
- "data-boundary-previous-block-id": boundary.previousBlockId,
414
- "data-boundary-next-block-id": boundary.nextBlockId,
415
- "data-style-group": boundary.styleGroup,
416
- style: boundaryCssVarsStyle(boundary)
417
- }, `${input.blockKey}:boundary`);
418
- return input.wrapBoundary ? input.wrapBoundary(boundary, rendered) : rendered;
419
- }
420
- function boundaryCssVarsStyle(boundary) {
421
- return {
422
- "--site-style-transition-from": boundary.cssVars.from,
423
- "--site-style-transition-to": boundary.cssVars.to
424
- };
500
+ "data-boundary-id": slot.join.boundaryId,
501
+ "data-boundary-previous-block-id": slot.previousBlockId,
502
+ "data-boundary-next-block-id": slot.nextBlockId,
503
+ "data-boundary-treatment": slot.join.treatment,
504
+ "data-boundary-placement": layout.placement,
505
+ style: boundaryPaintStyle(layout.paint)
506
+ }, `${input.blockKey}:boundary`) : null;
507
+ const extra = input.renderJoin?.({
508
+ previousBlockId: slot.previousBlockId,
509
+ nextBlockId: slot.nextBlockId,
510
+ join: slot.join
511
+ });
512
+ if (!painted && (extra === null || extra === void 0)) return null;
513
+ return /* @__PURE__ */ jsxs(React.Fragment, { children: [painted, extra] }, `${input.blockKey}:join`);
425
514
  }
426
- function boundaryReserveCssVarsStyle(input) {
427
- const before = input.before?.metrics.reserveCss ?? null;
428
- const after = input.after?.metrics.reserveCss ?? null;
429
- if (!before && !after) return void 0;
430
- return {
431
- ...before ? { "--site-style-boundary-before-reserve": before } : {},
432
- ...after ? { "--site-style-boundary-after-reserve": after } : {}
433
- };
515
+ /**
516
+ * The one render-edge place a theme token becomes CSS.
517
+ */
518
+ function themeTokenCss(token) {
519
+ return `rgb(var(--tb-${token}))`;
434
520
  }
435
- function transitionCssVarsStyle(content) {
436
- const transitionStyles = isObjectRecord(content._transitionStyles) ? content._transitionStyles : null;
437
- const cssVars = isObjectRecord(transitionStyles?.cssVars) ? transitionStyles.cssVars : null;
438
- const from = typeof cssVars?.from === "string" ? cssVars.from : null;
439
- const to = typeof cssVars?.to === "string" ? cssVars.to : null;
440
- if (!from && !to) return void 0;
521
+ function boundaryPaintStyle(paint) {
441
522
  return {
442
- ...from ? { "--site-style-transition-from": from } : {},
443
- ...to ? { "--site-style-transition-to": to } : {}
523
+ "--boundary-shape-paint": themeTokenCss(paint.shape),
524
+ ...paint.band ? { "--boundary-band-paint": themeTokenCss(paint.band) } : {}
444
525
  };
445
526
  }
446
- function mergeStyleObjects(left, right) {
447
- if (!left) return right;
448
- if (!right) return left;
449
- return {
450
- ...left,
451
- ...right
527
+ /**
528
+ * Reserve attributes and variables for a block wrapper, from the joins on
529
+ * either side. A join's `before` reserve sits inside its previous section, so
530
+ * it pads the bottom of the block above the join; its `after` reserve pads the
531
+ * top of the block below. Joins that do not draw reserve nothing.
532
+ */
533
+ function blockBoundaryReserves(input) {
534
+ const top = reserveOnSide(input.before, "after");
535
+ const bottom = reserveOnSide(input.after, "before");
536
+ const style = {
537
+ ...top ? { "--site-style-boundary-before-reserve": top.length } : {},
538
+ ...bottom ? { "--site-style-boundary-after-reserve": bottom.length } : {}
452
539
  };
540
+ return {
541
+ topPlacement: top?.placement,
542
+ bottomPlacement: bottom?.placement,
543
+ style: top || bottom ? style : void 0
544
+ };
545
+ }
546
+ /** The reserve one join needs on one side of itself, if it draws at all. */
547
+ function reserveOnSide(slot, side) {
548
+ const layout = renderedJoinLayout(slot?.join ?? null);
549
+ const length = layout?.reserves[side] ?? null;
550
+ return layout && length ? {
551
+ length,
552
+ placement: layout.placement
553
+ } : null;
453
554
  }
454
555
  function pageBlockPosition(index, blockCount) {
455
556
  if (blockCount <= 1) return "only";
@@ -652,11 +753,10 @@ function buildPageRenderPlan(input) {
652
753
  return {
653
754
  entries,
654
755
  omitted,
655
- runtimeBoundaries: retargetBoundariesAcrossOmissions({
656
- boundaries: input.runtimeBoundaries,
756
+ runtimeJoins: retargetJoinsAcrossOmissions({
757
+ joins: input.runtimeJoins ?? [],
657
758
  originalBlocks: input.page.blocks,
658
- survivingBlocks: new Set(entries.map((entry) => entry.block)),
659
- previewStage: input.previewStage
759
+ survivingBlocks: new Set(entries.map((entry) => entry.block))
660
760
  })
661
761
  };
662
762
  }
@@ -758,86 +858,15 @@ function getBlockOverride(blockKind, overrides) {
758
858
  * For draft/preview: draftContent takes priority over content.
759
859
  * For published: content is the source of truth.
760
860
  */
761
- function getRenderableContent(block, previewStage = "published") {
762
- const source = previewStage === "preview" && block.draftContent ? block.draftContent : block.content ?? {};
763
- return isObjectRecord(source) ? source : {};
764
- }
765
861
  /**
766
- * Re-points section boundaries across omitted blocks.
767
- *
768
- * Boundaries are keyed by adjacent block-id *pairs*, so dropping B from
769
- * [A, B, C] does not merely remove B's boundaries — it removes the boundary
770
- * between the survivors, because no `A→C` key was ever compiled.
771
- *
772
- * Per decision D2 the treatment for a merged gap comes from the boundary
773
- * entering the omitted run (`A→firstOmitted`), falling back to the one leaving
774
- * it (`lastOmitted→C`). The destination surface is a separate question: only
775
- * the exiting boundary knows what C looks like, so the merged boundary ends on
776
- * that endpoint rather than on the omitted block's. In the exiting-only
777
- * fallback the origin remains an approximation: `from` is the omitted block's
778
- * surface, because no compiled boundary carries A's. The hosted path no longer
779
- * needs this at all (site-renderer admits blocks before compiling boundaries);
780
- * it remains the safety net for an SDK whose compiled boundaries predate an
781
- * omission.
862
+ * The content a block renders with. Every render path (public, preview,
863
+ * templates, SDK) chooses content here, so this is also where a stale
864
+ * `site-style-transition-*` styleGroup is dropped; authored values survive.
782
865
  */
783
- function retargetBoundariesAcrossOmissions(input) {
784
- const { boundaries, originalBlocks, survivingBlocks, previewStage } = input;
785
- if (boundaries === void 0) return void 0;
786
- if (boundaries.length === 0) return boundaries;
787
- if (!originalBlocks.some((block) => !survivingBlocks.has(block))) return boundaries;
788
- const byPair = new Map(boundaries.map((boundary) => [pairKey(boundary.previousBlockId, boundary.nextBlockId), boundary]));
789
- const retargeted = [];
790
- let previousSurvivor = null;
791
- let run = [];
792
- for (const block of originalBlocks) {
793
- if (!survivingBlocks.has(block)) {
794
- run.push(block);
795
- continue;
796
- }
797
- if (previousSurvivor?.id && block.id) {
798
- const boundary = run.length === 0 ? byPair.get(pairKey(previousSurvivor.id, block.id)) : mergedBoundary({
799
- byPair,
800
- previousBlock: previousSurvivor,
801
- previousBlockId: previousSurvivor.id,
802
- nextBlock: block,
803
- nextBlockId: block.id,
804
- run,
805
- previewStage
806
- });
807
- if (boundary) retargeted.push(boundary);
808
- }
809
- previousSurvivor = block;
810
- run = [];
811
- }
812
- return retargeted;
813
- }
814
- function mergedBoundary(input) {
815
- const { byPair, previousBlock, previousBlockId, nextBlock, nextBlockId, run, previewStage } = input;
816
- const firstOmittedId = run[0]?.id;
817
- const lastOmittedId = run[run.length - 1]?.id;
818
- const entering = firstOmittedId ? byPair.get(pairKey(previousBlockId, firstOmittedId)) : void 0;
819
- const exiting = lastOmittedId ? byPair.get(pairKey(lastOmittedId, nextBlockId)) : void 0;
820
- const donor = entering ?? exiting;
821
- if (!donor) return void 0;
822
- const transition = compileTransitionRuntime({
823
- treatment: donor.treatment,
824
- from: donor.from,
825
- to: exiting?.to ?? donor.to
826
- });
827
- return retargetCompiledBoundaryRuntimeForContentAdjacency({
828
- ...donor,
829
- boundaryId: makeBoundaryId(asDesignBlockId(previousBlockId), asDesignBlockId(nextBlockId)),
830
- previousBlockId,
831
- nextBlockId,
832
- from: transition.from,
833
- to: transition.to,
834
- cssVars: transition.cssVars
835
- }, {
836
- currentContent: getRenderableContent(previousBlock, previewStage),
837
- nextContent: getRenderableContent(nextBlock, previewStage)
838
- });
866
+ function getRenderableContent(block, previewStage = "published") {
867
+ const source = previewStage === "preview" && block.draftContent ? block.draftContent : block.content ?? {};
868
+ return isObjectRecord(source) ? stripStaleTransitionStyleGroup(source) : {};
839
869
  }
840
- const pairKey = boundaryKey;
841
870
  //#endregion
842
871
  //#region ../blocks/src/system/manifest/hydrateLinks.ts
843
872
  /**
@@ -872,7 +901,7 @@ function hydrateResolvedBookingConsentValue(value, context) {
872
901
  const hydratedItems = value.map((item) => hydrateResolvedBookingConsentValue(item, context));
873
902
  return hydratedItems.every((item, index) => item === value[index]) ? value : hydratedItems;
874
903
  }
875
- if (!isRecord$13(value)) return value;
904
+ if (!isRecord$11(value)) return value;
876
905
  if (isBookingConsentCarrier(value)) {
877
906
  const agreement = hydrateValue(value.agreement, context);
878
907
  return agreement === value.agreement ? value : {
@@ -892,7 +921,7 @@ function hydrateValue(value, context) {
892
921
  const resolvedItems = value.map((item) => hydrateValue(item, context));
893
922
  return resolvedItems.every((item, index) => item === value[index]) ? value : resolvedItems;
894
923
  }
895
- if (isRecord$13(value)) {
924
+ if (isRecord$11(value)) {
896
925
  if (isInternalLink(value)) return hydrateInternalLink(value, context.routes);
897
926
  if (isPageLink(value)) return hydratePageLink(value, context);
898
927
  if (isEntryLink(value)) return hydrateEntryLink(value, context);
@@ -957,10 +986,43 @@ function hydrateEntryLink(link, context) {
957
986
  //#region ../blocks/src/system/manifest/resolveBlockData.ts
958
987
  function resolveBlockData(blockId, dataLoaders, dataContext, routes) {
959
988
  const raw = blockId ? dataContext?.resolvedData?.[blockId] : void 0;
960
- if (isRecord$13(raw)) return routes ? hydrateResolvedBookingConsentLinks(raw, routes, dataContext?.pagesByIdentifier, dataContext?.entriesByIdentifier) : raw;
989
+ if (isRecord$11(raw)) return routes ? hydrateResolvedBookingConsentLinks(raw, routes, dataContext?.pagesByIdentifier, dataContext?.entriesByIdentifier) : raw;
961
990
  return dataLoaders && typeof dataLoaders === "object" && Object.keys(dataLoaders).length > 0 ? {} : void 0;
962
991
  }
963
992
  //#endregion
993
+ //#region ../blocks/src/system/runtime/nodes/newsletter-form.block-submission.ts
994
+ /** Authorise one block source for both public and preview rendering. */
995
+ function planNewsletterBlockSubmission(placement) {
996
+ if (placement.stage === "published") {
997
+ const sourceRef = buildMailingListSignupBlockSourceRef(placement.blockId, placement.selectedContentVersionId);
998
+ return sourceRef ? {
999
+ tag: "ready",
1000
+ sourceRef
1001
+ } : { tag: "unavailable" };
1002
+ }
1003
+ if (placement.publishedPlacement) return planNewsletterPreviewSubmission({
1004
+ blockId: placement.blockId,
1005
+ publishedContentId: placement.publishedPlacement.id,
1006
+ renderedContent: placement.renderedContent,
1007
+ publishedContent: placement.publishedPlacement.content
1008
+ });
1009
+ if (placement.stage === "preview") return { tag: "unpublished-form" };
1010
+ return { tag: "unavailable" };
1011
+ }
1012
+ /** Decide whether the visible draft can safely cite the published placement. */
1013
+ function planNewsletterPreviewSubmission(placement) {
1014
+ if (!placement.publishedContentId) return { tag: "unpublished-form" };
1015
+ if (!placement.publishedContent) return { tag: "unpublished-settings" };
1016
+ const draft = parseMailingListPlacementTargeting(placement.renderedContent.targeting ?? { mode: "default" });
1017
+ const published = parseMailingListPlacementTargeting(placement.publishedContent.targeting);
1018
+ if (!draft.ok || !published.ok || !sameMailingListPlacementTargeting(draft.value, published.value)) return { tag: "unpublished-settings" };
1019
+ const sourceRef = buildMailingListSignupBlockSourceRef(placement.blockId, placement.publishedContentId);
1020
+ return sourceRef ? {
1021
+ tag: "ready",
1022
+ sourceRef
1023
+ } : { tag: "unpublished-settings" };
1024
+ }
1025
+ //#endregion
964
1026
  //#region ../blocks/src/pageRenderPreparation.ts
965
1027
  /**
966
1028
  * Stage two of the render plan.
@@ -992,23 +1054,44 @@ function preparePageRender(input) {
992
1054
  prepared
993
1055
  });
994
1056
  }
995
- if (constructionFailures.length === 0 || input.audience === "authoring") return {
996
- entries,
997
- constructionFailures,
998
- runtimeBoundaries: input.plan.runtimeBoundaries
999
- };
1000
- const survivors = entries.filter((candidate) => candidate.prepared.kind !== "render-threw");
1057
+ const survivors = input.audience === "authoring" ? entries : entries.filter((candidate) => candidate.prepared.kind !== "render-threw");
1001
1058
  return {
1002
1059
  entries: survivors,
1003
1060
  constructionFailures,
1004
- runtimeBoundaries: retargetBoundariesAcrossOmissions({
1005
- boundaries: input.plan.runtimeBoundaries,
1006
- originalBlocks: input.plan.entries.map((planned) => planned.block),
1007
- survivingBlocks: new Set(survivors.map((survivor) => survivor.entry.block)),
1008
- previewStage: input.previewStage
1009
- })
1061
+ joins: composeSurvivorJoins(input.plan, survivors, input.themeResources)
1010
1062
  };
1011
1063
  }
1064
+ /**
1065
+ * The only place joins are composed. Plan-time omissions were already
1066
+ * re-pointed by the plan; construction failures are re-pointed here by the
1067
+ * same primitive, so `[A, B, C]` losing B still gets an A→C join. Each
1068
+ * survivor is then classified from its final content.
1069
+ */
1070
+ function composeSurvivorJoins(plan, survivors, themeResources) {
1071
+ return composePageJoins({
1072
+ joins: retargetJoinsAcrossOmissions({
1073
+ joins: plan.runtimeJoins,
1074
+ originalBlocks: plan.entries.map((planned) => planned.block),
1075
+ survivingBlocks: new Set(survivors.map((survivor) => survivor.entry.block))
1076
+ }),
1077
+ survivors: survivors.map(({ entry }) => ({
1078
+ id: entry.block.id,
1079
+ kind: entry.block.kind,
1080
+ content: boundaryClassificationContent(entry, themeResources)
1081
+ }))
1082
+ });
1083
+ }
1084
+ /**
1085
+ * The content a join is classified from must be the content that paints the
1086
+ * section. The default block renderer layers the theme's per-block style
1087
+ * defaults (`theme.blockOverrides[kind].styles`, background included) under
1088
+ * the block's own `_sectionStyles`, so classify that same projection. An
1089
+ * override component renders its own markup from the unmerged content.
1090
+ */
1091
+ function boundaryClassificationContent(entry, themeResources) {
1092
+ if (entry.kind !== "renderable" || entry.override) return entry.renderableContent;
1093
+ return mergeContentWithBlockStyleOverrides(entry.renderableContent, themeResources.kind === "available" ? themeResources.config : void 0, entry.block.kind);
1094
+ }
1012
1095
  function prepareEntry(entry, input) {
1013
1096
  if (entry.kind !== "renderable") return { kind: "plan-decided" };
1014
1097
  const draftContent = previewableEditorContent(entry);
@@ -1068,9 +1151,20 @@ function buildBlockOverrideProps(input) {
1068
1151
  imageResolveContext: input.imageResolveContext,
1069
1152
  blockId: block.id ?? null,
1070
1153
  contentVersionId: block.contentVersionId ?? null,
1154
+ ...newsletterBlockProps(block, input.content, dataContext?.previewStage),
1071
1155
  blockKind: block.kind
1072
1156
  };
1073
1157
  }
1158
+ function newsletterBlockProps(block, renderedContent, stage) {
1159
+ if (block.kind !== "block.newsletter-signup") return {};
1160
+ return { newsletterBlockSubmission: planNewsletterBlockSubmission({
1161
+ blockId: block.id,
1162
+ selectedContentVersionId: block.contentVersionId ?? null,
1163
+ publishedPlacement: block.publishedPlacement ?? null,
1164
+ renderedContent,
1165
+ stage
1166
+ }) };
1167
+ }
1074
1168
  /** Site, transport and session context a block needs to call back to the API. */
1075
1169
  function blockSessionProps(dataContext) {
1076
1170
  return {
@@ -1181,7 +1275,7 @@ function EditorPageRenderer(props) {
1181
1275
  });
1182
1276
  }
1183
1277
  function PageRendererCore(props) {
1184
- const { page, audience, runtimeBoundaries, dataContext, routeMap, registry, sdkConfig, customBlocks, blockOverrides } = props;
1278
+ const { page, audience, runtimeJoins, dataContext, routeMap, registry, sdkConfig, customBlocks, blockOverrides } = props;
1185
1279
  const imageResolveContext = React$1.useMemo(() => resolvePageRendererImageResolveContext(dataContext), [
1186
1280
  dataContext?.imageResolveContext,
1187
1281
  dataContext?.mediaAssets,
@@ -1197,7 +1291,7 @@ function PageRendererCore(props) {
1197
1291
  blocks: []
1198
1292
  },
1199
1293
  audience,
1200
- runtimeBoundaries,
1294
+ runtimeJoins,
1201
1295
  previewStage,
1202
1296
  sdkConfig,
1203
1297
  customBlocks,
@@ -1205,7 +1299,7 @@ function PageRendererCore(props) {
1205
1299
  }), [
1206
1300
  page,
1207
1301
  audience,
1208
- runtimeBoundaries,
1302
+ runtimeJoins,
1209
1303
  previewStage,
1210
1304
  sdkConfig,
1211
1305
  customBlocks,
@@ -1222,19 +1316,16 @@ function PageRendererCore(props) {
1222
1316
  dataContext,
1223
1317
  routeMap,
1224
1318
  themeResources,
1225
- imageResolveContext,
1226
- previewStage
1319
+ imageResolveContext
1227
1320
  }), [
1228
1321
  plan,
1229
1322
  audience,
1230
1323
  dataContext,
1231
1324
  routeMap,
1232
1325
  themeResources,
1233
- imageResolveContext,
1234
- previewStage
1326
+ imageResolveContext
1235
1327
  ]);
1236
- const boundaryByAdjacentBlockIds = React$1.useMemo(() => boundaryMapForAdjacentBlockIds(preparation.runtimeBoundaries ?? []), [preparation.runtimeBoundaries]);
1237
- const usesRuntimeBoundaries = preparation.runtimeBoundaries !== void 0;
1328
+ const joinSlots = React$1.useMemo(() => joinSlotsByPair(preparation.joins), [preparation.joins]);
1238
1329
  reportAndReplayOmissions({
1239
1330
  plan,
1240
1331
  preparation,
@@ -1252,10 +1343,9 @@ function PageRendererCore(props) {
1252
1343
  themeResources,
1253
1344
  imageResolveContext,
1254
1345
  resolvedRegistry,
1255
- boundaryByAdjacentBlockIds,
1256
- usesRuntimeBoundaries,
1346
+ joinSlots,
1257
1347
  wrapBlock: props.wrapBlock,
1258
- wrapBoundary: props.wrapBoundary
1348
+ renderJoin: props.renderJoin
1259
1349
  })) });
1260
1350
  }
1261
1351
  /**
@@ -1344,27 +1434,25 @@ function requireEntryBlockOverride(entry, themeResources) {
1344
1434
  }
1345
1435
  /**
1346
1436
  * Renders one planned block: its wrapper, style-group data attributes,
1347
- * boundary reserve space and any boundary or transition sibling that follows.
1437
+ * boundary reserve space and the join markup that follows it.
1348
1438
  *
1349
1439
  * Extracted from PageRendererCore so the component stays about wiring the plan
1350
1440
  * rather than also owning per-block markup.
1351
1441
  */
1352
1442
  function renderPlanEntry(input) {
1353
- const { index, entries, props, themeResources, imageResolveContext, resolvedRegistry, boundaryByAdjacentBlockIds, usesRuntimeBoundaries, wrapBlock, wrapBoundary } = input;
1443
+ const { index, entries, props, themeResources, imageResolveContext, resolvedRegistry, joinSlots, wrapBlock, renderJoin } = input;
1354
1444
  const entry = input.entry.entry;
1355
1445
  const block = entry.block;
1356
1446
  const blockPosition = pageBlockPosition(index, entries.length);
1357
1447
  const blockKey = blockKeyFor(block, index);
1358
1448
  const previousBlock = entries[index - 1]?.entry.block ?? null;
1359
1449
  const nextBlock = entries[index + 1]?.entry.block ?? null;
1360
- const boundaryBefore = boundaryBetweenBlocks(previousBlock, block, boundaryByAdjacentBlockIds);
1361
- const boundaryAfter = boundaryBetweenBlocks(block, nextBlock, boundaryByAdjacentBlockIds);
1362
- const boundaryElement = renderBoundaryAfterBlock({
1363
- block,
1364
- nextBlock,
1450
+ const joinBefore = joinSlotBetween(previousBlock?.id, block.id, joinSlots);
1451
+ const joinAfter = joinSlotBetween(block.id, nextBlock?.id, joinSlots);
1452
+ const boundaryElement = renderJoinSlot({
1453
+ slot: joinAfter,
1365
1454
  blockKey,
1366
- boundaryByAdjacentBlockIds,
1367
- wrapBoundary
1455
+ renderJoin
1368
1456
  });
1369
1457
  const cleanKind = block.kind.replace(/^block\./, "");
1370
1458
  const managesOwnWrapper = entry.kind === "renderable" && entry.managesOwnWrapper;
@@ -1387,11 +1475,10 @@ function renderPlanEntry(input) {
1387
1475
  const styleGroup = typeof renderableContent.styleGroup === "string" ? renderableContent.styleGroup : void 0;
1388
1476
  const blockLook = typeof renderableContent.blockLook === "string" ? renderableContent.blockLook : void 0;
1389
1477
  const blockComposition = readBlockComposition(renderableContent.blockComposition);
1390
- const transitionStyle = transitionCssVarsStyle(renderableContent);
1391
- const blockStyle = mergeStyleObjects(transitionStyle, boundaryReserveCssVarsStyle({
1392
- before: boundaryBefore,
1393
- after: boundaryAfter
1394
- }));
1478
+ const reserves = blockBoundaryReserves({
1479
+ before: joinBefore,
1480
+ after: joinAfter
1481
+ });
1395
1482
  const blockElement = /* @__PURE__ */ jsx("div", {
1396
1483
  className: wrapperClassName,
1397
1484
  "data-block": cleanKind,
@@ -1403,21 +1490,14 @@ function renderPlanEntry(input) {
1403
1490
  "data-block-composition": blockComposition?.treatment,
1404
1491
  "data-block-composition-kind": blockComposition?.kind,
1405
1492
  "data-page-block-position": blockPosition,
1406
- "data-site-style-boundary-before": boundaryBefore?.metrics.size,
1407
- "data-site-style-boundary-after": boundaryAfter?.metrics.size,
1493
+ "data-site-style-boundary-before": reserves.topPlacement,
1494
+ "data-site-style-boundary-after": reserves.bottomPlacement,
1408
1495
  "data-style-group": styleGroup,
1409
- style: blockStyle,
1496
+ style: reserves.style,
1410
1497
  children: /* @__PURE__ */ jsx(MemoBlockSection, { ...blockSectionProps })
1411
1498
  }, blockKey);
1412
1499
  if (boundaryElement) return /* @__PURE__ */ jsxs(React$1.Fragment, { children: [blockElement, boundaryElement] }, blockKey);
1413
- if (usesRuntimeBoundaries || !isSiteStyleTransitionStyleGroup(styleGroup)) return blockElement;
1414
- return /* @__PURE__ */ jsxs(React$1.Fragment, { children: [blockElement, /* @__PURE__ */ jsx("div", {
1415
- "aria-hidden": "true",
1416
- "data-block-transition": "",
1417
- "data-block-transition-for": block.id ?? blockKey,
1418
- "data-style-group": styleGroup,
1419
- style: transitionStyle
1420
- })] }, blockKey);
1500
+ return blockElement;
1421
1501
  }
1422
1502
  function resolvePageRendererImageResolveContext(dataContext) {
1423
1503
  const input = dataContext?.imageResolveContext;
@@ -2063,6 +2143,17 @@ function coerceToString(value) {
2063
2143
  return "";
2064
2144
  }
2065
2145
  /**
2146
+ * The appointment-services catalogue (issue 1403) pairs the services with the
2147
+ * site's ordered categories. Both are needed to group them, so that response
2148
+ * is passed through whole; any other `{ services }` wrapper is unwrapped.
2149
+ */
2150
+ function coerceServicesPayload(record) {
2151
+ return Array.isArray(record.services) && Array.isArray(record.categories) ? {
2152
+ services: record.services,
2153
+ categories: record.categories
2154
+ } : record.services;
2155
+ }
2156
+ /**
2066
2157
  * Extract data from API response.
2067
2158
  * Unwraps common response wrappers: { data }, { form }, { entries }, { services }, { teamMembers }
2068
2159
  *
@@ -2077,7 +2168,7 @@ function coercePayload(payload) {
2077
2168
  if ("data" in record && typeof record.data !== "function") return record.data;
2078
2169
  if ("form" in record && typeof record.form !== "function") return record.form;
2079
2170
  if ("entries" in record && typeof record.entries !== "function") return record.entries;
2080
- if ("services" in record && typeof record.services !== "function") return record.services;
2171
+ if ("services" in record && typeof record.services !== "function") return coerceServicesPayload(record);
2081
2172
  if ("teamMembers" in record && typeof record.teamMembers !== "function") return record.teamMembers;
2082
2173
  }
2083
2174
  return payload;
@@ -2865,7 +2956,7 @@ function assertRelativeStoragePath(value) {
2865
2956
  if (!parsed.ok) throw new Error(`Expected RelativeStoragePath, got ${parsed.error.tag}`);
2866
2957
  return parsed.value;
2867
2958
  }
2868
- function isRecord$11(value) {
2959
+ function isRecord$9(value) {
2869
2960
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
2870
2961
  }
2871
2962
  function parseFileKindJson(value) {
@@ -3086,7 +3177,7 @@ function parseEntitledCustomerAccessScopeJson(value) {
3086
3177
  }
3087
3178
  }
3088
3179
  function requireRecord(value) {
3089
- if (!isRecord$11(value)) return err("expected-object");
3180
+ if (!isRecord$9(value)) return err("expected-object");
3090
3181
  return ok(value);
3091
3182
  }
3092
3183
  function requireString(value) {
@@ -3338,7 +3429,7 @@ const DEFAULT_MESSAGES = {
3338
3429
  update: "Failed to update media asset",
3339
3430
  delete: "Failed to delete media asset"
3340
3431
  };
3341
- function isRecord$10(value) {
3432
+ function isRecord$8(value) {
3342
3433
  return typeof value === "object" && value !== null;
3343
3434
  }
3344
3435
  const normalizeLabels = (labels) => labels !== void 0 && labels.length > 0 ? labels.map((label) => label.trim()).filter((label) => label.length > 0).join(",") : void 0;
@@ -3372,7 +3463,7 @@ const filterUpdatePayload = (input) => {
3372
3463
  return payload;
3373
3464
  };
3374
3465
  const extractErrorMessage = (body) => {
3375
- if (!isRecord$10(body)) return typeof body === "string" && body.trim().length > 0 ? body : null;
3466
+ if (!isRecord$8(body)) return typeof body === "string" && body.trim().length > 0 ? body : null;
3376
3467
  for (const key of [
3377
3468
  "error",
3378
3469
  "message",
@@ -3385,11 +3476,11 @@ const extractErrorMessage = (body) => {
3385
3476
  const details = body.details;
3386
3477
  if (Array.isArray(details)) for (const entry of details) {
3387
3478
  if (typeof entry === "string" && entry.trim().length > 0) return entry;
3388
- if (isRecord$10(entry) && typeof entry.message === "string" && entry.message.trim().length > 0) return entry.message;
3479
+ if (isRecord$8(entry) && typeof entry.message === "string" && entry.message.trim().length > 0) return entry.message;
3389
3480
  }
3390
3481
  const errors = body.errors;
3391
3482
  if (Array.isArray(errors)) {
3392
- for (const entry of errors) if (isRecord$10(entry) && typeof entry.message === "string" && entry.message.trim().length > 0) return entry.message;
3483
+ for (const entry of errors) if (isRecord$8(entry) && typeof entry.message === "string" && entry.message.trim().length > 0) return entry.message;
3393
3484
  }
3394
3485
  return null;
3395
3486
  };
@@ -5267,7 +5358,7 @@ function parseBackgroundOverrideFromContent(content) {
5267
5358
  * Only the explicit owner marker can make a background a page-design override.
5268
5359
  */
5269
5360
  function parseCanonicalSectionBackground(content) {
5270
- const background = (isRecord$9(content._sectionStyles) ? content._sectionStyles : null)?.background;
5361
+ const background = (isRecord$7(content._sectionStyles) ? content._sectionStyles : null)?.background;
5271
5362
  if (background === null || background === void 0) return { kind: "none" };
5272
5363
  const canonical = parseBackgroundContent(background);
5273
5364
  if (!canonical) return { kind: "none" };
@@ -5285,7 +5376,7 @@ function parseBackgroundOverride(value) {
5285
5376
  kind: "supported",
5286
5377
  override: DEFAULT_BACKGROUND_OVERRIDE
5287
5378
  };
5288
- if (!isRecord$9(value)) return {
5379
+ if (!isRecord$7(value)) return {
5289
5380
  kind: "unsupported",
5290
5381
  reason: "unsupported-shape",
5291
5382
  background: {}
@@ -5373,7 +5464,7 @@ function parseBackgroundOverride(value) {
5373
5464
  }
5374
5465
  }
5375
5466
  function applyBackgroundOverrideContentPatch(content, override) {
5376
- const sectionStyles = isRecord$9(content._sectionStyles) ? content._sectionStyles : {};
5467
+ const sectionStyles = isRecord$7(content._sectionStyles) ? content._sectionStyles : {};
5377
5468
  const serialized = serializeBackgroundOverride(override);
5378
5469
  if (serialized === null) return withSectionStyles(content, omitRecordKey$1(sectionStyles, "background"));
5379
5470
  return withSectionStyles(content, {
@@ -5597,7 +5688,7 @@ function imageAllowed(mediaId, pool) {
5597
5688
  return pool?.some((item) => item.mediaId === mediaId) ?? false;
5598
5689
  }
5599
5690
  function parseImageMediaAssetId(value) {
5600
- if (!isRecord$9(value)) return { kind: "missing" };
5691
+ if (!isRecord$7(value)) return { kind: "missing" };
5601
5692
  if (value.type !== void 0 && value.type !== "image") return { kind: "missing" };
5602
5693
  const parsed = parseMediaAssetId(value.assetId);
5603
5694
  if (!parsed.ok) return value.assetId === void 0 || value.assetId === null ? { kind: "missing" } : { kind: "invalid" };
@@ -5638,7 +5729,7 @@ function withSectionStyles(content, sectionStyles) {
5638
5729
  function omitRecordKey$1(content, key) {
5639
5730
  return Object.fromEntries(Object.entries(content).filter(([entryKey]) => entryKey !== key));
5640
5731
  }
5641
- function isRecord$9(value) {
5732
+ function isRecord$7(value) {
5642
5733
  return typeof value === "object" && value !== null && !Array.isArray(value);
5643
5734
  }
5644
5735
  //#endregion
@@ -6238,10 +6329,12 @@ function applyPreviewCustomizeActionToLoadedState(state, action) {
6238
6329
  ...state.editorModel,
6239
6330
  boundaries: state.editorModel.boundaries.map((boundary) => {
6240
6331
  if (boundary.previousBlockId !== action.previousBlockId || boundary.nextBlockId !== action.nextBlockId) return boundary;
6241
- return {
6242
- ...boundary,
6243
- breakChoice: optimisticBoundaryBreakChoice(state.editorModel, boundary, action)
6244
- };
6332
+ return resolvePageDesignEditorBoundaryForChoice({
6333
+ editorModel: state.editorModel,
6334
+ previousBlockId: boundary.previousBlockId,
6335
+ nextBlockId: boundary.nextBlockId,
6336
+ choice: optimisticBoundaryChoice(action)
6337
+ }) ?? boundary;
6245
6338
  })
6246
6339
  }
6247
6340
  };
@@ -6274,26 +6367,17 @@ function optimisticLayoutLookState(block, layoutVariantKey) {
6274
6367
  default: return assertNever$1(plan, "Unhandled layout/Look compatibility plan");
6275
6368
  }
6276
6369
  }
6277
- function optimisticBoundaryBreakChoice(editorModel, boundary, action) {
6370
+ /**
6371
+ * The stored choice an action leaves behind. The effective break, its source
6372
+ * and the join are then resolved by theme-core, exactly as the server will.
6373
+ */
6374
+ function optimisticBoundaryChoice(action) {
6278
6375
  switch (action.kind) {
6279
- case "set-boundary": return {
6280
- kind: "user-pinned",
6281
- value: action.boundaryOptionId,
6282
- status: "supported",
6283
- effectiveValue: action.boundaryOptionId
6284
- };
6285
- case "reset-boundary": return {
6286
- kind: "auto",
6287
- effectiveValue: autoBoundaryEffectiveValue(editorModel, boundary)
6288
- };
6376
+ case "set-boundary": return userPinnedDesignChoice(boundaryTreatmentForBoundaryOptionId(action.boundaryOptionId));
6377
+ case "reset-boundary": return autoDesignChoice();
6289
6378
  default: return assertNever$1(action, "Unhandled optimistic boundary action");
6290
6379
  }
6291
6380
  }
6292
- function autoBoundaryEffectiveValue(editorModel, boundary) {
6293
- const preferredBoundaryOptionId = editorModel.pageFlowPresets.find((preset) => preset.id === editorModel.pageFlow.effectiveValue)?.defaultBoundaryOptionId ?? null;
6294
- if (preferredBoundaryOptionId && boundary.availableBreaks.some((option) => option.id === preferredBoundaryOptionId)) return preferredBoundaryOptionId;
6295
- return boundary.availableBreaks[0]?.id ?? null;
6296
- }
6297
6381
  //#endregion
6298
6382
  //#region ../blocks/src/system/customize/facets.ts
6299
6383
  function defineCustomizeFacet(definition) {
@@ -6439,8 +6523,8 @@ function contentWithPreviousLayoutVariant(currentContent, previousContent) {
6439
6523
  return nextContent;
6440
6524
  }
6441
6525
  function contentWithPreviousBackground(currentContent, previousContent) {
6442
- const previousSectionStyles = isRecord$8(previousContent._sectionStyles) ? previousContent._sectionStyles : {};
6443
- const nextSectionStyles = { ...isRecord$8(currentContent._sectionStyles) ? currentContent._sectionStyles : {} };
6526
+ const previousSectionStyles = isRecord$6(previousContent._sectionStyles) ? previousContent._sectionStyles : {};
6527
+ const nextSectionStyles = { ...isRecord$6(currentContent._sectionStyles) ? currentContent._sectionStyles : {} };
6444
6528
  if (Object.prototype.hasOwnProperty.call(previousSectionStyles, "background")) nextSectionStyles.background = previousSectionStyles.background;
6445
6529
  else delete nextSectionStyles.background;
6446
6530
  if (Object.keys(nextSectionStyles).length > 0) return {
@@ -6453,9 +6537,9 @@ function contentWithPreviousBackground(currentContent, previousContent) {
6453
6537
  }
6454
6538
  function withRuntimeBackgroundImageAsset(content, imageAsset) {
6455
6539
  if (!imageAsset) return content;
6456
- const sectionStyles = isRecord$8(content._sectionStyles) ? content._sectionStyles : null;
6457
- const background = isRecord$8(sectionStyles?.background) ? sectionStyles.background : null;
6458
- const image = isRecord$8(background?.image) ? background.image : null;
6540
+ const sectionStyles = isRecord$6(content._sectionStyles) ? content._sectionStyles : null;
6541
+ const background = isRecord$6(sectionStyles?.background) ? sectionStyles.background : null;
6542
+ const image = isRecord$6(background?.image) ? background.image : null;
6459
6543
  if (!sectionStyles || !background || !image || background.type !== "image") return content;
6460
6544
  return {
6461
6545
  ...content,
@@ -6468,7 +6552,7 @@ function withRuntimeBackgroundImageAsset(content, imageAsset) {
6468
6552
  }
6469
6553
  };
6470
6554
  }
6471
- function isRecord$8(value) {
6555
+ function isRecord$6(value) {
6472
6556
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
6473
6557
  }
6474
6558
  //#endregion
@@ -6498,7 +6582,7 @@ function rollbackPreviewCustomizeDraftPatch(uiStore, patch) {
6498
6582
  }
6499
6583
  function currentLocalBlockContent(uiStore, targetBlockId) {
6500
6584
  const current = uiStore.getState().drafts.getCurrentValues(unsafeAsEditorBlockId(targetBlockId));
6501
- return isRecord$7(current) ? current : null;
6585
+ return isRecord$5(current) ? current : null;
6502
6586
  }
6503
6587
  function replaceLocalBlockContentWithoutHistory(input) {
6504
6588
  const editorBlockId = unsafeAsEditorBlockId(input.targetBlockId);
@@ -6551,7 +6635,7 @@ function localRuntimeDraftForBlock(input) {
6551
6635
  }
6552
6636
  };
6553
6637
  }
6554
- function isRecord$7(value) {
6638
+ function isRecord$5(value) {
6555
6639
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
6556
6640
  }
6557
6641
  //#endregion
@@ -6976,6 +7060,20 @@ const PAGE_CONTENT_TYPE_SCHEMA = {
6976
7060
  };
6977
7061
  //#endregion
6978
7062
  //#region ../preview-next/src/client/preview/PreviewEntryControllerProvider.tsx
7063
+ function toEditorInitialBlock(block, index) {
7064
+ return {
7065
+ id: block.id,
7066
+ draftContentId: block.draftContentId ?? null,
7067
+ publishedContentId: block.publishedContentId ?? null,
7068
+ kind: block.kind,
7069
+ orderIndex: typeof block.orderIndex === "number" ? block.orderIndex : index,
7070
+ content: block.content ?? null,
7071
+ draftContent: block.draftContent ?? null,
7072
+ publishedContent: block.publishedContent ?? null,
7073
+ bindings: block.bindings ?? null,
7074
+ optimisticHash: block.optimisticHash ?? null
7075
+ };
7076
+ }
6979
7077
  function PreviewEntryControllerProvider({ children, siteId, pageId, routeId: providedRouteId, entryData, contentTypeSchema, draftContent, initialStatus = "draft", initialBlocks, pageMetadata, apiClient }) {
6980
7078
  const { isEditingMode } = useEditor();
6981
7079
  const schema = contentTypeSchema ?? PAGE_CONTENT_TYPE_SCHEMA;
@@ -7036,16 +7134,7 @@ function PreviewEntryControllerProvider({ children, siteId, pageId, routeId: pro
7036
7134
  schema
7037
7135
  ]);
7038
7136
  const normalizedInitialBlocks = useMemo(() => {
7039
- return (initialBlocks ?? []).map((b, index) => ({
7040
- id: b.id ?? null,
7041
- kind: b.kind,
7042
- orderIndex: typeof b.orderIndex === "number" ? b.orderIndex : index,
7043
- content: b.content ?? null,
7044
- draftContent: b.draftContent ?? null,
7045
- publishedContent: b.publishedContent ?? null,
7046
- bindings: b.bindings ?? null,
7047
- optimisticHash: b.optimisticHash ?? null
7048
- }));
7137
+ return (initialBlocks ?? []).map(toEditorInitialBlock);
7049
7138
  }, [initialBlocks]);
7050
7139
  const entityId = pageId || entryData?.id || "";
7051
7140
  const entityType = entryData ? entryData.type : "page";
@@ -7395,25 +7484,25 @@ const INITIAL_ONBOARDING_CONFIRMATION_STATE = {
7395
7484
  resendFeedback: null,
7396
7485
  statusLoadFailed: false
7397
7486
  };
7398
- function isRecord$6(value) {
7487
+ function isRecord$4(value) {
7399
7488
  return value !== null && typeof value === "object";
7400
7489
  }
7401
7490
  function getErrorMessageFromEnvelope(payload, fallback) {
7402
- const error = isRecord$6(payload) ? payload.error : null;
7403
- const message = isRecord$6(error) ? error.message : null;
7491
+ const error = isRecord$4(payload) ? payload.error : null;
7492
+ const message = isRecord$4(error) ? error.message : null;
7404
7493
  return typeof message === "string" && message.trim().length > 0 ? message : fallback;
7405
7494
  }
7406
7495
  function isLaunchReadiness(value) {
7407
- return isRecord$6(value) && Array.isArray(value.requirements) && typeof value.pendingRequiredCount === "number" && typeof value.pendingRecommendedCount === "number" && typeof value.pendingOptionalCount === "number" && isRecord$6(value.goLiveDecision) && (value.goLiveDecision.kind === "allowed" || value.goLiveDecision.kind === "blocked");
7496
+ return isRecord$4(value) && Array.isArray(value.requirements) && typeof value.pendingRequiredCount === "number" && typeof value.pendingRecommendedCount === "number" && typeof value.pendingOptionalCount === "number" && isRecord$4(value.goLiveDecision) && (value.goLiveDecision.kind === "allowed" || value.goLiveDecision.kind === "blocked");
7408
7497
  }
7409
7498
  function isOnboardingPreviewStatusResponse(value) {
7410
- return isRecord$6(value) && typeof value.dashboardUnlocked === "boolean" && typeof value.requiresEmailConfirmation === "boolean" && isLaunchReadiness(value.launchReadiness);
7499
+ return isRecord$4(value) && typeof value.dashboardUnlocked === "boolean" && typeof value.requiresEmailConfirmation === "boolean" && isLaunchReadiness(value.launchReadiness);
7411
7500
  }
7412
7501
  function isResendOnboardingPreviewConfirmationResponse(value) {
7413
- return isRecord$6(value) && (value.result === "resent" || value.result === "already_confirmed") && typeof value.dashboardUnlocked === "boolean" && typeof value.requiresEmailConfirmation === "boolean" && isLaunchReadiness(value.launchReadiness);
7502
+ return isRecord$4(value) && (value.result === "resent" || value.result === "already_confirmed") && typeof value.dashboardUnlocked === "boolean" && typeof value.requiresEmailConfirmation === "boolean" && isLaunchReadiness(value.launchReadiness);
7414
7503
  }
7415
7504
  function getSuccessData(payload, isData) {
7416
- if (!isRecord$6(payload) || payload.success !== true || !isData(payload.data)) return null;
7505
+ if (!isRecord$4(payload) || payload.success !== true || !isData(payload.data)) return null;
7417
7506
  return payload.data;
7418
7507
  }
7419
7508
  function useOnboardingConfirmationCheck(input) {
@@ -8562,7 +8651,7 @@ function CustomizeBackgroundControlRows({ modeLabel, valueLabel, valueAriaLabel,
8562
8651
  }
8563
8652
  //#endregion
8564
8653
  //#region ../preview-next/src/client/preview/SiteChromeCustomizeButton.tsx
8565
- function SiteChromeCustomizeButton({ surface, containerClassName = "pointer-events-auto absolute right-2 top-2 z-50 opacity-0 transition group-focus-within/site-chrome:opacity-100 group-hover/site-chrome:opacity-100" }) {
8654
+ function SiteChromeCustomizeButton({ surface, containerClassName = "pointer-events-auto absolute right-2 top-2 z-50 flex gap-1 opacity-0 transition group-focus-within/site-chrome:opacity-100 group-hover/site-chrome:opacity-100" }) {
8566
8655
  const customize = useSiteChromeCustomizeOptional();
8567
8656
  const editorUiStore = useOptionalEditorUiStoreInstance();
8568
8657
  const popover = useCustomizePopoverController();
@@ -8628,121 +8717,136 @@ function SiteChromeCustomizeButton({ surface, containerClassName = "pointer-even
8628
8717
  }),
8629
8718
  fallbackClassName: containerClassName,
8630
8719
  forceVisible: popover.open,
8631
- children: [/* @__PURE__ */ jsx(CustomizePillButton, {
8632
- buttonRef: popover.buttonRef,
8633
- ariaLabel: `Customize ${surface}`,
8634
- open: popover.open,
8635
- controlsId: popover.panelId,
8636
- onClick: popover.toggle,
8637
- disabled: !hasCustomizeControls
8638
- }), popover.open && surfaceState.kind === "available" ? /* @__PURE__ */ jsxs(CustomizePopoverShell, {
8639
- panelId: popover.panelId,
8640
- descriptionId: popover.descriptionId,
8641
- dialogLabel: `Customize ${surface}`,
8642
- eyebrow: "Site",
8643
- title: surfaceState.label,
8644
- dialogRef: popover.dialogRef,
8645
- closeButtonRef: popover.registerInitialFocus,
8646
- onClose: popover.close,
8647
- onKeyDown: popover.handleDialogKeyDown,
8648
- side: popoverSide,
8649
- children: [
8650
- controlPlan.cycleRows.map((row) => /* @__PURE__ */ jsx(CustomizeCycleRow, { ...row }, row.label)),
8651
- background?.available ? /* @__PURE__ */ jsx(SiteChromeBackgroundControl, {
8652
- background,
8653
- applyAllowed: surfaceState.applyAllowed,
8654
- chooserOpen: backgroundChooserOpen,
8655
- onToggleChooser: (event) => {
8656
- event.preventDefault();
8657
- event.stopPropagation();
8658
- setBackgroundChooserOpen((open) => !open);
8659
- },
8660
- onCycleMode: (direction, event) => {
8661
- event.preventDefault();
8662
- event.stopPropagation();
8663
- chooseSiteChromeBackgroundMode({
8664
- background,
8665
- direction,
8666
- onChoose: (override) => customize?.chooseSurfaceBackground(surfaceState.surface, override)
8667
- });
8668
- },
8669
- onCycleValue: (direction, event) => {
8670
- event.preventDefault();
8671
- event.stopPropagation();
8672
- customize?.cycleSurfaceBackground(surfaceState.surface, direction);
8673
- },
8674
- onChoose: (override) => customize?.chooseSurfaceBackground(surfaceState.surface, override)
8675
- }) : null,
8676
- surfaceState.surface === "header" ? /* @__PURE__ */ jsxs("div", {
8677
- className: "grid grid-cols-2 gap-2 border-t pt-3",
8678
- children: [/* @__PURE__ */ jsxs("label", {
8679
- className: "block text-xs font-medium text-muted-foreground",
8680
- children: [/* @__PURE__ */ jsx("span", { children: "Display" }), /* @__PURE__ */ jsx("select", {
8681
- className: "mt-1 h-8 w-full rounded-md border bg-background px-2 text-sm text-foreground disabled:cursor-not-allowed disabled:opacity-50",
8682
- value: surfaceState.brandDisplay,
8683
- onChange: (event) => {
8684
- event.stopPropagation();
8685
- customize?.setHeaderBrandDisplay(event.currentTarget.value);
8686
- },
8687
- disabled: !surfaceState.applyAllowed,
8688
- children: surfaceState.brandDisplayOptions.map((option) => /* @__PURE__ */ jsx("option", {
8689
- value: option.value,
8690
- disabled: option.disabled,
8691
- children: option.label
8692
- }, option.value))
8693
- })]
8694
- }), /* @__PURE__ */ jsxs("label", {
8695
- className: "block text-xs font-medium text-muted-foreground",
8696
- children: [/* @__PURE__ */ jsx("span", { children: surfaceState.brandSizeLabel }), /* @__PURE__ */ jsx("select", {
8697
- className: "mt-1 h-8 w-full rounded-md border bg-background px-2 text-sm text-foreground disabled:cursor-not-allowed disabled:opacity-50",
8698
- value: surfaceState.logoSize,
8699
- onChange: (event) => {
8700
- event.stopPropagation();
8701
- customize?.setHeaderLogoSize(event.currentTarget.value);
8702
- },
8703
- disabled: !surfaceState.applyAllowed,
8704
- children: surfaceState.logoSizeOptions.map((option) => /* @__PURE__ */ jsx("option", {
8705
- value: option.value,
8706
- children: option.label
8707
- }, option.value))
8708
- })]
8709
- })]
8710
- }) : null,
8711
- editorUiStore && (surfaceState.surface === "footer" || customize?.canOpenDesignEditor === true) ? /* @__PURE__ */ jsx("div", {
8712
- className: "border-t pt-2",
8713
- children: /* @__PURE__ */ jsx("button", {
8714
- type: "button",
8715
- className: "w-full rounded-md border bg-background px-3 py-2 text-sm font-medium hover:bg-muted",
8716
- onClick: (event) => {
8720
+ children: [
8721
+ /* @__PURE__ */ jsx(CustomizePillButton, {
8722
+ buttonRef: popover.buttonRef,
8723
+ ariaLabel: `Customize ${surface}`,
8724
+ open: popover.open,
8725
+ controlsId: popover.panelId,
8726
+ onClick: popover.toggle,
8727
+ disabled: !hasCustomizeControls
8728
+ }),
8729
+ surface === "footer" ? /* @__PURE__ */ jsx(FooterEditPill, {}) : null,
8730
+ popover.open && surfaceState.kind === "available" ? /* @__PURE__ */ jsxs(CustomizePopoverShell, {
8731
+ panelId: popover.panelId,
8732
+ descriptionId: popover.descriptionId,
8733
+ dialogLabel: `Customize ${surface}`,
8734
+ eyebrow: "Site",
8735
+ title: surfaceState.label,
8736
+ dialogRef: popover.dialogRef,
8737
+ closeButtonRef: popover.registerInitialFocus,
8738
+ onClose: popover.close,
8739
+ onKeyDown: popover.handleDialogKeyDown,
8740
+ side: popoverSide,
8741
+ children: [
8742
+ controlPlan.cycleRows.map((row) => /* @__PURE__ */ jsx(CustomizeCycleRow, { ...row }, row.label)),
8743
+ background?.available ? /* @__PURE__ */ jsx(SiteChromeBackgroundControl, {
8744
+ background,
8745
+ applyAllowed: surfaceState.applyAllowed,
8746
+ chooserOpen: backgroundChooserOpen,
8747
+ onToggleChooser: (event) => {
8717
8748
  event.preventDefault();
8718
8749
  event.stopPropagation();
8719
- if (surfaceState.surface === "footer") editorUiStore.getState().openPreviewEditor({
8720
- kind: "footer",
8721
- target: "overview"
8722
- });
8723
- else editorUiStore.getState().openPreviewEditor({
8724
- kind: "design",
8725
- row: "header-style"
8750
+ setBackgroundChooserOpen((open) => !open);
8751
+ },
8752
+ onCycleMode: (direction, event) => {
8753
+ event.preventDefault();
8754
+ event.stopPropagation();
8755
+ chooseSiteChromeBackgroundMode({
8756
+ background,
8757
+ direction,
8758
+ onChoose: (override) => customize?.chooseSurfaceBackground(surfaceState.surface, override)
8726
8759
  });
8727
- popover.close();
8728
8760
  },
8729
- children: surfaceState.surface === "footer" ? "Edit footer" : "More options"
8730
- })
8731
- }) : null,
8732
- surfaceState.diagnostics.length > 0 ? /* @__PURE__ */ jsx("ul", {
8733
- className: "space-y-1 text-xs text-amber-700",
8734
- children: surfaceState.diagnostics.map((diagnostic) => /* @__PURE__ */ jsx("li", { children: diagnostic }, diagnostic))
8735
- }) : null,
8736
- surfaceState.failure ? /* @__PURE__ */ jsx("p", {
8737
- className: "text-xs text-red-700",
8738
- children: surfaceState.failure
8739
- }) : null,
8740
- !surfaceState.applyAllowed ? /* @__PURE__ */ jsx("p", {
8741
- className: "text-xs text-muted-foreground",
8742
- children: "Preview only - ask an admin to apply."
8743
- }) : null
8744
- ]
8745
- }) : null]
8761
+ onCycleValue: (direction, event) => {
8762
+ event.preventDefault();
8763
+ event.stopPropagation();
8764
+ customize?.cycleSurfaceBackground(surfaceState.surface, direction);
8765
+ },
8766
+ onChoose: (override) => customize?.chooseSurfaceBackground(surfaceState.surface, override)
8767
+ }) : null,
8768
+ surfaceState.surface === "header" ? /* @__PURE__ */ jsxs("div", {
8769
+ className: "grid grid-cols-2 gap-2 border-t pt-3",
8770
+ children: [/* @__PURE__ */ jsxs("label", {
8771
+ className: "block text-xs font-medium text-muted-foreground",
8772
+ children: [/* @__PURE__ */ jsx("span", { children: "Display" }), /* @__PURE__ */ jsx("select", {
8773
+ className: "mt-1 h-8 w-full rounded-md border bg-background px-2 text-sm text-foreground disabled:cursor-not-allowed disabled:opacity-50",
8774
+ value: surfaceState.brandDisplay,
8775
+ onChange: (event) => {
8776
+ event.stopPropagation();
8777
+ customize?.setHeaderBrandDisplay(event.currentTarget.value);
8778
+ },
8779
+ disabled: !surfaceState.applyAllowed,
8780
+ children: surfaceState.brandDisplayOptions.map((option) => /* @__PURE__ */ jsx("option", {
8781
+ value: option.value,
8782
+ disabled: option.disabled,
8783
+ children: option.label
8784
+ }, option.value))
8785
+ })]
8786
+ }), /* @__PURE__ */ jsxs("label", {
8787
+ className: "block text-xs font-medium text-muted-foreground",
8788
+ children: [/* @__PURE__ */ jsx("span", { children: surfaceState.brandSizeLabel }), /* @__PURE__ */ jsx("select", {
8789
+ className: "mt-1 h-8 w-full rounded-md border bg-background px-2 text-sm text-foreground disabled:cursor-not-allowed disabled:opacity-50",
8790
+ value: surfaceState.logoSize,
8791
+ onChange: (event) => {
8792
+ event.stopPropagation();
8793
+ customize?.setHeaderLogoSize(event.currentTarget.value);
8794
+ },
8795
+ disabled: !surfaceState.applyAllowed,
8796
+ children: surfaceState.logoSizeOptions.map((option) => /* @__PURE__ */ jsx("option", {
8797
+ value: option.value,
8798
+ children: option.label
8799
+ }, option.value))
8800
+ })]
8801
+ })]
8802
+ }) : null,
8803
+ editorUiStore && surfaceState.surface === "header" && customize?.canOpenDesignEditor === true ? /* @__PURE__ */ jsx("div", {
8804
+ className: "border-t pt-2",
8805
+ children: /* @__PURE__ */ jsx("button", {
8806
+ type: "button",
8807
+ className: "w-full rounded-md border bg-background px-3 py-2 text-sm font-medium hover:bg-muted",
8808
+ onClick: (event) => {
8809
+ event.preventDefault();
8810
+ event.stopPropagation();
8811
+ editorUiStore.getState().openPreviewEditor({
8812
+ kind: "design",
8813
+ row: "header-style"
8814
+ });
8815
+ popover.close();
8816
+ },
8817
+ children: "More options"
8818
+ })
8819
+ }) : null,
8820
+ surfaceState.diagnostics.length > 0 ? /* @__PURE__ */ jsx("ul", {
8821
+ className: "space-y-1 text-xs text-amber-700",
8822
+ children: surfaceState.diagnostics.map((diagnostic) => /* @__PURE__ */ jsx("li", { children: diagnostic }, diagnostic))
8823
+ }) : null,
8824
+ surfaceState.failure ? /* @__PURE__ */ jsx("p", {
8825
+ className: "text-xs text-red-700",
8826
+ children: surfaceState.failure
8827
+ }) : null,
8828
+ !surfaceState.applyAllowed ? /* @__PURE__ */ jsx("p", {
8829
+ className: "text-xs text-muted-foreground",
8830
+ children: "Preview only - ask an admin to apply."
8831
+ }) : null
8832
+ ]
8833
+ }) : null
8834
+ ]
8835
+ });
8836
+ }
8837
+ /** Opens the footer composer, matching the block toolbar's Edit pill. */
8838
+ function FooterEditPill() {
8839
+ const editorUiStore = useOptionalEditorUiStoreInstance();
8840
+ if (!editorUiStore) return null;
8841
+ return /* @__PURE__ */ jsx("button", {
8842
+ type: "button",
8843
+ className: previewCustomizePillButtonClassName,
8844
+ "aria-label": "Edit footer",
8845
+ onClick: () => editorUiStore.getState().openPreviewEditor({
8846
+ kind: "footer",
8847
+ target: "overview"
8848
+ }),
8849
+ children: "Edit"
8746
8850
  });
8747
8851
  }
8748
8852
  const POPOVER_VIEWPORT_GUTTER_PX = 16;
@@ -8916,36 +9020,52 @@ function FooterModuleInspectionSurface({ children }) {
8916
9020
  children
8917
9021
  }) : /* @__PURE__ */ jsx(Fragment$1, { children });
8918
9022
  }
9023
+ const FOOTER_MODULE_SELECTOR = "[data-preview-footer-module-id]";
9024
+ /**
9025
+ * Footer sections are edited like in-place text: hovering one, or keyboard
9026
+ * focus anywhere inside it, draws the preview's standard dashed outline.
9027
+ *
9028
+ * - A section with nothing interactive inside (logo, text) is itself a
9029
+ * button: click, Enter or Space opens the footer composer on it.
9030
+ * - A section holding links or form controls is a labelled group, never a
9031
+ * button (no nested interactive content, no extra tab stop). Activating one
9032
+ * of its links, by click or Enter, opens the section; form controls (the
9033
+ * footer signup form) keep working.
9034
+ *
9035
+ * The footer-wide Edit and Customize pills live in SiteChromeCustomizeButton.
9036
+ */
9037
+ const footerModuleAffordanceCss = `
9038
+ ${FOOTER_MODULE_SELECTOR} {
9039
+ cursor: pointer;
9040
+ border-radius: 2px;
9041
+ }
9042
+ ${FOOTER_MODULE_SELECTOR}:hover,
9043
+ ${FOOTER_MODULE_SELECTOR}:focus-visible,
9044
+ ${FOOTER_MODULE_SELECTOR}:has(:focus-visible) {
9045
+ outline: ${PREVIEW_EDITABLE_OUTLINE};
9046
+ outline-offset: 2px;
9047
+ }
9048
+ `;
8919
9049
  function EnabledFooterModuleInspectionSurface({ children, editorUiStore }) {
8920
9050
  const rootRef = useRef(null);
8921
- const [active, setActive] = useState(null);
8922
- const [position, setPosition] = useState(null);
8923
9051
  useEffect(() => {
8924
9052
  const root = rootRef.current;
8925
9053
  if (!root) return;
8926
- const modules = root.querySelectorAll("[data-preview-footer-module-id]");
9054
+ const modules = root.querySelectorAll(FOOTER_MODULE_SELECTOR);
8927
9055
  for (const module of modules) {
8928
- module.tabIndex = 0;
9056
+ if (module.querySelector(INTERACTIVE_CONTENT_SELECTOR)) {
9057
+ module.setAttribute("role", "group");
9058
+ module.removeAttribute("tabindex");
9059
+ } else {
9060
+ module.setAttribute("role", "button");
9061
+ module.tabIndex = 0;
9062
+ }
8929
9063
  const label = module.dataset.previewFooterModuleId?.replace(/-/gu, " ") ?? "footer section";
8930
9064
  module.setAttribute("aria-label", `Edit ${label}`);
8931
9065
  }
8932
9066
  }, [children]);
8933
- const activateElement = (element) => {
8934
- if (!element) return;
8935
- const parsed = parseFooterModuleId(element.dataset.previewFooterModuleId);
8936
- if (!parsed.ok) return;
8937
- const label = element.dataset.previewFooterModuleId?.replace(/-/gu, " ") ?? "footer section";
8938
- const rect = element.getBoundingClientRect();
8939
- setActive({
8940
- moduleId: parsed.value,
8941
- label
8942
- });
8943
- setPosition({
8944
- top: Math.max(8, rect.top + 8),
8945
- left: Math.max(8, rect.right - 64)
8946
- });
8947
- };
8948
- const inspect = (moduleId) => {
9067
+ const inspect = (moduleId, event) => {
9068
+ event.preventDefault();
8949
9069
  editorUiStore.getState().openPreviewEditor({
8950
9070
  kind: "footer",
8951
9071
  target: { moduleId }
@@ -8954,27 +9074,34 @@ function EnabledFooterModuleInspectionSurface({ children, editorUiStore }) {
8954
9074
  return /* @__PURE__ */ jsxs("div", {
8955
9075
  ref: rootRef,
8956
9076
  style: { display: "contents" },
8957
- onMouseOver: (event) => activateElement(event.target.closest("[data-preview-footer-module-id]")),
8958
- onFocusCapture: (event) => activateElement(event.target.closest("[data-preview-footer-module-id]")),
9077
+ onClick: (event) => {
9078
+ const moduleId = footerModuleIdForClick(event.target);
9079
+ if (moduleId) inspect(moduleId, event);
9080
+ },
8959
9081
  onKeyDown: (event) => {
8960
9082
  if (event.key !== "Enter" && event.key !== " ") return;
8961
- const element = event.target.closest("[data-preview-footer-module-id]");
8962
- if (!element) return;
8963
- const parsed = parseFooterModuleId(element.dataset.previewFooterModuleId);
8964
- if (!parsed.ok) return;
8965
- event.preventDefault();
8966
- inspect(parsed.value);
9083
+ const moduleId = footerModuleIdForKey(event.target);
9084
+ if (moduleId) inspect(moduleId, event);
8967
9085
  },
8968
- children: [children, active && position ? /* @__PURE__ */ jsx("button", {
8969
- type: "button",
8970
- className: "pointer-events-auto fixed z-[75] rounded-full border bg-background px-3 py-1.5 text-xs font-medium text-foreground shadow-md",
8971
- style: position,
8972
- "aria-label": `Edit ${active.label}`,
8973
- onClick: () => inspect(active.moduleId),
8974
- children: "Edit"
8975
- }) : null]
9086
+ children: [/* @__PURE__ */ jsx("style", { children: footerModuleAffordanceCss }), children]
8976
9087
  });
8977
9088
  }
9089
+ const FORM_CONTROL_SELECTOR = "input, select, textarea, button, label";
9090
+ const INTERACTIVE_CONTENT_SELECTOR = `a[href], ${FORM_CONTROL_SELECTOR}`;
9091
+ function footerModuleIdOf(element) {
9092
+ if (!(element instanceof HTMLElement)) return null;
9093
+ const parsed = parseFooterModuleId(element.dataset.previewFooterModuleId);
9094
+ return parsed.ok ? parsed.value : null;
9095
+ }
9096
+ /** The footer section a click should open, or null to let the click through. */
9097
+ function footerModuleIdForClick(target) {
9098
+ if (!(target instanceof Element) || target.closest(FORM_CONTROL_SELECTOR)) return null;
9099
+ return footerModuleIdOf(target.closest(FOOTER_MODULE_SELECTOR));
9100
+ }
9101
+ /** Enter/Space only opens a section when the section itself has focus. */
9102
+ function footerModuleIdForKey(target) {
9103
+ return target instanceof Element && target.matches(FOOTER_MODULE_SELECTOR) ? footerModuleIdOf(target) : null;
9104
+ }
8978
9105
  function isHostElement(child) {
8979
9106
  return typeof child.type === "string";
8980
9107
  }
@@ -9259,10 +9386,10 @@ function resolveShellThemeRoles(props) {
9259
9386
  }
9260
9387
  const previewContainerResponsiveEnabled = process.env.NEXT_PUBLIC_ENABLE_PREVIEW_CONTAINER_RESPONSIVE !== "false";
9261
9388
  const PreviewEditorSidebar = React.lazy(async () => {
9262
- return { default: (await import("./PreviewEditorSidebar-CQZNnFiM.mjs")).PreviewEditorSidebar };
9389
+ return { default: (await import("./PreviewEditorSidebar-kg2r2Fyi.mjs")).PreviewEditorSidebar };
9263
9390
  });
9264
9391
  const PreviewEditorUI = React.lazy(async () => {
9265
- return { default: (await import("./PreviewEditorUI-DCNxnmI0.mjs")).PreviewEditorUI };
9392
+ return { default: (await import("./PreviewEditorUI-sWMLp5dT.mjs")).PreviewEditorUI };
9266
9393
  });
9267
9394
  const previewPaneContainmentStyle = {
9268
9395
  contain: "layout paint",
@@ -9709,11 +9836,11 @@ function resolveShellAccess(input) {
9709
9836
  //#region ../preview-next/src/client/utils/path.ts
9710
9837
  const PATH_SEPARATOR_REGEX = /\./g;
9711
9838
  const BRACKET_ACCESS_REGEX = /\[([^\]]+)\]/g;
9712
- function isRecord$5(value) {
9839
+ function isRecord$3(value) {
9713
9840
  return typeof value === "object" && value !== null && !Array.isArray(value);
9714
9841
  }
9715
9842
  function isPathContainer(value) {
9716
- return Array.isArray(value) || isRecord$5(value);
9843
+ return Array.isArray(value) || isRecord$3(value);
9717
9844
  }
9718
9845
  function createPathContainer(nextIsIndex) {
9719
9846
  return nextIsIndex ? [] : {};
@@ -9876,24 +10003,21 @@ function runtimeContentDecorationProjectionFromEditorModel(editorModel, surfaceR
9876
10003
  kind: "runtime-content-decoration",
9877
10004
  source: "page-design",
9878
10005
  fieldsByBlockId: runtimeFieldsByBlockId(compiled.blocks),
9879
- boundaries: compiled.boundaries
10006
+ joins: compiled.joins
9880
10007
  };
9881
10008
  }
9882
10009
  function runtimeFieldsByBlockId(blocks) {
9883
10010
  return new Map(blocks.map((block) => [block.blockId, block.fields]));
9884
10011
  }
9885
- function applyRuntimeContentDecorationProjection(block, content, projection, adjacency) {
10012
+ function applyRuntimeContentDecorationProjection(block, content, projection) {
9886
10013
  const blockId = designBlockIdFromBlockItem(block);
9887
- const retargetedFields = retargetCompiledRuntimeFieldsForContentAdjacency(blockId ? projection.fieldsByBlockId.get(blockId) : void 0, {
9888
- currentContent: isRecord$4(content) ? content : null,
9889
- nextContent: adjacency?.nextContent
9890
- });
9891
- return applyCompiledRuntimeFieldsToContent(isRecord$4(content) ? content : {}, retargetedFields);
10014
+ const fields = blockId ? projection.fieldsByBlockId.get(blockId) : void 0;
10015
+ return applyCompiledRuntimeFieldsToContent(isRecord$2(content) ? content : {}, fields);
9892
10016
  }
9893
10017
  function designBlockIdFromBlockItem(block) {
9894
10018
  return typeof block.id === "string" && block.id.length > 0 ? asDesignBlockId(block.id) : null;
9895
10019
  }
9896
- function isRecord$4(value) {
10020
+ function isRecord$2(value) {
9897
10021
  return typeof value === "object" && value !== null && !Array.isArray(value);
9898
10022
  }
9899
10023
  //#endregion
@@ -9910,10 +10034,10 @@ function applyPreviewContentFieldProjections(blockId, content, projections) {
9910
10034
  return applyContentFieldOverrideProjection(blockId, current, projection);
9911
10035
  }, content);
9912
10036
  }
9913
- function applyPreviewRuntimeContentProjections(block, content, projections, adjacency) {
10037
+ function applyPreviewRuntimeContentProjections(block, content, projections) {
9914
10038
  return projections.reduce((current, projection) => {
9915
10039
  if (projection.kind !== "runtime-content-decoration") return current;
9916
- return applyRuntimeContentDecorationProjection(block, current, projection, adjacency);
10040
+ return applyRuntimeContentDecorationProjection(block, current, projection);
9917
10041
  }, content);
9918
10042
  }
9919
10043
  function blockHasPreviewContentFieldProjection(blockId, projections) {
@@ -9944,7 +10068,7 @@ function overlayValue(value, overlays) {
9944
10068
  });
9945
10069
  return changed ? next : value;
9946
10070
  }
9947
- if (!isRecord$3(value)) return value;
10071
+ if (!isRecord$1(value)) return value;
9948
10072
  const meta = parseLinkedEntryMeta(value[LINKED_CONTENT_ENTRY_META_KEY]);
9949
10073
  if (meta) {
9950
10074
  const overlay = overlays.get(unsafeAsLinkedContentEntryId(meta.entryId));
@@ -10010,7 +10134,7 @@ function resolveOverlayTitle(content, meta) {
10010
10134
  function parseLinkedEntryMeta(value) {
10011
10135
  return getLinkedContentEntryMeta({ [LINKED_CONTENT_ENTRY_META_KEY]: value });
10012
10136
  }
10013
- function isRecord$3(value) {
10137
+ function isRecord$1(value) {
10014
10138
  return typeof value === "object" && value !== null && !Array.isArray(value);
10015
10139
  }
10016
10140
  //#endregion
@@ -10020,48 +10144,43 @@ function getDraftSnapshots(uiStore) {
10020
10144
  const snapshots = uiStore.getState().drafts.inspect();
10021
10145
  return new Map(snapshots.map((snap) => [snap.id, snap]));
10022
10146
  }
10023
- function mergeBlockWithDraft(block, draftMap, index, projections = [], linkedEntryOverlays = EMPTY_LINKED_ENTRY_OVERLAY, nextBlock = null) {
10147
+ function mergeBlockWithDraft(block, draftMap, index, projections = [], linkedEntryOverlays = EMPTY_LINKED_ENTRY_OVERLAY) {
10148
+ const { draftContentId = null, publishedContentId = null } = block;
10024
10149
  const id = block.id ?? null;
10025
10150
  const editorBlockId = id ? unsafeAsEditorBlockId(id) : null;
10026
10151
  const snap = editorBlockId ? draftMap.get(editorBlockId) ?? null : null;
10027
10152
  const draftContent = editorBlockId ? readProjectedDraftRenderContent(block, editorBlockId, snap, projections) : null;
10028
- const baseline = snap?.baseline ?? block.content ?? block.publishedContent ?? null;
10029
- const nextContent = nextBlock ? readBlockRenderContents(nextBlock, draftMap, projections) : null;
10153
+ const baseline = blockBaseline(block, snap);
10030
10154
  return {
10031
10155
  id,
10156
+ draftContentId,
10157
+ publishedContentId,
10032
10158
  kind: block.kind,
10033
10159
  purpose: "content",
10034
10160
  orderIndex: block.orderIndex ?? index,
10035
- content: renderContent(block, baseline, projections, linkedEntryOverlays, nextContent?.baseline ?? null),
10036
- draftContent: renderContent(block, draftContent, projections, linkedEntryOverlays, nextContent?.draft ?? null),
10037
- publishedContent: renderContent(block, block.publishedContent ?? null, projections, EMPTY_LINKED_ENTRY_OVERLAY, nextContent?.published ?? null),
10161
+ content: renderContent(block, baseline, projections, linkedEntryOverlays),
10162
+ draftContent: renderContent(block, draftContent, projections, linkedEntryOverlays),
10163
+ publishedContent: block.publishedContent ?? null,
10038
10164
  bindings: block.bindings ?? null
10039
10165
  };
10040
10166
  }
10041
- function readBlockRenderContents(block, draftMap, projections) {
10042
- const id = block.id ?? null;
10043
- const editorBlockId = id ? unsafeAsEditorBlockId(id) : null;
10044
- const snap = editorBlockId ? draftMap.get(editorBlockId) ?? null : null;
10045
- return {
10046
- baseline: snap?.baseline ?? block.content ?? block.publishedContent ?? null,
10047
- draft: editorBlockId ? readProjectedDraftRenderContent(block, editorBlockId, snap, projections) : null,
10048
- published: block.publishedContent ?? null
10049
- };
10050
- }
10051
10167
  function readProjectedDraftRenderContent(block, editorBlockId, snap, projections) {
10052
- return applyPreviewContentFieldProjections(editorBlockId, snap?.current ?? snap?.baseline ?? block.content ?? block.publishedContent ?? null, projections);
10168
+ return applyPreviewContentFieldProjections(editorBlockId, snap?.current ?? blockBaseline(block, snap), projections);
10053
10169
  }
10054
- function renderContent(block, content, projections, linkedEntryOverlays, nextContent) {
10055
- return applyPreviewRuntimeContentProjections(block, applyLinkedEntryRenderOverlay(content, linkedEntryOverlays), projections, { nextContent: isRecord$2(nextContent) ? nextContent : null });
10170
+ function blockBaseline(block, snapshot) {
10171
+ return snapshot?.baseline ?? block.content ?? block.publishedContent ?? null;
10056
10172
  }
10057
- function isRecord$2(value) {
10058
- return typeof value === "object" && value !== null && !Array.isArray(value);
10173
+ function renderContent(block, content, projections, linkedEntryOverlays) {
10174
+ return applyPreviewRuntimeContentProjections(block, applyLinkedEntryRenderOverlay(content, linkedEntryOverlays), projections);
10059
10175
  }
10060
10176
  //#endregion
10061
10177
  //#region ../preview-next/src/client/blocks/composer/transformBlock.ts
10062
10178
  function transformToPageBlock(enriched) {
10063
10179
  return {
10064
10180
  id: enriched.id,
10181
+ draftContentId: enriched.draftContentId,
10182
+ publishedContentId: enriched.publishedContentId,
10183
+ contentVersionId: enriched.draftContentId ?? enriched.publishedContentId,
10065
10184
  kind: enriched.kind,
10066
10185
  purpose: enriched.purpose,
10067
10186
  content: enriched.content ?? {},
@@ -10113,8 +10232,7 @@ function composePreviewRenderPage(args, cacheRef) {
10113
10232
  if (!page) return page;
10114
10233
  if (!blockItems.length) return page;
10115
10234
  const draftMap = draftSnapshotMap(draftSnapshots);
10116
- const projectedBlockItems = applyPreviewStructureProjections(blockItems, projections);
10117
- const renderedBlocks = applyCacheOptimization([...projectedBlockItems.map((block, index) => mergeBlockWithDraft(block, draftMap, index, projections, linkedEntryOverlays, projectedBlockItems[index + 1] ?? null))].sort((a, b) => (a.orderIndex ?? 0) - (b.orderIndex ?? 0)), cacheRef);
10235
+ const renderedBlocks = applyCacheOptimization([...applyPreviewStructureProjections(blockItems, projections).map((block, index) => mergeBlockWithDraft(block, draftMap, index, projections, linkedEntryOverlays))].sort((a, b) => (a.orderIndex ?? 0) - (b.orderIndex ?? 0)), cacheRef);
10118
10236
  return {
10119
10237
  ...page,
10120
10238
  blocks: renderedBlocks
@@ -10276,7 +10394,7 @@ const editorRegistry = {
10276
10394
  };
10277
10395
  //#endregion
10278
10396
  //#region ../preview-next/src/client/blocks/isRecord.ts
10279
- function isRecord$1(value) {
10397
+ function isRecord(value) {
10280
10398
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
10281
10399
  }
10282
10400
  //#endregion
@@ -10450,7 +10568,7 @@ function BlockToolbar({ blockId, blockKind, content, bookingOfferingPresets, the
10450
10568
  const uiStore = useEditorUiStoreInstance();
10451
10569
  const editorBlockId = useMemo(() => unsafeAsEditorBlockId(blockId), [blockId]);
10452
10570
  const draftContent = useEditorUiStore((state) => state.drafts.getCurrentValues(editorBlockId));
10453
- const customizeContent = useMemo(() => isRecord$1(draftContent) ? draftContent : content, [content, draftContent]);
10571
+ const customizeContent = useMemo(() => isRecord(draftContent) ? draftContent : content, [content, draftContent]);
10454
10572
  const customizeSelection = usePreviewBlockCustomizeSelectionOptional();
10455
10573
  const popover = useCustomizePopoverController();
10456
10574
  const focusTarget = useMemo(() => computeDefaultFocus(blockKind, customizeContent), [blockKind, customizeContent]);
@@ -11006,13 +11124,13 @@ function findFirstFieldPath(fields, data, prefix) {
11006
11124
  if (Array.isArray(field.visibleRoles) && !field.visibleRoles.includes("author")) continue;
11007
11125
  const nextPrefix = [...prefix, field.id];
11008
11126
  if (field.type === "group") {
11009
- const groupValue = isRecord$1(data) ? data[field.id] : void 0;
11127
+ const groupValue = isRecord(data) ? data[field.id] : void 0;
11010
11128
  const nested = findFirstFieldPath(field.schema.fields, groupValue, nextPrefix);
11011
11129
  if (nested) return nested;
11012
11130
  continue;
11013
11131
  }
11014
11132
  if (field.type === "repeater" && field.schema) {
11015
- const collection = isRecord$1(data) ? data[field.id] : void 0;
11133
+ const collection = isRecord(data) ? data[field.id] : void 0;
11016
11134
  const items = isUnknownArray(collection) ? collection : [];
11017
11135
  if (items.length > 0) {
11018
11136
  const firstItem = items[0];
@@ -11189,7 +11307,7 @@ function dedupeBackgroundImagePool(items) {
11189
11307
  }
11190
11308
  //#endregion
11191
11309
  //#region ../preview-next/src/client/blocks/BoundaryControl.tsx
11192
- function BoundaryControl({ previousBlockId, nextBlockId, previousBlockKind, nextBlockKind }) {
11310
+ function BoundaryControl({ previousBlockId, nextBlockId, previousBlockKind, nextBlockKind, outcome }) {
11193
11311
  const panelId = useId();
11194
11312
  const panelDescriptionId = `${panelId}-description`;
11195
11313
  const [open, setOpen] = useState(false);
@@ -11217,11 +11335,17 @@ function BoundaryControl({ previousBlockId, nextBlockId, previousBlockKind, next
11217
11335
  }, [hasControls]);
11218
11336
  if (!boundary || !hasControls) return null;
11219
11337
  const display = boundaryBreakDisplay(boundary);
11220
- const panelStatus = display.detail ? {
11221
- id: `${panelId}-status`,
11222
- text: display.detail
11223
- } : null;
11224
- const panelDescribedBy = panelStatus ? `${panelDescriptionId} ${panelStatus.id}` : panelDescriptionId;
11338
+ const panelSummaryId = `${panelId}-summary`;
11339
+ const panelStatuses = boundaryPanelStatuses({
11340
+ panelId,
11341
+ detail: display.detail,
11342
+ outcome
11343
+ });
11344
+ const panelDescribedBy = [
11345
+ panelDescriptionId,
11346
+ panelSummaryId,
11347
+ ...panelStatuses.map((status) => status.id)
11348
+ ].join(" ");
11225
11349
  const openPanel = (event) => {
11226
11350
  event.preventDefault();
11227
11351
  event.stopPropagation();
@@ -11277,7 +11401,7 @@ function BoundaryControl({ previousBlockId, nextBlockId, previousBlockKind, next
11277
11401
  /* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-sky-500/10 opacity-0 transition-opacity duration-150 group-hover/boundary:opacity-100 group-focus-within/boundary:opacity-100" }),
11278
11402
  /* @__PURE__ */ jsx("button", {
11279
11403
  type: "button",
11280
- className: "pointer-events-auto absolute inset-0 z-10 flex items-center justify-center opacity-0 transition hover:opacity-100 focus:opacity-100 focus:outline-none focus:ring-2 focus:ring-inset focus:ring-sky-300 group-hover/boundary:opacity-100 group-focus-within/boundary:opacity-100",
11404
+ className: "pointer-events-auto relative z-10 flex h-11 min-w-11 items-center justify-center rounded-full opacity-0 transition hover:opacity-100 focus:opacity-100 focus:outline-none focus-visible:ring-2 focus-visible:ring-sky-300 group-hover/boundary:opacity-100 group-focus-within/boundary:opacity-100",
11281
11405
  "aria-controls": open ? panelId : void 0,
11282
11406
  "aria-expanded": open,
11283
11407
  "aria-haspopup": "dialog",
@@ -11325,15 +11449,9 @@ function BoundaryControl({ previousBlockId, nextBlockId, previousBlockKind, next
11325
11449
  })
11326
11450
  })]
11327
11451
  }),
11328
- /* @__PURE__ */ jsxs("div", {
11329
- className: "rounded-lg border border-slate-200 bg-slate-50 p-2 text-center",
11330
- children: [/* @__PURE__ */ jsx("div", {
11331
- className: "truncate text-sm font-medium",
11332
- children: boundaryBreakLabel(boundary)
11333
- }), /* @__PURE__ */ jsx("div", {
11334
- className: "mt-0.5 text-xs text-slate-500",
11335
- children: boundaryBreakModeLabel(boundary)
11336
- })]
11452
+ /* @__PURE__ */ jsx(BoundaryBreakSummary, {
11453
+ id: panelSummaryId,
11454
+ display
11337
11455
  }),
11338
11456
  /* @__PURE__ */ jsxs("div", {
11339
11457
  className: "mt-3",
@@ -11363,11 +11481,7 @@ function BoundaryControl({ previousBlockId, nextBlockId, previousBlockKind, next
11363
11481
  }, variant.boundaryOption.id))
11364
11482
  })]
11365
11483
  }) : null,
11366
- panelStatus ? /* @__PURE__ */ jsx("p", {
11367
- id: panelStatus.id,
11368
- className: "mt-2 text-xs text-slate-500",
11369
- children: panelStatus.text
11370
- }) : null,
11484
+ /* @__PURE__ */ jsx(BoundaryPanelStatusLines, { statuses: panelStatuses }),
11371
11485
  display.canReset ? /* @__PURE__ */ jsxs("button", {
11372
11486
  type: "button",
11373
11487
  className: "mt-2 inline-flex w-full items-center justify-center gap-2 rounded-md border border-slate-200 px-3 py-2 text-sm font-medium text-slate-700 transition hover:bg-slate-50 focus:outline-none focus:ring-2 focus:ring-sky-400",
@@ -11391,6 +11505,53 @@ function BoundaryControl({ previousBlockId, nextBlockId, previousBlockKind, next
11391
11505
  })
11392
11506
  });
11393
11507
  }
11508
+ /** Approved copy (issue 1422) for a join the renderer did not draw. */
11509
+ const notShownCopy = {
11510
+ "both-unpainted": "This break won't show here, because both sections have an image or video background. It'll appear if you give one of them a color background.",
11511
+ "flush-panel": "This break won't show here, because one of these sections has an image that runs right to its edge. It'll appear if you pick a different look for that section."
11512
+ };
11513
+ /**
11514
+ * Status lines under the controls, each wired into the dialog's
11515
+ * `aria-describedby`. The not-shown line comes from the same composition as
11516
+ * the painted page, so it appears or clears as backgrounds change.
11517
+ */
11518
+ function boundaryPanelStatuses(input) {
11519
+ return [...input.detail ? [{
11520
+ id: `${input.panelId}-status`,
11521
+ kind: "saved-break-unavailable",
11522
+ text: input.detail
11523
+ }] : [], ...input.outcome?.kind === "not-shown" ? [{
11524
+ id: `${input.panelId}-not-shown`,
11525
+ kind: `not-shown:${input.outcome.reason}`,
11526
+ text: notShownCopy[input.outcome.reason]
11527
+ }] : []];
11528
+ }
11529
+ function BoundaryPanelStatusLines({ statuses }) {
11530
+ return statuses.map((status) => /* @__PURE__ */ jsx("p", {
11531
+ id: status.id,
11532
+ "data-boundary-status": status.kind,
11533
+ className: "mt-2 text-xs text-slate-500",
11534
+ children: status.text
11535
+ }, status.id));
11536
+ }
11537
+ /**
11538
+ * The current break and where it comes from. The source is exposed as data so
11539
+ * the state is inspectable without reading the copy.
11540
+ */
11541
+ function BoundaryBreakSummary({ id, display }) {
11542
+ return /* @__PURE__ */ jsxs("div", {
11543
+ id,
11544
+ "data-boundary-break-source": display.source,
11545
+ className: "rounded-lg border border-slate-200 bg-slate-50 p-2 text-center",
11546
+ children: [/* @__PURE__ */ jsx("div", {
11547
+ className: "truncate text-sm font-medium",
11548
+ children: display.label
11549
+ }), /* @__PURE__ */ jsx("div", {
11550
+ className: "mt-0.5 text-xs text-slate-500",
11551
+ children: display.modeLabel
11552
+ })]
11553
+ });
11554
+ }
11394
11555
  function SectionTransitionFamilyButton({ family, active, onClick }) {
11395
11556
  return /* @__PURE__ */ jsx("button", {
11396
11557
  type: "button",
@@ -11414,24 +11575,13 @@ function SectionTransitionVariantButton({ variant, active, onClick }) {
11414
11575
  function sectionTransitionChoiceClassName(active) {
11415
11576
  return ["min-h-8 flex-1 rounded-md px-2.5 text-xs font-medium transition focus:outline-none focus:ring-2 focus:ring-sky-400", active ? "bg-slate-950 text-white shadow-sm" : "bg-transparent text-slate-600 hover:bg-white hover:text-slate-950"].join(" ");
11416
11577
  }
11417
- function boundaryBreakLabel(boundary) {
11418
- return boundaryBreakDisplay(boundary).label;
11419
- }
11420
- function boundaryBreakModeLabel(boundary) {
11421
- return boundaryBreakDisplay(boundary).modeLabel;
11422
- }
11423
11578
  function boundaryBreakDisplay(boundary) {
11424
11579
  const option = boundary.availableBreaks.find((candidate) => candidate.id === boundary.breakChoice.effectiveValue) ?? null;
11425
11580
  switch (boundary.breakChoice.kind) {
11426
- case "auto": return {
11427
- label: option ? `Default: ${option.label}` : "Default",
11428
- modeLabel: "Page Flow",
11429
- detail: null,
11430
- canReset: false,
11431
- resetLabel: "Default"
11432
- };
11581
+ case "auto": return autoBoundaryBreakDisplay(boundary.breakChoice.source, option ? `Default: ${option.label}` : "Default");
11433
11582
  case "user-pinned":
11434
11583
  if (boundary.breakChoice.status === "supported") return {
11584
+ source: "user-pinned",
11435
11585
  label: option?.label ?? "Selected break",
11436
11586
  modeLabel: "Custom",
11437
11587
  detail: null,
@@ -11439,6 +11589,7 @@ function boundaryBreakDisplay(boundary) {
11439
11589
  resetLabel: "Default"
11440
11590
  };
11441
11591
  return {
11592
+ source: "unavailable",
11442
11593
  label: "Saved break unavailable",
11443
11594
  modeLabel: option ? `Using default: ${option.label}` : "Using Page Flow fallback",
11444
11595
  detail: "This page still has a saved custom break that is no longer available for these sections.",
@@ -11448,6 +11599,31 @@ function boundaryBreakDisplay(boundary) {
11448
11599
  default: return assertNever$1(boundary.breakChoice, "Unhandled boundary break choice");
11449
11600
  }
11450
11601
  }
11602
+ /**
11603
+ * A default break has no reset: there is nothing saved to clear. Picking
11604
+ * another break pins it as a user choice, and reset returns here.
11605
+ */
11606
+ function autoBoundaryBreakDisplay(source, label) {
11607
+ switch (source.kind) {
11608
+ case "site-style-default": return {
11609
+ source: "site-style-default",
11610
+ label,
11611
+ modeLabel: "Set by your site style",
11612
+ detail: null,
11613
+ canReset: false,
11614
+ resetLabel: "Default"
11615
+ };
11616
+ case "page-flow-default": return {
11617
+ source: "page-flow-default",
11618
+ label,
11619
+ modeLabel: "Page Flow",
11620
+ detail: null,
11621
+ canReset: false,
11622
+ resetLabel: "Default"
11623
+ };
11624
+ default: return assertNever$1(source, "Unhandled boundary default source");
11625
+ }
11626
+ }
11451
11627
  function formatBlockKindLabel(blockKind) {
11452
11628
  const blockTitle = getBlockDefinition(blockKind)?.manifest.title;
11453
11629
  if (blockTitle) return blockTitle;
@@ -11682,33 +11858,32 @@ function EditablePageRenderer(props) {
11682
11858
  uiStore,
11683
11859
  renderStateVersion
11684
11860
  ]) ?? pageRendererProps.page;
11685
- const runtimeBoundaries = useMemo(() => retargetRuntimeBoundariesForRenderPage(runtimeProjection?.boundaries ?? pageRendererProps.runtimeBoundaries ?? [], renderPage), [
11686
- pageRendererProps.runtimeBoundaries,
11687
- renderPage,
11688
- runtimeProjection
11689
- ]);
11861
+ const runtimeJoins = editorRuntimeJoins(runtimeProjection, pageRendererProps.runtimeJoins);
11690
11862
  const renderedBlockById = useMemo(() => {
11691
11863
  return new Map((renderPage?.blocks ?? []).filter((block) => Boolean(block.id)).map((block) => [block.id, block]));
11692
11864
  }, [renderPage?.blocks]);
11693
- const wrapBoundaryWithControl = useCallback((boundary, rendered) => {
11694
- const previousBlock = renderedBlockById.get(boundary.previousBlockId);
11695
- const nextBlock = renderedBlockById.get(boundary.nextBlockId);
11865
+ const renderJoinWithControl = useCallback((input) => {
11866
+ const previousBlock = renderedBlockById.get(input.previousBlockId);
11867
+ const nextBlock = renderedBlockById.get(input.nextBlockId);
11696
11868
  const control = !isEntryTemplatePage && previousBlock && nextBlock ? /* @__PURE__ */ jsx(BoundaryControl, {
11697
- previousBlockId: asDesignBlockId(boundary.previousBlockId),
11698
- nextBlockId: asDesignBlockId(boundary.nextBlockId),
11869
+ previousBlockId: asDesignBlockId(input.previousBlockId),
11870
+ nextBlockId: asDesignBlockId(input.nextBlockId),
11699
11871
  previousBlockKind: previousBlock.kind,
11700
- nextBlockKind: nextBlock.kind
11872
+ nextBlockKind: nextBlock.kind,
11873
+ outcome: input.join?.outcome ?? null
11701
11874
  }) : null;
11702
- const wrapped = pageRendererProps.wrapBoundary ? pageRendererProps.wrapBoundary(boundary, rendered) : rendered;
11875
+ const extra = pageRendererProps.renderJoin?.(input) ?? null;
11876
+ if (!control && !extra) return null;
11703
11877
  return /* @__PURE__ */ jsxs("div", {
11704
11878
  className: "relative",
11705
11879
  "data-preview-boundary-wrapper": "",
11706
- "data-boundary-id": boundary.boundaryId,
11707
- children: [wrapped, control]
11880
+ "data-boundary-previous-block-id": input.previousBlockId,
11881
+ "data-boundary-next-block-id": input.nextBlockId,
11882
+ children: [extra, control]
11708
11883
  });
11709
11884
  }, [
11710
11885
  isEntryTemplatePage,
11711
- pageRendererProps.wrapBoundary,
11886
+ pageRendererProps.renderJoin,
11712
11887
  renderedBlockById
11713
11888
  ]);
11714
11889
  const wrapBlockWithProvider = useCallback((blockId, rendered) => {
@@ -11779,32 +11954,20 @@ function EditablePageRenderer(props) {
11779
11954
  return /* @__PURE__ */ jsx(EditorPageRenderer, {
11780
11955
  ...pageRendererProps,
11781
11956
  page: renderPage,
11782
- runtimeBoundaries,
11957
+ runtimeJoins,
11783
11958
  registry: allowInlineEditing ? editorRegistry : pageRendererProps.registry ?? clientComponentRegistry,
11784
11959
  wrapBlock: allowInlineEditing ? wrapBlockWithProvider : pageRendererProps.wrapBlock,
11785
- wrapBoundary: allowInlineEditing ? wrapBoundaryWithControl : pageRendererProps.wrapBoundary,
11960
+ renderJoin: allowInlineEditing ? renderJoinWithControl : pageRendererProps.renderJoin,
11786
11961
  dataContext,
11787
11962
  previewAuthoring
11788
11963
  });
11789
11964
  }
11790
- function retargetRuntimeBoundariesForRenderPage(boundaries, page) {
11791
- if (!boundaries?.length) return boundaries;
11792
- const blockById = new Map(page.blocks.filter((block) => Boolean(block.id)).map((block) => [block.id, block]));
11793
- return boundaries.map((boundary) => {
11794
- const currentBlock = blockById.get(boundary.previousBlockId);
11795
- const nextBlock = blockById.get(boundary.nextBlockId);
11796
- return retargetCompiledBoundaryRuntimeForContentAdjacency(boundary, {
11797
- currentContent: renderableBoundaryContent(currentBlock),
11798
- nextContent: renderableBoundaryContent(nextBlock)
11799
- });
11800
- });
11801
- }
11802
- function renderableBoundaryContent(block) {
11803
- const source = block?.draftContent ?? block?.content ?? null;
11804
- return isRecord(source) ? source : null;
11805
- }
11806
- function isRecord(value) {
11807
- return typeof value === "object" && value !== null && !Array.isArray(value);
11965
+ const emptyRuntimeJoins = [];
11966
+ /**
11967
+ * The editor's joins: its live projection wins, then whatever the caller sent.
11968
+ */
11969
+ function editorRuntimeJoins(projection, fallback) {
11970
+ return projection?.joins ?? fallback ?? emptyRuntimeJoins;
11808
11971
  }
11809
11972
  function usePreviewBlockResolvedData(args) {
11810
11973
  const { page, dataContext, apiClient } = args;
@@ -12039,6 +12202,21 @@ var SdkPreviewModeRuntime_exports = /* @__PURE__ */ __exportAll({ SdkPreviewMode
12039
12202
  function isSdkCustomBlockArray(value) {
12040
12203
  return Array.isArray(value);
12041
12204
  }
12205
+ function toPreviewBlock(block, index) {
12206
+ const publishedContent = block.publishedContent;
12207
+ return {
12208
+ id: block.id,
12209
+ draftContentId: typeof block.draftContentId === "string" ? block.draftContentId : null,
12210
+ publishedContentId: typeof block.publishedContentId === "string" ? block.publishedContentId : null,
12211
+ kind: block.kind,
12212
+ purpose: block.purpose,
12213
+ orderIndex: index,
12214
+ content: block.content ?? null,
12215
+ draftContent: block.draftContent ?? null,
12216
+ publishedContent: publishedContent && typeof publishedContent === "object" && !Array.isArray(publishedContent) ? publishedContent : null,
12217
+ bindings: block.bindings ?? null
12218
+ };
12219
+ }
12042
12220
  function getSdkConfigForPreview(value) {
12043
12221
  if (!value || typeof value !== "object") return null;
12044
12222
  if (!("customBlocks" in value)) return { layout: { footerMode: resolveSdkFooterMode(value) } };
@@ -12142,16 +12320,7 @@ function resolveSdkPreviewRuntimeModel(props) {
12142
12320
  const routeMap = content.routeMap ?? void 0;
12143
12321
  const sdkConfig = getSdkConfigForPreview(content.sdkConfig);
12144
12322
  const customBlocks = isSdkCustomBlockArray(content.customBlocks) ? content.customBlocks : null;
12145
- const initialBlocks = (page.blocks ?? []).map((block, index) => ({
12146
- id: block.id ?? null,
12147
- kind: block.kind,
12148
- purpose: block.purpose ?? null,
12149
- orderIndex: index,
12150
- content: block.content ?? null,
12151
- draftContent: block.draftContent ?? null,
12152
- publishedContent: null,
12153
- bindings: block.bindings ?? null
12154
- }));
12323
+ const initialBlocks = (page.blocks ?? []).map(toPreviewBlock);
12155
12324
  const commonModel = {
12156
12325
  content,
12157
12326
  customBlocks,