@numueg/theme-sdk 0.1.2 → 0.2.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.
- package/dist/{index-CGx6FNqb.d.ts → entities-iiuRSPpk.d.mts} +1 -3
- package/dist/{index-zSb0FIyh.d.mts → entities-iiuRSPpk.d.ts} +1 -3
- package/dist/index.cjs +763 -43
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +493 -38
- package/dist/index.d.ts +493 -38
- package/dist/index.mjs +747 -45
- package/dist/index.mjs.map +1 -1
- package/dist/normalize.d.mts +1 -1
- package/dist/normalize.d.ts +1 -1
- package/dist/theme-D0QybTQS.d.mts +197 -0
- package/dist/theme-D0QybTQS.d.ts +197 -0
- package/dist/types.d.mts +2 -2
- package/dist/types.d.ts +2 -2
- package/dist/v2-compat.cjs +248 -0
- package/dist/v2-compat.cjs.map +1 -0
- package/dist/v2-compat.d.mts +129 -0
- package/dist/v2-compat.d.ts +129 -0
- package/dist/v2-compat.mjs +242 -0
- package/dist/v2-compat.mjs.map +1 -0
- package/package.json +12 -1
- package/dist/theme-NWJAU9jd.d.mts +0 -128
- package/dist/theme-NWJAU9jd.d.ts +0 -128
package/dist/index.mjs
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import { createContext,
|
|
1
|
+
import { createContext, forwardRef, useState, useImperativeHandle, useEffect, useCallback, useMemo, useRef, useContext, StrictMode, createElement, Component } from 'react';
|
|
2
|
+
import { createRoot } from 'react-dom/client';
|
|
2
3
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
3
4
|
|
|
4
|
-
// src/
|
|
5
|
+
// src/types/theme.ts
|
|
6
|
+
var MAX_BLOCK_DEPTH = 5;
|
|
5
7
|
var ShopContext = createContext(null);
|
|
6
8
|
var ProductContext = createContext(null);
|
|
7
9
|
var CollectionContext = createContext(null);
|
|
@@ -10,6 +12,10 @@ var CustomerContext = createContext(null);
|
|
|
10
12
|
var ThemeSettingsContext = createContext(null);
|
|
11
13
|
var LocalizationContext = createContext(null);
|
|
12
14
|
var PageContext = createContext(null);
|
|
15
|
+
var CurrentTemplateContext = createContext("home");
|
|
16
|
+
var NavigationContext = createContext(
|
|
17
|
+
{}
|
|
18
|
+
);
|
|
13
19
|
function useLocalization() {
|
|
14
20
|
const ctx = useContext(LocalizationContext);
|
|
15
21
|
if (!ctx) throw new Error("useLocalization must be used within NuMuProvider");
|
|
@@ -118,6 +124,9 @@ function useThemeSettings() {
|
|
|
118
124
|
if (!ctx) throw new Error("useThemeSettings must be used within NuMuProvider");
|
|
119
125
|
return ctx;
|
|
120
126
|
}
|
|
127
|
+
function useCurrentTemplate() {
|
|
128
|
+
return useContext(CurrentTemplateContext);
|
|
129
|
+
}
|
|
121
130
|
function usePage() {
|
|
122
131
|
return useContext(PageContext);
|
|
123
132
|
}
|
|
@@ -487,15 +496,67 @@ function useCustomerAddresses() {
|
|
|
487
496
|
};
|
|
488
497
|
}
|
|
489
498
|
var cache = /* @__PURE__ */ new Map();
|
|
499
|
+
function localizeLabel(label, locale) {
|
|
500
|
+
if (!label) return "";
|
|
501
|
+
return label[locale] || label.en || label.ar || Object.values(label).find((v) => !!v) || "";
|
|
502
|
+
}
|
|
503
|
+
function mapResourceType(type) {
|
|
504
|
+
switch (type) {
|
|
505
|
+
case "product":
|
|
506
|
+
return "product";
|
|
507
|
+
case "collection":
|
|
508
|
+
return "collection";
|
|
509
|
+
case "page":
|
|
510
|
+
return "page";
|
|
511
|
+
case "blog":
|
|
512
|
+
return "blog";
|
|
513
|
+
case "article":
|
|
514
|
+
return "article";
|
|
515
|
+
case "http":
|
|
516
|
+
case "url":
|
|
517
|
+
return "url";
|
|
518
|
+
default:
|
|
519
|
+
return null;
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
function toNavigationItem(raw, locale) {
|
|
523
|
+
return {
|
|
524
|
+
id: raw.id,
|
|
525
|
+
title: localizeLabel(raw.label, locale),
|
|
526
|
+
url: raw.url || "/",
|
|
527
|
+
resource_type: mapResourceType(raw.type),
|
|
528
|
+
resource_handle: raw.resource_id ?? null,
|
|
529
|
+
children: (raw.children ?? []).map(
|
|
530
|
+
(child) => toNavigationItem(child, locale)
|
|
531
|
+
)
|
|
532
|
+
};
|
|
533
|
+
}
|
|
490
534
|
function useNavigation(handle, options) {
|
|
535
|
+
const navMap = useContext(NavigationContext);
|
|
536
|
+
const localization = useContext(LocalizationContext);
|
|
537
|
+
const locale = localization?.locale ?? "en";
|
|
538
|
+
const hostProvidedAny = !!navMap && Object.keys(navMap).length > 0;
|
|
539
|
+
const rawItems = handle ? navMap?.[handle] : void 0;
|
|
540
|
+
const hostItems = useMemo(() => {
|
|
541
|
+
if (rawItems) return rawItems.map((it) => toNavigationItem(it, locale));
|
|
542
|
+
if (hostProvidedAny) return [];
|
|
543
|
+
return null;
|
|
544
|
+
}, [rawItems, hostProvidedAny, locale]);
|
|
491
545
|
const [items, setItems] = useState(
|
|
492
|
-
options?.initialItems ?? cache.get(handle) ?? []
|
|
546
|
+
hostItems ?? options?.initialItems ?? cache.get(handle) ?? []
|
|
493
547
|
);
|
|
494
548
|
const [loading, setLoading] = useState(
|
|
495
|
-
!options?.initialItems && !cache.has(handle)
|
|
549
|
+
hostItems === null && !options?.initialItems && !cache.has(handle)
|
|
496
550
|
);
|
|
497
551
|
const [error, setError] = useState(null);
|
|
498
552
|
useEffect(() => {
|
|
553
|
+
if (hostItems === null) return;
|
|
554
|
+
setItems(hostItems);
|
|
555
|
+
setLoading(false);
|
|
556
|
+
setError(null);
|
|
557
|
+
}, [hostItems]);
|
|
558
|
+
useEffect(() => {
|
|
559
|
+
if (hostItems !== null) return;
|
|
499
560
|
if (typeof window === "undefined") return;
|
|
500
561
|
if (!handle) {
|
|
501
562
|
setItems([]);
|
|
@@ -538,7 +599,7 @@ function useNavigation(handle, options) {
|
|
|
538
599
|
return () => {
|
|
539
600
|
cancelled = true;
|
|
540
601
|
};
|
|
541
|
-
}, [handle]);
|
|
602
|
+
}, [handle, hostItems === null]);
|
|
542
603
|
return { items, loading, error };
|
|
543
604
|
}
|
|
544
605
|
var EMPTY = {
|
|
@@ -612,34 +673,92 @@ function useSearch(query, options = {}) {
|
|
|
612
673
|
}, [query, mode, debounceMs, immediate, limit, types?.join(",")]);
|
|
613
674
|
return { query, results, loading, error };
|
|
614
675
|
}
|
|
676
|
+
var EVENT_TO_FUNNEL_STEP = {
|
|
677
|
+
page_view: "page_view",
|
|
678
|
+
view_item: "product_view",
|
|
679
|
+
view_collection: "page_view",
|
|
680
|
+
add_to_cart: "add_to_cart",
|
|
681
|
+
begin_checkout: "checkout_started",
|
|
682
|
+
purchase: "order_completed",
|
|
683
|
+
// Wave 2+ standard Meta events — backend's FUNNEL_STEP_TO_META_EVENT
|
|
684
|
+
// table accepts these as funnel steps directly.
|
|
685
|
+
search: "search",
|
|
686
|
+
lead: "lead",
|
|
687
|
+
sign_up: "complete_registration",
|
|
688
|
+
add_to_wishlist: "add_to_wishlist",
|
|
689
|
+
add_payment_info: "add_payment_info"
|
|
690
|
+
};
|
|
691
|
+
function readAttribution() {
|
|
692
|
+
if (typeof window === "undefined") return null;
|
|
693
|
+
try {
|
|
694
|
+
return window.__numu_attribution?.get?.() ?? null;
|
|
695
|
+
} catch {
|
|
696
|
+
return null;
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
function readCustomerId() {
|
|
700
|
+
if (typeof window === "undefined") return null;
|
|
701
|
+
try {
|
|
702
|
+
return window.__numu_customer?.getId?.() ?? null;
|
|
703
|
+
} catch {
|
|
704
|
+
return null;
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
function getFingerprint() {
|
|
708
|
+
if (typeof window === "undefined") return "ssr";
|
|
709
|
+
const env = readAttribution();
|
|
710
|
+
if (env?.session_id) return env.session_id;
|
|
711
|
+
const w = window;
|
|
712
|
+
if (w.__numu_session_fp) return w.__numu_session_fp;
|
|
713
|
+
const fp = crypto.randomUUID();
|
|
714
|
+
w.__numu_session_fp = fp;
|
|
715
|
+
return fp;
|
|
716
|
+
}
|
|
717
|
+
function dispatchAnalyticsEvent(eventName, payload = {}) {
|
|
718
|
+
if (typeof window === "undefined") return;
|
|
719
|
+
try {
|
|
720
|
+
window.dispatchEvent(
|
|
721
|
+
new CustomEvent("numu:analytics:event", {
|
|
722
|
+
detail: { event: eventName, payload, ts: Date.now() }
|
|
723
|
+
})
|
|
724
|
+
);
|
|
725
|
+
} catch {
|
|
726
|
+
}
|
|
727
|
+
const step = EVENT_TO_FUNNEL_STEP[eventName] ?? null;
|
|
728
|
+
const customerId = readCustomerId();
|
|
729
|
+
const body = step ? {
|
|
730
|
+
event_id: crypto.randomUUID(),
|
|
731
|
+
path: window.location.pathname,
|
|
732
|
+
fingerprint: getFingerprint(),
|
|
733
|
+
step,
|
|
734
|
+
step_data: payload,
|
|
735
|
+
referrer: typeof document !== "undefined" && document.referrer ? document.referrer : void 0,
|
|
736
|
+
attribution: readAttribution() ?? void 0,
|
|
737
|
+
customer_id: customerId ?? void 0
|
|
738
|
+
} : {
|
|
739
|
+
event: eventName,
|
|
740
|
+
payload,
|
|
741
|
+
ts: Date.now(),
|
|
742
|
+
attribution: readAttribution() ?? void 0,
|
|
743
|
+
customer_id: customerId ?? void 0
|
|
744
|
+
};
|
|
745
|
+
void (async () => {
|
|
746
|
+
try {
|
|
747
|
+
await fetch("/api/storefront/track", {
|
|
748
|
+
method: "POST",
|
|
749
|
+
headers: { "Content-Type": "application/json" },
|
|
750
|
+
body: JSON.stringify(body),
|
|
751
|
+
keepalive: true
|
|
752
|
+
// survive page-unload (e.g. begin_checkout → redirect)
|
|
753
|
+
});
|
|
754
|
+
} catch {
|
|
755
|
+
}
|
|
756
|
+
})();
|
|
757
|
+
}
|
|
615
758
|
function useAnalytics() {
|
|
616
759
|
const track = useCallback(
|
|
617
760
|
(eventName, payload = {}) => {
|
|
618
|
-
|
|
619
|
-
try {
|
|
620
|
-
window.dispatchEvent(
|
|
621
|
-
new CustomEvent("numu:analytics:event", {
|
|
622
|
-
detail: { event: eventName, payload, ts: Date.now() }
|
|
623
|
-
})
|
|
624
|
-
);
|
|
625
|
-
} catch {
|
|
626
|
-
}
|
|
627
|
-
void (async () => {
|
|
628
|
-
try {
|
|
629
|
-
await fetch("/api/storefront/track", {
|
|
630
|
-
method: "POST",
|
|
631
|
-
headers: { "Content-Type": "application/json" },
|
|
632
|
-
body: JSON.stringify({
|
|
633
|
-
event: eventName,
|
|
634
|
-
payload,
|
|
635
|
-
ts: Date.now()
|
|
636
|
-
}),
|
|
637
|
-
keepalive: true
|
|
638
|
-
// survive page-unload (e.g. begin_checkout → redirect)
|
|
639
|
-
});
|
|
640
|
-
} catch {
|
|
641
|
-
}
|
|
642
|
-
})();
|
|
761
|
+
dispatchAnalyticsEvent(eventName, payload);
|
|
643
762
|
},
|
|
644
763
|
[]
|
|
645
764
|
);
|
|
@@ -1355,8 +1474,23 @@ function NuMuProvider({
|
|
|
1355
1474
|
customer,
|
|
1356
1475
|
locale: initialLocale,
|
|
1357
1476
|
translations: initialTranslations,
|
|
1477
|
+
currentTemplate = "home",
|
|
1478
|
+
initialProducts,
|
|
1479
|
+
initialCollections,
|
|
1480
|
+
navigation,
|
|
1358
1481
|
children
|
|
1359
1482
|
}) {
|
|
1483
|
+
const pageValue = useMemo(
|
|
1484
|
+
() => ({
|
|
1485
|
+
type: currentTemplate,
|
|
1486
|
+
title: store?.name ?? "",
|
|
1487
|
+
data: {
|
|
1488
|
+
products: initialProducts ?? [],
|
|
1489
|
+
collections: initialCollections ?? []
|
|
1490
|
+
}
|
|
1491
|
+
}),
|
|
1492
|
+
[currentTemplate, store?.name, initialProducts, initialCollections]
|
|
1493
|
+
);
|
|
1360
1494
|
const [cart, setCart] = useState(
|
|
1361
1495
|
initialCart || { ...EMPTY_CART, currency: store.currency }
|
|
1362
1496
|
);
|
|
@@ -1726,11 +1860,238 @@ function NuMuProvider({
|
|
|
1726
1860
|
defaultNumberFmt
|
|
1727
1861
|
]
|
|
1728
1862
|
);
|
|
1729
|
-
return /* @__PURE__ */ jsx(ShopContext.Provider, { value: store, children: /* @__PURE__ */ jsx(ThemeSettingsContext.Provider, { value: themeSettings, children: /* @__PURE__ */ jsx(LocalizationContext.Provider, { value: localization, children: /* @__PURE__ */ jsx(CartContext.Provider, { value: cartValue, children: /* @__PURE__ */ jsx(CustomerContext.Provider, { value: customerState, children: /* @__PURE__ */ jsx(CustomerActionsContext.Provider, { value: customerActions, children }) }) }) }) }) });
|
|
1863
|
+
return /* @__PURE__ */ jsx(ShopContext.Provider, { value: store, children: /* @__PURE__ */ jsx(ThemeSettingsContext.Provider, { value: themeSettings, children: /* @__PURE__ */ jsx(CurrentTemplateContext.Provider, { value: currentTemplate, children: /* @__PURE__ */ jsx(PageContext.Provider, { value: pageValue, children: /* @__PURE__ */ jsx(LocalizationContext.Provider, { value: localization, children: /* @__PURE__ */ jsx(CartContext.Provider, { value: cartValue, children: /* @__PURE__ */ jsx(CustomerContext.Provider, { value: customerState, children: /* @__PURE__ */ jsx(CustomerActionsContext.Provider, { value: customerActions, children: /* @__PURE__ */ jsx(NavigationContext.Provider, { value: navigation ?? {}, children }) }) }) }) }) }) }) }) });
|
|
1730
1864
|
}
|
|
1731
1865
|
function ProductProvider({ product, children }) {
|
|
1732
1866
|
return /* @__PURE__ */ jsx(ProductContext.Provider, { value: product, children });
|
|
1733
1867
|
}
|
|
1868
|
+
|
|
1869
|
+
// src/utils/styleTokens.ts
|
|
1870
|
+
var COLOR_ROLE_ALIASES = {
|
|
1871
|
+
background_color: "background",
|
|
1872
|
+
color_background: "background",
|
|
1873
|
+
bg_color: "background",
|
|
1874
|
+
text_color: "text",
|
|
1875
|
+
color_text: "text",
|
|
1876
|
+
primary_color: "primary",
|
|
1877
|
+
color_primary: "primary",
|
|
1878
|
+
secondary_color: "secondary",
|
|
1879
|
+
color_secondary: "secondary",
|
|
1880
|
+
accent_color: "accent",
|
|
1881
|
+
color_accent: "accent",
|
|
1882
|
+
border_color: "border",
|
|
1883
|
+
color_border: "border",
|
|
1884
|
+
button_color: "button",
|
|
1885
|
+
color_button: "button",
|
|
1886
|
+
button_text_color: "button-text",
|
|
1887
|
+
color_button_text: "button-text"
|
|
1888
|
+
};
|
|
1889
|
+
var FONT_ROLE_ALIASES = {
|
|
1890
|
+
heading_font: "heading",
|
|
1891
|
+
font_heading: "heading",
|
|
1892
|
+
headings_font: "heading",
|
|
1893
|
+
body_font: "body",
|
|
1894
|
+
font_body: "body",
|
|
1895
|
+
text_font: "body"
|
|
1896
|
+
};
|
|
1897
|
+
var FONT_REGISTRY = {
|
|
1898
|
+
cormorant: {
|
|
1899
|
+
stack: '"Cormorant Garamond", Georgia, "Times New Roman", serif',
|
|
1900
|
+
href: "https://fonts.googleapis.com/css2?family=Cormorant+Garamond:ital,wght@0,400;0,500;0,600;0,700;1,400&display=swap"
|
|
1901
|
+
},
|
|
1902
|
+
"dm-sans": {
|
|
1903
|
+
stack: '"DM Sans", system-ui, -apple-system, "Segoe UI", sans-serif',
|
|
1904
|
+
href: "https://fonts.googleapis.com/css2?family=DM+Sans:ital,opsz,wght@0,9..40,400;0,9..40,500;0,9..40,700&display=swap"
|
|
1905
|
+
},
|
|
1906
|
+
playfair: {
|
|
1907
|
+
stack: '"Playfair Display", Georgia, serif',
|
|
1908
|
+
href: "https://fonts.googleapis.com/css2?family=Playfair+Display:wght@400;500;600;700&display=swap"
|
|
1909
|
+
},
|
|
1910
|
+
inter: {
|
|
1911
|
+
stack: '"Inter", system-ui, -apple-system, sans-serif',
|
|
1912
|
+
href: "https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap"
|
|
1913
|
+
},
|
|
1914
|
+
poppins: {
|
|
1915
|
+
stack: '"Poppins", system-ui, sans-serif',
|
|
1916
|
+
href: "https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600;700&display=swap"
|
|
1917
|
+
},
|
|
1918
|
+
montserrat: {
|
|
1919
|
+
stack: '"Montserrat", system-ui, sans-serif',
|
|
1920
|
+
href: "https://fonts.googleapis.com/css2?family=Montserrat:wght@400;500;600;700&display=swap"
|
|
1921
|
+
},
|
|
1922
|
+
lora: {
|
|
1923
|
+
stack: '"Lora", Georgia, serif',
|
|
1924
|
+
href: "https://fonts.googleapis.com/css2?family=Lora:ital,wght@0,400;0,500;0,600;1,400&display=swap"
|
|
1925
|
+
},
|
|
1926
|
+
cairo: {
|
|
1927
|
+
stack: '"Cairo", system-ui, sans-serif',
|
|
1928
|
+
href: "https://fonts.googleapis.com/css2?family=Cairo:wght@400;500;600;700&display=swap"
|
|
1929
|
+
},
|
|
1930
|
+
tajawal: {
|
|
1931
|
+
stack: '"Tajawal", system-ui, sans-serif',
|
|
1932
|
+
href: "https://fonts.googleapis.com/css2?family=Tajawal:wght@400;500;700&display=swap"
|
|
1933
|
+
}
|
|
1934
|
+
};
|
|
1935
|
+
var COLOR_RE = /^(#([0-9a-f]{3,8})|rgba?\(|hsla?\(|color\(|var\()/i;
|
|
1936
|
+
function isColorValue(v) {
|
|
1937
|
+
return typeof v === "string" && COLOR_RE.test(v.trim());
|
|
1938
|
+
}
|
|
1939
|
+
function isFontToken(v) {
|
|
1940
|
+
return typeof v === "string" && Object.prototype.hasOwnProperty.call(FONT_REGISTRY, v);
|
|
1941
|
+
}
|
|
1942
|
+
function injectFontLink(href) {
|
|
1943
|
+
if (typeof document === "undefined" || !href) return;
|
|
1944
|
+
const existing = document.querySelector(
|
|
1945
|
+
`link[data-numu-font][href="${href}"]`
|
|
1946
|
+
);
|
|
1947
|
+
if (existing) return;
|
|
1948
|
+
const link = document.createElement("link");
|
|
1949
|
+
link.rel = "stylesheet";
|
|
1950
|
+
link.href = href;
|
|
1951
|
+
link.setAttribute("data-numu-font", "");
|
|
1952
|
+
document.head.appendChild(link);
|
|
1953
|
+
}
|
|
1954
|
+
function resolveFontStack(value) {
|
|
1955
|
+
const entry = FONT_REGISTRY[value];
|
|
1956
|
+
if (entry) {
|
|
1957
|
+
if (entry.href) injectFontLink(entry.href);
|
|
1958
|
+
return entry.stack;
|
|
1959
|
+
}
|
|
1960
|
+
return value;
|
|
1961
|
+
}
|
|
1962
|
+
function applyGlobalStyleTokens(globalSettings, el) {
|
|
1963
|
+
if (!el || !globalSettings || typeof globalSettings !== "object") return;
|
|
1964
|
+
const style = el.style;
|
|
1965
|
+
for (const [key, value] of Object.entries(globalSettings)) {
|
|
1966
|
+
if (!key || key.startsWith("__")) continue;
|
|
1967
|
+
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
1968
|
+
for (const [role, c] of Object.entries(value)) {
|
|
1969
|
+
if (isColorValue(c)) style.setProperty(`--scheme-${key}-${role}`, c);
|
|
1970
|
+
}
|
|
1971
|
+
continue;
|
|
1972
|
+
}
|
|
1973
|
+
if (isColorValue(value)) {
|
|
1974
|
+
style.setProperty(`--theme-${key}`, value.trim());
|
|
1975
|
+
const role = COLOR_ROLE_ALIASES[key];
|
|
1976
|
+
if (role) style.setProperty(`--theme-color-${role}`, value.trim());
|
|
1977
|
+
continue;
|
|
1978
|
+
}
|
|
1979
|
+
if (isFontToken(value)) {
|
|
1980
|
+
const stack = resolveFontStack(value);
|
|
1981
|
+
style.setProperty(`--theme-${key}`, stack);
|
|
1982
|
+
const role = FONT_ROLE_ALIASES[key];
|
|
1983
|
+
if (role) style.setProperty(`--theme-font-${role}`, stack);
|
|
1984
|
+
continue;
|
|
1985
|
+
}
|
|
1986
|
+
if (typeof value === "string" || typeof value === "number") {
|
|
1987
|
+
const v = String(value).trim();
|
|
1988
|
+
if (v) style.setProperty(`--theme-${key}`, v);
|
|
1989
|
+
}
|
|
1990
|
+
}
|
|
1991
|
+
}
|
|
1992
|
+
function pickStore(ctx) {
|
|
1993
|
+
const s = ctx.storeData ?? ctx.store;
|
|
1994
|
+
if (s) return s;
|
|
1995
|
+
return {
|
|
1996
|
+
id: "unknown",
|
|
1997
|
+
name: "Store",
|
|
1998
|
+
slug: "store",
|
|
1999
|
+
currency: "EGP",
|
|
2000
|
+
default_language: "en",
|
|
2001
|
+
use_nextjs_storefront: true
|
|
2002
|
+
};
|
|
2003
|
+
}
|
|
2004
|
+
function pickTemplate(ctx) {
|
|
2005
|
+
if (typeof ctx.currentTemplate === "string" && ctx.currentTemplate) {
|
|
2006
|
+
return ctx.currentTemplate;
|
|
2007
|
+
}
|
|
2008
|
+
const pageType = ctx.page?.type;
|
|
2009
|
+
if (typeof pageType === "string" && pageType) return pageType;
|
|
2010
|
+
return "home";
|
|
2011
|
+
}
|
|
2012
|
+
function pickDemo(ctx, themeSettings) {
|
|
2013
|
+
if (typeof ctx.demo === "boolean") return ctx.demo;
|
|
2014
|
+
const t = themeSettings.templates;
|
|
2015
|
+
return !t || Object.keys(t).length === 0;
|
|
2016
|
+
}
|
|
2017
|
+
var ThemeMountBridge = forwardRef(function ThemeMountBridge2({ ctx, mountEl, renderApp }, ref) {
|
|
2018
|
+
const [themeSettings, setThemeSettings] = useState(
|
|
2019
|
+
ctx.themeSettings
|
|
2020
|
+
);
|
|
2021
|
+
useImperativeHandle(
|
|
2022
|
+
ref,
|
|
2023
|
+
() => ({
|
|
2024
|
+
applyDraft: (next) => setThemeSettings((prev) => prev === next ? prev : next)
|
|
2025
|
+
}),
|
|
2026
|
+
[]
|
|
2027
|
+
);
|
|
2028
|
+
useEffect(() => {
|
|
2029
|
+
const gs = themeSettings.global_settings ?? {};
|
|
2030
|
+
applyGlobalStyleTokens(gs, mountEl);
|
|
2031
|
+
const headingFont = gs.heading_font;
|
|
2032
|
+
if (typeof headingFont === "string" && headingFont.trim()) {
|
|
2033
|
+
mountEl.style.setProperty(
|
|
2034
|
+
"--theme-heading_font",
|
|
2035
|
+
resolveFontStack(headingFont)
|
|
2036
|
+
);
|
|
2037
|
+
}
|
|
2038
|
+
const bodyFont = gs.body_font;
|
|
2039
|
+
if (typeof bodyFont === "string" && bodyFont.trim()) {
|
|
2040
|
+
mountEl.style.setProperty("--theme-body_font", resolveFontStack(bodyFont));
|
|
2041
|
+
}
|
|
2042
|
+
}, [themeSettings, mountEl]);
|
|
2043
|
+
const store = pickStore(ctx);
|
|
2044
|
+
const template = pickTemplate(ctx);
|
|
2045
|
+
const demo = pickDemo(ctx, themeSettings);
|
|
2046
|
+
const pageData = ctx.page?.data ?? {};
|
|
2047
|
+
const app = renderApp({
|
|
2048
|
+
currentTemplate: template,
|
|
2049
|
+
demo,
|
|
2050
|
+
page: ctx.page ?? null,
|
|
2051
|
+
store,
|
|
2052
|
+
themeSettings
|
|
2053
|
+
});
|
|
2054
|
+
return /* @__PURE__ */ jsx(
|
|
2055
|
+
NuMuProvider,
|
|
2056
|
+
{
|
|
2057
|
+
store,
|
|
2058
|
+
themeSettings,
|
|
2059
|
+
initialCart: ctx.initialCart,
|
|
2060
|
+
customer: ctx.customer,
|
|
2061
|
+
locale: ctx.locale,
|
|
2062
|
+
translations: ctx.translations,
|
|
2063
|
+
navigation: ctx.navigation,
|
|
2064
|
+
initialProducts: pageData.products,
|
|
2065
|
+
initialCollections: pageData.collections,
|
|
2066
|
+
currentTemplate: template,
|
|
2067
|
+
children: pageData.product ? /* @__PURE__ */ jsx(ProductProvider, { product: pageData.product, children: app }) : app
|
|
2068
|
+
}
|
|
2069
|
+
);
|
|
2070
|
+
});
|
|
2071
|
+
function mountTheme(el, ctx, renderApp) {
|
|
2072
|
+
const root = createRoot(el);
|
|
2073
|
+
const handleRef = { current: null };
|
|
2074
|
+
root.render(
|
|
2075
|
+
/* @__PURE__ */ jsx(StrictMode, { children: /* @__PURE__ */ jsx(
|
|
2076
|
+
ThemeMountBridge,
|
|
2077
|
+
{
|
|
2078
|
+
ctx,
|
|
2079
|
+
mountEl: el,
|
|
2080
|
+
renderApp,
|
|
2081
|
+
ref: (h) => {
|
|
2082
|
+
handleRef.current = h;
|
|
2083
|
+
}
|
|
2084
|
+
}
|
|
2085
|
+
) })
|
|
2086
|
+
);
|
|
2087
|
+
return {
|
|
2088
|
+
applyDraft: (next) => handleRef.current?.applyDraft(next),
|
|
2089
|
+
cleanup: () => {
|
|
2090
|
+
root.unmount();
|
|
2091
|
+
handleRef.current = null;
|
|
2092
|
+
}
|
|
2093
|
+
};
|
|
2094
|
+
}
|
|
1734
2095
|
function CollectionProvider({ collection, children }) {
|
|
1735
2096
|
return /* @__PURE__ */ jsx(CollectionContext.Provider, { value: collection, children });
|
|
1736
2097
|
}
|
|
@@ -2373,6 +2734,239 @@ function LocaleSwitcher({
|
|
|
2373
2734
|
}
|
|
2374
2735
|
);
|
|
2375
2736
|
}
|
|
2737
|
+
function useIsEditor() {
|
|
2738
|
+
const [isEditor, setIsEditor] = useState(false);
|
|
2739
|
+
useEffect(() => {
|
|
2740
|
+
if (typeof window === "undefined") return;
|
|
2741
|
+
try {
|
|
2742
|
+
const params = new URLSearchParams(window.location.search);
|
|
2743
|
+
const flag = params.get("editor") === "v3" || params.get("preview") === "true";
|
|
2744
|
+
const inFrame = window.parent !== window;
|
|
2745
|
+
setIsEditor(flag && inFrame);
|
|
2746
|
+
} catch {
|
|
2747
|
+
}
|
|
2748
|
+
}, []);
|
|
2749
|
+
return isEditor;
|
|
2750
|
+
}
|
|
2751
|
+
function postFieldSelected(sectionId, settingId, blockId) {
|
|
2752
|
+
if (typeof window === "undefined") return;
|
|
2753
|
+
if (window.parent === window) return;
|
|
2754
|
+
try {
|
|
2755
|
+
window.parent.postMessage(
|
|
2756
|
+
{
|
|
2757
|
+
type: "numu:editor:select-field",
|
|
2758
|
+
payload: {
|
|
2759
|
+
sectionId,
|
|
2760
|
+
blockId: blockId ?? null,
|
|
2761
|
+
settingId
|
|
2762
|
+
}
|
|
2763
|
+
},
|
|
2764
|
+
"*"
|
|
2765
|
+
);
|
|
2766
|
+
} catch {
|
|
2767
|
+
}
|
|
2768
|
+
}
|
|
2769
|
+
var EditableText = forwardRef(
|
|
2770
|
+
function EditableText2({
|
|
2771
|
+
sectionId,
|
|
2772
|
+
blockId,
|
|
2773
|
+
settingId,
|
|
2774
|
+
value,
|
|
2775
|
+
as: Component2 = "span",
|
|
2776
|
+
html = false,
|
|
2777
|
+
placeholder,
|
|
2778
|
+
className,
|
|
2779
|
+
onClick,
|
|
2780
|
+
style,
|
|
2781
|
+
...rest
|
|
2782
|
+
}, ref) {
|
|
2783
|
+
const isEditor = useIsEditor();
|
|
2784
|
+
const handleClick = useCallback(
|
|
2785
|
+
(e) => {
|
|
2786
|
+
onClick?.(e);
|
|
2787
|
+
if (!isEditor) return;
|
|
2788
|
+
e.stopPropagation();
|
|
2789
|
+
postFieldSelected(sectionId, settingId, blockId);
|
|
2790
|
+
},
|
|
2791
|
+
[isEditor, onClick, sectionId, settingId, blockId]
|
|
2792
|
+
);
|
|
2793
|
+
const editorAttrs = useMemo(
|
|
2794
|
+
() => isEditor ? {
|
|
2795
|
+
"data-numu-editable": "text",
|
|
2796
|
+
"data-numu-section-id": sectionId,
|
|
2797
|
+
"data-numu-setting-id": settingId,
|
|
2798
|
+
"data-numu-block-id": blockId ?? void 0,
|
|
2799
|
+
role: "button",
|
|
2800
|
+
tabIndex: 0
|
|
2801
|
+
} : {},
|
|
2802
|
+
[isEditor, sectionId, settingId, blockId]
|
|
2803
|
+
);
|
|
2804
|
+
const effectiveStyle = isEditor ? {
|
|
2805
|
+
...style,
|
|
2806
|
+
cursor: "text",
|
|
2807
|
+
// Subtle dotted underline so the merchant discovers what's
|
|
2808
|
+
// editable. The dashed style + inherited color keeps the
|
|
2809
|
+
// affordance from clashing with the theme's typography.
|
|
2810
|
+
textDecoration: "underline dotted rgba(99, 102, 241, 0.7)",
|
|
2811
|
+
textUnderlineOffset: "4px"
|
|
2812
|
+
} : style;
|
|
2813
|
+
const isEmpty = value == null || value === "";
|
|
2814
|
+
const display = isEmpty && placeholder !== void 0 ? placeholder : value ?? "";
|
|
2815
|
+
if (html && typeof display === "string") {
|
|
2816
|
+
return /* @__PURE__ */ jsx(
|
|
2817
|
+
Component2,
|
|
2818
|
+
{
|
|
2819
|
+
ref,
|
|
2820
|
+
className,
|
|
2821
|
+
style: effectiveStyle,
|
|
2822
|
+
onClick: handleClick,
|
|
2823
|
+
dangerouslySetInnerHTML: { __html: display },
|
|
2824
|
+
...editorAttrs,
|
|
2825
|
+
...rest
|
|
2826
|
+
}
|
|
2827
|
+
);
|
|
2828
|
+
}
|
|
2829
|
+
return /* @__PURE__ */ jsx(
|
|
2830
|
+
Component2,
|
|
2831
|
+
{
|
|
2832
|
+
ref,
|
|
2833
|
+
className,
|
|
2834
|
+
style: effectiveStyle,
|
|
2835
|
+
onClick: handleClick,
|
|
2836
|
+
...editorAttrs,
|
|
2837
|
+
...rest,
|
|
2838
|
+
children: display
|
|
2839
|
+
}
|
|
2840
|
+
);
|
|
2841
|
+
}
|
|
2842
|
+
);
|
|
2843
|
+
var EMPTY_GIF = "data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==";
|
|
2844
|
+
var EditableImage = forwardRef(
|
|
2845
|
+
function EditableImage2({
|
|
2846
|
+
sectionId,
|
|
2847
|
+
blockId,
|
|
2848
|
+
settingId,
|
|
2849
|
+
src,
|
|
2850
|
+
alt,
|
|
2851
|
+
emptyPlaceholderSrc,
|
|
2852
|
+
className,
|
|
2853
|
+
onClick,
|
|
2854
|
+
style,
|
|
2855
|
+
...rest
|
|
2856
|
+
}, ref) {
|
|
2857
|
+
const isEditor = useIsEditor();
|
|
2858
|
+
const isEmpty = !src;
|
|
2859
|
+
const handleClick = useCallback(
|
|
2860
|
+
(e) => {
|
|
2861
|
+
onClick?.(e);
|
|
2862
|
+
if (!isEditor) return;
|
|
2863
|
+
e.stopPropagation();
|
|
2864
|
+
postFieldSelected(sectionId, settingId, blockId);
|
|
2865
|
+
},
|
|
2866
|
+
[isEditor, onClick, sectionId, settingId, blockId]
|
|
2867
|
+
);
|
|
2868
|
+
const editorAttrs = useMemo(
|
|
2869
|
+
() => isEditor ? {
|
|
2870
|
+
"data-numu-editable": "image",
|
|
2871
|
+
"data-numu-section-id": sectionId,
|
|
2872
|
+
"data-numu-setting-id": settingId,
|
|
2873
|
+
"data-numu-block-id": blockId ?? void 0,
|
|
2874
|
+
role: "button",
|
|
2875
|
+
tabIndex: 0
|
|
2876
|
+
} : {},
|
|
2877
|
+
[isEditor, sectionId, settingId, blockId]
|
|
2878
|
+
);
|
|
2879
|
+
const effectiveStyle = isEditor ? {
|
|
2880
|
+
...style,
|
|
2881
|
+
cursor: "pointer",
|
|
2882
|
+
outline: isEmpty ? "2px dashed rgba(99, 102, 241, 0.6)" : "2px dashed transparent",
|
|
2883
|
+
outlineOffset: "-2px"
|
|
2884
|
+
} : style;
|
|
2885
|
+
const effectiveSrc = src || emptyPlaceholderSrc || EMPTY_GIF;
|
|
2886
|
+
const effectiveAlt = alt ?? "";
|
|
2887
|
+
return /* @__PURE__ */ jsx(
|
|
2888
|
+
"img",
|
|
2889
|
+
{
|
|
2890
|
+
ref,
|
|
2891
|
+
src: effectiveSrc,
|
|
2892
|
+
alt: effectiveAlt,
|
|
2893
|
+
className,
|
|
2894
|
+
style: effectiveStyle,
|
|
2895
|
+
onClick: handleClick,
|
|
2896
|
+
...editorAttrs,
|
|
2897
|
+
...rest
|
|
2898
|
+
}
|
|
2899
|
+
);
|
|
2900
|
+
}
|
|
2901
|
+
);
|
|
2902
|
+
var ICON_DEFS = {
|
|
2903
|
+
star: '<polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"/>',
|
|
2904
|
+
heart: '<path d="M19 14c1.49-1.46 3-3.21 3-5.5A5.5 5.5 0 0 0 16.5 3c-1.76 0-3 .5-4.5 2-1.5-1.5-2.74-2-4.5-2A5.5 5.5 0 0 0 2 8.5c0 2.29 1.51 4.04 3 5.5l7 7Z"/>',
|
|
2905
|
+
check: '<path d="M20 6 9 17l-5-5"/>',
|
|
2906
|
+
"check-circle": '<circle cx="12" cy="12" r="10"/><path d="m9 12 2 2 4-4"/>',
|
|
2907
|
+
shield: '<path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10Z"/>',
|
|
2908
|
+
"shield-check": '<path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10Z"/><path d="m9 12 2 2 4-4"/>',
|
|
2909
|
+
truck: '<path d="M10 17h4V5H2v12h3"/><path d="M20 17h2v-3.34a4 4 0 0 0-1.17-2.83L19 9h-5v8h1"/><circle cx="7.5" cy="17.5" r="2.5"/><circle cx="17.5" cy="17.5" r="2.5"/>',
|
|
2910
|
+
"shopping-bag": '<path d="M6 2 3 6v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V6l-3-4Z"/><path d="M3 6h18"/><path d="M16 10a4 4 0 0 1-8 0"/>',
|
|
2911
|
+
"shopping-cart": '<circle cx="8" cy="21" r="1"/><circle cx="19" cy="21" r="1"/><path d="M2.05 2.05h2l2.66 12.42a2 2 0 0 0 2 1.58h9.78a2 2 0 0 0 1.95-1.57l1.65-7.43H5.12"/>',
|
|
2912
|
+
gift: '<rect x="3" y="8" width="18" height="4" rx="1"/><path d="M12 8v13"/><path d="M19 12v7a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2v-7"/><path d="M7.5 8a2.5 2.5 0 0 1 0-5C9 3 10.5 4.5 12 8c1.5-3.5 3-5 4.5-5a2.5 2.5 0 0 1 0 5"/>',
|
|
2913
|
+
tag: '<path d="M20.59 13.41 13.42 20.6a2 2 0 0 1-2.83 0L2 12V2h10l8.59 8.59a2 2 0 0 1 0 2.82Z"/><circle cx="7" cy="7" r="1"/>',
|
|
2914
|
+
zap: '<polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/>',
|
|
2915
|
+
sparkles: '<path d="M12 3 13.9 9.2 20 11l-6.1 1.8L12 19l-1.9-6.2L4 11l6.1-1.8L12 3Z"/><path d="M5 3v4"/><path d="M3 5h4"/><path d="M19 17v4"/><path d="M17 19h4"/>',
|
|
2916
|
+
flame: '<path d="M8.5 14.5A2.5 2.5 0 0 0 11 12c0-1.38-.5-2-1-3-1.07-2.14-.22-4.05 2-6 .5 2.5 2 4.9 4 6.5 2 1.6 3 3.5 3 5.5a7 7 0 1 1-14 0c0-1.15.43-2.29 1-3a2.5 2.5 0 0 0 2.5 2.5Z"/>',
|
|
2917
|
+
leaf: '<path d="M11 20A7 7 0 0 1 9.8 6.1C15.5 5 17 4.48 19 2c1 2 2 4.18 2 8 0 5.5-4.78 10-10 10Z"/><path d="M2 21c0-3 1.85-5.36 5.08-6"/>',
|
|
2918
|
+
globe: '<circle cx="12" cy="12" r="10"/><path d="M2 12h20"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10Z"/>',
|
|
2919
|
+
"map-pin": '<path d="M20 10c0 6-8 12-8 12s-8-6-8-12a8 8 0 0 1 16 0Z"/><circle cx="12" cy="10" r="3"/>',
|
|
2920
|
+
phone: '<path d="M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72c.13.96.36 1.9.7 2.81a2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45c.91.34 1.85.57 2.81.7A2 2 0 0 1 22 16.92Z"/>',
|
|
2921
|
+
mail: '<rect width="20" height="16" x="2" y="4" rx="2"/><path d="m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7"/>',
|
|
2922
|
+
clock: '<circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/>',
|
|
2923
|
+
lock: '<rect width="18" height="11" x="3" y="11" rx="2" ry="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/>',
|
|
2924
|
+
headphones: '<path d="M3 14h3a2 2 0 0 1 2 2v3a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-7a9 9 0 0 1 18 0v7a2 2 0 0 1-2 2h-1a2 2 0 0 1-2-2v-3a2 2 0 0 1 2-2h3"/>',
|
|
2925
|
+
percent: '<line x1="19" x2="5" y1="5" y2="19"/><circle cx="6.5" cy="6.5" r="2.5"/><circle cx="17.5" cy="17.5" r="2.5"/>',
|
|
2926
|
+
users: '<path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M22 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/>',
|
|
2927
|
+
home: '<path d="m3 9 9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><polyline points="9 22 9 12 15 12 15 22"/>',
|
|
2928
|
+
store: '<path d="M2 7l2-4h16l2 4"/><path d="M4 7v13a1 1 0 0 0 1 1h14a1 1 0 0 0 1-1V7"/><path d="M2 7h20"/><path d="M9 21v-6h6v6"/>',
|
|
2929
|
+
bell: '<path d="M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9"/><path d="M10.3 21a1.94 1.94 0 0 0 3.4 0"/>',
|
|
2930
|
+
camera: '<path d="M14.5 4h-5L7 7H4a2 2 0 0 0-2 2v9a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V9a2 2 0 0 0-2-2h-3l-2.5-3z"/><circle cx="12" cy="13" r="3"/>',
|
|
2931
|
+
image: '<rect width="18" height="18" x="3" y="3" rx="2" ry="2"/><circle cx="9" cy="9" r="2"/><path d="m21 15-3.09-3.09a2 2 0 0 0-2.82 0L6 21"/>',
|
|
2932
|
+
smile: '<circle cx="12" cy="12" r="10"/><path d="M8 14s1.5 2 4 2 4-2 4-2"/><line x1="9" x2="9.01" y1="9" y2="9"/><line x1="15" x2="15.01" y1="9" y2="9"/>',
|
|
2933
|
+
send: '<path d="m22 2-7 20-4-9-9-4Z"/><path d="M22 2 11 13"/>',
|
|
2934
|
+
"message-circle": '<path d="M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5Z"/>',
|
|
2935
|
+
search: '<circle cx="11" cy="11" r="8"/><path d="m21 21-4.3-4.3"/>',
|
|
2936
|
+
package: '<path d="M21 8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16Z"/><path d="m3.3 7 8.7 5 8.7-5"/><path d="M12 22V12"/>',
|
|
2937
|
+
award: '<circle cx="12" cy="8" r="6"/><path d="M15.477 12.89 17 22l-5-3-5 3 1.523-9.11"/>',
|
|
2938
|
+
coffee: '<path d="M10 2v2"/><path d="M14 2v2"/><path d="M6 2v2"/><path d="M16 8a1 1 0 0 1 1 1v8a4 4 0 0 1-4 4H7a4 4 0 0 1-4-4V9a1 1 0 0 1 1-1h14a4 4 0 1 1 0 8h-1"/>'
|
|
2939
|
+
};
|
|
2940
|
+
var ICON_NAMES = Object.keys(ICON_DEFS);
|
|
2941
|
+
var IconMap = ICON_DEFS;
|
|
2942
|
+
var FALLBACK = ICON_DEFS["check-circle"];
|
|
2943
|
+
function Icon({
|
|
2944
|
+
name,
|
|
2945
|
+
size = 24,
|
|
2946
|
+
strokeWidth = 2,
|
|
2947
|
+
className,
|
|
2948
|
+
title
|
|
2949
|
+
}) {
|
|
2950
|
+
const inner = ICON_DEFS[name] ?? FALLBACK;
|
|
2951
|
+
return /* @__PURE__ */ jsx(
|
|
2952
|
+
"svg",
|
|
2953
|
+
{
|
|
2954
|
+
width: size,
|
|
2955
|
+
height: size,
|
|
2956
|
+
viewBox: "0 0 24 24",
|
|
2957
|
+
fill: "none",
|
|
2958
|
+
stroke: "currentColor",
|
|
2959
|
+
strokeWidth,
|
|
2960
|
+
strokeLinecap: "round",
|
|
2961
|
+
strokeLinejoin: "round",
|
|
2962
|
+
className,
|
|
2963
|
+
role: title ? "img" : void 0,
|
|
2964
|
+
"aria-hidden": title ? void 0 : true,
|
|
2965
|
+
"aria-label": title,
|
|
2966
|
+
dangerouslySetInnerHTML: { __html: inner }
|
|
2967
|
+
}
|
|
2968
|
+
);
|
|
2969
|
+
}
|
|
2376
2970
|
|
|
2377
2971
|
// src/utils/normalize.ts
|
|
2378
2972
|
var DEFAULT_THEME_ID = typeof process !== "undefined" && process.env?.NUMU_DEFAULT_THEME_ID || "modern";
|
|
@@ -2466,22 +3060,11 @@ function resolveThemeSettings(raw) {
|
|
|
2466
3060
|
}
|
|
2467
3061
|
|
|
2468
3062
|
// src/utils/federation.ts
|
|
2469
|
-
var SDK_SYMBOL_KEY = "__NUMU_SDK_SLOT__";
|
|
2470
|
-
var REACT_SYMBOL_KEY = "__NUMU_REACT_SLOT__";
|
|
2471
|
-
function globalSlot(name, slotKey) {
|
|
2472
|
-
const g = globalThis;
|
|
2473
|
-
let sym = g[slotKey];
|
|
2474
|
-
if (!sym) {
|
|
2475
|
-
sym = Symbol.for(name);
|
|
2476
|
-
g[slotKey] = sym;
|
|
2477
|
-
}
|
|
2478
|
-
return sym;
|
|
2479
|
-
}
|
|
2480
3063
|
function sdkSlot() {
|
|
2481
|
-
return
|
|
3064
|
+
return /* @__PURE__ */ Symbol.for("@numueg/theme-sdk:singleton");
|
|
2482
3065
|
}
|
|
2483
3066
|
function reactSlot() {
|
|
2484
|
-
return
|
|
3067
|
+
return /* @__PURE__ */ Symbol.for("@numueg/theme-sdk:react");
|
|
2485
3068
|
}
|
|
2486
3069
|
function registerSdkSingleton(sdk) {
|
|
2487
3070
|
if (typeof globalThis === "undefined") return;
|
|
@@ -2491,6 +3074,10 @@ function getSdkSingleton() {
|
|
|
2491
3074
|
if (typeof globalThis === "undefined") return null;
|
|
2492
3075
|
return globalThis[sdkSlot()] ?? null;
|
|
2493
3076
|
}
|
|
3077
|
+
function clearSdkSingleton() {
|
|
3078
|
+
if (typeof globalThis === "undefined") return;
|
|
3079
|
+
delete globalThis[sdkSlot()];
|
|
3080
|
+
}
|
|
2494
3081
|
function registerReactSingleton(react, reactDom) {
|
|
2495
3082
|
if (typeof globalThis === "undefined") return;
|
|
2496
3083
|
globalThis[reactSlot()] = {
|
|
@@ -2506,6 +3093,121 @@ function isSdkAvailable() {
|
|
|
2506
3093
|
return getSdkSingleton() !== null;
|
|
2507
3094
|
}
|
|
2508
3095
|
|
|
3096
|
+
// src/utils/dynamicSources.ts
|
|
3097
|
+
function isDynamicSource(value) {
|
|
3098
|
+
return typeof value === "object" && value !== null && typeof value.__numu_source === "string";
|
|
3099
|
+
}
|
|
3100
|
+
function dynamicSource(path) {
|
|
3101
|
+
return { __numu_source: path };
|
|
3102
|
+
}
|
|
3103
|
+
function resolveSourcePath(path, ctx) {
|
|
3104
|
+
const [root, ...rest] = path.split(".");
|
|
3105
|
+
switch (root) {
|
|
3106
|
+
case "product": {
|
|
3107
|
+
const p = ctx.product;
|
|
3108
|
+
if (!p) return null;
|
|
3109
|
+
return resolveProductField(p, rest.join("."));
|
|
3110
|
+
}
|
|
3111
|
+
case "collection": {
|
|
3112
|
+
const c = ctx.collection;
|
|
3113
|
+
if (!c) return null;
|
|
3114
|
+
return resolveCollectionField(c, rest.join("."));
|
|
3115
|
+
}
|
|
3116
|
+
case "store": {
|
|
3117
|
+
const s = ctx.store;
|
|
3118
|
+
if (!s) return null;
|
|
3119
|
+
return resolveStoreField(s, rest.join("."));
|
|
3120
|
+
}
|
|
3121
|
+
default:
|
|
3122
|
+
return null;
|
|
3123
|
+
}
|
|
3124
|
+
}
|
|
3125
|
+
function resolveProductField(p, field) {
|
|
3126
|
+
switch (field) {
|
|
3127
|
+
case "title":
|
|
3128
|
+
case "name":
|
|
3129
|
+
return p.name;
|
|
3130
|
+
case "description":
|
|
3131
|
+
return p.description ?? "";
|
|
3132
|
+
case "description_snippet":
|
|
3133
|
+
return (p.description ?? "").replace(/<[^>]+>/g, " ").trim().slice(0, 200);
|
|
3134
|
+
case "price":
|
|
3135
|
+
return p.price;
|
|
3136
|
+
case "sku":
|
|
3137
|
+
return p.variants?.[0]?.sku ?? null;
|
|
3138
|
+
case "image":
|
|
3139
|
+
case "first_image_url":
|
|
3140
|
+
return p.images?.[0]?.url ?? null;
|
|
3141
|
+
case "slug":
|
|
3142
|
+
return p.slug;
|
|
3143
|
+
default:
|
|
3144
|
+
return null;
|
|
3145
|
+
}
|
|
3146
|
+
}
|
|
3147
|
+
function resolveCollectionField(c, field) {
|
|
3148
|
+
switch (field) {
|
|
3149
|
+
case "title":
|
|
3150
|
+
case "name":
|
|
3151
|
+
return c.name;
|
|
3152
|
+
case "description":
|
|
3153
|
+
return c.description ?? "";
|
|
3154
|
+
case "description_snippet":
|
|
3155
|
+
return (c.description ?? "").replace(/<[^>]+>/g, " ").trim().slice(0, 200);
|
|
3156
|
+
case "image":
|
|
3157
|
+
return c.image_url ?? null;
|
|
3158
|
+
case "slug":
|
|
3159
|
+
return c.slug;
|
|
3160
|
+
case "product_count":
|
|
3161
|
+
return c.product_count ?? null;
|
|
3162
|
+
default:
|
|
3163
|
+
return null;
|
|
3164
|
+
}
|
|
3165
|
+
}
|
|
3166
|
+
function resolveStoreField(s, field) {
|
|
3167
|
+
switch (field) {
|
|
3168
|
+
case "name":
|
|
3169
|
+
return s.name ?? "";
|
|
3170
|
+
case "description":
|
|
3171
|
+
return s.description ?? "";
|
|
3172
|
+
case "logo":
|
|
3173
|
+
return s.logo_url ?? null;
|
|
3174
|
+
default:
|
|
3175
|
+
return null;
|
|
3176
|
+
}
|
|
3177
|
+
}
|
|
3178
|
+
function resolveDynamicValue(value, ctx) {
|
|
3179
|
+
if (!isDynamicSource(value)) return value;
|
|
3180
|
+
return resolveSourcePath(value.__numu_source, ctx);
|
|
3181
|
+
}
|
|
3182
|
+
function resolveSettingsMap(settings, ctx) {
|
|
3183
|
+
if (!settings || typeof settings !== "object") return settings;
|
|
3184
|
+
const input = settings;
|
|
3185
|
+
const out = {};
|
|
3186
|
+
for (const key of Object.keys(input)) {
|
|
3187
|
+
const v = input[key];
|
|
3188
|
+
if (isDynamicSource(v)) {
|
|
3189
|
+
const resolved = resolveSourcePath(v.__numu_source, ctx);
|
|
3190
|
+
out[key] = resolved;
|
|
3191
|
+
} else {
|
|
3192
|
+
out[key] = v;
|
|
3193
|
+
}
|
|
3194
|
+
}
|
|
3195
|
+
return out;
|
|
3196
|
+
}
|
|
3197
|
+
function useResolvedSettings(instance) {
|
|
3198
|
+
const product = useContext(ProductContext);
|
|
3199
|
+
const collection = useContext(CollectionContext);
|
|
3200
|
+
const store = useContext(ShopContext);
|
|
3201
|
+
const ctx = useMemo(
|
|
3202
|
+
() => ({ product, collection, store }),
|
|
3203
|
+
[product, collection, store]
|
|
3204
|
+
);
|
|
3205
|
+
return useMemo(() => {
|
|
3206
|
+
const settings = instance?.settings ?? {};
|
|
3207
|
+
return resolveSettingsMap(settings, ctx);
|
|
3208
|
+
}, [instance, ctx]);
|
|
3209
|
+
}
|
|
3210
|
+
|
|
2509
3211
|
// src/utils/defineSection.ts
|
|
2510
3212
|
var SECTION_MARKER = /* @__PURE__ */ Symbol.for("numu.theme.section");
|
|
2511
3213
|
var BLOCK_MARKER = /* @__PURE__ */ Symbol.for("numu.theme.block");
|
|
@@ -2664,6 +3366,6 @@ function buildLocaleBundle(modules) {
|
|
|
2664
3366
|
return bundle;
|
|
2665
3367
|
}
|
|
2666
3368
|
|
|
2667
|
-
export { AddToCartButton, Block, CartContext, CollectionCard, CollectionContext, CollectionProvider, CurrencySwitcher, CustomerContext, Form, Image, Link, LocaleSwitcher, LocalizationContext, Money, NuMuProvider, PageContext, ProductCard, ProductContext, ProductProvider, RichText, Section, SectionContext, ShopContext, ThemeSettingsContext, assetUrl, availableValues, buildLocaleBundle, collectBlocks, collectSections, defaultVariant, defineBlock, defineSection, findVariantByOptions, flattenMessages, getReactSingleton, getSdkSingleton, isDefinedBlock, isDefinedSection, isSdkAvailable, pickTranslations, registerReactSingleton, registerSdkSingleton, resolveThemeSettings, sanitizeHtml, useAnalytics, useApp, useCart, useCheckout, useCollection, useCollectionOptional, useCollections, useCurrency, useCustomer, useCustomerActions, useCustomerAddresses, useDirection, useFieldTranslation, useGiftCardBalance, useImage, useLocale, useLocalization, useMoney, useNavigation, useNumberFormat, useOrder, useOrders, usePage, useProduct, useProductOptional, useProducts, useRelatedProducts, useReorder, useSearch, useSection, useSectionOptional, useShippingRates, useShop, useThemeSettings, useTranslation, useVariantSelection, useWishlist };
|
|
3369
|
+
export { AddToCartButton, Block, CartContext, CollectionCard, CollectionContext, CollectionProvider, CurrencySwitcher, CustomerContext, EditableImage, EditableText, Form, ICON_NAMES, Icon, IconMap, Image, Link, LocaleSwitcher, LocalizationContext, MAX_BLOCK_DEPTH, Money, NavigationContext, NuMuProvider, PageContext, ProductCard, ProductContext, ProductProvider, RichText, Section, SectionContext, ShopContext, ThemeSettingsContext, applyGlobalStyleTokens, assetUrl, availableValues, buildLocaleBundle, clearSdkSingleton, collectBlocks, collectSections, defaultVariant, defineBlock, defineSection, dynamicSource, findVariantByOptions, flattenMessages, getReactSingleton, getSdkSingleton, isDefinedBlock, isDefinedSection, isDynamicSource, isSdkAvailable, mountTheme, pickTranslations, registerReactSingleton, registerSdkSingleton, resolveDynamicValue, resolveFontStack, resolveSettingsMap, resolveSourcePath, resolveThemeSettings, 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 };
|
|
2668
3370
|
//# sourceMappingURL=index.mjs.map
|
|
2669
3371
|
//# sourceMappingURL=index.mjs.map
|