/** * 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 Animated = require('Animated'); var NativeMethodsMixin = require('NativeMethodsMixin'); var React = require('React'); var TimerMixin = require('react-timer-mixin'); var Touchable = require('Touchable'); var TouchableWithoutFeedback = require('TouchableWithoutFeedback'); var ensurePositiveDelayProps = require('ensurePositiveDelayProps'); var flattenStyle = require('flattenStyle'); 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, }, getDefaultProps: function() { return { activeOpacity: 0.2, }; }, getInitialState: function() { return { ...this.touchableGetInitialState(), anim: new Animated.Value(1), }; }, componentDidMount: function() { ensurePositiveDelayProps(this.props); }, componentWillReceiveProps: function(nextProps) { ensurePositiveDelayProps(nextProps); }, setOpacityTo: function(value) { Animated.timing( this.state.anim, {toValue: value, duration: 150} ).start(); }, /** * `Touchable.Mixin` self callbacks. The mixin will invoke these if they are * defined on your component. */ touchableHandleActivePressIn: function(e: Event) { this.clearTimeout(this._hideTimeout); this._hideTimeout = null; this._opacityActive(); this.props.onPressIn && this.props.onPressIn(e); }, touchableHandleActivePressOut: function(e: Event) { if (!this._hideTimeout) { this._opacityInactive(); } this.props.onPressOut && this.props.onPressOut(e); }, touchableHandlePress: function(e: Event) { this.clearTimeout(this._hideTimeout); this._opacityActive(); this._hideTimeout = this.setTimeout( this._opacityInactive, 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; }, 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() { this.setOpacityTo(this.props.activeOpacity); }, _opacityInactive: function() { this.clearTimeout(this._hideTimeout); this._hideTimeout = null; var childStyle = flattenStyle(this.props.style) || {}; this.setOpacityTo( childStyle.opacity === undefined ? 1 : childStyle.opacity ); }, render: function() { return ( {this.props.children} ); }, }); module.exports = TouchableOpacity;