Skip to content

Reanimated and GestureHandler upgrade #3203

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 27 commits into from
Sep 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
8f76e95
SectionsWheelPicker - wrap with GestureHandlerRootView
Inbal-Tish Aug 7, 2024
1b1c725
remove redundent
Inbal-Tish Aug 7, 2024
adcaf4a
remove // @ts-expect-error should be fixed in version 3.5 (https://gi…
Inbal-Tish Aug 7, 2024
e8f970c
Modal - applying useGestureHandlerRootView on iOS as well
Inbal-Tish Aug 8, 2024
66e0b0c
TouchableOpacity - migrate from deprecated onGestureEvent to onHandle…
Inbal-Tish Aug 8, 2024
88ef194
PanView - migrate from PanGestureHandler with deprecated onGestureEve…
Inbal-Tish Aug 8, 2024
c501fc4
Calendar header - ignore TS error
Inbal-Tish Aug 8, 2024
97a0973
upgrade libraries
Inbal-Tish Aug 8, 2024
c54cafe
gesture upgrade to 2.16.0
Inbal-Tish Aug 11, 2024
28b750a
gestureHandler to 2.14.1
Inbal-Tish Aug 13, 2024
70d2a05
Modal - update docs
Inbal-Tish Aug 13, 2024
418fbd2
WheelPicker - wrap with GestureHandlerRootView, instead of wrapping t…
Inbal-Tish Aug 13, 2024
36ec4a6
Wrapping SectionWheelPickerScreen instead of WheelPicker component
Inbal-Tish Aug 13, 2024
8324ef9
clean
Inbal-Tish Aug 13, 2024
7957805
Remove migration from useAnimatedGestureHandler
Inbal-Tish Aug 14, 2024
03a695c
//@ts-expect-error - useAnimatedGestureHandler migration
Inbal-Tish Aug 14, 2024
323a558
fix TS error on ConnectionStatusBar NetInfo.fetch
Inbal-Tish Aug 15, 2024
6a545d4
Revert "fix TS error on ConnectionStatusBar NetInfo.fetch"
Inbal-Tish Aug 15, 2024
98d62a3
Revert "//@ts-expect-error - useAnimatedGestureHandler migration"
Inbal-Tish Aug 15, 2024
c616f07
Revert "Remove migration from useAnimatedGestureHandler"
Inbal-Tish Aug 15, 2024
3c6c796
Wrap screens with gestureHandlerRootHOC
Inbal-Tish Aug 15, 2024
a3bcdc7
Merge branch 'master' into fix/GestureHandlerRootView
M-i-k-e-l Aug 18, 2024
df8f1b8
Fix TabController's indicator
M-i-k-e-l Aug 19, 2024
ae5b10f
Fix PanView (and screen)
M-i-k-e-l Aug 19, 2024
167c3b6
Remove missed comment
M-i-k-e-l Aug 19, 2024
a07caac
Change to map (also fixes initial indicator)
M-i-k-e-l Aug 27, 2024
1e21608
Revert "Change to map (also fixes initial indicator)"
M-i-k-e-l Sep 1, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions demo/src/screens/componentScreens/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export function registerScreens(registrar) {
registrar('unicorn.components.CheckboxScreen', () => require('./CheckboxScreen').default);
registrar('unicorn.components.ChipScreen', () => require('./ChipScreen').default);
registrar('unicorn.components.ChipsInputScreen', () => require('./ChipsInputScreen').default);
registrar('unicorn.components.ColorPickerScreen', () => require('./ColorPickerScreen').default);
registrar('unicorn.components.ColorPickerScreen', () => gestureHandlerRootHOC(require('./ColorPickerScreen').default));
registrar('unicorn.components.ColorSwatchScreen', () => require('./ColorSwatchScreen').default);
registrar('unicorn.components.ConnectionStatusBar', () => require('./ConnectionStatusBarScreen').default);
registrar('unicorn.components.DateTimePickerScreen', () => require('./DateTimePickerScreen').default);
Expand All @@ -28,7 +28,7 @@ export function registerScreens(registrar) {
registrar('unicorn.components.IconScreen', () => require('./IconScreen').default);
registrar('unicorn.components.ImageScreen', () => require('./ImageScreen').default);
registrar('unicorn.components.GridListScreen', () => require('./GridListScreen').default);
registrar('unicorn.components.GridViewScreen', () => require('./GridViewScreen').default);
registrar('unicorn.components.GridViewScreen', () => gestureHandlerRootHOC(require('./GridViewScreen').default));
registrar('unicorn.components.KeyboardAwareScrollViewScreen', () => require('./KeyboardAwareScrollViewScreen').default);
registrar('unicorn.components.MaskedInputScreen', () => require('./MaskedInputScreen').default);
registrar('unicorn.components.MarqueeScreen', () => require('./MarqueeScreen').default);
Expand All @@ -38,12 +38,12 @@ export function registerScreens(registrar) {
registrar('unicorn.components.PanDismissibleScreen', () => require('./PanDismissibleScreen').default);
registrar('unicorn.components.PanListenerScreen', () => require('./PanListenerScreen').default);
registrar('unicorn.components.PanResponderScreen', () => require('./PanResponderScreen').default);
registrar('unicorn.components.PickerScreen', () => require('./PickerScreen').default);
registrar('unicorn.components.PickerScreen', () => gestureHandlerRootHOC(require('./PickerScreen').default));
registrar('unicorn.animations.ProgressBarScreen', () => require('../componentScreens/ProgressBarScreen').default);
registrar('unicorn.components.ProgressiveImageScreen', () => require('./ProgressiveImageScreen').default);
registrar('unicorn.components.RadioButtonScreen', () => require('./RadioButtonScreen').default);
registrar('unicorn.components.ScrollBarScreen', () => require('./ScrollBarScreen').default);
registrar('unicorn.components.SectionsWheelPickerScreen', () => require('./SectionsWheelPickerScreen').default);
registrar('unicorn.components.SectionsWheelPickerScreen', () => gestureHandlerRootHOC(require('./SectionsWheelPickerScreen').default));
registrar('unicorn.components.SegmentedControlScreen', () => require('./SegmentedControlScreen').default);
registrar('unicorn.components.SharedTransitionScreen', () => require('./SharedTransitionScreen').default);
registrar('unicorn.components.SkeletonViewScreen', () => require('./SkeletonViewScreen').default);
Expand Down
5 changes: 2 additions & 3 deletions demo/src/screens/incubatorScreens/PanViewScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -146,9 +146,8 @@ class PanViewScreen extends Component {

render() {
const {showToast, showDialog} = this.state;
const Container = showDialog ? View : GestureHandlerRootView;
return (
<Container style={styles.root}>
<GestureHandlerRootView style={styles.root}>
<View marginL-page height={50} centerV>
<Text text50>New Pan View</Text>
</View>
Expand All @@ -164,7 +163,7 @@ class PanViewScreen extends Component {
</ScrollView>
{showToast && this.renderToast()}
{showDialog && this.renderDialog()}
</Container>
</GestureHandlerRootView>
);
}
}
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -106,12 +106,12 @@
"react-dom": "^18.2.0",
"react-native": "0.71.12",
"react-native-fs": "^2.20.0",
"react-native-gesture-handler": "2.9.0",
"react-native-gesture-handler": "2.14.1",
"react-native-haptic-feedback": "^1.11.0",
"react-native-linear-gradient": "2.6.2",
"react-native-mmkv": "2.11.0",
"react-native-navigation": "7.32.1",
"react-native-reanimated": "3.4.0",
"react-native-reanimated": "3.8.1",
"react-native-shimmer-placeholder": "^2.0.6",
"react-native-svg": "^13.7.0",
"react-native-svg-transformer": "1.1.0",
Expand Down
2 changes: 0 additions & 2 deletions src/components/marquee/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,6 @@ function Marquee(props: MarqueeProps) {
}
}, [viewLayout, textLayout]);

// @ts-expect-error should be fixed in version 3.5 (https://github.com/software-mansion/react-native-reanimated/pull/4881)
const translateStyle = useAnimatedStyle(() => {
if (offset.value) {
return {
Expand All @@ -90,7 +89,6 @@ function Marquee(props: MarqueeProps) {

return (
<View style={[styles.container, containerStyle]} onLayout={onLayoutView}>
{/* @ts-expect-error should be fixed in version 3.5 (https://github.com/software-mansion/react-native-reanimated/pull/4881) */}
<View reanimated style={[translateStyle]}>
<Text style={[styles.text, labelStyle]} onLayout={onLayoutText}>
{label}
Expand Down
3 changes: 1 addition & 2 deletions src/components/modal/api/modal.api.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,7 @@
{
"name": "useGestureHandlerRootView",
"type": "boolean",
"description": "Should add a GestureHandlerRootView",
"note": "Android only"
"description": "Should add a GestureHandlerRootView"
}
],
"snippet": [
Expand Down
7 changes: 3 additions & 4 deletions src/components/modal/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export interface ModalProps extends RNModalProps {
*/
accessibilityLabel?: string;
/**
* Should add a GestureHandlerRootView (Android only)
* Should add a GestureHandlerRootView
*/
useGestureHandlerRootView?: boolean;
/**
Expand Down Expand Up @@ -112,9 +112,8 @@ class Modal extends Component<ModalProps> {
...others
} = this.props;
const defaultContainer = enableModalBlur && Constants.isIOS && BlurView ? BlurView : View;
const useGestureHandler = useGestureHandlerRootView && Constants.isAndroid;
const GestureContainer = useGestureHandler ? GestureHandlerRootView : React.Fragment;
const gestureContainerProps = useGestureHandler ? {style: styles.fill} : {};
const GestureContainer = useGestureHandlerRootView ? GestureHandlerRootView : React.Fragment;
const gestureContainerProps = useGestureHandlerRootView ? {style: styles.fill} : {};
const useKeyboardAvoiding = useKeyboardAvoidingView && Constants.isIOS;
const KeyboardAvoidingContainer = useKeyboardAvoiding ? KeyboardAvoidingView : React.Fragment;
const keyboardAvoidingContainerProps = useKeyboardAvoiding
Expand Down
2 changes: 0 additions & 2 deletions src/components/sortableGridList/SortableItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,6 @@ function SortableItem(props: PropsWithChildren<SortableItemProps & ReturnType<ty
}
});

// @ts-expect-error should be fixed in version 3.5 (https://github.com/software-mansion/react-native-reanimated/pull/4881)
const animatedStyle = useAnimatedStyle(() => {
const scale = withSpring(isDragging.value ? 1.1 : 1);
const zIndex = isDragging.value ? 100 : withTiming(0, animationConfig);
Expand All @@ -183,7 +182,6 @@ function SortableItem(props: PropsWithChildren<SortableItemProps & ReturnType<ty
});

return (
// @ts-expect-error should be fixed in version 3.5 (https://github.com/software-mansion/react-native-reanimated/pull/4881)
<View reanimated style={[style, animatedStyle]} onLayout={onLayout}>
<GestureDetector gesture={dragOnLongPressGesture}>
<View>{props.children}</View>
Expand Down
1 change: 0 additions & 1 deletion src/components/tabController/PageCarousel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,6 @@ function PageCarousel(props: ScrollViewProps) {
<Reanimated.ScrollView
{...others}
style={_style}
// @ts-expect-error should be fixed in version 3.5 (https://github.com/software-mansion/react-native-reanimated/pull/4881)
ref={carousel}
horizontal
pagingEnabled
Expand Down
1 change: 0 additions & 1 deletion src/components/tabController/TabBarItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,6 @@ export interface TabControllerItemProps extends Pick<TabControllerBarProps, 'spr
interface Props extends TabControllerItemProps {
index: number;
targetPage: any; // TODO: typescript?
// @ts-expect-error should be fixed in version 3.5 (https://github.com/software-mansion/react-native-reanimated/pull/4881)
currentPage: Reanimated.Adaptable<number>;
onLayout?: (event: LayoutChangeEvent, index: number) => void;
}
Expand Down
28 changes: 18 additions & 10 deletions src/components/tabController/useScrollToItem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,13 +128,6 @@ const useScrollToItem = <T extends ScrollToSupportedViews>(props: ScrollToItemPr
const rightOffsets = [];
rightOffsets.push(-containerWidth + widths[0] + outerSpacing + innerSpacing);
while (index < itemsCount) {
/* map animated widths and offsets */
itemsWidthsAnimated.value[index] = widths[index];
if (index > 0) {
itemsOffsetsAnimated.value[index] =
itemsOffsetsAnimated.value[index - 1] + itemsWidthsAnimated.value[index - 1];
}

/* calc center, left and right offsets */
centeredOffsets[index] = currentCenterOffset - screenCenter + widths[index] / 2;
++index;
Expand All @@ -154,9 +147,24 @@ const useScrollToItem = <T extends ScrollToSupportedViews>(props: ScrollToItemPr

setOffsets({CENTER: centeredOffsets, LEFT: leftOffsets, RIGHT: rightOffsets}); // default for DYNAMIC is CENTER

// trigger value change
itemsWidthsAnimated.value = [...itemsWidthsAnimated.value];
itemsOffsetsAnimated.value = [...itemsOffsetsAnimated.value];
// Update shared values
itemsWidthsAnimated.modify((value) => {
'worklet';
value.forEach((_, index) => {
value[index] = widths[index];
});
return value;
Comment on lines +153 to +156
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's something a little confusing when you both update the value and return it.
Maybe use map instead of forEach and return it, it might even shorten this

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tried it but it caused a TS error I could not find a fix for.

});

itemsOffsetsAnimated.modify((value) => {
'worklet';
value.forEach((_, index) => {
if (index > 0) {
value[index] = value[index - 1] + widths[index - 1];
}
});
Comment on lines +161 to +165
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here, consider using map

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It appears that accessing value[index - 1] gives 0

return value;
});
},
[itemsCount, outerSpacing, innerSpacing, addOffsetMargin, containerWidth]);

Expand Down
2 changes: 0 additions & 2 deletions src/components/textField/ClearButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ const ClearButton = ({testID, onClear, onChangeText}: Pick<TextFieldProps, 'onCl
const animatedValue = useSharedValue(hasValue ? VISIBLE_POSITION : NON_VISIBLE_POSITION);
const animatedOpacity = useSharedValue(hasValue ? 1 : 0);

// @ts-expect-error should be fixed in version 3.5 (https://github.com/software-mansion/react-native-reanimated/pull/4881)
const animatedStyle = useAnimatedStyle(() => {
return {
transform: [{translateY: animatedValue.value}, {translateX: 0}],
Expand All @@ -49,7 +48,6 @@ const ClearButton = ({testID, onClear, onChangeText}: Pick<TextFieldProps, 'onCl
};

return (
//@ts-expect-error should be fixed in version 3.5 (https://github.com/software-mansion/react-native-reanimated/pull/4881)
<View reanimated style={style} testID={`${testID}.container`}>
<Button
link
Expand Down
2 changes: 1 addition & 1 deletion src/incubator/Calendar/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,11 @@ const Header = (props: HeaderProps) => {
return <Text style={styles.title}>{title}</Text>;
}
return (
//@ts-expect-error - hack to animate the title text change
<AnimatedTextInput
value={getTitle(selectedDate.value)} // setting initial value
{...{animatedProps}}
editable={false}
// @ts-expect-error should be fixed in version 3.5 (https://github.com/software-mansion/react-native-reanimated/pull/4881)
style={styles.title}
/>);
};
Expand Down
2 changes: 0 additions & 2 deletions src/incubator/Calendar/TodayButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ const TodayButton = (props: TodayButtonProps) => {
const {containerStyle, buttonProps} = props;
const {selectedDate, setDate} = useContext(CalendarContext);

// @ts-expect-error should be fixed in version 3.5 (https://github.com/software-mansion/react-native-reanimated/pull/4881)
const animatedStyle = useAnimatedStyle(() => {
return {
transform: [
Expand All @@ -40,7 +39,6 @@ const TodayButton = (props: TodayButtonProps) => {
[buttonProps]);

return (
// @ts-expect-error should be fixed in version 3.5 (https://github.com/software-mansion/react-native-reanimated/pull/4881)
<View reanimated style={[styles.container, containerStyle, animatedStyle]}>
<Button
outline
Expand Down
2 changes: 0 additions & 2 deletions src/incubator/Dialog/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,6 @@ const Dialog = (props: DialogProps, ref: ForwardedRef<DialogImperativeMethods>)
children
});

// @ts-expect-error should be fixed in version 3.5 (https://github.com/software-mansion/react-native-reanimated/pull/4881)
const animatedStyle = useAnimatedStyle(() => {
if (isVertical) {
return {
Expand Down Expand Up @@ -213,7 +212,6 @@ const Dialog = (props: DialogProps, ref: ForwardedRef<DialogImperativeMethods>)

const renderDialog = () => (
<GestureDetector gesture={panGesture}>
{/* @ts-expect-error should be fixed in version 3.5 (https://github.com/software-mansion/react-native-reanimated/pull/4881) */}
<View {...containerProps} reanimated style={style} onLayout={onLayout} ref={setRef} testID={testID}>
<DialogContent/>
</View>
Expand Down
2 changes: 0 additions & 2 deletions src/incubator/Slider/Thumb.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,6 @@ const Thumb = (props: ThumbProps) => {
});
gesture.enabled(!disabled);

// @ts-expect-error should be fixed in version 3.5 (https://github.com/software-mansion/react-native-reanimated/pull/4881)
const animatedStyle = useAnimatedStyle(() => {
const customStyle = isPressed.value ? activeStyle?.value : defaultStyle?.value;
return {
Expand All @@ -110,7 +109,6 @@ const Thumb = (props: ThumbProps) => {
<GestureDetector gesture={gesture}>
<View
reanimated
// @ts-expect-error should be fixed in version 3.5 (https://github.com/software-mansion/react-native-reanimated/pull/4881)
style={[styles.thumbPosition, enableShadow && styles.thumbShadow, animatedStyle]}
hitSlop={hitSlop}
onLayout={onThumbLayout}
Expand Down
1 change: 0 additions & 1 deletion src/incubator/Slider/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,6 @@ const Slider = React.memo((props: Props) => {
}
};

// @ts-expect-error should be fixed in version 3.5 (https://github.com/software-mansion/react-native-reanimated/pull/4881)
const trackAnimatedStyles = useAnimatedStyle(() => {
if (useRange) {
return {
Expand Down
61 changes: 33 additions & 28 deletions src/incubator/TouchableOpacity.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import React, {PropsWithChildren, useCallback, useMemo} from 'react';
import {LayoutChangeEvent} from 'react-native';
import Reanimated, {
useAnimatedGestureHandler,
useAnimatedStyle,
useSharedValue,
withTiming,
Expand Down Expand Up @@ -104,35 +103,41 @@ function TouchableOpacity(props: Props) {
isActive.value = withTiming(value, {duration: 200});
};

const tapGestureHandler = useAnimatedGestureHandler({
onStart: () => {
toggleActive(1);
},
onEnd: () => {
toggleActive(0);
runOnJS(onPress)();
},
onFail: () => {
if (!isLongPressed.value) {
const tapGestureHandler = ({nativeEvent: {state}}: any) => {
switch (state) {
case State.BEGAN:
toggleActive(1);
break;
case State.CANCELLED:
case State.END:
toggleActive(0);
}
runOnJS(onPress)();
break;
case State.FAILED:
if (!isLongPressed.value) {
toggleActive(0);
}
break;
}
});

const longPressGestureHandler = useAnimatedGestureHandler({
onActive: () => {
if (!isLongPressed.value) {
isLongPressed.value = true;
runOnJS(onLongPress)();
}
},
onFinish: () => {
toggleActive(0);
isLongPressed.value = false;
};

const longPressGestureHandler = ({nativeEvent: {state}}: any) => {
switch (state) {
case State.ACTIVE:
if (!isLongPressed.value) {
isLongPressed.value = true;
runOnJS(onLongPress)();
}
break;
case State.CANCELLED:
case State.END:
case State.FAILED:
toggleActive(0);
isLongPressed.value = false;
break;
}
});
};

// @ts-expect-error should be fixed in version 3.5 (https://github.com/software-mansion/react-native-reanimated/pull/4881)
const animatedStyle = useAnimatedStyle(() => {
const activeColor = feedbackColor || backgroundColor;
const opacity = interpolate(isActive.value, [0, 1], [1, activeOpacity]);
Expand All @@ -151,12 +156,12 @@ function TouchableOpacity(props: Props) {

return (
<TapGestureHandler
onGestureEvent={tapGestureHandler}
onHandlerStateChange={tapGestureHandler}
shouldCancelWhenOutside
enabled={!disabled}
>
<Reanimated.View>
<Container onGestureEvent={longPressGestureHandler} shouldCancelWhenOutside>
<Container onHandlerStateChange={longPressGestureHandler} shouldCancelWhenOutside>
<Reanimated.View
{...others}
ref={forwardedRef}
Expand Down
Loading