Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
dad2eaa
new file
m-bert Nov 3, 2025
6dbc10d
use native
m-bert Nov 3, 2025
4f1dcaa
Buttons
m-bert Nov 3, 2025
8ccf267
Remove Reanimated
m-bert Nov 3, 2025
df3f1fb
Components
m-bert Nov 4, 2025
a1da35a
Add proper values to relations
m-bert Nov 4, 2025
a680461
Bring back old components
m-bert Nov 4, 2025
a0d0240
Deprecate legacy buttons
m-bert Nov 4, 2025
ef1e736
Deprecate legacy components
m-bert Nov 4, 2025
563fab3
Export new components
m-bert Nov 4, 2025
0f40c58
Add web file
m-bert Nov 4, 2025
13951df
Merge branch 'next' into @mbert/components-new-api
m-bert Nov 4, 2025
b77cc2b
Update import
m-bert Nov 4, 2025
c336453
use ref in check
m-bert Nov 4, 2025
c3f4320
Correct refs
m-bert Nov 4, 2025
c6c83ba
Merge branch 'next' into @mbert/components-new-api
m-bert Nov 12, 2025
86c38f3
Merge branch 'next' into @mbert/components-new-api
m-bert Nov 13, 2025
baf7eb1
Merge branch 'next' into @mbert/components-new-api
m-bert Nov 14, 2025
c8f7c8c
Add examples
m-bert Nov 14, 2025
2a356f8
Fix buttons
m-bert Nov 14, 2025
73969da
Yet another fix
m-bert Nov 14, 2025
f4fa5f6
Remove Drawer Layout
m-bert Nov 14, 2025
ede51fe
Impoort hooks directly
m-bert Nov 15, 2025
d34ef86
remove import
m-bert Nov 15, 2025
fdf9533
Update examples
m-bert Nov 15, 2025
38f36fe
Merge branch 'next' into @mbert/components-new-api
m-bert Nov 17, 2025
25bd430
Update scroll example
m-bert Nov 18, 2025
4c5eaf8
Correctly attach NativeViewGestureHandler
m-bert Nov 18, 2025
36d1afb
Fix relations in ScrollView
m-bert Nov 18, 2025
11eeef1
FlatList
m-bert Nov 19, 2025
753d43b
Merge branch 'next' into @mbert/components-new-api
m-bert Nov 24, 2025
9b4743a
Import hooks directly
m-bert Nov 24, 2025
f04d434
Fixes
m-bert Nov 24, 2025
1f77201
Update example
m-bert Nov 24, 2025
b491534
Update Scroll ref
m-bert Nov 24, 2025
0ea974e
Correct web initialization
m-bert Nov 24, 2025
03b8a0f
Remove comment
m-bert Nov 24, 2025
5a6dc60
Do not unpack rippleColor
m-bert Nov 24, 2025
0ce2be8
Remove testID
m-bert Nov 24, 2025
23403fa
Remove testID from cnw
m-bert Nov 24, 2025
b7c461d
Disbale reanimated for components
m-bert Nov 24, 2025
7f36f1b
Merge branch 'next' into @mbert/components-new-api
m-bert Nov 24, 2025
e84f3cf
Update packages/react-native-gesture-handler/src/v3/components/Gestur…
m-bert Nov 26, 2025
110d333
Always assign hostDetectorView
m-bert Nov 26, 2025
5f7ec9c
Add ref types
m-bert Nov 27, 2025
cff6bce
Merge branch 'next' into @mbert/components-new-api
m-bert Nov 27, 2025
3da70f6
Remove handlerData
m-bert Nov 27, 2025
aabc5b4
New viewForEvents
m-bert Nov 27, 2025
7ad7ad7
Add comment
m-bert Nov 28, 2025
06428d4
Fix type
m-bert Nov 28, 2025
a2298ef
Merge branch 'next' into @mbert/components-new-api
m-bert Nov 28, 2025
05e7327
Merge branch 'next' into @mbert/components-new-api
m-bert Dec 1, 2025
410cc90
Rename callbacks
m-bert Dec 1, 2025
a66158c
Bring back ref only to component
m-bert Dec 1, 2025
95d7d1a
Merge branch 'next' into @mbert/components-new-api
m-bert Dec 1, 2025
f35b66a
Rename and add effect
m-bert Dec 2, 2025
90bb817
Merge branch 'next' into @mbert/components-new-api
m-bert Dec 2, 2025
8381df0
Correct type
m-bert Dec 2, 2025
9e4c666
Add example
m-bert Dec 2, 2025
fc4d06f
Fix wrong layouts
m-bert Dec 3, 2025
28ea2ce
Move check
m-bert Dec 3, 2025
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
3 changes: 1 addition & 2 deletions apps/common-app/src/components/flatlist/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import {
FlatList,
RefreshControl,
GestureHandlerRootView,
GHFlatListRef,
} from 'react-native-gesture-handler';

const DATA = Array.from({ length: 20 }, (_, i) => ({
Expand All @@ -21,7 +20,7 @@ const Item = ({ title }: { title: string }) => (
export default function FlatListExample() {
const [refreshing, setRefreshing] = useState(false);

const ref = useRef<GHFlatListRef>(null);
const ref = useRef<FlatList>(null);

const onRefresh = () => {
setRefreshing(true);
Expand Down
8 changes: 2 additions & 6 deletions apps/common-app/src/components/scrollview/index.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
import React, { useRef, useState } from 'react';
import { Text, StyleSheet, View } from 'react-native';
import {
ScrollView,
RefreshControl,
GHScrollViewRef,
} from 'react-native-gesture-handler';
import { ScrollView, RefreshControl } from 'react-native-gesture-handler';

const DATA = Array.from({ length: 20 }, (_, i) => ({
id: i.toString(),
Expand All @@ -20,7 +16,7 @@ const Item = ({ title }: { title: string }) => (
export default function ScrollViewExample() {
const [refreshing, setRefreshing] = useState(false);

const ref = useRef<GHScrollViewRef>(null);
const ref = useRef<ScrollView>(null);

const onRefresh = () => {
setRefreshing(true);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import React, {
PropsWithChildren,
ReactElement,
useRef,
useImperativeHandle,
useState,
RefObject,
} from 'react';
Expand All @@ -16,22 +14,15 @@ import {
FlatList as RNFlatList,
FlatListProps as RNFlatListProps,
RefreshControl as RNRefreshControl,
RefreshControlProps as RNRefreshControlProps,
} from 'react-native';

import createNativeWrapper, {
ComponentWrapperRef,
} from '../createNativeWrapper';
import createNativeWrapper from '../createNativeWrapper';

import { NativeWrapperProperties } from '../types/NativeWrapperType';
import { NativeWrapperProps } from '../hooks/utils';
import { DetectorType } from '../detectors';
import { NativeGesture } from '../hooks/gestures/native/useNativeGesture';

export type ImperativeRefreshControlRef = ComponentWrapperRef<
RNRefreshControlProps,
RNRefreshControl
> | null;
import { ghQueueMicrotask } from '../../ghQueueMicrotask';

export const RefreshControl = createNativeWrapper(
RNRefreshControl,
Expand All @@ -43,12 +34,7 @@ export const RefreshControl = createNativeWrapper(
);

// eslint-disable-next-line @typescript-eslint/no-redeclare
export type RefreshControl = typeof RefreshControl;

export type ImperativeScrollViewRef = ComponentWrapperRef<
RNScrollViewProps,
RNScrollView
> | null;
export type RefreshControl = typeof RefreshControl & RNRefreshControl;

const GHScrollView = createNativeWrapper<PropsWithChildren<RNScrollViewProps>>(
RNScrollView,
Expand All @@ -62,33 +48,33 @@ const GHScrollView = createNativeWrapper<PropsWithChildren<RNScrollViewProps>>(
export const ScrollView = (
props: RNScrollViewProps &
NativeWrapperProperties & {
ref?: React.RefObject<ImperativeScrollViewRef>;
// This prop exists because using `ref` in `renderScrollComponent` doesn't work (it is overwritten by RN internals).
innerRef?: (node: ImperativeScrollViewRef) => void;
ref?: React.RefObject<RNScrollView | null>;
updateGesture_CAN_CAUSE_INFINITE_RERENDER?: (
gesture: NativeGesture
) => void;
}
) => {
const { refreshControl, innerRef, ref, ...rest } = props;
const { refreshControl, updateGesture_CAN_CAUSE_INFINITE_RERENDER, ...rest } =
props;

const [scrollGesture, setScrollGesture] = useState<NativeGesture | null>(
null
);

const wrapperRef = useRef<ImperativeScrollViewRef>(null);

useImperativeHandle<ImperativeScrollViewRef, ImperativeScrollViewRef>(
ref,
() => wrapperRef.current
);
const updateGesture = (gesture: NativeGesture) => {
ghQueueMicrotask(() => {
if (!scrollGesture || scrollGesture.tag !== gesture.tag) {
setScrollGesture(gesture);
updateGesture_CAN_CAUSE_INFINITE_RERENDER?.(gesture);
}
});
};

return (
<GHScrollView
{...rest}
// @ts-ignore `ref` exists on `GHScrollView`
ref={(node: ImperativeScrollViewRef) => {
setScrollGesture(node?.gestureRef ?? null);
wrapperRef.current = node;
innerRef?.(node);
}}
ref={props.ref}
updateGesture_CAN_CAUSE_INFINITE_RERENDER={updateGesture}
// @ts-ignore we don't pass `refreshing` prop as we only want to override the ref
refreshControl={
refreshControl
Expand All @@ -104,12 +90,7 @@ export const ScrollView = (
};

// eslint-disable-next-line @typescript-eslint/no-redeclare
export type ScrollView = typeof ScrollView;

export type ImperativeSwitchRef = ComponentWrapperRef<
RNSwitchProps,
RNSwitch
> | null;
export type ScrollView = typeof ScrollView & RNScrollView;

export const Switch = createNativeWrapper<RNSwitchProps>(RNSwitch, {
shouldCancelWhenOutside: false,
Expand All @@ -118,33 +99,33 @@ export const Switch = createNativeWrapper<RNSwitchProps>(RNSwitch, {
});

// eslint-disable-next-line @typescript-eslint/no-redeclare
export type Switch = typeof Switch;

export type ImperativeTextInputRef = ComponentWrapperRef<
RNTextInputProps,
RNTextInput
> | null;
export type Switch = typeof Switch & RNSwitch;

export const TextInput = createNativeWrapper<RNTextInputProps>(RNTextInput);

export type ImperativeFlatListRef<T = any> =
| (ComponentWrapperRef<RNScrollViewProps, RNScrollView> & {
flatListRef: RNFlatList<T> | null;
})
| null;

// eslint-disable-next-line @typescript-eslint/no-redeclare
export type TextInput = typeof TextInput;
export type TextInput = typeof TextInput & RNTextInput;

export const FlatList = ((props) => {
const { refreshControl, ref, ...rest } = props;
const {
refreshControl,
ref,
updateGesture_CAN_CAUSE_INFINITE_RERENDER,
...rest
} = props;

const [scrollGesture, setScrollGesture] = useState<NativeGesture | null>(
null
);

const wrapperRef = useRef<ImperativeScrollViewRef>(null);
const flatListRef = useRef<RNFlatList<any>>(null);
const updateGesture = (gesture: NativeGesture) => {
ghQueueMicrotask(() => {
if (!scrollGesture || scrollGesture.tag !== gesture.tag) {
setScrollGesture(gesture);
updateGesture_CAN_CAUSE_INFINITE_RERENDER?.(gesture);
}
});
};

const flatListProps = {};
const scrollViewProps = {};
Expand All @@ -162,28 +143,14 @@ export const FlatList = ((props) => {
}
}

useImperativeHandle<ImperativeFlatListRef, ImperativeFlatListRef>(
// @ts-ignore We want to override ref
ref,
() => {
return {
...wrapperRef.current,
flatListRef: flatListRef.current,
};
}
);

return (
// @ts-ignore - this function cannot have generic type so we have to ignore this error
<RNFlatList
ref={flatListRef}
ref={ref}
{...flatListProps}
renderScrollComponent={(scrollProps) => (
<ScrollView
innerRef={(node: ImperativeScrollViewRef) => {
setScrollGesture(node?.gestureRef ?? null);
wrapperRef.current = node;
}}
updateGesture_CAN_CAUSE_INFINITE_RERENDER={updateGesture}
{...{
...scrollProps,
...scrollViewProps,
Expand All @@ -206,10 +173,13 @@ export const FlatList = ((props) => {
props: PropsWithChildren<
Omit<RNFlatListProps<ItemT>, 'renderScrollComponent' | 'ref'> &
NativeWrapperProperties & {
ref?: RefObject<ImperativeFlatListRef<ItemT>>;
ref?: RefObject<RNFlatList<ItemT> | null>;
updateGesture_CAN_CAUSE_INFINITE_RERENDER?: (
gesture: NativeGesture
) => void;
}
>
) => ReactElement | null;

// eslint-disable-next-line @typescript-eslint/no-redeclare
export type FlatList = typeof FlatList;
export type FlatList = typeof FlatList & RNFlatList;
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,3 @@ export {
FlatList,
RefreshControl,
} from './GestureComponents';

export type {
ImperativeFlatListRef as GHFlatListRef,
ImperativeRefreshControlRef as GHRefreshControlRef,
ImperativeScrollViewRef as GHScrollViewRef,
ImperativeSwitchRef as GHSwitchRef,
ImperativeTextInputRef as GHTextInputRef,
} from './GestureComponents';
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useImperativeHandle, useRef } from 'react';
import React from 'react';

import { NativeWrapperProps } from './hooks/utils';
import { useNativeGesture } from './hooks/gestures';
Expand All @@ -8,21 +8,24 @@ import { NativeGesture } from './hooks/gestures/native/useNativeGesture';
import { DetectorType, InterceptingGestureDetector } from './detectors';
import { VirtualDetector } from './detectors/VirtualDetector/VirtualDetector';

export type ComponentWrapperRef<P, T> = {
componentRef?: React.ComponentType<P> & T;
gestureRef?: NativeGesture;
};

export default function createNativeWrapper<P>(
Component: React.ComponentType<P>,
config: Readonly<NativeWrapperProperties> = {},
detectorType: DetectorType = DetectorType.Native
) {
const ComponentWrapper = (
props: P & NativeWrapperProperties & { ref?: React.RefObject<unknown> }
props: P &
NativeWrapperProperties & {
ref?: React.RefObject<unknown>;
updateGesture_CAN_CAUSE_INFINITE_RERENDER?: (
gesture: NativeGesture
) => void;
}
) => {
const { ref, updateGesture_CAN_CAUSE_INFINITE_RERENDER, ...restProps } =
props;
// Filter out props that should be passed to gesture handler wrapper
const { gestureHandlerProps, childProps } = Object.keys(props).reduce(
const { gestureHandlerProps, childProps } = Object.keys(restProps).reduce(
(res, key) => {
// @ts-ignore TS being overly protective with it's types, see https://github.com/microsoft/TypeScript/issues/26255#issuecomment-458013731 for more info
if (NativeWrapperProps.has(key)) {
Expand All @@ -48,14 +51,7 @@ export default function createNativeWrapper<P>(
}

const native = useNativeGesture(gestureHandlerProps);

const componentRef = useRef<React.ComponentType<P>>(null);
const gestureRef = useRef<NativeGesture>(native);

useImperativeHandle(props.ref, () => ({
componentRef: componentRef.current,
gestureRef: gestureRef.current,
}));
updateGesture_CAN_CAUSE_INFINITE_RERENDER?.(native);

const DetectorComponent =
detectorType === DetectorType.Intercepting
Expand All @@ -66,7 +62,7 @@ export default function createNativeWrapper<P>(

return (
<DetectorComponent gesture={native}>
<Component {...childProps} ref={componentRef} />
<Component {...childProps} ref={ref} />
</DetectorComponent>
);
};
Expand Down
Loading