@deriv-web-design/ui 0.1.17 → 0.1.19
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/components.manifest.json +16 -1
- package/dist/index.d.mts +47 -2
- package/dist/index.d.ts +47 -2
- package/dist/index.js +149 -29
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +179 -63
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/components.manifest.json
CHANGED
|
@@ -891,7 +891,7 @@
|
|
|
891
891
|
"name": "DotLottieInView",
|
|
892
892
|
"source": "components/DotLottieInView/DotLottieInView.tsx",
|
|
893
893
|
"props": {},
|
|
894
|
-
"description": "Plays a .lottie once when it scrolls into view. Stops and resets when it leaves view. When it enters view again, it plays once more. Set `enabled={false}` to force stop (e.g. hidden slides) without relying on geometry alone."
|
|
894
|
+
"description": "Plays a .lottie once when it scrolls into view. Stops and resets when it leaves view. When it enters view again, it plays once more. Set `enabled={false}` to force stop (e.g. hidden slides) without relying on geometry alone. The player itself is fetched lazily, the first time this instance is in view — so a page with no animation never downloads it, and a below-the-fold band does not pay for it during initial load. `enabled` gates playback only: a consumer that crossfades between stacked instances needs them all loaded, not just the one currently showing."
|
|
895
895
|
},
|
|
896
896
|
"DownloadBadge": {
|
|
897
897
|
"name": "DownloadBadge",
|
|
@@ -1836,6 +1836,11 @@
|
|
|
1836
1836
|
"required": true,
|
|
1837
1837
|
"description": "URL to the .lottie file or any image asset (png, jpg, svg, webp…)"
|
|
1838
1838
|
},
|
|
1839
|
+
"posterUrl": {
|
|
1840
|
+
"type": "string",
|
|
1841
|
+
"required": false,
|
|
1842
|
+
"description": "Still frame painted while an animation's player and engine are loading. Only used when the item resolves to `\"lottie\"`. The WebAssembly engine is ~630 KB compressed and one engine serves every animation on the page, so on a cold visit over a slow connection the first animated band can sit empty for seconds. A poster turns that into a progressive load instead of a hole in the layout. Ignored once the animation is playing."
|
|
1843
|
+
},
|
|
1839
1844
|
"title": {
|
|
1840
1845
|
"type": "string",
|
|
1841
1846
|
"required": true,
|
|
@@ -1843,6 +1848,16 @@
|
|
|
1843
1848
|
}
|
|
1844
1849
|
}
|
|
1845
1850
|
},
|
|
1851
|
+
"mediaRootMargin": {
|
|
1852
|
+
"type": "string",
|
|
1853
|
+
"required": false,
|
|
1854
|
+
"description": "`rootMargin` for the observer that decides when an animation's player may load and play. Forwarded to `DotLottieInView`. The default starts the work only once a band is actually on screen, which is the safe choice: the engine is large, and fetching it earlier competes with whatever the visitor is currently looking at — including the LCP image. Widen it (e.g. `\"600px 0px\"`) on pages where the animated band sits well below the fold and you would rather it were ready on arrival."
|
|
1855
|
+
},
|
|
1856
|
+
"mediaThreshold": {
|
|
1857
|
+
"type": "number | number[]",
|
|
1858
|
+
"required": false,
|
|
1859
|
+
"description": "`threshold` for that same observer. Forwarded to `DotLottieInView`."
|
|
1860
|
+
},
|
|
1846
1861
|
"variant": {
|
|
1847
1862
|
"type": "\"media-left\" | \"media-right\"",
|
|
1848
1863
|
"required": false,
|
package/dist/index.d.mts
CHANGED
|
@@ -750,6 +750,16 @@ interface FeatureScrollItem {
|
|
|
750
750
|
mediaType?: "lottie" | "image";
|
|
751
751
|
/** URL to the .lottie file or any image asset (png, jpg, svg, webp…) */
|
|
752
752
|
mediaUrl: string;
|
|
753
|
+
/**
|
|
754
|
+
* Still frame painted while an animation's player and engine are loading.
|
|
755
|
+
*
|
|
756
|
+
* Only used when the item resolves to `"lottie"`. The WebAssembly engine is
|
|
757
|
+
* ~630 KB compressed and one engine serves every animation on the page, so
|
|
758
|
+
* on a cold visit over a slow connection the first animated band can sit
|
|
759
|
+
* empty for seconds. A poster turns that into a progressive load instead of
|
|
760
|
+
* a hole in the layout. Ignored once the animation is playing.
|
|
761
|
+
*/
|
|
762
|
+
posterUrl?: string;
|
|
753
763
|
}
|
|
754
764
|
interface FeatureScrollProps extends HTMLAttributes<HTMLElement> {
|
|
755
765
|
/** Section heading rendered as an H2 */
|
|
@@ -764,10 +774,27 @@ interface FeatureScrollProps extends HTMLAttributes<HTMLElement> {
|
|
|
764
774
|
* @default "media-right"
|
|
765
775
|
*/
|
|
766
776
|
variant?: "media-left" | "media-right";
|
|
777
|
+
/**
|
|
778
|
+
* `rootMargin` for the observer that decides when an animation's player may
|
|
779
|
+
* load and play. Forwarded to `DotLottieInView`.
|
|
780
|
+
*
|
|
781
|
+
* The default starts the work only once a band is actually on screen, which
|
|
782
|
+
* is the safe choice: the engine is large, and fetching it earlier competes
|
|
783
|
+
* with whatever the visitor is currently looking at — including the LCP
|
|
784
|
+
* image. Widen it (e.g. `"600px 0px"`) on pages where the animated band sits
|
|
785
|
+
* well below the fold and you would rather it were ready on arrival.
|
|
786
|
+
* @default "0px"
|
|
787
|
+
*/
|
|
788
|
+
mediaRootMargin?: string;
|
|
789
|
+
/**
|
|
790
|
+
* `threshold` for that same observer. Forwarded to `DotLottieInView`.
|
|
791
|
+
* @default 0.2
|
|
792
|
+
*/
|
|
793
|
+
mediaThreshold?: number | number[];
|
|
767
794
|
}
|
|
768
795
|
|
|
769
796
|
declare const FEATURE_SCROLL_DATA: FeatureScrollItem[];
|
|
770
|
-
declare const FeatureScroll: ({ header, items, variant, className, ...props }: FeatureScrollProps) => react_jsx_runtime.JSX.Element;
|
|
797
|
+
declare const FeatureScroll: ({ header, items, variant, className, mediaRootMargin, mediaThreshold, ...props }: FeatureScrollProps) => react_jsx_runtime.JSX.Element;
|
|
771
798
|
|
|
772
799
|
type FeatureSplitImagePosition = "left" | "right";
|
|
773
800
|
interface FeatureSplitProps {
|
|
@@ -799,13 +826,31 @@ type DotLottieInViewProps = Omit<ComponentProps<typeof DotLottieReact>, "autopla
|
|
|
799
826
|
enabled?: boolean;
|
|
800
827
|
rootMargin?: string;
|
|
801
828
|
threshold?: number | number[];
|
|
829
|
+
/**
|
|
830
|
+
* Painted in place of the player until the animation is ready, and as the
|
|
831
|
+
* Suspense fallback while the player chunk loads.
|
|
832
|
+
*
|
|
833
|
+
* Worth supplying on anything a visitor meets early on a slow connection:
|
|
834
|
+
* the WebAssembly engine is ~630 KB compressed and one engine serves every
|
|
835
|
+
* animation on the page, so the first animated band on a cold visit can sit
|
|
836
|
+
* empty for seconds. A still frame makes that a progressive load rather than
|
|
837
|
+
* a hole in the layout. A `ReactNode` rather than a URL so the consumer can
|
|
838
|
+
* pass a properly sized, responsive `<img>` rather than a bare `src`.
|
|
839
|
+
*/
|
|
840
|
+
poster?: ReactNode;
|
|
802
841
|
};
|
|
803
842
|
/**
|
|
804
843
|
* Plays a .lottie once when it scrolls into view. Stops and resets when it leaves view.
|
|
805
844
|
* When it enters view again, it plays once more. Set `enabled={false}` to force stop
|
|
806
845
|
* (e.g. hidden slides) without relying on geometry alone.
|
|
846
|
+
*
|
|
847
|
+
* The player itself is fetched lazily, the first time this instance is in view —
|
|
848
|
+
* so a page with no animation never downloads it, and a below-the-fold band does
|
|
849
|
+
* not pay for it during initial load. `enabled` gates playback only: a consumer
|
|
850
|
+
* that crossfades between stacked instances needs them all loaded, not just the
|
|
851
|
+
* one currently showing.
|
|
807
852
|
*/
|
|
808
|
-
declare function DotLottieInView({ enabled, rootMargin, threshold, className, style, ...dotProps }: DotLottieInViewProps): react_jsx_runtime.JSX.Element;
|
|
853
|
+
declare function DotLottieInView({ enabled, rootMargin, threshold, className, style, poster, ...dotProps }: DotLottieInViewProps): react_jsx_runtime.JSX.Element;
|
|
809
854
|
|
|
810
855
|
/** Visual colour theme for each card — matches the Figma palette. */
|
|
811
856
|
type StickyCardTheme = "light" | "coral" | "dark";
|
package/dist/index.d.ts
CHANGED
|
@@ -750,6 +750,16 @@ interface FeatureScrollItem {
|
|
|
750
750
|
mediaType?: "lottie" | "image";
|
|
751
751
|
/** URL to the .lottie file or any image asset (png, jpg, svg, webp…) */
|
|
752
752
|
mediaUrl: string;
|
|
753
|
+
/**
|
|
754
|
+
* Still frame painted while an animation's player and engine are loading.
|
|
755
|
+
*
|
|
756
|
+
* Only used when the item resolves to `"lottie"`. The WebAssembly engine is
|
|
757
|
+
* ~630 KB compressed and one engine serves every animation on the page, so
|
|
758
|
+
* on a cold visit over a slow connection the first animated band can sit
|
|
759
|
+
* empty for seconds. A poster turns that into a progressive load instead of
|
|
760
|
+
* a hole in the layout. Ignored once the animation is playing.
|
|
761
|
+
*/
|
|
762
|
+
posterUrl?: string;
|
|
753
763
|
}
|
|
754
764
|
interface FeatureScrollProps extends HTMLAttributes<HTMLElement> {
|
|
755
765
|
/** Section heading rendered as an H2 */
|
|
@@ -764,10 +774,27 @@ interface FeatureScrollProps extends HTMLAttributes<HTMLElement> {
|
|
|
764
774
|
* @default "media-right"
|
|
765
775
|
*/
|
|
766
776
|
variant?: "media-left" | "media-right";
|
|
777
|
+
/**
|
|
778
|
+
* `rootMargin` for the observer that decides when an animation's player may
|
|
779
|
+
* load and play. Forwarded to `DotLottieInView`.
|
|
780
|
+
*
|
|
781
|
+
* The default starts the work only once a band is actually on screen, which
|
|
782
|
+
* is the safe choice: the engine is large, and fetching it earlier competes
|
|
783
|
+
* with whatever the visitor is currently looking at — including the LCP
|
|
784
|
+
* image. Widen it (e.g. `"600px 0px"`) on pages where the animated band sits
|
|
785
|
+
* well below the fold and you would rather it were ready on arrival.
|
|
786
|
+
* @default "0px"
|
|
787
|
+
*/
|
|
788
|
+
mediaRootMargin?: string;
|
|
789
|
+
/**
|
|
790
|
+
* `threshold` for that same observer. Forwarded to `DotLottieInView`.
|
|
791
|
+
* @default 0.2
|
|
792
|
+
*/
|
|
793
|
+
mediaThreshold?: number | number[];
|
|
767
794
|
}
|
|
768
795
|
|
|
769
796
|
declare const FEATURE_SCROLL_DATA: FeatureScrollItem[];
|
|
770
|
-
declare const FeatureScroll: ({ header, items, variant, className, ...props }: FeatureScrollProps) => react_jsx_runtime.JSX.Element;
|
|
797
|
+
declare const FeatureScroll: ({ header, items, variant, className, mediaRootMargin, mediaThreshold, ...props }: FeatureScrollProps) => react_jsx_runtime.JSX.Element;
|
|
771
798
|
|
|
772
799
|
type FeatureSplitImagePosition = "left" | "right";
|
|
773
800
|
interface FeatureSplitProps {
|
|
@@ -799,13 +826,31 @@ type DotLottieInViewProps = Omit<ComponentProps<typeof DotLottieReact>, "autopla
|
|
|
799
826
|
enabled?: boolean;
|
|
800
827
|
rootMargin?: string;
|
|
801
828
|
threshold?: number | number[];
|
|
829
|
+
/**
|
|
830
|
+
* Painted in place of the player until the animation is ready, and as the
|
|
831
|
+
* Suspense fallback while the player chunk loads.
|
|
832
|
+
*
|
|
833
|
+
* Worth supplying on anything a visitor meets early on a slow connection:
|
|
834
|
+
* the WebAssembly engine is ~630 KB compressed and one engine serves every
|
|
835
|
+
* animation on the page, so the first animated band on a cold visit can sit
|
|
836
|
+
* empty for seconds. A still frame makes that a progressive load rather than
|
|
837
|
+
* a hole in the layout. A `ReactNode` rather than a URL so the consumer can
|
|
838
|
+
* pass a properly sized, responsive `<img>` rather than a bare `src`.
|
|
839
|
+
*/
|
|
840
|
+
poster?: ReactNode;
|
|
802
841
|
};
|
|
803
842
|
/**
|
|
804
843
|
* Plays a .lottie once when it scrolls into view. Stops and resets when it leaves view.
|
|
805
844
|
* When it enters view again, it plays once more. Set `enabled={false}` to force stop
|
|
806
845
|
* (e.g. hidden slides) without relying on geometry alone.
|
|
846
|
+
*
|
|
847
|
+
* The player itself is fetched lazily, the first time this instance is in view —
|
|
848
|
+
* so a page with no animation never downloads it, and a below-the-fold band does
|
|
849
|
+
* not pay for it during initial load. `enabled` gates playback only: a consumer
|
|
850
|
+
* that crossfades between stacked instances needs them all loaded, not just the
|
|
851
|
+
* one currently showing.
|
|
807
852
|
*/
|
|
808
|
-
declare function DotLottieInView({ enabled, rootMargin, threshold, className, style, ...dotProps }: DotLottieInViewProps): react_jsx_runtime.JSX.Element;
|
|
853
|
+
declare function DotLottieInView({ enabled, rootMargin, threshold, className, style, poster, ...dotProps }: DotLottieInViewProps): react_jsx_runtime.JSX.Element;
|
|
809
854
|
|
|
810
855
|
/** Visual colour theme for each card — matches the Figma palette. */
|
|
811
856
|
type StickyCardTheme = "light" | "coral" | "dark";
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
2
3
|
var __defProp = Object.defineProperty;
|
|
3
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
5
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
8
|
var __export = (target, all) => {
|
|
7
9
|
for (var name in all)
|
|
@@ -15,6 +17,14 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
15
17
|
}
|
|
16
18
|
return to;
|
|
17
19
|
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
18
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
29
|
|
|
20
30
|
// index.ts
|
|
@@ -2635,18 +2645,22 @@ var import_react13 = require("react");
|
|
|
2635
2645
|
|
|
2636
2646
|
// components/DotLottieInView/DotLottieInView.tsx
|
|
2637
2647
|
var import_react12 = require("react");
|
|
2638
|
-
var import_dotlottie_react = require("@lottiefiles/dotlottie-react");
|
|
2639
2648
|
var import_jsx_runtime27 = require("react/jsx-runtime");
|
|
2649
|
+
var DotLottiePlayer = (0, import_react12.lazy)(
|
|
2650
|
+
() => import("@lottiefiles/dotlottie-react").then((m) => ({ default: m.DotLottieReact }))
|
|
2651
|
+
);
|
|
2640
2652
|
function DotLottieInView({
|
|
2641
2653
|
enabled = true,
|
|
2642
2654
|
rootMargin = "0px",
|
|
2643
2655
|
threshold = 0.2,
|
|
2644
2656
|
className,
|
|
2645
2657
|
style,
|
|
2658
|
+
poster,
|
|
2646
2659
|
...dotProps
|
|
2647
2660
|
}) {
|
|
2648
2661
|
const wrapRef = (0, import_react12.useRef)(null);
|
|
2649
2662
|
const [inView, setInView] = (0, import_react12.useState)(false);
|
|
2663
|
+
const [mounted, setMounted] = (0, import_react12.useState)(false);
|
|
2650
2664
|
const [dotLottie, setDotLottie] = (0, import_react12.useState)(null);
|
|
2651
2665
|
(0, import_react12.useEffect)(() => {
|
|
2652
2666
|
const el = wrapRef.current;
|
|
@@ -2660,14 +2674,40 @@ function DotLottieInView({
|
|
|
2660
2674
|
observer.observe(el);
|
|
2661
2675
|
return () => observer.disconnect();
|
|
2662
2676
|
}, [rootMargin, threshold]);
|
|
2677
|
+
(0, import_react12.useEffect)(() => {
|
|
2678
|
+
if (mounted) return;
|
|
2679
|
+
if (!inView) return;
|
|
2680
|
+
if (typeof window === "undefined") return;
|
|
2681
|
+
let cancelled = false;
|
|
2682
|
+
const commit = () => {
|
|
2683
|
+
if (!cancelled) setMounted(true);
|
|
2684
|
+
};
|
|
2685
|
+
const idleId = typeof window.requestIdleCallback === "function" ? window.requestIdleCallback(commit, { timeout: 400 }) : null;
|
|
2686
|
+
const timerId = idleId === null ? window.setTimeout(commit, 0) : null;
|
|
2687
|
+
return () => {
|
|
2688
|
+
cancelled = true;
|
|
2689
|
+
if (idleId !== null && typeof window.cancelIdleCallback === "function") {
|
|
2690
|
+
window.cancelIdleCallback(idleId);
|
|
2691
|
+
}
|
|
2692
|
+
if (timerId !== null) window.clearTimeout(timerId);
|
|
2693
|
+
};
|
|
2694
|
+
}, [inView, mounted]);
|
|
2663
2695
|
(0, import_react12.useEffect)(() => {
|
|
2664
2696
|
if (!dotLottie) return;
|
|
2665
2697
|
if (!enabled || !inView) {
|
|
2666
2698
|
dotLottie.stop();
|
|
2667
2699
|
return;
|
|
2668
2700
|
}
|
|
2669
|
-
|
|
2670
|
-
|
|
2701
|
+
const start = () => {
|
|
2702
|
+
dotLottie.stop();
|
|
2703
|
+
dotLottie.play();
|
|
2704
|
+
};
|
|
2705
|
+
if (dotLottie.isLoaded) {
|
|
2706
|
+
start();
|
|
2707
|
+
return;
|
|
2708
|
+
}
|
|
2709
|
+
dotLottie.addEventListener("load", start);
|
|
2710
|
+
return () => dotLottie.removeEventListener("load", start);
|
|
2671
2711
|
}, [dotLottie, enabled, inView]);
|
|
2672
2712
|
return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
2673
2713
|
"div",
|
|
@@ -2684,15 +2724,15 @@ function DotLottieInView({
|
|
|
2684
2724
|
backgroundColor: "transparent",
|
|
2685
2725
|
...style
|
|
2686
2726
|
},
|
|
2687
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
2688
|
-
|
|
2727
|
+
children: mounted ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_react12.Suspense, { fallback: poster ?? null, children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
2728
|
+
DotLottiePlayer,
|
|
2689
2729
|
{
|
|
2690
2730
|
...dotProps,
|
|
2691
2731
|
loop: false,
|
|
2692
2732
|
autoplay: false,
|
|
2693
2733
|
dotLottieRefCallback: setDotLottie
|
|
2694
2734
|
}
|
|
2695
|
-
)
|
|
2735
|
+
) }) : poster ?? null
|
|
2696
2736
|
}
|
|
2697
2737
|
);
|
|
2698
2738
|
}
|
|
@@ -2764,26 +2804,45 @@ var ChevronRight2 = () => /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
|
2764
2804
|
)
|
|
2765
2805
|
}
|
|
2766
2806
|
);
|
|
2807
|
+
function mediaSrc(item) {
|
|
2808
|
+
return typeof item.mediaUrl === "string" && item.mediaUrl !== "" ? item.mediaUrl : null;
|
|
2809
|
+
}
|
|
2767
2810
|
function resolveMediaType(item) {
|
|
2768
2811
|
if (item.mediaType) return item.mediaType;
|
|
2769
|
-
|
|
2812
|
+
const src = mediaSrc(item);
|
|
2813
|
+
return src?.split("?")[0].endsWith(".lottie") ? "lottie" : "image";
|
|
2770
2814
|
}
|
|
2771
|
-
var MediaRenderer = ({ item, active }) => {
|
|
2815
|
+
var MediaRenderer = ({ item, active, rootMargin, threshold }) => {
|
|
2816
|
+
const src = mediaSrc(item);
|
|
2817
|
+
if (!src) return null;
|
|
2772
2818
|
if (resolveMediaType(item) === "lottie") {
|
|
2773
2819
|
return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
2774
2820
|
DotLottieInView,
|
|
2775
2821
|
{
|
|
2776
|
-
src
|
|
2777
|
-
enabled: active
|
|
2822
|
+
src,
|
|
2823
|
+
enabled: active,
|
|
2824
|
+
rootMargin,
|
|
2825
|
+
threshold,
|
|
2826
|
+
poster: item.posterUrl ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
2827
|
+
"img",
|
|
2828
|
+
{
|
|
2829
|
+
src: item.posterUrl,
|
|
2830
|
+
alt: "",
|
|
2831
|
+
"aria-hidden": "true",
|
|
2832
|
+
loading: "lazy",
|
|
2833
|
+
decoding: "async"
|
|
2834
|
+
}
|
|
2835
|
+
) : void 0
|
|
2778
2836
|
}
|
|
2779
2837
|
);
|
|
2780
2838
|
}
|
|
2781
2839
|
return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
2782
2840
|
"img",
|
|
2783
2841
|
{
|
|
2784
|
-
src
|
|
2842
|
+
src,
|
|
2785
2843
|
alt: item.title,
|
|
2786
|
-
loading: "lazy"
|
|
2844
|
+
loading: "lazy",
|
|
2845
|
+
decoding: "async"
|
|
2787
2846
|
}
|
|
2788
2847
|
);
|
|
2789
2848
|
};
|
|
@@ -2792,10 +2851,16 @@ var FeatureScroll = ({
|
|
|
2792
2851
|
items,
|
|
2793
2852
|
variant = "media-right",
|
|
2794
2853
|
className,
|
|
2854
|
+
// Destructured, not spread: `...props` lands on the <section>, and an
|
|
2855
|
+
// unknown attribute there is a React DOM warning at best.
|
|
2856
|
+
mediaRootMargin,
|
|
2857
|
+
mediaThreshold,
|
|
2795
2858
|
...props
|
|
2796
2859
|
}) => {
|
|
2797
2860
|
const [activeIndex, setActiveIndex] = (0, import_react13.useState)(0);
|
|
2861
|
+
const [mobileActiveIndex, setMobileActiveIndex] = (0, import_react13.useState)(0);
|
|
2798
2862
|
const titleRefs = (0, import_react13.useRef)([]);
|
|
2863
|
+
const mobileItemRefs = (0, import_react13.useRef)([]);
|
|
2799
2864
|
const mediaColRef = (0, import_react13.useRef)(null);
|
|
2800
2865
|
(0, import_react13.useLayoutEffect)(() => {
|
|
2801
2866
|
if (items.length === 0) return;
|
|
@@ -2843,6 +2908,40 @@ var FeatureScroll = ({
|
|
|
2843
2908
|
if (rafId !== 0) window.cancelAnimationFrame(rafId);
|
|
2844
2909
|
};
|
|
2845
2910
|
}, [items.length]);
|
|
2911
|
+
(0, import_react13.useEffect)(() => {
|
|
2912
|
+
if (items.length === 0) return;
|
|
2913
|
+
if (typeof window === "undefined") return;
|
|
2914
|
+
const ratios = /* @__PURE__ */ new Map();
|
|
2915
|
+
const observer = new IntersectionObserver(
|
|
2916
|
+
(entries) => {
|
|
2917
|
+
if (window.matchMedia("(min-width: 992px)").matches) return;
|
|
2918
|
+
for (const entry of entries) {
|
|
2919
|
+
const idx = Number(entry.target.getAttribute("data-fs-mobile-idx"));
|
|
2920
|
+
if (!Number.isFinite(idx)) continue;
|
|
2921
|
+
ratios.set(idx, entry.isIntersecting ? entry.intersectionRatio : 0);
|
|
2922
|
+
}
|
|
2923
|
+
let best = 0;
|
|
2924
|
+
let bestRatio = -1;
|
|
2925
|
+
for (const [idx, ratio] of ratios) {
|
|
2926
|
+
if (ratio > bestRatio) {
|
|
2927
|
+
bestRatio = ratio;
|
|
2928
|
+
best = idx;
|
|
2929
|
+
}
|
|
2930
|
+
}
|
|
2931
|
+
if (bestRatio <= 0) return;
|
|
2932
|
+
setMobileActiveIndex((prev) => prev === best ? prev : best);
|
|
2933
|
+
},
|
|
2934
|
+
{
|
|
2935
|
+
root: null,
|
|
2936
|
+
rootMargin: "-28% 0px -28% 0px",
|
|
2937
|
+
threshold: [0, 0.15, 0.3, 0.5, 0.75, 1]
|
|
2938
|
+
}
|
|
2939
|
+
);
|
|
2940
|
+
for (const el of mobileItemRefs.current) {
|
|
2941
|
+
if (el) observer.observe(el);
|
|
2942
|
+
}
|
|
2943
|
+
return () => observer.disconnect();
|
|
2944
|
+
}, [items.length]);
|
|
2846
2945
|
const rootClass = [
|
|
2847
2946
|
"fs",
|
|
2848
2947
|
`fs--${variant}`,
|
|
@@ -2870,7 +2969,9 @@ var FeatureScroll = ({
|
|
|
2870
2969
|
MediaRenderer,
|
|
2871
2970
|
{
|
|
2872
2971
|
item,
|
|
2873
|
-
active: i === activeIndex
|
|
2972
|
+
active: i === activeIndex,
|
|
2973
|
+
rootMargin: mediaRootMargin,
|
|
2974
|
+
threshold: mediaThreshold
|
|
2874
2975
|
}
|
|
2875
2976
|
)
|
|
2876
2977
|
},
|
|
@@ -2910,22 +3011,41 @@ var FeatureScroll = ({
|
|
|
2910
3011
|
i
|
|
2911
3012
|
)) })
|
|
2912
3013
|
] }),
|
|
2913
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: "fs__mobile-list", children: items.map((item, i) => /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
|
|
2914
|
-
|
|
2915
|
-
|
|
2916
|
-
|
|
2917
|
-
|
|
2918
|
-
|
|
2919
|
-
|
|
2920
|
-
|
|
2921
|
-
|
|
2922
|
-
children:
|
|
2923
|
-
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
|
|
2927
|
-
|
|
2928
|
-
|
|
3014
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: "fs__mobile-list", children: items.map((item, i) => /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
|
|
3015
|
+
"div",
|
|
3016
|
+
{
|
|
3017
|
+
className: "fs__mobile-item",
|
|
3018
|
+
"data-fs-mobile-idx": i,
|
|
3019
|
+
ref: (el) => {
|
|
3020
|
+
mobileItemRefs.current[i] = el;
|
|
3021
|
+
},
|
|
3022
|
+
children: [
|
|
3023
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("h3", { className: "fs__item-title", children: item.title }),
|
|
3024
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: "fs__mobile-media", children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
3025
|
+
MediaRenderer,
|
|
3026
|
+
{
|
|
3027
|
+
item,
|
|
3028
|
+
active: i === mobileActiveIndex,
|
|
3029
|
+
rootMargin: mediaRootMargin,
|
|
3030
|
+
threshold: mediaThreshold
|
|
3031
|
+
}
|
|
3032
|
+
) }),
|
|
3033
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("p", { className: "fs__item-desc", children: item.description }),
|
|
3034
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
|
|
3035
|
+
"a",
|
|
3036
|
+
{
|
|
3037
|
+
href: item.link,
|
|
3038
|
+
className: "fs__item-link",
|
|
3039
|
+
children: [
|
|
3040
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { children: item.linkLabel }),
|
|
3041
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(ChevronRight2, {})
|
|
3042
|
+
]
|
|
3043
|
+
}
|
|
3044
|
+
)
|
|
3045
|
+
]
|
|
3046
|
+
},
|
|
3047
|
+
i
|
|
3048
|
+
)) })
|
|
2929
3049
|
] }) });
|
|
2930
3050
|
};
|
|
2931
3051
|
|