react-native-macos/Libraries/Components/Pressable/Pressable.js

241 строка
6.3 KiB
JavaScript
Исходник Обычный вид История

/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict-local
* @format
*/
'use strict';
import * as React from 'react';
import {useMemo, useState, useRef, useImperativeHandle} from 'react';
add ripple config object to Pressable (#28156) Summary: Motivation is to support ripple radius just like in TouchableNativeFeedback, plus borderless attribute. See https://github.com/facebook/react-native/pull/28009#issuecomment-589489520 In the current form this means user needs to pass an `android_ripple` prop which is an object of this shape: ``` export type RippleConfig = {| color?: ?ColorValue, borderless?: ?boolean, radius?: ?number, |}; ``` Do we want to add methods that would create such config objects - https://facebook.github.io/react-native/docs/touchablenativefeedback#methods ? ## Changelog [Android] [Added] - support borderless and custom ripple radius on Pressable Pull Request resolved: https://github.com/facebook/react-native/pull/28156 Test Plan: Tested locally in RNTester. I noticed that when some content is rendered after the touchables, the ripple effect is "cut off" by the boundaries of the next view. This is not specific to Pressable, it happens to TouchableNativeFeedback too but I just didn't notice it before in https://github.com/facebook/react-native/pull/28009. As it is an issue of its own, I didn't investigate that. ![pressable](https://user-images.githubusercontent.com/1566403/75098762-785f2200-55ba-11ea-8842-e648317610e3.gif) I changed the Touchable example slightly too (I just moved the "custom ripple radius" up to show the "cutting off" issue), so just for completeness: ![touchable](https://user-images.githubusercontent.com/1566403/75098763-81e88a00-55ba-11ea-9528-e0343d1e054b.gif) Reviewed By: yungsters Differential Revision: D20071021 Pulled By: TheSavior fbshipit-source-id: cb553030934205a52dd50a2a8c8a20da6100e23f
2020-04-04 04:34:15 +03:00
import useAndroidRippleForView, {
type RippleConfig,
} from './useAndroidRippleForView';
import type {
AccessibilityActionEvent,
AccessibilityActionInfo,
AccessibilityRole,
AccessibilityState,
AccessibilityValue,
} from '../View/ViewAccessibility';
import {PressabilityDebugView} from '../../Pressability/PressabilityDebug';
import usePressability from '../../Pressability/usePressability';
import {normalizeRect, type RectOrSize} from '../../StyleSheet/Rect';
import type {LayoutEvent, PressEvent} from '../../Types/CoreEventTypes';
import View from '../View/View';
type ViewStyleProp = $ElementType<React.ElementConfig<typeof View>, 'style'>;
export type StateCallbackType = $ReadOnly<{|
pressed: boolean,
|}>;
type Props = $ReadOnly<{|
/**
* Accessibility.
*/
accessibilityActions?: ?$ReadOnlyArray<AccessibilityActionInfo>,
accessibilityElementsHidden?: ?boolean,
accessibilityHint?: ?Stringish,
accessibilityIgnoresInvertColors?: ?boolean,
accessibilityLabel?: ?Stringish,
accessibilityLiveRegion?: ?('none' | 'polite' | 'assertive'),
accessibilityRole?: ?AccessibilityRole,
accessibilityState?: ?AccessibilityState,
accessibilityValue?: ?AccessibilityValue,
accessibilityViewIsModal?: ?boolean,
accessible?: ?boolean,
focusable?: ?boolean,
importantForAccessibility?: ?('auto' | 'yes' | 'no' | 'no-hide-descendants'),
onAccessibilityAction?: ?(event: AccessibilityActionEvent) => mixed,
/**
* Either children or a render prop that receives a boolean reflecting whether
* the component is currently pressed.
*/
children: React.Node | ((state: StateCallbackType) => React.Node),
/**
* Duration (in milliseconds) from `onPressIn` before `onLongPress` is called.
*/
delayLongPress?: ?number,
/**
* Whether the press behavior is disabled.
*/
disabled?: ?boolean,
/**
* Additional distance outside of this view in which a press is detected.
*/
hitSlop?: ?RectOrSize,
/**
* Additional distance outside of this view in which a touch is considered a
* press before `onPressOut` is triggered.
*/
pressRetentionOffset?: ?RectOrSize,
/**
* Called when this view's layout changes.
*/
onLayout?: ?(event: LayoutEvent) => void,
/**
* Called when a long-tap gesture is detected.
*/
onLongPress?: ?(event: PressEvent) => void,
/**
* Called when a single tap gesture is detected.
*/
onPress?: ?(event: PressEvent) => void,
/**
* Called when a touch is engaged before `onPress`.
*/
onPressIn?: ?(event: PressEvent) => void,
/**
* Called when a touch is released before `onPress`.
*/
onPressOut?: ?(event: PressEvent) => void,
/**
* Either view styles or a function that receives a boolean reflecting whether
* the component is currently pressed and returns view styles.
*/
style?: ViewStyleProp | ((state: StateCallbackType) => ViewStyleProp),
/**
* Identifier used to find this view in tests.
*/
testID?: ?string,
/**
* If true, doesn't play system sound on touch.
*/
android_disableSound?: ?boolean,
/**
* Enables the Android ripple effect and configures its color.
*/
add ripple config object to Pressable (#28156) Summary: Motivation is to support ripple radius just like in TouchableNativeFeedback, plus borderless attribute. See https://github.com/facebook/react-native/pull/28009#issuecomment-589489520 In the current form this means user needs to pass an `android_ripple` prop which is an object of this shape: ``` export type RippleConfig = {| color?: ?ColorValue, borderless?: ?boolean, radius?: ?number, |}; ``` Do we want to add methods that would create such config objects - https://facebook.github.io/react-native/docs/touchablenativefeedback#methods ? ## Changelog [Android] [Added] - support borderless and custom ripple radius on Pressable Pull Request resolved: https://github.com/facebook/react-native/pull/28156 Test Plan: Tested locally in RNTester. I noticed that when some content is rendered after the touchables, the ripple effect is "cut off" by the boundaries of the next view. This is not specific to Pressable, it happens to TouchableNativeFeedback too but I just didn't notice it before in https://github.com/facebook/react-native/pull/28009. As it is an issue of its own, I didn't investigate that. ![pressable](https://user-images.githubusercontent.com/1566403/75098762-785f2200-55ba-11ea-8842-e648317610e3.gif) I changed the Touchable example slightly too (I just moved the "custom ripple radius" up to show the "cutting off" issue), so just for completeness: ![touchable](https://user-images.githubusercontent.com/1566403/75098763-81e88a00-55ba-11ea-9528-e0343d1e054b.gif) Reviewed By: yungsters Differential Revision: D20071021 Pulled By: TheSavior fbshipit-source-id: cb553030934205a52dd50a2a8c8a20da6100e23f
2020-04-04 04:34:15 +03:00
android_ripple?: ?RippleConfig,
/**
* Used only for documentation or testing (e.g. snapshot testing).
*/
testOnly_pressed?: ?boolean,
|}>;
/**
* Component used to build display components that should respond to whether the
* component is currently pressed or not.
*/
function Pressable(props: Props, forwardedRef): React.Node {
const {
accessible,
android_disableSound,
add ripple config object to Pressable (#28156) Summary: Motivation is to support ripple radius just like in TouchableNativeFeedback, plus borderless attribute. See https://github.com/facebook/react-native/pull/28009#issuecomment-589489520 In the current form this means user needs to pass an `android_ripple` prop which is an object of this shape: ``` export type RippleConfig = {| color?: ?ColorValue, borderless?: ?boolean, radius?: ?number, |}; ``` Do we want to add methods that would create such config objects - https://facebook.github.io/react-native/docs/touchablenativefeedback#methods ? ## Changelog [Android] [Added] - support borderless and custom ripple radius on Pressable Pull Request resolved: https://github.com/facebook/react-native/pull/28156 Test Plan: Tested locally in RNTester. I noticed that when some content is rendered after the touchables, the ripple effect is "cut off" by the boundaries of the next view. This is not specific to Pressable, it happens to TouchableNativeFeedback too but I just didn't notice it before in https://github.com/facebook/react-native/pull/28009. As it is an issue of its own, I didn't investigate that. ![pressable](https://user-images.githubusercontent.com/1566403/75098762-785f2200-55ba-11ea-8842-e648317610e3.gif) I changed the Touchable example slightly too (I just moved the "custom ripple radius" up to show the "cutting off" issue), so just for completeness: ![touchable](https://user-images.githubusercontent.com/1566403/75098763-81e88a00-55ba-11ea-9528-e0343d1e054b.gif) Reviewed By: yungsters Differential Revision: D20071021 Pulled By: TheSavior fbshipit-source-id: cb553030934205a52dd50a2a8c8a20da6100e23f
2020-04-04 04:34:15 +03:00
android_ripple,
children,
delayLongPress,
disabled,
focusable,
onLongPress,
onPress,
onPressIn,
onPressOut,
pressRetentionOffset,
style,
testOnly_pressed,
...restProps
} = props;
const viewRef = useRef<React.ElementRef<typeof View> | null>(null);
useImperativeHandle(forwardedRef, () => viewRef.current);
add ripple config object to Pressable (#28156) Summary: Motivation is to support ripple radius just like in TouchableNativeFeedback, plus borderless attribute. See https://github.com/facebook/react-native/pull/28009#issuecomment-589489520 In the current form this means user needs to pass an `android_ripple` prop which is an object of this shape: ``` export type RippleConfig = {| color?: ?ColorValue, borderless?: ?boolean, radius?: ?number, |}; ``` Do we want to add methods that would create such config objects - https://facebook.github.io/react-native/docs/touchablenativefeedback#methods ? ## Changelog [Android] [Added] - support borderless and custom ripple radius on Pressable Pull Request resolved: https://github.com/facebook/react-native/pull/28156 Test Plan: Tested locally in RNTester. I noticed that when some content is rendered after the touchables, the ripple effect is "cut off" by the boundaries of the next view. This is not specific to Pressable, it happens to TouchableNativeFeedback too but I just didn't notice it before in https://github.com/facebook/react-native/pull/28009. As it is an issue of its own, I didn't investigate that. ![pressable](https://user-images.githubusercontent.com/1566403/75098762-785f2200-55ba-11ea-8842-e648317610e3.gif) I changed the Touchable example slightly too (I just moved the "custom ripple radius" up to show the "cutting off" issue), so just for completeness: ![touchable](https://user-images.githubusercontent.com/1566403/75098763-81e88a00-55ba-11ea-9528-e0343d1e054b.gif) Reviewed By: yungsters Differential Revision: D20071021 Pulled By: TheSavior fbshipit-source-id: cb553030934205a52dd50a2a8c8a20da6100e23f
2020-04-04 04:34:15 +03:00
const android_rippleConfig = useAndroidRippleForView(android_ripple, viewRef);
const [pressed, setPressed] = usePressState(testOnly_pressed === true);
const hitSlop = normalizeRect(props.hitSlop);
const config = useMemo(
() => ({
disabled,
hitSlop,
pressRectOffset: pressRetentionOffset,
android_disableSound,
delayLongPress,
onLongPress,
onPress,
onPressIn(event: PressEvent): void {
add ripple config object to Pressable (#28156) Summary: Motivation is to support ripple radius just like in TouchableNativeFeedback, plus borderless attribute. See https://github.com/facebook/react-native/pull/28009#issuecomment-589489520 In the current form this means user needs to pass an `android_ripple` prop which is an object of this shape: ``` export type RippleConfig = {| color?: ?ColorValue, borderless?: ?boolean, radius?: ?number, |}; ``` Do we want to add methods that would create such config objects - https://facebook.github.io/react-native/docs/touchablenativefeedback#methods ? ## Changelog [Android] [Added] - support borderless and custom ripple radius on Pressable Pull Request resolved: https://github.com/facebook/react-native/pull/28156 Test Plan: Tested locally in RNTester. I noticed that when some content is rendered after the touchables, the ripple effect is "cut off" by the boundaries of the next view. This is not specific to Pressable, it happens to TouchableNativeFeedback too but I just didn't notice it before in https://github.com/facebook/react-native/pull/28009. As it is an issue of its own, I didn't investigate that. ![pressable](https://user-images.githubusercontent.com/1566403/75098762-785f2200-55ba-11ea-8842-e648317610e3.gif) I changed the Touchable example slightly too (I just moved the "custom ripple radius" up to show the "cutting off" issue), so just for completeness: ![touchable](https://user-images.githubusercontent.com/1566403/75098763-81e88a00-55ba-11ea-9528-e0343d1e054b.gif) Reviewed By: yungsters Differential Revision: D20071021 Pulled By: TheSavior fbshipit-source-id: cb553030934205a52dd50a2a8c8a20da6100e23f
2020-04-04 04:34:15 +03:00
if (android_rippleConfig != null) {
android_rippleConfig.onPressIn(event);
}
setPressed(true);
if (onPressIn != null) {
onPressIn(event);
}
},
add ripple config object to Pressable (#28156) Summary: Motivation is to support ripple radius just like in TouchableNativeFeedback, plus borderless attribute. See https://github.com/facebook/react-native/pull/28009#issuecomment-589489520 In the current form this means user needs to pass an `android_ripple` prop which is an object of this shape: ``` export type RippleConfig = {| color?: ?ColorValue, borderless?: ?boolean, radius?: ?number, |}; ``` Do we want to add methods that would create such config objects - https://facebook.github.io/react-native/docs/touchablenativefeedback#methods ? ## Changelog [Android] [Added] - support borderless and custom ripple radius on Pressable Pull Request resolved: https://github.com/facebook/react-native/pull/28156 Test Plan: Tested locally in RNTester. I noticed that when some content is rendered after the touchables, the ripple effect is "cut off" by the boundaries of the next view. This is not specific to Pressable, it happens to TouchableNativeFeedback too but I just didn't notice it before in https://github.com/facebook/react-native/pull/28009. As it is an issue of its own, I didn't investigate that. ![pressable](https://user-images.githubusercontent.com/1566403/75098762-785f2200-55ba-11ea-8842-e648317610e3.gif) I changed the Touchable example slightly too (I just moved the "custom ripple radius" up to show the "cutting off" issue), so just for completeness: ![touchable](https://user-images.githubusercontent.com/1566403/75098763-81e88a00-55ba-11ea-9528-e0343d1e054b.gif) Reviewed By: yungsters Differential Revision: D20071021 Pulled By: TheSavior fbshipit-source-id: cb553030934205a52dd50a2a8c8a20da6100e23f
2020-04-04 04:34:15 +03:00
onPressMove: android_rippleConfig?.onPressMove,
onPressOut(event: PressEvent): void {
add ripple config object to Pressable (#28156) Summary: Motivation is to support ripple radius just like in TouchableNativeFeedback, plus borderless attribute. See https://github.com/facebook/react-native/pull/28009#issuecomment-589489520 In the current form this means user needs to pass an `android_ripple` prop which is an object of this shape: ``` export type RippleConfig = {| color?: ?ColorValue, borderless?: ?boolean, radius?: ?number, |}; ``` Do we want to add methods that would create such config objects - https://facebook.github.io/react-native/docs/touchablenativefeedback#methods ? ## Changelog [Android] [Added] - support borderless and custom ripple radius on Pressable Pull Request resolved: https://github.com/facebook/react-native/pull/28156 Test Plan: Tested locally in RNTester. I noticed that when some content is rendered after the touchables, the ripple effect is "cut off" by the boundaries of the next view. This is not specific to Pressable, it happens to TouchableNativeFeedback too but I just didn't notice it before in https://github.com/facebook/react-native/pull/28009. As it is an issue of its own, I didn't investigate that. ![pressable](https://user-images.githubusercontent.com/1566403/75098762-785f2200-55ba-11ea-8842-e648317610e3.gif) I changed the Touchable example slightly too (I just moved the "custom ripple radius" up to show the "cutting off" issue), so just for completeness: ![touchable](https://user-images.githubusercontent.com/1566403/75098763-81e88a00-55ba-11ea-9528-e0343d1e054b.gif) Reviewed By: yungsters Differential Revision: D20071021 Pulled By: TheSavior fbshipit-source-id: cb553030934205a52dd50a2a8c8a20da6100e23f
2020-04-04 04:34:15 +03:00
if (android_rippleConfig != null) {
android_rippleConfig.onPressOut(event);
}
setPressed(false);
if (onPressOut != null) {
onPressOut(event);
}
},
}),
[
android_disableSound,
add ripple config object to Pressable (#28156) Summary: Motivation is to support ripple radius just like in TouchableNativeFeedback, plus borderless attribute. See https://github.com/facebook/react-native/pull/28009#issuecomment-589489520 In the current form this means user needs to pass an `android_ripple` prop which is an object of this shape: ``` export type RippleConfig = {| color?: ?ColorValue, borderless?: ?boolean, radius?: ?number, |}; ``` Do we want to add methods that would create such config objects - https://facebook.github.io/react-native/docs/touchablenativefeedback#methods ? ## Changelog [Android] [Added] - support borderless and custom ripple radius on Pressable Pull Request resolved: https://github.com/facebook/react-native/pull/28156 Test Plan: Tested locally in RNTester. I noticed that when some content is rendered after the touchables, the ripple effect is "cut off" by the boundaries of the next view. This is not specific to Pressable, it happens to TouchableNativeFeedback too but I just didn't notice it before in https://github.com/facebook/react-native/pull/28009. As it is an issue of its own, I didn't investigate that. ![pressable](https://user-images.githubusercontent.com/1566403/75098762-785f2200-55ba-11ea-8842-e648317610e3.gif) I changed the Touchable example slightly too (I just moved the "custom ripple radius" up to show the "cutting off" issue), so just for completeness: ![touchable](https://user-images.githubusercontent.com/1566403/75098763-81e88a00-55ba-11ea-9528-e0343d1e054b.gif) Reviewed By: yungsters Differential Revision: D20071021 Pulled By: TheSavior fbshipit-source-id: cb553030934205a52dd50a2a8c8a20da6100e23f
2020-04-04 04:34:15 +03:00
android_rippleConfig,
delayLongPress,
disabled,
hitSlop,
onLongPress,
onPress,
onPressIn,
onPressOut,
pressRetentionOffset,
setPressed,
],
);
const eventHandlers = usePressability(config);
return (
<View
{...restProps}
{...eventHandlers}
add ripple config object to Pressable (#28156) Summary: Motivation is to support ripple radius just like in TouchableNativeFeedback, plus borderless attribute. See https://github.com/facebook/react-native/pull/28009#issuecomment-589489520 In the current form this means user needs to pass an `android_ripple` prop which is an object of this shape: ``` export type RippleConfig = {| color?: ?ColorValue, borderless?: ?boolean, radius?: ?number, |}; ``` Do we want to add methods that would create such config objects - https://facebook.github.io/react-native/docs/touchablenativefeedback#methods ? ## Changelog [Android] [Added] - support borderless and custom ripple radius on Pressable Pull Request resolved: https://github.com/facebook/react-native/pull/28156 Test Plan: Tested locally in RNTester. I noticed that when some content is rendered after the touchables, the ripple effect is "cut off" by the boundaries of the next view. This is not specific to Pressable, it happens to TouchableNativeFeedback too but I just didn't notice it before in https://github.com/facebook/react-native/pull/28009. As it is an issue of its own, I didn't investigate that. ![pressable](https://user-images.githubusercontent.com/1566403/75098762-785f2200-55ba-11ea-8842-e648317610e3.gif) I changed the Touchable example slightly too (I just moved the "custom ripple radius" up to show the "cutting off" issue), so just for completeness: ![touchable](https://user-images.githubusercontent.com/1566403/75098763-81e88a00-55ba-11ea-9528-e0343d1e054b.gif) Reviewed By: yungsters Differential Revision: D20071021 Pulled By: TheSavior fbshipit-source-id: cb553030934205a52dd50a2a8c8a20da6100e23f
2020-04-04 04:34:15 +03:00
{...android_rippleConfig?.viewProps}
accessible={accessible !== false}
focusable={focusable !== false}
hitSlop={hitSlop}
ref={viewRef}
style={typeof style === 'function' ? style({pressed}) : style}
collapsable={false}>
{typeof children === 'function' ? children({pressed}) : children}
{__DEV__ ? <PressabilityDebugView color="red" hitSlop={hitSlop} /> : null}
</View>
);
}
function usePressState(forcePressed: boolean): [boolean, (boolean) => void] {
const [pressed, setPressed] = useState(false);
return [pressed || forcePressed, setPressed];
}
add ripple config object to Pressable (#28156) Summary: Motivation is to support ripple radius just like in TouchableNativeFeedback, plus borderless attribute. See https://github.com/facebook/react-native/pull/28009#issuecomment-589489520 In the current form this means user needs to pass an `android_ripple` prop which is an object of this shape: ``` export type RippleConfig = {| color?: ?ColorValue, borderless?: ?boolean, radius?: ?number, |}; ``` Do we want to add methods that would create such config objects - https://facebook.github.io/react-native/docs/touchablenativefeedback#methods ? ## Changelog [Android] [Added] - support borderless and custom ripple radius on Pressable Pull Request resolved: https://github.com/facebook/react-native/pull/28156 Test Plan: Tested locally in RNTester. I noticed that when some content is rendered after the touchables, the ripple effect is "cut off" by the boundaries of the next view. This is not specific to Pressable, it happens to TouchableNativeFeedback too but I just didn't notice it before in https://github.com/facebook/react-native/pull/28009. As it is an issue of its own, I didn't investigate that. ![pressable](https://user-images.githubusercontent.com/1566403/75098762-785f2200-55ba-11ea-8842-e648317610e3.gif) I changed the Touchable example slightly too (I just moved the "custom ripple radius" up to show the "cutting off" issue), so just for completeness: ![touchable](https://user-images.githubusercontent.com/1566403/75098763-81e88a00-55ba-11ea-9528-e0343d1e054b.gif) Reviewed By: yungsters Differential Revision: D20071021 Pulled By: TheSavior fbshipit-source-id: cb553030934205a52dd50a2a8c8a20da6100e23f
2020-04-04 04:34:15 +03:00
const MemoedPressable = React.memo(React.forwardRef(Pressable));
MemoedPressable.displayName = 'Pressable';
add ripple config object to Pressable (#28156) Summary: Motivation is to support ripple radius just like in TouchableNativeFeedback, plus borderless attribute. See https://github.com/facebook/react-native/pull/28009#issuecomment-589489520 In the current form this means user needs to pass an `android_ripple` prop which is an object of this shape: ``` export type RippleConfig = {| color?: ?ColorValue, borderless?: ?boolean, radius?: ?number, |}; ``` Do we want to add methods that would create such config objects - https://facebook.github.io/react-native/docs/touchablenativefeedback#methods ? ## Changelog [Android] [Added] - support borderless and custom ripple radius on Pressable Pull Request resolved: https://github.com/facebook/react-native/pull/28156 Test Plan: Tested locally in RNTester. I noticed that when some content is rendered after the touchables, the ripple effect is "cut off" by the boundaries of the next view. This is not specific to Pressable, it happens to TouchableNativeFeedback too but I just didn't notice it before in https://github.com/facebook/react-native/pull/28009. As it is an issue of its own, I didn't investigate that. ![pressable](https://user-images.githubusercontent.com/1566403/75098762-785f2200-55ba-11ea-8842-e648317610e3.gif) I changed the Touchable example slightly too (I just moved the "custom ripple radius" up to show the "cutting off" issue), so just for completeness: ![touchable](https://user-images.githubusercontent.com/1566403/75098763-81e88a00-55ba-11ea-9528-e0343d1e054b.gif) Reviewed By: yungsters Differential Revision: D20071021 Pulled By: TheSavior fbshipit-source-id: cb553030934205a52dd50a2a8c8a20da6100e23f
2020-04-04 04:34:15 +03:00
export default (MemoedPressable: React.AbstractComponent<
Props,
React.ElementRef<typeof View>,
>);