/* eslint-disable */ /** * 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 TouchableOpacity * @noflow */ 'use strict'; // Note (avik): add @flow when Flow supports spread properties in propTypes var NativeMethodsMixin = require('../../modules/NativeMethodsMixin'); var React = require('react'); var StyleSheet = require('../../apis/StyleSheet'); var TimerMixin = require('react-timer-mixin'); var Touchable = require('./Touchable'); var TouchableWithoutFeedback = require('./TouchableWithoutFeedback'); var View = require('../View'); var ensurePositiveDelayProps = require('./ensurePositiveDelayProps'); var flattenStyle = StyleSheet.flatten; type Event = Object; var 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. * * Example: * * ``` * renderButton: function() { * return ( * * * * ); * }, * ``` */ var TouchableOpacity = React.createClass({ mixins: [TimerMixin, Touchable.Mixin, NativeMethodsMixin], propTypes: { ...TouchableWithoutFeedback.propTypes, /** * Determines what the opacity of the wrapped view should be when touch is * active. */ activeOpacity: React.PropTypes.number, focusedOpacity: React.PropTypes.number }, getDefaultProps: function() { return { activeOpacity: 0.2, focusedOpacity: 0.7 }; }, getInitialState: function() { return this.touchableGetInitialState(); }, componentDidMount: function() { ensurePositiveDelayProps(this.props); }, componentWillReceiveProps: function(nextProps) { ensurePositiveDelayProps(nextProps); }, setOpacityTo: function(value: number, duration: number) { this.setNativeProps({ style: { opacity: value, transitionDuration: `${duration / 1000}s` } }); }, /** * `Touchable.Mixin` self callbacks. The mixin will invoke these if they are * defined on your component. */ touchableHandleActivePressIn: function(e: Event) { if (e.dispatchConfig.registrationName === 'onResponderGrant') { this._opacityActive(0); } else { this._opacityActive(150); } this.props.onPressIn && this.props.onPressIn(e); }, touchableHandleActivePressOut: function(e: Event) { this._opacityInactive(250); this.props.onPressOut && this.props.onPressOut(e); }, touchableHandlePress: function(e: Event) { 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 || 0; }, touchableGetLongPressDelayMS: function() { return this.props.delayLongPress === 0 ? 0 : this.props.delayLongPress || 500; }, touchableGetPressOutDelayMS: function() { return this.props.delayPressOut; }, _opacityActive: function(duration: number) { this.setOpacityTo(this.props.activeOpacity, duration); }, _opacityInactive: function(duration: number) { var childStyle = flattenStyle(this.props.style) || {}; this.setOpacityTo(childStyle.opacity === undefined ? 1 : childStyle.opacity, duration); }, _opacityFocused: function() { this.setOpacityTo(this.props.focusedOpacity); }, _onKeyEnter(e, callback) { var ENTER = 13; if ((e.type === 'keypress' ? e.charCode : e.keyCode) === ENTER) { callback && callback(e); } }, render: function() { const { children, /* eslint-disable */ activeOpacity, focusedOpacity, delayLongPress, delayPressIn, delayPressOut, onLongPress, onPress, onPressIn, onPressOut, pressRetentionOffset, /* eslint-enable */ ...other } = this.props; return ( { 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} onResponderGrant={this.touchableHandleResponderGrant} onResponderMove={this.touchableHandleResponderMove} onResponderRelease={this.touchableHandleResponderRelease} onResponderTerminate={this.touchableHandleResponderTerminate} tabIndex={this.props.disabled ? null : '0'} > {children} {Touchable.renderDebugView({ color: 'blue', hitSlop: this.props.hitSlop })} ); } }); var styles = StyleSheet.create({ root: { cursor: 'pointer', transitionProperty: 'opacity', transitionDuration: '0.15s', userSelect: 'none' }, disabled: { cursor: 'default' } }); module.exports = TouchableOpacity;