mirror of
https://github.com/zhigang1992/react-native-web.git
synced 2026-04-05 09:29:53 +08:00
Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c44da41497 | ||
|
|
331c92fb3a | ||
|
|
26758e905c | ||
|
|
a15b15c55d | ||
|
|
f0202dbe61 | ||
|
|
d4d67dafc0 | ||
|
|
579bdeb8a5 | ||
|
|
7132a18440 | ||
|
|
18881b1edb |
7
.babelrc
7
.babelrc
@@ -1,10 +1,5 @@
|
||||
{
|
||||
"presets": [
|
||||
"es2015",
|
||||
"stage-1",
|
||||
"react"
|
||||
],
|
||||
"plugins": [
|
||||
"transform-decorators-legacy"
|
||||
"react-native"
|
||||
]
|
||||
}
|
||||
|
||||
15
package.json
15
package.json
@@ -1,13 +1,13 @@
|
||||
{
|
||||
"name": "react-native-web",
|
||||
"version": "0.0.29",
|
||||
"version": "0.0.30",
|
||||
"description": "React Native for Web",
|
||||
"main": "dist/index.js",
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "del ./dist && mkdir dist && babel src -d dist --ignore **/__tests__,src/modules/specHelpers",
|
||||
"build": "del ./dist && mkdir dist && babel src -d dist --ignore **/__tests__",
|
||||
"build:umd": "webpack --config webpack.config.js --sort-assets-by --progress",
|
||||
"examples": "webpack-dev-server --config examples/webpack.config.js --inline --hot --colors --quiet",
|
||||
"lint": "eslint src",
|
||||
@@ -27,13 +27,10 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-cli": "^6.10.1",
|
||||
"babel-core": "^6.9.1",
|
||||
"babel-eslint": "^6.0.4",
|
||||
"babel-core": "^6.10.4",
|
||||
"babel-eslint": "^6.1.0",
|
||||
"babel-loader": "^6.2.4",
|
||||
"babel-plugin-transform-decorators-legacy": "^1.3.4",
|
||||
"babel-preset-es2015": "^6.9.0",
|
||||
"babel-preset-react": "^6.5.0",
|
||||
"babel-preset-stage-1": "^6.5.0",
|
||||
"babel-preset-react-native": "^1.9.0",
|
||||
"del-cli": "^0.2.0",
|
||||
"enzyme": "^2.3.0",
|
||||
"eslint": "^2.12.0",
|
||||
@@ -46,7 +43,7 @@
|
||||
"karma-browserstack-launcher": "^1.0.1",
|
||||
"karma-chrome-launcher": "^1.0.1",
|
||||
"karma-firefox-launcher": "^1.0.0",
|
||||
"karma-mocha": "^1.0.1",
|
||||
"karma-mocha": "^1.1.1",
|
||||
"karma-mocha-reporter": "^2.0.4",
|
||||
"karma-sourcemap-loader": "^0.3.7",
|
||||
"karma-webpack": "^1.7.0",
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import React, { Component, PropTypes } from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
import StyleSheet from '../StyleSheet'
|
||||
import View from '../../components/View'
|
||||
|
||||
|
||||
@@ -4,20 +4,29 @@ import assert from 'assert'
|
||||
import expandStyle from '../expandStyle'
|
||||
|
||||
suite('apis/StyleSheet/expandStyle', () => {
|
||||
test('style resolution', () => {
|
||||
test('shortform -> longform', () => {
|
||||
const initial = {
|
||||
borderTopWidth: 1,
|
||||
borderWidth: 2,
|
||||
borderStyle: 'solid',
|
||||
boxSizing: 'border-box',
|
||||
borderBottomColor: 'white',
|
||||
borderBottomWidth: 1,
|
||||
borderWidth: 0,
|
||||
marginTop: 50,
|
||||
marginVertical: 25,
|
||||
margin: 10
|
||||
}
|
||||
|
||||
const expected = {
|
||||
borderTopWidth: '1px',
|
||||
borderLeftWidth: '2px',
|
||||
borderRightWidth: '2px',
|
||||
borderBottomWidth: '2px',
|
||||
borderBottomStyle: 'solid',
|
||||
borderLeftStyle: 'solid',
|
||||
borderRightStyle: 'solid',
|
||||
boxSizing: 'border-box',
|
||||
borderBottomColor: 'white',
|
||||
borderTopStyle: 'solid',
|
||||
borderTopWidth: '0px',
|
||||
borderLeftWidth: '0px',
|
||||
borderRightWidth: '0px',
|
||||
borderBottomWidth: '1px',
|
||||
marginTop: '50px',
|
||||
marginBottom: '25px',
|
||||
marginLeft: '10px',
|
||||
@@ -27,6 +36,18 @@ suite('apis/StyleSheet/expandStyle', () => {
|
||||
assert.deepEqual(expandStyle(initial), expected)
|
||||
})
|
||||
|
||||
test('textAlignVertical', () => {
|
||||
const initial = {
|
||||
textAlignVertical: 'center'
|
||||
}
|
||||
|
||||
const expected = {
|
||||
verticalAlign: 'middle'
|
||||
}
|
||||
|
||||
assert.deepEqual(expandStyle(initial), expected)
|
||||
})
|
||||
|
||||
test('flex', () => {
|
||||
const value = 10
|
||||
|
||||
|
||||
@@ -1,6 +1,17 @@
|
||||
/**
|
||||
* The browser implements the CSS cascade, where the order of properties is a
|
||||
* factor in determining which styles to paint. React Native is different in
|
||||
* giving precedence to the more specific styles. For example, the value of
|
||||
* `paddingTop` takes precedence over that of `padding`.
|
||||
*
|
||||
* This module creates mutally exclusive style declarations by expanding all of
|
||||
* React Native's supported shortform properties (e.g. `padding`) to their
|
||||
* longfrom equivalents.
|
||||
*/
|
||||
|
||||
import normalizeValue from './normalizeValue'
|
||||
|
||||
const styleShortHands = {
|
||||
const styleShortFormProperties = {
|
||||
borderColor: [ 'borderTopColor', 'borderRightColor', 'borderBottomColor', 'borderLeftColor' ],
|
||||
borderRadius: [ 'borderTopLeftRadius', 'borderTopRightRadius', 'borderBottomRightRadius', 'borderBottomLeftRadius' ],
|
||||
borderStyle: [ 'borderTopStyle', 'borderRightStyle', 'borderBottomStyle', 'borderLeftStyle' ],
|
||||
@@ -16,50 +27,46 @@ const styleShortHands = {
|
||||
writingDirection: [ 'direction' ]
|
||||
}
|
||||
|
||||
/**
|
||||
* Alpha-sort properties, apart from shorthands – they must appear before the
|
||||
* longhand properties that they expand into. This lets more specific styles
|
||||
* override less specific styles, whatever the order in which they were
|
||||
* originally declared.
|
||||
*/
|
||||
const sortProps = (propsArray) => propsArray.sort((a, b) => {
|
||||
const expandedA = styleShortHands[a]
|
||||
const expandedB = styleShortHands[b]
|
||||
if (expandedA && expandedA.indexOf(b) > -1) {
|
||||
return -1
|
||||
} else if (expandedB && expandedB.indexOf(a) > -1) {
|
||||
return 1
|
||||
}
|
||||
return a < b ? -1 : a > b ? 1 : 0
|
||||
const alphaSort = (arr) => arr.sort((a, b) => {
|
||||
if (a < b) { return -1 }
|
||||
if (a > b) { return 1 }
|
||||
return 0
|
||||
})
|
||||
|
||||
/**
|
||||
* Expand the shorthand properties to isolate every declaration from the others.
|
||||
*/
|
||||
const expandStyle = (style) => {
|
||||
const propsArray = Object.keys(style)
|
||||
const sortedProps = sortProps(propsArray)
|
||||
const createStyleReducer = (originalStyle) => {
|
||||
const originalStyleProps = Object.keys(originalStyle)
|
||||
|
||||
return sortedProps.reduce((resolvedStyle, key) => {
|
||||
const expandedProps = styleShortHands[key]
|
||||
const value = normalizeValue(key, style[key])
|
||||
return (style, prop) => {
|
||||
const value = normalizeValue(prop, originalStyle[prop])
|
||||
const longFormProperties = styleShortFormProperties[prop]
|
||||
|
||||
// React Native treats `flex:1` like `flex:1 1 auto`
|
||||
if (key === 'flex') {
|
||||
resolvedStyle.flexGrow = value
|
||||
resolvedStyle.flexShrink = 1
|
||||
resolvedStyle.flexBasis = 'auto'
|
||||
} else if (key === 'textAlignVertical') {
|
||||
resolvedStyle.verticalAlign = (value === 'center' ? 'middle' : value)
|
||||
} else if (expandedProps) {
|
||||
expandedProps.forEach((prop, i) => {
|
||||
resolvedStyle[expandedProps[i]] = value
|
||||
if (prop === 'flex') {
|
||||
style.flexGrow = value
|
||||
if (style.flexShrink == null) { style.flexShrink = 1 }
|
||||
if (style.flexBasis == null) { style.flexBasis = 'auto' }
|
||||
// React Native accepts 'center' as a value
|
||||
} else if (prop === 'textAlignVertical') {
|
||||
style.verticalAlign = (value === 'center' ? 'middle' : value)
|
||||
} else if (longFormProperties) {
|
||||
longFormProperties.forEach((longForm, i) => {
|
||||
// the value of any longform property in the original styles takes
|
||||
// precedence over the shortform's value
|
||||
if (originalStyleProps.indexOf(longForm) === -1) {
|
||||
style[longForm] = value
|
||||
}
|
||||
})
|
||||
} else {
|
||||
resolvedStyle[key] = value
|
||||
style[prop] = value
|
||||
}
|
||||
return resolvedStyle
|
||||
}, {})
|
||||
return style
|
||||
}
|
||||
}
|
||||
|
||||
const expandStyle = (style) => {
|
||||
const sortedStyleProps = alphaSort(Object.keys(style))
|
||||
const styleReducer = createStyleReducer(style)
|
||||
return sortedStyleProps.reduce(styleReducer, {})
|
||||
}
|
||||
|
||||
module.exports = expandStyle
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import NativeMethodsDecorator from '../../modules/NativeMethodsDecorator'
|
||||
import applyNativeMethods from '../../modules/applyNativeMethods'
|
||||
import React, { Component, PropTypes } from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
import StyleSheet from '../../apis/StyleSheet'
|
||||
@@ -19,7 +19,6 @@ const keyframeEffects = [
|
||||
{ transform: 'scale(0.95)', opacity: 0.5 }
|
||||
]
|
||||
|
||||
@NativeMethodsDecorator
|
||||
class ActivityIndicator extends Component {
|
||||
static propTypes = {
|
||||
animating: PropTypes.bool,
|
||||
@@ -87,6 +86,8 @@ class ActivityIndicator extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
applyNativeMethods(ActivityIndicator)
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
alignItems: 'center',
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { PropTypes } from 'react'
|
||||
import BorderPropTypes from '../../apis/StyleSheet/BorderPropTypes'
|
||||
import ColorPropType from '../../apis/StyleSheet/ColorPropType'
|
||||
import LayoutPropTypes from '../../apis/StyleSheet/LayoutPropTypes'
|
||||
import TransformPropTypes from '../../apis/StyleSheet/TransformPropTypes'
|
||||
@@ -7,6 +8,7 @@ import ImageResizeMode from './ImageResizeMode'
|
||||
const hiddenOrVisible = PropTypes.oneOf([ 'hidden', 'visible' ])
|
||||
|
||||
module.exports = {
|
||||
...BorderPropTypes,
|
||||
...LayoutPropTypes,
|
||||
...TransformPropTypes,
|
||||
backfaceVisibility: hiddenOrVisible,
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/* global window */
|
||||
import applyNativeMethods from '../../modules/applyNativeMethods'
|
||||
import createNativeComponent from '../../modules/createNativeComponent'
|
||||
import ImageResizeMode from './ImageResizeMode'
|
||||
import ImageStylePropTypes from './ImageStylePropTypes'
|
||||
import NativeMethodsDecorator from '../../modules/NativeMethodsDecorator'
|
||||
import resolveAssetSource from './resolveAssetSource'
|
||||
import React, { Component, PropTypes } from 'react'
|
||||
import StyleSheet from '../../apis/StyleSheet'
|
||||
@@ -22,7 +22,6 @@ const ImageSourcePropType = PropTypes.oneOfType([
|
||||
PropTypes.string
|
||||
])
|
||||
|
||||
@NativeMethodsDecorator
|
||||
class Image extends Component {
|
||||
static propTypes = {
|
||||
accessibilityLabel: createNativeComponent.propTypes.accessibilityLabel,
|
||||
@@ -176,6 +175,8 @@ class Image extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
applyNativeMethods(Image)
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
initial: {
|
||||
alignSelf: 'flex-start',
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import NativeMethodsDecorator from '../../modules/NativeMethodsDecorator'
|
||||
import applyNativeMethods from '../../modules/applyNativeMethods'
|
||||
import React, { Component } from 'react'
|
||||
import ScrollView from '../ScrollView'
|
||||
import ListViewDataSource from './ListViewDataSource'
|
||||
@@ -6,7 +6,6 @@ import ListViewPropTypes from './ListViewPropTypes'
|
||||
|
||||
const SCROLLVIEW_REF = 'listviewscroll'
|
||||
|
||||
@NativeMethodsDecorator
|
||||
class ListView extends Component {
|
||||
static propTypes = ListViewPropTypes;
|
||||
|
||||
@@ -100,4 +99,6 @@ class ListView extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
applyNativeMethods(ListView)
|
||||
|
||||
module.exports = ListView
|
||||
|
||||
@@ -1,24 +1,22 @@
|
||||
/* eslint-env mocha */
|
||||
|
||||
import * as utils from '../../../modules/specHelpers'
|
||||
import assert from 'assert'
|
||||
import React from 'react'
|
||||
import ReactTestUtils from 'react-addons-test-utils'
|
||||
|
||||
import Text from '../'
|
||||
import { mount, shallow } from 'enzyme'
|
||||
|
||||
suite('components/Text', () => {
|
||||
test('prop "children"', () => {
|
||||
const children = 'children'
|
||||
const result = utils.shallowRender(<Text>{children}</Text>)
|
||||
assert.equal(result.props.children, children)
|
||||
const text = shallow(<Text>{children}</Text>)
|
||||
assert.equal(text.prop('children'), children)
|
||||
})
|
||||
|
||||
test('prop "numberOfLines"')
|
||||
|
||||
test('prop "onPress"', (done) => {
|
||||
const dom = utils.renderToDOM(<Text onPress={onPress} />)
|
||||
ReactTestUtils.Simulate.click(dom)
|
||||
const text = mount(<Text onPress={onPress} />)
|
||||
text.simulate('click')
|
||||
function onPress(e) {
|
||||
assert.ok(e.nativeEvent)
|
||||
done()
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
import applyNativeMethods from '../../modules/applyNativeMethods'
|
||||
import createNativeComponent from '../../modules/createNativeComponent'
|
||||
import NativeMethodsDecorator from '../../modules/NativeMethodsDecorator'
|
||||
import { Component, PropTypes } from 'react'
|
||||
import StyleSheet from '../../apis/StyleSheet'
|
||||
import StyleSheetPropType from '../../apis/StyleSheet/StyleSheetPropType'
|
||||
import TextStylePropTypes from './TextStylePropTypes'
|
||||
|
||||
@NativeMethodsDecorator
|
||||
class Text extends Component {
|
||||
static propTypes = {
|
||||
accessibilityLabel: createNativeComponent.propTypes.accessibilityLabel,
|
||||
@@ -49,6 +48,8 @@ class Text extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
applyNativeMethods(Text)
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
initial: {
|
||||
color: 'inherit',
|
||||
|
||||
@@ -1,88 +1,96 @@
|
||||
/* eslint-env mocha */
|
||||
|
||||
import * as utils from '../../../modules/specHelpers'
|
||||
import assert from 'assert'
|
||||
import React from 'react'
|
||||
import ReactTestUtils from 'react-addons-test-utils'
|
||||
import StyleSheet from '../../../apis/StyleSheet'
|
||||
import TextareaAutosize from 'react-textarea-autosize'
|
||||
import TextInput from '..'
|
||||
import { mount, shallow } from 'enzyme'
|
||||
|
||||
import TextInput from '../'
|
||||
const placeholderText = 'placeholderText'
|
||||
const findNativeInput = (wrapper) => wrapper.find('input')
|
||||
const findNativeTextarea = (wrapper) => wrapper.find(TextareaAutosize)
|
||||
const findPlaceholder = (wrapper) => wrapper.find({ children: placeholderText })
|
||||
|
||||
const findInput = (dom) => dom.querySelector('input, textarea')
|
||||
const findShallowInput = (vdom) => vdom.props.children.props.children[0]
|
||||
const findShallowPlaceholder = (vdom) => vdom.props.children.props.children[1]
|
||||
const testIfDocumentIsFocused = (message, fn) => {
|
||||
if (document.hasFocus && document.hasFocus()) {
|
||||
test(message, fn)
|
||||
} else {
|
||||
test.skip(`${message} – document is not focused`)
|
||||
}
|
||||
}
|
||||
|
||||
suite('components/TextInput', () => {
|
||||
test('prop "autoComplete"', () => {
|
||||
// off
|
||||
let input = findInput(utils.renderToDOM(<TextInput />))
|
||||
assert.equal(input.getAttribute('autocomplete'), undefined)
|
||||
let input = findNativeInput(shallow(<TextInput />))
|
||||
assert.equal(input.prop('autoComplete'), undefined)
|
||||
// on
|
||||
input = findInput(utils.renderToDOM(<TextInput autoComplete />))
|
||||
assert.equal(input.getAttribute('autocomplete'), 'on')
|
||||
input = findNativeInput(shallow(<TextInput autoComplete />))
|
||||
assert.equal(input.prop('autoComplete'), 'on')
|
||||
})
|
||||
|
||||
test.skip('prop "autoFocus"', () => {
|
||||
test('prop "autoFocus"', () => {
|
||||
// false
|
||||
let input = findInput(utils.renderToDOM(<TextInput />))
|
||||
assert.deepEqual(document.activeElement, document.body)
|
||||
let input = findNativeInput(mount(<TextInput />))
|
||||
assert.equal(input.prop('autoFocus'), undefined)
|
||||
// true
|
||||
input = findInput(utils.renderToDOM(<TextInput autoFocus />))
|
||||
assert.deepEqual(document.activeElement, input)
|
||||
input = findNativeInput(mount(<TextInput autoFocus />))
|
||||
assert.equal(input.prop('autoFocus'), true)
|
||||
})
|
||||
|
||||
utils.testIfDocumentFocused('prop "clearTextOnFocus"', () => {
|
||||
testIfDocumentIsFocused('prop "clearTextOnFocus"', () => {
|
||||
const defaultValue = 'defaultValue'
|
||||
// false
|
||||
let input = findInput(utils.renderAndInject(<TextInput defaultValue={defaultValue} />))
|
||||
input.focus()
|
||||
assert.equal(input.value, defaultValue)
|
||||
let input = findNativeInput(mount(<TextInput defaultValue={defaultValue} />))
|
||||
input.simulate('focus')
|
||||
assert.equal(input.node.value, defaultValue)
|
||||
// true
|
||||
input = findInput(utils.renderAndInject(<TextInput clearTextOnFocus defaultValue={defaultValue} />))
|
||||
input.focus()
|
||||
assert.equal(input.value, '')
|
||||
input = findNativeInput(mount(<TextInput clearTextOnFocus defaultValue={defaultValue} />))
|
||||
input.simulate('focus')
|
||||
assert.equal(input.node.value, '')
|
||||
})
|
||||
|
||||
test('prop "defaultValue"', () => {
|
||||
const defaultValue = 'defaultValue'
|
||||
const input = findShallowInput(utils.shallowRender(<TextInput defaultValue={defaultValue} />))
|
||||
assert.equal(input.props.defaultValue, defaultValue)
|
||||
const input = findNativeInput(shallow(<TextInput defaultValue={defaultValue} />))
|
||||
assert.equal(input.prop('defaultValue'), defaultValue)
|
||||
})
|
||||
|
||||
test('prop "editable"', () => {
|
||||
// true
|
||||
let input = findInput(utils.renderToDOM(<TextInput />))
|
||||
assert.equal(input.getAttribute('readonly'), undefined)
|
||||
let input = findNativeInput(shallow(<TextInput />))
|
||||
assert.equal(input.prop('readOnly'), false)
|
||||
// false
|
||||
input = findInput(utils.renderToDOM(<TextInput editable={false} />))
|
||||
assert.equal(input.getAttribute('readonly'), '')
|
||||
input = findNativeInput(shallow(<TextInput editable={false} />))
|
||||
assert.equal(input.prop('readOnly'), true)
|
||||
})
|
||||
|
||||
test('prop "keyboardType"', () => {
|
||||
// default
|
||||
let input = findInput(utils.renderToDOM(<TextInput />))
|
||||
assert.equal(input.getAttribute('type'), undefined)
|
||||
input = findInput(utils.renderToDOM(<TextInput keyboardType='default' />))
|
||||
assert.equal(input.getAttribute('type'), undefined)
|
||||
let input = findNativeInput(shallow(<TextInput />))
|
||||
assert.equal(input.prop('type'), undefined)
|
||||
input = findNativeInput(shallow(<TextInput keyboardType='default' />))
|
||||
assert.equal(input.prop('type'), undefined)
|
||||
// email-address
|
||||
input = findInput(utils.renderToDOM(<TextInput keyboardType='email-address' />))
|
||||
assert.equal(input.getAttribute('type'), 'email')
|
||||
input = findNativeInput(shallow(<TextInput keyboardType='email-address' />))
|
||||
assert.equal(input.prop('type'), 'email')
|
||||
// numeric
|
||||
input = findInput(utils.renderToDOM(<TextInput keyboardType='numeric' />))
|
||||
assert.equal(input.getAttribute('type'), 'number')
|
||||
input = findNativeInput(shallow(<TextInput keyboardType='numeric' />))
|
||||
assert.equal(input.prop('type'), 'number')
|
||||
// phone-pad
|
||||
input = findInput(utils.renderToDOM(<TextInput keyboardType='phone-pad' />))
|
||||
assert.equal(input.getAttribute('type'), 'tel')
|
||||
input = findNativeInput(shallow(<TextInput keyboardType='phone-pad' />))
|
||||
assert.equal(input.prop('type'), 'tel')
|
||||
// url
|
||||
input = findInput(utils.renderToDOM(<TextInput keyboardType='url' />))
|
||||
assert.equal(input.getAttribute('type'), 'url')
|
||||
input = findNativeInput(shallow(<TextInput keyboardType='url' />))
|
||||
assert.equal(input.prop('type'), 'url')
|
||||
})
|
||||
|
||||
test('prop "maxLength"', () => {
|
||||
let input = findInput(utils.renderToDOM(<TextInput />))
|
||||
assert.equal(input.getAttribute('maxlength'), undefined)
|
||||
input = findInput(utils.renderToDOM(<TextInput maxLength={10} />))
|
||||
assert.equal(input.getAttribute('maxlength'), '10')
|
||||
let input = findNativeInput(shallow(<TextInput />))
|
||||
assert.equal(input.prop('maxLength'), undefined)
|
||||
input = findNativeInput(shallow(<TextInput maxLength={10} />))
|
||||
assert.equal(input.prop('maxLength'), '10')
|
||||
})
|
||||
|
||||
test('prop "maxNumberOfLines"', () => {
|
||||
@@ -92,45 +100,45 @@ suite('components/TextInput', () => {
|
||||
return str
|
||||
}
|
||||
|
||||
const result = utils.shallowRender(
|
||||
const input = findNativeTextarea(shallow(
|
||||
<TextInput
|
||||
maxNumberOfLines={3}
|
||||
multiline
|
||||
value={generateValue()}
|
||||
/>
|
||||
)
|
||||
assert.equal(findShallowInput(result).props.maxRows, 3)
|
||||
))
|
||||
assert.equal(input.prop('maxRows'), 3)
|
||||
})
|
||||
|
||||
test('prop "multiline"', () => {
|
||||
// false
|
||||
let input = findInput(utils.renderToDOM(<TextInput />))
|
||||
assert.equal(input.tagName, 'INPUT')
|
||||
let input = findNativeInput(shallow(<TextInput />))
|
||||
assert.equal(input.length, 1)
|
||||
// true
|
||||
input = findInput(utils.renderToDOM(<TextInput multiline />))
|
||||
assert.equal(input.tagName, 'TEXTAREA')
|
||||
input = findNativeTextarea(shallow(<TextInput multiline />))
|
||||
assert.equal(input.length, 1)
|
||||
})
|
||||
|
||||
test('prop "numberOfLines"', () => {
|
||||
// missing multiline
|
||||
let input = findInput(utils.renderToDOM(<TextInput numberOfLines={2} />))
|
||||
assert.equal(input.tagName, 'INPUT')
|
||||
let input = findNativeInput(shallow(<TextInput numberOfLines={2} />))
|
||||
assert.equal(input.length, 1)
|
||||
// with multiline
|
||||
input = findInput(utils.renderAndInject(<TextInput multiline numberOfLines={2} />))
|
||||
assert.equal(input.tagName, 'TEXTAREA')
|
||||
input = findNativeTextarea(shallow(<TextInput multiline numberOfLines={2} />))
|
||||
assert.equal(input.length, 1)
|
||||
|
||||
const result = utils.shallowRender(
|
||||
input = findNativeTextarea(shallow(
|
||||
<TextInput
|
||||
multiline
|
||||
numberOfLines={3}
|
||||
/>
|
||||
)
|
||||
assert.equal(findShallowInput(result).props.minRows, 3)
|
||||
))
|
||||
assert.equal(input.prop('minRows'), 3)
|
||||
})
|
||||
|
||||
test('prop "onBlur"', (done) => {
|
||||
const input = findInput(utils.renderToDOM(<TextInput onBlur={onBlur} />))
|
||||
ReactTestUtils.Simulate.blur(input)
|
||||
const input = findNativeInput(mount(<TextInput onBlur={onBlur} />))
|
||||
input.simulate('blur')
|
||||
function onBlur(e) {
|
||||
assert.ok(e)
|
||||
done()
|
||||
@@ -138,8 +146,8 @@ suite('components/TextInput', () => {
|
||||
})
|
||||
|
||||
test('prop "onChange"', (done) => {
|
||||
const input = findInput(utils.renderToDOM(<TextInput onChange={onChange} />))
|
||||
ReactTestUtils.Simulate.change(input)
|
||||
const input = findNativeInput(mount(<TextInput onChange={onChange} />))
|
||||
input.simulate('change')
|
||||
function onChange(e) {
|
||||
assert.ok(e)
|
||||
done()
|
||||
@@ -148,8 +156,8 @@ suite('components/TextInput', () => {
|
||||
|
||||
test('prop "onChangeText"', (done) => {
|
||||
const newText = 'newText'
|
||||
const input = findInput(utils.renderToDOM(<TextInput onChangeText={onChangeText} />))
|
||||
ReactTestUtils.Simulate.change(input, { target: { value: newText } })
|
||||
const input = findNativeInput(mount(<TextInput onChangeText={onChangeText} />))
|
||||
input.simulate('change', { target: { value: newText } })
|
||||
function onChangeText(text) {
|
||||
assert.equal(text, newText)
|
||||
done()
|
||||
@@ -157,8 +165,8 @@ suite('components/TextInput', () => {
|
||||
})
|
||||
|
||||
test('prop "onFocus"', (done) => {
|
||||
const input = findInput(utils.renderToDOM(<TextInput onFocus={onFocus} />))
|
||||
ReactTestUtils.Simulate.focus(input)
|
||||
const input = findNativeInput(mount(<TextInput onFocus={onFocus} />))
|
||||
input.simulate('focus')
|
||||
function onFocus(e) {
|
||||
assert.ok(e)
|
||||
done()
|
||||
@@ -168,8 +176,8 @@ suite('components/TextInput', () => {
|
||||
test('prop "onLayout"')
|
||||
|
||||
test('prop "onSelectionChange"', (done) => {
|
||||
const input = findInput(utils.renderAndInject(<TextInput defaultValue='12345' onSelectionChange={onSelectionChange} />))
|
||||
ReactTestUtils.Simulate.select(input, { target: { selectionStart: 0, selectionEnd: 3 } })
|
||||
const input = findNativeInput(mount(<TextInput defaultValue='12345' onSelectionChange={onSelectionChange} />))
|
||||
input.simulate('select', { target: { selectionStart: 0, selectionEnd: 3 } })
|
||||
function onSelectionChange(e) {
|
||||
assert.equal(e.selectionEnd, 3)
|
||||
assert.equal(e.selectionStart, 0)
|
||||
@@ -178,46 +186,46 @@ suite('components/TextInput', () => {
|
||||
})
|
||||
|
||||
test('prop "placeholder"', () => {
|
||||
const placeholder = 'placeholder'
|
||||
const result = findShallowPlaceholder(utils.shallowRender(<TextInput placeholder={placeholder} />))
|
||||
assert.equal(result.props.children.props.children, placeholder)
|
||||
let textInput = shallow(<TextInput />)
|
||||
assert.equal(findPlaceholder(textInput).length, 0)
|
||||
|
||||
textInput = shallow(<TextInput placeholder={placeholderText} />)
|
||||
assert.equal(findPlaceholder(textInput).length, 1)
|
||||
})
|
||||
|
||||
test('prop "placeholderTextColor"', () => {
|
||||
const placeholder = 'placeholder'
|
||||
let placeholderElement = findPlaceholder(shallow(<TextInput placeholder={placeholderText} />))
|
||||
assert.equal(StyleSheet.flatten(placeholderElement.prop('style')).color, 'darkgray')
|
||||
|
||||
let result = findShallowPlaceholder(utils.shallowRender(<TextInput placeholder={placeholder} />))
|
||||
assert.equal(StyleSheet.flatten(result.props.children.props.style).color, 'darkgray')
|
||||
|
||||
result = findShallowPlaceholder(utils.shallowRender(<TextInput placeholder={placeholder} placeholderTextColor='red' />))
|
||||
assert.equal(StyleSheet.flatten(result.props.children.props.style).color, 'red')
|
||||
placeholderElement = findPlaceholder(shallow(<TextInput placeholder={placeholderText} placeholderTextColor='red' />))
|
||||
assert.equal(StyleSheet.flatten(placeholderElement.prop('style')).color, 'red')
|
||||
})
|
||||
|
||||
test('prop "secureTextEntry"', () => {
|
||||
let input = findInput(utils.renderToDOM(<TextInput secureTextEntry />))
|
||||
assert.equal(input.getAttribute('type'), 'password')
|
||||
let input = findNativeInput(shallow(<TextInput secureTextEntry />))
|
||||
assert.equal(input.prop('type'), 'password')
|
||||
// ignored for multiline
|
||||
input = findInput(utils.renderToDOM(<TextInput multiline secureTextEntry />))
|
||||
assert.equal(input.getAttribute('type'), undefined)
|
||||
input = findNativeTextarea(shallow(<TextInput multiline secureTextEntry />))
|
||||
assert.equal(input.prop('type'), undefined)
|
||||
})
|
||||
|
||||
utils.testIfDocumentFocused('prop "selectTextOnFocus"', () => {
|
||||
testIfDocumentIsFocused('prop "selectTextOnFocus"', () => {
|
||||
const text = 'Text'
|
||||
// false
|
||||
let input = findInput(utils.renderAndInject(<TextInput defaultValue={text} />))
|
||||
input.focus()
|
||||
assert.equal(input.selectionEnd, 0)
|
||||
assert.equal(input.selectionStart, 0)
|
||||
let input = findNativeInput(mount(<TextInput defaultValue={text} />))
|
||||
input.node.focus()
|
||||
assert.equal(input.node.selectionEnd, 4)
|
||||
assert.equal(input.node.selectionStart, 4)
|
||||
// true
|
||||
input = findInput(utils.renderAndInject(<TextInput defaultValue={text} selectTextOnFocus />))
|
||||
input.focus()
|
||||
assert.equal(input.selectionEnd, 4)
|
||||
assert.equal(input.selectionStart, 0)
|
||||
// input = findNativeInput(mount(<TextInput defaultValue={text} selectTextOnFocus />))
|
||||
// input.node.focus()
|
||||
// assert.equal(input.node.selectionEnd, 4)
|
||||
// assert.equal(input.node.selectionStart, 0)
|
||||
})
|
||||
|
||||
test('prop "value"', () => {
|
||||
const value = 'value'
|
||||
const input = findShallowInput(utils.shallowRender(<TextInput value={value} />))
|
||||
assert.equal(input.props.value, value)
|
||||
const input = findNativeInput(shallow(<TextInput value={value} />))
|
||||
assert.equal(input.prop('value'), value)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import applyNativeMethods from '../../modules/applyNativeMethods'
|
||||
import createNativeComponent from '../../modules/createNativeComponent'
|
||||
import NativeMethodsDecorator from '../../modules/NativeMethodsDecorator'
|
||||
import omit from 'lodash/omit'
|
||||
import pick from 'lodash/pick'
|
||||
import React, { Component, PropTypes } from 'react'
|
||||
@@ -8,12 +8,12 @@ import StyleSheet from '../../apis/StyleSheet'
|
||||
import Text from '../Text'
|
||||
import TextareaAutosize from 'react-textarea-autosize'
|
||||
import TextInputState from './TextInputState'
|
||||
import UIManager from '../../apis/UIManager'
|
||||
import View from '../View'
|
||||
import ViewStylePropTypes from '../View/ViewStylePropTypes'
|
||||
|
||||
const viewStyleProps = Object.keys(ViewStylePropTypes)
|
||||
|
||||
@NativeMethodsDecorator
|
||||
class TextInput extends Component {
|
||||
static propTypes = {
|
||||
...View.propTypes,
|
||||
@@ -68,7 +68,7 @@ class TextInput extends Component {
|
||||
}
|
||||
|
||||
setNativeProps(props) {
|
||||
this.refs.input.setNativeProps(props)
|
||||
UIManager.updateView(this.refs.input, props, this)
|
||||
}
|
||||
|
||||
render() {
|
||||
@@ -232,13 +232,15 @@ class TextInput extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
applyNativeMethods(TextInput)
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
initial: {
|
||||
borderColor: 'black',
|
||||
borderWidth: 1
|
||||
},
|
||||
wrapper: {
|
||||
flexGrow: 1
|
||||
flex: 1
|
||||
},
|
||||
input: {
|
||||
appearance: 'none',
|
||||
@@ -246,8 +248,9 @@ const styles = StyleSheet.create({
|
||||
borderWidth: 0,
|
||||
boxSizing: 'border-box',
|
||||
color: 'inherit',
|
||||
flexGrow: 1,
|
||||
flex: 1,
|
||||
font: 'inherit',
|
||||
minHeight: '100%', // center small inputs (fix #139)
|
||||
padding: 0,
|
||||
zIndex: 1
|
||||
},
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import applyNativeMethods from '../../modules/applyNativeMethods'
|
||||
import createNativeComponent from '../../modules/createNativeComponent'
|
||||
import NativeMethodsDecorator from '../../modules/NativeMethodsDecorator'
|
||||
import normalizeNativeEvent from '../../apis/PanResponder/normalizeNativeEvent'
|
||||
import { Component, PropTypes } from 'react'
|
||||
import StyleSheet from '../../apis/StyleSheet'
|
||||
import StyleSheetPropType from '../../apis/StyleSheet/StyleSheetPropType'
|
||||
import ViewStylePropTypes from './ViewStylePropTypes'
|
||||
|
||||
@NativeMethodsDecorator
|
||||
class View extends Component {
|
||||
static propTypes = {
|
||||
accessibilityLabel: createNativeComponent.propTypes.accessibilityLabel,
|
||||
@@ -98,6 +97,8 @@ class View extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
applyNativeMethods(View)
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
// https://github.com/facebook/css-layout#default-values
|
||||
initial: {
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
import NativeMethodsMixin from '../NativeMethodsMixin'
|
||||
|
||||
const NativeMethodsDecorator = (Component) => {
|
||||
const applyNativeMethods = (Component) => {
|
||||
Object.keys(NativeMethodsMixin).forEach((method) => {
|
||||
if (!Component.prototype[method]) {
|
||||
Component.prototype[method] = NativeMethodsMixin[method]
|
||||
@@ -16,4 +16,4 @@ const NativeMethodsDecorator = (Component) => {
|
||||
return Component
|
||||
}
|
||||
|
||||
module.exports = NativeMethodsDecorator
|
||||
module.exports = applyNativeMethods
|
||||
@@ -1,61 +1,59 @@
|
||||
/* eslint-env mocha */
|
||||
|
||||
import * as utils from '../../specHelpers'
|
||||
import assert from 'assert'
|
||||
|
||||
import createNativeComponent from '../'
|
||||
import createNativeComponent from '..'
|
||||
import { shallow } from 'enzyme'
|
||||
|
||||
suite('modules/createNativeComponent', () => {
|
||||
test('prop "accessibilityLabel"', () => {
|
||||
const accessibilityLabel = 'accessibilityLabel'
|
||||
const dom = utils.renderToDOM(createNativeComponent({ accessibilityLabel }))
|
||||
assert.equal(dom.getAttribute('aria-label'), accessibilityLabel)
|
||||
const element = shallow(createNativeComponent({ accessibilityLabel }))
|
||||
assert.equal(element.prop('aria-label'), accessibilityLabel)
|
||||
})
|
||||
|
||||
test('prop "accessibilityLiveRegion"', () => {
|
||||
const accessibilityLiveRegion = 'polite'
|
||||
const dom = utils.renderToDOM(createNativeComponent({ accessibilityLiveRegion }))
|
||||
assert.equal(dom.getAttribute('aria-live'), accessibilityLiveRegion)
|
||||
const element = shallow(createNativeComponent({ accessibilityLiveRegion }))
|
||||
assert.equal(element.prop('aria-live'), accessibilityLiveRegion)
|
||||
})
|
||||
|
||||
test('prop "accessibilityRole"', () => {
|
||||
const accessibilityRole = 'banner'
|
||||
let dom = utils.renderToDOM(createNativeComponent({ accessibilityRole }))
|
||||
assert.equal(dom.getAttribute('role'), accessibilityRole)
|
||||
assert.equal((dom.tagName).toLowerCase(), 'header')
|
||||
let element = shallow(createNativeComponent({ accessibilityRole }))
|
||||
assert.equal(element.prop('role'), accessibilityRole)
|
||||
assert.equal(element.is('header'), true)
|
||||
|
||||
const button = 'button'
|
||||
dom = utils.renderToDOM(createNativeComponent({ accessibilityRole: 'button' }))
|
||||
assert.equal(dom.getAttribute('type'), button)
|
||||
assert.equal((dom.tagName).toLowerCase(), button)
|
||||
element = shallow(createNativeComponent({ accessibilityRole: 'button' }))
|
||||
assert.equal(element.prop('type'), button)
|
||||
assert.equal(element.is('button'), true)
|
||||
})
|
||||
|
||||
test('prop "accessible"', () => {
|
||||
// accessible (implicit)
|
||||
let dom = utils.renderToDOM(createNativeComponent({}))
|
||||
assert.equal(dom.getAttribute('aria-hidden'), null)
|
||||
let element = shallow(createNativeComponent({}))
|
||||
assert.equal(element.prop('aria-hidden'), null)
|
||||
// accessible (explicit)
|
||||
dom = utils.renderToDOM(createNativeComponent({ accessible: true }))
|
||||
assert.equal(dom.getAttribute('aria-hidden'), null)
|
||||
element = shallow(createNativeComponent({ accessible: true }))
|
||||
assert.equal(element.prop('aria-hidden'), null)
|
||||
// not accessible
|
||||
dom = utils.renderToDOM(createNativeComponent({ accessible: false }))
|
||||
assert.equal(dom.getAttribute('aria-hidden'), 'true')
|
||||
element = shallow(createNativeComponent({ accessible: false }))
|
||||
assert.equal(element.prop('aria-hidden'), true)
|
||||
})
|
||||
|
||||
test('prop "component"', () => {
|
||||
const component = 'main'
|
||||
const dom = utils.renderToDOM(createNativeComponent({ component }))
|
||||
const tagName = (dom.tagName).toLowerCase()
|
||||
assert.equal(tagName, component)
|
||||
const element = shallow(createNativeComponent({ component }))
|
||||
assert.equal(element.is('main'), true)
|
||||
})
|
||||
|
||||
test('prop "testID"', () => {
|
||||
// no testID
|
||||
let dom = utils.renderToDOM(createNativeComponent({}))
|
||||
assert.equal(dom.getAttribute('data-testid'), null)
|
||||
let element = shallow(createNativeComponent({}))
|
||||
assert.equal(element.prop('data-testid'), null)
|
||||
// with testID
|
||||
const testID = 'Example.testID'
|
||||
dom = utils.renderToDOM(createNativeComponent({ testID }))
|
||||
assert.equal(dom.getAttribute('data-testid'), testID)
|
||||
element = shallow(createNativeComponent({ testID }))
|
||||
assert.equal(element.prop('data-testid'), testID)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
/* eslint-env mocha */
|
||||
|
||||
import assert from 'assert'
|
||||
import React from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
import ReactTestUtils from 'react-addons-test-utils'
|
||||
|
||||
export const assertProps = {
|
||||
style: function (Component, props) {
|
||||
let shallow
|
||||
// default styles
|
||||
shallow = shallowRender(<Component {...props} />)
|
||||
assert.deepEqual(
|
||||
shallow.props.style,
|
||||
Component.defaultProps.style
|
||||
)
|
||||
// filtering of unsupported styles
|
||||
const styleToFilter = { unsupported: 'unsupported' }
|
||||
shallow = shallowRender(<Component {...props} style={styleToFilter} />)
|
||||
assert.deepEqual(
|
||||
shallow.props.style.unsupported,
|
||||
undefined,
|
||||
'unsupported "style" properties must not be transferred'
|
||||
)
|
||||
// merging of custom styles
|
||||
const styleToMerge = { margin: '10' }
|
||||
shallow = shallowRender(<Component {...props} style={styleToMerge} />)
|
||||
assert.deepEqual(
|
||||
shallow.props.style,
|
||||
{ ...Component.defaultProps.style, ...styleToMerge }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export function render(element, container) {
|
||||
return container
|
||||
? ReactDOM.render(element, container)
|
||||
: ReactTestUtils.renderIntoDocument(element)
|
||||
}
|
||||
|
||||
export function renderAndInject(element) {
|
||||
const id = '_renderAndInject'
|
||||
let div = document.getElementById(id)
|
||||
|
||||
if (!div) {
|
||||
div = document.createElement('div')
|
||||
div.id = id
|
||||
document.body.appendChild(div)
|
||||
} else {
|
||||
div.innerHTML = ''
|
||||
}
|
||||
|
||||
const result = render(element, div)
|
||||
return ReactDOM.findDOMNode(result)
|
||||
}
|
||||
|
||||
export function renderToDOM(element, container) {
|
||||
const result = render(element, container)
|
||||
return ReactDOM.findDOMNode(result)
|
||||
}
|
||||
|
||||
export function shallowRender(component, context = {}) {
|
||||
const shallowRenderer = ReactTestUtils.createRenderer()
|
||||
shallowRenderer.render(component, context)
|
||||
return shallowRenderer.getRenderOutput()
|
||||
}
|
||||
|
||||
export function testIfDocumentFocused(message, fn) {
|
||||
if (document.hasFocus && document.hasFocus()) {
|
||||
test(message, fn)
|
||||
} else {
|
||||
test.skip(`${message} – WARNING: document is not focused`)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user