Skip to content

Update GestureButton props type#3973

Open
m-bert wants to merge 3 commits intomainfrom
@mbert/button-types
Open

Update GestureButton props type#3973
m-bert wants to merge 3 commits intomainfrom
@mbert/button-types

Conversation

@m-bert
Copy link
Contributor

@m-bert m-bert commented Feb 12, 2026

Description

I've noticed that our buttons still had props like onBegan available, even though it was a reference to the old API. This PR changes that, so that additional properties on buttons come only from NativeWrapper.

It also changes hitSlop type to the one from React Native.

Test plan

  • yarn ts-check
  • yarn lint-js
  • Example with buttons in basic-example (with console.log in onPress added)

Copilot AI review requested due to automatic review settings February 12, 2026 10:08
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR updates the v3 button/native-wrapper TypeScript surface so that “extra” button props come from NativeWrapper (removing legacy handler-style props like onBegan), and tightens wrapper generics to better type ref/wrapper behavior across wrapped RN components.

Changes:

  • Make NativeWrapperProperties generic over the wrapped ref type and move wrapper-only props (e.g. ref, onGestureUpdate_CAN_CAUSE_INFINITE_RERENDER) into that type.
  • Update v3 wrapped components (ScrollView, FlatList, Switch, TextInput, RefreshControl) to use the new generic wrapper typing.
  • Refactor v3 GestureButton prop types to be based on GestureHandlerButton’s props + NativeWrapperProperties (and aim to switch hitSlop typing).

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
packages/react-native-gesture-handler/src/v3/types/NativeWrapperType.ts Makes native-wrapper props generic and adds wrapper-only props to the exported type.
packages/react-native-gesture-handler/src/v3/hooks/utils/propsWhiteList.ts Updates whitelist typing to account for the new NativeWrapperProperties<T> generic.
packages/react-native-gesture-handler/src/v3/createNativeWrapper.tsx Updates createNativeWrapper generics/signature to use the new NativeWrapperProperties<R> form.
packages/react-native-gesture-handler/src/v3/components/GestureComponents.tsx Updates wrapped RN component exports to pass correct ref/props generics.
packages/react-native-gesture-handler/src/v3/components/GestureButtonsProps.ts Refactors v3 button prop types to derive from GestureHandlerButton + NativeWrapperProperties.
packages/react-native-gesture-handler/src/components/GestureHandlerButton.tsx Moves button prop definitions here and updates the native component typing accordingly.
Comments suppressed due to low confidence (1)

packages/react-native-gesture-handler/src/components/GestureHandlerButton.tsx:163

  • StyleSheet.flatten(style) can return undefined when style is not provided. Destructuring flattenedStyle will then throw at runtime (e.g., when RawButton/BaseButton are rendered without a style prop). Default flattenedStyle to an empty object before destructuring (e.g., StyleSheet.flatten(style) ?? {}).
export default function GestureHandlerButton({ style, ...rest }: ButtonProps) {
  const flattenedStyle = useMemo(() => StyleSheet.flatten(style), [style]);

  const {
    // Layout properties
    display,
    width,
    height,
    minWidth,
    maxWidth,
    minHeight,
    maxHeight,
    flex,
    flexGrow,
    flexShrink,
    flexBasis,
    flexDirection,
    flexWrap,
    justifyContent,
    alignItems,
    alignContent,
    alignSelf,
    aspectRatio,
    gap,
    rowGap,
    columnGap,
    margin,
    marginTop,
    marginBottom,
    marginLeft,
    marginRight,
    marginVertical,
    marginHorizontal,
    marginStart,
    marginEnd,
    padding,
    paddingTop,
    paddingBottom,
    paddingLeft,
    paddingRight,
    paddingVertical,
    paddingHorizontal,
    paddingStart,
    paddingEnd,
    position,
    top,
    right,
    bottom,
    left,
    start,
    end,
    overflow,

    // Visual properties
    ...restStyle
  } = flattenedStyle;


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

* set true.
*/
exclusive?: boolean;
// TODO: we should transform props in `createNativeWrapper`
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Well this is here for at least 5 years (I've gone down to #1327). I'm not sure which props should be transformed, and also I don't think that anyone knows what it supposed to mean.

Should we delete it? Most of the props are number/boolean anyway

Copy link
Member

Choose a reason for hiding this comment

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

I think so. Now that I think about it, it might've been referring to splitting props between those targeted at a gesture and those targeted at the underlying view, which we are doing.

} from '../hooks/gestures/native/useNativeGesture';

export type NativeWrapperProperties = CommonGestureConfig &
export type NativeWrapperProperties<T> = CommonGestureConfig &
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This change was mostly due to the fact that BorderlessButton was throwing TS errors with ref property, because when Animated component detects ref<unknown> it simply removes this prop.

import { VirtualDetector } from './detectors/VirtualDetector/VirtualDetector';

export default function createNativeWrapper<P>(
export default function createNativeWrapper<R = unknown, P = unknown>(
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Let me know if the order should be swapped, or if more descriptive name should be used.

Copy link
Member

Choose a reason for hiding this comment

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

Not a fan of single-letter generic names when there's more than one, and it's not obvious what they refer to.


const GHScrollView = createNativeWrapper<PropsWithChildren<RNScrollViewProps>>(
const GHScrollView = createNativeWrapper<
RNScrollView | null,
Copy link
Member

Choose a reason for hiding this comment

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

Why null?

import { VirtualDetector } from './detectors/VirtualDetector/VirtualDetector';

export default function createNativeWrapper<P>(
export default function createNativeWrapper<R = unknown, P = unknown>(
Copy link
Member

Choose a reason for hiding this comment

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

Not a fan of single-letter generic names when there's more than one, and it's not obvious what they refer to.

* set true.
*/
exclusive?: boolean;
// TODO: we should transform props in `createNativeWrapper`
Copy link
Member

Choose a reason for hiding this comment

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

I think so. Now that I think about it, it might've been referring to splitting props between those targeted at a gesture and those targeted at the underlying view, which we are doing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants