Skip to content
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

Add mouseButton prop #2676

Merged
merged 44 commits into from
Jan 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
cb67ac2
Remove context menu
m-bert Nov 17, 2023
bd3b6a9
Add prop
m-bert Nov 17, 2023
441c02c
Change enum order to match web
m-bert Nov 17, 2023
f82e08a
Change enum
m-bert Nov 17, 2023
6e1c651
Fix field in TouchEventManager
m-bert Nov 17, 2023
9731777
Implement logic on tap
m-bert Nov 17, 2023
edd5c2c
Add example
m-bert Nov 17, 2023
75f94b2
Merge branch 'main' into @mbert/web-right-click
m-bert Nov 20, 2023
eeb5ada
Change type
m-bert Nov 20, 2023
f414760
Another type change
m-bert Nov 20, 2023
fd7e0bb
Yet another type change
m-bert Nov 20, 2023
5373c13
change condition
m-bert Nov 20, 2023
0e2aaf8
Add check to other gestures
m-bert Nov 20, 2023
ecfcee2
Update example
m-bert Nov 20, 2023
6284ab3
Change View to ScrollView
m-bert Nov 20, 2023
64ff5d4
remove console.log
m-bert Nov 21, 2023
193e240
Change button names
m-bert Nov 21, 2023
0cbaebd
Change MouseButtons name in App
m-bert Nov 21, 2023
f77f453
Add MouseButton.ALL
m-bert Nov 21, 2023
09e11fd
Rename function
m-bert Nov 21, 2023
577724b
Merge branch 'main' into @mbert/web-right-click
m-bert Nov 21, 2023
7501737
Merge branch 'main' into @mbert/web-right-click
m-bert Nov 21, 2023
2d39d22
Merge branch 'main' into @mbert/web-right-click
m-bert Dec 6, 2023
ac10025
Merge branch 'main' into @mbert/web-right-click
m-bert Dec 14, 2023
7b660b4
Merge branch 'main' into @mbert/web-right-click
m-bert Dec 18, 2023
fbe82e2
Add enableContextMenu to builder
m-bert Dec 18, 2023
8f518b0
Merge branch 'main' into @mbert/web-right-click
m-bert Dec 19, 2023
0a1a18d
False now turns off context menu
m-bert Dec 19, 2023
1107e38
Move enableContextMenu to GestureDetector
m-bert Dec 19, 2023
6bd1c79
Add context menu example
m-bert Dec 20, 2023
19aa15b
Remove listeners on handler drop
m-bert Dec 20, 2023
063889e
Update example
m-bert Dec 20, 2023
5313243
Merge main
m-bert Jan 12, 2024
47e72e1
Merge branch 'main' into @mbert/web-right-click
m-bert Jan 15, 2024
60b8487
Change example
m-bert Jan 15, 2024
9ece9f9
Remove EnableContextMenu alias
m-bert Jan 15, 2024
2327174
Remove bounded listeners
m-bert Jan 15, 2024
1da7bfb
Remove finalize to onDestroy
m-bert Jan 15, 2024
26c4b3c
Restore default context menu blockade in LongPress
m-bert Jan 15, 2024
8279c90
Add destroy to WebDelegate
m-bert Jan 15, 2024
471002e
Restore bounded listeners
m-bert Jan 15, 2024
7432cdd
Revert "Restore bounded listeners"
m-bert Jan 15, 2024
c75fdb7
Change binding to this:void
m-bert Jan 15, 2024
f357411
Add destroy to delegate interface
m-bert Jan 16, 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
4 changes: 4 additions & 0 deletions example/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
import { TouchablesIndex, TouchableExample } from './release_tests/touchables';
import Rows from './release_tests/rows';
import Fling from './release_tests/fling';
import MouseButtons from './release_tests/mouseButtons';
import ContextMenu from './release_tests/contextMenu';
import NestedTouchables from './release_tests/nestedTouchables';
import NestedButtons from './release_tests/nestedButtons';
import NestedGestureHandlerRootViewWithModal from './release_tests/nestedGHRootViewWithModal';
Expand Down Expand Up @@ -116,6 +118,8 @@
{ name: 'Fling', component: Fling },
{ name: 'Combo', component: ComboWithGHScroll },
{ name: 'Touchables', component: TouchablesIndex as React.ComponentType },
{ name: 'MouseButtons', component: MouseButtons },
{ name: 'ContextMenu (web only)', component: ContextMenu },
{ name: 'Rounded buttons', component: RoundedButtons },
],
},
Expand Down Expand Up @@ -199,7 +203,7 @@
renderSectionHeader={({ section: { sectionTitle } }) => (
<Text style={styles.sectionTitle}>{sectionTitle}</Text>
)}
ItemSeparatorComponent={() => <View style={styles.separator} />}

Check warning on line 206 in example/src/App.tsx

View workflow job for this annotation

GitHub Actions / check (example)

Do not define components during render. React will see a new component type on every render and destroy the entire subtree’s DOM nodes and state (https://reactjs.org/docs/reconciliation.html#elements-of-different-types). Instead, move this component definition out of the parent component “MainScreen” and pass data as props. If you want to allow component creation in props, set allowAsProps option to true
/>
);
}
Expand Down
61 changes: 61 additions & 0 deletions example/src/release_tests/contextMenu/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import React from 'react';
import { StyleSheet, View } from 'react-native';
import {
Gesture,
GestureDetector,
MouseButton,
} from 'react-native-gesture-handler';

export default function ContextMenuExample() {
const p1 = Gesture.Pan().mouseButton(MouseButton.RIGHT);
const p2 = Gesture.Pan();
const p3 = Gesture.Pan();

return (
<View style={styles.container}>
<GestureDetector gesture={p1}>
<View style={[styles.box, styles.grandParent]}>
<GestureDetector gesture={p2} enableContextMenu={true}>
<View style={[styles.box, styles.parent]}>
<GestureDetector gesture={p3} enableContextMenu={false}>
<View style={[styles.box, styles.child]} />
</GestureDetector>
</View>
</GestureDetector>
</View>
</GestureDetector>
j-piasecki marked this conversation as resolved.
Show resolved Hide resolved
</View>
);
}

const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'space-around',
alignItems: 'center',
},

grandParent: {
width: 300,
height: 300,
backgroundColor: 'lightblue',
},

parent: {
width: 200,
height: 200,
backgroundColor: 'lightgreen',
},

child: {
width: 100,
height: 100,
backgroundColor: 'crimson',
},

box: {
display: 'flex',
justifyContent: 'space-around',
alignItems: 'center',
},
});
181 changes: 181 additions & 0 deletions example/src/release_tests/mouseButtons/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
import React from 'react';
import {
Gesture,
GestureDetector,
GestureType,
MouseButton,
Directions,
ScrollView,
} from 'react-native-gesture-handler';
import { StyleSheet, View, Text } from 'react-native';

const COLORS = ['darkmagenta', 'darkgreen', 'darkblue', 'crimson', 'pink'];

type TestProps = {
name: string;
gestureHandlers: GestureType[];
};

function Test({ name, gestureHandlers }: TestProps) {
return (
<View style={styles.center}>
<Text>{name}</Text>
<View
style={[
{ margin: 10, width: '100%', flexDirection: 'row' },
styles.center,
]}>
{gestureHandlers.map((handler, index) => {
return (
<GestureDetector gesture={handler} key={index}>
<View style={[styles.box, { backgroundColor: COLORS[index] }]} />
</GestureDetector>
);
})}
</View>
</View>
);
}

function TapTests() {
const leftTap = Gesture.Tap()
.mouseButton(MouseButton.LEFT)
.onEnd(() => console.log('Tap with left'));

const middleTap = Gesture.Tap()
.mouseButton(MouseButton.MIDDLE)
.onEnd(() => console.log('Tap with middle'));

const rightTap = Gesture.Tap()
.mouseButton(MouseButton.RIGHT)
.onEnd(() => console.log('Tap with right'));

const leftRightTap = Gesture.Tap()
.mouseButton(MouseButton.LEFT | MouseButton.RIGHT)
.onEnd(() => console.log('Tap with left | right'));

const allTap = Gesture.Tap()
m-bert marked this conversation as resolved.
Show resolved Hide resolved
.mouseButton(MouseButton.ALL)
.onEnd(() => console.log('Tap with any button'));

const gestureHandlers = [leftTap, middleTap, rightTap, leftRightTap, allTap];

return <Test name={'Tap'} gestureHandlers={gestureHandlers} />;
}

function PanTests() {
const leftPan = Gesture.Pan()
.mouseButton(MouseButton.LEFT)
.onChange(() => console.log('Panning with left'));

const middlePan = Gesture.Pan()
.mouseButton(MouseButton.MIDDLE)
.onChange(() => console.log('Panning with middle'));

const rightPan = Gesture.Pan()
.mouseButton(MouseButton.RIGHT)
.onChange(() => console.log('Panning with right'));

const leftRightPan = Gesture.Pan()
.mouseButton(MouseButton.LEFT | MouseButton.RIGHT)
.onChange(() => console.log('Panning with left | right'));

const allPan = Gesture.Pan()
.mouseButton(MouseButton.ALL)
.onChange(() => console.log('Panning with any button'));

const gestureHandlers = [leftPan, middlePan, rightPan, leftRightPan, allPan];

return <Test name={'Pan'} gestureHandlers={gestureHandlers} />;
}

function LongPressTests() {
const leftLongPress = Gesture.LongPress()
.mouseButton(MouseButton.LEFT)
.onStart(() => console.log('LongPress with left'));

const middleLongPress = Gesture.LongPress()
.mouseButton(MouseButton.MIDDLE)
.onStart(() => console.log('LongPress with middle'));

const rightLongPress = Gesture.LongPress()
.mouseButton(MouseButton.RIGHT)
.onStart(() => console.log('LongPress with right'));

const leftRightLongPress = Gesture.LongPress()
.mouseButton(MouseButton.LEFT | MouseButton.RIGHT)
.onStart(() => console.log('LongPress with left | right'));

const allLongPress = Gesture.LongPress()
.mouseButton(MouseButton.ALL)
.onStart(() => console.log('LongPress with any button'));

const gestureHandlers = [
leftLongPress,
middleLongPress,
rightLongPress,
leftRightLongPress,
allLongPress,
];

return <Test name={'LongPress'} gestureHandlers={gestureHandlers} />;
}

function FlingTests() {
const leftFling = Gesture.Fling()
.direction(Directions.LEFT | Directions.RIGHT)
.mouseButton(MouseButton.LEFT)
.onStart(() => console.log('Fling with left'));

const middleFling = Gesture.Fling()
.direction(Directions.LEFT | Directions.RIGHT)
.mouseButton(MouseButton.MIDDLE)
.onStart(() => console.log('Fling with middle'));

const rightFling = Gesture.Fling()
.direction(Directions.LEFT | Directions.RIGHT)
.mouseButton(MouseButton.RIGHT)
.onStart(() => console.log('Fling with right'));

const leftRightFling = Gesture.Fling()
.direction(Directions.LEFT | Directions.RIGHT)
.mouseButton(MouseButton.LEFT | MouseButton.RIGHT)
.onStart(() => console.log('Fling with left | right'));

const allFling = Gesture.Fling()
.direction(Directions.LEFT | Directions.RIGHT)
.mouseButton(MouseButton.ALL)
.onStart(() => console.log('Fling with any button'));

const gestureHandlers = [
leftFling,
middleFling,
rightFling,
leftRightFling,
allFling,
];

return <Test name={'Fling'} gestureHandlers={gestureHandlers} />;
}

export default function Buttons() {
return (
<ScrollView style={{ flex: 1 }}>
<TapTests />
<PanTests />
<LongPressTests />
<FlingTests />
</ScrollView>
);
}

const styles = StyleSheet.create({
center: {
alignItems: 'center',
justifyContent: 'space-around',
},
box: {
width: 75,
height: 75,
},
});
15 changes: 15 additions & 0 deletions src/components/DrawerLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
TapGestureHandlerEventPayload,
} from '../handlers/TapGestureHandler';
import { State } from '../State';
import { MouseButton } from '../web/interfaces';

const DRAG_TOSS = 0.05;

Expand Down Expand Up @@ -173,6 +174,18 @@
* Values: see CSS cursor values
*/
activeCursor?: ActiveCursor;

/**
* @default 'MouseButton.LEFT'
* Allows to choose which mouse button should underlying pan handler react to.
*/
mouseButton?: MouseButton;

/**
* @default 'false if MouseButton.RIGHT is specified'
* Allows to enable/disable context menu.
*/
enableContextMenu?: boolean;
}

export type DrawerLayoutState = {
Expand Down Expand Up @@ -319,7 +332,7 @@
);

const dragOffsetFromOnStartPosition = startPositionX.interpolate({
inputRange: [drawerWidth! - 1, drawerWidth!, drawerWidth! + 1],

Check warning on line 335 in src/components/DrawerLayout.tsx

View workflow job for this annotation

GitHub Actions / check

Forbidden non-null assertion

Check warning on line 335 in src/components/DrawerLayout.tsx

View workflow job for this annotation

GitHub Actions / check

Forbidden non-null assertion

Check warning on line 335 in src/components/DrawerLayout.tsx

View workflow job for this annotation

GitHub Actions / check

Forbidden non-null assertion
outputRange: [0, 0, 1],
});
translationX = Animated.add(
Expand All @@ -329,7 +342,7 @@
}

this.openValue = Animated.add(translationX, drawerTranslation).interpolate({
inputRange: [0, drawerWidth!],

Check warning on line 345 in src/components/DrawerLayout.tsx

View workflow job for this annotation

GitHub Actions / check

Forbidden non-null assertion
outputRange: [0, 1],
extrapolate: 'clamp',
});
Expand All @@ -341,7 +354,7 @@
ev: NativeSyntheticEvent<PanGestureHandlerEventPayload>
) => void;
} = {
useNativeDriver: props.useNativeAnimations!,

Check warning on line 357 in src/components/DrawerLayout.tsx

View workflow job for this annotation

GitHub Actions / check

Forbidden non-null assertion
};

if (this.props.onDrawerSlide) {
Expand Down Expand Up @@ -419,14 +432,14 @@

if (drawerType === 'front') {
dragOffsetBasedOnStart =
gestureStartX > drawerWidth! ? gestureStartX - drawerWidth! : 0;

Check warning on line 435 in src/components/DrawerLayout.tsx

View workflow job for this annotation

GitHub Actions / check

Forbidden non-null assertion

Check warning on line 435 in src/components/DrawerLayout.tsx

View workflow job for this annotation

GitHub Actions / check

Forbidden non-null assertion
}

const startOffsetX =
dragX + dragOffsetBasedOnStart + (this.drawerShown ? drawerWidth! : 0);

Check warning on line 439 in src/components/DrawerLayout.tsx

View workflow job for this annotation

GitHub Actions / check

Forbidden non-null assertion
const projOffsetX = startOffsetX + DRAG_TOSS * velocityX;

const shouldOpen = projOffsetX > drawerWidth! / 2;

Check warning on line 442 in src/components/DrawerLayout.tsx

View workflow job for this annotation

GitHub Actions / check

Forbidden non-null assertion

if (shouldOpen) {
this.animateDrawer(startOffsetX, drawerWidth!, velocityX);
Expand Down Expand Up @@ -700,6 +713,8 @@
// @ts-ignore could be fixed in handler types
userSelect={this.props.userSelect}
activeCursor={this.props.activeCursor}
mouseButton={this.props.mouseButton}
enableContextMenu={this.props.enableContextMenu}
ref={this.setPanGestureRef}
hitSlop={hitSlop}
activeOffsetX={gestureOrientation * minSwipeDistance!}
Expand Down
5 changes: 5 additions & 0 deletions src/handlers/gestureHandlerCommon.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { handlerIDToTag } from './handlersRegistry';
import { toArray } from '../utils';
import RNGestureHandlerModule from '../RNGestureHandlerModule';
import { ghQueueMicrotask } from '../ghQueueMicrotask';
import { MouseButton } from '../web/interfaces';

const commonProps = [
'id',
Expand All @@ -21,6 +22,8 @@ const commonProps = [
'cancelsTouchesInView',
'userSelect',
'activeCursor',
'mouseButton',
'enableContextMenu',
] as const;

const componentInteractionProps = [
Expand Down Expand Up @@ -149,6 +152,8 @@ export type CommonGestureConfig = {
hitSlop?: HitSlop;
userSelect?: UserSelect;
activeCursor?: ActiveCursor;
mouseButton?: MouseButton;
enableContextMenu?: boolean;
};

// Events payloads are types instead of interfaces due to TS limitation.
Expand Down
16 changes: 15 additions & 1 deletion src/handlers/gestures/GestureDetector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -605,10 +605,20 @@ const applyUserSelectProp = (
}
};

const applyEnableContextMenuProp = (
enableContextMenu: boolean,
gesture: ComposedGesture | GestureType
): void => {
for (const g of gesture.toGestureArray()) {
g.config.enableContextMenu = enableContextMenu;
}
};

interface GestureDetectorProps {
gesture: ComposedGesture | GestureType;
userSelect?: UserSelect;
children?: React.ReactNode;
userSelect?: UserSelect;
enableContextMenu?: boolean;
}
interface GestureDetectorState {
firstRender: boolean;
Expand All @@ -630,6 +640,10 @@ export const GestureDetector = (props: GestureDetectorProps) => {
applyUserSelectProp(props.userSelect, gestureConfig);
}

if (props.enableContextMenu !== undefined) {
applyEnableContextMenuProp(props.enableContextMenu, gestureConfig);
}

const gesture = gestureConfig.toGestureArray();
const useReanimatedHook = gesture.some((g) => g.shouldUseReanimated);

Expand Down
6 changes: 6 additions & 0 deletions src/handlers/gestures/gesture.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { RotationGestureHandlerEventPayload } from '../RotationGestureHandler';
import { TapGestureHandlerEventPayload } from '../TapGestureHandler';
import { NativeViewGestureHandlerPayload } from '../NativeViewGestureHandler';
import { isRemoteDebuggingEnabled } from '../../utils';
import { MouseButton } from '../../web/interfaces';

export type GestureType =
| BaseGesture<Record<string, unknown>>
Expand Down Expand Up @@ -257,6 +258,11 @@ export abstract class BaseGesture<
return this;
}

mouseButton(mouseButton: MouseButton) {
this.config.mouseButton = mouseButton;
return this;
}

runOnJS(runOnJS: boolean) {
this.config.runOnJS = runOnJS;
return this;
Expand Down
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { initialize } from './init';

export { Directions } from './Directions';
export { State } from './State';
export { MouseButton } from './web/interfaces';
export { default as gestureHandlerRootHOC } from './components/gestureHandlerRootHOC';
export { default as GestureHandlerRootView } from './components/GestureHandlerRootView';
export type {
Expand Down
4 changes: 4 additions & 0 deletions src/web/handlers/FlingGestureHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,10 @@ export default class FlingGestureHandler extends GestureHandler {
}

protected onPointerDown(event: AdaptedEvent): void {
if (!this.isButtonInConfig(event.button)) {
return;
}

this.tracker.addToTracker(event);
this.keyPointer = event.pointerId;

Expand Down
Loading
Loading