mirror of
https://github.com/zhigang1992/react-native-web.git
synced 2026-04-24 12:35:31 +08:00
Add new components
- ActivityIndicator - Portal - StaticContainer - StaticRenderer
This commit is contained in:
@@ -20,34 +20,4 @@ suite('ReactNativeWeb', () => {
|
||||
assert.ok(React.renderToStaticMarkup)
|
||||
})
|
||||
})
|
||||
|
||||
suite('render methods', () => {
|
||||
const id = 'test'
|
||||
let div
|
||||
|
||||
setup(() => {
|
||||
div = document.createElement('div')
|
||||
div.id = id
|
||||
document.body.appendChild(div)
|
||||
})
|
||||
|
||||
teardown(() => {
|
||||
document.body.removeChild(div)
|
||||
})
|
||||
|
||||
test('"render" creates style sheet', () => {
|
||||
React.render(<div />, div)
|
||||
assert.ok(document.getElementById('react-stylesheet'))
|
||||
})
|
||||
|
||||
test('"renderToString" creates style sheet', () => {
|
||||
const result = React.renderToString(<div />)
|
||||
assert.ok(result.indexOf('react-stylesheet') > -1)
|
||||
})
|
||||
|
||||
test('"renderToStaticMarkup" creates style sheet', () => {
|
||||
const result = React.renderToStaticMarkup(<div />)
|
||||
assert.ok(result.indexOf('react-stylesheet') > -1)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
5
src/components/ActivityIndicator/__tests__/index-test.js
Normal file
5
src/components/ActivityIndicator/__tests__/index-test.js
Normal file
@@ -0,0 +1,5 @@
|
||||
/* eslint-env mocha */
|
||||
|
||||
suite('components/ActivityIndicator', () => {
|
||||
test.skip('NO TEST COVERAGE', () => {})
|
||||
})
|
||||
108
src/components/ActivityIndicator/index.js
Normal file
108
src/components/ActivityIndicator/index.js
Normal file
@@ -0,0 +1,108 @@
|
||||
import React, { Component, PropTypes } from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
import StyleSheet from '../../apis/StyleSheet'
|
||||
import View from '../View'
|
||||
|
||||
const GRAY = '#999999'
|
||||
|
||||
const animationEffectTimingProperties = {
|
||||
direction: 'alternate',
|
||||
duration: 700,
|
||||
easing: 'ease-in-out',
|
||||
fill: 'forwards',
|
||||
iterations: Infinity
|
||||
}
|
||||
|
||||
const keyframeEffects = [
|
||||
{ transform: 'scale(1)', opacity: 1.0 },
|
||||
{ transform: 'scale(0.95)', opacity: 0.5 }
|
||||
]
|
||||
|
||||
export default class ActivityIndicator extends Component {
|
||||
static propTypes = {
|
||||
animating: PropTypes.bool,
|
||||
color: PropTypes.string,
|
||||
hidesWhenStopped: PropTypes.bool,
|
||||
size: PropTypes.oneOf(['small', 'large']),
|
||||
style: PropTypes.object
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
animating: true,
|
||||
color: GRAY,
|
||||
hidesWhenStopped: true,
|
||||
size: 'small',
|
||||
style: {}
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
if (document.documentElement.animate) {
|
||||
this._player = ReactDOM.findDOMNode(this._indicatorRef).animate(keyframeEffects, animationEffectTimingProperties)
|
||||
}
|
||||
if (this.props.animating) {
|
||||
this._player.play()
|
||||
} else {
|
||||
this._player.cancel()
|
||||
}
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
if (this.props.animating) {
|
||||
this._player.play()
|
||||
} else {
|
||||
this._player.cancel()
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
animating,
|
||||
color,
|
||||
hidesWhenStopped,
|
||||
size,
|
||||
style,
|
||||
...other
|
||||
} = this.props
|
||||
|
||||
return (
|
||||
<View {...other} style={{ ...styles.container, ...style }}>
|
||||
<View
|
||||
ref={(c) => { this._indicatorRef = c }}
|
||||
style={{
|
||||
...styles.indicator[size],
|
||||
...(hidesWhenStopped && !animating && styles.hidesWhenStopped),
|
||||
borderColor: color
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const indicatorStyle = StyleSheet.create({
|
||||
borderRadius: 100,
|
||||
borderWidth: 3
|
||||
})
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center'
|
||||
},
|
||||
hidesWhenStopped: {
|
||||
visibility: 'hidden'
|
||||
},
|
||||
indicator: {
|
||||
small: {
|
||||
...indicatorStyle,
|
||||
width: 20,
|
||||
height: 20
|
||||
},
|
||||
large: {
|
||||
...indicatorStyle,
|
||||
borderWidth: 4,
|
||||
width: 36,
|
||||
height: 36
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { PropTypes } from 'react'
|
||||
import React, { Component, PropTypes } from 'react'
|
||||
import StylePropTypes from '../../apis/StyleSheet/StylePropTypes'
|
||||
import StyleSheet from '../../apis/StyleSheet'
|
||||
|
||||
@@ -18,7 +18,7 @@ const roleComponents = {
|
||||
region: 'section'
|
||||
}
|
||||
|
||||
class CoreComponent extends React.Component {
|
||||
export default class CoreComponent extends Component {
|
||||
static propTypes = {
|
||||
accessibilityLabel: PropTypes.string,
|
||||
accessibilityLiveRegion: PropTypes.oneOf([ 'assertive', 'off', 'polite' ]),
|
||||
@@ -66,5 +66,3 @@ class CoreComponent extends React.Component {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default CoreComponent
|
||||
|
||||
@@ -3,7 +3,7 @@ import { pickProps } from '../../modules/filterObjectProps'
|
||||
import StyleSheet from '../../apis/StyleSheet'
|
||||
import CoreComponent from '../CoreComponent'
|
||||
import ImageStylePropTypes from './ImageStylePropTypes'
|
||||
import React, { PropTypes } from 'react'
|
||||
import React, { Component, PropTypes } from 'react'
|
||||
import View from '../View'
|
||||
|
||||
const STATUS_ERRORED = 'ERRORED'
|
||||
@@ -52,7 +52,7 @@ const styles = StyleSheet.create({
|
||||
}
|
||||
})
|
||||
|
||||
class Image extends React.Component {
|
||||
export default class Image extends Component {
|
||||
constructor(props, context) {
|
||||
super(props, context)
|
||||
const { uri } = props.source
|
||||
@@ -209,5 +209,3 @@ class Image extends React.Component {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default Image
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React, { PropTypes } from 'react'
|
||||
import React, { Component, PropTypes } from 'react'
|
||||
import ScrollView from '../ScrollView'
|
||||
|
||||
class ListView extends React.Component {
|
||||
export default class ListView extends Component {
|
||||
static propTypes = {
|
||||
children: PropTypes.any,
|
||||
style: PropTypes.style
|
||||
@@ -17,5 +17,3 @@ class ListView extends React.Component {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default ListView
|
||||
|
||||
156
src/components/Portal/index.js
Normal file
156
src/components/Portal/index.js
Normal file
@@ -0,0 +1,156 @@
|
||||
/**
|
||||
* Copyright 2015-present, Nicolas Gallagher
|
||||
* Copyright 2004-present, Facebook Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import invariant from 'invariant'
|
||||
import Platform from '../../apis/Platform'
|
||||
import React, { Component, PropTypes } from 'react'
|
||||
import StyleSheet from '../../apis/StyleSheet'
|
||||
import View from '../View'
|
||||
|
||||
let _portalRef: any
|
||||
// unique identifiers for modals
|
||||
let lastUsedTag = 0
|
||||
|
||||
/**
|
||||
* A container that renders all the modals on top of everything else in the application.
|
||||
*/
|
||||
export default class Portal extends Component {
|
||||
static propTypes = {
|
||||
onModalVisibilityChanged: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a new unique tag.
|
||||
*/
|
||||
static allocateTag(): string {
|
||||
return `__modal_${++lastUsedTag}`
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a new modal.
|
||||
*/
|
||||
static showModal(tag: string, component: any) {
|
||||
if (!_portalRef) {
|
||||
console.error('Calling showModal but no "Portal" has been rendered.')
|
||||
return
|
||||
}
|
||||
_portalRef._showModal(tag, component)
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a modal from the collection of modals to be rendered.
|
||||
*/
|
||||
static closeModal(tag: string) {
|
||||
if (!_portalRef) {
|
||||
console.error('Calling closeModal but no "Portal" has been rendered.')
|
||||
return
|
||||
}
|
||||
_portalRef._closeModal(tag)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an array of all the open modals, as identified by their tag string.
|
||||
*/
|
||||
static getOpenModals(): Array<string> {
|
||||
if (!_portalRef) {
|
||||
console.error('Calling getOpenModals but no "Portal" has been rendered.')
|
||||
return []
|
||||
}
|
||||
return _portalRef._getOpenModals()
|
||||
}
|
||||
|
||||
static notifyAccessibilityService() {
|
||||
if (!_portalRef) {
|
||||
console.error('Calling closeModal but no "Portal" has been rendered.')
|
||||
return
|
||||
}
|
||||
_portalRef._notifyAccessibilityService()
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.state = { modals: {} }
|
||||
this._closeModal = this._closeModal.bind(this)
|
||||
this._getOpenModals = this._getOpenModals.bind(this)
|
||||
this._showModal = this._showModal.bind(this)
|
||||
}
|
||||
|
||||
render() {
|
||||
invariant(
|
||||
_portalRef === this || _portalRef === undefined,
|
||||
'More than one Portal instance detected. Never use <Portal> in your code.'
|
||||
)
|
||||
_portalRef = this
|
||||
if (!this.state.modals) { return null }
|
||||
const modals = []
|
||||
for (const tag in this.state.modals) {
|
||||
modals.push(this.state.modals[tag])
|
||||
}
|
||||
if (modals.length === 0) { return null }
|
||||
|
||||
return (
|
||||
<View style={styles.root}>
|
||||
{modals}
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
_closeModal(tag: string) {
|
||||
if (!this.state.modals.hasOwnProperty(tag)) {
|
||||
return
|
||||
}
|
||||
// We are about to close last modal, so Portal will disappear.
|
||||
// Let's enable accessibility for application view.
|
||||
if (this._getOpenModals().length === 1) {
|
||||
this.props.onModalVisibilityChanged(false)
|
||||
}
|
||||
// This way state is chained through multiple calls to
|
||||
// _showModal, _closeModal correctly.
|
||||
this.setState((state) => {
|
||||
const modals = state.modals
|
||||
delete modals[tag]
|
||||
return { modals }
|
||||
})
|
||||
}
|
||||
|
||||
_getOpenModals(): Array<string> {
|
||||
return Object.keys(this.state.modals)
|
||||
}
|
||||
|
||||
_notifyAccessibilityService() {
|
||||
if (Platform.OS === 'web') {
|
||||
// We need to send accessibility event in a new batch, as otherwise
|
||||
// TextViews have no text set at the moment of populating event.
|
||||
}
|
||||
}
|
||||
|
||||
_showModal(tag: string, component: any) {
|
||||
// We are about to open first modal, so Portal will appear.
|
||||
// Let's disable accessibility for background view on Android.
|
||||
if (this._getOpenModals().length === 0) {
|
||||
this.props.onModalVisibilityChanged(true)
|
||||
}
|
||||
// This way state is chained through multiple calls to
|
||||
// _showModal, _closeModal correctly.
|
||||
this.setState((state) => {
|
||||
const modals = state.modals
|
||||
modals[tag] = component
|
||||
return { modals }
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
root: {
|
||||
position: 'absolute',
|
||||
left: 0,
|
||||
top: 0,
|
||||
right: 0,
|
||||
bottom: 0
|
||||
}
|
||||
})
|
||||
@@ -1,6 +1,6 @@
|
||||
import { pickProps } from '../../modules/filterObjectProps'
|
||||
import debounce from 'lodash.debounce'
|
||||
import React, { PropTypes } from 'react'
|
||||
import React, { Component, PropTypes } from 'react'
|
||||
import ScrollViewStylePropTypes from './ScrollViewStylePropTypes'
|
||||
import StyleSheet from '../../apis/StyleSheet'
|
||||
import View from '../View'
|
||||
@@ -22,7 +22,7 @@ const styles = StyleSheet.create({
|
||||
}
|
||||
})
|
||||
|
||||
class ScrollView extends React.Component {
|
||||
export default class ScrollView extends Component {
|
||||
static propTypes = {
|
||||
children: PropTypes.any,
|
||||
contentContainerStyle: PropTypes.shape(ScrollViewStylePropTypes),
|
||||
@@ -136,5 +136,3 @@ class ScrollView extends React.Component {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default ScrollView
|
||||
|
||||
5
src/components/StaticContainer/__tests__/index-test.js
Normal file
5
src/components/StaticContainer/__tests__/index-test.js
Normal file
@@ -0,0 +1,5 @@
|
||||
/* eslint-env mocha */
|
||||
|
||||
suite('components/StaticContainer', () => {
|
||||
test.skip('NO TEST COVERAGE', () => {})
|
||||
})
|
||||
40
src/components/StaticContainer/index.js
Normal file
40
src/components/StaticContainer/index.js
Normal file
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Nicolas Gallagher.
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import React, { Component, PropTypes } from 'react'
|
||||
|
||||
/**
|
||||
* Renders static content efficiently by allowing React to short-circuit the
|
||||
* reconciliation process. This component should be used when you know that a
|
||||
* subtree of components will never need to be updated.
|
||||
*
|
||||
* const someValue = ...; // We know for certain this value will never change.
|
||||
* return (
|
||||
* <StaticContainer>
|
||||
* <MyComponent value={someValue} />
|
||||
* </StaticContainer>
|
||||
* );
|
||||
*
|
||||
* Typically, you will not need to use this component and should opt for normal
|
||||
* React reconciliation.
|
||||
*/
|
||||
export default class StaticContainer extends Component {
|
||||
static propTypes = {
|
||||
children: PropTypes.any.isRequired,
|
||||
shouldUpdate: PropTypes.bool.isRequired
|
||||
};
|
||||
|
||||
shouldComponentUpdate(nextProps: { shouldUpdate: boolean }): boolean {
|
||||
return nextProps.shouldUpdate
|
||||
}
|
||||
|
||||
render() {
|
||||
const child = this.props.children
|
||||
return (child === null || child === false) ? null : React.Children.only(child)
|
||||
}
|
||||
}
|
||||
5
src/components/StaticRenderer/__tests__/index-test.js
Normal file
5
src/components/StaticRenderer/__tests__/index-test.js
Normal file
@@ -0,0 +1,5 @@
|
||||
/* eslint-env mocha */
|
||||
|
||||
suite('components/StaticRenderer', () => {
|
||||
test.skip('NO TEST COVERAGE', () => {})
|
||||
})
|
||||
38
src/components/StaticRenderer/index.js
Normal file
38
src/components/StaticRenderer/index.js
Normal file
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Nicolas Gallagher.
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import { Component, PropTypes } from 'react'
|
||||
|
||||
/**
|
||||
* Renders static content efficiently by allowing React to short-circuit the
|
||||
* reconciliation process. This component should be used when you know that a
|
||||
* subtree of components will never need to be updated.
|
||||
*
|
||||
* const someValue = ...; // We know for certain this value will never change.
|
||||
* return (
|
||||
* <StaticRenderer render={() => <MyComponent value={someValue} />} />
|
||||
* );
|
||||
*
|
||||
* Typically, you will not need to use this component and should opt for normal
|
||||
* React reconciliation.
|
||||
*/
|
||||
|
||||
export default class StaticRenderer extends Component {
|
||||
static propTypes = {
|
||||
render: PropTypes.func.isRequired,
|
||||
shouldUpdate: PropTypes.bool.isRequired
|
||||
};
|
||||
|
||||
shouldComponentUpdate(nextProps: { shouldUpdate: boolean }): boolean {
|
||||
return nextProps.shouldUpdate
|
||||
}
|
||||
|
||||
render() {
|
||||
return this.props.render()
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import { pickProps } from '../../modules/filterObjectProps'
|
||||
import CoreComponent from '../CoreComponent'
|
||||
import React, { PropTypes } from 'react'
|
||||
import React, { Component, PropTypes } from 'react'
|
||||
import StyleSheet from '../../apis/StyleSheet'
|
||||
import TextStylePropTypes from './TextStylePropTypes'
|
||||
|
||||
@@ -24,7 +24,7 @@ const styles = StyleSheet.create({
|
||||
}
|
||||
})
|
||||
|
||||
class Text extends React.Component {
|
||||
export default class Text extends Component {
|
||||
static propTypes = {
|
||||
_className: PropTypes.string, // escape-hatch for code migrations
|
||||
accessibilityLabel: CoreComponent.propTypes.accessibilityLabel,
|
||||
@@ -76,5 +76,3 @@ class Text extends React.Component {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default Text
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { pickProps } from '../../modules/filterObjectProps'
|
||||
import CoreComponent from '../CoreComponent'
|
||||
import React, { PropTypes } from 'react'
|
||||
import React, { Component, PropTypes } from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
import StyleSheet from '../../apis/StyleSheet'
|
||||
import Text from '../Text'
|
||||
@@ -39,7 +39,7 @@ const styles = StyleSheet.create({
|
||||
}
|
||||
})
|
||||
|
||||
class TextInput extends React.Component {
|
||||
export default class TextInput extends Component {
|
||||
constructor(props, context) {
|
||||
super(props, context)
|
||||
this.state = { showPlaceholder: !props.value && !props.defaultValue }
|
||||
@@ -221,5 +221,3 @@ class TextInput extends React.Component {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default TextInput
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { PropTypes } from 'react'
|
||||
import React, { Component, PropTypes } from 'react'
|
||||
import Tappable from 'react-tappable'
|
||||
import View from '../View'
|
||||
import StyleSheet from '../../apis/StyleSheet'
|
||||
@@ -11,7 +11,7 @@ const styles = StyleSheet.create({
|
||||
}
|
||||
})
|
||||
|
||||
class Touchable extends React.Component {
|
||||
export default class Touchable extends Component {
|
||||
constructor(props, context) {
|
||||
super(props, context)
|
||||
this.state = {
|
||||
@@ -130,5 +130,3 @@ class Touchable extends React.Component {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default Touchable
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { pickProps } from '../../modules/filterObjectProps'
|
||||
import CoreComponent from '../CoreComponent'
|
||||
import React, { PropTypes } from 'react'
|
||||
import React, { Component, PropTypes } from 'react'
|
||||
import StyleSheet from '../../apis/StyleSheet'
|
||||
import ViewStylePropTypes from './ViewStylePropTypes'
|
||||
|
||||
@@ -30,7 +30,7 @@ const styles = StyleSheet.create({
|
||||
}
|
||||
})
|
||||
|
||||
class View extends React.Component {
|
||||
export default class View extends Component {
|
||||
static propTypes = {
|
||||
_className: PropTypes.string, // escape-hatch for code migrations
|
||||
accessibilityLabel: CoreComponent.propTypes.accessibilityLabel,
|
||||
@@ -76,5 +76,3 @@ class View extends React.Component {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default View
|
||||
|
||||
56
src/index.js
56
src/index.js
@@ -2,63 +2,55 @@ import React from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
import ReactDOMServer from 'react-dom/server'
|
||||
|
||||
// api
|
||||
import StyleSheet from './modules/StyleSheet'
|
||||
// apis
|
||||
import AppRegistry from './apis/AppRegistry'
|
||||
import AppState from './apis/AppState'
|
||||
import AsyncStorage from './apis/AsyncStorage'
|
||||
import Dimensions from './apis/Dimensions'
|
||||
import NetInfo from './apis/NetInfo'
|
||||
import PixelRatio from './apis/PixelRatio'
|
||||
import Platform from './apis/Platform'
|
||||
import StyleSheet from './apis/StyleSheet'
|
||||
|
||||
// components
|
||||
import ActivityIndicator from './components/ActivityIndicator'
|
||||
import Image from './components/Image'
|
||||
import ListView from './components/ListView'
|
||||
import Portal from './components/Portal'
|
||||
import ScrollView from './components/ScrollView'
|
||||
import Text from './components/Text'
|
||||
import TextInput from './components/TextInput'
|
||||
import Touchable from './components/Touchable'
|
||||
import View from './components/View'
|
||||
|
||||
const renderStyle = () => {
|
||||
return `<style id='react-stylesheet'>${StyleSheet._renderToString()}</style>`
|
||||
}
|
||||
|
||||
const render = (element, container, callback) => {
|
||||
const styleElement = document.getElementById('react-stylesheet')
|
||||
if (!styleElement) {
|
||||
const style = renderStyle()
|
||||
container.insertAdjacentHTML('beforebegin', style)
|
||||
}
|
||||
return ReactDOM.render(element, container, callback)
|
||||
}
|
||||
|
||||
const renderToString = (element) => {
|
||||
const style = renderStyle()
|
||||
const html = ReactDOMServer.renderToString(element)
|
||||
return `${style}\n${html}`
|
||||
}
|
||||
|
||||
const renderToStaticMarkup = (element) => {
|
||||
const style = renderStyle()
|
||||
const html = ReactDOMServer.renderToStaticMarkup(element)
|
||||
return `${style}\n${html}`
|
||||
}
|
||||
|
||||
const ReactNative = {
|
||||
// apis
|
||||
AppRegistry,
|
||||
AppState,
|
||||
AsyncStorage,
|
||||
Dimensions,
|
||||
NetInfo,
|
||||
PixelRatio,
|
||||
Platform,
|
||||
StyleSheet,
|
||||
|
||||
// components
|
||||
ActivityIndicator,
|
||||
Image,
|
||||
ListView,
|
||||
Portal,
|
||||
ScrollView,
|
||||
Text,
|
||||
TextInput,
|
||||
Touchable,
|
||||
TouchableHighlight: Touchable,
|
||||
TouchableOpacity: Touchable,
|
||||
TouchableWithoutFeedback: Touchable,
|
||||
View,
|
||||
|
||||
// React
|
||||
...React,
|
||||
...ReactDOM,
|
||||
...ReactDOMServer,
|
||||
render,
|
||||
renderToString,
|
||||
renderToStaticMarkup
|
||||
...ReactDOMServer
|
||||
}
|
||||
|
||||
module.exports = ReactNative
|
||||
|
||||
Reference in New Issue
Block a user