diff --git a/Libraries/Components/Touchable/TouchableNativeFeedback.android.js b/Libraries/Components/Touchable/TouchableNativeFeedback.android.js
deleted file mode 100644
index ff54f40993..0000000000
--- a/Libraries/Components/Touchable/TouchableNativeFeedback.android.js
+++ /dev/null
@@ -1,403 +0,0 @@
-/**
- * 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 TouchableInjection from './TouchableInjection';
-
-const Platform = require('../../Utilities/Platform');
-const PropTypes = require('prop-types');
-const React = require('react');
-const ReactNative = require('../../Renderer/shims/ReactNative');
-const Touchable = require('./Touchable');
-const TouchableWithoutFeedback = require('./TouchableWithoutFeedback');
-const View = require('../View/View');
-import {Commands} from '../View/ViewNativeComponent';
-
-const createReactClass = require('create-react-class');
-const ensurePositiveDelayProps = require('./ensurePositiveDelayProps');
-const processColor = require('../../StyleSheet/processColor');
-
-import type {Props as TouchableWithoutFeedbackProps} from './TouchableWithoutFeedback';
-import type {PressEvent} from '../../Types/CoreEventTypes';
-
-const rippleBackgroundPropType = PropTypes.shape({
- type: PropTypes.oneOf(['RippleAndroid']),
- color: PropTypes.number,
- borderless: PropTypes.bool,
-});
-
-const themeAttributeBackgroundPropType = PropTypes.shape({
- type: PropTypes.oneOf(['ThemeAttrAndroid']),
- attribute: PropTypes.string.isRequired,
-});
-
-const backgroundPropType = PropTypes.oneOfType([
- rippleBackgroundPropType,
- themeAttributeBackgroundPropType,
-]);
-
-const PRESS_RETENTION_OFFSET = {top: 20, left: 20, right: 20, bottom: 30};
-
-export type Props = $ReadOnly<{|
- ...TouchableWithoutFeedbackProps,
-
- background?: ?(
- | $ReadOnly<{|
- type: 'ThemeAttrAndroid',
- attribute:
- | 'selectableItemBackground'
- | 'selectableItemBackgroundBorderless',
- |}>
- | $ReadOnly<{|
- type: 'RippleAndroid',
- color: ?number,
- borderless: boolean,
- |}>
- ),
- hasTVPreferredFocus?: ?boolean,
- nextFocusDown?: ?number,
- nextFocusForward?: ?number,
- nextFocusLeft?: ?number,
- nextFocusRight?: ?number,
- nextFocusUp?: ?number,
- useForeground?: ?boolean,
-|}>;
-
-/**
- * A wrapper for making views respond properly to touches (Android only).
- * On Android this component uses native state drawable to display touch
- * feedback.
- *
- * At the moment it only supports having a single View instance as a child
- * node, as it's implemented by replacing that View with another instance of
- * RCTView node with some additional properties set.
- *
- * Background drawable of native feedback touchable can be customized with
- * `background` property.
- *
- * Example:
- *
- * ```
- * renderButton: function() {
- * return (
- *
- *
- * Button
- *
- *
- * );
- * },
- * ```
- */
-
-const TouchableNativeFeedbackImpl = createReactClass({
- displayName: 'TouchableNativeFeedback',
- propTypes: {
- /* $FlowFixMe(>=0.89.0 site=react_native_android_fb) This comment
- * suppresses an error found when Flow v0.89 was deployed. To see the
- * error, delete this comment and run Flow. */
- ...TouchableWithoutFeedback.propTypes,
-
- /**
- * Determines the type of background drawable that's going to be used to
- * display feedback. It takes an object with `type` property and extra data
- * depending on the `type`. It's recommended to use one of the static
- * methods to generate that dictionary.
- */
- background: backgroundPropType,
-
- /**
- * TV preferred focus (see documentation for the View component).
- */
- hasTVPreferredFocus: PropTypes.bool,
-
- /**
- * TV next focus down (see documentation for the View component).
- */
- nextFocusDown: PropTypes.number,
-
- /**
- * TV next focus forward (see documentation for the View component).
- */
- nextFocusForward: PropTypes.number,
-
- /**
- * TV next focus left (see documentation for the View component).
- */
- nextFocusLeft: PropTypes.number,
-
- /**
- * TV next focus right (see documentation for the View component).
- */
- nextFocusRight: PropTypes.number,
-
- /**
- * TV next focus up (see documentation for the View component).
- */
- nextFocusUp: PropTypes.number,
-
- /**
- * Set to true to add the ripple effect to the foreground of the view, instead of the
- * background. This is useful if one of your child views has a background of its own, or you're
- * e.g. displaying images, and you don't want the ripple to be covered by them.
- *
- * Check TouchableNativeFeedback.canUseNativeForeground() first, as this is only available on
- * Android 6.0 and above. If you try to use this on older versions you will get a warning and
- * fallback to background.
- */
- useForeground: PropTypes.bool,
- },
-
- statics: {
- /**
- * Creates an object that represents android theme's default background for
- * selectable elements (?android:attr/selectableItemBackground).
- */
- SelectableBackground: function(): {
- type: 'ThemeAttrAndroid',
- attribute: 'selectableItemBackground',
- ...
- } {
- return {type: 'ThemeAttrAndroid', attribute: 'selectableItemBackground'};
- },
- /**
- * Creates an object that represent android theme's default background for borderless
- * selectable elements (?android:attr/selectableItemBackgroundBorderless).
- * Available on android API level 21+.
- */
- SelectableBackgroundBorderless: function(): {
- type: 'ThemeAttrAndroid',
- attribute: 'selectableItemBackgroundBorderless',
- ...
- } {
- return {
- type: 'ThemeAttrAndroid',
- attribute: 'selectableItemBackgroundBorderless',
- };
- },
- /**
- * Creates an object that represents ripple drawable with specified color (as a
- * string). If property `borderless` evaluates to true the ripple will
- * render outside of the view bounds (see native actionbar buttons as an
- * example of that behavior). This background type is available on Android
- * API level 21+.
- *
- * @param color The ripple color
- * @param borderless If the ripple can render outside it's bounds
- */
- Ripple: function(
- color: string,
- borderless: boolean,
- ): {
- type: 'RippleAndroid',
- color: ?number,
- borderless: boolean,
- ...
- } {
- return {
- type: 'RippleAndroid',
- color: processColor(color),
- borderless: borderless,
- };
- },
-
- canUseNativeForeground: function(): boolean {
- return Platform.OS === 'android' && Platform.Version >= 23;
- },
- },
-
- mixins: [Touchable.Mixin],
-
- getDefaultProps: function() {
- return {
- background: this.SelectableBackground(),
- };
- },
-
- getInitialState: function() {
- return this.touchableGetInitialState();
- },
-
- componentDidMount: function() {
- ensurePositiveDelayProps(this.props);
- },
-
- UNSAFE_componentWillReceiveProps: function(nextProps) {
- ensurePositiveDelayProps(nextProps);
- },
-
- /**
- * `Touchable.Mixin` self callbacks. The mixin will invoke these if they are
- * defined on your component.
- */
- touchableHandleActivePressIn: function(e: PressEvent) {
- this.props.onPressIn && this.props.onPressIn(e);
- this._dispatchPressedStateChange(true);
- if (this.pressInLocation) {
- this._dispatchHotspotUpdate(
- this.pressInLocation.locationX,
- this.pressInLocation.locationY,
- );
- }
- },
-
- touchableHandleActivePressOut: function(e: PressEvent) {
- this.props.onPressOut && this.props.onPressOut(e);
- this._dispatchPressedStateChange(false);
- },
-
- touchableHandlePress: function(e: PressEvent) {
- this.props.onPress && this.props.onPress(e);
- },
-
- touchableHandleLongPress: function(e: PressEvent) {
- this.props.onLongPress && this.props.onLongPress(e);
- },
-
- touchableGetPressRectOffset: function() {
- // Always make sure to predeclare a constant!
- return this.props.pressRetentionOffset || PRESS_RETENTION_OFFSET;
- },
-
- touchableGetHitSlop: function() {
- return this.props.hitSlop;
- },
-
- touchableGetHighlightDelayMS: function() {
- return this.props.delayPressIn;
- },
-
- touchableGetLongPressDelayMS: function() {
- return this.props.delayLongPress;
- },
-
- touchableGetPressOutDelayMS: function() {
- return this.props.delayPressOut;
- },
-
- _handleResponderMove: function(e) {
- this.touchableHandleResponderMove(e);
- this._dispatchHotspotUpdate(
- e.nativeEvent.locationX,
- e.nativeEvent.locationY,
- );
- },
-
- _dispatchHotspotUpdate: function(destX, destY) {
- const hostComponentRef = ReactNative.findHostInstance_DEPRECATED(this);
-
- if (hostComponentRef == null) {
- console.warn(
- 'Touchable: Unable to find HostComponent instance. ' +
- 'Has your Touchable component been unmounted?',
- );
- } else {
- Commands.hotspotUpdate(hostComponentRef, destX || 0, destY || 0);
- }
- },
-
- _dispatchPressedStateChange: function(pressed) {
- const hostComponentRef = ReactNative.findHostInstance_DEPRECATED(this);
- if (hostComponentRef == null) {
- console.warn(
- 'Touchable: Unable to find HostComponent instance. ' +
- 'Has your Touchable component been unmounted?',
- );
- } else {
- Commands.setPressed(hostComponentRef, pressed);
- }
- },
-
- render: function() {
- const child = React.Children.only(this.props.children);
- let children = child.props.children;
- if (Touchable.TOUCH_TARGET_DEBUG && child.type === View) {
- if (!Array.isArray(children)) {
- children = [children];
- }
- children.push(
- Touchable.renderDebugView({
- color: 'brown',
- hitSlop: this.props.hitSlop,
- }),
- );
- }
- if (
- this.props.useForeground &&
- !TouchableNativeFeedbackImpl.canUseNativeForeground()
- ) {
- console.warn(
- 'Requested foreground ripple, but it is not available on this version of Android. ' +
- 'Consider calling TouchableNativeFeedback.canUseNativeForeground() and using a different ' +
- 'Touchable if the result is false.',
- );
- }
- const drawableProp =
- this.props.useForeground &&
- TouchableNativeFeedbackImpl.canUseNativeForeground()
- ? 'nativeForegroundAndroid'
- : 'nativeBackgroundAndroid';
- const childProps = {
- ...child.props,
- /* $FlowFixMe(>=0.111.0 site=react_native_android_fb) This comment
- * suppresses an error found when Flow v0.111 was deployed. To see the
- * error, delete this comment and run Flow. */
- [drawableProp]: this.props.background,
- accessible: this.props.accessible !== false,
- accessibilityLabel: this.props.accessibilityLabel,
- 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,
- children,
- testID: this.props.testID,
- onLayout: this.props.onLayout,
- hitSlop: this.props.hitSlop,
- nextFocusDown: this.props.nextFocusDown,
- nextFocusForward: this.props.nextFocusForward,
- nextFocusLeft: this.props.nextFocusLeft,
- nextFocusRight: this.props.nextFocusRight,
- nextFocusUp: this.props.nextFocusUp,
- hasTVPreferredFocus: this.props.hasTVPreferredFocus,
- focusable:
- this.props.focusable !== false &&
- this.props.onPress !== undefined &&
- !this.props.disabled,
- onClick: this.touchableHandlePress,
- onStartShouldSetResponder: this.touchableHandleStartShouldSetResponder,
- onResponderTerminationRequest: this
- .touchableHandleResponderTerminationRequest,
- onResponderGrant: this.touchableHandleResponderGrant,
- onResponderMove: this._handleResponderMove,
- onResponderRelease: this.touchableHandleResponderRelease,
- onResponderTerminate: this.touchableHandleResponderTerminate,
- };
-
- // We need to clone the actual element so that the ripple background drawable
- // can be applied directly to the background of this element rather than to
- // a wrapper view as done in other Touchable*
- return React.cloneElement(child, childProps);
- },
-});
-
-const TouchableNativeFeedback: React.ComponentType =
- TouchableInjection.unstable_TouchableNativeFeedback == null
- ? TouchableNativeFeedbackImpl
- : TouchableInjection.unstable_TouchableNativeFeedback;
-
-module.exports = (TouchableNativeFeedback: $FlowFixMe);
diff --git a/Libraries/Components/Touchable/TouchableNativeFeedback.ios.js b/Libraries/Components/Touchable/TouchableNativeFeedback.ios.js
deleted file mode 100644
index 8efacfa365..0000000000
--- a/Libraries/Components/Touchable/TouchableNativeFeedback.ios.js
+++ /dev/null
@@ -1,51 +0,0 @@
-/**
- * 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.
- *
- * @format
- */
-
-'use strict';
-
-const React = require('react');
-const StyleSheet = require('../../StyleSheet/StyleSheet');
-const Text = require('../../Text/Text');
-const View = require('../View/View');
-
-class DummyTouchableNativeFeedback extends React.Component {
- static SelectableBackground = () => ({});
- static SelectableBackgroundBorderless = () => ({});
- static Ripple = () => ({});
- static canUseNativeForeground = () => false;
-
- render() {
- return (
-
-
- TouchableNativeFeedback is not supported on this platform!
-
-
- );
- }
-}
-
-const styles = StyleSheet.create({
- container: {
- height: 100,
- width: 300,
- backgroundColor: '#ffbcbc',
- borderWidth: 1,
- borderColor: 'red',
- alignItems: 'center',
- justifyContent: 'center',
- margin: 10,
- },
- info: {
- color: '#333333',
- margin: 20,
- },
-});
-
-module.exports = DummyTouchableNativeFeedback;
diff --git a/Libraries/Components/Touchable/TouchableNativeFeedback.js b/Libraries/Components/Touchable/TouchableNativeFeedback.js
new file mode 100644
index 0000000000..2b54b95c07
--- /dev/null
+++ b/Libraries/Components/Touchable/TouchableNativeFeedback.js
@@ -0,0 +1,331 @@
+/**
+ * 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 from '../../Pressability/Pressability.js';
+import {PressabilityDebugView} from '../../Pressability/PressabilityDebug.js';
+import TVTouchable from './TVTouchable.js';
+import type {Props as TouchableWithoutFeedbackProps} from './TouchableWithoutFeedback.js';
+import {Commands} from 'react-native/Libraries/Components/View/ViewNativeComponent';
+import ReactNative from 'react-native/Libraries/Renderer/shims/ReactNative';
+import type {PressEvent} from 'react-native/Libraries/Types/CoreEventTypes';
+import {Platform, View, processColor} from 'react-native';
+import * as React from 'react';
+
+type Props = $ReadOnly<{|
+ ...TouchableWithoutFeedbackProps,
+
+ /**
+ * Determines the type of background drawable that's going to be used to
+ * display feedback. It takes an object with `type` property and extra data
+ * depending on the `type`. It's recommended to use one of the static
+ * methods to generate that dictionary.
+ */
+ background?: ?(
+ | $ReadOnly<{|
+ type: 'ThemeAttrAndroid',
+ attribute:
+ | 'selectableItemBackground'
+ | 'selectableItemBackgroundBorderless',
+ |}>
+ | $ReadOnly<{|
+ type: 'RippleAndroid',
+ color: ?number,
+ borderless: boolean,
+ |}>
+ ),
+
+ /**
+ * TV preferred focus (see documentation for the View component).
+ */
+ hasTVPreferredFocus?: ?boolean,
+
+ /**
+ * TV next focus down (see documentation for the View component).
+ */
+ nextFocusDown?: ?number,
+
+ /**
+ * TV next focus forward (see documentation for the View component).
+ */
+ nextFocusForward?: ?number,
+
+ /**
+ * TV next focus left (see documentation for the View component).
+ */
+ nextFocusLeft?: ?number,
+
+ /**
+ * TV next focus right (see documentation for the View component).
+ */
+ nextFocusRight?: ?number,
+
+ /**
+ * TV next focus up (see documentation for the View component).
+ */
+ nextFocusUp?: ?number,
+
+ /**
+ * Set to true to add the ripple effect to the foreground of the view, instead
+ * of the background. This is useful if one of your child views has a
+ * background of its own, or you're e.g. displaying images, and you don't want
+ * the ripple to be covered by them.
+ *
+ * Check TouchableNativeFeedback.canUseNativeForeground() first, as this is
+ * only available on Android 6.0 and above. If you try to use this on older
+ * versions, this will fallback to background.
+ */
+ useForeground?: ?boolean,
+|}>;
+
+type State = $ReadOnly<{|
+ pressability: Pressability,
+|}>;
+
+class TouchableNativeFeedback extends React.Component {
+ /**
+ * Creates a value for the `background` prop that uses the Android theme's
+ * default background for selectable elements.
+ */
+ static SelectableBackground: () => $ReadOnly<{|
+ attribute: 'selectableItemBackground',
+ type: 'ThemeAttrAndroid',
+ |}> = () => ({
+ type: 'ThemeAttrAndroid',
+ attribute: 'selectableItemBackground',
+ });
+
+ /**
+ * Creates a value for the `background` prop that uses the Android theme's
+ * default background for borderless selectable elements. Requires API 21+.
+ */
+ static SelectableBackgroundBorderless: () => $ReadOnly<{|
+ attribute: 'selectableItemBackgroundBorderless',
+ type: 'ThemeAttrAndroid',
+ |}> = () => ({
+ type: 'ThemeAttrAndroid',
+ attribute: 'selectableItemBackgroundBorderless',
+ });
+
+ /**
+ * Creates a value for the `background` prop that uses the Android ripple with
+ * the supplied color. If `borderless` is true, the ripple will render outside
+ * of the view bounds. Requires API 21+.
+ */
+ static Ripple: (
+ color: string,
+ borderless: boolean,
+ ) => $ReadOnly<{|
+ borderless: boolean,
+ color: ?number,
+ type: 'RippleAndroid',
+ |}> = (color: string, borderless: boolean) => ({
+ type: 'RippleAndroid',
+ color: processColor(color),
+ borderless,
+ });
+
+ /**
+ * Whether `useForeground` is supported.
+ */
+ static canUseNativeForeground: () => boolean = () =>
+ Platform.OS === 'android' && Platform.Version >= 23;
+
+ _tvTouchable: ?TVTouchable;
+
+ state: State = {
+ pressability: new Pressability({
+ getHitSlop: () => this.props.hitSlop,
+ getLongPressDelayMS: () => {
+ if (this.props.delayLongPress != null) {
+ const maybeNumber = this.props.delayLongPress;
+ if (typeof maybeNumber === 'number') {
+ return maybeNumber;
+ }
+ }
+ return 500;
+ },
+ getPressDelayMS: () => this.props.delayPressIn,
+ getPressOutDelayMS: () => this.props.delayPressOut,
+ getPressRectOffset: () => this.props.pressRetentionOffset,
+ getTouchSoundDisabled: () => this.props.touchSoundDisabled,
+ onLongPress: event => {
+ if (this.props.onLongPress != null) {
+ this.props.onLongPress(event);
+ }
+ },
+ onPress: event => {
+ if (this.props.onPress != null) {
+ this.props.onPress(event);
+ }
+ },
+ onPressIn: event => {
+ if (Platform.OS === 'android') {
+ this._dispatchPressedStateChange(true);
+ this._dispatchHotspotUpdate(event);
+ }
+ if (this.props.onPressIn != null) {
+ this.props.onPressIn(event);
+ }
+ },
+ onPressMove: event => {
+ if (Platform.OS === 'android') {
+ this._dispatchHotspotUpdate(event);
+ }
+ },
+ onPressOut: event => {
+ if (Platform.OS === 'android') {
+ this._dispatchPressedStateChange(false);
+ }
+ if (this.props.onPressOut != null) {
+ this.props.onPressOut(event);
+ }
+ },
+ onResponderTerminationRequest: () =>
+ !this.props.rejectResponderTermination,
+ onStartShouldSetResponder: () => !this.props.disabled,
+ }),
+ };
+
+ _dispatchPressedStateChange(pressed: boolean): void {
+ if (Platform.OS === 'android') {
+ const hostComponentRef = ReactNative.findHostInstance_DEPRECATED(this);
+ if (hostComponentRef == null) {
+ console.warn(
+ 'Touchable: Unable to find HostComponent instance. ' +
+ 'Has your Touchable component been unmounted?',
+ );
+ } else {
+ Commands.setPressed(hostComponentRef, pressed);
+ }
+ }
+ }
+
+ _dispatchHotspotUpdate(event: PressEvent): void {
+ if (Platform.OS === 'android') {
+ const {locationX, locationY} = event.nativeEvent;
+ const hostComponentRef = ReactNative.findHostInstance_DEPRECATED(this);
+ if (hostComponentRef == null) {
+ console.warn(
+ 'Touchable: Unable to find HostComponent instance. ' +
+ 'Has your Touchable component been unmounted?',
+ );
+ } else {
+ Commands.hotspotUpdate(
+ hostComponentRef,
+ locationX ?? 0,
+ locationY ?? 0,
+ );
+ }
+ }
+ }
+
+ render(): React.Node {
+ const element = React.Children.only(this.props.children);
+ const children = [element.props.children];
+ if (__DEV__) {
+ if (element.type === View) {
+ children.push(
+ ,
+ );
+ }
+ }
+
+ // BACKWARD-COMPATIBILITY: Focus and blur events were never supported before
+ // adopting `Pressability`, so preserve that behavior.
+ const {
+ onBlur,
+ onFocus,
+ ...eventHandlersWithoutBlurAndFocus
+ } = this.state.pressability.getEventHandlers();
+
+ return React.cloneElement(
+ element,
+ {
+ ...eventHandlersWithoutBlurAndFocus,
+ ...getBackgroundProp(
+ this.props.background === undefined
+ ? TouchableNativeFeedback.SelectableBackground()
+ : this.props.background,
+ this.props.useForeground === true,
+ ),
+ accessible: this.props.accessible !== false,
+ accessibilityLabel: this.props.accessibilityLabel,
+ 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,
+ hasTVPreferredFocus: this.props.hasTVPreferredFocus,
+ hitSlop: this.props.hitSlop,
+ focusable:
+ this.props.focusable !== false &&
+ this.props.onPress !== undefined &&
+ !this.props.disabled,
+ nativeID: this.props.nativeID,
+ nextFocusDown: this.props.nextFocusDown,
+ nextFocusForward: this.props.nextFocusForward,
+ nextFocusLeft: this.props.nextFocusLeft,
+ nextFocusRight: this.props.nextFocusRight,
+ nextFocusUp: this.props.nextFocusUp,
+ onLayout: this.props.onLayout,
+ testID: this.props.testID,
+ },
+ ...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);
+ }
+ },
+ });
+ }
+ }
+
+ componentWillUnmount(): void {
+ if (Platform.isTV) {
+ if (this._tvTouchable != null) {
+ this._tvTouchable.destroy();
+ }
+ }
+ this.state.pressability.reset();
+ }
+}
+
+const getBackgroundProp =
+ Platform.OS === 'android'
+ ? (background, useForeground) =>
+ useForeground && TouchableNativeFeedback.canUseNativeForeground()
+ ? {nativeForegroundAndroid: background}
+ : {nativeBackgroundAndroid: background}
+ : (background, useForeground) => null;
+
+module.exports = TouchableNativeFeedback;
diff --git a/RNTester/js/examples/Touchable/TouchableExample.js b/RNTester/js/examples/Touchable/TouchableExample.js
index a687f13f1f..3fbecac3a1 100644
--- a/RNTester/js/examples/Touchable/TouchableExample.js
+++ b/RNTester/js/examples/Touchable/TouchableExample.js
@@ -402,10 +402,9 @@ class TouchableDisabled extends React.Component<{...}> {
{Platform.OS === 'android' && (
console.log('custom TNF has been clicked')}
background={TouchableNativeFeedback.SelectableBackground()}>
-
+
Enabled TouchableNativeFeedback
@@ -416,10 +415,9 @@ class TouchableDisabled extends React.Component<{...}> {
{Platform.OS === 'android' && (
console.log('custom TNF has been clicked')}
background={TouchableNativeFeedback.SelectableBackground()}>
-
+
Disabled TouchableNativeFeedback