diff --git a/apps/common-app/src/common.tsx b/apps/common-app/src/common.tsx index 46aa1aed87..b8c35a81c4 100644 --- a/apps/common-app/src/common.tsx +++ b/apps/common-app/src/common.tsx @@ -32,6 +32,21 @@ export interface ExamplesSection { data: Example[]; } +export const COLORS = { + offWhite: '#f8f9ff', + headerSeparator: '#eef0ff', + PURPLE: '#b58df1', + NAVY: '#001A72', + RED: '#A41623', + YELLOW: '#F2AF29', + GREEN: '#0F956F', + GRAY: '#ADB1C2', + KINDA_RED: '#FFB2AD', + KINDA_YELLOW: '#FFF096', + KINDA_GREEN: '#C4E7DB', + KINDA_BLUE: '#A0D5EF', +}; + /* eslint-disable react-native/no-unused-styles */ export const commonStyles = StyleSheet.create({ centerView: { @@ -44,6 +59,8 @@ export const commonStyles = StyleSheet.create({ width: 150, borderRadius: 20, marginBottom: 30, + justifyContent: 'center', + alignItems: 'center', }, ball: { height: 120, @@ -72,6 +89,25 @@ export const commonStyles = StyleSheet.create({ justifyContent: 'center', textAlign: 'center', }, + row: { + flex: 1, + justifyContent: 'center', + alignItems: 'center', + flexDirection: 'row', + gap: 40, + padding: 20, + }, + centered: { + flexDirection: 'column', + alignItems: 'center', + justifyContent: 'center', + }, + caption: { + fontSize: 12, + color: COLORS.GRAY, + fontWeight: '600', + marginTop: 4, + }, }); /* eslint-enable react-native/no-unused-styles */ @@ -93,7 +129,7 @@ const styles = StyleSheet.create({ color: '#4A5568', }, feedback: { - marginTop: 20, + marginVertical: 10, fontSize: 16, fontWeight: '600', }, @@ -197,21 +233,6 @@ export const Feedback = ({ duration = 1000, ref }: FeedbackProps) => { ); }; -export const COLORS = { - offWhite: '#f8f9ff', - headerSeparator: '#eef0ff', - PURPLE: '#b58df1', - NAVY: '#001A72', - RED: '#A41623', - YELLOW: '#F2AF29', - GREEN: '#0F956F', - GRAY: '#ADB1C2', - KINDA_RED: '#FFB2AD', - KINDA_YELLOW: '#FFF096', - KINDA_GREEN: '#C4E7DB', - KINDA_BLUE: '#A0D5EF', -}; - const LOREM_IPSUM = ` Curabitur accumsan sit amet massa quis cursus. Fusce sollicitudin nunc nisl, quis efficitur quam tristique eget. Ut non erat molestie, ullamcorper turpis nec, euismod neque. Praesent aliquam risus ultricies, cursus mi consectetur, bibendum lorem. Nunc eleifend consectetur metus quis pulvinar. In vitae lacus eu nibh tincidunt sagittis ut id lorem. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Quisque sagittis mauris rhoncus, maximus justo in, consequat dolor. Pellentesque ornare laoreet est vulputate vestibulum. Aliquam sit amet metus lorem. diff --git a/apps/common-app/src/legacy/release_tests/gesturizedPressable/testingBase.tsx b/apps/common-app/src/legacy/release_tests/gesturizedPressable/testingBase.tsx index 44db3bf420..cbc827d83f 100644 --- a/apps/common-app/src/legacy/release_tests/gesturizedPressable/testingBase.tsx +++ b/apps/common-app/src/legacy/release_tests/gesturizedPressable/testingBase.tsx @@ -7,8 +7,8 @@ import { PressableProps as RNPressableProps, } from 'react-native'; import { - Pressable as GesturizedPressable, - PressableProps as GHPressableProps, + LegacyPressable as GesturizedPressable, + LegacyPressableProps as GHPressableProps, } from 'react-native-gesture-handler'; const TestingBase = (props: GHPressableProps & RNPressableProps) => ( diff --git a/apps/common-app/src/new_api/hover_mouse/mouse_buttons/index.tsx b/apps/common-app/src/new_api/hover_mouse/mouse_buttons/index.tsx index 34420985d1..bc01d0ba41 100644 --- a/apps/common-app/src/new_api/hover_mouse/mouse_buttons/index.tsx +++ b/apps/common-app/src/new_api/hover_mouse/mouse_buttons/index.tsx @@ -70,6 +70,7 @@ function Tests({ name, color, mouseButton, feedbackRef }: TestsProps) { onUpdate: () => { feedbackRef.current?.showMessage(`Panning with ${name}`); }, + disableReanimated: true, }); const longPress = useLongPressGesture({ @@ -77,6 +78,7 @@ function Tests({ name, color, mouseButton, feedbackRef }: TestsProps) { onActivate: () => { feedbackRef.current?.showMessage(`LongPress with ${name}`); }, + disableReanimated: true, }); const fling = useFlingGesture({ @@ -85,6 +87,7 @@ function Tests({ name, color, mouseButton, feedbackRef }: TestsProps) { onActivate: () => { feedbackRef.current?.showMessage(`Fling with ${name}`); }, + disableReanimated: true, }); const gestures = [tap, longPress, pan, fling]; diff --git a/apps/common-app/src/new_api/index.tsx b/apps/common-app/src/new_api/index.tsx index 0e7f37b047..3c706cf91b 100644 --- a/apps/common-app/src/new_api/index.tsx +++ b/apps/common-app/src/new_api/index.tsx @@ -5,6 +5,7 @@ import OverlapExample from './showcase/overlap'; import SharedValueExample from './showcase/shared_value'; import SvgExample from './showcase/svg'; import StateManagerExample from './showcase/state_manager'; +import TimerExample from './showcase/timer'; import CameraExample from './complicated/camera'; import ChatHeadsExample from './complicated/chat_heads'; @@ -32,6 +33,15 @@ import ScrollViewExample from './components/scrollview'; import Swipeable from './components/swipeable/index'; import SwitchTextInputExample from './components/switchAndInput'; +import RectButtonExample from './tests/rectButton'; +import TwoFingerPanExample from './tests/twoFingerPan'; +import WebStylesResetExample from './tests/webStylesReset'; +import PointerTypeExample from './tests/pointerType'; +import ReattachingExample from './tests/reattaching'; +import NestedRootViewExample from './tests/nestedRootView'; +import NestedPressablesExample from './tests/nestedPressables'; +import PressableExample from './tests/pressable'; + import { ExamplesSection } from '../common'; import EmptyExample from '../empty'; @@ -62,13 +72,18 @@ export const NEW_EXAMPLES: ExamplesSection[] = [ { name: 'Bottom Sheet', component: BottomSheetExample }, { name: 'Overlap', component: OverlapExample }, { name: 'Animated', component: AnimatedExample }, + { name: 'Timer', component: TimerExample }, ], }, { sectionTitle: 'Hover and mouse', data: [ { name: 'Stylus Data', component: StylusDataExample }, - { name: 'Context Menu', component: ContextMenuExample }, + { + name: 'Context Menu', + component: ContextMenuExample, + unsupportedPlatforms: new Set(['android', 'ios', 'macos']), + }, { name: 'Hover Icons', component: HoverIconsExample }, { name: 'Hoverable Icons', component: HoverableIconsExample }, { name: 'Mouse Buttons', component: MouseButtonsExample }, @@ -95,4 +110,21 @@ export const NEW_EXAMPLES: ExamplesSection[] = [ { name: 'Reanimated Drawer Layout', component: ReanimatedDrawerLayout }, ], }, + { + sectionTitle: 'Tests', + data: [ + { name: 'RectButton', component: RectButtonExample }, + { name: 'Two Finger Trackpad Pan', component: TwoFingerPanExample }, + { + name: 'Web Styles Reset', + component: WebStylesResetExample, + unsupportedPlatforms: new Set(['android', 'ios', 'macos']), + }, + { name: 'Pointer Type', component: PointerTypeExample }, + { name: 'Reattaching', component: ReattachingExample }, + { name: 'Modal with Nested Root View', component: NestedRootViewExample }, + { name: 'Nested pressables', component: NestedPressablesExample }, + { name: 'Pressable', component: PressableExample }, + ], + }, ]; diff --git a/apps/common-app/src/new_api/showcase/timer/index.tsx b/apps/common-app/src/new_api/showcase/timer/index.tsx new file mode 100644 index 0000000000..daaba6d640 --- /dev/null +++ b/apps/common-app/src/new_api/showcase/timer/index.tsx @@ -0,0 +1,96 @@ +import React, { useRef } from 'react'; +import { StyleSheet, View, Text, TextInput } from 'react-native'; +import { + useLongPressGesture, + GestureDetector, + GestureHandlerRootView, +} from 'react-native-gesture-handler'; +import Animated, { + useSharedValue, + withTiming, + cancelAnimation, + Easing, + useAnimatedProps, + useAnimatedStyle, + interpolateColor, +} from 'react-native-reanimated'; +import { + Feedback, + FeedbackHandle, + COLORS, + commonStyles, +} from '../../../common'; + +const AnimatedTextInput = Animated.createAnimatedComponent(TextInput); + +export default function TimerExample() { + const feedbackRef = useRef(null); + const duration = useSharedValue(0); + const colorProgress = useSharedValue(0); + const animatedProps = useAnimatedProps(() => { + return { + text: `Duration: ${duration.value.toFixed(2)}s`, + } as any; + }); + + const animatedBoxStyle = useAnimatedStyle(() => { + return { + backgroundColor: interpolateColor( + colorProgress.value, + [0, 1], + [COLORS.PURPLE, COLORS.NAVY] + ), + }; + }); + + const longPressGesture = useLongPressGesture({ + onBegin: () => { + colorProgress.value = withTiming(1, { duration: 150 }); + duration.value = 0; + duration.value = withTiming(600, { + duration: 600000, + easing: Easing.linear, + }); + }, + onFinalize: () => { + colorProgress.value = withTiming(0, { duration: 300 }); + cancelAnimation(duration); + }, + }); + + return ( + + + + + + + + Hold the box to measure press duration + + + + + ); +} + +const styles = StyleSheet.create({ + container: { + alignItems: 'center', + justifyContent: 'center', + }, + timerText: { + fontSize: 20, + fontWeight: 'bold', + color: COLORS.NAVY, + marginBottom: 20, + textAlign: 'center', + fontVariant: ['tabular-nums'], + }, +}); diff --git a/apps/common-app/src/new_api/tests/nestedPressables/index.tsx b/apps/common-app/src/new_api/tests/nestedPressables/index.tsx new file mode 100644 index 0000000000..9d216d6b76 --- /dev/null +++ b/apps/common-app/src/new_api/tests/nestedPressables/index.tsx @@ -0,0 +1,133 @@ +import React, { useRef } from 'react'; +import { + Pressable as RNPressable, + PressableStateCallbackType, + StyleSheet, + Text, + View, +} from 'react-native'; +import { Pressable } from 'react-native-gesture-handler'; +import { + COLORS, + commonStyles, + Feedback, + FeedbackHandle, +} from '../../../common'; + +export default function Example() { + const feedbackRefRNGH = useRef(null); + const feedbackRefRN = useRef(null); + + const showRNGH = (message: string) => { + feedbackRefRNGH.current?.showMessage(message); + }; + const showRN = (message: string) => { + feedbackRefRN.current?.showMessage(message); + }; + return ( + + + Gesturized Nested Pressables + + + + + React Native Nested Pressables + + + + + ); +} + +const BOX_SIZE_COEFFICIENT = 80; + +const getBoxStyle = (size: number) => ({ + width: size, + height: size, +}); + +const innerStyle = ({ pressed }: PressableStateCallbackType) => [ + getBoxStyle(BOX_SIZE_COEFFICIENT), + pressed + ? { backgroundColor: COLORS.KINDA_RED } + : { backgroundColor: COLORS.RED }, + styles.centering, +]; +const middleStyle = ({ pressed }: PressableStateCallbackType) => [ + getBoxStyle(BOX_SIZE_COEFFICIENT * 2), + pressed + ? { backgroundColor: COLORS.KINDA_GREEN } + : { backgroundColor: COLORS.GREEN }, + styles.centering, +]; +const outerStyle = ({ pressed }: PressableStateCallbackType) => [ + getBoxStyle(BOX_SIZE_COEFFICIENT * 3), + pressed + ? { backgroundColor: COLORS.KINDA_BLUE } + : { backgroundColor: COLORS.NAVY }, + styles.centering, +]; + +function GesturizedBoxes({ show }: { show: (m: string) => void }) { + return ( + show('[outer] onPressIn')} + onPressOut={() => show('[outer] onPressOut')} + onPress={() => show('[outer] onPress')} + onLongPress={() => show('[outer] onLongPress')}> + show('[middle] onPressIn')} + onPressOut={() => show('[middle] onPressOut')} + onPress={() => show('[middle] onPress')} + onLongPress={() => show('[middle] onLongPress')}> + show('[inner] onPressIn')} + onPressOut={() => show('[inner] onPressOut')} + onPress={() => show('[inner] onPress')} + onLongPress={() => show('[inner] onLongPress')} + /> + + + ); +} + +function LegacyBoxes({ show }: { show: (m: string) => void }) { + return ( + show('[outer] onPressIn')} + onPressOut={() => show('[outer] onPressOut')} + onPress={() => show('[outer] onPress')} + onLongPress={() => show('[outer] onLongPress')}> + show('[middle] onPressIn')} + onPressOut={() => show('[middle] onPressOut')} + onPress={() => show('[middle] onPress')} + onLongPress={() => show('[middle] onLongPress')}> + show('[inner] onPressIn')} + onPressOut={() => show('[inner] onPressOut')} + onPress={() => show('[inner] onPress')} + onLongPress={() => show('[inner] onLongPress')} + /> + + + ); +} + +const styles = StyleSheet.create({ + centering: { + alignItems: 'center', + justifyContent: 'center', + borderRadius: 20, + }, +}); diff --git a/apps/common-app/src/new_api/tests/nestedRootView/index.tsx b/apps/common-app/src/new_api/tests/nestedRootView/index.tsx new file mode 100644 index 0000000000..4060adf558 --- /dev/null +++ b/apps/common-app/src/new_api/tests/nestedRootView/index.tsx @@ -0,0 +1,128 @@ +import * as React from 'react'; +import { useState, useRef } from 'react'; +import { StyleSheet, Modal, View, Text } from 'react-native'; +import { + GestureHandlerRootView, + RectButton, + GestureDetector, + usePanGesture, +} from 'react-native-gesture-handler'; +import Animated, { + useAnimatedStyle, + useSharedValue, +} from 'react-native-reanimated'; +import { + Feedback, + FeedbackHandle, + COLORS, + commonStyles, +} from '../../../common'; + +interface DraggableBoxProps { + minDist?: number; +} + +function DraggableBox({ minDist }: DraggableBoxProps) { + const translationX = useSharedValue(0); + const translationY = useSharedValue(0); + const prevTranslationX = useSharedValue(0); + const prevTranslationY = useSharedValue(0); + + const panGesture = usePanGesture({ + minDistance: minDist, + onActivate: () => { + prevTranslationX.value = translationX.value; + prevTranslationY.value = translationY.value; + }, + onUpdate: (event) => { + translationX.value = prevTranslationX.value + event.translationX; + translationY.value = prevTranslationY.value + event.translationY; + }, + }); + + const animatedStyle = useAnimatedStyle(() => ({ + transform: [ + { translateX: translationX.value }, + { translateY: translationY.value }, + ], + })); + + return ( + + + + ); +} + +export default function App() { + const [isModalVisible, setIsModalVisible] = useState(false); + const feedbackRef = useRef(null); + + function ToggleModalButton() { + return ( + { + const newState = !isModalVisible; + setIsModalVisible(newState); + feedbackRef.current?.showMessage( + newState ? 'Modal Opened' : 'Modal Closed' + ); + }}> + + {isModalVisible ? 'Close' : 'Open'} modal + + + ); + } + + return ( + + + DraggableBox inside modal should be moveable + + + + + + + + + + + + + + ); +} + +const styles = StyleSheet.create({ + modalView: { + margin: 20, + marginTop: 200, + backgroundColor: 'transparent', + borderRadius: 20, + padding: 20, + alignItems: 'center', + borderWidth: 2, + }, + description: { + margin: 20, + color: COLORS.NAVY, + }, + button: { + padding: 12, + borderRadius: 12, + alignItems: 'center', + justifyContent: 'center', + minWidth: 150, + }, + box: { + backgroundColor: COLORS.PURPLE, + width: 100, + height: 100, + borderRadius: 20, + zIndex: 1, + }, +}); diff --git a/apps/common-app/src/new_api/tests/pointerType/index.tsx b/apps/common-app/src/new_api/tests/pointerType/index.tsx new file mode 100644 index 0000000000..d877516bfd --- /dev/null +++ b/apps/common-app/src/new_api/tests/pointerType/index.tsx @@ -0,0 +1,110 @@ +import React, { useRef } from 'react'; +import { View } from 'react-native'; +import Animated, { + interpolateColor, + useAnimatedStyle, + useSharedValue, + withTiming, +} from 'react-native-reanimated'; +import { + GestureDetector, + PointerType, + useLongPressGesture, +} from 'react-native-gesture-handler'; +import { + commonStyles, + COLORS, + Feedback, + FeedbackHandle, +} from '../../../common'; + +const Colors = { + Default: COLORS.NAVY, + Touch: COLORS.GREEN, + Stylus: COLORS.YELLOW, + Mouse: COLORS.PURPLE, +}; + +interface BoxProps { + feedbackRef: React.RefObject; +} + +function Box({ feedbackRef }: BoxProps) { + const translationX = useSharedValue(0); + const translationY = useSharedValue(0); + + const progress = useSharedValue(0); + + const currentColor = useSharedValue(Colors.Default); + const prevColor = useSharedValue(Colors.Default); + + const animatedStyle = useAnimatedStyle(() => { + return { + transform: [ + { translateX: translationX.value }, + { translateY: translationY.value }, + ], + backgroundColor: interpolateColor( + progress.value, + [0, 1], + [prevColor.value, currentColor.value] + ), + }; + }); + + const panGesture = useLongPressGesture({ + onActivate: (e) => { + progress.value = 0; + prevColor.value = currentColor.value; + + let typeLabel = 'Touch'; + switch (e.pointerType) { + case PointerType.TOUCH: + currentColor.value = Colors.Touch; + typeLabel = 'Touch'; + break; + case PointerType.STYLUS: + currentColor.value = Colors.Stylus; + typeLabel = 'Stylus'; + break; + case PointerType.MOUSE: + currentColor.value = Colors.Mouse; + typeLabel = 'Mouse'; + break; + default: + currentColor.value = Colors.Touch; + } + + feedbackRef.current?.showMessage(typeLabel); + progress.value = withTiming(1, { duration: 250 }); + }, + onDeactivate: () => { + translationX.value = withTiming(0); + translationY.value = withTiming(0); + + prevColor.value = currentColor.value; + currentColor.value = Colors.Default; + progress.value = 0; + progress.value = withTiming(1, { duration: 500 }); + }, + minDuration: 0, + runOnJS: true, + }); + + return ( + + + + ); +} + +export default function Example() { + const feedbackRef = useRef(null); + + return ( + + + + + ); +} diff --git a/apps/common-app/src/new_api/tests/pressable/androidRipple.tsx b/apps/common-app/src/new_api/tests/pressable/androidRipple.tsx new file mode 100644 index 0000000000..1e27f680d2 --- /dev/null +++ b/apps/common-app/src/new_api/tests/pressable/androidRipple.tsx @@ -0,0 +1,41 @@ +import React, { useRef } from 'react'; +import { Platform, View } from 'react-native'; +import TestingBase from './testingBase'; +import { + COLORS, + commonStyles, + Feedback, + FeedbackHandle, +} from '../../../common'; + +export function RippleExample() { + const feedbackRef = useRef(null); + + const buttonOpacity = + Platform.OS === 'android' ? { opacity: 1 } : { opacity: 0.6 }; + + const handlePress = () => { + feedbackRef.current?.showMessage('Pressed with Ripple effect'); + }; + + return ( + + + + + + + ); +} diff --git a/apps/common-app/src/new_api/tests/pressable/delayedPress.tsx b/apps/common-app/src/new_api/tests/pressable/delayedPress.tsx new file mode 100644 index 0000000000..4590ef4d42 --- /dev/null +++ b/apps/common-app/src/new_api/tests/pressable/delayedPress.tsx @@ -0,0 +1,65 @@ +import React, { useRef } from 'react'; +import { View } from 'react-native'; +import TestingBase from './testingBase'; +import { + useSharedValue, + withSequence, + withSpring, +} from 'react-native-reanimated'; +import { + COLORS, + commonStyles, + Feedback, + FeedbackHandle, +} from '../../../common'; + +const signalerConfig = { + duration: 200, + dampingRatio: 1, + stiffness: 500, + overshootClamping: true, + restDisplacementThreshold: 0.01, + restSpeedThreshold: 2, +}; + +export function DelayedPressExample() { + const feedbackRef = useRef(null); + const startColor = COLORS.offWhite; + const pressColor = COLORS.YELLOW; + const longPressColor = COLORS.PURPLE; + const animatedColor = useSharedValue(startColor); + + const pressDelay = 1000; + const longPressDelay = 1000; + + const onPressIn = () => { + feedbackRef.current?.showMessage('Pressed with delay'); + animatedColor.value = withSequence( + withSpring(pressColor, signalerConfig), + withSpring(startColor, signalerConfig) + ); + }; + + const onLongPress = () => { + feedbackRef.current?.showMessage('Long pressed with delay'); + animatedColor.value = withSequence( + withSpring(longPressColor, signalerConfig), + withSpring(startColor, signalerConfig) + ); + }; + + return ( + + + + + + + ); +} diff --git a/apps/common-app/src/new_api/tests/pressable/functionalStyles.tsx b/apps/common-app/src/new_api/tests/pressable/functionalStyles.tsx new file mode 100644 index 0000000000..a38e2d55d3 --- /dev/null +++ b/apps/common-app/src/new_api/tests/pressable/functionalStyles.tsx @@ -0,0 +1,30 @@ +import React from 'react'; +import { PressableStateCallbackType, View } from 'react-native'; +import TestingBase from './testingBase'; +import { COLORS, commonStyles } from '../../../common'; + +export function FunctionalStyleExample() { + const functionalStyle = (state: PressableStateCallbackType) => { + if (state.pressed) { + return [ + commonStyles.box, + { + backgroundColor: COLORS.KINDA_BLUE, + }, + ]; + } else { + return [ + commonStyles.box, + { + backgroundColor: COLORS.PURPLE, + }, + ]; + } + }; + + return ( + + + + ); +} diff --git a/apps/common-app/src/new_api/tests/pressable/hitSlop.tsx b/apps/common-app/src/new_api/tests/pressable/hitSlop.tsx new file mode 100644 index 0000000000..5e769bffb3 --- /dev/null +++ b/apps/common-app/src/new_api/tests/pressable/hitSlop.tsx @@ -0,0 +1,81 @@ +import React, { useRef } from 'react'; +import { StyleSheet, Text, View } from 'react-native'; +import TestingBase from './testingBase'; +import { + COLORS, + commonStyles, + Feedback, + FeedbackHandle, +} from '../../../common'; + +const HIT_SLOP = 40; +const PRESS_RETENTION_OFFSET = HIT_SLOP; + +export function HitSlopExample() { + const feedbackRef = useRef(null); + + const show = (msg: string) => feedbackRef.current?.showMessage(msg); + + return ( + + + + + show('Pressable pressed in')} + onPressOut={() => show('Pressable pressed out')} + onPress={() => show('Pressable pressed')} + onHoverIn={() => show('Hovered in')} + onHoverOut={() => show('Hovered out')} + onLongPress={() => show('Long pressed')} + /> + + + Hit Slop + + + + Retention Offset + + + + + ); +} + +const styles = StyleSheet.create({ + buttonContainer: { + alignItems: 'center', + gap: 20, + paddingVertical: 20, + }, + pressable: { + backgroundColor: COLORS.PURPLE, + width: 80, + height: 80, + borderRadius: 12, + }, + indicatorLabel: { + alignSelf: 'flex-end', + marginRight: 8, + marginBottom: 4, + }, + slopIndicator: { + justifyContent: 'center', + alignItems: 'center', + width: 100 + HIT_SLOP * 2, + borderRightWidth: 2, + borderColor: COLORS.KINDA_BLUE, + }, + retentionIndicator: { + justifyContent: 'center', + alignItems: 'center', + width: 180 + PRESS_RETENTION_OFFSET * 2, + borderRightWidth: 2, + borderColor: COLORS.GRAY, + marginVertical: 20, + }, +}); diff --git a/apps/common-app/src/new_api/tests/pressable/hoverDelay.tsx b/apps/common-app/src/new_api/tests/pressable/hoverDelay.tsx new file mode 100644 index 0000000000..55d5751cf6 --- /dev/null +++ b/apps/common-app/src/new_api/tests/pressable/hoverDelay.tsx @@ -0,0 +1,36 @@ +import React, { useRef } from 'react'; +import { View } from 'react-native'; +import TestingBase from './testingBase'; +import { + COLORS, + commonStyles, + Feedback, + FeedbackHandle, +} from '../../../common'; + +export function DelayHoverExample() { + const feedbackRef = useRef(null); + + const hoverIn = () => { + feedbackRef.current?.showMessage('Hover in with delay registered'); + }; + + const hoverOut = () => { + feedbackRef.current?.showMessage('Hover out with delay registered'); + }; + + return ( + + + hoverIn()} + onHoverOut={() => hoverOut()} + delayHoverIn={500} + delayHoverOut={500} + /> + + + + ); +} diff --git a/apps/common-app/src/new_api/tests/pressable/index.tsx b/apps/common-app/src/new_api/tests/pressable/index.tsx new file mode 100644 index 0000000000..1616219e8f --- /dev/null +++ b/apps/common-app/src/new_api/tests/pressable/index.tsx @@ -0,0 +1,85 @@ +import React, { ReactNode } from 'react'; +import { Text, View, StyleSheet } from 'react-native'; +import { ScrollView } from 'react-native-gesture-handler'; + +import { HitSlopExample } from './hitSlop'; +import { RippleExample } from './androidRipple'; +import { FunctionalStyleExample } from './functionalStyles'; +import { DelayedPressExample } from './delayedPress'; +import { DelayHoverExample } from './hoverDelay'; +import { commonStyles } from '../../../common'; + +type TestingEntryProps = { + title: string; + platform?: string; + comment?: string; + children: ReactNode; +}; +const TestingEntry = ({ + children, + title, + platform, + comment, +}: TestingEntryProps) => ( + + + + {title} + {platform && {platform}} + + {comment && {comment}} + + {children} + +); + +export default function Example() { + return ( + + + + + + + + + + + + + + + + + + ); +} + +const styles = StyleSheet.create({ + data: { + marginBottom: 10, + }, + code: { + fontSize: 16, + fontWeight: '400', + padding: 5, + borderRadius: 5, + marginBottom: 10, + color: '#37474f', + backgroundColor: '#bbc', + fontFamily: 'monospace', + fontVariant: ['tabular-nums'], + }, +}); diff --git a/apps/common-app/src/new_api/tests/pressable/testingBase.tsx b/apps/common-app/src/new_api/tests/pressable/testingBase.tsx new file mode 100644 index 0000000000..48b498fc76 --- /dev/null +++ b/apps/common-app/src/new_api/tests/pressable/testingBase.tsx @@ -0,0 +1,29 @@ +import { commonStyles } from '../../../common'; +import React from 'react'; +import { + Text, + View, + Pressable, + PressableProps as RNPressableProps, +} from 'react-native'; +import { + Pressable as GesturizedPressable, + PressableProps as GHPressableProps, +} from 'react-native-gesture-handler'; + +const TestingBase = (props: GHPressableProps & RNPressableProps) => ( + <> + + + RNGH pressable! + + + + + RN pressable! + + + +); + +export default TestingBase; diff --git a/apps/common-app/src/new_api/tests/reattaching/index.tsx b/apps/common-app/src/new_api/tests/reattaching/index.tsx new file mode 100644 index 0000000000..61e373ee59 --- /dev/null +++ b/apps/common-app/src/new_api/tests/reattaching/index.tsx @@ -0,0 +1,62 @@ +import React, { useState, useRef } from 'react'; +import { View, Text, StyleSheet } from 'react-native'; +import { GestureDetector, useTapGesture } from 'react-native-gesture-handler'; +import { + commonStyles, + COLORS, + Feedback, + FeedbackHandle, +} from '../../../common'; + +export default function TapExample() { + const [isTopActive, setIsTopActive] = useState(false); + const feedbackRef = useRef(null); + + const tap = useTapGesture({ + onActivate: () => { + const message = `${isTopActive ? 'top' : 'bottom'} clicked`; + feedbackRef.current?.showMessage(message); + setIsTopActive((prev) => !prev); + }, + runOnJS: true, + }); + + const noopGesture = useTapGesture({}); + + return ( + + + + + {isTopActive ? Tap me next : <>} + + + + + {!isTopActive ? ( + Tap me next + ) : ( + <> + )} + + + + + + ); +} +export const styles = StyleSheet.create({ + text: { + color: 'white', + textAlign: 'center', + textAlignVertical: 'center', + }, +}); diff --git a/apps/common-app/src/new_api/tests/rectButton/index.tsx b/apps/common-app/src/new_api/tests/rectButton/index.tsx new file mode 100644 index 0000000000..05bbf3e026 --- /dev/null +++ b/apps/common-app/src/new_api/tests/rectButton/index.tsx @@ -0,0 +1,146 @@ +import React, { useRef } from 'react'; +import { StyleSheet, Text, View, StyleProp, ViewStyle } from 'react-native'; +import { RectButton } from 'react-native-gesture-handler'; +import { + COLORS, + commonStyles, + Feedback, + FeedbackHandle, +} from '../../../common'; + +export default function RectButtonBorders() { + const feedbackRef = useRef(null); + + const handlePress = (text: string) => { + feedbackRef.current?.showMessage(`Pressed ${text}!`); + }; + + return ( + + +