From 77fd21ea44e63bf4c18a025c3312bdac4d721f9b Mon Sep 17 00:00:00 2001 From: Nicolas Gallagher Date: Mon, 7 Sep 2015 14:40:37 -0700 Subject: [PATCH] Touchable: add support for 'style' and keyboard --- docs/components/Touchable.md | 12 ++- docs/components/View.md | 1 + .../CoreComponent/modules/stylePropTypes.js | 1 + src/components/Touchable/index.js | 78 +++++++++++++------ src/components/View/ViewStylePropTypes.js | 1 + 5 files changed, 67 insertions(+), 26 deletions(-) diff --git a/docs/components/Touchable.md b/docs/components/Touchable.md index b7db960a..c9209136 100644 --- a/docs/components/Touchable.md +++ b/docs/components/Touchable.md @@ -1,5 +1,9 @@ # Touchable +A wrapper for making views respond to mouse, keyboard, and touch presses. On +press in, the touchable area can display a highlight color, and the opacity of +the wrapped view can be decreased. + ## Props **activeHighlight** string @@ -12,9 +16,9 @@ highlight is removed when `onPressOut` is called. Default: `transparent`. Sets the opacity of the child view when `onPressIn` is called. The opacity is reset when `onPressOut` is called. Default: `1`. -**component** function or string +**children** element -The backing component. Default: `div`. +A single child element. **delayLongPress** number @@ -36,6 +40,10 @@ Delay in ms, from the release of the touch, before `onPressOut` is called. Defau **onPressOut** function +**style** style + +[View](View.md) style + ## Examples ```js diff --git a/docs/components/View.md b/docs/components/View.md index e5461d5a..efff5924 100644 --- a/docs/components/View.md +++ b/docs/components/View.md @@ -57,6 +57,7 @@ therefore `pointerEvents` is excluded from `style`. + `bottom` + `boxShadow` + `boxSizing` ++ `cursor` + `flexBasis` + `flexDirection` + `flexGrow` diff --git a/src/components/CoreComponent/modules/stylePropTypes.js b/src/components/CoreComponent/modules/stylePropTypes.js index 6c18a6b8..5a8098e2 100644 --- a/src/components/CoreComponent/modules/stylePropTypes.js +++ b/src/components/CoreComponent/modules/stylePropTypes.js @@ -49,6 +49,7 @@ export default { boxSizing: string, clear: string, color: string, + cursor: string, direction: string, display: string, flexBasis: string, diff --git a/src/components/Touchable/index.js b/src/components/Touchable/index.js index f770aa74..948a6fbe 100644 --- a/src/components/Touchable/index.js +++ b/src/components/Touchable/index.js @@ -1,5 +1,6 @@ import React, { PropTypes } from 'react' import Tappable from 'react-tappable' +import View from '../View' class Touchable extends React.Component { constructor(props, context) { @@ -7,23 +8,25 @@ class Touchable extends React.Component { this.state = { isActive: false } + + this._onLongPress = this._onLongPress.bind(this) + this._onPress = this._onPress.bind(this) + this._onPressIn = this._onPressIn.bind(this) + this._onPressOut = this._onPressOut.bind(this) } static propTypes = { activeHighlight: PropTypes.string, activeOpacity: PropTypes.number, children: PropTypes.element, - component: PropTypes.oneOfType([ - PropTypes.func, - PropTypes.string - ]), delayLongPress: PropTypes.number, delayPressIn: PropTypes.number, delayPressOut: PropTypes.number, onLongPress: PropTypes.func, onPress: PropTypes.func, onPressIn: PropTypes.func, - onPressOut: PropTypes.func + onPressOut: PropTypes.func, + style: View.propTypes.style } static defaultProps = { @@ -32,11 +35,30 @@ class Touchable extends React.Component { component: 'div', delayLongPress: 1000, delayPressIn: 0, - delayPressOut: 0 + delayPressOut: 0, + style: View.defaultProps.style + } + + _getChildren() { + const { activeOpacity, children } = this.props + return React.cloneElement(React.Children.only(children), { + style: { + ...children.props.style, + ...(this.state.isActive ? { opacity: activeOpacity } : {}) + } + }) + } + + _onKeyEnter(e, callback) { + var ENTER = 13 + if (e.keyCode === ENTER) { + callback(e) + } } _onLongPress(e) { - if (this.props.onLongPress) this.props.onLongPress(e) + const event = e + if (this.props.onLongPress) this.props.onLongPress(event) } _onPress(e) { @@ -53,33 +75,41 @@ class Touchable extends React.Component { if (this.props.onPressOut) this.props.onPressOut(e) } - _getChildren() { - const { activeOpacity, children } = this.props - return React.cloneElement(React.Children.only(children), { - style: { ...children.props.style, ...(this.state.isActive ? { opacity: activeOpacity } : {}) } - }) - } - render() { const { activeHighlight, - component, - delayLongPress + delayLongPress, + style } = this.props + /** + * Creates a wrapping element that can receive beyboard focus. The + * highlight is applied as a background color on this wrapper. The opacity + * is set on the child element, allowing it to have its own background + * color. + */ return ( { this._onKeyEnter(e, this._onPressIn) }} + onKeyPress={this._onPress} + onKeyUp={(e) => { this._onKeyEnter(e, this._onPressOut) }} + onMouseDown={this._onPressIn} + onMouseUp={this._onPressOut} + onPress={this._onLongPress} + onTap={this._onPress} + onTouchEnd={this._onPressOut} + onTouchStart={this._onPressIn} pressDelay={delayLongPress} pressMoveThreshold={5} - style={{ backgroundColor: this.state.isActive ? activeHighlight : null }} + style={{ + ...style, + backgroundColor: this.state.isActive ? activeHighlight : null, + cursor: 'pointer', + userSelect: undefined + }} + tabIndex='0' /> ) } diff --git a/src/components/View/ViewStylePropTypes.js b/src/components/View/ViewStylePropTypes.js index ce80621a..272efb7b 100644 --- a/src/components/View/ViewStylePropTypes.js +++ b/src/components/View/ViewStylePropTypes.js @@ -43,6 +43,7 @@ export default { 'bottom', 'boxShadow', 'boxSizing', + 'cursor', 'flexBasis', 'flexDirection', 'flexGrow',