react-ui-animate 2.0.0-rc.7 → 3.0.0-rc.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/.vscode/settings.json +3 -3
- package/LICENSE +21 -21
- package/README.md +115 -115
- package/dist/animation/animationType.d.ts +15 -15
- package/dist/animation/core/animation/Animation.d.ts +16 -0
- package/dist/animation/core/animation/FluidValue.d.ts +21 -0
- package/dist/animation/core/animation/RequestAnimationFrame.d.ts +8 -0
- package/dist/animation/core/animation/SpringAnimation.d.ts +41 -0
- package/dist/animation/core/animation/TimingAnimation.d.ts +35 -0
- package/dist/animation/core/animation/TransitionValue.d.ts +21 -0
- package/dist/animation/core/controllers/Animation.d.ts +16 -0
- package/dist/animation/core/controllers/FluidValue.d.ts +32 -0
- package/dist/animation/core/controllers/RequestAnimationFrame.d.ts +8 -0
- package/dist/animation/core/controllers/SpringAnimation.d.ts +41 -0
- package/dist/animation/core/controllers/TimingAnimation.d.ts +35 -0
- package/dist/animation/core/easing/Bezier.d.ts +8 -0
- package/dist/animation/core/easing/Easing.d.ts +40 -0
- package/dist/animation/core/helpers/camelCaseToKebabCase.d.ts +8 -0
- package/dist/animation/core/helpers/camelToDash.d.ts +7 -0
- package/dist/animation/core/helpers/canInterpolate.d.ts +11 -0
- package/dist/animation/core/helpers/getAnimatableObject.d.ts +22 -0
- package/dist/animation/core/helpers/getCleanProps.d.ts +10 -0
- package/dist/animation/core/helpers/getCssValue.d.ts +8 -0
- package/dist/animation/core/helpers/getNonAnimatableStyle.d.ts +6 -0
- package/dist/animation/core/helpers/index.d.ts +5 -0
- package/dist/animation/core/helpers/isDefined.d.ts +12 -0
- package/dist/animation/core/helpers/isFluidValue.d.ts +6 -0
- package/dist/animation/core/index.d.ts +11 -0
- package/dist/animation/core/interpolation/Colors.d.ts +25 -0
- package/dist/animation/core/interpolation/Interpolation.d.ts +80 -0
- package/dist/animation/core/interpolation/__tests__/Colors.test.d.ts +1 -0
- package/dist/animation/core/react/Tags.d.ts +3 -0
- package/dist/animation/core/react/TransformStyles.d.ts +8 -0
- package/dist/animation/core/react/animated.d.ts +29 -0
- package/dist/animation/core/react/combineRefs.d.ts +2 -0
- package/dist/animation/core/react/fluid.d.ts +6 -0
- package/dist/animation/core/react/functions/camelToDash.d.ts +7 -0
- package/dist/animation/core/react/functions/getAnimatableObject.d.ts +22 -0
- package/dist/animation/core/react/functions/getCleanProps.d.ts +4 -0
- package/dist/animation/core/react/functions/getCssValue.d.ts +8 -0
- package/dist/animation/core/react/functions/getNonAnimatableStyle.d.ts +6 -0
- package/dist/animation/core/react/functions/index.d.ts +7 -0
- package/dist/animation/core/react/functions/isDefined.d.ts +6 -0
- package/dist/animation/core/react/functions/isTransitionValue.d.ts +6 -0
- package/dist/animation/core/react/helpers/camelToDash.d.ts +7 -0
- package/dist/animation/core/react/helpers/canInterpolate.d.ts +7 -0
- package/dist/animation/core/react/helpers/getAnimatableObject.d.ts +22 -0
- package/dist/animation/core/react/helpers/getCleanProps.d.ts +4 -0
- package/dist/animation/core/react/helpers/getCssValue.d.ts +8 -0
- package/dist/animation/core/react/helpers/getNonAnimatableStyle.d.ts +6 -0
- package/dist/animation/core/react/helpers/index.d.ts +7 -0
- package/dist/animation/core/react/helpers/isDefined.d.ts +6 -0
- package/dist/animation/core/react/helpers/isFluidValue.d.ts +6 -0
- package/dist/animation/core/react/helpers/isTransitionValue.d.ts +6 -0
- package/dist/animation/core/react/makeFluid.d.ts +30 -0
- package/dist/animation/core/react/transforms.d.ts +6 -0
- package/dist/animation/core/react/useFluidValue.d.ts +9 -0
- package/dist/animation/core/react/useMount.d.ts +20 -0
- package/dist/animation/core/react/useMounts.d.ts +26 -0
- package/dist/animation/core/react/useTransition.d.ts +9 -0
- package/dist/animation/core/react/useTransitions.d.ts +11 -0
- package/dist/animation/core/types/animation.d.ts +54 -0
- package/dist/animation/core/types/common.d.ts +4 -0
- package/dist/animation/core/types/fluid.d.ts +19 -0
- package/dist/animation/core/types/index.d.ts +2 -0
- package/dist/animation/getInitialConfig.d.ts +3 -3
- package/dist/animation/index.d.ts +6 -6
- package/dist/animation/interpolation.d.ts +21 -21
- package/dist/animation/lib/animationType.d.ts +15 -0
- package/dist/animation/lib/getInitialConfig.d.ts +3 -0
- package/dist/animation/lib/index.d.ts +5 -0
- package/dist/animation/lib/interpolation.d.ts +20 -0
- package/dist/animation/lib/modules/AnimatedBlock.d.ts +8 -0
- package/dist/animation/lib/modules/AnimatedImage.d.ts +8 -0
- package/dist/animation/lib/modules/AnimatedInline.d.ts +8 -0
- package/dist/animation/lib/modules/MountedBlock.d.ts +29 -0
- package/dist/animation/lib/modules/ScrollableBlock.d.ts +22 -0
- package/dist/animation/lib/modules/TransitionBlock.d.ts +18 -0
- package/dist/animation/lib/modules/index.d.ts +6 -0
- package/dist/animation/lib/useAnimatedValue.d.ts +17 -0
- package/dist/animation/lib/useMountedValue.d.ts +14 -0
- package/dist/animation/modules/AnimatedBlock.d.ts +8 -8
- package/dist/animation/modules/AnimatedImage.d.ts +8 -8
- package/dist/animation/modules/AnimatedInline.d.ts +8 -8
- package/dist/animation/modules/MountedBlock.d.ts +29 -18
- package/dist/animation/modules/ScrollableBlock.d.ts +21 -21
- package/dist/animation/modules/TransitionBlock.d.ts +17 -17
- package/dist/animation/modules/index.d.ts +6 -6
- package/dist/animation/useAnimatedValue.d.ts +22 -22
- package/dist/animation/useMountedValue.d.ts +15 -15
- package/dist/gestures/controllers/DragGesture.d.ts +17 -17
- package/dist/gestures/controllers/Gesture.d.ts +20 -20
- package/dist/gestures/controllers/MouseMoveGesture.d.ts +13 -13
- package/dist/gestures/controllers/ScrollGesture.d.ts +14 -14
- package/dist/gestures/controllers/WheelGesture.d.ts +15 -15
- package/dist/gestures/controllers/index.d.ts +4 -4
- package/dist/gestures/eventAttacher.d.ts +11 -11
- package/dist/gestures/helpers/eventAttacher.d.ts +11 -0
- package/dist/gestures/helpers/index.d.ts +1 -0
- package/dist/gestures/helpers/math.d.ts +34 -0
- package/dist/gestures/helpers/withDefault.d.ts +4 -0
- package/dist/gestures/hooks/index.d.ts +5 -5
- package/dist/gestures/hooks/useDrag.d.ts +4 -4
- package/dist/gestures/hooks/useGesture.d.ts +9 -9
- package/dist/gestures/hooks/useMouseMove.d.ts +4 -4
- package/dist/gestures/hooks/useRecognizer.d.ts +10 -10
- package/dist/gestures/hooks/useScroll.d.ts +4 -4
- package/dist/gestures/hooks/useWheel.d.ts +4 -4
- package/dist/gestures/index.d.ts +2 -2
- package/dist/gestures/math.d.ts +34 -34
- package/dist/gestures/types.d.ts +51 -51
- package/dist/gestures/withDefault.d.ts +4 -4
- package/dist/hooks/index.d.ts +3 -3
- package/dist/hooks/useMeasure.d.ts +14 -14
- package/dist/hooks/useOutsideClick.d.ts +2 -2
- package/dist/hooks/useWindowDimension.d.ts +9 -9
- package/dist/index.d.ts +9 -5
- package/dist/index.js +2758 -1052
- package/dist/index.js.map +1 -1
- package/dist/utils/delay.d.ts +5 -5
- package/dist/utils/index.d.ts +1 -2
- package/dist/utils/isDefined.d.ts +1 -1
- package/ecosystem.config.js +12 -0
- package/example/README.md +46 -0
- package/example/package-lock.json +19597 -0
- package/example/package.json +45 -0
- package/example/public/favicon.ico +0 -0
- package/example/public/index.html +20 -0
- package/example/public/logo192.png +0 -0
- package/example/public/logo512.png +0 -0
- package/example/public/manifest.json +25 -0
- package/example/public/robots.txt +3 -0
- package/example/src/App.tsx +41 -0
- package/example/src/components/Draggable.tsx +46 -0
- package/example/src/components/Gestures.tsx +151 -0
- package/example/src/components/Interpolation.tsx +21 -0
- package/example/src/components/Loop.tsx +48 -0
- package/example/src/components/MountedBlock.tsx +25 -0
- package/example/src/components/MouseMove.tsx +59 -0
- package/example/src/components/MultistageTransition.tsx +34 -0
- package/example/src/components/Scroll.tsx +39 -0
- package/example/src/components/ScrollableBlock.tsx +27 -0
- package/example/src/components/SnapTo.tsx +55 -0
- package/example/src/components/TransitionBlock.tsx +37 -0
- package/example/src/components/Wheel.tsx +39 -0
- package/example/src/components/index.ts +18 -0
- package/example/src/components/svgLine.tsx +48 -0
- package/example/src/components/useAnimatedValue.tsx +57 -0
- package/example/src/components/useMountedValue.tsx +62 -0
- package/example/src/index.css +8 -0
- package/example/src/index.tsx +16 -0
- package/example/tsconfig.json +26 -0
- package/package.json +48 -48
- package/{rollup.config.js → rollup.config.mjs} +18 -18
- package/src/animation/core/controllers/Animation.ts +27 -0
- package/src/animation/core/controllers/FluidValue.ts +97 -0
- package/src/animation/core/controllers/RequestAnimationFrame.ts +13 -0
- package/src/animation/core/controllers/SpringAnimation.ts +218 -0
- package/src/animation/core/controllers/TimingAnimation.ts +152 -0
- package/src/animation/core/easing/Bezier.ts +146 -0
- package/src/animation/core/easing/Easing.ts +132 -0
- package/src/animation/core/helpers/camelCaseToKebabCase.ts +10 -0
- package/src/animation/core/helpers/getCleanProps.ts +16 -0
- package/src/animation/core/helpers/getCssValue.ts +60 -0
- package/src/animation/core/helpers/index.ts +5 -0
- package/src/animation/core/helpers/isDefined.ts +14 -0
- package/src/animation/core/helpers/isFluidValue.ts +11 -0
- package/src/animation/core/index.ts +16 -0
- package/src/animation/core/interpolation/Colors.ts +232 -0
- package/src/animation/core/interpolation/Interpolation.ts +395 -0
- package/src/animation/core/interpolation/__tests__/Colors.test.tsx +35 -0
- package/src/animation/core/react/fluid.ts +197 -0
- package/src/animation/core/react/makeFluid.ts +294 -0
- package/src/animation/core/react/transforms.ts +90 -0
- package/src/animation/core/react/useFluidValue.ts +43 -0
- package/src/animation/core/react/useMount.ts +58 -0
- package/src/animation/core/types/animation.d.ts +56 -0
- package/src/animation/core/types/common.d.ts +4 -0
- package/src/animation/core/types/fluid.d.ts +38 -0
- package/src/animation/{animationType.ts → lib/animationType.ts} +17 -17
- package/src/animation/{getInitialConfig.ts → lib/getInitialConfig.ts} +61 -61
- package/src/animation/lib/index.ts +12 -0
- package/src/animation/{interpolation.ts → lib/interpolation.ts} +47 -48
- package/src/animation/{modules → lib/modules}/AnimatedBlock.ts +8 -8
- package/src/animation/{modules → lib/modules}/AnimatedImage.ts +8 -8
- package/src/animation/{modules → lib/modules}/AnimatedInline.ts +8 -8
- package/src/animation/lib/modules/MountedBlock.tsx +51 -0
- package/src/animation/{modules → lib/modules}/ScrollableBlock.tsx +68 -69
- package/src/animation/{modules → lib/modules}/TransitionBlock.tsx +28 -29
- package/src/animation/{modules → lib/modules}/index.ts +6 -6
- package/src/animation/{useAnimatedValue.ts → lib/useAnimatedValue.ts} +60 -71
- package/src/animation/{useMountedValue.ts → lib/useMountedValue.ts} +18 -19
- package/src/gestures/controllers/DragGesture.ts +178 -177
- package/src/gestures/controllers/Gesture.ts +54 -54
- package/src/gestures/controllers/MouseMoveGesture.ts +111 -111
- package/src/gestures/controllers/ScrollGesture.ts +107 -107
- package/src/gestures/controllers/WheelGesture.ts +123 -123
- package/src/gestures/controllers/index.ts +4 -4
- package/src/gestures/{eventAttacher.ts → helpers/eventAttacher.ts} +67 -67
- package/src/gestures/helpers/index.ts +1 -0
- package/src/gestures/{math.ts → helpers/math.ts} +120 -120
- package/src/gestures/{withDefault.ts → helpers/withDefault.ts} +3 -3
- package/src/gestures/hooks/index.ts +5 -5
- package/src/gestures/hooks/useDrag.ts +14 -14
- package/src/gestures/hooks/useGesture.ts +38 -38
- package/src/gestures/hooks/useMouseMove.ts +11 -11
- package/src/gestures/hooks/useRecognizer.ts +59 -59
- package/src/gestures/hooks/useScroll.ts +11 -11
- package/src/gestures/hooks/useWheel.ts +11 -11
- package/src/gestures/{types.ts → types/index.d.ts} +49 -49
- package/src/hooks/index.ts +3 -3
- package/src/hooks/useMeasure.ts +132 -133
- package/src/hooks/useOutsideClick.ts +36 -36
- package/src/hooks/useWindowDimension.ts +58 -59
- package/src/index.ts +42 -5
- package/src/utils/delay.ts +9 -9
- package/src/utils/index.ts +1 -2
- package/tsconfig.json +24 -25
- package/src/animation/index.ts +0 -10
- package/src/animation/modules/MountedBlock.tsx +0 -25
- package/src/gestures/index.ts +0 -2
- package/src/utils/isDefined.ts +0 -4
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import { Animation } from './Animation';
|
|
2
|
+
import {
|
|
3
|
+
RequestAnimationFrame,
|
|
4
|
+
CancelAnimationFrame,
|
|
5
|
+
} from './RequestAnimationFrame';
|
|
6
|
+
|
|
7
|
+
import type { FluidValueConfig, ResultType } from '../types/animation';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Class implementing spring based animation
|
|
11
|
+
*/
|
|
12
|
+
export class SpringAnimation extends Animation {
|
|
13
|
+
_overshootClamping: boolean;
|
|
14
|
+
_restDisplacementThreshold: number;
|
|
15
|
+
_restSpeedThreshold: number;
|
|
16
|
+
_initialVelocity?: number;
|
|
17
|
+
_lastVelocity: number;
|
|
18
|
+
_startPosition: number;
|
|
19
|
+
_lastPosition: number;
|
|
20
|
+
_position: number;
|
|
21
|
+
_fromValue: number;
|
|
22
|
+
_toValue: any;
|
|
23
|
+
_mass: number;
|
|
24
|
+
_tension: number;
|
|
25
|
+
_friction: number;
|
|
26
|
+
_lastTime: number;
|
|
27
|
+
_onFrame: (value: number) => void;
|
|
28
|
+
_animationFrame: any;
|
|
29
|
+
_timeout: any;
|
|
30
|
+
|
|
31
|
+
// Modifiers
|
|
32
|
+
_delay: number;
|
|
33
|
+
_onRest?: (value: ResultType) => void;
|
|
34
|
+
_onChange?: (value: number) => void;
|
|
35
|
+
|
|
36
|
+
constructor({
|
|
37
|
+
initialPosition,
|
|
38
|
+
config,
|
|
39
|
+
}: {
|
|
40
|
+
initialPosition: number;
|
|
41
|
+
config?: Omit<FluidValueConfig, 'duration' | 'easing'>;
|
|
42
|
+
}) {
|
|
43
|
+
super();
|
|
44
|
+
|
|
45
|
+
this._overshootClamping = false;
|
|
46
|
+
this._initialVelocity = 0;
|
|
47
|
+
this._lastVelocity = 0;
|
|
48
|
+
this._startPosition = initialPosition;
|
|
49
|
+
this._position = this._startPosition;
|
|
50
|
+
|
|
51
|
+
this._restDisplacementThreshold = config?.restDistance ?? 0.001;
|
|
52
|
+
this._restSpeedThreshold = config?.restDistance ?? 0.001;
|
|
53
|
+
this._mass = config?.mass ?? 1;
|
|
54
|
+
this._tension = config?.tension ?? 170;
|
|
55
|
+
this._friction = config?.friction ?? 26;
|
|
56
|
+
this._delay = config?.delay ?? 0;
|
|
57
|
+
|
|
58
|
+
this._onRest = config?.onRest;
|
|
59
|
+
this._onChange = config?.onChange;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
onChange(value: number) {
|
|
63
|
+
this._onFrame(value);
|
|
64
|
+
|
|
65
|
+
if (this._lastPosition !== value) {
|
|
66
|
+
if (this._onChange) {
|
|
67
|
+
this._onChange(value);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
this._lastPosition = value;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
onUpdate() {
|
|
75
|
+
var now = Date.now();
|
|
76
|
+
|
|
77
|
+
const deltaTime = Math.min(now - this._lastTime, 64);
|
|
78
|
+
this._lastTime = now;
|
|
79
|
+
|
|
80
|
+
const c = this._friction;
|
|
81
|
+
const m = this._mass;
|
|
82
|
+
const k = this._tension;
|
|
83
|
+
|
|
84
|
+
const v0 = -this._lastVelocity;
|
|
85
|
+
const x0 = this._toValue - this._position;
|
|
86
|
+
|
|
87
|
+
const zeta = c / (2 * Math.sqrt(k * m)); // damping ratio
|
|
88
|
+
const omega0 = Math.sqrt(k / m); // undamped angular frequency of the oscillator (rad/ms)
|
|
89
|
+
const omega1 = omega0 * Math.sqrt(1 - zeta ** 2); // exponential decay
|
|
90
|
+
|
|
91
|
+
const t = deltaTime / 1000;
|
|
92
|
+
|
|
93
|
+
const sin1 = Math.sin(omega1 * t);
|
|
94
|
+
const cos1 = Math.cos(omega1 * t);
|
|
95
|
+
|
|
96
|
+
// under damped
|
|
97
|
+
const underDampedEnvelope = Math.exp(-zeta * omega0 * t);
|
|
98
|
+
const underDampedFrag1 =
|
|
99
|
+
underDampedEnvelope *
|
|
100
|
+
(sin1 * ((v0 + zeta * omega0 * x0) / omega1) + x0 * cos1);
|
|
101
|
+
|
|
102
|
+
const underDampedPosition = this._toValue - underDampedFrag1;
|
|
103
|
+
// This looks crazy -- it's actually just the derivative of the oscillation function
|
|
104
|
+
const underDampedVelocity =
|
|
105
|
+
zeta * omega0 * underDampedFrag1 -
|
|
106
|
+
underDampedEnvelope *
|
|
107
|
+
(cos1 * (v0 + zeta * omega0 * x0) - omega1 * x0 * sin1);
|
|
108
|
+
|
|
109
|
+
// critically damped
|
|
110
|
+
const criticallyDampedEnvelope = Math.exp(-omega0 * t);
|
|
111
|
+
const criticallyDampedPosition =
|
|
112
|
+
this._toValue - criticallyDampedEnvelope * (x0 + (v0 + omega0 * x0) * t);
|
|
113
|
+
|
|
114
|
+
const criticallyDampedVelocity =
|
|
115
|
+
criticallyDampedEnvelope *
|
|
116
|
+
(v0 * (t * omega0 - 1) + t * x0 * omega0 * omega0);
|
|
117
|
+
|
|
118
|
+
this.onChange(this._position);
|
|
119
|
+
|
|
120
|
+
const isOvershooting = () => {
|
|
121
|
+
if (this._overshootClamping && this._tension !== 0) {
|
|
122
|
+
return this._position < this._toValue
|
|
123
|
+
? this._position > this._toValue
|
|
124
|
+
: this._position < this._toValue;
|
|
125
|
+
} else {
|
|
126
|
+
return false;
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
const isVelocity = Math.abs(this._lastVelocity) < this._restSpeedThreshold;
|
|
131
|
+
const isDisplacement =
|
|
132
|
+
this._tension === 0 ||
|
|
133
|
+
Math.abs(this._toValue - this._position) <
|
|
134
|
+
this._restDisplacementThreshold;
|
|
135
|
+
|
|
136
|
+
if (zeta < 1) {
|
|
137
|
+
this._position = underDampedPosition;
|
|
138
|
+
this._lastVelocity = underDampedVelocity;
|
|
139
|
+
} else {
|
|
140
|
+
this._position = criticallyDampedPosition;
|
|
141
|
+
this._lastVelocity = criticallyDampedVelocity;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (isOvershooting() || (isVelocity && isDisplacement)) {
|
|
145
|
+
if (this._tension !== 0) {
|
|
146
|
+
this._lastVelocity = 0;
|
|
147
|
+
this._position = this._toValue;
|
|
148
|
+
|
|
149
|
+
this.onChange(this._position);
|
|
150
|
+
}
|
|
151
|
+
// clear lastTimestamp to avoid using stale value by the next spring animation that starts after this one
|
|
152
|
+
this._lastTime = 0;
|
|
153
|
+
|
|
154
|
+
this._debounceOnEnd({ finished: true, value: this._toValue });
|
|
155
|
+
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
this._animationFrame = RequestAnimationFrame.current(
|
|
160
|
+
this.onUpdate.bind(this)
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
stop() {
|
|
165
|
+
this._active = false;
|
|
166
|
+
clearTimeout(this._timeout);
|
|
167
|
+
CancelAnimationFrame.current(this._animationFrame);
|
|
168
|
+
this._debounceOnEnd({ finished: false, value: this._position });
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Set value
|
|
172
|
+
set(toValue: number) {
|
|
173
|
+
this.stop();
|
|
174
|
+
this._position = toValue;
|
|
175
|
+
this._lastTime = 0;
|
|
176
|
+
this._lastVelocity = 0;
|
|
177
|
+
this.onChange(toValue);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
start({
|
|
181
|
+
toValue,
|
|
182
|
+
onFrame,
|
|
183
|
+
previousAnimation,
|
|
184
|
+
onEnd,
|
|
185
|
+
}: {
|
|
186
|
+
toValue: number;
|
|
187
|
+
onFrame: (value: number) => void;
|
|
188
|
+
previousAnimation?: SpringAnimation;
|
|
189
|
+
onEnd?: (result: ResultType) => void;
|
|
190
|
+
}) {
|
|
191
|
+
const onStart: any = () => {
|
|
192
|
+
this._onFrame = onFrame;
|
|
193
|
+
this._active = true;
|
|
194
|
+
this._toValue = toValue;
|
|
195
|
+
this._onEnd = onEnd;
|
|
196
|
+
|
|
197
|
+
const now = Date.now();
|
|
198
|
+
|
|
199
|
+
if (previousAnimation instanceof SpringAnimation) {
|
|
200
|
+
this._lastVelocity =
|
|
201
|
+
previousAnimation._lastVelocity || this._lastVelocity || 0;
|
|
202
|
+
this._lastTime = previousAnimation._lastTime || now;
|
|
203
|
+
} else {
|
|
204
|
+
this._lastTime = now;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
this._animationFrame = RequestAnimationFrame.current(
|
|
208
|
+
this.onUpdate.bind(this)
|
|
209
|
+
);
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
if (this._delay !== 0) {
|
|
213
|
+
this._timeout = setTimeout(() => onStart(), this._delay);
|
|
214
|
+
} else {
|
|
215
|
+
onStart();
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { Animation } from './Animation';
|
|
2
|
+
import {
|
|
3
|
+
RequestAnimationFrame,
|
|
4
|
+
CancelAnimationFrame,
|
|
5
|
+
} from './RequestAnimationFrame';
|
|
6
|
+
import { Easing } from '../easing/Easing';
|
|
7
|
+
|
|
8
|
+
import type { FluidValueConfig, ResultType } from '../types/animation';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Class implementing timing based animation
|
|
12
|
+
*/
|
|
13
|
+
export class TimingAnimation extends Animation {
|
|
14
|
+
_startTime: number;
|
|
15
|
+
_fromValue: number;
|
|
16
|
+
_toValue: any;
|
|
17
|
+
_duration: number;
|
|
18
|
+
_easing: (value: number) => number;
|
|
19
|
+
_onFrame: (value: number) => void;
|
|
20
|
+
_animationFrame: any;
|
|
21
|
+
_timeout: any;
|
|
22
|
+
_lastPosition: number;
|
|
23
|
+
_position: number;
|
|
24
|
+
|
|
25
|
+
// Modifiers
|
|
26
|
+
_delay: number;
|
|
27
|
+
_tempDuration: number;
|
|
28
|
+
_onRest?: (value: ResultType) => void;
|
|
29
|
+
_onChange?: (value: number) => void;
|
|
30
|
+
|
|
31
|
+
constructor({
|
|
32
|
+
initialPosition,
|
|
33
|
+
config,
|
|
34
|
+
}: {
|
|
35
|
+
initialPosition: number;
|
|
36
|
+
config?: Omit<FluidValueConfig, 'mass' | 'friction' | 'tension'>;
|
|
37
|
+
}) {
|
|
38
|
+
super();
|
|
39
|
+
|
|
40
|
+
this._fromValue = initialPosition;
|
|
41
|
+
this._position = this._fromValue;
|
|
42
|
+
this._easing = config?.easing ?? Easing.linear;
|
|
43
|
+
this._duration = config?.duration ?? 500;
|
|
44
|
+
this._tempDuration = this._duration;
|
|
45
|
+
|
|
46
|
+
// Modifiers
|
|
47
|
+
// here immediate acts like duration: 0
|
|
48
|
+
if (config?.immediate) {
|
|
49
|
+
this._duration = 0;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
this._delay = config?.delay ?? 0;
|
|
53
|
+
this._onRest = config?.onRest;
|
|
54
|
+
this._onChange = config?.onChange;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
onChange(value: number) {
|
|
58
|
+
this._onFrame(value);
|
|
59
|
+
|
|
60
|
+
if (this._lastPosition !== value) {
|
|
61
|
+
if (this._onChange) {
|
|
62
|
+
this._onChange(value);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
this._lastPosition = value;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
onUpdate() {
|
|
70
|
+
const now = Date.now();
|
|
71
|
+
|
|
72
|
+
const runTime = now - this._startTime;
|
|
73
|
+
|
|
74
|
+
if (runTime >= this._duration) {
|
|
75
|
+
this._startTime = 0;
|
|
76
|
+
this._position = this._toValue;
|
|
77
|
+
|
|
78
|
+
this.onChange(this._position);
|
|
79
|
+
|
|
80
|
+
this._debounceOnEnd({ finished: true, value: this._position });
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const progress = this._easing(runTime / this._duration);
|
|
85
|
+
|
|
86
|
+
this._position =
|
|
87
|
+
this._fromValue + (this._toValue - this._fromValue) * progress;
|
|
88
|
+
|
|
89
|
+
this.onChange(this._position);
|
|
90
|
+
|
|
91
|
+
this._animationFrame = RequestAnimationFrame.current(
|
|
92
|
+
this.onUpdate.bind(this)
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
stop() {
|
|
97
|
+
this._active = false;
|
|
98
|
+
clearTimeout(this._timeout);
|
|
99
|
+
CancelAnimationFrame.current(this._animationFrame);
|
|
100
|
+
this._debounceOnEnd({ finished: false, value: this._position });
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Set value
|
|
104
|
+
set(toValue: number) {
|
|
105
|
+
this.stop();
|
|
106
|
+
this._position = toValue;
|
|
107
|
+
this.onChange(toValue);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
start({
|
|
111
|
+
toValue,
|
|
112
|
+
onFrame,
|
|
113
|
+
previousAnimation,
|
|
114
|
+
onEnd,
|
|
115
|
+
}: {
|
|
116
|
+
toValue: number;
|
|
117
|
+
onFrame: (value: number) => void;
|
|
118
|
+
previousAnimation?: TimingAnimation;
|
|
119
|
+
onEnd?: (result: ResultType) => void;
|
|
120
|
+
}) {
|
|
121
|
+
const onStart: any = () => {
|
|
122
|
+
this._onFrame = onFrame;
|
|
123
|
+
this._active = true;
|
|
124
|
+
this._onEnd = onEnd;
|
|
125
|
+
this._toValue = toValue;
|
|
126
|
+
|
|
127
|
+
if (
|
|
128
|
+
previousAnimation &&
|
|
129
|
+
previousAnimation instanceof TimingAnimation &&
|
|
130
|
+
previousAnimation._toValue === toValue &&
|
|
131
|
+
previousAnimation._startTime
|
|
132
|
+
) {
|
|
133
|
+
this._startTime = previousAnimation._startTime;
|
|
134
|
+
this._fromValue = previousAnimation._fromValue;
|
|
135
|
+
} else {
|
|
136
|
+
const now = Date.now();
|
|
137
|
+
this._startTime = now;
|
|
138
|
+
this._fromValue = this._position;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
this._animationFrame = RequestAnimationFrame.current(
|
|
142
|
+
this.onUpdate.bind(this)
|
|
143
|
+
);
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
if (this._delay !== 0) {
|
|
147
|
+
this._timeout = setTimeout(() => onStart(), this._delay);
|
|
148
|
+
} else {
|
|
149
|
+
onStart();
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* https://github.com/gre/bezier-easing
|
|
3
|
+
* BezierEasing - use bezier curve for transition easing function
|
|
4
|
+
* by Gaëtan Renaudeau 2014 - 2015 – MIT License
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
// These values are established by empiricism with tests (tradeoff: performance VS precision)
|
|
8
|
+
var NEWTON_ITERATIONS = 4;
|
|
9
|
+
var NEWTON_MIN_SLOPE = 0.001;
|
|
10
|
+
var SUBDIVISION_PRECISION = 0.0000001;
|
|
11
|
+
var SUBDIVISION_MAX_ITERATIONS = 10;
|
|
12
|
+
|
|
13
|
+
var kSplineTableSize = 11;
|
|
14
|
+
var kSampleStepSize = 1.0 / (kSplineTableSize - 1.0);
|
|
15
|
+
|
|
16
|
+
var float32ArraySupported = typeof Float32Array === "function";
|
|
17
|
+
|
|
18
|
+
function A(aA1: number, aA2: number) {
|
|
19
|
+
return 1.0 - 3.0 * aA2 + 3.0 * aA1;
|
|
20
|
+
}
|
|
21
|
+
function B(aA1: number, aA2: number) {
|
|
22
|
+
return 3.0 * aA2 - 6.0 * aA1;
|
|
23
|
+
}
|
|
24
|
+
function C(aA1: number) {
|
|
25
|
+
return 3.0 * aA1;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Returns x(t) given t, x1, and x2, or y(t) given t, y1, and y2.
|
|
29
|
+
function calcBezier(aT: number, aA1: number, aA2: number) {
|
|
30
|
+
return ((A(aA1, aA2) * aT + B(aA1, aA2)) * aT + C(aA1)) * aT;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Returns dx/dt given t, x1, and x2, or dy/dt given t, y1, and y2.
|
|
34
|
+
function getSlope(aT: number, aA1: number, aA2: number) {
|
|
35
|
+
return 3.0 * A(aA1, aA2) * aT * aT + 2.0 * B(aA1, aA2) * aT + C(aA1);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function binarySubdivide(
|
|
39
|
+
aX: number,
|
|
40
|
+
aA: number,
|
|
41
|
+
aB: number,
|
|
42
|
+
mX1: number,
|
|
43
|
+
mX2: number
|
|
44
|
+
) {
|
|
45
|
+
var currentX,
|
|
46
|
+
currentT,
|
|
47
|
+
i = 0;
|
|
48
|
+
do {
|
|
49
|
+
currentT = aA + (aB - aA) / 2.0;
|
|
50
|
+
currentX = calcBezier(currentT, mX1, mX2) - aX;
|
|
51
|
+
if (currentX > 0.0) {
|
|
52
|
+
aB = currentT;
|
|
53
|
+
} else {
|
|
54
|
+
aA = currentT;
|
|
55
|
+
}
|
|
56
|
+
} while (
|
|
57
|
+
Math.abs(currentX) > SUBDIVISION_PRECISION &&
|
|
58
|
+
++i < SUBDIVISION_MAX_ITERATIONS
|
|
59
|
+
);
|
|
60
|
+
return currentT;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function newtonRaphsonIterate(
|
|
64
|
+
aX: number,
|
|
65
|
+
aGuessT: number,
|
|
66
|
+
mX1: number,
|
|
67
|
+
mX2: number
|
|
68
|
+
) {
|
|
69
|
+
for (var i = 0; i < NEWTON_ITERATIONS; ++i) {
|
|
70
|
+
var currentSlope = getSlope(aGuessT, mX1, mX2);
|
|
71
|
+
if (currentSlope === 0.0) {
|
|
72
|
+
return aGuessT;
|
|
73
|
+
}
|
|
74
|
+
var currentX = calcBezier(aGuessT, mX1, mX2) - aX;
|
|
75
|
+
aGuessT -= currentX / currentSlope;
|
|
76
|
+
}
|
|
77
|
+
return aGuessT;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function LinearEasing(x: number) {
|
|
81
|
+
return x;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function bezier(mX1: number, mY1: number, mX2: number, mY2: number) {
|
|
85
|
+
if (!(0 <= mX1 && mX1 <= 1 && 0 <= mX2 && mX2 <= 1)) {
|
|
86
|
+
throw new Error("bezier x values must be in [0, 1] range");
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (mX1 === mY1 && mX2 === mY2) {
|
|
90
|
+
return LinearEasing;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Precompute samples table
|
|
94
|
+
var sampleValues = float32ArraySupported
|
|
95
|
+
? new Float32Array(kSplineTableSize)
|
|
96
|
+
: new Array(kSplineTableSize);
|
|
97
|
+
for (var i = 0; i < kSplineTableSize; ++i) {
|
|
98
|
+
sampleValues[i] = calcBezier(i * kSampleStepSize, mX1, mX2);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function getTForX(aX: number) {
|
|
102
|
+
var intervalStart = 0.0;
|
|
103
|
+
var currentSample = 1;
|
|
104
|
+
var lastSample = kSplineTableSize - 1;
|
|
105
|
+
|
|
106
|
+
for (
|
|
107
|
+
;
|
|
108
|
+
currentSample !== lastSample && sampleValues[currentSample] <= aX;
|
|
109
|
+
++currentSample
|
|
110
|
+
) {
|
|
111
|
+
intervalStart += kSampleStepSize;
|
|
112
|
+
}
|
|
113
|
+
--currentSample;
|
|
114
|
+
|
|
115
|
+
// Interpolate to provide an initial guess for t
|
|
116
|
+
var dist =
|
|
117
|
+
(aX - sampleValues[currentSample]) /
|
|
118
|
+
(sampleValues[currentSample + 1] - sampleValues[currentSample]);
|
|
119
|
+
var guessForT = intervalStart + dist * kSampleStepSize;
|
|
120
|
+
|
|
121
|
+
var initialSlope = getSlope(guessForT, mX1, mX2);
|
|
122
|
+
if (initialSlope >= NEWTON_MIN_SLOPE) {
|
|
123
|
+
return newtonRaphsonIterate(aX, guessForT, mX1, mX2);
|
|
124
|
+
} else if (initialSlope === 0.0) {
|
|
125
|
+
return guessForT;
|
|
126
|
+
} else {
|
|
127
|
+
return binarySubdivide(
|
|
128
|
+
aX,
|
|
129
|
+
intervalStart,
|
|
130
|
+
intervalStart + kSampleStepSize,
|
|
131
|
+
mX1,
|
|
132
|
+
mX2
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return function BezierEasing(x: number) {
|
|
138
|
+
// Because JavaScript number are imprecise, we should guarantee the extremes are right.
|
|
139
|
+
if (x === 0 || x === 1) {
|
|
140
|
+
return x;
|
|
141
|
+
}
|
|
142
|
+
return calcBezier(getTForX(x), mY1, mY2);
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export { bezier };
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2015-present, Facebook, Inc.
|
|
3
|
+
* All rights reserved.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*
|
|
8
|
+
*/
|
|
9
|
+
import { bezier as _bezier } from "./Bezier";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* This class implements common easing functions. The math is pretty obscure,
|
|
13
|
+
* but this cool website has nice visual illustrations of what they represent:
|
|
14
|
+
* http://xaedes.de/dev/transitions/
|
|
15
|
+
*/
|
|
16
|
+
export class Easing {
|
|
17
|
+
static step0(n: number) {
|
|
18
|
+
return n > 0 ? 1 : 0;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
static step1(n: number) {
|
|
22
|
+
return n >= 1 ? 1 : 0;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
static linear(t: number) {
|
|
26
|
+
return t;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
static ease(t: number): number {
|
|
30
|
+
return ease(t);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
static quad(t: number) {
|
|
34
|
+
return t * t;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
static cubic(t: number) {
|
|
38
|
+
return t * t * t;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
static poly(n: number) {
|
|
42
|
+
return (t: number) => Math.pow(t, n);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
static sin(t: number) {
|
|
46
|
+
return 1 - Math.cos((t * Math.PI) / 2);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
static circle(t: number) {
|
|
50
|
+
return 1 - Math.sqrt(1 - t * t);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
static exp(t: number) {
|
|
54
|
+
return Math.pow(2, 10 * (t - 1));
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* A simple elastic interaction, similar to a spring. Default bounciness
|
|
59
|
+
* is 1, which overshoots a little bit once. 0 bounciness doesn't overshoot
|
|
60
|
+
* at all, and bounciness of N > 1 will overshoot about N times.
|
|
61
|
+
*
|
|
62
|
+
* Wolfram Plots:
|
|
63
|
+
*
|
|
64
|
+
* http://tiny.cc/elastic_b_1 (default bounciness = 1)
|
|
65
|
+
* http://tiny.cc/elastic_b_3 (bounciness = 3)
|
|
66
|
+
*/
|
|
67
|
+
static elastic(bounciness: number = 1): (t: number) => number {
|
|
68
|
+
var p = bounciness * Math.PI;
|
|
69
|
+
return (t) =>
|
|
70
|
+
1 - Math.pow(Math.cos((t * Math.PI) / 2), 3) * Math.cos(t * p);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
static back(s: number): (t: number) => number {
|
|
74
|
+
if (s === undefined) {
|
|
75
|
+
s = 1.70158;
|
|
76
|
+
}
|
|
77
|
+
return (t) => t * t * ((s + 1) * t - s);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
static bounce(t: number): number {
|
|
81
|
+
if (t < 1 / 2.75) {
|
|
82
|
+
return 7.5625 * t * t;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (t < 2 / 2.75) {
|
|
86
|
+
t -= 1.5 / 2.75;
|
|
87
|
+
return 7.5625 * t * t + 0.75;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (t < 2.5 / 2.75) {
|
|
91
|
+
t -= 2.25 / 2.75;
|
|
92
|
+
return 7.5625 * t * t + 0.9375;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
t -= 2.625 / 2.75;
|
|
96
|
+
return 7.5625 * t * t + 0.984375;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
static bezier(
|
|
100
|
+
x1: number,
|
|
101
|
+
y1: number,
|
|
102
|
+
x2: number,
|
|
103
|
+
y2: number
|
|
104
|
+
): (t: number) => number {
|
|
105
|
+
return _bezier(x1, y1, x2, y2);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
static in(easing: (t: number) => number): (t: number) => number {
|
|
109
|
+
return easing;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Runs an easing function backwards.
|
|
114
|
+
*/
|
|
115
|
+
static out(easing: (t: number) => number): (t: number) => number {
|
|
116
|
+
return (t) => 1 - easing(1 - t);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Makes any easing function symmetrical.
|
|
121
|
+
*/
|
|
122
|
+
static inOut(easing: (t: number) => number): (t: number) => number {
|
|
123
|
+
return (t) => {
|
|
124
|
+
if (t < 0.5) {
|
|
125
|
+
return easing(t * 2) / 2;
|
|
126
|
+
}
|
|
127
|
+
return 1 - easing((1 - t) * 2) / 2;
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
var ease = Easing.bezier(0.42, 0, 1, 1);
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Converts a camelCase string to kebab-case.
|
|
3
|
+
* e.g. backgroundColor -> background-color
|
|
4
|
+
*
|
|
5
|
+
* @param str - The camelCase string to convert.
|
|
6
|
+
* @returns The converted kebab-case string.
|
|
7
|
+
*/
|
|
8
|
+
export function camelCaseToKebabCase(str: string): string {
|
|
9
|
+
return str.replace(/([A-Z])/g, (match) => '-' + match.toLowerCase());
|
|
10
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { isFluidValue } from './isFluidValue';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Filters out properties with fluid values from a given props object.
|
|
5
|
+
* This function removes any properties that are considered fluid values,
|
|
6
|
+
* typically those that subscribe to updates and therefore should not be
|
|
7
|
+
* included in a static props object.
|
|
8
|
+
*
|
|
9
|
+
* @param props - The original props object, which may include fluid values.
|
|
10
|
+
* @returns A new props object with fluid values removed.
|
|
11
|
+
*/
|
|
12
|
+
export const getCleanProps = ({ style, ...props }: any) => {
|
|
13
|
+
return Object.fromEntries(
|
|
14
|
+
Object.entries(props).filter(([_, value]) => !isFluidValue(value))
|
|
15
|
+
) as any;
|
|
16
|
+
};
|