Add filtering to e2e tests (#22828)

Summary:
This PR adds filtering for e2e test examples using the new examples filter introduced in https://github.com/facebook/react-native/pull/22777

To do that we:
- Add a `testID` to `RNTesterExampleFilter` to select an example
- Refactor a few examples to export multiple examples for filtering
- Update all tests to filter by example title
Pull Request resolved: https://github.com/facebook/react-native/pull/22828

Reviewed By: TheSavior

Differential Revision: D13562664

Pulled By: rickhanlonii

fbshipit-source-id: efb0ca8050c1ca5c10d96bd77d35dd1143c3a3b3
This commit is contained in:
Rick Hanlon 2018-12-31 04:30:58 -08:00 committed by Facebook Github Bot
parent 9db0050635
commit 34ee8250b5
13 changed files with 483 additions and 363 deletions

View File

@ -9,34 +9,36 @@
*/ */
/* global device, element, by, expect */ /* global device, element, by, expect */
const {
openComponentWithLabel,
openExampleWithTitle,
} = require('../e2e-helpers');
describe('Button', () => { describe('Button', () => {
beforeAll(async () => { beforeAll(async () => {
await device.reloadReactNative(); await device.reloadReactNative();
await element(by.id('explorer_search')).replaceText('<Button>'); await openComponentWithLabel(
await element( '<Button>',
by.label('<Button> Simple React Native button component.'), '<Button> Simple React Native button component.',
).tap(); );
});
afterAll(async () => {
//TODO - remove app state persistency, till then, we must go back to main screen,
await element(by.label('Back')).tap();
}); });
it('Simple button should be tappable', async () => { it('Simple button should be tappable', async () => {
await openExampleWithTitle('Simple Button');
await element(by.id('simple_button')).tap(); await element(by.id('simple_button')).tap();
await expect(element(by.text('Simple has been pressed!'))).toBeVisible(); await expect(element(by.text('Simple has been pressed!'))).toBeVisible();
await element(by.text('OK')).tap(); await element(by.text('OK')).tap();
}); });
it('Adjusted color button should be tappable', async () => { it('Adjusted color button should be tappable', async () => {
await openExampleWithTitle('Adjusted color');
await element(by.id('purple_button')).tap(); await element(by.id('purple_button')).tap();
await expect(element(by.text('Purple has been pressed!'))).toBeVisible(); await expect(element(by.text('Purple has been pressed!'))).toBeVisible();
await element(by.text('OK')).tap(); await element(by.text('OK')).tap();
}); });
it("Two buttons with JustifyContent:'space-between' should be tappable", async () => { it("Two buttons with JustifyContent:'space-between' should be tappable", async () => {
await openExampleWithTitle('Fit to text layout');
await element(by.id('left_button')).tap(); await element(by.id('left_button')).tap();
await expect(element(by.text('Left has been pressed!'))).toBeVisible(); await expect(element(by.text('Left has been pressed!'))).toBeVisible();
await element(by.text('OK')).tap(); await element(by.text('OK')).tap();
@ -47,6 +49,7 @@ describe('Button', () => {
}); });
it('Disabled button should not interact', async () => { it('Disabled button should not interact', async () => {
await openExampleWithTitle('Disabled Button');
await element(by.id('disabled_button')).tap(); await element(by.id('disabled_button')).tap();
await expect( await expect(
element(by.text('Disabled has been pressed!')), element(by.text('Disabled has been pressed!')),

View File

@ -8,23 +8,24 @@
* @format * @format
*/ */
/* global element, by, expect */ /* global element, by, expect, device */
const {
openComponentWithLabel,
openExampleWithTitle,
} = require('../e2e-helpers');
describe('DatePickerIOS', () => { describe('DatePickerIOS', () => {
beforeAll(async () => { beforeAll(async () => {
await element(by.id('explorer_search')).replaceText('<DatePickerIOS>'); await device.reloadReactNative();
await element( await openComponentWithLabel(
by.label( '<DatePickerIOS>',
'<DatePickerIOS> Select dates and times using the native UIDatePicker.', '<DatePickerIOS> Select dates and times using the native UIDatePicker.',
), );
).tap();
});
afterAll(async () => {
await element(by.label('Back')).tap();
}); });
it('Should change indicator with datetime picker', async () => { it('Should change indicator with datetime picker', async () => {
await openExampleWithTitle('Date and time picker');
const testID = 'date-and-time'; const testID = 'date-and-time';
const indicatorID = 'date-and-time-indicator'; const indicatorID = 'date-and-time-indicator';
@ -45,6 +46,7 @@ describe('DatePickerIOS', () => {
}); });
it('Should change indicator with date-only picker', async () => { it('Should change indicator with date-only picker', async () => {
await openExampleWithTitle('Date only');
const testID = 'date-only'; const testID = 'date-only';
const indicatorID = 'date-and-time-indicator'; const indicatorID = 'date-and-time-indicator';

View File

@ -8,23 +8,23 @@
* @format * @format
*/ */
/* global element, by, expect */ /* global device, element, by, expect */
const {
openComponentWithLabel,
openExampleWithTitle,
} = require('../e2e-helpers');
describe('Picker', () => { describe('Picker', () => {
beforeAll(async () => { beforeAll(async () => {
await element(by.id('explorer_search')).replaceText('<Picker>'); await device.reloadReactNative();
await element( await openComponentWithLabel(
by.label( '<Picker>',
'<Picker> Provides multiple options to choose from, using either a dropdown menu or a dialog.', '<Picker> Provides multiple options to choose from, using either a dropdown menu or a dialog.',
), );
).tap();
});
afterAll(async () => {
await element(by.label('Back')).tap();
}); });
it('should be selectable by ID', async () => { it('should be selectable by ID', async () => {
await openExampleWithTitle('Basic picker');
await expect(element(by.id('basic-picker'))).toBeVisible(); await expect(element(by.id('basic-picker'))).toBeVisible();
}); });
}); });

View File

@ -11,12 +11,20 @@
/* global device, element, by, expect */ /* global device, element, by, expect */
const jestExpect = require('expect'); const jestExpect = require('expect');
const {
openComponentWithLabel,
openExampleWithTitle,
} = require('../e2e-helpers');
describe('Switch', () => { describe('Switch', () => {
beforeEach(async () => { beforeAll(async () => {
await device.reloadReactNative(); await device.reloadReactNative();
await element(by.id('explorer_search')).replaceText('<Switch>'); await openComponentWithLabel('<Switch>', '<Switch> Native boolean input');
await element(by.label('<Switch> Native boolean input')).tap(); });
describe('Switches can be set to true or false', () => {
beforeAll(async () => {
await openExampleWithTitle('Switches can be set to true or false');
}); });
it('Switch that starts off should switch', async () => { it('Switch that starts off should switch', async () => {
@ -40,6 +48,12 @@ describe('Switch', () => {
await expect(element(by.id(testID))).toHaveValue('0'); await expect(element(by.id(testID))).toHaveValue('0');
await expect(element(by.id(indicatorID))).toHaveText('Off'); await expect(element(by.id(indicatorID))).toHaveText('Off');
}); });
});
describe('Switches can be disabled', () => {
beforeAll(async () => {
await openExampleWithTitle('Switches can be disabled');
});
it('disabled switch should not toggle', async () => { it('disabled switch should not toggle', async () => {
const onTestID = 'disabled-initial-on'; const onTestID = 'disabled-initial-on';
@ -78,4 +92,5 @@ describe('Switch', () => {
await expect(element(by.id(offTestID))).toHaveValue('0'); await expect(element(by.id(offTestID))).toHaveValue('0');
await expect(element(by.id(offIndicatorID))).toHaveText('Off'); await expect(element(by.id(offIndicatorID))).toHaveText('Off');
}); });
});
}); });

View File

@ -8,22 +8,23 @@
* @format * @format
*/ */
/* global element, by, expect */ /* global device, element, by, expect */
const {
openComponentWithLabel,
openExampleWithTitle,
} = require('../e2e-helpers');
describe('Touchable', () => { describe('Touchable', () => {
beforeAll(async () => { beforeAll(async () => {
await element(by.id('explorer_search')).replaceText('<Touchable*'); await device.reloadReactNative();
await element( await openComponentWithLabel(
by.label('<Touchable*> and onPress Touchable and onPress examples.'), '<Touchable*',
).tap(); '<Touchable*> and onPress Touchable and onPress examples.',
}); );
afterAll(async () => {
//TODO - remove app state persistency, till then, we must go back to main screen,
await element(by.label('Back')).tap();
}); });
it('Touchable Highlight should be tappable', async () => { it('Touchable Highlight should be tappable', async () => {
await openExampleWithTitle('<TouchableHighlight>');
const buttonID = 'touchable_highlight_image_button'; const buttonID = 'touchable_highlight_image_button';
const button2ID = 'touchable_highlight_text_button'; const button2ID = 'touchable_highlight_text_button';
const consoleID = 'touchable_highlight_console'; const consoleID = 'touchable_highlight_console';
@ -45,6 +46,8 @@ describe('Touchable', () => {
}); });
it('Touchable Without Feedback should be tappable', async () => { it('Touchable Without Feedback should be tappable', async () => {
await openExampleWithTitle('<TouchableWithoutFeedback>');
const buttonID = 'touchable_without_feedback_button'; const buttonID = 'touchable_without_feedback_button';
const consoleID = 'touchable_without_feedback_console'; const consoleID = 'touchable_without_feedback_console';
@ -60,6 +63,8 @@ describe('Touchable', () => {
}); });
it('Text should be tappable', async () => { it('Text should be tappable', async () => {
await openExampleWithTitle('<Text onPress={fn}> with highlight');
const buttonID = 'tappable_text'; const buttonID = 'tappable_text';
const consoleID = 'tappable_text_console'; const consoleID = 'tappable_text_console';

View File

@ -0,0 +1,24 @@
/**
* 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.
*
* @emails oncall+react_native
* @format
*/
/* global element, by, expect */
// Will open a component example from the root list
// by filtering by component and then tapping on the label
exports.openComponentWithLabel = async (component, label) => {
await element(by.id('explorer_search')).replaceText(component);
await element(by.label(label)).tap();
};
// Will open an individual example for a component
// by filtering on the example title
exports.openExampleWithTitle = async title => {
await element(by.id('example_search')).replaceText(title);
};

View File

@ -14,20 +14,21 @@ const React = require('react');
const ReactNative = require('react-native'); const ReactNative = require('react-native');
const {DatePickerIOS, StyleSheet, Text, TextInput, View} = ReactNative; const {DatePickerIOS, StyleSheet, Text, TextInput, View} = ReactNative;
class DatePickerExample extends React.Component< type State = {|
$FlowFixMeProps, date: Date,
$FlowFixMeState, timeZoneOffsetInHours: number,
> { |};
static defaultProps = {
type Props = {|
children: (State, (Date) => void) => React.Node,
|};
class WithDatePickerData extends React.Component<Props, State> {
state = {
date: new Date(), date: new Date(),
timeZoneOffsetInHours: (-1 * new Date().getTimezoneOffset()) / 60, timeZoneOffsetInHours: (-1 * new Date().getTimezoneOffset()) / 60,
}; };
state = {
date: this.props.date,
timeZoneOffsetInHours: this.props.timeZoneOffsetInHours,
};
onDateChange = date => { onDateChange = date => {
this.setState({date: date}); this.setState({date: date});
}; };
@ -63,37 +64,18 @@ class DatePickerExample extends React.Component<
/> />
<Text> hours from UTC</Text> <Text> hours from UTC</Text>
</WithLabel> </WithLabel>
<Heading label="Date + time picker" /> {this.props.children(this.state, this.onDateChange)}
<DatePickerIOS
testID="date-and-time"
date={this.state.date}
mode="datetime"
timeZoneOffsetInMinutes={this.state.timeZoneOffsetInHours * 60}
onDateChange={this.onDateChange}
/>
<Heading label="Date picker" />
<DatePickerIOS
testID="date-only"
date={this.state.date}
mode="date"
timeZoneOffsetInMinutes={this.state.timeZoneOffsetInHours * 60}
onDateChange={this.onDateChange}
/>
<Heading label="Time picker, 10-minute interval" />
<DatePickerIOS
testID="time-only"
date={this.state.date}
mode="time"
timeZoneOffsetInMinutes={this.state.timeZoneOffsetInHours * 60}
onDateChange={this.onDateChange}
minuteInterval={10}
/>
</View> </View>
); );
} }
} }
class WithLabel extends React.Component<$FlowFixMeProps> { type LabelProps = {|
label: string,
children: React.Node,
|};
class WithLabel extends React.Component<LabelProps> {
render() { render() {
return ( return (
<View style={styles.labelContainer}> <View style={styles.labelContainer}>
@ -106,28 +88,6 @@ class WithLabel extends React.Component<$FlowFixMeProps> {
} }
} }
class Heading extends React.Component<$FlowFixMeProps> {
render() {
return (
<View style={styles.headingContainer}>
<Text style={styles.heading}>{this.props.label}</Text>
</View>
);
}
}
exports.displayName = (undefined: ?string);
exports.title = '<DatePickerIOS>';
exports.description = 'Select dates and times using the native UIDatePicker.';
exports.examples = [
{
title: '<DatePickerIOS>',
render: function(): React.Element<any> {
return <DatePickerExample />;
},
},
];
const styles = StyleSheet.create({ const styles = StyleSheet.create({
textinput: { textinput: {
height: 26, height: 26,
@ -149,12 +109,63 @@ const styles = StyleSheet.create({
label: { label: {
fontWeight: '500', fontWeight: '500',
}, },
headingContainer: {
padding: 4,
backgroundColor: '#f6f7f8',
},
heading: {
fontWeight: '500',
fontSize: 14,
},
}); });
exports.title = '<DatePickerIOS>';
exports.description = 'Select dates and times using the native UIDatePicker.';
exports.examples = [
{
title: 'Date and time picker',
render: function(): React.Element<any> {
return (
<WithDatePickerData>
{(state, onDateChange) => (
<DatePickerIOS
testID="date-and-time"
date={state.date}
mode="datetime"
timeZoneOffsetInMinutes={state.timeZoneOffsetInHours * 60}
onDateChange={onDateChange}
/>
)}
</WithDatePickerData>
);
},
},
{
title: 'Date only picker',
render: function(): React.Element<any> {
return (
<WithDatePickerData>
{(state, onDateChange) => (
<DatePickerIOS
testID="date-only"
date={state.date}
mode="date"
timeZoneOffsetInMinutes={state.timeZoneOffsetInHours * 60}
onDateChange={onDateChange}
/>
)}
</WithDatePickerData>
);
},
},
{
title: 'Time only picker, 10-minute interval',
render: function(): React.Element<any> {
return (
<WithDatePickerData>
{(state, onDateChange) => (
<DatePickerIOS
testID="time-only"
date={state.date}
mode="time"
timeZoneOffsetInMinutes={state.timeZoneOffsetInHours * 60}
onDateChange={onDateChange}
/>
)}
</WithDatePickerData>
);
},
},
];

View File

@ -13,83 +13,106 @@
const React = require('react'); const React = require('react');
const ReactNative = require('react-native'); const ReactNative = require('react-native');
const StyleSheet = require('StyleSheet'); const StyleSheet = require('StyleSheet');
const RNTesterBlock = require('RNTesterBlock');
const RNTesterPage = require('RNTesterPage');
const {Picker, Text} = ReactNative; const {Picker, Text} = ReactNative;
const Item = Picker.Item; const Item = Picker.Item;
class PickerExample extends React.Component<{}, $FlowFixMeState> { type State = {
static title = '<Picker>'; value: string | number,
static description = };
'Provides multiple options to choose from, using either a dropdown menu or a dialog.';
class BasicPickerExample extends React.Component<{}, State> {
state = { state = {
selected1: 'key1', value: 'key1',
selected2: 'key1',
selected3: 'key1',
color: 'red',
mode: Picker.MODE_DIALOG,
}; };
render() { render() {
return ( return (
<RNTesterPage title="<Picker>">
<RNTesterBlock title="Basic Picker">
<Picker <Picker
testID="basic-picker" testID="basic-picker"
style={styles.picker} style={styles.picker}
selectedValue={this.state.selected1} selectedValue={this.state.value}
onValueChange={this.onValueChange.bind(this, 'selected1')}> onValueChange={v => this.setState({value: v})}>
<Item label="hello" value="key0" /> <Item label="hello" value="key0" />
<Item label="world" value="key1" /> <Item label="world" value="key1" />
</Picker> </Picker>
</RNTesterBlock> );
<RNTesterBlock title="Disabled picker"> }
}
class DisabledPickerExample extends React.Component<{}, State> {
state = {
value: 'key1',
};
render() {
return (
<Picker <Picker
style={styles.picker} style={styles.picker}
enabled={false} enabled={false}
selectedValue={this.state.selected1}> selectedValue={this.state.value}>
<Item label="hello" value="key0" /> <Item label="hello" value="key0" />
<Item label="world" value="key1" /> <Item label="world" value="key1" />
</Picker> </Picker>
</RNTesterBlock> );
<RNTesterBlock title="Dropdown Picker"> }
}
class DropdownPickerExample extends React.Component<{}, State> {
state = {
value: 'key1',
};
render() {
return (
<Picker <Picker
style={styles.picker} style={styles.picker}
selectedValue={this.state.selected2} selectedValue={this.state.value}
onValueChange={this.onValueChange.bind(this, 'selected2')} onValueChange={v => this.setState({value: v})}
mode="dropdown"> mode="dropdown">
<Item label="hello" value="key0" /> <Item label="hello" value="key0" />
<Item label="world" value="key1" /> <Item label="world" value="key1" />
</Picker> </Picker>
</RNTesterBlock> );
<RNTesterBlock title="Picker with prompt message"> }
}
class PromptPickerExample extends React.Component<{}, State> {
state = {
value: 'key1',
};
render() {
return (
<Picker <Picker
style={styles.picker} style={styles.picker}
selectedValue={this.state.selected3} selectedValue={this.state.value}
onValueChange={this.onValueChange.bind(this, 'selected3')} onValueChange={v => this.setState({value: v})}
prompt="Pick one, just one"> prompt="Pick one, just one">
<Item label="hello" value="key0" /> <Item label="hello" value="key0" />
<Item label="world" value="key1" /> <Item label="world" value="key1" />
</Picker> </Picker>
</RNTesterBlock> );
<RNTesterBlock title="Picker with no listener"> }
<Picker style={styles.picker}> }
<Item label="hello" value="key0" />
<Item label="world" value="key1" /> type ColorState = {
</Picker> color: string | number,
<Text> };
Cannot change the value of this picker because it doesn't update
selectedValue. class ColorPickerExample extends React.Component<{}, ColorState> {
</Text> state = {
</RNTesterBlock> color: 'red',
<RNTesterBlock title="Colorful pickers"> };
render() {
return (
<>
<Picker <Picker
style={[styles.picker, {color: 'white', backgroundColor: '#333'}]} style={[styles.picker, {color: 'white', backgroundColor: '#333'}]}
selectedValue={this.state.color} selectedValue={this.state.color}
onValueChange={this.onValueChange.bind(this, 'color')} onValueChange={v => this.setState({color: v})}
mode="dropdown"> mode="dropdown">
<Item label="red" color="red" value="red" /> <Item label="red" color="red" value="red" />
<Item label="green" color="green" value="green" /> <Item label="green" color="green" value="green" />
@ -98,30 +121,15 @@ class PickerExample extends React.Component<{}, $FlowFixMeState> {
<Picker <Picker
style={styles.picker} style={styles.picker}
selectedValue={this.state.color} selectedValue={this.state.color}
onValueChange={this.onValueChange.bind(this, 'color')} onValueChange={v => this.setState({color: v})}
mode="dialog"> mode="dialog">
<Item label="red" color="red" value="red" /> <Item label="red" color="red" value="red" />
<Item label="green" color="green" value="green" /> <Item label="green" color="green" value="green" />
<Item label="blue" color="blue" value="blue" /> <Item label="blue" color="blue" value="blue" />
</Picker> </Picker>
</RNTesterBlock> </>
</RNTesterPage>
); );
} }
changeMode = () => {
const newMode =
this.state.mode === Picker.MODE_DIALOG
? Picker.MODE_DROPDOWN
: Picker.MODE_DIALOG;
this.setState({mode: newMode});
};
onValueChange = (key: string, value: string | number) => {
const newState = {};
newState[key] = value;
this.setState(newState);
};
} }
const styles = StyleSheet.create({ const styles = StyleSheet.create({
@ -130,4 +138,55 @@ const styles = StyleSheet.create({
}, },
}); });
module.exports = PickerExample; exports.title = '<Picker>';
exports.description =
'Provides multiple options to choose from, using either a dropdown menu or a dialog.';
exports.examples = [
{
title: 'Basic Picker',
render: function(): React.Element<typeof BasicPickerExample> {
return <BasicPickerExample />;
},
},
{
title: 'Disabled Picker',
render: function(): React.Element<typeof DisabledPickerExample> {
return <DisabledPickerExample />;
},
},
{
title: 'Dropdown Picker',
render: function(): React.Element<typeof DropdownPickerExample> {
return <DropdownPickerExample />;
},
},
{
title: 'Picker with prompt message',
render: function(): React.Element<typeof PromptPickerExample> {
return <PromptPickerExample />;
},
},
{
title: 'Picker with no listener',
render: function(): React.Element<typeof PromptPickerExample> {
return (
<>
<Picker style={styles.picker}>
<Item label="hello" value="key0" />
<Item label="world" value="key1" />
</Picker>
<Text>
Cannot change the value of this picker because it doesn't update
selectedValue.
</Text>
</>
);
},
},
{
title: 'Colorful pickers',
render: function(): React.Element<typeof ColorPickerExample> {
return <ColorPickerExample />;
},
},
];

View File

@ -56,6 +56,7 @@ class RNTesterExampleContainer extends React.Component {
return ( return (
<RNTesterPage title={this.props.title}> <RNTesterPage title={this.props.title}>
<RNTesterExampleFilter <RNTesterExampleFilter
testID="example_search"
sections={sections} sections={sections}
filter={filter} filter={filter}
render={({filteredSections}) => render={({filteredSections}) =>

View File

@ -20,6 +20,7 @@ type Props = {
render: Function, render: Function,
sections: Object, sections: Object,
disableSearch?: boolean, disableSearch?: boolean,
testID?: string,
}; };
type State = { type State = {
@ -75,7 +76,7 @@ class RNTesterExampleFilter extends React.Component<Props, State> {
placeholder="Search..." placeholder="Search..."
underlineColorAndroid="transparent" underlineColorAndroid="transparent"
style={styles.searchTextInput} style={styles.searchTextInput}
testID="explorer_search" testID={this.props.testID}
value={this.state.filter} value={this.state.filter}
/> />
</View> </View>

View File

@ -94,6 +94,7 @@ class RNTesterExampleList extends React.Component<Props, $FlowFixMeState> {
<View style={[styles.listContainer, this.props.style]}> <View style={[styles.listContainer, this.props.style]}>
{this._renderTitleRow()} {this._renderTitleRow()}
<RNTesterExampleFilter <RNTesterExampleFilter
testID="explorer_search"
sections={sections} sections={sections}
filter={filter} filter={filter}
render={({filteredSections}) => ( render={({filteredSections}) => (

View File

@ -198,7 +198,10 @@ class EventSwitchExample extends React.Component<{}, $FlowFixMeState> {
} }
} }
const examples = [ exports.title = '<Switch>';
exports.displayName = 'SwitchExample';
exports.description = 'Native boolean input';
exports.examples = [
{ {
title: 'Switches can be set to true or false', title: 'Switches can be set to true or false',
render(): React.Element<any> { render(): React.Element<any> {
@ -230,8 +233,3 @@ const examples = [
}, },
}, },
]; ];
exports.title = '<Switch>';
exports.displayName = 'SwitchExample';
exports.description = 'Native boolean input';
exports.examples = examples;

View File

@ -32,108 +32,6 @@ const forceTouchAvailable =
NativeModules.PlatformConstants.forceTouchAvailable) || NativeModules.PlatformConstants.forceTouchAvailable) ||
false; false;
exports.displayName = (undefined: ?string);
exports.description = 'Touchable and onPress examples.';
exports.title = '<Touchable*> and onPress';
exports.examples = [
{
title: '<TouchableHighlight>',
description:
'TouchableHighlight works by adding an extra view with a ' +
'black background under the single child view. This works best when the ' +
'child view is fully opaque, although it can be made to work as a simple ' +
'background color change as well with the activeOpacity and ' +
'underlayColor props.',
render: function() {
return <TouchableHighlightBox />;
},
},
{
title: '<TouchableWithoutFeedback>',
render: function() {
return <TouchableWithoutFeedbackBox />;
},
},
{
title: 'TouchableNativeFeedback with Animated child',
description:
'TouchableNativeFeedback can have an AnimatedComponent as a' +
'direct child.',
platform: 'android',
render: function() {
const mScale = new Animated.Value(1);
Animated.timing(mScale, {toValue: 0.3, duration: 1000}).start();
const style = {
backgroundColor: 'rgb(180, 64, 119)',
width: 200,
height: 100,
transform: [{scale: mScale}],
};
return (
<View>
<View style={styles.row}>
<TouchableNativeFeedback>
<Animated.View style={style} />
</TouchableNativeFeedback>
</View>
</View>
);
},
},
{
title: '<Text onPress={fn}> with highlight',
render: function(): React.Element<any> {
return <TextOnPressBox />;
},
},
{
title: 'Touchable feedback events',
description:
'<Touchable*> components accept onPress, onPressIn, ' +
'onPressOut, and onLongPress as props.',
render: function(): React.Element<any> {
return <TouchableFeedbackEvents />;
},
},
{
title: 'Touchable delay for events',
description:
'<Touchable*> components also accept delayPressIn, ' +
'delayPressOut, and delayLongPress as props. These props impact the ' +
'timing of feedback events.',
render: function(): React.Element<any> {
return <TouchableDelayEvents />;
},
},
{
title: '3D Touch / Force Touch',
description:
'iPhone 6s and 6s plus support 3D touch, which adds a force property to touches',
render: function(): React.Element<any> {
return <ForceTouchExample />;
},
platform: 'ios',
},
{
title: 'Touchable Hit Slop',
description:
'<Touchable*> components accept hitSlop prop which extends the touch area ' +
'without changing the view bounds.',
render: function(): React.Element<any> {
return <TouchableHitSlop />;
},
},
{
title: 'Disabled Touchable*',
description:
'<Touchable*> components accept disabled prop which prevents ' +
'any interaction with component',
render: function(): React.Element<any> {
return <TouchableDisabled />;
},
},
];
class TouchableHighlightBox extends React.Component<{}, $FlowFixMeState> { class TouchableHighlightBox extends React.Component<{}, $FlowFixMeState> {
state = { state = {
timesPressed: 0, timesPressed: 0,
@ -566,3 +464,105 @@ const styles = StyleSheet.create({
color: 'blue', color: 'blue',
}, },
}); });
exports.displayName = (undefined: ?string);
exports.description = 'Touchable and onPress examples.';
exports.title = '<Touchable*> and onPress';
exports.examples = [
{
title: '<TouchableHighlight>',
description:
'TouchableHighlight works by adding an extra view with a ' +
'black background under the single child view. This works best when the ' +
'child view is fully opaque, although it can be made to work as a simple ' +
'background color change as well with the activeOpacity and ' +
'underlayColor props.',
render: function() {
return <TouchableHighlightBox />;
},
},
{
title: '<TouchableWithoutFeedback>',
render: function() {
return <TouchableWithoutFeedbackBox />;
},
},
{
title: 'TouchableNativeFeedback with Animated child',
description:
'TouchableNativeFeedback can have an AnimatedComponent as a' +
'direct child.',
platform: 'android',
render: function() {
const mScale = new Animated.Value(1);
Animated.timing(mScale, {toValue: 0.3, duration: 1000}).start();
const style = {
backgroundColor: 'rgb(180, 64, 119)',
width: 200,
height: 100,
transform: [{scale: mScale}],
};
return (
<View>
<View style={styles.row}>
<TouchableNativeFeedback>
<Animated.View style={style} />
</TouchableNativeFeedback>
</View>
</View>
);
},
},
{
title: '<Text onPress={fn}> with highlight',
render: function(): React.Element<any> {
return <TextOnPressBox />;
},
},
{
title: 'Touchable feedback events',
description:
'<Touchable*> components accept onPress, onPressIn, ' +
'onPressOut, and onLongPress as props.',
render: function(): React.Element<any> {
return <TouchableFeedbackEvents />;
},
},
{
title: 'Touchable delay for events',
description:
'<Touchable*> components also accept delayPressIn, ' +
'delayPressOut, and delayLongPress as props. These props impact the ' +
'timing of feedback events.',
render: function(): React.Element<any> {
return <TouchableDelayEvents />;
},
},
{
title: '3D Touch / Force Touch',
description:
'iPhone 6s and 6s plus support 3D touch, which adds a force property to touches',
render: function(): React.Element<any> {
return <ForceTouchExample />;
},
platform: 'ios',
},
{
title: 'Touchable Hit Slop',
description:
'<Touchable*> components accept hitSlop prop which extends the touch area ' +
'without changing the view bounds.',
render: function(): React.Element<any> {
return <TouchableHitSlop />;
},
},
{
title: 'Disabled Touchable*',
description:
'<Touchable*> components accept disabled prop which prevents ' +
'any interaction with component',
render: function(): React.Element<any> {
return <TouchableDisabled />;
},
},
];