mirror of
https://github.com/zhigang1992/react-native-web.git
synced 2026-01-12 22:51:09 +08:00
[add] Update components with native methods
Hack in touch event normalization within `View` to produce events that contain `pageX`, `pageY` for React Native compatibility.
This commit is contained in:
3
.babelrc
3
.babelrc
@@ -3,5 +3,8 @@
|
||||
"es2015",
|
||||
"stage-1",
|
||||
"react"
|
||||
],
|
||||
"plugins": [
|
||||
"transform-decorators-legacy"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -100,12 +100,14 @@ Exported modules:
|
||||
* [`TouchableWithoutFeedback`](docs/components/TouchableWithoutFeedback.md)
|
||||
* [`View`](docs/components/View.md)
|
||||
* APIs
|
||||
* [`Animated`](http://facebook.github.io/react-native/releases/0.20/docs/animated.html) (mirrors React Native)
|
||||
* [`AppRegistry`](docs/apis/AppRegistry.md)
|
||||
* [`AppState`](docs/apis/AppState.md)
|
||||
* [`AsyncStorage`](docs/apis/AsyncStorage.md)
|
||||
* [`Dimensions`](docs/apis/Dimensions.md)
|
||||
* [`NativeMethods`](docs/apis/NativeMethods.md)
|
||||
* [`NetInfo`](docs/apis/NetInfo.md)
|
||||
* [`PanResponder`](http://facebook.github.io/react-native/releases/0.20/docs/panresponder.html#content) (mirrors React Native)
|
||||
* [`PixelRatio`](docs/apis/PixelRatio.md)
|
||||
* [`Platform`](docs/apis/Platform.md)
|
||||
* [`StyleSheet`](docs/apis/StyleSheet.md)
|
||||
|
||||
@@ -31,7 +31,7 @@ module.exports = {
|
||||
],
|
||||
resolve: {
|
||||
alias: {
|
||||
'react-native': path.join(__dirname, '../dist/react-native-web')
|
||||
'react-native': path.join(__dirname, '../src')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { NativeMethodsDecorator } from '../../modules/NativeMethodsMixin'
|
||||
import React, { Component, PropTypes } from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
import StyleSheet from '../../apis/StyleSheet'
|
||||
@@ -18,6 +19,7 @@ const keyframeEffects = [
|
||||
{ transform: 'scale(0.95)', opacity: 0.5 }
|
||||
]
|
||||
|
||||
@NativeMethodsDecorator
|
||||
export default class ActivityIndicator extends Component {
|
||||
static propTypes = {
|
||||
animating: PropTypes.bool,
|
||||
@@ -39,19 +41,11 @@ export default class ActivityIndicator extends Component {
|
||||
if (document.documentElement.animate) {
|
||||
this._player = ReactDOM.findDOMNode(this._indicatorRef).animate(keyframeEffects, animationEffectTimingProperties)
|
||||
}
|
||||
if (this.props.animating) {
|
||||
this._player.play()
|
||||
} else {
|
||||
this._player.cancel()
|
||||
}
|
||||
this._manageAnimation()
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
if (this.props.animating) {
|
||||
this._player.play()
|
||||
} else {
|
||||
this._player.cancel()
|
||||
}
|
||||
this._manageAnimation()
|
||||
}
|
||||
|
||||
render() {
|
||||
@@ -77,6 +71,16 @@ export default class ActivityIndicator extends Component {
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
_manageAnimation() {
|
||||
if (this._player) {
|
||||
if (this.props.animating) {
|
||||
this._player.play()
|
||||
} else {
|
||||
this._player.cancel()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { NativeMethodsDecorator } from '../../modules/NativeMethodsMixin'
|
||||
import React, { Component, PropTypes } from 'react'
|
||||
import StyleSheet from '../../apis/StyleSheet'
|
||||
|
||||
@@ -17,6 +18,7 @@ const roleComponents = {
|
||||
region: 'section'
|
||||
}
|
||||
|
||||
@NativeMethodsDecorator
|
||||
export default class CoreComponent extends Component {
|
||||
static propTypes = {
|
||||
accessibilityLabel: PropTypes.string,
|
||||
|
||||
10
src/components/Image/ImageResizeMode.js
Normal file
10
src/components/Image/ImageResizeMode.js
Normal file
@@ -0,0 +1,10 @@
|
||||
import keyMirror from 'fbjs/lib/keyMirror';
|
||||
|
||||
const ImageResizeMode = keyMirror({
|
||||
contain: null,
|
||||
cover: null,
|
||||
none: null,
|
||||
stretch: null
|
||||
})
|
||||
|
||||
export default ImageResizeMode
|
||||
@@ -1,6 +1,8 @@
|
||||
/* global window */
|
||||
import { NativeMethodsDecorator } from '../../modules/NativeMethodsMixin'
|
||||
import StyleSheet from '../../apis/StyleSheet'
|
||||
import CoreComponent from '../CoreComponent'
|
||||
import ImageResizeMode from './ImageResizeMode'
|
||||
import ImageStylePropTypes from './ImageStylePropTypes'
|
||||
import React, { Component, PropTypes } from 'react'
|
||||
import StyleSheetPropType from '../../apis/StyleSheet/StyleSheetPropType'
|
||||
@@ -12,17 +14,8 @@ const STATUS_LOADING = 'LOADING'
|
||||
const STATUS_PENDING = 'PENDING'
|
||||
const STATUS_IDLE = 'IDLE'
|
||||
|
||||
@NativeMethodsDecorator
|
||||
export default class Image extends Component {
|
||||
constructor(props, context) {
|
||||
super(props, context)
|
||||
const { uri } = props.source
|
||||
// state
|
||||
this.state = { status: uri ? STATUS_PENDING : STATUS_IDLE }
|
||||
// autobinding
|
||||
this._onError = this._onError.bind(this)
|
||||
this._onLoad = this._onLoad.bind(this)
|
||||
}
|
||||
|
||||
static propTypes = {
|
||||
accessibilityLabel: CoreComponent.propTypes.accessibilityLabel,
|
||||
accessible: CoreComponent.propTypes.accessible,
|
||||
@@ -45,6 +38,18 @@ export default class Image extends Component {
|
||||
source: {}
|
||||
};
|
||||
|
||||
static resizeMode = ImageResizeMode;
|
||||
|
||||
constructor(props, context) {
|
||||
super(props, context)
|
||||
const { uri } = props.source
|
||||
// state
|
||||
this.state = { status: uri ? STATUS_PENDING : STATUS_IDLE }
|
||||
// autobinding
|
||||
this._onError = this._onError.bind(this)
|
||||
this._onLoad = this._onLoad.bind(this)
|
||||
}
|
||||
|
||||
_createImageLoader() {
|
||||
const { source } = this.props
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { NativeMethodsDecorator } from '../../modules/NativeMethodsMixin'
|
||||
import React, { Component, PropTypes } from 'react'
|
||||
import ScrollView from '../ScrollView'
|
||||
|
||||
@NativeMethodsDecorator
|
||||
export default class ListView extends Component {
|
||||
static propTypes = {
|
||||
children: PropTypes.any,
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import invariant from 'invariant'
|
||||
import invariant from 'fbjs/lib/invariant'
|
||||
import Platform from '../../apis/Platform'
|
||||
import React, { Component, PropTypes } from 'react'
|
||||
import StyleSheet from '../../apis/StyleSheet'
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import { NativeMethodsDecorator } from '../../modules/NativeMethodsMixin'
|
||||
import debounce from 'lodash.debounce'
|
||||
import React, { Component, PropTypes } from 'react'
|
||||
import StyleSheet from '../../apis/StyleSheet'
|
||||
import View from '../View'
|
||||
|
||||
@NativeMethodsDecorator
|
||||
export default class ScrollView extends Component {
|
||||
static propTypes = {
|
||||
children: PropTypes.any,
|
||||
@@ -91,7 +93,6 @@ export default class ScrollView extends Component {
|
||||
|
||||
return (
|
||||
<View
|
||||
_className='ScrollView'
|
||||
onScroll={(e) => this._onScroll(e)}
|
||||
onTouchMove={(e) => this._maybePreventScroll(e)}
|
||||
onWheel={(e) => this._maybePreventScroll(e)}
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import { NativeMethodsDecorator } from '../../modules/NativeMethodsMixin'
|
||||
import CoreComponent from '../CoreComponent'
|
||||
import React, { Component, PropTypes } from 'react'
|
||||
import StyleSheet from '../../apis/StyleSheet'
|
||||
import StyleSheetPropType from '../../apis/StyleSheet/StyleSheetPropType'
|
||||
import TextStylePropTypes from './TextStylePropTypes'
|
||||
|
||||
@NativeMethodsDecorator
|
||||
export default class Text extends Component {
|
||||
static propTypes = {
|
||||
accessibilityLabel: CoreComponent.propTypes.accessibilityLabel,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { NativeMethodsDecorator } from '../../modules/NativeMethodsMixin'
|
||||
import CoreComponent from '../CoreComponent'
|
||||
import React, { Component, PropTypes } from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
@@ -6,12 +7,8 @@ import Text from '../Text'
|
||||
import TextareaAutosize from 'react-textarea-autosize'
|
||||
import View from '../View'
|
||||
|
||||
@NativeMethodsDecorator
|
||||
export default class TextInput extends Component {
|
||||
constructor(props, context) {
|
||||
super(props, context)
|
||||
this.state = { showPlaceholder: !props.value && !props.defaultValue }
|
||||
}
|
||||
|
||||
static propTypes = {
|
||||
...View.propTypes,
|
||||
autoComplete: PropTypes.bool,
|
||||
@@ -47,6 +44,23 @@ export default class TextInput extends Component {
|
||||
style: {}
|
||||
};
|
||||
|
||||
constructor(props, context) {
|
||||
super(props, context)
|
||||
this.state = { showPlaceholder: !props.value && !props.defaultValue }
|
||||
}
|
||||
|
||||
blur() {
|
||||
this.refs.input.blur()
|
||||
}
|
||||
|
||||
focus() {
|
||||
this.refs.input.focus()
|
||||
}
|
||||
|
||||
setNativeProps(props) {
|
||||
this.refs.input.setNativeProps(props)
|
||||
}
|
||||
|
||||
_onBlur(e) {
|
||||
const { onBlur } = this.props
|
||||
const value = e.target.value
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import { NativeMethodsDecorator } from '../../modules/NativeMethodsMixin'
|
||||
import CoreComponent from '../CoreComponent'
|
||||
import React, { Component, PropTypes } from 'react'
|
||||
import StyleSheet from '../../apis/StyleSheet'
|
||||
import StyleSheetPropType from '../../apis/StyleSheet/StyleSheetPropType'
|
||||
import ViewStylePropTypes from './ViewStylePropTypes'
|
||||
|
||||
@NativeMethodsDecorator
|
||||
export default class View extends Component {
|
||||
static propTypes = {
|
||||
accessibilityLabel: CoreComponent.propTypes.accessibilityLabel,
|
||||
@@ -11,6 +13,26 @@ export default class View extends Component {
|
||||
accessibilityRole: CoreComponent.propTypes.accessibilityRole,
|
||||
accessible: CoreComponent.propTypes.accessible,
|
||||
children: PropTypes.any,
|
||||
onClick: PropTypes.func,
|
||||
onClickCapture: PropTypes.func,
|
||||
onMoveShouldSetResponder: PropTypes.func,
|
||||
onMoveShouldSetResponderCapture: PropTypes.func,
|
||||
onResponderGrant: PropTypes.func,
|
||||
onResponderMove: PropTypes.func,
|
||||
onResponderReject: PropTypes.func,
|
||||
onResponderRelease: PropTypes.func,
|
||||
onResponderTerminate: PropTypes.func,
|
||||
onResponderTerminationRequest: PropTypes.func,
|
||||
onStartShouldSetResponder: PropTypes.func,
|
||||
onStartShouldSetResponderCapture: PropTypes.func,
|
||||
onTouchCancel: PropTypes.func,
|
||||
onTouchCancelCapture: PropTypes.func,
|
||||
onTouchEnd: PropTypes.func,
|
||||
onTouchEndCapture: PropTypes.func,
|
||||
onTouchMove: PropTypes.func,
|
||||
onTouchMoveCapture: PropTypes.func,
|
||||
onTouchStart: PropTypes.func,
|
||||
onTouchStartCapture: PropTypes.func,
|
||||
pointerEvents: PropTypes.oneOf(['auto', 'box-none', 'box-only', 'none']),
|
||||
style: StyleSheetPropType(ViewStylePropTypes),
|
||||
testID: CoreComponent.propTypes.testID
|
||||
@@ -20,6 +42,20 @@ export default class View extends Component {
|
||||
accessible: true
|
||||
};
|
||||
|
||||
constructor(props, context) {
|
||||
super(props, context)
|
||||
this._handleClick = this._handleClick.bind(this)
|
||||
this._handleClickCapture = this._handleClickCapture.bind(this)
|
||||
this._handleTouchCancel = this._handleTouchCancel.bind(this)
|
||||
this._handleTouchCancelCapture = this._handleTouchCancelCapture.bind(this)
|
||||
this._handleTouchEnd = this._handleTouchEnd.bind(this)
|
||||
this._handleTouchEndCapture = this._handleTouchEndCapture.bind(this)
|
||||
this._handleTouchMove = this._handleTouchMove.bind(this)
|
||||
this._handleTouchMoveCapture = this._handleTouchMoveCapture.bind(this)
|
||||
this._handleTouchStart = this._handleTouchStart.bind(this)
|
||||
this._handleTouchStartCapture = this._handleTouchStartCapture.bind(this)
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
pointerEvents,
|
||||
@@ -32,6 +68,16 @@ export default class View extends Component {
|
||||
return (
|
||||
<CoreComponent
|
||||
{...other}
|
||||
onClick={this._handleClick}
|
||||
onClickCapture={this._handleClickCapture}
|
||||
onTouchCancel={this._handleTouchCancel}
|
||||
onTouchCancelCapture={this._handleTouchCancelCapture}
|
||||
onTouchEnd={this._handleTouchEnd}
|
||||
onTouchEndCapture={this._handleTouchEndCapture}
|
||||
onTouchMove={this._handleTouchMove}
|
||||
onTouchMoveCapture={this._handleTouchMoveCapture}
|
||||
onTouchStart={this._handleTouchStart}
|
||||
onTouchStartCapture={this._handleTouchStartCapture}
|
||||
style={[
|
||||
styles.initial,
|
||||
style,
|
||||
@@ -40,6 +86,80 @@ export default class View extends Component {
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* React Native expects `pageX` and `pageY` to be on the `nativeEvent`, but
|
||||
* React doesn't include them for touch events.
|
||||
*/
|
||||
_normalizeTouchEvent(event) {
|
||||
const { pageX, changedTouches } = event.nativeEvent
|
||||
if (pageX === undefined) {
|
||||
const { pageX, pageY } = changedTouches[0]
|
||||
event.nativeEvent.pageX = pageX
|
||||
event.nativeEvent.pageY = pageY
|
||||
}
|
||||
return event
|
||||
}
|
||||
|
||||
_handleClick(e) {
|
||||
if (this.props.onClick) {
|
||||
this.props.onClick(this._normalizeTouchEvent(e))
|
||||
}
|
||||
}
|
||||
|
||||
_handleClickCapture(e) {
|
||||
if (this.props.onClickCapture) {
|
||||
this.props.onClickCapture(this._normalizeTouchEvent(e))
|
||||
}
|
||||
}
|
||||
|
||||
_handleTouchCancel(e) {
|
||||
if (this.props.onTouchCancel) {
|
||||
this.props.onTouchCancel(this._normalizeTouchEvent(e))
|
||||
}
|
||||
}
|
||||
|
||||
_handleTouchCancelCapture(e) {
|
||||
if (this.props.onTouchCancelCapture) {
|
||||
this.props.onTouchCancelCapture(this._normalizeTouchEvent(e))
|
||||
}
|
||||
}
|
||||
|
||||
_handleTouchEnd(e) {
|
||||
if (this.props.onTouchEnd) {
|
||||
this.props.onTouchEnd(this._normalizeTouchEvent(e))
|
||||
}
|
||||
}
|
||||
|
||||
_handleTouchEndCapture(e) {
|
||||
if (this.props.onTouchEndCapture) {
|
||||
this.props.onTouchEndCapture(this._normalizeTouchEvent(e))
|
||||
}
|
||||
}
|
||||
|
||||
_handleTouchMove(e) {
|
||||
if (this.props.onTouchMove) {
|
||||
this.props.onTouchMove(this._normalizeTouchEvent(e))
|
||||
}
|
||||
}
|
||||
|
||||
_handleTouchMoveCapture(e) {
|
||||
if (this.props.onTouchMoveCapture) {
|
||||
this.props.onTouchMoveCapture(this._normalizeTouchEvent(e))
|
||||
}
|
||||
}
|
||||
|
||||
_handleTouchStart(e) {
|
||||
if (this.props.onTouchStart) {
|
||||
this.props.onTouchStart(this._normalizeTouchEvent(e))
|
||||
}
|
||||
}
|
||||
|
||||
_handleTouchStartCapture(e) {
|
||||
if (this.props.onTouchStartCapture) {
|
||||
this.props.onTouchStartCapture(this._normalizeTouchEvent(e))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
|
||||
@@ -90,11 +90,11 @@ const mountSafeCallback = (context: Component, callback: ?Function) => () => {
|
||||
return callback.apply(context, arguments)
|
||||
}
|
||||
|
||||
export default NativeMethodsMixin
|
||||
|
||||
export const nativeMethodsDecorator = (Component) => {
|
||||
export const NativeMethodsDecorator = (Component) => {
|
||||
Object.keys(NativeMethodsMixin).forEach((method) => {
|
||||
Component.prototype[method] = NativeMethodsMixin[method]
|
||||
})
|
||||
return Component
|
||||
}
|
||||
|
||||
export default NativeMethodsMixin
|
||||
|
||||
Reference in New Issue
Block a user