[change] Deprecate Touchables and Button components

These components have been replaced by Pressable and will be removed
from React Native.

Fix #2382
This commit is contained in:
Nicolas Gallagher
2022-09-01 15:08:39 -07:00
committed by Nicolas Gallagher
parent e8a0cbc60a
commit a33c322152
15 changed files with 51 additions and 277 deletions
@@ -71,7 +71,7 @@ import * as ReactNativeModules from 'react-native-web/dist/cjs/index';
exports[`Rewrite react-native to react-native-web import from "react-native-web": import from "react-native-web" 1`] = `
import { unstable_createElement } from 'react-native-web';
import { StyleSheet, View, TouchableOpacity, processColor } from 'react-native-web';
import { StyleSheet, View, Pressable, processColor } from 'react-native-web';
import * as ReactNativeModules from 'react-native-web';
↓ ↓ ↓ ↓ ↓ ↓
@@ -79,7 +79,7 @@ import * as ReactNativeModules from 'react-native-web';
import unstable_createElement from 'react-native-web/dist/exports/createElement';
import StyleSheet from 'react-native-web/dist/exports/StyleSheet';
import View from 'react-native-web/dist/exports/View';
import TouchableOpacity from 'react-native-web/dist/exports/TouchableOpacity';
import Pressable from 'react-native-web/dist/exports/Pressable';
import processColor from 'react-native-web/dist/exports/processColor';
import * as ReactNativeModules from 'react-native-web/dist/index';
@@ -90,7 +90,7 @@ exports[`Rewrite react-native to react-native-web require "react-native": requir
const ReactNative = require('react-native');
const { View } = require('react-native');
const { StyleSheet, TouchableOpacity } = require('react-native');
const { StyleSheet, Pressable } = require('react-native');
↓ ↓ ↓ ↓ ↓ ↓
@@ -100,8 +100,7 @@ const View = require('react-native-web/dist/exports/View').default;
const StyleSheet = require('react-native-web/dist/exports/StyleSheet').default;
const TouchableOpacity =
require('react-native-web/dist/exports/TouchableOpacity').default;
const Pressable = require('react-native-web/dist/exports/Pressable').default;
`;
@@ -110,7 +109,7 @@ exports[`Rewrite react-native to react-native-web require "react-native": requir
const ReactNative = require('react-native');
const { View } = require('react-native');
const { StyleSheet, TouchableOpacity } = require('react-native');
const { StyleSheet, Pressable } = require('react-native');
↓ ↓ ↓ ↓ ↓ ↓
@@ -121,8 +120,8 @@ const View = require('react-native-web/dist/cjs/exports/View').default;
const StyleSheet =
require('react-native-web/dist/cjs/exports/StyleSheet').default;
const TouchableOpacity =
require('react-native-web/dist/cjs/exports/TouchableOpacity').default;
const Pressable =
require('react-native-web/dist/cjs/exports/Pressable').default;
`;
@@ -131,7 +130,7 @@ exports[`Rewrite react-native to react-native-web require "react-native-web": re
const ReactNative = require('react-native-web');
const { unstable_createElement } = require('react-native-web');
const { StyleSheet, View, TouchableOpacity, processColor } = require('react-native-web');
const { StyleSheet, View, Pressable, processColor } = require('react-native-web');
↓ ↓ ↓ ↓ ↓ ↓
@@ -144,8 +143,7 @@ const StyleSheet = require('react-native-web/dist/exports/StyleSheet').default;
const View = require('react-native-web/dist/exports/View').default;
const TouchableOpacity =
require('react-native-web/dist/exports/TouchableOpacity').default;
const Pressable = require('react-native-web/dist/exports/Pressable').default;
const processColor =
require('react-native-web/dist/exports/processColor').default;
@@ -24,7 +24,7 @@ import * as ReactNativeModules from 'react-native';`,
{
title: 'import from "react-native-web"',
code: `import { unstable_createElement } from 'react-native-web';
import { StyleSheet, View, TouchableOpacity, processColor } from 'react-native-web';
import { StyleSheet, View, Pressable, processColor } from 'react-native-web';
import * as ReactNativeModules from 'react-native-web';`,
snapshot: true
},
@@ -45,14 +45,14 @@ export { StyleSheet, Text, unstable_createElement } from 'react-native-web';`,
title: 'require "react-native"',
code: `const ReactNative = require('react-native');
const { View } = require('react-native');
const { StyleSheet, TouchableOpacity } = require('react-native');`,
const { StyleSheet, Pressable } = require('react-native');`,
snapshot: true
},
{
title: 'require "react-native"',
code: `const ReactNative = require('react-native');
const { View } = require('react-native');
const { StyleSheet, TouchableOpacity } = require('react-native');`,
const { StyleSheet, Pressable } = require('react-native');`,
snapshot: true,
pluginOptions: { commonjs: true }
},
@@ -60,7 +60,7 @@ const { StyleSheet, TouchableOpacity } = require('react-native');`,
title: 'require "react-native-web"',
code: `const ReactNative = require('react-native-web');
const { unstable_createElement } = require('react-native-web');
const { StyleSheet, View, TouchableOpacity, processColor } = require('react-native-web');`,
const { StyleSheet, View, Pressable, processColor } = require('react-native-web');`,
snapshot: true
}
];
+5 -11
View File
@@ -1,11 +1,5 @@
import Benchmark from './Benchmark';
import {
Picker,
StyleSheet,
ScrollView,
TouchableOpacity,
View
} from 'react-native';
import { Picker, StyleSheet, ScrollView, Pressable, View } from 'react-native';
import React, { Component } from 'react';
import Button from './Button';
import { IconClear, IconEye } from './Icons';
@@ -100,9 +94,9 @@ export default class App extends Component {
<View style={styles.grow}>
<View style={styles.listBar}>
<View style={styles.iconClearContainer}>
<TouchableOpacity onPress={this._handleClear}>
<Pressable onPress={this._handleClear}>
<IconClear />
</TouchableOpacity>
</Pressable>
</View>
</View>
<ScrollView ref={this._setScrollRef} style={styles.grow}>
@@ -134,9 +128,9 @@ export default class App extends Component {
viewPanel={
<View style={styles.viewPanel}>
<View style={styles.iconEyeContainer}>
<TouchableOpacity onPress={this._handleVisuallyHideBenchmark}>
<Pressable onPress={this._handleVisuallyHideBenchmark}>
<IconEye style={styles.iconEye} />
</TouchableOpacity>
</Pressable>
</View>
<Provider>
@@ -1,58 +0,0 @@
---
title: Button
date: Last Modified
permalink: /docs/button/index.html
eleventyNavigation:
key: Button
parent: Components
---
{% import "fragments/macros.html" as macro with context %}
:::lead
A basic button component. Supports a minimal level of customization.
:::
You can also build a custom button using `Pressable`.
```jsx
import { Button } from 'react-native';
<Button {...props} />;
```
---
## API
### Props
{% call macro.prop('accessibilityLabel', '?string') %}
Equivalent to [aria-label](https://www.w3.org/TR/wai-aria-1.2/#aria-label).
{% endcall %}
{% call macro.prop('color', '?string') %}
Default `"#2196F3"`. Set the background color of the button.
{% endcall %}
{% call macro.prop('disabled', '?boolean') %}
Prevent all interactions with the button.
{% endcall %}
{% call macro.prop('onPress', '?(e: ClickEvent) => void') %}
Called when the button is pressed by a pointer or keyboard.
{% endcall %}
{% call macro.prop('testID', '?string') %}
Set the test selector label (via `data-testid`).
{% endcall %}
{% call macro.prop('title', 'string') %}
Set the text content of the button.
{% endcall %}
---
## Examples
{{ macro.codesandbox('button') }}
@@ -1,25 +0,0 @@
---
title: Touchables
date: Last Modified
permalink: /docs/touchables/index.html
eleventyNavigation:
key: Touchables
parent: Components
---
{% import "fragments/macros.html" as macro with context %}
:::lead
Components for making views respond to touch, mouse, and keyboard on web.
:::
Please refer to the React Native documentation below:
* [TouchableHighlight](https://reactnative.dev/docs/touchablehighlight)
* [TouchableOpacity](https://reactnative.dev/docs/touchableopacity)
* [TouchableWithoutFeedback](https://reactnative.dev/docs/touchablewithoutfeedback)
:::callout
**Did you know?** The [Pressable]({{ '/docs/pressable' | url }}) component is a more accessible, flexible, and future-proof way to handle tap and click interactions with React Native.
:::
@@ -1,36 +0,0 @@
import React from 'react';
import { Button, StyleSheet, View } from 'react-native';
import Example from '../../shared/example';
const emptyFunction = () => {};
function Divider() {
return <View style={styles.divider} />;
}
export default function ButtonPage() {
const disabledOnPress = () => {
console.error('Disabled button should not trigger onPress!');
};
return (
<Example title="Button">
<Divider />
<Button onPress={emptyFunction} title="Button" />
<Divider />
<Button color="#17BF63" onPress={emptyFunction} title="Button" />
<Divider />
<Button color="#794BC4" onPress={emptyFunction} title="Button" />
<Divider />
<Button color="#E0245E" onPress={emptyFunction} title="Button" />
<Divider />
<Button disabled onPress={disabledOnPress} title="Disabled button" />
</Example>
);
}
const styles = StyleSheet.create({
divider: {
height: '1rem'
}
});
+3 -3
View File
@@ -1,7 +1,7 @@
import React from 'react';
import { StyleSheet } from 'react-native';
import Example from '../../shared/example';
import { FlatList, Text, TouchableOpacity, View } from 'react-native-web';
import { FlatList, Text, Pressable, View } from 'react-native-web';
const multiSelectData = ['First', 'Second', 'Third'].map((title, id) => ({
id,
@@ -18,13 +18,13 @@ class MyListItem extends React.PureComponent {
render() {
const textColor = this.props.selected ? 'red' : 'black';
return (
<TouchableOpacity onPress={this._onPress}>
<Pressable onPress={this._onPress}>
<View>
<Text style={[styles.listItemText, { color: textColor }]}>
{this.props.title}
</Text>
</View>
</TouchableOpacity>
</Pressable>
);
}
}
@@ -4,7 +4,7 @@ import {
ScrollView,
StyleSheet,
Text,
TouchableOpacity,
Pressable,
View
} from 'react-native';
import Example from '../../shared/example';
@@ -13,9 +13,9 @@ const ITEMS = [...Array(12)].map((_, i) => `Item ${i}`);
function createItemRow(msg, index) {
return (
<TouchableOpacity key={index} style={[styles.item]}>
<Pressable key={index} style={[styles.item]}>
<Text style={styles.text}>{msg}</Text>
</TouchableOpacity>
</Pressable>
);
}
@@ -1,78 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`components/Button prop "accessibilityLabel" 1`] = `
<button
aria-label="accessibility label"
class="css-view-175oi2r r-transitionProperty-1i6wzkk r-userSelect-lrvibr r-cursor-1loqt21 r-touchAction-1otgn73 r-backgroundColor-14sbq61 r-borderRadius-1jkafct"
role="button"
style="transition-duration: 0s;"
type="button"
>
<div
class="css-text-1rynq56 r-color-jwli3a r-fontWeight-majxgm r-padding-edyy15 r-textAlign-q4m81j r-textTransform-tsynxw"
dir="auto"
/>
</button>
`;
exports[`components/Button prop "color" 1`] = `
<button
class="css-view-175oi2r r-transitionProperty-1i6wzkk r-userSelect-lrvibr r-cursor-1loqt21 r-touchAction-1otgn73 r-borderRadius-1jkafct"
role="button"
style="background-color: rgb(0, 0, 255); transition-duration: 0s;"
type="button"
>
<div
class="css-text-1rynq56 r-color-jwli3a r-fontWeight-majxgm r-padding-edyy15 r-textAlign-q4m81j r-textTransform-tsynxw"
dir="auto"
/>
</button>
`;
exports[`components/Button prop "disabled" 1`] = `
<button
aria-disabled="true"
class="css-view-175oi2r r-transitionProperty-1i6wzkk r-userSelect-lrvibr r-borderRadius-1jkafct r-backgroundColor-11mpjr4 r-pointerEvents-633pao"
disabled=""
role="button"
style="transition-duration: 0s;"
tabindex="-1"
type="button"
>
<div
class="css-text-1rynq56 r-fontWeight-majxgm r-padding-edyy15 r-textAlign-q4m81j r-textTransform-tsynxw r-color-c68hjy"
dir="auto"
/>
</button>
`;
exports[`components/Button prop "testID" 1`] = `
<button
class="css-view-175oi2r r-transitionProperty-1i6wzkk r-userSelect-lrvibr r-cursor-1loqt21 r-touchAction-1otgn73 r-backgroundColor-14sbq61 r-borderRadius-1jkafct"
data-testid="123"
role="button"
style="transition-duration: 0s;"
type="button"
>
<div
class="css-text-1rynq56 r-color-jwli3a r-fontWeight-majxgm r-padding-edyy15 r-textAlign-q4m81j r-textTransform-tsynxw"
dir="auto"
/>
</button>
`;
exports[`components/Button prop "title" 1`] = `
<button
class="css-view-175oi2r r-transitionProperty-1i6wzkk r-userSelect-lrvibr r-cursor-1loqt21 r-touchAction-1otgn73 r-backgroundColor-14sbq61 r-borderRadius-1jkafct"
role="button"
style="transition-duration: 0s;"
type="button"
>
<div
class="css-text-1rynq56 r-color-jwli3a r-fontWeight-majxgm r-padding-edyy15 r-textAlign-q4m81j r-textTransform-tsynxw"
dir="auto"
>
Click me
</div>
</button>
`;
@@ -1,48 +0,0 @@
import Button from '..';
import React from 'react';
import { createEventTarget } from 'dom-event-testing-library';
import { act, render } from '@testing-library/react';
describe('components/Button', () => {
test('prop "accessibilityLabel"', () => {
const { container } = render(
<Button accessibilityLabel="accessibility label" title="" />
);
expect(container.firstChild).toMatchSnapshot();
});
test('prop "color"', () => {
const color = 'rgb(0, 0, 255)';
const { container } = render(<Button color={color} title="" />);
expect(container.firstChild).toMatchSnapshot();
});
test('prop "disabled"', () => {
const { container } = render(<Button disabled={true} title="" />);
expect(container.firstChild).toMatchSnapshot();
});
test('prop "onPress"', () => {
const onPress = jest.fn();
const ref = React.createRef();
act(() => {
render(<Button onPress={onPress} ref={ref} title="" />);
});
const target = createEventTarget(ref.current);
act(() => {
target.pointerdown({ button: 0 });
target.pointerup({ button: 0 });
});
expect(onPress).toBeCalled();
});
test('prop "testID"', () => {
const { container } = render(<Button testID="123" title="" />);
expect(container.firstChild).toMatchSnapshot();
});
test('prop "title"', () => {
const { container } = render(<Button title="Click me" />);
expect(container.firstChild).toMatchSnapshot();
});
});
+3
View File
@@ -12,6 +12,7 @@ import * as React from 'react';
import StyleSheet from '../StyleSheet';
import TouchableOpacity from '../TouchableOpacity';
import Text from '../Text';
import { warnOnce } from '../../modules/warnOnce';
type ButtonProps = {|
accessibilityLabel?: ?string,
@@ -26,6 +27,8 @@ const Button: React.AbstractComponent<
ButtonProps,
React.ElementRef<typeof TouchableOpacity>
> = React.forwardRef((props, forwardedRef) => {
warnOnce('Button', 'Button is deprecated. Please use Pressable.');
const { accessibilityLabel, color, disabled, onPress, testID, title } = props;
return (
@@ -18,6 +18,7 @@ import Position from './Position';
import React from 'react';
import UIManager from '../UIManager';
import View from '../View';
import { warnOnce } from '../../modules/warnOnce';
type Event = Object;
type PressEvent = Object;
@@ -371,6 +372,11 @@ const LONG_PRESS_ALLOWED_MOVEMENT = 10;
const TouchableMixin = {
// HACK (part 1): basic support for touchable interactions using a keyboard
componentDidMount: function () {
warnOnce(
'TouchableMixin',
'TouchableMixin is deprecated. Please use Pressable.'
);
const touchableNode = this.getTouchableNode && this.getTouchableNode();
if (touchableNode && touchableNode.addEventListener) {
this._touchableBlurListener = (e) => {
@@ -20,6 +20,7 @@ import useMergeRefs from '../../modules/useMergeRefs';
import usePressEvents from '../../modules/usePressEvents';
import StyleSheet from '../StyleSheet';
import View from '../View';
import { warnOnce } from '../../modules/warnOnce';
type ViewStyle = $PropertyType<ViewProps, 'style'>;
@@ -70,6 +71,11 @@ function hasPressHandler(props): boolean {
* If you wish to have several child components, wrap them in a View.
*/
function TouchableHighlight(props: Props, forwardedRef): React.Node {
warnOnce(
'TouchableHighlight',
'TouchableHighlight is deprecated. Please use Pressable.'
);
const {
activeOpacity,
children,
@@ -19,6 +19,7 @@ import useMergeRefs from '../../modules/useMergeRefs';
import usePressEvents from '../../modules/usePressEvents';
import StyleSheet from '../StyleSheet';
import View from '../View';
import { warnOnce } from '../../modules/warnOnce';
type ViewStyle = $PropertyType<ViewProps, 'style'>;
@@ -33,6 +34,11 @@ type Props = $ReadOnly<{|
* On press down, the opacity of the wrapped view is decreased, dimming it.
*/
function TouchableOpacity(props: Props, forwardedRef): React.Node {
warnOnce(
'TouchableOpacity',
'TouchableOpacity is deprecated. Please use Pressable.'
);
const {
activeOpacity,
delayPressIn,
@@ -18,6 +18,7 @@ import { useMemo, useRef } from 'react';
import pick from '../../modules/pick';
import useMergeRefs from '../../modules/useMergeRefs';
import usePressEvents from '../../modules/usePressEvents';
import { warnOnce } from '../../modules/warnOnce';
export type Props = $ReadOnly<{|
accessibilityLabel?: $PropertyType<ViewProps, 'accessibilityLabel'>,
@@ -63,6 +64,11 @@ const forwardPropsList = {
const pickProps = (props) => pick(props, forwardPropsList);
function TouchableWithoutFeedback(props: Props, forwardedRef): React.Node {
warnOnce(
'TouchableWithoutFeedback',
'TouchableWithoutFeedback is deprecated. Please use Pressable.'
);
const {
delayPressIn,
delayPressOut,