@numueg/theme-sdk 0.2.3 → 0.3.2

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.
package/dist/index.d.mts CHANGED
@@ -1,9 +1,9 @@
1
- import { S as Store, e as Product, b as Collection, C as Cart, c as Customer, P as Page, g as ProductVariant } from './entities-C8B2U-V0.mjs';
2
- export { A as Address, a as CartItem, O as Order, d as OrderItem, f as ProductImage, h as ProductOption } from './entities-C8B2U-V0.mjs';
1
+ import { i as Store, e as Product, b as Collection, C as Cart, c as Customer, P as Page, S as SizeChart, g as ProductVariant } from './entities-6MGANln7.mjs';
2
+ export { A as Address, a as CartItem, O as Order, d as OrderItem, f as ProductImage, j as ProductOption, h as SizeChartMode } from './entities-6MGANln7.mjs';
3
3
  import { T as ThemeSettingsV3, c as SectionInstance, M as MountResult, B as BlockInstance, b as BlockSchema, a as BlockProps$1, f as SectionSchema, e as SectionProps$1 } from './theme-D0QybTQS.mjs';
4
4
  export { E as ExternalThemeMetadata, h as MAX_BLOCK_DEPTH, P as PageTemplate, i as PresetBlock, S as SectionGroup, d as SectionPreset, g as SettingDefinition } from './theme-D0QybTQS.mjs';
5
5
  import * as react from 'react';
6
- import { ReactNode, ElementType, CSSProperties, ImgHTMLAttributes, AnchorHTMLAttributes, ButtonHTMLAttributes, HTMLAttributes, FormHTMLAttributes, ComponentType } from 'react';
6
+ import { ReactNode, ReactElement, ElementType, CSSProperties, ImgHTMLAttributes, AnchorHTMLAttributes, ButtonHTMLAttributes, HTMLAttributes, FormHTMLAttributes, ComponentType } from 'react';
7
7
  export { resolveThemeSettings } from './normalize.mjs';
8
8
 
9
9
  /**
@@ -146,6 +146,12 @@ interface MenuItemData {
146
146
  url: string;
147
147
  type?: string | null;
148
148
  resource_id?: string | null;
149
+ /**
150
+ * §5 hide-page → hide-nav-link. `false` when the item targets a CMS page
151
+ * (`/pages/<handle>`) that is currently unpublished or deleted. The backend
152
+ * menus resolver annotates it; absent/`true` means visible (back-compat).
153
+ */
154
+ target_visible?: boolean;
149
155
  children?: MenuItemData[];
150
156
  }
151
157
  /**
@@ -485,6 +491,13 @@ interface NavigationItem {
485
491
  /** Optional foreign keys when the item references a typed resource. */
486
492
  resource_type?: "product" | "collection" | "page" | "blog" | "article" | "url" | null;
487
493
  resource_handle?: string | null;
494
+ /**
495
+ * §5 hide-page → hide-nav-link. `false` when the target CMS page is
496
+ * unpublished/deleted (backend-annotated). Defaults to `true` (visible)
497
+ * when the backend doesn't annotate, so themes can safely filter on
498
+ * `item.target_visible !== false`.
499
+ */
500
+ target_visible: boolean;
488
501
  children: NavigationItem[];
489
502
  }
490
503
  interface NavigationState {
@@ -744,6 +757,33 @@ declare function useRelatedProducts(productId: string | null | undefined, option
744
757
  limit?: number;
745
758
  }): RelatedProductsState;
746
759
 
760
+ /**
761
+ * useProductSizeChart — resolve the size chart to show for a product.
762
+ *
763
+ * The merchant hub writes the per-product chart to
764
+ * `product.attributes.size_chart` and the store-wide default to
765
+ * `store.settings.size_chart`, with an explicit `mode`:
766
+ *
767
+ * "off" → never show, even if a store default exists
768
+ * "custom" → use the product's own chart
769
+ * "default" → fall back to the store-wide chart
770
+ * (legacy) → no `mode`: a populated product chart wins, else the default
771
+ *
772
+ * This hook centralises that precedence so every theme resolves it identically
773
+ * (the backend `SizeChartSchema` validator and the hub editor share the same
774
+ * shape). Returns `null` when there is nothing to show — render the size-guide
775
+ * trigger only when this is non-null.
776
+ *
777
+ * @param productOverride - resolve against this product instead of the one in
778
+ * context (e.g. when rendering a chart for a related/quick-view product).
779
+ */
780
+ declare function useProductSizeChart(productOverride?: Product | null): SizeChart | null;
781
+ /**
782
+ * Pure resolver (no React) — exported so non-hook code (SSR helpers, tests)
783
+ * can apply the same precedence.
784
+ */
785
+ declare function resolveSizeChart(productAttributes: Record<string, unknown> | undefined, storeSettings: Record<string, unknown> | undefined): SizeChart | null;
786
+
747
787
  /**
748
788
  * Multi-currency presentment — Phase 6.
749
789
  *
@@ -1155,6 +1195,14 @@ interface ThemeMountContext {
1155
1195
  demo?: boolean;
1156
1196
  /** Store navigation menus keyed by handle, resolved server-side. */
1157
1197
  navigation?: Record<string, MenuItemData[]>;
1198
+ /**
1199
+ * Host signal that the container already holds server-rendered HTML for
1200
+ * this exact ctx (produced via `createApp` from `defineThemeEntry`).
1201
+ * `mountTheme` then adopts it with `hydrateRoot` instead of re-rendering
1202
+ * from scratch. Ignored when the container is empty, so a host can pass
1203
+ * it optimistically and still get a plain client mount on SSR failure.
1204
+ */
1205
+ hydrate?: boolean;
1158
1206
  [extra: string]: unknown;
1159
1207
  }
1160
1208
  /** Arguments handed to a theme's render callback on every (re)render. */
@@ -1170,17 +1218,81 @@ interface ThemeRenderArgs {
1170
1218
  /** Live theme settings (reflects customizer drafts via applyDraft). */
1171
1219
  themeSettings: ThemeSettingsV3;
1172
1220
  }
1221
+ interface DraftHandle {
1222
+ applyDraft: (next: ThemeSettingsV3) => void;
1223
+ }
1224
+ /**
1225
+ * Build the canonical theme element tree for a ctx. BOTH render paths go
1226
+ * through here — `mountTheme` (client mount/hydrate) and `createApp`
1227
+ * (host-side `renderToString`) — so the server markup and the hydration
1228
+ * tree are the same React tree by construction. `mountEl` is a prop, not
1229
+ * DOM output, so it differing between server (null) and client (the
1230
+ * container) cannot cause a hydration mismatch.
1231
+ */
1232
+ declare function buildThemeElement(ctx: ThemeMountContext, mountEl: HTMLElement | null, renderApp: (args: ThemeRenderArgs) => ReactNode, ref?: (h: DraftHandle | null) => void): ReactElement;
1173
1233
  /**
1174
1234
  * Mount a V3 theme. Owns the React root, the provider stack (catalog + nav +
1175
1235
  * style tokens), and the live-preview draft cycle. Returns the host-contract
1176
1236
  * `MountResult` (`cleanup` + `applyDraft`).
1177
1237
  *
1238
+ * When the host passes `ctx.hydrate === true` and the container already
1239
+ * holds server-rendered HTML (produced by this theme's `createApp` with the
1240
+ * identical ctx), the tree is adopted via `hydrateRoot` — no re-render, no
1241
+ * flash. An empty container downgrades to a plain client mount so hosts can
1242
+ * pass the flag optimistically.
1243
+ *
1178
1244
  * @param el the host-supplied container element
1179
1245
  * @param ctx the mount context (either host or legacy/dev shape)
1180
1246
  * @param renderApp returns the theme's section tree for the current args
1181
1247
  */
1182
1248
  declare function mountTheme(el: HTMLElement, ctx: ThemeMountContext, renderApp: (args: ThemeRenderArgs) => ReactNode): MountResult;
1183
1249
 
1250
+ /**
1251
+ * `defineThemeEntry(renderApp)` — one-call theme entry that yields BOTH
1252
+ * halves of the V3 contract from a single component:
1253
+ *
1254
+ * - `mount(el, ctx)` — the client entry every host already calls
1255
+ * (now hydration-aware via `ctx.hydrate`).
1256
+ * - `createApp(ctx)` — the same React tree as a plain element, so the
1257
+ * host can `renderToString(createApp(ctx))` on the
1258
+ * server and ship real HTML before any JS runs.
1259
+ *
1260
+ * ```tsx
1261
+ * // src/main.tsx
1262
+ * import { defineThemeEntry } from "@numueg/theme-sdk";
1263
+ *
1264
+ * const entry = defineThemeEntry(({ currentTemplate }) => (
1265
+ * <ThemeApp currentTemplate={currentTemplate} />
1266
+ * ));
1267
+ *
1268
+ * export const mount = entry.mount;
1269
+ * export const createApp = entry.createApp;
1270
+ * ```
1271
+ *
1272
+ * Why both MUST come from one definition: hydration only succeeds when the
1273
+ * server markup and the client tree are identical. Routing both through
1274
+ * `buildThemeElement` makes that true by construction — a theme cannot
1275
+ * accidentally ship a `createApp` that disagrees with its `mount`.
1276
+ *
1277
+ * Themes that only export `mount` keep working exactly as before; they are
1278
+ * simply never server-rendered (the host detects the missing `createApp`
1279
+ * and falls back to today's client-only mount).
1280
+ */
1281
+
1282
+ /** The pair of entry points a V3 theme bundle exports. */
1283
+ interface ThemeEntry {
1284
+ /** Client entry — host contract `mount(el, ctx): MountResult`. */
1285
+ mount: (el: HTMLElement, ctx: ThemeMountContext) => MountResult;
1286
+ /**
1287
+ * Server entry — returns the exact element tree `mount` would render,
1288
+ * for host-side `renderToString`. Must stay side-effect free: no DOM
1289
+ * access happens until React effects run (which they don't on the
1290
+ * server).
1291
+ */
1292
+ createApp: (ctx: ThemeMountContext) => ReactElement;
1293
+ }
1294
+ declare function defineThemeEntry(renderApp: (args: ThemeRenderArgs) => ReactNode): ThemeEntry;
1295
+
1184
1296
  interface NuMuProviderProps {
1185
1297
  store: Store;
1186
1298
  themeSettings: ThemeSettingsV3;
@@ -2126,11 +2238,32 @@ type GlobalSettings = Record<string, unknown> | null | undefined;
2126
2238
  * family/stack the theme author supplied.
2127
2239
  */
2128
2240
  declare function resolveFontStack(value: string): string;
2241
+ /** Result of `computeGlobalStyleTokens` — everything a host needs to paint
2242
+ * global settings without a DOM. */
2243
+ interface ComputedStyleTokens {
2244
+ /** CSS custom properties to set on the theme's mount root. */
2245
+ cssVars: Record<string, string>;
2246
+ /** Google-Fonts stylesheet hrefs for any registry fonts in use. */
2247
+ fontHrefs: string[];
2248
+ }
2249
+ /**
2250
+ * Pure half of `applyGlobalStyleTokens`: compute the exact CSS custom
2251
+ * properties (and webfont hrefs) a settings object maps to, without touching
2252
+ * any DOM. This is what lets a host SERVER-render a theme with the same vars
2253
+ * the bundle applies on mount — both sides call this one function, so the
2254
+ * values cannot drift (drift = unstyled flash or hydration noise).
2255
+ *
2256
+ * Includes the explicit `heading_font` / `body_font` resolution that
2257
+ * `mountTheme` historically layered on top: any string value for those two
2258
+ * ids resolves through the registry (or passes verbatim) so a picked font
2259
+ * gets a real stack even when it isn't a known token.
2260
+ */
2261
+ declare function computeGlobalStyleTokens(globalSettings: GlobalSettings): ComputedStyleTokens;
2129
2262
  /**
2130
2263
  * Map a store's global settings onto CSS custom properties on `el`. Call on
2131
2264
  * mount and on every `applyDraft` (live preview). No-op when `el` or the
2132
2265
  * settings are missing. Reserved `__`-prefixed keys (e.g. `__translations`)
2133
- * are skipped.
2266
+ * are skipped. Thin DOM shell over `computeGlobalStyleTokens`.
2134
2267
  */
2135
2268
  declare function applyGlobalStyleTokens(globalSettings: GlobalSettings, el: HTMLElement | null | undefined): void;
2136
2269
 
@@ -2192,4 +2325,4 @@ declare function pickTranslations(bundle: LocaleBundle, locale: string): LocaleM
2192
2325
  */
2193
2326
  declare function buildLocaleBundle<T extends Record<string, unknown>>(modules: T): LocaleBundle;
2194
2327
 
2195
- export { AddToCartButton, type AddressInput, type AnalyticsApi, type AnalyticsPayload, type AppManifestBlock, type AppPayload, type AppState, Block, BlockInstance, BlockProps$1 as BlockProps, BlockSchema, Cart, CartContext, type CheckoutAddress, type CheckoutApi, type CheckoutSessionState, type CheckoutStep, Collection, CollectionCard, type CollectionCardProps, type CollectionCardSlots, CollectionContext, CollectionProvider, type CurrencyConfig, type CurrencyState, CurrencySwitcher, type CurrencySwitcherProps, Customer, type CustomerAddress, type CustomerAddressesState, CustomerContext, type DefineBlockInput, type DefineSectionInput, type DefinedBlock, type DefinedSection, type DynamicResolveContext, type DynamicSourceRef, EditableImage, type EditableImageProps, EditableText, type EditableTextProps, type FocalSrcOptions, Form, type GiftCardBalance, ICON_NAMES, Icon, IconMap, type IconProps, Image, type ImageTransform, Link, type LocaleBundle, type LocaleMessages, LocaleSwitcher, type LocaleSwitcherProps, LocalizationContext, type MenuItemData, Money, MountResult, NavigationContext, type NavigationItem, type NavigationState, NuMuProvider, type OrderDetail, type OrderListEntry, type OrderListState, type OrderState, Page, PageContext, type PlaceOrderResult, Product, ProductCard, type ProductCardProps, type ProductCardSlots, ProductContext, ProductProvider, ProductVariant, type RelatedProductsState, type ReorderResult, type ReorderSkipReason, type ReorderSkippedItem, RichText, type RichTextProps, type SearchResults, type SearchState, Section, SectionContext, SectionInstance, SectionProps$1 as SectionProps, SectionSchema, type ShippingRateOption, ShopContext, type ShopWithHelpers, Store, type ThemeMountContext, type ThemeMountPage, type ThemeRenderArgs, ThemeSettingsContext, ThemeSettingsV3, type UseGiftCardBalance, type UseReorder, type UseSearchOptions, type UseShippingRatesOptions, type UseShippingRatesState, type UseVariantSelection, type WishlistItem, type WishlistState, applyGlobalStyleTokens, applyImageTransform, asImageTransform, assetUrl, availableValues, buildLocaleBundle, clearSdkSingleton, collectBlocks, collectSections, defaultVariant, defineBlock, defineSection, dynamicSource, findVariantByOptions, flattenMessages, focalSrc, getReactSingleton, getSdkSingleton, isDefinedBlock, isDefinedSection, isDynamicSource, isSdkAvailable, mountTheme, pickTranslations, registerReactSingleton, registerSdkSingleton, resolveDynamicValue, resolveFontStack, resolveSettingsMap, resolveSourcePath, sanitizeHtml, useAnalytics, useApp, useCart, useCheckout, useCollection, useCollectionOptional, useCollections, useCurrency, useCurrentTemplate, useCustomer, useCustomerActions, useCustomerAddresses, useDirection, useFieldTranslation, useGiftCardBalance, useImage, useLocale, useLocalization, useMoney, useNavigation, useNumberFormat, useOrder, useOrders, usePage, useProduct, useProductOptional, useProducts, useRelatedProducts, useReorder, useResolvedSettings, useSearch, useSection, useSectionOptional, useShippingRates, useShop, useThemeSettings, useTranslation, useVariantSelection, useWishlist };
2328
+ export { AddToCartButton, type AddressInput, type AnalyticsApi, type AnalyticsPayload, type AppManifestBlock, type AppPayload, type AppState, Block, BlockInstance, BlockProps$1 as BlockProps, BlockSchema, Cart, CartContext, type CheckoutAddress, type CheckoutApi, type CheckoutSessionState, type CheckoutStep, Collection, CollectionCard, type CollectionCardProps, type CollectionCardSlots, CollectionContext, CollectionProvider, type ComputedStyleTokens, type CurrencyConfig, type CurrencyState, CurrencySwitcher, type CurrencySwitcherProps, Customer, type CustomerAddress, type CustomerAddressesState, CustomerContext, type DefineBlockInput, type DefineSectionInput, type DefinedBlock, type DefinedSection, type DynamicResolveContext, type DynamicSourceRef, EditableImage, type EditableImageProps, EditableText, type EditableTextProps, type FocalSrcOptions, Form, type GiftCardBalance, ICON_NAMES, Icon, IconMap, type IconProps, Image, type ImageTransform, Link, type LocaleBundle, type LocaleMessages, LocaleSwitcher, type LocaleSwitcherProps, LocalizationContext, type MenuItemData, Money, MountResult, NavigationContext, type NavigationItem, type NavigationState, NuMuProvider, type OrderDetail, type OrderListEntry, type OrderListState, type OrderState, Page, PageContext, type PlaceOrderResult, Product, ProductCard, type ProductCardProps, type ProductCardSlots, ProductContext, ProductProvider, ProductVariant, type RelatedProductsState, type ReorderResult, type ReorderSkipReason, type ReorderSkippedItem, RichText, type RichTextProps, type SearchResults, type SearchState, Section, SectionContext, SectionInstance, SectionProps$1 as SectionProps, SectionSchema, type ShippingRateOption, ShopContext, type ShopWithHelpers, SizeChart, Store, type ThemeEntry, type ThemeMountContext, type ThemeMountPage, type ThemeRenderArgs, ThemeSettingsContext, ThemeSettingsV3, type UseGiftCardBalance, type UseReorder, type UseSearchOptions, type UseShippingRatesOptions, type UseShippingRatesState, type UseVariantSelection, type WishlistItem, type WishlistState, applyGlobalStyleTokens, applyImageTransform, asImageTransform, assetUrl, availableValues, buildLocaleBundle, buildThemeElement, clearSdkSingleton, collectBlocks, collectSections, computeGlobalStyleTokens, defaultVariant, defineBlock, defineSection, defineThemeEntry, dynamicSource, findVariantByOptions, flattenMessages, focalSrc, getReactSingleton, getSdkSingleton, isDefinedBlock, isDefinedSection, isDynamicSource, isSdkAvailable, mountTheme, pickTranslations, registerReactSingleton, registerSdkSingleton, resolveDynamicValue, resolveFontStack, resolveSettingsMap, resolveSizeChart, resolveSourcePath, sanitizeHtml, useAnalytics, useApp, useCart, useCheckout, useCollection, useCollectionOptional, useCollections, useCurrency, useCurrentTemplate, useCustomer, useCustomerActions, useCustomerAddresses, useDirection, useFieldTranslation, useGiftCardBalance, useImage, useLocale, useLocalization, useMoney, useNavigation, useNumberFormat, useOrder, useOrders, usePage, useProduct, useProductOptional, useProductSizeChart, useProducts, useRelatedProducts, useReorder, useResolvedSettings, useSearch, useSection, useSectionOptional, useShippingRates, useShop, useThemeSettings, useTranslation, useVariantSelection, useWishlist };
package/dist/index.d.ts CHANGED
@@ -1,9 +1,9 @@
1
- import { S as Store, e as Product, b as Collection, C as Cart, c as Customer, P as Page, g as ProductVariant } from './entities-C8B2U-V0.js';
2
- export { A as Address, a as CartItem, O as Order, d as OrderItem, f as ProductImage, h as ProductOption } from './entities-C8B2U-V0.js';
1
+ import { i as Store, e as Product, b as Collection, C as Cart, c as Customer, P as Page, S as SizeChart, g as ProductVariant } from './entities-6MGANln7.js';
2
+ export { A as Address, a as CartItem, O as Order, d as OrderItem, f as ProductImage, j as ProductOption, h as SizeChartMode } from './entities-6MGANln7.js';
3
3
  import { T as ThemeSettingsV3, c as SectionInstance, M as MountResult, B as BlockInstance, b as BlockSchema, a as BlockProps$1, f as SectionSchema, e as SectionProps$1 } from './theme-D0QybTQS.js';
4
4
  export { E as ExternalThemeMetadata, h as MAX_BLOCK_DEPTH, P as PageTemplate, i as PresetBlock, S as SectionGroup, d as SectionPreset, g as SettingDefinition } from './theme-D0QybTQS.js';
5
5
  import * as react from 'react';
6
- import { ReactNode, ElementType, CSSProperties, ImgHTMLAttributes, AnchorHTMLAttributes, ButtonHTMLAttributes, HTMLAttributes, FormHTMLAttributes, ComponentType } from 'react';
6
+ import { ReactNode, ReactElement, ElementType, CSSProperties, ImgHTMLAttributes, AnchorHTMLAttributes, ButtonHTMLAttributes, HTMLAttributes, FormHTMLAttributes, ComponentType } from 'react';
7
7
  export { resolveThemeSettings } from './normalize.js';
8
8
 
9
9
  /**
@@ -146,6 +146,12 @@ interface MenuItemData {
146
146
  url: string;
147
147
  type?: string | null;
148
148
  resource_id?: string | null;
149
+ /**
150
+ * §5 hide-page → hide-nav-link. `false` when the item targets a CMS page
151
+ * (`/pages/<handle>`) that is currently unpublished or deleted. The backend
152
+ * menus resolver annotates it; absent/`true` means visible (back-compat).
153
+ */
154
+ target_visible?: boolean;
149
155
  children?: MenuItemData[];
150
156
  }
151
157
  /**
@@ -485,6 +491,13 @@ interface NavigationItem {
485
491
  /** Optional foreign keys when the item references a typed resource. */
486
492
  resource_type?: "product" | "collection" | "page" | "blog" | "article" | "url" | null;
487
493
  resource_handle?: string | null;
494
+ /**
495
+ * §5 hide-page → hide-nav-link. `false` when the target CMS page is
496
+ * unpublished/deleted (backend-annotated). Defaults to `true` (visible)
497
+ * when the backend doesn't annotate, so themes can safely filter on
498
+ * `item.target_visible !== false`.
499
+ */
500
+ target_visible: boolean;
488
501
  children: NavigationItem[];
489
502
  }
490
503
  interface NavigationState {
@@ -744,6 +757,33 @@ declare function useRelatedProducts(productId: string | null | undefined, option
744
757
  limit?: number;
745
758
  }): RelatedProductsState;
746
759
 
760
+ /**
761
+ * useProductSizeChart — resolve the size chart to show for a product.
762
+ *
763
+ * The merchant hub writes the per-product chart to
764
+ * `product.attributes.size_chart` and the store-wide default to
765
+ * `store.settings.size_chart`, with an explicit `mode`:
766
+ *
767
+ * "off" → never show, even if a store default exists
768
+ * "custom" → use the product's own chart
769
+ * "default" → fall back to the store-wide chart
770
+ * (legacy) → no `mode`: a populated product chart wins, else the default
771
+ *
772
+ * This hook centralises that precedence so every theme resolves it identically
773
+ * (the backend `SizeChartSchema` validator and the hub editor share the same
774
+ * shape). Returns `null` when there is nothing to show — render the size-guide
775
+ * trigger only when this is non-null.
776
+ *
777
+ * @param productOverride - resolve against this product instead of the one in
778
+ * context (e.g. when rendering a chart for a related/quick-view product).
779
+ */
780
+ declare function useProductSizeChart(productOverride?: Product | null): SizeChart | null;
781
+ /**
782
+ * Pure resolver (no React) — exported so non-hook code (SSR helpers, tests)
783
+ * can apply the same precedence.
784
+ */
785
+ declare function resolveSizeChart(productAttributes: Record<string, unknown> | undefined, storeSettings: Record<string, unknown> | undefined): SizeChart | null;
786
+
747
787
  /**
748
788
  * Multi-currency presentment — Phase 6.
749
789
  *
@@ -1155,6 +1195,14 @@ interface ThemeMountContext {
1155
1195
  demo?: boolean;
1156
1196
  /** Store navigation menus keyed by handle, resolved server-side. */
1157
1197
  navigation?: Record<string, MenuItemData[]>;
1198
+ /**
1199
+ * Host signal that the container already holds server-rendered HTML for
1200
+ * this exact ctx (produced via `createApp` from `defineThemeEntry`).
1201
+ * `mountTheme` then adopts it with `hydrateRoot` instead of re-rendering
1202
+ * from scratch. Ignored when the container is empty, so a host can pass
1203
+ * it optimistically and still get a plain client mount on SSR failure.
1204
+ */
1205
+ hydrate?: boolean;
1158
1206
  [extra: string]: unknown;
1159
1207
  }
1160
1208
  /** Arguments handed to a theme's render callback on every (re)render. */
@@ -1170,17 +1218,81 @@ interface ThemeRenderArgs {
1170
1218
  /** Live theme settings (reflects customizer drafts via applyDraft). */
1171
1219
  themeSettings: ThemeSettingsV3;
1172
1220
  }
1221
+ interface DraftHandle {
1222
+ applyDraft: (next: ThemeSettingsV3) => void;
1223
+ }
1224
+ /**
1225
+ * Build the canonical theme element tree for a ctx. BOTH render paths go
1226
+ * through here — `mountTheme` (client mount/hydrate) and `createApp`
1227
+ * (host-side `renderToString`) — so the server markup and the hydration
1228
+ * tree are the same React tree by construction. `mountEl` is a prop, not
1229
+ * DOM output, so it differing between server (null) and client (the
1230
+ * container) cannot cause a hydration mismatch.
1231
+ */
1232
+ declare function buildThemeElement(ctx: ThemeMountContext, mountEl: HTMLElement | null, renderApp: (args: ThemeRenderArgs) => ReactNode, ref?: (h: DraftHandle | null) => void): ReactElement;
1173
1233
  /**
1174
1234
  * Mount a V3 theme. Owns the React root, the provider stack (catalog + nav +
1175
1235
  * style tokens), and the live-preview draft cycle. Returns the host-contract
1176
1236
  * `MountResult` (`cleanup` + `applyDraft`).
1177
1237
  *
1238
+ * When the host passes `ctx.hydrate === true` and the container already
1239
+ * holds server-rendered HTML (produced by this theme's `createApp` with the
1240
+ * identical ctx), the tree is adopted via `hydrateRoot` — no re-render, no
1241
+ * flash. An empty container downgrades to a plain client mount so hosts can
1242
+ * pass the flag optimistically.
1243
+ *
1178
1244
  * @param el the host-supplied container element
1179
1245
  * @param ctx the mount context (either host or legacy/dev shape)
1180
1246
  * @param renderApp returns the theme's section tree for the current args
1181
1247
  */
1182
1248
  declare function mountTheme(el: HTMLElement, ctx: ThemeMountContext, renderApp: (args: ThemeRenderArgs) => ReactNode): MountResult;
1183
1249
 
1250
+ /**
1251
+ * `defineThemeEntry(renderApp)` — one-call theme entry that yields BOTH
1252
+ * halves of the V3 contract from a single component:
1253
+ *
1254
+ * - `mount(el, ctx)` — the client entry every host already calls
1255
+ * (now hydration-aware via `ctx.hydrate`).
1256
+ * - `createApp(ctx)` — the same React tree as a plain element, so the
1257
+ * host can `renderToString(createApp(ctx))` on the
1258
+ * server and ship real HTML before any JS runs.
1259
+ *
1260
+ * ```tsx
1261
+ * // src/main.tsx
1262
+ * import { defineThemeEntry } from "@numueg/theme-sdk";
1263
+ *
1264
+ * const entry = defineThemeEntry(({ currentTemplate }) => (
1265
+ * <ThemeApp currentTemplate={currentTemplate} />
1266
+ * ));
1267
+ *
1268
+ * export const mount = entry.mount;
1269
+ * export const createApp = entry.createApp;
1270
+ * ```
1271
+ *
1272
+ * Why both MUST come from one definition: hydration only succeeds when the
1273
+ * server markup and the client tree are identical. Routing both through
1274
+ * `buildThemeElement` makes that true by construction — a theme cannot
1275
+ * accidentally ship a `createApp` that disagrees with its `mount`.
1276
+ *
1277
+ * Themes that only export `mount` keep working exactly as before; they are
1278
+ * simply never server-rendered (the host detects the missing `createApp`
1279
+ * and falls back to today's client-only mount).
1280
+ */
1281
+
1282
+ /** The pair of entry points a V3 theme bundle exports. */
1283
+ interface ThemeEntry {
1284
+ /** Client entry — host contract `mount(el, ctx): MountResult`. */
1285
+ mount: (el: HTMLElement, ctx: ThemeMountContext) => MountResult;
1286
+ /**
1287
+ * Server entry — returns the exact element tree `mount` would render,
1288
+ * for host-side `renderToString`. Must stay side-effect free: no DOM
1289
+ * access happens until React effects run (which they don't on the
1290
+ * server).
1291
+ */
1292
+ createApp: (ctx: ThemeMountContext) => ReactElement;
1293
+ }
1294
+ declare function defineThemeEntry(renderApp: (args: ThemeRenderArgs) => ReactNode): ThemeEntry;
1295
+
1184
1296
  interface NuMuProviderProps {
1185
1297
  store: Store;
1186
1298
  themeSettings: ThemeSettingsV3;
@@ -2126,11 +2238,32 @@ type GlobalSettings = Record<string, unknown> | null | undefined;
2126
2238
  * family/stack the theme author supplied.
2127
2239
  */
2128
2240
  declare function resolveFontStack(value: string): string;
2241
+ /** Result of `computeGlobalStyleTokens` — everything a host needs to paint
2242
+ * global settings without a DOM. */
2243
+ interface ComputedStyleTokens {
2244
+ /** CSS custom properties to set on the theme's mount root. */
2245
+ cssVars: Record<string, string>;
2246
+ /** Google-Fonts stylesheet hrefs for any registry fonts in use. */
2247
+ fontHrefs: string[];
2248
+ }
2249
+ /**
2250
+ * Pure half of `applyGlobalStyleTokens`: compute the exact CSS custom
2251
+ * properties (and webfont hrefs) a settings object maps to, without touching
2252
+ * any DOM. This is what lets a host SERVER-render a theme with the same vars
2253
+ * the bundle applies on mount — both sides call this one function, so the
2254
+ * values cannot drift (drift = unstyled flash or hydration noise).
2255
+ *
2256
+ * Includes the explicit `heading_font` / `body_font` resolution that
2257
+ * `mountTheme` historically layered on top: any string value for those two
2258
+ * ids resolves through the registry (or passes verbatim) so a picked font
2259
+ * gets a real stack even when it isn't a known token.
2260
+ */
2261
+ declare function computeGlobalStyleTokens(globalSettings: GlobalSettings): ComputedStyleTokens;
2129
2262
  /**
2130
2263
  * Map a store's global settings onto CSS custom properties on `el`. Call on
2131
2264
  * mount and on every `applyDraft` (live preview). No-op when `el` or the
2132
2265
  * settings are missing. Reserved `__`-prefixed keys (e.g. `__translations`)
2133
- * are skipped.
2266
+ * are skipped. Thin DOM shell over `computeGlobalStyleTokens`.
2134
2267
  */
2135
2268
  declare function applyGlobalStyleTokens(globalSettings: GlobalSettings, el: HTMLElement | null | undefined): void;
2136
2269
 
@@ -2192,4 +2325,4 @@ declare function pickTranslations(bundle: LocaleBundle, locale: string): LocaleM
2192
2325
  */
2193
2326
  declare function buildLocaleBundle<T extends Record<string, unknown>>(modules: T): LocaleBundle;
2194
2327
 
2195
- export { AddToCartButton, type AddressInput, type AnalyticsApi, type AnalyticsPayload, type AppManifestBlock, type AppPayload, type AppState, Block, BlockInstance, BlockProps$1 as BlockProps, BlockSchema, Cart, CartContext, type CheckoutAddress, type CheckoutApi, type CheckoutSessionState, type CheckoutStep, Collection, CollectionCard, type CollectionCardProps, type CollectionCardSlots, CollectionContext, CollectionProvider, type CurrencyConfig, type CurrencyState, CurrencySwitcher, type CurrencySwitcherProps, Customer, type CustomerAddress, type CustomerAddressesState, CustomerContext, type DefineBlockInput, type DefineSectionInput, type DefinedBlock, type DefinedSection, type DynamicResolveContext, type DynamicSourceRef, EditableImage, type EditableImageProps, EditableText, type EditableTextProps, type FocalSrcOptions, Form, type GiftCardBalance, ICON_NAMES, Icon, IconMap, type IconProps, Image, type ImageTransform, Link, type LocaleBundle, type LocaleMessages, LocaleSwitcher, type LocaleSwitcherProps, LocalizationContext, type MenuItemData, Money, MountResult, NavigationContext, type NavigationItem, type NavigationState, NuMuProvider, type OrderDetail, type OrderListEntry, type OrderListState, type OrderState, Page, PageContext, type PlaceOrderResult, Product, ProductCard, type ProductCardProps, type ProductCardSlots, ProductContext, ProductProvider, ProductVariant, type RelatedProductsState, type ReorderResult, type ReorderSkipReason, type ReorderSkippedItem, RichText, type RichTextProps, type SearchResults, type SearchState, Section, SectionContext, SectionInstance, SectionProps$1 as SectionProps, SectionSchema, type ShippingRateOption, ShopContext, type ShopWithHelpers, Store, type ThemeMountContext, type ThemeMountPage, type ThemeRenderArgs, ThemeSettingsContext, ThemeSettingsV3, type UseGiftCardBalance, type UseReorder, type UseSearchOptions, type UseShippingRatesOptions, type UseShippingRatesState, type UseVariantSelection, type WishlistItem, type WishlistState, applyGlobalStyleTokens, applyImageTransform, asImageTransform, assetUrl, availableValues, buildLocaleBundle, clearSdkSingleton, collectBlocks, collectSections, defaultVariant, defineBlock, defineSection, dynamicSource, findVariantByOptions, flattenMessages, focalSrc, getReactSingleton, getSdkSingleton, isDefinedBlock, isDefinedSection, isDynamicSource, isSdkAvailable, mountTheme, pickTranslations, registerReactSingleton, registerSdkSingleton, resolveDynamicValue, resolveFontStack, resolveSettingsMap, resolveSourcePath, sanitizeHtml, useAnalytics, useApp, useCart, useCheckout, useCollection, useCollectionOptional, useCollections, useCurrency, useCurrentTemplate, useCustomer, useCustomerActions, useCustomerAddresses, useDirection, useFieldTranslation, useGiftCardBalance, useImage, useLocale, useLocalization, useMoney, useNavigation, useNumberFormat, useOrder, useOrders, usePage, useProduct, useProductOptional, useProducts, useRelatedProducts, useReorder, useResolvedSettings, useSearch, useSection, useSectionOptional, useShippingRates, useShop, useThemeSettings, useTranslation, useVariantSelection, useWishlist };
2328
+ export { AddToCartButton, type AddressInput, type AnalyticsApi, type AnalyticsPayload, type AppManifestBlock, type AppPayload, type AppState, Block, BlockInstance, BlockProps$1 as BlockProps, BlockSchema, Cart, CartContext, type CheckoutAddress, type CheckoutApi, type CheckoutSessionState, type CheckoutStep, Collection, CollectionCard, type CollectionCardProps, type CollectionCardSlots, CollectionContext, CollectionProvider, type ComputedStyleTokens, type CurrencyConfig, type CurrencyState, CurrencySwitcher, type CurrencySwitcherProps, Customer, type CustomerAddress, type CustomerAddressesState, CustomerContext, type DefineBlockInput, type DefineSectionInput, type DefinedBlock, type DefinedSection, type DynamicResolveContext, type DynamicSourceRef, EditableImage, type EditableImageProps, EditableText, type EditableTextProps, type FocalSrcOptions, Form, type GiftCardBalance, ICON_NAMES, Icon, IconMap, type IconProps, Image, type ImageTransform, Link, type LocaleBundle, type LocaleMessages, LocaleSwitcher, type LocaleSwitcherProps, LocalizationContext, type MenuItemData, Money, MountResult, NavigationContext, type NavigationItem, type NavigationState, NuMuProvider, type OrderDetail, type OrderListEntry, type OrderListState, type OrderState, Page, PageContext, type PlaceOrderResult, Product, ProductCard, type ProductCardProps, type ProductCardSlots, ProductContext, ProductProvider, ProductVariant, type RelatedProductsState, type ReorderResult, type ReorderSkipReason, type ReorderSkippedItem, RichText, type RichTextProps, type SearchResults, type SearchState, Section, SectionContext, SectionInstance, SectionProps$1 as SectionProps, SectionSchema, type ShippingRateOption, ShopContext, type ShopWithHelpers, SizeChart, Store, type ThemeEntry, type ThemeMountContext, type ThemeMountPage, type ThemeRenderArgs, ThemeSettingsContext, ThemeSettingsV3, type UseGiftCardBalance, type UseReorder, type UseSearchOptions, type UseShippingRatesOptions, type UseShippingRatesState, type UseVariantSelection, type WishlistItem, type WishlistState, applyGlobalStyleTokens, applyImageTransform, asImageTransform, assetUrl, availableValues, buildLocaleBundle, buildThemeElement, clearSdkSingleton, collectBlocks, collectSections, computeGlobalStyleTokens, defaultVariant, defineBlock, defineSection, defineThemeEntry, dynamicSource, findVariantByOptions, flattenMessages, focalSrc, getReactSingleton, getSdkSingleton, isDefinedBlock, isDefinedSection, isDynamicSource, isSdkAvailable, mountTheme, pickTranslations, registerReactSingleton, registerSdkSingleton, resolveDynamicValue, resolveFontStack, resolveSettingsMap, resolveSizeChart, resolveSourcePath, sanitizeHtml, useAnalytics, useApp, useCart, useCheckout, useCollection, useCollectionOptional, useCollections, useCurrency, useCurrentTemplate, useCustomer, useCustomerActions, useCustomerAddresses, useDirection, useFieldTranslation, useGiftCardBalance, useImage, useLocale, useLocalization, useMoney, useNavigation, useNumberFormat, useOrder, useOrders, usePage, useProduct, useProductOptional, useProductSizeChart, useProducts, useRelatedProducts, useReorder, useResolvedSettings, useSearch, useSection, useSectionOptional, useShippingRates, useShop, useThemeSettings, useTranslation, useVariantSelection, useWishlist };