@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/CHANGELOG.md +29 -1
- package/dist/{entities-C8B2U-V0.d.mts → entities-6MGANln7.d.mts} +45 -1
- package/dist/{entities-C8B2U-V0.d.ts → entities-6MGANln7.d.ts} +45 -1
- package/dist/index.cjs +123 -44
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +138 -5
- package/dist/index.d.ts +138 -5
- package/dist/index.mjs +120 -46
- package/dist/index.mjs.map +1 -1
- package/dist/types.d.mts +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/v2-compat.cjs.map +1 -1
- package/dist/v2-compat.d.mts +1 -1
- package/dist/v2-compat.d.ts +1 -1
- package/dist/v2-compat.mjs.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,7 +4,35 @@ All notable changes to `@numueg/theme-sdk` are documented here. The format is ba
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
-
## [0.1
|
|
7
|
+
## [0.3.1] - 2026-06-17
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- **Size charts** — `useProductSizeChart()` hook + `resolveSizeChart()` pure
|
|
12
|
+
resolver. Resolves the per-product chart (`product.attributes.size_chart`)
|
|
13
|
+
against the store-wide default (`store.settings.size_chart`) using the same
|
|
14
|
+
precedence as the merchant hub + backend validator (`mode`:
|
|
15
|
+
`custom` → `default` → `off`, with a legacy no-mode fallback). New types
|
|
16
|
+
`SizeChart` / `SizeChartMode`.
|
|
17
|
+
- `Product.attributes` and `Store.settings` are now typed (optional
|
|
18
|
+
`Record<string, unknown>`) — the storefront already forwards these JSONB
|
|
19
|
+
blobs (also used by `useFieldTranslation`); they were previously untyped.
|
|
20
|
+
|
|
21
|
+
## [0.3.0] - 2026-06-10
|
|
22
|
+
|
|
23
|
+
### Added
|
|
24
|
+
|
|
25
|
+
- **`defineThemeEntry`** — one-call theme entry that returns both `mount`
|
|
26
|
+
(client, hydration-aware via `hydrateRoot`) and `createApp` (server
|
|
27
|
+
`renderToString`), wiring `NuMuProvider` + page/product/collection context +
|
|
28
|
+
catalog forwarding + global style tokens + the customizer's live-preview
|
|
29
|
+
draft cycle. This is the SSR contract for federated themes.
|
|
30
|
+
|
|
31
|
+
### Changed
|
|
32
|
+
|
|
33
|
+
- `mount()` adopts host-server-rendered HTML instead of re-rendering when the
|
|
34
|
+
host passes `hydrate: true`; pure, browser-free global-style-token compute so
|
|
35
|
+
the server render is deterministic.
|
|
8
36
|
|
|
9
37
|
First public release. Full surface documented at [numueg.app/docs/sdk/overview](https://numueg.app/docs/sdk/overview).
|
|
10
38
|
|
|
@@ -11,6 +11,14 @@ interface Store {
|
|
|
11
11
|
default_language: string;
|
|
12
12
|
use_nextjs_storefront: boolean;
|
|
13
13
|
social_links?: Record<string, string>;
|
|
14
|
+
/**
|
|
15
|
+
* Store-level JSONB settings blob. Holds merchant-wide configuration the
|
|
16
|
+
* storefront forwards to themes — e.g. the store-wide default
|
|
17
|
+
* `size_chart` (see {@link SizeChart}) used when a product opts into
|
|
18
|
+
* `mode: "default"`. Untyped here because the shape grows independently
|
|
19
|
+
* of the SDK; narrow it at the read site.
|
|
20
|
+
*/
|
|
21
|
+
settings?: Record<string, unknown>;
|
|
14
22
|
}
|
|
15
23
|
/** Product entity */
|
|
16
24
|
interface Product {
|
|
@@ -30,6 +38,42 @@ interface Product {
|
|
|
30
38
|
in_stock: boolean;
|
|
31
39
|
seo_title?: string;
|
|
32
40
|
seo_description?: string;
|
|
41
|
+
/**
|
|
42
|
+
* Per-product JSONB attribute blob the storefront forwards verbatim.
|
|
43
|
+
* Holds translated fields (`name_ar`, … — see `useFieldTranslation`) and
|
|
44
|
+
* the per-product `size_chart` ({@link SizeChart}). Untyped because the
|
|
45
|
+
* shape is open-ended; `useProductSizeChart` narrows the size-chart slot.
|
|
46
|
+
*/
|
|
47
|
+
attributes?: Record<string, unknown>;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Size-chart resolution mode (mirrors the merchant hub's editor).
|
|
51
|
+
*
|
|
52
|
+
* "custom" → use the product's own chart
|
|
53
|
+
* "default" → fall back to the store-wide chart (`store.settings.size_chart`)
|
|
54
|
+
* "off" → never show, even if a store default exists
|
|
55
|
+
*/
|
|
56
|
+
type SizeChartMode = "default" | "custom" | "off";
|
|
57
|
+
/**
|
|
58
|
+
* A size / measurement chart, stored per-product at
|
|
59
|
+
* `product.attributes.size_chart` and store-wide at
|
|
60
|
+
* `store.settings.size_chart`. Resolve the two with {@link useProductSizeChart}
|
|
61
|
+
* instead of reading the raw blobs.
|
|
62
|
+
*/
|
|
63
|
+
interface SizeChart {
|
|
64
|
+
/** Legacy boolean kept for charts written before `mode` existed. */
|
|
65
|
+
enabled?: boolean;
|
|
66
|
+
mode?: SizeChartMode;
|
|
67
|
+
/** Column labels, e.g. ["Chest", "Waist", "Hip"]. */
|
|
68
|
+
column_headers: string[];
|
|
69
|
+
/** One row per size; `values` aligns to `column_headers`. */
|
|
70
|
+
rows: Array<{
|
|
71
|
+
size: string;
|
|
72
|
+
values: string[];
|
|
73
|
+
}>;
|
|
74
|
+
unit?: "cm" | "in" | "kg";
|
|
75
|
+
notes?: string;
|
|
76
|
+
image_url?: string;
|
|
33
77
|
}
|
|
34
78
|
interface ProductImage {
|
|
35
79
|
id: string;
|
|
@@ -181,4 +225,4 @@ interface Page {
|
|
|
181
225
|
data?: Record<string, any>;
|
|
182
226
|
}
|
|
183
227
|
|
|
184
|
-
export type { Address as A, Cart as C, Order as O, Page as P,
|
|
228
|
+
export type { Address as A, Cart as C, Order as O, Page as P, SizeChart as S, CartItem as a, Collection as b, Customer as c, OrderItem as d, Product as e, ProductImage as f, ProductVariant as g, SizeChartMode as h, Store as i, ProductOption as j };
|
|
@@ -11,6 +11,14 @@ interface Store {
|
|
|
11
11
|
default_language: string;
|
|
12
12
|
use_nextjs_storefront: boolean;
|
|
13
13
|
social_links?: Record<string, string>;
|
|
14
|
+
/**
|
|
15
|
+
* Store-level JSONB settings blob. Holds merchant-wide configuration the
|
|
16
|
+
* storefront forwards to themes — e.g. the store-wide default
|
|
17
|
+
* `size_chart` (see {@link SizeChart}) used when a product opts into
|
|
18
|
+
* `mode: "default"`. Untyped here because the shape grows independently
|
|
19
|
+
* of the SDK; narrow it at the read site.
|
|
20
|
+
*/
|
|
21
|
+
settings?: Record<string, unknown>;
|
|
14
22
|
}
|
|
15
23
|
/** Product entity */
|
|
16
24
|
interface Product {
|
|
@@ -30,6 +38,42 @@ interface Product {
|
|
|
30
38
|
in_stock: boolean;
|
|
31
39
|
seo_title?: string;
|
|
32
40
|
seo_description?: string;
|
|
41
|
+
/**
|
|
42
|
+
* Per-product JSONB attribute blob the storefront forwards verbatim.
|
|
43
|
+
* Holds translated fields (`name_ar`, … — see `useFieldTranslation`) and
|
|
44
|
+
* the per-product `size_chart` ({@link SizeChart}). Untyped because the
|
|
45
|
+
* shape is open-ended; `useProductSizeChart` narrows the size-chart slot.
|
|
46
|
+
*/
|
|
47
|
+
attributes?: Record<string, unknown>;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Size-chart resolution mode (mirrors the merchant hub's editor).
|
|
51
|
+
*
|
|
52
|
+
* "custom" → use the product's own chart
|
|
53
|
+
* "default" → fall back to the store-wide chart (`store.settings.size_chart`)
|
|
54
|
+
* "off" → never show, even if a store default exists
|
|
55
|
+
*/
|
|
56
|
+
type SizeChartMode = "default" | "custom" | "off";
|
|
57
|
+
/**
|
|
58
|
+
* A size / measurement chart, stored per-product at
|
|
59
|
+
* `product.attributes.size_chart` and store-wide at
|
|
60
|
+
* `store.settings.size_chart`. Resolve the two with {@link useProductSizeChart}
|
|
61
|
+
* instead of reading the raw blobs.
|
|
62
|
+
*/
|
|
63
|
+
interface SizeChart {
|
|
64
|
+
/** Legacy boolean kept for charts written before `mode` existed. */
|
|
65
|
+
enabled?: boolean;
|
|
66
|
+
mode?: SizeChartMode;
|
|
67
|
+
/** Column labels, e.g. ["Chest", "Waist", "Hip"]. */
|
|
68
|
+
column_headers: string[];
|
|
69
|
+
/** One row per size; `values` aligns to `column_headers`. */
|
|
70
|
+
rows: Array<{
|
|
71
|
+
size: string;
|
|
72
|
+
values: string[];
|
|
73
|
+
}>;
|
|
74
|
+
unit?: "cm" | "in" | "kg";
|
|
75
|
+
notes?: string;
|
|
76
|
+
image_url?: string;
|
|
33
77
|
}
|
|
34
78
|
interface ProductImage {
|
|
35
79
|
id: string;
|
|
@@ -181,4 +225,4 @@ interface Page {
|
|
|
181
225
|
data?: Record<string, any>;
|
|
182
226
|
}
|
|
183
227
|
|
|
184
|
-
export type { Address as A, Cart as C, Order as O, Page as P,
|
|
228
|
+
export type { Address as A, Cart as C, Order as O, Page as P, SizeChart as S, CartItem as a, Collection as b, Customer as c, OrderItem as d, Product as e, ProductImage as f, ProductVariant as g, SizeChartMode as h, Store as i, ProductOption as j };
|
package/dist/index.cjs
CHANGED
|
@@ -528,9 +528,8 @@ function toNavigationItem(raw, locale) {
|
|
|
528
528
|
url: raw.url || "/",
|
|
529
529
|
resource_type: mapResourceType(raw.type),
|
|
530
530
|
resource_handle: raw.resource_id ?? null,
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
)
|
|
531
|
+
target_visible: raw.target_visible !== false,
|
|
532
|
+
children: (raw.children ?? []).map((child) => toNavigationItem(child, locale)).filter((child) => child.target_visible)
|
|
534
533
|
};
|
|
535
534
|
}
|
|
536
535
|
function useNavigation(handle, options) {
|
|
@@ -540,7 +539,8 @@ function useNavigation(handle, options) {
|
|
|
540
539
|
const hostProvidedAny = !!navMap && Object.keys(navMap).length > 0;
|
|
541
540
|
const rawItems = handle ? navMap?.[handle] : void 0;
|
|
542
541
|
const hostItems = react.useMemo(() => {
|
|
543
|
-
if (rawItems)
|
|
542
|
+
if (rawItems)
|
|
543
|
+
return rawItems.map((it) => toNavigationItem(it, locale)).filter((it) => it.target_visible);
|
|
544
544
|
if (hostProvidedAny) return [];
|
|
545
545
|
return null;
|
|
546
546
|
}, [rawItems, hostProvidedAny, locale]);
|
|
@@ -942,6 +942,29 @@ function useRelatedProducts(productId, options = {}) {
|
|
|
942
942
|
}, [productId, limit]);
|
|
943
943
|
return { items, loading, error };
|
|
944
944
|
}
|
|
945
|
+
function useProductSizeChart(productOverride) {
|
|
946
|
+
const ctxProduct = useProductOptional();
|
|
947
|
+
const product = productOverride ?? ctxProduct;
|
|
948
|
+
const shop = useShop();
|
|
949
|
+
const storeSettings = shop?.settings;
|
|
950
|
+
return react.useMemo(
|
|
951
|
+
() => resolveSizeChart(product?.attributes, storeSettings),
|
|
952
|
+
[product?.attributes, storeSettings]
|
|
953
|
+
);
|
|
954
|
+
}
|
|
955
|
+
function hasRows(c) {
|
|
956
|
+
return !!c && typeof c === "object" && Array.isArray(c.rows) && c.rows.length > 0;
|
|
957
|
+
}
|
|
958
|
+
function resolveSizeChart(productAttributes, storeSettings) {
|
|
959
|
+
const product = productAttributes?.size_chart;
|
|
960
|
+
const storeDefault = storeSettings?.size_chart;
|
|
961
|
+
if (product?.mode === "off") return null;
|
|
962
|
+
if (product?.mode === "custom") return hasRows(product) ? product : null;
|
|
963
|
+
if (product?.mode === "default") return hasRows(storeDefault) ? storeDefault : null;
|
|
964
|
+
if (hasRows(product)) return product;
|
|
965
|
+
if (hasRows(storeDefault)) return storeDefault;
|
|
966
|
+
return null;
|
|
967
|
+
}
|
|
945
968
|
var COOKIE_NAME = "numu_currency";
|
|
946
969
|
var COOKIE_MAX_AGE = 60 * 60 * 24 * 30;
|
|
947
970
|
function readCookie(name) {
|
|
@@ -1454,7 +1477,15 @@ function normalizeCartFromServer(cart) {
|
|
|
1454
1477
|
subtotal: toMajor(cart.subtotal),
|
|
1455
1478
|
total: toMajor(cart.total),
|
|
1456
1479
|
...cart.discount_amount != null ? { discount_amount: toMajor(cart.discount_amount) } : {},
|
|
1457
|
-
items: Array.isArray(cart.items) ? cart.items.map((it) =>
|
|
1480
|
+
items: Array.isArray(cart.items) ? cart.items.map((it) => {
|
|
1481
|
+
const raw = it;
|
|
1482
|
+
return {
|
|
1483
|
+
...it,
|
|
1484
|
+
name: raw.name || raw.product_name || "",
|
|
1485
|
+
price: toMajor(raw.price ?? raw.unit_price),
|
|
1486
|
+
variant_name: raw.variant_name ?? void 0
|
|
1487
|
+
};
|
|
1488
|
+
}) : []
|
|
1458
1489
|
};
|
|
1459
1490
|
}
|
|
1460
1491
|
function unwrapCart(json) {
|
|
@@ -1991,6 +2022,9 @@ function injectFontLink(href) {
|
|
|
1991
2022
|
link.setAttribute("data-numu-font", "");
|
|
1992
2023
|
document.head.appendChild(link);
|
|
1993
2024
|
}
|
|
2025
|
+
function lookupFontStack(value) {
|
|
2026
|
+
return FONT_REGISTRY[value]?.stack ?? value;
|
|
2027
|
+
}
|
|
1994
2028
|
function resolveFontStack(value) {
|
|
1995
2029
|
const entry = FONT_REGISTRY[value];
|
|
1996
2030
|
if (entry) {
|
|
@@ -1999,39 +2033,69 @@ function resolveFontStack(value) {
|
|
|
1999
2033
|
}
|
|
2000
2034
|
return value;
|
|
2001
2035
|
}
|
|
2002
|
-
function
|
|
2003
|
-
|
|
2004
|
-
const
|
|
2036
|
+
function computeGlobalStyleTokens(globalSettings) {
|
|
2037
|
+
const cssVars = {};
|
|
2038
|
+
const fontHrefs = [];
|
|
2039
|
+
if (!globalSettings || typeof globalSettings !== "object") {
|
|
2040
|
+
return { cssVars, fontHrefs };
|
|
2041
|
+
}
|
|
2042
|
+
const pushHref = (href) => {
|
|
2043
|
+
if (href && !fontHrefs.includes(href)) fontHrefs.push(href);
|
|
2044
|
+
};
|
|
2005
2045
|
for (const [key, value] of Object.entries(globalSettings)) {
|
|
2006
2046
|
if (!key || key.startsWith("__")) continue;
|
|
2007
2047
|
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
2008
2048
|
for (const [role, c] of Object.entries(value)) {
|
|
2009
|
-
if (isColorValue(c))
|
|
2049
|
+
if (isColorValue(c)) cssVars[`--scheme-${key}-${role}`] = c;
|
|
2010
2050
|
}
|
|
2011
2051
|
continue;
|
|
2012
2052
|
}
|
|
2013
2053
|
if (isColorValue(value)) {
|
|
2014
|
-
|
|
2054
|
+
cssVars[`--theme-${key}`] = value.trim();
|
|
2015
2055
|
const role = COLOR_ROLE_ALIASES[key];
|
|
2016
|
-
if (role)
|
|
2056
|
+
if (role) cssVars[`--theme-color-${role}`] = value.trim();
|
|
2017
2057
|
continue;
|
|
2018
2058
|
}
|
|
2019
2059
|
if (isFontToken(value)) {
|
|
2020
|
-
const
|
|
2021
|
-
|
|
2060
|
+
const entry = FONT_REGISTRY[value];
|
|
2061
|
+
cssVars[`--theme-${key}`] = entry.stack;
|
|
2022
2062
|
const role = FONT_ROLE_ALIASES[key];
|
|
2023
|
-
if (role)
|
|
2063
|
+
if (role) cssVars[`--theme-font-${role}`] = entry.stack;
|
|
2064
|
+
pushHref(entry.href);
|
|
2024
2065
|
continue;
|
|
2025
2066
|
}
|
|
2026
2067
|
if (typeof value === "string" || typeof value === "number") {
|
|
2027
2068
|
const v = String(value).trim();
|
|
2028
|
-
if (v)
|
|
2069
|
+
if (v) cssVars[`--theme-${key}`] = v;
|
|
2070
|
+
}
|
|
2071
|
+
}
|
|
2072
|
+
for (const id of ["heading_font", "body_font"]) {
|
|
2073
|
+
const value = globalSettings[id];
|
|
2074
|
+
if (typeof value === "string" && value.trim()) {
|
|
2075
|
+
cssVars[`--theme-${id}`] = lookupFontStack(value);
|
|
2076
|
+
pushHref(FONT_REGISTRY[value]?.href);
|
|
2029
2077
|
}
|
|
2030
2078
|
}
|
|
2079
|
+
return { cssVars, fontHrefs };
|
|
2080
|
+
}
|
|
2081
|
+
function applyGlobalStyleTokens(globalSettings, el) {
|
|
2082
|
+
if (!el || !globalSettings || typeof globalSettings !== "object") return;
|
|
2083
|
+
const { cssVars, fontHrefs } = computeGlobalStyleTokens(globalSettings);
|
|
2084
|
+
const style = el.style;
|
|
2085
|
+
for (const [prop, value] of Object.entries(cssVars)) {
|
|
2086
|
+
style.setProperty(prop, value);
|
|
2087
|
+
}
|
|
2088
|
+
for (const href of fontHrefs) injectFontLink(href);
|
|
2031
2089
|
}
|
|
2032
2090
|
function pickStore(ctx) {
|
|
2033
2091
|
const s = ctx.storeData ?? ctx.store;
|
|
2034
|
-
if (s)
|
|
2092
|
+
if (s) {
|
|
2093
|
+
const raw = s;
|
|
2094
|
+
if (!raw.currency && raw.default_currency) {
|
|
2095
|
+
return { ...raw, currency: raw.default_currency };
|
|
2096
|
+
}
|
|
2097
|
+
return s;
|
|
2098
|
+
}
|
|
2035
2099
|
return {
|
|
2036
2100
|
id: "unknown",
|
|
2037
2101
|
name: "Store",
|
|
@@ -2066,19 +2130,9 @@ var ThemeMountBridge = react.forwardRef(function ThemeMountBridge2({ ctx, mountE
|
|
|
2066
2130
|
[]
|
|
2067
2131
|
);
|
|
2068
2132
|
react.useEffect(() => {
|
|
2133
|
+
if (!mountEl) return;
|
|
2069
2134
|
const gs = themeSettings.global_settings ?? {};
|
|
2070
2135
|
applyGlobalStyleTokens(gs, mountEl);
|
|
2071
|
-
const headingFont = gs.heading_font;
|
|
2072
|
-
if (typeof headingFont === "string" && headingFont.trim()) {
|
|
2073
|
-
mountEl.style.setProperty(
|
|
2074
|
-
"--theme-heading_font",
|
|
2075
|
-
resolveFontStack(headingFont)
|
|
2076
|
-
);
|
|
2077
|
-
}
|
|
2078
|
-
const bodyFont = gs.body_font;
|
|
2079
|
-
if (typeof bodyFont === "string" && bodyFont.trim()) {
|
|
2080
|
-
mountEl.style.setProperty("--theme-body_font", resolveFontStack(bodyFont));
|
|
2081
|
-
}
|
|
2082
2136
|
}, [themeSettings, mountEl]);
|
|
2083
2137
|
const store = pickStore(ctx);
|
|
2084
2138
|
const template = pickTemplate(ctx);
|
|
@@ -2108,22 +2162,22 @@ var ThemeMountBridge = react.forwardRef(function ThemeMountBridge2({ ctx, mountE
|
|
|
2108
2162
|
}
|
|
2109
2163
|
);
|
|
2110
2164
|
});
|
|
2165
|
+
function buildThemeElement(ctx, mountEl, renderApp, ref) {
|
|
2166
|
+
return /* @__PURE__ */ jsxRuntime.jsx(react.StrictMode, { children: /* @__PURE__ */ jsxRuntime.jsx(ThemeMountBridge, { ctx, mountEl, renderApp, ref }) });
|
|
2167
|
+
}
|
|
2111
2168
|
function mountTheme(el, ctx, renderApp) {
|
|
2112
|
-
const root = client.createRoot(el);
|
|
2113
2169
|
const handleRef = { current: null };
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
) })
|
|
2126
|
-
);
|
|
2170
|
+
const element = buildThemeElement(ctx, el, renderApp, (h) => {
|
|
2171
|
+
handleRef.current = h;
|
|
2172
|
+
});
|
|
2173
|
+
const shouldHydrate = ctx.hydrate === true && el.firstElementChild !== null;
|
|
2174
|
+
let root;
|
|
2175
|
+
if (shouldHydrate) {
|
|
2176
|
+
root = client.hydrateRoot(el, element);
|
|
2177
|
+
} else {
|
|
2178
|
+
root = client.createRoot(el);
|
|
2179
|
+
root.render(element);
|
|
2180
|
+
}
|
|
2127
2181
|
return {
|
|
2128
2182
|
applyDraft: (next) => handleRef.current?.applyDraft(next),
|
|
2129
2183
|
cleanup: () => {
|
|
@@ -2132,6 +2186,14 @@ function mountTheme(el, ctx, renderApp) {
|
|
|
2132
2186
|
}
|
|
2133
2187
|
};
|
|
2134
2188
|
}
|
|
2189
|
+
|
|
2190
|
+
// src/entry.tsx
|
|
2191
|
+
function defineThemeEntry(renderApp) {
|
|
2192
|
+
return {
|
|
2193
|
+
mount: (el, ctx) => mountTheme(el, ctx, renderApp),
|
|
2194
|
+
createApp: (ctx) => buildThemeElement(ctx, null, renderApp)
|
|
2195
|
+
};
|
|
2196
|
+
}
|
|
2135
2197
|
function CollectionProvider({ collection, children }) {
|
|
2136
2198
|
return /* @__PURE__ */ jsxRuntime.jsx(CollectionContext.Provider, { value: collection, children });
|
|
2137
2199
|
}
|
|
@@ -2755,7 +2817,14 @@ function sanitizeHtmlServer(input) {
|
|
|
2755
2817
|
return s;
|
|
2756
2818
|
}
|
|
2757
2819
|
function RichText({ html, className, as = "div" }) {
|
|
2758
|
-
const
|
|
2820
|
+
const [domReady, setDomReady] = react.useState(false);
|
|
2821
|
+
react.useEffect(() => {
|
|
2822
|
+
setDomReady(true);
|
|
2823
|
+
}, []);
|
|
2824
|
+
const safe = react.useMemo(
|
|
2825
|
+
() => domReady ? sanitizeHtml(html || "") : sanitizeHtmlServer(html || ""),
|
|
2826
|
+
[html, domReady]
|
|
2827
|
+
);
|
|
2759
2828
|
if (!safe) return null;
|
|
2760
2829
|
const Tag = as;
|
|
2761
2830
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -3421,8 +3490,13 @@ function collectBlocks(modules) {
|
|
|
3421
3490
|
|
|
3422
3491
|
// src/utils/assetUrl.ts
|
|
3423
3492
|
function getRuntime() {
|
|
3424
|
-
if (typeof window
|
|
3425
|
-
|
|
3493
|
+
if (typeof window !== "undefined") {
|
|
3494
|
+
return window;
|
|
3495
|
+
}
|
|
3496
|
+
if (typeof globalThis !== "undefined") {
|
|
3497
|
+
return globalThis;
|
|
3498
|
+
}
|
|
3499
|
+
return {};
|
|
3426
3500
|
}
|
|
3427
3501
|
function assetUrl(name) {
|
|
3428
3502
|
if (!name) return "";
|
|
@@ -3520,12 +3594,15 @@ exports.asImageTransform = asImageTransform;
|
|
|
3520
3594
|
exports.assetUrl = assetUrl;
|
|
3521
3595
|
exports.availableValues = availableValues;
|
|
3522
3596
|
exports.buildLocaleBundle = buildLocaleBundle;
|
|
3597
|
+
exports.buildThemeElement = buildThemeElement;
|
|
3523
3598
|
exports.clearSdkSingleton = clearSdkSingleton;
|
|
3524
3599
|
exports.collectBlocks = collectBlocks;
|
|
3525
3600
|
exports.collectSections = collectSections;
|
|
3601
|
+
exports.computeGlobalStyleTokens = computeGlobalStyleTokens;
|
|
3526
3602
|
exports.defaultVariant = defaultVariant;
|
|
3527
3603
|
exports.defineBlock = defineBlock;
|
|
3528
3604
|
exports.defineSection = defineSection;
|
|
3605
|
+
exports.defineThemeEntry = defineThemeEntry;
|
|
3529
3606
|
exports.dynamicSource = dynamicSource;
|
|
3530
3607
|
exports.findVariantByOptions = findVariantByOptions;
|
|
3531
3608
|
exports.flattenMessages = flattenMessages;
|
|
@@ -3543,6 +3620,7 @@ exports.registerSdkSingleton = registerSdkSingleton;
|
|
|
3543
3620
|
exports.resolveDynamicValue = resolveDynamicValue;
|
|
3544
3621
|
exports.resolveFontStack = resolveFontStack;
|
|
3545
3622
|
exports.resolveSettingsMap = resolveSettingsMap;
|
|
3623
|
+
exports.resolveSizeChart = resolveSizeChart;
|
|
3546
3624
|
exports.resolveSourcePath = resolveSourcePath;
|
|
3547
3625
|
exports.resolveThemeSettings = resolveThemeSettings;
|
|
3548
3626
|
exports.sanitizeHtml = sanitizeHtml;
|
|
@@ -3572,6 +3650,7 @@ exports.useOrders = useOrders;
|
|
|
3572
3650
|
exports.usePage = usePage;
|
|
3573
3651
|
exports.useProduct = useProduct;
|
|
3574
3652
|
exports.useProductOptional = useProductOptional;
|
|
3653
|
+
exports.useProductSizeChart = useProductSizeChart;
|
|
3575
3654
|
exports.useProducts = useProducts;
|
|
3576
3655
|
exports.useRelatedProducts = useRelatedProducts;
|
|
3577
3656
|
exports.useReorder = useReorder;
|