@numueg/theme-sdk 0.10.1 → 0.13.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/CHANGELOG.md +139 -0
- package/dist/{chunk-O4GLTNLE.cjs → chunk-H7RGDWSU.cjs} +3 -3
- package/dist/{chunk-O4GLTNLE.cjs.map → chunk-H7RGDWSU.cjs.map} +1 -1
- package/dist/{chunk-QFFTHIFZ.mjs → chunk-QPXMBK5U.mjs} +3 -3
- package/dist/{chunk-QFFTHIFZ.mjs.map → chunk-QPXMBK5U.mjs.map} +1 -1
- package/dist/{entities-B8378GKp.d.mts → entities-DRKn04q0.d.mts} +77 -1
- package/dist/{entities-B8378GKp.d.ts → entities-DRKn04q0.d.ts} +77 -1
- package/dist/index.cjs +336 -30
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +492 -8
- package/dist/index.d.ts +492 -8
- package/dist/index.mjs +305 -21
- package/dist/index.mjs.map +1 -1
- package/dist/{mount-BDo4a42I.d.mts → mount-BTaDtz8k.d.mts} +1 -1
- package/dist/{mount-DQZu8aBB.d.ts → mount-CLQniVfc.d.ts} +1 -1
- package/dist/types.d.mts +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/v2-compat.d.mts +1 -1
- package/dist/v2-compat.d.ts +1 -1
- package/dist/validation.cjs +11 -11
- package/dist/validation.mjs +1 -1
- package/dist/verify.cjs +3 -3
- package/dist/verify.d.mts +2 -2
- package/dist/verify.d.ts +2 -2
- package/dist/verify.mjs +2 -2
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var chunkTBSNHHFH_cjs = require('./chunk-TBSNHHFH.cjs');
|
|
4
|
-
var
|
|
4
|
+
var chunkH7RGDWSU_cjs = require('./chunk-H7RGDWSU.cjs');
|
|
5
5
|
var chunkV3JDQXD3_cjs = require('./chunk-V3JDQXD3.cjs');
|
|
6
6
|
var react = require('react');
|
|
7
7
|
var client = require('react-dom/client');
|
|
@@ -25,6 +25,20 @@ function useCollection() {
|
|
|
25
25
|
function useCollectionOptional() {
|
|
26
26
|
return react.useContext(chunkV3JDQXD3_cjs.CollectionContext);
|
|
27
27
|
}
|
|
28
|
+
function useListingHeading(options = {}) {
|
|
29
|
+
const collection = react.useContext(chunkV3JDQXD3_cjs.CollectionContext);
|
|
30
|
+
const clean = (v) => typeof v === "string" && v.trim() !== "" ? v.trim() : "";
|
|
31
|
+
const collectionName = clean(collection?.name);
|
|
32
|
+
const collectionDescription = clean(
|
|
33
|
+
collection?.description
|
|
34
|
+
);
|
|
35
|
+
return {
|
|
36
|
+
collection: collection ?? null,
|
|
37
|
+
isCollection: collectionName !== "",
|
|
38
|
+
title: collectionName || clean(options.title) || clean(options.defaultTitle) || "",
|
|
39
|
+
description: collectionDescription || clean(options.description) || ""
|
|
40
|
+
};
|
|
41
|
+
}
|
|
28
42
|
function useCart() {
|
|
29
43
|
const ctx = react.useContext(chunkV3JDQXD3_cjs.CartContext);
|
|
30
44
|
if (!ctx) throw new Error("useCart must be used within NuMuProvider");
|
|
@@ -33,6 +47,59 @@ function useCart() {
|
|
|
33
47
|
function useCurrentTemplate() {
|
|
34
48
|
return react.useContext(chunkV3JDQXD3_cjs.CurrentTemplateContext);
|
|
35
49
|
}
|
|
50
|
+
function isMetafield(value) {
|
|
51
|
+
return typeof value === "object" && value !== null && typeof value.namespace === "string" && typeof value.key === "string";
|
|
52
|
+
}
|
|
53
|
+
function pageMetafields(data) {
|
|
54
|
+
if (!data) return [];
|
|
55
|
+
const record = data.page;
|
|
56
|
+
for (const candidate of [record?.metafields, data.metafields]) {
|
|
57
|
+
if (Array.isArray(candidate)) return candidate.filter(isMetafield);
|
|
58
|
+
}
|
|
59
|
+
return [];
|
|
60
|
+
}
|
|
61
|
+
function useMetafields(owner) {
|
|
62
|
+
const product = react.useContext(chunkV3JDQXD3_cjs.ProductContext);
|
|
63
|
+
const collection = react.useContext(chunkV3JDQXD3_cjs.CollectionContext);
|
|
64
|
+
const page = react.useContext(chunkV3JDQXD3_cjs.PageContext);
|
|
65
|
+
switch (owner) {
|
|
66
|
+
case "product":
|
|
67
|
+
return product?.metafields ?? [];
|
|
68
|
+
case "collection":
|
|
69
|
+
return collection?.metafields ?? [];
|
|
70
|
+
case "page":
|
|
71
|
+
return pageMetafields(page?.data);
|
|
72
|
+
default:
|
|
73
|
+
return [];
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
function useMetafield(owner, namespace, key) {
|
|
77
|
+
const fields = useMetafields(owner);
|
|
78
|
+
return fields.find((m) => m.namespace === namespace && m.key === key) ?? null;
|
|
79
|
+
}
|
|
80
|
+
function pageData() {
|
|
81
|
+
return react.useContext(chunkV3JDQXD3_cjs.PageContext)?.data;
|
|
82
|
+
}
|
|
83
|
+
function useBlogs() {
|
|
84
|
+
const data = pageData();
|
|
85
|
+
const blogs = data?.blogs;
|
|
86
|
+
return Array.isArray(blogs) ? blogs : [];
|
|
87
|
+
}
|
|
88
|
+
function useBlog() {
|
|
89
|
+
const data = pageData();
|
|
90
|
+
const blog = data?.blog ?? data?.article?.blog;
|
|
91
|
+
return blog && typeof blog === "object" ? blog : null;
|
|
92
|
+
}
|
|
93
|
+
function useArticles() {
|
|
94
|
+
const data = pageData();
|
|
95
|
+
const articles = data?.articles;
|
|
96
|
+
return Array.isArray(articles) ? articles : [];
|
|
97
|
+
}
|
|
98
|
+
function useArticle() {
|
|
99
|
+
const data = pageData();
|
|
100
|
+
const article = data?.article;
|
|
101
|
+
return article && typeof article === "object" ? article : null;
|
|
102
|
+
}
|
|
36
103
|
var SectionContext = react.createContext(null);
|
|
37
104
|
function useSection() {
|
|
38
105
|
const ctx = react.useContext(SectionContext);
|
|
@@ -82,16 +149,16 @@ function useCurrency() {
|
|
|
82
149
|
|
|
83
150
|
// src/hooks/useMoney.ts
|
|
84
151
|
function useMoney(currencyOverride) {
|
|
85
|
-
const { formatMoney } = chunkV3JDQXD3_cjs.useLocalization();
|
|
152
|
+
const { formatMoney: formatMoney2 } = chunkV3JDQXD3_cjs.useLocalization();
|
|
86
153
|
const shop = chunkV3JDQXD3_cjs.useShop();
|
|
87
154
|
const { selected, base, autoConvert, convert } = useCurrency();
|
|
88
155
|
return (amount) => {
|
|
89
156
|
const shouldConvert = autoConvert && !currencyOverride && !!selected && selected !== base;
|
|
90
157
|
if (shouldConvert) {
|
|
91
158
|
const converted = convert(Math.round(amount * 100), selected) / 100;
|
|
92
|
-
return
|
|
159
|
+
return formatMoney2(converted, selected);
|
|
93
160
|
}
|
|
94
|
-
return
|
|
161
|
+
return formatMoney2(amount, currencyOverride || shop?.currency);
|
|
95
162
|
};
|
|
96
163
|
}
|
|
97
164
|
var DEFAULT_WIDTHS = [320, 480, 640, 768, 1024, 1280, 1600, 1920];
|
|
@@ -956,6 +1023,133 @@ function useRelatedProducts(productId, options = {}) {
|
|
|
956
1023
|
});
|
|
957
1024
|
return { items: data ?? EMPTY4, loading: isLoading, error: error ?? null };
|
|
958
1025
|
}
|
|
1026
|
+
function useActivePromotions(page = "/", locale = "ar") {
|
|
1027
|
+
const key = `numu:promotions:${page}:${locale}`;
|
|
1028
|
+
const fetcher = react.useCallback(
|
|
1029
|
+
async (signal) => {
|
|
1030
|
+
const qs = new URLSearchParams({ page, locale });
|
|
1031
|
+
const res = await fetch(`/api/storefront/promotions?${qs.toString()}`, {
|
|
1032
|
+
credentials: "include",
|
|
1033
|
+
cache: "no-store",
|
|
1034
|
+
signal
|
|
1035
|
+
});
|
|
1036
|
+
if (!res.ok) return null;
|
|
1037
|
+
const json = await res.json();
|
|
1038
|
+
if (!json) return null;
|
|
1039
|
+
return (json.data ?? json) || null;
|
|
1040
|
+
},
|
|
1041
|
+
[page, locale]
|
|
1042
|
+
);
|
|
1043
|
+
const { data } = useCachedResource(
|
|
1044
|
+
key,
|
|
1045
|
+
fetcher,
|
|
1046
|
+
{ initialData: null }
|
|
1047
|
+
);
|
|
1048
|
+
return data ?? null;
|
|
1049
|
+
}
|
|
1050
|
+
|
|
1051
|
+
// src/utils/money.ts
|
|
1052
|
+
function resolveLocale(locale) {
|
|
1053
|
+
return locale === "ar" ? "ar-EG" : "en-EG";
|
|
1054
|
+
}
|
|
1055
|
+
function formatMoney(cents, options = {}) {
|
|
1056
|
+
const { currency, locale, fractionDigits = 0 } = options;
|
|
1057
|
+
const safe = Number.isFinite(cents) ? cents : 0;
|
|
1058
|
+
return new Intl.NumberFormat(resolveLocale(locale), {
|
|
1059
|
+
style: "currency",
|
|
1060
|
+
currency: currency || "EGP",
|
|
1061
|
+
maximumFractionDigits: fractionDigits
|
|
1062
|
+
}).format(safe / 100);
|
|
1063
|
+
}
|
|
1064
|
+
function formatMoneyMajor(amount, options = {}) {
|
|
1065
|
+
return formatMoney(
|
|
1066
|
+
(Number.isFinite(amount) ? amount : 0) * 100,
|
|
1067
|
+
options
|
|
1068
|
+
);
|
|
1069
|
+
}
|
|
1070
|
+
function centsToMajor(cents) {
|
|
1071
|
+
return (Number.isFinite(cents) ? cents : 0) / 100;
|
|
1072
|
+
}
|
|
1073
|
+
function majorToCents(amount) {
|
|
1074
|
+
return Math.round((Number.isFinite(amount) ? amount : 0) * 100);
|
|
1075
|
+
}
|
|
1076
|
+
|
|
1077
|
+
// src/lib/promotions.ts
|
|
1078
|
+
function multibuyOffers(promotions) {
|
|
1079
|
+
if (!promotions) return [];
|
|
1080
|
+
const list = Array.isArray(promotions) ? promotions : promotions.auto_discounts ?? [];
|
|
1081
|
+
const offers = [];
|
|
1082
|
+
for (const promo of list) {
|
|
1083
|
+
const rule = promo?.discount_rule;
|
|
1084
|
+
if (!rule || rule.kind !== "multibuy") continue;
|
|
1085
|
+
const quantity = rule.multibuy_quantity;
|
|
1086
|
+
const groupPriceCents = rule.multibuy_price_cents;
|
|
1087
|
+
if (typeof quantity !== "number" || quantity < 2) continue;
|
|
1088
|
+
if (typeof groupPriceCents !== "number" || groupPriceCents <= 0) continue;
|
|
1089
|
+
const eligibleProductIds = promo.eligible_product_ids ?? [];
|
|
1090
|
+
const eligibleCategoryIds = promo.eligible_category_ids ?? [];
|
|
1091
|
+
offers.push({
|
|
1092
|
+
promotionId: promo.promotion_id,
|
|
1093
|
+
quantity,
|
|
1094
|
+
groupPriceCents,
|
|
1095
|
+
groupPriceMajor: centsToMajor(groupPriceCents),
|
|
1096
|
+
headline: promo.translated_content?.headline,
|
|
1097
|
+
eligibleProductIds,
|
|
1098
|
+
eligibleCategoryIds,
|
|
1099
|
+
// No scoping rows at all ⇒ every product qualifies. Note an older
|
|
1100
|
+
// backend that doesn't send these fields also lands here, which is the
|
|
1101
|
+
// right default: counting everything is what themes did before.
|
|
1102
|
+
isStoreWide: eligibleProductIds.length === 0 && eligibleCategoryIds.length === 0,
|
|
1103
|
+
raw: promo
|
|
1104
|
+
});
|
|
1105
|
+
}
|
|
1106
|
+
return offers;
|
|
1107
|
+
}
|
|
1108
|
+
function offerIncludesProduct(offer, product) {
|
|
1109
|
+
if (!offer) return false;
|
|
1110
|
+
if (offer.isStoreWide) return true;
|
|
1111
|
+
const id = product?.product_id ?? product?.id;
|
|
1112
|
+
if (id && offer.eligibleProductIds.includes(id)) return true;
|
|
1113
|
+
const category = product?.category_id;
|
|
1114
|
+
return Boolean(category && offer.eligibleCategoryIds.includes(category));
|
|
1115
|
+
}
|
|
1116
|
+
function eligibleUnitsInCart(offer, cart) {
|
|
1117
|
+
if (!offer) return 0;
|
|
1118
|
+
return (cart?.items ?? []).reduce((sum, item) => {
|
|
1119
|
+
if (!item) return sum;
|
|
1120
|
+
if (!offerIncludesProduct(offer, item)) return sum;
|
|
1121
|
+
return sum + (item.quantity || 0);
|
|
1122
|
+
}, 0);
|
|
1123
|
+
}
|
|
1124
|
+
function offerProgress(offer, cart, eligibleUnits) {
|
|
1125
|
+
const empty = {
|
|
1126
|
+
unitsInCart: 0,
|
|
1127
|
+
unitsNeeded: 0,
|
|
1128
|
+
groupsUnlocked: 0,
|
|
1129
|
+
savingMajor: 0
|
|
1130
|
+
};
|
|
1131
|
+
if (!offer) return empty;
|
|
1132
|
+
const unitsInCart = typeof eligibleUnits === "number" ? Math.max(0, eligibleUnits) : eligibleUnitsInCart(offer, cart);
|
|
1133
|
+
const groupsUnlocked = Math.floor(unitsInCart / offer.quantity);
|
|
1134
|
+
const remainder = unitsInCart % offer.quantity;
|
|
1135
|
+
const unitsNeeded = remainder === 0 ? 0 : offer.quantity - remainder;
|
|
1136
|
+
const applied = (cart?.applied_promotions ?? []).find(
|
|
1137
|
+
(p) => p && p.id === offer.promotionId
|
|
1138
|
+
);
|
|
1139
|
+
return {
|
|
1140
|
+
unitsInCart,
|
|
1141
|
+
unitsNeeded,
|
|
1142
|
+
groupsUnlocked,
|
|
1143
|
+
savingMajor: applied ? applied.amount || 0 : 0
|
|
1144
|
+
};
|
|
1145
|
+
}
|
|
1146
|
+
function offerBeatsRegularPrice(offer, unitPriceMajor) {
|
|
1147
|
+
if (!offer || typeof unitPriceMajor !== "number" || unitPriceMajor <= 0) {
|
|
1148
|
+
return false;
|
|
1149
|
+
}
|
|
1150
|
+
const unitCents = Math.round(unitPriceMajor * 100);
|
|
1151
|
+
return unitCents * offer.quantity > offer.groupPriceCents;
|
|
1152
|
+
}
|
|
959
1153
|
function useProductSizeChart(productOverride) {
|
|
960
1154
|
const ctxProduct = useProductOptional();
|
|
961
1155
|
const product = productOverride ?? ctxProduct;
|
|
@@ -1429,11 +1623,27 @@ var EMPTY_CART = {
|
|
|
1429
1623
|
};
|
|
1430
1624
|
function normalizeCartFromServer(cart) {
|
|
1431
1625
|
const toMajor = (n) => typeof n === "number" ? n / 100 : 0;
|
|
1626
|
+
const { automatic_discount_cents: wireAutomaticCents, ...rest } = cart;
|
|
1432
1627
|
return {
|
|
1433
|
-
...
|
|
1628
|
+
...rest,
|
|
1434
1629
|
subtotal: toMajor(cart.subtotal),
|
|
1435
1630
|
total: toMajor(cart.total),
|
|
1436
1631
|
...cart.discount_amount != null ? { discount_amount: toMajor(cart.discount_amount) } : {},
|
|
1632
|
+
// Offers-v2 automatic promotions. These MUST be converted here too —
|
|
1633
|
+
// they arrive in cents next to already-major totals, so forwarding them
|
|
1634
|
+
// raw makes every theme render a saving 100x too large. This function is
|
|
1635
|
+
// the one and only cents→major boundary for the cart.
|
|
1636
|
+
//
|
|
1637
|
+
// The backend field is `automatic_discount_cents`; themes get
|
|
1638
|
+
// `automatic_discount` (major), because a `_cents` name holding pounds
|
|
1639
|
+
// invites exactly the double-divide this conversion exists to prevent.
|
|
1640
|
+
...wireAutomaticCents != null ? { automatic_discount: toMajor(wireAutomaticCents) } : {},
|
|
1641
|
+
...Array.isArray(cart.applied_promotions) ? {
|
|
1642
|
+
applied_promotions: cart.applied_promotions.map((p) => ({
|
|
1643
|
+
...p,
|
|
1644
|
+
amount: toMajor(p.amount)
|
|
1645
|
+
}))
|
|
1646
|
+
} : {},
|
|
1437
1647
|
items: Array.isArray(cart.items) ? cart.items.map((it) => {
|
|
1438
1648
|
const raw = it;
|
|
1439
1649
|
return {
|
|
@@ -2255,13 +2465,13 @@ function pickDemo(ctx, themeSettings) {
|
|
|
2255
2465
|
const t = themeSettings.templates;
|
|
2256
2466
|
return !t || Object.keys(t).length === 0;
|
|
2257
2467
|
}
|
|
2258
|
-
function wrapEntityProviders(app,
|
|
2468
|
+
function wrapEntityProviders(app, pageData2) {
|
|
2259
2469
|
let inner = app;
|
|
2260
|
-
if (
|
|
2261
|
-
inner = /* @__PURE__ */ jsxRuntime.jsx(CollectionProvider, { collection:
|
|
2470
|
+
if (pageData2.collection) {
|
|
2471
|
+
inner = /* @__PURE__ */ jsxRuntime.jsx(CollectionProvider, { collection: pageData2.collection, children: inner });
|
|
2262
2472
|
}
|
|
2263
|
-
if (
|
|
2264
|
-
inner = /* @__PURE__ */ jsxRuntime.jsx(ProductProvider, { product:
|
|
2473
|
+
if (pageData2.product) {
|
|
2474
|
+
inner = /* @__PURE__ */ jsxRuntime.jsx(ProductProvider, { product: pageData2.product, children: inner });
|
|
2265
2475
|
}
|
|
2266
2476
|
return inner;
|
|
2267
2477
|
}
|
|
@@ -2284,7 +2494,7 @@ var ThemeMountBridge = react.forwardRef(function ThemeMountBridge2({ ctx, mountE
|
|
|
2284
2494
|
const store = pickStore(ctx);
|
|
2285
2495
|
const template = pickTemplate(ctx);
|
|
2286
2496
|
const demo = pickDemo(ctx, themeSettings);
|
|
2287
|
-
const
|
|
2497
|
+
const pageData2 = ctx.page?.data ?? {};
|
|
2288
2498
|
const app = renderApp({
|
|
2289
2499
|
currentTemplate: template,
|
|
2290
2500
|
demo,
|
|
@@ -2302,11 +2512,11 @@ var ThemeMountBridge = react.forwardRef(function ThemeMountBridge2({ ctx, mountE
|
|
|
2302
2512
|
locale: ctx.locale,
|
|
2303
2513
|
translations: ctx.translations,
|
|
2304
2514
|
navigation: ctx.navigation,
|
|
2305
|
-
initialProducts:
|
|
2306
|
-
initialCollections:
|
|
2515
|
+
initialProducts: pageData2.products,
|
|
2516
|
+
initialCollections: pageData2.collections,
|
|
2307
2517
|
currentTemplate: template,
|
|
2308
2518
|
pageTemplate: ctx.page?.template,
|
|
2309
|
-
children: wrapEntityProviders(app,
|
|
2519
|
+
children: wrapEntityProviders(app, pageData2)
|
|
2310
2520
|
}
|
|
2311
2521
|
);
|
|
2312
2522
|
});
|
|
@@ -2349,7 +2559,7 @@ function Money({
|
|
|
2349
2559
|
className,
|
|
2350
2560
|
as = "span"
|
|
2351
2561
|
}) {
|
|
2352
|
-
const { formatMoney } = chunkV3JDQXD3_cjs.useLocalization();
|
|
2562
|
+
const { formatMoney: formatMoney2 } = chunkV3JDQXD3_cjs.useLocalization();
|
|
2353
2563
|
const shop = chunkV3JDQXD3_cjs.useShop();
|
|
2354
2564
|
const { selected, base, autoConvert, convert } = useCurrency();
|
|
2355
2565
|
const shouldConvert = autoConvert && !currency && !!selected && selected !== base;
|
|
@@ -2357,12 +2567,12 @@ function Money({
|
|
|
2357
2567
|
const toDisplay = (major) => shouldConvert ? convert(Math.round(major * 100), selected) / 100 : major;
|
|
2358
2568
|
const showCompare = compareAt != null && compareAt > amount;
|
|
2359
2569
|
const children = [
|
|
2360
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { children:
|
|
2570
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: formatMoney2(toDisplay(amount), ccy) }, "amt")
|
|
2361
2571
|
];
|
|
2362
2572
|
if (showCompare) {
|
|
2363
2573
|
children.push(" ");
|
|
2364
2574
|
children.push(
|
|
2365
|
-
/* @__PURE__ */ jsxRuntime.jsx("s", { style: { opacity: 0.6 }, children:
|
|
2575
|
+
/* @__PURE__ */ jsxRuntime.jsx("s", { style: { opacity: 0.6 }, children: formatMoney2(toDisplay(compareAt), ccy) }, "cmp")
|
|
2366
2576
|
);
|
|
2367
2577
|
}
|
|
2368
2578
|
return react.createElement(
|
|
@@ -2382,7 +2592,7 @@ function asImageTransform(v) {
|
|
|
2382
2592
|
return void 0;
|
|
2383
2593
|
}
|
|
2384
2594
|
function applyImageTransform(t, fit = "cover") {
|
|
2385
|
-
if (!t) return {
|
|
2595
|
+
if (!t) return {};
|
|
2386
2596
|
const fx = Math.round(_clampT(t.focal?.x ?? 0.5, 0, 1) * 1e4) / 100;
|
|
2387
2597
|
const fy = Math.round(_clampT(t.focal?.y ?? 0.5, 0, 1) * 1e4) / 100;
|
|
2388
2598
|
const zoom = _clampT(t.zoom ?? 1, 1, 4);
|
|
@@ -2585,7 +2795,10 @@ function HeroMedia({
|
|
|
2585
2795
|
const activeBase = useMobile ? MOBILE_BASE_WIDTH : DESKTOP_BASE_WIDTH;
|
|
2586
2796
|
const activeSrc = rawFallback ? activeUrl : focalSrc(activeUrl, { width: activeBase, ...activeCrop });
|
|
2587
2797
|
const activeSrcSet = rawFallback ? void 0 : heroSrcSet(activeUrl, activeCrop);
|
|
2588
|
-
const fitStyle =
|
|
2798
|
+
const fitStyle = {
|
|
2799
|
+
objectFit: fit,
|
|
2800
|
+
...applyImageTransform(useMobile ? mobileTransform ?? transform : transform, fit)
|
|
2801
|
+
};
|
|
2589
2802
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2590
2803
|
"img",
|
|
2591
2804
|
{
|
|
@@ -2926,6 +3139,20 @@ function Form({
|
|
|
2926
3139
|
}
|
|
2927
3140
|
);
|
|
2928
3141
|
}
|
|
3142
|
+
|
|
3143
|
+
// src/utils/routes.ts
|
|
3144
|
+
function productHref(slugOrId) {
|
|
3145
|
+
if (!slugOrId) return "/products";
|
|
3146
|
+
return `/products/${slugOrId}`;
|
|
3147
|
+
}
|
|
3148
|
+
function collectionHref(category) {
|
|
3149
|
+
if (!category) return "/collections";
|
|
3150
|
+
if (typeof category === "string") {
|
|
3151
|
+
return category ? `/collections/${category}` : "/collections";
|
|
3152
|
+
}
|
|
3153
|
+
const key = category.slug || category.id;
|
|
3154
|
+
return key ? `/collections/${key}` : "/collections";
|
|
3155
|
+
}
|
|
2929
3156
|
function joinClass(...names) {
|
|
2930
3157
|
return names.filter(Boolean).join(" ");
|
|
2931
3158
|
}
|
|
@@ -2936,7 +3163,7 @@ function ProductCard({
|
|
|
2936
3163
|
slots,
|
|
2937
3164
|
imageSizes
|
|
2938
3165
|
}) {
|
|
2939
|
-
const target = href ??
|
|
3166
|
+
const target = href ?? productHref(product.slug);
|
|
2940
3167
|
const firstImage = product.images?.[0];
|
|
2941
3168
|
const inStock = product.in_stock;
|
|
2942
3169
|
const badge = slots?.badge !== void 0 ? slots.badge : inStock ? null : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "numu-product-card__badge", children: "Sold out" });
|
|
@@ -3549,7 +3776,19 @@ function resolveSourcePath(path, ctx) {
|
|
|
3549
3776
|
return null;
|
|
3550
3777
|
}
|
|
3551
3778
|
}
|
|
3779
|
+
function resolveMetafield(metafields, field) {
|
|
3780
|
+
const address = field.slice("metafield:".length);
|
|
3781
|
+
const dot = address.indexOf(".");
|
|
3782
|
+
if (dot === -1) return null;
|
|
3783
|
+
const namespace = address.slice(0, dot);
|
|
3784
|
+
const key = address.slice(dot + 1);
|
|
3785
|
+
const hit = (metafields ?? []).find(
|
|
3786
|
+
(m) => m.namespace === namespace && m.key === key
|
|
3787
|
+
);
|
|
3788
|
+
return hit ? hit.value ?? null : null;
|
|
3789
|
+
}
|
|
3552
3790
|
function resolveProductField(p, field) {
|
|
3791
|
+
if (field.startsWith("metafield:")) return resolveMetafield(p.metafields, field);
|
|
3553
3792
|
switch (field) {
|
|
3554
3793
|
case "title":
|
|
3555
3794
|
case "name":
|
|
@@ -3572,6 +3811,7 @@ function resolveProductField(p, field) {
|
|
|
3572
3811
|
}
|
|
3573
3812
|
}
|
|
3574
3813
|
function resolveCollectionField(c, field) {
|
|
3814
|
+
if (field.startsWith("metafield:")) return resolveMetafield(c.metafields, field);
|
|
3575
3815
|
switch (field) {
|
|
3576
3816
|
case "title":
|
|
3577
3817
|
case "name":
|
|
@@ -3754,6 +3994,50 @@ function assetUrl(name) {
|
|
|
3754
3994
|
return `${cleanBase}${filename}`;
|
|
3755
3995
|
}
|
|
3756
3996
|
|
|
3997
|
+
// src/utils/templates.ts
|
|
3998
|
+
function resolveSections(group) {
|
|
3999
|
+
if (!group) return [];
|
|
4000
|
+
if (Array.isArray(group.sections)) {
|
|
4001
|
+
return group.sections.map((instance, idx) => ({
|
|
4002
|
+
id: `${instance.type}-${idx}`,
|
|
4003
|
+
instance
|
|
4004
|
+
}));
|
|
4005
|
+
}
|
|
4006
|
+
const map = group.sections ?? {};
|
|
4007
|
+
const order = group.order ?? Object.keys(map);
|
|
4008
|
+
const out = [];
|
|
4009
|
+
for (const id of order) {
|
|
4010
|
+
const instance = map[id];
|
|
4011
|
+
if (instance) out.push({ id, instance });
|
|
4012
|
+
}
|
|
4013
|
+
return out;
|
|
4014
|
+
}
|
|
4015
|
+
function selectTemplateSections(hostTemplate, builtinTemplate, isKnown) {
|
|
4016
|
+
const hostSections = resolveSections(hostTemplate);
|
|
4017
|
+
if (hostSections.length === 0) {
|
|
4018
|
+
return resolveSections(builtinTemplate);
|
|
4019
|
+
}
|
|
4020
|
+
const anyKnown = hostSections.some(({ instance }) => isKnown(instance.type));
|
|
4021
|
+
if (!anyKnown) return resolveSections(builtinTemplate);
|
|
4022
|
+
return hostSections.filter(({ instance }) => isKnown(instance.type));
|
|
4023
|
+
}
|
|
4024
|
+
function selectChromeSections(options) {
|
|
4025
|
+
const { hostGroup, presetGroup, inline, templates, isChrome, isKnown } = options;
|
|
4026
|
+
const known = (list) => list.filter(({ instance }) => isKnown(instance.type));
|
|
4027
|
+
const fromHost = known(resolveSections(hostGroup));
|
|
4028
|
+
if (fromHost.length > 0) return fromHost;
|
|
4029
|
+
if (inline && inline.length > 0) return known(inline);
|
|
4030
|
+
const fromPreset = known(resolveSections(presetGroup));
|
|
4031
|
+
if (fromPreset.length > 0) return fromPreset;
|
|
4032
|
+
for (const template of templates ?? []) {
|
|
4033
|
+
const borrowed = known(resolveSections(template)).filter(
|
|
4034
|
+
({ instance }) => isChrome(instance.type)
|
|
4035
|
+
);
|
|
4036
|
+
if (borrowed.length > 0) return borrowed;
|
|
4037
|
+
}
|
|
4038
|
+
return [];
|
|
4039
|
+
}
|
|
4040
|
+
|
|
3757
4041
|
// src/utils/locales.ts
|
|
3758
4042
|
function flattenMessages(source, prefix = "") {
|
|
3759
4043
|
const out = {};
|
|
@@ -3804,43 +4088,43 @@ Object.defineProperty(exports, "resolveThemeSettings", {
|
|
|
3804
4088
|
});
|
|
3805
4089
|
Object.defineProperty(exports, "KNOWN_SETTING_TYPES", {
|
|
3806
4090
|
enumerable: true,
|
|
3807
|
-
get: function () { return
|
|
4091
|
+
get: function () { return chunkH7RGDWSU_cjs.KNOWN_SETTING_TYPES; }
|
|
3808
4092
|
});
|
|
3809
4093
|
Object.defineProperty(exports, "KNOWN_TEMPLATES", {
|
|
3810
4094
|
enumerable: true,
|
|
3811
|
-
get: function () { return
|
|
4095
|
+
get: function () { return chunkH7RGDWSU_cjs.KNOWN_TEMPLATES; }
|
|
3812
4096
|
});
|
|
3813
4097
|
Object.defineProperty(exports, "REQUIRED_TEMPLATES", {
|
|
3814
4098
|
enumerable: true,
|
|
3815
|
-
get: function () { return
|
|
4099
|
+
get: function () { return chunkH7RGDWSU_cjs.REQUIRED_TEMPLATES; }
|
|
3816
4100
|
});
|
|
3817
4101
|
Object.defineProperty(exports, "SDK_VERSION", {
|
|
3818
4102
|
enumerable: true,
|
|
3819
|
-
get: function () { return
|
|
4103
|
+
get: function () { return chunkH7RGDWSU_cjs.SDK_VERSION; }
|
|
3820
4104
|
});
|
|
3821
4105
|
Object.defineProperty(exports, "THEME_CONTRACT_VERSION", {
|
|
3822
4106
|
enumerable: true,
|
|
3823
|
-
get: function () { return
|
|
4107
|
+
get: function () { return chunkH7RGDWSU_cjs.THEME_CONTRACT_VERSION; }
|
|
3824
4108
|
});
|
|
3825
4109
|
Object.defineProperty(exports, "mergeResults", {
|
|
3826
4110
|
enumerable: true,
|
|
3827
|
-
get: function () { return
|
|
4111
|
+
get: function () { return chunkH7RGDWSU_cjs.mergeResults; }
|
|
3828
4112
|
});
|
|
3829
4113
|
Object.defineProperty(exports, "validateBuiltManifest", {
|
|
3830
4114
|
enumerable: true,
|
|
3831
|
-
get: function () { return
|
|
4115
|
+
get: function () { return chunkH7RGDWSU_cjs.validateBuiltManifest; }
|
|
3832
4116
|
});
|
|
3833
4117
|
Object.defineProperty(exports, "validateManifest", {
|
|
3834
4118
|
enumerable: true,
|
|
3835
|
-
get: function () { return
|
|
4119
|
+
get: function () { return chunkH7RGDWSU_cjs.validateManifest; }
|
|
3836
4120
|
});
|
|
3837
4121
|
Object.defineProperty(exports, "validateSectionSchema", {
|
|
3838
4122
|
enumerable: true,
|
|
3839
|
-
get: function () { return
|
|
4123
|
+
get: function () { return chunkH7RGDWSU_cjs.validateSectionSchema; }
|
|
3840
4124
|
});
|
|
3841
4125
|
Object.defineProperty(exports, "validateSettingsAgainstSchema", {
|
|
3842
4126
|
enumerable: true,
|
|
3843
|
-
get: function () { return
|
|
4127
|
+
get: function () { return chunkH7RGDWSU_cjs.validateSettingsAgainstSchema; }
|
|
3844
4128
|
});
|
|
3845
4129
|
Object.defineProperty(exports, "CartContext", {
|
|
3846
4130
|
enumerable: true,
|
|
@@ -3964,18 +4248,23 @@ exports.assetUrl = assetUrl;
|
|
|
3964
4248
|
exports.availableValues = availableValues;
|
|
3965
4249
|
exports.buildLocaleBundle = buildLocaleBundle;
|
|
3966
4250
|
exports.buildThemeElement = buildThemeElement;
|
|
4251
|
+
exports.centsToMajor = centsToMajor;
|
|
3967
4252
|
exports.clearSdkSingleton = clearSdkSingleton;
|
|
3968
4253
|
exports.collectBlocks = collectBlocks;
|
|
3969
4254
|
exports.collectSections = collectSections;
|
|
4255
|
+
exports.collectionHref = collectionHref;
|
|
3970
4256
|
exports.computeGlobalStyleTokens = computeGlobalStyleTokens;
|
|
3971
4257
|
exports.defaultVariant = defaultVariant;
|
|
3972
4258
|
exports.defineBlock = defineBlock;
|
|
3973
4259
|
exports.defineSection = defineSection;
|
|
3974
4260
|
exports.defineThemeEntry = defineThemeEntry;
|
|
3975
4261
|
exports.dynamicSource = dynamicSource;
|
|
4262
|
+
exports.eligibleUnitsInCart = eligibleUnitsInCart;
|
|
3976
4263
|
exports.findVariantByOptions = findVariantByOptions;
|
|
3977
4264
|
exports.flattenMessages = flattenMessages;
|
|
3978
4265
|
exports.focalSrc = focalSrc;
|
|
4266
|
+
exports.formatMoney = formatMoney;
|
|
4267
|
+
exports.formatMoneyMajor = formatMoneyMajor;
|
|
3979
4268
|
exports.getReactSingleton = getReactSingleton;
|
|
3980
4269
|
exports.getSdkSingleton = getSdkSingleton;
|
|
3981
4270
|
exports.isDefinedBlock = isDefinedBlock;
|
|
@@ -3984,8 +4273,14 @@ exports.isDynamicSource = isDynamicSource;
|
|
|
3984
4273
|
exports.isSdkAvailable = isSdkAvailable;
|
|
3985
4274
|
exports.logoImgStyle = logoImgStyle;
|
|
3986
4275
|
exports.logoStyleTokens = logoStyleTokens;
|
|
4276
|
+
exports.majorToCents = majorToCents;
|
|
3987
4277
|
exports.mountTheme = mountTheme;
|
|
4278
|
+
exports.multibuyOffers = multibuyOffers;
|
|
4279
|
+
exports.offerBeatsRegularPrice = offerBeatsRegularPrice;
|
|
4280
|
+
exports.offerIncludesProduct = offerIncludesProduct;
|
|
4281
|
+
exports.offerProgress = offerProgress;
|
|
3988
4282
|
exports.pickTranslations = pickTranslations;
|
|
4283
|
+
exports.productHref = productHref;
|
|
3989
4284
|
exports.publishVariantSelection = publishVariantSelection;
|
|
3990
4285
|
exports.readVariantSelection = readVariantSelection;
|
|
3991
4286
|
exports.registerReactSingleton = registerReactSingleton;
|
|
@@ -3993,12 +4288,20 @@ exports.registerSdkSingleton = registerSdkSingleton;
|
|
|
3993
4288
|
exports.requestNavigate = requestNavigate;
|
|
3994
4289
|
exports.resolveDynamicValue = resolveDynamicValue;
|
|
3995
4290
|
exports.resolveFontStack = resolveFontStack;
|
|
4291
|
+
exports.resolveSections = resolveSections;
|
|
3996
4292
|
exports.resolveSettingsMap = resolveSettingsMap;
|
|
3997
4293
|
exports.resolveSizeChart = resolveSizeChart;
|
|
3998
4294
|
exports.resolveSourcePath = resolveSourcePath;
|
|
3999
4295
|
exports.sanitizeHtml = sanitizeHtml;
|
|
4296
|
+
exports.selectChromeSections = selectChromeSections;
|
|
4297
|
+
exports.selectTemplateSections = selectTemplateSections;
|
|
4298
|
+
exports.useActivePromotions = useActivePromotions;
|
|
4000
4299
|
exports.useAnalytics = useAnalytics;
|
|
4001
4300
|
exports.useApp = useApp;
|
|
4301
|
+
exports.useArticle = useArticle;
|
|
4302
|
+
exports.useArticles = useArticles;
|
|
4303
|
+
exports.useBlog = useBlog;
|
|
4304
|
+
exports.useBlogs = useBlogs;
|
|
4002
4305
|
exports.useCachedResource = useCachedResource;
|
|
4003
4306
|
exports.useCart = useCart;
|
|
4004
4307
|
exports.useCheckout = useCheckout;
|
|
@@ -4010,6 +4313,9 @@ exports.useCustomerActions = useCustomerActions;
|
|
|
4010
4313
|
exports.useCustomerAddresses = useCustomerAddresses;
|
|
4011
4314
|
exports.useGiftCardBalance = useGiftCardBalance;
|
|
4012
4315
|
exports.useImage = useImage;
|
|
4316
|
+
exports.useListingHeading = useListingHeading;
|
|
4317
|
+
exports.useMetafield = useMetafield;
|
|
4318
|
+
exports.useMetafields = useMetafields;
|
|
4013
4319
|
exports.useMoney = useMoney;
|
|
4014
4320
|
exports.useNavigation = useNavigation;
|
|
4015
4321
|
exports.useOrder = useOrder;
|