@riverbankcms/sdk 0.101.0 → 0.103.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 (123) hide show
  1. package/README.md +10 -2
  2. package/dist/{PreviewEditorSidebar-DBpy0KTh.mjs → PreviewEditorSidebar-DkNpCPja.mjs} +430 -74
  3. package/dist/{PreviewEditorUI-Fg6I2R2T.mjs → PreviewEditorUI-DeNKtqk3.mjs} +3 -3
  4. package/dist/{PreviewQueryProvider-BICQLAUF.mjs → PreviewQueryProvider-ZF6TXq5Q.mjs} +1 -1
  5. package/dist/{SdkPreviewModeRuntime-DFQP-Q53.mjs → SdkPreviewModeRuntime-5bCsXK2y.mjs} +694 -329
  6. package/dist/{SiteChromeCustomizeContext-GwZc89KN.mjs → SiteChromeCustomizeContext-CO1sTK_W.mjs} +538 -69
  7. package/dist/_dts/ai/src/contracts/proposals.d.ts +298 -298
  8. package/dist/_dts/ai/src/designer/rfc6902.d.ts +57 -1
  9. package/dist/_dts/ai/src/designer/themePatch.d.ts +16 -6
  10. package/dist/_dts/api/src/bookingVerticals.d.ts +53 -1
  11. package/dist/_dts/api/src/index.d.ts +1 -1
  12. package/dist/_dts/api/src/navigation/contracts.d.ts +6 -6
  13. package/dist/_dts/api/src/siteBanner.d.ts +2 -2
  14. package/dist/_dts/api/src/siteRuntimeEndpoints.d.ts +1 -0
  15. package/dist/_dts/blocks/src/PageRenderer.d.ts +6 -1
  16. package/dist/_dts/blocks/src/bindings/index.d.ts +2 -2
  17. package/dist/_dts/blocks/src/index.d.ts +1 -1
  18. package/dist/_dts/blocks/src/server.d.ts +1 -1
  19. package/dist/_dts/blocks/src/system/blocks/courses/shared/schemas.d.ts +7 -7
  20. package/dist/_dts/blocks/src/system/blocks/events/event-calendar.d.ts +1 -1
  21. package/dist/_dts/blocks/src/system/blocks/events/shared/schemas.d.ts +14 -14
  22. package/dist/_dts/blocks/src/system/blocks/location-map.d.ts +5 -5
  23. package/dist/_dts/blocks/src/system/blocks/media-text.d.ts +227 -227
  24. package/dist/_dts/blocks/src/system/blocks/offerings-preview/model.d.ts +1 -1
  25. package/dist/_dts/blocks/src/system/constants/background.d.ts +1 -1
  26. package/dist/_dts/blocks/src/system/customize/facets.d.ts +2 -2
  27. package/dist/_dts/blocks/src/system/inlineText.d.ts +2 -2
  28. package/dist/_dts/blocks/src/system/manifest/schema.d.ts +177 -177
  29. package/dist/_dts/blocks/src/system/node/schema.d.ts +1 -1
  30. package/dist/_dts/blocks/src/system/runtime/components/runtime-backed-blocks.d.ts +1 -1
  31. package/dist/_dts/blocks/src/system/runtime/nodes/layout.d.ts +1 -0
  32. package/dist/_dts/blocks/src/system/runtime/nodes/shared/contract-schemas.d.ts +7 -7
  33. package/dist/_dts/blocks/src/system/transforms/typed.d.ts +1 -1
  34. package/dist/_dts/content-editor/src/index.d.ts +1 -0
  35. package/dist/_dts/content-model/src/content-types/schema.d.ts +8 -8
  36. package/dist/_dts/core/src/branded.d.ts +4 -0
  37. package/dist/_dts/core/src/person-records.d.ts +6 -1
  38. package/dist/_dts/db/src/generated/supabase/database.types.d.ts +154 -18
  39. package/dist/_dts/db/src/schemas/forms.d.ts +15 -15
  40. package/dist/_dts/media-core/src/identifiers.d.ts +14 -1
  41. package/dist/_dts/preview-next/src/client/blocks/composer/mergeDrafts.d.ts +1 -1
  42. package/dist/_dts/preview-next/src/client/blocks/previewProjection/applyPreviewProjections.d.ts +3 -1
  43. package/dist/_dts/preview-next/src/client/blocks/previewProjection/runtimeContentDecoration.d.ts +2 -2
  44. package/dist/_dts/preview-next/src/client/blocks/previewProjection/types.d.ts +2 -1
  45. package/dist/_dts/preview-next/src/client/preview/CustomizeColorTokenPicker.d.ts +27 -0
  46. package/dist/_dts/preview-next/src/client/preview/PageBlockEditorPanel.d.ts +2 -1
  47. package/dist/_dts/preview-next/src/client/preview/PreviewChromeLayer.d.ts +2 -1
  48. package/dist/_dts/preview-next/src/client/preview/SiteChromeCustomizeContext.d.ts +10 -2
  49. package/dist/_dts/preview-next/src/client/preview/StyleConfigurator.state.d.ts +43 -7
  50. package/dist/_dts/preview-next/src/client/preview/sidebarTabPreference.d.ts +1 -1
  51. package/dist/_dts/preview-next/src/client/preview/siteChromeQuickControlHistoryState.d.ts +16 -1
  52. package/dist/_dts/preview-next/src/client/preview/siteChromeSavePlan.d.ts +3 -2
  53. package/dist/_dts/preview-next/src/client/preview/siteStylePreviewPlanner.d.ts +4 -4
  54. package/dist/_dts/preview-next/src/client/preview/styleConfiguratorApplyPayload.d.ts +1 -1
  55. package/dist/_dts/preview-next/src/client/preview/typographySelectionInput.d.ts +4 -2
  56. package/dist/_dts/sdk/src/config/validation.d.ts +3 -3
  57. package/dist/_dts/sdk/src/contracts/index.d.ts +1 -1
  58. package/dist/_dts/sdk/src/contracts/page.d.ts +2 -0
  59. package/dist/_dts/sdk/src/manifest/passes/pass1-fields.d.ts +10 -10
  60. package/dist/_dts/sdk/src/next/revalidate.d.ts +14 -1
  61. package/dist/_dts/sdk/src/public-api/contracts.d.ts +4 -4
  62. package/dist/_dts/sdk/src/rendering/blocks-page-renderer.d.ts +2 -1
  63. package/dist/_dts/sdk/src/rendering/components/pageShared.d.ts +3 -2
  64. package/dist/_dts/sdk/src/rendering/helpers/loadContent.d.ts +3 -4
  65. package/dist/_dts/sdk/src/rendering/hooks/useContent.d.ts +1 -0
  66. package/dist/_dts/sdk/src/version.d.ts +1 -1
  67. package/dist/_dts/site-commands/src/commands.d.ts +19 -19
  68. package/dist/_dts/theme-core/src/accordions/types.d.ts +3 -3
  69. package/dist/_dts/theme-core/src/buttons/personalities/types.d.ts +3 -3
  70. package/dist/_dts/theme-core/src/buttons/types.d.ts +7 -7
  71. package/dist/_dts/theme-core/src/cards/types.d.ts +6 -6
  72. package/dist/_dts/theme-core/src/generated/containerResponsiveThemeCss.d.ts +1 -1
  73. package/dist/_dts/theme-core/src/inputs/types.d.ts +4 -4
  74. package/dist/_dts/theme-core/src/mock-themes/all.d.ts +150 -144
  75. package/dist/_dts/theme-core/src/navigation/types.d.ts +6 -6
  76. package/dist/_dts/theme-core/src/palette/variants/types.d.ts +5 -5
  77. package/dist/_dts/theme-core/src/schema.d.ts +199 -169
  78. package/dist/_dts/theme-core/src/site-styles/backgroundAppearance.d.ts +2 -2
  79. package/dist/_dts/theme-core/src/site-styles/contentTemplateRuntimeCompiler.d.ts +2 -1
  80. package/dist/_dts/theme-core/src/site-styles/designState.d.ts +28 -26
  81. package/dist/_dts/theme-core/src/site-styles/generatedSchemas.d.ts +2 -2
  82. package/dist/_dts/theme-core/src/site-styles/headerLooks.d.ts +4 -4
  83. package/dist/_dts/theme-core/src/site-styles/index.d.ts +1 -0
  84. package/dist/_dts/theme-core/src/site-styles/previewCompiler.d.ts +9 -2
  85. package/dist/_dts/theme-core/src/site-styles/rawStyleFields.d.ts +3 -3
  86. package/dist/_dts/theme-core/src/site-styles/runtimeCompiler.d.ts +50 -2
  87. package/dist/_dts/theme-core/src/site-styles/sectionTransitions.d.ts +77 -0
  88. package/dist/_dts/theme-core/src/site-styles/siteChromeNavPreferences.d.ts +44 -0
  89. package/dist/_dts/theme-core/src/site-styles/styleTags.d.ts +1 -1
  90. package/dist/_dts/theme-core/src/site-styles/tokenRecipes.d.ts +1 -1
  91. package/dist/_dts/theme-core/src/tokens/themeColorTokens.d.ts +3 -3
  92. package/dist/_dts/ui/src/badge.d.ts +1 -1
  93. package/dist/_dts/ui/src/button.d.ts +1 -1
  94. package/dist/_dts/ui/src/card.d.ts +1 -1
  95. package/dist/_dts/ui/src/toggle.d.ts +2 -2
  96. package/dist/cli/index.mjs +58 -21
  97. package/dist/cli/init-docs/content/workflow-isr-revalidation.md +9 -1
  98. package/dist/client/client.mjs +379 -83
  99. package/dist/client/hooks.mjs +27 -6
  100. package/dist/client/rendering/client.mjs +46 -17
  101. package/dist/client/rendering.mjs +378 -82
  102. package/dist/preview-next/before-render.mjs +1 -1
  103. package/dist/preview-next/client/runtime.mjs +4 -4
  104. package/dist/{previewAuthStore-Da74OL0X.mjs → previewAuthStore-ByPPZqmp.mjs} +1 -0
  105. package/dist/{sdk-runtime-CP6Kwalv.mjs → sdk-runtime-C8whifOy.mjs} +2 -2
  106. package/dist/{separator-BVk7GvGN.mjs → separator-CM2C5Axs.mjs} +1 -1
  107. package/dist/server/components.mjs +357 -77
  108. package/dist/server/config-validation.mjs +26 -6
  109. package/dist/server/config.mjs +26 -6
  110. package/dist/server/data.mjs +26 -6
  111. package/dist/server/index.mjs +2 -2
  112. package/dist/server/next/revalidate.mjs +31 -1
  113. package/dist/server/next.mjs +361 -78
  114. package/dist/server/page-converter.mjs +19 -5
  115. package/dist/server/prebuild.mjs +1 -1
  116. package/dist/server/rendering/server.mjs +359 -77
  117. package/dist/server/rendering.mjs +359 -77
  118. package/dist/server/routing.mjs +40 -9
  119. package/dist/server/server.mjs +29 -7
  120. package/dist/server/theme-bridge.mjs +158 -36
  121. package/dist/server/theme.mjs +3 -0
  122. package/dist/styles/index.css +123 -30
  123. package/package.json +1 -1
@@ -1,8 +1,8 @@
1
1
  "use client";
2
- import { $l as DropdownMenuLabel, $t as listEntryPageContentSlots, A as markApplySaving, Ai as requireEntriesForCuratedChoices, B as setTypographyBodyFontOverride, Bl as CollapsibleTrigger, C as createStyleConfiguratorState, Ci as curatedSiteStyles, Cl as TabsContent, D as isPreviewingChange, Dd as LoaderCircle, Di as evaluateTypographyFontSlot, E as dismissWarnings, Ed as Maximize2, F as previewHeaderStyle, Gi as findPaletteVariant, Gu as assertNever$1, H as styleConfiguratorHistoryEntryForPersistedSelection, Ht as FormRenderer, I as previewPaletteVariant, Ki as paletteVariants, L as previewSiteStyle, M as previewButtonPersonality, Mc as findButtonPersonality, Mi as getFooterLayout, Mt as resolvePageRouteSlug, N as previewFooterLook, Ni as getHeaderLayout, Nt as resolveContentTitle, O as markApplyFailed, Oi as findTypographyPreset, P as previewHeaderLayout, Pi as getHeaderStyle, Q as resolvePreviewSidebarTab, Ql as DropdownMenuItem, R as previewTypographyPreset, Rl as Collapsible, S as clearTypographyFontOverrides, Sl as Tabs, T as dismissNotices, Ti as getCuratedSiteStyle, Tl as TabsTrigger, Tu as unsafeAsEditorBlockId, U as syncStyleConfiguratorState, V as setTypographyHeadingFontOverride, Vt as createManifestValidation, W as toggleRow, Wt as createStoreBackend, Xd as ChevronRight, Xl as DropdownMenu, Yl as Surface, Z as createOptimisticActionRunner, Zd as ChevronLeft, Zl as DropdownMenuContent, _ as usePreviewDesignCoordinator, _t as useEditorUiStore, _u as Button, b as applyResolvedSelections, bl as PopoverTrigger, bu as cn, c as selectionSnapshotFromApplySiteStyleSelectionResponse, d as buildSiteChromeLookModels, dl as Select, dt as useUISelector, eu as DropdownMenuSeparator, f as cycleSiteChromeLookId, fd as Tablet, fl as SelectContent, h as planSiteChromeLookSelection, hd as Smartphone, hl as SelectValue, j as openRow, jc as buttonPersonalities, ji as findFooterLook, jt as deriveRouteMetadataPresentation, k as markApplySaved, ki as typographyPresets, l as planSiteStylePreviewChange, m as planSiteChromeFooterLayoutSelection, ml as SelectTrigger, mt as useEntryController, n as useSiteChromeCustomizeOptional, od as X$1, p as cycleableSiteChromeOptions, pl as SelectItem, qi as paletteOverridesSchema, s as buildApplySiteStyleSelectionBody, tu as DropdownMenuTrigger, u as resolveStyleConfiguratorInitialSnapshot, ut as ContentFieldsForm, vl as Popover, vt as useEditorUiStoreInstance, w as deriveStyleConfiguratorCapabilities, wd as Monitor, wl as TabsList, x as cancelPreview, xl as Input, yl as PopoverContent, z as setPaletteOverrides, zl as CollapsibleContent, zt as ManifestForm } from "./SiteChromeCustomizeContext-GwZc89KN.mjs";
3
- import { d as unwrapResponse, f as getDashboardUrl, r as usePreviewAuth } from "./previewAuthStore-Da74OL0X.mjs";
4
- import { S as isAdapterReferenceKind, T as CalloutDescription, _ as usePreviewBlockCustomizeSelectionOptional, b as previewWidgetOverrides, d as buildPreviewDashboardSetupUrl, f as resolvePreviewDashboardSetupHandoff, g as canInspectSiteStyle, h as canApplySiteStyle, m as resolvePreviewSidebarChromeModel, p as resolvePreviewEditorGuidanceModel, v as useBlockCustomizeControls, w as Callout, x as BlockEditor, y as PreviewFormProvider } from "./SdkPreviewModeRuntime-DFQP-Q53.mjs";
5
- import { t as Separator } from "./separator-BVk7GvGN.mjs";
2
+ import { A as markApplySaving, Al as TabsTrigger, Au as unsafeAsEditorBlockId, B as setPaletteOverrides, Bt as ManifestForm, C as createStyleConfiguratorState, Cl as Popover, D as isPreviewingChange, Di as curatedSiteStyles, Dl as Tabs, E as dismissWarnings, El as Input, F as previewHeaderStyle, Fi as findFooterLook, Gl as CollapsibleTrigger, Gt as createStoreBackend, H as syncStyleConfiguratorState, Ht as createManifestValidation, I as previewPaletteVariant, Ic as buttonPersonalities, Ii as getFooterLayout, L as previewSiteStyle, Lc as findButtonPersonality, Li as getHeaderLayout, M as previewButtonPersonality, Md as LoaderCircle, Mi as findTypographyPreset, Mt as deriveRouteMetadataPresentation, N as previewFooterLook, Ni as typographyPresets, Nt as resolvePageRouteSlug, O as markApplyFailed, Ol as TabsContent, P as previewHeaderLayout, Pi as requireEntriesForCuratedChoices, Pt as resolveContentTitle, Q as resolvePreviewSidebarTab, Qi as paletteOverridesSchema, R as previewTypographyPreset, Ri as getHeaderStyle, S as cancelPreview, Su as Button, T as dismissNotices, Tl as PopoverTrigger, Tu as cn, U as toggleRow, Ul as Collapsible, Ut as FormRenderer, V as styleConfiguratorHistoryEntryForPersistedSelection, W as typographySelectionSnapshotFromFlat, Wl as CollapsibleContent, Xi as findPaletteVariant, Xu as assertNever$1, Z as createOptimisticActionRunner, Zi as paletteVariants, _ as usePreviewDesignCoordinator, _d as Tablet, _l as SelectContent, _t as useEditorUiStore, au as DropdownMenuSeparator, b as applyResolvedSelections, bd as Smartphone, bl as SelectValue, c as selectionSnapshotFromApplySiteStyleSelectionResponse, d as buildSiteChromeLookModels, dd as X$1, dt as useUISelector, en as listEntryPageContentSlots, eu as Surface, f as cycleSiteChromeLookId, gl as Select, h as planSiteChromeLookSelection, iu as DropdownMenuLabel, j as openRow, jd as Maximize2, ji as evaluateTypographyFontSlot, k as markApplySaved, kd as Monitor, ki as getCuratedSiteStyle, kl as TabsList, l as planSiteStylePreviewChange, m as planSiteChromeFooterLayoutSelection, mt as useEntryController, n as useSiteChromeCustomizeOptional, nf as ChevronLeft, ns as assertNever$2, nu as DropdownMenuContent, ou as DropdownMenuTrigger, p as cycleableSiteChromeOptions, ru as DropdownMenuItem, s as buildApplySiteStyleSelectionBody, tf as ChevronRight, tu as DropdownMenu, u as resolveStyleConfiguratorInitialSnapshot, ut as ContentFieldsForm, vl as SelectItem, vt as useEditorUiStoreInstance, w as deriveStyleConfiguratorCapabilities, wl as PopoverContent, x as applyTypographyDraftPatch, yl as SelectTrigger, z as resetTypographyToSaved } from "./SiteChromeCustomizeContext-CO1sTK_W.mjs";
3
+ import { d as unwrapResponse, f as getDashboardUrl, r as usePreviewAuth } from "./previewAuthStore-ByPPZqmp.mjs";
4
+ import { S as isAdapterReferenceKind, T as CalloutDescription, _ as usePreviewBlockCustomizeSelectionOptional, b as previewWidgetOverrides, d as buildPreviewDashboardSetupUrl, f as resolvePreviewDashboardSetupHandoff, g as canInspectSiteStyle, h as canApplySiteStyle, m as resolvePreviewSidebarChromeModel, p as resolvePreviewEditorGuidanceModel, v as useBlockCustomizeControls, w as Callout, x as BlockEditor, y as PreviewFormProvider } from "./SdkPreviewModeRuntime-5bCsXK2y.mjs";
5
+ import { t as Separator } from "./separator-CM2C5Axs.mjs";
6
6
  import React, { forwardRef, useCallback, useEffect, useId, useLayoutEffect, useMemo, useRef, useState, useSyncExternalStore, useTransition } from "react";
7
7
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
8
8
  import { useQuery, useQueryClient } from "@tanstack/react-query";
@@ -1562,12 +1562,13 @@ function formatBlockKindLabel(blockKind) {
1562
1562
  }
1563
1563
  //#endregion
1564
1564
  //#region ../preview-next/src/client/preview/PageBlockEditorPanel.tsx
1565
- function PageBlockEditorPanel({ siteId, pageId, theme, apiClient, bearerToken, supabaseUrl, blockItems, uiStoreForBlockEditor, blockEditorRef, onBlocksChange, metadataPanel, linkedEntrySection, designPanel, sdkConfig, mediaAssets, bookingOfferingPresets, viewportMode, viewportWidth, zoom, onViewportModeChange, onViewportWidthChange, onZoomChange }) {
1565
+ function PageBlockEditorPanel({ siteId, pageId, theme, apiClient, bearerToken, supabaseUrl, blockItems, uiStoreForBlockEditor, blockEditorRef, onBlocksChange, metadataPanel, linkedEntrySection, designPanel, designOpenRequestId = null, sdkConfig, mediaAssets, bookingOfferingPresets, viewportMode, viewportWidth, zoom, onViewportModeChange, onViewportWidthChange, onZoomChange }) {
1566
1566
  const customizeSelection = usePreviewBlockCustomizeSelectionOptional();
1567
1567
  const [designOpen, setDesignOpen] = useState(false);
1568
1568
  const [customizeOpen, setCustomizeOpen] = useState(false);
1569
1569
  const [contentOpen, setContentOpen] = useState(true);
1570
1570
  const [detailsOpen, setDetailsOpen] = useState(false);
1571
+ const designSectionRef = useRef(null);
1571
1572
  const customizeSectionRef = useRef(null);
1572
1573
  const selectionKind = customizeSelection?.selection.kind;
1573
1574
  const selectionRequestId = customizeSelection?.selection.kind === "selected" ? customizeSelection.selection.requestId : 0;
@@ -1594,6 +1595,14 @@ function PageBlockEditorPanel({ siteId, pageId, theme, apiClient, bearerToken, s
1594
1595
  });
1595
1596
  }
1596
1597
  }, [selectionKind, selectionRequestId]);
1598
+ useEffect(() => {
1599
+ if (designOpenRequestId === null) return;
1600
+ setDesignOpen(true);
1601
+ designSectionRef.current?.scrollIntoView({
1602
+ block: "start",
1603
+ behavior: "smooth"
1604
+ });
1605
+ }, [designOpenRequestId]);
1597
1606
  return /* @__PURE__ */ jsxs("div", {
1598
1607
  className: "flex h-full min-h-0 flex-col overflow-hidden",
1599
1608
  children: [/* @__PURE__ */ jsx("div", {
@@ -1627,6 +1636,7 @@ function PageBlockEditorPanel({ siteId, pageId, theme, apiClient, bearerToken, s
1627
1636
  open: designOpen,
1628
1637
  onOpenChange: setDesignOpen,
1629
1638
  children: /* @__PURE__ */ jsxs("div", {
1639
+ ref: designSectionRef,
1630
1640
  className: "border-b",
1631
1641
  children: [/* @__PURE__ */ jsx(CollapsibleTrigger, {
1632
1642
  asChild: true,
@@ -2107,7 +2117,7 @@ function StyleConfigurator({ siteId, apiClient, theme, selectionId, selectionVer
2107
2117
  const router = useRouter();
2108
2118
  const previewDesign = usePreviewDesignCoordinator();
2109
2119
  const siteChromeCustomize = useSiteChromeCustomizeOptional();
2110
- const setSiteStyleStagedPreviewActive = siteChromeCustomize?.siteStyleHistory.setStagedPreviewActive;
2120
+ const setSiteStyleStagedPreviewActive = siteChromeCustomize?.siteStyleHistory?.setStagedPreviewActive;
2111
2121
  const { applyFailed, applyStarted, applySucceeded, clearPreview, previewTheme } = previewDesign;
2112
2122
  const [isRefreshPending, startRefreshTransition] = useTransition();
2113
2123
  const baseSnapshot = useMemo(() => resolveStyleConfiguratorInitialSnapshot({
@@ -2194,7 +2204,7 @@ function StyleConfigurator({ siteId, apiClient, theme, selectionId, selectionVer
2194
2204
  setState((current) => {
2195
2205
  if (!current) return current;
2196
2206
  appliedExpandedRowRequestIdRef.current = expandedRowRequest.id;
2197
- return openRow(current, expandedRowRequest.row === "header" ? "header-layout" : expandedRowRequest.row);
2207
+ return openRow(current, expandedRowForPreviewDesignRow(expandedRowRequest.row));
2198
2208
  });
2199
2209
  }, [expandedRowRequest, hasLoadedState]);
2200
2210
  const handlePreviewSiteStyle = useCallback((siteStyleId) => {
@@ -2212,6 +2222,10 @@ function StyleConfigurator({ siteId, apiClient, theme, selectionId, selectionVer
2212
2222
  });
2213
2223
  return applyResolvedSelections(next, {
2214
2224
  resolved: result.resolvedSelections,
2225
+ ...result.resolvedSelections.typographySelection.kind === "custom" ? { typographySelection: {
2226
+ kind: "custom",
2227
+ typography: result.themeOverlay.typography
2228
+ } } : {},
2215
2229
  warnings: result.warnings
2216
2230
  });
2217
2231
  });
@@ -2264,14 +2278,44 @@ function StyleConfigurator({ siteId, apiClient, theme, selectionId, selectionVer
2264
2278
  const handlePreviewTypographyPreset = useCallback((id) => {
2265
2279
  setState((current) => current ? previewTypographyPreset(current, id) : current);
2266
2280
  }, []);
2267
- const handleBodyFontOverride = useCallback((fontFamily) => {
2268
- setState((current) => current ? setTypographyBodyFontOverride(current, fontFamily) : current);
2269
- }, []);
2270
- const handleHeadingFontOverride = useCallback((fontFamily) => {
2271
- setState((current) => current ? setTypographyHeadingFontOverride(current, fontFamily) : current);
2272
- }, []);
2273
- const handleClearTypographyOverrides = useCallback(() => {
2274
- setState((current) => current ? clearTypographyFontOverrides(current) : current);
2281
+ const patchTypography = useCallback((patch) => {
2282
+ setState((current) => {
2283
+ if (!current) return current;
2284
+ const siteStyle = getCuratedSiteStyle(current.previewed.siteStyleId);
2285
+ if (!siteStyle) return current;
2286
+ return applyTypographyDraftPatch(current, planSiteStylePreviewChange({
2287
+ siteStyle,
2288
+ selection: current.previewed,
2289
+ baseTheme: theme,
2290
+ headerSelectionContext,
2291
+ footerSelectionContext
2292
+ }).themeOverlay.typography, patch);
2293
+ });
2294
+ }, [
2295
+ footerSelectionContext,
2296
+ headerSelectionContext,
2297
+ theme
2298
+ ]);
2299
+ const handleHeadingTypographyChange = useCallback((patch) => {
2300
+ patchTypography({
2301
+ kind: "heading",
2302
+ patch
2303
+ });
2304
+ }, [patchTypography]);
2305
+ const handleBodyTypographyChange = useCallback((patch) => {
2306
+ patchTypography({
2307
+ kind: "body",
2308
+ patch
2309
+ });
2310
+ }, [patchTypography]);
2311
+ const handleTypographyScaleChange = useCallback((scale) => {
2312
+ patchTypography({
2313
+ kind: "scale",
2314
+ scale
2315
+ });
2316
+ }, [patchTypography]);
2317
+ const handleResetTypography = useCallback(() => {
2318
+ setState((current) => current ? resetTypographyToSaved(current) : current);
2275
2319
  }, []);
2276
2320
  const handleTokenOverride = useCallback((role, hex) => {
2277
2321
  setState((current) => {
@@ -2323,9 +2367,10 @@ function StyleConfigurator({ siteId, apiClient, theme, selectionId, selectionVer
2323
2367
  headerLayoutId: compiled.resolvedSelections.headerLayoutId,
2324
2368
  headerStyleId: compiled.resolvedSelections.headerStyleId,
2325
2369
  headerLookId: compiled.resolvedSelections.headerLookId,
2326
- typographyPresetId: compiled.resolvedSelections.typographyPresetId,
2327
- typographyBodyFontOverride: compiled.resolvedSelections.typographyBodyFontOverride,
2328
- typographyHeadingFontOverride: compiled.resolvedSelections.typographyHeadingFontOverride
2370
+ typographySelection: compiled.resolvedSelections.typographySelection.kind === "custom" ? {
2371
+ kind: "custom",
2372
+ typography: compiled.themeOverlay.typography
2373
+ } : typographySelectionSnapshotFromFlat(compiled.resolvedSelections)
2329
2374
  },
2330
2375
  selectionId
2331
2376
  });
@@ -2345,7 +2390,7 @@ function StyleConfigurator({ siteId, apiClient, theme, selectionId, selectionVer
2345
2390
  const persisted = selectionSnapshotFromApplySiteStyleSelectionResponse(saved, previewed);
2346
2391
  const historyEntry = styleConfiguratorHistoryEntryForPersistedSelection(live, persisted);
2347
2392
  setState((current) => current ? markApplySaved(current, persisted) : current);
2348
- if (historyEntry) siteChromeCustomize?.siteStyleHistory.recordAppliedSelection(historyEntry);
2393
+ if (historyEntry) siteChromeCustomize?.siteStyleHistory?.recordAppliedSelection(historyEntry);
2349
2394
  applySucceeded("style-configurator");
2350
2395
  startRefreshTransition(() => {
2351
2396
  router.refresh();
@@ -2390,7 +2435,14 @@ function StyleConfigurator({ siteId, apiClient, theme, selectionId, selectionVer
2390
2435
  });
2391
2436
  const currentPersonality = findButtonPersonality(state.previewed.buttonPersonalityId);
2392
2437
  const currentPaletteVariant = findPaletteVariant(state.previewed.paletteVariantId);
2393
- const currentTypographyPreset = state.previewed.typographyPresetId ? findTypographyPreset(state.previewed.typographyPresetId) : null;
2438
+ const currentTypographyPreset = state.previewed.typographySelection.kind === "preset" && state.previewed.typographySelection.presetId ? findTypographyPreset(state.previewed.typographySelection.presetId) : null;
2439
+ const currentTypography = planSiteStylePreviewChange({
2440
+ siteStyle: currentSiteStyle,
2441
+ selection: state.previewed,
2442
+ baseTheme: theme,
2443
+ headerSelectionContext,
2444
+ footerSelectionContext
2445
+ }).themeOverlay.typography;
2394
2446
  const chromeLookModels = buildSiteChromeLookModels({
2395
2447
  state,
2396
2448
  siteStyle: currentSiteStyle,
@@ -2401,6 +2453,7 @@ function StyleConfigurator({ siteId, apiClient, theme, selectionId, selectionVer
2401
2453
  const currentHeaderStyle = getHeaderStyle(state.previewed.headerStyleId);
2402
2454
  const currentFooterLayout = getFooterLayout(chromeLookModels.footerLayout.renderedLayoutId);
2403
2455
  const currentFooterLook = state.previewed.footerLookId ? findFooterLook(state.previewed.footerLookId) : findFooterLook(chromeLookModels.footer.renderedLookId);
2456
+ const headerSurfaceState = siteChromeCustomize?.getSurfaceState("header") ?? { kind: "unavailable" };
2404
2457
  return /* @__PURE__ */ jsxs("div", {
2405
2458
  className: "space-y-3",
2406
2459
  children: [
@@ -2453,7 +2506,13 @@ function StyleConfigurator({ siteId, apiClient, theme, selectionId, selectionVer
2453
2506
  if (next !== void 0) handlePreviewHeaderStyle(next);
2454
2507
  },
2455
2508
  onPreview: handlePreviewHeaderStyle,
2456
- disabled: saving
2509
+ disabled: saving,
2510
+ extraControls: isHeaderMenuSurfaceState(headerSurfaceState) ? /* @__PURE__ */ jsx(HeaderMenuControls, {
2511
+ state: headerSurfaceState,
2512
+ disabled: saving,
2513
+ onMenuFontChange: siteChromeCustomize?.setHeaderMenuFont,
2514
+ onMenuFontSizeChange: siteChromeCustomize?.setHeaderMenuFontSize
2515
+ }) : null
2457
2516
  }),
2458
2517
  /* @__PURE__ */ jsx(SiteChromeLookRow, {
2459
2518
  label: "Footer layout",
@@ -2505,14 +2564,14 @@ function StyleConfigurator({ siteId, apiClient, theme, selectionId, selectionVer
2505
2564
  onToggle: () => handleToggleRow("typography"),
2506
2565
  apiClient,
2507
2566
  siteStyle: currentSiteStyle,
2508
- currentPresetId: state.previewed.typographyPresetId,
2567
+ typography: currentTypography,
2568
+ currentPresetId: state.previewed.typographySelection.kind === "preset" ? state.previewed.typographySelection.presetId : null,
2509
2569
  currentLabel: currentTypographyPreset?.name ?? "Custom typography",
2510
- bodyFontOverride: state.previewed.typographyBodyFontOverride,
2511
- headingFontOverride: state.previewed.typographyHeadingFontOverride,
2512
2570
  onPreviewPreset: handlePreviewTypographyPreset,
2513
- onBodyFontOverride: handleBodyFontOverride,
2514
- onHeadingFontOverride: handleHeadingFontOverride,
2515
- onClearOverrides: handleClearTypographyOverrides,
2571
+ onHeadingChange: handleHeadingTypographyChange,
2572
+ onBodyChange: handleBodyTypographyChange,
2573
+ onScaleChange: handleTypographyScaleChange,
2574
+ onReset: handleResetTypography,
2516
2575
  disabled: saving
2517
2576
  }),
2518
2577
  /* @__PURE__ */ jsx(PaletteRow, {
@@ -2643,21 +2702,25 @@ function PersonalityRow({ expanded, onToggle, siteStyle, currentId, currentLabel
2643
2702
  })
2644
2703
  });
2645
2704
  }
2646
- function TypographyRow({ expanded, onToggle, apiClient, siteStyle, currentPresetId, currentLabel, bodyFontOverride, headingFontOverride, onPreviewPreset, onBodyFontOverride, onHeadingFontOverride, onClearOverrides, disabled }) {
2705
+ function TypographyRow({ expanded, onToggle, apiClient, siteStyle, typography, currentPresetId, currentLabel, onPreviewPreset, onHeadingChange, onBodyChange, onScaleChange, onReset, disabled }) {
2706
+ const [headingOpen, setHeadingOpen] = useState(true);
2707
+ const [bodyOpen, setBodyOpen] = useState(false);
2647
2708
  const options = useMemo(() => requireEntriesForCuratedChoices(typographyPresets, siteStyle.typographyPresetChoices), [siteStyle.typographyPresetChoices]);
2648
2709
  const fontCatalog = useFontCatalog(apiClient, expanded);
2649
- const selectedPreset = currentPresetId ? findTypographyPreset(currentPresetId) : null;
2710
+ const fontPolicyPreset = (currentPresetId ? findTypographyPreset(currentPresetId) : null) ?? options[0] ?? typographyPresets[0];
2711
+ if (!fontPolicyPreset) return null;
2650
2712
  return /* @__PURE__ */ jsxs(StyleRowFrame, {
2651
2713
  label: "Typography",
2652
2714
  currentLabel,
2653
2715
  expanded,
2654
2716
  onToggle,
2655
- children: [
2656
- currentPresetId === null ? /* @__PURE__ */ jsx("div", {
2657
- className: "mb-3 rounded-md border border-muted-foreground/20 bg-muted/30 px-3 py-2 text-xs text-muted-foreground",
2658
- children: "Current custom setup"
2659
- }) : null,
2660
- /* @__PURE__ */ jsx("ul", {
2717
+ children: [/* @__PURE__ */ jsxs("section", {
2718
+ "aria-label": "Start from preset",
2719
+ className: "space-y-2",
2720
+ children: [/* @__PURE__ */ jsx("div", {
2721
+ className: "text-xs font-medium text-muted-foreground",
2722
+ children: "Start from preset"
2723
+ }), /* @__PURE__ */ jsx("ul", {
2661
2724
  role: "radiogroup",
2662
2725
  "aria-label": "Typography preset",
2663
2726
  className: "space-y-1",
@@ -2667,40 +2730,262 @@ function TypographyRow({ expanded, onToggle, apiClient, siteStyle, currentPreset
2667
2730
  onSelect: () => onPreviewPreset(preset.id),
2668
2731
  disabled
2669
2732
  }, preset.id))
2670
- }),
2671
- /* @__PURE__ */ jsxs("div", {
2672
- className: "mt-3 space-y-3 border-t pt-3",
2673
- children: [selectedPreset ? /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(TypographyFontSlotPicker, {
2674
- label: "Body font",
2675
- slot: "body",
2676
- preset: selectedPreset,
2677
- catalog: fontCatalog,
2678
- value: bodyFontOverride,
2679
- onChange: onBodyFontOverride,
2680
- disabled
2681
- }), /* @__PURE__ */ jsx(TypographyFontSlotPicker, {
2682
- label: "Heading font",
2683
- slot: "heading",
2684
- preset: selectedPreset,
2685
- catalog: fontCatalog,
2686
- value: headingFontOverride,
2687
- onChange: onHeadingFontOverride,
2688
- disabled
2689
- })] }) : /* @__PURE__ */ jsx("p", {
2690
- className: "text-xs text-muted-foreground",
2691
- children: "Choose a typography preset to use curated font overrides."
2692
- }), /* @__PURE__ */ jsx(Button, {
2733
+ })]
2734
+ }), /* @__PURE__ */ jsxs("div", {
2735
+ className: "mt-3 space-y-2 border-t pt-3",
2736
+ children: [
2737
+ /* @__PURE__ */ jsxs(TypographyDisclosure, {
2738
+ label: "Heading",
2739
+ open: headingOpen,
2740
+ onOpenChange: setHeadingOpen,
2741
+ children: [
2742
+ /* @__PURE__ */ jsx(TypographyFontSlotPicker, {
2743
+ label: "Heading font",
2744
+ slot: "heading",
2745
+ preset: fontPolicyPreset,
2746
+ catalog: fontCatalog,
2747
+ value: typography.headings.default.family,
2748
+ onChange: (family) => onHeadingChange({ family }),
2749
+ disabled
2750
+ }),
2751
+ /* @__PURE__ */ jsx(TypographySelectControl, {
2752
+ label: "Weight",
2753
+ value: typography.headings.default.weight,
2754
+ options: typographyWeightOptions,
2755
+ onChange: (weight) => onHeadingChange({ weight }),
2756
+ disabled
2757
+ }),
2758
+ /* @__PURE__ */ jsx(TypographySelectControl, {
2759
+ label: "Line height",
2760
+ value: typography.headings.default.lineHeight,
2761
+ options: typographyLineHeightOptions,
2762
+ onChange: (lineHeight) => onHeadingChange({ lineHeight }),
2763
+ disabled
2764
+ }),
2765
+ /* @__PURE__ */ jsx(TypographySelectControl, {
2766
+ label: "Scale",
2767
+ value: normalizeTypographyScaleForControl(typography.scale),
2768
+ options: typographyScaleOptions,
2769
+ onChange: onScaleChange,
2770
+ disabled
2771
+ }),
2772
+ /* @__PURE__ */ jsx(TypographyColorTokenControl, {
2773
+ value: typography.headings.default.colorToken ?? "text",
2774
+ onChange: (colorToken) => onHeadingChange({ colorToken: colorToken === "text" ? null : colorToken }),
2775
+ disabled
2776
+ })
2777
+ ]
2778
+ }),
2779
+ /* @__PURE__ */ jsxs(TypographyDisclosure, {
2780
+ label: "Body",
2781
+ open: bodyOpen,
2782
+ onOpenChange: setBodyOpen,
2783
+ children: [
2784
+ /* @__PURE__ */ jsx(TypographyFontSlotPicker, {
2785
+ label: "Body font",
2786
+ slot: "body",
2787
+ preset: fontPolicyPreset,
2788
+ catalog: fontCatalog,
2789
+ value: typography.body.family,
2790
+ onChange: (family) => onBodyChange({ family }),
2791
+ disabled
2792
+ }),
2793
+ /* @__PURE__ */ jsx(TypographySelectControl, {
2794
+ label: "Size",
2795
+ value: typography.body.size,
2796
+ options: bodySizeOptions,
2797
+ onChange: (size) => onBodyChange({ size }),
2798
+ disabled
2799
+ }),
2800
+ /* @__PURE__ */ jsx(TypographySelectControl, {
2801
+ label: "Weight",
2802
+ value: typography.body.weight,
2803
+ options: typographyWeightOptions,
2804
+ onChange: (weight) => onBodyChange({ weight }),
2805
+ disabled
2806
+ }),
2807
+ /* @__PURE__ */ jsx(TypographySelectControl, {
2808
+ label: "Line height",
2809
+ value: typography.body.lineHeight,
2810
+ options: typographyLineHeightOptions,
2811
+ onChange: (lineHeight) => onBodyChange({ lineHeight }),
2812
+ disabled
2813
+ })
2814
+ ]
2815
+ }),
2816
+ /* @__PURE__ */ jsx(Button, {
2693
2817
  type: "button",
2694
2818
  size: "sm",
2695
2819
  variant: "outline",
2696
- onClick: onClearOverrides,
2697
- disabled: disabled || !bodyFontOverride && !headingFontOverride,
2698
- children: "Use preset fonts"
2699
- })]
2700
- })
2701
- ]
2820
+ onClick: onReset,
2821
+ disabled,
2822
+ children: "Reset typography"
2823
+ })
2824
+ ]
2825
+ })]
2826
+ });
2827
+ }
2828
+ const typographyWeightOptions = [
2829
+ {
2830
+ value: "light",
2831
+ label: "Light"
2832
+ },
2833
+ {
2834
+ value: "regular",
2835
+ label: "Regular"
2836
+ },
2837
+ {
2838
+ value: "medium",
2839
+ label: "Medium"
2840
+ },
2841
+ {
2842
+ value: "semibold",
2843
+ label: "Semibold"
2844
+ },
2845
+ {
2846
+ value: "bold",
2847
+ label: "Bold"
2848
+ }
2849
+ ];
2850
+ const typographyLineHeightOptions = [
2851
+ {
2852
+ value: "normal",
2853
+ label: "Normal"
2854
+ },
2855
+ {
2856
+ value: "relaxed",
2857
+ label: "Relaxed"
2858
+ },
2859
+ {
2860
+ value: "loose",
2861
+ label: "Loose"
2862
+ }
2863
+ ];
2864
+ const bodySizeOptions = [
2865
+ {
2866
+ value: "md",
2867
+ label: "Medium"
2868
+ },
2869
+ {
2870
+ value: "lg",
2871
+ label: "Large"
2872
+ },
2873
+ {
2874
+ value: "xl",
2875
+ label: "Extra large"
2876
+ }
2877
+ ];
2878
+ const typographyScaleOptions = [
2879
+ {
2880
+ value: "compact",
2881
+ label: "Compact"
2882
+ },
2883
+ {
2884
+ value: "balanced",
2885
+ label: "Balanced"
2886
+ },
2887
+ {
2888
+ value: "spacious",
2889
+ label: "Spacious"
2890
+ }
2891
+ ];
2892
+ const headingColorTokenOptions = [
2893
+ {
2894
+ value: "text",
2895
+ label: "Text"
2896
+ },
2897
+ {
2898
+ value: "primary",
2899
+ label: "Primary"
2900
+ },
2901
+ {
2902
+ value: "secondary",
2903
+ label: "Secondary"
2904
+ },
2905
+ {
2906
+ value: "accent",
2907
+ label: "Accent"
2908
+ }
2909
+ ];
2910
+ function TypographyDisclosure({ label, open, onOpenChange, children }) {
2911
+ return /* @__PURE__ */ jsx(Collapsible, {
2912
+ open,
2913
+ onOpenChange,
2914
+ children: /* @__PURE__ */ jsxs("div", {
2915
+ className: "rounded-md border bg-muted/10",
2916
+ children: [/* @__PURE__ */ jsx(CollapsibleTrigger, {
2917
+ asChild: true,
2918
+ children: /* @__PURE__ */ jsxs("button", {
2919
+ type: "button",
2920
+ className: "flex w-full items-center gap-2 px-3 py-2 text-left text-sm font-medium hover:bg-accent/30",
2921
+ "aria-expanded": open,
2922
+ children: [/* @__PURE__ */ jsx(ChevronRight, {
2923
+ className: cn("h-4 w-4 transition", open && "rotate-90"),
2924
+ "aria-hidden": "true"
2925
+ }), /* @__PURE__ */ jsx("span", { children: label })]
2926
+ })
2927
+ }), /* @__PURE__ */ jsx(CollapsibleContent, { children: /* @__PURE__ */ jsx("div", {
2928
+ className: "space-y-3 border-t px-3 py-3",
2929
+ children
2930
+ }) })]
2931
+ })
2702
2932
  });
2703
2933
  }
2934
+ function TypographySelectControl({ label, value, options, onChange, disabled }) {
2935
+ return /* @__PURE__ */ jsxs("label", {
2936
+ className: "block space-y-1",
2937
+ children: [/* @__PURE__ */ jsx("span", {
2938
+ className: "text-xs font-medium text-muted-foreground",
2939
+ children: label
2940
+ }), /* @__PURE__ */ jsx("select", {
2941
+ value,
2942
+ onChange: (event) => onChange(event.currentTarget.value),
2943
+ disabled,
2944
+ className: "h-8 w-full rounded-md border bg-background px-2 text-sm outline-none focus:border-primary disabled:cursor-not-allowed disabled:opacity-50",
2945
+ children: options.map((option) => /* @__PURE__ */ jsx("option", {
2946
+ value: option.value,
2947
+ children: option.label
2948
+ }, option.value))
2949
+ })]
2950
+ });
2951
+ }
2952
+ function TypographyColorTokenControl({ value, onChange, disabled }) {
2953
+ return /* @__PURE__ */ jsxs("section", {
2954
+ className: "space-y-2",
2955
+ "aria-label": "Default heading color",
2956
+ children: [/* @__PURE__ */ jsxs("div", {
2957
+ className: "flex items-center justify-between gap-2",
2958
+ children: [/* @__PURE__ */ jsx("span", {
2959
+ className: "text-xs font-medium text-muted-foreground",
2960
+ children: "Default heading color"
2961
+ }), /* @__PURE__ */ jsx("span", {
2962
+ className: "text-[11px] text-muted-foreground",
2963
+ children: "Sections may override"
2964
+ })]
2965
+ }), /* @__PURE__ */ jsx("div", {
2966
+ className: "grid grid-cols-2 gap-1",
2967
+ children: headingColorTokenOptions.map((option) => /* @__PURE__ */ jsx("button", {
2968
+ type: "button",
2969
+ className: cn("rounded-md border px-2 py-1.5 text-left text-xs transition disabled:cursor-not-allowed disabled:opacity-50", value === option.value ? "border-primary bg-primary/10" : "border-border hover:bg-muted/60"),
2970
+ "aria-pressed": value === option.value,
2971
+ onClick: () => onChange(option.value),
2972
+ disabled,
2973
+ children: option.label
2974
+ }, option.value))
2975
+ })]
2976
+ });
2977
+ }
2978
+ function normalizeTypographyScaleForControl(scale) {
2979
+ switch (scale) {
2980
+ case "compact":
2981
+ case "balanced":
2982
+ case "spacious": return scale;
2983
+ case "minorThird": return "compact";
2984
+ case "majorThird": return "balanced";
2985
+ case "perfectFourth": return "spacious";
2986
+ default: return "balanced";
2987
+ }
2988
+ }
2704
2989
  function TypographyPresetOption({ preset, selected, onSelect, disabled }) {
2705
2990
  return /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx("button", {
2706
2991
  type: "button",
@@ -2735,8 +3020,24 @@ function TypographyPresetOption({ preset, selected, onSelect, disabled }) {
2735
3020
  }
2736
3021
  function TypographyFontSlotPicker({ label, slot, preset, catalog, value, onChange, disabled }) {
2737
3022
  const [query, setQuery] = useState("");
3023
+ const [manualFamilyDraft, setManualFamilyDraft] = useState(value);
2738
3024
  const defaultFont = primaryFontFamily(preset.defaultFonts[slot]);
2739
- const selectedFamily = value ?? defaultFont;
3025
+ const selectedFamily = primaryFontFamily(value);
3026
+ useEffect(() => {
3027
+ setManualFamilyDraft(value);
3028
+ }, [value]);
3029
+ const commitManualFamilyDraft = useCallback(() => {
3030
+ const normalized = normalizeFontFamilyOverride(manualFamilyDraft);
3031
+ if (!normalized) {
3032
+ setManualFamilyDraft(value);
3033
+ return;
3034
+ }
3035
+ onChange(normalized);
3036
+ }, [
3037
+ manualFamilyDraft,
3038
+ onChange,
3039
+ value
3040
+ ]);
2740
3041
  const recordsByFamily = useMemo(() => indexFontsByFamily(catalog.fonts), [catalog.fonts]);
2741
3042
  const selectedFit = evaluateTypographyFontSlot({
2742
3043
  slot,
@@ -2768,7 +3069,7 @@ function TypographyFontSlotPicker({ label, slot, preset, catalog, value, onChang
2768
3069
  children: label
2769
3070
  }), /* @__PURE__ */ jsx("div", {
2770
3071
  className: "truncate text-sm",
2771
- children: value ? selectedFamily : `${defaultFont} (preset)`
3072
+ children: selectedFamily
2772
3073
  })]
2773
3074
  }), /* @__PURE__ */ jsx(TypographyFontFitBadge, { fit: selectedFit })]
2774
3075
  }),
@@ -2776,19 +3077,19 @@ function TypographyFontSlotPicker({ label, slot, preset, catalog, value, onChang
2776
3077
  className: "grid grid-cols-1 gap-1",
2777
3078
  children: [/* @__PURE__ */ jsxs("button", {
2778
3079
  type: "button",
2779
- className: cn("rounded-md border px-3 py-2 text-left text-sm transition disabled:cursor-not-allowed disabled:opacity-50", value === null ? "border-foreground bg-accent/40" : "border-transparent hover:border-foreground/40 hover:bg-accent/20"),
2780
- onClick: () => onChange(null),
3080
+ className: cn("rounded-md border px-3 py-2 text-left text-sm transition disabled:cursor-not-allowed disabled:opacity-50", selectedFamily === defaultFont ? "border-foreground bg-accent/40" : "border-transparent hover:border-foreground/40 hover:bg-accent/20"),
3081
+ onClick: () => onChange(preset.defaultFonts[slot]),
2781
3082
  disabled,
2782
3083
  children: [/* @__PURE__ */ jsx("span", {
2783
3084
  className: "font-medium",
2784
- children: "Use preset font"
3085
+ children: "Use recipe font"
2785
3086
  }), /* @__PURE__ */ jsx("span", {
2786
3087
  className: "ml-2 text-xs text-muted-foreground",
2787
3088
  children: defaultFont
2788
3089
  })]
2789
3090
  }), recommendedOptions.map((family) => /* @__PURE__ */ jsx(FontFamilyOption, {
2790
3091
  family,
2791
- selected: value === family,
3092
+ selected: selectedFamily === family,
2792
3093
  fit: evaluateTypographyFontSlot({
2793
3094
  slot,
2794
3095
  policy: preset.slotPolicies[slot],
@@ -2804,6 +3105,7 @@ function TypographyFontSlotPicker({ label, slot, preset, catalog, value, onChang
2804
3105
  /* @__PURE__ */ jsx("input", {
2805
3106
  type: "search",
2806
3107
  value: query,
3108
+ "aria-label": `Search ${slot} fonts`,
2807
3109
  placeholder: `Search ${slot} fonts`,
2808
3110
  onChange: (event) => setQuery(event.currentTarget.value),
2809
3111
  disabled: disabled || catalog.kind === "loading",
@@ -2820,7 +3122,7 @@ function TypographyFontSlotPicker({ label, slot, preset, catalog, value, onChang
2820
3122
  className: "max-h-56 space-y-1 overflow-y-auto pr-1",
2821
3123
  children: browseOptions.map((font) => /* @__PURE__ */ jsx(FontFamilyOption, {
2822
3124
  family: font.family,
2823
- selected: value === font.family,
3125
+ selected: selectedFamily === font.family,
2824
3126
  fit: evaluateTypographyFontSlot({
2825
3127
  slot,
2826
3128
  policy: preset.slotPolicies[slot],
@@ -2842,9 +3144,14 @@ function TypographyFontSlotPicker({ label, slot, preset, catalog, value, onChang
2842
3144
  children: "Brand or uploaded font name"
2843
3145
  }), /* @__PURE__ */ jsx("input", {
2844
3146
  type: "text",
2845
- value: value ?? "",
3147
+ value: manualFamilyDraft,
2846
3148
  placeholder: "Enter any font family",
2847
- onChange: (event) => onChange(normalizeFontFamilyOverride(event.currentTarget.value)),
3149
+ onChange: (event) => setManualFamilyDraft(event.currentTarget.value),
3150
+ onBlur: commitManualFamilyDraft,
3151
+ onKeyDown: (event) => {
3152
+ if (event.key !== "Enter") return;
3153
+ event.currentTarget.blur();
3154
+ },
2848
3155
  disabled,
2849
3156
  className: "h-8 w-full rounded-md border bg-background px-2 text-sm outline-none focus:border-primary disabled:cursor-not-allowed disabled:opacity-50"
2850
3157
  })]
@@ -3003,7 +3310,7 @@ function SiteChromeLookRow({ label, ariaLabel, defaultDescription, catalog, opti
3003
3310
  }, ...(catalog ?? []).map((look) => ({
3004
3311
  ...look,
3005
3312
  available: true
3006
- }))], diagnostics, scopeDescription, expanded, onToggle, currentId, currentLabel, onCycle, onPreview, disabled }) {
3313
+ }))], diagnostics, scopeDescription, expanded, onToggle, currentId, currentLabel, onCycle, onPreview, disabled, extraControls }) {
3007
3314
  return /* @__PURE__ */ jsxs(StyleRowFrame, {
3008
3315
  label,
3009
3316
  currentLabel,
@@ -3038,6 +3345,10 @@ function SiteChromeLookRow({ label, ariaLabel, defaultDescription, catalog, opti
3038
3345
  className: "mb-3 list-none space-y-1 p-0 text-xs text-amber-700",
3039
3346
  children: diagnostics.map((diagnostic) => /* @__PURE__ */ jsx("li", { children: diagnostic }, diagnostic))
3040
3347
  }) : null,
3348
+ extraControls ? /* @__PURE__ */ jsx("div", {
3349
+ className: "mb-3",
3350
+ children: extraControls
3351
+ }) : null,
3041
3352
  /* @__PURE__ */ jsx("ul", {
3042
3353
  role: "radiogroup",
3043
3354
  "aria-label": ariaLabel,
@@ -3053,6 +3364,40 @@ function SiteChromeLookRow({ label, ariaLabel, defaultDescription, catalog, opti
3053
3364
  ]
3054
3365
  });
3055
3366
  }
3367
+ function isHeaderMenuSurfaceState(state) {
3368
+ return state.kind === "available" && state.surface === "header" && Array.isArray(state.menuFontOptions) && Array.isArray(state.menuFontSizeOptions);
3369
+ }
3370
+ function HeaderMenuControls({ state, disabled, onMenuFontChange, onMenuFontSizeChange }) {
3371
+ const controlDisabled = disabled || !state.applyAllowed;
3372
+ return /* @__PURE__ */ jsxs("div", {
3373
+ className: "grid grid-cols-2 gap-2 rounded-md border bg-muted/20 p-2",
3374
+ children: [/* @__PURE__ */ jsxs("label", {
3375
+ className: "block text-xs font-medium text-muted-foreground",
3376
+ children: [/* @__PURE__ */ jsx("span", { children: "Menu font" }), /* @__PURE__ */ jsx("select", {
3377
+ 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",
3378
+ value: state.menuFont,
3379
+ onChange: (event) => onMenuFontChange?.(event.currentTarget.value),
3380
+ disabled: controlDisabled,
3381
+ children: state.menuFontOptions.map((option) => /* @__PURE__ */ jsx("option", {
3382
+ value: option.value,
3383
+ children: option.label
3384
+ }, option.value))
3385
+ })]
3386
+ }), /* @__PURE__ */ jsxs("label", {
3387
+ className: "block text-xs font-medium text-muted-foreground",
3388
+ children: [/* @__PURE__ */ jsx("span", { children: "Menu font size" }), /* @__PURE__ */ jsx("select", {
3389
+ 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",
3390
+ value: state.menuFontSize,
3391
+ onChange: (event) => onMenuFontSizeChange?.(event.currentTarget.value),
3392
+ disabled: controlDisabled,
3393
+ children: state.menuFontSizeOptions.map((option) => /* @__PURE__ */ jsx("option", {
3394
+ value: option.value,
3395
+ children: option.label
3396
+ }, option.value))
3397
+ })]
3398
+ })]
3399
+ });
3400
+ }
3056
3401
  function PaletteRow({ expanded, onToggle, siteStyle, currentId, currentLabel, currentSwatch, onPreview, disabled }) {
3057
3402
  const options = useMemo(() => {
3058
3403
  const recommended = requireEntriesForCuratedChoices(paletteVariants, siteStyle.paletteVariantChoices);
@@ -3171,6 +3516,16 @@ function classifyStyleApplyError(error) {
3171
3516
  message: error instanceof Error ? error.message : "Unable to apply your selection."
3172
3517
  };
3173
3518
  }
3519
+ function expandedRowForPreviewDesignRow(row) {
3520
+ switch (row) {
3521
+ case "header": return "header-layout";
3522
+ case "header-layout":
3523
+ case "header-style":
3524
+ case "footer-layout":
3525
+ case "footer": return row;
3526
+ default: return assertNever$2(row, "Unhandled preview design row");
3527
+ }
3528
+ }
3174
3529
  function isRecord(value) {
3175
3530
  return typeof value === "object" && value !== null;
3176
3531
  }
@@ -3344,6 +3699,7 @@ function PreviewEditorSidebar({ surfaceId, siteId, dashboardBaseUrl = null, page
3344
3699
  blockEditorRef,
3345
3700
  onBlocksChange: handleBlocksChange,
3346
3701
  metadataPanel: metadataSectionContent,
3702
+ designOpenRequestId: designRowRequest?.id ?? null,
3347
3703
  designPanel: canInspectSiteStyle(siteStyleAccess) ? /* @__PURE__ */ jsx(StyleConfigurator, {
3348
3704
  siteId,
3349
3705
  apiClient,