Skip to content

Commit beac877

Browse files
committed
refactor: migrate components to Reanimated
1 parent c672183 commit beac877

19 files changed

Lines changed: 2266 additions & 714 deletions

File tree

‎docs/6.x/docs/components/Surface.mdx‎

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,14 @@ const styles = StyleSheet.create({
172172

173173
<div>
174174

175+
### children (required)
176+
177+
</div>
178+
179+
<PropTable componentLink="Surface" prop="children" />
180+
181+
<div>
182+
175183
### style
176184

177185
</div>
@@ -204,14 +212,6 @@ const styles = StyleSheet.create({
204212

205213
<div>
206214

207-
### children (required)
208-
209-
</div>
210-
211-
<PropTable componentLink="Surface" prop="children" />
212-
213-
<div>
214-
215215
### testID
216216

217217
</div>

‎docs/src/data/componentDocs6x.json‎

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -302,19 +302,19 @@
302302
"style": {
303303
"required": false,
304304
"tsType": {
305-
"name": "Animated.WithAnimatedValue",
305+
"name": "StyleProp",
306306
"elements": [
307307
{
308-
"name": "StyleProp",
308+
"name": "AnimatedStyle",
309309
"elements": [
310310
{
311311
"name": "ViewStyle"
312312
}
313313
],
314-
"raw": "StyleProp<ViewStyle>"
314+
"raw": "AnimatedStyle<ViewStyle>"
315315
}
316316
],
317-
"raw": "Animated.WithAnimatedValue<StyleProp<ViewStyle>>"
317+
"raw": "StyleProp<AnimatedStyle<ViewStyle>>"
318318
},
319319
"description": ""
320320
},
@@ -414,19 +414,19 @@
414414
"style": {
415415
"required": false,
416416
"tsType": {
417-
"name": "Animated.WithAnimatedValue",
417+
"name": "StyleProp",
418418
"elements": [
419419
{
420-
"name": "StyleProp",
420+
"name": "AnimatedStyle",
421421
"elements": [
422422
{
423423
"name": "ViewStyle"
424424
}
425425
],
426-
"raw": "StyleProp<ViewStyle>"
426+
"raw": "AnimatedStyle<ViewStyle>"
427427
}
428428
],
429-
"raw": "Animated.WithAnimatedValue<StyleProp<ViewStyle>>"
429+
"raw": "StyleProp<AnimatedStyle<ViewStyle>>"
430430
},
431431
"description": ""
432432
},
@@ -5785,10 +5785,16 @@
57855785
"name": "StyleProp",
57865786
"elements": [
57875787
{
5788-
"name": "ViewStyle"
5788+
"name": "AnimatedStyle",
5789+
"elements": [
5790+
{
5791+
"name": "ViewStyle"
5792+
}
5793+
],
5794+
"raw": "AnimatedStyle<ViewStyle>"
57895795
}
57905796
],
5791-
"raw": "StyleProp<ViewStyle>"
5797+
"raw": "StyleProp<AnimatedStyle<ViewStyle>>"
57925798
},
57935799
"description": ""
57945800
},
@@ -11339,6 +11345,14 @@
1133911345
},
1134011346
"description": "Corner curve of the Surface on iOS."
1134111347
},
11348+
"children": {
11349+
"required": true,
11350+
"tsType": {
11351+
"name": "ReactReactNode",
11352+
"raw": "React.ReactNode"
11353+
},
11354+
"description": "Content of the `Surface`."
11355+
},
1134211356
"style": {
1134311357
"required": false,
1134411358
"tsType": {
@@ -11407,14 +11421,6 @@
1140711421
},
1140811422
"description": ""
1140911423
},
11410-
"children": {
11411-
"required": true,
11412-
"tsType": {
11413-
"name": "ReactReactNode",
11414-
"raw": "React.ReactNode"
11415-
},
11416-
"description": "Content of the `Surface`."
11417-
},
1141811424
"testID": {
1141911425
"required": false,
1142011426
"tsType": {

‎src/components/Appbar/AppbarAction.tsx‎

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,7 @@
11
import * as React from 'react';
2-
import type {
3-
Animated,
4-
ColorValue,
5-
StyleProp,
6-
View,
7-
ViewStyle,
8-
} from 'react-native';
2+
import type { ColorValue, StyleProp, View, ViewStyle } from 'react-native';
3+
4+
import type { AnimatedStyle } from 'react-native-reanimated';
95

106
import { useInternalTheme } from '../../core/theming';
117
import type { ThemeProp } from '../../types';
@@ -43,7 +39,7 @@ export type Props = React.ComponentPropsWithoutRef<typeof IconButton> & {
4339
* Whether it's the leading button. Note: If `Appbar.BackAction` is present, it will be rendered before any `isLeading` icons.
4440
*/
4541
isLeading?: boolean;
46-
style?: Animated.WithAnimatedValue<StyleProp<ViewStyle>>;
42+
style?: StyleProp<AnimatedStyle<ViewStyle>>;
4743
ref?: React.Ref<View>;
4844
/**
4945
* @optional

‎src/components/Appbar/AppbarBackAction.tsx‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
import * as React from 'react';
22
import type {
3-
Animated,
43
ColorValue,
54
GestureResponderEvent,
65
StyleProp,
76
View,
87
ViewStyle,
98
} from 'react-native';
109

10+
import type { AnimatedStyle } from 'react-native-reanimated';
11+
1112
import type { $Omit } from './../../types';
1213
import AppbarAction from './AppbarAction';
1314
import AppbarBackIcon from './AppbarBackIcon';
@@ -36,7 +37,7 @@ export type Props = $Omit<
3637
* Function to execute on press.
3738
*/
3839
onPress?: (e: GestureResponderEvent) => void;
39-
style?: Animated.WithAnimatedValue<StyleProp<ViewStyle>>;
40+
style?: StyleProp<AnimatedStyle<ViewStyle>>;
4041
ref?: React.Ref<View>;
4142
};
4243

‎src/components/Checkbox/Checkbox.tsx‎

Lines changed: 42 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,8 @@ import type {
1010
} from 'react-native';
1111

1212
import Animated, {
13-
Easing,
14-
ReduceMotion,
15-
useAnimatedStyle,
16-
useSharedValue,
17-
withTiming,
13+
cubicBezier,
14+
type AnimatedStyle,
1815
} from 'react-native-reanimated';
1916

2017
import { CheckboxTokens } from './tokens';
@@ -123,7 +120,9 @@ const Checkbox = ({
123120
...rest
124121
}: Props) => {
125122
const theme = useInternalTheme(themeOverrides);
123+
126124
const reduceMotion = useReduceMotion();
125+
127126
const { direction } = useLocale();
128127
// Web (react-native-web) doesn't auto-mirror layout, so flip the mask
129128
// anchor manually for RTL. Native handles it via `I18nManager`.
@@ -132,56 +131,6 @@ const Checkbox = ({
132131

133132
const selected = status === 'checked' || status === 'indeterminate';
134133

135-
const reanimatedReduceMotion = reduceMotion
136-
? ReduceMotion.Always
137-
: ReduceMotion.Never;
138-
139-
const fillTimingConfig = React.useMemo(
140-
() => ({
141-
duration: theme.motion.duration.short2,
142-
easing: Easing.bezier(...theme.motion.easing.standard),
143-
reduceMotion: reanimatedReduceMotion,
144-
}),
145-
[
146-
theme.motion.duration.short2,
147-
theme.motion.easing.standard,
148-
reanimatedReduceMotion,
149-
]
150-
);
151-
const checkTimingConfig = React.useMemo(
152-
() => ({
153-
duration: theme.motion.duration.short3,
154-
easing: Easing.bezier(...theme.motion.easing.standard),
155-
reduceMotion: reanimatedReduceMotion,
156-
}),
157-
[
158-
theme.motion.duration.short3,
159-
theme.motion.easing.standard,
160-
reanimatedReduceMotion,
161-
]
162-
);
163-
164-
// 0 = unselected (outline only), 1 = selected (filled + drawn icon).
165-
const fillProgress = useSharedValue(selected ? 1 : 0);
166-
const checkProgress = useSharedValue(selected ? 1 : 0);
167-
const firstRender = React.useRef(true);
168-
169-
React.useEffect(() => {
170-
if (firstRender.current) {
171-
firstRender.current = false;
172-
return;
173-
}
174-
const target = selected ? 1 : 0;
175-
fillProgress.value = withTiming(target, fillTimingConfig);
176-
checkProgress.value = withTiming(target, checkTimingConfig);
177-
}, [
178-
selected,
179-
fillProgress,
180-
checkProgress,
181-
fillTimingConfig,
182-
checkTimingConfig,
183-
]);
184-
185134
// Visual state (colors + opacity) for the static layers. `hovered` /
186135
// `pressed` aren't tracked here — `TouchableRipple` owns the press ripple
187136
// and hover overlay.
@@ -194,19 +143,39 @@ const Checkbox = ({
194143
customUncheckedColor: uncheckedColor,
195144
});
196145

197-
// Outline fades out as fill fades in (and vice versa).
198-
const outlineAnimatedStyle = useAnimatedStyle(() => ({
199-
opacity: 1 - fillProgress.value,
200-
}));
146+
const transitionTimingFunction = cubicBezier(...theme.motion.easing.standard);
147+
148+
const fillTransitionDuration = reduceMotion
149+
? 0
150+
: theme.motion.duration.short2;
151+
152+
const checkTransitionDuration = reduceMotion
153+
? 0
154+
: theme.motion.duration.short3;
155+
156+
const outlineStyle: AnimatedStyle<ViewStyle> = {
157+
borderColor: visual.outlineColor,
158+
opacity: selected ? 0 : 1,
159+
transitionDuration: fillTransitionDuration,
160+
transitionProperty: ['opacity'],
161+
transitionTimingFunction,
162+
};
201163

202-
const fillAnimatedStyle = useAnimatedStyle(() => ({
203-
opacity: fillProgress.value,
204-
}));
164+
const fillStyle: AnimatedStyle<ViewStyle> = {
165+
backgroundColor: visual.containerColor,
166+
opacity: selected ? 1 : 0,
167+
transitionDuration: fillTransitionDuration,
168+
transitionProperty: ['opacity'],
169+
transitionTimingFunction,
170+
};
205171

206-
const maskAnimatedStyle = useAnimatedStyle(() => ({
207-
width: checkProgress.value * CONTAINER_SIZE,
208-
opacity: checkProgress.value,
209-
}));
172+
const maskStyle: AnimatedStyle<ViewStyle> = {
173+
width: selected ? CONTAINER_SIZE : 0,
174+
opacity: selected ? 1 : 0,
175+
transitionDuration: checkTransitionDuration,
176+
transitionProperty: ['width', 'opacity'],
177+
transitionTimingFunction,
178+
};
210179

211180
// Remember the last drawn glyph so the reveal-mask can finish collapsing
212181
// when `selected` flips back to false. Computed via the "derive state
@@ -283,27 +252,19 @@ const Checkbox = ({
283252
<View style={[styles.container, { opacity: visual.containerOpacity }]}>
284253
<Animated.View
285254
pointerEvents="none"
286-
style={[
287-
styles.outline,
288-
{ borderColor: visual.outlineColor },
289-
outlineAnimatedStyle,
290-
]}
255+
style={[styles.outline, outlineStyle]}
291256
/>
292257
<Animated.View
293258
pointerEvents="none"
294-
style={[
295-
styles.fill,
296-
{ backgroundColor: visual.containerColor },
297-
fillAnimatedStyle,
298-
]}
259+
style={[styles.fill, fillStyle]}
299260
/>
300261
{showIndeterminate ? (
301262
<Animated.View
302263
style={[
303264
flipMaskForWebRTL
304265
? styles.checkmarkMaskWebRTL
305266
: styles.checkmarkMask,
306-
maskAnimatedStyle,
267+
maskStyle,
307268
]}
308269
>
309270
<View style={styles.checkmarkContent}>
@@ -315,7 +276,7 @@ const Checkbox = ({
315276
) : (
316277
<Checkmark
317278
color={visual.iconColor}
318-
maskAnimatedStyle={maskAnimatedStyle}
279+
maskStyle={maskStyle}
319280
flipMaskForWebRTL={flipMaskForWebRTL}
320281
isRTL={direction === 'rtl'}
321282
autoSwapsBorders={Platform.OS !== 'web'}
@@ -334,13 +295,13 @@ const Checkbox = ({
334295
*/
335296
const Checkmark = ({
336297
color,
337-
maskAnimatedStyle,
298+
maskStyle,
338299
flipMaskForWebRTL,
339300
isRTL,
340301
autoSwapsBorders,
341302
}: {
342303
color: ColorValue;
343-
maskAnimatedStyle: ReturnType<typeof useAnimatedStyle>;
304+
maskStyle: AnimatedStyle<ViewStyle>;
344305
flipMaskForWebRTL: boolean;
345306
isRTL: boolean;
346307
// True on platforms whose layout engine auto-swaps `borderLeftWidth`
@@ -351,7 +312,7 @@ const Checkmark = ({
351312
<Animated.View
352313
style={[
353314
flipMaskForWebRTL ? styles.checkmarkMaskWebRTL : styles.checkmarkMask,
354-
maskAnimatedStyle,
315+
maskStyle,
355316
]}
356317
>
357318
<View style={styles.checkmarkContent}>

0 commit comments

Comments
 (0)