@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.
Files changed (154) hide show
  1. package/LICENSE.md +9 -0
  2. package/README.md +4 -10
  3. package/build/_virtual/_rolldown/runtime.cjs +23 -0
  4. package/build/animation/Lottie.cjs +39 -0
  5. package/build/animation/Lottie.d.cts +47 -0
  6. package/build/animation/Lottie.d.ts +47 -0
  7. package/build/animation/Lottie.js +37 -0
  8. package/build/animation/LottieDisplay.cjs +55 -0
  9. package/build/animation/LottieDisplay.d.cts +46 -0
  10. package/build/animation/LottieDisplay.d.ts +46 -0
  11. package/build/animation/LottieDisplay.js +53 -0
  12. package/build/animation/LottieInstanceContext.cjs +16 -0
  13. package/build/animation/LottieInstanceContext.js +17 -0
  14. package/build/animation/LottieLight.cjs +19 -0
  15. package/build/animation/LottieLight.d.cts +23 -0
  16. package/build/animation/LottieLight.d.ts +23 -0
  17. package/build/animation/LottieLight.js +17 -0
  18. package/build/animation/LottieRegistryContext.cjs +36 -0
  19. package/build/animation/LottieRegistryContext.js +35 -0
  20. package/build/animation/LottieSvg.cjs +20 -0
  21. package/build/animation/LottieSvg.d.cts +24 -0
  22. package/build/animation/LottieSvg.d.ts +24 -0
  23. package/build/animation/LottieSvg.js +18 -0
  24. package/build/animation/collectMarkerCrossings.cjs +38 -0
  25. package/build/animation/collectMarkerCrossings.js +38 -0
  26. package/build/animation/createLottieComponent.cjs +131 -0
  27. package/build/animation/createLottieComponent.d.cts +45 -0
  28. package/build/animation/createLottieComponent.d.ts +45 -0
  29. package/build/animation/createLottieComponent.js +131 -0
  30. package/build/animation/hasExpressions.cjs +25 -0
  31. package/build/animation/hasExpressions.js +25 -0
  32. package/build/animation/normalizeAnimationSource.cjs +38 -0
  33. package/build/animation/normalizeAnimationSource.js +38 -0
  34. package/build/animation/polymorphicForwardRef.cjs +18 -0
  35. package/build/animation/polymorphicForwardRef.js +19 -0
  36. package/build/animation/renderStyledElement.cjs +31 -0
  37. package/build/animation/renderStyledElement.js +31 -0
  38. package/build/animation/resolveSeekTarget.cjs +97 -0
  39. package/build/animation/resolveSeekTarget.js +95 -0
  40. package/build/animation/styleLayer.cjs +24 -0
  41. package/build/animation/styleLayer.js +24 -0
  42. package/build/animation/stylePrecedence.cjs +12 -0
  43. package/build/animation/stylePrecedence.js +12 -0
  44. package/build/animation/types.cjs +71 -0
  45. package/build/animation/types.d.cts +461 -0
  46. package/build/animation/types.d.ts +461 -0
  47. package/build/animation/types.js +68 -0
  48. package/build/animation/useLottie.cjs +40 -0
  49. package/build/animation/useLottie.d.cts +36 -0
  50. package/build/animation/useLottie.d.ts +36 -0
  51. package/build/animation/useLottie.js +38 -0
  52. package/build/animation/useLottieAnimation.cjs +434 -0
  53. package/build/animation/useLottieAnimation.d.cts +40 -0
  54. package/build/animation/useLottieAnimation.d.ts +40 -0
  55. package/build/animation/useLottieAnimation.js +434 -0
  56. package/build/animation/useLottieInstance.cjs +20 -0
  57. package/build/animation/useLottieInstance.d.cts +14 -0
  58. package/build/animation/useLottieInstance.d.ts +14 -0
  59. package/build/animation/useLottieInstance.js +20 -0
  60. package/build/animation/useLottieLight.cjs +20 -0
  61. package/build/animation/useLottieLight.d.cts +16 -0
  62. package/build/animation/useLottieLight.d.ts +16 -0
  63. package/build/animation/useLottieLight.js +18 -0
  64. package/build/animation/useLottieSvg.cjs +18 -0
  65. package/build/animation/useLottieSvg.d.cts +14 -0
  66. package/build/animation/useLottieSvg.d.ts +14 -0
  67. package/build/animation/useLottieSvg.js +16 -0
  68. package/build/controls/LottieControls.cjs +180 -0
  69. package/build/controls/LottieControls.d.cts +58 -0
  70. package/build/controls/LottieControls.d.ts +58 -0
  71. package/build/controls/LottieControls.js +178 -0
  72. package/build/controls/LottieDirectionButton.cjs +36 -0
  73. package/build/controls/LottieDirectionButton.js +35 -0
  74. package/build/controls/LottieFullscreenButton.cjs +35 -0
  75. package/build/controls/LottieFullscreenButton.js +34 -0
  76. package/build/controls/LottieLoopButton.cjs +32 -0
  77. package/build/controls/LottieLoopButton.js +31 -0
  78. package/build/controls/LottiePlayButton.cjs +34 -0
  79. package/build/controls/LottiePlayButton.js +33 -0
  80. package/build/controls/LottieReadout.cjs +61 -0
  81. package/build/controls/LottieReadout.d.cts +13 -0
  82. package/build/controls/LottieReadout.d.ts +13 -0
  83. package/build/controls/LottieReadout.js +60 -0
  84. package/build/controls/LottieSeekBar.cjs +87 -0
  85. package/build/controls/LottieSeekBar.js +86 -0
  86. package/build/controls/LottieSpeedSelect.cjs +51 -0
  87. package/build/controls/LottieSpeedSelect.js +50 -0
  88. package/build/controls/LottieStopButton.cjs +29 -0
  89. package/build/controls/LottieStopButton.js +28 -0
  90. package/build/controls/controlIcon.cjs +25 -0
  91. package/build/controls/controlIcon.js +25 -0
  92. package/build/controls/useFullscreen.cjs +46 -0
  93. package/build/controls/useFullscreen.js +46 -0
  94. package/build/controls/useShortcuts.cjs +70 -0
  95. package/build/controls/useShortcuts.js +70 -0
  96. package/build/index.cjs +36 -0
  97. package/build/index.d.cts +19 -0
  98. package/build/index.d.ts +19 -80
  99. package/build/index.js +17 -667
  100. package/build/interactions/LottieInteractions.cjs +41 -0
  101. package/build/interactions/LottieInteractions.d.cts +37 -0
  102. package/build/interactions/LottieInteractions.d.ts +37 -0
  103. package/build/interactions/LottieInteractions.js +41 -0
  104. package/build/interactions/coverProgress.cjs +55 -0
  105. package/build/interactions/coverProgress.js +53 -0
  106. package/build/interactions/lottieInView.cjs +109 -0
  107. package/build/interactions/lottieInView.d.cts +44 -0
  108. package/build/interactions/lottieInView.d.ts +44 -0
  109. package/build/interactions/lottieInView.js +109 -0
  110. package/build/interactions/lottieScrollScrub.cjs +152 -0
  111. package/build/interactions/lottieScrollScrub.d.cts +47 -0
  112. package/build/interactions/lottieScrollScrub.d.ts +47 -0
  113. package/build/interactions/lottieScrollScrub.js +152 -0
  114. package/build/interactions/types.d.cts +46 -0
  115. package/build/interactions/types.d.ts +46 -0
  116. package/build/interactions/useInteractionsRunner.cjs +142 -0
  117. package/build/interactions/useInteractionsRunner.js +141 -0
  118. package/build/interactions/useLottieInteractions.cjs +21 -0
  119. package/build/interactions/useLottieInteractions.d.cts +19 -0
  120. package/build/interactions/useLottieInteractions.d.ts +19 -0
  121. package/build/interactions/useLottieInteractions.js +21 -0
  122. package/build/overlays/LottieError.cjs +74 -0
  123. package/build/overlays/LottieError.d.cts +40 -0
  124. package/build/overlays/LottieError.d.ts +40 -0
  125. package/build/overlays/LottieError.js +72 -0
  126. package/build/overlays/LottieLoading.cjs +89 -0
  127. package/build/overlays/LottieLoading.d.cts +45 -0
  128. package/build/overlays/LottieLoading.d.ts +45 -0
  129. package/build/overlays/LottieLoading.js +87 -0
  130. package/build/overlays/overlayStyles.cjs +33 -0
  131. package/build/overlays/overlayStyles.js +33 -0
  132. package/build/utils/SubscriptionManager.cjs +42 -0
  133. package/build/utils/SubscriptionManager.d.cts +30 -0
  134. package/build/utils/SubscriptionManager.d.ts +30 -0
  135. package/build/utils/SubscriptionManager.js +42 -0
  136. package/build/utils/createLogger.cjs +25 -0
  137. package/build/utils/createLogger.js +25 -0
  138. package/build/utils/isSameJson.cjs +37 -0
  139. package/build/utils/isSameJson.js +37 -0
  140. package/build/utils/mergeRefs.cjs +37 -0
  141. package/build/utils/mergeRefs.js +37 -0
  142. package/build/utils/useStableValue.cjs +26 -0
  143. package/build/utils/useStableValue.js +26 -0
  144. package/changes.json +3 -8
  145. package/package.json +144 -89
  146. package/LICENSE +0 -46
  147. package/build/index.es.js +0 -653
  148. package/build/index.es.js.map +0 -1
  149. package/build/index.es.min.js +0 -3
  150. package/build/index.js.map +0 -1
  151. package/build/index.min.js +0 -3
  152. package/build/index.umd.js +0 -670
  153. package/build/index.umd.js.map +0 -1
  154. package/build/index.umd.min.js +0 -3
@@ -0,0 +1,31 @@
1
+ import { useLottieInstance } from "../animation/useLottieInstance.js";
2
+ import { controlIcon } from "./controlIcon.js";
3
+ import { jsx } from "react/jsx-runtime";
4
+ //#region src/controls/LottieLoopButton.tsx
5
+ /** The class this control carries, which the bar's stylesheet targets. */
6
+ const lottieLoopClass = "lottie-loop";
7
+ const loopPath = "M7 7h10v3l4-4-4-4v3H5v6h2V7zm10 10H7v-3l-4 4 4 4v-3h12v-6h-2v4z";
8
+ /**
9
+ * Turns looping on and off.
10
+ *
11
+ * The switching itself is handed in rather than done here, because the `l`
12
+ * shortcut does the same thing and the count in force has to be remembered
13
+ * across both. Two memories would mean pressing the key and then the button
14
+ * loses a `loop={3}`, which is the exact fault that got the old surface's
15
+ * `toggleLoop` dropped rather than rebuilt.
16
+ */
17
+ function LottieLoopButton({ lottie, toggle, className, ...rest }) {
18
+ const looping = useLottieInstance(lottie).loop !== false;
19
+ return /* @__PURE__ */ jsx("button", {
20
+ "aria-label": "Loop",
21
+ title: "Loop",
22
+ ...rest,
23
+ "aria-pressed": looping,
24
+ className: className ? `${lottieLoopClass} ${className}` : lottieLoopClass,
25
+ onClick: toggle,
26
+ type: "button",
27
+ children: controlIcon(loopPath)
28
+ });
29
+ }
30
+ //#endregion
31
+ export { LottieLoopButton, lottieLoopClass };
@@ -0,0 +1,34 @@
1
+ const require_useLottieInstance = require("../animation/useLottieInstance.cjs");
2
+ const require_types = require("../animation/types.cjs");
3
+ const require_controlIcon = require("./controlIcon.cjs");
4
+ let react_jsx_runtime = require("react/jsx-runtime");
5
+ //#region src/controls/LottiePlayButton.tsx
6
+ /** The class this control carries, which the bar's stylesheet targets. */
7
+ const lottiePlayClass = "lottie-play";
8
+ const playPath = "M8 5v14l11-7z";
9
+ const pausePath = "M6 5h4v14H6zm8 0h4v14h-4z";
10
+ /**
11
+ * Starts the animation, or stops it where it is.
12
+ *
13
+ * One button rather than two, so that pressing it does not unmount the element
14
+ * that has focus. The player this replaces rendered play and pause as separate
15
+ * components in separate positions, which dropped focus to the document body
16
+ * every time someone pressed either with the keyboard.
17
+ */
18
+ function LottiePlayButton({ lottie, className, ...rest }) {
19
+ const instance = require_useLottieInstance.useLottieInstance(lottie);
20
+ const playing = instance.state === require_types.LottieState.playing;
21
+ const label = playing ? "Pause" : "Play";
22
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
23
+ "aria-label": label,
24
+ title: label,
25
+ ...rest,
26
+ className: className ? `${lottiePlayClass} ${className}` : lottiePlayClass,
27
+ onClick: playing ? instance.pause : instance.play,
28
+ type: "button",
29
+ children: require_controlIcon.controlIcon(playing ? pausePath : playPath)
30
+ });
31
+ }
32
+ //#endregion
33
+ exports.LottiePlayButton = LottiePlayButton;
34
+ exports.lottiePlayClass = lottiePlayClass;
@@ -0,0 +1,33 @@
1
+ import { useLottieInstance } from "../animation/useLottieInstance.js";
2
+ import { LottieState } from "../animation/types.js";
3
+ import { controlIcon } from "./controlIcon.js";
4
+ import { jsx } from "react/jsx-runtime";
5
+ //#region src/controls/LottiePlayButton.tsx
6
+ /** The class this control carries, which the bar's stylesheet targets. */
7
+ const lottiePlayClass = "lottie-play";
8
+ const playPath = "M8 5v14l11-7z";
9
+ const pausePath = "M6 5h4v14H6zm8 0h4v14h-4z";
10
+ /**
11
+ * Starts the animation, or stops it where it is.
12
+ *
13
+ * One button rather than two, so that pressing it does not unmount the element
14
+ * that has focus. The player this replaces rendered play and pause as separate
15
+ * components in separate positions, which dropped focus to the document body
16
+ * every time someone pressed either with the keyboard.
17
+ */
18
+ function LottiePlayButton({ lottie, className, ...rest }) {
19
+ const instance = useLottieInstance(lottie);
20
+ const playing = instance.state === LottieState.playing;
21
+ const label = playing ? "Pause" : "Play";
22
+ return /* @__PURE__ */ jsx("button", {
23
+ "aria-label": label,
24
+ title: label,
25
+ ...rest,
26
+ className: className ? `${lottiePlayClass} ${className}` : lottiePlayClass,
27
+ onClick: playing ? instance.pause : instance.play,
28
+ type: "button",
29
+ children: controlIcon(playing ? pausePath : playPath)
30
+ });
31
+ }
32
+ //#endregion
33
+ export { LottiePlayButton, lottiePlayClass };
@@ -0,0 +1,61 @@
1
+ const require_useLottieInstance = require("../animation/useLottieInstance.cjs");
2
+ const require_types = require("../animation/types.cjs");
3
+ let react = require("react");
4
+ let react_jsx_runtime = require("react/jsx-runtime");
5
+ //#region src/controls/LottieReadout.tsx
6
+ /** The class this control carries, which the bar's stylesheet targets. */
7
+ const lottieReadoutClass = "lottie-readout";
8
+ /**
9
+ * One position, in whichever unit was asked for.
10
+ *
11
+ * Seconds carry one decimal rather than the `0:04` a video player would use.
12
+ * Most animations are a few seconds long, so minutes are always zero and the
13
+ * seconds place is the only one doing any work, which makes dragging look like
14
+ * it is doing nothing.
15
+ */
16
+ function format(frames, secondsPerFrame, unit) {
17
+ return unit === "seconds" ? `${(frames * secondsPerFrame).toFixed(1)}s` : String(Math.round(frames));
18
+ }
19
+ /**
20
+ * Where the playhead is, and how far it has to go.
21
+ *
22
+ * Both numbers describe what is currently playable rather than the whole file,
23
+ * so a segment moves them together. With nothing loaded they are zeros, which
24
+ * keeps the element the same shape it will be a moment later.
25
+ *
26
+ * Like the seek bar, the moving half is written straight onto the element rather
27
+ * than held in state, because it changes on every rendered frame.
28
+ */
29
+ function LottieReadout({ lottie, unit = "frames", className, ...rest }) {
30
+ const { subscribe, playableFrames, playableDuration, animationItem } = require_useLottieInstance.useLottieInstance(lottie);
31
+ const element = (0, react.useRef)(null);
32
+ const secondsPerFrame = playableFrames === 0 ? 0 : playableDuration / playableFrames;
33
+ (0, react.useEffect)(() => {
34
+ const write = (frame) => {
35
+ const node = element.current;
36
+ if (node !== null) node.textContent = format(frame, secondsPerFrame, unit);
37
+ };
38
+ write(animationItem === null ? 0 : animationItem.currentFrame);
39
+ return subscribe(require_types.LottieSubscription.frame, ({ currentFrame }) => {
40
+ write(currentFrame);
41
+ });
42
+ }, [
43
+ subscribe,
44
+ animationItem,
45
+ secondsPerFrame,
46
+ unit
47
+ ]);
48
+ const total = format(Math.max(playableFrames - 1, 0), secondsPerFrame, unit);
49
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("output", {
50
+ ...rest,
51
+ className: className ? `${lottieReadoutClass} ${className}` : lottieReadoutClass,
52
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
53
+ ref: element,
54
+ style: { minWidth: `${String(total.length)}ch` },
55
+ children: format(0, secondsPerFrame, unit)
56
+ }), ` / ${total}`]
57
+ });
58
+ }
59
+ //#endregion
60
+ exports.LottieReadout = LottieReadout;
61
+ exports.lottieReadoutClass = lottieReadoutClass;
@@ -0,0 +1,13 @@
1
+ import "../animation/types.cjs";
2
+ //#region src/controls/LottieReadout.d.ts
3
+ /**
4
+ * What the position is counted in.
5
+ *
6
+ * A plain union rather than an object map, unlike the library's public
7
+ * vocabulary, because nothing reads it at runtime: it is only ever written as a
8
+ * literal at a call site, so a runtime object would ship to every consumer of
9
+ * the bar in order to serve nobody.
10
+ */
11
+ type LottieReadoutUnit = "frames" | "seconds";
12
+ //#endregion
13
+ export { LottieReadoutUnit };
@@ -0,0 +1,13 @@
1
+ import "../animation/types.js";
2
+ //#region src/controls/LottieReadout.d.ts
3
+ /**
4
+ * What the position is counted in.
5
+ *
6
+ * A plain union rather than an object map, unlike the library's public
7
+ * vocabulary, because nothing reads it at runtime: it is only ever written as a
8
+ * literal at a call site, so a runtime object would ship to every consumer of
9
+ * the bar in order to serve nobody.
10
+ */
11
+ type LottieReadoutUnit = "frames" | "seconds";
12
+ //#endregion
13
+ export { LottieReadoutUnit };
@@ -0,0 +1,60 @@
1
+ import { useLottieInstance } from "../animation/useLottieInstance.js";
2
+ import { LottieSubscription } from "../animation/types.js";
3
+ import { useEffect, useRef } from "react";
4
+ import { jsx, jsxs } from "react/jsx-runtime";
5
+ //#region src/controls/LottieReadout.tsx
6
+ /** The class this control carries, which the bar's stylesheet targets. */
7
+ const lottieReadoutClass = "lottie-readout";
8
+ /**
9
+ * One position, in whichever unit was asked for.
10
+ *
11
+ * Seconds carry one decimal rather than the `0:04` a video player would use.
12
+ * Most animations are a few seconds long, so minutes are always zero and the
13
+ * seconds place is the only one doing any work, which makes dragging look like
14
+ * it is doing nothing.
15
+ */
16
+ function format(frames, secondsPerFrame, unit) {
17
+ return unit === "seconds" ? `${(frames * secondsPerFrame).toFixed(1)}s` : String(Math.round(frames));
18
+ }
19
+ /**
20
+ * Where the playhead is, and how far it has to go.
21
+ *
22
+ * Both numbers describe what is currently playable rather than the whole file,
23
+ * so a segment moves them together. With nothing loaded they are zeros, which
24
+ * keeps the element the same shape it will be a moment later.
25
+ *
26
+ * Like the seek bar, the moving half is written straight onto the element rather
27
+ * than held in state, because it changes on every rendered frame.
28
+ */
29
+ function LottieReadout({ lottie, unit = "frames", className, ...rest }) {
30
+ const { subscribe, playableFrames, playableDuration, animationItem } = useLottieInstance(lottie);
31
+ const element = useRef(null);
32
+ const secondsPerFrame = playableFrames === 0 ? 0 : playableDuration / playableFrames;
33
+ useEffect(() => {
34
+ const write = (frame) => {
35
+ const node = element.current;
36
+ if (node !== null) node.textContent = format(frame, secondsPerFrame, unit);
37
+ };
38
+ write(animationItem === null ? 0 : animationItem.currentFrame);
39
+ return subscribe(LottieSubscription.frame, ({ currentFrame }) => {
40
+ write(currentFrame);
41
+ });
42
+ }, [
43
+ subscribe,
44
+ animationItem,
45
+ secondsPerFrame,
46
+ unit
47
+ ]);
48
+ const total = format(Math.max(playableFrames - 1, 0), secondsPerFrame, unit);
49
+ return /* @__PURE__ */ jsxs("output", {
50
+ ...rest,
51
+ className: className ? `${lottieReadoutClass} ${className}` : lottieReadoutClass,
52
+ children: [/* @__PURE__ */ jsx("span", {
53
+ ref: element,
54
+ style: { minWidth: `${String(total.length)}ch` },
55
+ children: format(0, secondsPerFrame, unit)
56
+ }), ` / ${total}`]
57
+ });
58
+ }
59
+ //#endregion
60
+ export { LottieReadout, lottieReadoutClass };
@@ -0,0 +1,87 @@
1
+ const require_useLottieInstance = require("../animation/useLottieInstance.cjs");
2
+ const require_types = require("../animation/types.cjs");
3
+ let react = require("react");
4
+ let react_jsx_runtime = require("react/jsx-runtime");
5
+ //#region src/controls/LottieSeekBar.tsx
6
+ /** The class this control carries, which the bar's stylesheet targets. */
7
+ const lottieSeekClass = "lottie-seek";
8
+ /**
9
+ * Shows where the playhead is, and moves it.
10
+ *
11
+ * A native range input, so the browser turns a frame number into a position on
12
+ * the track and nothing here computes geometry. That also means the element
13
+ * reports its own value to assistive technology, which is why no `aria-valuenow`
14
+ * is written: one hardcoded here is exactly the defect the old player shipped,
15
+ * where a screen reader was told the position was zero forever.
16
+ *
17
+ * The position is written straight onto the element rather than held in state,
18
+ * because it changes on every rendered frame and this component would otherwise
19
+ * re-render sixty times a second on top of the animation's own work. The input
20
+ * is uncontrolled, which is what stops React putting its own value back.
21
+ */
22
+ function LottieSeekBar({ lottie, className, ...rest }) {
23
+ const instance = require_useLottieInstance.useLottieInstance(lottie);
24
+ const { subscribe, playableFrames, animationItem } = instance;
25
+ const element = (0, react.useRef)(null);
26
+ const dragging = (0, react.useRef)(false);
27
+ const stopWatching = (0, react.useRef)(() => void 0);
28
+ (0, react.useEffect)(() => () => {
29
+ stopWatching.current();
30
+ }, []);
31
+ (0, react.useEffect)(() => {
32
+ const write = (frame) => {
33
+ const node = element.current;
34
+ if (node !== null && !dragging.current) node.value = String(frame);
35
+ };
36
+ write(animationItem === null ? 0 : animationItem.currentFrame);
37
+ return subscribe(require_types.LottieSubscription.frame, ({ currentFrame }) => {
38
+ write(currentFrame);
39
+ });
40
+ }, [subscribe, animationItem]);
41
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
42
+ "aria-label": "Seek",
43
+ title: "Seek",
44
+ ...rest,
45
+ className: className ? `${lottieSeekClass} ${className}` : lottieSeekClass,
46
+ defaultValue: 0,
47
+ max: Math.max(playableFrames - 1, 0),
48
+ min: 0,
49
+ onChange: (event) => {
50
+ const frame = Number(event.target.value);
51
+ if (dragging.current) instance.scrubTo(frame);
52
+ else instance.seek(frame);
53
+ },
54
+ onKeyDown: (event) => {
55
+ const forward = event.key === "ArrowRight" || event.key === "ArrowUp";
56
+ const back = event.key === "ArrowLeft" || event.key === "ArrowDown";
57
+ if (!forward && !back) return;
58
+ event.preventDefault();
59
+ instance.pause();
60
+ const node = element.current;
61
+ const from = node === null ? 0 : Number(node.value);
62
+ instance.seek(forward ? Math.floor(from) + 1 : Math.ceil(from) - 1);
63
+ },
64
+ onPointerDown: () => {
65
+ dragging.current = true;
66
+ instance.scrubStart();
67
+ const end = () => {
68
+ stopWatching.current();
69
+ dragging.current = false;
70
+ instance.scrubEnd();
71
+ };
72
+ stopWatching.current = () => {
73
+ stopWatching.current = () => void 0;
74
+ window.removeEventListener("pointerup", end);
75
+ window.removeEventListener("pointercancel", end);
76
+ };
77
+ window.addEventListener("pointerup", end);
78
+ window.addEventListener("pointercancel", end);
79
+ },
80
+ ref: element,
81
+ step: "any",
82
+ type: "range"
83
+ });
84
+ }
85
+ //#endregion
86
+ exports.LottieSeekBar = LottieSeekBar;
87
+ exports.lottieSeekClass = lottieSeekClass;
@@ -0,0 +1,86 @@
1
+ import { useLottieInstance } from "../animation/useLottieInstance.js";
2
+ import { LottieSubscription } from "../animation/types.js";
3
+ import { useEffect, useRef } from "react";
4
+ import { jsx } from "react/jsx-runtime";
5
+ //#region src/controls/LottieSeekBar.tsx
6
+ /** The class this control carries, which the bar's stylesheet targets. */
7
+ const lottieSeekClass = "lottie-seek";
8
+ /**
9
+ * Shows where the playhead is, and moves it.
10
+ *
11
+ * A native range input, so the browser turns a frame number into a position on
12
+ * the track and nothing here computes geometry. That also means the element
13
+ * reports its own value to assistive technology, which is why no `aria-valuenow`
14
+ * is written: one hardcoded here is exactly the defect the old player shipped,
15
+ * where a screen reader was told the position was zero forever.
16
+ *
17
+ * The position is written straight onto the element rather than held in state,
18
+ * because it changes on every rendered frame and this component would otherwise
19
+ * re-render sixty times a second on top of the animation's own work. The input
20
+ * is uncontrolled, which is what stops React putting its own value back.
21
+ */
22
+ function LottieSeekBar({ lottie, className, ...rest }) {
23
+ const instance = useLottieInstance(lottie);
24
+ const { subscribe, playableFrames, animationItem } = instance;
25
+ const element = useRef(null);
26
+ const dragging = useRef(false);
27
+ const stopWatching = useRef(() => void 0);
28
+ useEffect(() => () => {
29
+ stopWatching.current();
30
+ }, []);
31
+ useEffect(() => {
32
+ const write = (frame) => {
33
+ const node = element.current;
34
+ if (node !== null && !dragging.current) node.value = String(frame);
35
+ };
36
+ write(animationItem === null ? 0 : animationItem.currentFrame);
37
+ return subscribe(LottieSubscription.frame, ({ currentFrame }) => {
38
+ write(currentFrame);
39
+ });
40
+ }, [subscribe, animationItem]);
41
+ return /* @__PURE__ */ jsx("input", {
42
+ "aria-label": "Seek",
43
+ title: "Seek",
44
+ ...rest,
45
+ className: className ? `${lottieSeekClass} ${className}` : lottieSeekClass,
46
+ defaultValue: 0,
47
+ max: Math.max(playableFrames - 1, 0),
48
+ min: 0,
49
+ onChange: (event) => {
50
+ const frame = Number(event.target.value);
51
+ if (dragging.current) instance.scrubTo(frame);
52
+ else instance.seek(frame);
53
+ },
54
+ onKeyDown: (event) => {
55
+ const forward = event.key === "ArrowRight" || event.key === "ArrowUp";
56
+ const back = event.key === "ArrowLeft" || event.key === "ArrowDown";
57
+ if (!forward && !back) return;
58
+ event.preventDefault();
59
+ instance.pause();
60
+ const node = element.current;
61
+ const from = node === null ? 0 : Number(node.value);
62
+ instance.seek(forward ? Math.floor(from) + 1 : Math.ceil(from) - 1);
63
+ },
64
+ onPointerDown: () => {
65
+ dragging.current = true;
66
+ instance.scrubStart();
67
+ const end = () => {
68
+ stopWatching.current();
69
+ dragging.current = false;
70
+ instance.scrubEnd();
71
+ };
72
+ stopWatching.current = () => {
73
+ stopWatching.current = () => void 0;
74
+ window.removeEventListener("pointerup", end);
75
+ window.removeEventListener("pointercancel", end);
76
+ };
77
+ window.addEventListener("pointerup", end);
78
+ window.addEventListener("pointercancel", end);
79
+ },
80
+ ref: element,
81
+ step: "any",
82
+ type: "range"
83
+ });
84
+ }
85
+ //#endregion
86
+ export { LottieSeekBar, lottieSeekClass };
@@ -0,0 +1,51 @@
1
+ const require_useLottieInstance = require("../animation/useLottieInstance.cjs");
2
+ let react_jsx_runtime = require("react/jsx-runtime");
3
+ //#region src/controls/LottieSpeedSelect.tsx
4
+ /** The class this control carries, which the bar's stylesheet targets. */
5
+ const lottieSpeedClass = "lottie-speed";
6
+ /** The rates offered, slow ones included because inspecting a file needs them. */
7
+ const rates = [
8
+ .25,
9
+ .5,
10
+ .75,
11
+ 1,
12
+ 1.25,
13
+ 1.5,
14
+ 2
15
+ ];
16
+ /**
17
+ * Chooses how fast the animation plays.
18
+ *
19
+ * A native `<select>`, which is what makes this control affordable at all. The
20
+ * player this replaces built a custom dropdown whose options stayed in the
21
+ * document when it was closed, so every animation on a page added seven
22
+ * invisible tab stops, and it carried none of the menu semantics that would have
23
+ * made a custom one usable. The native element has one tab stop and needs no
24
+ * semantics of ours.
25
+ *
26
+ * A rate set from somewhere else, a prop or `setSpeed`, is added to the list
27
+ * rather than ignored, so the control never sits blank or reports a rate the
28
+ * animation is not playing at.
29
+ */
30
+ function LottieSpeedSelect({ lottie, className, ...rest }) {
31
+ const instance = require_useLottieInstance.useLottieInstance(lottie);
32
+ const { speed } = instance;
33
+ const offered = rates.includes(speed) ? rates : [...rates, speed].sort((first, second) => first - second);
34
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("select", {
35
+ "aria-label": "Playback speed",
36
+ title: "Playback speed",
37
+ ...rest,
38
+ className: className ? `${lottieSpeedClass} ${className}` : lottieSpeedClass,
39
+ onChange: (event) => {
40
+ instance.setSpeed(Number(event.target.value));
41
+ },
42
+ value: String(speed),
43
+ children: offered.map((rate) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("option", {
44
+ value: String(rate),
45
+ children: [rate, "x"]
46
+ }, rate))
47
+ });
48
+ }
49
+ //#endregion
50
+ exports.LottieSpeedSelect = LottieSpeedSelect;
51
+ exports.lottieSpeedClass = lottieSpeedClass;
@@ -0,0 +1,50 @@
1
+ import { useLottieInstance } from "../animation/useLottieInstance.js";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ //#region src/controls/LottieSpeedSelect.tsx
4
+ /** The class this control carries, which the bar's stylesheet targets. */
5
+ const lottieSpeedClass = "lottie-speed";
6
+ /** The rates offered, slow ones included because inspecting a file needs them. */
7
+ const rates = [
8
+ .25,
9
+ .5,
10
+ .75,
11
+ 1,
12
+ 1.25,
13
+ 1.5,
14
+ 2
15
+ ];
16
+ /**
17
+ * Chooses how fast the animation plays.
18
+ *
19
+ * A native `<select>`, which is what makes this control affordable at all. The
20
+ * player this replaces built a custom dropdown whose options stayed in the
21
+ * document when it was closed, so every animation on a page added seven
22
+ * invisible tab stops, and it carried none of the menu semantics that would have
23
+ * made a custom one usable. The native element has one tab stop and needs no
24
+ * semantics of ours.
25
+ *
26
+ * A rate set from somewhere else, a prop or `setSpeed`, is added to the list
27
+ * rather than ignored, so the control never sits blank or reports a rate the
28
+ * animation is not playing at.
29
+ */
30
+ function LottieSpeedSelect({ lottie, className, ...rest }) {
31
+ const instance = useLottieInstance(lottie);
32
+ const { speed } = instance;
33
+ const offered = rates.includes(speed) ? rates : [...rates, speed].sort((first, second) => first - second);
34
+ return /* @__PURE__ */ jsx("select", {
35
+ "aria-label": "Playback speed",
36
+ title: "Playback speed",
37
+ ...rest,
38
+ className: className ? `${lottieSpeedClass} ${className}` : lottieSpeedClass,
39
+ onChange: (event) => {
40
+ instance.setSpeed(Number(event.target.value));
41
+ },
42
+ value: String(speed),
43
+ children: offered.map((rate) => /* @__PURE__ */ jsxs("option", {
44
+ value: String(rate),
45
+ children: [rate, "x"]
46
+ }, rate))
47
+ });
48
+ }
49
+ //#endregion
50
+ export { LottieSpeedSelect, lottieSpeedClass };
@@ -0,0 +1,29 @@
1
+ const require_useLottieInstance = require("../animation/useLottieInstance.cjs");
2
+ const require_controlIcon = require("./controlIcon.cjs");
3
+ let react_jsx_runtime = require("react/jsx-runtime");
4
+ //#region src/controls/LottieStopButton.tsx
5
+ /** The class this control carries, which the bar's stylesheet targets. */
6
+ const lottieStopClass = "lottie-stop";
7
+ const stopPath = "M6 6h12v12H6z";
8
+ /**
9
+ * Stops the animation and returns it to the first frame of what is playable.
10
+ *
11
+ * Distinct from pausing, which leaves the playhead where it is. Both exist
12
+ * because this control set is for inspecting a file, where returning to a known
13
+ * position is something you do constantly.
14
+ */
15
+ function LottieStopButton({ lottie, className, ...rest }) {
16
+ const instance = require_useLottieInstance.useLottieInstance(lottie);
17
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
18
+ "aria-label": "Stop",
19
+ title: "Stop",
20
+ ...rest,
21
+ className: className ? `${lottieStopClass} ${className}` : lottieStopClass,
22
+ onClick: instance.stop,
23
+ type: "button",
24
+ children: require_controlIcon.controlIcon(stopPath)
25
+ });
26
+ }
27
+ //#endregion
28
+ exports.LottieStopButton = LottieStopButton;
29
+ exports.lottieStopClass = lottieStopClass;
@@ -0,0 +1,28 @@
1
+ import { useLottieInstance } from "../animation/useLottieInstance.js";
2
+ import { controlIcon } from "./controlIcon.js";
3
+ import { jsx } from "react/jsx-runtime";
4
+ //#region src/controls/LottieStopButton.tsx
5
+ /** The class this control carries, which the bar's stylesheet targets. */
6
+ const lottieStopClass = "lottie-stop";
7
+ const stopPath = "M6 6h12v12H6z";
8
+ /**
9
+ * Stops the animation and returns it to the first frame of what is playable.
10
+ *
11
+ * Distinct from pausing, which leaves the playhead where it is. Both exist
12
+ * because this control set is for inspecting a file, where returning to a known
13
+ * position is something you do constantly.
14
+ */
15
+ function LottieStopButton({ lottie, className, ...rest }) {
16
+ const instance = useLottieInstance(lottie);
17
+ return /* @__PURE__ */ jsx("button", {
18
+ "aria-label": "Stop",
19
+ title: "Stop",
20
+ ...rest,
21
+ className: className ? `${lottieStopClass} ${className}` : lottieStopClass,
22
+ onClick: instance.stop,
23
+ type: "button",
24
+ children: controlIcon(stopPath)
25
+ });
26
+ }
27
+ //#endregion
28
+ export { LottieStopButton, lottieStopClass };
@@ -0,0 +1,25 @@
1
+ let react_jsx_runtime = require("react/jsx-runtime");
2
+ //#region src/controls/controlIcon.tsx
3
+ /**
4
+ * One control's icon, drawn from a single path on a 24 unit grid.
5
+ *
6
+ * Every icon in the bar is one shape, filled in `currentColor` so it takes the
7
+ * button's own colour, and hidden from assistive technology because the button
8
+ * already carries a label. Sharing the wrapper rather than repeating it is worth
9
+ * doing here: in the player this replaces, the identical `<svg>` opening tag was
10
+ * about two thirds of every icon's source.
11
+ *
12
+ * A function rather than a component, because nothing needs it to be one: it has
13
+ * no state, takes no children, and adding a component boundary would put a node
14
+ * in the tree for React to reconcile on every render of the bar.
15
+ */
16
+ function controlIcon(path) {
17
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
18
+ viewBox: "0 0 24 24",
19
+ fill: "currentColor",
20
+ "aria-hidden": "true",
21
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: path })
22
+ });
23
+ }
24
+ //#endregion
25
+ exports.controlIcon = controlIcon;
@@ -0,0 +1,25 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ //#region src/controls/controlIcon.tsx
3
+ /**
4
+ * One control's icon, drawn from a single path on a 24 unit grid.
5
+ *
6
+ * Every icon in the bar is one shape, filled in `currentColor` so it takes the
7
+ * button's own colour, and hidden from assistive technology because the button
8
+ * already carries a label. Sharing the wrapper rather than repeating it is worth
9
+ * doing here: in the player this replaces, the identical `<svg>` opening tag was
10
+ * about two thirds of every icon's source.
11
+ *
12
+ * A function rather than a component, because nothing needs it to be one: it has
13
+ * no state, takes no children, and adding a component boundary would put a node
14
+ * in the tree for React to reconcile on every render of the bar.
15
+ */
16
+ function controlIcon(path) {
17
+ return /* @__PURE__ */ jsx("svg", {
18
+ viewBox: "0 0 24 24",
19
+ fill: "currentColor",
20
+ "aria-hidden": "true",
21
+ children: /* @__PURE__ */ jsx("path", { d: path })
22
+ });
23
+ }
24
+ //#endregion
25
+ export { controlIcon };