Skip to content

Commit 3f61496

Browse files
authored
oncomplete handler (#3)
* oncomplete handler * fix build * remove unused var * populate readme * Update README.md * Update README.md * Update README.md
1 parent bd6e614 commit 3f61496

File tree

4 files changed

+648
-924
lines changed

4 files changed

+648
-924
lines changed

README.md

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,61 @@
11
# use-web-animation
22

3+
[![npm version](https://badgen.net/npm/v/use-web-animation)](https://www.npmjs.com/package/use-web-animation)
4+
[![Bundle size](https://badgen.net/bundlephobia/minzip/use-web-animation)](https://badgen.net/bundlephobia/minzip/use-web-animation)
5+
6+
This project aims to provide an API to use the [web-animations API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Animations_API)
7+
8+
## useWebAnimation
9+
10+
This package exports 1 function called `useWebAnimation` which allows you to manipulate stylistic properties.
11+
12+
```js
13+
import { useWebAnimation } from 'use-web-animation';
14+
15+
const RotatingAnimation = () => {
16+
const [ref] = useWebAnimation({
17+
from: 0,
18+
to: 180,
19+
property: "transform",
20+
infinite: true,
21+
getValue: (x) => `rotate(${x}deg)`
22+
});
23+
24+
return (
25+
<div
26+
ref={ref}
27+
style={{
28+
backgroundColor: "red",
29+
width: 100,
30+
height: 100,
31+
marginRight: 12
32+
}}
33+
/>
34+
);
35+
};
36+
```
37+
38+
The second returned argument is a `play` function which can be used to imperatively
39+
start playing a paused animation. This function also accepts an `onComplete` callback
40+
which will be called when the animation completes.
41+
42+
Accepted properties:
43+
44+
```ts
45+
type AnimationOptions = {
46+
duration?: number; // How long the animation should take
47+
infinite?: boolean; // Should the animation keep looping?
48+
pause?: boolean; // Start the animation out in a non-playing state
49+
delay?: number; // Delay before starting to animate
50+
easing?: string; // https://developer.mozilla.org/en-US/docs/Web/API/EffectTiming/easing
51+
from: number; // The starting value
52+
to: number; // The ending value
53+
getValue: (x: number) => string; // Function used to inject the value for "from" and "to"
54+
property: string; // The property name
55+
};
56+
```
57+
358
## Examples
459

5-
https://codesandbox.io/s/zealous-rubin-fgdhk?file=/src/use-animation/index.ts
6-
https://codesandbox.io/s/charming-hermann-v4o2h?file=/src/useSpring.ts
60+
- https://codesandbox.io/s/zealous-rubin-fgdhk?file=/src/use-animation/index.ts
61+
- https://codesandbox.io/s/charming-hermann-v4o2h?file=/src/useSpring.ts

package.json

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,9 @@
5050
},
5151
"scripts": {
5252
"build": "rimraf dist && yarn build:preact && yarn build:react",
53-
"build:react": "microbundle --define process.env.NODE_ENV=production --external react --name use-web-animation --no-compress --output dist/",
54-
"build:preact": "microbundle --define process.env.NODE_ENV=production --external preact --name use-web-animation --no-compress --output preact/dist --alias react=./preact/preact.ts",
55-
"build:ci": "microbundle --define process.env.NODE_ENV=production --external preact --name use-web-animation --output dist/"
53+
"build:react": "microbundle --external react --name use-web-animation --output dist/",
54+
"build:preact": "microbundle --external preact --name use-web-animation --output preact/dist --alias react=./preact/preact.ts",
55+
"build:ci": "microbundle --define process.env.NODE_ENV=production --external react --name use-web-animation --output dist/"
5656
},
5757
"prettier": {
5858
"singleQuote": true,
@@ -75,15 +75,15 @@
7575
}
7676
},
7777
"devDependencies": {
78-
"@types/react": "16.9.16",
79-
"@types/react-dom": "16.9.4",
80-
"@typescript-eslint/eslint-plugin": "2.11.0",
81-
"@typescript-eslint/parser": "2.11.0",
82-
"eslint": "6.7.2",
83-
"eslint-config-prettier": "6.7.0",
84-
"eslint-plugin-react": "7.17.0",
85-
"husky": "3.1.0",
86-
"lint-staged": "9.5.0",
78+
"@types/react": "^17.0.14",
79+
"@types/react-dom": "^17.0.9",
80+
"@typescript-eslint/eslint-plugin": "^4.28.4",
81+
"@typescript-eslint/parser": "^4.28.4",
82+
"eslint": "^7.31.0",
83+
"eslint-config-prettier": "^8.3.0",
84+
"eslint-plugin-react": "^7.24.0",
85+
"husky": "^7.0.1",
86+
"lint-staged": "^11.1.0",
8787
"microbundle": "^0.13.3",
8888
"preact": "^10.5.14",
8989
"prettier": "^2.3.2",

src/index.ts

Lines changed: 51 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
import { useRef, useLayoutEffect, useCallback, MutableRefObject } from "react";
22

3-
const DEFAULT_DURATION = 750;
4-
53
export type AnimationOptions = {
64
duration?: number;
75
infinite?: boolean;
@@ -30,53 +28,73 @@ export const useWebAnimation = ({
3028
const animation = useRef<Animation | undefined>();
3129
const reverse = useRef(false);
3230

33-
const animate = useCallback(() => {
34-
const timingObject: KeyframeAnimationOptions = {
35-
duration: duration || DEFAULT_DURATION,
36-
iterations: 1,
37-
delay: delay || 0,
38-
easing,
39-
direction: "normal"
40-
};
41-
reverse.current = false;
31+
const animate = useCallback(
32+
(onComplete?: (() => void)) => {
33+
if (!ref.current || !ref.current.animate) {
34+
if (process.env.NODE_ENV !== 'production') {
35+
throw new Error('Please apply the ref to a dom-element.');
36+
}
37+
return;
38+
}
4239

43-
callback.current = () => {
44-
if (infinite) {
45-
timingObject.direction = reverse.current ? "reverse" : "normal";
46-
reverse.current = !reverse.current;
40+
if (!ref.current.animate) {
41+
ref.current!.style[property as any] = getValue(to);
42+
return;
43+
}
44+
45+
const timingObject: KeyframeAnimationOptions = {
46+
duration: duration || 750,
47+
iterations: 1,
48+
delay,
49+
easing,
50+
};
51+
52+
callback.current = () => {
53+
if (infinite) {
54+
timingObject.direction = reverse.current ? "reverse" : "normal";
55+
reverse.current = !reverse.current;
4756

48-
animation.current = ref.current!.animate(
49-
[{ [property]: getValue(from) }, { [property]: getValue(to) }],
50-
timingObject
51-
);
52-
animation.current.addEventListener("finish", callback.current);
53-
} else {
54-
if (animation.current) {
55-
if (animation.current && callback.current) {
56-
animation.current!.removeEventListener("finish", callback.current);
57-
}
58-
animation.current = undefined;
59-
callback.current = undefined;
60-
} else {
6157
animation.current = ref.current!.animate(
6258
[{ [property]: getValue(from) }, { [property]: getValue(to) }],
6359
timingObject
6460
);
6561
animation.current.addEventListener("finish", callback.current);
62+
} else {
63+
if (animation.current) {
64+
ref.current!.style[property as any] = getValue(to);
65+
if (onComplete) {
66+
onComplete();
67+
}
68+
if (animation.current && callback.current) {
69+
animation.current!.removeEventListener(
70+
"finish",
71+
callback.current
72+
);
73+
}
74+
animation.current = undefined;
75+
callback.current = undefined;
76+
} else {
77+
animation.current = ref.current!.animate(
78+
[{ [property]: getValue(from) }, { [property]: getValue(to) }],
79+
timingObject
80+
);
81+
animation.current.addEventListener("finish", callback.current);
82+
}
6683
}
67-
}
68-
};
84+
};
6985

70-
callback.current();
71-
}, [delay, duration, easing, from, infinite, property, to]);
86+
callback.current();
87+
},
88+
[delay, duration, easing, from, infinite, property, to]
89+
);
7290

7391
useLayoutEffect(() => {
7492
if (!pause) {
7593
animate();
7694
}
7795

7896
return () => {
79-
if (animation.current) {
97+
if (animation.current && !pause) {
8098
if (animation.current && callback.current) {
8199
animation.current!.removeEventListener("finish", callback.current);
82100
}

0 commit comments

Comments
 (0)