motion-on-native 1.2.7 → 1.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/README.md +13 -12
- package/lib/index.d.ts +12 -5
- package/lib/index.js +165 -103
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -23,25 +23,19 @@ This package requires:
|
|
|
23
23
|
```tsx
|
|
24
24
|
import { NativeMotion } from 'motion-on-native';
|
|
25
25
|
|
|
26
|
-
//
|
|
26
|
+
// Controlled animation
|
|
27
27
|
<NativeMotion.View
|
|
28
28
|
initial={{ opacity: 0, x: -100 }}
|
|
29
29
|
animate={{ opacity: 1, x: 0 }}
|
|
30
|
+
exit={{ opacity: 0, scale: 0 }}
|
|
31
|
+
shouldAnimate={shouldShow}
|
|
32
|
+
shouldDeAnimate={shouldHide}
|
|
33
|
+
shouldExit={shouldExit}
|
|
30
34
|
transition={{ type: 'spring', damping: 15 }}
|
|
35
|
+
onExitComplete={() => console.log('Exit animation complete')}
|
|
31
36
|
>
|
|
32
37
|
<Text>Animated content</Text>
|
|
33
38
|
</NativeMotion.View>
|
|
34
|
-
|
|
35
|
-
// Exit animation
|
|
36
|
-
<NativeMotion.View
|
|
37
|
-
initial={{ opacity: 0, scale: 0.5 }}
|
|
38
|
-
animate={{ opacity: 1, scale: 1 }}
|
|
39
|
-
exit={{ opacity: 0, scale: 0 }}
|
|
40
|
-
shouldExit={shouldHide}
|
|
41
|
-
onExitComplete={() => console.log('Animation complete')}
|
|
42
|
-
>
|
|
43
|
-
<Text>Content with exit animation</Text>
|
|
44
|
-
</NativeMotion.View>
|
|
45
39
|
```
|
|
46
40
|
|
|
47
41
|
## Components
|
|
@@ -52,6 +46,13 @@ import { NativeMotion } from 'motion-on-native';
|
|
|
52
46
|
- `NativeMotion.TextInput`
|
|
53
47
|
- `NativeMotion.TouchableOpacity`
|
|
54
48
|
|
|
49
|
+
## Animation Control Props
|
|
50
|
+
|
|
51
|
+
- `shouldAnimate`: boolean - Triggers animation from `initial` to `animate`
|
|
52
|
+
- `shouldDeAnimate`: boolean - Triggers animation from `animate` back to `initial`
|
|
53
|
+
- `shouldExit`: boolean - Triggers animation from current state to `exit` (element stays mounted)
|
|
54
|
+
- `onExitComplete`: callback - Called when exit animation completes
|
|
55
|
+
|
|
55
56
|
## Animation Properties
|
|
56
57
|
|
|
57
58
|
- `opacity`: 0-1
|
package/lib/index.d.ts
CHANGED
|
@@ -78,6 +78,8 @@ export interface MotionComponentProps {
|
|
|
78
78
|
animate?: AnimationProps;
|
|
79
79
|
exit?: AnimationProps;
|
|
80
80
|
transition?: TransitionProps;
|
|
81
|
+
shouldAnimate?: boolean;
|
|
82
|
+
shouldDeAnimate?: boolean;
|
|
81
83
|
shouldExit?: boolean;
|
|
82
84
|
onExitComplete?: () => void;
|
|
83
85
|
whileHover?: AnimationProps;
|
|
@@ -89,9 +91,14 @@ export interface MotionComponentProps {
|
|
|
89
91
|
children?: React.ReactNode;
|
|
90
92
|
}
|
|
91
93
|
export declare const NativeMotion: {
|
|
92
|
-
View: (props: MotionComponentProps & import("react-native").ViewProps) => React.ReactElement<import("react-native-reanimated").AnimateProps<any>, string | React.JSXElementConstructor<any
|
|
93
|
-
Text: (props: MotionComponentProps & import("react-native").TextProps) => React.ReactElement<import("react-native-reanimated").AnimateProps<any>, string | React.JSXElementConstructor<any
|
|
94
|
-
Image: (props: MotionComponentProps & import("react-native").ImageProps) => React.ReactElement<import("react-native-reanimated").AnimateProps<any>, string | React.JSXElementConstructor<any
|
|
95
|
-
|
|
96
|
-
|
|
94
|
+
View: (props: MotionComponentProps & import("react-native").ViewProps) => React.ReactElement<import("react-native-reanimated").AnimateProps<any>, string | React.JSXElementConstructor<any>>;
|
|
95
|
+
Text: (props: MotionComponentProps & import("react-native").TextProps) => React.ReactElement<import("react-native-reanimated").AnimateProps<any>, string | React.JSXElementConstructor<any>>;
|
|
96
|
+
Image: (props: MotionComponentProps & import("react-native").ImageProps) => React.ReactElement<import("react-native-reanimated").AnimateProps<any>, string | React.JSXElementConstructor<any>>;
|
|
97
|
+
ImageBackground: (props: MotionComponentProps & import("react-native").ImageBackgroundProps) => React.ReactElement<import("react-native-reanimated").AnimateProps<any>, string | React.JSXElementConstructor<any>>;
|
|
98
|
+
TextInput: (props: MotionComponentProps & import("react-native").TextInputProps) => React.ReactElement<import("react-native-reanimated").AnimateProps<any>, string | React.JSXElementConstructor<any>>;
|
|
99
|
+
TouchableOpacity: (props: MotionComponentProps & import("react-native").TouchableOpacityProps & React.RefAttributes<View>) => React.ReactElement<import("react-native-reanimated").AnimateProps<any>, string | React.JSXElementConstructor<any>>;
|
|
100
|
+
ScrollView: (props: MotionComponentProps & import("react-native").ScrollViewProps) => React.ReactElement<import("react-native-reanimated").AnimateProps<any>, string | React.JSXElementConstructor<any>>;
|
|
101
|
+
FlatList: (props: MotionComponentProps & import("react-native").FlatListProps<unknown>) => React.ReactElement<import("react-native-reanimated").AnimateProps<any>, string | React.JSXElementConstructor<any>>;
|
|
102
|
+
SectionList: (props: MotionComponentProps & import("react-native").SectionListProps<unknown, unknown>) => React.ReactElement<import("react-native-reanimated").AnimateProps<any>, string | React.JSXElementConstructor<any>>;
|
|
103
|
+
Pressable: (props: MotionComponentProps & import("react-native").PressableProps & React.RefAttributes<View>) => React.ReactElement<import("react-native-reanimated").AnimateProps<any>, string | React.JSXElementConstructor<any>>;
|
|
97
104
|
};
|
package/lib/index.js
CHANGED
|
@@ -58,10 +58,7 @@ const DEFAULT_TRANSITION = {
|
|
|
58
58
|
};
|
|
59
59
|
function createMotionComponent(Component) {
|
|
60
60
|
return function MotionComponent(props) {
|
|
61
|
-
const { initial = {}, animate = {}, exit = {}, transition = DEFAULT_TRANSITION, shouldExit = false, onExitComplete, whileHover, whileTap, whileFocus, layout, layoutId, style = {}, children } = props, rest = __rest(props, ["initial", "animate", "exit", "transition", "shouldExit", "onExitComplete", "whileHover", "whileTap", "whileFocus", "layout", "layoutId", "style", "children"]);
|
|
62
|
-
const [isPresent, setIsPresent] = (0, react_1.useState)(true);
|
|
63
|
-
const [hasAnimated, setHasAnimated] = (0, react_1.useState)(false);
|
|
64
|
-
const isExitingRef = (0, react_1.useRef)(false);
|
|
61
|
+
const { initial = {}, animate = {}, exit = {}, transition = DEFAULT_TRANSITION, shouldAnimate = false, shouldDeAnimate = false, shouldExit = false, onExitComplete, whileHover, whileTap, whileFocus, layout, layoutId, style = {}, children } = props, rest = __rest(props, ["initial", "animate", "exit", "transition", "shouldAnimate", "shouldDeAnimate", "shouldExit", "onExitComplete", "whileHover", "whileTap", "whileFocus", "layout", "layoutId", "style", "children"]);
|
|
65
62
|
// Create shared values
|
|
66
63
|
const opacity = (0, react_native_reanimated_1.useSharedValue)(getInitialValue('opacity', initial));
|
|
67
64
|
const x = (0, react_native_reanimated_1.useSharedValue)(getInitialValue('x', initial));
|
|
@@ -111,42 +108,96 @@ function createMotionComponent(Component) {
|
|
|
111
108
|
const borderBottomWidth = (0, react_native_reanimated_1.useSharedValue)(getInitialValue('borderBottomWidth', initial));
|
|
112
109
|
const borderLeftWidth = (0, react_native_reanimated_1.useSharedValue)(getInitialValue('borderLeftWidth', initial));
|
|
113
110
|
const borderRightWidth = (0, react_native_reanimated_1.useSharedValue)(getInitialValue('borderRightWidth', initial));
|
|
114
|
-
const borderColor = (0, react_native_reanimated_1.useSharedValue)(getInitialValue('borderColor', initial));
|
|
115
111
|
const borderTopColor = (0, react_native_reanimated_1.useSharedValue)(getInitialValue('borderTopColor', initial));
|
|
116
112
|
const borderBottomColor = (0, react_native_reanimated_1.useSharedValue)(getInitialValue('borderBottomColor', initial));
|
|
117
113
|
const borderLeftColor = (0, react_native_reanimated_1.useSharedValue)(getInitialValue('borderLeftColor', initial));
|
|
118
114
|
const borderRightColor = (0, react_native_reanimated_1.useSharedValue)(getInitialValue('borderRightColor', initial));
|
|
119
|
-
// Color properties
|
|
120
|
-
const
|
|
121
|
-
const
|
|
115
|
+
// Color properties - use progress values for interpolation
|
|
116
|
+
const backgroundColorProgress = (0, react_native_reanimated_1.useSharedValue)(0);
|
|
117
|
+
const colorProgress = (0, react_native_reanimated_1.useSharedValue)(0);
|
|
118
|
+
const borderColorProgress = (0, react_native_reanimated_1.useSharedValue)(0);
|
|
119
|
+
const shadowColorProgress = (0, react_native_reanimated_1.useSharedValue)(0);
|
|
120
|
+
// Store color values for interpolation
|
|
121
|
+
const backgroundColorFrom = (0, react_1.useRef)(getInitialValue('backgroundColor', initial));
|
|
122
|
+
const backgroundColorTo = (0, react_1.useRef)(getInitialValue('backgroundColor', initial));
|
|
123
|
+
const colorFrom = (0, react_1.useRef)(getInitialValue('color', initial));
|
|
124
|
+
const colorTo = (0, react_1.useRef)(getInitialValue('color', initial));
|
|
125
|
+
const borderColorFrom = (0, react_1.useRef)(getInitialValue('borderColor', initial));
|
|
126
|
+
const borderColorTo = (0, react_1.useRef)(getInitialValue('borderColor', initial));
|
|
127
|
+
const shadowColorFrom = (0, react_1.useRef)(getInitialValue('shadowColor', initial));
|
|
128
|
+
const shadowColorTo = (0, react_1.useRef)(getInitialValue('shadowColor', initial));
|
|
122
129
|
// Position properties
|
|
123
130
|
const top = (0, react_native_reanimated_1.useSharedValue)(getInitialValue('top', initial));
|
|
124
131
|
const bottom = (0, react_native_reanimated_1.useSharedValue)(getInitialValue('bottom', initial));
|
|
125
132
|
const left = (0, react_native_reanimated_1.useSharedValue)(getInitialValue('left', initial));
|
|
126
133
|
const right = (0, react_native_reanimated_1.useSharedValue)(getInitialValue('right', initial));
|
|
127
134
|
// Shadow properties
|
|
128
|
-
const shadowColor = (0, react_native_reanimated_1.useSharedValue)(getInitialValue('shadowColor', initial));
|
|
129
135
|
const shadowOpacity = (0, react_native_reanimated_1.useSharedValue)(getInitialValue('shadowOpacity', initial));
|
|
130
136
|
const shadowRadius = (0, react_native_reanimated_1.useSharedValue)(getInitialValue('shadowRadius', initial));
|
|
131
137
|
const elevation = (0, react_native_reanimated_1.useSharedValue)(getInitialValue('elevation', initial));
|
|
132
138
|
// Animation helper
|
|
133
139
|
const animateToValues = (targetValues, transitionConfig = transition) => {
|
|
134
140
|
Object.entries(targetValues).forEach(([key, value]) => {
|
|
135
|
-
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
141
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v;
|
|
136
142
|
if (value !== undefined) {
|
|
143
|
+
// Handle color properties with interpolation
|
|
144
|
+
if (key === 'backgroundColor') {
|
|
145
|
+
backgroundColorTo.current = value;
|
|
146
|
+
const config = transitionConfig.type === 'spring'
|
|
147
|
+
? (0, react_native_reanimated_1.withSpring)(1, {
|
|
148
|
+
damping: (_a = transitionConfig.damping) !== null && _a !== void 0 ? _a : DEFAULT_TRANSITION.damping,
|
|
149
|
+
stiffness: (_b = transitionConfig.stiffness) !== null && _b !== void 0 ? _b : DEFAULT_TRANSITION.stiffness,
|
|
150
|
+
})
|
|
151
|
+
: (0, react_native_reanimated_1.withTiming)(1, { duration: (_c = transitionConfig.duration) !== null && _c !== void 0 ? _c : DEFAULT_TRANSITION.duration });
|
|
152
|
+
backgroundColorProgress.value = config;
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
if (key === 'color') {
|
|
156
|
+
colorTo.current = value;
|
|
157
|
+
const config = transitionConfig.type === 'spring'
|
|
158
|
+
? (0, react_native_reanimated_1.withSpring)(1, {
|
|
159
|
+
damping: (_d = transitionConfig.damping) !== null && _d !== void 0 ? _d : DEFAULT_TRANSITION.damping,
|
|
160
|
+
stiffness: (_e = transitionConfig.stiffness) !== null && _e !== void 0 ? _e : DEFAULT_TRANSITION.stiffness,
|
|
161
|
+
})
|
|
162
|
+
: (0, react_native_reanimated_1.withTiming)(1, { duration: (_f = transitionConfig.duration) !== null && _f !== void 0 ? _f : DEFAULT_TRANSITION.duration });
|
|
163
|
+
colorProgress.value = config;
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
if (key === 'borderColor') {
|
|
167
|
+
borderColorTo.current = value;
|
|
168
|
+
const config = transitionConfig.type === 'spring'
|
|
169
|
+
? (0, react_native_reanimated_1.withSpring)(1, {
|
|
170
|
+
damping: (_g = transitionConfig.damping) !== null && _g !== void 0 ? _g : DEFAULT_TRANSITION.damping,
|
|
171
|
+
stiffness: (_h = transitionConfig.stiffness) !== null && _h !== void 0 ? _h : DEFAULT_TRANSITION.stiffness,
|
|
172
|
+
})
|
|
173
|
+
: (0, react_native_reanimated_1.withTiming)(1, { duration: (_j = transitionConfig.duration) !== null && _j !== void 0 ? _j : DEFAULT_TRANSITION.duration });
|
|
174
|
+
borderColorProgress.value = config;
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
if (key === 'shadowColor') {
|
|
178
|
+
shadowColorTo.current = value;
|
|
179
|
+
const config = transitionConfig.type === 'spring'
|
|
180
|
+
? (0, react_native_reanimated_1.withSpring)(1, {
|
|
181
|
+
damping: (_k = transitionConfig.damping) !== null && _k !== void 0 ? _k : DEFAULT_TRANSITION.damping,
|
|
182
|
+
stiffness: (_l = transitionConfig.stiffness) !== null && _l !== void 0 ? _l : DEFAULT_TRANSITION.stiffness,
|
|
183
|
+
})
|
|
184
|
+
: (0, react_native_reanimated_1.withTiming)(1, { duration: (_m = transitionConfig.duration) !== null && _m !== void 0 ? _m : DEFAULT_TRANSITION.duration });
|
|
185
|
+
shadowColorProgress.value = config;
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
// Handle non-color properties
|
|
137
189
|
const sharedValue = getSharedValue(key);
|
|
138
190
|
if (sharedValue) {
|
|
139
191
|
let config;
|
|
140
192
|
if (transitionConfig.repeat && (transitionConfig.repeat > 0 || transitionConfig.repeat === 'infinity')) {
|
|
141
|
-
// Use withRepeat for repeated animations
|
|
142
193
|
const baseAnimation = transitionConfig.type === 'spring'
|
|
143
194
|
? (0, react_native_reanimated_1.withSpring)(value, {
|
|
144
|
-
damping: (
|
|
145
|
-
stiffness: (
|
|
146
|
-
mass: (
|
|
195
|
+
damping: (_o = transitionConfig.damping) !== null && _o !== void 0 ? _o : DEFAULT_TRANSITION.damping,
|
|
196
|
+
stiffness: (_p = transitionConfig.stiffness) !== null && _p !== void 0 ? _p : DEFAULT_TRANSITION.stiffness,
|
|
197
|
+
mass: (_q = transitionConfig.mass) !== null && _q !== void 0 ? _q : 1,
|
|
147
198
|
})
|
|
148
199
|
: (0, react_native_reanimated_1.withTiming)(value, {
|
|
149
|
-
duration: (
|
|
200
|
+
duration: (_r = transitionConfig.duration) !== null && _r !== void 0 ? _r : DEFAULT_TRANSITION.duration,
|
|
150
201
|
easing: react_native_reanimated_1.Easing.linear,
|
|
151
202
|
});
|
|
152
203
|
const repeatCount = transitionConfig.repeat === 'infinity' ? -1 : transitionConfig.repeat;
|
|
@@ -154,15 +205,14 @@ function createMotionComponent(Component) {
|
|
|
154
205
|
config = (0, react_native_reanimated_1.withRepeat)(baseAnimation, repeatCount, reverse);
|
|
155
206
|
}
|
|
156
207
|
else {
|
|
157
|
-
// Single animation
|
|
158
208
|
config = transitionConfig.type === 'spring'
|
|
159
209
|
? (0, react_native_reanimated_1.withSpring)(value, {
|
|
160
|
-
damping: (
|
|
161
|
-
stiffness: (
|
|
162
|
-
mass: (
|
|
210
|
+
damping: (_s = transitionConfig.damping) !== null && _s !== void 0 ? _s : DEFAULT_TRANSITION.damping,
|
|
211
|
+
stiffness: (_t = transitionConfig.stiffness) !== null && _t !== void 0 ? _t : DEFAULT_TRANSITION.stiffness,
|
|
212
|
+
mass: (_u = transitionConfig.mass) !== null && _u !== void 0 ? _u : 1,
|
|
163
213
|
})
|
|
164
214
|
: (0, react_native_reanimated_1.withTiming)(value, {
|
|
165
|
-
duration: (
|
|
215
|
+
duration: (_v = transitionConfig.duration) !== null && _v !== void 0 ? _v : DEFAULT_TRANSITION.duration,
|
|
166
216
|
});
|
|
167
217
|
}
|
|
168
218
|
if (transitionConfig.delay) {
|
|
@@ -229,30 +279,22 @@ function createMotionComponent(Component) {
|
|
|
229
279
|
case 'borderBottomWidth': return borderBottomWidth;
|
|
230
280
|
case 'borderLeftWidth': return borderLeftWidth;
|
|
231
281
|
case 'borderRightWidth': return borderRightWidth;
|
|
232
|
-
case 'borderColor': return borderColor;
|
|
233
282
|
case 'borderTopColor': return borderTopColor;
|
|
234
283
|
case 'borderBottomColor': return borderBottomColor;
|
|
235
284
|
case 'borderLeftColor': return borderLeftColor;
|
|
236
285
|
case 'borderRightColor': return borderRightColor;
|
|
237
|
-
// Color properties
|
|
238
|
-
case 'backgroundColor': return backgroundColor;
|
|
239
|
-
case 'color': return color;
|
|
240
286
|
// Position properties
|
|
241
287
|
case 'top': return top;
|
|
242
288
|
case 'bottom': return bottom;
|
|
243
289
|
case 'left': return left;
|
|
244
290
|
case 'right': return right;
|
|
245
291
|
// Shadow properties
|
|
246
|
-
case 'shadowColor': return shadowColor;
|
|
247
292
|
case 'shadowOpacity': return shadowOpacity;
|
|
248
293
|
case 'shadowRadius': return shadowRadius;
|
|
249
294
|
case 'elevation': return elevation;
|
|
250
295
|
default: return null;
|
|
251
296
|
}
|
|
252
297
|
};
|
|
253
|
-
// Memoize animate prop to prevent unnecessary re-animations
|
|
254
|
-
const animateString = JSON.stringify(animate);
|
|
255
|
-
const memoizedAnimate = (0, react_1.useMemo)(() => animate, [animateString]);
|
|
256
298
|
// Set initial values on mount
|
|
257
299
|
(0, react_1.useEffect)(() => {
|
|
258
300
|
if (initial !== false) {
|
|
@@ -264,78 +306,90 @@ function createMotionComponent(Component) {
|
|
|
264
306
|
});
|
|
265
307
|
}
|
|
266
308
|
}, []);
|
|
267
|
-
//
|
|
309
|
+
// Handle shouldAnimate: initial -> animate
|
|
268
310
|
(0, react_1.useEffect)(() => {
|
|
269
|
-
if (
|
|
270
|
-
//
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
311
|
+
if (shouldAnimate) {
|
|
312
|
+
// Reset color progress and update from/to values
|
|
313
|
+
if (animate.backgroundColor) {
|
|
314
|
+
backgroundColorFrom.current = backgroundColorTo.current;
|
|
315
|
+
backgroundColorProgress.value = 0;
|
|
316
|
+
}
|
|
317
|
+
if (animate.color) {
|
|
318
|
+
colorFrom.current = colorTo.current;
|
|
319
|
+
colorProgress.value = 0;
|
|
320
|
+
}
|
|
321
|
+
if (animate.borderColor) {
|
|
322
|
+
borderColorFrom.current = borderColorTo.current;
|
|
323
|
+
borderColorProgress.value = 0;
|
|
324
|
+
}
|
|
325
|
+
if (animate.shadowColor) {
|
|
326
|
+
shadowColorFrom.current = shadowColorTo.current;
|
|
327
|
+
shadowColorProgress.value = 0;
|
|
328
|
+
}
|
|
329
|
+
animateToValues(animate);
|
|
278
330
|
}
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
// Handle animate prop changes (only animate if values actually changed)
|
|
282
|
-
const prevAnimateRef = (0, react_1.useRef)(memoizedAnimate);
|
|
331
|
+
}, [shouldAnimate]);
|
|
332
|
+
// Handle shouldDeAnimate: animate -> initial
|
|
283
333
|
(0, react_1.useEffect)(() => {
|
|
284
|
-
if (
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
if (
|
|
288
|
-
|
|
289
|
-
|
|
334
|
+
if (shouldDeAnimate && initial !== false) {
|
|
335
|
+
const initialProps = initial;
|
|
336
|
+
// Reset color progress and update from/to values
|
|
337
|
+
if (initialProps.backgroundColor) {
|
|
338
|
+
backgroundColorFrom.current = backgroundColorTo.current;
|
|
339
|
+
backgroundColorTo.current = initialProps.backgroundColor;
|
|
340
|
+
backgroundColorProgress.value = 0;
|
|
341
|
+
}
|
|
342
|
+
if (initialProps.color) {
|
|
343
|
+
colorFrom.current = colorTo.current;
|
|
344
|
+
colorTo.current = initialProps.color;
|
|
345
|
+
colorProgress.value = 0;
|
|
290
346
|
}
|
|
347
|
+
if (initialProps.borderColor) {
|
|
348
|
+
borderColorFrom.current = borderColorTo.current;
|
|
349
|
+
borderColorTo.current = initialProps.borderColor;
|
|
350
|
+
borderColorProgress.value = 0;
|
|
351
|
+
}
|
|
352
|
+
if (initialProps.shadowColor) {
|
|
353
|
+
shadowColorFrom.current = shadowColorTo.current;
|
|
354
|
+
shadowColorTo.current = initialProps.shadowColor;
|
|
355
|
+
shadowColorProgress.value = 0;
|
|
356
|
+
}
|
|
357
|
+
animateToValues(initialProps);
|
|
291
358
|
}
|
|
292
|
-
}, [
|
|
293
|
-
// Handle shouldExit
|
|
359
|
+
}, [shouldDeAnimate]);
|
|
360
|
+
// Handle shouldExit: animate -> exit (no unmount)
|
|
294
361
|
(0, react_1.useEffect)(() => {
|
|
295
362
|
var _a;
|
|
296
|
-
if (shouldExit &&
|
|
297
|
-
|
|
298
|
-
if (exit
|
|
299
|
-
|
|
363
|
+
if (shouldExit && exit && Object.keys(exit).length > 0) {
|
|
364
|
+
// Reset color progress and update from/to values
|
|
365
|
+
if (exit.backgroundColor) {
|
|
366
|
+
backgroundColorFrom.current = backgroundColorTo.current;
|
|
367
|
+
backgroundColorTo.current = exit.backgroundColor;
|
|
368
|
+
backgroundColorProgress.value = 0;
|
|
369
|
+
}
|
|
370
|
+
if (exit.color) {
|
|
371
|
+
colorFrom.current = colorTo.current;
|
|
372
|
+
colorTo.current = exit.color;
|
|
373
|
+
colorProgress.value = 0;
|
|
374
|
+
}
|
|
375
|
+
if (exit.borderColor) {
|
|
376
|
+
borderColorFrom.current = borderColorTo.current;
|
|
377
|
+
borderColorTo.current = exit.borderColor;
|
|
378
|
+
borderColorProgress.value = 0;
|
|
379
|
+
}
|
|
380
|
+
if (exit.shadowColor) {
|
|
381
|
+
shadowColorFrom.current = shadowColorTo.current;
|
|
382
|
+
shadowColorTo.current = exit.shadowColor;
|
|
383
|
+
shadowColorProgress.value = 0;
|
|
384
|
+
}
|
|
385
|
+
animateToValues(exit, transition);
|
|
386
|
+
if (onExitComplete) {
|
|
300
387
|
const exitDuration = (_a = transition.duration) !== null && _a !== void 0 ? _a : 300;
|
|
301
388
|
setTimeout(() => {
|
|
302
|
-
setIsPresent(false);
|
|
303
|
-
if (onExitComplete) {
|
|
304
|
-
onExitComplete();
|
|
305
|
-
}
|
|
306
|
-
}, exitDuration);
|
|
307
|
-
}
|
|
308
|
-
else {
|
|
309
|
-
setIsPresent(false);
|
|
310
|
-
if (onExitComplete) {
|
|
311
389
|
onExitComplete();
|
|
312
|
-
}
|
|
390
|
+
}, exitDuration);
|
|
313
391
|
}
|
|
314
392
|
}
|
|
315
|
-
else if (!shouldExit && isExitingRef.current) {
|
|
316
|
-
// Re-entering: reset everything
|
|
317
|
-
isExitingRef.current = false;
|
|
318
|
-
setIsPresent(true);
|
|
319
|
-
setHasAnimated(false);
|
|
320
|
-
// Reset to initial values and animate
|
|
321
|
-
setTimeout(() => {
|
|
322
|
-
if (initial !== false) {
|
|
323
|
-
Object.entries(initial).forEach(([key, value]) => {
|
|
324
|
-
const sharedValue = getSharedValue(key);
|
|
325
|
-
if (sharedValue && value !== undefined) {
|
|
326
|
-
sharedValue.value = value;
|
|
327
|
-
}
|
|
328
|
-
});
|
|
329
|
-
}
|
|
330
|
-
// Animate to target after a frame
|
|
331
|
-
setTimeout(() => {
|
|
332
|
-
if (!isExitingRef.current) {
|
|
333
|
-
animateToValues(memoizedAnimate);
|
|
334
|
-
setHasAnimated(true);
|
|
335
|
-
}
|
|
336
|
-
}, 16);
|
|
337
|
-
}, 0);
|
|
338
|
-
}
|
|
339
393
|
}, [shouldExit]);
|
|
340
394
|
// Animated style
|
|
341
395
|
const animatedStyle = (0, react_native_reanimated_1.useAnimatedStyle)(() => {
|
|
@@ -436,21 +490,18 @@ function createMotionComponent(Component) {
|
|
|
436
490
|
style.borderLeftWidth = borderLeftWidth.value;
|
|
437
491
|
if (borderRightWidth.value !== 0)
|
|
438
492
|
style.borderRightWidth = borderRightWidth.value;
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
if (borderTopColor.value !== 0)
|
|
493
|
+
style.borderColor = (0, react_native_reanimated_1.interpolateColor)(borderColorProgress.value, [0, 1], [borderColorFrom.current, borderColorTo.current]);
|
|
494
|
+
if (borderTopColor.value !== 'transparent')
|
|
442
495
|
style.borderTopColor = borderTopColor.value;
|
|
443
|
-
if (borderBottomColor.value !==
|
|
496
|
+
if (borderBottomColor.value !== 'transparent')
|
|
444
497
|
style.borderBottomColor = borderBottomColor.value;
|
|
445
|
-
if (borderLeftColor.value !==
|
|
498
|
+
if (borderLeftColor.value !== 'transparent')
|
|
446
499
|
style.borderLeftColor = borderLeftColor.value;
|
|
447
|
-
if (borderRightColor.value !==
|
|
500
|
+
if (borderRightColor.value !== 'transparent')
|
|
448
501
|
style.borderRightColor = borderRightColor.value;
|
|
449
|
-
// Color properties
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
if (color.value !== 0)
|
|
453
|
-
style.color = color.value;
|
|
502
|
+
// Color properties with interpolation
|
|
503
|
+
style.backgroundColor = (0, react_native_reanimated_1.interpolateColor)(backgroundColorProgress.value, [0, 1], [backgroundColorFrom.current, backgroundColorTo.current]);
|
|
504
|
+
style.color = (0, react_native_reanimated_1.interpolateColor)(colorProgress.value, [0, 1], [colorFrom.current, colorTo.current]);
|
|
454
505
|
// Position properties
|
|
455
506
|
if (top.value !== 0)
|
|
456
507
|
style.top = top.value;
|
|
@@ -461,8 +512,7 @@ function createMotionComponent(Component) {
|
|
|
461
512
|
if (right.value !== 0)
|
|
462
513
|
style.right = right.value;
|
|
463
514
|
// Shadow properties
|
|
464
|
-
|
|
465
|
-
style.shadowColor = shadowColor.value;
|
|
515
|
+
style.shadowColor = (0, react_native_reanimated_1.interpolateColor)(shadowColorProgress.value, [0, 1], [shadowColorFrom.current, shadowColorTo.current]);
|
|
466
516
|
if (shadowOpacity.value !== 0)
|
|
467
517
|
style.shadowOpacity = shadowOpacity.value;
|
|
468
518
|
if (shadowRadius.value !== 0)
|
|
@@ -472,8 +522,6 @@ function createMotionComponent(Component) {
|
|
|
472
522
|
return style;
|
|
473
523
|
});
|
|
474
524
|
const AnimatedComponent = react_native_reanimated_1.default.createAnimatedComponent(Component);
|
|
475
|
-
if (!isPresent)
|
|
476
|
-
return null;
|
|
477
525
|
return react_1.default.createElement(AnimatedComponent, Object.assign({ style: [style, animatedStyle] }, rest), children);
|
|
478
526
|
};
|
|
479
527
|
}
|
|
@@ -504,6 +552,15 @@ function getDefaultValue(key) {
|
|
|
504
552
|
case 'skewX':
|
|
505
553
|
case 'skewY':
|
|
506
554
|
return '0deg';
|
|
555
|
+
case 'backgroundColor':
|
|
556
|
+
case 'color':
|
|
557
|
+
case 'borderColor':
|
|
558
|
+
case 'borderTopColor':
|
|
559
|
+
case 'borderBottomColor':
|
|
560
|
+
case 'borderLeftColor':
|
|
561
|
+
case 'borderRightColor':
|
|
562
|
+
case 'shadowColor':
|
|
563
|
+
return 'transparent';
|
|
507
564
|
default:
|
|
508
565
|
return 0;
|
|
509
566
|
}
|
|
@@ -512,6 +569,11 @@ exports.NativeMotion = {
|
|
|
512
569
|
View: createMotionComponent(react_native_1.View),
|
|
513
570
|
Text: createMotionComponent(react_native_1.Text),
|
|
514
571
|
Image: createMotionComponent(react_native_1.Image),
|
|
572
|
+
ImageBackground: createMotionComponent(react_native_1.ImageBackground),
|
|
515
573
|
TextInput: createMotionComponent(react_native_1.TextInput),
|
|
516
574
|
TouchableOpacity: createMotionComponent(react_native_1.TouchableOpacity),
|
|
575
|
+
ScrollView: createMotionComponent(react_native_1.ScrollView),
|
|
576
|
+
FlatList: createMotionComponent(react_native_1.FlatList),
|
|
577
|
+
SectionList: createMotionComponent(react_native_1.SectionList),
|
|
578
|
+
Pressable: createMotionComponent(react_native_1.Pressable),
|
|
517
579
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "motion-on-native",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "Framer Motion-inspired animation library for React Native with Reanimated. Easy spring animations, gestures, and transitions for mobile apps.",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"types": "lib/index.d.ts",
|