mirror of
https://github.com/status-im/react-native.git
synced 2025-01-21 06:49:39 +00:00
f7f347329e
Summary: <!-- Thank you for sending the PR! We appreciate you spending the time to work on these changes. Help us understand your motivation by explaining why you decided to make this change. You can learn more about contributing to React Native here: http://facebook.github.io/react-native/docs/contributing.html Happy contributing! --> Adding example on components section with [react-native-web-player](https://github.com/dabbott/react-native-web-player) - ActivityIndicator - TouchableOpacity - TouchableHighlight Screenshot on http://localhost:8079/react-native/docs/activityindicator.html ![react-native-activityindicator](https://user-images.githubusercontent.com/13135332/30432801-adca0982-9988-11e7-8e70-94ad9e42ea43.png) Screenshot on http://localhost:8079/react-native/docs/touchableopacity.html ![react-native-touchableopacity](https://user-images.githubusercontent.com/13135332/30432718-80570554-9988-11e7-9c81-15ab98327fed.png) Screenshot on http://localhost:8079/react-native/docs/touchablehighlight.html ![react-native-touchablehighlight](https://user-images.githubusercontent.com/13135332/30432733-8290fbb8-9988-11e7-94a1-86c3166e544d.png) Closes https://github.com/facebook/react-native/pull/15950 Differential Revision: D5881366 Pulled By: hramos fbshipit-source-id: 2926071723defedf9ed5cb1b1128204256c71dd9
403 lines
13 KiB
JavaScript
403 lines
13 KiB
JavaScript
/**
|
|
* Copyright (c) 2015-present, Facebook, Inc.
|
|
* 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. An additional grant
|
|
* of patent rights can be found in the PATENTS file in the same directory.
|
|
*
|
|
* @providesModule TouchableHighlight
|
|
* @flow
|
|
*/
|
|
'use strict';
|
|
|
|
const ColorPropType = require('ColorPropType');
|
|
const NativeMethodsMixin = require('NativeMethodsMixin');
|
|
const PropTypes = require('prop-types');
|
|
const React = require('React');
|
|
const ReactNativeViewAttributes = require('ReactNativeViewAttributes');
|
|
const StyleSheet = require('StyleSheet');
|
|
/* $FlowFixMe(>=0.54.0 site=react_native_oss) This comment suppresses an error
|
|
* found when Flow v0.54 was deployed. To see the error delete this comment and
|
|
* run Flow. */
|
|
const TimerMixin = require('react-timer-mixin');
|
|
const Touchable = require('Touchable');
|
|
const TouchableWithoutFeedback = require('TouchableWithoutFeedback');
|
|
const View = require('View');
|
|
const ViewPropTypes = require('ViewPropTypes');
|
|
|
|
const createReactClass = require('create-react-class');
|
|
const ensureComponentIsNative = require('ensureComponentIsNative');
|
|
const ensurePositiveDelayProps = require('ensurePositiveDelayProps');
|
|
/* $FlowFixMe(>=0.54.0 site=react_native_oss) This comment suppresses an error
|
|
* found when Flow v0.54 was deployed. To see the error delete this comment and
|
|
* run Flow. */
|
|
const keyOf = require('fbjs/lib/keyOf');
|
|
const merge = require('merge');
|
|
|
|
import type {Event} from 'TouchableWithoutFeedback';
|
|
|
|
const DEFAULT_PROPS = {
|
|
activeOpacity: 0.85,
|
|
underlayColor: 'black',
|
|
};
|
|
|
|
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 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:
|
|
*
|
|
* ```
|
|
* renderButton: function() {
|
|
* return (
|
|
* <TouchableHighlight onPress={this._onPressButton}>
|
|
* <Image
|
|
* style={styles.button}
|
|
* source={require('./myButton.png')}
|
|
* />
|
|
* </TouchableHighlight>
|
|
* );
|
|
* },
|
|
* ```
|
|
*
|
|
*
|
|
* ### Example
|
|
*
|
|
* ```ReactNativeWebPlayer
|
|
* import React, { Component } from 'react'
|
|
* import {
|
|
* AppRegistry,
|
|
* StyleSheet,
|
|
* TouchableHighlight,
|
|
* Text,
|
|
* View,
|
|
* } from 'react-native'
|
|
*
|
|
* class App extends Component {
|
|
* constructor(props) {
|
|
* super(props)
|
|
* this.state = { count: 0 }
|
|
* }
|
|
*
|
|
* onPress = () => {
|
|
* this.setState({
|
|
* count: this.state.count+1
|
|
* })
|
|
* }
|
|
*
|
|
* render() {
|
|
* return (
|
|
* <View style={styles.container}>
|
|
* <TouchableHighlight
|
|
* style={styles.button}
|
|
* onPress={this.onPress}
|
|
* >
|
|
* <Text> Touch Here </Text>
|
|
* </TouchableHighlight>
|
|
* <View style={[styles.countContainer]}>
|
|
* <Text style={[styles.countText]}>
|
|
* { this.state.count !== 0 ? this.state.count: null}
|
|
* </Text>
|
|
* </View>
|
|
* </View>
|
|
* )
|
|
* }
|
|
* }
|
|
*
|
|
* const styles = StyleSheet.create({
|
|
* container: {
|
|
* flex: 1,
|
|
* justifyContent: 'center',
|
|
* paddingHorizontal: 10
|
|
* },
|
|
* button: {
|
|
* alignItems: 'center',
|
|
* backgroundColor: '#DDDDDD',
|
|
* padding: 10
|
|
* },
|
|
* countContainer: {
|
|
* alignItems: 'center',
|
|
* padding: 10
|
|
* },
|
|
* countText: {
|
|
* color: '#FF00FF'
|
|
* }
|
|
* })
|
|
*
|
|
* AppRegistry.registerComponent('App', () => App)
|
|
* ```
|
|
*
|
|
*/
|
|
|
|
var TouchableHighlight = createReactClass({
|
|
displayName: 'TouchableHighlight',
|
|
propTypes: {
|
|
...TouchableWithoutFeedback.propTypes,
|
|
/**
|
|
* Determines what the opacity of the wrapped view should be when touch is
|
|
* active.
|
|
*/
|
|
activeOpacity: PropTypes.number,
|
|
/**
|
|
* The color of the underlay that will show through when the touch is
|
|
* active.
|
|
*/
|
|
underlayColor: ColorPropType,
|
|
style: ViewPropTypes.style,
|
|
/**
|
|
* Called immediately after the underlay is shown
|
|
*/
|
|
onShowUnderlay: PropTypes.func,
|
|
/**
|
|
* Called immediately after the underlay is hidden
|
|
*/
|
|
onHideUnderlay: PropTypes.func,
|
|
/**
|
|
* *(Apple TV only)* TV preferred focus (see documentation for the View component).
|
|
*
|
|
* @platform ios
|
|
*/
|
|
hasTVPreferredFocus: PropTypes.bool,
|
|
/**
|
|
* *(Apple TV only)* Object with properties to control Apple TV parallax effects.
|
|
*
|
|
* enabled: If true, parallax effects are enabled. Defaults to true.
|
|
* shiftDistanceX: Defaults to 2.0.
|
|
* shiftDistanceY: Defaults to 2.0.
|
|
* tiltAngle: Defaults to 0.05.
|
|
* magnification: Defaults to 1.0.
|
|
*
|
|
* @platform ios
|
|
*/
|
|
tvParallaxProperties: PropTypes.object,
|
|
},
|
|
|
|
mixins: [NativeMethodsMixin, TimerMixin, Touchable.Mixin],
|
|
|
|
getDefaultProps: () => DEFAULT_PROPS,
|
|
|
|
// Performance optimization to avoid constantly re-generating these objects.
|
|
_computeSyntheticState: function(props) {
|
|
return {
|
|
activeProps: {
|
|
style: {
|
|
opacity: props.activeOpacity,
|
|
}
|
|
},
|
|
activeUnderlayProps: {
|
|
style: {
|
|
backgroundColor: props.underlayColor,
|
|
}
|
|
},
|
|
underlayStyle: [
|
|
INACTIVE_UNDERLAY_PROPS.style,
|
|
props.style,
|
|
],
|
|
hasTVPreferredFocus: props.hasTVPreferredFocus
|
|
};
|
|
},
|
|
|
|
getInitialState: function() {
|
|
/* $FlowFixMe(>=0.53.0 site=react_native_fb,react_native_oss) This comment
|
|
* suppresses an error when upgrading Flow's support for React. To see the
|
|
* error delete this comment and run Flow. */
|
|
this._isMounted = false;
|
|
return merge(
|
|
this.touchableGetInitialState(), this._computeSyntheticState(this.props)
|
|
);
|
|
},
|
|
|
|
componentDidMount: function() {
|
|
/* $FlowFixMe(>=0.53.0 site=react_native_fb,react_native_oss) This comment
|
|
* suppresses an error when upgrading Flow's support for React. To see the
|
|
* error delete this comment and run Flow. */
|
|
this._isMounted = true;
|
|
ensurePositiveDelayProps(this.props);
|
|
ensureComponentIsNative(this.refs[CHILD_REF]);
|
|
},
|
|
|
|
componentWillUnmount: function() {
|
|
/* $FlowFixMe(>=0.53.0 site=react_native_fb,react_native_oss) This comment
|
|
* suppresses an error when upgrading Flow's support for React. To see the
|
|
* error delete this comment and run Flow. */
|
|
this._isMounted = false;
|
|
},
|
|
|
|
componentDidUpdate: function() {
|
|
ensureComponentIsNative(this.refs[CHILD_REF]);
|
|
},
|
|
|
|
componentWillReceiveProps: function(nextProps) {
|
|
ensurePositiveDelayProps(nextProps);
|
|
if (nextProps.activeOpacity !== this.props.activeOpacity ||
|
|
nextProps.underlayColor !== this.props.underlayColor ||
|
|
nextProps.style !== this.props.style) {
|
|
this.setState(this._computeSyntheticState(nextProps));
|
|
}
|
|
},
|
|
|
|
viewConfig: {
|
|
uiViewClassName: 'RCTView',
|
|
validAttributes: ReactNativeViewAttributes.RCTView
|
|
},
|
|
|
|
/**
|
|
* `Touchable.Mixin` self callbacks. The mixin will invoke these if they are
|
|
* defined on your component.
|
|
*/
|
|
touchableHandleActivePressIn: function(e: Event) {
|
|
this.clearTimeout(this._hideTimeout);
|
|
/* $FlowFixMe(>=0.53.0 site=react_native_fb,react_native_oss) This comment
|
|
* suppresses an error when upgrading Flow's support for React. To see the
|
|
* error delete this comment and run Flow. */
|
|
this._hideTimeout = null;
|
|
this._showUnderlay();
|
|
this.props.onPressIn && this.props.onPressIn(e);
|
|
},
|
|
|
|
touchableHandleActivePressOut: function(e: Event) {
|
|
if (!this._hideTimeout) {
|
|
this._hideUnderlay();
|
|
}
|
|
this.props.onPressOut && this.props.onPressOut(e);
|
|
},
|
|
|
|
touchableHandlePress: function(e: Event) {
|
|
this.clearTimeout(this._hideTimeout);
|
|
this._showUnderlay();
|
|
/* $FlowFixMe(>=0.53.0 site=react_native_fb,react_native_oss) This comment
|
|
* suppresses an error when upgrading Flow's support for React. To see the
|
|
* error delete this comment and run Flow. */
|
|
this._hideTimeout = this.setTimeout(this._hideUnderlay,
|
|
this.props.delayPressOut || 100);
|
|
this.props.onPress && this.props.onPress(e);
|
|
},
|
|
|
|
touchableHandleLongPress: function(e: Event) {
|
|
this.props.onLongPress && this.props.onLongPress(e);
|
|
},
|
|
|
|
touchableGetPressRectOffset: function() {
|
|
return this.props.pressRetentionOffset || PRESS_RETENTION_OFFSET;
|
|
},
|
|
|
|
touchableGetHitSlop: function() {
|
|
return this.props.hitSlop;
|
|
},
|
|
|
|
touchableGetHighlightDelayMS: function() {
|
|
return this.props.delayPressIn;
|
|
},
|
|
|
|
touchableGetLongPressDelayMS: function() {
|
|
return this.props.delayLongPress;
|
|
},
|
|
|
|
touchableGetPressOutDelayMS: function() {
|
|
return this.props.delayPressOut;
|
|
},
|
|
|
|
_showUnderlay: function() {
|
|
if (!this._isMounted || !this._hasPressHandler()) {
|
|
return;
|
|
}
|
|
|
|
this.refs[UNDERLAY_REF].setNativeProps(this.state.activeUnderlayProps);
|
|
this.refs[CHILD_REF].setNativeProps(this.state.activeProps);
|
|
this.props.onShowUnderlay && this.props.onShowUnderlay();
|
|
},
|
|
|
|
_hideUnderlay: function() {
|
|
this.clearTimeout(this._hideTimeout);
|
|
/* $FlowFixMe(>=0.53.0 site=react_native_fb,react_native_oss) This comment
|
|
* suppresses an error when upgrading Flow's support for React. To see the
|
|
* error delete this comment and run Flow. */
|
|
this._hideTimeout = null;
|
|
if (this._hasPressHandler() && this.refs[UNDERLAY_REF]) {
|
|
this.refs[CHILD_REF].setNativeProps(INACTIVE_CHILD_PROPS);
|
|
this.refs[UNDERLAY_REF].setNativeProps({
|
|
...INACTIVE_UNDERLAY_PROPS,
|
|
style: this.state.underlayStyle,
|
|
});
|
|
this.props.onHideUnderlay && this.props.onHideUnderlay();
|
|
}
|
|
},
|
|
|
|
_hasPressHandler: function() {
|
|
return !!(
|
|
this.props.onPress ||
|
|
this.props.onPressIn ||
|
|
this.props.onPressOut ||
|
|
this.props.onLongPress
|
|
);
|
|
},
|
|
|
|
render: function() {
|
|
return (
|
|
<View
|
|
accessible={this.props.accessible !== false}
|
|
/* $FlowFixMe(>=0.53.0 site=react_native_fb,react_native_oss) This
|
|
* comment suppresses an error when upgrading Flow's support for React.
|
|
* To see the error delete this comment and run Flow. */
|
|
accessibilityLabel={this.props.accessibilityLabel}
|
|
accessibilityComponentType={this.props.accessibilityComponentType}
|
|
accessibilityTraits={this.props.accessibilityTraits}
|
|
ref={UNDERLAY_REF}
|
|
style={this.state.underlayStyle}
|
|
onLayout={this.props.onLayout}
|
|
hitSlop={this.props.hitSlop}
|
|
isTVSelectable={true}
|
|
tvParallaxProperties={this.props.tvParallaxProperties}
|
|
hasTVPreferredFocus={this.state.hasTVPreferredFocus}
|
|
onStartShouldSetResponder={this.touchableHandleStartShouldSetResponder}
|
|
onResponderTerminationRequest={this.touchableHandleResponderTerminationRequest}
|
|
onResponderGrant={this.touchableHandleResponderGrant}
|
|
onResponderMove={this.touchableHandleResponderMove}
|
|
onResponderRelease={this.touchableHandleResponderRelease}
|
|
onResponderTerminate={this.touchableHandleResponderTerminate}
|
|
/* $FlowFixMe(>=0.53.0 site=react_native_fb,react_native_oss) This
|
|
* comment suppresses an error when upgrading Flow's support for React.
|
|
* To see the error delete this comment and run Flow. */
|
|
nativeID={this.props.nativeID}
|
|
/* $FlowFixMe(>=0.53.0 site=react_native_fb,react_native_oss) This
|
|
* comment suppresses an error when upgrading Flow's support for React.
|
|
* To see the error delete this comment and run Flow. */
|
|
testID={this.props.testID}>
|
|
{React.cloneElement(
|
|
/* $FlowFixMe(>=0.53.0 site=react_native_fb,react_native_oss) This
|
|
* comment suppresses an error when upgrading Flow's support for
|
|
* React. To see the error delete this comment and run Flow. */
|
|
React.Children.only(this.props.children),
|
|
{
|
|
ref: CHILD_REF,
|
|
}
|
|
)}
|
|
{Touchable.renderDebugView({color: 'green', hitSlop: this.props.hitSlop})}
|
|
</View>
|
|
);
|
|
}
|
|
});
|
|
|
|
var CHILD_REF = keyOf({childRef: null});
|
|
var UNDERLAY_REF = keyOf({underlayRef: null});
|
|
var INACTIVE_CHILD_PROPS = {
|
|
style: StyleSheet.create({x: {opacity: 1.0}}).x,
|
|
};
|
|
var INACTIVE_UNDERLAY_PROPS = {
|
|
style: StyleSheet.create({x: {backgroundColor: 'transparent'}}).x,
|
|
};
|
|
|
|
module.exports = TouchableHighlight;
|