mirror of
https://github.com/zoriya/react-native-web.git
synced 2026-05-25 15:42:24 +00:00
[change] better Touchable support for keyboards
Problem: Although 'Touchable' supports basic keyboard usage, it doesn't support delays or interaction via the Space key. Solution: Extend the 'Touchable' mixin to better support keyboard interactions. All touchable callbacks and delays are now supported when interacted with via a keyboard's Enter and Space keys (as would be expected of native 'button' elements). However, events are not normalized to mimic touch events. Minor upstream changes to the Touchables in React Native are also included.
This commit is contained in:
@@ -5,6 +5,8 @@
|
||||
*/
|
||||
|
||||
import CustomStyleOverrides from './examples/CustomStyleOverrides';
|
||||
import DelayEvents from './examples/DelayEvents';
|
||||
import FeedbackEvents from './examples/FeedbackEvents';
|
||||
import React from 'react';
|
||||
import { storiesOf } from '@kadira/storybook';
|
||||
import { TouchableHighlightDisabled } from './examples/PropDisabled';
|
||||
@@ -45,13 +47,27 @@ const sections = [
|
||||
title: 'More examples',
|
||||
entries: [
|
||||
<DocItem
|
||||
description="Disabled TouchableHighlight"
|
||||
description="Disabled"
|
||||
example={{
|
||||
code: '',
|
||||
render: () => <TouchableHighlightDisabled />
|
||||
}}
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
description="Feedback events"
|
||||
example={{
|
||||
render: () => <FeedbackEvents touchable="highlight" />
|
||||
}}
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
description="Delay events"
|
||||
example={{
|
||||
render: () => <DelayEvents touchable="highlight" />
|
||||
}}
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
description="Custom style overrides"
|
||||
example={{
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import DelayEvents from './examples/DelayEvents';
|
||||
import FeedbackEvents from './examples/FeedbackEvents';
|
||||
import React from 'react';
|
||||
import { storiesOf } from '@kadira/storybook';
|
||||
import { TouchableOpacityDisabled } from './examples/PropDisabled';
|
||||
@@ -44,9 +46,22 @@ const sections = [
|
||||
<DocItem
|
||||
description="Disabled TouchableOpacity"
|
||||
example={{
|
||||
code: '',
|
||||
render: () => <TouchableOpacityDisabled />
|
||||
}}
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
description="Feedback events"
|
||||
example={{
|
||||
render: () => <FeedbackEvents touchable="opacity" />
|
||||
}}
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
description="Delay events"
|
||||
example={{
|
||||
render: () => <DelayEvents touchable="opacity" />
|
||||
}}
|
||||
/>
|
||||
]
|
||||
}
|
||||
|
||||
@@ -4,9 +4,12 @@
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import DelayEvents from './examples/DelayEvents';
|
||||
import FeedbackEvents from './examples/FeedbackEvents';
|
||||
import React from 'react';
|
||||
import PropHitSlop from './examples/PropHitSlop';
|
||||
import { storiesOf } from '@kadira/storybook';
|
||||
import { TouchableWithoutFeedbackDisabled } from './examples/PropDisabled';
|
||||
import UIExplorer, { AppText, Code, DocItem } from '../../ui-explorer';
|
||||
|
||||
const sections = [
|
||||
@@ -53,6 +56,9 @@ const sections = [
|
||||
If <Code>true</Code>, disable all interactions for this component.
|
||||
</AppText>
|
||||
}
|
||||
example={{
|
||||
render: () => <TouchableWithoutFeedbackDisabled />
|
||||
}}
|
||||
/>,
|
||||
|
||||
<DocItem name="onLongPress" typeInfo="?function" />,
|
||||
@@ -83,7 +89,23 @@ constant to reduce memory allocations.`}
|
||||
|
||||
{
|
||||
title: 'More examples',
|
||||
entries: [<DocItem description="Hit slop" example={{ render: () => <PropHitSlop /> }} />]
|
||||
entries: [
|
||||
<DocItem
|
||||
description="Feedback events"
|
||||
example={{
|
||||
render: () => <FeedbackEvents touchable="withoutFeedback" />
|
||||
}}
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
description="Delay events"
|
||||
example={{
|
||||
render: () => <DelayEvents touchable="withoutFeedback" />
|
||||
}}
|
||||
/>,
|
||||
|
||||
<DocItem description="Hit slop" example={{ render: () => <PropHitSlop /> }} />
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import { oneOf } from 'prop-types';
|
||||
import React, { PureComponent } from 'react';
|
||||
import {
|
||||
StyleSheet,
|
||||
Text,
|
||||
TouchableHighlight,
|
||||
TouchableOpacity,
|
||||
TouchableWithoutFeedback,
|
||||
View
|
||||
} from 'react-native';
|
||||
|
||||
const Touchables = {
|
||||
highlight: TouchableHighlight,
|
||||
opacity: TouchableOpacity,
|
||||
withoutFeedback: TouchableWithoutFeedback
|
||||
};
|
||||
|
||||
export default class TouchableDelayEvents extends PureComponent {
|
||||
static propTypes = {
|
||||
touchable: oneOf(['highlight', 'opacity', 'withoutFeedback'])
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
touchable: 'highlight'
|
||||
};
|
||||
|
||||
state = { eventLog: [] };
|
||||
|
||||
render() {
|
||||
const Touchable = Touchables[this.props.touchable];
|
||||
const { displayName } = Touchable;
|
||||
return (
|
||||
<View>
|
||||
<View>
|
||||
<Touchable
|
||||
delayLongPress={800}
|
||||
delayPressIn={400}
|
||||
delayPressOut={1000}
|
||||
onLongPress={this._createPressHandler('longPress: 800ms delay')}
|
||||
onPress={this._createPressHandler('press')}
|
||||
onPressIn={this._createPressHandler('pressIn: 400ms delay')}
|
||||
onPressOut={this._createPressHandler('pressOut: 1000ms delay')}
|
||||
>
|
||||
<Text style={styles.touchableText}>
|
||||
{displayName}
|
||||
</Text>
|
||||
</Touchable>
|
||||
</View>
|
||||
<View style={styles.eventLogBox}>
|
||||
{this.state.eventLog.map((e, ii) =>
|
||||
<Text key={ii}>
|
||||
{e}
|
||||
</Text>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
_createPressHandler = eventName => {
|
||||
return () => {
|
||||
const limit = 6;
|
||||
this.setState(state => {
|
||||
const eventLog = state.eventLog.slice(0, limit - 1);
|
||||
eventLog.unshift(eventName);
|
||||
return { eventLog };
|
||||
});
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
touchableText: {
|
||||
borderRadius: 8,
|
||||
padding: 5,
|
||||
borderWidth: 1,
|
||||
borderColor: 'black',
|
||||
color: '#007AFF',
|
||||
borderStyle: 'solid',
|
||||
textAlign: 'center'
|
||||
},
|
||||
logBox: {
|
||||
padding: 20,
|
||||
margin: 10,
|
||||
borderWidth: StyleSheet.hairlineWidth,
|
||||
borderColor: '#f0f0f0',
|
||||
backgroundColor: '#f9f9f9'
|
||||
},
|
||||
eventLogBox: {
|
||||
padding: 10,
|
||||
margin: 10,
|
||||
height: 120,
|
||||
borderWidth: StyleSheet.hairlineWidth,
|
||||
borderColor: '#f0f0f0',
|
||||
backgroundColor: '#f9f9f9'
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,95 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import { oneOf } from 'prop-types';
|
||||
import React, { PureComponent } from 'react';
|
||||
import {
|
||||
StyleSheet,
|
||||
Text,
|
||||
TouchableHighlight,
|
||||
TouchableOpacity,
|
||||
TouchableWithoutFeedback,
|
||||
View
|
||||
} from 'react-native';
|
||||
|
||||
const Touchables = {
|
||||
highlight: TouchableHighlight,
|
||||
opacity: TouchableOpacity,
|
||||
withoutFeedback: TouchableWithoutFeedback
|
||||
};
|
||||
|
||||
export default class TouchableFeedbackEvents extends PureComponent {
|
||||
static propTypes = {
|
||||
touchable: oneOf(['highlight', 'opacity', 'withoutFeedback'])
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
touchable: 'highlight'
|
||||
};
|
||||
|
||||
state = { eventLog: [] };
|
||||
|
||||
render() {
|
||||
const Touchable = Touchables[this.props.touchable];
|
||||
return (
|
||||
<View>
|
||||
<View>
|
||||
<Touchable
|
||||
onLongPress={this._createPressHandler('longPress')}
|
||||
onPress={this._createPressHandler('press')}
|
||||
onPressIn={this._createPressHandler('pressIn')}
|
||||
onPressOut={this._createPressHandler('pressOut')}
|
||||
>
|
||||
<Text style={styles.touchableText}>Press Me</Text>
|
||||
</Touchable>
|
||||
</View>
|
||||
<View style={styles.eventLogBox}>
|
||||
{this.state.eventLog.map((e, ii) =>
|
||||
<Text key={ii}>
|
||||
{e}
|
||||
</Text>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
_createPressHandler = eventName => {
|
||||
return () => {
|
||||
const limit = 6;
|
||||
this.setState(state => {
|
||||
const eventLog = state.eventLog.slice(0, limit - 1);
|
||||
eventLog.unshift(eventName);
|
||||
return { eventLog };
|
||||
});
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
touchableText: {
|
||||
borderRadius: 8,
|
||||
padding: 5,
|
||||
borderWidth: 1,
|
||||
borderColor: 'black',
|
||||
color: '#007AFF',
|
||||
borderStyle: 'solid',
|
||||
textAlign: 'center'
|
||||
},
|
||||
logBox: {
|
||||
padding: 20,
|
||||
margin: 10,
|
||||
borderWidth: StyleSheet.hairlineWidth,
|
||||
borderColor: '#f0f0f0',
|
||||
backgroundColor: '#f9f9f9'
|
||||
},
|
||||
eventLogBox: {
|
||||
padding: 10,
|
||||
margin: 10,
|
||||
height: 120,
|
||||
borderWidth: StyleSheet.hairlineWidth,
|
||||
borderColor: '#f0f0f0',
|
||||
backgroundColor: '#f9f9f9'
|
||||
}
|
||||
});
|
||||
@@ -4,7 +4,14 @@
|
||||
|
||||
import React from 'react';
|
||||
import { action } from '@kadira/storybook';
|
||||
import { StyleSheet, View, Text, TouchableHighlight, TouchableOpacity } from 'react-native';
|
||||
import {
|
||||
StyleSheet,
|
||||
View,
|
||||
Text,
|
||||
TouchableHighlight,
|
||||
TouchableOpacity,
|
||||
TouchableWithoutFeedback
|
||||
} from 'react-native';
|
||||
|
||||
class TouchableHighlightDisabled extends React.Component {
|
||||
render() {
|
||||
@@ -57,7 +64,27 @@ class TouchableOpacityDisabled extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
export { TouchableHighlightDisabled, TouchableOpacityDisabled };
|
||||
class TouchableWithoutFeedbackDisabled extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<View>
|
||||
<TouchableWithoutFeedback disabled={true} onPress={action('TouchableWithoutFeedback')}>
|
||||
<View style={[styles.row, styles.block]}>
|
||||
<Text style={styles.disabledButton}>Disabled TouchableWithoutFeedback</Text>
|
||||
</View>
|
||||
</TouchableWithoutFeedback>
|
||||
|
||||
<TouchableWithoutFeedback disabled={false} onPress={action('TouchableWithoutFeedback')}>
|
||||
<View style={[styles.row, styles.block]}>
|
||||
<Text style={styles.button}>Enabled TouchableWithoutFeedback</Text>
|
||||
</View>
|
||||
</TouchableWithoutFeedback>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export { TouchableHighlightDisabled, TouchableOpacityDisabled, TouchableWithoutFeedbackDisabled };
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
row: {
|
||||
@@ -66,12 +93,5 @@ const styles = StyleSheet.create({
|
||||
},
|
||||
block: {
|
||||
padding: 10
|
||||
},
|
||||
button: {
|
||||
color: '#007AFF'
|
||||
},
|
||||
disabledButton: {
|
||||
color: '#007AFF',
|
||||
opacity: 0.5
|
||||
}
|
||||
});
|
||||
|
||||
@@ -17,92 +17,6 @@ import {
|
||||
View
|
||||
} from 'react-native';
|
||||
|
||||
class TouchableFeedbackEvents extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = { eventLog: [] };
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<View testID="touchable_feedback_events">
|
||||
<View style={[styles.row, { justifyContent: 'center' }]}>
|
||||
<TouchableOpacity
|
||||
accessibilityComponentType="button"
|
||||
accessibilityLabel="touchable feedback events"
|
||||
accessibilityTraits="button"
|
||||
onLongPress={this._createPressHandler('longPress')}
|
||||
onPress={this._createPressHandler('press')}
|
||||
onPressIn={this._createPressHandler('pressIn')}
|
||||
onPressOut={this._createPressHandler('pressOut')}
|
||||
style={styles.wrapper}
|
||||
testID="touchable_feedback_events_button"
|
||||
>
|
||||
<Text style={styles.button}>
|
||||
Press Me
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
<View style={styles.eventLogBox} testID="touchable_feedback_events_console">
|
||||
{this.state.eventLog.map((e, ii) => <Text key={ii}>{e}</Text>)}
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
_createPressHandler = eventName => {
|
||||
return () => {
|
||||
const limit = 6;
|
||||
const eventLog = this.state.eventLog.slice(0, limit - 1);
|
||||
eventLog.unshift(eventName);
|
||||
this.setState({ eventLog });
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
class TouchableDelayEvents extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = { eventLog: [] };
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<View testID="touchable_delay_events">
|
||||
<View style={[styles.row, { justifyContent: 'center' }]}>
|
||||
<TouchableOpacity
|
||||
delayLongPress={800}
|
||||
delayPressIn={400}
|
||||
delayPressOut={1000}
|
||||
onLongPress={this._createPressHandler('longPress - 800ms delay')}
|
||||
onPress={this._createPressHandler('press')}
|
||||
onPressIn={this._createPressHandler('pressIn - 400ms delay')}
|
||||
onPressOut={this._createPressHandler('pressOut - 1000ms delay')}
|
||||
style={styles.wrapper}
|
||||
testID="touchable_delay_events_button"
|
||||
>
|
||||
<Text style={styles.button}>
|
||||
Press Me
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
<View style={styles.eventLogBox} testID="touchable_delay_events_console">
|
||||
{this.state.eventLog.map((e, ii) => <Text key={ii}>{e}</Text>)}
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
_createPressHandler = eventName => {
|
||||
return () => {
|
||||
const limit = 6;
|
||||
const eventLog = this.state.eventLog.slice(0, limit - 1);
|
||||
eventLog.unshift(eventName);
|
||||
this.setState({ eventLog });
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
const heartImage = { uri: 'https://pbs.twimg.com/media/BlXBfT3CQAA6cVZ.png:small' };
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
@@ -214,33 +128,5 @@ const examples = [
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Touchable feedback events',
|
||||
description:
|
||||
'<Touchable*> components accept onPress, onPressIn, ' +
|
||||
'onPressOut, and onLongPress as props.',
|
||||
render() {
|
||||
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() {
|
||||
return <TouchableDelayEvents />;
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Disabled Touchable*',
|
||||
description:
|
||||
'<Touchable*> components accept disabled prop which prevents ' +
|
||||
'any interaction with component',
|
||||
render() {
|
||||
return <TouchableDisabled />;
|
||||
}
|
||||
}
|
||||
];
|
||||
*/
|
||||
|
||||
@@ -14,7 +14,6 @@ import applyLayout from '../../modules/applyLayout';
|
||||
import applyNativeMethods from '../../modules/applyNativeMethods';
|
||||
import { canUseDOM } from 'fbjs/lib/ExecutionEnvironment';
|
||||
import { Component } from 'react';
|
||||
import NativeMethodsMixin from '../../modules/NativeMethodsMixin';
|
||||
import createDOMElement from '../../modules/createDOMElement';
|
||||
import findNodeHandle from '../../modules/findNodeHandle';
|
||||
import StyleSheet from '../../apis/StyleSheet';
|
||||
@@ -145,10 +144,6 @@ class TextInput extends Component {
|
||||
return TextInputState.currentlyFocusedField() === this._node;
|
||||
}
|
||||
|
||||
setNativeProps(props) {
|
||||
NativeMethodsMixin.setNativeProps.call(this, props);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
setSelection(this._node, this.props.selection);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* eslint-disable */
|
||||
/* eslint-disable react/prop-types */
|
||||
|
||||
/**
|
||||
* Copyright (c) 2016-present, Nicolas Gallagher.
|
||||
@@ -9,18 +9,19 @@
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @providesModule Touchable
|
||||
* @noflow
|
||||
* @flow
|
||||
*/
|
||||
|
||||
/* @edit start */
|
||||
import BoundingDimensions from './BoundingDimensions';
|
||||
import findNodeHandle from '../../modules/findNodeHandle';
|
||||
import normalizeColor from 'normalize-css-color';
|
||||
import Position from './Position';
|
||||
import React from 'react';
|
||||
import TouchEventUtils from 'fbjs/lib/TouchEventUtils';
|
||||
import UIManager from '../../apis/UIManager';
|
||||
import View from '../../components/View';
|
||||
/* @edit end */
|
||||
|
||||
type Event = Object;
|
||||
|
||||
/**
|
||||
* `Touchable`: Taps done right.
|
||||
@@ -314,10 +315,27 @@ const LONG_PRESS_ALLOWED_MOVEMENT = 10;
|
||||
* @lends Touchable.prototype
|
||||
*/
|
||||
const TouchableMixin = {
|
||||
componentDidMount: function() {
|
||||
this._touchableNode = findNodeHandle(this);
|
||||
this._touchableBlurListener = e => {
|
||||
if (this._isTouchableKeyboardActive) {
|
||||
if (
|
||||
this.state.touchable.touchState &&
|
||||
this.state.touchable.touchState !== States.NOT_RESPONDER
|
||||
) {
|
||||
this.touchableHandleResponderTerminate({ nativeEvent: e });
|
||||
}
|
||||
this._isTouchableKeyboardActive = false;
|
||||
}
|
||||
};
|
||||
this._touchableNode.addEventListener('blur', this._touchableBlurListener);
|
||||
},
|
||||
|
||||
/**
|
||||
* Clear all timeouts on unmount
|
||||
*/
|
||||
componentWillUnmount: function() {
|
||||
this._touchableNode.removeEventListener('blur', this._touchableBlurListener);
|
||||
this.touchableDelayTimeout && clearTimeout(this.touchableDelayTimeout);
|
||||
this.longPressDelayTimeout && clearTimeout(this.longPressDelayTimeout);
|
||||
this.pressOutDelayTimeout && clearTimeout(this.pressOutDelayTimeout);
|
||||
@@ -360,16 +378,13 @@ const TouchableMixin = {
|
||||
|
||||
/**
|
||||
* Place as callback for a DOM element's `onResponderGrant` event.
|
||||
* @param {SyntheticEvent} e Synthetic event from event system.
|
||||
*
|
||||
*/
|
||||
touchableHandleResponderGrant: function(e) {
|
||||
touchableHandleResponderGrant: function(e: Event) {
|
||||
const dispatchID = e.currentTarget;
|
||||
// Since e is used in a callback invoked on another event loop
|
||||
// (as in setTimeout etc), we need to call e.persist() on the
|
||||
// event to make sure it doesn't get reused in the event object pool.
|
||||
e.persist();
|
||||
|
||||
this.pressOutDelayTimeout && clearTimeout(this.pressOutDelayTimeout);
|
||||
this.pressOutDelayTimeout = null;
|
||||
|
||||
@@ -401,7 +416,7 @@ const TouchableMixin = {
|
||||
/**
|
||||
* Place as callback for a DOM element's `onResponderRelease` event.
|
||||
*/
|
||||
touchableHandleResponderRelease: function(e) {
|
||||
touchableHandleResponderRelease: function(e: Event) {
|
||||
this._receiveSignal(Signals.RESPONDER_RELEASE, e);
|
||||
// Browsers fire mouse events after touch events. This causes the
|
||||
// 'onResponderRelease' handler to be called twice for Touchables.
|
||||
@@ -415,14 +430,14 @@ const TouchableMixin = {
|
||||
/**
|
||||
* Place as callback for a DOM element's `onResponderTerminate` event.
|
||||
*/
|
||||
touchableHandleResponderTerminate: function(e) {
|
||||
touchableHandleResponderTerminate: function(e: Event) {
|
||||
this._receiveSignal(Signals.RESPONDER_TERMINATED, e);
|
||||
},
|
||||
|
||||
/**
|
||||
* Place as callback for a DOM element's `onResponderMove` event.
|
||||
*/
|
||||
touchableHandleResponderMove: function(e) {
|
||||
touchableHandleResponderMove: function(e: Event) {
|
||||
// Not enough time elapsed yet, wait for highlight -
|
||||
// this is just a perf optimization.
|
||||
if (this.state.touchable.touchState === States.RESPONDER_INACTIVE_PRESS_IN) {
|
||||
@@ -578,21 +593,34 @@ const TouchableMixin = {
|
||||
UIManager.measure(tag, this._handleQueryLayout);
|
||||
},
|
||||
|
||||
_handleQueryLayout: function(l, t, w, h, globalX, globalY) {
|
||||
_handleQueryLayout: function(
|
||||
x: number,
|
||||
y: number,
|
||||
width: number,
|
||||
height: number,
|
||||
globalX: number,
|
||||
globalY: number
|
||||
) {
|
||||
// don't do anything if UIManager failed to measure node
|
||||
if (!x && !y && !width && !height && !globalX && !globalY) {
|
||||
return;
|
||||
}
|
||||
this.state.touchable.positionOnActivate &&
|
||||
Position.release(this.state.touchable.positionOnActivate);
|
||||
this.state.touchable.dimensionsOnActivate &&
|
||||
// $FlowFixMe
|
||||
BoundingDimensions.release(this.state.touchable.dimensionsOnActivate);
|
||||
this.state.touchable.positionOnActivate = Position.getPooled(globalX, globalY);
|
||||
this.state.touchable.dimensionsOnActivate = BoundingDimensions.getPooled(w, h);
|
||||
// $FlowFixMe
|
||||
this.state.touchable.dimensionsOnActivate = BoundingDimensions.getPooled(width, height);
|
||||
},
|
||||
|
||||
_handleDelay: function(e) {
|
||||
_handleDelay: function(e: Event) {
|
||||
this.touchableDelayTimeout = null;
|
||||
this._receiveSignal(Signals.DELAY, e);
|
||||
},
|
||||
|
||||
_handleLongDelay: function(e) {
|
||||
_handleLongDelay: function(e: Event) {
|
||||
this.longPressDelayTimeout = null;
|
||||
const curState = this.state.touchable.touchState;
|
||||
if (
|
||||
@@ -620,7 +648,7 @@ const TouchableMixin = {
|
||||
* @throws Error if invalid state transition or unrecognized signal.
|
||||
* @sideeffects
|
||||
*/
|
||||
_receiveSignal: function(signal, e) {
|
||||
_receiveSignal: function(signal: string, e: Event) {
|
||||
const responderID = this.state.touchable.responderID;
|
||||
const curState = this.state.touchable.touchState;
|
||||
const nextState = Transitions[curState] && Transitions[curState][signal];
|
||||
@@ -660,13 +688,13 @@ const TouchableMixin = {
|
||||
this.longPressDelayTimeout = null;
|
||||
},
|
||||
|
||||
_isHighlight: function(state) {
|
||||
_isHighlight: function(state: string) {
|
||||
return (
|
||||
state === States.RESPONDER_ACTIVE_PRESS_IN || state === States.RESPONDER_ACTIVE_LONG_PRESS_IN
|
||||
);
|
||||
},
|
||||
|
||||
_savePressInLocation: function(e) {
|
||||
_savePressInLocation: function(e: Event) {
|
||||
const touch = TouchEventUtils.extractSingleTouch(e.nativeEvent);
|
||||
const pageX = touch && touch.pageX;
|
||||
const pageY = touch && touch.pageY;
|
||||
@@ -675,7 +703,7 @@ const TouchableMixin = {
|
||||
this.pressInLocation = { pageX, pageY, locationX, locationY };
|
||||
},
|
||||
|
||||
_getDistanceBetweenPoints: function(aX, aY, bX, bY) {
|
||||
_getDistanceBetweenPoints: function(aX: number, aY: number, bX: number, bY: number) {
|
||||
const deltaX = aX - bX;
|
||||
const deltaY = aY - bY;
|
||||
return Math.sqrt(deltaX * deltaX + deltaY * deltaY);
|
||||
@@ -692,7 +720,12 @@ const TouchableMixin = {
|
||||
* @param {Event} e Native event.
|
||||
* @sideeffects
|
||||
*/
|
||||
_performSideEffectsForTransition: function(curState, nextState, signal, e) {
|
||||
_performSideEffectsForTransition: function(
|
||||
curState: string,
|
||||
nextState: string,
|
||||
signal: string,
|
||||
e: Event
|
||||
) {
|
||||
const curIsHighlight = this._isHighlight(curState);
|
||||
const newIsHighlight = this._isHighlight(nextState);
|
||||
|
||||
@@ -739,12 +772,12 @@ const TouchableMixin = {
|
||||
this.touchableDelayTimeout = null;
|
||||
},
|
||||
|
||||
_startHighlight: function(e) {
|
||||
_startHighlight: function(e: Event) {
|
||||
this._savePressInLocation(e);
|
||||
this.touchableHandleActivePressIn && this.touchableHandleActivePressIn(e);
|
||||
},
|
||||
|
||||
_endHighlight: function(e) {
|
||||
_endHighlight: function(e: Event) {
|
||||
if (this.touchableHandleActivePressOut) {
|
||||
if (this.touchableGetPressOutDelayMS && this.touchableGetPressOutDelayMS()) {
|
||||
this.pressOutDelayTimeout = setTimeout(() => {
|
||||
@@ -754,29 +787,59 @@ const TouchableMixin = {
|
||||
this.touchableHandleActivePressOut(e);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// HACK: basic support for touchable interactions using a keyboard (including
|
||||
// delays and longPress)
|
||||
touchableHandleKeyEvent: function(e: Event) {
|
||||
const ENTER = 13;
|
||||
const SPACE = 32;
|
||||
const { type, which } = e;
|
||||
if (which === ENTER || which === SPACE) {
|
||||
if (type === 'keydown') {
|
||||
if (!this._isTouchableKeyboardActive) {
|
||||
if (
|
||||
!this.state.touchable.touchState ||
|
||||
this.state.touchable.touchState === States.NOT_RESPONDER
|
||||
) {
|
||||
this.touchableHandleResponderGrant(e);
|
||||
this._isTouchableKeyboardActive = true;
|
||||
}
|
||||
}
|
||||
} else if (type === 'keyup') {
|
||||
if (this._isTouchableKeyboardActive) {
|
||||
if (
|
||||
this.state.touchable.touchState &&
|
||||
this.state.touchable.touchState !== States.NOT_RESPONDER
|
||||
) {
|
||||
this.touchableHandleResponderRelease(e);
|
||||
this._isTouchableKeyboardActive = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var Touchable = {
|
||||
const Touchable = {
|
||||
Mixin: TouchableMixin,
|
||||
TOUCH_TARGET_DEBUG: false, // Highlights all touchable targets. Toggle with Inspector.
|
||||
/**
|
||||
* Renders a debugging overlay to visualize touch target with hitSlop (might not work on Android).
|
||||
*/
|
||||
renderDebugView: ({ color, hitSlop }) => {
|
||||
renderDebugView: ({ color, hitSlop }: Object) => {
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
if (!Touchable.TOUCH_TARGET_DEBUG) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const debugHitSlopStyle = {};
|
||||
hitSlop = hitSlop || { top: 0, bottom: 0, left: 0, right: 0 };
|
||||
for (const key in hitSlop) {
|
||||
debugHitSlopStyle[key] = -hitSlop[key];
|
||||
}
|
||||
|
||||
const hexColor = '#' + ('00000000' + normalizeColor(color).toString(16)).substr(-8);
|
||||
|
||||
return (
|
||||
<View
|
||||
pointerEvents="none"
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
/* eslint-disable */
|
||||
|
||||
/**
|
||||
* Copyright (c) 2016-present, Nicolas Gallagher.
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
@@ -12,19 +10,18 @@
|
||||
* @noflow
|
||||
*/
|
||||
|
||||
import applyNativeMethods from '../../modules/applyNativeMethods';
|
||||
import ColorPropType from '../../propTypes/ColorPropType';
|
||||
import createReactClass from 'create-react-class';
|
||||
import ensureComponentIsNative from './ensureComponentIsNative';
|
||||
import ensurePositiveDelayProps from './ensurePositiveDelayProps';
|
||||
import NativeMethodsMixin from '../../modules/NativeMethodsMixin';
|
||||
import React from 'react';
|
||||
import StyleSheet from '../../apis/StyleSheet';
|
||||
import StyleSheetPropType from '../../propTypes/StyleSheetPropType';
|
||||
import TimerMixin from 'react-timer-mixin';
|
||||
import Touchable from './Touchable';
|
||||
import TouchableWithoutFeedback from './TouchableWithoutFeedback';
|
||||
import View from '../View';
|
||||
import ViewStylePropTypes from '../View/ViewStylePropTypes';
|
||||
import ViewPropTypes from '../View/ViewPropTypes';
|
||||
import { func, number } from 'prop-types';
|
||||
|
||||
type Event = Object;
|
||||
@@ -39,10 +36,15 @@ const PRESS_RETENTION_OFFSET = { top: 20, left: 20, right: 20, bottom: 30 };
|
||||
/**
|
||||
* A wrapper for making views respond properly to touches.
|
||||
* On press down, the opacity of the wrapped view is decreased, which allows
|
||||
* the underlay color to show through, darkening or tinting the view. The
|
||||
* underlay comes from adding a view to the view hierarchy, which can sometimes
|
||||
* cause unwanted visual artifacts if not used correctly, for example if the
|
||||
* backgroundColor of the wrapped view isn't explicitly set to an opaque color.
|
||||
* the underlay color to show through, darkening or tinting the view.
|
||||
*
|
||||
* The underlay comes from wrapping the child in a new View, which can affect
|
||||
* layout, and sometimes cause unwanted visual artifacts if not used correctly,
|
||||
* for example if the backgroundColor of the wrapped view isn't explicitly set
|
||||
* to an opaque color.
|
||||
*
|
||||
* TouchableHighlight must have one child (not zero or more than one).
|
||||
* If you wish to have several child components, wrap them in a View.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
@@ -52,18 +54,17 @@ const PRESS_RETENTION_OFFSET = { top: 20, left: 20, right: 20, bottom: 30 };
|
||||
* <TouchableHighlight onPress={this._onPressButton}>
|
||||
* <Image
|
||||
* style={styles.button}
|
||||
* source={require('./myButton')}
|
||||
* source={require('./myButton.png')}
|
||||
* />
|
||||
* </TouchableHighlight>
|
||||
* );
|
||||
* },
|
||||
* ```
|
||||
* > **NOTE**: TouchableHighlight must have one child (not zero or more than one)
|
||||
* >
|
||||
* > If you wish to have several child components, wrap them in a View.
|
||||
*/
|
||||
|
||||
/* eslint-disable react/prefer-es6-class */
|
||||
const TouchableHighlight = createReactClass({
|
||||
displayName: 'TouchableHighlight',
|
||||
propTypes: {
|
||||
...TouchableWithoutFeedback.propTypes,
|
||||
/**
|
||||
@@ -72,37 +73,36 @@ const TouchableHighlight = createReactClass({
|
||||
*/
|
||||
activeOpacity: number,
|
||||
/**
|
||||
* The color of the underlay that will show through when the touch is
|
||||
* active.
|
||||
* Called immediately after the underlay is hidden
|
||||
*/
|
||||
underlayColor: ColorPropType,
|
||||
style: StyleSheetPropType(ViewStylePropTypes),
|
||||
onHideUnderlay: func,
|
||||
/**
|
||||
* Called immediately after the underlay is shown
|
||||
*/
|
||||
onShowUnderlay: func,
|
||||
style: ViewPropTypes.style,
|
||||
/**
|
||||
* Called immediately after the underlay is hidden
|
||||
* The color of the underlay that will show through when the touch is
|
||||
* active.
|
||||
*/
|
||||
onHideUnderlay: func
|
||||
underlayColor: ColorPropType
|
||||
},
|
||||
|
||||
mixins: [NativeMethodsMixin, TimerMixin, Touchable.Mixin],
|
||||
mixins: [TimerMixin, Touchable.Mixin],
|
||||
|
||||
getDefaultProps: () => DEFAULT_PROPS,
|
||||
|
||||
// Performance optimization to avoid constantly re-generating these objects.
|
||||
computeSyntheticState: props => {
|
||||
const { activeOpacity, style, underlayColor } = props;
|
||||
_computeSyntheticState: function(props) {
|
||||
return {
|
||||
activeProps: {
|
||||
style: {
|
||||
opacity: activeOpacity
|
||||
opacity: props.activeOpacity
|
||||
}
|
||||
},
|
||||
activeUnderlayProps: {
|
||||
style: {
|
||||
backgroundColor: underlayColor
|
||||
backgroundColor: props.underlayColor
|
||||
}
|
||||
},
|
||||
underlayStyle: [INACTIVE_UNDERLAY_PROPS.style, props.style]
|
||||
@@ -110,20 +110,25 @@ const TouchableHighlight = createReactClass({
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
this._isMounted = false;
|
||||
return {
|
||||
...this.touchableGetInitialState(),
|
||||
...this.computeSyntheticState(this.props)
|
||||
...this._computeSyntheticState(this.props)
|
||||
};
|
||||
},
|
||||
|
||||
componentDidMount: function() {
|
||||
ensurePositiveDelayProps(this.props);
|
||||
ensureComponentIsNative(this.refs[CHILD_REF]);
|
||||
this._isMounted = true;
|
||||
ensurePositiveDelayProps(this.props);
|
||||
ensureComponentIsNative(this._childRef);
|
||||
},
|
||||
|
||||
componentWillUnmount: function() {
|
||||
this._isMounted = false;
|
||||
},
|
||||
|
||||
componentDidUpdate: function() {
|
||||
ensureComponentIsNative(this.refs[CHILD_REF]);
|
||||
ensureComponentIsNative(this._childRef);
|
||||
},
|
||||
|
||||
componentWillReceiveProps: function(nextProps) {
|
||||
@@ -133,19 +138,10 @@ const TouchableHighlight = createReactClass({
|
||||
nextProps.underlayColor !== this.props.underlayColor ||
|
||||
nextProps.style !== this.props.style
|
||||
) {
|
||||
this.setState(this.computeSyntheticState(nextProps));
|
||||
this.setState(this._computeSyntheticState(nextProps));
|
||||
}
|
||||
},
|
||||
|
||||
componentWillUnmount: function() {
|
||||
this._isMounted = false;
|
||||
},
|
||||
|
||||
// viewConfig: {
|
||||
// uiViewClassName: 'RCTView',
|
||||
// validAttributes: ReactNativeViewAttributes.RCTView
|
||||
// },
|
||||
|
||||
/**
|
||||
* `Touchable.Mixin` self callbacks. The mixin will invoke these if they are
|
||||
* defined on your component.
|
||||
@@ -200,17 +196,17 @@ const TouchableHighlight = createReactClass({
|
||||
return;
|
||||
}
|
||||
|
||||
this.refs[UNDERLAY_REF].setNativeProps(this.state.activeUnderlayProps);
|
||||
this.refs[CHILD_REF].setNativeProps(this.state.activeProps);
|
||||
this._underlayRef.setNativeProps(this.state.activeUnderlayProps);
|
||||
this._childRef.setNativeProps(this.state.activeProps);
|
||||
this.props.onShowUnderlay && this.props.onShowUnderlay();
|
||||
},
|
||||
|
||||
_hideUnderlay: function() {
|
||||
this.clearTimeout(this._hideTimeout);
|
||||
this._hideTimeout = null;
|
||||
if (this._hasPressHandler() && this.refs[UNDERLAY_REF]) {
|
||||
this.refs[CHILD_REF].setNativeProps(INACTIVE_CHILD_PROPS);
|
||||
this.refs[UNDERLAY_REF].setNativeProps({
|
||||
if (this._hasPressHandler() && this._underlayRef) {
|
||||
this._childRef.setNativeProps(INACTIVE_CHILD_PROPS);
|
||||
this._underlayRef.setNativeProps({
|
||||
...INACTIVE_UNDERLAY_PROPS,
|
||||
style: this.state.underlayStyle
|
||||
});
|
||||
@@ -227,12 +223,12 @@ const TouchableHighlight = createReactClass({
|
||||
);
|
||||
},
|
||||
|
||||
_onKeyEnter(e, callback) {
|
||||
const ENTER = 13;
|
||||
if ((e.type === 'keypress' ? e.charCode : e.keyCode) === ENTER) {
|
||||
callback && callback(e);
|
||||
e.stopPropagation();
|
||||
}
|
||||
_setChildRef(node) {
|
||||
this._childRef = node;
|
||||
},
|
||||
|
||||
_setUnderlayRef(node) {
|
||||
this._underlayRef = node;
|
||||
},
|
||||
|
||||
render: function() {
|
||||
@@ -258,26 +254,19 @@ const TouchableHighlight = createReactClass({
|
||||
<View
|
||||
{...other}
|
||||
accessible={this.props.accessible !== false}
|
||||
onKeyDown={e => {
|
||||
this._onKeyEnter(e, this.touchableHandleActivePressIn);
|
||||
}}
|
||||
onKeyPress={e => {
|
||||
this._onKeyEnter(e, this.touchableHandlePress);
|
||||
}}
|
||||
onKeyUp={e => {
|
||||
this._onKeyEnter(e, this.touchableHandleActivePressOut);
|
||||
}}
|
||||
onStartShouldSetResponder={this.touchableHandleStartShouldSetResponder}
|
||||
onResponderTerminationRequest={this.touchableHandleResponderTerminationRequest}
|
||||
onKeyDown={this.touchableHandleKeyEvent}
|
||||
onKeyUp={this.touchableHandleKeyEvent}
|
||||
onResponderGrant={this.touchableHandleResponderGrant}
|
||||
onResponderMove={this.touchableHandleResponderMove}
|
||||
onResponderRelease={this.touchableHandleResponderRelease}
|
||||
onResponderTerminate={this.touchableHandleResponderTerminate}
|
||||
ref={UNDERLAY_REF}
|
||||
onResponderTerminationRequest={this.touchableHandleResponderTerminationRequest}
|
||||
onStartShouldSetResponder={this.touchableHandleStartShouldSetResponder}
|
||||
ref={this._setUnderlayRef}
|
||||
style={[styles.root, this.props.disabled && styles.disabled, this.state.underlayStyle]}
|
||||
>
|
||||
{React.cloneElement(React.Children.only(this.props.children), {
|
||||
ref: CHILD_REF
|
||||
ref: this._setChildRef
|
||||
})}
|
||||
{Touchable.renderDebugView({ color: 'green', hitSlop: this.props.hitSlop })}
|
||||
</View>
|
||||
@@ -285,17 +274,14 @@ const TouchableHighlight = createReactClass({
|
||||
}
|
||||
});
|
||||
|
||||
var CHILD_REF = 'childRef';
|
||||
var UNDERLAY_REF = 'underlayRef';
|
||||
|
||||
var INACTIVE_CHILD_PROPS = {
|
||||
const INACTIVE_CHILD_PROPS = {
|
||||
style: StyleSheet.create({ x: { opacity: 1.0 } }).x
|
||||
};
|
||||
var INACTIVE_UNDERLAY_PROPS = {
|
||||
const INACTIVE_UNDERLAY_PROPS = {
|
||||
style: StyleSheet.create({ x: { backgroundColor: 'transparent' } }).x
|
||||
};
|
||||
|
||||
var styles = StyleSheet.create({
|
||||
const styles = StyleSheet.create({
|
||||
root: {
|
||||
cursor: 'pointer',
|
||||
userSelect: 'none'
|
||||
@@ -305,4 +291,4 @@ var styles = StyleSheet.create({
|
||||
}
|
||||
});
|
||||
|
||||
export default TouchableHighlight;
|
||||
export default applyNativeMethods(TouchableHighlight);
|
||||
|
||||
@@ -1,2 +1,12 @@
|
||||
/**
|
||||
* Copyright 2017-present, Nicolas Gallagher
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import UnimplementedView from '../UnimplementedView';
|
||||
export default UnimplementedView;
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
/* eslint-disable */
|
||||
|
||||
/**
|
||||
* Copyright (c) 2016-present, Nicolas Gallagher.
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
@@ -12,13 +10,12 @@
|
||||
* @noflow
|
||||
*/
|
||||
|
||||
import applyNativeMethods from '../../modules/applyNativeMethods';
|
||||
import createReactClass from 'create-react-class';
|
||||
import ensurePositiveDelayProps from './ensurePositiveDelayProps';
|
||||
import NativeMethodsMixin from '../../modules/NativeMethodsMixin';
|
||||
import { number } from 'prop-types';
|
||||
import React from 'react';
|
||||
import StyleSheet from '../../apis/StyleSheet';
|
||||
import TimerMixin from 'react-timer-mixin';
|
||||
import Touchable from './Touchable';
|
||||
import TouchableWithoutFeedback from './TouchableWithoutFeedback';
|
||||
import View from '../View';
|
||||
@@ -32,8 +29,9 @@ const PRESS_RETENTION_OFFSET = { top: 20, left: 20, right: 20, bottom: 30 };
|
||||
/**
|
||||
* A wrapper for making views respond properly to touches.
|
||||
* On press down, the opacity of the wrapped view is decreased, dimming it.
|
||||
* This is done without actually changing the view hierarchy, and in general is
|
||||
* easy to add to an app without weird side-effects.
|
||||
*
|
||||
* Opacity is controlled by wrapping the children in a View, which is
|
||||
* added to the view hiearchy. Be aware that this can affect layout.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
@@ -43,15 +41,18 @@ const PRESS_RETENTION_OFFSET = { top: 20, left: 20, right: 20, bottom: 30 };
|
||||
* <TouchableOpacity onPress={this._onPressButton}>
|
||||
* <Image
|
||||
* style={styles.button}
|
||||
* source={require('./myButton')}
|
||||
* source={require('./myButton.png')}
|
||||
* />
|
||||
* </TouchableOpacity>
|
||||
* );
|
||||
* },
|
||||
* ```
|
||||
*/
|
||||
|
||||
/* eslint-disable react/prefer-es6-class */
|
||||
const TouchableOpacity = createReactClass({
|
||||
mixins: [TimerMixin, Touchable.Mixin, NativeMethodsMixin],
|
||||
displayName: 'TouchableOpacity',
|
||||
mixins: [Touchable.Mixin],
|
||||
|
||||
propTypes: {
|
||||
...TouchableWithoutFeedback.propTypes,
|
||||
@@ -82,11 +83,14 @@ const TouchableOpacity = createReactClass({
|
||||
ensurePositiveDelayProps(nextProps);
|
||||
},
|
||||
|
||||
setOpacityTo: function(value: number, duration: number) {
|
||||
/**
|
||||
* Animate the touchable to a new opacity.
|
||||
*/
|
||||
setOpacityTo: function(value: number, duration: ?number) {
|
||||
this.setNativeProps({
|
||||
style: {
|
||||
opacity: value,
|
||||
transitionDuration: `${duration / 1000}s`
|
||||
transitionDuration: duration ? `${duration / 1000}s` : '0s'
|
||||
}
|
||||
});
|
||||
},
|
||||
@@ -142,20 +146,16 @@ const TouchableOpacity = createReactClass({
|
||||
},
|
||||
|
||||
_opacityInactive: function(duration: number) {
|
||||
const childStyle = flattenStyle(this.props.style) || {};
|
||||
this.setOpacityTo(childStyle.opacity === undefined ? 1 : childStyle.opacity, duration);
|
||||
this.setOpacityTo(this._getChildStyleOpacityWithDefault(), duration);
|
||||
},
|
||||
|
||||
_opacityFocused: function() {
|
||||
this.setOpacityTo(this.props.focusedOpacity);
|
||||
},
|
||||
|
||||
_onKeyEnter(e, callback) {
|
||||
const ENTER = 13;
|
||||
if ((e.type === 'keypress' ? e.charCode : e.keyCode) === ENTER) {
|
||||
callback && callback(e);
|
||||
e.stopPropagation();
|
||||
}
|
||||
_getChildStyleOpacityWithDefault: function() {
|
||||
const childStyle = flattenStyle(this.props.style) || {};
|
||||
return childStyle.opacity === undefined ? 1 : childStyle.opacity;
|
||||
},
|
||||
|
||||
render: function() {
|
||||
@@ -179,22 +179,15 @@ const TouchableOpacity = createReactClass({
|
||||
<View
|
||||
{...other}
|
||||
accessible={this.props.accessible !== false}
|
||||
style={[styles.root, this.props.disabled && styles.disabled, this.props.style]}
|
||||
onKeyDown={e => {
|
||||
this._onKeyEnter(e, this.touchableHandleActivePressIn);
|
||||
}}
|
||||
onKeyPress={e => {
|
||||
this._onKeyEnter(e, this.touchableHandlePress);
|
||||
}}
|
||||
onKeyUp={e => {
|
||||
this._onKeyEnter(e, this.touchableHandleActivePressOut);
|
||||
}}
|
||||
onStartShouldSetResponder={this.touchableHandleStartShouldSetResponder}
|
||||
onResponderTerminationRequest={this.touchableHandleResponderTerminationRequest}
|
||||
onKeyDown={this.touchableHandleKeyEvent}
|
||||
onKeyUp={this.touchableHandleKeyEvent}
|
||||
onResponderGrant={this.touchableHandleResponderGrant}
|
||||
onResponderMove={this.touchableHandleResponderMove}
|
||||
onResponderRelease={this.touchableHandleResponderRelease}
|
||||
onResponderTerminate={this.touchableHandleResponderTerminate}
|
||||
onResponderTerminationRequest={this.touchableHandleResponderTerminationRequest}
|
||||
onStartShouldSetResponder={this.touchableHandleStartShouldSetResponder}
|
||||
style={[styles.root, this.props.disabled && styles.disabled, this.props.style]}
|
||||
>
|
||||
{this.props.children}
|
||||
{Touchable.renderDebugView({ color: 'blue', hitSlop: this.props.hitSlop })}
|
||||
@@ -203,7 +196,7 @@ const TouchableOpacity = createReactClass({
|
||||
}
|
||||
});
|
||||
|
||||
var styles = StyleSheet.create({
|
||||
const styles = StyleSheet.create({
|
||||
root: {
|
||||
cursor: 'pointer',
|
||||
transitionProperty: 'opacity',
|
||||
@@ -215,4 +208,4 @@ var styles = StyleSheet.create({
|
||||
}
|
||||
});
|
||||
|
||||
export default TouchableOpacity;
|
||||
export default applyNativeMethods(TouchableOpacity);
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
/* eslint-disable */
|
||||
|
||||
/**
|
||||
* Copyright (c) 2016-present, Nicolas Gallagher.
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
@@ -9,9 +7,10 @@
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @providesModule TouchableWithoutFeedback
|
||||
* @noflow
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import BaseComponentPropTypes from '../../propTypes/BaseComponentPropTypes';
|
||||
import createReactClass from 'create-react-class';
|
||||
import EdgeInsetsPropType from '../../propTypes/EdgeInsetsPropType';
|
||||
import ensurePositiveDelayProps from './ensurePositiveDelayProps';
|
||||
@@ -27,42 +26,29 @@ type Event = Object;
|
||||
const PRESS_RETENTION_OFFSET = { top: 20, left: 20, right: 20, bottom: 30 };
|
||||
|
||||
/**
|
||||
* Do not use unless you have a very good reason. All the elements that
|
||||
* respond to press should have a visual feedback when touched. This is
|
||||
* one of the primary reasons a "web" app doesn't feel "native".
|
||||
* Do not use unless you have a very good reason. All elements that
|
||||
* respond to press should have a visual feedback when touched.
|
||||
*
|
||||
* > **NOTE**: TouchableWithoutFeedback supports only one child
|
||||
* >
|
||||
* > If you wish to have several child components, wrap them in a View.
|
||||
* TouchableWithoutFeedback supports only one child.
|
||||
* If you wish to have several child components, wrap them in a View.
|
||||
*/
|
||||
|
||||
/* eslint-disable react/prefer-es6-class */
|
||||
const TouchableWithoutFeedback = createReactClass({
|
||||
displayName: 'TouchableWithoutFeedback',
|
||||
mixins: [TimerMixin, Touchable.Mixin],
|
||||
|
||||
propTypes: {
|
||||
accessible: bool,
|
||||
accessibilityComponentType: BaseComponentPropTypes.accessibilityComponentType,
|
||||
accessibilityLabel: string,
|
||||
accessibilityRole: string,
|
||||
accessibilityRole: BaseComponentPropTypes.accessibilityRole,
|
||||
accessibilityTraits: BaseComponentPropTypes.accessibilityTraits,
|
||||
accessible: bool,
|
||||
children: element,
|
||||
/**
|
||||
* If true, disable all interactions for this component.
|
||||
* Delay in ms, from onPressIn, before onLongPress is called.
|
||||
*/
|
||||
disabled: bool,
|
||||
/**
|
||||
* Called when the touch is released, but not if cancelled (e.g. by a scroll
|
||||
* that steals the responder lock).
|
||||
*/
|
||||
onPress: func,
|
||||
onPressIn: func,
|
||||
onPressOut: func,
|
||||
/**
|
||||
* Invoked on mount and layout changes with
|
||||
*
|
||||
* `{nativeEvent: {layout: {x, y, width, height}}}`
|
||||
*/
|
||||
onLayout: func,
|
||||
|
||||
onLongPress: func,
|
||||
|
||||
delayLongPress: number,
|
||||
/**
|
||||
* Delay in ms, from the start of the touch, before onPressIn is called.
|
||||
*/
|
||||
@@ -72,9 +58,29 @@ const TouchableWithoutFeedback = createReactClass({
|
||||
*/
|
||||
delayPressOut: number,
|
||||
/**
|
||||
* Delay in ms, from onPressIn, before onLongPress is called.
|
||||
* If true, disable all interactions for this component.
|
||||
*/
|
||||
delayLongPress: number,
|
||||
disabled: bool,
|
||||
/**
|
||||
* This defines how far your touch can start away from the button. This is
|
||||
* added to `pressRetentionOffset` when moving off of the button.
|
||||
*/
|
||||
// $FlowFixMe(>=0.41.0)
|
||||
hitSlop: EdgeInsetsPropType,
|
||||
/**
|
||||
* Invoked on mount and layout changes with
|
||||
*
|
||||
* `{nativeEvent: {layout: {x, y, width, height}}}`
|
||||
*/
|
||||
onLayout: func,
|
||||
onLongPress: func,
|
||||
/**
|
||||
* Called when the touch is released, but not if cancelled (e.g. by a scroll
|
||||
* that steals the responder lock).
|
||||
*/
|
||||
onPress: func,
|
||||
onPressIn: func,
|
||||
onPressOut: func,
|
||||
/**
|
||||
* When the scroll view is disabled, this defines how far your touch may
|
||||
* move off of the button, before deactivating the button. Once deactivated,
|
||||
@@ -84,16 +90,7 @@ const TouchableWithoutFeedback = createReactClass({
|
||||
*/
|
||||
// $FlowFixMe
|
||||
pressRetentionOffset: EdgeInsetsPropType,
|
||||
/**
|
||||
* This defines how far your touch can start away from the button. This is
|
||||
* added to `pressRetentionOffset` when moving off of the button.
|
||||
* ** NOTE **
|
||||
* The touch area never extends past the parent view bounds and the Z-index
|
||||
* of sibling views always takes precedence if a touch hits two overlapping
|
||||
* views.
|
||||
*/
|
||||
// $FlowFixMe
|
||||
hitSlop: EdgeInsetsPropType
|
||||
testID: string
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
@@ -187,19 +184,19 @@ const TouchableWithoutFeedback = createReactClass({
|
||||
return (React: any).cloneElement(child, {
|
||||
...other,
|
||||
accessible: this.props.accessible !== false,
|
||||
onStartShouldSetResponder: this.touchableHandleStartShouldSetResponder,
|
||||
onResponderTerminationRequest: this.touchableHandleResponderTerminationRequest,
|
||||
children,
|
||||
onResponderGrant: this.touchableHandleResponderGrant,
|
||||
onResponderMove: this.touchableHandleResponderMove,
|
||||
onResponderRelease: this.touchableHandleResponderRelease,
|
||||
onResponderTerminate: this.touchableHandleResponderTerminate,
|
||||
style,
|
||||
children
|
||||
onResponderTerminationRequest: this.touchableHandleResponderTerminationRequest,
|
||||
onStartShouldSetResponder: this.touchableHandleStartShouldSetResponder,
|
||||
style
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
var styles = StyleSheet.create({
|
||||
const styles = StyleSheet.create({
|
||||
root: {
|
||||
cursor: 'pointer'
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user