@numueg/theme-sdk 0.10.1 → 0.12.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.cjs CHANGED
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  var chunkTBSNHHFH_cjs = require('./chunk-TBSNHHFH.cjs');
4
- var chunkO4GLTNLE_cjs = require('./chunk-O4GLTNLE.cjs');
4
+ var chunk7RZISLP2_cjs = require('./chunk-7RZISLP2.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 formatMoney(converted, selected);
159
+ return formatMoney2(converted, selected);
93
160
  }
94
- return formatMoney(amount, currencyOverride || shop?.currency);
161
+ return formatMoney2(amount, currencyOverride || shop?.currency);
95
162
  };
96
163
  }
97
164
  var DEFAULT_WIDTHS = [320, 480, 640, 768, 1024, 1280, 1600, 1920];
@@ -2255,13 +2322,13 @@ function pickDemo(ctx, themeSettings) {
2255
2322
  const t = themeSettings.templates;
2256
2323
  return !t || Object.keys(t).length === 0;
2257
2324
  }
2258
- function wrapEntityProviders(app, pageData) {
2325
+ function wrapEntityProviders(app, pageData2) {
2259
2326
  let inner = app;
2260
- if (pageData.collection) {
2261
- inner = /* @__PURE__ */ jsxRuntime.jsx(CollectionProvider, { collection: pageData.collection, children: inner });
2327
+ if (pageData2.collection) {
2328
+ inner = /* @__PURE__ */ jsxRuntime.jsx(CollectionProvider, { collection: pageData2.collection, children: inner });
2262
2329
  }
2263
- if (pageData.product) {
2264
- inner = /* @__PURE__ */ jsxRuntime.jsx(ProductProvider, { product: pageData.product, children: inner });
2330
+ if (pageData2.product) {
2331
+ inner = /* @__PURE__ */ jsxRuntime.jsx(ProductProvider, { product: pageData2.product, children: inner });
2265
2332
  }
2266
2333
  return inner;
2267
2334
  }
@@ -2284,7 +2351,7 @@ var ThemeMountBridge = react.forwardRef(function ThemeMountBridge2({ ctx, mountE
2284
2351
  const store = pickStore(ctx);
2285
2352
  const template = pickTemplate(ctx);
2286
2353
  const demo = pickDemo(ctx, themeSettings);
2287
- const pageData = ctx.page?.data ?? {};
2354
+ const pageData2 = ctx.page?.data ?? {};
2288
2355
  const app = renderApp({
2289
2356
  currentTemplate: template,
2290
2357
  demo,
@@ -2302,11 +2369,11 @@ var ThemeMountBridge = react.forwardRef(function ThemeMountBridge2({ ctx, mountE
2302
2369
  locale: ctx.locale,
2303
2370
  translations: ctx.translations,
2304
2371
  navigation: ctx.navigation,
2305
- initialProducts: pageData.products,
2306
- initialCollections: pageData.collections,
2372
+ initialProducts: pageData2.products,
2373
+ initialCollections: pageData2.collections,
2307
2374
  currentTemplate: template,
2308
2375
  pageTemplate: ctx.page?.template,
2309
- children: wrapEntityProviders(app, pageData)
2376
+ children: wrapEntityProviders(app, pageData2)
2310
2377
  }
2311
2378
  );
2312
2379
  });
@@ -2349,7 +2416,7 @@ function Money({
2349
2416
  className,
2350
2417
  as = "span"
2351
2418
  }) {
2352
- const { formatMoney } = chunkV3JDQXD3_cjs.useLocalization();
2419
+ const { formatMoney: formatMoney2 } = chunkV3JDQXD3_cjs.useLocalization();
2353
2420
  const shop = chunkV3JDQXD3_cjs.useShop();
2354
2421
  const { selected, base, autoConvert, convert } = useCurrency();
2355
2422
  const shouldConvert = autoConvert && !currency && !!selected && selected !== base;
@@ -2357,12 +2424,12 @@ function Money({
2357
2424
  const toDisplay = (major) => shouldConvert ? convert(Math.round(major * 100), selected) / 100 : major;
2358
2425
  const showCompare = compareAt != null && compareAt > amount;
2359
2426
  const children = [
2360
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: formatMoney(toDisplay(amount), ccy) }, "amt")
2427
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: formatMoney2(toDisplay(amount), ccy) }, "amt")
2361
2428
  ];
2362
2429
  if (showCompare) {
2363
2430
  children.push(" ");
2364
2431
  children.push(
2365
- /* @__PURE__ */ jsxRuntime.jsx("s", { style: { opacity: 0.6 }, children: formatMoney(toDisplay(compareAt), ccy) }, "cmp")
2432
+ /* @__PURE__ */ jsxRuntime.jsx("s", { style: { opacity: 0.6 }, children: formatMoney2(toDisplay(compareAt), ccy) }, "cmp")
2366
2433
  );
2367
2434
  }
2368
2435
  return react.createElement(
@@ -2382,7 +2449,7 @@ function asImageTransform(v) {
2382
2449
  return void 0;
2383
2450
  }
2384
2451
  function applyImageTransform(t, fit = "cover") {
2385
- if (!t) return { objectFit: fit };
2452
+ if (!t) return {};
2386
2453
  const fx = Math.round(_clampT(t.focal?.x ?? 0.5, 0, 1) * 1e4) / 100;
2387
2454
  const fy = Math.round(_clampT(t.focal?.y ?? 0.5, 0, 1) * 1e4) / 100;
2388
2455
  const zoom = _clampT(t.zoom ?? 1, 1, 4);
@@ -2585,7 +2652,10 @@ function HeroMedia({
2585
2652
  const activeBase = useMobile ? MOBILE_BASE_WIDTH : DESKTOP_BASE_WIDTH;
2586
2653
  const activeSrc = rawFallback ? activeUrl : focalSrc(activeUrl, { width: activeBase, ...activeCrop });
2587
2654
  const activeSrcSet = rawFallback ? void 0 : heroSrcSet(activeUrl, activeCrop);
2588
- const fitStyle = applyImageTransform(useMobile ? mobileTransform ?? transform : transform, fit);
2655
+ const fitStyle = {
2656
+ objectFit: fit,
2657
+ ...applyImageTransform(useMobile ? mobileTransform ?? transform : transform, fit)
2658
+ };
2589
2659
  return /* @__PURE__ */ jsxRuntime.jsx(
2590
2660
  "img",
2591
2661
  {
@@ -2926,6 +2996,20 @@ function Form({
2926
2996
  }
2927
2997
  );
2928
2998
  }
2999
+
3000
+ // src/utils/routes.ts
3001
+ function productHref(slugOrId) {
3002
+ if (!slugOrId) return "/products";
3003
+ return `/products/${slugOrId}`;
3004
+ }
3005
+ function collectionHref(category) {
3006
+ if (!category) return "/collections";
3007
+ if (typeof category === "string") {
3008
+ return category ? `/collections/${category}` : "/collections";
3009
+ }
3010
+ const key = category.slug || category.id;
3011
+ return key ? `/collections/${key}` : "/collections";
3012
+ }
2929
3013
  function joinClass(...names) {
2930
3014
  return names.filter(Boolean).join(" ");
2931
3015
  }
@@ -2936,7 +3020,7 @@ function ProductCard({
2936
3020
  slots,
2937
3021
  imageSizes
2938
3022
  }) {
2939
- const target = href ?? `/products/${product.slug}`;
3023
+ const target = href ?? productHref(product.slug);
2940
3024
  const firstImage = product.images?.[0];
2941
3025
  const inStock = product.in_stock;
2942
3026
  const badge = slots?.badge !== void 0 ? slots.badge : inStock ? null : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "numu-product-card__badge", children: "Sold out" });
@@ -3549,7 +3633,19 @@ function resolveSourcePath(path, ctx) {
3549
3633
  return null;
3550
3634
  }
3551
3635
  }
3636
+ function resolveMetafield(metafields, field) {
3637
+ const address = field.slice("metafield:".length);
3638
+ const dot = address.indexOf(".");
3639
+ if (dot === -1) return null;
3640
+ const namespace = address.slice(0, dot);
3641
+ const key = address.slice(dot + 1);
3642
+ const hit = (metafields ?? []).find(
3643
+ (m) => m.namespace === namespace && m.key === key
3644
+ );
3645
+ return hit ? hit.value ?? null : null;
3646
+ }
3552
3647
  function resolveProductField(p, field) {
3648
+ if (field.startsWith("metafield:")) return resolveMetafield(p.metafields, field);
3553
3649
  switch (field) {
3554
3650
  case "title":
3555
3651
  case "name":
@@ -3572,6 +3668,7 @@ function resolveProductField(p, field) {
3572
3668
  }
3573
3669
  }
3574
3670
  function resolveCollectionField(c, field) {
3671
+ if (field.startsWith("metafield:")) return resolveMetafield(c.metafields, field);
3575
3672
  switch (field) {
3576
3673
  case "title":
3577
3674
  case "name":
@@ -3754,6 +3851,76 @@ function assetUrl(name) {
3754
3851
  return `${cleanBase}${filename}`;
3755
3852
  }
3756
3853
 
3854
+ // src/utils/money.ts
3855
+ function resolveLocale(locale) {
3856
+ return locale === "ar" ? "ar-EG" : "en-EG";
3857
+ }
3858
+ function formatMoney(cents, options = {}) {
3859
+ const { currency, locale, fractionDigits = 0 } = options;
3860
+ const safe = Number.isFinite(cents) ? cents : 0;
3861
+ return new Intl.NumberFormat(resolveLocale(locale), {
3862
+ style: "currency",
3863
+ currency: currency || "EGP",
3864
+ maximumFractionDigits: fractionDigits
3865
+ }).format(safe / 100);
3866
+ }
3867
+ function formatMoneyMajor(amount, options = {}) {
3868
+ return formatMoney(
3869
+ (Number.isFinite(amount) ? amount : 0) * 100,
3870
+ options
3871
+ );
3872
+ }
3873
+ function centsToMajor(cents) {
3874
+ return (Number.isFinite(cents) ? cents : 0) / 100;
3875
+ }
3876
+ function majorToCents(amount) {
3877
+ return Math.round((Number.isFinite(amount) ? amount : 0) * 100);
3878
+ }
3879
+
3880
+ // src/utils/templates.ts
3881
+ function resolveSections(group) {
3882
+ if (!group) return [];
3883
+ if (Array.isArray(group.sections)) {
3884
+ return group.sections.map((instance, idx) => ({
3885
+ id: `${instance.type}-${idx}`,
3886
+ instance
3887
+ }));
3888
+ }
3889
+ const map = group.sections ?? {};
3890
+ const order = group.order ?? Object.keys(map);
3891
+ const out = [];
3892
+ for (const id of order) {
3893
+ const instance = map[id];
3894
+ if (instance) out.push({ id, instance });
3895
+ }
3896
+ return out;
3897
+ }
3898
+ function selectTemplateSections(hostTemplate, builtinTemplate, isKnown) {
3899
+ const hostSections = resolveSections(hostTemplate);
3900
+ if (hostSections.length === 0) {
3901
+ return resolveSections(builtinTemplate);
3902
+ }
3903
+ const anyKnown = hostSections.some(({ instance }) => isKnown(instance.type));
3904
+ if (!anyKnown) return resolveSections(builtinTemplate);
3905
+ return hostSections.filter(({ instance }) => isKnown(instance.type));
3906
+ }
3907
+ function selectChromeSections(options) {
3908
+ const { hostGroup, presetGroup, inline, templates, isChrome, isKnown } = options;
3909
+ const known = (list) => list.filter(({ instance }) => isKnown(instance.type));
3910
+ const fromHost = known(resolveSections(hostGroup));
3911
+ if (fromHost.length > 0) return fromHost;
3912
+ if (inline && inline.length > 0) return known(inline);
3913
+ const fromPreset = known(resolveSections(presetGroup));
3914
+ if (fromPreset.length > 0) return fromPreset;
3915
+ for (const template of templates ?? []) {
3916
+ const borrowed = known(resolveSections(template)).filter(
3917
+ ({ instance }) => isChrome(instance.type)
3918
+ );
3919
+ if (borrowed.length > 0) return borrowed;
3920
+ }
3921
+ return [];
3922
+ }
3923
+
3757
3924
  // src/utils/locales.ts
3758
3925
  function flattenMessages(source, prefix = "") {
3759
3926
  const out = {};
@@ -3804,43 +3971,43 @@ Object.defineProperty(exports, "resolveThemeSettings", {
3804
3971
  });
3805
3972
  Object.defineProperty(exports, "KNOWN_SETTING_TYPES", {
3806
3973
  enumerable: true,
3807
- get: function () { return chunkO4GLTNLE_cjs.KNOWN_SETTING_TYPES; }
3974
+ get: function () { return chunk7RZISLP2_cjs.KNOWN_SETTING_TYPES; }
3808
3975
  });
3809
3976
  Object.defineProperty(exports, "KNOWN_TEMPLATES", {
3810
3977
  enumerable: true,
3811
- get: function () { return chunkO4GLTNLE_cjs.KNOWN_TEMPLATES; }
3978
+ get: function () { return chunk7RZISLP2_cjs.KNOWN_TEMPLATES; }
3812
3979
  });
3813
3980
  Object.defineProperty(exports, "REQUIRED_TEMPLATES", {
3814
3981
  enumerable: true,
3815
- get: function () { return chunkO4GLTNLE_cjs.REQUIRED_TEMPLATES; }
3982
+ get: function () { return chunk7RZISLP2_cjs.REQUIRED_TEMPLATES; }
3816
3983
  });
3817
3984
  Object.defineProperty(exports, "SDK_VERSION", {
3818
3985
  enumerable: true,
3819
- get: function () { return chunkO4GLTNLE_cjs.SDK_VERSION; }
3986
+ get: function () { return chunk7RZISLP2_cjs.SDK_VERSION; }
3820
3987
  });
3821
3988
  Object.defineProperty(exports, "THEME_CONTRACT_VERSION", {
3822
3989
  enumerable: true,
3823
- get: function () { return chunkO4GLTNLE_cjs.THEME_CONTRACT_VERSION; }
3990
+ get: function () { return chunk7RZISLP2_cjs.THEME_CONTRACT_VERSION; }
3824
3991
  });
3825
3992
  Object.defineProperty(exports, "mergeResults", {
3826
3993
  enumerable: true,
3827
- get: function () { return chunkO4GLTNLE_cjs.mergeResults; }
3994
+ get: function () { return chunk7RZISLP2_cjs.mergeResults; }
3828
3995
  });
3829
3996
  Object.defineProperty(exports, "validateBuiltManifest", {
3830
3997
  enumerable: true,
3831
- get: function () { return chunkO4GLTNLE_cjs.validateBuiltManifest; }
3998
+ get: function () { return chunk7RZISLP2_cjs.validateBuiltManifest; }
3832
3999
  });
3833
4000
  Object.defineProperty(exports, "validateManifest", {
3834
4001
  enumerable: true,
3835
- get: function () { return chunkO4GLTNLE_cjs.validateManifest; }
4002
+ get: function () { return chunk7RZISLP2_cjs.validateManifest; }
3836
4003
  });
3837
4004
  Object.defineProperty(exports, "validateSectionSchema", {
3838
4005
  enumerable: true,
3839
- get: function () { return chunkO4GLTNLE_cjs.validateSectionSchema; }
4006
+ get: function () { return chunk7RZISLP2_cjs.validateSectionSchema; }
3840
4007
  });
3841
4008
  Object.defineProperty(exports, "validateSettingsAgainstSchema", {
3842
4009
  enumerable: true,
3843
- get: function () { return chunkO4GLTNLE_cjs.validateSettingsAgainstSchema; }
4010
+ get: function () { return chunk7RZISLP2_cjs.validateSettingsAgainstSchema; }
3844
4011
  });
3845
4012
  Object.defineProperty(exports, "CartContext", {
3846
4013
  enumerable: true,
@@ -3964,9 +4131,11 @@ exports.assetUrl = assetUrl;
3964
4131
  exports.availableValues = availableValues;
3965
4132
  exports.buildLocaleBundle = buildLocaleBundle;
3966
4133
  exports.buildThemeElement = buildThemeElement;
4134
+ exports.centsToMajor = centsToMajor;
3967
4135
  exports.clearSdkSingleton = clearSdkSingleton;
3968
4136
  exports.collectBlocks = collectBlocks;
3969
4137
  exports.collectSections = collectSections;
4138
+ exports.collectionHref = collectionHref;
3970
4139
  exports.computeGlobalStyleTokens = computeGlobalStyleTokens;
3971
4140
  exports.defaultVariant = defaultVariant;
3972
4141
  exports.defineBlock = defineBlock;
@@ -3976,6 +4145,8 @@ exports.dynamicSource = dynamicSource;
3976
4145
  exports.findVariantByOptions = findVariantByOptions;
3977
4146
  exports.flattenMessages = flattenMessages;
3978
4147
  exports.focalSrc = focalSrc;
4148
+ exports.formatMoney = formatMoney;
4149
+ exports.formatMoneyMajor = formatMoneyMajor;
3979
4150
  exports.getReactSingleton = getReactSingleton;
3980
4151
  exports.getSdkSingleton = getSdkSingleton;
3981
4152
  exports.isDefinedBlock = isDefinedBlock;
@@ -3984,8 +4155,10 @@ exports.isDynamicSource = isDynamicSource;
3984
4155
  exports.isSdkAvailable = isSdkAvailable;
3985
4156
  exports.logoImgStyle = logoImgStyle;
3986
4157
  exports.logoStyleTokens = logoStyleTokens;
4158
+ exports.majorToCents = majorToCents;
3987
4159
  exports.mountTheme = mountTheme;
3988
4160
  exports.pickTranslations = pickTranslations;
4161
+ exports.productHref = productHref;
3989
4162
  exports.publishVariantSelection = publishVariantSelection;
3990
4163
  exports.readVariantSelection = readVariantSelection;
3991
4164
  exports.registerReactSingleton = registerReactSingleton;
@@ -3993,12 +4166,19 @@ exports.registerSdkSingleton = registerSdkSingleton;
3993
4166
  exports.requestNavigate = requestNavigate;
3994
4167
  exports.resolveDynamicValue = resolveDynamicValue;
3995
4168
  exports.resolveFontStack = resolveFontStack;
4169
+ exports.resolveSections = resolveSections;
3996
4170
  exports.resolveSettingsMap = resolveSettingsMap;
3997
4171
  exports.resolveSizeChart = resolveSizeChart;
3998
4172
  exports.resolveSourcePath = resolveSourcePath;
3999
4173
  exports.sanitizeHtml = sanitizeHtml;
4174
+ exports.selectChromeSections = selectChromeSections;
4175
+ exports.selectTemplateSections = selectTemplateSections;
4000
4176
  exports.useAnalytics = useAnalytics;
4001
4177
  exports.useApp = useApp;
4178
+ exports.useArticle = useArticle;
4179
+ exports.useArticles = useArticles;
4180
+ exports.useBlog = useBlog;
4181
+ exports.useBlogs = useBlogs;
4002
4182
  exports.useCachedResource = useCachedResource;
4003
4183
  exports.useCart = useCart;
4004
4184
  exports.useCheckout = useCheckout;
@@ -4010,6 +4190,9 @@ exports.useCustomerActions = useCustomerActions;
4010
4190
  exports.useCustomerAddresses = useCustomerAddresses;
4011
4191
  exports.useGiftCardBalance = useGiftCardBalance;
4012
4192
  exports.useImage = useImage;
4193
+ exports.useListingHeading = useListingHeading;
4194
+ exports.useMetafield = useMetafield;
4195
+ exports.useMetafields = useMetafields;
4013
4196
  exports.useMoney = useMoney;
4014
4197
  exports.useNavigation = useNavigation;
4015
4198
  exports.useOrder = useOrder;