123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194 |
- /**
- * 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 Pressability, {
- type PressabilityConfig,
- } from '../../Pressability/Pressability';
- import {PressabilityDebugView} from '../../Pressability/PressabilityDebug';
- import TVTouchable from './TVTouchable';
- import type {
- AccessibilityActionEvent,
- AccessibilityActionInfo,
- AccessibilityRole,
- AccessibilityState,
- AccessibilityValue,
- } from '../../Components/View/ViewAccessibility';
- import type {EdgeInsetsProp} from '../../StyleSheet/EdgeInsetsPropType';
- import type {
- BlurEvent,
- FocusEvent,
- LayoutEvent,
- PressEvent,
- } from '../../Types/CoreEventTypes';
- import Platform from '../../Utilities/Platform';
- import View from '../../Components/View/View';
- import * as React from 'react';
- type Props = $ReadOnly<{|
- 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,
- children?: ?React.Node,
- delayLongPress?: ?number,
- delayPressIn?: ?number,
- delayPressOut?: ?number,
- disabled?: ?boolean,
- focusable?: ?boolean,
- hitSlop?: ?EdgeInsetsProp,
- importantForAccessibility?: ?('auto' | 'yes' | 'no' | 'no-hide-descendants'),
- nativeID?: ?string,
- onAccessibilityAction?: ?(event: AccessibilityActionEvent) => mixed,
- onBlur?: ?(event: BlurEvent) => mixed,
- onFocus?: ?(event: FocusEvent) => mixed,
- onLayout?: ?(event: LayoutEvent) => mixed,
- onLongPress?: ?(event: PressEvent) => mixed,
- onPress?: ?(event: PressEvent) => mixed,
- onPressIn?: ?(event: PressEvent) => mixed,
- onPressOut?: ?(event: PressEvent) => mixed,
- pressRetentionOffset?: ?EdgeInsetsProp,
- rejectResponderTermination?: ?boolean,
- testID?: ?string,
- touchSoundDisabled?: ?boolean,
- |}>;
- type State = $ReadOnly<{|
- pressability: Pressability,
- |}>;
- const PASSTHROUGH_PROPS = [
- 'accessibilityActions',
- 'accessibilityElementsHidden',
- 'accessibilityHint',
- 'accessibilityIgnoresInvertColors',
- 'accessibilityLabel',
- 'accessibilityLiveRegion',
- 'accessibilityRole',
- 'accessibilityState',
- 'accessibilityValue',
- 'accessibilityViewIsModal',
- 'hitSlop',
- 'importantForAccessibility',
- 'nativeID',
- 'onAccessibilityAction',
- 'onBlur',
- 'onFocus',
- 'onLayout',
- 'testID',
- ];
- class TouchableWithoutFeedback extends React.Component<Props, State> {
- _tvTouchable: ?TVTouchable;
- state: State = {
- pressability: new Pressability(createPressabilityConfig(this.props)),
- };
- render(): React.Node {
- const element = React.Children.only(this.props.children);
- const children = [element.props.children];
- if (__DEV__) {
- if (element.type === View) {
- children.push(
- <PressabilityDebugView color="red" hitSlop={this.props.hitSlop} />,
- );
- }
- }
- // BACKWARD-COMPATIBILITY: Focus and blur events were never supported before
- // adopting `Pressability`, so preserve that behavior.
- const {
- onBlur,
- onFocus,
- ...eventHandlersWithoutBlurAndFocus
- } = this.state.pressability.getEventHandlers();
- const elementProps: {[string]: mixed, ...} = {
- ...eventHandlersWithoutBlurAndFocus,
- accessible: this.props.accessible !== false,
- focusable:
- this.props.focusable !== false && this.props.onPress !== undefined,
- };
- for (const prop of PASSTHROUGH_PROPS) {
- if (this.props[prop] !== undefined) {
- elementProps[prop] = this.props[prop];
- }
- }
- return React.cloneElement(element, elementProps, ...children);
- }
- componentDidMount(): void {
- if (Platform.isTV) {
- this._tvTouchable = new TVTouchable(this, {
- getDisabled: () => this.props.disabled === true,
- onBlur: event => {
- if (this.props.onBlur != null) {
- this.props.onBlur(event);
- }
- },
- onFocus: event => {
- if (this.props.onFocus != null) {
- this.props.onFocus(event);
- }
- },
- onPress: event => {
- if (this.props.onPress != null) {
- this.props.onPress(event);
- }
- },
- });
- }
- }
- componentDidUpdate(): void {
- this.state.pressability.configure(createPressabilityConfig(this.props));
- }
- componentWillUnmount(): void {
- if (Platform.isTV) {
- if (this._tvTouchable != null) {
- this._tvTouchable.destroy();
- }
- }
- this.state.pressability.reset();
- }
- }
- function createPressabilityConfig(props: Props): PressabilityConfig {
- return {
- cancelable: !props.rejectResponderTermination,
- disabled: props.disabled,
- hitSlop: props.hitSlop,
- delayLongPress: props.delayLongPress,
- delayPressIn: props.delayPressIn,
- delayPressOut: props.delayPressOut,
- minPressDuration: 0,
- pressRectOffset: props.pressRetentionOffset,
- android_disableSound: props.touchSoundDisabled,
- onBlur: props.onBlur,
- onFocus: props.onFocus,
- onLongPress: props.onLongPress,
- onPress: props.onPress,
- onPressIn: props.onPressIn,
- onPressOut: props.onPressOut,
- };
- }
- module.exports = TouchableWithoutFeedback;
|