text: /**
   * 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 typeof TouchableWithoutFeedback from './TouchableWithoutFeedback';
  import Animated from 'react-native/Libraries/Animated/src/Animated';
  import Easing from 'react-native/Libraries/Animated/src/Easing';
  import type {ViewStyleProp} from 'react-native/Libraries/StyleSheet/StyleSheet';
  import flattenStyle from 'react-native/Libraries/StyleSheet/flattenStyle';
  import Platform from '../../Utilities/Platform';
  import * as React from 'react';
  
  type TVProps = $ReadOnly<{|
    hasTVPreferredFocus?: ?boolean,
    nextFocusDown?: ?number,
    nextFocusForward?: ?number,
    nextFocusLeft?: ?number,
    nextFocusRight?: ?number,
    nextFocusUp?: ?number,
  |}>;
  
  type Props = $ReadOnly<{|
    ...React.ElementConfig<TouchableWithoutFeedback>,
    ...TVProps,
  
    activeOpacity?: ?number,
    style?: ?ViewStyleProp,
  
    hostRef: React.Ref<typeof Animated.View>,
  |}>;
  
  type State = $ReadOnly<{|
    anim: Animated.Value,
    pressability: Pressability,
  |}>;
  
  /**
   * A wrapper for making views respond properly to touches.
   * On press down, the opacity of the wrapped view is decreased, dimming it.
   *
   * Opacity is controlled by wrapping the children in an Animated.View, which is
   * added to the view hierarchy.  Be aware that this can affect layout.
   *
   * Example:
   *
   * ```
   * renderButton: function() {
   *   return (
   *     <TouchableOpacity onPress={this._onPressButton}>
   *       <Image
   *         style={styles.button}
   *         source={require('./myButton.png')}
   *       />
   *     </TouchableOpacity>
   *   );
   * },
   * ```
   * ### Example
   *
   * ```ReactNativeWebPlayer
   * import React, { Component } from 'react'
   * import {
   *   AppRegistry,
   *   StyleSheet,
   *   TouchableOpacity,
   *   Text,
   *   View,
   * } from 'react-native'
   *
   * class App extends Component {
   *   state = { count: 0 }
   *
   *   onPress = () => {
   *     this.setState(state => ({
   *       count: state.count + 1
   *     }));
   *   };
   *
   *  render() {
   *    return (
   *      <View style={styles.container}>
   *        <TouchableOpacity
   *          style={styles.button}
   *          onPress={this.onPress}>
   *          <Text> Touch Here </Text>
   *        </TouchableOpacity>
   *        <View style={[styles.countContainer]}>
   *          <Text style={[styles.countText]}>
   *             { this.state.count !== 0 ? this.state.count: null}
   *           </Text>
   *         </View>
   *       </View>
   *     )
   *   }
   * }
   *
   * const styles = StyleSheet.create({
   *   container: {
   *     flex: 1,
   *     justifyContent: 'center',
   *     paddingHorizontal: 10
   *   },
   *   button: {
   *     alignItems: 'center',
   *     backgroundColor: '#DDDDDD',
   *     padding: 10
   *   },
   *   countContainer: {
   *     alignItems: 'center',
   *     padding: 10
   *   },
   *   countText: {
   *     color: '#FF00FF'
   *   }
   * })
   *
   * AppRegistry.registerComponent('App', () => App)
   * ```
   *
   */
  class TouchableOpacity extends React.Component<Props, State> {
    _tvTouchable: ?TVTouchable;
  
    state: State = {
      anim: new Animated.Value(this._getChildStyleOpacityWithDefault()),
      pressability: new Pressability(this._createPressabilityConfig()),
    };
  
    _createPressabilityConfig(): PressabilityConfig {
      return {
        cancelable: !this.props.rejectResponderTermination,
        disabled: this.props.disabled,
        hitSlop: this.props.hitSlop,
        delayLongPress: this.props.delayLongPress,
        delayPressIn: this.props.delayPressIn,
        delayPressOut: this.props.delayPressOut,
        pressRectOffset: this.props.pressRetentionOffset,
        onMouseEnter: this.props.onMouseEnter, // [Windows]
        onMouseLeave: this.props.onMouseLeave, // [Windows]
        onBlur: event => {
          if (Platform.isTV) {
            this._opacityInactive(250);
          }
          if (this.props.onBlur != null) {
            this.props.onBlur(event);
          }
        },
        onFocus: event => {
          if (Platform.isTV) {
            this._opacityActive(150);
          }
          if (this.props.onFocus != null) {
            this.props.onFocus(event);
          }
        },
        onLongPress: this.props.onLongPress,
        onPress: this.props.onPress,
        onPressIn: event => {
          this._opacityActive(
            event.dispatchConfig.registrationName === 'onResponderGrant'
              ? 0
              : 150,
          );
          if (this.props.onPressIn != null) {
            this.props.onPressIn(event);
          }
        },
        onPressOut: event => {
          this._opacityInactive(250);
          if (this.props.onPressOut != null) {
            this.props.onPressOut(event);
          }
        },
      };
    }
  
    /**
     * Animate the touchable to a new opacity.
     */
    _setOpacityTo(toValue: number, duration: number): void {
      Animated.timing(this.state.anim, {
        toValue,
        duration,
        easing: Easing.inOut(Easing.quad),
        useNativeDriver: true,
      }).start();
    }
  
    _opacityActive(duration: number): void {
      this._setOpacityTo(this.props.activeOpacity ?? 0.2, duration);
    }
  
    _opacityInactive(duration: number): void {
      this._setOpacityTo(this._getChildStyleOpacityWithDefault(), duration);
    }
  
    _getChildStyleOpacityWithDefault(): number {
      const opacity = flattenStyle(this.props.style)?.opacity;
      return typeof opacity === 'number' ? opacity : 1;
    }
  
    render(): React.Node {
      // BACKWARD-COMPATIBILITY: Focus and blur events were never supported before
      // adopting `Pressability`, so preserve that behavior.
      const {
        // [Windows We used to manually hook up onFocus and onBlur. Do we still need to?
        // onBlur,
        // onFocus,
        // Windows]
        ...eventHandlersWithoutBlurAndFocus
      } = this.state.pressability.getEventHandlers();
  
      return (
        <Animated.View
          accessible={this.props.accessible !== false}
          accessibilityLabel={this.props.accessibilityLabel}
          accessibilityHint={this.props.accessibilityHint}
          accessibilityRole={this.props.accessibilityRole}
          accessibilityState={this.props.accessibilityState}
          accessibilityActions={this.props.accessibilityActions}
          onAccessibilityAction={this.props.onAccessibilityAction}
          accessibilityValue={this.props.accessibilityValue}
          importantForAccessibility={this.props.importantForAccessibility}
          accessibilityLiveRegion={this.props.accessibilityLiveRegion}
          accessibilityViewIsModal={this.props.accessibilityViewIsModal}
          accessibilityElementsHidden={this.props.accessibilityElementsHidden}
          style={[this.props.style, {opacity: this.state.anim}]}
          nativeID={this.props.nativeID}
          testID={this.props.testID}
          onLayout={this.props.onLayout}
          nextFocusDown={this.props.nextFocusDown}
          nextFocusForward={this.props.nextFocusForward}
          nextFocusLeft={this.props.nextFocusLeft}
          nextFocusRight={this.props.nextFocusRight}
          nextFocusUp={this.props.nextFocusUp}
          hasTVPreferredFocus={this.props.hasTVPreferredFocus}
          hitSlop={this.props.hitSlop}
          // [Windows We need to reconcile between focusable and acceptsKeyboardFocus
          // (e.g. if one is explictly disabled, we shouldn't implicitly enable the
          // other on the underlying view). Prefer passing acceptsKeyboardFocus if
          // passed explicitly to preserve original behavior, and trigger view warnings.
          {...(this.props.acceptsKeyboardFocus !== undefined
            ? {
                acceptsKeyboardFocus:
                  (this.props.acceptsKeyboardFocus === undefined ||
                    this.props.acceptsKeyboardFocus === true) &&
                  !this.props.disabled,
              }
            : {
                focusable:
                  this.props.focusable !== false &&
                  this.props.onPress !== undefined,
              })}
          // Windows]
          ref={this.props.hostRef}
          accessibilityPosInSet={this.props.accessibilityPosInSet} // [Windows]
          accessibilitySetSize={this.props.accessibilitySetSize} // [Windows]
          onAccessibilityTap={this.props.onAccessibilityTap} // [Windows]
          tabIndex={this.props.tabIndex} // [Windows]
          tooltip={this.props.tooltip} // [Windows]
          onMouseEnter={this.props.onMouseEnter} // [Windows]
          onMouseLeave={this.props.onMouseLeave} // [Windows]
          {...eventHandlersWithoutBlurAndFocus}>
          {this.props.children}
          {__DEV__ ? (
            <PressabilityDebugView color="cyan" hitSlop={this.props.hitSlop} />
          ) : null}
        </Animated.View>
      );
    }
  
    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(prevProps: Props, prevState: State) {
      this.state.pressability.configure(this._createPressabilityConfig());
      if (this.props.disabled !== prevProps.disabled) {
        this._opacityInactive(250);
      }
    }
  
    componentWillUnmount(): void {
      if (Platform.isTV) {
        if (this._tvTouchable != null) {
          this._tvTouchable.destroy();
        }
      }
      this.state.pressability.reset();
    }
  }
  
  module.exports = (React.forwardRef((props, hostRef) => (
    <TouchableOpacity {...props} hostRef={hostRef} />
  )): React.ComponentType<$ReadOnly<$Diff<Props, {|hostRef: mixed|}>>>);
  