Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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: 2 additions & 2 deletions apps/common-app/src/new_api/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import SwitchTextInputExample from './components/switchAndInput';
import TouchableExample from './components/touchable';
import TouchableStressExample from './components/touchable_stress';
import ContextMenuExample from './hover_mouse/context_menu';
import HoverIconsExample from './hover_mouse/hover';
import HoverPositioningExample from './hover_mouse/hover';
import HoverableIconsExample from './hover_mouse/hoverable_icons';
import MouseButtonsExample from './hover_mouse/mouse_buttons';
import StylusDataExample from './hover_mouse/stylus_data';
Expand Down Expand Up @@ -83,7 +83,7 @@ export const NEW_EXAMPLES: ExamplesSection[] = [
component: ContextMenuExample,
unsupportedPlatforms: new Set(['android', 'ios', 'macos']),
},
{ name: 'Hover Icons', component: HoverIconsExample },
{ name: 'Hover Positioning', component: HoverPositioningExample },
{ name: 'Hoverable Icons', component: HoverableIconsExample },
{ name: 'Mouse Buttons', component: MouseButtonsExample },
],
Expand Down
119 changes: 52 additions & 67 deletions apps/common-app/src/new_api/showcase/shared_value/index.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import React from 'react';
import { Text, View } from 'react-native';
import { StyleSheet, Text, View } from 'react-native';
import {
GestureDetector,
useLongPressGesture,
usePanGesture,
useSimultaneousGestures,
Touchable,
useTapGesture,
} from 'react-native-gesture-handler';
import Animated, {
interpolateColor,
Expand All @@ -15,76 +14,62 @@ import Animated, {

import { COLORS, commonStyles } from '../../../common';

export default function PanExample() {
const translateX = useSharedValue(0);
const translateY = useSharedValue(0);
const colorProgress = useSharedValue(0);
const offsetX = useSharedValue(0);
const offsetY = useSharedValue(0);
const maxLongPressDistance = useSharedValue(20);
const panGesture = usePanGesture({
onBegin: () => {
colorProgress.value = withTiming(1, { duration: 150 });
},
onUpdate: (event) => {
translateX.value = offsetX.value + event.translationX;
translateY.value = offsetY.value + event.translationY;
maxLongPressDistance.value = Math.abs(event.translationY) * 2 + 20;
},
onFinalize: () => {
offsetX.value = translateX.value;
offsetY.value = translateY.value;
},
});
export default function SharedValueConfigExample() {
const numberOfTaps = useSharedValue(1);
const flashProgress = useSharedValue(0);

const longPressGesture = useLongPressGesture({
onBegin: () => {
colorProgress.value = withTiming(1, {
duration: 100,
});
},
const tap = useTapGesture({
numberOfTaps,
onActivate: () => {
colorProgress.value = withTiming(2, {
duration: 100,
});
flashProgress.value = 1;
flashProgress.value = withTiming(0, { duration: 400 });
},
onFinalize: () => {
colorProgress.value = withTiming(0, {
duration: 100,
});
},
minDuration: 1000,
maxDistance: maxLongPressDistance,
});

const gestures = useSimultaneousGestures(longPressGesture, panGesture);
const animatedStyle = useAnimatedStyle(() => {
const backgroundColor = interpolateColor(
colorProgress.value,
[0, 1, 2],
[COLORS.NAVY, COLORS.PURPLE, COLORS.KINDA_BLUE]
);
return {
transform: [
{ translateX: translateX.value },
{ translateY: translateY.value },
],
backgroundColor,
};
});
const boxStyle = useAnimatedStyle(() => ({
backgroundColor: interpolateColor(
flashProgress.value,
[0, 1],
[COLORS.NAVY, COLORS.KINDA_BLUE]
),
}));

return (
<View style={commonStyles.centerView}>
<View>
<GestureDetector gesture={gestures}>
<Animated.View style={[commonStyles.ball, animatedStyle]} />
</GestureDetector>
</View>
<Text style={commonStyles.instructions}>
The ball has simultanous pan and longPress gestures. Upon update pan
changes minDistance of longPress, such that longPress will fail if is
moved horizontally.
</Text>
<View style={styles.container}>
<GestureDetector gesture={tap}>
<Animated.View style={[commonStyles.box, boxStyle]} />
</GestureDetector>

<Touchable
style={styles.button}
activeOpacity={0.6}
animationDuration={{ in: 80, out: 200 }}
onPress={() => {
numberOfTaps.value += 1;
}}>
<Text style={styles.buttonLabel}>Increment required taps</Text>
</Touchable>
</View>
);
}

const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
gap: 24,
},

button: {
paddingHorizontal: 24,
paddingVertical: 12,
backgroundColor: COLORS.PURPLE,
borderRadius: 8,
},
buttonLabel: {
color: '#fff',
fontSize: 16,
fontWeight: '600',
},
});
148 changes: 79 additions & 69 deletions apps/common-app/src/new_api/showcase/state_manager/index.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import React from 'react';
import { View } from 'react-native';
import type { LongPressGesture } from 'react-native-gesture-handler';
import { StyleSheet, Text, View } from 'react-native';
import {
GestureDetector,
GestureHandlerRootView,
GestureStateManager,
useLongPressGesture,
usePanGesture,
} from 'react-native-gesture-handler';
import Animated, {
useAnimatedStyle,
Expand All @@ -15,83 +13,95 @@ import Animated, {

import { COLORS, commonStyles } from '../../../common';

export default function TwoPressables() {
const isActivated = [
useSharedValue(0),
useSharedValue(0),
useSharedValue(0),
useSharedValue(0),
];
const gestures: LongPressGesture[] = [];
export default function GestureStateManagerExample() {
const upperPanActive = useSharedValue(0);
const bottomPanActive = useSharedValue(0);

const createGestureConfig = (index: number) => ({
const bottomPan = usePanGesture({
onActivate: () => {
'worklet';
isActivated[index].value = 1;
console.log(`Box ${index}: long pressed`);
bottomPanActive.value = 1;
},
onFinalize: () => {
bottomPanActive.value = withTiming(0, { duration: 300 });
},
minDistance: 50,
});

const nextIndex = index + 1;
if (nextIndex < gestures.length) {
const nextGesture = gestures[nextIndex];
if (nextGesture) {
GestureStateManager.activate(nextGesture.handlerTag);
}
}
const upperPan = usePanGesture({
onActivate: () => {
upperPanActive.value = 1;
GestureStateManager.activate(bottomPan.handlerTag);
},
onFinalize: () => {
'worklet';
isActivated[index].value = 0;
const nextIndex = index + 1;
if (nextIndex < gestures.length) {
const nextGesture = gestures[nextIndex];
if (nextGesture) {
GestureStateManager.deactivate(nextGesture.handlerTag);
}
}
upperPanActive.value = withTiming(0, { duration: 300 });
GestureStateManager.deactivate(bottomPan.handlerTag);
},
disableReanimated: true,
});

const g0 = useLongPressGesture(createGestureConfig(0));
const g1 = useLongPressGesture(createGestureConfig(1));
const g2 = useLongPressGesture(createGestureConfig(2));
const g3 = useLongPressGesture(createGestureConfig(3));
const upperPanStyle = useAnimatedStyle(() => ({
backgroundColor: COLORS.PURPLE,
transform: [{ scale: withTiming(upperPanActive.value === 1 ? 0.9 : 1) }],
opacity: withTiming(upperPanActive.value === 1 ? 0.6 : 1),
}));

gestures[0] = g0;
gestures[1] = g1;
gestures[2] = g2;
gestures[3] = g3;
const bottomPanStyle = useAnimatedStyle(() => ({
backgroundColor: COLORS.GREEN,
transform: [{ scale: withTiming(bottomPanActive.value === 1 ? 0.9 : 1) }],
opacity: withTiming(bottomPanActive.value === 1 ? 0.6 : 1),
}));

const colors = [COLORS.PURPLE, COLORS.NAVY, COLORS.GREEN, COLORS.RED];
return (
<View style={styles.container}>
<Text style={styles.title}>GestureStateManager</Text>

function Box({ index }: { index: number }) {
const animatedStyle = useAnimatedStyle(() => ({
opacity: isActivated[index].value === 1 ? 0.5 : 1,
transform: [
{ scale: withTiming(isActivated[index].value === 1 ? 0.95 : 1) },
],
}));
<GestureDetector gesture={upperPan}>
<Animated.View style={[commonStyles.box, upperPanStyle]} />
</GestureDetector>
<Text style={styles.boxLabel}>Box A — pan me</Text>

return (
<GestureDetector gesture={gestures[index]}>
<Animated.View
style={[
commonStyles.box,
{ backgroundColor: colors[index] },
animatedStyle,
]}
/>
<GestureDetector gesture={bottomPan}>
<Animated.View style={[commonStyles.box, bottomPanStyle]} />
</GestureDetector>
);
}
return (
<GestureHandlerRootView>
<View style={commonStyles.centerView}>
<Box index={0} />
<Box index={1} />
<Box index={2} />
<Box index={3} />
</View>
</GestureHandlerRootView>
<Text style={styles.boxLabel}>Box B — touch me, then pan A</Text>

<Text style={styles.hint}>
Touch Box B to begin its pan gesture, then pan Box A. Box A calls{' '}
<Text style={styles.code}>GestureStateManager.activate</Text> on Box
B&apos;s gesture. Box B must have a pointer on its surface to be managed
by StateManager.
</Text>
</View>
);
}

const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
gap: 16,
},
title: {
fontSize: 20,
fontWeight: '700',
color: COLORS.NAVY,
marginBottom: 8,
},
boxLabel: {
fontSize: 13,
opacity: 0.6,
color: COLORS.NAVY,
},
hint: {
fontSize: 13,
opacity: 0.5,
textAlign: 'center',
paddingHorizontal: 32,
marginTop: 8,
color: COLORS.NAVY,
},
code: {
fontFamily: 'monospace',
fontSize: 12,
},
});
Loading