Skip to content

Commit

Permalink
feat(components-rn): clickable View with PanResponder
Browse files Browse the repository at this point in the history
  • Loading branch information
Manjiz committed Jun 5, 2019
1 parent 43724d9 commit 2c1d78e
Show file tree
Hide file tree
Showing 4 changed files with 299 additions and 328 deletions.
242 changes: 148 additions & 94 deletions packages/taro-components-rn/src/components/ClickableSimplified/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,56 +13,14 @@

import * as React from 'react'
import {
TouchableWithoutFeedback,
GestureResponderEvent
PanResponder,
GestureResponderEvent,
} from 'react-native'
import { omit, noop } from '../../utils'
import { omit } from '../../utils'
import { ClickableProps } from './PropsType'

const getWxAppEvent = (event: GestureResponderEvent) => {
event.persist()
const nativeEvent = event.nativeEvent || {}
const { timestamp, target, pageX, pageY, touches = [], changedTouches = [] } = nativeEvent
return {
type: 'tap',
timeStamp: timestamp,
target: {
id: target,
dataset: {}
},
currentTarget: {
id: target,
dataset: {}
},
detail: {
x: pageX,
y: pageY
},
touches: touches.map((item) => {
return {
identifier: item.identifier,
pageX: item.pageX,
pageY: item.pageY,
clientX: item.locationX,
clientY: item.locationY
}
}),
changedTouches: changedTouches.map((item) => {
return {
identifier: item.identifier,
pageX: item.pageX,
pageY: item.pageY,
clientX: item.locationX,
clientY: item.locationY
}
})
}
}

export default function clickableSimplified (WrappedComponent: React.ComponentType<any>) {
class ClickableSimplified extends React.Component<ClickableProps, any> {
static displayName: string = 'Component'

export default function (WrappedComponent: React.ComponentType<any>) {
return class _Clickable extends React.Component<ClickableProps> {
static defaultProps = {
hoverStartTime: 20,
hoverStayTime: 70
Expand All @@ -72,77 +30,173 @@ export default function clickableSimplified (WrappedComponent: React.ComponentTy
isHover: false
}

onPress = (evt: GestureResponderEvent) => {
const { onClick = noop } = this.props
onClick(getWxAppEvent(evt))
startTimestamp: number = 0
startTimer: any
stayTimer: any

panResponder: any = PanResponder.create({
onStartShouldSetPanResponder: (evt: GestureResponderEvent, gestureState) => {
const {
hoverStyle,
onClick,
onLongPress,
onTouchstart,
// onTouchmove,
// onTouchcancel,
onTouchend
} = this.props
return !!(hoverStyle || onClick || onLongPress || onTouchstart || onTouchend)
},
// onMoveShouldSetPanResponder: (evt: GestureResponderEvent, gestureState) => {
// const { onTouchmove, onTouchcancel, onTouchend } = this.props
// return !!(onTouchmove || onTouchcancel || onTouchend)
// },
onPanResponderGrant: (evt: GestureResponderEvent, gestureState) => {
const { onTouchstart } = this.props
onTouchstart && onTouchstart(this.getWxAppEvent(evt))
this.startTimestamp = evt.nativeEvent.timestamp
this.setStartTimer()
},
// onPanResponderMove: (evt: GestureResponderEvent, gestureState) => {
// const { onTouchmove } = this.props
// onTouchmove && onTouchmove(this.getWxAppEvent(evt))
// },
onPanResponderTerminationRequest: (evt: GestureResponderEvent, gestureState) => true,
onPanResponderRelease: (evt: GestureResponderEvent, gestureState) => {
const { onClick, onLongPress, onTouchend } = this.props
onTouchend && onTouchend(this.getWxAppEvent(evt))
const endTimestamp = evt.nativeEvent.timestamp
const gapTime = endTimestamp - this.startTimestamp
const hasMove = Math.abs(gestureState.dx) >= 1 || Math.abs(gestureState.dy) >= 1
if (!hasMove) {
if (gapTime <= 350) {
onClick && onClick(this.getWxAppEvent(evt))
} else {
onLongPress && onLongPress(this.getWxAppEvent(evt))
}
}
this.setStayTimer()
},
onPanResponderTerminate: (evt: GestureResponderEvent, gestureState) => {
// const { onTouchcancel } = this.props
// onTouchcancel && onTouchcancel(this.getWxAppEvent(evt))
this.setStayTimer()
},
})

setStartTimer = () => {
const { hoverStyle, hoverStartTime } = this.props
if (hoverStyle) {
this.startTimer && clearTimeout(this.startTimer)
this.startTimer = setTimeout(() => {
this.setState({ isHover: true })
}, hoverStartTime)
}
}

onLongPress = (evt: GestureResponderEvent) => {
const { onLongPress = noop } = this.props
onLongPress(getWxAppEvent(evt))
setStayTimer = () => {
const { hoverStyle, hoverStayTime } = this.props
this.startTimer && clearTimeout(this.startTimer)
if (hoverStyle) {
this.stayTimer && clearTimeout(this.stayTimer)
this.stayTimer = setTimeout(() => {
this.startTimer && clearTimeout(this.startTimer)
this.state.isHover && this.setState({ isHover: false })
}, hoverStayTime)
}
}

onPressIn = (evt: GestureResponderEvent) => {
const { onTouchstart = noop } = this.props
onTouchstart(getWxAppEvent(evt))
this.setState({ isHover: true })
getWxAppEvent = (event: GestureResponderEvent) => {
const nativeEvent = event.nativeEvent
const { timestamp, target, pageX, pageY, touches = [], changedTouches = [] } = nativeEvent
return {
type: 'tap',
timeStamp: timestamp,
target: {
id: target,
dataset: {}
},
currentTarget: {
id: target,
dataset: {}
},
detail: {
x: pageX,
y: pageY
},
touches: touches.map((item) => {
return {
identifier: item.identifier,
pageX: item.pageX,
pageY: item.pageY,
clientX: item.locationX,
clientY: item.locationY
}
}),
changedTouches: changedTouches.map((item) => {
return {
identifier: item.identifier,
pageX: item.pageX,
pageY: item.pageY,
clientX: item.locationX,
clientY: item.locationY
}
})
}
}

onPressOut = (evt: GestureResponderEvent) => {
const { onTouchend = noop } = this.props
onTouchend(getWxAppEvent(evt))
this.setState({ isHover: false })
componentWillUnmount () {
this.startTimer && clearTimeout(this.startTimer)
this.stayTimer && clearTimeout(this.stayTimer)
}

render () {
const {
style,
hoverStyle,
hoverStartTime,
hoverStayTime,
// hoverStopPropagation,
onClick,
onLongPress,
onTouchstart,
onTouchend
// onTouchmove,
// onTouchcancel,
onTouchend,
} = this.props
const { isHover } = this.state

if (!onClick && !onLongPress && !onTouchstart && !onTouchend) {
if (
!hoverStyle &&
// !hoverStopPropagation &&
!onClick &&
!onLongPress &&
!onTouchstart &&
// !onTouchmove &&
// !onTouchcancel &&
!onTouchend
) {
return (
<WrappedComponent {...this.props} />
)
}

return (
<TouchableWithoutFeedback
delayPressIn={hoverStartTime}
delayPressOut={hoverStayTime}
onPress={this.onPress}
onLongPress={this.onLongPress}
onPressIn={this.onPressIn}
onPressOut={this.onPressOut}
>
<WrappedComponent
{...omit(this.props, [
'style',
'hoverStyle',
'hoverStartTime',
'hoverStayTime',
'onClick',
'onLongPress',
'onTouchstart',
'onTouchend'
])}
style={[
style,
this.state.isHover && hoverStyle
]}
/>
</TouchableWithoutFeedback>
<WrappedComponent
{...omit(this.props, [
'style',
'hoverStyle',
'hoverStartTime',
'hoverStayTime',
'onClick',
'onLongPress',
'onTouchstart',
// 'onTouchmove',
// 'onTouchcancel',
'onTouchend'
])}
{...this.panResponder.panHandlers}
style={[style, isHover && hoverStyle]}
/>
)
}
}

ClickableSimplified.displayName = WrappedComponent.displayName || WrappedComponent.name || 'Component'

return ClickableSimplified
}

0 comments on commit 2c1d78e

Please sign in to comment.