@numueg/theme-sdk 0.6.0 → 0.9.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 +144 -0
- package/dist/chunk-3C37JX2X.cjs +207 -0
- package/dist/chunk-3C37JX2X.cjs.map +1 -0
- package/dist/chunk-JIAA7TGR.mjs +397 -0
- package/dist/chunk-JIAA7TGR.mjs.map +1 -0
- package/dist/chunk-PUR3FRGQ.mjs +183 -0
- package/dist/chunk-PUR3FRGQ.mjs.map +1 -0
- package/dist/chunk-TBSNHHFH.cjs +96 -0
- package/dist/chunk-TBSNHHFH.cjs.map +1 -0
- package/dist/chunk-X3J4GDI7.cjs +408 -0
- package/dist/chunk-X3J4GDI7.cjs.map +1 -0
- package/dist/chunk-XF2FGIVS.mjs +94 -0
- package/dist/chunk-XF2FGIVS.mjs.map +1 -0
- package/dist/{entities-6MGANln7.d.mts → entities-B8378GKp.d.mts} +12 -0
- package/dist/{entities-6MGANln7.d.ts → entities-B8378GKp.d.ts} +12 -0
- package/dist/index.cjs +643 -965
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +215 -82
- package/dist/index.d.ts +215 -82
- package/dist/index.mjs +485 -908
- package/dist/index.mjs.map +1 -1
- package/dist/{mount-BGumg1JM.d.mts → mount-CM4kGg9w.d.ts} +87 -14
- package/dist/{mount-Bt-4ken5.d.ts → mount-NLjFNyBv.d.mts} +87 -14
- package/dist/normalize.cjs +7 -91
- package/dist/normalize.cjs.map +1 -1
- package/dist/normalize.d.mts +1 -1
- package/dist/normalize.d.ts +1 -1
- package/dist/normalize.mjs +1 -92
- package/dist/normalize.mjs.map +1 -1
- package/dist/{theme-D8MOopvi.d.mts → theme-CNTB4KnU.d.mts} +29 -3
- package/dist/{theme-D8MOopvi.d.ts → theme-CNTB4KnU.d.ts} +29 -3
- package/dist/types.d.mts +2 -2
- package/dist/types.d.ts +2 -2
- package/dist/v2-compat.cjs +6 -163
- package/dist/v2-compat.cjs.map +1 -1
- package/dist/v2-compat.d.mts +1 -1
- package/dist/v2-compat.d.ts +1 -1
- package/dist/v2-compat.mjs +2 -159
- package/dist/v2-compat.mjs.map +1 -1
- package/dist/validation.cjs +43 -403
- package/dist/validation.cjs.map +1 -1
- package/dist/validation.d.mts +1 -1
- package/dist/validation.d.ts +1 -1
- package/dist/validation.mjs +1 -395
- package/dist/validation.mjs.map +1 -1
- package/dist/verify.cjs +6 -21
- package/dist/verify.cjs.map +1 -1
- package/dist/verify.d.mts +3 -3
- package/dist/verify.d.ts +3 -3
- package/dist/verify.mjs +3 -20
- package/dist/verify.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { i as Store, e as Product, b as Collection,
|
|
2
|
-
export { A as Address, a as CartItem, O as Order, d as OrderItem, f as ProductImage, j as ProductOption, h as SizeChartMode } from './entities-
|
|
3
|
-
import { T as ThemeSettingsV3, c as SectionInstance, M as MountResult, B as BlockInstance, b as BlockSchema, a as BlockProps$1, f as SectionSchema, e as SectionProps$1 } from './theme-
|
|
4
|
-
export { E as ExternalThemeMetadata, h as MAX_BLOCK_DEPTH, P as PageTemplate, i as PresetBlock, S as SectionGroup, d as SectionPreset, g as SettingDefinition } from './theme-
|
|
1
|
+
import { i as Store, e as Product, b as Collection, c as Customer, P as Page, S as SizeChart, g as ProductVariant, C as Cart } from './entities-B8378GKp.mjs';
|
|
2
|
+
export { A as Address, a as CartItem, O as Order, d as OrderItem, f as ProductImage, j as ProductOption, h as SizeChartMode } from './entities-B8378GKp.mjs';
|
|
3
|
+
import { T as ThemeSettingsV3, c as SectionInstance, M as MountResult, B as BlockInstance, b as BlockSchema, a as BlockProps$1, f as SectionSchema, e as SectionProps$1 } from './theme-CNTB4KnU.mjs';
|
|
4
|
+
export { E as ExternalThemeMetadata, h as MAX_BLOCK_DEPTH, P as PageTemplate, i as PresetBlock, S as SectionGroup, d as SectionPreset, g as SettingDefinition } from './theme-CNTB4KnU.mjs';
|
|
5
5
|
export { KNOWN_SETTING_TYPES, KNOWN_TEMPLATES, REQUIRED_TEMPLATES, SDK_VERSION, THEME_CONTRACT_VERSION, ValidationIssue, ValidationResult, mergeResults, validateBuiltManifest, validateManifest, validateSectionSchema, validateSettingsAgainstSchema } from './validation.mjs';
|
|
6
|
-
import { L as LocalizationState, T as ThemeMountContext,
|
|
7
|
-
export {
|
|
6
|
+
import { C as CartContextValue, L as LocalizationState, a as CurrencyState, T as ThemeMountContext, b as ThemeRenderArgs, M as MenuItemData } from './mount-NLjFNyBv.mjs';
|
|
7
|
+
export { c as CartContext, d as CartMutationResult, e as CollectionContext, f as CurrencyConfig, g as CurrencyContext, h as CustomerContext, i as LocalizationContext, N as NavigationContext, P as PageContext, j as ProductContext, S as ShopContext, k as ThemeMountPage, l as ThemeSettingsContext, m as buildThemeElement, n as mountTheme } from './mount-NLjFNyBv.mjs';
|
|
8
8
|
import * as react from 'react';
|
|
9
9
|
import { ReactElement, ReactNode, ElementType, CSSProperties, ImgHTMLAttributes, AnchorHTMLAttributes, ButtonHTMLAttributes, HTMLAttributes, FormHTMLAttributes, ComponentType } from 'react';
|
|
10
10
|
export { resolveThemeSettings } from './normalize.mjs';
|
|
@@ -43,17 +43,7 @@ declare function useProductOptional(): Product | null;
|
|
|
43
43
|
declare function useCollection(): Collection;
|
|
44
44
|
declare function useCollectionOptional(): Collection | null;
|
|
45
45
|
|
|
46
|
-
declare function useCart():
|
|
47
|
-
cart: Cart;
|
|
48
|
-
addItem: (productId: string, variantId?: string, quantity?: number) => Promise<void>;
|
|
49
|
-
removeItem: (itemId: string) => Promise<void>;
|
|
50
|
-
updateQuantity: (itemId: string, quantity: number) => Promise<void>;
|
|
51
|
-
applyDiscount: (code: string) => Promise<void>;
|
|
52
|
-
removeDiscount: () => Promise<void>;
|
|
53
|
-
updateNote: (note: string) => Promise<void>;
|
|
54
|
-
clearCart: () => Promise<void>;
|
|
55
|
-
loading: boolean;
|
|
56
|
-
};
|
|
46
|
+
declare function useCart(): CartContextValue;
|
|
57
47
|
|
|
58
48
|
declare function useCustomer(): Customer | null;
|
|
59
49
|
|
|
@@ -136,14 +126,67 @@ declare function useSection(): SectionInstance;
|
|
|
136
126
|
declare function useSectionOptional(): SectionInstance | null;
|
|
137
127
|
|
|
138
128
|
/**
|
|
139
|
-
*
|
|
140
|
-
* the
|
|
129
|
+
* A section instance from a section group, carrying its own `id` (the key it
|
|
130
|
+
* had inside the group's `sections` map). The raw `SectionInstance` drops the
|
|
131
|
+
* id — but a theme needs it to key its React list, wire `<Section id={…}>`
|
|
132
|
+
* click-to-select, and look the type up in its own registry — so
|
|
133
|
+
* `useSectionGroup` re-attaches it here.
|
|
134
|
+
*/
|
|
135
|
+
interface SectionGroupInstance extends SectionInstance {
|
|
136
|
+
/** The instance's key within the group's `sections` map. */
|
|
137
|
+
id: string;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* useSectionGroup — read the ordered section instances for a named section
|
|
141
|
+
* group ("header", "footer", or any custom global group) out of
|
|
142
|
+
* `themeSettings.section_groups[group]`.
|
|
143
|
+
*
|
|
144
|
+
* This is the SDK side of "global sections shared across pages": the host
|
|
145
|
+
* ships one `section_groups` map on every page, and a theme renders a given
|
|
146
|
+
* group in its layout (header/footer) or wherever it wants a page-independent
|
|
147
|
+
* section list. The returned array is in the group's `order`, and each entry
|
|
148
|
+
* carries its `id` so the theme can key + select + dispatch on it:
|
|
149
|
+
*
|
|
150
|
+
* ```tsx
|
|
151
|
+
* const headerSections = useSectionGroup("header");
|
|
152
|
+
* return headerSections.map(({ id, type, settings }) => {
|
|
153
|
+
* const Comp = registry[type]?.render; // theme owns the registry
|
|
154
|
+
* return Comp ? (
|
|
155
|
+
* <Section key={id} id={id} type={type} groupId="header">
|
|
156
|
+
* <Comp settings={settings} />
|
|
157
|
+
* </Section>
|
|
158
|
+
* ) : null;
|
|
159
|
+
* });
|
|
160
|
+
* ```
|
|
161
|
+
*
|
|
162
|
+
* Pure data hook — it does NOT map types to components. The SDK has no section
|
|
163
|
+
* registry (a theme builds its own via `collectSections`), so there is no
|
|
164
|
+
* generic `<GlobalSections>` renderer to ship: the theme walks the returned
|
|
165
|
+
* instances through its own registry, exactly as it already does for template
|
|
166
|
+
* sections. Returns `[]` (a stable reference) when there is no provider, no
|
|
167
|
+
* `section_groups`, the named group is absent, or its `order` is empty.
|
|
168
|
+
*
|
|
169
|
+
* Disabled instances are INCLUDED (a `disabled` flag is preserved on each
|
|
170
|
+
* entry); filter with `.filter((s) => !s.disabled)` if the theme hides them.
|
|
171
|
+
* Ids listed in `order` but missing from `sections` are skipped defensively.
|
|
172
|
+
*/
|
|
173
|
+
declare function useSectionGroup(group: string): SectionGroupInstance[];
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* useMoney — convenience hook that returns a formatter bound to the active
|
|
177
|
+
* store's currency.
|
|
141
178
|
*
|
|
142
179
|
* Useful when a section needs to format multiple amounts in a render:
|
|
143
180
|
*
|
|
144
181
|
* const money = useMoney();
|
|
145
182
|
* return <td>{money(item.price * item.quantity)}</td>
|
|
146
183
|
*
|
|
184
|
+
* Multi-currency: like <Money>, when the store has `auto_convert` on and no
|
|
185
|
+
* `currencyOverride` is passed, amounts are converted to and formatted in the
|
|
186
|
+
* visitor's SELECTED presentment currency (shared via `useCurrency()`), so a
|
|
187
|
+
* `<CurrencySwitcher>` change reflows these too. Pass a `currencyOverride` to
|
|
188
|
+
* pin a specific currency and skip conversion.
|
|
189
|
+
*
|
|
147
190
|
* For one-off price displays prefer the <Money> component which handles
|
|
148
191
|
* compare-at and inline rendering.
|
|
149
192
|
*/
|
|
@@ -579,10 +622,19 @@ declare function useAnalytics(): AnalyticsApi;
|
|
|
579
622
|
* `{ available: false }` rather than as a network error — themes
|
|
580
623
|
* branch on availability without try/catch.
|
|
581
624
|
*
|
|
582
|
-
*
|
|
583
|
-
*
|
|
584
|
-
*
|
|
585
|
-
*
|
|
625
|
+
* Phase 3 (client-data layer): the fetch now runs through the shared
|
|
626
|
+
* `useCachedResource` store keyed by `numu:app:<store_id>:<slug>`. Two upgrades
|
|
627
|
+
* over the old per-instance `useState` + fetch:
|
|
628
|
+
* - DEDUP + SYNC: N consumers of the same app slug share ONE request and one
|
|
629
|
+
* result, instead of each firing its own `/apps/{slug}` fetch.
|
|
630
|
+
* - CANCELLATION / ORDERING: the fetcher receives an AbortSignal and the
|
|
631
|
+
* cache seq-guards results, so a slow response for a superseded slug (or a
|
|
632
|
+
* superseded `refresh()`) can no longer apply stale state over a newer one
|
|
633
|
+
* — the audited "out-of-order responses apply stale state" bug.
|
|
634
|
+
*
|
|
635
|
+
* `loading` reflects the FIRST load only; a `refresh()` revalidates in the
|
|
636
|
+
* background (`isValidating`) while keeping the last-good data visible, rather
|
|
637
|
+
* than blanking to a skeleton on every manual refresh.
|
|
586
638
|
*/
|
|
587
639
|
interface AppManifestBlock {
|
|
588
640
|
type: string;
|
|
@@ -628,8 +680,17 @@ declare function useApp<T = unknown>(slug: string): AppState<T>;
|
|
|
628
680
|
* v1 implementation: localStorage only. The /api/customer/me/wishlist
|
|
629
681
|
* endpoint isn't wired yet; an authed visitor still gets the local
|
|
630
682
|
* fallback so themes work end-to-end. When the endpoint lands, the
|
|
631
|
-
*
|
|
632
|
-
*
|
|
683
|
+
* fetcher below swaps its localStorage read for the server fetch and the
|
|
684
|
+
* mutation methods gain a `{ revalidate: true }` write-through.
|
|
685
|
+
*
|
|
686
|
+
* Phase 3 (client-data layer): the items list now lives in the shared
|
|
687
|
+
* `useCachedResource` store keyed by `numu_wishlist_<store_id>`, NOT in
|
|
688
|
+
* per-instance `useState`. Previously two `<Heart>`s for the same product
|
|
689
|
+
* each held their own copy, so adding via one never re-rendered the other —
|
|
690
|
+
* the two hearts DESYNCED. Now every `useWishlist(storeId)` consumer reads
|
|
691
|
+
* and writes ONE shared entry, so an add/remove anywhere reflows every heart.
|
|
692
|
+
* Writes are optimistic (the shared store updates instantly) and roll back if
|
|
693
|
+
* persistence throws.
|
|
633
694
|
*/
|
|
634
695
|
interface WishlistItem {
|
|
635
696
|
product_id: string;
|
|
@@ -661,11 +722,17 @@ declare function useWishlist(storeId: string): WishlistState;
|
|
|
661
722
|
* together"; v1 ships the simpler same-category-minus-self heuristic.
|
|
662
723
|
*
|
|
663
724
|
* Backend contract: GET /api/storefront/products/{id}/related?limit=N
|
|
664
|
-
* → { items: Product[] } | Product[]
|
|
725
|
+
* → { items: Product[] } | { data: Product[] } | Product[]
|
|
665
726
|
*
|
|
666
727
|
* Returns an empty list (no error) when the endpoint is missing or the
|
|
667
728
|
* product has no siblings — themes should branch on `items.length` and
|
|
668
729
|
* either render the section or skip it entirely.
|
|
730
|
+
*
|
|
731
|
+
* Phase 3 (client-data layer): routed through the shared `useCachedResource`
|
|
732
|
+
* store keyed by `numu:related:<productId>:<limit>`. Two "related products"
|
|
733
|
+
* sections on the same PDP now share ONE request + one result instead of each
|
|
734
|
+
* refetching, and the AbortSignal + cache seq-guard drop a superseded response
|
|
735
|
+
* (e.g. after a rapid product switch) so it can't overwrite the newer list.
|
|
669
736
|
*/
|
|
670
737
|
interface RelatedProductsState {
|
|
671
738
|
items: Product[];
|
|
@@ -676,6 +743,103 @@ declare function useRelatedProducts(productId: string | null | undefined, option
|
|
|
676
743
|
limit?: number;
|
|
677
744
|
}): RelatedProductsState;
|
|
678
745
|
|
|
746
|
+
/**
|
|
747
|
+
* Shared client-data layer (Phase 3) — a tiny SWR-style cache with ZERO
|
|
748
|
+
* runtime dependencies.
|
|
749
|
+
*
|
|
750
|
+
* Why this exists (from the audit): several hooks fetched + held per-instance
|
|
751
|
+
* state, so N components rendering the same resource fired N identical requests
|
|
752
|
+
* AND drifted out of sync (e.g. two wishlist hearts for one product; `useApp`
|
|
753
|
+
* applying an out-of-order response over a newer one). `useCachedResource`
|
|
754
|
+
* centralizes fetching behind one module-level store keyed by a string:
|
|
755
|
+
*
|
|
756
|
+
* (a) DEDUP — the first consumer of a key starts the fetch and stashes the
|
|
757
|
+
* in-flight promise on the entry; every other consumer that revalidates
|
|
758
|
+
* the same key while it's pending joins that promise instead of firing a
|
|
759
|
+
* second request. N consumers → ONE network call.
|
|
760
|
+
* (b) CACHE — results live on the entry keyed by string, so a later mount
|
|
761
|
+
* reads the cached value immediately (and skips refetch within
|
|
762
|
+
* `dedupeIntervalMs`).
|
|
763
|
+
* (c) SUBSCRIBE / NOTIFY — every hook instance subscribes to its key via
|
|
764
|
+
* `useSyncExternalStore`. Any update (fetch resolve, `mutate`) rebuilds
|
|
765
|
+
* the entry's immutable snapshot and notifies ALL subscribers, so every
|
|
766
|
+
* instance re-renders with the same value — cross-instance state sync.
|
|
767
|
+
* (d) REVALIDATE + CANCELLATION — each fetch reserves a monotonic sequence
|
|
768
|
+
* number and an `AbortController`. Starting a new (forced) fetch aborts
|
|
769
|
+
* the previous one; when any fetch settles, its result is applied ONLY if
|
|
770
|
+
* its sequence is still the latest (`mySeq === entry.seq`). So a slow,
|
|
771
|
+
* superseded response can never overwrite a newer result regardless of
|
|
772
|
+
* the order the network resolves them in.
|
|
773
|
+
*
|
|
774
|
+
* SSR-safe: the fetch is triggered from `useEffect` (never runs under
|
|
775
|
+
* `renderToString`), and `useSyncExternalStore`'s server snapshot returns the
|
|
776
|
+
* `initialData` fallback without ever touching the module cache — so nothing is
|
|
777
|
+
* written to the shared map on the server and there is no cross-request bleed.
|
|
778
|
+
*
|
|
779
|
+
* This is intentionally NOT a full SWR clone (no focus/reconnect revalidation,
|
|
780
|
+
* no suspense, no infinite pagination). It's the smallest primitive that fixes
|
|
781
|
+
* the audited dedup + sync + ordering bugs and that themes can reuse.
|
|
782
|
+
*/
|
|
783
|
+
/** The reactive slice a consumer reads. */
|
|
784
|
+
interface CachedResourceState<T> {
|
|
785
|
+
/** Latest cached value, or `initialData` before the first fetch settles. */
|
|
786
|
+
data: T | undefined;
|
|
787
|
+
/** Error from the most recent settled fetch (cleared on success / mutate). */
|
|
788
|
+
error: Error | undefined;
|
|
789
|
+
/** True until the first fetch (or `mutate`) settles a value for this key. */
|
|
790
|
+
isLoading: boolean;
|
|
791
|
+
/** True whenever a fetch is currently in flight (initial OR background). */
|
|
792
|
+
isValidating: boolean;
|
|
793
|
+
}
|
|
794
|
+
/** Fetcher receives an AbortSignal so a superseding fetch can cancel it. */
|
|
795
|
+
type CacheFetcher<T> = (signal: AbortSignal) => Promise<T>;
|
|
796
|
+
/** `mutate` accepts a value or an updater `(current) => next`. */
|
|
797
|
+
type CacheMutator<T> = T | undefined | ((current: T | undefined) => T | undefined);
|
|
798
|
+
interface MutateOptions {
|
|
799
|
+
/** After applying the local value, kick a fresh (forced) revalidation. */
|
|
800
|
+
revalidate?: boolean;
|
|
801
|
+
}
|
|
802
|
+
interface CachedResource<T> extends CachedResourceState<T> {
|
|
803
|
+
/**
|
|
804
|
+
* Optimistically write the cached value for this key (all subscribers
|
|
805
|
+
* re-render). Pass `{ revalidate: true }` to also refetch afterwards.
|
|
806
|
+
*/
|
|
807
|
+
mutate: (next: CacheMutator<T>, opts?: MutateOptions) => void;
|
|
808
|
+
/** Force a fresh fetch, superseding + aborting any in-flight request. */
|
|
809
|
+
revalidate: () => Promise<void>;
|
|
810
|
+
}
|
|
811
|
+
interface UseCachedResourceOptions<T> {
|
|
812
|
+
/**
|
|
813
|
+
* Value shown on the server and on the first client paint before the fetch
|
|
814
|
+
* resolves. Used as the SSR snapshot (SSR-safe: no fetch on the server).
|
|
815
|
+
*/
|
|
816
|
+
initialData?: T;
|
|
817
|
+
/** When `false`, the hook holds no subscription and never fetches. */
|
|
818
|
+
enabled?: boolean;
|
|
819
|
+
/** Auto-fetch on mount / key change (default `true`). */
|
|
820
|
+
revalidateOnMount?: boolean;
|
|
821
|
+
/**
|
|
822
|
+
* Skip the mount fetch if a value settled within this window (ms). Prevents
|
|
823
|
+
* a staggered second mount from refetching a still-fresh key. Default 2000.
|
|
824
|
+
*/
|
|
825
|
+
dedupeIntervalMs?: number;
|
|
826
|
+
/** Called on a non-abort fetch error, with the key. */
|
|
827
|
+
onError?: (error: Error, key: string) => void;
|
|
828
|
+
}
|
|
829
|
+
/**
|
|
830
|
+
* Subscribe to a cached resource keyed by `key`, deduping the fetch across all
|
|
831
|
+
* instances and keeping them in sync. See the module docblock for the full
|
|
832
|
+
* contract.
|
|
833
|
+
*
|
|
834
|
+
* @param key Cache key. `null`/`undefined`/`""` (or `enabled: false`)
|
|
835
|
+
* disables the hook — no subscription, no fetch, `initialData`
|
|
836
|
+
* is returned.
|
|
837
|
+
* @param fetcher `(signal) => Promise<T>`. Recreated-per-render is fine; the
|
|
838
|
+
* latest is captured in a ref so it doesn't retrigger fetches.
|
|
839
|
+
* @param options See {@link UseCachedResourceOptions}.
|
|
840
|
+
*/
|
|
841
|
+
declare function useCachedResource<T>(key: string | null | undefined, fetcher: CacheFetcher<T>, options?: UseCachedResourceOptions<T>): CachedResource<T>;
|
|
842
|
+
|
|
679
843
|
/**
|
|
680
844
|
* useProductSizeChart — resolve the size chart to show for a product.
|
|
681
845
|
*
|
|
@@ -703,53 +867,6 @@ declare function useProductSizeChart(productOverride?: Product | null): SizeChar
|
|
|
703
867
|
*/
|
|
704
868
|
declare function resolveSizeChart(productAttributes: Record<string, unknown> | undefined, storeSettings: Record<string, unknown> | undefined): SizeChart | null;
|
|
705
869
|
|
|
706
|
-
/**
|
|
707
|
-
* Multi-currency presentment — Phase 6.
|
|
708
|
-
*
|
|
709
|
-
* The store's *capture* currency (what Paymob/Stripe/etc. charges)
|
|
710
|
-
* never changes mid-session. This hook is purely about **display**:
|
|
711
|
-
* letting visitors browse prices in a currency they recognize.
|
|
712
|
-
*
|
|
713
|
-
* Usage:
|
|
714
|
-
*
|
|
715
|
-
* const { base, selected, presentment, convert, setSelected } = useCurrency();
|
|
716
|
-
* <p>{convert(product.price.amount_cents)} {selected}</p>
|
|
717
|
-
* {presentment.length > 1 && (
|
|
718
|
-
* <select value={selected} onChange={(e) => setSelected(e.target.value)}>
|
|
719
|
-
* {presentment.map(c => <option key={c}>{c}</option>)}
|
|
720
|
-
* </select>
|
|
721
|
-
* )}
|
|
722
|
-
*
|
|
723
|
-
* Behavior:
|
|
724
|
-
* - `selected` defaults to the persisted `numu_currency` cookie if
|
|
725
|
-
* valid, else `default_presentment`, else `base`.
|
|
726
|
-
* - `setSelected` writes the cookie (path=/, 30d) so navigation
|
|
727
|
-
* preserves the choice across pages.
|
|
728
|
-
* - `convert(cents)` returns the converted cents in `selected`,
|
|
729
|
-
* using the rates from the API. When no rate exists, returns
|
|
730
|
-
* the input unchanged (theme renders in base — better than a
|
|
731
|
-
* wrong number).
|
|
732
|
-
*
|
|
733
|
-
* Use `<CurrencySwitcher>` from the SDK for an opinionated UI, or
|
|
734
|
-
* read this hook directly for full control.
|
|
735
|
-
*/
|
|
736
|
-
interface CurrencyConfig {
|
|
737
|
-
base: string;
|
|
738
|
-
default_presentment: string;
|
|
739
|
-
presentment: string[];
|
|
740
|
-
rates: Record<string, string>;
|
|
741
|
-
auto_convert: boolean;
|
|
742
|
-
}
|
|
743
|
-
interface CurrencyState {
|
|
744
|
-
base: string;
|
|
745
|
-
selected: string;
|
|
746
|
-
presentment: string[];
|
|
747
|
-
rates: Record<string, number>;
|
|
748
|
-
autoConvert: boolean;
|
|
749
|
-
loading: boolean;
|
|
750
|
-
setSelected: (currency: string) => void;
|
|
751
|
-
convert: (cents: number, target?: string) => number;
|
|
752
|
-
}
|
|
753
870
|
declare function useCurrency(): CurrencyState;
|
|
754
871
|
|
|
755
872
|
/**
|
|
@@ -1092,6 +1209,15 @@ interface NuMuProviderProps {
|
|
|
1092
1209
|
* built before the prop existed keep rendering their home template.
|
|
1093
1210
|
*/
|
|
1094
1211
|
currentTemplate?: string;
|
|
1212
|
+
/**
|
|
1213
|
+
* I3 — resolved alternate template key for the current page (e.g.
|
|
1214
|
+
* `"product.wholesale"`) when the storefront routed it to a template
|
|
1215
|
+
* suffix. Published on the synthesized `PageContext` value so themes read
|
|
1216
|
+
* it via `usePage()?.template`. Distinct from `currentTemplate`, which is
|
|
1217
|
+
* the base route type (`"product"`). Omit for pages on their default
|
|
1218
|
+
* template; additive, so themes/hosts predating it are unaffected.
|
|
1219
|
+
*/
|
|
1220
|
+
pageTemplate?: string;
|
|
1095
1221
|
/**
|
|
1096
1222
|
* Pre-fetched product list for the current page. Themes that call
|
|
1097
1223
|
* `useProducts()` will read these from PageContext without needing
|
|
@@ -1117,7 +1243,7 @@ interface NuMuProviderProps {
|
|
|
1117
1243
|
navigation?: Record<string, MenuItemData[]>;
|
|
1118
1244
|
children: ReactNode;
|
|
1119
1245
|
}
|
|
1120
|
-
declare function NuMuProvider({ store, themeSettings, initialCart, customer, locale: initialLocale, translations: initialTranslations, currentTemplate, initialProducts, initialCollections, navigation, children, }: NuMuProviderProps): react.JSX.Element;
|
|
1246
|
+
declare function NuMuProvider({ store, themeSettings, initialCart, customer, locale: initialLocale, translations: initialTranslations, currentTemplate, pageTemplate, initialProducts, initialCollections, navigation, children, }: NuMuProviderProps): react.JSX.Element;
|
|
1121
1247
|
|
|
1122
1248
|
interface ProductProviderProps {
|
|
1123
1249
|
product: Product;
|
|
@@ -1154,6 +1280,13 @@ interface MoneyProps {
|
|
|
1154
1280
|
* Intl.NumberFormat. Renders inline with `dir="auto"` so the digits
|
|
1155
1281
|
* flow naturally in RTL (Arabic) without flipping the currency symbol.
|
|
1156
1282
|
*
|
|
1283
|
+
* Multi-currency: when the store has `auto_convert` on and the caller did NOT
|
|
1284
|
+
* pin an explicit `currency`, the amount is presented in the visitor's
|
|
1285
|
+
* SELECTED currency (converted via the shared rates from `useCurrency()`). A
|
|
1286
|
+
* `<CurrencySwitcher>` change therefore re-renders every `<Money>` on the page
|
|
1287
|
+
* without a reload. An explicit `currency` prop means "this amount is already
|
|
1288
|
+
* in that currency" — it is respected and never converted.
|
|
1289
|
+
*
|
|
1157
1290
|
* Usage:
|
|
1158
1291
|
* <Money amount={product.price} compareAt={product.compare_at_price} />
|
|
1159
1292
|
*/
|
|
@@ -1670,13 +1803,13 @@ interface RichTextProps {
|
|
|
1670
1803
|
* Sanitize an HTML string against the allowlist above. Runs server-
|
|
1671
1804
|
* AND client-side because rich-text fields are server-rendered for SEO.
|
|
1672
1805
|
*
|
|
1673
|
-
* Implementation note:
|
|
1674
|
-
*
|
|
1675
|
-
*
|
|
1676
|
-
*
|
|
1677
|
-
*
|
|
1678
|
-
*
|
|
1679
|
-
*
|
|
1806
|
+
* Implementation note: in the browser we use DOMParser (structural allowlist
|
|
1807
|
+
* — see `sanitizeHtmlClient`/`walk`). On the server (no DOM) we fall through
|
|
1808
|
+
* to `sanitizeHtmlServer`, a hardened regex denylist that strips dangerous
|
|
1809
|
+
* element blocks to a fixpoint, removes inline event handlers (incl.
|
|
1810
|
+
* slash-separated ones), and drops non-allowlisted `href`/`src` URLs. Themes
|
|
1811
|
+
* needing server-rendered rich content with edge-case structure should
|
|
1812
|
+
* sanitize on the API tier and pass already-safe HTML through.
|
|
1680
1813
|
*/
|
|
1681
1814
|
declare function sanitizeHtml(input: string): string;
|
|
1682
1815
|
declare function RichText({ html, className, as }: RichTextProps): react.JSX.Element | null;
|
|
@@ -2267,4 +2400,4 @@ declare function pickTranslations(bundle: LocaleBundle, locale: string): LocaleM
|
|
|
2267
2400
|
*/
|
|
2268
2401
|
declare function buildLocaleBundle<T extends Record<string, unknown>>(modules: T): LocaleBundle;
|
|
2269
2402
|
|
|
2270
|
-
export { AddToCartButton, type AddressInput, type AnalyticsApi, type AnalyticsPayload, type AppManifestBlock, type AppPayload, type AppState, Block, BlockInstance, BlockProps$1 as BlockProps, BlockSchema, Cart, type CheckoutAddress, type CheckoutApi, type CheckoutSessionState, type CheckoutStep, Collection, CollectionCard, type CollectionCardProps, type CollectionCardSlots, CollectionProvider, type ComputedStyleTokens,
|
|
2403
|
+
export { AddToCartButton, type AddressInput, type AnalyticsApi, type AnalyticsPayload, type AppManifestBlock, type AppPayload, type AppState, Block, BlockInstance, BlockProps$1 as BlockProps, BlockSchema, type CacheFetcher, type CacheMutator, type CachedResource, type CachedResourceState, Cart, CartContextValue, type CheckoutAddress, type CheckoutApi, type CheckoutSessionState, type CheckoutStep, Collection, CollectionCard, type CollectionCardProps, type CollectionCardSlots, CollectionProvider, type ComputedStyleTokens, CurrencyState, CurrencySwitcher, type CurrencySwitcherProps, Customer, type CustomerAddress, type CustomerAddressesState, type DefineBlockInput, type DefineSectionInput, type DefinedBlock, type DefinedSection, type DynamicResolveContext, type DynamicSourceRef, EditableImage, type EditableImageProps, EditableText, type EditableTextProps, type FocalSrcOptions, Form, type GiftCardBalance, HeroMedia, type HeroMediaProps, ICON_NAMES, Icon, IconMap, type IconProps, Image, type ImageTransform, LOGO_SHAPE_OPTIONS, LOGO_SIZE_OPTIONS, Link, type LocaleBundle, type LocaleMessages, LocaleSwitcher, type LocaleSwitcherProps, Logo, type LogoProps, type LogoShape, type LogoSize, MenuItemData, Money, MountResult, type MutateOptions, type NavigationItem, type NavigationState, NuMuProvider, type OrderDetail, type OrderListEntry, type OrderListState, type OrderState, Page, type PlaceOrderResult, Product, ProductCard, type ProductCardProps, type ProductCardSlots, ProductProvider, ProductVariant, type RelatedProductsState, type ReorderResult, type ReorderSkipReason, type ReorderSkippedItem, RichText, type RichTextProps, type SearchResults, type SearchState, Section, SectionContext, type SectionGroupInstance, SectionInstance, SectionProps$1 as SectionProps, SectionSchema, type ShippingRateOption, type ShopWithHelpers, SizeChart, Store, type ThemeEntry, ThemeMountContext, ThemeRenderArgs, ThemeSettingsV3, type UseCachedResourceOptions, type UseGiftCardBalance, type UseReorder, type UseSearchOptions, type UseShippingRatesOptions, type UseShippingRatesState, type UseVariantSelection, type WishlistItem, type WishlistState, applyGlobalStyleTokens, applyImageTransform, asImageTransform, assetUrl, availableValues, buildLocaleBundle, clearSdkSingleton, collectBlocks, collectSections, computeGlobalStyleTokens, defaultVariant, defineBlock, defineSection, defineThemeEntry, dynamicSource, findVariantByOptions, flattenMessages, focalSrc, getReactSingleton, getSdkSingleton, isDefinedBlock, isDefinedSection, isDynamicSource, isSdkAvailable, logoImgStyle, logoStyleTokens, pickTranslations, registerReactSingleton, registerSdkSingleton, resolveDynamicValue, resolveFontStack, resolveSettingsMap, resolveSizeChart, resolveSourcePath, sanitizeHtml, useAnalytics, useApp, useCachedResource, useCart, useCheckout, useCollection, useCollectionOptional, useCollections, useCurrency, useCurrentTemplate, useCustomer, useCustomerActions, useCustomerAddresses, useDirection, useFieldTranslation, useGiftCardBalance, useImage, useLocale, useLocalization, useMoney, useNavigation, useNumberFormat, useOrder, useOrders, usePage, useProduct, useProductOptional, useProductSizeChart, useProducts, useRelatedProducts, useReorder, useResolvedSettings, useSearch, useSection, useSectionGroup, useSectionOptional, useShippingRates, useShop, useThemeSettings, useTranslation, useVariantSelection, useWishlist };
|