Swipe to reply in chat (#10920)

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Samuel Newman
2026-06-16 21:38:36 +03:00
committed by GitHub
parent bb6847f396
commit 721965e67c
7 changed files with 251 additions and 29 deletions
+10 -1
View File
@@ -241,6 +241,7 @@ export function Trigger({
contentLabel,
style,
onTap,
swipeGesture,
}: TriggerProps) {
const context = useContextMenuContext()
const playHaptic = useHaptics()
@@ -364,12 +365,20 @@ export function Trigger({
}, [open, hoverablesSV, onTouchUpMenuItem, hoveredItemSV, translationSV])
// Order matters here: doubleTapGesture must come before tapGesture.
const composedGestures = Gesture.Exclusive(
const tapAndHoldGestures = Gesture.Exclusive(
doubleTapGesture,
tapGesture,
pressAndHoldGesture,
)
// An optional swipe gesture (e.g. swipe-to-reply) races against the tap/hold
// group: whichever activates first wins and cancels the rest, so they're
// mutually exclusive. Race (not Exclusive) avoids a held-but-not-yet-moved
// swipe Pan blocking the long-press from firing.
const composedGestures = swipeGesture
? Gesture.Race(swipeGesture, tapAndHoldGestures)
: tapAndHoldGestures
const measurement = context.measurement || pendingMeasurement?.measurement
return (
+9
View File
@@ -4,6 +4,7 @@ import {
type StyleProp,
type ViewStyle,
} from 'react-native'
import {type GestureType} from 'react-native-gesture-handler'
import {type SharedValue} from 'react-native-reanimated'
import type * as Dialog from '#/components/Dialog'
@@ -94,6 +95,14 @@ export type TriggerProps = {
* @platform ios, android
*/
onTap?: () => void
/**
* An optional gesture (e.g. swipe-to-reply) composed into the same
* arbitration group as the tap and press-and-hold gestures via `Gesture.Race`,
* making it mutually exclusive with them - only one can win a given touch.
*
* @platform ios, android
*/
swipeGesture?: GestureType
}
export type TriggerChildProps =
| {