react-lottie 2.3.1 → 2.3.2

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/CHANGELOG.md CHANGED
@@ -2,6 +2,14 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
4
4
 
5
+ ## [2.3.2](https://github.com/chenqingspring/react-lottie/compare/v2.3.1...v2.3.2) (2026-11-07)
6
+
7
+ ### Bug Fixes
8
+
9
+ * accept a namespace import (`import * as animationData`) by unwrapping its `default` export and clone frozen animation objects before handing them to lottie-web, so they no longer fail with `Cannot read property 'length' of undefined` (#24, #65)
10
+ * throw an actionable error when `options.animationData` is a string or when neither `animationData` nor `path` is provided, instead of lottie-web's `Cannot create property 'tf' on string` / `Cannot read property 'length' of undefined` deep in the renderer (#44)
11
+ * fix the README examples that read `.default` from a default import, which passed `undefined` as the animation data
12
+
5
13
  ## [2.3.1](https://github.com/chenqingspring/react-lottie/compare/v2.3.0...v2.3.1) (2026-11-05)
6
14
 
7
15
  ### Bug Fixes
package/README.md CHANGED
@@ -37,6 +37,70 @@ npm install --save react-lottie
37
37
  > [GitHub](https://github.com/chenqingspring/react-lottie/issues) and Relay
38
38
  > will review and fix it.
39
39
 
40
+ ## Using from a CDN (no bundler)
41
+
42
+ The published `dist/index.js` is a CommonJS build for bundlers and npm
43
+ consumers. It uses `exports` and expects `react`, `prop-types` and `lottie-web`
44
+ to be resolvable, so loading that file with a plain `<script>` tag fails with
45
+ `Uncaught ReferenceError: exports is not defined`. The package does not ship a
46
+ UMD/browser global build.
47
+
48
+ To use react-lottie without a build step, load it as an ES module from a CDN
49
+ and map `react` to the same copy the page uses. [esm.sh](https://esm.sh)
50
+ supports `?external=react` for exactly this:
51
+
52
+ ```html
53
+ <script type="importmap">
54
+ {
55
+ "imports": {
56
+ "react": "https://esm.sh/react@18",
57
+ "react-dom/client": "https://esm.sh/react-dom@18/client",
58
+ "react-lottie": "https://esm.sh/react-lottie@2?external=react"
59
+ }
60
+ }
61
+ </script>
62
+ <script type="module">
63
+ import React from 'react';
64
+ import { createRoot } from 'react-dom/client';
65
+ import Lottie from 'react-lottie';
66
+
67
+ const options = {
68
+ path: '/animations/pinjump.json',
69
+ loop: true,
70
+ autoplay: true,
71
+ };
72
+
73
+ createRoot(document.getElementById('root')).render(
74
+ React.createElement(Lottie, { options, height: 400, width: 400 })
75
+ );
76
+ </script>
77
+ ```
78
+
79
+ Without a compiler for JSX, create elements with `React.createElement`, or add
80
+ `htm`/Babel. Keeping `react` in the import map gives the page one React
81
+ instance; a CDN build that bundles its own React (such as jsDelivr's `+esm`
82
+ output) produces two copies, which breaks context and hooks.
83
+
84
+ If you only need to play an animation and not the React wrapper, load
85
+ lottie-web directly and skip React entirely:
86
+
87
+ ```html
88
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/bodymovin/5.12.2/lottie.min.js"></script>
89
+ <script>
90
+ lottie.loadAnimation({
91
+ container: document.getElementById('root'),
92
+ path: '/animations/pinjump.json',
93
+ renderer: 'svg',
94
+ loop: true,
95
+ autoplay: true,
96
+ });
97
+ </script>
98
+ ```
99
+
100
+ An ESM CDN build still downloads React, React DOM, lottie-web and react-lottie,
101
+ so it removes the build step but not the bytes. For production, a bundler that
102
+ shares one React copy and tree-shakes lottie-web is smaller.
103
+
40
104
  ## Requirements
41
105
 
42
106
  React 16.8 or newer. The test suite runs against React 18; the component uses
@@ -95,7 +159,7 @@ export default class LottieControl extends React.Component {
95
159
  const defaultOptions = {
96
160
  loop: true,
97
161
  autoplay: true,
98
- animationData: animationData.default,
162
+ animationData,
99
163
  rendererSettings: {
100
164
  preserveAspectRatio: 'xMidYMid slice'
101
165
  }
@@ -116,6 +180,11 @@ export default class LottieControl extends React.Component {
116
180
 
117
181
  ```
118
182
 
183
+ Pass the parsed animation object as `options.animationData`. A file path or URL
184
+ belongs in `options.path`; a namespace import
185
+ (`import * as animationData`) is unwrapped automatically but the default import
186
+ above is preferred.
187
+
119
188
  ### Loading animation data without bloating the bundle
120
189
 
121
190
  A static import like `import animationData from './pinjump.json'` (the example
@@ -211,7 +280,7 @@ export default class HoverLottie extends React.Component {
211
280
  const defaultOptions = {
212
281
  loop: false,
213
282
  autoplay: false,
214
- animationData: animationData.default,
283
+ animationData,
215
284
  rendererSettings: {
216
285
  preserveAspectRatio: 'xMidYMid slice'
217
286
  }
package/dist/index.js CHANGED
@@ -32,6 +32,35 @@ var segmentsAreEqual = function segmentsAreEqual(a, b) {
32
32
  return value === b[index];
33
33
  });
34
34
  };
35
+
36
+ /* lottie-web crashes deep inside its renderer with "Cannot read property
37
+ 'length' of undefined" when the data is not a plain animation object. Accept
38
+ the shapes users actually pass (a namespace import, a frozen ESM object) and
39
+ fail with an actionable message for the rest (#24, #44, #65). */
40
+ var _normalizeAnimationData = function normalizeAnimationData(animationData, path) {
41
+ if (animationData === undefined || animationData === null) {
42
+ if (!path) {
43
+ throw new Error('[react-lottie] options must include `animationData` (the imported JSON) ' + 'or `path` (a URL to the JSON file).');
44
+ }
45
+ return animationData;
46
+ }
47
+ if (typeof animationData === 'string') {
48
+ throw new Error('[react-lottie] options.animationData must be an object, not a string. ' + 'Pass a file path or URL as options.path instead, or call JSON.parse() ' + 'on JSON text first.');
49
+ }
50
+
51
+ /* `import * as animationData` wraps the payload in a `default` property,
52
+ which lottie-web cannot read (#24, #65). */
53
+ if (!Array.isArray(animationData.layers) && animationData["default"]) {
54
+ return _normalizeAnimationData(animationData["default"], path);
55
+ }
56
+
57
+ /* lottie-web annotates the loaded animation (`__complete`), which throws on
58
+ the frozen objects produced by strict ESM bundlers (#24). */
59
+ if (Object.isFrozen(animationData)) {
60
+ return JSON.parse(JSON.stringify(animationData));
61
+ }
62
+ return animationData;
63
+ };
35
64
  var Lottie = exports["default"] = /*#__PURE__*/function (_React$Component) {
36
65
  function Lottie() {
37
66
  var _this;
@@ -71,7 +100,7 @@ var Lottie = exports["default"] = /*#__PURE__*/function (_React$Component) {
71
100
  whether either actually changed. */
72
101
  this.animationData = animationData;
73
102
  this.colorFilters = colorFilters;
74
- var filteredAnimationData = (0, _colorFilters.applyColorFilters)(animationData, colorFilters);
103
+ var filteredAnimationData = (0, _colorFilters.applyColorFilters)(_normalizeAnimationData(animationData, options.path), colorFilters);
75
104
  this.options = {
76
105
  container: this.el,
77
106
  renderer: renderer,
@@ -140,7 +169,7 @@ var Lottie = exports["default"] = /*#__PURE__*/function (_React$Component) {
140
169
  /* `options` is caller-owned and knows nothing about the wrapper, so the
141
170
  ref (already pointing at the newly rendered node) wins. */
142
171
  this.options.container = this.el;
143
- this.options.animationData = (0, _colorFilters.applyColorFilters)(this.props.options.animationData, this.props.colorFilters);
172
+ this.options.animationData = (0, _colorFilters.applyColorFilters)(_normalizeAnimationData(this.props.options.animationData, this.props.options.path), this.props.colorFilters);
144
173
  this.anim = _lottieWeb["default"].loadAnimation(this.options);
145
174
  this.registerEvents(this.props.eventListeners);
146
175
 
@@ -179,7 +208,8 @@ var Lottie = exports["default"] = /*#__PURE__*/function (_React$Component) {
179
208
  value: function componentWillUnmount() {
180
209
  this.deRegisterEvents(this.props.eventListeners);
181
210
  this.destroy();
182
- this.options.animationData = null;
211
+ /* A failed loadAnimation (e.g. invalid animationData) leaves no options. */
212
+ if (this.options) this.options.animationData = null;
183
213
  this.anim = null;
184
214
  }
185
215
  }, {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-lottie",
3
- "version": "2.3.1",
3
+ "version": "2.3.2",
4
4
  "funding": "https://opencollective.com/react-lottie",
5
5
  "description": "lottie animation view for React",
6
6
  "repository": {