diff --git a/packages/docs-gesture-handler/docs/components/pressable.mdx b/packages/docs-gesture-handler/docs/components/pressable.mdx index 4f6f1991b5..826953438e 100644 --- a/packages/docs-gesture-handler/docs/components/pressable.mdx +++ b/packages/docs-gesture-handler/docs/components/pressable.mdx @@ -52,7 +52,7 @@ Either view styles or a function that receives a boolean reflecting whether the onPress?: null | ((event: PressableEvent) => void); ``` -Called when a single tap gesture is detected. It follows [`onPressOut`](#onpressout), unless [`pressOutAfterAnimation`](#pressoutafteranimation) delays `onPressOut`. Details about the event object can be found in the [PressableEvent](#pressableevent) section below. +Called when a single tap gesture is detected. It follows [`onPressOut`](#onpressout), unless [`immediatePressOut`](#immediatepressout) is off and the platform deferred a quick tap. Details about the event object can be found in the [PressableEvent](#pressableevent) section below. ### onPressIn @@ -68,7 +68,7 @@ Called before `onPress` when a touch is engaged. Details about the event object onPressOut?: null | ((event: PressableEvent) => void); ``` -Called when a touch is released. When [`pressOutAfterAnimation`](#pressoutafteranimation) is set to `true`, a quick tap the platform deferred calls it after [`onPress`](#onpress). Details about the event object can be found in the [PressableEvent](#pressableevent) section below. +Called when a touch is released. Unless [`immediatePressOut`](#immediatepressout) is set to `true`, a quick tap the platform deferred calls it after [`onPress`](#onpress). Details about the event object can be found in the [PressableEvent](#pressableevent) section below. ### onLongPress @@ -201,19 +201,19 @@ needsOffscreenAlphaCompositing?: boolean; Whether the view should render with an offscreen alpha-compositing buffer when its `opacity` is less than `1`. Defaults to `false`. - -### pressOutAfterAnimation [A][I] + +### immediatePressOut [A][I] ```ts -pressOutAfterAnimation?: boolean; +immediatePressOut?: boolean; ``` -In some cases the platform defers the press, so a quick tap calls `onPressIn` and `onPressOut` almost at the same time and the `pressed` state never shows up. +In some cases the platform defers the press, so a quick tap would call `onPressIn` and `onPressOut` almost at the same time and the `pressed` state would never show up. By default, `onPressOut` for such a tap is held back so that `pressed` lasts at least 130 ms, matching React Native's `Pressable`. `onPress` is never delayed, so on such a tap it is called before `onPressOut`. Longer presses and presses that were not deferred by the platform keep the usual order. -When set to `true`, `onPressOut` for such a tap is held back so that `pressed` lasts at least 130 ms, matching React Native's `Pressable`. `onPress` is never delayed, so on such a tap it is called before `onPressOut`. Longer presses and presses that were not deferred by the platform keep the usual order. +When set to `true`, `onPressOut` is called as soon as the press ends, even for such a tap. -By default set to `true`. Has no effect on web, where presses are never deferred, or when `simultaneousWith`, `requireToFail` or `block` is passed. +By default set to `false`. Has no effect on web, where presses are never deferred, or when `simultaneousWith`, `requireToFail` or `block` is passed. ### testOnly_pressed diff --git a/packages/docs-gesture-handler/docs/components/touchable.mdx b/packages/docs-gesture-handler/docs/components/touchable.mdx index c0a9da612c..d36c2fbc3a 100644 --- a/packages/docs-gesture-handler/docs/components/touchable.mdx +++ b/packages/docs-gesture-handler/docs/components/touchable.mdx @@ -586,19 +586,19 @@ cancelOnLeave?: boolean; Whether the touch should be canceled when the pointer leaves the component. By default set to `true`. On web this prop doesn't have any effect and behaves as if `true` was set. - -### pressOutAfterAnimation [A][I] + +### immediatePressOut [A][I] ```ts -pressOutAfterAnimation?: boolean; +immediatePressOut?: boolean; ``` In some cases the platform defers the press, so a quick tap calls `onPressIn` and `onPressOut` almost at the same time and feedback driven from these callbacks never shows up. -When set to `true`, `onPressOut` for such a tap is held back until the press-in animation (see [`animationDuration`](#animationduration)) finishes. `onPress` is never delayed, so on such a tap it is called before `onPressOut`. Longer presses and presses that were not deferred by the platform keep the usual order. +When set to `false`, `onPressOut` for such a tap is held back until the press-in animation (see [`animationDuration`](#animationduration)) finishes. `onPress` is never delayed, so on such a tap it is called before `onPressOut`. Longer presses and presses that were not deferred by the platform keep the usual order. -By default set to `false`. Has no effect on web, where presses are never deferred. +By default set to `true`. Has no effect on web, where presses are never deferred. ### needsOffscreenAlphaCompositing [A] diff --git a/packages/docs-gesture-handler/src/css/overrides.css b/packages/docs-gesture-handler/src/css/overrides.css index d7b896b441..ee32ef57ac 100644 --- a/packages/docs-gesture-handler/src/css/overrides.css +++ b/packages/docs-gesture-handler/src/css/overrides.css @@ -254,3 +254,19 @@ footer align-items: center; } } + +[class*='_headerWithBadges_'] [class*='_badge_'][class*='_versionBadge_'] { + background: transparent; + margin-left: auto; + color: var(--swm-navy-light-60); + border: 1px solid var(--swm-navy-light-20); + font-weight: 400; + padding: calc(0.25rem - 1px) 0.5rem; +} + +[data-theme='dark'] + [class*='_headerWithBadges_'] + [class*='_badge_'][class*='_versionBadge_'] { + color: var(--swm-navy-light-40); + border-color: var(--swm-light-off-navy); +} diff --git a/packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerButtonViewManager.kt b/packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerButtonViewManager.kt index 8356f01035..a042563fdc 100644 --- a/packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerButtonViewManager.kt +++ b/packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerButtonViewManager.kt @@ -79,7 +79,7 @@ class RNGestureHandlerButtonViewManager : view.managedHandlerTestID = null view.managedHandlerHitSlop = null view.moduleId = null - view.pressOutAfterAnimation = false + view.immediatePressOut = true view.resetHoverState() // Has to come last — every setter above flags the view as needing a managed handler update. view.managedHandlerNeedsUpdate = false @@ -358,9 +358,9 @@ class RNGestureHandlerButtonViewManager : view.longPressDuration = value } - @ReactProp(name = "pressOutAfterAnimation") - override fun setPressOutAfterAnimation(view: ButtonViewGroup, value: Boolean) { - view.pressOutAfterAnimation = value + @ReactProp(name = "immediatePressOut") + override fun setImmediatePressOut(view: ButtonViewGroup, value: Boolean) { + view.immediatePressOut = value } @ReactProp(name = "longPressAnimationOutDuration") @@ -573,7 +573,7 @@ class RNGestureHandlerButtonViewManager : var tapAnimationInDuration: Int = 50 var tapAnimationOutDuration: Int = 100 var longPressDuration: Int = -1 - var pressOutAfterAnimation = false + var immediatePressOut = true var longPressAnimationOutDuration: Int = -1 get() = if (field < 0) tapAnimationOutDuration else field var activeOpacity: Float = 1.0f @@ -616,7 +616,7 @@ class RNGestureHandlerButtonViewManager : private var pressInTimestamp = 0L private var pendingPressOut: Runnable? = null - // PressOut event held back by `pressOutAfterAnimation` (the animation has its own hold above). + // PressOut event held back unless `immediatePressOut` (the animation has its own hold above). private var pendingPressOutEvent: Runnable? = null // InteractionFinished that arrived while PressOut was held; delivered right after it. @@ -881,13 +881,13 @@ class RNGestureHandlerButtonViewManager : eventDispatcher.dispatchEvent(event) } - // With `pressOutAfterAnimation`, a press the platform deferred (tap timeout inside a scrolling + // Unless `immediatePressOut`, a press the platform deferred (tap timeout inside a scrolling // container) holds PressOut until the press-in animation has played, like `animatePressOut` // holds the animation. An immediate press keeps its native timing. Press is never delayed, so // on such taps PressOut follows it. The event is built now so it carries the release position. private fun dispatchPressOut(handler: NativeViewGestureHandler) { val remaining = tapAnimationInDuration - (SystemClock.uptimeMillis() - pressInTimestamp) - if (!pressOutAfterAnimation || !pressDeferredByPlatform || remaining <= 0) { + if (immediatePressOut || !pressDeferredByPlatform || remaining <= 0) { dispatchJSEvent(EventType.PressOut, handler) return } diff --git a/packages/react-native-gesture-handler/apple/RNGestureHandlerButton.h b/packages/react-native-gesture-handler/apple/RNGestureHandlerButton.h index 16ce838206..f2bdb86953 100644 --- a/packages/react-native-gesture-handler/apple/RNGestureHandlerButton.h +++ b/packages/react-native-gesture-handler/apple/RNGestureHandlerButton.h @@ -51,7 +51,7 @@ typedef NS_ENUM(NSInteger, RNGHButtonEventType) { @property (nonatomic, assign) NSInteger tapAnimationInDuration; @property (nonatomic, assign) NSInteger tapAnimationOutDuration; @property (nonatomic, assign) NSInteger longPressDuration; -@property (nonatomic, assign) BOOL pressOutAfterAnimation; +@property (nonatomic, assign) BOOL immediatePressOut; @property (nonatomic, assign) NSInteger longPressAnimationOutDuration; @property (nonatomic, assign) CGFloat activeOpacity; @property (nonatomic, assign) CGFloat defaultOpacity; diff --git a/packages/react-native-gesture-handler/apple/RNGestureHandlerButton.mm b/packages/react-native-gesture-handler/apple/RNGestureHandlerButton.mm index c0f8911470..c83b64ba3c 100644 --- a/packages/react-native-gesture-handler/apple/RNGestureHandlerButton.mm +++ b/packages/react-native-gesture-handler/apple/RNGestureHandlerButton.mm @@ -51,7 +51,7 @@ @implementation RNGestureHandlerButton { UIEdgeInsets _underlayBorderInsets; // border widths for padding-box inset NSTimeInterval _pressInTimestamp; dispatch_block_t _pendingPressOutBlock; - // `onPressOut` held back by `pressOutAfterAnimation` (the press-out animation has its own block above). + // `onPressOut` held back unless `immediatePressOut` (the press-out animation has its own block above). // The payload is kept apart from the block: a cancelled dispatch block never runs its body. dispatch_block_t _pendingPressOutEventBlock; RNGestureHandlerEventExtraData *_pendingPressOutExtraData; @@ -109,7 +109,7 @@ - (void)commonInit _tapAnimationInDuration = 50; _tapAnimationOutDuration = 100; _longPressDuration = -1; - _pressOutAfterAnimation = NO; + _immediatePressOut = YES; _pressDeferredByPlatform = NO; _longPressAnimationOutDuration = -1; _activeOpacity = 1.0; @@ -763,14 +763,14 @@ - (BOOL)isInsideDelayingScrollView } #endif -// With `pressOutAfterAnimation`, a press UIKit deferred (`delaysContentTouches` in a scroll view) +// Unless `immediatePressOut`, a press UIKit deferred (`delaysContentTouches` in a scroll view) // holds `onPressOut` until the press-in animation has played, like `handleAnimatePressOut` holds // the animation. An immediate press keeps its native timing. `onPress` is never delayed, so on // such taps `onPressOut` follows it. - (void)dispatchPressOutWithExtraData:(RNGestureHandlerEventExtraData *)extraData { NSTimeInterval remaining = _tapAnimationInDuration - (CACurrentMediaTime() - _pressInTimestamp) * 1000.0; - if (!_pressOutAfterAnimation || !_pressDeferredByPlatform || remaining <= 0) { + if (_immediatePressOut || !_pressDeferredByPlatform || remaining <= 0) { [self dispatchButtonEvent:RNGHButtonEventTypePressOut withExtraData:extraData]; return; } @@ -1385,7 +1385,7 @@ - (BOOL)beginTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event } _isTouchInsideBounds = YES; - _pressDeferredByPlatform = _pressOutAfterAnimation && [self isInsideDelayingScrollView]; + _pressDeferredByPlatform = !_immediatePressOut && [self isInsideDelayingScrollView]; // A pencil's hover-out arrives just before touch-down but only schedules the // clear, so `_isHovered` still reflects the open hover. Under Reduce Motion // that delay is zero and the block can land first — the press then brackets diff --git a/packages/react-native-gesture-handler/apple/RNGestureHandlerButtonComponentView.mm b/packages/react-native-gesture-handler/apple/RNGestureHandlerButtonComponentView.mm index c27419985d..fb0ff7ecb7 100644 --- a/packages/react-native-gesture-handler/apple/RNGestureHandlerButtonComponentView.mm +++ b/packages/react-native-gesture-handler/apple/RNGestureHandlerButtonComponentView.mm @@ -546,7 +546,7 @@ - (void)updateProps:(const Props::Shared &)props oldProps:(const Props::Shared & _buttonView.tapAnimationInDuration = newProps.tapAnimationInDuration > 0 ? newProps.tapAnimationInDuration : 0; _buttonView.tapAnimationOutDuration = newProps.tapAnimationOutDuration > 0 ? newProps.tapAnimationOutDuration : 0; _buttonView.longPressDuration = newProps.longPressDuration; - _buttonView.pressOutAfterAnimation = newProps.pressOutAfterAnimation; + _buttonView.immediatePressOut = newProps.immediatePressOut; _buttonView.longPressAnimationOutDuration = newProps.longPressAnimationOutDuration; _buttonView.activeOpacity = newProps.activeOpacity; _buttonView.defaultOpacity = newProps.defaultOpacity; diff --git a/packages/react-native-gesture-handler/src/components/GestureHandlerButton.tsx b/packages/react-native-gesture-handler/src/components/GestureHandlerButton.tsx index 912b810ee9..d2207b5382 100644 --- a/packages/react-native-gesture-handler/src/components/GestureHandlerButton.tsx +++ b/packages/react-native-gesture-handler/src/components/GestureHandlerButton.tsx @@ -146,12 +146,12 @@ export interface ButtonProps extends ViewProps, AccessibilityProps { longPressDuration?: number | undefined; /** - * When the platform deferred the press (e.g. the tap timeout inside a - * scrolling container), hold the press-out event until the press-in - * animation has played, so feedback driven from the callbacks stays - * visible. The press event is not delayed. + * Set to `false` to hold the press-out event for a press the platform + * deferred (e.g. the tap timeout inside a scrolling container) until the + * press-in animation has played, so feedback driven from the callbacks + * stays visible. The press event is not delayed. */ - pressOutAfterAnimation?: boolean | undefined; + immediatePressOut?: boolean | undefined; /** * Duration of the press-out animation, in milliseconds, when the diff --git a/packages/react-native-gesture-handler/src/components/Pressable/PressableProps.tsx b/packages/react-native-gesture-handler/src/components/Pressable/PressableProps.tsx index ab20304ab9..5541645515 100644 --- a/packages/react-native-gesture-handler/src/components/Pressable/PressableProps.tsx +++ b/packages/react-native-gesture-handler/src/components/Pressable/PressableProps.tsx @@ -73,12 +73,13 @@ export interface PressableProps extends CommonPressableProps { block?: AnyGesture | AnyGesture[]; /** - * When the platform deferred the press, holds `onPressOut` so a quick tap keeps `pressed` for at - * least 130 ms, like React Native's `minPressDuration`. `onPress` is not delayed and may precede - * `onPressOut` on such taps. By default set to true. Has no effect on web or when any of - * `simultaneousWith`, `requireToFail` or `block` is passed. + * When the platform deferred the press, `onPressOut` is held so a quick tap keeps `pressed` for + * at least 130 ms, like React Native's `minPressDuration`. `onPress` is not delayed and may + * precede `onPressOut` on such taps. Set to `true` to call `onPressOut` as soon as the press ends + * instead. By default set to false. Has no effect on web or when any of `simultaneousWith`, + * `requireToFail` or `block` is passed. */ - pressOutAfterAnimation?: boolean | undefined; + immediatePressOut?: boolean | undefined; } interface CommonPressableProps diff --git a/packages/react-native-gesture-handler/src/specs/RNGestureHandlerButtonNativeComponent.ts b/packages/react-native-gesture-handler/src/specs/RNGestureHandlerButtonNativeComponent.ts index 2a8725a89c..4ec1a2a7b2 100644 --- a/packages/react-native-gesture-handler/src/specs/RNGestureHandlerButtonNativeComponent.ts +++ b/packages/react-native-gesture-handler/src/specs/RNGestureHandlerButtonNativeComponent.ts @@ -60,7 +60,7 @@ interface NativeProps extends ViewProps { tapAnimationInDuration?: CodegenTypes.WithDefault; tapAnimationOutDuration?: CodegenTypes.WithDefault; longPressDuration?: CodegenTypes.WithDefault; - pressOutAfterAnimation?: CodegenTypes.WithDefault; + immediatePressOut?: CodegenTypes.WithDefault; longPressAnimationOutDuration?: CodegenTypes.WithDefault< CodegenTypes.Int32, -1 diff --git a/packages/react-native-gesture-handler/src/v3/components/PressableWithTouchable.tsx b/packages/react-native-gesture-handler/src/v3/components/PressableWithTouchable.tsx index 8dd1f4a28e..2109c14fc8 100644 --- a/packages/react-native-gesture-handler/src/v3/components/PressableWithTouchable.tsx +++ b/packages/react-native-gesture-handler/src/v3/components/PressableWithTouchable.tsx @@ -21,8 +21,8 @@ const IS_TEST_ENV = isTestEnv(); // RN's Pressable default. Touchable's own default is 600ms const DEFAULT_LONG_PRESS_DURATION = 500; -// Pressable has no native opacity/scale animation. The press-in duration only matters with -// `pressOutAfterAnimation`: it is how long a platform-deferred quick tap keeps `pressed` before +// Pressable has no native opacity/scale animation. The press-in duration only matters without +// `immediatePressOut`: it is how long a platform-deferred quick tap keeps `pressed` before // onPressOut. 130 ms matches RN's minPressDuration. const PRESSABLE_ANIMATION_DURATION = { in: 50, out: 100, tap: { in: 130 } }; @@ -88,7 +88,7 @@ const PressableWithTouchable = (props: PressableProps) => { disabled, accessible, ref, - pressOutAfterAnimation = true, + immediatePressOut = false, ...rest } = props; @@ -319,7 +319,7 @@ const PressableWithTouchable = (props: PressableProps) => { delayLongPress={resolvedDelayLongPress} style={[pointerStyle, resolvedStyle]} animationDuration={PRESSABLE_ANIMATION_DURATION} - pressOutAfterAnimation={pressOutAfterAnimation} + immediatePressOut={immediatePressOut} onPressIn={handlePressIn} onPressOut={handlePressOut} onPress={handlePress} diff --git a/packages/react-native-gesture-handler/src/v3/components/StatefulPressable.tsx b/packages/react-native-gesture-handler/src/v3/components/StatefulPressable.tsx index 01edaf224a..bfbf25608e 100644 --- a/packages/react-native-gesture-handler/src/v3/components/StatefulPressable.tsx +++ b/packages/react-native-gesture-handler/src/v3/components/StatefulPressable.tsx @@ -80,7 +80,7 @@ const StatefulPressable = (props: PressableProps) => { ref, // Only PressableWithTouchable holds onPressOut; keep the native button at its default here. // eslint-disable-next-line @typescript-eslint/no-unused-vars - pressOutAfterAnimation, + immediatePressOut, ...remainingProps } = props; diff --git a/packages/react-native-gesture-handler/src/v3/components/Touchable/Touchable.tsx b/packages/react-native-gesture-handler/src/v3/components/Touchable/Touchable.tsx index e3a1a0e5d9..5ee7702419 100644 --- a/packages/react-native-gesture-handler/src/v3/components/Touchable/Touchable.tsx +++ b/packages/react-native-gesture-handler/src/v3/components/Touchable/Touchable.tsx @@ -85,7 +85,7 @@ export const Touchable = (props: TouchableProps) => { children, disabled = false, cancelOnLeave = true, - pressOutAfterAnimation = false, + immediatePressOut = true, ref, ...rest } = props; @@ -226,7 +226,7 @@ export const Touchable = (props: TouchableProps) => { activeUnderlayOpacity={activeUnderlayOpacity} underlayColor={underlayColor} longPressDuration={resolvedDelayLongPress} - pressOutAfterAnimation={pressOutAfterAnimation} + immediatePressOut={immediatePressOut} hasLongPressHandler={onLongPress !== undefined} onButtonPress={internalOnPress} onButtonPressIn={internalOnPressIn} diff --git a/packages/react-native-gesture-handler/src/v3/components/Touchable/TouchableProps.ts b/packages/react-native-gesture-handler/src/v3/components/Touchable/TouchableProps.ts index c58509c292..27cab35029 100644 --- a/packages/react-native-gesture-handler/src/v3/components/Touchable/TouchableProps.ts +++ b/packages/react-native-gesture-handler/src/v3/components/Touchable/TouchableProps.ts @@ -132,9 +132,9 @@ export type TouchableProps = Omit< cancelOnLeave?: boolean | undefined; /** - * When the platform deferred the press (e.g. inside a scrolling container), holds `onPressOut` - * until the press-in animation has finished, so a quick tap still shows its feedback. - * `onPress` is not delayed and may precede `onPressOut` on such taps. By default set to false. + * Set to `false` to hold `onPressOut` for a press the platform deferred (e.g. inside a scrolling + * container) until the press-in animation has finished, so a quick tap still shows its feedback. + * `onPress` is not delayed and may precede `onPressOut` on such taps. By default set to true. */ - pressOutAfterAnimation?: boolean | undefined; + immediatePressOut?: boolean | undefined; };