@nok-integration/storefront-react 0.19.39 → 0.19.41
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.d.ts +77 -5
- package/dist/index.mjs +133 -65
- package/dist/standalone/storefront.mjs +133 -65
- package/dist/standalone/styles.css +24 -24
- package/dist/styles.css +24 -24
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -2089,6 +2089,10 @@ declare type CategoryPage = z.infer<typeof CategoryPage>;
|
|
|
2089
2089
|
*
|
|
2090
2090
|
* Fetching happens on mount, client-side, through the provider's client — so it inherits
|
|
2091
2091
|
* the host's session and market without being told about either.
|
|
2092
|
+
*
|
|
2093
|
+
* The page is held under the CODE it belongs to and read back only while that code is
|
|
2094
|
+
* still the one being asked for, so a change of `code` never leaves the previous category
|
|
2095
|
+
* on screen while the next one loads.
|
|
2092
2096
|
*/
|
|
2093
2097
|
export declare function CategoryView({ code, initialData, onNotFound }: CategoryViewProps): JSX.Element;
|
|
2094
2098
|
|
|
@@ -2100,6 +2104,10 @@ export declare interface CategoryViewProps {
|
|
|
2100
2104
|
* synchronously on the first frame — no skeleton, no waterfall — and revalidated in the
|
|
2101
2105
|
* background, because a server-rendered page can be arbitrarily old by the time it is
|
|
2102
2106
|
* interactive and price and availability are the two things worst served by being stale.
|
|
2107
|
+
*
|
|
2108
|
+
* Matched against `code` on every render, not only at mount, so a host that swaps both
|
|
2109
|
+
* together has the new page painted immediately. A page for a different code is ignored
|
|
2110
|
+
* rather than shown.
|
|
2103
2111
|
*/
|
|
2104
2112
|
initialData?: CategoryPage;
|
|
2105
2113
|
/**
|
|
@@ -4803,6 +4811,19 @@ declare const Product: z.ZodObject<{
|
|
|
4803
4811
|
|
|
4804
4812
|
declare type Product = z.infer<typeof Product>;
|
|
4805
4813
|
|
|
4814
|
+
declare class ProductCache {
|
|
4815
|
+
private readonly now;
|
|
4816
|
+
private readonly entries;
|
|
4817
|
+
/** Injectable so the age limit can be tested without leaning on timers. */
|
|
4818
|
+
constructor(now?: () => number);
|
|
4819
|
+
private static keyFor;
|
|
4820
|
+
get(sku: string, market?: Market): Product | undefined;
|
|
4821
|
+
set(product: Product, market?: Market): void;
|
|
4822
|
+
setMany(products: readonly Product[], market?: Market): void;
|
|
4823
|
+
/** Test seam. Nothing in the SDK calls this. */
|
|
4824
|
+
clear(): void;
|
|
4825
|
+
}
|
|
4826
|
+
|
|
4806
4827
|
/**
|
|
4807
4828
|
* 4.3 PDP interactive surface, aligned to the DAZN mobile PDP design. Sections render
|
|
4808
4829
|
* from server-authoritative contract data: badges, title + price, promo nudge, description
|
|
@@ -4950,11 +4971,10 @@ declare type ProductVariant = z.infer<typeof ProductVariant>;
|
|
|
4950
4971
|
/**
|
|
4951
4972
|
* A whole product-detail screen, data fetching included — a **level 1 view**.
|
|
4952
4973
|
*
|
|
4953
|
-
*
|
|
4954
|
-
*
|
|
4955
|
-
*
|
|
4956
|
-
*
|
|
4957
|
-
* have bought from.
|
|
4974
|
+
* All of the fetching lives in {@link useProduct}, which is exported: a host composing its
|
|
4975
|
+
* own product screen from level-2 pieces gets the same behaviour rather than writing it
|
|
4976
|
+
* again. Switching between two items paints the new one immediately wherever the rail
|
|
4977
|
+
* already carried it, and never leaves the outgoing item up while the next one loads.
|
|
4958
4978
|
*
|
|
4959
4979
|
* `sku_not_found` is separated from the generic error path because it is not a fault: the
|
|
4960
4980
|
* product is gone, and "this is no longer available" is the honest thing to say. An error
|
|
@@ -5538,6 +5558,8 @@ export declare function ShippingInfo(): JSX.Element;
|
|
|
5538
5558
|
declare interface ShopContextValue {
|
|
5539
5559
|
api: DaznClient;
|
|
5540
5560
|
market?: Market;
|
|
5561
|
+
/** Products this provider has already been given — see {@link ProductCache}. */
|
|
5562
|
+
products: ProductCache;
|
|
5541
5563
|
theme: 'light' | 'dark' | 'auto';
|
|
5542
5564
|
notifications: 'internal' | 'host';
|
|
5543
5565
|
locale?: string;
|
|
@@ -6395,6 +6417,56 @@ export declare function useMoney(defaultLocale?: string): {
|
|
|
6395
6417
|
*/
|
|
6396
6418
|
export declare function useNavigate(): ((to: ShopRoute) => void) | null;
|
|
6397
6419
|
|
|
6420
|
+
/**
|
|
6421
|
+
* The data behind a product screen: the product, then inventory and recommendations.
|
|
6422
|
+
*
|
|
6423
|
+
* This is what {@link ProductView} is built from, exported so a host composing its own
|
|
6424
|
+
* product screen from the level-2 pieces does not have to write the fetching again. Two
|
|
6425
|
+
* properties are worth knowing about, because a hand-rolled version has to reproduce both.
|
|
6426
|
+
*
|
|
6427
|
+
* **Everything is held under the SKU it belongs to**, and read back only while that SKU is
|
|
6428
|
+
* still the one being asked for. A change of `sku` invalidates the whole set in the same
|
|
6429
|
+
* render that changes it, so the outgoing product is never left on screen while the next
|
|
6430
|
+
* one loads, and there is no frame in which one item's title sits above another item's
|
|
6431
|
+
* price.
|
|
6432
|
+
*
|
|
6433
|
+
* **A product already in memory is painted at once.** The recommendation rail carries whole
|
|
6434
|
+
* products, so opening one of them is usually drawn on the first frame and corrected a
|
|
6435
|
+
* moment later, rather than spending a round trip behind a skeleton. Inventory and
|
|
6436
|
+
* recommendations always come from the request — they are the two things worst served by
|
|
6437
|
+
* being remembered, and neither is needed to draw the top of the screen.
|
|
6438
|
+
*
|
|
6439
|
+
* Inventory and recommendations are best-effort: the screen renders perfectly well without
|
|
6440
|
+
* either, so a failure in one does not fault it.
|
|
6441
|
+
*/ export declare function useProduct(sku: string, options?: UseProductOptions): UseProductResult;
|
|
6442
|
+
|
|
6443
|
+
export declare interface UseProductOptions {
|
|
6444
|
+
/**
|
|
6445
|
+
* An already-fetched product, from a host that server-rendered this screen. Painted on
|
|
6446
|
+
* the first frame and revalidated in the background.
|
|
6447
|
+
*
|
|
6448
|
+
* Read on every render, not only at mount, so a host that swaps `sku` and `initialData`
|
|
6449
|
+
* together has the new product painted immediately. It is matched against `sku` before
|
|
6450
|
+
* use: a product for a different SKU is ignored rather than shown.
|
|
6451
|
+
*/
|
|
6452
|
+
initialData?: {
|
|
6453
|
+
product: Product;
|
|
6454
|
+
inventory?: Inventory | null;
|
|
6455
|
+
};
|
|
6456
|
+
/** Fetch the "you may also like" rail. Default `true`. */
|
|
6457
|
+
showRecommendations?: boolean;
|
|
6458
|
+
}
|
|
6459
|
+
|
|
6460
|
+
export declare interface UseProductResult {
|
|
6461
|
+
/** Null until there is something to draw for this SKU. */
|
|
6462
|
+
product: Product | null;
|
|
6463
|
+
inventory: Inventory | null;
|
|
6464
|
+
recommendations: Product[];
|
|
6465
|
+
/** Nothing to draw yet and nothing has gone wrong — it is still on its way. */
|
|
6466
|
+
loading: boolean;
|
|
6467
|
+
error: ReturnType<typeof codeOf> | undefined;
|
|
6468
|
+
}
|
|
6469
|
+
|
|
6398
6470
|
/** The typed, schema-validating commerce client. Requires a provider. */
|
|
6399
6471
|
export declare function useShopApi(): DaznClient;
|
|
6400
6472
|
|
package/dist/index.mjs
CHANGED
|
@@ -5112,6 +5112,49 @@ function resolveAssetUrl(src, base) {
|
|
|
5112
5112
|
if (!src.startsWith("/") || src.startsWith("//")) return src;
|
|
5113
5113
|
return `${base.replace(/\/+$/, "")}${src}`;
|
|
5114
5114
|
}
|
|
5115
|
+
const MAX_AGE_MS = 5 * 6e4;
|
|
5116
|
+
const CAPACITY = 60;
|
|
5117
|
+
class ProductCache {
|
|
5118
|
+
constructor(now = () => Date.now()) {
|
|
5119
|
+
this.now = now;
|
|
5120
|
+
}
|
|
5121
|
+
now;
|
|
5122
|
+
entries = /* @__PURE__ */ new Map();
|
|
5123
|
+
static keyFor(sku, market) {
|
|
5124
|
+
return `${market?.country ?? ""}\0${market?.lang ?? ""}\0${sku}`;
|
|
5125
|
+
}
|
|
5126
|
+
get(sku, market) {
|
|
5127
|
+
const key = ProductCache.keyFor(sku, market);
|
|
5128
|
+
const entry = this.entries.get(key);
|
|
5129
|
+
if (!entry) return void 0;
|
|
5130
|
+
if (this.now() - entry.at > MAX_AGE_MS) {
|
|
5131
|
+
this.entries.delete(key);
|
|
5132
|
+
return void 0;
|
|
5133
|
+
}
|
|
5134
|
+
this.entries.delete(key);
|
|
5135
|
+
this.entries.set(key, entry);
|
|
5136
|
+
return entry.product;
|
|
5137
|
+
}
|
|
5138
|
+
set(product, market) {
|
|
5139
|
+
const key = ProductCache.keyFor(product.sku, market);
|
|
5140
|
+
this.entries.delete(key);
|
|
5141
|
+
this.entries.set(key, {
|
|
5142
|
+
product,
|
|
5143
|
+
at: this.now()
|
|
5144
|
+
});
|
|
5145
|
+
while (this.entries.size > CAPACITY) {
|
|
5146
|
+
const oldest = this.entries.keys().next();
|
|
5147
|
+
if (oldest.done) break;
|
|
5148
|
+
this.entries.delete(oldest.value);
|
|
5149
|
+
}
|
|
5150
|
+
}
|
|
5151
|
+
setMany(products, market) {
|
|
5152
|
+
for (const product of products) this.set(product, market);
|
|
5153
|
+
}
|
|
5154
|
+
clear() {
|
|
5155
|
+
this.entries.clear();
|
|
5156
|
+
}
|
|
5157
|
+
}
|
|
5115
5158
|
function createShopFetch(opts) {
|
|
5116
5159
|
const baseFetch = opts.fetchImpl ?? globalThis.fetch;
|
|
5117
5160
|
if (!baseFetch) throw new Error("No fetch implementation available");
|
|
@@ -5226,6 +5269,9 @@ function DaznShopProvider({ children, ...config }) {
|
|
|
5226
5269
|
const getTokenRef = useRef(getToken);
|
|
5227
5270
|
getTokenRef.current = getToken;
|
|
5228
5271
|
const stableGetToken = useCallback(() => getTokenRef.current(), []);
|
|
5272
|
+
const productsRef = useRef(null);
|
|
5273
|
+
productsRef.current ??= new ProductCache();
|
|
5274
|
+
const products = productsRef.current;
|
|
5229
5275
|
const emit = useCallback((event) => {
|
|
5230
5276
|
for (const listener of listeners.current) {
|
|
5231
5277
|
try {
|
|
@@ -5266,6 +5312,7 @@ function DaznShopProvider({ children, ...config }) {
|
|
|
5266
5312
|
const value2 = useMemo(() => ({
|
|
5267
5313
|
api,
|
|
5268
5314
|
market,
|
|
5315
|
+
products,
|
|
5269
5316
|
theme,
|
|
5270
5317
|
notifications,
|
|
5271
5318
|
locale,
|
|
@@ -5273,7 +5320,7 @@ function DaznShopProvider({ children, ...config }) {
|
|
|
5273
5320
|
emit,
|
|
5274
5321
|
subscribe,
|
|
5275
5322
|
navigate
|
|
5276
|
-
}), [api, market, theme, notifications, locale, assetBaseUrl, emit, subscribe, navigate]);
|
|
5323
|
+
}), [api, market, products, theme, notifications, locale, assetBaseUrl, emit, subscribe, navigate]);
|
|
5277
5324
|
return jsx(ShopContext.Provider, {
|
|
5278
5325
|
value: value2,
|
|
5279
5326
|
children: jsx(ScreenTitleProvider, {
|
|
@@ -5482,7 +5529,7 @@ const styles$O = {
|
|
|
5482
5529
|
surface: surface$1,
|
|
5483
5530
|
fill
|
|
5484
5531
|
};
|
|
5485
|
-
const SETTLE_MS
|
|
5532
|
+
const SETTLE_MS = 150;
|
|
5486
5533
|
function scrolledOffOrigin(el) {
|
|
5487
5534
|
for (let node = el.parentElement; node; node = node.parentElement) {
|
|
5488
5535
|
if (node.scrollTop > 0) return true;
|
|
@@ -5506,11 +5553,11 @@ function useTopOffset(ref, property, enabled = true) {
|
|
|
5506
5553
|
};
|
|
5507
5554
|
const settle = () => {
|
|
5508
5555
|
if (timer2) clearTimeout(timer2);
|
|
5509
|
-
timer2 = setTimeout(measure, SETTLE_MS
|
|
5556
|
+
timer2 = setTimeout(measure, SETTLE_MS);
|
|
5510
5557
|
};
|
|
5511
5558
|
measure();
|
|
5512
5559
|
const frame2 = typeof requestAnimationFrame === "undefined" ? void 0 : requestAnimationFrame(measure);
|
|
5513
|
-
const settleAfterMount = setTimeout(measure, SETTLE_MS
|
|
5560
|
+
const settleAfterMount = setTimeout(measure, SETTLE_MS);
|
|
5514
5561
|
window.addEventListener("resize", measure);
|
|
5515
5562
|
window.addEventListener("orientationchange", measure);
|
|
5516
5563
|
document.addEventListener("scroll", settle, {
|
|
@@ -10710,32 +10757,51 @@ function CategoryContent({ page: page2 }) {
|
|
|
10710
10757
|
})]
|
|
10711
10758
|
});
|
|
10712
10759
|
}
|
|
10760
|
+
function productsIn(page2) {
|
|
10761
|
+
const found = [];
|
|
10762
|
+
for (const block of page2.blocks) {
|
|
10763
|
+
if (block.kind === "rail" || block.kind === "grid") found.push(...block.products);
|
|
10764
|
+
else if (block.kind === "featured" || block.kind === "product_gallery") found.push(block.product);
|
|
10765
|
+
}
|
|
10766
|
+
return found;
|
|
10767
|
+
}
|
|
10713
10768
|
function CategoryView({ code, initialData, onNotFound }) {
|
|
10714
10769
|
const t = useT();
|
|
10715
|
-
const { api, market, emit } = useShop();
|
|
10716
|
-
const [
|
|
10717
|
-
const [
|
|
10718
|
-
const
|
|
10770
|
+
const { api, market, emit, products } = useShop();
|
|
10771
|
+
const [loaded, setLoaded] = useState(null);
|
|
10772
|
+
const [failure, setFailure] = useState(null);
|
|
10773
|
+
const settled = loaded?.code === code;
|
|
10774
|
+
const seeded = initialData && initialData.code === code ? initialData : void 0;
|
|
10775
|
+
const page2 = (settled ? loaded?.page : void 0) ?? seeded ?? null;
|
|
10776
|
+
const error2 = failure?.code === code ? failure.error : void 0;
|
|
10777
|
+
const loading = !page2 && !error2 && !settled;
|
|
10719
10778
|
useEffect(() => {
|
|
10720
10779
|
let live = true;
|
|
10721
|
-
setError(void 0);
|
|
10722
10780
|
api.catalog.getCategoryPage(code, market).then((res) => {
|
|
10781
|
+
const fetched = res;
|
|
10782
|
+
products.setMany(productsIn(fetched), market);
|
|
10723
10783
|
if (!live) return;
|
|
10724
|
-
|
|
10784
|
+
setLoaded({
|
|
10785
|
+
code,
|
|
10786
|
+
page: fetched
|
|
10787
|
+
});
|
|
10725
10788
|
}).catch((err) => {
|
|
10726
10789
|
if (!live) return;
|
|
10727
10790
|
const c = codeOf(err);
|
|
10728
|
-
|
|
10791
|
+
setFailure({
|
|
10792
|
+
code,
|
|
10793
|
+
error: c
|
|
10794
|
+
});
|
|
10729
10795
|
emit({
|
|
10730
10796
|
type: "error",
|
|
10731
10797
|
code: c,
|
|
10732
10798
|
scope: "category"
|
|
10733
10799
|
});
|
|
10734
|
-
})
|
|
10800
|
+
});
|
|
10735
10801
|
return () => {
|
|
10736
10802
|
live = false;
|
|
10737
10803
|
};
|
|
10738
|
-
}, [api, code, market, emit]);
|
|
10804
|
+
}, [api, code, market, emit, products]);
|
|
10739
10805
|
if (error2 === "category_not_found" && onNotFound) return jsx(Fragment, {
|
|
10740
10806
|
children: onNotFound()
|
|
10741
10807
|
});
|
|
@@ -10756,23 +10822,22 @@ function CategoryView({ code, initialData, onNotFound }) {
|
|
|
10756
10822
|
})
|
|
10757
10823
|
});
|
|
10758
10824
|
}
|
|
10759
|
-
function
|
|
10760
|
-
const
|
|
10761
|
-
const { api, market, emit } = useShop();
|
|
10762
|
-
const [loaded, setLoaded] = useState(
|
|
10763
|
-
sku,
|
|
10764
|
-
product: initialData.product,
|
|
10765
|
-
inventory: initialData.inventory ?? null,
|
|
10766
|
-
recommendations: []
|
|
10767
|
-
} : null);
|
|
10825
|
+
function useProduct(sku, options2 = {}) {
|
|
10826
|
+
const { initialData, showRecommendations = true } = options2;
|
|
10827
|
+
const { api, market, emit, products } = useShop();
|
|
10828
|
+
const [loaded, setLoaded] = useState(null);
|
|
10768
10829
|
const [failure, setFailure] = useState(null);
|
|
10769
10830
|
const current2 = loaded?.sku === sku ? loaded : null;
|
|
10770
10831
|
const error2 = failure?.sku === sku ? failure.code : void 0;
|
|
10832
|
+
const seeded = initialData && initialData.product.sku === sku ? initialData.product : products.get(sku, market);
|
|
10833
|
+
const product = current2?.product ?? seeded ?? null;
|
|
10834
|
+
const inventory2 = current2 ? current2.inventory : initialData && initialData.product.sku === sku ? initialData.inventory ?? null : null;
|
|
10771
10835
|
useEffect(() => {
|
|
10772
10836
|
let live = true;
|
|
10773
10837
|
(async () => {
|
|
10774
10838
|
try {
|
|
10775
10839
|
const p = await api.catalog.getProduct(sku, market);
|
|
10840
|
+
products.set(p, market);
|
|
10776
10841
|
if (!live) return;
|
|
10777
10842
|
setLoaded({
|
|
10778
10843
|
sku,
|
|
@@ -10784,12 +10849,14 @@ function ProductView({ sku, initialData, showRecommendations = true, onNotFound
|
|
|
10784
10849
|
const [inv, recs] = await Promise.allSettled([hasVariants ? Promise.resolve(null) : api.inventory.get(sku), showRecommendations ? api.catalog.getRecommendations(sku, market) : Promise.resolve({
|
|
10785
10850
|
data: []
|
|
10786
10851
|
})]);
|
|
10852
|
+
const recommendations = recs.status === "fulfilled" ? recs.value.data : [];
|
|
10853
|
+
products.setMany(recommendations, market);
|
|
10787
10854
|
if (!live) return;
|
|
10788
10855
|
setLoaded({
|
|
10789
10856
|
sku,
|
|
10790
10857
|
product: p,
|
|
10791
10858
|
inventory: inv.status === "fulfilled" ? inv.value : null,
|
|
10792
|
-
recommendations
|
|
10859
|
+
recommendations
|
|
10793
10860
|
});
|
|
10794
10861
|
} catch (err) {
|
|
10795
10862
|
if (!live) return;
|
|
@@ -10808,7 +10875,23 @@ function ProductView({ sku, initialData, showRecommendations = true, onNotFound
|
|
|
10808
10875
|
return () => {
|
|
10809
10876
|
live = false;
|
|
10810
10877
|
};
|
|
10811
|
-
}, [api, sku, market, emit, showRecommendations]);
|
|
10878
|
+
}, [api, sku, market, emit, showRecommendations, products]);
|
|
10879
|
+
return {
|
|
10880
|
+
product,
|
|
10881
|
+
inventory: inventory2,
|
|
10882
|
+
recommendations: current2?.recommendations ?? [],
|
|
10883
|
+
loading: !product && !error2,
|
|
10884
|
+
error: error2
|
|
10885
|
+
};
|
|
10886
|
+
}
|
|
10887
|
+
function ProductView({ sku, initialData, showRecommendations = true, onNotFound }) {
|
|
10888
|
+
const t = useT();
|
|
10889
|
+
const { product, inventory: inventory2, recommendations, loading, error: error2 } = useProduct(sku, {
|
|
10890
|
+
...initialData ? {
|
|
10891
|
+
initialData
|
|
10892
|
+
} : {},
|
|
10893
|
+
showRecommendations
|
|
10894
|
+
});
|
|
10812
10895
|
const unavailable = jsx(ShopSurface, {
|
|
10813
10896
|
tone: "light",
|
|
10814
10897
|
fill: true,
|
|
@@ -10823,14 +10906,14 @@ function ProductView({ sku, initialData, showRecommendations = true, onNotFound
|
|
|
10823
10906
|
});
|
|
10824
10907
|
return unavailable;
|
|
10825
10908
|
}
|
|
10826
|
-
if (
|
|
10909
|
+
if (product) {
|
|
10827
10910
|
return jsx(ProductDetail, {
|
|
10828
|
-
product
|
|
10829
|
-
inventory:
|
|
10830
|
-
recommendations
|
|
10831
|
-
});
|
|
10911
|
+
product,
|
|
10912
|
+
inventory: inventory2,
|
|
10913
|
+
recommendations
|
|
10914
|
+
}, product.sku);
|
|
10832
10915
|
}
|
|
10833
|
-
if (
|
|
10916
|
+
if (loading) return jsx(ScreenSkeleton, {
|
|
10834
10917
|
tone: "light"
|
|
10835
10918
|
});
|
|
10836
10919
|
return jsx(ShopSurface, {
|
|
@@ -10841,24 +10924,24 @@ function ProductView({ sku, initialData, showRecommendations = true, onNotFound
|
|
|
10841
10924
|
})
|
|
10842
10925
|
});
|
|
10843
10926
|
}
|
|
10844
|
-
const showcase = "
|
|
10845
|
-
const panel = "
|
|
10846
|
-
const image = "
|
|
10847
|
-
const hero = "
|
|
10848
|
-
const heroContent = "
|
|
10849
|
-
const heroText = "
|
|
10850
|
-
const logo = "
|
|
10851
|
-
const heroTitle = "
|
|
10852
|
-
const heroSub = "
|
|
10853
|
-
const swipe = "
|
|
10854
|
-
const swipeLabel = "
|
|
10855
|
-
const chevron$1 = "
|
|
10856
|
-
const overlay$1 = "
|
|
10857
|
-
const copy = "
|
|
10858
|
-
const title$2 = "
|
|
10859
|
-
const subtitle$1 = "
|
|
10860
|
-
const cta = "
|
|
10861
|
-
const mosaic = "
|
|
10927
|
+
const showcase = "_showcase_c2hqd_59";
|
|
10928
|
+
const panel = "_panel_c2hqd_63";
|
|
10929
|
+
const image = "_image_c2hqd_91";
|
|
10930
|
+
const hero = "_hero_c2hqd_131";
|
|
10931
|
+
const heroContent = "_heroContent_c2hqd_212";
|
|
10932
|
+
const heroText = "_heroText_c2hqd_236";
|
|
10933
|
+
const logo = "_logo_c2hqd_245";
|
|
10934
|
+
const heroTitle = "_heroTitle_c2hqd_265";
|
|
10935
|
+
const heroSub = "_heroSub_c2hqd_289";
|
|
10936
|
+
const swipe = "_swipe_c2hqd_308";
|
|
10937
|
+
const swipeLabel = "_swipeLabel_c2hqd_315";
|
|
10938
|
+
const chevron$1 = "_chevron_c2hqd_321";
|
|
10939
|
+
const overlay$1 = "_overlay_c2hqd_11";
|
|
10940
|
+
const copy = "_copy_c2hqd_356";
|
|
10941
|
+
const title$2 = "_title_c2hqd_361";
|
|
10942
|
+
const subtitle$1 = "_subtitle_c2hqd_368";
|
|
10943
|
+
const cta = "_cta_c2hqd_374";
|
|
10944
|
+
const mosaic = "_mosaic_c2hqd_418";
|
|
10862
10945
|
const styles$2 = {
|
|
10863
10946
|
showcase,
|
|
10864
10947
|
panel,
|
|
@@ -10879,7 +10962,6 @@ const styles$2 = {
|
|
|
10879
10962
|
cta,
|
|
10880
10963
|
mosaic
|
|
10881
10964
|
};
|
|
10882
|
-
const SETTLE_MS = 150;
|
|
10883
10965
|
function useDocumentSnap(ref, enabled = true) {
|
|
10884
10966
|
useEffect(() => {
|
|
10885
10967
|
const el = ref.current;
|
|
@@ -10887,23 +10969,9 @@ function useDocumentSnap(ref, enabled = true) {
|
|
|
10887
10969
|
const root2 = document.documentElement;
|
|
10888
10970
|
const previousType = root2.style.scrollSnapType;
|
|
10889
10971
|
const previousPadding = root2.style.scrollPaddingTop;
|
|
10890
|
-
let timer2;
|
|
10891
|
-
const syncPadding = () => {
|
|
10892
|
-
const top2 = getComputedStyle(el).getPropertyValue("--showcase-top").trim();
|
|
10893
|
-
root2.style.scrollPaddingTop = top2 === "" ? "0px" : top2;
|
|
10894
|
-
};
|
|
10895
|
-
const schedule = () => {
|
|
10896
|
-
if (timer2) clearTimeout(timer2);
|
|
10897
|
-
timer2 = setTimeout(syncPadding, SETTLE_MS);
|
|
10898
|
-
};
|
|
10899
10972
|
root2.style.scrollSnapType = "y mandatory";
|
|
10900
|
-
|
|
10901
|
-
window.addEventListener("resize", schedule);
|
|
10902
|
-
window.addEventListener("orientationchange", schedule);
|
|
10973
|
+
root2.style.scrollPaddingTop = "0px";
|
|
10903
10974
|
return () => {
|
|
10904
|
-
if (timer2) clearTimeout(timer2);
|
|
10905
|
-
window.removeEventListener("resize", schedule);
|
|
10906
|
-
window.removeEventListener("orientationchange", schedule);
|
|
10907
10975
|
root2.style.scrollSnapType = previousType;
|
|
10908
10976
|
root2.style.scrollPaddingTop = previousPadding;
|
|
10909
10977
|
};
|
|
@@ -11030,7 +11098,6 @@ function HomeShowcase() {
|
|
|
11030
11098
|
const assetUrl = useAssetUrl();
|
|
11031
11099
|
const panels = useSlides();
|
|
11032
11100
|
const showcaseRef = useRef(null);
|
|
11033
|
-
useTopOffset(showcaseRef, "--showcase-top");
|
|
11034
11101
|
useDocumentSnap(showcaseRef);
|
|
11035
11102
|
return jsx(ShopSurface, {
|
|
11036
11103
|
tone: "dark",
|
|
@@ -11634,6 +11701,7 @@ export {
|
|
|
11634
11701
|
useCartSheet,
|
|
11635
11702
|
useMoney,
|
|
11636
11703
|
useNavigate,
|
|
11704
|
+
useProduct,
|
|
11637
11705
|
useShopApi,
|
|
11638
11706
|
useShopEvent,
|
|
11639
11707
|
useShopOptional,
|
|
@@ -5112,6 +5112,49 @@ function resolveAssetUrl(src, base) {
|
|
|
5112
5112
|
if (!src.startsWith("/") || src.startsWith("//")) return src;
|
|
5113
5113
|
return `${base.replace(/\/+$/, "")}${src}`;
|
|
5114
5114
|
}
|
|
5115
|
+
const MAX_AGE_MS = 5 * 6e4;
|
|
5116
|
+
const CAPACITY = 60;
|
|
5117
|
+
class ProductCache {
|
|
5118
|
+
constructor(now = () => Date.now()) {
|
|
5119
|
+
this.now = now;
|
|
5120
|
+
}
|
|
5121
|
+
now;
|
|
5122
|
+
entries = /* @__PURE__ */ new Map();
|
|
5123
|
+
static keyFor(sku, market) {
|
|
5124
|
+
return `${market?.country ?? ""}\0${market?.lang ?? ""}\0${sku}`;
|
|
5125
|
+
}
|
|
5126
|
+
get(sku, market) {
|
|
5127
|
+
const key = ProductCache.keyFor(sku, market);
|
|
5128
|
+
const entry = this.entries.get(key);
|
|
5129
|
+
if (!entry) return void 0;
|
|
5130
|
+
if (this.now() - entry.at > MAX_AGE_MS) {
|
|
5131
|
+
this.entries.delete(key);
|
|
5132
|
+
return void 0;
|
|
5133
|
+
}
|
|
5134
|
+
this.entries.delete(key);
|
|
5135
|
+
this.entries.set(key, entry);
|
|
5136
|
+
return entry.product;
|
|
5137
|
+
}
|
|
5138
|
+
set(product, market) {
|
|
5139
|
+
const key = ProductCache.keyFor(product.sku, market);
|
|
5140
|
+
this.entries.delete(key);
|
|
5141
|
+
this.entries.set(key, {
|
|
5142
|
+
product,
|
|
5143
|
+
at: this.now()
|
|
5144
|
+
});
|
|
5145
|
+
while (this.entries.size > CAPACITY) {
|
|
5146
|
+
const oldest = this.entries.keys().next();
|
|
5147
|
+
if (oldest.done) break;
|
|
5148
|
+
this.entries.delete(oldest.value);
|
|
5149
|
+
}
|
|
5150
|
+
}
|
|
5151
|
+
setMany(products, market) {
|
|
5152
|
+
for (const product of products) this.set(product, market);
|
|
5153
|
+
}
|
|
5154
|
+
clear() {
|
|
5155
|
+
this.entries.clear();
|
|
5156
|
+
}
|
|
5157
|
+
}
|
|
5115
5158
|
function createShopFetch(opts) {
|
|
5116
5159
|
const baseFetch = opts.fetchImpl ?? globalThis.fetch;
|
|
5117
5160
|
if (!baseFetch) throw new Error("No fetch implementation available");
|
|
@@ -5226,6 +5269,9 @@ function DaznShopProvider({ children, ...config }) {
|
|
|
5226
5269
|
const getTokenRef = useRef(getToken);
|
|
5227
5270
|
getTokenRef.current = getToken;
|
|
5228
5271
|
const stableGetToken = useCallback(() => getTokenRef.current(), []);
|
|
5272
|
+
const productsRef = useRef(null);
|
|
5273
|
+
productsRef.current ??= new ProductCache();
|
|
5274
|
+
const products = productsRef.current;
|
|
5229
5275
|
const emit = useCallback((event) => {
|
|
5230
5276
|
for (const listener of listeners.current) {
|
|
5231
5277
|
try {
|
|
@@ -5266,6 +5312,7 @@ function DaznShopProvider({ children, ...config }) {
|
|
|
5266
5312
|
const value2 = useMemo(() => ({
|
|
5267
5313
|
api,
|
|
5268
5314
|
market,
|
|
5315
|
+
products,
|
|
5269
5316
|
theme,
|
|
5270
5317
|
notifications,
|
|
5271
5318
|
locale,
|
|
@@ -5273,7 +5320,7 @@ function DaznShopProvider({ children, ...config }) {
|
|
|
5273
5320
|
emit,
|
|
5274
5321
|
subscribe,
|
|
5275
5322
|
navigate
|
|
5276
|
-
}), [api, market, theme, notifications, locale, assetBaseUrl, emit, subscribe, navigate]);
|
|
5323
|
+
}), [api, market, products, theme, notifications, locale, assetBaseUrl, emit, subscribe, navigate]);
|
|
5277
5324
|
return jsx(ShopContext.Provider, {
|
|
5278
5325
|
value: value2,
|
|
5279
5326
|
children: jsx(ScreenTitleProvider, {
|
|
@@ -5482,7 +5529,7 @@ const styles$O = {
|
|
|
5482
5529
|
surface: surface$1,
|
|
5483
5530
|
fill
|
|
5484
5531
|
};
|
|
5485
|
-
const SETTLE_MS
|
|
5532
|
+
const SETTLE_MS = 150;
|
|
5486
5533
|
function scrolledOffOrigin(el) {
|
|
5487
5534
|
for (let node = el.parentElement; node; node = node.parentElement) {
|
|
5488
5535
|
if (node.scrollTop > 0) return true;
|
|
@@ -5506,11 +5553,11 @@ function useTopOffset(ref, property, enabled = true) {
|
|
|
5506
5553
|
};
|
|
5507
5554
|
const settle = () => {
|
|
5508
5555
|
if (timer2) clearTimeout(timer2);
|
|
5509
|
-
timer2 = setTimeout(measure, SETTLE_MS
|
|
5556
|
+
timer2 = setTimeout(measure, SETTLE_MS);
|
|
5510
5557
|
};
|
|
5511
5558
|
measure();
|
|
5512
5559
|
const frame2 = typeof requestAnimationFrame === "undefined" ? void 0 : requestAnimationFrame(measure);
|
|
5513
|
-
const settleAfterMount = setTimeout(measure, SETTLE_MS
|
|
5560
|
+
const settleAfterMount = setTimeout(measure, SETTLE_MS);
|
|
5514
5561
|
window.addEventListener("resize", measure);
|
|
5515
5562
|
window.addEventListener("orientationchange", measure);
|
|
5516
5563
|
document.addEventListener("scroll", settle, {
|
|
@@ -10710,32 +10757,51 @@ function CategoryContent({ page: page2 }) {
|
|
|
10710
10757
|
})]
|
|
10711
10758
|
});
|
|
10712
10759
|
}
|
|
10760
|
+
function productsIn(page2) {
|
|
10761
|
+
const found = [];
|
|
10762
|
+
for (const block of page2.blocks) {
|
|
10763
|
+
if (block.kind === "rail" || block.kind === "grid") found.push(...block.products);
|
|
10764
|
+
else if (block.kind === "featured" || block.kind === "product_gallery") found.push(block.product);
|
|
10765
|
+
}
|
|
10766
|
+
return found;
|
|
10767
|
+
}
|
|
10713
10768
|
function CategoryView({ code, initialData, onNotFound }) {
|
|
10714
10769
|
const t = useT();
|
|
10715
|
-
const { api, market, emit } = useShop();
|
|
10716
|
-
const [
|
|
10717
|
-
const [
|
|
10718
|
-
const
|
|
10770
|
+
const { api, market, emit, products } = useShop();
|
|
10771
|
+
const [loaded, setLoaded] = useState(null);
|
|
10772
|
+
const [failure, setFailure] = useState(null);
|
|
10773
|
+
const settled = loaded?.code === code;
|
|
10774
|
+
const seeded = initialData && initialData.code === code ? initialData : void 0;
|
|
10775
|
+
const page2 = (settled ? loaded?.page : void 0) ?? seeded ?? null;
|
|
10776
|
+
const error2 = failure?.code === code ? failure.error : void 0;
|
|
10777
|
+
const loading = !page2 && !error2 && !settled;
|
|
10719
10778
|
useEffect(() => {
|
|
10720
10779
|
let live = true;
|
|
10721
|
-
setError(void 0);
|
|
10722
10780
|
api.catalog.getCategoryPage(code, market).then((res) => {
|
|
10781
|
+
const fetched = res;
|
|
10782
|
+
products.setMany(productsIn(fetched), market);
|
|
10723
10783
|
if (!live) return;
|
|
10724
|
-
|
|
10784
|
+
setLoaded({
|
|
10785
|
+
code,
|
|
10786
|
+
page: fetched
|
|
10787
|
+
});
|
|
10725
10788
|
}).catch((err) => {
|
|
10726
10789
|
if (!live) return;
|
|
10727
10790
|
const c = codeOf(err);
|
|
10728
|
-
|
|
10791
|
+
setFailure({
|
|
10792
|
+
code,
|
|
10793
|
+
error: c
|
|
10794
|
+
});
|
|
10729
10795
|
emit({
|
|
10730
10796
|
type: "error",
|
|
10731
10797
|
code: c,
|
|
10732
10798
|
scope: "category"
|
|
10733
10799
|
});
|
|
10734
|
-
})
|
|
10800
|
+
});
|
|
10735
10801
|
return () => {
|
|
10736
10802
|
live = false;
|
|
10737
10803
|
};
|
|
10738
|
-
}, [api, code, market, emit]);
|
|
10804
|
+
}, [api, code, market, emit, products]);
|
|
10739
10805
|
if (error2 === "category_not_found" && onNotFound) return jsx(Fragment, {
|
|
10740
10806
|
children: onNotFound()
|
|
10741
10807
|
});
|
|
@@ -10756,23 +10822,22 @@ function CategoryView({ code, initialData, onNotFound }) {
|
|
|
10756
10822
|
})
|
|
10757
10823
|
});
|
|
10758
10824
|
}
|
|
10759
|
-
function
|
|
10760
|
-
const
|
|
10761
|
-
const { api, market, emit } = useShop();
|
|
10762
|
-
const [loaded, setLoaded] = useState(
|
|
10763
|
-
sku,
|
|
10764
|
-
product: initialData.product,
|
|
10765
|
-
inventory: initialData.inventory ?? null,
|
|
10766
|
-
recommendations: []
|
|
10767
|
-
} : null);
|
|
10825
|
+
function useProduct(sku, options2 = {}) {
|
|
10826
|
+
const { initialData, showRecommendations = true } = options2;
|
|
10827
|
+
const { api, market, emit, products } = useShop();
|
|
10828
|
+
const [loaded, setLoaded] = useState(null);
|
|
10768
10829
|
const [failure, setFailure] = useState(null);
|
|
10769
10830
|
const current2 = loaded?.sku === sku ? loaded : null;
|
|
10770
10831
|
const error2 = failure?.sku === sku ? failure.code : void 0;
|
|
10832
|
+
const seeded = initialData && initialData.product.sku === sku ? initialData.product : products.get(sku, market);
|
|
10833
|
+
const product = current2?.product ?? seeded ?? null;
|
|
10834
|
+
const inventory2 = current2 ? current2.inventory : initialData && initialData.product.sku === sku ? initialData.inventory ?? null : null;
|
|
10771
10835
|
useEffect(() => {
|
|
10772
10836
|
let live = true;
|
|
10773
10837
|
(async () => {
|
|
10774
10838
|
try {
|
|
10775
10839
|
const p = await api.catalog.getProduct(sku, market);
|
|
10840
|
+
products.set(p, market);
|
|
10776
10841
|
if (!live) return;
|
|
10777
10842
|
setLoaded({
|
|
10778
10843
|
sku,
|
|
@@ -10784,12 +10849,14 @@ function ProductView({ sku, initialData, showRecommendations = true, onNotFound
|
|
|
10784
10849
|
const [inv, recs] = await Promise.allSettled([hasVariants ? Promise.resolve(null) : api.inventory.get(sku), showRecommendations ? api.catalog.getRecommendations(sku, market) : Promise.resolve({
|
|
10785
10850
|
data: []
|
|
10786
10851
|
})]);
|
|
10852
|
+
const recommendations = recs.status === "fulfilled" ? recs.value.data : [];
|
|
10853
|
+
products.setMany(recommendations, market);
|
|
10787
10854
|
if (!live) return;
|
|
10788
10855
|
setLoaded({
|
|
10789
10856
|
sku,
|
|
10790
10857
|
product: p,
|
|
10791
10858
|
inventory: inv.status === "fulfilled" ? inv.value : null,
|
|
10792
|
-
recommendations
|
|
10859
|
+
recommendations
|
|
10793
10860
|
});
|
|
10794
10861
|
} catch (err) {
|
|
10795
10862
|
if (!live) return;
|
|
@@ -10808,7 +10875,23 @@ function ProductView({ sku, initialData, showRecommendations = true, onNotFound
|
|
|
10808
10875
|
return () => {
|
|
10809
10876
|
live = false;
|
|
10810
10877
|
};
|
|
10811
|
-
}, [api, sku, market, emit, showRecommendations]);
|
|
10878
|
+
}, [api, sku, market, emit, showRecommendations, products]);
|
|
10879
|
+
return {
|
|
10880
|
+
product,
|
|
10881
|
+
inventory: inventory2,
|
|
10882
|
+
recommendations: current2?.recommendations ?? [],
|
|
10883
|
+
loading: !product && !error2,
|
|
10884
|
+
error: error2
|
|
10885
|
+
};
|
|
10886
|
+
}
|
|
10887
|
+
function ProductView({ sku, initialData, showRecommendations = true, onNotFound }) {
|
|
10888
|
+
const t = useT();
|
|
10889
|
+
const { product, inventory: inventory2, recommendations, loading, error: error2 } = useProduct(sku, {
|
|
10890
|
+
...initialData ? {
|
|
10891
|
+
initialData
|
|
10892
|
+
} : {},
|
|
10893
|
+
showRecommendations
|
|
10894
|
+
});
|
|
10812
10895
|
const unavailable = jsx(ShopSurface, {
|
|
10813
10896
|
tone: "light",
|
|
10814
10897
|
fill: true,
|
|
@@ -10823,14 +10906,14 @@ function ProductView({ sku, initialData, showRecommendations = true, onNotFound
|
|
|
10823
10906
|
});
|
|
10824
10907
|
return unavailable;
|
|
10825
10908
|
}
|
|
10826
|
-
if (
|
|
10909
|
+
if (product) {
|
|
10827
10910
|
return jsx(ProductDetail, {
|
|
10828
|
-
product
|
|
10829
|
-
inventory:
|
|
10830
|
-
recommendations
|
|
10831
|
-
});
|
|
10911
|
+
product,
|
|
10912
|
+
inventory: inventory2,
|
|
10913
|
+
recommendations
|
|
10914
|
+
}, product.sku);
|
|
10832
10915
|
}
|
|
10833
|
-
if (
|
|
10916
|
+
if (loading) return jsx(ScreenSkeleton, {
|
|
10834
10917
|
tone: "light"
|
|
10835
10918
|
});
|
|
10836
10919
|
return jsx(ShopSurface, {
|
|
@@ -10841,24 +10924,24 @@ function ProductView({ sku, initialData, showRecommendations = true, onNotFound
|
|
|
10841
10924
|
})
|
|
10842
10925
|
});
|
|
10843
10926
|
}
|
|
10844
|
-
const showcase = "
|
|
10845
|
-
const panel = "
|
|
10846
|
-
const image = "
|
|
10847
|
-
const hero = "
|
|
10848
|
-
const heroContent = "
|
|
10849
|
-
const heroText = "
|
|
10850
|
-
const logo = "
|
|
10851
|
-
const heroTitle = "
|
|
10852
|
-
const heroSub = "
|
|
10853
|
-
const swipe = "
|
|
10854
|
-
const swipeLabel = "
|
|
10855
|
-
const chevron$1 = "
|
|
10856
|
-
const overlay$1 = "
|
|
10857
|
-
const copy = "
|
|
10858
|
-
const title$2 = "
|
|
10859
|
-
const subtitle$1 = "
|
|
10860
|
-
const cta = "
|
|
10861
|
-
const mosaic = "
|
|
10927
|
+
const showcase = "_showcase_c2hqd_59";
|
|
10928
|
+
const panel = "_panel_c2hqd_63";
|
|
10929
|
+
const image = "_image_c2hqd_91";
|
|
10930
|
+
const hero = "_hero_c2hqd_131";
|
|
10931
|
+
const heroContent = "_heroContent_c2hqd_212";
|
|
10932
|
+
const heroText = "_heroText_c2hqd_236";
|
|
10933
|
+
const logo = "_logo_c2hqd_245";
|
|
10934
|
+
const heroTitle = "_heroTitle_c2hqd_265";
|
|
10935
|
+
const heroSub = "_heroSub_c2hqd_289";
|
|
10936
|
+
const swipe = "_swipe_c2hqd_308";
|
|
10937
|
+
const swipeLabel = "_swipeLabel_c2hqd_315";
|
|
10938
|
+
const chevron$1 = "_chevron_c2hqd_321";
|
|
10939
|
+
const overlay$1 = "_overlay_c2hqd_11";
|
|
10940
|
+
const copy = "_copy_c2hqd_356";
|
|
10941
|
+
const title$2 = "_title_c2hqd_361";
|
|
10942
|
+
const subtitle$1 = "_subtitle_c2hqd_368";
|
|
10943
|
+
const cta = "_cta_c2hqd_374";
|
|
10944
|
+
const mosaic = "_mosaic_c2hqd_418";
|
|
10862
10945
|
const styles$2 = {
|
|
10863
10946
|
showcase,
|
|
10864
10947
|
panel,
|
|
@@ -10879,7 +10962,6 @@ const styles$2 = {
|
|
|
10879
10962
|
cta,
|
|
10880
10963
|
mosaic
|
|
10881
10964
|
};
|
|
10882
|
-
const SETTLE_MS = 150;
|
|
10883
10965
|
function useDocumentSnap(ref, enabled = true) {
|
|
10884
10966
|
useEffect(() => {
|
|
10885
10967
|
const el = ref.current;
|
|
@@ -10887,23 +10969,9 @@ function useDocumentSnap(ref, enabled = true) {
|
|
|
10887
10969
|
const root2 = document.documentElement;
|
|
10888
10970
|
const previousType = root2.style.scrollSnapType;
|
|
10889
10971
|
const previousPadding = root2.style.scrollPaddingTop;
|
|
10890
|
-
let timer2;
|
|
10891
|
-
const syncPadding = () => {
|
|
10892
|
-
const top2 = getComputedStyle(el).getPropertyValue("--showcase-top").trim();
|
|
10893
|
-
root2.style.scrollPaddingTop = top2 === "" ? "0px" : top2;
|
|
10894
|
-
};
|
|
10895
|
-
const schedule = () => {
|
|
10896
|
-
if (timer2) clearTimeout(timer2);
|
|
10897
|
-
timer2 = setTimeout(syncPadding, SETTLE_MS);
|
|
10898
|
-
};
|
|
10899
10972
|
root2.style.scrollSnapType = "y mandatory";
|
|
10900
|
-
|
|
10901
|
-
window.addEventListener("resize", schedule);
|
|
10902
|
-
window.addEventListener("orientationchange", schedule);
|
|
10973
|
+
root2.style.scrollPaddingTop = "0px";
|
|
10903
10974
|
return () => {
|
|
10904
|
-
if (timer2) clearTimeout(timer2);
|
|
10905
|
-
window.removeEventListener("resize", schedule);
|
|
10906
|
-
window.removeEventListener("orientationchange", schedule);
|
|
10907
10975
|
root2.style.scrollSnapType = previousType;
|
|
10908
10976
|
root2.style.scrollPaddingTop = previousPadding;
|
|
10909
10977
|
};
|
|
@@ -11030,7 +11098,6 @@ function HomeShowcase() {
|
|
|
11030
11098
|
const assetUrl = useAssetUrl();
|
|
11031
11099
|
const panels = useSlides();
|
|
11032
11100
|
const showcaseRef = useRef(null);
|
|
11033
|
-
useTopOffset(showcaseRef, "--showcase-top");
|
|
11034
11101
|
useDocumentSnap(showcaseRef);
|
|
11035
11102
|
return jsx(ShopSurface, {
|
|
11036
11103
|
tone: "dark",
|
|
@@ -11634,6 +11701,7 @@ export {
|
|
|
11634
11701
|
useCartSheet,
|
|
11635
11702
|
useMoney,
|
|
11636
11703
|
useNavigate,
|
|
11704
|
+
useProduct,
|
|
11637
11705
|
useShopApi,
|
|
11638
11706
|
useShopEvent,
|
|
11639
11707
|
useShopOptional,
|
|
@@ -3487,22 +3487,22 @@
|
|
|
3487
3487
|
column-gap: var(--space-12);
|
|
3488
3488
|
row-gap: var(--space-12);
|
|
3489
3489
|
}
|
|
3490
|
-
.
|
|
3490
|
+
._showcase_c2hqd_59 {
|
|
3491
3491
|
background: #080e12;
|
|
3492
3492
|
}
|
|
3493
|
-
.
|
|
3493
|
+
._panel_c2hqd_63 {
|
|
3494
3494
|
position: relative;
|
|
3495
|
-
height:
|
|
3495
|
+
height: 100lvh;
|
|
3496
3496
|
scroll-snap-align: start;
|
|
3497
3497
|
scroll-snap-stop: always;
|
|
3498
3498
|
overflow: hidden;
|
|
3499
3499
|
background: #080e12;
|
|
3500
3500
|
}
|
|
3501
|
-
.
|
|
3501
|
+
._image_c2hqd_91 {
|
|
3502
3502
|
object-fit: cover;
|
|
3503
3503
|
object-position: 50% var(--slide-focal-y, 50%);
|
|
3504
3504
|
}
|
|
3505
|
-
.
|
|
3505
|
+
._hero_c2hqd_131::after {
|
|
3506
3506
|
content: "";
|
|
3507
3507
|
position: absolute;
|
|
3508
3508
|
inset: 0;
|
|
@@ -3517,7 +3517,7 @@
|
|
|
3517
3517
|
rgba(8, 14, 18, 0) 520px);
|
|
3518
3518
|
pointer-events: none;
|
|
3519
3519
|
}
|
|
3520
|
-
.
|
|
3520
|
+
._hero_c2hqd_131 ._heroContent_c2hqd_212 {
|
|
3521
3521
|
position: absolute;
|
|
3522
3522
|
bottom: 32px;
|
|
3523
3523
|
bottom: calc(32px + 100lvh - 100dvh);
|
|
@@ -3529,7 +3529,7 @@
|
|
|
3529
3529
|
gap: 24px;
|
|
3530
3530
|
align-items: stretch;
|
|
3531
3531
|
}
|
|
3532
|
-
.
|
|
3532
|
+
._heroText_c2hqd_236 {
|
|
3533
3533
|
display: flex;
|
|
3534
3534
|
flex-direction: column;
|
|
3535
3535
|
gap: 8px;
|
|
@@ -3537,11 +3537,11 @@
|
|
|
3537
3537
|
padding: 0 24px;
|
|
3538
3538
|
text-align: center;
|
|
3539
3539
|
}
|
|
3540
|
-
.
|
|
3540
|
+
._heroText_c2hqd_236 ._logo_c2hqd_245 {
|
|
3541
3541
|
width: 48px;
|
|
3542
3542
|
height: 48px;
|
|
3543
3543
|
}
|
|
3544
|
-
.
|
|
3544
|
+
._heroTitle_c2hqd_265 {
|
|
3545
3545
|
width: 100%;
|
|
3546
3546
|
margin: 0;
|
|
3547
3547
|
font-family:
|
|
@@ -3556,33 +3556,33 @@
|
|
|
3556
3556
|
letter-spacing: -1.12px;
|
|
3557
3557
|
color: #f9fafa;
|
|
3558
3558
|
}
|
|
3559
|
-
.
|
|
3559
|
+
._heroSub_c2hqd_289 {
|
|
3560
3560
|
margin: 0;
|
|
3561
3561
|
font-size: 16px;
|
|
3562
3562
|
line-height: 1.55;
|
|
3563
3563
|
color: #f9fafa;
|
|
3564
3564
|
max-width: 327px;
|
|
3565
3565
|
}
|
|
3566
|
-
.
|
|
3566
|
+
._swipe_c2hqd_308 {
|
|
3567
3567
|
display: flex;
|
|
3568
3568
|
flex-direction: column;
|
|
3569
3569
|
align-items: center;
|
|
3570
3570
|
gap: 6px;
|
|
3571
3571
|
padding: 8px 0;
|
|
3572
3572
|
}
|
|
3573
|
-
.
|
|
3573
|
+
._swipeLabel_c2hqd_315 {
|
|
3574
3574
|
margin: 0;
|
|
3575
3575
|
font-size: 14px;
|
|
3576
3576
|
line-height: 1;
|
|
3577
3577
|
color: rgba(255, 255, 255, 0.54);
|
|
3578
3578
|
}
|
|
3579
|
-
.
|
|
3579
|
+
._chevron_c2hqd_321 {
|
|
3580
3580
|
width: 24px;
|
|
3581
3581
|
height: 24px;
|
|
3582
3582
|
color: rgba(255, 255, 255, 0.54);
|
|
3583
|
-
animation:
|
|
3583
|
+
animation: _bob_c2hqd_1 1.8s ease-in-out infinite;
|
|
3584
3584
|
}
|
|
3585
|
-
@keyframes
|
|
3585
|
+
@keyframes _bob_c2hqd_1 {
|
|
3586
3586
|
0%, 100% {
|
|
3587
3587
|
transform: translateY(0);
|
|
3588
3588
|
}
|
|
@@ -3590,7 +3590,7 @@
|
|
|
3590
3590
|
transform: translateY(4px);
|
|
3591
3591
|
}
|
|
3592
3592
|
}
|
|
3593
|
-
.
|
|
3593
|
+
._overlay_c2hqd_11 {
|
|
3594
3594
|
position: absolute;
|
|
3595
3595
|
inset: 0;
|
|
3596
3596
|
z-index: 1;
|
|
@@ -3607,25 +3607,25 @@
|
|
|
3607
3607
|
padding: 0 24px 24px;
|
|
3608
3608
|
padding-bottom: calc(24px + 100lvh - 100dvh);
|
|
3609
3609
|
}
|
|
3610
|
-
.
|
|
3610
|
+
._copy_c2hqd_356 {
|
|
3611
3611
|
display: flex;
|
|
3612
3612
|
flex-direction: column;
|
|
3613
3613
|
gap: 8px;
|
|
3614
3614
|
}
|
|
3615
|
-
.
|
|
3615
|
+
._title_c2hqd_361 {
|
|
3616
3616
|
margin: 0;
|
|
3617
3617
|
font-size: 32px;
|
|
3618
3618
|
line-height: 1.2;
|
|
3619
3619
|
font-weight: 700;
|
|
3620
3620
|
color: #f9fafa;
|
|
3621
3621
|
}
|
|
3622
|
-
.
|
|
3622
|
+
._subtitle_c2hqd_368 {
|
|
3623
3623
|
margin: 0;
|
|
3624
3624
|
font-size: 16px;
|
|
3625
3625
|
line-height: 1.55;
|
|
3626
3626
|
color: #f9fafa;
|
|
3627
3627
|
}
|
|
3628
|
-
.
|
|
3628
|
+
._cta_c2hqd_374 {
|
|
3629
3629
|
display: inline-flex;
|
|
3630
3630
|
align-items: center;
|
|
3631
3631
|
justify-content: center;
|
|
@@ -3639,19 +3639,19 @@
|
|
|
3639
3639
|
font-weight: 700;
|
|
3640
3640
|
text-decoration: none;
|
|
3641
3641
|
}
|
|
3642
|
-
.
|
|
3642
|
+
._cta_c2hqd_374::after {
|
|
3643
3643
|
content: "";
|
|
3644
3644
|
position: absolute;
|
|
3645
3645
|
inset: 0;
|
|
3646
3646
|
}
|
|
3647
|
-
.
|
|
3647
|
+
._cta_c2hqd_374:active {
|
|
3648
3648
|
background: rgba(249, 250, 250, 0.12);
|
|
3649
3649
|
}
|
|
3650
|
-
.
|
|
3650
|
+
._cta_c2hqd_374:focus-visible {
|
|
3651
3651
|
outline: none;
|
|
3652
3652
|
box-shadow: var(--focus-ring);
|
|
3653
3653
|
}
|
|
3654
|
-
.
|
|
3654
|
+
._mosaic_c2hqd_418 {
|
|
3655
3655
|
background: #080e12;
|
|
3656
3656
|
}
|
|
3657
3657
|
._header_8o3d7_25 {
|
package/dist/styles.css
CHANGED
|
@@ -3487,22 +3487,22 @@
|
|
|
3487
3487
|
column-gap: var(--space-12);
|
|
3488
3488
|
row-gap: var(--space-12);
|
|
3489
3489
|
}
|
|
3490
|
-
.
|
|
3490
|
+
._showcase_c2hqd_59 {
|
|
3491
3491
|
background: #080e12;
|
|
3492
3492
|
}
|
|
3493
|
-
.
|
|
3493
|
+
._panel_c2hqd_63 {
|
|
3494
3494
|
position: relative;
|
|
3495
|
-
height:
|
|
3495
|
+
height: 100lvh;
|
|
3496
3496
|
scroll-snap-align: start;
|
|
3497
3497
|
scroll-snap-stop: always;
|
|
3498
3498
|
overflow: hidden;
|
|
3499
3499
|
background: #080e12;
|
|
3500
3500
|
}
|
|
3501
|
-
.
|
|
3501
|
+
._image_c2hqd_91 {
|
|
3502
3502
|
object-fit: cover;
|
|
3503
3503
|
object-position: 50% var(--slide-focal-y, 50%);
|
|
3504
3504
|
}
|
|
3505
|
-
.
|
|
3505
|
+
._hero_c2hqd_131::after {
|
|
3506
3506
|
content: "";
|
|
3507
3507
|
position: absolute;
|
|
3508
3508
|
inset: 0;
|
|
@@ -3517,7 +3517,7 @@
|
|
|
3517
3517
|
rgba(8, 14, 18, 0) 520px);
|
|
3518
3518
|
pointer-events: none;
|
|
3519
3519
|
}
|
|
3520
|
-
.
|
|
3520
|
+
._hero_c2hqd_131 ._heroContent_c2hqd_212 {
|
|
3521
3521
|
position: absolute;
|
|
3522
3522
|
bottom: 32px;
|
|
3523
3523
|
bottom: calc(32px + 100lvh - 100dvh);
|
|
@@ -3529,7 +3529,7 @@
|
|
|
3529
3529
|
gap: 24px;
|
|
3530
3530
|
align-items: stretch;
|
|
3531
3531
|
}
|
|
3532
|
-
.
|
|
3532
|
+
._heroText_c2hqd_236 {
|
|
3533
3533
|
display: flex;
|
|
3534
3534
|
flex-direction: column;
|
|
3535
3535
|
gap: 8px;
|
|
@@ -3537,11 +3537,11 @@
|
|
|
3537
3537
|
padding: 0 24px;
|
|
3538
3538
|
text-align: center;
|
|
3539
3539
|
}
|
|
3540
|
-
.
|
|
3540
|
+
._heroText_c2hqd_236 ._logo_c2hqd_245 {
|
|
3541
3541
|
width: 48px;
|
|
3542
3542
|
height: 48px;
|
|
3543
3543
|
}
|
|
3544
|
-
.
|
|
3544
|
+
._heroTitle_c2hqd_265 {
|
|
3545
3545
|
width: 100%;
|
|
3546
3546
|
margin: 0;
|
|
3547
3547
|
font-family:
|
|
@@ -3556,33 +3556,33 @@
|
|
|
3556
3556
|
letter-spacing: -1.12px;
|
|
3557
3557
|
color: #f9fafa;
|
|
3558
3558
|
}
|
|
3559
|
-
.
|
|
3559
|
+
._heroSub_c2hqd_289 {
|
|
3560
3560
|
margin: 0;
|
|
3561
3561
|
font-size: 16px;
|
|
3562
3562
|
line-height: 1.55;
|
|
3563
3563
|
color: #f9fafa;
|
|
3564
3564
|
max-width: 327px;
|
|
3565
3565
|
}
|
|
3566
|
-
.
|
|
3566
|
+
._swipe_c2hqd_308 {
|
|
3567
3567
|
display: flex;
|
|
3568
3568
|
flex-direction: column;
|
|
3569
3569
|
align-items: center;
|
|
3570
3570
|
gap: 6px;
|
|
3571
3571
|
padding: 8px 0;
|
|
3572
3572
|
}
|
|
3573
|
-
.
|
|
3573
|
+
._swipeLabel_c2hqd_315 {
|
|
3574
3574
|
margin: 0;
|
|
3575
3575
|
font-size: 14px;
|
|
3576
3576
|
line-height: 1;
|
|
3577
3577
|
color: rgba(255, 255, 255, 0.54);
|
|
3578
3578
|
}
|
|
3579
|
-
.
|
|
3579
|
+
._chevron_c2hqd_321 {
|
|
3580
3580
|
width: 24px;
|
|
3581
3581
|
height: 24px;
|
|
3582
3582
|
color: rgba(255, 255, 255, 0.54);
|
|
3583
|
-
animation:
|
|
3583
|
+
animation: _bob_c2hqd_1 1.8s ease-in-out infinite;
|
|
3584
3584
|
}
|
|
3585
|
-
@keyframes
|
|
3585
|
+
@keyframes _bob_c2hqd_1 {
|
|
3586
3586
|
0%, 100% {
|
|
3587
3587
|
transform: translateY(0);
|
|
3588
3588
|
}
|
|
@@ -3590,7 +3590,7 @@
|
|
|
3590
3590
|
transform: translateY(4px);
|
|
3591
3591
|
}
|
|
3592
3592
|
}
|
|
3593
|
-
.
|
|
3593
|
+
._overlay_c2hqd_11 {
|
|
3594
3594
|
position: absolute;
|
|
3595
3595
|
inset: 0;
|
|
3596
3596
|
z-index: 1;
|
|
@@ -3607,25 +3607,25 @@
|
|
|
3607
3607
|
padding: 0 24px 24px;
|
|
3608
3608
|
padding-bottom: calc(24px + 100lvh - 100dvh);
|
|
3609
3609
|
}
|
|
3610
|
-
.
|
|
3610
|
+
._copy_c2hqd_356 {
|
|
3611
3611
|
display: flex;
|
|
3612
3612
|
flex-direction: column;
|
|
3613
3613
|
gap: 8px;
|
|
3614
3614
|
}
|
|
3615
|
-
.
|
|
3615
|
+
._title_c2hqd_361 {
|
|
3616
3616
|
margin: 0;
|
|
3617
3617
|
font-size: 32px;
|
|
3618
3618
|
line-height: 1.2;
|
|
3619
3619
|
font-weight: 700;
|
|
3620
3620
|
color: #f9fafa;
|
|
3621
3621
|
}
|
|
3622
|
-
.
|
|
3622
|
+
._subtitle_c2hqd_368 {
|
|
3623
3623
|
margin: 0;
|
|
3624
3624
|
font-size: 16px;
|
|
3625
3625
|
line-height: 1.55;
|
|
3626
3626
|
color: #f9fafa;
|
|
3627
3627
|
}
|
|
3628
|
-
.
|
|
3628
|
+
._cta_c2hqd_374 {
|
|
3629
3629
|
display: inline-flex;
|
|
3630
3630
|
align-items: center;
|
|
3631
3631
|
justify-content: center;
|
|
@@ -3639,19 +3639,19 @@
|
|
|
3639
3639
|
font-weight: 700;
|
|
3640
3640
|
text-decoration: none;
|
|
3641
3641
|
}
|
|
3642
|
-
.
|
|
3642
|
+
._cta_c2hqd_374::after {
|
|
3643
3643
|
content: "";
|
|
3644
3644
|
position: absolute;
|
|
3645
3645
|
inset: 0;
|
|
3646
3646
|
}
|
|
3647
|
-
.
|
|
3647
|
+
._cta_c2hqd_374:active {
|
|
3648
3648
|
background: rgba(249, 250, 250, 0.12);
|
|
3649
3649
|
}
|
|
3650
|
-
.
|
|
3650
|
+
._cta_c2hqd_374:focus-visible {
|
|
3651
3651
|
outline: none;
|
|
3652
3652
|
box-shadow: var(--focus-ring);
|
|
3653
3653
|
}
|
|
3654
|
-
.
|
|
3654
|
+
._mosaic_c2hqd_418 {
|
|
3655
3655
|
background: #080e12;
|
|
3656
3656
|
}
|
|
3657
3657
|
._header_8o3d7_25 {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nok-integration/storefront-react",
|
|
3
|
-
"version": "0.19.
|
|
3
|
+
"version": "0.19.41",
|
|
4
4
|
"description": "Mountable React storefront components: catalogue, product detail and cart, mounted directly into a host DOM tree. No iframe.",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"publishConfig": {
|