Touchable: add support for 'style' and keyboard

This commit is contained in:
Nicolas Gallagher
2015-09-07 14:40:37 -07:00
parent 38e4de76cd
commit 77fd21ea44
5 changed files with 67 additions and 26 deletions
+10 -2
View File
@@ -1,5 +1,9 @@
# Touchable # 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 ## Props
**activeHighlight** string **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 Sets the opacity of the child view when `onPressIn` is called. The opacity is
reset when `onPressOut` is called. Default: `1`. reset when `onPressOut` is called. Default: `1`.
**component** function or string **children** element
The backing component. Default: `div`. A single child element.
**delayLongPress** number **delayLongPress** number
@@ -36,6 +40,10 @@ Delay in ms, from the release of the touch, before `onPressOut` is called. Defau
**onPressOut** function **onPressOut** function
**style** style
[View](View.md) style
## Examples ## Examples
```js ```js
+1
View File
@@ -57,6 +57,7 @@ therefore `pointerEvents` is excluded from `style`.
+ `bottom` + `bottom`
+ `boxShadow` + `boxShadow`
+ `boxSizing` + `boxSizing`
+ `cursor`
+ `flexBasis` + `flexBasis`
+ `flexDirection` + `flexDirection`
+ `flexGrow` + `flexGrow`
@@ -49,6 +49,7 @@ export default {
boxSizing: string, boxSizing: string,
clear: string, clear: string,
color: string, color: string,
cursor: string,
direction: string, direction: string,
display: string, display: string,
flexBasis: string, flexBasis: string,
+54 -24
View File
@@ -1,5 +1,6 @@
import React, { PropTypes } from 'react' import React, { PropTypes } from 'react'
import Tappable from 'react-tappable' import Tappable from 'react-tappable'
import View from '../View'
class Touchable extends React.Component { class Touchable extends React.Component {
constructor(props, context) { constructor(props, context) {
@@ -7,23 +8,25 @@ class Touchable extends React.Component {
this.state = { this.state = {
isActive: false 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 = { static propTypes = {
activeHighlight: PropTypes.string, activeHighlight: PropTypes.string,
activeOpacity: PropTypes.number, activeOpacity: PropTypes.number,
children: PropTypes.element, children: PropTypes.element,
component: PropTypes.oneOfType([
PropTypes.func,
PropTypes.string
]),
delayLongPress: PropTypes.number, delayLongPress: PropTypes.number,
delayPressIn: PropTypes.number, delayPressIn: PropTypes.number,
delayPressOut: PropTypes.number, delayPressOut: PropTypes.number,
onLongPress: PropTypes.func, onLongPress: PropTypes.func,
onPress: PropTypes.func, onPress: PropTypes.func,
onPressIn: PropTypes.func, onPressIn: PropTypes.func,
onPressOut: PropTypes.func onPressOut: PropTypes.func,
style: View.propTypes.style
} }
static defaultProps = { static defaultProps = {
@@ -32,11 +35,30 @@ class Touchable extends React.Component {
component: 'div', component: 'div',
delayLongPress: 1000, delayLongPress: 1000,
delayPressIn: 0, 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) { _onLongPress(e) {
if (this.props.onLongPress) this.props.onLongPress(e) const event = e
if (this.props.onLongPress) this.props.onLongPress(event)
} }
_onPress(e) { _onPress(e) {
@@ -53,33 +75,41 @@ class Touchable extends React.Component {
if (this.props.onPressOut) this.props.onPressOut(e) 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() { render() {
const { const {
activeHighlight, activeHighlight,
component, delayLongPress,
delayLongPress style
} = this.props } = 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 ( return (
<Tappable <Tappable
children={this._getChildren()} children={this._getChildren()}
component={component} component={View}
onMouseDown={this._onPressIn.bind(this)} onKeyDown={(e) => { this._onKeyEnter(e, this._onPressIn) }}
onMouseUp={this._onPressOut.bind(this)} onKeyPress={this._onPress}
onPress={this._onLongPress.bind(this)} onKeyUp={(e) => { this._onKeyEnter(e, this._onPressOut) }}
onTap={this._onPress.bind(this)} onMouseDown={this._onPressIn}
onTouchEnd={this._onPressOut.bind(this)} onMouseUp={this._onPressOut}
onTouchStart={this._onPressIn.bind(this)} onPress={this._onLongPress}
onTap={this._onPress}
onTouchEnd={this._onPressOut}
onTouchStart={this._onPressIn}
pressDelay={delayLongPress} pressDelay={delayLongPress}
pressMoveThreshold={5} pressMoveThreshold={5}
style={{ backgroundColor: this.state.isActive ? activeHighlight : null }} style={{
...style,
backgroundColor: this.state.isActive ? activeHighlight : null,
cursor: 'pointer',
userSelect: undefined
}}
tabIndex='0'
/> />
) )
} }
@@ -43,6 +43,7 @@ export default {
'bottom', 'bottom',
'boxShadow', 'boxShadow',
'boxSizing', 'boxSizing',
'cursor',
'flexBasis', 'flexBasis',
'flexDirection', 'flexDirection',
'flexGrow', 'flexGrow',