@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,87 @@
1
+ import { renderStyledElement } from "../animation/renderStyledElement.js";
2
+ import { useLottieInstance } from "../animation/useLottieInstance.js";
3
+ import { LottieState } from "../animation/types.js";
4
+ import { overlayStyles } from "./overlayStyles.js";
5
+ import { forwardRef } from "react";
6
+ import { jsx } from "react/jsx-runtime";
7
+ //#region src/overlays/LottieLoading.tsx
8
+ /**
9
+ * The class the overlay carries, and the name React deduplicates its stylesheet
10
+ * by. One string does both, so two components can only collide in the document
11
+ * if they already collide in CSS.
12
+ */
13
+ const lottieLoadingClass = "lottie-loading";
14
+ /** The class the built-in indicator carries. */
15
+ const spinnerClass = "lottie-spinner";
16
+ const spinKeyframes = "lottie-spin";
17
+ const loadingInKeyframes = "lottie-loading-in";
18
+ /** The two knobs a consumer's stylesheet can set. `showAfter` writes the first. */
19
+ const delayProperty = "--lottie-loading-delay";
20
+ /**
21
+ * The overlay's own defaults, at zero specificity and inside the library's
22
+ * cascade layer, so that any rule the consumer
23
+ * writes beats them per property.
24
+ *
25
+ * The indicator is drawn in `currentColor` and sized in `em`, so it takes the
26
+ * surrounding text's colour and size rather than any this library picked.
27
+ *
28
+ * Three of these are load-bearing.
29
+ *
30
+ * The wait is expressed as a fade **in** from a keyframe, never as a hidden
31
+ * element the animation reveals. The two look equivalent and are not: with the
32
+ * element hidden by its own rule, anything that switches the animation off
33
+ * leaves it hidden for good, while written this way the same switch shows it
34
+ * immediately, which is the right way round for an indicator.
35
+ *
36
+ * Both durations read a custom property with the default in the fallback, which
37
+ * is what lets a stylesheet change either one, at any level from the element to
38
+ * the document. `showAfter` sets the same property, so the prop and the CSS are
39
+ * one mechanism rather than two that can disagree.
40
+ *
41
+ * Under a reduced-motion preference the indicator is **slowed rather than
42
+ * stopped**, because the preference asks for less motion and a stationary
43
+ * indicator no longer says the page is working.
44
+ */
45
+ const lottieLoadingStyles = `${overlayStyles(lottieLoadingClass)}:where(.${lottieLoadingClass}) > :where(.${spinnerClass}){box-sizing:border-box;width:2em;height:2em;border:0.15em solid currentColor;border-top-color:transparent;border-radius:50%;animation-name:${spinKeyframes};animation-duration:0.8s;animation-timing-function:linear;animation-iteration-count:infinite}:where(.${lottieLoadingClass}){animation-name:${loadingInKeyframes};animation-duration:var(--lottie-loading-fade,150ms);animation-delay:var(${delayProperty},400ms);animation-fill-mode:both}@media (prefers-reduced-motion:reduce){:where(.${lottieLoadingClass}) > :where(.${spinnerClass}){animation-duration:1.6s}}@keyframes ${spinKeyframes}{to{transform:rotate(360deg)}}@keyframes ${loadingInKeyframes}{from{opacity:0}}`;
46
+ /**
47
+ * What to show while the animation loads.
48
+ *
49
+ * Render it among the children of a component that publishes an animation, or
50
+ * anywhere at all with the result of `useLottie`. It covers the box it sits in
51
+ * while the animation is loading and renders nothing the rest of the time.
52
+ *
53
+ * ```jsx
54
+ * <Lottie src="/hero.json">
55
+ * <LottieDisplay />
56
+ * <LottieLoading />
57
+ * </Lottie>
58
+ * ```
59
+ *
60
+ * It takes every attribute of the `div` it renders, and `ref` names that same
61
+ * element. Its own rules are all zero-specificity, so any of them can be
62
+ * replaced one property at a time from your own stylesheet. If your CSS lives
63
+ * in cascade layers, declare `@layer lottie-react;` before your own styles so
64
+ * the library's layer ranks below them.
65
+ */
66
+ const LottieLoading = forwardRef(function LottieLoading({ lottie, className, children, showAfter, style, ...rest }, ref) {
67
+ const { state } = useLottieInstance(lottie);
68
+ if (state !== LottieState.loading) return null;
69
+ return renderStyledElement({
70
+ tag: "div",
71
+ styleClass: lottieLoadingClass,
72
+ styles: lottieLoadingStyles,
73
+ className,
74
+ attributes: {
75
+ role: "status",
76
+ ...rest,
77
+ style: showAfter === void 0 ? style : {
78
+ [delayProperty]: `${String(showAfter)}ms`,
79
+ ...style
80
+ }
81
+ },
82
+ ref,
83
+ children: children ?? /* @__PURE__ */ jsx("div", { className: spinnerClass })
84
+ });
85
+ });
86
+ //#endregion
87
+ export { LottieLoading, lottieLoadingClass, lottieLoadingStyles };
@@ -0,0 +1,33 @@
1
+ //#region src/overlays/overlayStyles.ts
2
+ /**
3
+ * The rules that put an overlay over the animation, scoped to the class it is
4
+ * given.
5
+ *
6
+ * Both overlays cover the same box in the same way, and each still ships its
7
+ * own copy under its own name, because the class and the stylesheet's `href`
8
+ * are one string. Sharing the class instead would mean two names on one element
9
+ * and a second stylesheet to order against the first.
10
+ *
11
+ * The overlay anchors to whichever ancestor is positioned, which is the element
12
+ * `<Lottie>` renders around its children.
13
+ *
14
+ * Three details are not free choices. The four edges are written out rather than
15
+ * as `inset`, because the test environment does not expand that shorthand, so a
16
+ * rule written with it could never be shown to apply. And `z-index` is what
17
+ * decides the overlay wins against the animation whichever order the two are
18
+ * written in, since without it a display rendered afterwards paints on top.
19
+ *
20
+ * The third is the background. An overlay spans everything the animation's box
21
+ * holds, the control bar included, so with no background of its own the buttons
22
+ * and the seek bar read straight through the message it is there to show. It is
23
+ * mixed from `Canvas`, the system colour for page background, rather than from
24
+ * `currentColor`, because a scrim has to move towards the surface behind it and
25
+ * `currentColor` is the text, which would lighten the overlay on a dark page and
26
+ * darken it on a light one. Partly transparent, so what is underneath stays
27
+ * visible as context rather than disappearing.
28
+ */
29
+ function overlayStyles(styleClass) {
30
+ return `:where(.${styleClass}){position:absolute;top:0;right:0;bottom:0;left:0;z-index:1;display:flex;align-items:center;justify-content:center;background:color-mix(in srgb,Canvas 80%,transparent)}`;
31
+ }
32
+ //#endregion
33
+ exports.overlayStyles = overlayStyles;
@@ -0,0 +1,33 @@
1
+ //#region src/overlays/overlayStyles.ts
2
+ /**
3
+ * The rules that put an overlay over the animation, scoped to the class it is
4
+ * given.
5
+ *
6
+ * Both overlays cover the same box in the same way, and each still ships its
7
+ * own copy under its own name, because the class and the stylesheet's `href`
8
+ * are one string. Sharing the class instead would mean two names on one element
9
+ * and a second stylesheet to order against the first.
10
+ *
11
+ * The overlay anchors to whichever ancestor is positioned, which is the element
12
+ * `<Lottie>` renders around its children.
13
+ *
14
+ * Three details are not free choices. The four edges are written out rather than
15
+ * as `inset`, because the test environment does not expand that shorthand, so a
16
+ * rule written with it could never be shown to apply. And `z-index` is what
17
+ * decides the overlay wins against the animation whichever order the two are
18
+ * written in, since without it a display rendered afterwards paints on top.
19
+ *
20
+ * The third is the background. An overlay spans everything the animation's box
21
+ * holds, the control bar included, so with no background of its own the buttons
22
+ * and the seek bar read straight through the message it is there to show. It is
23
+ * mixed from `Canvas`, the system colour for page background, rather than from
24
+ * `currentColor`, because a scrim has to move towards the surface behind it and
25
+ * `currentColor` is the text, which would lighten the overlay on a dark page and
26
+ * darken it on a light one. Partly transparent, so what is underneath stays
27
+ * visible as context rather than disappearing.
28
+ */
29
+ function overlayStyles(styleClass) {
30
+ return `:where(.${styleClass}){position:absolute;top:0;right:0;bottom:0;left:0;z-index:1;display:flex;align-items:center;justify-content:center;background:color-mix(in srgb,Canvas 80%,transparent)}`;
31
+ }
32
+ //#endregion
33
+ export { overlayStyles };
@@ -0,0 +1,42 @@
1
+ //#region src/utils/SubscriptionManager.ts
2
+ /**
3
+ * A typed event emitter, small enough to avoid a dependency and precise enough
4
+ * that a wrong payload is a compile error rather than a runtime surprise.
5
+ *
6
+ * The map it is given must be declared as a `type` rather than an `interface`,
7
+ * because an interface has no implicit index signature and cannot satisfy the
8
+ * constraint above.
9
+ *
10
+ * Both methods are fields rather than prototype methods so they can be handed
11
+ * out on their own, which is how `subscribe` reaches a consumer.
12
+ */
13
+ var SubscriptionManager = class {
14
+ listeners = {};
15
+ /** Registers a handler and returns the function that removes it. */
16
+ subscribe = (type, handler) => {
17
+ let handlers = this.listeners[type];
18
+ if (!handlers) {
19
+ handlers = /* @__PURE__ */ new Set();
20
+ this.listeners[type] = handlers;
21
+ }
22
+ handlers.add(handler);
23
+ return () => {
24
+ this.listeners[type]?.delete(handler);
25
+ };
26
+ };
27
+ /**
28
+ * Calls every handler registered for an event.
29
+ *
30
+ * The set is walked in place rather than copied, because `frame` is notified
31
+ * once per rendered frame and a copy per notification would allocate at that
32
+ * rate. A handler that removes itself while being called is safe; one that
33
+ * subscribes during its own notification may be called in the same pass.
34
+ */
35
+ notify = (type, ...args) => {
36
+ this.listeners[type]?.forEach((handler) => {
37
+ handler(...args);
38
+ });
39
+ };
40
+ };
41
+ //#endregion
42
+ exports.SubscriptionManager = SubscriptionManager;
@@ -0,0 +1,30 @@
1
+ //#region src/utils/SubscriptionManager.d.ts
2
+ /** The shape a subscription map has to have: a handler per event name. */
3
+ type HandlerMap = Record<string, (...args: never[]) => void>;
4
+ /**
5
+ * A typed event emitter, small enough to avoid a dependency and precise enough
6
+ * that a wrong payload is a compile error rather than a runtime surprise.
7
+ *
8
+ * The map it is given must be declared as a `type` rather than an `interface`,
9
+ * because an interface has no implicit index signature and cannot satisfy the
10
+ * constraint above.
11
+ *
12
+ * Both methods are fields rather than prototype methods so they can be handed
13
+ * out on their own, which is how `subscribe` reaches a consumer.
14
+ */
15
+ declare class SubscriptionManager<Subscriptions extends HandlerMap> {
16
+ private readonly listeners;
17
+ /** Registers a handler and returns the function that removes it. */
18
+ subscribe: <Type extends keyof Subscriptions>(type: Type, handler: Subscriptions[Type]) => (() => void);
19
+ /**
20
+ * Calls every handler registered for an event.
21
+ *
22
+ * The set is walked in place rather than copied, because `frame` is notified
23
+ * once per rendered frame and a copy per notification would allocate at that
24
+ * rate. A handler that removes itself while being called is safe; one that
25
+ * subscribes during its own notification may be called in the same pass.
26
+ */
27
+ notify: <Type extends keyof Subscriptions>(type: Type, ...args: Parameters<Subscriptions[Type]>) => void;
28
+ }
29
+ //#endregion
30
+ export { SubscriptionManager };
@@ -0,0 +1,30 @@
1
+ //#region src/utils/SubscriptionManager.d.ts
2
+ /** The shape a subscription map has to have: a handler per event name. */
3
+ type HandlerMap = Record<string, (...args: never[]) => void>;
4
+ /**
5
+ * A typed event emitter, small enough to avoid a dependency and precise enough
6
+ * that a wrong payload is a compile error rather than a runtime surprise.
7
+ *
8
+ * The map it is given must be declared as a `type` rather than an `interface`,
9
+ * because an interface has no implicit index signature and cannot satisfy the
10
+ * constraint above.
11
+ *
12
+ * Both methods are fields rather than prototype methods so they can be handed
13
+ * out on their own, which is how `subscribe` reaches a consumer.
14
+ */
15
+ declare class SubscriptionManager<Subscriptions extends HandlerMap> {
16
+ private readonly listeners;
17
+ /** Registers a handler and returns the function that removes it. */
18
+ subscribe: <Type extends keyof Subscriptions>(type: Type, handler: Subscriptions[Type]) => (() => void);
19
+ /**
20
+ * Calls every handler registered for an event.
21
+ *
22
+ * The set is walked in place rather than copied, because `frame` is notified
23
+ * once per rendered frame and a copy per notification would allocate at that
24
+ * rate. A handler that removes itself while being called is safe; one that
25
+ * subscribes during its own notification may be called in the same pass.
26
+ */
27
+ notify: <Type extends keyof Subscriptions>(type: Type, ...args: Parameters<Subscriptions[Type]>) => void;
28
+ }
29
+ //#endregion
30
+ export { SubscriptionManager };
@@ -0,0 +1,42 @@
1
+ //#region src/utils/SubscriptionManager.ts
2
+ /**
3
+ * A typed event emitter, small enough to avoid a dependency and precise enough
4
+ * that a wrong payload is a compile error rather than a runtime surprise.
5
+ *
6
+ * The map it is given must be declared as a `type` rather than an `interface`,
7
+ * because an interface has no implicit index signature and cannot satisfy the
8
+ * constraint above.
9
+ *
10
+ * Both methods are fields rather than prototype methods so they can be handed
11
+ * out on their own, which is how `subscribe` reaches a consumer.
12
+ */
13
+ var SubscriptionManager = class {
14
+ listeners = {};
15
+ /** Registers a handler and returns the function that removes it. */
16
+ subscribe = (type, handler) => {
17
+ let handlers = this.listeners[type];
18
+ if (!handlers) {
19
+ handlers = /* @__PURE__ */ new Set();
20
+ this.listeners[type] = handlers;
21
+ }
22
+ handlers.add(handler);
23
+ return () => {
24
+ this.listeners[type]?.delete(handler);
25
+ };
26
+ };
27
+ /**
28
+ * Calls every handler registered for an event.
29
+ *
30
+ * The set is walked in place rather than copied, because `frame` is notified
31
+ * once per rendered frame and a copy per notification would allocate at that
32
+ * rate. A handler that removes itself while being called is safe; one that
33
+ * subscribes during its own notification may be called in the same pass.
34
+ */
35
+ notify = (type, ...args) => {
36
+ this.listeners[type]?.forEach((handler) => {
37
+ handler(...args);
38
+ });
39
+ };
40
+ };
41
+ //#endregion
42
+ export { SubscriptionManager };
@@ -0,0 +1,25 @@
1
+ //#region src/utils/createLogger.ts
2
+ const PREFIX = "[lottie-react]";
3
+ const noop = () => void 0;
4
+ /**
5
+ * Builds a logger that says nothing unless the caller asked for it.
6
+ *
7
+ * This is tracing rather than diagnosis, and it deliberately reports only what
8
+ * no subscription can: the configuration actually handed to the engine, and the
9
+ * teardown. Anything a consumer can already subscribe to is not repeated here,
10
+ * and nothing per frame is ever written.
11
+ *
12
+ * There is no `warn`, because everything worth warning about reaches the
13
+ * consumer through the `error` subscription with the reason attached.
14
+ *
15
+ * Unlike a development-only warning this survives into a production build on
16
+ * purpose, so a problem that appears only in one can still be looked at.
17
+ */
18
+ function createLogger(debug) {
19
+ if (!debug) return { log: noop };
20
+ return { log: (message, ...rest) => {
21
+ console.log(`${PREFIX} ${message}`, ...rest);
22
+ } };
23
+ }
24
+ //#endregion
25
+ exports.createLogger = createLogger;
@@ -0,0 +1,25 @@
1
+ //#region src/utils/createLogger.ts
2
+ const PREFIX = "[lottie-react]";
3
+ const noop = () => void 0;
4
+ /**
5
+ * Builds a logger that says nothing unless the caller asked for it.
6
+ *
7
+ * This is tracing rather than diagnosis, and it deliberately reports only what
8
+ * no subscription can: the configuration actually handed to the engine, and the
9
+ * teardown. Anything a consumer can already subscribe to is not repeated here,
10
+ * and nothing per frame is ever written.
11
+ *
12
+ * There is no `warn`, because everything worth warning about reaches the
13
+ * consumer through the `error` subscription with the reason attached.
14
+ *
15
+ * Unlike a development-only warning this survives into a production build on
16
+ * purpose, so a problem that appears only in one can still be looked at.
17
+ */
18
+ function createLogger(debug) {
19
+ if (!debug) return { log: noop };
20
+ return { log: (message, ...rest) => {
21
+ console.log(`${PREFIX} ${message}`, ...rest);
22
+ } };
23
+ }
24
+ //#endregion
25
+ export { createLogger };
@@ -0,0 +1,37 @@
1
+ //#region src/utils/isSameJson.ts
2
+ /** Narrows without a cast: any array can be read as a list of unknowns. */
3
+ function isJsonArray(value) {
4
+ return Array.isArray(value);
5
+ }
6
+ /** Narrows without a cast: any plain object can be read as unknown-valued. */
7
+ function isJsonObject(value) {
8
+ return typeof value === "object" && value !== null && !Array.isArray(value);
9
+ }
10
+ /**
11
+ * Compares two JSON values by content: objects, arrays, and the primitives JSON
12
+ * can hold. Key order does not matter, and `NaN` equals itself.
13
+ *
14
+ * Deliberately narrower than a general deep-equality function. It has no
15
+ * understanding of `Map`, `Set`, `Date`, `RegExp` or typed arrays, and treating
16
+ * one as a plain object would report two different values as the same. Animation
17
+ * data is parsed JSON, so none of them can appear in it.
18
+ *
19
+ * It recurses, so a value that refers to itself overflows the stack rather than
20
+ * returning. JSON cannot express one.
21
+ */
22
+ function isSameJson(a, b) {
23
+ if (Object.is(a, b)) return true;
24
+ if (isJsonArray(a)) {
25
+ if (!isJsonArray(b) || a.length !== b.length) return false;
26
+ return a.every((item, index) => isSameJson(item, b[index]));
27
+ }
28
+ if (isJsonObject(a)) {
29
+ if (!isJsonObject(b)) return false;
30
+ const keys = Object.keys(a);
31
+ if (keys.length !== Object.keys(b).length) return false;
32
+ return keys.every((key) => Object.hasOwn(b, key) && isSameJson(a[key], b[key]));
33
+ }
34
+ return false;
35
+ }
36
+ //#endregion
37
+ exports.isSameJson = isSameJson;
@@ -0,0 +1,37 @@
1
+ //#region src/utils/isSameJson.ts
2
+ /** Narrows without a cast: any array can be read as a list of unknowns. */
3
+ function isJsonArray(value) {
4
+ return Array.isArray(value);
5
+ }
6
+ /** Narrows without a cast: any plain object can be read as unknown-valued. */
7
+ function isJsonObject(value) {
8
+ return typeof value === "object" && value !== null && !Array.isArray(value);
9
+ }
10
+ /**
11
+ * Compares two JSON values by content: objects, arrays, and the primitives JSON
12
+ * can hold. Key order does not matter, and `NaN` equals itself.
13
+ *
14
+ * Deliberately narrower than a general deep-equality function. It has no
15
+ * understanding of `Map`, `Set`, `Date`, `RegExp` or typed arrays, and treating
16
+ * one as a plain object would report two different values as the same. Animation
17
+ * data is parsed JSON, so none of them can appear in it.
18
+ *
19
+ * It recurses, so a value that refers to itself overflows the stack rather than
20
+ * returning. JSON cannot express one.
21
+ */
22
+ function isSameJson(a, b) {
23
+ if (Object.is(a, b)) return true;
24
+ if (isJsonArray(a)) {
25
+ if (!isJsonArray(b) || a.length !== b.length) return false;
26
+ return a.every((item, index) => isSameJson(item, b[index]));
27
+ }
28
+ if (isJsonObject(a)) {
29
+ if (!isJsonObject(b)) return false;
30
+ const keys = Object.keys(a);
31
+ if (keys.length !== Object.keys(b).length) return false;
32
+ return keys.every((key) => Object.hasOwn(b, key) && isSameJson(a[key], b[key]));
33
+ }
34
+ return false;
35
+ }
36
+ //#endregion
37
+ export { isSameJson };
@@ -0,0 +1,37 @@
1
+ //#region src/utils/mergeRefs.ts
2
+ /**
3
+ * Sends one element to several refs.
4
+ *
5
+ * An element has a single `ref` slot, so any element that both this library and
6
+ * the person using it want a handle on needs one callback that feeds both.
7
+ *
8
+ * Teardown is the part that is not boilerplate, because the two supported React
9
+ * versions differ. React 19 treats a function returned from a ref callback as
10
+ * its cleanup and then never calls that ref with `null`, while React 18
11
+ * discards the return and calls with `null`. So each ref gets its own cleanup
12
+ * where it returned one and a `null` call where it did not, and the combined
13
+ * teardown is returned for React 19 to run. React 18 ignores it and calls this
14
+ * callback with `null` instead, which does the same work.
15
+ */
16
+ function mergeRefs(...refs) {
17
+ return (node) => {
18
+ const teardowns = refs.map((ref) => {
19
+ if (typeof ref === "function") {
20
+ const cleanup = ref(node);
21
+ return typeof cleanup === "function" ? cleanup : () => ref(null);
22
+ }
23
+ if (ref) {
24
+ ref.current = node;
25
+ return () => {
26
+ ref.current = null;
27
+ };
28
+ }
29
+ return () => void 0;
30
+ });
31
+ return () => {
32
+ for (const teardown of teardowns) teardown();
33
+ };
34
+ };
35
+ }
36
+ //#endregion
37
+ exports.mergeRefs = mergeRefs;
@@ -0,0 +1,37 @@
1
+ //#region src/utils/mergeRefs.ts
2
+ /**
3
+ * Sends one element to several refs.
4
+ *
5
+ * An element has a single `ref` slot, so any element that both this library and
6
+ * the person using it want a handle on needs one callback that feeds both.
7
+ *
8
+ * Teardown is the part that is not boilerplate, because the two supported React
9
+ * versions differ. React 19 treats a function returned from a ref callback as
10
+ * its cleanup and then never calls that ref with `null`, while React 18
11
+ * discards the return and calls with `null`. So each ref gets its own cleanup
12
+ * where it returned one and a `null` call where it did not, and the combined
13
+ * teardown is returned for React 19 to run. React 18 ignores it and calls this
14
+ * callback with `null` instead, which does the same work.
15
+ */
16
+ function mergeRefs(...refs) {
17
+ return (node) => {
18
+ const teardowns = refs.map((ref) => {
19
+ if (typeof ref === "function") {
20
+ const cleanup = ref(node);
21
+ return typeof cleanup === "function" ? cleanup : () => ref(null);
22
+ }
23
+ if (ref) {
24
+ ref.current = node;
25
+ return () => {
26
+ ref.current = null;
27
+ };
28
+ }
29
+ return () => void 0;
30
+ });
31
+ return () => {
32
+ for (const teardown of teardowns) teardown();
33
+ };
34
+ };
35
+ }
36
+ //#endregion
37
+ export { mergeRefs };
@@ -0,0 +1,26 @@
1
+ const require_isSameJson = require("./isSameJson.cjs");
2
+ let react = require("react");
3
+ //#region src/utils/useStableValue.ts
4
+ /**
5
+ * Keeps a value stable until its **content** changes, so it can be depended on.
6
+ *
7
+ * A value written inline at a call site is a new value on every render, and an
8
+ * effect that depends on it therefore re-runs on every render. Where that
9
+ * effect also sets state, the component re-renders, the value is built again,
10
+ * and it never settles.
11
+ *
12
+ * The reference is compared first, so a caller who passes something they
13
+ * already hold pays nothing at all. Only a caller who rebuilds an equal value
14
+ * pays for the comparison, which is exactly the case being rescued.
15
+ *
16
+ * Assigning state during render is React's own answer to adjusting state when a
17
+ * prop changes: the component renders again immediately, before anything is
18
+ * committed, so the intermediate result is never seen.
19
+ */
20
+ function useStableValue(value) {
21
+ const [stable, setStable] = (0, react.useState)(value);
22
+ if (stable !== value && !require_isSameJson.isSameJson(stable, value)) setStable(value);
23
+ return stable;
24
+ }
25
+ //#endregion
26
+ exports.useStableValue = useStableValue;
@@ -0,0 +1,26 @@
1
+ import { isSameJson } from "./isSameJson.js";
2
+ import { useState } from "react";
3
+ //#region src/utils/useStableValue.ts
4
+ /**
5
+ * Keeps a value stable until its **content** changes, so it can be depended on.
6
+ *
7
+ * A value written inline at a call site is a new value on every render, and an
8
+ * effect that depends on it therefore re-runs on every render. Where that
9
+ * effect also sets state, the component re-renders, the value is built again,
10
+ * and it never settles.
11
+ *
12
+ * The reference is compared first, so a caller who passes something they
13
+ * already hold pays nothing at all. Only a caller who rebuilds an equal value
14
+ * pays for the comparison, which is exactly the case being rescued.
15
+ *
16
+ * Assigning state during render is React's own answer to adjusting state when a
17
+ * prop changes: the component renders again immediately, before anything is
18
+ * committed, so the intermediate result is never seen.
19
+ */
20
+ function useStableValue(value) {
21
+ const [stable, setStable] = useState(value);
22
+ if (stable !== value && !isSameJson(stable, value)) setStable(value);
23
+ return stable;
24
+ }
25
+ //#endregion
26
+ export { useStableValue };
package/changes.json CHANGED
@@ -1,10 +1,5 @@
1
1
  {
2
- "bumped": {
3
- "lottie-web": {
4
- "from": "^5.10.2",
5
- "to": "^5.13.0"
6
- }
7
- },
8
- "timestamp": "2026-03-18T22:40:32.392Z",
9
- "totalUpdated": 1
2
+ "bumped": {},
3
+ "timestamp": "2026-08-16T00:26:02.638Z",
4
+ "totalUpdated": 0
10
5
  }