@nok-integration/storefront-react 0.19.44 → 0.19.46
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 +17 -7
- package/dist/index.mjs +23 -5
- package/dist/standalone/storefront.mjs +23 -5
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -5971,18 +5971,28 @@ export declare type ShopTone = 'dark' | 'light';
|
|
|
5971
5971
|
/**
|
|
5972
5972
|
* Full-bleed background video: muted, looping, inline, and never showing a control.
|
|
5973
5973
|
*
|
|
5974
|
-
* The
|
|
5975
|
-
*
|
|
5974
|
+
* The attributes below are not stylistic. `muted` and `playsInline` together are the only
|
|
5975
|
+
* combination iOS will start without a gesture — a video that is unmuted, or that is
|
|
5976
5976
|
* allowed to go fullscreen, simply does not play, and the panel shows its poster forever.
|
|
5977
5977
|
* `loop` is the brief. `controls` is absent because this is artwork behind copy, not a
|
|
5978
5978
|
* player: a tap belongs to the CTA stretched over the panel, and a play button in the
|
|
5979
5979
|
* middle of a category slide would sit directly on that hit area.
|
|
5980
5980
|
*
|
|
5981
|
-
* **
|
|
5982
|
-
*
|
|
5983
|
-
*
|
|
5984
|
-
*
|
|
5985
|
-
*
|
|
5981
|
+
* **There is no `autoplay` attribute, and its absence is what makes `preload` mean
|
|
5982
|
+
* anything.** A `<video autoplay preload="none">` is a contradiction the browser resolves
|
|
5983
|
+
* in favour of autoplay: WebKit ignores the `preload` hint and begins fetching at once,
|
|
5984
|
+
* because it has been told the clip is going to play regardless. On the shop entry that is
|
|
5985
|
+
* five full-screen clips, several megabytes, all pulling against each other on a phone from
|
|
5986
|
+
* the moment the screen opens — which is slowest for the one panel a fan is actually
|
|
5987
|
+
* looking at. Playback is driven from the observer below instead, so the clips still start
|
|
5988
|
+
* by themselves and still loop, and `preload` is honoured.
|
|
5989
|
+
*
|
|
5990
|
+
* **Playback follows visibility; fetching runs one screen ahead of it.** Each clip plays
|
|
5991
|
+
* when its panel comes into view and pauses when it leaves, which keeps one video decoding
|
|
5992
|
+
* at a time. Downloading cannot wait that long: a clip that only starts arriving once its
|
|
5993
|
+
* panel is on screen shows its poster for as long as the file takes. So `preload` flips to
|
|
5994
|
+
* `auto` a screen out — the panel being approached is buffered before it is reached, and a
|
|
5995
|
+
* fan who never scrolls past the hero pays for the hero and its neighbour, not for all five.
|
|
5986
5996
|
*
|
|
5987
5997
|
* **Reduced motion is honoured by not playing at all.** Autoplaying background video is
|
|
5988
5998
|
* exactly what the preference is about, and there is a good still to fall back to — the
|
package/dist/index.mjs
CHANGED
|
@@ -5431,6 +5431,7 @@ function ShopImage({ src, alt, fill: fill2 = false, width, height, sizes, classN
|
|
|
5431
5431
|
fetchPriority: priority ? "high" : void 0
|
|
5432
5432
|
});
|
|
5433
5433
|
}
|
|
5434
|
+
const WARM_MARGIN = "100%";
|
|
5434
5435
|
function ShopVideo({ src, poster, fill: fill2 = false, className, style, priority = false }) {
|
|
5435
5436
|
const assetUrl = useAssetUrl();
|
|
5436
5437
|
const ref = useRef(null);
|
|
@@ -5438,6 +5439,9 @@ function ShopVideo({ src, poster, fill: fill2 = false, className, style, priorit
|
|
|
5438
5439
|
const el = ref.current;
|
|
5439
5440
|
if (!el || typeof IntersectionObserver === "undefined") return;
|
|
5440
5441
|
const reduced = window.matchMedia?.("(prefers-reduced-motion: reduce)");
|
|
5442
|
+
const fetchNow = () => {
|
|
5443
|
+
if (el.preload === "none") el.preload = "auto";
|
|
5444
|
+
};
|
|
5441
5445
|
const play = () => {
|
|
5442
5446
|
if (reduced?.matches) {
|
|
5443
5447
|
el.pause();
|
|
@@ -5446,10 +5450,18 @@ function ShopVideo({ src, poster, fill: fill2 = false, className, style, priorit
|
|
|
5446
5450
|
void el.play().catch(() => {
|
|
5447
5451
|
});
|
|
5448
5452
|
};
|
|
5449
|
-
const
|
|
5453
|
+
const warm = new IntersectionObserver((entries) => {
|
|
5454
|
+
if (!entries.some((entry) => entry.isIntersecting)) return;
|
|
5455
|
+
if (!reduced?.matches) fetchNow();
|
|
5456
|
+
warm.disconnect();
|
|
5457
|
+
}, {
|
|
5458
|
+
rootMargin: WARM_MARGIN
|
|
5459
|
+
});
|
|
5460
|
+
warm.observe(el);
|
|
5461
|
+
const playback = new IntersectionObserver((entries) => {
|
|
5450
5462
|
for (const entry of entries) {
|
|
5451
5463
|
if (entry.isIntersecting) {
|
|
5452
|
-
|
|
5464
|
+
fetchNow();
|
|
5453
5465
|
play();
|
|
5454
5466
|
} else {
|
|
5455
5467
|
el.pause();
|
|
@@ -5458,10 +5470,11 @@ function ShopVideo({ src, poster, fill: fill2 = false, className, style, priorit
|
|
|
5458
5470
|
}, {
|
|
5459
5471
|
threshold: 0.25
|
|
5460
5472
|
});
|
|
5461
|
-
|
|
5473
|
+
playback.observe(el);
|
|
5462
5474
|
reduced?.addEventListener("change", play);
|
|
5463
5475
|
return () => {
|
|
5464
|
-
|
|
5476
|
+
warm.disconnect();
|
|
5477
|
+
playback.disconnect();
|
|
5465
5478
|
reduced?.removeEventListener("change", play);
|
|
5466
5479
|
};
|
|
5467
5480
|
}, []);
|
|
@@ -5480,7 +5493,6 @@ function ShopVideo({ src, poster, fill: fill2 = false, className, style, priorit
|
|
|
5480
5493
|
...fillStyle,
|
|
5481
5494
|
...style
|
|
5482
5495
|
},
|
|
5483
|
-
autoPlay: true,
|
|
5484
5496
|
loop: true,
|
|
5485
5497
|
muted: true,
|
|
5486
5498
|
playsInline: true,
|
|
@@ -11004,7 +11016,13 @@ function useDocumentSnap(ref, enabled = true) {
|
|
|
11004
11016
|
const previousPadding = root2.style.scrollPaddingTop;
|
|
11005
11017
|
root2.style.scrollSnapType = "y mandatory";
|
|
11006
11018
|
root2.style.scrollPaddingTop = "0px";
|
|
11019
|
+
const top2 = () => window.scrollTo(0, 0);
|
|
11020
|
+
top2();
|
|
11021
|
+
const frame2 = typeof window.requestAnimationFrame === "function" ? window.requestAnimationFrame(top2) : null;
|
|
11007
11022
|
return () => {
|
|
11023
|
+
if (frame2 !== null && typeof window.cancelAnimationFrame === "function") {
|
|
11024
|
+
window.cancelAnimationFrame(frame2);
|
|
11025
|
+
}
|
|
11008
11026
|
root2.style.scrollSnapType = previousType;
|
|
11009
11027
|
root2.style.scrollPaddingTop = previousPadding;
|
|
11010
11028
|
};
|
|
@@ -5431,6 +5431,7 @@ function ShopImage({ src, alt, fill: fill2 = false, width, height, sizes, classN
|
|
|
5431
5431
|
fetchPriority: priority ? "high" : void 0
|
|
5432
5432
|
});
|
|
5433
5433
|
}
|
|
5434
|
+
const WARM_MARGIN = "100%";
|
|
5434
5435
|
function ShopVideo({ src, poster, fill: fill2 = false, className, style, priority = false }) {
|
|
5435
5436
|
const assetUrl = useAssetUrl();
|
|
5436
5437
|
const ref = useRef(null);
|
|
@@ -5438,6 +5439,9 @@ function ShopVideo({ src, poster, fill: fill2 = false, className, style, priorit
|
|
|
5438
5439
|
const el = ref.current;
|
|
5439
5440
|
if (!el || typeof IntersectionObserver === "undefined") return;
|
|
5440
5441
|
const reduced = window.matchMedia?.("(prefers-reduced-motion: reduce)");
|
|
5442
|
+
const fetchNow = () => {
|
|
5443
|
+
if (el.preload === "none") el.preload = "auto";
|
|
5444
|
+
};
|
|
5441
5445
|
const play = () => {
|
|
5442
5446
|
if (reduced?.matches) {
|
|
5443
5447
|
el.pause();
|
|
@@ -5446,10 +5450,18 @@ function ShopVideo({ src, poster, fill: fill2 = false, className, style, priorit
|
|
|
5446
5450
|
void el.play().catch(() => {
|
|
5447
5451
|
});
|
|
5448
5452
|
};
|
|
5449
|
-
const
|
|
5453
|
+
const warm = new IntersectionObserver((entries) => {
|
|
5454
|
+
if (!entries.some((entry) => entry.isIntersecting)) return;
|
|
5455
|
+
if (!reduced?.matches) fetchNow();
|
|
5456
|
+
warm.disconnect();
|
|
5457
|
+
}, {
|
|
5458
|
+
rootMargin: WARM_MARGIN
|
|
5459
|
+
});
|
|
5460
|
+
warm.observe(el);
|
|
5461
|
+
const playback = new IntersectionObserver((entries) => {
|
|
5450
5462
|
for (const entry of entries) {
|
|
5451
5463
|
if (entry.isIntersecting) {
|
|
5452
|
-
|
|
5464
|
+
fetchNow();
|
|
5453
5465
|
play();
|
|
5454
5466
|
} else {
|
|
5455
5467
|
el.pause();
|
|
@@ -5458,10 +5470,11 @@ function ShopVideo({ src, poster, fill: fill2 = false, className, style, priorit
|
|
|
5458
5470
|
}, {
|
|
5459
5471
|
threshold: 0.25
|
|
5460
5472
|
});
|
|
5461
|
-
|
|
5473
|
+
playback.observe(el);
|
|
5462
5474
|
reduced?.addEventListener("change", play);
|
|
5463
5475
|
return () => {
|
|
5464
|
-
|
|
5476
|
+
warm.disconnect();
|
|
5477
|
+
playback.disconnect();
|
|
5465
5478
|
reduced?.removeEventListener("change", play);
|
|
5466
5479
|
};
|
|
5467
5480
|
}, []);
|
|
@@ -5480,7 +5493,6 @@ function ShopVideo({ src, poster, fill: fill2 = false, className, style, priorit
|
|
|
5480
5493
|
...fillStyle,
|
|
5481
5494
|
...style
|
|
5482
5495
|
},
|
|
5483
|
-
autoPlay: true,
|
|
5484
5496
|
loop: true,
|
|
5485
5497
|
muted: true,
|
|
5486
5498
|
playsInline: true,
|
|
@@ -11004,7 +11016,13 @@ function useDocumentSnap(ref, enabled = true) {
|
|
|
11004
11016
|
const previousPadding = root2.style.scrollPaddingTop;
|
|
11005
11017
|
root2.style.scrollSnapType = "y mandatory";
|
|
11006
11018
|
root2.style.scrollPaddingTop = "0px";
|
|
11019
|
+
const top2 = () => window.scrollTo(0, 0);
|
|
11020
|
+
top2();
|
|
11021
|
+
const frame2 = typeof window.requestAnimationFrame === "function" ? window.requestAnimationFrame(top2) : null;
|
|
11007
11022
|
return () => {
|
|
11023
|
+
if (frame2 !== null && typeof window.cancelAnimationFrame === "function") {
|
|
11024
|
+
window.cancelAnimationFrame(frame2);
|
|
11025
|
+
}
|
|
11008
11026
|
root2.style.scrollSnapType = previousType;
|
|
11009
11027
|
root2.style.scrollPaddingTop = previousPadding;
|
|
11010
11028
|
};
|
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.46",
|
|
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
|
"type": "module",
|