@riverbankcms/sdk 0.80.0 → 0.82.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 (574) hide show
  1. package/README.md +65 -3
  2. package/dist/{PreviewEditorSidebar-O4NDX5TP.css → PreviewEditorSidebar-JA4VIPSZ.css} +1 -1
  3. package/dist/{PreviewEditorSidebar-QZG37QIF.mjs → PreviewEditorSidebar-LHGK6RIO.mjs} +760 -711
  4. package/dist/{SdkPreviewModeRuntime-PBGALTMK.css → PreviewEditorUI-36T7QYV4.css} +1 -1
  5. package/dist/{PreviewEditorUI-AXIKSMZA.mjs → PreviewEditorUI-AXZG2SDC.mjs} +167 -28
  6. package/dist/{PreviewEditorUI-4JVDBZBS.css → SdkPreviewModeRuntime-FXKI6XNL.css} +1 -1
  7. package/dist/SdkPreviewModeRuntime-RNVRHFFR.mjs +8 -0
  8. package/dist/_dts/ai/src/contracts/proposals.d.ts +838 -262
  9. package/dist/_dts/altcha/src/AltchaWidget.d.ts +1 -1
  10. package/dist/_dts/api/src/analytics.d.ts +1 -1
  11. package/dist/_dts/api/src/bookingConfig.d.ts +4 -0
  12. package/dist/_dts/api/src/contentRuntime.d.ts +15 -3
  13. package/dist/_dts/api/src/contentTypes.d.ts +6 -0
  14. package/dist/_dts/api/src/courses.d.ts +1 -1
  15. package/dist/_dts/api/src/event-destination-policy.d.ts +17 -0
  16. package/dist/_dts/api/src/index.d.ts +6 -2
  17. package/dist/_dts/api/src/navigation/boundaries.d.ts +64 -0
  18. package/dist/_dts/api/src/navigation.d.ts +2 -0
  19. package/dist/_dts/api/src/publicExperienceEndpoints.d.ts +17 -12
  20. package/dist/_dts/api/src/siteGeneration.d.ts +1 -1
  21. package/dist/_dts/api/src/sitePlatformEndpoints.d.ts +7 -6
  22. package/dist/_dts/api/src/types.d.ts +1 -1
  23. package/dist/_dts/block-form/src/backend/store-backend.d.ts +3 -1
  24. package/dist/_dts/block-form/src/backend/types.d.ts +3 -3
  25. package/dist/_dts/block-form/src/context/BlockContext.d.ts +1 -1
  26. package/dist/_dts/block-form/src/context/DisplayLabelResolverContext.d.ts +1 -1
  27. package/dist/_dts/block-form/src/context/FieldPreviewResolverContext.d.ts +2 -2
  28. package/dist/_dts/block-form/src/manifest/ManifestForm.d.ts +1 -1
  29. package/dist/_dts/block-form/src/palette/PaletteContext.d.ts +1 -1
  30. package/dist/_dts/block-form/src/sdk-config/SdkConfigContext.d.ts +1 -1
  31. package/dist/_dts/block-form/src/widgets/BackgroundColorWidget/BackgroundColorWidget.d.ts +2 -1
  32. package/dist/_dts/block-form/src/widgets/BackgroundGradientWidget/BackgroundGradientWidget.d.ts +1 -1
  33. package/dist/_dts/block-form/src/widgets/BooleanField/BooleanField.d.ts +1 -1
  34. package/dist/_dts/block-form/src/widgets/DateField/datePickerPopover.d.ts +1 -1
  35. package/dist/_dts/block-form/src/widgets/Field.d.ts +2 -2
  36. package/dist/_dts/block-form/src/widgets/FieldFrame.d.ts +3 -3
  37. package/dist/_dts/block-form/src/widgets/NumberField/NumberField.d.ts +1 -1
  38. package/dist/_dts/block-form/src/widgets/PresetOrCustomField/PresetOrCustomField.d.ts +1 -1
  39. package/dist/_dts/block-form/src/widgets/SdkSelectField/SdkSelectField.d.ts +1 -1
  40. package/dist/_dts/block-form/src/widgets/SelectField/SelectField.d.ts +1 -1
  41. package/dist/_dts/block-form/src/widgets/SelectWidget.d.ts +1 -1
  42. package/dist/_dts/block-form/src/widgets/SliderField/SliderField.d.ts +1 -1
  43. package/dist/_dts/block-form/src/widgets/TextField/TextField.d.ts +1 -1
  44. package/dist/_dts/block-form/src/widgets/TextInputWidget.d.ts +1 -1
  45. package/dist/_dts/block-form/src/widgets/ToggleWidget.d.ts +1 -1
  46. package/dist/_dts/block-form/src/widgets/stringDefaultValue.d.ts +1 -0
  47. package/dist/_dts/blocks/src/PageRenderer.d.ts +4 -1
  48. package/dist/_dts/blocks/src/contracts/proof-block-islands.d.ts +28 -44
  49. package/dist/_dts/blocks/src/index.d.ts +6 -4
  50. package/dist/_dts/blocks/src/portal/types.d.ts +1 -1
  51. package/dist/_dts/blocks/src/primitives/content/components/Button.d.ts +7 -7
  52. package/dist/_dts/blocks/src/primitives/content/components/RichText.d.ts +2 -1
  53. package/dist/_dts/blocks/src/primitives/content/components/Text.d.ts +2 -1
  54. package/dist/_dts/blocks/src/primitives/content/primitives.d.ts +4 -0
  55. package/dist/_dts/blocks/src/primitives/layout/Grid.d.ts +2 -1
  56. package/dist/_dts/blocks/src/primitives/layout/Inline.d.ts +2 -1
  57. package/dist/_dts/blocks/src/primitives/layout/Stack.d.ts +2 -1
  58. package/dist/_dts/blocks/src/server.d.ts +1 -1
  59. package/dist/_dts/blocks/src/system/blocks/appointment-booking.d.ts +592 -592
  60. package/dist/_dts/blocks/src/system/blocks/blog-listing.d.ts +592 -592
  61. package/dist/_dts/blocks/src/system/blocks/cart.d.ts +592 -592
  62. package/dist/_dts/blocks/src/system/blocks/checkout.d.ts +592 -592
  63. package/dist/_dts/blocks/src/system/blocks/collection.d.ts +592 -592
  64. package/dist/_dts/blocks/src/system/blocks/courses/shared/types.d.ts +1 -1
  65. package/dist/_dts/blocks/src/system/blocks/events/event-calendar.d.ts +3 -2
  66. package/dist/_dts/blocks/src/system/blocks/events/shared/schemas.d.ts +397 -111
  67. package/dist/_dts/blocks/src/system/blocks/events/shared/types.d.ts +6 -15
  68. package/dist/_dts/blocks/src/system/blocks/faq.d.ts +592 -592
  69. package/dist/_dts/blocks/src/system/blocks/feature-card-icons.d.ts +1 -1
  70. package/dist/_dts/blocks/src/system/blocks/feature-cards.d.ts +2 -0
  71. package/dist/_dts/blocks/src/system/blocks/form.d.ts +20 -1
  72. package/dist/_dts/blocks/src/system/blocks/gifting.d.ts +592 -592
  73. package/dist/_dts/blocks/src/system/blocks/hero.d.ts +2 -0
  74. package/dist/_dts/blocks/src/system/blocks/image-gallery.d.ts +3 -0
  75. package/dist/_dts/blocks/src/system/blocks/location-map.d.ts +3 -3
  76. package/dist/_dts/blocks/src/system/blocks/media-text.d.ts +54 -54
  77. package/dist/_dts/blocks/src/system/blocks/offerings-preview/index.d.ts +21 -0
  78. package/dist/_dts/blocks/src/system/blocks/offerings-preview/model.d.ts +162 -0
  79. package/dist/_dts/blocks/src/system/blocks/product-detail.d.ts +592 -602
  80. package/dist/_dts/blocks/src/system/blocks/product-list.d.ts +592 -604
  81. package/dist/_dts/blocks/src/system/blocks/products/shared.d.ts +0 -4
  82. package/dist/_dts/blocks/src/system/blocks/shop.d.ts +592 -592
  83. package/dist/_dts/blocks/src/system/blocks/team-members.d.ts +2 -2
  84. package/dist/_dts/blocks/src/system/blocks/testimonials.d.ts +3 -0
  85. package/dist/_dts/blocks/src/system/componentFactory.d.ts +1 -0
  86. package/dist/_dts/blocks/src/system/constants/background.d.ts +1 -1
  87. package/dist/_dts/blocks/src/system/constants/blockKinds.d.ts +1 -1
  88. package/dist/_dts/blocks/src/system/customize/backgrounds.d.ts +19 -5
  89. package/dist/_dts/blocks/src/system/customize/facets.d.ts +2 -2
  90. package/dist/_dts/blocks/src/system/data/index.d.ts +2 -0
  91. package/dist/_dts/blocks/src/system/data/linkedContentEntries.d.ts +102 -0
  92. package/dist/_dts/blocks/src/system/data/loaderEndpoints.d.ts +1 -1
  93. package/dist/_dts/blocks/src/system/defineBlock.d.ts +3 -1
  94. package/dist/_dts/blocks/src/system/designCapabilities.d.ts +2 -2
  95. package/dist/_dts/blocks/src/system/fields/boxStyles.d.ts +6 -1
  96. package/dist/_dts/blocks/src/system/fragments/library/faqHeading.d.ts +0 -1
  97. package/dist/_dts/blocks/src/system/manifest/schema.d.ts +71 -56
  98. package/dist/_dts/blocks/src/system/media/slotContracts.d.ts +2 -0
  99. package/dist/_dts/blocks/src/system/node/types.d.ts +8 -1
  100. package/dist/_dts/blocks/src/system/node/validation-constants.d.ts +1 -1
  101. package/dist/_dts/blocks/src/system/registry.d.ts +1 -0
  102. package/dist/_dts/blocks/src/system/runtime/api/types.d.ts +1 -1
  103. package/dist/_dts/blocks/src/system/runtime/components/registry.client.d.ts +56 -74
  104. package/dist/_dts/blocks/src/system/runtime/components/runtime-backed-blocks.d.ts +27 -36
  105. package/dist/_dts/blocks/src/system/runtime/headingDecoration.d.ts +21 -0
  106. package/dist/_dts/blocks/src/system/runtime/hooks/useCalendarEvents.d.ts +45 -14
  107. package/dist/_dts/blocks/src/system/runtime/hooks/useEventFilters.d.ts +2 -9
  108. package/dist/_dts/blocks/src/system/runtime/hooks/useEventPagination.d.ts +1 -10
  109. package/dist/_dts/blocks/src/system/runtime/nodes/ImageResolveContext.d.ts +2 -2
  110. package/dist/_dts/blocks/src/system/runtime/nodes/basic.d.ts +4 -0
  111. package/dist/_dts/blocks/src/system/runtime/nodes/booking-form.server.d.ts +1 -1
  112. package/dist/_dts/blocks/src/system/runtime/nodes/booking-runtime-sources.d.ts +3 -1
  113. package/dist/_dts/blocks/src/system/runtime/nodes/carousel.shared.d.ts +2 -1
  114. package/dist/_dts/blocks/src/system/runtime/nodes/cart.client.d.ts +2 -1
  115. package/dist/_dts/blocks/src/system/runtime/nodes/cart.server.d.ts +1 -1
  116. package/dist/_dts/blocks/src/system/runtime/nodes/checkout.client.d.ts +2 -1
  117. package/dist/_dts/blocks/src/system/runtime/nodes/checkout.server.d.ts +1 -1
  118. package/dist/_dts/blocks/src/system/runtime/nodes/commerce/shared/display.d.ts +1 -5
  119. package/dist/_dts/blocks/src/system/runtime/nodes/commerce/shared/view.d.ts +10 -13
  120. package/dist/_dts/blocks/src/system/runtime/nodes/course-details/view.d.ts +3 -2
  121. package/dist/_dts/blocks/src/system/runtime/nodes/course-details.server.d.ts +2 -2
  122. package/dist/_dts/blocks/src/system/runtime/nodes/course-registration/BookingModeStep.d.ts +1 -1
  123. package/dist/_dts/blocks/src/system/runtime/nodes/course-registration/CourseRegistrationWizard.d.ts +2 -1
  124. package/dist/_dts/blocks/src/system/runtime/nodes/course-registration/ErrorStep.d.ts +1 -1
  125. package/dist/_dts/blocks/src/system/runtime/nodes/course-registration/MembershipHero.d.ts +1 -1
  126. package/dist/_dts/blocks/src/system/runtime/nodes/course-registration/PaymentFailedStep.d.ts +1 -1
  127. package/dist/_dts/blocks/src/system/runtime/nodes/course-registration/PortalAuthSidebar.d.ts +1 -1
  128. package/dist/_dts/blocks/src/system/runtime/nodes/course-registration/StepIndicator.d.ts +1 -1
  129. package/dist/_dts/blocks/src/system/runtime/nodes/course-registration/SuccessStep.d.ts +1 -1
  130. package/dist/_dts/blocks/src/system/runtime/nodes/course-registration/VerifyingTimeoutStep.d.ts +1 -1
  131. package/dist/_dts/blocks/src/system/runtime/nodes/course-registration/WaitlistStep.d.ts +1 -1
  132. package/dist/_dts/blocks/src/system/runtime/nodes/course-registration/components.d.ts +5 -4
  133. package/dist/_dts/blocks/src/system/runtime/nodes/course-registration.client.d.ts +3 -2
  134. package/dist/_dts/blocks/src/system/runtime/nodes/course-registration.server.d.ts +1 -1
  135. package/dist/_dts/blocks/src/system/runtime/nodes/event-details/CoursePricingDisplay.d.ts +2 -1
  136. package/dist/_dts/blocks/src/system/runtime/nodes/event-details/view.d.ts +1 -1
  137. package/dist/_dts/blocks/src/system/runtime/nodes/event-details.client.d.ts +2 -2
  138. package/dist/_dts/blocks/src/system/runtime/nodes/event-details.server.d.ts +1 -1
  139. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/EventRegistrationSummaryBar.d.ts +2 -1
  140. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/EventRegistrationWizard.d.ts +2 -1
  141. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/EventRegistrationWizardActions.d.ts +2 -1
  142. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/EventRegistrationWizardContent.d.ts +2 -1
  143. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/EventSelectionStep.d.ts +2 -0
  144. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/OrderSummary.d.ts +1 -1
  145. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/PastOccurrenceNotice.d.ts +2 -1
  146. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/SelectableOptionCard.d.ts +1 -1
  147. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/StepIndicator.d.ts +1 -1
  148. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/registrationDerivations.d.ts +1 -1
  149. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/types.d.ts +1 -2
  150. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/utils.d.ts +2 -1
  151. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration.interactive.d.ts +12 -5
  152. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration.server.d.ts +1 -1
  153. package/dist/_dts/blocks/src/system/runtime/nodes/events/EventCalendar.interactive.d.ts +21 -16
  154. package/dist/_dts/blocks/src/system/runtime/nodes/events/EventCombined.client.d.ts +3 -2
  155. package/dist/_dts/blocks/src/system/runtime/nodes/events/EventCombined.interactive.d.ts +21 -16
  156. package/dist/_dts/blocks/src/system/runtime/nodes/events/EventListing.interactive.d.ts +17 -28
  157. package/dist/_dts/blocks/src/system/runtime/nodes/events/EventListing.view.d.ts +1 -1
  158. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/DateTimeTile.d.ts +2 -1
  159. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/DayEventsModal.d.ts +2 -1
  160. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/EventDetailModal.d.ts +2 -1
  161. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/EventPaginatedListView.client.d.ts +2 -3
  162. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/WeekAgendaView.d.ts +3 -3
  163. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/listOptions.d.ts +50 -0
  164. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/utils.d.ts +2 -1
  165. package/dist/_dts/blocks/src/system/runtime/nodes/gifting.client.d.ts +2 -1
  166. package/dist/_dts/blocks/src/system/runtime/nodes/gifting.server.d.ts +2 -1
  167. package/dist/_dts/blocks/src/system/runtime/nodes/location-map.client.d.ts +2 -2
  168. package/dist/_dts/blocks/src/system/runtime/nodes/location-map.server.d.ts +1 -1
  169. package/dist/_dts/blocks/src/system/runtime/nodes/location-map.shared.d.ts +4 -4
  170. package/dist/_dts/blocks/src/system/runtime/nodes/location-map.view.d.ts +1 -1
  171. package/dist/_dts/blocks/src/system/runtime/nodes/media.d.ts +29 -14
  172. package/dist/_dts/blocks/src/system/runtime/nodes/newsletter-form.server.d.ts +2 -1
  173. package/dist/_dts/blocks/src/system/runtime/nodes/offerings-preview.d.ts +23 -0
  174. package/dist/_dts/blocks/src/system/runtime/nodes/product-detail.client.d.ts +2 -1
  175. package/dist/_dts/blocks/src/system/runtime/nodes/product-detail.server.d.ts +1 -1
  176. package/dist/_dts/blocks/src/system/runtime/nodes/product-list.client.d.ts +2 -1
  177. package/dist/_dts/blocks/src/system/runtime/nodes/product-list.server.d.ts +1 -1
  178. package/dist/_dts/blocks/src/system/runtime/nodes/shared/MagicLinkForm.d.ts +2 -1
  179. package/dist/_dts/blocks/src/system/runtime/nodes/shop-add-feedback.d.ts +1 -1
  180. package/dist/_dts/blocks/src/system/runtime/nodes/shop-commerce.d.ts +5 -4
  181. package/dist/_dts/blocks/src/system/runtime/nodes/shop-commerce.server.d.ts +5 -4
  182. package/dist/_dts/blocks/src/system/runtime/nodes/shop.client.d.ts +2 -1
  183. package/dist/_dts/blocks/src/system/runtime/nodes/shop.interactive.d.ts +0 -17
  184. package/dist/_dts/blocks/src/system/runtime/nodes/shop.server.d.ts +1 -1
  185. package/dist/_dts/blocks/src/system/runtime/nodes/shop.types.d.ts +0 -1
  186. package/dist/_dts/blocks/src/system/runtime/nodes/spinner.d.ts +1 -1
  187. package/dist/_dts/blocks/src/system/runtime/resolver.d.ts +13 -0
  188. package/dist/_dts/blocks/src/system/runtime/shared/components/ActionRow.d.ts +1 -1
  189. package/dist/_dts/blocks/src/system/runtime/shared/components/CheckIcon.d.ts +1 -1
  190. package/dist/_dts/blocks/src/system/runtime/shared/components/ClockIcon.d.ts +1 -1
  191. package/dist/_dts/blocks/src/system/runtime/shared/components/CrossIcon.d.ts +1 -1
  192. package/dist/_dts/blocks/src/system/runtime/shared/components/FeedbackMessage.d.ts +1 -1
  193. package/dist/_dts/blocks/src/system/runtime/shared/components/FieldValidationMessage.d.ts +1 -1
  194. package/dist/_dts/blocks/src/system/runtime/shared/components/MembershipHero.d.ts +1 -1
  195. package/dist/_dts/blocks/src/system/runtime/shared/components/StateIcon.d.ts +1 -1
  196. package/dist/_dts/blocks/src/system/runtime/shared/components/StepIndicator.d.ts +1 -1
  197. package/dist/_dts/blocks/src/system/runtime/shared/components/TerminalPanel.d.ts +1 -1
  198. package/dist/_dts/blocks/src/system/transforms/registry/_utils/sectionForegroundStyles.d.ts +2 -0
  199. package/dist/_dts/blocks/src/system/transforms/registry/boxStyles.d.ts +4 -2
  200. package/dist/_dts/blocks/src/system/transforms/typed.d.ts +1 -1
  201. package/dist/_dts/calendar/src/grid.d.ts +27 -0
  202. package/dist/_dts/calendar/src/index.d.ts +2 -2
  203. package/dist/_dts/content-editor/src/components/ContentFieldsForm.d.ts +1 -1
  204. package/dist/_dts/content-editor/src/components/EditableBlockProvider.d.ts +1 -1
  205. package/dist/_dts/content-editor/src/controller/EntryControllerProvider.d.ts +1 -1
  206. package/dist/_dts/content-editor/src/controller/useAutosaveTriggers.d.ts +3 -1
  207. package/dist/_dts/content-editor/src/editorTransactionState.d.ts +1 -0
  208. package/dist/_dts/content-editor/src/hooks/autosaveScopePlanning.d.ts +26 -0
  209. package/dist/_dts/content-editor/src/hooks/publishability.d.ts +1 -0
  210. package/dist/_dts/content-editor/src/hooks/useLinkedEntryAutosave.d.ts +23 -0
  211. package/dist/_dts/content-editor/src/hooks/useReactiveToolbar.d.ts +1 -1
  212. package/dist/_dts/content-editor/src/hooks/useSimpleAutosave.d.ts +2 -2
  213. package/dist/_dts/content-editor/src/index.d.ts +3 -1
  214. package/dist/_dts/content-editor/src/lib/json.d.ts +2 -0
  215. package/dist/_dts/content-editor/src/linkedEntries/domain.d.ts +8 -0
  216. package/dist/_dts/content-editor/src/primitives/PreviewRichTextEditor.d.ts +6 -1
  217. package/dist/_dts/content-editor/src/primitives/PreviewTextEditor.d.ts +6 -1
  218. package/dist/_dts/content-editor/src/primitives/shared/activePreviewField.d.ts +2 -0
  219. package/dist/_dts/content-editor/src/primitives/shared/index.d.ts +1 -1
  220. package/dist/_dts/content-editor/src/primitives/shared/storeBinding.d.ts +3 -1
  221. package/dist/_dts/content-editor/src/primitives/shared/types.d.ts +5 -0
  222. package/dist/_dts/content-editor/src/ui/editorSnapshot.d.ts +58 -0
  223. package/dist/_dts/content-editor/src/ui/editorTransactionState.d.ts +93 -0
  224. package/dist/_dts/content-editor/src/ui/editorUiStore.d.ts +67 -5
  225. package/dist/_dts/content-editor/src/ui/stores/autosaveStore.d.ts +2 -0
  226. package/dist/_dts/content-editor/src/ui/stores/types.d.ts +1 -1
  227. package/dist/_dts/content-model/src/content-types/builtin-schemas.d.ts +0 -40
  228. package/dist/_dts/content-model/src/content-types/builtins.d.ts +43 -40
  229. package/dist/_dts/content-model/src/metadataConfig.d.ts +87 -47
  230. package/dist/_dts/content-model/src/templates/defaults.d.ts +0 -1
  231. package/dist/_dts/core/src/branded.d.ts +5 -0
  232. package/dist/_dts/core/src/event-pricing.d.ts +72 -0
  233. package/dist/_dts/core/src/index.d.ts +1 -0
  234. package/dist/_dts/core/src/stable-json.d.ts +1 -0
  235. package/dist/_dts/db/src/generated/supabase/database.types.d.ts +27 -2
  236. package/dist/_dts/db/src/schemas/forms.d.ts +4 -4
  237. package/dist/_dts/editor/src/EditorProvider.d.ts +26 -0
  238. package/dist/_dts/editor/src/chrome/EditorChrome.d.ts +26 -0
  239. package/dist/_dts/editor/src/chrome/EditorStatusBar.d.ts +45 -0
  240. package/dist/_dts/editor/src/chrome/statusBarPresentation.d.ts +25 -0
  241. package/dist/_dts/editor/src/components/EditingToggle.d.ts +9 -0
  242. package/dist/_dts/editor/src/hooks/useEditableElement.d.ts +18 -0
  243. package/dist/_dts/editor/src/index.d.ts +29 -0
  244. package/dist/_dts/editor/src/inline/InlineTextEditor.d.ts +1 -0
  245. package/dist/_dts/editor/src/lib/utils.d.ts +1 -0
  246. package/dist/_dts/editor/src/primitives/EditorPrimitivesProvider.d.ts +20 -0
  247. package/dist/_dts/editor/src/primitives/InlineFieldContext.d.ts +11 -0
  248. package/dist/_dts/editor/src/primitives/SaveContext.d.ts +12 -0
  249. package/dist/_dts/editor/src/primitives/helpers.d.ts +1 -0
  250. package/dist/_dts/editor/src/primitives/rich-text/RichTextEditorSurface.d.ts +26 -0
  251. package/dist/_dts/editor/src/primitives/rich-text/RichTextToolbar.d.ts +16 -0
  252. package/dist/_dts/editor/src/primitives/rich-text/config.d.ts +23 -0
  253. package/dist/_dts/editor/src/primitives/rich-text/extensions/RichTextImage.d.ts +2 -0
  254. package/dist/_dts/editor/src/primitives/rich-text/extensions/RichTextLink.d.ts +1 -0
  255. package/dist/_dts/editor/src/primitives/rich-text/imageActions.d.ts +22 -0
  256. package/dist/_dts/editor/src/primitives/rich-text/sanitize.d.ts +23 -0
  257. package/dist/_dts/editor/src/primitives/rich-text/toolbar/BlockTypeDropdown.d.ts +6 -0
  258. package/dist/_dts/editor/src/primitives/rich-text/toolbar/LinkPopover.d.ts +10 -0
  259. package/dist/_dts/editor/src/primitives/rich-text/toolbar/ToolbarIconButton.d.ts +11 -0
  260. package/dist/_dts/editor/src/primitives/rich-text/toolbar/linkPopoverUtils.d.ts +58 -0
  261. package/dist/_dts/editor/src/primitives/rich-text/useRichTextEditor.d.ts +19 -0
  262. package/dist/_dts/editor/src/primitives/rich-text/utils.d.ts +20 -0
  263. package/dist/_dts/editor/src/utils/optimisticTokens.d.ts +27 -0
  264. package/dist/_dts/editor-blocks/src/BlockEditor.d.ts +2 -2
  265. package/dist/_dts/editor-blocks/src/BlockForm.d.ts +2 -1
  266. package/dist/_dts/editor-blocks/src/FormProvider.d.ts +1 -1
  267. package/dist/_dts/editor-blocks/src/block-editor/AddBlockDivider.d.ts +1 -1
  268. package/dist/_dts/editor-blocks/src/block-editor/BlockCard.d.ts +4 -4
  269. package/dist/_dts/editor-blocks/src/block-editor/BlockCardBody.d.ts +1 -1
  270. package/dist/_dts/editor-blocks/src/block-editor/BlockCardHeader.d.ts +5 -5
  271. package/dist/_dts/editor-blocks/src/block-editor/BlockListContext.d.ts +1 -1
  272. package/dist/_dts/editor-blocks/src/block-editor/BlockPickerDialog.d.ts +1 -1
  273. package/dist/_dts/editor-blocks/src/block-editor/BlockThumbnail.d.ts +1 -1
  274. package/dist/_dts/editor-blocks/src/block-editor/BlockTile.d.ts +2 -2
  275. package/dist/_dts/editor-blocks/src/block-editor/EmptyState.d.ts +1 -1
  276. package/dist/_dts/editor-blocks/src/block-editor/EnhancedBlockPickerDialog.d.ts +1 -1
  277. package/dist/_dts/editor-blocks/src/block-editor/FeatureCardIconsPanel.d.ts +1 -1
  278. package/dist/_dts/editor-blocks/src/block-editor/GeneratedIconSetDialog.d.ts +1 -1
  279. package/dist/_dts/editor-blocks/src/block-editor/HeaderActions.d.ts +1 -1
  280. package/dist/_dts/editor-blocks/src/block-editor/SortableBlockItem.d.ts +4 -4
  281. package/dist/_dts/editor-blocks/src/block-editor/actionPresentation.d.ts +15 -0
  282. package/dist/_dts/editor-blocks/src/block-editor/blockHeaderActionPlan.d.ts +49 -0
  283. package/dist/_dts/editor-blocks/src/block-editor/types.d.ts +1 -0
  284. package/dist/_dts/editor-blocks/src/media/MediaField.d.ts +2 -2
  285. package/dist/_dts/editor-blocks/src/widgets/button/ButtonField.d.ts +1 -1
  286. package/dist/_dts/editor-blocks/src/widgets/button/ButtonVariantField.d.ts +1 -1
  287. package/dist/_dts/editor-blocks/src/widgets/button/context.d.ts +1 -1
  288. package/dist/_dts/editor-blocks/src/widgets/content-type-select/ContentTypeSelectField.d.ts +1 -1
  289. package/dist/_dts/editor-blocks/src/widgets/content-type-select/ContentTypeWidgetProvider.d.ts +1 -1
  290. package/dist/_dts/editor-blocks/src/widgets/entry-picker/EntryPickerField.d.ts +1 -1
  291. package/dist/_dts/editor-blocks/src/widgets/entry-picker/EntryPickerWidgetProvider.d.ts +1 -1
  292. package/dist/_dts/editor-blocks/src/widgets/icon-picker/IconPickerField.d.ts +1 -1
  293. package/dist/_dts/editor-blocks/src/widgets/index.d.ts +2 -0
  294. package/dist/_dts/editor-blocks/src/widgets/link/LinkPicker.d.ts +1 -1
  295. package/dist/_dts/editor-blocks/src/widgets/link/LinkPickerDialog.d.ts +1 -1
  296. package/dist/_dts/editor-blocks/src/widgets/link/LinkSummary.d.ts +1 -1
  297. package/dist/_dts/editor-blocks/src/widgets/link/LinkWidget.d.ts +1 -1
  298. package/dist/_dts/editor-blocks/src/widgets/link/LinkWidgetContext.d.ts +1 -1
  299. package/dist/_dts/editor-blocks/src/widgets/offerings-preview/OfferingsPreviewGroupOrderField.d.ts +2 -0
  300. package/dist/_dts/editor-blocks/src/widgets/offerings-preview/OfferingsPreviewWidgetProvider.d.ts +10 -0
  301. package/dist/_dts/editor-blocks/src/widgets/offerings-preview/index.d.ts +3 -0
  302. package/dist/_dts/editor-blocks/src/widgets/offerings-preview/orderDomain.d.ts +29 -0
  303. package/dist/_dts/editor-blocks/src/widgets/reference/ReferenceField.d.ts +1 -1
  304. package/dist/_dts/editor-blocks/src/widgets/reference/ReferenceWidgetProvider.d.ts +1 -1
  305. package/dist/_dts/editor-blocks/src/widgets/rich-text/RichTextField.d.ts +1 -1
  306. package/dist/_dts/editor-blocks/src/widgets/rich-text/RichTextWidgetProvider.d.ts +2 -2
  307. package/dist/_dts/editor-blocks/src/widgets/rich-text/useImagePicker.d.ts +2 -2
  308. package/dist/_dts/editor-blocks/src/widgets/site-option-picker/SiteOptionPickerField.d.ts +3 -0
  309. package/dist/_dts/editor-blocks/src/widgets/site-option-picker/SiteOptionWidgetProvider.d.ts +14 -0
  310. package/dist/_dts/editor-blocks/src/widgets/site-option-picker/index.d.ts +6 -0
  311. package/dist/_dts/editor-blocks/src/widgets/site-option-picker/loaders.d.ts +51 -0
  312. package/dist/_dts/editor-blocks/src/widgets/site-option-picker/types.d.ts +20 -0
  313. package/dist/_dts/editor-blocks/src/widgets/site-option-picker/utils.d.ts +5 -0
  314. package/dist/_dts/media-core/src/index.d.ts +1 -0
  315. package/dist/_dts/media-core/src/renderableMediaAsset.d.ts +18 -0
  316. package/dist/_dts/media-editor/src/CropDialog.d.ts +1 -1
  317. package/dist/_dts/media-editor/src/CropDialogShell.d.ts +1 -1
  318. package/dist/_dts/media-editor/src/FileAssetPreview.d.ts +1 -1
  319. package/dist/_dts/media-editor/src/MediaEditor.d.ts +4 -1
  320. package/dist/_dts/media-editor/src/MediaPickerDialog.d.ts +2 -1
  321. package/dist/_dts/media-editor/src/MediaPreview.d.ts +1 -1
  322. package/dist/_dts/media-editor/src/context.d.ts +1 -1
  323. package/dist/_dts/media-editor/src/createMediaEditorProvider.d.ts +1 -1
  324. package/dist/_dts/media-editor/src/index.d.ts +1 -1
  325. package/dist/_dts/media-editor/src/provider.d.ts +1 -1
  326. package/dist/_dts/media-react/src/components/AuthenticatedImage.d.ts +1 -1
  327. package/dist/_dts/media-react/src/components/MediaLibrary.d.ts +1 -1
  328. package/dist/_dts/media-react/src/components/MediaPickerMini.d.ts +1 -1
  329. package/dist/_dts/preview-next/src/client/PreviewShellSmoke.d.ts +2 -1
  330. package/dist/_dts/preview-next/src/client/blocks/BlockToolbar.d.ts +7 -4
  331. package/dist/_dts/preview-next/src/client/blocks/BoundaryControl.d.ts +2 -1
  332. package/dist/_dts/preview-next/src/client/blocks/EditablePageRenderer.d.ts +7 -3
  333. package/dist/_dts/preview-next/src/client/blocks/blockCustomizePopoverRows.d.ts +25 -0
  334. package/dist/_dts/preview-next/src/client/blocks/composer/mergeDrafts.d.ts +2 -1
  335. package/dist/_dts/preview-next/src/client/blocks/composer/types.d.ts +4 -30
  336. package/dist/_dts/preview-next/src/client/blocks/linkedEntryRenderOverlay.d.ts +11 -0
  337. package/dist/_dts/preview-next/src/client/blocks/previewCustomizeActions.d.ts +3 -9
  338. package/dist/_dts/preview-next/src/client/blocks/previewCustomizeControlPlan.d.ts +2 -2
  339. package/dist/_dts/preview-next/src/client/blocks/useBlockCustomizeControls.d.ts +2 -1
  340. package/dist/_dts/preview-next/src/client/index.d.ts +0 -1
  341. package/dist/_dts/preview-next/src/client/layout/PreviewLayoutContext.d.ts +1 -1
  342. package/dist/_dts/preview-next/src/client/preview/EntryEditorPanel.d.ts +4 -2
  343. package/dist/_dts/preview-next/src/client/preview/LinkedEntryEditEventBridge.d.ts +1 -0
  344. package/dist/_dts/preview-next/src/client/preview/MaintenanceModeBadge.d.ts +1 -1
  345. package/dist/_dts/preview-next/src/client/preview/OnboardingThemeSwitcher.d.ts +2 -1
  346. package/dist/_dts/preview-next/src/client/preview/PageBlockEditorPanel.d.ts +6 -3
  347. package/dist/_dts/preview-next/src/client/preview/PageDesignEditorStateContext.d.ts +2 -2
  348. package/dist/_dts/preview-next/src/client/preview/PreviewAuthBanner.d.ts +2 -1
  349. package/dist/_dts/preview-next/src/client/preview/PreviewAuthInit.d.ts +1 -1
  350. package/dist/_dts/preview-next/src/client/preview/PreviewBlockCustomizeSelectionContext.d.ts +2 -2
  351. package/dist/_dts/preview-next/src/client/preview/PreviewChromeLayer.d.ts +20 -0
  352. package/dist/_dts/preview-next/src/client/preview/PreviewConfirmationDialog.d.ts +2 -1
  353. package/dist/_dts/preview-next/src/client/preview/PreviewDesignCoordinatorContext.d.ts +2 -2
  354. package/dist/_dts/preview-next/src/client/preview/PreviewDesignHistoryOrderContext.d.ts +13 -0
  355. package/dist/_dts/preview-next/src/client/preview/PreviewEditorGuidanceCard.d.ts +2 -1
  356. package/dist/_dts/preview-next/src/client/preview/PreviewEditorSidebar.d.ts +4 -3
  357. package/dist/_dts/preview-next/src/client/preview/PreviewEntryControllerProvider.d.ts +2 -2
  358. package/dist/_dts/preview-next/src/client/preview/PreviewOpenEditorButton.d.ts +3 -2
  359. package/dist/_dts/preview-next/src/client/preview/PreviewQueryProvider.d.ts +2 -2
  360. package/dist/_dts/preview-next/src/client/preview/PreviewShell.d.ts +21 -20
  361. package/dist/_dts/preview-next/src/client/preview/PreviewShellLayout.d.ts +4 -3
  362. package/dist/_dts/preview-next/src/client/preview/PreviewSidebarSection.d.ts +13 -0
  363. package/dist/_dts/preview-next/src/client/preview/PreviewViewportControls.d.ts +1 -1
  364. package/dist/_dts/preview-next/src/client/preview/PreviewZoomControls.d.ts +1 -1
  365. package/dist/_dts/preview-next/src/client/preview/SelectedBlockCustomizePanel.d.ts +2 -1
  366. package/dist/_dts/preview-next/src/client/preview/SiteChromeCustomizeButton.d.ts +2 -1
  367. package/dist/_dts/preview-next/src/client/preview/SiteChromeCustomizeContext.d.ts +60 -6
  368. package/dist/_dts/preview-next/src/client/preview/StyleConfigurator.d.ts +2 -1
  369. package/dist/_dts/preview-next/src/client/preview/StyleConfigurator.state.d.ts +14 -1
  370. package/dist/_dts/preview-next/src/client/preview/SubrouteNoticePanel.d.ts +2 -1
  371. package/dist/_dts/preview-next/src/client/preview/linkedEntryEditEvents.d.ts +9 -0
  372. package/dist/_dts/preview-next/src/client/preview/previewChromePlacement.d.ts +51 -0
  373. package/dist/_dts/preview-next/src/client/preview/previewCustomizeControls.d.ts +68 -0
  374. package/dist/_dts/preview-next/src/client/preview/previewCustomizeHistory.d.ts +8 -1
  375. package/dist/_dts/preview-next/src/client/preview/previewCustomizeWorkflowState.d.ts +11 -9
  376. package/dist/_dts/preview-next/src/client/preview/previewDesignHistoryOrder.d.ts +18 -0
  377. package/dist/_dts/preview-next/src/client/preview/previewUndoDomains.d.ts +1 -1
  378. package/dist/_dts/preview-next/src/client/preview/siteChromeBrandPreferences.d.ts +41 -0
  379. package/dist/_dts/preview-next/src/client/preview/siteChromeQuickControlHistoryState.d.ts +120 -0
  380. package/dist/_dts/preview-next/src/client/preview/siteChromeSavePlan.d.ts +30 -0
  381. package/dist/_dts/preview-next/src/client/preview/siteStyleHistoryState.d.ts +55 -0
  382. package/dist/_dts/preview-next/src/client/preview/styleConfiguratorApplyPayload.d.ts +1 -0
  383. package/dist/_dts/preview-next/src/client/preview/themeOverlay.d.ts +2 -2
  384. package/dist/_dts/preview-next/src/client/sdk/SdkPreviewModeRuntime.d.ts +2 -1
  385. package/dist/_dts/preview-next/src/client/widgets/widgetAdapters.d.ts +2 -1
  386. package/dist/_dts/preview-next/src/client/widgets/widgetOverrides.d.ts +8 -5
  387. package/dist/_dts/preview-next/src/constants.d.ts +0 -1
  388. package/dist/_dts/sdk/src/__mocks__/next-cache.d.ts +4 -3
  389. package/dist/_dts/sdk/src/cli/commands/pull-dry-run.d.ts +1 -1
  390. package/dist/_dts/sdk/src/cli/config-loader.d.ts +3 -1
  391. package/dist/_dts/sdk/src/cli/content/reader.d.ts +6 -12
  392. package/dist/_dts/sdk/src/cli/site-commands/commandSurfaceDispatch.d.ts +1 -0
  393. package/dist/_dts/sdk/src/cli/site-commands/localBlockManifestResolver.d.ts +31 -0
  394. package/dist/_dts/sdk/src/cli/site-commands/pageCommands.d.ts +3 -1
  395. package/dist/_dts/sdk/src/cli/site-commands/pushExecution.d.ts +1 -0
  396. package/dist/_dts/sdk/src/cli/sync/validation.d.ts +7 -7
  397. package/dist/_dts/sdk/src/client/types.d.ts +36 -4
  398. package/dist/_dts/sdk/src/client.d.ts +1 -1
  399. package/dist/_dts/sdk/src/config/content-types.d.ts +3 -14
  400. package/dist/_dts/sdk/src/config/content-validation.d.ts +9 -214
  401. package/dist/_dts/sdk/src/config/types.d.ts +10 -1
  402. package/dist/_dts/sdk/src/config/validation.d.ts +24 -24
  403. package/dist/_dts/sdk/src/contracts/system-block-content.d.ts +30 -4
  404. package/dist/_dts/sdk/src/index.d.ts +1 -1
  405. package/dist/_dts/sdk/src/preview-next/client/index.d.ts +6 -6
  406. package/dist/_dts/sdk/src/preview-next/client/runtime.d.ts +4 -3
  407. package/dist/_dts/sdk/src/public-api/contracts.d.ts +39 -37
  408. package/dist/_dts/sdk/src/rendering/components/Block.d.ts +1 -1
  409. package/dist/_dts/sdk/src/rendering/components/Block.server.d.ts +1 -1
  410. package/dist/_dts/sdk/src/rendering/components/Layout.d.ts +1 -1
  411. package/dist/_dts/sdk/src/rendering/components/Page.d.ts +1 -1
  412. package/dist/_dts/sdk/src/rendering/components/Page.server.d.ts +1 -1
  413. package/dist/_dts/sdk/src/rendering/components/PageHydrationBootstrap.d.ts +1 -1
  414. package/dist/_dts/sdk/src/rendering/helpers/bindings.d.ts +10 -9
  415. package/dist/_dts/sdk/src/rendering/islands/enhancers/routeIslandApiConfig.d.ts +9 -0
  416. package/dist/_dts/sdk/src/rendering/islands/types.d.ts +6 -15
  417. package/dist/_dts/sdk/src/rendering/mediaAssets.d.ts +4 -0
  418. package/dist/_dts/sdk/src/rendering/primitives/RichText.d.ts +2 -1
  419. package/dist/_dts/sdk/src/server.d.ts +1 -1
  420. package/dist/_dts/sdk/src/theme-bridge/ThemeBridgeProvider.d.ts +1 -1
  421. package/dist/_dts/sdk/src/types/block-kinds.d.ts +1 -1
  422. package/dist/_dts/sdk/src/version.d.ts +1 -1
  423. package/dist/_dts/site-commands/src/commands.d.ts +69 -21
  424. package/dist/_dts/theme-core/src/ClientThemeScope.d.ts +1 -1
  425. package/dist/_dts/theme-core/src/ThemeFontLoader.d.ts +3 -2
  426. package/dist/_dts/theme-core/src/ThemeScope.d.ts +1 -1
  427. package/dist/_dts/theme-core/src/ThemeScopeCore.d.ts +1 -1
  428. package/dist/_dts/theme-core/src/accordions/types.d.ts +5 -5
  429. package/dist/_dts/theme-core/src/buttons/constants.d.ts +26 -1
  430. package/dist/_dts/theme-core/src/buttons/personalities/index.d.ts +11 -0
  431. package/dist/_dts/theme-core/src/buttons/personalities/joy-stamp.d.ts +22 -0
  432. package/dist/_dts/theme-core/src/buttons/personalities/types.d.ts +8 -7
  433. package/dist/_dts/theme-core/src/buttons/types.d.ts +26 -17
  434. package/dist/_dts/theme-core/src/cards/siteStyleDefaults.d.ts +44 -0
  435. package/dist/_dts/theme-core/src/cards/types.d.ts +5 -5
  436. package/dist/_dts/theme-core/src/generated/containerResponsiveThemeCss.d.ts +1 -1
  437. package/dist/_dts/theme-core/src/inputs/types.d.ts +2 -2
  438. package/dist/_dts/theme-core/src/interactive/baseSchema.d.ts +1 -1
  439. package/dist/_dts/theme-core/src/interactive/types.d.ts +10 -0
  440. package/dist/_dts/theme-core/src/mock-themes/all.d.ts +228 -198
  441. package/dist/_dts/theme-core/src/mock-themes/components/PaletteCard.d.ts +1 -1
  442. package/dist/_dts/theme-core/src/mock-themes/components/swatch.d.ts +1 -1
  443. package/dist/_dts/theme-core/src/navigation/presets.d.ts +1 -1
  444. package/dist/_dts/theme-core/src/navigation/types.d.ts +1 -1
  445. package/dist/_dts/theme-core/src/palette/variants/index.d.ts +15 -0
  446. package/dist/_dts/theme-core/src/palette/variants/types.d.ts +6 -6
  447. package/dist/_dts/theme-core/src/palette/variants/warm-dark.d.ts +27 -0
  448. package/dist/_dts/theme-core/src/schema.d.ts +273 -226
  449. package/dist/_dts/theme-core/src/shared/componentStyles.d.ts +2 -2
  450. package/dist/_dts/theme-core/src/site-styles/accessibleSurfaces.d.ts +4 -1
  451. package/dist/_dts/theme-core/src/site-styles/appearancePresetCatalog.d.ts +87 -31
  452. package/dist/_dts/theme-core/src/site-styles/appearancePresetResolution.d.ts +6 -2
  453. package/dist/_dts/theme-core/src/site-styles/backgroundAppearance.d.ts +27 -0
  454. package/dist/_dts/theme-core/src/site-styles/blockAppearancePresets.d.ts +87 -31
  455. package/dist/_dts/theme-core/src/site-styles/curatedSiteStyles.d.ts +30 -1
  456. package/dist/_dts/theme-core/src/site-styles/designState.d.ts +32 -16
  457. package/dist/_dts/theme-core/src/site-styles/generatedSchemas.d.ts +13 -9
  458. package/dist/_dts/theme-core/src/site-styles/headerLooks.d.ts +5 -0
  459. package/dist/_dts/theme-core/src/site-styles/index.d.ts +3 -0
  460. package/dist/_dts/theme-core/src/site-styles/logoBranding.d.ts +4 -4
  461. package/dist/_dts/theme-core/src/site-styles/pageDesignEditorModel.d.ts +3 -23
  462. package/dist/_dts/theme-core/src/site-styles/pageDesignIntent.d.ts +276 -4
  463. package/dist/_dts/theme-core/src/site-styles/rawStyleFields.d.ts +2 -0
  464. package/dist/_dts/theme-core/src/site-styles/runtimeCompiler.d.ts +33 -3
  465. package/dist/_dts/theme-core/src/site-styles/sectionTransitions.d.ts +508 -0
  466. package/dist/_dts/theme-core/src/site-styles/siteChromeBackgrounds.d.ts +30 -0
  467. package/dist/_dts/theme-core/src/site-styles/sourceCatalogs.d.ts +10 -10
  468. package/dist/_dts/theme-core/src/site-styles/styleTags.d.ts +1 -1
  469. package/dist/_dts/theme-core/src/site-styles/tokenRecipes.d.ts +1 -1
  470. package/dist/_dts/theme-core/src/site-styles/types.d.ts +26 -6
  471. package/dist/_dts/theme-core/src/site-styles/typographyPresets.d.ts +16 -1
  472. package/dist/_dts/theme-core/src/tokens/themeColorTokens.d.ts +3 -3
  473. package/dist/_dts/ui/src/async-boundary.d.ts +1 -1
  474. package/dist/_dts/ui/src/badge.d.ts +1 -1
  475. package/dist/_dts/ui/src/button-group.d.ts +3 -3
  476. package/dist/_dts/ui/src/calendar.d.ts +2 -2
  477. package/dist/_dts/ui/src/card.d.ts +6 -6
  478. package/dist/_dts/ui/src/combobox.d.ts +1 -1
  479. package/dist/_dts/ui/src/command-multi-select.d.ts +1 -1
  480. package/dist/_dts/ui/src/content-spinner.d.ts +1 -1
  481. package/dist/_dts/ui/src/delayed-spinner.d.ts +1 -1
  482. package/dist/_dts/ui/src/dev-toolbar.d.ts +1 -1
  483. package/dist/_dts/ui/src/dialog.d.ts +10 -10
  484. package/dist/_dts/ui/src/dropdown-menu.d.ts +1 -1
  485. package/dist/_dts/ui/src/editor-drawer.d.ts +1 -1
  486. package/dist/_dts/ui/src/empty-state.d.ts +1 -1
  487. package/dist/_dts/ui/src/filter-button-group.d.ts +1 -1
  488. package/dist/_dts/ui/src/fixed-bottom-surface.d.ts +1 -1
  489. package/dist/_dts/ui/src/form.d.ts +7 -7
  490. package/dist/_dts/ui/src/label.d.ts +1 -1
  491. package/dist/_dts/ui/src/menubar.d.ts +16 -16
  492. package/dist/_dts/ui/src/navigation-tabs.d.ts +2 -2
  493. package/dist/_dts/ui/src/number-input.d.ts +1 -1
  494. package/dist/_dts/ui/src/palette/ColorChooserDialog.d.ts +1 -1
  495. package/dist/_dts/ui/src/palette/ColorSlotButton.d.ts +1 -1
  496. package/dist/_dts/ui/src/palette/ColorSwatchButton.d.ts +1 -1
  497. package/dist/_dts/ui/src/palette/PaletteTokenEditor.d.ts +1 -1
  498. package/dist/_dts/ui/src/resizable-split-pane.d.ts +1 -1
  499. package/dist/_dts/ui/src/select.d.ts +10 -10
  500. package/dist/_dts/ui/src/separator.d.ts +1 -1
  501. package/dist/_dts/ui/src/sheet.d.ts +9 -9
  502. package/dist/_dts/ui/src/spinner.d.ts +1 -1
  503. package/dist/_dts/ui/src/tooltip.d.ts +4 -4
  504. package/dist/{chunk-MPBNEVPB.mjs → chunk-2BUMISSH.mjs} +1 -1
  505. package/dist/{chunk-7PCYG6YV.mjs → chunk-6FWNF3DJ.mjs} +2086 -1128
  506. package/dist/{chunk-BBLZSQEY.mjs → chunk-FIREV57T.mjs} +14 -9
  507. package/dist/{chunk-5NZGBSJF.mjs → chunk-G35HOQEN.mjs} +2608 -2397
  508. package/dist/{chunk-HTB4BMKD.mjs → chunk-HKB6XVIP.mjs} +321 -113
  509. package/dist/{chunk-GYXKAUFV.mjs → chunk-XQR6THQJ.mjs} +27831 -17740
  510. package/dist/cli/index.mjs +4581 -2802
  511. package/dist/cli/init-docs/content/workflow-custom-block.md +5 -0
  512. package/dist/client/{accordion-QFZMNB7O.mjs → accordion-G34C45TW.mjs} +2 -2
  513. package/dist/client/{bookingForm-NCIXFWIG.mjs → bookingForm-BLBVKSAQ.mjs} +12 -12
  514. package/dist/client/bookings.mjs +321 -60
  515. package/dist/client/{carousel-EO4BJMWD.mjs → carousel-7ZVTBRMD.mjs} +3 -3
  516. package/dist/client/{cart-FTYCLYUW.mjs → cart-Q6S6LZUO.mjs} +8 -7
  517. package/dist/client/{checkout-NFGLVCOX.mjs → checkout-5QJLDE4I.mjs} +8 -7
  518. package/dist/client/{chunk-IWFZSQNZ.mjs → chunk-5PQH4Y75.mjs} +3 -3
  519. package/dist/client/{chunk-Y37KDO7P.mjs → chunk-CHAB5ACD.mjs} +5 -4
  520. package/dist/client/{chunk-VDS5YFLX.mjs → chunk-CSZGLBYR.mjs} +1 -1
  521. package/dist/client/{chunk-3PEDD5KJ.mjs → chunk-DVNUDUVT.mjs} +1 -1
  522. package/dist/client/{chunk-6GVVWSPU.mjs → chunk-EQKYMX4N.mjs} +348 -301
  523. package/dist/client/{chunk-YLMKMCSJ.mjs → chunk-GFSQNTRW.mjs} +1 -3
  524. package/dist/client/chunk-L4J5Y62O.mjs +18 -0
  525. package/dist/client/{chunk-PUOELU4O.mjs → chunk-RJHTCTCZ.mjs} +550 -262
  526. package/dist/client/{chunk-AUJ5DBZJ.mjs → chunk-S3MKFGOG.mjs} +170 -28
  527. package/dist/client/{chunk-CE7IBGVW.mjs → chunk-SBBSMFFG.mjs} +1 -1
  528. package/dist/client/{chunk-4W66ALYT.mjs → chunk-U2EW7RSR.mjs} +1 -1
  529. package/dist/client/{chunk-PYRBIURC.mjs → chunk-WJFHDTYF.mjs} +17 -34
  530. package/dist/client/{chunk-T6UIP6UZ.mjs → chunk-ZF4XEWDM.mjs} +1 -1
  531. package/dist/client/client.mjs +13449 -9393
  532. package/dist/client/{courseRegistration-2EORROPS.mjs → courseRegistration-VUG2JJDB.mjs} +13 -12
  533. package/dist/client/{eventCalendar-WZI4VL6N.mjs → eventCalendar-E7D2LD4N.mjs} +14 -14
  534. package/dist/client/{eventCombined-QCB2TCNL.mjs → eventCombined-FUZ2Z3CS.mjs} +14 -14
  535. package/dist/client/{eventDetails-TFTATAPH.mjs → eventDetails-QRITJAOW.mjs} +9 -9
  536. package/dist/client/{eventListing-A2CQEHEQ.mjs → eventListing-INMQMJZ5.mjs} +14 -14
  537. package/dist/client/{eventRegistration-OELPVLUY.mjs → eventRegistration-TOOJD4WU.mjs} +17 -15
  538. package/dist/client/{form-NTIFD6WQ.mjs → form-BOWN7ZNQ.mjs} +3 -3
  539. package/dist/client/{headerSection-7TBNKCLA.mjs → headerSection-HFQNZOUU.mjs} +55 -14
  540. package/dist/client/hooks.mjs +26989 -25527
  541. package/dist/client/{locationMap-LRLB5A3H.mjs → locationMap-VUZGC7Y5.mjs} +2 -2
  542. package/dist/client/{newsletterForm-XI52RZSN.mjs → newsletterForm-X2XQTPCB.mjs} +3 -3
  543. package/dist/client/{productDetail-GSNKBFLY.mjs → productDetail-TA7D2G2B.mjs} +8 -7
  544. package/dist/client/{productList-BGCGT4KZ.mjs → productList-AZOLOZKM.mjs} +8 -7
  545. package/dist/client/rendering/client.mjs +5518 -3869
  546. package/dist/client/rendering/islands.mjs +32 -20
  547. package/dist/client/rendering.mjs +14494 -10485
  548. package/dist/client/{shop-RQHUCLNY.mjs → shop-ZDLO7IIG.mjs} +8 -7
  549. package/dist/client/spam-protection.mjs +3 -5
  550. package/dist/preview-next/client/runtime.css +1 -1
  551. package/dist/preview-next/client/runtime.mjs +5 -5
  552. package/dist/preview-next/constants.mjs +0 -2
  553. package/dist/preview-next/index.mjs +0 -2
  554. package/dist/{sdk-runtime-A4LHT2RS.mjs → sdk-runtime-CTWKNBDQ.mjs} +6 -6
  555. package/dist/{sdk-runtime-EEMNSB7J.css → sdk-runtime-JD4A6SU6.css} +1 -1
  556. package/dist/server/components.mjs +10475 -7369
  557. package/dist/server/config-validation.mjs +26616 -25360
  558. package/dist/server/config.mjs +26616 -25360
  559. package/dist/server/data.mjs +27048 -25586
  560. package/dist/server/index.mjs +109 -56
  561. package/dist/server/next.mjs +15424 -12076
  562. package/dist/server/page-converter.mjs +5570 -3107
  563. package/dist/server/prebuild.mjs +2 -1
  564. package/dist/server/rendering/server.mjs +10850 -7549
  565. package/dist/server/rendering.mjs +10855 -7554
  566. package/dist/server/routing.mjs +30134 -28531
  567. package/dist/server/server.mjs +27369 -25856
  568. package/dist/server/theme-bridge.mjs +902 -167
  569. package/dist/server/theme.mjs +197 -133
  570. package/dist/styles/index.css +606 -133
  571. package/package.json +16 -16
  572. package/dist/SdkPreviewModeRuntime-XE5M4UKM.mjs +0 -8
  573. package/dist/_dts/editor-blocks/src/block-editor/actionControlMode.d.ts +0 -2
  574. package/dist/_dts/preview-next/src/client/preview/previewSurface.d.ts +0 -3
@@ -1,11 +1,12 @@
1
1
  "use client";
2
- import { useOptionalPreviewLayout, PreviewQueryProvider } from './chunk-MPBNEVPB.mjs';
3
- import { PreviewThemeOverlayProvider, PreviewDesignCoordinatorProvider, PreviewBlockCustomizeSelectionProvider, resolveSiteStyleAccess, usePreviewDesignCoordinator, createOptimisticActionRunner, resolveStyleConfiguratorInitialSnapshot, createStyleConfiguratorState, syncStyleConfiguratorState, buildSiteChromeLookModels, planSiteStylePreviewChange, markApplyFailed, markApplySaved, markApplySaving, previewHeaderStyle, previewHeaderLayout, previewFooterLook, cycleSiteChromeLookId, usePreviewThemeOverlay, resolvePreviewDashboardSetupHandoff, buildPreviewDashboardSetupUrl, resolvePreviewSetupBannerModel, planSiteChromeLookSelection, usePreviewBlockCustomizeSelectionOptional, useBlockCustomizeControls, MAX_CUSTOMIZE_POPOVER_ROWS, MAX_QUICK_MANIFEST_FIELDS, sanitizeDashboardPath } from './chunk-5NZGBSJF.mjs';
4
- import { resolvePreviewChromeSurface, getPreviewSidebarTab, onPreviewSidebarOpenRequest, getPreviewChromeSurfaceDataProps, PREVIEW_CHROME_THEME_CLASS_NAME, setPreviewSidebarTab, PreviewPageDesignEditorStateProvider, usePreviewPageDesignEditorState, PREVIEW_SURFACE_PARAM } from './chunk-HTB4BMKD.mjs';
5
- import { clientComponentRegistry, deriveLaunchReadiness, DEFAULT_LAUNCH_READINESS_INPUT, useEditorUiStore, ResizableSplitPane, BlockApiProvider, EditorProvider, MediaEditorProvider, getCuratedSiteStyle, useEditor, createRoutingHelpers, createSnapshotFromPageRecord, EntryControllerProvider, useEntryEditorController, useEditorUiStoreInstance, surfaceResolutionContextFromTheme, unsafeAsEditorBlockId, EditableBlockProvider, asDesignBlockId, PageRenderer, planSiteDocument, ThemeScope, FixedBottomSurface, Button, unwrapResponse, X, ChevronLeft, ChevronRight, RotateCcw, parseBackgroundOverrideFromContent, rankBackgroundImagePoolItems, imagePoolForOverride, resolveBackgroundCapability, enabledBackgroundModes, FormRenderer, PreviewRichTextEditor, RichText, PreviewTextEditor, Text, buildThemeRuntime, renderBlock, siteHeaderManifest, siteFooterManifest, SiteDocumentLayout, SITE_CHROME_CLASS_NAMES, Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter, buildEditorModelRuntimeFieldsByBlockId, applyCompiledRuntimeFieldsToContent, assertNever2, getBlockDefinition, systemCustomizeFacetDefinitionsForBlock, systemCustomizeFacetAppliesToLayoutVariant, systemCustomizeFacetCurrentValue, systemCustomizeFacetLabelForValue, backgroundColorTokens, Image, useMediaEditorOptional, defaultBackgroundOverrideForMode, Upload, MediaEditor, visibleHeaderClearancePx, systemCustomizeFacetNextValue, planBackgroundTransition, GRADIENT_PRESETS, gradientToCss, parseMediaAssetId, planBackgroundOverride, EDITABLE_SURFACE_FORWARDING_PROP, assertNever, SITE_CHROME_VISIBLE_HEADER_SELECTOR } from './chunk-GYXKAUFV.mjs';
6
- import { API_ENDPOINTS, createBearerAPIClient, isPreviewRuntimeSessionEditable, DEFAULT_SURFACE_ID, initPreviewAuth, usePreviewAuth, usePreviewAuthFetch, markPreviewAuthExpired, usePreviewToken, parseSurfaceId } from './chunk-BBLZSQEY.mjs';
7
- import React9, { createContext, useMemo, useState, useEffect, useRef, useCallback, useId, useReducer, Children, isValidElement, Fragment as Fragment$1, cloneElement, useContext } from 'react';
2
+ import { useOptionalPreviewLayout, PreviewQueryProvider } from './chunk-2BUMISSH.mjs';
3
+ import { PreviewBlockCustomizeSelectionProvider, resolveSiteStyleAccess, resolvePreviewDashboardSetupHandoff, buildPreviewDashboardSetupUrl, resolvePreviewSetupBannerModel, usePreviewBlockCustomizeSelectionOptional, useBlockCustomizeControls, MAX_CUSTOMIZE_POPOVER_ROWS, MAX_QUICK_MANIFEST_FIELDS, OfferingsPreviewWidgetProvider, previewWidgetOverrides, sanitizeDashboardPath } from './chunk-G35HOQEN.mjs';
4
+ import { resolvePreviewChromeSurface, getPreviewSidebarTab, onPreviewSidebarOpenRequest, getPreviewChromeSurfaceDataProps, PREVIEW_CHROME_THEME_CLASS_NAME, setPreviewSidebarTab, PreviewPageDesignEditorStateProvider, usePreviewPageDesignEditorState } from './chunk-HKB6XVIP.mjs';
5
+ import { clientComponentRegistry, deriveLaunchReadiness, DEFAULT_LAUNCH_READINESS_INPUT, useEditorUiStore, PreviewThemeOverlayProvider, PreviewDesignCoordinatorProvider, SiteChromeCustomizeProvider, ResizableSplitPane, BlockApiProvider, EditorProvider, PreviewDesignHistoryOrderProvider, MediaEditorProvider, useEditorUiStoreInstance, useEditor, createRoutingHelpers, createSnapshotFromPageRecord, EntryControllerProvider, useEntryEditorController, surfaceResolutionContextFromTheme, unsafeAsEditorBlockId, EditableBlockProvider, asDesignBlockId, PageRenderer, usePreviewThemeOverlay, planSiteDocument, ThemeScope, FixedBottomSurface, Button, unsafeAsLinkedContentEntryId, sectionTransitionVariantForBoundaryOptionId, sectionTransitionFamilyForBoundaryOptionId, sectionTransitionFamilies, X, defaultSectionTransitionVariantForFamily, RotateCcw, parseBackgroundOverrideFromContent, rankBackgroundImagePoolItems, imagePoolForOverride, resolveBackgroundCapability, enabledBackgroundModes, canCycleBackgroundOverrideValue, FormRenderer, stableSerialize, prefetchBlockData, isSupportedLoaderEndpoint, PreviewRichTextEditor, RichText, PreviewTextEditor, Text, buildThemeRuntime, renderBlock, siteHeaderManifest, siteFooterManifest, SiteDocumentLayout, SITE_CHROME_CLASS_NAMES, Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter, buildEditorModelRuntimeFieldsByBlockId, applyCompiledRuntimeFieldsToContent, assertNever2, getBlockDefinition, systemCustomizeFacetDefinitionsForBlock, systemCustomizeFacetAppliesToLayoutVariant, systemCustomizeFacetCurrentValue, systemCustomizeFacetLabelForValue, backgroundColorTokens, ChevronLeft, ChevronRight, createMicrobatcher, unwrapResponse, normalizePublicApiLoaderParams, visibleHeaderClearancePx, LINKED_CONTENT_ENTRY_META_KEY, useMediaEditorOptional, Image, defaultBackgroundOverrideForMode, decodePublicProductCategorySelectorQuery, EDITABLE_SURFACE_FORWARDING_PROP, useSiteChromeCustomizeOptional, assertNever, SITE_CHROME_VISIBLE_HEADER_SELECTOR, getLinkedContentEntryMeta, GRADIENT_PRESETS, resolveImageUrlWithContext, gradientToCss, Upload, MediaEditor, SECTION_BACKGROUND_MIN_SOURCE_WIDTH, SECTION_BACKGROUND_MIN_SOURCE_HEIGHT, parseMediaAssetId, formatSiteChromeBackgroundTokenLabel, planBackgroundOverride, planBackgroundTransition, systemCustomizeFacetNextValue } from './chunk-XQR6THQJ.mjs';
6
+ import { API_ENDPOINTS, createBearerAPIClient, isPreviewRuntimeSessionEditable, DEFAULT_SURFACE_ID, initPreviewAuth, usePreviewAuth, usePreviewAuthFetch, markPreviewAuthExpired, usePreviewToken } from './chunk-FIREV57T.mjs';
7
+ import React10, { createContext, useMemo, useState, useEffect, useRef, useCallback, useId, useReducer, Children, isValidElement, Fragment as Fragment$1, cloneElement, useContext } from 'react';
8
8
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
9
+ import { createPortal } from 'react-dom';
9
10
 
10
11
  // ../preview-next/src/client/utils/path.ts
11
12
  var PATH_SEPARATOR_REGEX = /\./g;
@@ -252,12 +253,117 @@ function blockHasPreviewContentFieldProjection(blockId, projections) {
252
253
  );
253
254
  }
254
255
 
256
+ // ../preview-next/src/client/blocks/linkedEntryRenderOverlay.ts
257
+ function applyLinkedEntryRenderOverlay(value, overlays) {
258
+ if (overlays.size === 0) return value;
259
+ return overlayValue(value, overlays);
260
+ }
261
+ function applyLinkedEntryRenderOverlayToDataContext(dataContext, overlays) {
262
+ if (!dataContext?.resolvedData || overlays.size === 0) {
263
+ return dataContext;
264
+ }
265
+ const resolvedData = applyLinkedEntryRenderOverlay(
266
+ dataContext.resolvedData,
267
+ overlays
268
+ );
269
+ if (resolvedData === dataContext.resolvedData) {
270
+ return dataContext;
271
+ }
272
+ return {
273
+ ...dataContext,
274
+ resolvedData
275
+ };
276
+ }
277
+ function overlayValue(value, overlays) {
278
+ if (Array.isArray(value)) {
279
+ let changed2 = false;
280
+ const next2 = value.map((item) => {
281
+ const overlaid = overlayValue(item, overlays);
282
+ if (overlaid !== item) changed2 = true;
283
+ return overlaid;
284
+ });
285
+ return changed2 ? next2 : value;
286
+ }
287
+ if (!isRecord3(value)) return value;
288
+ const meta = parseLinkedEntryMeta(value[LINKED_CONTENT_ENTRY_META_KEY]);
289
+ if (meta) {
290
+ const overlay = overlays.get(unsafeAsLinkedContentEntryId(meta.entryId));
291
+ if (overlay) {
292
+ const displayProjections = resolveOverlayDisplayProjections(overlay.content, meta);
293
+ const titleProjection = resolveOverlayTitleProjection({
294
+ currentValue: value,
295
+ content: overlay.content,
296
+ meta,
297
+ displayProjections
298
+ });
299
+ return {
300
+ ...value,
301
+ ...displayProjections,
302
+ ...titleProjection ? { title: titleProjection } : {},
303
+ content: overlay.content,
304
+ optimisticHash: overlay.optimisticHash,
305
+ [LINKED_CONTENT_ENTRY_META_KEY]: {
306
+ ...meta,
307
+ ...titleProjection ? { title: titleProjection } : {},
308
+ optimisticHash: overlay.optimisticHash
309
+ }
310
+ };
311
+ }
312
+ }
313
+ let changed = false;
314
+ const next = {};
315
+ for (const [key, child] of Object.entries(value)) {
316
+ const overlaid = overlayValue(child, overlays);
317
+ if (overlaid !== child) changed = true;
318
+ next[key] = overlaid;
319
+ }
320
+ return changed ? next : value;
321
+ }
322
+ function resolveOverlayDisplayProjections(content, meta) {
323
+ const projections = {};
324
+ for (const source of meta.fieldSources) {
325
+ if (source.kind !== "content-field") continue;
326
+ if (source.displayPath.startsWith("content.")) continue;
327
+ if (source.displayPath.includes(".")) continue;
328
+ if (!(source.fieldPath in content)) continue;
329
+ projections[source.displayPath] = content[source.fieldPath];
330
+ }
331
+ return projections;
332
+ }
333
+ function resolveOverlayTitleProjection(input) {
334
+ const projectedTitle = input.displayProjections.title;
335
+ if (typeof projectedTitle === "string") return projectedTitle;
336
+ const titleSource = input.meta.fieldSources.find((source) => source.displayPath === "title");
337
+ if (titleSource?.kind === "read-only") {
338
+ const currentTitle = input.currentValue.title;
339
+ return typeof currentTitle === "string" ? currentTitle : input.meta.title;
340
+ }
341
+ return resolveOverlayTitle(input.content, input.meta);
342
+ }
343
+ function resolveOverlayTitle(content, meta) {
344
+ const titleField = meta.contentType.titleField;
345
+ if (titleField) {
346
+ const value = content[titleField];
347
+ if (typeof value === "string" && value.trim().length > 0) {
348
+ return value;
349
+ }
350
+ }
351
+ return meta.title;
352
+ }
353
+ function parseLinkedEntryMeta(value) {
354
+ return getLinkedContentEntryMeta({ [LINKED_CONTENT_ENTRY_META_KEY]: value });
355
+ }
356
+ function isRecord3(value) {
357
+ return typeof value === "object" && value !== null && !Array.isArray(value);
358
+ }
359
+
255
360
  // ../preview-next/src/client/blocks/composer/mergeDrafts.ts
361
+ var EMPTY_LINKED_ENTRY_OVERLAY = /* @__PURE__ */ new Map();
256
362
  function getDraftSnapshots(uiStore) {
257
363
  const snapshots = uiStore.getState().drafts.inspect();
258
364
  return new Map(snapshots.map((snap) => [snap.id, snap]));
259
365
  }
260
- function mergeBlockWithDraft(block, draftMap, index, projections = []) {
366
+ function mergeBlockWithDraft(block, draftMap, index, projections = [], linkedEntryOverlays = EMPTY_LINKED_ENTRY_OVERLAY) {
261
367
  const id = block.id ?? null;
262
368
  const editorBlockId = id ? unsafeAsEditorBlockId(id) : null;
263
369
  const snap = editorBlockId ? draftMap.get(editorBlockId) ?? null : null;
@@ -269,20 +375,22 @@ function mergeBlockWithDraft(block, draftMap, index, projections = []) {
269
375
  kind: block.kind,
270
376
  purpose: "content",
271
377
  orderIndex: block.orderIndex ?? index,
272
- content: renderContent(block, baseline, projections),
273
- draftContent: renderContent(block, draftContent, projections),
378
+ content: renderContent(block, baseline, projections, linkedEntryOverlays),
379
+ draftContent: renderContent(block, draftContent, projections, linkedEntryOverlays),
274
380
  publishedContent: renderContent(
275
381
  block,
276
382
  block.publishedContent ?? null,
277
- projections
383
+ projections,
384
+ EMPTY_LINKED_ENTRY_OVERLAY
278
385
  ),
279
386
  bindings: block.bindings ?? null
280
387
  };
281
388
  }
282
- function renderContent(block, content, projections) {
389
+ function renderContent(block, content, projections, linkedEntryOverlays) {
390
+ const overlaidContent = applyLinkedEntryRenderOverlay(content, linkedEntryOverlays);
283
391
  return applyPreviewRuntimeContentProjections(
284
392
  block,
285
- content,
393
+ overlaidContent,
286
394
  projections
287
395
  );
288
396
  }
@@ -333,18 +441,20 @@ function composePageFromBlocks(args, cacheRef) {
333
441
  const aiProjections = previewProjectionsFromAiOverlays(
334
442
  uiStore.getState().aiOverlays
335
443
  );
444
+ const linkedEntryOverlays = getLinkedEntryRenderOverlays(uiStore);
336
445
  return composePreviewRenderPage(
337
446
  {
338
447
  page,
339
448
  blockItems,
340
449
  draftSnapshots: Array.from(draftMap.values()),
341
- projections: [...aiProjections, ...projections]
450
+ projections: [...aiProjections, ...projections],
451
+ linkedEntryOverlays
342
452
  },
343
453
  cacheRef
344
454
  );
345
455
  }
346
456
  function composePreviewRenderPage(args, cacheRef) {
347
- const { page, blockItems, draftSnapshots, projections } = args;
457
+ const { page, blockItems, draftSnapshots, projections, linkedEntryOverlays } = args;
348
458
  if (!page) return page;
349
459
  if (!blockItems.length) return page;
350
460
  const draftMap = draftSnapshotMap(draftSnapshots);
@@ -353,7 +463,7 @@ function composePreviewRenderPage(args, cacheRef) {
353
463
  projections
354
464
  );
355
465
  const enrichedBlocks = projectedBlockItems.map(
356
- (block, index) => mergeBlockWithDraft(block, draftMap, index, projections)
466
+ (block, index) => mergeBlockWithDraft(block, draftMap, index, projections, linkedEntryOverlays)
357
467
  );
358
468
  const sortedBlocks = [...enrichedBlocks].sort(
359
469
  (a, b) => (a.orderIndex ?? 0) - (b.orderIndex ?? 0)
@@ -361,9 +471,47 @@ function composePreviewRenderPage(args, cacheRef) {
361
471
  const renderedBlocks = applyCacheOptimization(sortedBlocks, cacheRef);
362
472
  return { ...page, blocks: renderedBlocks };
363
473
  }
474
+ function getLinkedEntryRenderOverlays(uiStore) {
475
+ const linkedEntries = uiStore.getState().linkedEntries.inspect();
476
+ const overlays = /* @__PURE__ */ new Map();
477
+ for (const linkedEntry of linkedEntries) {
478
+ const content = linkedEntry.current ?? linkedEntry.baseline;
479
+ if (!content) continue;
480
+ overlays.set(linkedEntry.meta.entryId, {
481
+ content,
482
+ optimisticHash: linkedEntry.meta.optimisticHash
483
+ });
484
+ }
485
+ return overlays;
486
+ }
364
487
  function draftSnapshotMap(snapshots) {
365
488
  return new Map(snapshots.map((snap) => [snap.id, snap]));
366
489
  }
490
+
491
+ // ../preview-next/src/client/preview/linkedEntryEditEvents.ts
492
+ var LINKED_ENTRY_EDIT_EVENT = "riverbank:preview:linked-entry-edit";
493
+ var LINKED_ENTRY_FIELD_FOCUS_EVENT = "riverbank:preview:linked-entry-field-focus";
494
+ function dispatchLinkedEntryEditEvent(target) {
495
+ window.dispatchEvent(new CustomEvent(LINKED_ENTRY_EDIT_EVENT, {
496
+ detail: target
497
+ }));
498
+ }
499
+ function dispatchLinkedEntryFieldFocusEvent(binding) {
500
+ window.dispatchEvent(new CustomEvent(LINKED_ENTRY_FIELD_FOCUS_EVENT, {
501
+ detail: binding
502
+ }));
503
+ }
504
+ function isLinkedEntryEditEvent(event) {
505
+ if (!(event instanceof CustomEvent)) return false;
506
+ const detail = event.detail;
507
+ return Boolean(detail) && typeof detail === "object" && detail.kind === "linked-content-entry";
508
+ }
509
+ function isLinkedEntryFieldFocusEvent(event) {
510
+ if (!(event instanceof CustomEvent)) return false;
511
+ const detail = event.detail;
512
+ const write = detail?.write;
513
+ return Boolean(detail) && typeof detail === "object" && detail.kind === "linked-entry-field" && Boolean(detail.target) && Boolean(write) && typeof write === "object" && typeof write.fieldPath === "string";
514
+ }
367
515
  function requireClientRegistryComponent(key) {
368
516
  const component = clientComponentRegistry[key];
369
517
  if (!component) {
@@ -372,22 +520,71 @@ function requireClientRegistryComponent(key) {
372
520
  return component;
373
521
  }
374
522
  var ButtonComponent = requireClientRegistryComponent("button");
375
- var TextWithEditor = ({ value, children, path, ...rest }) => {
523
+ var TextWithEditor = ({ value, children, path, linkedEntryField, ...rest }) => {
376
524
  const raw = value ?? children;
377
525
  const content = typeof raw === "string" || typeof raw === "number" ? raw : "";
378
526
  const { isEditingMode } = useEditor();
379
527
  if (isEditingMode) {
380
- return path ? /* @__PURE__ */ jsx(PreviewTextEditor, { ...rest, path, children: content }) : /* @__PURE__ */ jsx(Text, { ...rest, children: content });
528
+ return path || linkedEntryField ? /* @__PURE__ */ jsx(
529
+ PreviewTextEditor,
530
+ {
531
+ ...rest,
532
+ path,
533
+ linkedEntryField,
534
+ onLinkedEntryFieldFocus: dispatchLinkedEntryFieldFocusEvent,
535
+ children: content
536
+ }
537
+ ) : /* @__PURE__ */ jsx(Text, { ...rest, children: content });
381
538
  }
382
539
  return /* @__PURE__ */ jsx(Text, { ...rest, path, children: content });
383
540
  };
384
- var RichTextWithEditor = ({ value, path, ...rest }) => {
541
+ var RichTextWithEditor = ({ value, path, linkedEntryField, ...rest }) => {
385
542
  const { isEditingMode } = useEditor();
386
- if (isEditingMode && path) {
387
- return /* @__PURE__ */ jsx(PreviewRichTextEditor, { ...rest, path, doc: value });
543
+ if (isEditingMode && (path || linkedEntryField)) {
544
+ return /* @__PURE__ */ jsx(
545
+ PreviewRichTextEditor,
546
+ {
547
+ ...rest,
548
+ path,
549
+ linkedEntryField,
550
+ onLinkedEntryFieldFocus: dispatchLinkedEntryFieldFocusEvent,
551
+ doc: value
552
+ }
553
+ );
388
554
  }
389
555
  return /* @__PURE__ */ jsx(RichText, { ...rest, path, doc: value });
390
556
  };
557
+ var LinkedEntryEditFrame = ({ target, children }) => {
558
+ const { isEditingMode } = useEditor();
559
+ if (!isEditingMode) {
560
+ return /* @__PURE__ */ jsx(Fragment, { children });
561
+ }
562
+ return /* @__PURE__ */ jsxs(
563
+ "div",
564
+ {
565
+ className: "group/linked-entry-edit relative",
566
+ "data-linked-entry-id": target.entryId,
567
+ "data-linked-entry-type": target.contentTypeKey,
568
+ children: [
569
+ children,
570
+ /* @__PURE__ */ jsx(
571
+ "button",
572
+ {
573
+ type: "button",
574
+ "aria-label": `Edit ${target.contentTypeLabel}: ${target.title}`,
575
+ className: "absolute right-2 top-2 z-20 rounded-full border border-white/80 bg-neutral-950/85 px-3 py-1 text-xs font-medium text-white opacity-0 shadow-sm transition focus:opacity-100 group-hover/linked-entry-edit:opacity-100",
576
+ onClick: (event) => {
577
+ event.preventDefault();
578
+ event.stopPropagation();
579
+ dispatchLinkedEntryEditEvent(target);
580
+ },
581
+ children: "Edit"
582
+ }
583
+ )
584
+ ]
585
+ }
586
+ );
587
+ };
391
588
  var ButtonWithEditorInterception = (props) => {
392
589
  const { isEditingMode } = useEditor();
393
590
  if (!isEditingMode) {
@@ -411,14 +608,604 @@ var editorRegistry = {
411
608
  text: TextWithEditor,
412
609
  richText: RichTextWithEditor,
413
610
  button: ButtonWithEditorInterception,
414
- media: requireClientRegistryComponent("media")
611
+ media: requireClientRegistryComponent("media"),
612
+ linkedEntryEditFrame: LinkedEntryEditFrame
415
613
  };
416
614
 
615
+ // ../preview-next/src/client/preview/previewChromePlacement.ts
616
+ var PREVIEW_CHROME_EDGE_OFFSET_PX = 8;
617
+ var DEFAULT_PREVIEW_CHROME_FLOATING_PLACEMENT = Object.freeze({
618
+ kind: "anchor-top-right",
619
+ topPx: PREVIEW_CHROME_EDGE_OFFSET_PX,
620
+ rightPx: PREVIEW_CHROME_EDGE_OFFSET_PX
621
+ });
622
+ function headerClearanceFromPx(px) {
623
+ return Number.isFinite(px) && px > 0 ? { kind: "overlay", px: Math.ceil(px) } : { kind: "none" };
624
+ }
625
+ function findFirstEditableContentBlockIndex(blocks) {
626
+ const index = blocks.findIndex((block) => block.kind !== "block.site-header");
627
+ return index >= 0 ? index : null;
628
+ }
629
+ function blockReceivesHeaderClearance(blocks, blockIndex) {
630
+ return findFirstEditableContentBlockIndex(blocks) === blockIndex;
631
+ }
632
+ function planBlockToolbarPlacement(input) {
633
+ if (input.headerClearance.kind === "overlay" && blockReceivesHeaderClearance(input.blocks, input.blockIndex)) {
634
+ return {
635
+ kind: "anchor-top-right-clamped",
636
+ topPx: PREVIEW_CHROME_EDGE_OFFSET_PX,
637
+ rightPx: PREVIEW_CHROME_EDGE_OFFSET_PX,
638
+ minTopPx: input.headerClearance.px + PREVIEW_CHROME_EDGE_OFFSET_PX
639
+ };
640
+ }
641
+ return {
642
+ kind: "anchor-top-right",
643
+ topPx: PREVIEW_CHROME_EDGE_OFFSET_PX,
644
+ rightPx: PREVIEW_CHROME_EDGE_OFFSET_PX
645
+ };
646
+ }
647
+ function planSiteChromeCustomizePlacement(input) {
648
+ if (input.surface === "header" && !isUsableAnchorBox(input.anchorBox)) {
649
+ return {
650
+ kind: "viewport-top-right",
651
+ topPx: PREVIEW_CHROME_EDGE_OFFSET_PX * 2,
652
+ rightPx: PREVIEW_CHROME_EDGE_OFFSET_PX * 2
653
+ };
654
+ }
655
+ return {
656
+ kind: "anchor-top-right",
657
+ topPx: PREVIEW_CHROME_EDGE_OFFSET_PX,
658
+ rightPx: PREVIEW_CHROME_EDGE_OFFSET_PX
659
+ };
660
+ }
661
+ function resolvePreviewChromeFloatingPosition(input) {
662
+ if (input.placement.kind === "viewport-top-right") {
663
+ return {
664
+ topPx: input.placement.topPx,
665
+ rightPx: input.placement.rightPx
666
+ };
667
+ }
668
+ const anchorBox = input.anchorBox;
669
+ if (!isUsableAnchorBox(anchorBox)) {
670
+ return {
671
+ topPx: resolvePreviewChromeMinimumTopPx(input.placement),
672
+ rightPx: input.placement.rightPx
673
+ };
674
+ }
675
+ return {
676
+ topPx: Math.max(
677
+ PREVIEW_CHROME_EDGE_OFFSET_PX,
678
+ resolvePreviewChromeMinimumTopPx(input.placement),
679
+ anchorBox.top - (input.containerTopEdgePx ?? 0) + input.placement.topPx
680
+ ),
681
+ rightPx: Math.max(
682
+ PREVIEW_CHROME_EDGE_OFFSET_PX,
683
+ input.containerRightEdgePx - anchorBox.right + input.placement.rightPx
684
+ )
685
+ };
686
+ }
687
+ function resolvePreviewChromeMinimumTopPx(placement) {
688
+ return placement.kind === "anchor-top-right-clamped" ? placement.minTopPx : placement.topPx;
689
+ }
690
+ function isUsableAnchorBox(box) {
691
+ return Boolean(
692
+ box && Number.isFinite(box.top) && Number.isFinite(box.right) && Number.isFinite(box.bottom) && Number.isFinite(box.height) && box.height > 0
693
+ );
694
+ }
695
+ var PreviewChromeLayerContext = createContext(null);
696
+ function PreviewChromeLayerProvider({
697
+ children
698
+ }) {
699
+ const [portalTarget, setPortalTarget] = useState(null);
700
+ const listenersRef = useRef(/* @__PURE__ */ new Set());
701
+ const notifyLayout = useCallback(() => {
702
+ listenersRef.current.forEach((listener) => listener());
703
+ }, []);
704
+ const subscribeLayout = useCallback((listener) => {
705
+ listenersRef.current.add(listener);
706
+ return () => {
707
+ listenersRef.current.delete(listener);
708
+ };
709
+ }, []);
710
+ useEffect(() => {
711
+ let frame = null;
712
+ const scheduleNotify = () => {
713
+ if (frame !== null) return;
714
+ frame = window.requestAnimationFrame(() => {
715
+ frame = null;
716
+ notifyLayout();
717
+ });
718
+ };
719
+ const mutationObserver = typeof MutationObserver !== "undefined" ? new MutationObserver(scheduleNotify) : null;
720
+ mutationObserver?.observe(document.body, {
721
+ attributes: true,
722
+ childList: true,
723
+ subtree: true
724
+ });
725
+ window.addEventListener("resize", scheduleNotify);
726
+ window.addEventListener("scroll", scheduleNotify, true);
727
+ return () => {
728
+ if (frame !== null) {
729
+ window.cancelAnimationFrame(frame);
730
+ }
731
+ mutationObserver?.disconnect();
732
+ window.removeEventListener("resize", scheduleNotify);
733
+ window.removeEventListener("scroll", scheduleNotify, true);
734
+ };
735
+ }, [notifyLayout]);
736
+ const value = useMemo(
737
+ () => ({ portalTarget, subscribeLayout }),
738
+ [portalTarget, subscribeLayout]
739
+ );
740
+ return /* @__PURE__ */ jsxs(PreviewChromeLayerContext.Provider, { value, children: [
741
+ children,
742
+ /* @__PURE__ */ jsx(
743
+ "div",
744
+ {
745
+ ref: setPortalTarget,
746
+ className: "pointer-events-none fixed inset-0 z-[70]",
747
+ "data-preview-chrome-layer": ""
748
+ }
749
+ )
750
+ ] });
751
+ }
752
+ function usePreviewChromeLayerOptional() {
753
+ return useContext(PreviewChromeLayerContext);
754
+ }
755
+ function PreviewChromeFloatingControl({
756
+ anchorSelector,
757
+ placement,
758
+ fallbackClassName,
759
+ fallbackStyle,
760
+ portalClassName = "absolute z-[70] flex gap-1 transition",
761
+ forceVisible = false,
762
+ children
763
+ }) {
764
+ const layer = usePreviewChromeLayerOptional();
765
+ const probeRef = useRef(null);
766
+ const anchorElementRef = useRef(null);
767
+ const [controlElement, setControlElement] = useState(
768
+ null
769
+ );
770
+ const [anchorElement, setAnchorElement] = useState(null);
771
+ const [anchorBox, setAnchorBox] = useState(
772
+ null
773
+ );
774
+ const [themeCustomProperties, setThemeCustomProperties] = useState({});
775
+ const [isActive, setIsActive] = useState(false);
776
+ const hoverStateRef = useRef({ anchor: false, control: false });
777
+ useEffect(() => {
778
+ if (!layer?.portalTarget) return;
779
+ let resizeObserver = null;
780
+ const readAnchor = () => probeRef.current?.closest(anchorSelector);
781
+ const update = () => {
782
+ const anchor = readAnchor();
783
+ if (anchor !== anchorElementRef.current) {
784
+ resizeObserver?.disconnect();
785
+ resizeObserver = null;
786
+ anchorElementRef.current = anchor;
787
+ setAnchorElement(anchor);
788
+ if (anchor && typeof ResizeObserver !== "undefined") {
789
+ resizeObserver = new ResizeObserver(update);
790
+ resizeObserver.observe(anchor);
791
+ }
792
+ }
793
+ if (!anchor) {
794
+ setAnchorBox(null);
795
+ setThemeCustomProperties({});
796
+ return;
797
+ }
798
+ const rect = anchor.getBoundingClientRect();
799
+ setThemeCustomProperties(readThemeCustomProperties(anchor));
800
+ setAnchorBox({
801
+ top: rect.top,
802
+ right: rect.right,
803
+ bottom: rect.bottom,
804
+ height: rect.height
805
+ });
806
+ };
807
+ update();
808
+ const unsubscribe = layer.subscribeLayout(update);
809
+ return () => {
810
+ resizeObserver?.disconnect();
811
+ anchorElementRef.current = null;
812
+ unsubscribe();
813
+ };
814
+ }, [anchorSelector, layer]);
815
+ useEffect(() => {
816
+ if (!anchorElement || !controlElement) return;
817
+ hoverStateRef.current = { anchor: false, control: false };
818
+ const show = (event) => {
819
+ updatePreviewChromeHoverState(
820
+ hoverStateRef.current,
821
+ event.currentTarget,
822
+ anchorElement,
823
+ controlElement,
824
+ true
825
+ );
826
+ setIsActive(true);
827
+ };
828
+ const hideIfFocusLeft = (event) => {
829
+ updatePreviewChromeHoverState(
830
+ hoverStateRef.current,
831
+ event.currentTarget,
832
+ anchorElement,
833
+ controlElement,
834
+ false
835
+ );
836
+ window.setTimeout(() => {
837
+ const active = document.activeElement;
838
+ const hoverState = hoverStateRef.current;
839
+ const nextIsActive = Boolean(
840
+ hoverState.anchor || hoverState.control || active && (anchorElement.contains(active) || controlElement.contains(active))
841
+ );
842
+ setIsActive(nextIsActive);
843
+ }, 0);
844
+ };
845
+ anchorElement.addEventListener("mouseenter", show);
846
+ anchorElement.addEventListener("mouseleave", hideIfFocusLeft);
847
+ anchorElement.addEventListener("focusin", show);
848
+ anchorElement.addEventListener("focusout", hideIfFocusLeft);
849
+ controlElement.addEventListener("mouseenter", show);
850
+ controlElement.addEventListener("mouseleave", hideIfFocusLeft);
851
+ controlElement.addEventListener("focusin", show);
852
+ controlElement.addEventListener("focusout", hideIfFocusLeft);
853
+ return () => {
854
+ anchorElement.removeEventListener("mouseenter", show);
855
+ anchorElement.removeEventListener("mouseleave", hideIfFocusLeft);
856
+ anchorElement.removeEventListener("focusin", show);
857
+ anchorElement.removeEventListener("focusout", hideIfFocusLeft);
858
+ controlElement.removeEventListener("mouseenter", show);
859
+ controlElement.removeEventListener("mouseleave", hideIfFocusLeft);
860
+ controlElement.removeEventListener("focusin", show);
861
+ controlElement.removeEventListener("focusout", hideIfFocusLeft);
862
+ };
863
+ }, [anchorElement, controlElement]);
864
+ if (!layer?.portalTarget) {
865
+ return /* @__PURE__ */ jsx("div", { className: fallbackClassName, style: fallbackStyle, children });
866
+ }
867
+ const resolvedPlacement = typeof placement === "function" ? placement(anchorBox) : placement;
868
+ const position = resolvePreviewChromeFloatingPosition({
869
+ anchorBox,
870
+ containerTopEdgePx: resolvePortalTopEdgePx(layer.portalTarget),
871
+ containerRightEdgePx: resolvePortalRightEdgePx(layer.portalTarget),
872
+ placement: resolvedPlacement
873
+ });
874
+ const isVisible = forceVisible || isActive;
875
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
876
+ /* @__PURE__ */ jsx("span", { ref: probeRef, "aria-hidden": "true", style: { display: "contents" } }),
877
+ createPortal(
878
+ /* @__PURE__ */ jsx(
879
+ "div",
880
+ {
881
+ ref: setControlElement,
882
+ className: joinClassNames(
883
+ portalClassName,
884
+ isVisible ? "pointer-events-auto opacity-100" : "pointer-events-none opacity-0"
885
+ ),
886
+ style: {
887
+ ...themeCustomProperties,
888
+ top: position.topPx,
889
+ right: position.rightPx
890
+ },
891
+ children
892
+ }
893
+ ),
894
+ layer.portalTarget
895
+ )
896
+ ] });
897
+ }
898
+ function readThemeCustomProperties(element) {
899
+ if (typeof window === "undefined") return {};
900
+ const computedStyle = window.getComputedStyle(element);
901
+ const properties = {};
902
+ copyThemeCustomProperties(computedStyle, properties);
903
+ for (let current = element; current; current = current.parentElement) {
904
+ copyThemeCustomProperties(current.style, properties);
905
+ }
906
+ return properties;
907
+ }
908
+ function copyThemeCustomProperties(style, target) {
909
+ for (let index = 0; index < style.length; index += 1) {
910
+ const propertyName = style.item(index);
911
+ if (!propertyName.startsWith("--tb-")) continue;
912
+ const propertyValue = style.getPropertyValue(propertyName).trim();
913
+ if (propertyValue.length > 0 && target[propertyName] === void 0) {
914
+ target[propertyName] = propertyValue;
915
+ }
916
+ }
917
+ }
918
+ function resolvePortalRightEdgePx(portalTarget) {
919
+ const rect = portalTarget.getBoundingClientRect();
920
+ if (Number.isFinite(rect.right) && rect.right > 0) {
921
+ return rect.right;
922
+ }
923
+ if (typeof window === "undefined") {
924
+ return 0;
925
+ }
926
+ return window.innerWidth;
927
+ }
928
+ function resolvePortalTopEdgePx(portalTarget) {
929
+ const rect = portalTarget.getBoundingClientRect();
930
+ return Number.isFinite(rect.top) ? rect.top : 0;
931
+ }
932
+ function joinClassNames(...values) {
933
+ const className = values.filter(Boolean).join(" ");
934
+ return className.length > 0 ? className : void 0;
935
+ }
936
+ function updatePreviewChromeHoverState(hoverState, currentTarget, anchorElement, controlElement, value) {
937
+ if (currentTarget === anchorElement) {
938
+ hoverState.anchor = value;
939
+ } else if (currentTarget === controlElement) {
940
+ hoverState.control = value;
941
+ }
942
+ }
943
+ function useDialogFocusTrap(input) {
944
+ const { open, onClose } = input;
945
+ const dialogRef = useRef(null);
946
+ const initialFocusRef = useRef(null);
947
+ const returnFocusRef = useRef(null);
948
+ useEffect(() => {
949
+ if (open) {
950
+ initialFocusRef.current?.focus();
951
+ return;
952
+ }
953
+ const returnFocusTarget = returnFocusRef.current;
954
+ returnFocusRef.current = null;
955
+ returnFocusTarget?.focus();
956
+ }, [open]);
957
+ const registerInitialFocus = useCallback((node) => {
958
+ initialFocusRef.current = node;
959
+ }, []);
960
+ const setReturnFocusTarget = useCallback((node) => {
961
+ returnFocusRef.current = node;
962
+ }, []);
963
+ const handleDialogKeyDown = useCallback(
964
+ (event) => {
965
+ if (event.key === "Escape") {
966
+ event.preventDefault();
967
+ onClose();
968
+ return;
969
+ }
970
+ if (event.key !== "Tab") return;
971
+ const focusableElements = focusableElementsIn(dialogRef.current);
972
+ if (focusableElements.length === 0) {
973
+ event.preventDefault();
974
+ return;
975
+ }
976
+ const firstElement = focusableElements[0];
977
+ const lastElement = focusableElements[focusableElements.length - 1];
978
+ if (!firstElement || !lastElement) return;
979
+ if (event.shiftKey && document.activeElement === firstElement) {
980
+ event.preventDefault();
981
+ lastElement.focus();
982
+ return;
983
+ }
984
+ if (!event.shiftKey && document.activeElement === lastElement) {
985
+ event.preventDefault();
986
+ firstElement.focus();
987
+ }
988
+ },
989
+ [onClose]
990
+ );
991
+ return {
992
+ dialogRef,
993
+ registerInitialFocus,
994
+ setReturnFocusTarget,
995
+ handleDialogKeyDown
996
+ };
997
+ }
998
+ function focusableElementsIn(root) {
999
+ if (!root) return [];
1000
+ return Array.from(
1001
+ root.querySelectorAll(
1002
+ 'a[href], button:not([disabled]), textarea:not([disabled]), input:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex="-1"])'
1003
+ )
1004
+ ).filter((element) => !element.hasAttribute("disabled") && element.getAttribute("aria-hidden") !== "true");
1005
+ }
1006
+
417
1007
  // ../preview-next/src/client/preview/previewCustomizeControlStyles.ts
418
1008
  var previewCustomizePillButtonClassName = "rounded-full bg-black/80 px-2.5 py-1 text-xs text-white shadow hover:bg-black";
1009
+ function useCustomizePopoverController() {
1010
+ const panelId = useId();
1011
+ const descriptionId = `${panelId}-description`;
1012
+ const [open, setOpen] = useState(false);
1013
+ const buttonRef = useRef(null);
1014
+ const close = useCallback(() => {
1015
+ setOpen(false);
1016
+ }, []);
1017
+ const {
1018
+ dialogRef,
1019
+ registerInitialFocus,
1020
+ setReturnFocusTarget,
1021
+ handleDialogKeyDown
1022
+ } = useDialogFocusTrap({
1023
+ open,
1024
+ onClose: close
1025
+ });
1026
+ const toggle = useCallback(
1027
+ (event) => {
1028
+ event.preventDefault();
1029
+ event.stopPropagation();
1030
+ if (!open) {
1031
+ setReturnFocusTarget(
1032
+ event.currentTarget instanceof HTMLElement ? event.currentTarget : buttonRef.current
1033
+ );
1034
+ }
1035
+ setOpen((current) => !current);
1036
+ },
1037
+ [open, setReturnFocusTarget]
1038
+ );
1039
+ return {
1040
+ open,
1041
+ close,
1042
+ toggle,
1043
+ buttonRef,
1044
+ panelId,
1045
+ descriptionId,
1046
+ dialogRef,
1047
+ registerInitialFocus,
1048
+ handleDialogKeyDown
1049
+ };
1050
+ }
1051
+ function CustomizePillButton({
1052
+ buttonRef,
1053
+ ariaLabel,
1054
+ open,
1055
+ controlsId,
1056
+ onClick,
1057
+ disabled = false
1058
+ }) {
1059
+ return /* @__PURE__ */ jsx(
1060
+ "button",
1061
+ {
1062
+ ref: buttonRef,
1063
+ type: "button",
1064
+ onClick,
1065
+ className: previewCustomizePillButtonClassName,
1066
+ "aria-label": ariaLabel,
1067
+ "aria-expanded": open,
1068
+ "aria-haspopup": "dialog",
1069
+ "aria-controls": open ? controlsId : void 0,
1070
+ disabled,
1071
+ children: "Customize"
1072
+ }
1073
+ );
1074
+ }
1075
+ function CustomizePopoverShell({
1076
+ panelId,
1077
+ descriptionId,
1078
+ dialogLabel,
1079
+ eyebrow,
1080
+ title,
1081
+ dialogRef,
1082
+ closeButtonRef,
1083
+ onClose,
1084
+ onKeyDown,
1085
+ spacing = "normal",
1086
+ children
1087
+ }) {
1088
+ return /* @__PURE__ */ jsxs(
1089
+ "div",
1090
+ {
1091
+ id: panelId,
1092
+ className: "builder-dashboard-chrome-theme fixed inset-x-3 bottom-[calc(var(--builder-editor-chrome-offset,0px)+1rem)] z-[70] rounded-lg border bg-background p-3 text-foreground shadow-xl sm:absolute sm:inset-x-auto sm:bottom-auto sm:right-0 sm:top-9 sm:w-72",
1093
+ role: "dialog",
1094
+ "aria-modal": "true",
1095
+ "aria-label": dialogLabel,
1096
+ "aria-describedby": descriptionId,
1097
+ ref: dialogRef,
1098
+ onKeyDown,
1099
+ onClick: (event) => event.stopPropagation(),
1100
+ children: [
1101
+ /* @__PURE__ */ jsxs("div", { className: "mb-3 flex items-start justify-between gap-3", children: [
1102
+ /* @__PURE__ */ jsxs("div", { children: [
1103
+ /* @__PURE__ */ jsx("div", { className: "text-xs font-medium uppercase text-muted-foreground", children: eyebrow }),
1104
+ /* @__PURE__ */ jsx("div", { id: descriptionId, className: "text-sm font-semibold", children: title })
1105
+ ] }),
1106
+ /* @__PURE__ */ jsx(
1107
+ "button",
1108
+ {
1109
+ ref: closeButtonRef,
1110
+ type: "button",
1111
+ className: "rounded-full px-2 py-1 text-xs text-muted-foreground hover:bg-muted hover:text-foreground",
1112
+ onClick: (event) => {
1113
+ event.preventDefault();
1114
+ event.stopPropagation();
1115
+ onClose();
1116
+ },
1117
+ children: "Close"
1118
+ }
1119
+ )
1120
+ ] }),
1121
+ /* @__PURE__ */ jsx("div", { className: spacing === "compact" ? "space-y-2" : "space-y-3", children })
1122
+ ]
1123
+ }
1124
+ );
1125
+ }
1126
+ function CustomizeCycleRow({
1127
+ label,
1128
+ valueLabel,
1129
+ previousLabel,
1130
+ nextLabel,
1131
+ availability,
1132
+ onPrevious,
1133
+ onNext
1134
+ }) {
1135
+ const reasonId = useId();
1136
+ const disabled = availability.kind === "unavailable";
1137
+ const unavailableReason = availability.kind === "unavailable" ? cycleUnavailableReasonLabel(availability.reason) : null;
1138
+ return /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2", children: [
1139
+ /* @__PURE__ */ jsxs("div", { children: [
1140
+ /* @__PURE__ */ jsx("div", { className: "text-sm font-medium", children: label }),
1141
+ /* @__PURE__ */ jsx("div", { className: "text-xs text-muted-foreground", children: valueLabel })
1142
+ ] }),
1143
+ /* @__PURE__ */ jsxs("div", { className: "flex shrink-0 items-center overflow-hidden rounded-full border bg-background", children: [
1144
+ unavailableReason ? /* @__PURE__ */ jsx("span", { id: reasonId, className: "sr-only", children: unavailableReason }) : null,
1145
+ /* @__PURE__ */ jsx(
1146
+ "button",
1147
+ {
1148
+ type: "button",
1149
+ onClick: (event) => {
1150
+ event.preventDefault();
1151
+ event.stopPropagation();
1152
+ onPrevious();
1153
+ },
1154
+ className: "grid h-8 w-8 place-items-center hover:bg-muted disabled:cursor-not-allowed disabled:opacity-50",
1155
+ "aria-label": previousLabel,
1156
+ "aria-describedby": unavailableReason ? reasonId : void 0,
1157
+ title: unavailableReason ?? void 0,
1158
+ disabled,
1159
+ children: /* @__PURE__ */ jsx(ChevronLeft, { size: 14 })
1160
+ }
1161
+ ),
1162
+ /* @__PURE__ */ jsx(
1163
+ "button",
1164
+ {
1165
+ type: "button",
1166
+ onClick: (event) => {
1167
+ event.preventDefault();
1168
+ event.stopPropagation();
1169
+ onNext();
1170
+ },
1171
+ className: "grid h-8 w-8 place-items-center border-l hover:bg-muted disabled:cursor-not-allowed disabled:opacity-50",
1172
+ "aria-label": nextLabel,
1173
+ "aria-describedby": unavailableReason ? reasonId : void 0,
1174
+ title: unavailableReason ?? void 0,
1175
+ disabled,
1176
+ children: /* @__PURE__ */ jsx(ChevronRight, { size: 14 })
1177
+ }
1178
+ )
1179
+ ] })
1180
+ ] });
1181
+ }
1182
+ function cycleAvailability(input) {
1183
+ if (input.kind === "available") {
1184
+ return input;
1185
+ }
1186
+ return { kind: "unavailable", reason: input.kind };
1187
+ }
1188
+ function cycleUnavailableReasonLabel(reason) {
1189
+ if (reason === "preview-only") {
1190
+ return "Preview-only users cannot change this control.";
1191
+ }
1192
+ if (reason === "single-option") {
1193
+ return "There are no other options to cycle to.";
1194
+ }
1195
+ return reason;
1196
+ }
1197
+ function cycleAvailabilityFromFlags(input) {
1198
+ if (!input.applyAllowed) {
1199
+ return { kind: "unavailable", reason: "preview-only" };
1200
+ }
1201
+ if (!input.canCycle) {
1202
+ return { kind: "unavailable", reason: "single-option" };
1203
+ }
1204
+ return { kind: "available" };
1205
+ }
419
1206
 
420
1207
  // ../preview-next/src/client/blocks/isRecord.ts
421
- function isRecord3(value) {
1208
+ function isRecord4(value) {
422
1209
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
423
1210
  }
424
1211
 
@@ -484,35 +1271,18 @@ function setPageDesignBlockBackground(input) {
484
1271
  });
485
1272
  const plan = planBackgroundOverride(current, capability, input.override);
486
1273
  if (plan.kind !== "apply") return null;
1274
+ const imageAsset = plan.override.kind === "image" ? imagePoolAssetForMediaId(input.imagePool, plan.override.mediaId) : void 0;
487
1275
  return {
488
1276
  kind: "set-background",
489
1277
  blockId: input.block.blockId,
490
1278
  override: plan.override,
491
1279
  fromOverride: plan.fromOverride,
492
- baseContentId: input.block.contentRevision?.contentId ?? null
1280
+ baseContentId: input.block.contentRevision?.contentId ?? null,
1281
+ ...imageAsset ? { imageAsset } : {}
493
1282
  };
494
1283
  }
495
- function cyclePageDesignBoundaryBreak(boundary, direction) {
496
- if (boundary.availableBreaks.length === 0) return null;
497
- const breakIds = boundary.availableBreaks.map((option) => option.id);
498
- const values = [null, ...breakIds];
499
- const currentIndex = cycleChoiceIndex(boundary.breakChoice, values, direction);
500
- if (currentIndex === -1) return null;
501
- const nextIndex = direction === "next" ? (currentIndex + 1) % values.length : currentIndex === 0 ? values.length - 1 : currentIndex - 1;
502
- const boundaryOptionId = values[nextIndex];
503
- if (boundaryOptionId === void 0) return null;
504
- return {
505
- ...boundaryOptionId ? {
506
- kind: "set-boundary",
507
- previousBlockId: boundary.previousBlockId,
508
- nextBlockId: boundary.nextBlockId,
509
- boundaryOptionId
510
- } : {
511
- kind: "reset-boundary",
512
- previousBlockId: boundary.previousBlockId,
513
- nextBlockId: boundary.nextBlockId
514
- }
515
- };
1284
+ function imagePoolAssetForMediaId(imagePool, mediaId) {
1285
+ return imagePool?.find((item) => item.mediaId === mediaId)?.mediaAsset;
516
1286
  }
517
1287
  function cycleChoiceIndex(choice, values, direction) {
518
1288
  if (choice.kind === "user-pinned" && choice.status === "supported") {
@@ -543,68 +1313,37 @@ function previewCustomizeFacetControlsFor(blockKind, content, designBlock) {
543
1313
  };
544
1314
  });
545
1315
  }
546
- function useDialogFocusTrap(input) {
547
- const { open, onClose } = input;
548
- const dialogRef = useRef(null);
549
- const initialFocusRef = useRef(null);
550
- const returnFocusRef = useRef(null);
551
- useEffect(() => {
552
- if (open) {
553
- initialFocusRef.current?.focus();
554
- return;
555
- }
556
- const returnFocusTarget = returnFocusRef.current;
557
- returnFocusRef.current = null;
558
- returnFocusTarget?.focus();
559
- }, [open]);
560
- const registerInitialFocus = useCallback((node) => {
561
- initialFocusRef.current = node;
562
- }, []);
563
- const setReturnFocusTarget = useCallback((node) => {
564
- returnFocusRef.current = node;
565
- }, []);
566
- const handleDialogKeyDown = useCallback(
567
- (event) => {
568
- if (event.key === "Escape") {
569
- event.preventDefault();
570
- onClose();
571
- return;
572
- }
573
- if (event.key !== "Tab") return;
574
- const focusableElements = focusableElementsIn(dialogRef.current);
575
- if (focusableElements.length === 0) {
576
- event.preventDefault();
577
- return;
578
- }
579
- const firstElement = focusableElements[0];
580
- const lastElement = focusableElements[focusableElements.length - 1];
581
- if (!firstElement || !lastElement) return;
582
- if (event.shiftKey && document.activeElement === firstElement) {
583
- event.preventDefault();
584
- lastElement.focus();
585
- return;
586
- }
587
- if (!event.shiftKey && document.activeElement === lastElement) {
588
- event.preventDefault();
589
- firstElement.focus();
590
- }
591
- },
592
- [onClose]
1316
+
1317
+ // ../preview-next/src/client/blocks/blockCustomizePopoverRows.ts
1318
+ function buildBlockCustomizeBuiltinRows({
1319
+ designBlock,
1320
+ facetControls,
1321
+ hasLayoutControls,
1322
+ hasLookControls,
1323
+ hasBackgroundControls
1324
+ }) {
1325
+ const rows = [];
1326
+ if (designBlock?.layout && hasLayoutControls) {
1327
+ rows.push({ kind: "variant", block: designBlock });
1328
+ }
1329
+ if (designBlock?.layout?.status === "unsupported") {
1330
+ rows.push({ kind: "unsupported-variant-warning" });
1331
+ }
1332
+ if (designBlock && hasLookControls) {
1333
+ rows.push({ kind: "look", block: designBlock });
1334
+ }
1335
+ if (hasBackgroundControls) {
1336
+ rows.push({ kind: "background" });
1337
+ }
1338
+ rows.push(
1339
+ ...facetControls.map(
1340
+ (control) => ({ kind: "facet", control })
1341
+ )
593
1342
  );
594
- return {
595
- dialogRef,
596
- registerInitialFocus,
597
- setReturnFocusTarget,
598
- handleDialogKeyDown
599
- };
1343
+ return rows;
600
1344
  }
601
- function focusableElementsIn(root) {
602
- if (!root) return [];
603
- return Array.from(
604
- root.querySelectorAll(
605
- 'a[href], button:not([disabled]), textarea:not([disabled]), input:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex="-1"])'
606
- )
607
- ).filter((element) => !element.hasAttribute("disabled") && element.getAttribute("aria-hidden") !== "true");
1345
+ function blockCustomizeBuiltinRowBudget(rows) {
1346
+ return rows.length;
608
1347
  }
609
1348
  function isUnknownArray(value) {
610
1349
  return Array.isArray(value);
@@ -613,8 +1352,9 @@ function BlockToolbar({
613
1352
  blockId,
614
1353
  blockKind,
615
1354
  content,
1355
+ bookingOfferingPresets,
616
1356
  theme = null,
617
- headerClearancePx = 0
1357
+ placement = DEFAULT_PREVIEW_CHROME_FLOATING_PLACEMENT
618
1358
  }) {
619
1359
  const uiStore = useEditorUiStoreInstance();
620
1360
  const editorBlockId = useMemo(() => unsafeAsEditorBlockId(blockId), [blockId]);
@@ -622,41 +1362,25 @@ function BlockToolbar({
622
1362
  (state) => state.drafts.getCurrentValues(editorBlockId)
623
1363
  );
624
1364
  const customizeContent = useMemo(
625
- () => isRecord3(draftContent) ? draftContent : content,
1365
+ () => isRecord4(draftContent) ? draftContent : content,
626
1366
  [content, draftContent]
627
1367
  );
628
1368
  const customizeSelection = usePreviewBlockCustomizeSelectionOptional();
629
- const customizePanelId = useId();
630
- const customizeDescriptionId = `${customizePanelId}-description`;
1369
+ const popover = useCustomizePopoverController();
631
1370
  const focusTarget = useMemo(
632
1371
  () => computeDefaultFocus(blockKind, customizeContent),
633
1372
  [blockKind, customizeContent]
634
1373
  );
635
- const [customizeOpen, setCustomizeOpen] = useState(false);
636
1374
  const [backgroundChooserOpen, setBackgroundChooserOpen] = useState(false);
637
1375
  const [backgroundColorPalette, setBackgroundColorPalette] = useState(null);
638
- const customizeButtonRef = useRef(null);
639
1376
  const {
640
1377
  state: pageDesignState,
641
1378
  applyAction: applyPageDesignAction,
642
- isHistoryPending,
643
1379
  historyFailure,
644
1380
  backgroundImagePool = [],
645
1381
  backgroundImagePoolStatus = "idle",
646
1382
  loadBackgroundImagePool = async () => []
647
1383
  } = usePreviewPageDesignEditorState();
648
- const closeCustomize = useCallback(() => {
649
- setCustomizeOpen(false);
650
- }, []);
651
- const {
652
- dialogRef: customizeDialogRef,
653
- registerInitialFocus: registerCustomizeInitialFocus,
654
- setReturnFocusTarget: setCustomizeReturnFocusTarget,
655
- handleDialogKeyDown: handleCustomizeDialogKeyDown
656
- } = useDialogFocusTrap({
657
- open: customizeOpen,
658
- onClose: closeCustomize
659
- });
660
1384
  const designBlock = useMemo(() => {
661
1385
  if (pageDesignState.kind !== "loaded") return null;
662
1386
  return pageDesignState.editorModel.blocks.find(
@@ -669,11 +1393,12 @@ function BlockToolbar({
669
1393
  const hasLookControls = Boolean(
670
1394
  designBlock && designBlock.availableLooks.length > 0
671
1395
  );
672
- const canCycleLook = Boolean(
673
- designBlock && designBlock.availableLooks.length > 1
674
- );
675
1396
  const facetControls = useMemo(
676
- () => previewCustomizeFacetControlsFor(blockKind, customizeContent, designBlock),
1397
+ () => previewCustomizeFacetControlsFor(
1398
+ blockKind,
1399
+ customizeContent,
1400
+ designBlock
1401
+ ),
677
1402
  [blockKind, customizeContent, designBlock]
678
1403
  );
679
1404
  const hasFacetControls = facetControls.length > 0;
@@ -690,6 +1415,26 @@ function BlockToolbar({
690
1415
  ),
691
1416
  [backgroundImagePool, currentBackground]
692
1417
  );
1418
+ const backgroundCycleImagePool = useMemo(
1419
+ () => {
1420
+ if (currentBackground.kind === "supported" && currentBackground.override.kind === "image") {
1421
+ const currentOverride = currentBackground.override;
1422
+ const currentExistsInPool = backgroundImagePool.some(
1423
+ (item) => item.mediaId === currentOverride.mediaId
1424
+ );
1425
+ if (!currentExistsInPool) {
1426
+ return rankBackgroundImagePoolItems(
1427
+ dedupeBackgroundImagePool([
1428
+ ...imagePoolForOverride(currentOverride),
1429
+ ...backgroundImagePool
1430
+ ])
1431
+ );
1432
+ }
1433
+ }
1434
+ return rankBackgroundImagePoolItems(backgroundImagePool);
1435
+ },
1436
+ [backgroundImagePool, currentBackground]
1437
+ );
693
1438
  const backgroundCapability = useMemo(
694
1439
  () => designBlock ? resolveBackgroundCapability({
695
1440
  block: designBlock,
@@ -698,14 +1443,34 @@ function BlockToolbar({
698
1443
  }) : null,
699
1444
  [backgroundColorPalette, designBlock, mergedBackgroundImagePool]
700
1445
  );
1446
+ const backgroundTransitionCapability = useMemo(
1447
+ () => backgroundCapability ? { ...backgroundCapability, imagePool: backgroundCycleImagePool } : null,
1448
+ [backgroundCapability, backgroundCycleImagePool]
1449
+ );
701
1450
  const enabledBackgroundModeList = useMemo(
702
1451
  () => backgroundCapability ? enabledBackgroundModes(backgroundCapability) : [],
703
1452
  [backgroundCapability]
704
1453
  );
705
1454
  const hasBackgroundControls = currentBackground.kind === "supported" && enabledBackgroundModeList.length > 1;
706
- const builtInCustomizeRowCount = (hasLayoutControls ? 1 : 0) + facetControls.length + (hasBackgroundControls ? 1 : 0) + (hasLookControls ? 1 : 0);
1455
+ const builtInCustomizeRows = useMemo(
1456
+ () => buildBlockCustomizeBuiltinRows({
1457
+ designBlock,
1458
+ facetControls,
1459
+ hasLayoutControls,
1460
+ hasLookControls,
1461
+ hasBackgroundControls
1462
+ }),
1463
+ [
1464
+ designBlock,
1465
+ facetControls,
1466
+ hasBackgroundControls,
1467
+ hasLayoutControls,
1468
+ hasLookControls
1469
+ ]
1470
+ );
1471
+ const builtInCustomizeRowCount = blockCustomizeBuiltinRowBudget(builtInCustomizeRows);
707
1472
  const manifestCustomize = useBlockCustomizeControls({
708
- blockId,
1473
+ blockId: editorBlockId,
709
1474
  blockKind,
710
1475
  content: customizeContent,
711
1476
  uiStore,
@@ -719,24 +1484,23 @@ function BlockToolbar({
719
1484
  const hasOverflowCustomizeControls = manifestCustomize.hasOverflowControls;
720
1485
  const quickManifestBackend = manifestCustomize.backend;
721
1486
  const canCycleBackgroundMode = enabledBackgroundModeList.length > 1;
722
- const canCycleBackgroundValue = currentBackground.kind === "supported" && backgroundCapability ? canCycleBackgroundOverrideValue(
1487
+ const canCycleBackgroundValue = currentBackground.kind === "supported" && backgroundTransitionCapability ? canCycleBackgroundOverrideValue(
723
1488
  currentBackground.override,
724
- backgroundCapability
1489
+ backgroundTransitionCapability
725
1490
  ) : false;
726
1491
  const hasCustomizeControls = hasLayoutControls || hasLookControls || hasFacetControls || hasBackgroundControls || quickManifestFields.length > 0 || hasSidebarCustomizeControls;
727
- const isSavingCustomize = isHistoryPending;
728
1492
  useEffect(() => {
729
1493
  if (!hasCustomizeControls) {
730
- setCustomizeOpen(false);
1494
+ popover.close();
731
1495
  setBackgroundChooserOpen(false);
732
1496
  }
733
- }, [hasCustomizeControls]);
1497
+ }, [hasCustomizeControls, popover.close]);
734
1498
  useEffect(() => {
735
- if (!customizeOpen) return;
1499
+ if (!popover.open) return;
736
1500
  setBackgroundColorPalette(readBackgroundColorPaletteSnapshot());
737
- }, [customizeOpen, pageDesignState]);
1501
+ }, [pageDesignState, popover.open]);
738
1502
  useEffect(() => {
739
- if (!customizeOpen || !backgroundCapability?.modes.includes("image")) {
1503
+ if (!popover.open || !backgroundCapability?.modes.includes("image")) {
740
1504
  return;
741
1505
  }
742
1506
  if (backgroundImagePoolStatus !== "idle") return;
@@ -744,8 +1508,8 @@ function BlockToolbar({
744
1508
  }, [
745
1509
  backgroundCapability,
746
1510
  backgroundImagePoolStatus,
747
- customizeOpen,
748
- loadBackgroundImagePool
1511
+ loadBackgroundImagePool,
1512
+ popover.open
749
1513
  ]);
750
1514
  const handleEdit = (e) => {
751
1515
  e.preventDefault();
@@ -763,40 +1527,32 @@ function BlockToolbar({
763
1527
  const inspectBlock = useCallback(() => {
764
1528
  customizeSelection?.inspectBlock(unsafeAsEditorBlockId(blockId));
765
1529
  }, [blockId, customizeSelection]);
766
- const openCustomizeSettings = useCallback((e) => {
767
- e.preventDefault();
768
- e.stopPropagation();
769
- inspectBlock();
770
- const state = uiStore.getState();
771
- setPreviewSidebarTab("editor");
772
- state.setPreviewSidebarTab("editor");
773
- state.setDrawerOpen(true);
774
- }, [inspectBlock, uiStore]);
775
- const cycleLayout = (direction) => (e) => {
776
- e.preventDefault();
777
- e.stopPropagation();
1530
+ const openSidebarCustomize = useCallback(
1531
+ (e) => {
1532
+ e.preventDefault();
1533
+ e.stopPropagation();
1534
+ inspectBlock();
1535
+ const state = uiStore.getState();
1536
+ setPreviewSidebarTab("editor");
1537
+ state.setPreviewSidebarTab("editor");
1538
+ state.setDrawerOpen(true);
1539
+ },
1540
+ [inspectBlock, uiStore]
1541
+ );
1542
+ const cycleLayout = (direction) => {
778
1543
  if (!designBlock) return;
779
1544
  const action = cyclePageDesignBlockLayout(designBlock, direction);
780
1545
  if (!action) return;
781
1546
  saveBlockCustomizeAction(action);
782
1547
  };
783
- const cycleLook = (direction) => (e) => {
784
- e.preventDefault();
785
- e.stopPropagation();
1548
+ const cycleLook = (direction) => {
786
1549
  if (!designBlock) return;
787
1550
  const action = cyclePageDesignBlockLook(designBlock, direction);
788
1551
  if (!action) return;
789
1552
  saveBlockCustomizeAction(action);
790
1553
  };
791
- const handleFacetCycle = (e) => {
792
- e.preventDefault();
793
- e.stopPropagation();
1554
+ const cycleFacet = (control, direction) => {
794
1555
  if (!designBlock) return;
795
- const facetId = e.currentTarget.dataset.facetId;
796
- const direction = e.currentTarget.dataset.direction;
797
- if (direction !== "prev" && direction !== "next") return;
798
- const control = facetControls.find((candidate) => candidate.facetId === facetId) ?? null;
799
- if (!control) return;
800
1556
  const action = cyclePageDesignBlockFacet({
801
1557
  block: designBlock,
802
1558
  facetId: control.facetId,
@@ -824,12 +1580,12 @@ function BlockToolbar({
824
1580
  setBackgroundChooserOpen(false);
825
1581
  };
826
1582
  const saveBackgroundTransition = (transition) => {
827
- if (!designBlock || !backgroundCapability || currentBackground.kind !== "supported") {
1583
+ if (!designBlock || !backgroundTransitionCapability || currentBackground.kind !== "supported") {
828
1584
  return;
829
1585
  }
830
1586
  const plan = planBackgroundTransition(
831
1587
  currentBackground.override,
832
- backgroundCapability,
1588
+ backgroundTransitionCapability,
833
1589
  transition
834
1590
  );
835
1591
  if (plan.kind !== "apply") return;
@@ -846,305 +1602,96 @@ function BlockToolbar({
846
1602
  void applyPageDesignAction(action, { runtimeContent: customizeContent });
847
1603
  };
848
1604
  const toggleCustomize = (e) => {
849
- e.preventDefault();
850
- e.stopPropagation();
851
- if (!customizeOpen) {
1605
+ if (!popover.open) {
852
1606
  inspectBlock();
853
- setCustomizeReturnFocusTarget(
854
- e.currentTarget instanceof HTMLElement ? e.currentTarget : customizeButtonRef.current
855
- );
856
1607
  }
857
- setCustomizeOpen((open) => !open);
1608
+ popover.toggle(e);
858
1609
  };
859
1610
  return /* @__PURE__ */ jsxs(
860
- "div",
1611
+ PreviewChromeFloatingControl,
861
1612
  {
862
- className: "pointer-events-auto absolute right-2 z-50 flex gap-1 opacity-0 transition group-focus-within:opacity-100 group-hover:opacity-100",
863
- style: { top: headerClearancePx > 0 ? headerClearancePx + 8 : 8 },
864
- children: [
865
- hasCustomizeControls ? /* @__PURE__ */ jsx(
866
- "button",
867
- {
868
- ref: customizeButtonRef,
869
- type: "button",
870
- onClick: toggleCustomize,
871
- className: previewCustomizePillButtonClassName,
872
- "aria-label": "Customize",
873
- "aria-expanded": customizeOpen,
874
- "aria-haspopup": "dialog",
875
- "aria-controls": customizeOpen ? customizePanelId : void 0,
876
- children: isSavingCustomize ? "Saving..." : "Customize"
877
- }
878
- ) : null,
879
- /* @__PURE__ */ jsx(
880
- "button",
881
- {
882
- type: "button",
883
- onClick: handleEdit,
884
- className: previewCustomizePillButtonClassName,
885
- children: "Edit"
886
- }
887
- ),
888
- customizeOpen && (designBlock || hasSidebarCustomizeControls) ? /* @__PURE__ */ jsxs(
889
- "div",
890
- {
891
- id: customizePanelId,
892
- className: "builder-dashboard-chrome-theme fixed inset-x-3 bottom-[calc(var(--builder-editor-chrome-offset,0px)+1rem)] z-[70] rounded-lg border bg-background p-3 text-foreground shadow-xl sm:absolute sm:inset-x-auto sm:bottom-auto sm:right-0 sm:top-9 sm:w-72",
893
- role: "dialog",
894
- "aria-modal": "true",
895
- "aria-label": "Customize section",
896
- "aria-describedby": customizeDescriptionId,
897
- ref: customizeDialogRef,
898
- onKeyDown: handleCustomizeDialogKeyDown,
899
- onClick: (event) => event.stopPropagation(),
900
- children: [
901
- /* @__PURE__ */ jsxs("div", { className: "mb-3 flex items-start justify-between gap-3", children: [
902
- /* @__PURE__ */ jsxs("div", { children: [
903
- /* @__PURE__ */ jsx("div", { className: "text-xs font-medium uppercase text-muted-foreground", children: "Section" }),
904
- /* @__PURE__ */ jsx(
905
- "div",
906
- {
907
- id: customizeDescriptionId,
908
- className: "text-sm font-semibold",
909
- children: formatBlockKindLabel(blockKind)
910
- }
911
- )
912
- ] }),
913
- /* @__PURE__ */ jsx(
914
- "button",
915
- {
916
- ref: registerCustomizeInitialFocus,
917
- type: "button",
918
- className: "rounded-full px-2 py-1 text-xs text-muted-foreground hover:bg-muted hover:text-foreground",
919
- onClick: (event) => {
920
- event.preventDefault();
921
- event.stopPropagation();
922
- closeCustomize();
923
- },
924
- children: "Close"
925
- }
926
- )
927
- ] }),
928
- /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
929
- designBlock?.layout && hasLayoutControls ? /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2", children: [
930
- /* @__PURE__ */ jsxs("div", { children: [
931
- /* @__PURE__ */ jsx("div", { className: "text-sm font-medium", children: "Layout" }),
932
- /* @__PURE__ */ jsx("div", { className: "text-xs text-muted-foreground", children: layoutLabel(
933
- designBlock.availableLayouts,
934
- designBlock.layout.effectiveValue
935
- ) })
936
- ] }),
937
- /* @__PURE__ */ jsxs("div", { className: "flex shrink-0 items-center overflow-hidden rounded-full border bg-background", children: [
938
- /* @__PURE__ */ jsx(
939
- "button",
940
- {
941
- type: "button",
942
- onClick: cycleLayout("prev"),
943
- className: "grid h-8 w-8 place-items-center hover:bg-muted disabled:cursor-not-allowed disabled:opacity-50",
944
- "aria-label": "Previous layout",
945
- children: /* @__PURE__ */ jsx(ChevronLeft, { size: 14 })
946
- }
947
- ),
948
- /* @__PURE__ */ jsx(
949
- "button",
950
- {
951
- type: "button",
952
- onClick: cycleLayout("next"),
953
- className: "grid h-8 w-8 place-items-center border-l hover:bg-muted disabled:cursor-not-allowed disabled:opacity-50",
954
- "aria-label": "Next layout",
955
- children: /* @__PURE__ */ jsx(ChevronRight, { size: 14 })
956
- }
957
- )
958
- ] })
959
- ] }) : null,
960
- designBlock?.layout?.status === "unsupported" ? /* @__PURE__ */ jsx("p", { className: "text-xs text-amber-700", children: "This layout is no longer available. The preview is using the closest safe option." }) : null,
961
- facetControls.map((control) => /* @__PURE__ */ jsxs(
962
- "div",
963
- {
964
- className: "flex items-center justify-between gap-2",
965
- children: [
966
- /* @__PURE__ */ jsxs("div", { children: [
967
- /* @__PURE__ */ jsx("div", { className: "text-sm font-medium", children: control.label }),
968
- /* @__PURE__ */ jsx("div", { className: "text-xs text-muted-foreground", children: control.valueLabel })
969
- ] }),
970
- /* @__PURE__ */ jsxs("div", { className: "flex shrink-0 items-center overflow-hidden rounded-full border bg-background", children: [
971
- /* @__PURE__ */ jsx(
972
- "button",
973
- {
974
- type: "button",
975
- onClick: handleFacetCycle,
976
- "data-facet-id": control.facetId,
977
- "data-direction": "prev",
978
- className: "grid h-8 w-8 place-items-center hover:bg-muted disabled:cursor-not-allowed disabled:opacity-50",
979
- "aria-label": `Previous ${control.label.toLowerCase()}`,
980
- children: /* @__PURE__ */ jsx(ChevronLeft, { size: 14 })
981
- }
982
- ),
983
- /* @__PURE__ */ jsx(
984
- "button",
985
- {
986
- type: "button",
987
- onClick: handleFacetCycle,
988
- "data-facet-id": control.facetId,
989
- "data-direction": "next",
990
- className: "grid h-8 w-8 place-items-center border-l hover:bg-muted disabled:cursor-not-allowed disabled:opacity-50",
991
- "aria-label": `Next ${control.label.toLowerCase()}`,
992
- children: /* @__PURE__ */ jsx(ChevronRight, { size: 14 })
993
- }
994
- )
995
- ] })
996
- ]
997
- },
998
- control.facetId
999
- )),
1000
- hasBackgroundControls && currentBackground.kind === "supported" && backgroundCapability ? /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
1001
- /* @__PURE__ */ jsxs("div", { className: "flex items-stretch overflow-hidden rounded-full border bg-background", children: [
1002
- /* @__PURE__ */ jsx(
1003
- "button",
1004
- {
1005
- type: "button",
1006
- onClick: handleBackgroundCycle({
1007
- kind: "cycle-mode",
1008
- direction: "prev"
1009
- }),
1010
- className: "grid h-8 w-8 place-items-center hover:bg-muted disabled:cursor-not-allowed disabled:opacity-50",
1011
- "aria-label": "Previous background mode",
1012
- disabled: !canCycleBackgroundMode,
1013
- children: /* @__PURE__ */ jsx(ChevronLeft, { size: 14 })
1014
- }
1015
- ),
1016
- /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1 border-x px-2 py-1 text-center", children: [
1017
- /* @__PURE__ */ jsx("div", { className: "text-xs font-medium leading-3 text-muted-foreground", children: "Background:" }),
1018
- /* @__PURE__ */ jsx("div", { className: "truncate text-xs font-semibold leading-4", children: backgroundModeLabel(currentBackground.override.kind) })
1019
- ] }),
1020
- /* @__PURE__ */ jsx(
1021
- "button",
1022
- {
1023
- type: "button",
1024
- onClick: handleBackgroundCycle({
1025
- kind: "cycle-mode",
1026
- direction: "next"
1027
- }),
1028
- className: "grid h-8 w-8 place-items-center hover:bg-muted disabled:cursor-not-allowed disabled:opacity-50",
1029
- "aria-label": "Next background mode",
1030
- disabled: !canCycleBackgroundMode,
1031
- children: /* @__PURE__ */ jsx(ChevronRight, { size: 14 })
1032
- }
1033
- )
1034
- ] }),
1035
- /* @__PURE__ */ jsxs("div", { className: "flex items-stretch overflow-hidden rounded-full border bg-background", children: [
1036
- /* @__PURE__ */ jsx(
1037
- "button",
1038
- {
1039
- type: "button",
1040
- onClick: handleBackgroundCycle({
1041
- kind: "cycle-value",
1042
- direction: "prev"
1043
- }),
1044
- className: "grid h-8 w-8 place-items-center hover:bg-muted disabled:cursor-not-allowed disabled:opacity-50",
1045
- "aria-label": "Previous background value",
1046
- disabled: !canCycleBackgroundValue,
1047
- children: /* @__PURE__ */ jsx(ChevronLeft, { size: 14 })
1048
- }
1049
- ),
1050
- /* @__PURE__ */ jsxs(
1051
- "button",
1052
- {
1053
- type: "button",
1054
- className: "flex min-w-0 flex-1 items-center justify-center gap-2 border-x px-2 py-1 text-center hover:bg-muted",
1055
- "aria-expanded": backgroundChooserOpen,
1056
- "aria-label": `Choose background ${backgroundOverrideLabel(currentBackground.override).toLowerCase()}`,
1057
- onClick: (event) => {
1058
- event.preventDefault();
1059
- event.stopPropagation();
1060
- setBackgroundChooserOpen((open) => !open);
1061
- },
1062
- children: [
1063
- /* @__PURE__ */ jsx(BackgroundPreviewSwatch, { override: currentBackground.override }),
1064
- /* @__PURE__ */ jsx("span", { className: "truncate text-xs font-medium", children: backgroundOverrideValueLabel(
1065
- currentBackground.override,
1066
- mergedBackgroundImagePool
1067
- ) })
1068
- ]
1069
- }
1070
- ),
1071
- /* @__PURE__ */ jsx(
1072
- "button",
1073
- {
1074
- type: "button",
1075
- onClick: handleBackgroundCycle({
1076
- kind: "cycle-value",
1077
- direction: "next"
1078
- }),
1079
- className: "grid h-8 w-8 place-items-center hover:bg-muted disabled:cursor-not-allowed disabled:opacity-50",
1080
- "aria-label": "Next background value",
1081
- disabled: !canCycleBackgroundValue,
1082
- children: /* @__PURE__ */ jsx(ChevronRight, { size: 14 })
1083
- }
1084
- )
1085
- ] }),
1086
- backgroundChooserOpen ? /* @__PURE__ */ jsx(
1087
- BackgroundChooser,
1088
- {
1089
- capability: backgroundCapability,
1090
- current: currentBackground.override,
1091
- enabledModes: enabledBackgroundModeList,
1092
- imagePoolStatus: backgroundImagePoolStatus,
1093
- onChoose: chooseBackgroundOverride
1094
- }
1095
- ) : null
1096
- ] }) : null,
1097
- quickManifestFields.length > 0 && quickManifestBackend ? /* @__PURE__ */ jsx("div", { className: "border-t pt-3", children: /* @__PURE__ */ jsx(
1098
- FormRenderer,
1099
- {
1100
- fields: quickManifestFields,
1101
- backend: quickManifestBackend,
1102
- showSettingsTrigger: false,
1103
- blockKind,
1104
- className: "space-y-3"
1105
- }
1106
- ) }) : null,
1107
- hasLookControls && designBlock ? /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2", children: [
1108
- /* @__PURE__ */ jsxs("div", { children: [
1109
- /* @__PURE__ */ jsx("div", { className: "text-sm font-medium", children: "Look" }),
1110
- /* @__PURE__ */ jsx("div", { className: "text-xs text-muted-foreground", children: lookLabel(designBlock) })
1111
- ] }),
1112
- /* @__PURE__ */ jsxs("div", { className: "flex shrink-0 items-center overflow-hidden rounded-full border bg-background", children: [
1113
- /* @__PURE__ */ jsx(
1114
- "button",
1115
- {
1116
- type: "button",
1117
- onClick: cycleLook("prev"),
1118
- className: "grid h-8 w-8 place-items-center hover:bg-muted disabled:cursor-not-allowed disabled:opacity-50",
1119
- "aria-label": "Previous look",
1120
- disabled: !canCycleLook,
1121
- children: /* @__PURE__ */ jsx(ChevronLeft, { size: 14 })
1122
- }
1123
- ),
1124
- /* @__PURE__ */ jsx(
1125
- "button",
1126
- {
1127
- type: "button",
1128
- onClick: cycleLook("next"),
1129
- className: "grid h-8 w-8 place-items-center border-l hover:bg-muted disabled:cursor-not-allowed disabled:opacity-50",
1130
- "aria-label": "Next look",
1131
- disabled: !canCycleLook,
1132
- children: /* @__PURE__ */ jsx(ChevronRight, { size: 14 })
1133
- }
1134
- )
1135
- ] })
1136
- ] }) : null,
1137
- historyFailure ? /* @__PURE__ */ jsx("p", { className: "text-xs text-red-700", children: historyFailure }) : null,
1138
- hasOverflowCustomizeControls ? /* @__PURE__ */ jsx("div", { className: "border-t pt-2", children: /* @__PURE__ */ jsx(
1139
- "button",
1140
- {
1141
- type: "button",
1142
- className: "w-full rounded-md border bg-background px-3 py-2 text-sm font-medium hover:bg-muted",
1143
- onClick: openCustomizeSettings,
1144
- children: "Settings"
1145
- }
1146
- ) }) : null
1147
- ] })
1613
+ anchorSelector: "[data-block-id]",
1614
+ placement,
1615
+ fallbackClassName: "pointer-events-auto absolute z-50 flex gap-1 opacity-0 transition group-focus-within:opacity-100 group-hover:opacity-100",
1616
+ fallbackStyle: {
1617
+ top: placement.kind === "anchor-top-right-clamped" ? placement.minTopPx : placement.topPx,
1618
+ right: placement.rightPx
1619
+ },
1620
+ forceVisible: popover.open,
1621
+ children: [
1622
+ hasCustomizeControls ? /* @__PURE__ */ jsx(
1623
+ CustomizePillButton,
1624
+ {
1625
+ buttonRef: popover.buttonRef,
1626
+ ariaLabel: "Customize",
1627
+ open: popover.open,
1628
+ controlsId: popover.panelId,
1629
+ onClick: toggleCustomize
1630
+ }
1631
+ ) : null,
1632
+ /* @__PURE__ */ jsx(
1633
+ "button",
1634
+ {
1635
+ type: "button",
1636
+ onClick: handleEdit,
1637
+ className: previewCustomizePillButtonClassName,
1638
+ children: "Edit"
1639
+ }
1640
+ ),
1641
+ popover.open && (designBlock || hasSidebarCustomizeControls) ? /* @__PURE__ */ jsxs(
1642
+ CustomizePopoverShell,
1643
+ {
1644
+ panelId: popover.panelId,
1645
+ descriptionId: popover.descriptionId,
1646
+ dialogLabel: "Customize section",
1647
+ eyebrow: "Section",
1648
+ title: formatBlockKindLabel(blockKind),
1649
+ dialogRef: popover.dialogRef,
1650
+ closeButtonRef: popover.registerInitialFocus,
1651
+ onClose: popover.close,
1652
+ onKeyDown: popover.handleDialogKeyDown,
1653
+ spacing: "compact",
1654
+ children: [
1655
+ builtInCustomizeRows.map(
1656
+ (row) => renderBlockCustomizeBuiltinRow(row, {
1657
+ backgroundCapability,
1658
+ backgroundChooserOpen,
1659
+ canCycleBackgroundMode,
1660
+ canCycleBackgroundValue,
1661
+ currentBackground,
1662
+ cycleLayout,
1663
+ cycleLook,
1664
+ cycleFacet,
1665
+ enabledBackgroundModeList,
1666
+ handleBackgroundCycle,
1667
+ imagePoolStatus: backgroundImagePoolStatus,
1668
+ mergedBackgroundImagePool,
1669
+ onChooseBackgroundOverride: chooseBackgroundOverride,
1670
+ onToggleBackgroundChooser: () => setBackgroundChooserOpen((open) => !open)
1671
+ })
1672
+ ),
1673
+ quickManifestFields.length > 0 && quickManifestBackend ? /* @__PURE__ */ jsx("div", { className: "border-t pt-3", children: /* @__PURE__ */ jsx(OfferingsPreviewWidgetProvider, { bookingOfferingPresets, children: /* @__PURE__ */ jsx(
1674
+ FormRenderer,
1675
+ {
1676
+ fields: quickManifestFields,
1677
+ backend: quickManifestBackend,
1678
+ widgetOverrides: previewWidgetOverrides,
1679
+ showSettingsTrigger: false,
1680
+ blockKind,
1681
+ className: "space-y-3"
1682
+ }
1683
+ ) }) }) : null,
1684
+ historyFailure ? /* @__PURE__ */ jsx("p", { className: "text-xs text-red-700", children: historyFailure }) : null,
1685
+ hasOverflowCustomizeControls ? /* @__PURE__ */ jsx("div", { className: "border-t pt-2", children: /* @__PURE__ */ jsx(
1686
+ "button",
1687
+ {
1688
+ type: "button",
1689
+ "aria-label": "Open detailed customization settings",
1690
+ className: "w-full rounded-md border bg-background px-3 py-2 text-sm font-medium hover:bg-muted",
1691
+ onClick: openSidebarCustomize,
1692
+ children: "Customize"
1693
+ }
1694
+ ) }) : null
1148
1695
  ]
1149
1696
  }
1150
1697
  ) : null
@@ -1152,16 +1699,178 @@ function BlockToolbar({
1152
1699
  }
1153
1700
  );
1154
1701
  }
1702
+ function renderBlockCustomizeBuiltinRow(row, context) {
1703
+ switch (row.kind) {
1704
+ case "variant":
1705
+ return /* @__PURE__ */ jsx(
1706
+ CustomizeCycleRow,
1707
+ {
1708
+ label: "Variant",
1709
+ valueLabel: layoutLabel(
1710
+ row.block.availableLayouts,
1711
+ row.block.layout?.effectiveValue ?? ""
1712
+ ),
1713
+ previousLabel: "Previous variant",
1714
+ nextLabel: "Next variant",
1715
+ availability: cycleAvailability({ kind: "available" }),
1716
+ onPrevious: () => context.cycleLayout("prev"),
1717
+ onNext: () => context.cycleLayout("next")
1718
+ },
1719
+ "variant"
1720
+ );
1721
+ case "unsupported-variant-warning":
1722
+ return /* @__PURE__ */ jsx("p", { className: "text-xs text-amber-700", children: "This layout is no longer available. The preview is using the closest safe option." }, "unsupported-variant-warning");
1723
+ case "look":
1724
+ return /* @__PURE__ */ jsx(
1725
+ CustomizeCycleRow,
1726
+ {
1727
+ label: "Look",
1728
+ valueLabel: lookLabel(row.block),
1729
+ previousLabel: "Previous look",
1730
+ nextLabel: "Next look",
1731
+ availability: cycleAvailability(
1732
+ canCycleLookForRow(row.block) ? { kind: "available" } : { kind: "single-option" }
1733
+ ),
1734
+ onPrevious: () => context.cycleLook("prev"),
1735
+ onNext: () => context.cycleLook("next")
1736
+ },
1737
+ "look"
1738
+ );
1739
+ case "background":
1740
+ if (context.currentBackground.kind !== "supported" || !context.backgroundCapability) {
1741
+ return null;
1742
+ }
1743
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
1744
+ /* @__PURE__ */ jsxs("div", { className: "flex items-stretch overflow-hidden rounded-full border bg-background", children: [
1745
+ /* @__PURE__ */ jsx(
1746
+ "button",
1747
+ {
1748
+ type: "button",
1749
+ onClick: context.handleBackgroundCycle({
1750
+ kind: "cycle-mode",
1751
+ direction: "prev"
1752
+ }),
1753
+ className: "grid h-8 w-8 place-items-center hover:bg-muted disabled:cursor-not-allowed disabled:opacity-50",
1754
+ "aria-label": "Previous background mode",
1755
+ disabled: !context.canCycleBackgroundMode,
1756
+ children: /* @__PURE__ */ jsx(ChevronLeft, { size: 14 })
1757
+ }
1758
+ ),
1759
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1 border-x px-2 py-1 text-center", children: [
1760
+ /* @__PURE__ */ jsx("div", { className: "text-xs font-medium leading-3 text-muted-foreground", children: "Background:" }),
1761
+ /* @__PURE__ */ jsx("div", { className: "truncate text-xs font-semibold leading-4", children: backgroundModeLabel(context.currentBackground.override.kind) })
1762
+ ] }),
1763
+ /* @__PURE__ */ jsx(
1764
+ "button",
1765
+ {
1766
+ type: "button",
1767
+ onClick: context.handleBackgroundCycle({
1768
+ kind: "cycle-mode",
1769
+ direction: "next"
1770
+ }),
1771
+ className: "grid h-8 w-8 place-items-center hover:bg-muted disabled:cursor-not-allowed disabled:opacity-50",
1772
+ "aria-label": "Next background mode",
1773
+ disabled: !context.canCycleBackgroundMode,
1774
+ children: /* @__PURE__ */ jsx(ChevronRight, { size: 14 })
1775
+ }
1776
+ )
1777
+ ] }),
1778
+ /* @__PURE__ */ jsxs("div", { className: "flex items-stretch overflow-hidden rounded-full border bg-background", children: [
1779
+ /* @__PURE__ */ jsx(
1780
+ "button",
1781
+ {
1782
+ type: "button",
1783
+ onClick: context.handleBackgroundCycle({
1784
+ kind: "cycle-value",
1785
+ direction: "prev"
1786
+ }),
1787
+ className: "grid h-8 w-8 place-items-center hover:bg-muted disabled:cursor-not-allowed disabled:opacity-50",
1788
+ "aria-label": "Previous background value",
1789
+ disabled: !context.canCycleBackgroundValue,
1790
+ children: /* @__PURE__ */ jsx(ChevronLeft, { size: 14 })
1791
+ }
1792
+ ),
1793
+ /* @__PURE__ */ jsxs(
1794
+ "button",
1795
+ {
1796
+ type: "button",
1797
+ className: "flex min-w-0 flex-1 items-center justify-center gap-2 border-x px-2 py-1 text-center hover:bg-muted",
1798
+ "aria-expanded": context.backgroundChooserOpen,
1799
+ "aria-label": `Choose background ${backgroundOverrideLabel(context.currentBackground.override).toLowerCase()}`,
1800
+ onClick: (event) => {
1801
+ event.preventDefault();
1802
+ event.stopPropagation();
1803
+ context.onToggleBackgroundChooser();
1804
+ },
1805
+ children: [
1806
+ /* @__PURE__ */ jsx(
1807
+ BackgroundPreviewSwatch,
1808
+ {
1809
+ override: context.currentBackground.override,
1810
+ imagePool: context.mergedBackgroundImagePool
1811
+ }
1812
+ ),
1813
+ /* @__PURE__ */ jsx("span", { className: "truncate text-xs font-medium", children: backgroundOverrideValueLabel(
1814
+ context.currentBackground.override,
1815
+ context.mergedBackgroundImagePool
1816
+ ) })
1817
+ ]
1818
+ }
1819
+ ),
1820
+ /* @__PURE__ */ jsx(
1821
+ "button",
1822
+ {
1823
+ type: "button",
1824
+ onClick: context.handleBackgroundCycle({
1825
+ kind: "cycle-value",
1826
+ direction: "next"
1827
+ }),
1828
+ className: "grid h-8 w-8 place-items-center hover:bg-muted disabled:cursor-not-allowed disabled:opacity-50",
1829
+ "aria-label": "Next background value",
1830
+ disabled: !context.canCycleBackgroundValue,
1831
+ children: /* @__PURE__ */ jsx(ChevronRight, { size: 14 })
1832
+ }
1833
+ )
1834
+ ] }),
1835
+ context.backgroundChooserOpen ? /* @__PURE__ */ jsx(
1836
+ BackgroundChooser,
1837
+ {
1838
+ capability: context.backgroundCapability,
1839
+ current: context.currentBackground.override,
1840
+ imagePoolStatus: context.imagePoolStatus,
1841
+ onChoose: context.onChooseBackgroundOverride
1842
+ }
1843
+ ) : null
1844
+ ] }, "background");
1845
+ case "facet":
1846
+ return /* @__PURE__ */ jsx(
1847
+ CustomizeCycleRow,
1848
+ {
1849
+ label: row.control.label,
1850
+ valueLabel: row.control.valueLabel,
1851
+ previousLabel: `Previous ${row.control.label.toLowerCase()}`,
1852
+ nextLabel: `Next ${row.control.label.toLowerCase()}`,
1853
+ availability: cycleAvailability({ kind: "available" }),
1854
+ onPrevious: () => context.cycleFacet(row.control, "prev"),
1855
+ onNext: () => context.cycleFacet(row.control, "next")
1856
+ },
1857
+ `facet:${row.control.facetId}`
1858
+ );
1859
+ default:
1860
+ return assertNever2(row, "Unhandled block customize builtin row");
1861
+ }
1862
+ }
1863
+ function canCycleLookForRow(block) {
1864
+ return block.availableLooks.length > 1;
1865
+ }
1155
1866
  function BackgroundChooser({
1156
1867
  capability,
1157
1868
  current,
1158
- enabledModes,
1159
1869
  imagePoolStatus,
1160
1870
  onChoose
1161
1871
  }) {
1162
1872
  const mediaEditorContext = useMediaEditorOptional();
1163
1873
  const [mediaPickerOpenKey, setMediaPickerOpenKey] = useState(0);
1164
- const enabledModeSet = new Set(enabledModes);
1165
1874
  const images = rankBackgroundImagePoolItems(capability.imagePool ?? []);
1166
1875
  const recommendedTokens = capability.recommendedColorTokens ?? capability.colorTokens ?? [];
1167
1876
  const advancedTokens = capability.advancedColorTokens ?? [];
@@ -1177,21 +1886,30 @@ function BackgroundChooser({
1177
1886
  onChoose({ kind: "image", mediaId: parsed.value });
1178
1887
  setMediaPickerOpenKey(0);
1179
1888
  };
1180
- return /* @__PURE__ */ jsxs("div", { className: "mt-2 max-h-80 overflow-y-auto rounded-md border bg-muted/20 p-2", children: [
1181
- /* @__PURE__ */ jsx("div", { className: "mb-2 grid grid-cols-4 gap-1", children: ["default", "color", "gradient", "image"].map((mode) => /* @__PURE__ */ jsx(
1889
+ const renderColorOptions = () => recommendedTokens.length || advancedTokens.length ? /* @__PURE__ */ jsxs("div", { children: [
1890
+ /* @__PURE__ */ jsx("div", { className: "mb-1 text-xs font-medium text-muted-foreground", children: "Colors" }),
1891
+ /* @__PURE__ */ jsx("div", { className: "grid grid-cols-2 gap-1", children: recommendedTokens.map((token) => /* @__PURE__ */ jsxs(
1182
1892
  "button",
1183
1893
  {
1184
1894
  type: "button",
1185
- className: `rounded-md border px-2 py-1 text-xs ${current.kind === mode ? "border-foreground bg-foreground text-background" : "bg-background hover:bg-muted"} disabled:cursor-not-allowed disabled:opacity-50`,
1186
- disabled: !enabledModeSet.has(mode),
1187
- onClick: chooseFromClick(defaultBackgroundOverrideForMode(mode, capability)),
1188
- children: backgroundModeLabel(mode)
1895
+ className: `flex min-w-0 items-center gap-2 rounded-md border px-2 py-1 text-left text-xs hover:bg-muted ${current.kind === "color" && current.token === token ? "border-foreground" : "bg-background"}`,
1896
+ onClick: chooseFromClick({ kind: "color", token }),
1897
+ children: [
1898
+ /* @__PURE__ */ jsx(
1899
+ "span",
1900
+ {
1901
+ className: "h-3 w-3 shrink-0 rounded-full border",
1902
+ style: { backgroundColor: tokenSwatchCss(token) }
1903
+ }
1904
+ ),
1905
+ /* @__PURE__ */ jsx("span", { className: "truncate", children: formatTokenLabel(token) })
1906
+ ]
1189
1907
  },
1190
- mode
1908
+ token
1191
1909
  )) }),
1192
- recommendedTokens.length || advancedTokens.length ? /* @__PURE__ */ jsxs("div", { className: "mb-2", children: [
1193
- /* @__PURE__ */ jsx("div", { className: "mb-1 text-xs font-medium text-muted-foreground", children: "Colors" }),
1194
- /* @__PURE__ */ jsx("div", { className: "grid grid-cols-2 gap-1", children: recommendedTokens.map((token) => /* @__PURE__ */ jsxs(
1910
+ advancedTokens.length ? /* @__PURE__ */ jsxs("details", { className: "mt-1", children: [
1911
+ /* @__PURE__ */ jsx("summary", { className: "cursor-pointer text-xs text-muted-foreground", children: "More colors" }),
1912
+ /* @__PURE__ */ jsx("div", { className: "mt-1 grid grid-cols-2 gap-1", children: advancedTokens.map((token) => /* @__PURE__ */ jsxs(
1195
1913
  "button",
1196
1914
  {
1197
1915
  type: "button",
@@ -1209,78 +1927,72 @@ function BackgroundChooser({
1209
1927
  ]
1210
1928
  },
1211
1929
  token
1212
- )) }),
1213
- advancedTokens.length ? /* @__PURE__ */ jsxs("details", { className: "mt-1", children: [
1214
- /* @__PURE__ */ jsx("summary", { className: "cursor-pointer text-xs text-muted-foreground", children: "More colors" }),
1215
- /* @__PURE__ */ jsx("div", { className: "mt-1 grid grid-cols-2 gap-1", children: advancedTokens.map((token) => /* @__PURE__ */ jsxs(
1216
- "button",
1217
- {
1218
- type: "button",
1219
- className: `flex min-w-0 items-center gap-2 rounded-md border px-2 py-1 text-left text-xs hover:bg-muted ${current.kind === "color" && current.token === token ? "border-foreground" : "bg-background"}`,
1220
- onClick: chooseFromClick({ kind: "color", token }),
1221
- children: [
1222
- /* @__PURE__ */ jsx(
1223
- "span",
1224
- {
1225
- className: "h-3 w-3 shrink-0 rounded-full border",
1226
- style: { backgroundColor: tokenSwatchCss(token) }
1227
- }
1228
- ),
1229
- /* @__PURE__ */ jsx("span", { className: "truncate", children: formatTokenLabel(token) })
1230
- ]
1231
- },
1232
- token
1233
- )) })
1234
- ] }) : null
1235
- ] }) : null,
1236
- capability.gradientIds?.length ? /* @__PURE__ */ jsxs("div", { className: "mb-2", children: [
1237
- /* @__PURE__ */ jsx("div", { className: "mb-1 text-xs font-medium text-muted-foreground", children: "Gradients" }),
1238
- /* @__PURE__ */ jsx("div", { className: "space-y-1", children: capability.gradientIds.map((gradientId) => /* @__PURE__ */ jsx(
1239
- "button",
1240
- {
1241
- type: "button",
1242
- className: `w-full rounded-md border px-2 py-1 text-left text-xs hover:bg-muted ${current.kind === "gradient" && current.gradientId === gradientId ? "border-foreground" : "bg-background"}`,
1243
- onClick: chooseFromClick({ kind: "gradient", gradientId }),
1244
- children: /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-2", children: [
1245
- /* @__PURE__ */ jsx(
1246
- "span",
1247
- {
1248
- className: "h-4 w-8 shrink-0 rounded border",
1249
- style: { backgroundImage: gradientPreviewCss(gradientId) }
1250
- }
1251
- ),
1252
- /* @__PURE__ */ jsx("span", { className: "truncate", children: gradientLabel(gradientId) })
1253
- ] })
1254
- },
1255
- gradientId
1256
1930
  )) })
1257
- ] }) : null,
1258
- capability.modes.includes("image") ? /* @__PURE__ */ jsxs("div", { children: [
1259
- /* @__PURE__ */ jsx("div", { className: "mb-1 text-xs font-medium text-muted-foreground", children: "Images" }),
1260
- mediaEditorContext ? /* @__PURE__ */ jsxs(
1261
- "button",
1262
- {
1263
- type: "button",
1264
- className: "mb-2 inline-flex w-full items-center justify-center gap-2 rounded-md border bg-background px-2 py-1.5 text-xs font-medium hover:bg-muted",
1265
- onClick: (event) => {
1266
- event.preventDefault();
1267
- event.stopPropagation();
1268
- setMediaPickerOpenKey((key) => key + 1);
1269
- },
1270
- children: [
1271
- /* @__PURE__ */ jsx(Upload, { size: 13 }),
1272
- "Media library"
1273
- ]
1274
- }
1275
- ) : null,
1276
- images.length ? /* @__PURE__ */ jsx("div", { className: "space-y-1", children: images.map((item) => /* @__PURE__ */ jsx(
1931
+ ] }) : null
1932
+ ] }) : null;
1933
+ const renderGradientOptions = () => capability.gradientIds?.length ? /* @__PURE__ */ jsxs("div", { children: [
1934
+ /* @__PURE__ */ jsx("div", { className: "mb-1 text-xs font-medium text-muted-foreground", children: "Gradients" }),
1935
+ /* @__PURE__ */ jsx("div", { className: "space-y-1", children: capability.gradientIds.map((gradientId) => /* @__PURE__ */ jsx(
1936
+ "button",
1937
+ {
1938
+ type: "button",
1939
+ className: `w-full rounded-md border px-2 py-1 text-left text-xs hover:bg-muted ${current.kind === "gradient" && current.gradientId === gradientId ? "border-foreground" : "bg-background"}`,
1940
+ onClick: chooseFromClick({ kind: "gradient", gradientId }),
1941
+ children: /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-2", children: [
1942
+ /* @__PURE__ */ jsx(
1943
+ "span",
1944
+ {
1945
+ className: "h-4 w-8 shrink-0 rounded border",
1946
+ style: { backgroundImage: gradientPreviewCss(gradientId) }
1947
+ }
1948
+ ),
1949
+ /* @__PURE__ */ jsx("span", { className: "truncate", children: gradientLabel(gradientId) })
1950
+ ] })
1951
+ },
1952
+ gradientId
1953
+ )) })
1954
+ ] }) : null;
1955
+ const renderImageOptions = () => capability.modes.includes("image") ? /* @__PURE__ */ jsxs("div", { children: [
1956
+ /* @__PURE__ */ jsx("div", { className: "mb-1 text-xs font-medium text-muted-foreground", children: "Images" }),
1957
+ mediaEditorContext ? /* @__PURE__ */ jsxs(
1958
+ "button",
1959
+ {
1960
+ type: "button",
1961
+ className: "mb-2 inline-flex w-full items-center justify-center gap-2 rounded-md border bg-background px-2 py-1.5 text-xs font-medium hover:bg-muted",
1962
+ onClick: (event) => {
1963
+ event.preventDefault();
1964
+ event.stopPropagation();
1965
+ setMediaPickerOpenKey((key) => key + 1);
1966
+ },
1967
+ children: [
1968
+ /* @__PURE__ */ jsx(Upload, { size: 13 }),
1969
+ "Media library"
1970
+ ]
1971
+ }
1972
+ ) : null,
1973
+ images.length ? /* @__PURE__ */ jsx("div", { className: "space-y-1", children: images.map((item) => {
1974
+ const thumbnailUrl = backgroundImagePreviewUrl(
1975
+ item,
1976
+ mediaEditorContext
1977
+ );
1978
+ return /* @__PURE__ */ jsx(
1277
1979
  "button",
1278
1980
  {
1279
1981
  type: "button",
1280
1982
  className: `w-full rounded-md border px-2 py-1 text-left text-xs hover:bg-muted ${current.kind === "image" && current.mediaId === item.mediaId ? "border-foreground" : "bg-background"}`,
1281
- onClick: chooseFromClick({ kind: "image", mediaId: item.mediaId }),
1983
+ onClick: chooseFromClick({
1984
+ kind: "image",
1985
+ mediaId: item.mediaId
1986
+ }),
1282
1987
  children: /* @__PURE__ */ jsxs("span", { className: "flex min-w-0 items-center gap-2", children: [
1283
- /* @__PURE__ */ jsx("span", { className: "grid h-7 w-9 shrink-0 place-items-center rounded border bg-muted", children: /* @__PURE__ */ jsx(Image, { size: 14 }) }),
1988
+ /* @__PURE__ */ jsx("span", { className: "grid h-7 w-9 shrink-0 place-items-center overflow-hidden rounded border bg-muted", children: thumbnailUrl ? /* @__PURE__ */ jsx(
1989
+ "img",
1990
+ {
1991
+ alt: "",
1992
+ className: "h-full w-full object-cover",
1993
+ src: thumbnailUrl
1994
+ }
1995
+ ) : /* @__PURE__ */ jsx(Image, { size: 14 }) }),
1284
1996
  /* @__PURE__ */ jsxs("span", { className: "min-w-0", children: [
1285
1997
  /* @__PURE__ */ jsx("span", { className: "block truncate", children: item.label ?? "Image" }),
1286
1998
  /* @__PURE__ */ jsx("span", { className: "text-[11px] text-muted-foreground", children: imageSourceLabel(item.source) })
@@ -1288,25 +2000,51 @@ function BackgroundChooser({
1288
2000
  ] })
1289
2001
  },
1290
2002
  `${item.source}:${item.mediaId}`
1291
- )) }) : /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: imagePoolStatus === "loading" ? "Loading images..." : "No images available yet." }),
1292
- mediaPickerOpenKey > 0 && mediaEditorContext ? /* @__PURE__ */ jsx("div", { onClick: (event) => event.stopPropagation(), children: /* @__PURE__ */ jsx(
1293
- MediaEditor,
1294
- {
1295
- value: void 0,
1296
- onChange: chooseMediaValue,
1297
- allowedKinds: ["image"],
1298
- mediaPickerAutoOpen: true,
1299
- showPreview: false,
1300
- showAltInput: false,
1301
- uploadIntent: { tag: "media-library", allowedRenderUses: ["image"] },
1302
- onUploadComplete: (asset) => {
1303
- onChoose({ kind: "image", mediaId: asset.id });
1304
- setMediaPickerOpenKey(0);
1305
- }
2003
+ );
2004
+ }) }) : /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: imagePoolStatus === "loading" ? "Loading images..." : "No background-ready images yet." }),
2005
+ mediaPickerOpenKey > 0 && mediaEditorContext ? /* @__PURE__ */ jsx("div", { onClick: (event) => event.stopPropagation(), children: /* @__PURE__ */ jsx(
2006
+ MediaEditor,
2007
+ {
2008
+ value: void 0,
2009
+ onChange: chooseMediaValue,
2010
+ allowedKinds: ["image"],
2011
+ mediaPickerAutoOpen: true,
2012
+ mediaPickerPolicy: {
2013
+ assetSelection: backgroundMediaPickerAssetSelection
1306
2014
  },
1307
- mediaPickerOpenKey
1308
- ) }) : null
1309
- ] }) : null
2015
+ showPreview: false,
2016
+ showAltInput: false,
2017
+ uploadIntent: {
2018
+ tag: "media-library",
2019
+ allowedRenderUses: ["image"]
2020
+ },
2021
+ onUploadComplete: (asset) => {
2022
+ if (backgroundMediaPickerAssetSelection(asset).tag === "disabled") {
2023
+ return;
2024
+ }
2025
+ onChoose({ kind: "image", mediaId: asset.id });
2026
+ setMediaPickerOpenKey(0);
2027
+ }
2028
+ },
2029
+ mediaPickerOpenKey
2030
+ ) }) : null
2031
+ ] }) : null;
2032
+ return /* @__PURE__ */ jsxs("div", { className: "mt-2 max-h-80 overflow-y-auto rounded-md border bg-muted/20 p-2", children: [
2033
+ current.kind === "default" ? /* @__PURE__ */ jsxs(
2034
+ "button",
2035
+ {
2036
+ type: "button",
2037
+ className: "flex w-full items-center gap-2 rounded-md border border-foreground bg-background px-2 py-1 text-left text-xs",
2038
+ onClick: chooseFromClick(defaultBackgroundOverrideForMode("default", capability)),
2039
+ children: [
2040
+ /* @__PURE__ */ jsx(BackgroundPreviewSwatch, { override: current, imagePool: images }),
2041
+ /* @__PURE__ */ jsx("span", { children: "Default background" })
2042
+ ]
2043
+ }
2044
+ ) : null,
2045
+ current.kind === "color" ? renderColorOptions() : null,
2046
+ current.kind === "gradient" ? renderGradientOptions() : null,
2047
+ current.kind === "image" ? renderImageOptions() : null
1310
2048
  ] });
1311
2049
  }
1312
2050
  function computeDefaultFocus(blockKind, content) {
@@ -1331,7 +2069,7 @@ function findFirstFieldPath(fields, data, prefix) {
1331
2069
  }
1332
2070
  const nextPrefix = [...prefix, field.id];
1333
2071
  if (field.type === "group") {
1334
- const groupValue = isRecord3(data) ? data[field.id] : void 0;
2072
+ const groupValue = isRecord4(data) ? data[field.id] : void 0;
1335
2073
  const nested = findFirstFieldPath(
1336
2074
  field.schema.fields,
1337
2075
  groupValue,
@@ -1341,7 +2079,7 @@ function findFirstFieldPath(fields, data, prefix) {
1341
2079
  continue;
1342
2080
  }
1343
2081
  if (field.type === "repeater" && field.schema) {
1344
- const collection = isRecord3(data) ? data[field.id] : void 0;
2082
+ const collection = isRecord4(data) ? data[field.id] : void 0;
1345
2083
  const items = isUnknownArray(collection) ? collection : [];
1346
2084
  if (items.length > 0) {
1347
2085
  const firstItem = items[0];
@@ -1402,19 +2140,11 @@ function backgroundOverrideValueLabel(override, imagePool) {
1402
2140
  return imagePool.find((item) => item.mediaId === override.mediaId)?.label ?? "Image";
1403
2141
  }
1404
2142
  }
1405
- function canCycleBackgroundOverrideValue(override, capability) {
1406
- switch (override.kind) {
1407
- case "default":
1408
- return false;
1409
- case "color":
1410
- return (capability.colorTokens?.length ?? 0) > 1;
1411
- case "gradient":
1412
- return (capability.gradientIds?.length ?? 0) > 1;
1413
- case "image":
1414
- return rankBackgroundImagePoolItems(capability.imagePool ?? []).length > 1;
1415
- }
1416
- }
1417
- function BackgroundPreviewSwatch({ override }) {
2143
+ function BackgroundPreviewSwatch({
2144
+ override,
2145
+ imagePool
2146
+ }) {
2147
+ const mediaEditorContext = useMediaEditorOptional();
1418
2148
  const baseClassName = "grid h-6 w-9 shrink-0 place-items-center overflow-hidden rounded-md border";
1419
2149
  switch (override.kind) {
1420
2150
  case "default":
@@ -1436,8 +2166,47 @@ function BackgroundPreviewSwatch({ override }) {
1436
2166
  }
1437
2167
  );
1438
2168
  case "image":
1439
- return /* @__PURE__ */ jsx("span", { className: `${baseClassName} bg-muted`, children: /* @__PURE__ */ jsx(Image, { size: 15 }) });
2169
+ const imageItem = imagePool.find((item) => item.mediaId === override.mediaId);
2170
+ const thumbnailUrl = imageItem ? backgroundImagePreviewUrl(imageItem, mediaEditorContext) : void 0;
2171
+ return /* @__PURE__ */ jsx("span", { className: `${baseClassName} bg-muted`, children: thumbnailUrl ? /* @__PURE__ */ jsx("img", { alt: "", className: "h-full w-full object-cover", src: thumbnailUrl }) : /* @__PURE__ */ jsx(Image, { size: 15 }) });
2172
+ }
2173
+ }
2174
+ function backgroundImagePreviewUrl(item, mediaEditorContext) {
2175
+ const asset = item.mediaAsset;
2176
+ if (!asset) return void 0;
2177
+ return resolveImageUrlWithContext(
2178
+ {
2179
+ type: "image",
2180
+ assetId: asset.id,
2181
+ ...asset.identifier ? { identifier: asset.identifier } : {},
2182
+ storageBucket: asset.storageBucket,
2183
+ storagePath: asset.storagePath,
2184
+ ...asset.width != null ? { width: asset.width } : {},
2185
+ ...asset.height != null ? { height: asset.height } : {},
2186
+ mimeType: asset.mimeType
2187
+ },
2188
+ { width: 72, height: 48, resize: "cover", quality: 70 },
2189
+ mediaEditorContext?.imageResolveContext ?? null
2190
+ );
2191
+ }
2192
+ function backgroundMediaPickerAssetSelection(asset) {
2193
+ if (isMarkedBackgroundAsset(asset)) return { tag: "selectable" };
2194
+ if (asset.width == null || asset.height == null) {
2195
+ return {
2196
+ tag: "disabled",
2197
+ reason: "This image is missing dimensions, so it cannot be checked for background use."
2198
+ };
2199
+ }
2200
+ if (asset.width < SECTION_BACKGROUND_MIN_SOURCE_WIDTH || asset.height < SECTION_BACKGROUND_MIN_SOURCE_HEIGHT) {
2201
+ return {
2202
+ tag: "disabled",
2203
+ reason: `Background images need to be at least ${SECTION_BACKGROUND_MIN_SOURCE_WIDTH}x${SECTION_BACKGROUND_MIN_SOURCE_HEIGHT}. This image is ${asset.width}x${asset.height}.`
2204
+ };
1440
2205
  }
2206
+ return { tag: "selectable" };
2207
+ }
2208
+ function isMarkedBackgroundAsset(asset) {
2209
+ return asset.fileUses?.some((fileUse) => fileUse.tag === "site-background-asset") ?? false;
1441
2210
  }
1442
2211
  function backgroundModeLabel(mode) {
1443
2212
  return mode === "default" ? "Default" : formatVariantLabel(mode);
@@ -1461,7 +2230,9 @@ function tokenSwatchCss(token) {
1461
2230
  return `rgb(var(--tb-${token}))`;
1462
2231
  }
1463
2232
  function gradientPreviewCss(gradientId) {
1464
- const preset = GRADIENT_PRESETS.find((candidate) => candidate.id === gradientId);
2233
+ const preset = GRADIENT_PRESETS.find(
2234
+ (candidate) => candidate.id === gradientId
2235
+ );
1465
2236
  if (!preset) {
1466
2237
  return "linear-gradient(135deg, rgb(var(--tb-primary)), rgb(var(--tb-secondary)))";
1467
2238
  }
@@ -1491,7 +2262,21 @@ function dedupeBackgroundImagePool(items) {
1491
2262
  const seen = /* @__PURE__ */ new Set();
1492
2263
  const deduped = [];
1493
2264
  for (const item of items) {
1494
- if (seen.has(item.mediaId)) continue;
2265
+ if (seen.has(item.mediaId)) {
2266
+ const existingIndex = deduped.findIndex(
2267
+ (candidate) => candidate.mediaId === item.mediaId
2268
+ );
2269
+ const existing = deduped[existingIndex];
2270
+ if (existing && !existing.mediaAsset && item.mediaAsset) {
2271
+ deduped[existingIndex] = {
2272
+ ...existing,
2273
+ mediaAsset: item.mediaAsset,
2274
+ label: existing.label ?? item.label,
2275
+ rank: existing.rank ?? item.rank
2276
+ };
2277
+ }
2278
+ continue;
2279
+ }
1495
2280
  seen.add(item.mediaId);
1496
2281
  deduped.push(item);
1497
2282
  }
@@ -1564,12 +2349,15 @@ function BoundaryControl({
1564
2349
  });
1565
2350
  });
1566
2351
  };
1567
- const applyBoundaryBreak = (direction) => (event) => {
2352
+ const applyBoundaryOption = (boundaryOptionId) => (event) => {
1568
2353
  event.preventDefault();
1569
2354
  event.stopPropagation();
1570
- const action = cyclePageDesignBoundaryBreak(boundary, direction);
1571
- if (!action) return;
1572
- saveBoundaryAction(action);
2355
+ saveBoundaryAction({
2356
+ kind: "set-boundary",
2357
+ previousBlockId: boundary.previousBlockId,
2358
+ nextBlockId: boundary.nextBlockId,
2359
+ boundaryOptionId
2360
+ });
1573
2361
  };
1574
2362
  const resetBoundaryBreak = (event) => {
1575
2363
  event.preventDefault();
@@ -1580,19 +2368,26 @@ function BoundaryControl({
1580
2368
  nextBlockId: boundary.nextBlockId
1581
2369
  });
1582
2370
  };
2371
+ const selectedVariant = sectionTransitionVariantForBoundaryOptionId(
2372
+ boundary.breakChoice.effectiveValue
2373
+ );
2374
+ const selectedFamily = sectionTransitionFamilyForBoundaryOptionId(
2375
+ boundary.breakChoice.effectiveValue
2376
+ ) ?? sectionTransitionFamilies[0];
2377
+ const variantOptions = selectedFamily.variants.length > 1 ? selectedFamily.variants : null;
1583
2378
  return /* @__PURE__ */ jsx("div", { className: "pointer-events-none absolute inset-x-0 top-0 z-20 h-16 -translate-y-1/2", children: /* @__PURE__ */ jsxs("div", { className: "group/boundary relative flex h-full items-center justify-center", children: [
1584
2379
  /* @__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" }),
1585
2380
  /* @__PURE__ */ jsx(
1586
2381
  "button",
1587
2382
  {
1588
2383
  type: "button",
1589
- className: "pointer-events-auto relative z-10 rounded-full border border-white/20 bg-zinc-950/85 px-3 py-1 text-xs font-semibold text-white opacity-0 shadow-lg shadow-zinc-950/25 backdrop-blur transition hover:bg-zinc-900 focus:opacity-100 focus:outline-none focus:ring-2 focus:ring-sky-300 group-hover/boundary:opacity-100 group-focus-within/boundary:opacity-100",
2384
+ 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",
1590
2385
  "aria-controls": open ? panelId : void 0,
1591
2386
  "aria-expanded": open,
1592
2387
  "aria-haspopup": "dialog",
1593
2388
  "aria-label": "Customize section break",
1594
2389
  onClick: openPanel,
1595
- children: "Break"
2390
+ children: /* @__PURE__ */ jsx("span", { className: "rounded-full border border-white/20 bg-zinc-950/85 px-3 py-1 text-xs font-semibold text-white shadow-lg shadow-zinc-950/25 backdrop-blur transition hover:bg-zinc-900", children: "Break" })
1596
2391
  }
1597
2392
  ),
1598
2393
  open ? /* @__PURE__ */ jsxs(
@@ -1629,32 +2424,39 @@ function BoundaryControl({
1629
2424
  }
1630
2425
  )
1631
2426
  ] }),
1632
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-3 rounded-lg border border-slate-200 bg-slate-50 p-2", children: [
1633
- /* @__PURE__ */ jsx(
1634
- "button",
2427
+ /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-slate-200 bg-slate-50 p-2 text-center", children: [
2428
+ /* @__PURE__ */ jsx("div", { className: "truncate text-sm font-medium", children: boundaryBreakLabel(boundary) }),
2429
+ /* @__PURE__ */ jsx("div", { className: "mt-0.5 text-xs text-slate-500", children: boundaryBreakModeLabel(boundary) })
2430
+ ] }),
2431
+ /* @__PURE__ */ jsxs("div", { className: "mt-3", children: [
2432
+ /* @__PURE__ */ jsx("div", { className: "mb-1 text-xs font-medium text-slate-500", children: "Type" }),
2433
+ /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1 rounded-lg border border-slate-200 bg-slate-50 p-1", children: sectionTransitionFamilies.map((family) => /* @__PURE__ */ jsx(
2434
+ SectionTransitionFamilyButton,
1635
2435
  {
1636
- type: "button",
1637
- className: "rounded-md p-2 text-slate-600 transition hover:bg-white hover:text-slate-950 focus:outline-none focus:ring-2 focus:ring-sky-400",
1638
- "aria-label": "Previous section break",
1639
- onClick: applyBoundaryBreak("prev"),
1640
- children: /* @__PURE__ */ jsx(ChevronLeft, { className: "h-4 w-4", "aria-hidden": "true" })
1641
- }
1642
- ),
1643
- /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1 text-center", children: [
1644
- /* @__PURE__ */ jsx("div", { className: "truncate text-sm font-medium", children: boundaryBreakLabel(boundary) }),
1645
- /* @__PURE__ */ jsx("div", { className: "mt-0.5 text-xs text-slate-500", children: boundaryBreakModeLabel(boundary) })
2436
+ family,
2437
+ active: selectedFamily.id === family.id,
2438
+ onClick: applyBoundaryOption(
2439
+ defaultSectionTransitionVariantForFamily(family.id).boundaryOption.id
2440
+ )
2441
+ },
2442
+ family.id
2443
+ )) })
2444
+ ] }),
2445
+ variantOptions ? /* @__PURE__ */ jsxs("div", { className: "mt-3", children: [
2446
+ /* @__PURE__ */ jsxs("div", { className: "mb-1 text-xs font-medium text-slate-500", children: [
2447
+ selectedFamily.label,
2448
+ " style"
1646
2449
  ] }),
1647
- /* @__PURE__ */ jsx(
1648
- "button",
2450
+ /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1 rounded-lg border border-slate-200 bg-slate-50 p-1", children: variantOptions.map((variant) => /* @__PURE__ */ jsx(
2451
+ SectionTransitionVariantButton,
1649
2452
  {
1650
- type: "button",
1651
- className: "rounded-md p-2 text-slate-600 transition hover:bg-white hover:text-slate-950 focus:outline-none focus:ring-2 focus:ring-sky-400",
1652
- "aria-label": "Next section break",
1653
- onClick: applyBoundaryBreak("next"),
1654
- children: /* @__PURE__ */ jsx(ChevronRight, { className: "h-4 w-4", "aria-hidden": "true" })
1655
- }
1656
- )
1657
- ] }),
2453
+ variant,
2454
+ active: selectedVariant?.boundaryOption.id === variant.boundaryOption.id,
2455
+ onClick: applyBoundaryOption(variant.boundaryOption.id)
2456
+ },
2457
+ variant.boundaryOption.id
2458
+ )) })
2459
+ ] }) : null,
1658
2460
  panelStatus ? /* @__PURE__ */ jsx("p", { id: panelStatus.id, className: "mt-2 text-xs text-slate-500", children: panelStatus.text }) : null,
1659
2461
  display.canReset ? /* @__PURE__ */ jsxs(
1660
2462
  "button",
@@ -1675,6 +2477,46 @@ function BoundaryControl({
1675
2477
  ) : null
1676
2478
  ] }) });
1677
2479
  }
2480
+ function SectionTransitionFamilyButton({
2481
+ family,
2482
+ active,
2483
+ onClick
2484
+ }) {
2485
+ return /* @__PURE__ */ jsx(
2486
+ "button",
2487
+ {
2488
+ type: "button",
2489
+ className: sectionTransitionChoiceClassName(active),
2490
+ "aria-pressed": active,
2491
+ "aria-label": `Use ${family.label} section break`,
2492
+ onClick,
2493
+ children: family.label
2494
+ }
2495
+ );
2496
+ }
2497
+ function SectionTransitionVariantButton({
2498
+ variant,
2499
+ active,
2500
+ onClick
2501
+ }) {
2502
+ return /* @__PURE__ */ jsx(
2503
+ "button",
2504
+ {
2505
+ type: "button",
2506
+ className: sectionTransitionChoiceClassName(active),
2507
+ "aria-pressed": active,
2508
+ "aria-label": `Use ${variant.label} section break`,
2509
+ onClick,
2510
+ children: variant.label
2511
+ }
2512
+ );
2513
+ }
2514
+ function sectionTransitionChoiceClassName(active) {
2515
+ return [
2516
+ "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",
2517
+ active ? "bg-slate-950 text-white shadow-sm" : "bg-transparent text-slate-600 hover:bg-white hover:text-slate-950"
2518
+ ].join(" ");
2519
+ }
1678
2520
  function boundaryBreakLabel(boundary) {
1679
2521
  return boundaryBreakDisplay(boundary).label;
1680
2522
  }
@@ -1738,7 +2580,9 @@ function resolveRuntimePreviewSource(input) {
1738
2580
  }
1739
2581
  return { kind: "preserve-server-runtime" };
1740
2582
  }
2583
+ var MAX_PREVIEW_BLOCK_DATA_BATCH_SIZE = 25;
1741
2584
  function EditablePageRenderer(props) {
2585
+ const { blockDataApiClient = null, ...pageRendererProps } = props;
1742
2586
  const { blocks } = useEntryEditorController();
1743
2587
  const uiStore = useEditorUiStoreInstance();
1744
2588
  const { state: pageDesignState } = usePreviewPageDesignEditorState();
@@ -1749,21 +2593,45 @@ function EditablePageRenderer(props) {
1749
2593
  (state) => state.aiOverlays.hasActiveProposals()
1750
2594
  );
1751
2595
  const allowInlineEditing = isEditingMode && !isStreaming && !hasProposals;
1752
- const isEntryTemplatePage = Boolean(props.dataContext?.contentEntry);
1753
- const headerClearancePx = usePreviewHeaderClearance();
2596
+ const isEntryTemplatePage = Boolean(pageRendererProps.dataContext?.contentEntry);
2597
+ const headerClearance = usePreviewHeaderClearance();
1754
2598
  const cacheRef = useRef(/* @__PURE__ */ new Map());
1755
- const draftsVersion = useEditorUiStore((state) => {
2599
+ const renderStateVersion = useEditorUiStore((state) => {
1756
2600
  const snapshots = state.drafts.inspect();
2601
+ const linkedEntries = state.linkedEntries.inspect();
1757
2602
  const overlayRevision = state.aiOverlays.revision;
1758
- return `${snapshots.map((s) => `${s.id}:${s.version}`).join("|")}|overlay:${overlayRevision}`;
2603
+ return [
2604
+ snapshots.map((s) => `${s.id}:${s.version}`).join("|"),
2605
+ linkedEntries.map((entry) => `${entry.meta.entryId}:${entry.version}`).join("|"),
2606
+ `overlay:${overlayRevision}`
2607
+ ].join("|");
1759
2608
  });
2609
+ const linkedEntryOverlays = useMemo(() => {
2610
+ const overlays = /* @__PURE__ */ new Map();
2611
+ for (const linkedEntry of uiStore.getState().linkedEntries.inspect()) {
2612
+ const content = linkedEntry.current ?? linkedEntry.baseline;
2613
+ if (!content) continue;
2614
+ overlays.set(linkedEntry.meta.entryId, {
2615
+ content,
2616
+ optimisticHash: linkedEntry.meta.optimisticHash
2617
+ });
2618
+ }
2619
+ return overlays;
2620
+ }, [uiStore, renderStateVersion]);
2621
+ const linkedEntryDataContext = useMemo(
2622
+ () => applyLinkedEntryRenderOverlayToDataContext(
2623
+ pageRendererProps.dataContext,
2624
+ linkedEntryOverlays
2625
+ ),
2626
+ [linkedEntryOverlays, pageRendererProps.dataContext]
2627
+ );
1760
2628
  const aiProjections = useMemo(
1761
2629
  () => previewProjectionsFromAiOverlays(uiStore.getState().aiOverlays),
1762
- [uiStore, draftsVersion]
2630
+ [uiStore, renderStateVersion]
1763
2631
  );
1764
2632
  const surfaceResolutionContext = useMemo(
1765
- () => hasThemePalette(props.theme) ? surfaceResolutionContextFromTheme(props.theme) : null,
1766
- [props.theme]
2633
+ () => hasThemePalette(pageRendererProps.theme) ? surfaceResolutionContextFromTheme(pageRendererProps.theme) : null,
2634
+ [pageRendererProps.theme]
1767
2635
  );
1768
2636
  const runtimePreviewSource = useMemo(
1769
2637
  () => resolveRuntimePreviewSource({
@@ -1786,19 +2654,34 @@ function EditablePageRenderer(props) {
1786
2654
  const mergedPage = useMemo(() => {
1787
2655
  return composePageFromBlocks(
1788
2656
  {
1789
- page: props.page,
2657
+ page: pageRendererProps.page,
1790
2658
  blockItems,
1791
2659
  uiStore,
1792
2660
  projections: renderProjections
1793
2661
  },
1794
2662
  cacheRef
1795
2663
  );
1796
- }, [blockItems, props.page, renderProjections, uiStore, draftsVersion]);
2664
+ }, [
2665
+ blockItems,
2666
+ pageRendererProps.page,
2667
+ renderProjections,
2668
+ uiStore,
2669
+ renderStateVersion
2670
+ ]);
2671
+ const renderPage = mergedPage ?? pageRendererProps.page;
1797
2672
  const wrapBlockWithProvider = useCallback(
1798
2673
  (blockId, rendered) => {
1799
- const blockIndex = blockItemsForRender.findIndex((b) => b.id === blockId);
1800
- const block = blockIndex >= 0 ? blockItemsForRender[blockIndex] ?? null : null;
1801
- const previousBlock = blockIndex > 0 ? blockItemsForRender[blockIndex - 1] ?? null : null;
2674
+ const renderedBlocks = renderPage?.blocks ?? [];
2675
+ const controllerBlockIndex = blockItemsForRender.findIndex(
2676
+ (b) => b.id === blockId
2677
+ );
2678
+ const renderedBlockIndex = renderedBlocks.findIndex(
2679
+ (b) => b.id === blockId
2680
+ );
2681
+ const blockIndex = controllerBlockIndex >= 0 ? controllerBlockIndex : renderedBlockIndex;
2682
+ const chromeBlocks = controllerBlockIndex >= 0 ? blockItemsForRender : renderedBlocks;
2683
+ const block = blockIndex >= 0 ? chromeBlocks[blockIndex] ?? null : null;
2684
+ const previousBlock = blockIndex > 0 ? chromeBlocks[blockIndex - 1] ?? null : null;
1802
2685
  const canonicalBlockIndex = blockItems.findIndex((b) => b.id === blockId);
1803
2686
  const canonicalPreviousBlock = canonicalBlockIndex > 0 ? blockItems[canonicalBlockIndex - 1] ?? null : null;
1804
2687
  const editorBlockId = unsafeAsEditorBlockId(blockId);
@@ -1839,8 +2722,13 @@ function EditablePageRenderer(props) {
1839
2722
  blockId,
1840
2723
  blockKind: block.kind,
1841
2724
  content,
1842
- theme: props.theme,
1843
- headerClearancePx: shouldClearHeaderForBlock(blockItemsForRender, blockIndex) ? headerClearancePx : 0
2725
+ bookingOfferingPresets: pageRendererProps.dataContext?.bookingOfferingPresets ?? [],
2726
+ theme: pageRendererProps.theme,
2727
+ placement: planBlockToolbarPlacement({
2728
+ blocks: chromeBlocks,
2729
+ blockIndex,
2730
+ headerClearance
2731
+ })
1844
2732
  }
1845
2733
  )
1846
2734
  ] }) : null
@@ -1854,16 +2742,29 @@ function EditablePageRenderer(props) {
1854
2742
  aiProjections,
1855
2743
  blockItems,
1856
2744
  blockItemsForRender,
1857
- headerClearancePx,
2745
+ headerClearance,
2746
+ isEntryTemplatePage,
2747
+ pageRendererProps.theme,
1858
2748
  renderProjections,
2749
+ renderPage?.blocks,
1859
2750
  uiStore
1860
2751
  ]
1861
2752
  );
2753
+ const liveResolvedData = usePreviewBlockResolvedData({
2754
+ page: renderPage,
2755
+ dataContext: linkedEntryDataContext,
2756
+ apiClient: blockDataApiClient
2757
+ });
2758
+ const dataContext = useMemo(
2759
+ () => mergeResolvedDataContext(linkedEntryDataContext, liveResolvedData),
2760
+ [linkedEntryDataContext, liveResolvedData]
2761
+ );
1862
2762
  const rendererProps = {
1863
- ...props,
1864
- page: mergedPage,
1865
- registry: allowInlineEditing ? editorRegistry : props.registry ?? clientComponentRegistry,
1866
- wrapBlock: allowInlineEditing ? wrapBlockWithProvider : props.wrapBlock,
2763
+ ...pageRendererProps,
2764
+ page: renderPage,
2765
+ registry: allowInlineEditing ? editorRegistry : pageRendererProps.registry ?? clientComponentRegistry,
2766
+ wrapBlock: allowInlineEditing ? wrapBlockWithProvider : pageRendererProps.wrapBlock,
2767
+ dataContext,
1867
2768
  // Phase 10: the legacy `isEditingMode` flag forced the renderer into
1868
2769
  // draft-mode validation; `usePlaceholders` consolidates that into a
1869
2770
  // narrowly-scoped fallback. The editor's contract is unchanged: a user
@@ -1875,16 +2776,258 @@ function EditablePageRenderer(props) {
1875
2776
  };
1876
2777
  return /* @__PURE__ */ jsx(PageRenderer, { ...rendererProps });
1877
2778
  }
2779
+ function usePreviewBlockResolvedData(args) {
2780
+ const { page, dataContext, apiClient } = args;
2781
+ const cacheKey = useMemo(() => {
2782
+ if (!apiClient || !dataContext?.siteId) return null;
2783
+ return stableSerialize({
2784
+ siteId: dataContext.siteId,
2785
+ pageId: dataContext.pageId ?? null,
2786
+ previewStage: dataContext.previewStage ?? "published",
2787
+ blocks: page.blocks.map((block) => ({
2788
+ id: block.id,
2789
+ kind: block.kind,
2790
+ content: block.content ?? null,
2791
+ draftContent: block.draftContent ?? null,
2792
+ publishedContent: block.publishedContent ?? null
2793
+ }))
2794
+ });
2795
+ }, [apiClient, dataContext?.pageId, dataContext?.previewStage, dataContext?.siteId, page]);
2796
+ const [resolvedData, setResolvedData] = useState(null);
2797
+ useEffect(() => {
2798
+ if (!apiClient || !dataContext?.siteId || !cacheKey) {
2799
+ setResolvedData(null);
2800
+ return;
2801
+ }
2802
+ let cancelled = false;
2803
+ const context = buildPreviewBlockDataContext(dataContext);
2804
+ const loaderClient = createPreviewBlockDataApiClient(apiClient, context);
2805
+ void prefetchBlockData(page, context, {
2806
+ apiClient: loaderClient,
2807
+ isValidEndpoint: isSupportedLoaderEndpoint,
2808
+ onError: () => {
2809
+ }
2810
+ }).then((data) => {
2811
+ if (!cancelled) setResolvedData({ key: cacheKey, data });
2812
+ }).catch(() => {
2813
+ });
2814
+ return () => {
2815
+ cancelled = true;
2816
+ };
2817
+ }, [apiClient, cacheKey, dataContext, page]);
2818
+ return resolvedData?.data ?? null;
2819
+ }
2820
+ function buildPreviewBlockDataContext(dataContext) {
2821
+ return {
2822
+ siteId: dataContext.siteId,
2823
+ pageId: dataContext.pageId,
2824
+ previewStage: dataContext.previewStage,
2825
+ root: {
2826
+ ...dataContext.routes ? { routes: dataContext.routes } : {},
2827
+ ...dataContext.pagesByIdentifier ? { pagesByIdentifier: dataContext.pagesByIdentifier } : {},
2828
+ ...dataContext.entriesByIdentifier ? { entriesByIdentifier: dataContext.entriesByIdentifier } : {},
2829
+ occurrenceContext: dataContext.occurrenceContext ?? null,
2830
+ entrySubrouteContext: dataContext.entrySubrouteContext ?? null,
2831
+ contentEntry: dataContext.contentEntry ?? null,
2832
+ bookingOfferingPresets: dataContext.bookingOfferingPresets ?? []
2833
+ }
2834
+ };
2835
+ }
2836
+ function mergeResolvedDataContext(dataContext, liveResolvedData) {
2837
+ if (!dataContext || !liveResolvedData) return dataContext;
2838
+ return {
2839
+ ...dataContext,
2840
+ resolvedData: {
2841
+ ...dataContext.resolvedData ?? {},
2842
+ ...liveResolvedData
2843
+ }
2844
+ };
2845
+ }
2846
+ function createPreviewBlockDataApiClient(dashboardApiClient, context) {
2847
+ const batcher = createMicrobatcher({
2848
+ maxBatchSize: MAX_PREVIEW_BLOCK_DATA_BATCH_SIZE,
2849
+ runBatch: async (requests) => {
2850
+ if (!context.siteId) {
2851
+ return requests.reduce((acc, request) => {
2852
+ acc[request.id] = {
2853
+ ok: false,
2854
+ error: { code: "missing_site_id", message: "Missing siteId" }
2855
+ };
2856
+ return acc;
2857
+ }, {});
2858
+ }
2859
+ const envelope = await dashboardApiClient({
2860
+ endpoint: "batchBlockLoaders",
2861
+ params: {
2862
+ siteId: context.siteId,
2863
+ stage: context.previewStage
2864
+ },
2865
+ body: { requests }
2866
+ });
2867
+ const payload = unwrapResponse(envelope);
2868
+ return payload.results;
2869
+ }
2870
+ });
2871
+ return async ({ endpoint, params }) => {
2872
+ if (!isSupportedLoaderEndpoint(endpoint)) {
2873
+ throw new Error(`Unsupported block loader endpoint: ${endpoint}`);
2874
+ }
2875
+ const normalizedParams = normalizePublicApiLoaderParams(endpoint, params, context);
2876
+ if (isBatchableEndpoint(endpoint)) {
2877
+ const batchParams = toBatchParams(endpoint, normalizedParams);
2878
+ const batchKey = `${endpoint}:${stableSerialize(batchParams ?? null)}`;
2879
+ return batcher.getOrEnqueue(
2880
+ batchKey,
2881
+ (id) => buildBatchLoaderRequest(id, endpoint, batchParams)
2882
+ );
2883
+ }
2884
+ return callDirectLoaderApiEndpoint(
2885
+ dashboardApiClient,
2886
+ endpoint,
2887
+ normalizedParams
2888
+ );
2889
+ };
2890
+ }
2891
+ async function callDirectLoaderApiEndpoint(dashboardApiClient, endpoint, params) {
2892
+ switch (endpoint) {
2893
+ case "listPublishedEntries":
2894
+ return unwrapResponse(await dashboardApiClient({
2895
+ endpoint,
2896
+ params
2897
+ }));
2898
+ case "getPublishedEntryPreview":
2899
+ return unwrapResponse(await dashboardApiClient({
2900
+ endpoint,
2901
+ params
2902
+ }));
2903
+ case "listPublicPasses":
2904
+ return unwrapResponse(await dashboardApiClient({
2905
+ endpoint,
2906
+ params
2907
+ }));
2908
+ case "listPublicMemberships":
2909
+ return unwrapResponse(await dashboardApiClient({
2910
+ endpoint,
2911
+ params
2912
+ }));
2913
+ }
2914
+ }
2915
+ function isBatchableEndpoint(endpoint) {
2916
+ return endpoint === "listPublicEvents" || endpoint === "getPublicEventDetails" || endpoint === "listPublicCourses" || endpoint === "listPublicRouteCandidates" || endpoint === "listPublicTeamMembers" || endpoint === "listPublicProducts" || endpoint === "getPublicBookingServices" || endpoint === "getPublicFormById";
2917
+ }
2918
+ function buildBatchLoaderRequest(id, endpoint, params) {
2919
+ switch (endpoint) {
2920
+ case "listPublicEvents": {
2921
+ const typedParams = params;
2922
+ return typedParams ? { id, endpoint, params: typedParams } : { id, endpoint };
2923
+ }
2924
+ case "getPublicEventDetails": {
2925
+ const typedParams = params;
2926
+ return typedParams ? { id, endpoint, params: typedParams } : { id, endpoint };
2927
+ }
2928
+ case "listPublicCourses": {
2929
+ const typedParams = params;
2930
+ return typedParams ? { id, endpoint, params: typedParams } : { id, endpoint };
2931
+ }
2932
+ case "listPublicRouteCandidates":
2933
+ return { id, endpoint };
2934
+ case "listPublicProducts": {
2935
+ const typedParams = params;
2936
+ return typedParams ? { id, endpoint, params: typedParams } : { id, endpoint };
2937
+ }
2938
+ case "listPublicTeamMembers":
2939
+ return { id, endpoint };
2940
+ case "getPublicBookingServices": {
2941
+ const typedParams = params;
2942
+ return typedParams ? { id, endpoint, params: typedParams } : { id, endpoint };
2943
+ }
2944
+ case "getPublicFormById":
2945
+ return {
2946
+ id,
2947
+ endpoint,
2948
+ params: params ?? { formId: "" }
2949
+ };
2950
+ }
2951
+ }
2952
+ function stripUndefined(obj) {
2953
+ const out = {};
2954
+ for (const [key, value] of Object.entries(obj)) {
2955
+ if (value !== void 0) out[key] = value;
2956
+ }
2957
+ return out;
2958
+ }
2959
+ function normalizeIdsParam(ids) {
2960
+ if (!ids) return void 0;
2961
+ const parts = ids.split(",").map((id) => id.trim()).filter(Boolean).sort();
2962
+ return parts.length ? parts.join(",") : void 0;
2963
+ }
2964
+ function toBatchParams(endpoint, params) {
2965
+ if (endpoint === "listPublicEvents") {
2966
+ const p = stripUndefined({
2967
+ limit: params.limit || void 0,
2968
+ from: params.from || void 0,
2969
+ to: params.to || void 0,
2970
+ afterStartsAt: params.afterStartsAt || void 0,
2971
+ afterId: params.afterId || void 0,
2972
+ categoryIds: params.categoryIds || void 0,
2973
+ venueId: params.venueId || void 0,
2974
+ staffMemberId: params.staffMemberId || void 0,
2975
+ kind: params.kind || void 0,
2976
+ eventSurface: params.eventSurface || void 0,
2977
+ eventPresets: params.eventPresets || void 0,
2978
+ scheduleScope: params.scheduleScope || void 0,
2979
+ entryId: params.entryId || void 0,
2980
+ seriesId: params.seriesId || void 0,
2981
+ includeOccurrenceId: params.includeOccurrenceId || void 0,
2982
+ detailLevel: params.detailLevel || void 0,
2983
+ readProfile: params.readProfile || void 0
2984
+ });
2985
+ return Object.keys(p).length ? p : void 0;
2986
+ }
2987
+ if (endpoint === "getPublicEventDetails") {
2988
+ const p = stripUndefined({
2989
+ limit: params.limit || void 0,
2990
+ from: params.from || void 0,
2991
+ to: params.to || void 0,
2992
+ afterStartsAt: params.afterStartsAt || void 0,
2993
+ afterId: params.afterId || void 0,
2994
+ categoryIds: params.categoryIds || void 0,
2995
+ venueId: params.venueId || void 0,
2996
+ staffMemberId: params.staffMemberId || void 0,
2997
+ kind: params.kind || void 0,
2998
+ eventSurface: params.eventSurface || void 0,
2999
+ eventPresets: params.eventPresets || void 0,
3000
+ scheduleScope: params.scheduleScope || void 0,
3001
+ entryId: params.entryId || void 0,
3002
+ seriesId: params.seriesId || void 0,
3003
+ includeOccurrenceId: params.includeOccurrenceId || void 0
3004
+ });
3005
+ return Object.keys(p).length ? p : void 0;
3006
+ }
3007
+ if (endpoint === "listPublicCourses") {
3008
+ const p = stripUndefined({ limit: params.limit || void 0 });
3009
+ return Object.keys(p).length ? p : void 0;
3010
+ }
3011
+ if (endpoint === "listPublicProducts") {
3012
+ const p = stripUndefined({
3013
+ categorySelector: decodePublicProductCategorySelectorQuery(params) ?? void 0
3014
+ });
3015
+ return Object.keys(p).length ? p : void 0;
3016
+ }
3017
+ if (endpoint === "getPublicBookingServices") {
3018
+ const p = stripUndefined({ ids: normalizeIdsParam(params.ids || void 0) });
3019
+ return Object.keys(p).length ? p : void 0;
3020
+ }
3021
+ if (endpoint === "getPublicFormById") {
3022
+ return { formId: params.formId ?? "" };
3023
+ }
3024
+ return void 0;
3025
+ }
1878
3026
  function hasThemePalette(theme) {
1879
3027
  return Boolean(theme?.palette);
1880
3028
  }
1881
- function shouldClearHeaderForBlock(blocks, blockIndex) {
1882
- const block = blocks[blockIndex];
1883
- if (block?.kind !== "block.hero") return false;
1884
- return blocks.slice(0, blockIndex).every((candidate) => candidate.kind === "block.site-header");
1885
- }
1886
3029
  function usePreviewHeaderClearance() {
1887
- const [clearance, setClearance] = useState(0);
3030
+ const [clearance, setClearance] = useState({ kind: "none" });
1888
3031
  useEffect(() => {
1889
3032
  let observedHeader = null;
1890
3033
  let resizeObserver = null;
@@ -1899,12 +3042,19 @@ function usePreviewHeaderClearance() {
1899
3042
  }
1900
3043
  }
1901
3044
  if (!header) {
1902
- setClearance(0);
3045
+ setClearance(
3046
+ (current) => current.kind === "none" ? current : { kind: "none" }
3047
+ );
1903
3048
  return;
1904
3049
  }
1905
3050
  const style = window.getComputedStyle(header);
1906
3051
  const isOverlayHeader = style.position === "fixed" || style.position === "sticky";
1907
- setClearance(isOverlayHeader ? measuredOverlayHeaderClearancePx(header) : 0);
3052
+ const nextClearance = headerClearanceFromPx(
3053
+ isOverlayHeader ? measuredOverlayHeaderClearancePx(header) : 0
3054
+ );
3055
+ setClearance(
3056
+ (current) => headerClearanceEquals(current, nextClearance) ? current : nextClearance
3057
+ );
1908
3058
  };
1909
3059
  update();
1910
3060
  const mutationObserver = new MutationObserver(update);
@@ -1923,6 +3073,15 @@ function usePreviewHeaderClearance() {
1923
3073
  }, []);
1924
3074
  return clearance;
1925
3075
  }
3076
+ function headerClearanceEquals(left, right) {
3077
+ if (left.kind !== right.kind) return false;
3078
+ switch (left.kind) {
3079
+ case "none":
3080
+ return true;
3081
+ case "overlay":
3082
+ return right.kind === "overlay" && left.px === right.px;
3083
+ }
3084
+ }
1926
3085
  function findPreviewOverlayHeader() {
1927
3086
  return document.querySelector(
1928
3087
  ".block-site-header.rb-fixed, .block-site-header.rb-sticky"
@@ -1953,8 +3112,8 @@ function PreviewAuthInit({
1953
3112
  token
1954
3113
  }) {
1955
3114
  const lastInitRef = useRef(null);
1956
- const sessionKey = session ? session.kind === "userSession" ? `${session.kind}:${session.canEdit}:${session.canManage}:${session.expiresAt}` : `${session.kind}:${session.expiresAt}` : "none";
1957
- const currentKey = `${siteId}:${pageId}:${sessionKey}:${token ? "has-token" : "no-token"}`;
3115
+ const sessionKey = session ? session.kind === "userSession" ? `${session.kind}:${session.canEdit}:${session.canManage}:${session.expiresAt ?? "no-expiry"}` : `${session.kind}:${session.expiresAt ?? "no-expiry"}` : "none";
3116
+ const currentKey = `${siteId}:${pageId ?? "no-page"}:${sessionKey}:${token ? "has-token" : "no-token"}`;
1958
3117
  if (lastInitRef.current !== currentKey) {
1959
3118
  initPreviewAuth({
1960
3119
  session,
@@ -2388,25 +3547,25 @@ var INITIAL_ONBOARDING_CONFIRMATION_STATE = {
2388
3547
  resendFeedback: null,
2389
3548
  statusLoadFailed: false
2390
3549
  };
2391
- function isRecord4(value) {
3550
+ function isRecord5(value) {
2392
3551
  return value !== null && typeof value === "object";
2393
3552
  }
2394
3553
  function getErrorMessageFromEnvelope(payload, fallback) {
2395
- const error = isRecord4(payload) ? payload.error : null;
2396
- const message = isRecord4(error) ? error.message : null;
3554
+ const error = isRecord5(payload) ? payload.error : null;
3555
+ const message = isRecord5(error) ? error.message : null;
2397
3556
  return typeof message === "string" && message.trim().length > 0 ? message : fallback;
2398
3557
  }
2399
3558
  function isLaunchReadiness(value) {
2400
- return isRecord4(value) && Array.isArray(value.requirements) && typeof value.pendingRequiredCount === "number" && typeof value.pendingRecommendedCount === "number" && typeof value.pendingOptionalCount === "number" && isRecord4(value.goLiveDecision) && (value.goLiveDecision.kind === "allowed" || value.goLiveDecision.kind === "blocked");
3559
+ return isRecord5(value) && Array.isArray(value.requirements) && typeof value.pendingRequiredCount === "number" && typeof value.pendingRecommendedCount === "number" && typeof value.pendingOptionalCount === "number" && isRecord5(value.goLiveDecision) && (value.goLiveDecision.kind === "allowed" || value.goLiveDecision.kind === "blocked");
2401
3560
  }
2402
3561
  function isOnboardingPreviewStatusResponse(value) {
2403
- return isRecord4(value) && typeof value.dashboardUnlocked === "boolean" && typeof value.requiresEmailConfirmation === "boolean" && isLaunchReadiness(value.launchReadiness);
3562
+ return isRecord5(value) && typeof value.dashboardUnlocked === "boolean" && typeof value.requiresEmailConfirmation === "boolean" && isLaunchReadiness(value.launchReadiness);
2404
3563
  }
2405
3564
  function isResendOnboardingPreviewConfirmationResponse(value) {
2406
- return isRecord4(value) && (value.result === "resent" || value.result === "already_confirmed") && typeof value.dashboardUnlocked === "boolean" && typeof value.requiresEmailConfirmation === "boolean" && isLaunchReadiness(value.launchReadiness);
3565
+ return isRecord5(value) && (value.result === "resent" || value.result === "already_confirmed") && typeof value.dashboardUnlocked === "boolean" && typeof value.requiresEmailConfirmation === "boolean" && isLaunchReadiness(value.launchReadiness);
2407
3566
  }
2408
3567
  function getSuccessData(payload, isData) {
2409
- if (!isRecord4(payload) || payload.success !== true || !isData(payload.data)) {
3568
+ if (!isRecord5(payload) || payload.success !== true || !isData(payload.data)) {
2410
3569
  return null;
2411
3570
  }
2412
3571
  return payload.data;
@@ -2872,313 +4031,6 @@ function PreviewAuthBanner({
2872
4031
  )
2873
4032
  ] });
2874
4033
  }
2875
- var SiteChromeCustomizeContext = createContext(null);
2876
- function SiteChromeCustomizeProvider({
2877
- children,
2878
- siteId,
2879
- apiClient,
2880
- theme,
2881
- themeId = null,
2882
- selectionId = null,
2883
- selectionVersion = null,
2884
- selectionUpdatedAt = null,
2885
- initialSelections,
2886
- headerSelectionContext,
2887
- footerSelectionContext,
2888
- siteStyleAccess = { kind: "hidden" }
2889
- }) {
2890
- const previewDesign = usePreviewDesignCoordinator();
2891
- const { clearPreview, previewTheme } = previewDesign;
2892
- const runnerRef = useRef(createOptimisticActionRunner());
2893
- const saveQueueRef = useRef(Promise.resolve());
2894
- const latestSelectionUpdatedAtRef = useRef(
2895
- initialSelections.selectionUpdatedAt ?? selectionUpdatedAt ?? null
2896
- );
2897
- const initialSelectionVersion = initialSelections.selectionVersion ?? selectionVersion ?? 0;
2898
- const baseSnapshot = useMemo(
2899
- () => resolveStyleConfiguratorInitialSnapshot({
2900
- theme,
2901
- initialSelections: {
2902
- ...initialSelections,
2903
- selectionVersion: initialSelectionVersion,
2904
- selectionUpdatedAt: initialSelections.selectionUpdatedAt ?? selectionUpdatedAt ?? null
2905
- },
2906
- headerSelectionContext,
2907
- footerSelectionContext
2908
- }),
2909
- [footerSelectionContext, headerSelectionContext, initialSelectionVersion, initialSelections, selectionUpdatedAt, theme]
2910
- );
2911
- const [state, setState] = useState(
2912
- () => baseSnapshot ? createStyleConfiguratorState(baseSnapshot) : null
2913
- );
2914
- const stateRef = useRef(state);
2915
- const clearPreviewRef = useRef(clearPreview);
2916
- useEffect(() => {
2917
- stateRef.current = state;
2918
- }, [state]);
2919
- useEffect(() => {
2920
- clearPreviewRef.current = clearPreview;
2921
- }, [clearPreview]);
2922
- useEffect(() => {
2923
- latestSelectionUpdatedAtRef.current = baseSnapshot?.selectionUpdatedAt ?? null;
2924
- }, [baseSnapshot?.selectionUpdatedAt]);
2925
- useEffect(() => {
2926
- if (!baseSnapshot) {
2927
- setState(null);
2928
- return;
2929
- }
2930
- setState(
2931
- (current) => current ? syncStyleConfiguratorState(current, baseSnapshot) : createStyleConfiguratorState(baseSnapshot)
2932
- );
2933
- }, [baseSnapshot]);
2934
- useEffect(() => {
2935
- const runner = runnerRef.current;
2936
- return () => {
2937
- runner.invalidate();
2938
- clearPreviewRef.current("site-chrome");
2939
- };
2940
- }, []);
2941
- const lookModels = useMemo(() => {
2942
- if (!state) return null;
2943
- const siteStyle = getCuratedSiteStyle(state.previewed.siteStyleId);
2944
- if (!siteStyle) return null;
2945
- return buildSiteChromeLookModels({
2946
- state,
2947
- siteStyle,
2948
- headerSelectionContext,
2949
- footerSelectionContext
2950
- });
2951
- }, [footerSelectionContext, headerSelectionContext, state]);
2952
- const applyAllowed = siteStyleAccess.kind === "apply-allowed";
2953
- const getSurfaceState = useCallback(
2954
- (surface) => {
2955
- if (!state || !lookModels) return { kind: "unavailable" };
2956
- if (surface === "header") {
2957
- const currentLayoutId = state.previewed.headerLayoutId;
2958
- const selectedLayout = lookModels.headerLayout.options.find(
2959
- (option) => option.id === currentLayoutId
2960
- );
2961
- const renderedLayout = lookModels.headerLayout.options.find(
2962
- (option) => option.id === lookModels.headerLayout.renderedLayoutId
2963
- );
2964
- const currentId2 = state.previewed.headerStyleId;
2965
- const selected2 = lookModels.headerStyle.options.find(
2966
- (option) => option.id === currentId2
2967
- );
2968
- const rendered2 = lookModels.headerStyle.options.find(
2969
- (option) => option.id === lookModels.headerStyle.renderedStyleId
2970
- );
2971
- return {
2972
- kind: "available",
2973
- surface: "header",
2974
- label: "Header",
2975
- currentLayoutId,
2976
- currentLayoutLabel: selectedLayout?.label ?? (renderedLayout ? `${renderedLayout.label} (default)` : "Unknown Layout"),
2977
- layoutOptions: lookModels.headerLayout.options,
2978
- currentId: currentId2,
2979
- currentLabel: selected2?.label ?? (rendered2 ? `${rendered2.label} (default)` : "Unknown Look"),
2980
- options: lookModels.headerStyle.options,
2981
- diagnostics: [],
2982
- saving: state.saveStatus.kind === "saving",
2983
- failure: state.saveStatus.kind === "failed" ? state.saveStatus.message : null,
2984
- applyAllowed
2985
- };
2986
- }
2987
- const currentId = state.previewed.footerLookId;
2988
- const selected = lookModels.footer.options.find((option) => option.id === currentId);
2989
- const rendered = lookModels.footer.options.find(
2990
- (option) => option.id === lookModels.footer.renderedLookId
2991
- );
2992
- return {
2993
- kind: "available",
2994
- surface: "footer",
2995
- label: "Footer",
2996
- currentId,
2997
- currentLabel: selected?.label ?? (currentId ? "Unknown Look" : `${rendered?.label ?? "Site style"} (default)`),
2998
- options: lookModels.footer.options,
2999
- diagnostics: lookModels.footer.diagnostics,
3000
- saving: state.saveStatus.kind === "saving",
3001
- failure: state.saveStatus.kind === "failed" ? state.saveStatus.message : null,
3002
- applyAllowed
3003
- };
3004
- },
3005
- [applyAllowed, lookModels, state]
3006
- );
3007
- const persistSelection = useCallback(
3008
- (surface, nextSnapshot) => {
3009
- const siteStyle = getCuratedSiteStyle(nextSnapshot.siteStyleId);
3010
- if (!siteStyle) return;
3011
- const compiled = planSiteStylePreviewChange({
3012
- siteStyle,
3013
- selection: nextSnapshot,
3014
- baseTheme: theme,
3015
- headerSelectionContext,
3016
- footerSelectionContext
3017
- });
3018
- void runnerRef.current.run({
3019
- optimistic: () => {
3020
- previewTheme("site-chrome", compiled.themeOverlay, "site-chrome");
3021
- setState((latest) => {
3022
- if (!latest) return latest;
3023
- return markApplySaving({ ...latest, previewed: nextSnapshot });
3024
- });
3025
- },
3026
- network: async () => {
3027
- const runSave = async () => {
3028
- const body = surface === "header" ? {
3029
- surface,
3030
- lookId: nextSnapshot.headerLookId,
3031
- layoutId: nextSnapshot.headerLayoutId,
3032
- styleId: nextSnapshot.headerStyleId,
3033
- theme: compiled.themeOverlay,
3034
- themeId: themeId ?? null,
3035
- selectionId: selectionId ?? null,
3036
- baseSelectionUpdatedAt: latestSelectionUpdatedAtRef.current
3037
- } : {
3038
- surface,
3039
- lookId: nextSnapshot.footerLookId,
3040
- theme: compiled.themeOverlay,
3041
- themeId: themeId ?? null,
3042
- selectionId: selectionId ?? null,
3043
- baseSelectionUpdatedAt: latestSelectionUpdatedAtRef.current
3044
- };
3045
- const response = await apiClient({
3046
- endpoint: "saveSiteChromeLookSelection",
3047
- params: { siteId },
3048
- body
3049
- });
3050
- const saved = unwrapResponse(response);
3051
- latestSelectionUpdatedAtRef.current = saved.selectionUpdatedAt ?? latestSelectionUpdatedAtRef.current;
3052
- return saved;
3053
- };
3054
- const queuedSave = saveQueueRef.current.catch(() => void 0).then(runSave);
3055
- saveQueueRef.current = queuedSave.then(
3056
- () => void 0,
3057
- () => void 0
3058
- );
3059
- return queuedSave;
3060
- },
3061
- onSuccess: (saved) => {
3062
- latestSelectionUpdatedAtRef.current = saved.selectionUpdatedAt ?? latestSelectionUpdatedAtRef.current;
3063
- const persisted = {
3064
- siteStyleId: nextSnapshot.siteStyleId,
3065
- selectionVersion: nextSnapshot.selectionVersion,
3066
- selectionUpdatedAt: saved.selectionUpdatedAt ?? nextSnapshot.selectionUpdatedAt ?? null,
3067
- buttonPersonalityId: compiled.resolvedSelections.buttonPersonalityId,
3068
- paletteVariantId: compiled.resolvedSelections.paletteVariantId,
3069
- paletteOverrides: nextSnapshot.paletteOverrides,
3070
- typographyPresetId: compiled.resolvedSelections.typographyPresetId,
3071
- typographyBodyFontOverride: compiled.resolvedSelections.typographyBodyFontOverride,
3072
- typographyHeadingFontOverride: compiled.resolvedSelections.typographyHeadingFontOverride,
3073
- headerLookId: saved.headerLookId ?? nextSnapshot.headerLookId,
3074
- headerLayoutId: saved.headerLayoutId ?? compiled.resolvedSelections.headerLayoutId,
3075
- headerStyleId: saved.headerStyleId ?? compiled.resolvedSelections.headerStyleId,
3076
- footerLookId: saved.footerLookId ?? nextSnapshot.footerLookId
3077
- };
3078
- setState((latest) => latest ? markApplySaved(latest, persisted) : latest);
3079
- },
3080
- onError: (error) => {
3081
- const message = error instanceof Error ? error.message : "Unable to apply your selection.";
3082
- setState((latest) => latest ? markApplyFailed(latest, message) : latest);
3083
- }
3084
- });
3085
- },
3086
- [
3087
- apiClient,
3088
- footerSelectionContext,
3089
- headerSelectionContext,
3090
- previewTheme,
3091
- selectionId,
3092
- siteId,
3093
- themeId,
3094
- theme
3095
- ]
3096
- );
3097
- const selectHeaderStyle = useCallback(
3098
- (styleId) => {
3099
- if (!applyAllowed) return;
3100
- const current = stateRef.current;
3101
- if (!current) return;
3102
- const nextState = previewHeaderStyle(current, styleId);
3103
- persistSelection("header", nextState.previewed);
3104
- },
3105
- [applyAllowed, persistSelection]
3106
- );
3107
- const selectHeaderLayout = useCallback(
3108
- (layoutId) => {
3109
- if (!applyAllowed) return;
3110
- const current = stateRef.current;
3111
- if (!current) return;
3112
- const nextState = previewHeaderLayout(current, layoutId);
3113
- persistSelection("header", nextState.previewed);
3114
- },
3115
- [applyAllowed, persistSelection]
3116
- );
3117
- const selectFooterLook = useCallback(
3118
- (lookId) => {
3119
- if (!applyAllowed) return;
3120
- const current = stateRef.current;
3121
- if (!current) return;
3122
- const nextState = previewFooterLook(current, planFooterLookSelection(lookId));
3123
- persistSelection("footer", nextState.previewed);
3124
- },
3125
- [applyAllowed, persistSelection]
3126
- );
3127
- const cycleSurfaceLook = useCallback(
3128
- (surface, direction) => {
3129
- const currentState = getSurfaceState(surface);
3130
- if (currentState.kind !== "available") return;
3131
- if (currentState.surface === "header") {
3132
- const next2 = cycleSiteChromeLookId(
3133
- currentState.options,
3134
- currentState.currentId,
3135
- direction
3136
- );
3137
- if (next2 !== void 0 && next2 !== null) selectHeaderStyle(next2);
3138
- return;
3139
- }
3140
- const next = cycleSiteChromeLookId(
3141
- currentState.options,
3142
- currentState.currentId,
3143
- direction
3144
- );
3145
- if (next !== void 0) selectFooterLook(next);
3146
- },
3147
- [getSurfaceState, selectFooterLook, selectHeaderStyle]
3148
- );
3149
- const cycleSurfaceLayout = useCallback(
3150
- (surface, direction) => {
3151
- const currentState = getSurfaceState(surface);
3152
- if (currentState.kind !== "available" || currentState.surface !== "header") {
3153
- return;
3154
- }
3155
- const next = cycleSiteChromeLookId(
3156
- currentState.layoutOptions,
3157
- currentState.currentLayoutId,
3158
- direction
3159
- );
3160
- if (next !== void 0 && next !== null) selectHeaderLayout(next);
3161
- },
3162
- [getSurfaceState, selectHeaderLayout]
3163
- );
3164
- const value = useMemo(
3165
- () => ({
3166
- getSurfaceState,
3167
- cycleSurfaceLook,
3168
- cycleSurfaceLayout
3169
- }),
3170
- [cycleSurfaceLayout, cycleSurfaceLook, getSurfaceState]
3171
- );
3172
- return /* @__PURE__ */ jsx(SiteChromeCustomizeContext.Provider, { value, children });
3173
- }
3174
- function planFooterLookSelection(lookId) {
3175
- const plan = planSiteChromeLookSelection({ surface: "footer", lookId });
3176
- if (plan.kind !== "footer") return lookId;
3177
- return plan.next.footerLookId;
3178
- }
3179
- function useSiteChromeCustomizeOptional() {
3180
- return useContext(SiteChromeCustomizeContext);
3181
- }
3182
4034
 
3183
4035
  // ../blocks/src/client/site-chrome.tsx
3184
4036
  function renderSiteChromeBlock(model, surface, theme, options = {}) {
@@ -3212,26 +4064,12 @@ function SiteChromeCustomizeButton({
3212
4064
  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"
3213
4065
  }) {
3214
4066
  const customize = useSiteChromeCustomizeOptional();
3215
- const customizePanelId = useId();
3216
- const customizeDescriptionId = `${customizePanelId}-description`;
3217
- const [customizeOpen, setCustomizeOpen] = useState(false);
3218
- const customizeButtonRef = useRef(null);
3219
- const closeCustomize = useCallback(() => {
3220
- setCustomizeOpen(false);
3221
- }, []);
3222
- const {
3223
- dialogRef: customizeDialogRef,
3224
- registerInitialFocus: registerCustomizeInitialFocus,
3225
- setReturnFocusTarget: setCustomizeReturnFocusTarget,
3226
- handleDialogKeyDown: handleCustomizeDialogKeyDown
3227
- } = useDialogFocusTrap({
3228
- open: customizeOpen,
3229
- onClose: closeCustomize
3230
- });
4067
+ const popover = useCustomizePopoverController();
3231
4068
  const surfaceState = customize?.getSurfaceState(surface) ?? {
3232
4069
  kind: "unavailable"
3233
4070
  };
3234
4071
  const hasCustomizeControls = surfaceState.kind === "available";
4072
+ const background = surfaceState.kind === "available" ? surfaceState.background : null;
3235
4073
  const cycleableOptionCount = useMemo(() => {
3236
4074
  if (surfaceState.kind !== "available") return 0;
3237
4075
  return surfaceState.options.filter((option) => option.available).length;
@@ -3242,158 +4080,243 @@ function SiteChromeCustomizeButton({
3242
4080
  }
3243
4081
  return surfaceState.layoutOptions.filter((option) => option.available).length;
3244
4082
  }, [surfaceState]);
3245
- const toggleCustomize = (event) => {
4083
+ const controlPlan = useMemo(() => {
4084
+ if (surfaceState.kind !== "available" || !background) {
4085
+ return { cycleRows: [] };
4086
+ }
4087
+ return {
4088
+ cycleRows: [
4089
+ ...surfaceState.surface === "header" ? [
4090
+ {
4091
+ label: "Layout",
4092
+ valueLabel: surfaceState.currentLayoutLabel,
4093
+ previousLabel: `Previous ${surface} Layout`,
4094
+ nextLabel: `Next ${surface} Layout`,
4095
+ availability: cycleAvailabilityFromFlags({
4096
+ canCycle: cycleableLayoutOptionCount > 1,
4097
+ applyAllowed: surfaceState.applyAllowed
4098
+ }),
4099
+ onPrevious: () => customize?.cycleSurfaceLayout(surface, "prev"),
4100
+ onNext: () => customize?.cycleSurfaceLayout(surface, "next")
4101
+ }
4102
+ ] : [],
4103
+ {
4104
+ label: "Look",
4105
+ valueLabel: surfaceState.currentLabel,
4106
+ previousLabel: `Previous ${surface} Look`,
4107
+ nextLabel: `Next ${surface} Look`,
4108
+ availability: cycleAvailabilityFromFlags({
4109
+ canCycle: cycleableOptionCount > 1,
4110
+ applyAllowed: surfaceState.applyAllowed
4111
+ }),
4112
+ onPrevious: () => customize?.cycleSurfaceLook(surface, "prev"),
4113
+ onNext: () => customize?.cycleSurfaceLook(surface, "next")
4114
+ },
4115
+ ...background.available ? [
4116
+ {
4117
+ label: "Background",
4118
+ valueLabel: background.currentLabel,
4119
+ previousLabel: `Previous ${surface} background`,
4120
+ nextLabel: `Next ${surface} background`,
4121
+ availability: cycleAvailabilityFromFlags({
4122
+ canCycle: background.quickTokens.length > 0,
4123
+ applyAllowed: surfaceState.applyAllowed
4124
+ }),
4125
+ onPrevious: () => customize?.cycleSurfaceBackground(surface, "prev"),
4126
+ onNext: () => customize?.cycleSurfaceBackground(surface, "next")
4127
+ }
4128
+ ] : []
4129
+ ]
4130
+ };
4131
+ }, [
4132
+ background,
4133
+ customize,
4134
+ cycleableLayoutOptionCount,
4135
+ cycleableOptionCount,
4136
+ surface,
4137
+ surfaceState
4138
+ ]);
4139
+ return /* @__PURE__ */ jsxs(
4140
+ PreviewChromeFloatingControl,
4141
+ {
4142
+ anchorSelector: "[data-preview-site-chrome-surface]",
4143
+ placement: (anchorBox) => planSiteChromeCustomizePlacement({ surface, anchorBox }),
4144
+ fallbackClassName: containerClassName,
4145
+ forceVisible: popover.open,
4146
+ children: [
4147
+ /* @__PURE__ */ jsx(
4148
+ CustomizePillButton,
4149
+ {
4150
+ buttonRef: popover.buttonRef,
4151
+ ariaLabel: `Customize ${surface}`,
4152
+ open: popover.open,
4153
+ controlsId: popover.panelId,
4154
+ onClick: popover.toggle,
4155
+ disabled: !hasCustomizeControls
4156
+ }
4157
+ ),
4158
+ popover.open && surfaceState.kind === "available" ? /* @__PURE__ */ jsxs(
4159
+ CustomizePopoverShell,
4160
+ {
4161
+ panelId: popover.panelId,
4162
+ descriptionId: popover.descriptionId,
4163
+ dialogLabel: `Customize ${surface}`,
4164
+ eyebrow: "Site",
4165
+ title: surfaceState.label,
4166
+ dialogRef: popover.dialogRef,
4167
+ closeButtonRef: popover.registerInitialFocus,
4168
+ onClose: popover.close,
4169
+ onKeyDown: popover.handleDialogKeyDown,
4170
+ children: [
4171
+ controlPlan.cycleRows.map((row) => /* @__PURE__ */ jsx(CustomizeCycleRow, { ...row }, row.label)),
4172
+ background?.available ? /* @__PURE__ */ jsx(
4173
+ SiteChromeBackgroundPalette,
4174
+ {
4175
+ surface: surfaceState.surface,
4176
+ background,
4177
+ applyAllowed: surfaceState.applyAllowed,
4178
+ onChoose: (override) => customize?.chooseSurfaceBackground(surfaceState.surface, override)
4179
+ }
4180
+ ) : null,
4181
+ surfaceState.surface === "header" ? /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-2 border-t pt-3", children: [
4182
+ /* @__PURE__ */ jsxs("label", { className: "block text-xs font-medium text-muted-foreground", children: [
4183
+ /* @__PURE__ */ jsx("span", { children: "Display" }),
4184
+ /* @__PURE__ */ jsx(
4185
+ "select",
4186
+ {
4187
+ 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",
4188
+ value: surfaceState.brandDisplay,
4189
+ onChange: (event) => {
4190
+ event.stopPropagation();
4191
+ customize?.setHeaderBrandDisplay(
4192
+ event.currentTarget.value
4193
+ );
4194
+ },
4195
+ disabled: !surfaceState.applyAllowed,
4196
+ children: surfaceState.brandDisplayOptions.map((option) => /* @__PURE__ */ jsx(
4197
+ "option",
4198
+ {
4199
+ value: option.value,
4200
+ disabled: option.disabled,
4201
+ children: option.label
4202
+ },
4203
+ option.value
4204
+ ))
4205
+ }
4206
+ )
4207
+ ] }),
4208
+ /* @__PURE__ */ jsxs("label", { className: "block text-xs font-medium text-muted-foreground", children: [
4209
+ /* @__PURE__ */ jsx("span", { children: "Logo size" }),
4210
+ /* @__PURE__ */ jsx(
4211
+ "select",
4212
+ {
4213
+ 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",
4214
+ value: surfaceState.logoSize,
4215
+ onChange: (event) => {
4216
+ event.stopPropagation();
4217
+ customize?.setHeaderLogoSize(
4218
+ event.currentTarget.value
4219
+ );
4220
+ },
4221
+ disabled: !surfaceState.applyAllowed,
4222
+ children: surfaceState.logoSizeOptions.map((option) => /* @__PURE__ */ jsx("option", { value: option.value, children: option.label }, option.value))
4223
+ }
4224
+ )
4225
+ ] })
4226
+ ] }) : null,
4227
+ surfaceState.diagnostics.length > 0 ? /* @__PURE__ */ jsx("ul", { className: "space-y-1 text-xs text-amber-700", children: surfaceState.diagnostics.map((diagnostic) => /* @__PURE__ */ jsx("li", { children: diagnostic }, diagnostic)) }) : null,
4228
+ surfaceState.failure ? /* @__PURE__ */ jsx("p", { className: "text-xs text-red-700", children: surfaceState.failure }) : null,
4229
+ !surfaceState.applyAllowed ? /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: "Preview only - ask an admin to apply." }) : null
4230
+ ]
4231
+ }
4232
+ ) : null
4233
+ ]
4234
+ }
4235
+ );
4236
+ }
4237
+ function SiteChromeBackgroundPalette({
4238
+ surface,
4239
+ background,
4240
+ applyAllowed,
4241
+ onChoose
4242
+ }) {
4243
+ const choose = (override) => (event) => {
3246
4244
  event.preventDefault();
3247
4245
  event.stopPropagation();
3248
- if (!customizeOpen) {
3249
- setCustomizeReturnFocusTarget(
3250
- event.currentTarget instanceof HTMLElement ? event.currentTarget : customizeButtonRef.current
3251
- );
3252
- }
3253
- setCustomizeOpen((open) => !open);
4246
+ onChoose(override);
3254
4247
  };
3255
- return /* @__PURE__ */ jsxs("div", { className: containerClassName, children: [
3256
- /* @__PURE__ */ jsx(
3257
- "button",
3258
- {
3259
- ref: customizeButtonRef,
3260
- type: "button",
3261
- onClick: toggleCustomize,
3262
- className: previewCustomizePillButtonClassName,
3263
- "aria-label": `Customize ${surface}`,
3264
- "aria-expanded": customizeOpen,
3265
- "aria-haspopup": "dialog",
3266
- "aria-controls": customizeOpen ? customizePanelId : void 0,
3267
- disabled: !hasCustomizeControls,
3268
- children: surfaceState.kind === "available" && surfaceState.saving ? "Saving..." : "Customize"
3269
- }
3270
- ),
3271
- customizeOpen && surfaceState.kind === "available" ? /* @__PURE__ */ jsxs(
3272
- "div",
4248
+ return /* @__PURE__ */ jsxs("div", { className: "border-t pt-3", children: [
4249
+ /* @__PURE__ */ jsxs("div", { className: "mb-2 flex items-center justify-between gap-2", children: [
4250
+ /* @__PURE__ */ jsx("div", { className: "text-xs font-medium text-muted-foreground", children: "Background colors" }),
4251
+ /* @__PURE__ */ jsx(
4252
+ "button",
4253
+ {
4254
+ type: "button",
4255
+ className: `rounded-md border px-2 py-1 text-xs hover:bg-muted disabled:cursor-not-allowed disabled:opacity-50 ${background.current.kind === "default" ? "border-foreground" : "bg-background"}`,
4256
+ disabled: !applyAllowed,
4257
+ onClick: choose({ kind: "default" }),
4258
+ children: "Default"
4259
+ }
4260
+ )
4261
+ ] }),
4262
+ /* @__PURE__ */ jsx("div", { className: "grid grid-cols-3 gap-1", children: background.quickTokens.map((token) => /* @__PURE__ */ jsx(
4263
+ BackgroundSwatchButton,
3273
4264
  {
3274
- id: customizePanelId,
3275
- className: "builder-dashboard-chrome-theme fixed inset-x-3 bottom-[calc(var(--builder-editor-chrome-offset,0px)+1rem)] z-[70] rounded-lg border bg-background p-3 text-foreground shadow-xl sm:absolute sm:inset-x-auto sm:bottom-auto sm:right-0 sm:top-9 sm:w-72",
3276
- role: "dialog",
3277
- "aria-modal": "true",
3278
- "aria-label": `Customize ${surface}`,
3279
- "aria-describedby": customizeDescriptionId,
3280
- ref: customizeDialogRef,
3281
- onKeyDown: handleCustomizeDialogKeyDown,
3282
- onClick: (event) => event.stopPropagation(),
3283
- children: [
3284
- /* @__PURE__ */ jsxs("div", { className: "mb-3 flex items-start justify-between gap-3", children: [
3285
- /* @__PURE__ */ jsxs("div", { children: [
3286
- /* @__PURE__ */ jsx("div", { className: "text-xs font-medium uppercase text-muted-foreground", children: "Site" }),
3287
- /* @__PURE__ */ jsx(
3288
- "div",
3289
- {
3290
- id: customizeDescriptionId,
3291
- className: "text-sm font-semibold",
3292
- children: surfaceState.label
3293
- }
3294
- )
3295
- ] }),
3296
- /* @__PURE__ */ jsx(
3297
- "button",
3298
- {
3299
- ref: registerCustomizeInitialFocus,
3300
- type: "button",
3301
- className: "rounded-full px-2 py-1 text-xs text-muted-foreground hover:bg-muted hover:text-foreground",
3302
- onClick: (event) => {
3303
- event.preventDefault();
3304
- event.stopPropagation();
3305
- closeCustomize();
3306
- },
3307
- children: "Close"
3308
- }
3309
- )
3310
- ] }),
3311
- /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
3312
- surfaceState.surface === "header" ? /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2", children: [
3313
- /* @__PURE__ */ jsxs("div", { children: [
3314
- /* @__PURE__ */ jsx("div", { className: "text-sm font-medium", children: "Layout" }),
3315
- /* @__PURE__ */ jsx("div", { className: "text-xs text-muted-foreground", children: surfaceState.currentLayoutLabel })
3316
- ] }),
3317
- /* @__PURE__ */ jsxs("div", { className: "flex shrink-0 items-center overflow-hidden rounded-full border bg-background", children: [
3318
- /* @__PURE__ */ jsx(
3319
- "button",
3320
- {
3321
- type: "button",
3322
- onClick: (event) => {
3323
- event.preventDefault();
3324
- event.stopPropagation();
3325
- customize?.cycleSurfaceLayout(surface, "prev");
3326
- },
3327
- className: "grid h-8 w-8 place-items-center hover:bg-muted disabled:cursor-not-allowed disabled:opacity-50",
3328
- "aria-label": `Previous ${surface} Layout`,
3329
- disabled: surfaceState.saving || !surfaceState.applyAllowed || cycleableLayoutOptionCount <= 1,
3330
- children: /* @__PURE__ */ jsx(ChevronLeft, { size: 14 })
3331
- }
3332
- ),
3333
- /* @__PURE__ */ jsx(
3334
- "button",
3335
- {
3336
- type: "button",
3337
- onClick: (event) => {
3338
- event.preventDefault();
3339
- event.stopPropagation();
3340
- customize?.cycleSurfaceLayout(surface, "next");
3341
- },
3342
- className: "grid h-8 w-8 place-items-center border-l hover:bg-muted disabled:cursor-not-allowed disabled:opacity-50",
3343
- "aria-label": `Next ${surface} Layout`,
3344
- disabled: surfaceState.saving || !surfaceState.applyAllowed || cycleableLayoutOptionCount <= 1,
3345
- children: /* @__PURE__ */ jsx(ChevronRight, { size: 14 })
3346
- }
3347
- )
3348
- ] })
3349
- ] }) : null,
3350
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2", children: [
3351
- /* @__PURE__ */ jsxs("div", { children: [
3352
- /* @__PURE__ */ jsx("div", { className: "text-sm font-medium", children: "Look" }),
3353
- /* @__PURE__ */ jsx("div", { className: "text-xs text-muted-foreground", children: surfaceState.currentLabel })
3354
- ] }),
3355
- /* @__PURE__ */ jsxs("div", { className: "flex shrink-0 items-center overflow-hidden rounded-full border bg-background", children: [
3356
- /* @__PURE__ */ jsx(
3357
- "button",
3358
- {
3359
- type: "button",
3360
- onClick: (event) => {
3361
- event.preventDefault();
3362
- event.stopPropagation();
3363
- customize?.cycleSurfaceLook(surface, "prev");
3364
- },
3365
- className: "grid h-8 w-8 place-items-center hover:bg-muted disabled:cursor-not-allowed disabled:opacity-50",
3366
- "aria-label": `Previous ${surface} Look`,
3367
- disabled: surfaceState.saving || !surfaceState.applyAllowed || cycleableOptionCount <= 1,
3368
- children: /* @__PURE__ */ jsx(ChevronLeft, { size: 14 })
3369
- }
3370
- ),
3371
- /* @__PURE__ */ jsx(
3372
- "button",
3373
- {
3374
- type: "button",
3375
- onClick: (event) => {
3376
- event.preventDefault();
3377
- event.stopPropagation();
3378
- customize?.cycleSurfaceLook(surface, "next");
3379
- },
3380
- className: "grid h-8 w-8 place-items-center border-l hover:bg-muted disabled:cursor-not-allowed disabled:opacity-50",
3381
- "aria-label": `Next ${surface} Look`,
3382
- disabled: surfaceState.saving || !surfaceState.applyAllowed || cycleableOptionCount <= 1,
3383
- children: /* @__PURE__ */ jsx(ChevronRight, { size: 14 })
3384
- }
3385
- )
3386
- ] })
3387
- ] }),
3388
- surfaceState.diagnostics.length > 0 ? /* @__PURE__ */ jsx("ul", { className: "space-y-1 text-xs text-amber-700", children: surfaceState.diagnostics.map((diagnostic) => /* @__PURE__ */ jsx("li", { children: diagnostic }, diagnostic)) }) : null,
3389
- surfaceState.failure ? /* @__PURE__ */ jsx("p", { className: "text-xs text-red-700", children: surfaceState.failure }) : null,
3390
- !surfaceState.applyAllowed ? /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: "Preview only - ask an admin to apply." }) : null
3391
- ] })
3392
- ]
3393
- }
3394
- ) : null
4265
+ token,
4266
+ surface,
4267
+ selected: background.current.kind === "color" && background.current.token === token,
4268
+ disabled: !applyAllowed,
4269
+ onClick: choose({ kind: "color", token })
4270
+ },
4271
+ token
4272
+ )) }),
4273
+ background.advancedTokens.length ? /* @__PURE__ */ jsxs("details", { className: "mt-2", children: [
4274
+ /* @__PURE__ */ jsx("summary", { className: "cursor-pointer text-xs text-muted-foreground", children: "More colors" }),
4275
+ /* @__PURE__ */ jsx("div", { className: "mt-1 grid grid-cols-3 gap-1", children: background.advancedTokens.map((token) => /* @__PURE__ */ jsx(
4276
+ BackgroundSwatchButton,
4277
+ {
4278
+ token,
4279
+ surface,
4280
+ selected: background.current.kind === "color" && background.current.token === token,
4281
+ disabled: !applyAllowed,
4282
+ onClick: choose({ kind: "color", token })
4283
+ },
4284
+ token
4285
+ )) })
4286
+ ] }) : null
3395
4287
  ] });
3396
4288
  }
4289
+ function BackgroundSwatchButton({
4290
+ token,
4291
+ surface,
4292
+ selected,
4293
+ disabled,
4294
+ onClick
4295
+ }) {
4296
+ return /* @__PURE__ */ jsxs(
4297
+ "button",
4298
+ {
4299
+ type: "button",
4300
+ className: `flex min-w-0 items-center gap-2 rounded-md border px-2 py-1 text-left text-xs hover:bg-muted disabled:cursor-not-allowed disabled:opacity-50 ${selected ? "border-foreground" : "bg-background"}`,
4301
+ disabled,
4302
+ "aria-label": `Set ${surface} background to ${token}`,
4303
+ onClick,
4304
+ children: [
4305
+ /* @__PURE__ */ jsx(
4306
+ "span",
4307
+ {
4308
+ className: "h-3 w-3 shrink-0 rounded-full border",
4309
+ style: { backgroundColor: tokenSwatchCss2(token) }
4310
+ }
4311
+ ),
4312
+ /* @__PURE__ */ jsx("span", { className: "truncate", children: formatSiteChromeBackgroundTokenLabel(token) })
4313
+ ]
4314
+ }
4315
+ );
4316
+ }
4317
+ function tokenSwatchCss2(token) {
4318
+ return `rgb(var(--tb-${token}))`;
4319
+ }
3397
4320
  function SiteChromeEditableSurface({
3398
4321
  surface,
3399
4322
  children,
@@ -3410,7 +4333,7 @@ function renderEditableSurface(children, surface, options) {
3410
4333
  const child = childArray.length === 1 ? childArray[0] : null;
3411
4334
  if (isValidElement(child) && child.type !== Fragment$1 && (isHostElement(child) || options.preserveSingleComponentRoot || isEditableSurfaceForwardingElement(child))) {
3412
4335
  return cloneElement(child, {
3413
- className: joinClassNames(child.props.className, "group/site-chrome relative"),
4336
+ className: joinClassNames2(child.props.className, "group/site-chrome relative"),
3414
4337
  "data-preview-site-chrome-surface": surface,
3415
4338
  children: /* @__PURE__ */ jsxs(Fragment, { children: [
3416
4339
  child.props.children,
@@ -3449,7 +4372,7 @@ function isHostElement(child) {
3449
4372
  function isEditableSurfaceForwardingElement(child) {
3450
4373
  return typeof child.type !== "string" && child.type !== Fragment$1 && child.type[EDITABLE_SURFACE_FORWARDING_PROP] === true;
3451
4374
  }
3452
- function joinClassNames(...values) {
4375
+ function joinClassNames2(...values) {
3453
4376
  const className = values.filter(Boolean).join(" ");
3454
4377
  return className.length > 0 ? className : void 0;
3455
4378
  }
@@ -3631,13 +4554,41 @@ function renderPreviewDocument({
3631
4554
  }
3632
4555
  return null;
3633
4556
  }
4557
+ function LinkedEntryEditEventBridge() {
4558
+ const uiStore = useEditorUiStoreInstance();
4559
+ useEffect(() => {
4560
+ const handleLinkedEntryEdit = (event) => {
4561
+ if (!isLinkedEntryEditEvent(event)) return;
4562
+ uiStore.getState().linkedEntries.open(event.detail);
4563
+ };
4564
+ const handleLinkedEntryFieldFocus = (event) => {
4565
+ if (!isLinkedEntryFieldFocusEvent(event)) return;
4566
+ const state = uiStore.getState();
4567
+ if (state.linkedEntries.getSelectedEntryId() !== event.detail.write.entryId) {
4568
+ state.linkedEntries.open(event.detail.target);
4569
+ }
4570
+ state.setActivePreviewField({
4571
+ kind: "linked-entry",
4572
+ entryId: unsafeAsLinkedContentEntryId(event.detail.write.entryId),
4573
+ fieldPath: event.detail.write.fieldPath
4574
+ });
4575
+ };
4576
+ window.addEventListener(LINKED_ENTRY_EDIT_EVENT, handleLinkedEntryEdit);
4577
+ window.addEventListener(LINKED_ENTRY_FIELD_FOCUS_EVENT, handleLinkedEntryFieldFocus);
4578
+ return () => {
4579
+ window.removeEventListener(LINKED_ENTRY_EDIT_EVENT, handleLinkedEntryEdit);
4580
+ window.removeEventListener(LINKED_ENTRY_FIELD_FOCUS_EVENT, handleLinkedEntryFieldFocus);
4581
+ };
4582
+ }, [uiStore]);
4583
+ return null;
4584
+ }
3634
4585
  var previewContainerResponsiveEnabled = process.env.NEXT_PUBLIC_ENABLE_PREVIEW_CONTAINER_RESPONSIVE !== "false";
3635
- var PreviewEditorSidebar = React9.lazy(async () => {
3636
- const mod = await import('./PreviewEditorSidebar-QZG37QIF.mjs');
4586
+ var PreviewEditorSidebar = React10.lazy(async () => {
4587
+ const mod = await import('./PreviewEditorSidebar-LHGK6RIO.mjs');
3637
4588
  return { default: mod.PreviewEditorSidebar };
3638
4589
  });
3639
- var PreviewEditorUI = React9.lazy(async () => {
3640
- const mod = await import('./PreviewEditorUI-AXIKSMZA.mjs');
4590
+ var PreviewEditorUI = React10.lazy(async () => {
4591
+ const mod = await import('./PreviewEditorUI-AXZG2SDC.mjs');
3641
4592
  return { default: mod.PreviewEditorUI };
3642
4593
  });
3643
4594
  var previewPaneContainmentStyle = {
@@ -3682,6 +4633,7 @@ function PreviewShellLayout({
3682
4633
  assistantPanel,
3683
4634
  sdkConfig,
3684
4635
  mediaAssets,
4636
+ bookingOfferingPresets,
3685
4637
  useThemeScope = true,
3686
4638
  siteStyleAccess = { kind: "hidden" }
3687
4639
  }) {
@@ -3853,7 +4805,7 @@ function PreviewShellLayout({
3853
4805
  {
3854
4806
  className: "relative flex h-full min-h-0 flex-col overflow-auto bg-muted/30",
3855
4807
  style: previewPaneContainmentStyle,
3856
- children: /* @__PURE__ */ jsx(
4808
+ children: /* @__PURE__ */ jsx(PreviewChromeLayerProvider, { children: /* @__PURE__ */ jsx(
3857
4809
  PreviewThemedSiteDocument,
3858
4810
  {
3859
4811
  useThemeScope,
@@ -3870,7 +4822,7 @@ function PreviewShellLayout({
3870
4822
  siteChromeRenderModel,
3871
4823
  children
3872
4824
  }
3873
- )
4825
+ ) })
3874
4826
  }
3875
4827
  );
3876
4828
  const rightPane = /* @__PURE__ */ jsx(
@@ -3878,7 +4830,7 @@ function PreviewShellLayout({
3878
4830
  {
3879
4831
  className: `${PREVIEW_CHROME_THEME_CLASS_NAME} flex h-full min-h-0 flex-col overflow-hidden ${surfaceDocument.surfaceClassName ?? ""}`,
3880
4832
  ...getPreviewChromeSurfaceDataProps(surfaceDocument),
3881
- children: /* @__PURE__ */ jsx(React9.Suspense, { fallback: null, children: /* @__PURE__ */ jsx(
4833
+ children: /* @__PURE__ */ jsx(React10.Suspense, { fallback: null, children: /* @__PURE__ */ jsx(
3882
4834
  PreviewEditorSidebar,
3883
4835
  {
3884
4836
  surfaceId,
@@ -3921,6 +4873,7 @@ function PreviewShellLayout({
3921
4873
  entrySubrouteContext: entrySubrouteContext ?? null,
3922
4874
  assistantPanel,
3923
4875
  mediaAssets,
4876
+ bookingOfferingPresets,
3924
4877
  siteStyleAccess,
3925
4878
  viewportMode,
3926
4879
  viewportWidth,
@@ -3933,7 +4886,7 @@ function PreviewShellLayout({
3933
4886
  ) })
3934
4887
  }
3935
4888
  );
3936
- const editorUI = /* @__PURE__ */ jsx(React9.Suspense, { fallback: null, children: /* @__PURE__ */ jsx(
4889
+ const editorUI = /* @__PURE__ */ jsx(React10.Suspense, { fallback: null, children: /* @__PURE__ */ jsx(
3937
4890
  PreviewEditorUI,
3938
4891
  {
3939
4892
  inMaintenanceMode: maintenanceModeEnabled,
@@ -3978,6 +4931,7 @@ function PreviewShellLayout({
3978
4931
  footerSelectionContext: themeSelectionFooterContext,
3979
4932
  siteStyleAccess,
3980
4933
  children: /* @__PURE__ */ jsxs(PreviewBlockCustomizeSelectionProvider, { children: [
4934
+ /* @__PURE__ */ jsx(LinkedEntryEditEventBridge, {}),
3981
4935
  editorUI,
3982
4936
  previewBanner,
3983
4937
  /* @__PURE__ */ jsx("div", { className: "fixed inset-0 overflow-hidden bg-background", children: isOpen ? /* @__PURE__ */ jsx(
@@ -4044,6 +4998,7 @@ function PreviewShell({
4044
4998
  assistantPanel,
4045
4999
  sdkConfig,
4046
5000
  mediaAssets,
5001
+ bookingOfferingPresets,
4047
5002
  supabaseUrl,
4048
5003
  useThemeScope = true,
4049
5004
  designEditorEligibility,
@@ -4077,7 +5032,7 @@ function PreviewShell({
4077
5032
  initialBlocks,
4078
5033
  pageMetadata,
4079
5034
  apiClient,
4080
- children: /* @__PURE__ */ jsx(
5035
+ children: /* @__PURE__ */ jsx(PreviewDesignHistoryOrderProvider, { children: /* @__PURE__ */ jsx(
4081
5036
  PreviewPageDesignEditorStateProvider,
4082
5037
  {
4083
5038
  apiClient,
@@ -4132,6 +5087,7 @@ function PreviewShell({
4132
5087
  assistantPanel,
4133
5088
  sdkConfig: sdkConfig ?? null,
4134
5089
  mediaAssets,
5090
+ bookingOfferingPresets,
4135
5091
  useThemeScope,
4136
5092
  siteStyleAccess,
4137
5093
  children
@@ -4141,7 +5097,7 @@ function PreviewShell({
4141
5097
  }
4142
5098
  )
4143
5099
  }
4144
- )
5100
+ ) })
4145
5101
  }
4146
5102
  ) })
4147
5103
  }
@@ -4156,16 +5112,18 @@ function defaultDesignEditorEligibility(input) {
4156
5112
  }
4157
5113
  return { kind: "unsupported" };
4158
5114
  }
4159
-
4160
- // ../preview-next/src/client/preview/previewSurface.ts
4161
- function resolvePreviewSurfaceIdFromSearch(search) {
4162
- return parseSurfaceId(new URLSearchParams(search).get(PREVIEW_SURFACE_PARAM));
5115
+ function isSdkCustomBlockArray(value) {
5116
+ return Array.isArray(value);
4163
5117
  }
4164
- function resolvePreviewSurfaceId() {
4165
- if (typeof window === "undefined") {
5118
+ function getSdkConfigForBlockPicker(value) {
5119
+ if (!value || typeof value !== "object") {
4166
5120
  return null;
4167
5121
  }
4168
- return resolvePreviewSurfaceIdFromSearch(window.location.search);
5122
+ if (!("customBlocks" in value)) {
5123
+ return {};
5124
+ }
5125
+ const customBlocks = value.customBlocks;
5126
+ return isSdkCustomBlockArray(customBlocks) ? { customBlocks } : {};
4169
5127
  }
4170
5128
  function SdkPreviewModeRuntime(props) {
4171
5129
  const {
@@ -4180,12 +5138,12 @@ function SdkPreviewModeRuntime(props) {
4180
5138
  useThemeScope = true
4181
5139
  } = props;
4182
5140
  const resolvedDashboardBaseUrl = dashboardBaseUrl ?? deriveDashboardBaseUrlFromApiBaseUrl(apiBaseUrl);
4183
- const surfaceId = props.surfaceId ?? resolvePreviewSurfaceId() ?? DEFAULT_SURFACE_ID;
5141
+ const surfaceId = props.surfaceId ?? DEFAULT_SURFACE_ID;
4184
5142
  const theme = content.theme;
4185
5143
  const page = content.page;
4186
5144
  const routeMap = content.routeMap ?? void 0;
4187
- const sdkConfig = content.sdkConfig ?? null;
4188
- const customBlocks = content.customBlocks ?? null;
5145
+ const sdkConfig = getSdkConfigForBlockPicker(content.sdkConfig);
5146
+ const customBlocks = isSdkCustomBlockArray(content.customBlocks) ? content.customBlocks : null;
4189
5147
  const typedBlockOverrides = blockOverrides ?? null;
4190
5148
  const sdkConfigForEditor = useMemo(() => {
4191
5149
  const blocks = customBlocks ?? sdkConfig?.customBlocks ?? void 0;