react-lottie 2.2.0 → 2.3.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/CHANGELOG.md +6 -0
- package/README.md +90 -0
- package/dist/index.js +21 -11
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,12 @@
|
|
|
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.0](https://github.com/chenqingspring/react-lottie/compare/v2.2.0...v2.3.0) (2026-11-05)
|
|
6
|
+
|
|
7
|
+
### Features
|
|
8
|
+
|
|
9
|
+
* add an `as` prop to choose the element rendered around the animation, so `<Lottie as="span" />` can be nested in a `<p>` without invalid HTML. Changing `as` rebinds the animation to the new node and keeps the current frame ([#73](https://github.com/chenqingspring/react-lottie/issues/73))
|
|
10
|
+
|
|
5
11
|
## [2.2.0](https://github.com/chenqingspring/react-lottie/compare/v2.1.0...v2.2.0) (2026-11-05)
|
|
6
12
|
|
|
7
13
|
### Features
|
package/README.md
CHANGED
|
@@ -116,6 +116,74 @@ export default class LottieControl extends React.Component {
|
|
|
116
116
|
|
|
117
117
|
```
|
|
118
118
|
|
|
119
|
+
### Loading animation data without bloating the bundle
|
|
120
|
+
|
|
121
|
+
A static import like `import animationData from './pinjump.json'` (the example
|
|
122
|
+
above) makes the bundler inline the animation into the JavaScript chunk that
|
|
123
|
+
imports it. A 500 kB JSON file then becomes 500 kB of JavaScript the browser has
|
|
124
|
+
to download and parse before the page can run. The JSON is data, not code, so
|
|
125
|
+
keep it out of the main bundle:
|
|
126
|
+
|
|
127
|
+
**Serve it from `public/` and use `options.path`.** In Create React App, Vite
|
|
128
|
+
and Next.js, files in `public/` are copied to the build output as static
|
|
129
|
+
assets; they are not bundled into JavaScript. `lottie-web` fetches the file when
|
|
130
|
+
the component mounts, and the browser caches it separately from the app bundle:
|
|
131
|
+
|
|
132
|
+
```jsx
|
|
133
|
+
const defaultOptions = {
|
|
134
|
+
path: '/animations/pinjump.json', // relative to the deployed site root
|
|
135
|
+
loop: true,
|
|
136
|
+
autoplay: true,
|
|
137
|
+
rendererSettings: {
|
|
138
|
+
preserveAspectRatio: 'xMidYMid slice'
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
<Lottie options={defaultOptions} height={400} width={400} />
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Because lottie-web owns the fetch, `colorFilters` is not applied to animations
|
|
146
|
+
loaded this way — fetch the JSON yourself if you need to recolor it.
|
|
147
|
+
|
|
148
|
+
**Or load it on demand with a dynamic `import()`.** If you need the parsed data
|
|
149
|
+
in your own code, a dynamic import puts the JSON in a separate chunk that is
|
|
150
|
+
downloaded only when the component renders:
|
|
151
|
+
|
|
152
|
+
```jsx
|
|
153
|
+
import { useEffect, useState } from 'react';
|
|
154
|
+
import Lottie from 'react-lottie';
|
|
155
|
+
|
|
156
|
+
export default function Animation() {
|
|
157
|
+
const [animationData, setAnimationData] = useState(null);
|
|
158
|
+
|
|
159
|
+
useEffect(() => {
|
|
160
|
+
let cancelled = false;
|
|
161
|
+
import('./pinjump.json').then(({ default: data }) => {
|
|
162
|
+
if (!cancelled) setAnimationData(data);
|
|
163
|
+
});
|
|
164
|
+
return () => { cancelled = true; };
|
|
165
|
+
}, []);
|
|
166
|
+
|
|
167
|
+
if (!animationData) return null;
|
|
168
|
+
|
|
169
|
+
return (
|
|
170
|
+
<Lottie
|
|
171
|
+
options={{ animationData, loop: true, autoplay: true }}
|
|
172
|
+
height={400}
|
|
173
|
+
width={400}
|
|
174
|
+
/>
|
|
175
|
+
);
|
|
176
|
+
}
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
Rendering `<Animation />` lazily (for example when it scrolls into view) defers
|
|
180
|
+
even that chunk until it is needed. The same idea works with `React.lazy` around
|
|
181
|
+
a component that imports the JSON.
|
|
182
|
+
|
|
183
|
+
Finally, the file itself can usually get smaller: export at a lower precision,
|
|
184
|
+
remove unused layers and precompositions, avoid embedded raster images, and let
|
|
185
|
+
gzip/Brotli compress the JSON. LottieFiles' optimizer automates the first steps.
|
|
186
|
+
|
|
119
187
|
### Play on hover
|
|
120
188
|
|
|
121
189
|
`eventListeners` takes lottie-web animation events (`complete`, `loopComplete`,
|
|
@@ -215,6 +283,21 @@ frame and paused/playing state are preserved. Animations loaded from
|
|
|
215
283
|
`options.path` are not recolored, since the JSON is fetched by lottie-web:
|
|
216
284
|
load the JSON yourself and pass it as `animationData` instead.
|
|
217
285
|
|
|
286
|
+
### Render inline inside a paragraph
|
|
287
|
+
|
|
288
|
+
The container is a `div` by default, which is not a valid child of `<p>`. Pass
|
|
289
|
+
`as` to choose the element (issue #73):
|
|
290
|
+
|
|
291
|
+
```jsx
|
|
292
|
+
<p>
|
|
293
|
+
Text <Lottie as="span" options={defaultOptions} ariaRole="img" /> more text
|
|
294
|
+
</p>
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
`as` accepts a tag name or a component that forwards its `ref` to the DOM node
|
|
298
|
+
lottie-web should render into. Changing `as` reloads the animation into the new
|
|
299
|
+
element and keeps the current frame.
|
|
300
|
+
|
|
218
301
|
### Imperative control
|
|
219
302
|
|
|
220
303
|
A `ref` to the component exposes `play()`, `pause()`, `stop()`,
|
|
@@ -336,6 +419,13 @@ layout defaults. Use it to override `overflow` or `margin`.
|
|
|
336
419
|
Tab order of the rendered container. Pass `-1` for a purely presentational
|
|
337
420
|
animation that should not receive keyboard focus.
|
|
338
421
|
|
|
422
|
+
**as** *optional* [default: `div`]
|
|
423
|
+
|
|
424
|
+
Element or component rendered as the animation container. Use `as="span"` when
|
|
425
|
+
`<Lottie />` is a child of `<p>`, where a `div` is invalid HTML (issue #73). A
|
|
426
|
+
custom component must forward its `ref` to a DOM element. See
|
|
427
|
+
[Render inline inside a paragraph](#render-inline-inside-a-paragraph).
|
|
428
|
+
|
|
339
429
|
## Related Projects
|
|
340
430
|
|
|
341
431
|
* [lottie-web](https://github.com/airbnb/lottie-web) react-lottie is a wrapper of lottie-web
|
package/dist/index.js
CHANGED
|
@@ -122,24 +122,31 @@ var Lottie = exports["default"] = /*#__PURE__*/function (_React$Component) {
|
|
|
122
122
|
var dataChanged = this.animationData !== this.props.options.animationData;
|
|
123
123
|
var pathChanged = this.options.path !== this.props.options.path;
|
|
124
124
|
var colorFiltersChanged = !(0, _colorFilters.colorFiltersAreEqual)(this.colorFilters, this.props.colorFilters);
|
|
125
|
-
|
|
125
|
+
/* The wrapper element is part of lottie-web's configuration, so a new
|
|
126
|
+
element means the animation has to be bound to the new node. */
|
|
127
|
+
var containerChanged = prevProps.as !== this.props.as;
|
|
128
|
+
if (dataChanged || pathChanged || colorFiltersChanged || containerChanged) {
|
|
126
129
|
var currentFrame = this.anim ? this.anim.currentFrame : 0;
|
|
127
130
|
var wasPaused = this.anim ? this.anim.isPaused : true;
|
|
128
|
-
/* lottie-web cannot recolor a loaded animation
|
|
129
|
-
load the data again. Only
|
|
130
|
-
|
|
131
|
+
/* lottie-web cannot recolor a loaded animation and cannot move one to
|
|
132
|
+
another node, so those changes load the same data again. Only then is
|
|
133
|
+
it worth restoring the frame and playback state. */
|
|
134
|
+
var reloadInPlace = !dataChanged && !pathChanged;
|
|
131
135
|
this.deRegisterEvents(prevProps.eventListeners);
|
|
132
136
|
this.destroy();
|
|
133
137
|
this.animationData = this.props.options.animationData;
|
|
134
138
|
this.colorFilters = this.props.colorFilters;
|
|
135
139
|
this.options = _objectSpread(_objectSpread({}, this.options), this.props.options);
|
|
140
|
+
/* `options` is caller-owned and knows nothing about the wrapper, so the
|
|
141
|
+
ref (already pointing at the newly rendered node) wins. */
|
|
142
|
+
this.options.container = this.el;
|
|
136
143
|
this.options.animationData = (0, _colorFilters.applyColorFilters)(this.props.options.animationData, this.props.colorFilters);
|
|
137
144
|
this.anim = _lottieWeb["default"].loadAnimation(this.options);
|
|
138
145
|
this.registerEvents(this.props.eventListeners);
|
|
139
146
|
|
|
140
|
-
/* Keep the frame and playback state so a theme change does
|
|
141
|
-
a paused or half-played animation. */
|
|
142
|
-
if (
|
|
147
|
+
/* Keep the frame and playback state so a theme or element change does
|
|
148
|
+
not restart a paused or half-played animation. */
|
|
149
|
+
if (reloadInPlace) {
|
|
143
150
|
if (this.props.segments) this.anim.playSegments(this.props.segments, true);
|
|
144
151
|
if (Number.isFinite(currentFrame)) this.anim.goToAndStop(currentFrame, true);
|
|
145
152
|
if (!wasPaused) this.anim.play();
|
|
@@ -264,7 +271,8 @@ var Lottie = exports["default"] = /*#__PURE__*/function (_React$Component) {
|
|
|
264
271
|
ariaLabel = _this$props2.ariaLabel,
|
|
265
272
|
isClickToPauseDisabled = _this$props2.isClickToPauseDisabled,
|
|
266
273
|
title = _this$props2.title,
|
|
267
|
-
tabIndex = _this$props2.tabIndex
|
|
274
|
+
tabIndex = _this$props2.tabIndex,
|
|
275
|
+
Container = _this$props2.as;
|
|
268
276
|
var getSize = function getSize(initial) {
|
|
269
277
|
var size;
|
|
270
278
|
if (typeof initial === 'number') {
|
|
@@ -289,7 +297,7 @@ var Lottie = exports["default"] = /*#__PURE__*/function (_React$Component) {
|
|
|
289
297
|
// Click-to-pause is intentional and role="button" is set; keyboard control
|
|
290
298
|
// is not part of the API yet.
|
|
291
299
|
// eslint-disable-next-line jsx-a11y/click-events-have-key-events
|
|
292
|
-
_react["default"].createElement(
|
|
300
|
+
_react["default"].createElement(Container, {
|
|
293
301
|
ref: function ref(c) {
|
|
294
302
|
_this4.el = c;
|
|
295
303
|
},
|
|
@@ -324,7 +332,8 @@ Lottie.propTypes = {
|
|
|
324
332
|
isClickToPauseDisabled: _propTypes["default"].bool,
|
|
325
333
|
title: _propTypes["default"].string,
|
|
326
334
|
style: _propTypes["default"].object,
|
|
327
|
-
tabIndex: _propTypes["default"].number
|
|
335
|
+
tabIndex: _propTypes["default"].number,
|
|
336
|
+
as: _propTypes["default"].elementType
|
|
328
337
|
};
|
|
329
338
|
Lottie.defaultProps = {
|
|
330
339
|
eventListeners: [],
|
|
@@ -337,5 +346,6 @@ Lottie.defaultProps = {
|
|
|
337
346
|
ariaLabel: 'animation',
|
|
338
347
|
isClickToPauseDisabled: false,
|
|
339
348
|
title: '',
|
|
340
|
-
tabIndex: 0
|
|
349
|
+
tabIndex: 0,
|
|
350
|
+
as: 'div'
|
|
341
351
|
};
|