Skip to content

Commit 1369a2f

Browse files
committed
feat: add shouldUpdateAnimation option
1 parent 13fee55 commit 1369a2f

File tree

4 files changed

+63
-17
lines changed

4 files changed

+63
-17
lines changed

README.md

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ Using [Web Animations API](https://developer.mozilla.org/en-US/docs/Web/API/Web_
3434
- 🔩 Supports custom `refs` for [some reasons](#use-your-own-ref).
3535
- 📜 Supports [TypeScript](https://www.typescriptlang.org) type definition.
3636
- 🗄️ Server-side rendering compatibility.
37-
- 🦔 Tiny size ([~ 4.8KB gzipped](https://bundlephobia.com/result?p=@wellyshen/use-web-animations)). No external dependencies, aside for the `react`.
37+
- 🦔 Tiny size ([~ 4.8KB gzipped](https://bundlephobia.com/result?p=@wellyshen/use-web-animations)).
3838

3939
## Requirement
4040

@@ -129,6 +129,8 @@ const App = () => {
129129
};
130130
```
131131

132+
> 💡 By default, the hook will be updated when options changed (i.e. keyframes, animationOptions etc.). However, you can disable this behavior by setting the `shouldUpdateAnimation` option to `false`.
133+
132134
### Playback Control
133135

134136
The shortcoming with existing technologies was the lack of playback control. The Web Animations API provides several useful methods for controlling playback: play, pause, reverse, cancel, finish, seek, control speed via the [methods](https://developer.mozilla.org/en-US/docs/Web/API/Animation#Methods) of the **Animation** interface. This hook exposes the animation instance for us to interact with animations, we can access it by the `getAnimation()` return value.
@@ -532,17 +534,18 @@ It's returned with the following properties.
532534

533535
The `options` provides the following configurations and event callbacks for you.
534536

535-
| Key | Type | Default | Description |
536-
| ------------------ | ---------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
537-
| `ref` | object | | For [some reasons](#use-your-own-ref), you can pass in your own ref instead of using the built-in. |
538-
| `id` | string | `""` | Sets the ID of an animation, implemented based on the [Animation.id](https://developer.mozilla.org/en-US/docs/Web/API/Animation/id). |
539-
| `playbackRate` | number | `1` | Sets the playback rate of an animation, implemented based on the [Animation.playbackRate](https://developer.mozilla.org/en-US/docs/Web/API/Animation/playbackRate). |
540-
| `autoPlay` | boolean | `true` | Automatically starts the animation. |
541-
| `keyframes` | Array \| object | | An array of keyframe objects, or a keyframe object whose property are arrays of values to iterate over. See [basic usage](#basic-usage) for more details. |
542-
| `animationOptions` | number \| object | | An **integer** representing the animation's duration (in milliseconds), or an **object** containing one or more timing properties. See [basic usage](#basic-usage) for more details. |
543-
| `onReady` | function | | It's invoked when an animation is ready to play. You can access the [playState](#basic-usage), [animate](#dynamic-interactions-with-animation) and [animation](#getting-animations-information) from the event object. |
544-
| `onUpdate` | function | | It's invoked when an animation enters the `running` state or changes state. You can access the [playState](#basic-usage), [animate](#dynamic-interactions-with-animation) and [animation](#getting-animations-information) from the event object. |
545-
| `onFinish` | function | | It's invoked when an animation enters the `finished` state. You can access the [playState](#basic-usage), [animate](#dynamic-interactions-with-animation) and [animation](#getting-animations-information) from the event object. |
537+
| Key | Type | Default | Description |
538+
| ----------------------- | ---------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
539+
| `ref` | object | | For [some reasons](#use-your-own-ref), you can pass in your own ref instead of using the built-in. |
540+
| `id` | string | `""` | Sets the ID of an animation, implemented based on the [Animation.id](https://developer.mozilla.org/en-US/docs/Web/API/Animation/id). |
541+
| `playbackRate` | number | `1` | Sets the playback rate of an animation, implemented based on the [Animation.playbackRate](https://developer.mozilla.org/en-US/docs/Web/API/Animation/playbackRate). |
542+
| `autoPlay` | boolean | `true` | Automatically starts the animation. |
543+
| `keyframes` | Array \| object | | An array of keyframe objects, or a keyframe object whose property are arrays of values to iterate over. See [basic usage](#basic-usage) for more details. |
544+
| `animationOptions` | number \| object | | An **integer** representing the animation's duration (in milliseconds), or an **object** containing one or more timing properties. See [basic usage](#basic-usage) for more details. |
545+
| `shouldUpdateAnimation` | boolean | `true` | By default, the hook will be updated when options changed (i.e. keyframes, animationOptions etc.). However, you can disable this behavior by setting this option to `false`. |
546+
| `onReady` | function | | It's invoked when an animation is ready to play. You can access the [playState](#basic-usage), [animate](#dynamic-interactions-with-animation) and [animation](#getting-animations-information) from the event object. |
547+
| `onUpdate` | function | | It's invoked when an animation enters the `running` state or changes state. You can access the [playState](#basic-usage), [animate](#dynamic-interactions-with-animation) and [animation](#getting-animations-information) from the event object. |
548+
| `onFinish` | function | | It's invoked when an animation enters the `finished` state. You can access the [playState](#basic-usage), [animate](#dynamic-interactions-with-animation) and [animation](#getting-animations-information) from the event object. |
546549

547550
## Use Polyfill
548551

src/__tests__/useWebAnimations.ts

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,19 @@ describe("useWebAnimations", () => {
2222
ref = target,
2323
keyframes = mockKeyframes,
2424
animationOptions = mockTiming,
25+
shouldUpdateAnimation = true,
2526
...rest
2627
}: Partial<Options<HTMLDivElement>> = {}) =>
27-
renderHook(() =>
28-
useWebAnimations({ ref, keyframes, animationOptions, ...rest })
28+
renderHook(
29+
(config) => useWebAnimations({ ...config, shouldUpdateAnimation }),
30+
{
31+
initialProps: {
32+
ref,
33+
keyframes,
34+
animationOptions,
35+
...rest,
36+
},
37+
}
2938
);
3039

3140
const e = { playState: "pause" };
@@ -44,6 +53,32 @@ describe("useWebAnimations", () => {
4453
el.animate = jest.fn(() => animation);
4554
});
4655

56+
it("should update animation", () => {
57+
const { rerender } = renderHelper();
58+
expect(el.animate).toHaveBeenCalledWith(mockKeyframes, 3000);
59+
const elm = document.createElement("div");
60+
// @ts-expect-error
61+
elm.animate = jest.fn(() => animation);
62+
const keyframes = { transform: ["translateX(100px)"] };
63+
const animationOptions = 5000;
64+
rerender({ ref: { current: elm }, keyframes, animationOptions });
65+
expect(elm.animate).toHaveBeenCalledWith(keyframes, animationOptions);
66+
});
67+
68+
it("should not update animation", () => {
69+
const { rerender } = renderHelper({ shouldUpdateAnimation: false });
70+
expect(el.animate).toHaveBeenCalledWith(mockKeyframes, 3000);
71+
const elm = document.createElement("div");
72+
// @ts-expect-error
73+
elm.animate = jest.fn(() => animation);
74+
rerender({
75+
ref: { current: elm },
76+
keyframes: { transform: ["translateX(100px)"] },
77+
animationOptions: 5000,
78+
});
79+
expect(elm.animate).not.toHaveBeenCalled();
80+
});
81+
4782
it("should cancel animation", async () => {
4883
const { unmount } = renderHelper();
4984
unmount();

src/use-web-animations.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ declare module "@wellyshen/use-web-animations" {
1212
animationOptions:
1313
| number
1414
| (KeyframeAnimationOptions & { pseudoElement?: string });
15+
shouldUpdateAnimation: boolean;
1516
}>;
1617

1718
export interface Animate {

src/useWebAnimations.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ type AnimConf = Partial<{
1717
animationOptions:
1818
| number
1919
| (KeyframeAnimationOptions & { pseudoElement?: string });
20+
shouldUpdateAnimation: boolean;
2021
}>;
2122
interface Animate {
2223
(args: AnimConf & { keyframes: Keyframes }): void;
@@ -49,6 +50,7 @@ const useWebAnimations = <T extends HTMLElement>({
4950
autoPlay,
5051
keyframes,
5152
animationOptions,
53+
shouldUpdateAnimation = true,
5254
onReady,
5355
onUpdate,
5456
onFinish,
@@ -121,9 +123,14 @@ const useWebAnimations = <T extends HTMLElement>({
121123
[onFinishRef, onReadyRef, ref]
122124
);
123125

124-
useDeepCompareEffect(() => {
125-
animate({ id, playbackRate, autoPlay, keyframes, animationOptions });
126-
}, [id, playbackRate, autoPlay, keyframes, animationOptions, animate]);
126+
useDeepCompareEffect(
127+
() => {
128+
animate({ id, playbackRate, autoPlay, keyframes, animationOptions });
129+
},
130+
shouldUpdateAnimation
131+
? [id, playbackRate, autoPlay, keyframes, animationOptions, animate]
132+
: [{}]
133+
);
127134

128135
useEffect(() => {
129136
let rafId: number;

0 commit comments

Comments
 (0)