@depup/lottie-react 2.4.1-depup.0 → 3.0.0-depup.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/LICENSE.md +9 -0
- package/README.md +4 -10
- package/build/_virtual/_rolldown/runtime.cjs +23 -0
- package/build/animation/Lottie.cjs +39 -0
- package/build/animation/Lottie.d.cts +47 -0
- package/build/animation/Lottie.d.ts +47 -0
- package/build/animation/Lottie.js +37 -0
- package/build/animation/LottieDisplay.cjs +55 -0
- package/build/animation/LottieDisplay.d.cts +46 -0
- package/build/animation/LottieDisplay.d.ts +46 -0
- package/build/animation/LottieDisplay.js +53 -0
- package/build/animation/LottieInstanceContext.cjs +16 -0
- package/build/animation/LottieInstanceContext.js +17 -0
- package/build/animation/LottieLight.cjs +19 -0
- package/build/animation/LottieLight.d.cts +23 -0
- package/build/animation/LottieLight.d.ts +23 -0
- package/build/animation/LottieLight.js +17 -0
- package/build/animation/LottieRegistryContext.cjs +36 -0
- package/build/animation/LottieRegistryContext.js +35 -0
- package/build/animation/LottieSvg.cjs +20 -0
- package/build/animation/LottieSvg.d.cts +24 -0
- package/build/animation/LottieSvg.d.ts +24 -0
- package/build/animation/LottieSvg.js +18 -0
- package/build/animation/collectMarkerCrossings.cjs +38 -0
- package/build/animation/collectMarkerCrossings.js +38 -0
- package/build/animation/createLottieComponent.cjs +131 -0
- package/build/animation/createLottieComponent.d.cts +45 -0
- package/build/animation/createLottieComponent.d.ts +45 -0
- package/build/animation/createLottieComponent.js +131 -0
- package/build/animation/hasExpressions.cjs +25 -0
- package/build/animation/hasExpressions.js +25 -0
- package/build/animation/normalizeAnimationSource.cjs +38 -0
- package/build/animation/normalizeAnimationSource.js +38 -0
- package/build/animation/polymorphicForwardRef.cjs +18 -0
- package/build/animation/polymorphicForwardRef.js +19 -0
- package/build/animation/renderStyledElement.cjs +31 -0
- package/build/animation/renderStyledElement.js +31 -0
- package/build/animation/resolveSeekTarget.cjs +97 -0
- package/build/animation/resolveSeekTarget.js +95 -0
- package/build/animation/styleLayer.cjs +24 -0
- package/build/animation/styleLayer.js +24 -0
- package/build/animation/stylePrecedence.cjs +12 -0
- package/build/animation/stylePrecedence.js +12 -0
- package/build/animation/types.cjs +71 -0
- package/build/animation/types.d.cts +461 -0
- package/build/animation/types.d.ts +461 -0
- package/build/animation/types.js +68 -0
- package/build/animation/useLottie.cjs +40 -0
- package/build/animation/useLottie.d.cts +36 -0
- package/build/animation/useLottie.d.ts +36 -0
- package/build/animation/useLottie.js +38 -0
- package/build/animation/useLottieAnimation.cjs +434 -0
- package/build/animation/useLottieAnimation.d.cts +40 -0
- package/build/animation/useLottieAnimation.d.ts +40 -0
- package/build/animation/useLottieAnimation.js +434 -0
- package/build/animation/useLottieInstance.cjs +20 -0
- package/build/animation/useLottieInstance.d.cts +14 -0
- package/build/animation/useLottieInstance.d.ts +14 -0
- package/build/animation/useLottieInstance.js +20 -0
- package/build/animation/useLottieLight.cjs +20 -0
- package/build/animation/useLottieLight.d.cts +16 -0
- package/build/animation/useLottieLight.d.ts +16 -0
- package/build/animation/useLottieLight.js +18 -0
- package/build/animation/useLottieSvg.cjs +18 -0
- package/build/animation/useLottieSvg.d.cts +14 -0
- package/build/animation/useLottieSvg.d.ts +14 -0
- package/build/animation/useLottieSvg.js +16 -0
- package/build/controls/LottieControls.cjs +180 -0
- package/build/controls/LottieControls.d.cts +58 -0
- package/build/controls/LottieControls.d.ts +58 -0
- package/build/controls/LottieControls.js +178 -0
- package/build/controls/LottieDirectionButton.cjs +36 -0
- package/build/controls/LottieDirectionButton.js +35 -0
- package/build/controls/LottieFullscreenButton.cjs +35 -0
- package/build/controls/LottieFullscreenButton.js +34 -0
- package/build/controls/LottieLoopButton.cjs +32 -0
- package/build/controls/LottieLoopButton.js +31 -0
- package/build/controls/LottiePlayButton.cjs +34 -0
- package/build/controls/LottiePlayButton.js +33 -0
- package/build/controls/LottieReadout.cjs +61 -0
- package/build/controls/LottieReadout.d.cts +13 -0
- package/build/controls/LottieReadout.d.ts +13 -0
- package/build/controls/LottieReadout.js +60 -0
- package/build/controls/LottieSeekBar.cjs +87 -0
- package/build/controls/LottieSeekBar.js +86 -0
- package/build/controls/LottieSpeedSelect.cjs +51 -0
- package/build/controls/LottieSpeedSelect.js +50 -0
- package/build/controls/LottieStopButton.cjs +29 -0
- package/build/controls/LottieStopButton.js +28 -0
- package/build/controls/controlIcon.cjs +25 -0
- package/build/controls/controlIcon.js +25 -0
- package/build/controls/useFullscreen.cjs +46 -0
- package/build/controls/useFullscreen.js +46 -0
- package/build/controls/useShortcuts.cjs +70 -0
- package/build/controls/useShortcuts.js +70 -0
- package/build/index.cjs +36 -0
- package/build/index.d.cts +19 -0
- package/build/index.d.ts +19 -80
- package/build/index.js +17 -667
- package/build/interactions/LottieInteractions.cjs +41 -0
- package/build/interactions/LottieInteractions.d.cts +37 -0
- package/build/interactions/LottieInteractions.d.ts +37 -0
- package/build/interactions/LottieInteractions.js +41 -0
- package/build/interactions/coverProgress.cjs +55 -0
- package/build/interactions/coverProgress.js +53 -0
- package/build/interactions/lottieInView.cjs +109 -0
- package/build/interactions/lottieInView.d.cts +44 -0
- package/build/interactions/lottieInView.d.ts +44 -0
- package/build/interactions/lottieInView.js +109 -0
- package/build/interactions/lottieScrollScrub.cjs +152 -0
- package/build/interactions/lottieScrollScrub.d.cts +47 -0
- package/build/interactions/lottieScrollScrub.d.ts +47 -0
- package/build/interactions/lottieScrollScrub.js +152 -0
- package/build/interactions/types.d.cts +46 -0
- package/build/interactions/types.d.ts +46 -0
- package/build/interactions/useInteractionsRunner.cjs +142 -0
- package/build/interactions/useInteractionsRunner.js +141 -0
- package/build/interactions/useLottieInteractions.cjs +21 -0
- package/build/interactions/useLottieInteractions.d.cts +19 -0
- package/build/interactions/useLottieInteractions.d.ts +19 -0
- package/build/interactions/useLottieInteractions.js +21 -0
- package/build/overlays/LottieError.cjs +74 -0
- package/build/overlays/LottieError.d.cts +40 -0
- package/build/overlays/LottieError.d.ts +40 -0
- package/build/overlays/LottieError.js +72 -0
- package/build/overlays/LottieLoading.cjs +89 -0
- package/build/overlays/LottieLoading.d.cts +45 -0
- package/build/overlays/LottieLoading.d.ts +45 -0
- package/build/overlays/LottieLoading.js +87 -0
- package/build/overlays/overlayStyles.cjs +33 -0
- package/build/overlays/overlayStyles.js +33 -0
- package/build/utils/SubscriptionManager.cjs +42 -0
- package/build/utils/SubscriptionManager.d.cts +30 -0
- package/build/utils/SubscriptionManager.d.ts +30 -0
- package/build/utils/SubscriptionManager.js +42 -0
- package/build/utils/createLogger.cjs +25 -0
- package/build/utils/createLogger.js +25 -0
- package/build/utils/isSameJson.cjs +37 -0
- package/build/utils/isSameJson.js +37 -0
- package/build/utils/mergeRefs.cjs +37 -0
- package/build/utils/mergeRefs.js +37 -0
- package/build/utils/useStableValue.cjs +26 -0
- package/build/utils/useStableValue.js +26 -0
- package/changes.json +3 -8
- package/package.json +144 -89
- package/LICENSE +0 -46
- package/build/index.es.js +0 -653
- package/build/index.es.js.map +0 -1
- package/build/index.es.min.js +0 -3
- package/build/index.js.map +0 -1
- package/build/index.min.js +0 -3
- package/build/index.umd.js +0 -670
- package/build/index.umd.js.map +0 -1
- package/build/index.umd.min.js +0 -3
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
const require_LottieInstanceContext = require("../animation/LottieInstanceContext.cjs");
|
|
2
|
+
const require_LottieRegistryContext = require("../animation/LottieRegistryContext.cjs");
|
|
3
|
+
const require_useInteractionsRunner = require("./useInteractionsRunner.cjs");
|
|
4
|
+
let react = require("react");
|
|
5
|
+
let react_jsx_runtime = require("react/jsx-runtime");
|
|
6
|
+
//#region src/interactions/LottieInteractions.tsx
|
|
7
|
+
/**
|
|
8
|
+
* Attaches behaviours to animations, from any of three positions.
|
|
9
|
+
*
|
|
10
|
+
* Around a `<Lottie>` it drives every animation inside it, however deep and
|
|
11
|
+
* however many, with no display of its own to place. Inside a `<Lottie>` it
|
|
12
|
+
* drives that animation. Handed a `lottie` from the hook path it drives
|
|
13
|
+
* exactly that one, like every other component here.
|
|
14
|
+
*
|
|
15
|
+
* ```jsx
|
|
16
|
+
* <LottieInteractions interactions={[lottieInView({ once: true })]}>
|
|
17
|
+
* <Lottie src={anim} autoplay={false} />
|
|
18
|
+
* </LottieInteractions>
|
|
19
|
+
* ```
|
|
20
|
+
*
|
|
21
|
+
* The resolution is the nearest claim wins: the `lottie` prop, else the
|
|
22
|
+
* animation whose `<Lottie>` this sits inside, else whatever renders below.
|
|
23
|
+
* When one of the first two wins, the children pass through untouched, so an
|
|
24
|
+
* animation below still reaches a wrapper further out. Wrapping nothing is
|
|
25
|
+
* not an error, because the animations inside may mount later; it simply
|
|
26
|
+
* does nothing yet.
|
|
27
|
+
*/
|
|
28
|
+
function LottieInteractions({ lottie, interactions, children }) {
|
|
29
|
+
const surrounding = (0, react.useContext)(require_LottieInstanceContext.LottieInstanceContext);
|
|
30
|
+
const explicit = lottie ?? surrounding;
|
|
31
|
+
const [store] = (0, react.useState)(require_LottieRegistryContext.createLottieRegistry);
|
|
32
|
+
const single = require_useInteractionsRunner.useSingleInstanceSource(explicit);
|
|
33
|
+
require_useInteractionsRunner.useInteractionsRunner(explicit !== null ? single : store, interactions);
|
|
34
|
+
if (explicit !== null) return children ?? null;
|
|
35
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_LottieRegistryContext.LottieRegistryContext.Provider, {
|
|
36
|
+
value: store,
|
|
37
|
+
children
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
//#endregion
|
|
41
|
+
exports.LottieInteractions = LottieInteractions;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { LottieInstance } from "../animation/types.cjs";
|
|
2
|
+
import { LottieInteraction } from "./types.cjs";
|
|
3
|
+
import { ReactNode } from "react";
|
|
4
|
+
//#region src/interactions/LottieInteractions.d.ts
|
|
5
|
+
/** What {@link LottieInteractions} owns. It renders no element of its own. */
|
|
6
|
+
interface LottieInteractionsProps {
|
|
7
|
+
/** The animation to drive. Omit it around or inside `<Lottie>`. */
|
|
8
|
+
lottie?: LottieInstance;
|
|
9
|
+
/** The behaviours, each made by a factory such as `lottieInView(...)`. */
|
|
10
|
+
interactions: readonly LottieInteraction[];
|
|
11
|
+
/** Anything at all, rendered untouched. */
|
|
12
|
+
children?: ReactNode;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Attaches behaviours to animations, from any of three positions.
|
|
16
|
+
*
|
|
17
|
+
* Around a `<Lottie>` it drives every animation inside it, however deep and
|
|
18
|
+
* however many, with no display of its own to place. Inside a `<Lottie>` it
|
|
19
|
+
* drives that animation. Handed a `lottie` from the hook path it drives
|
|
20
|
+
* exactly that one, like every other component here.
|
|
21
|
+
*
|
|
22
|
+
* ```jsx
|
|
23
|
+
* <LottieInteractions interactions={[lottieInView({ once: true })]}>
|
|
24
|
+
* <Lottie src={anim} autoplay={false} />
|
|
25
|
+
* </LottieInteractions>
|
|
26
|
+
* ```
|
|
27
|
+
*
|
|
28
|
+
* The resolution is the nearest claim wins: the `lottie` prop, else the
|
|
29
|
+
* animation whose `<Lottie>` this sits inside, else whatever renders below.
|
|
30
|
+
* When one of the first two wins, the children pass through untouched, so an
|
|
31
|
+
* animation below still reaches a wrapper further out. Wrapping nothing is
|
|
32
|
+
* not an error, because the animations inside may mount later; it simply
|
|
33
|
+
* does nothing yet.
|
|
34
|
+
*/
|
|
35
|
+
declare function LottieInteractions({ lottie, interactions, children }: LottieInteractionsProps): ReactNode;
|
|
36
|
+
//#endregion
|
|
37
|
+
export { LottieInteractions, LottieInteractionsProps };
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { LottieInstance } from "../animation/types.js";
|
|
2
|
+
import { LottieInteraction } from "./types.js";
|
|
3
|
+
import { ReactNode } from "react";
|
|
4
|
+
//#region src/interactions/LottieInteractions.d.ts
|
|
5
|
+
/** What {@link LottieInteractions} owns. It renders no element of its own. */
|
|
6
|
+
interface LottieInteractionsProps {
|
|
7
|
+
/** The animation to drive. Omit it around or inside `<Lottie>`. */
|
|
8
|
+
lottie?: LottieInstance;
|
|
9
|
+
/** The behaviours, each made by a factory such as `lottieInView(...)`. */
|
|
10
|
+
interactions: readonly LottieInteraction[];
|
|
11
|
+
/** Anything at all, rendered untouched. */
|
|
12
|
+
children?: ReactNode;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Attaches behaviours to animations, from any of three positions.
|
|
16
|
+
*
|
|
17
|
+
* Around a `<Lottie>` it drives every animation inside it, however deep and
|
|
18
|
+
* however many, with no display of its own to place. Inside a `<Lottie>` it
|
|
19
|
+
* drives that animation. Handed a `lottie` from the hook path it drives
|
|
20
|
+
* exactly that one, like every other component here.
|
|
21
|
+
*
|
|
22
|
+
* ```jsx
|
|
23
|
+
* <LottieInteractions interactions={[lottieInView({ once: true })]}>
|
|
24
|
+
* <Lottie src={anim} autoplay={false} />
|
|
25
|
+
* </LottieInteractions>
|
|
26
|
+
* ```
|
|
27
|
+
*
|
|
28
|
+
* The resolution is the nearest claim wins: the `lottie` prop, else the
|
|
29
|
+
* animation whose `<Lottie>` this sits inside, else whatever renders below.
|
|
30
|
+
* When one of the first two wins, the children pass through untouched, so an
|
|
31
|
+
* animation below still reaches a wrapper further out. Wrapping nothing is
|
|
32
|
+
* not an error, because the animations inside may mount later; it simply
|
|
33
|
+
* does nothing yet.
|
|
34
|
+
*/
|
|
35
|
+
declare function LottieInteractions({ lottie, interactions, children }: LottieInteractionsProps): ReactNode;
|
|
36
|
+
//#endregion
|
|
37
|
+
export { LottieInteractions, LottieInteractionsProps };
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { LottieInstanceContext } from "../animation/LottieInstanceContext.js";
|
|
2
|
+
import { LottieRegistryContext, createLottieRegistry } from "../animation/LottieRegistryContext.js";
|
|
3
|
+
import { useInteractionsRunner, useSingleInstanceSource } from "./useInteractionsRunner.js";
|
|
4
|
+
import { useContext, useState } from "react";
|
|
5
|
+
import { jsx } from "react/jsx-runtime";
|
|
6
|
+
//#region src/interactions/LottieInteractions.tsx
|
|
7
|
+
/**
|
|
8
|
+
* Attaches behaviours to animations, from any of three positions.
|
|
9
|
+
*
|
|
10
|
+
* Around a `<Lottie>` it drives every animation inside it, however deep and
|
|
11
|
+
* however many, with no display of its own to place. Inside a `<Lottie>` it
|
|
12
|
+
* drives that animation. Handed a `lottie` from the hook path it drives
|
|
13
|
+
* exactly that one, like every other component here.
|
|
14
|
+
*
|
|
15
|
+
* ```jsx
|
|
16
|
+
* <LottieInteractions interactions={[lottieInView({ once: true })]}>
|
|
17
|
+
* <Lottie src={anim} autoplay={false} />
|
|
18
|
+
* </LottieInteractions>
|
|
19
|
+
* ```
|
|
20
|
+
*
|
|
21
|
+
* The resolution is the nearest claim wins: the `lottie` prop, else the
|
|
22
|
+
* animation whose `<Lottie>` this sits inside, else whatever renders below.
|
|
23
|
+
* When one of the first two wins, the children pass through untouched, so an
|
|
24
|
+
* animation below still reaches a wrapper further out. Wrapping nothing is
|
|
25
|
+
* not an error, because the animations inside may mount later; it simply
|
|
26
|
+
* does nothing yet.
|
|
27
|
+
*/
|
|
28
|
+
function LottieInteractions({ lottie, interactions, children }) {
|
|
29
|
+
const surrounding = useContext(LottieInstanceContext);
|
|
30
|
+
const explicit = lottie ?? surrounding;
|
|
31
|
+
const [store] = useState(createLottieRegistry);
|
|
32
|
+
const single = useSingleInstanceSource(explicit);
|
|
33
|
+
useInteractionsRunner(explicit !== null ? single : store, interactions);
|
|
34
|
+
if (explicit !== null) return children ?? null;
|
|
35
|
+
return /* @__PURE__ */ jsx(LottieRegistryContext.Provider, {
|
|
36
|
+
value: store,
|
|
37
|
+
children
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
//#endregion
|
|
41
|
+
export { LottieInteractions };
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
//#region src/interactions/coverProgress.ts
|
|
2
|
+
/**
|
|
3
|
+
* Where an element's journey across a viewport stands: 0 as its leading edge
|
|
4
|
+
* reaches the viewport's far end, 1 as its trailing edge leaves the near end.
|
|
5
|
+
*
|
|
6
|
+
* This is the platform's `cover` range written out, which is what makes the
|
|
7
|
+
* fallback and a real `ViewTimeline` agree wherever both can run. It reads
|
|
8
|
+
* a rectangle rather than the live layout, so the caller decides where the
|
|
9
|
+
* rectangle comes from and the arithmetic stays measurable.
|
|
10
|
+
*/
|
|
11
|
+
function coverProgress(rect, viewport, axis) {
|
|
12
|
+
const size = axis === "inline" ? viewport.width : viewport.height;
|
|
13
|
+
const leading = axis === "inline" ? rect.left : rect.top;
|
|
14
|
+
const span = size + (axis === "inline" ? rect.width : rect.height);
|
|
15
|
+
if (span === 0) return 0;
|
|
16
|
+
return Math.min(Math.max((size - leading) / span, 0), 1);
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* The journey progress mapped into a band of it, clamped at the band's ends.
|
|
20
|
+
*
|
|
21
|
+
* Holding still below the band and holding still above it are what replace
|
|
22
|
+
* v2's `stop` bands: they are not features, they are what clamping does.
|
|
23
|
+
*/
|
|
24
|
+
function bandProgress(progress, range) {
|
|
25
|
+
const [start, end] = range;
|
|
26
|
+
if (end === start) return progress < start ? 0 : 1;
|
|
27
|
+
return Math.min(Math.max((progress - start) / (end - start), 0), 1);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Compares two banded samples and names the edges crossed between them.
|
|
31
|
+
*
|
|
32
|
+
* Inside means strictly between the clamps; a sample pinned at 0 or 1 is
|
|
33
|
+
* outside, which is what makes leaving fire exactly when the scrub reaches
|
|
34
|
+
* an end. The first sample of a gesture has no predecessor, and starting
|
|
35
|
+
* already inside counts as entering forward. A single sample that crosses
|
|
36
|
+
* the whole band reports both edges in its direction of travel.
|
|
37
|
+
*/
|
|
38
|
+
function bandEdges(previous, current) {
|
|
39
|
+
const isInside = current > 0 && current < 1;
|
|
40
|
+
if (previous === null) return isInside ? { enter: "forward" } : {};
|
|
41
|
+
const wasInside = previous > 0 && previous < 1;
|
|
42
|
+
const direction = current >= previous ? "forward" : "backward";
|
|
43
|
+
const events = {};
|
|
44
|
+
if (!wasInside && isInside) events.enter = direction;
|
|
45
|
+
if (wasInside && !isInside) events.leave = direction;
|
|
46
|
+
if (!wasInside && !isInside && previous !== current && previous <= 0 !== current <= 0) {
|
|
47
|
+
events.enter = direction;
|
|
48
|
+
events.leave = direction;
|
|
49
|
+
}
|
|
50
|
+
return events;
|
|
51
|
+
}
|
|
52
|
+
//#endregion
|
|
53
|
+
exports.bandEdges = bandEdges;
|
|
54
|
+
exports.bandProgress = bandProgress;
|
|
55
|
+
exports.coverProgress = coverProgress;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
//#region src/interactions/coverProgress.ts
|
|
2
|
+
/**
|
|
3
|
+
* Where an element's journey across a viewport stands: 0 as its leading edge
|
|
4
|
+
* reaches the viewport's far end, 1 as its trailing edge leaves the near end.
|
|
5
|
+
*
|
|
6
|
+
* This is the platform's `cover` range written out, which is what makes the
|
|
7
|
+
* fallback and a real `ViewTimeline` agree wherever both can run. It reads
|
|
8
|
+
* a rectangle rather than the live layout, so the caller decides where the
|
|
9
|
+
* rectangle comes from and the arithmetic stays measurable.
|
|
10
|
+
*/
|
|
11
|
+
function coverProgress(rect, viewport, axis) {
|
|
12
|
+
const size = axis === "inline" ? viewport.width : viewport.height;
|
|
13
|
+
const leading = axis === "inline" ? rect.left : rect.top;
|
|
14
|
+
const span = size + (axis === "inline" ? rect.width : rect.height);
|
|
15
|
+
if (span === 0) return 0;
|
|
16
|
+
return Math.min(Math.max((size - leading) / span, 0), 1);
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* The journey progress mapped into a band of it, clamped at the band's ends.
|
|
20
|
+
*
|
|
21
|
+
* Holding still below the band and holding still above it are what replace
|
|
22
|
+
* v2's `stop` bands: they are not features, they are what clamping does.
|
|
23
|
+
*/
|
|
24
|
+
function bandProgress(progress, range) {
|
|
25
|
+
const [start, end] = range;
|
|
26
|
+
if (end === start) return progress < start ? 0 : 1;
|
|
27
|
+
return Math.min(Math.max((progress - start) / (end - start), 0), 1);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Compares two banded samples and names the edges crossed between them.
|
|
31
|
+
*
|
|
32
|
+
* Inside means strictly between the clamps; a sample pinned at 0 or 1 is
|
|
33
|
+
* outside, which is what makes leaving fire exactly when the scrub reaches
|
|
34
|
+
* an end. The first sample of a gesture has no predecessor, and starting
|
|
35
|
+
* already inside counts as entering forward. A single sample that crosses
|
|
36
|
+
* the whole band reports both edges in its direction of travel.
|
|
37
|
+
*/
|
|
38
|
+
function bandEdges(previous, current) {
|
|
39
|
+
const isInside = current > 0 && current < 1;
|
|
40
|
+
if (previous === null) return isInside ? { enter: "forward" } : {};
|
|
41
|
+
const wasInside = previous > 0 && previous < 1;
|
|
42
|
+
const direction = current >= previous ? "forward" : "backward";
|
|
43
|
+
const events = {};
|
|
44
|
+
if (!wasInside && isInside) events.enter = direction;
|
|
45
|
+
if (wasInside && !isInside) events.leave = direction;
|
|
46
|
+
if (!wasInside && !isInside && previous !== current && previous <= 0 !== current <= 0) {
|
|
47
|
+
events.enter = direction;
|
|
48
|
+
events.leave = direction;
|
|
49
|
+
}
|
|
50
|
+
return events;
|
|
51
|
+
}
|
|
52
|
+
//#endregion
|
|
53
|
+
export { bandEdges, bandProgress, coverProgress };
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
const require_types = require("../animation/types.cjs");
|
|
2
|
+
//#region src/interactions/lottieInView.ts
|
|
3
|
+
function isInViewOptions(value) {
|
|
4
|
+
if (typeof value !== "object" || value === null) return false;
|
|
5
|
+
if ("once" in value && typeof value.once !== "boolean") return false;
|
|
6
|
+
if ("amount" in value && typeof value.amount !== "number") return false;
|
|
7
|
+
return !("margin" in value && typeof value.margin !== "string");
|
|
8
|
+
}
|
|
9
|
+
/** Whether a play command would fight something that outranks it. */
|
|
10
|
+
function playable(state) {
|
|
11
|
+
return state !== require_types.LottieState.loading && state !== require_types.LottieState.error && state !== require_types.LottieState.frozen;
|
|
12
|
+
}
|
|
13
|
+
function attachInView(context, raw) {
|
|
14
|
+
const options = isInViewOptions(raw) ? raw : {};
|
|
15
|
+
let observer = null;
|
|
16
|
+
let observedRoot = null;
|
|
17
|
+
let playedByUs = false;
|
|
18
|
+
let previousState = context.lottie.state;
|
|
19
|
+
let lastIntersecting = null;
|
|
20
|
+
const warnRedundant = () => {
|
|
21
|
+
if (typeof process !== "undefined" && process.env.NODE_ENV !== "production") {
|
|
22
|
+
if (context.memory.warnedRedundant !== true && !playedByUs && context.lottie.state === require_types.LottieState.playing) {
|
|
23
|
+
context.memory.warnedRedundant = true;
|
|
24
|
+
console.warn("[lottie-react] an in-view trigger is watching an animation that already plays by itself. With autoplay on, the trigger has nothing left to start; drop one of the two.");
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
const playFromEntry = () => {
|
|
29
|
+
if (options.once === true) {
|
|
30
|
+
context.memory.entered = true;
|
|
31
|
+
observer?.disconnect();
|
|
32
|
+
observer = null;
|
|
33
|
+
}
|
|
34
|
+
playedByUs = true;
|
|
35
|
+
context.lottie.play();
|
|
36
|
+
};
|
|
37
|
+
const handleEntries = (entries) => {
|
|
38
|
+
const entry = entries.at(-1);
|
|
39
|
+
if (entry === void 0) return;
|
|
40
|
+
lastIntersecting = entry.isIntersecting;
|
|
41
|
+
const lottie = context.lottie;
|
|
42
|
+
if (entry.isIntersecting) {
|
|
43
|
+
if (options.once === true && context.memory.entered === true) return;
|
|
44
|
+
if (playable(lottie.state)) playFromEntry();
|
|
45
|
+
} else if (options.once !== true && lottie.state === require_types.LottieState.playing) lottie.pause();
|
|
46
|
+
};
|
|
47
|
+
const arm = () => {
|
|
48
|
+
const root = context.lottie.root;
|
|
49
|
+
if (root === observedRoot) return;
|
|
50
|
+
observer?.disconnect();
|
|
51
|
+
observer = null;
|
|
52
|
+
observedRoot = root;
|
|
53
|
+
if (root === null) return;
|
|
54
|
+
if (options.once === true && context.memory.entered === true) return;
|
|
55
|
+
try {
|
|
56
|
+
observer = new IntersectionObserver(handleEntries, {
|
|
57
|
+
threshold: options.amount ?? 0,
|
|
58
|
+
rootMargin: options.margin
|
|
59
|
+
});
|
|
60
|
+
} catch {
|
|
61
|
+
if (typeof process !== "undefined" && process.env.NODE_ENV !== "production") console.warn(`[lottie-react] the margin ${JSON.stringify(options.margin)} was refused, so the trigger watches without it. A margin is written in px or %, the only lengths the platform accepts here.`);
|
|
62
|
+
observer = new IntersectionObserver(handleEntries, { threshold: options.amount ?? 0 });
|
|
63
|
+
}
|
|
64
|
+
observer.observe(root);
|
|
65
|
+
};
|
|
66
|
+
const stopListening = context.onChange(() => {
|
|
67
|
+
const state = context.lottie.state;
|
|
68
|
+
if (previousState === require_types.LottieState.loading && state === require_types.LottieState.playing) warnRedundant();
|
|
69
|
+
if (previousState === require_types.LottieState.loading && lastIntersecting === true && playable(state) && state !== require_types.LottieState.playing && !(options.once === true && context.memory.entered === true)) playFromEntry();
|
|
70
|
+
previousState = state;
|
|
71
|
+
arm();
|
|
72
|
+
});
|
|
73
|
+
warnRedundant();
|
|
74
|
+
arm();
|
|
75
|
+
return () => {
|
|
76
|
+
stopListening();
|
|
77
|
+
observer?.disconnect();
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Plays the animation when it scrolls into view and pauses it when it leaves,
|
|
82
|
+
* or with `once`, plays on the first entry and never again.
|
|
83
|
+
*
|
|
84
|
+
* ```jsx
|
|
85
|
+
* <LottieInteractions interactions={[lottieInView({ once: true })]}>
|
|
86
|
+
* <Lottie src={anim} autoplay={false} />
|
|
87
|
+
* </LottieInteractions>
|
|
88
|
+
* ```
|
|
89
|
+
*
|
|
90
|
+
* An entry seen while the animation is still loading plays as soon as the
|
|
91
|
+
* load finishes, so an animation already on screen at page load starts by
|
|
92
|
+
* itself.
|
|
93
|
+
*
|
|
94
|
+
* Leaving pauses rather than stops, so coming back resumes mid-motion instead
|
|
95
|
+
* of restarting. The trigger never overrides a load still in flight or a
|
|
96
|
+
* failed one, and it cannot tell its own pause from one a person asked for,
|
|
97
|
+
* so re-entering resumes either.
|
|
98
|
+
*/
|
|
99
|
+
function lottieInView(options = {}) {
|
|
100
|
+
if (typeof process !== "undefined" && process.env.NODE_ENV !== "production") {
|
|
101
|
+
if (options.amount === 1) console.warn("[lottie-react] amount: 1 never fires for an animation taller than the viewport, because such an element is never entirely visible. Use a smaller amount, or a negative margin for a centre band.");
|
|
102
|
+
}
|
|
103
|
+
return {
|
|
104
|
+
attach: attachInView,
|
|
105
|
+
options
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
//#endregion
|
|
109
|
+
exports.lottieInView = lottieInView;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { LottieInteraction } from "./types.cjs";
|
|
2
|
+
//#region src/interactions/lottieInView.d.ts
|
|
3
|
+
/** What {@link lottieInView} can be told. */
|
|
4
|
+
interface LottieInViewOptions {
|
|
5
|
+
/**
|
|
6
|
+
* Play on the first entry and then stop watching for good, so scrolling
|
|
7
|
+
* past again replays nothing. Off unless asked for.
|
|
8
|
+
*/
|
|
9
|
+
once?: boolean;
|
|
10
|
+
/**
|
|
11
|
+
* How much of the animation must be visible to count as entered, `0` to
|
|
12
|
+
* `1`. The default is `0`: a single visible pixel. `1` is accepted and
|
|
13
|
+
* warned about, because an element taller than the viewport can never be
|
|
14
|
+
* entirely visible, so a threshold of one silently never fires for it.
|
|
15
|
+
*/
|
|
16
|
+
amount?: number;
|
|
17
|
+
/**
|
|
18
|
+
* Grows or shrinks the viewport the entry is measured against, in the
|
|
19
|
+
* platform's own `rootMargin` grammar: px or % only.
|
|
20
|
+
*/
|
|
21
|
+
margin?: string;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Plays the animation when it scrolls into view and pauses it when it leaves,
|
|
25
|
+
* or with `once`, plays on the first entry and never again.
|
|
26
|
+
*
|
|
27
|
+
* ```jsx
|
|
28
|
+
* <LottieInteractions interactions={[lottieInView({ once: true })]}>
|
|
29
|
+
* <Lottie src={anim} autoplay={false} />
|
|
30
|
+
* </LottieInteractions>
|
|
31
|
+
* ```
|
|
32
|
+
*
|
|
33
|
+
* An entry seen while the animation is still loading plays as soon as the
|
|
34
|
+
* load finishes, so an animation already on screen at page load starts by
|
|
35
|
+
* itself.
|
|
36
|
+
*
|
|
37
|
+
* Leaving pauses rather than stops, so coming back resumes mid-motion instead
|
|
38
|
+
* of restarting. The trigger never overrides a load still in flight or a
|
|
39
|
+
* failed one, and it cannot tell its own pause from one a person asked for,
|
|
40
|
+
* so re-entering resumes either.
|
|
41
|
+
*/
|
|
42
|
+
declare function lottieInView(options?: LottieInViewOptions): LottieInteraction;
|
|
43
|
+
//#endregion
|
|
44
|
+
export { LottieInViewOptions, lottieInView };
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { LottieInteraction } from "./types.js";
|
|
2
|
+
//#region src/interactions/lottieInView.d.ts
|
|
3
|
+
/** What {@link lottieInView} can be told. */
|
|
4
|
+
interface LottieInViewOptions {
|
|
5
|
+
/**
|
|
6
|
+
* Play on the first entry and then stop watching for good, so scrolling
|
|
7
|
+
* past again replays nothing. Off unless asked for.
|
|
8
|
+
*/
|
|
9
|
+
once?: boolean;
|
|
10
|
+
/**
|
|
11
|
+
* How much of the animation must be visible to count as entered, `0` to
|
|
12
|
+
* `1`. The default is `0`: a single visible pixel. `1` is accepted and
|
|
13
|
+
* warned about, because an element taller than the viewport can never be
|
|
14
|
+
* entirely visible, so a threshold of one silently never fires for it.
|
|
15
|
+
*/
|
|
16
|
+
amount?: number;
|
|
17
|
+
/**
|
|
18
|
+
* Grows or shrinks the viewport the entry is measured against, in the
|
|
19
|
+
* platform's own `rootMargin` grammar: px or % only.
|
|
20
|
+
*/
|
|
21
|
+
margin?: string;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Plays the animation when it scrolls into view and pauses it when it leaves,
|
|
25
|
+
* or with `once`, plays on the first entry and never again.
|
|
26
|
+
*
|
|
27
|
+
* ```jsx
|
|
28
|
+
* <LottieInteractions interactions={[lottieInView({ once: true })]}>
|
|
29
|
+
* <Lottie src={anim} autoplay={false} />
|
|
30
|
+
* </LottieInteractions>
|
|
31
|
+
* ```
|
|
32
|
+
*
|
|
33
|
+
* An entry seen while the animation is still loading plays as soon as the
|
|
34
|
+
* load finishes, so an animation already on screen at page load starts by
|
|
35
|
+
* itself.
|
|
36
|
+
*
|
|
37
|
+
* Leaving pauses rather than stops, so coming back resumes mid-motion instead
|
|
38
|
+
* of restarting. The trigger never overrides a load still in flight or a
|
|
39
|
+
* failed one, and it cannot tell its own pause from one a person asked for,
|
|
40
|
+
* so re-entering resumes either.
|
|
41
|
+
*/
|
|
42
|
+
declare function lottieInView(options?: LottieInViewOptions): LottieInteraction;
|
|
43
|
+
//#endregion
|
|
44
|
+
export { LottieInViewOptions, lottieInView };
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { LottieState } from "../animation/types.js";
|
|
2
|
+
//#region src/interactions/lottieInView.ts
|
|
3
|
+
function isInViewOptions(value) {
|
|
4
|
+
if (typeof value !== "object" || value === null) return false;
|
|
5
|
+
if ("once" in value && typeof value.once !== "boolean") return false;
|
|
6
|
+
if ("amount" in value && typeof value.amount !== "number") return false;
|
|
7
|
+
return !("margin" in value && typeof value.margin !== "string");
|
|
8
|
+
}
|
|
9
|
+
/** Whether a play command would fight something that outranks it. */
|
|
10
|
+
function playable(state) {
|
|
11
|
+
return state !== LottieState.loading && state !== LottieState.error && state !== LottieState.frozen;
|
|
12
|
+
}
|
|
13
|
+
function attachInView(context, raw) {
|
|
14
|
+
const options = isInViewOptions(raw) ? raw : {};
|
|
15
|
+
let observer = null;
|
|
16
|
+
let observedRoot = null;
|
|
17
|
+
let playedByUs = false;
|
|
18
|
+
let previousState = context.lottie.state;
|
|
19
|
+
let lastIntersecting = null;
|
|
20
|
+
const warnRedundant = () => {
|
|
21
|
+
if (typeof process !== "undefined" && process.env.NODE_ENV !== "production") {
|
|
22
|
+
if (context.memory.warnedRedundant !== true && !playedByUs && context.lottie.state === LottieState.playing) {
|
|
23
|
+
context.memory.warnedRedundant = true;
|
|
24
|
+
console.warn("[lottie-react] an in-view trigger is watching an animation that already plays by itself. With autoplay on, the trigger has nothing left to start; drop one of the two.");
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
const playFromEntry = () => {
|
|
29
|
+
if (options.once === true) {
|
|
30
|
+
context.memory.entered = true;
|
|
31
|
+
observer?.disconnect();
|
|
32
|
+
observer = null;
|
|
33
|
+
}
|
|
34
|
+
playedByUs = true;
|
|
35
|
+
context.lottie.play();
|
|
36
|
+
};
|
|
37
|
+
const handleEntries = (entries) => {
|
|
38
|
+
const entry = entries.at(-1);
|
|
39
|
+
if (entry === void 0) return;
|
|
40
|
+
lastIntersecting = entry.isIntersecting;
|
|
41
|
+
const lottie = context.lottie;
|
|
42
|
+
if (entry.isIntersecting) {
|
|
43
|
+
if (options.once === true && context.memory.entered === true) return;
|
|
44
|
+
if (playable(lottie.state)) playFromEntry();
|
|
45
|
+
} else if (options.once !== true && lottie.state === LottieState.playing) lottie.pause();
|
|
46
|
+
};
|
|
47
|
+
const arm = () => {
|
|
48
|
+
const root = context.lottie.root;
|
|
49
|
+
if (root === observedRoot) return;
|
|
50
|
+
observer?.disconnect();
|
|
51
|
+
observer = null;
|
|
52
|
+
observedRoot = root;
|
|
53
|
+
if (root === null) return;
|
|
54
|
+
if (options.once === true && context.memory.entered === true) return;
|
|
55
|
+
try {
|
|
56
|
+
observer = new IntersectionObserver(handleEntries, {
|
|
57
|
+
threshold: options.amount ?? 0,
|
|
58
|
+
rootMargin: options.margin
|
|
59
|
+
});
|
|
60
|
+
} catch {
|
|
61
|
+
if (typeof process !== "undefined" && process.env.NODE_ENV !== "production") console.warn(`[lottie-react] the margin ${JSON.stringify(options.margin)} was refused, so the trigger watches without it. A margin is written in px or %, the only lengths the platform accepts here.`);
|
|
62
|
+
observer = new IntersectionObserver(handleEntries, { threshold: options.amount ?? 0 });
|
|
63
|
+
}
|
|
64
|
+
observer.observe(root);
|
|
65
|
+
};
|
|
66
|
+
const stopListening = context.onChange(() => {
|
|
67
|
+
const state = context.lottie.state;
|
|
68
|
+
if (previousState === LottieState.loading && state === LottieState.playing) warnRedundant();
|
|
69
|
+
if (previousState === LottieState.loading && lastIntersecting === true && playable(state) && state !== LottieState.playing && !(options.once === true && context.memory.entered === true)) playFromEntry();
|
|
70
|
+
previousState = state;
|
|
71
|
+
arm();
|
|
72
|
+
});
|
|
73
|
+
warnRedundant();
|
|
74
|
+
arm();
|
|
75
|
+
return () => {
|
|
76
|
+
stopListening();
|
|
77
|
+
observer?.disconnect();
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Plays the animation when it scrolls into view and pauses it when it leaves,
|
|
82
|
+
* or with `once`, plays on the first entry and never again.
|
|
83
|
+
*
|
|
84
|
+
* ```jsx
|
|
85
|
+
* <LottieInteractions interactions={[lottieInView({ once: true })]}>
|
|
86
|
+
* <Lottie src={anim} autoplay={false} />
|
|
87
|
+
* </LottieInteractions>
|
|
88
|
+
* ```
|
|
89
|
+
*
|
|
90
|
+
* An entry seen while the animation is still loading plays as soon as the
|
|
91
|
+
* load finishes, so an animation already on screen at page load starts by
|
|
92
|
+
* itself.
|
|
93
|
+
*
|
|
94
|
+
* Leaving pauses rather than stops, so coming back resumes mid-motion instead
|
|
95
|
+
* of restarting. The trigger never overrides a load still in flight or a
|
|
96
|
+
* failed one, and it cannot tell its own pause from one a person asked for,
|
|
97
|
+
* so re-entering resumes either.
|
|
98
|
+
*/
|
|
99
|
+
function lottieInView(options = {}) {
|
|
100
|
+
if (typeof process !== "undefined" && process.env.NODE_ENV !== "production") {
|
|
101
|
+
if (options.amount === 1) console.warn("[lottie-react] amount: 1 never fires for an animation taller than the viewport, because such an element is never entirely visible. Use a smaller amount, or a negative margin for a centre band.");
|
|
102
|
+
}
|
|
103
|
+
return {
|
|
104
|
+
attach: attachInView,
|
|
105
|
+
options
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
//#endregion
|
|
109
|
+
export { lottieInView };
|