mirror of
https://github.com/zhigang1992/react-native-web.git
synced 2026-03-30 23:23:35 +08:00
Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fd04d65b03 | ||
|
|
0ab984f507 | ||
|
|
3d1ad50a58 | ||
|
|
92554321df | ||
|
|
1c9270c4ea | ||
|
|
8a5f9cd7d9 | ||
|
|
aac6b796b2 | ||
|
|
c77ce19f1b | ||
|
|
25b74d30c4 | ||
|
|
4191d58694 | ||
|
|
11b861ae64 | ||
|
|
68bf08112a | ||
|
|
b277b3e509 | ||
|
|
c135dddbd1 |
@@ -128,7 +128,8 @@ reactStyleSheet.textContent = StyleSheet.renderToString()
|
||||
### [`StyleSheet`](docs/apis/StyleSheet.md)
|
||||
|
||||
StyleSheet is a style abstraction that transforms inline styles to CSS on the
|
||||
client or the server. It provides a minimal CSS reset.
|
||||
client or the server. It provides a minimal CSS reset targeting elements and
|
||||
pseudo-elements beyond the reach of React inline styles.
|
||||
|
||||
## Components
|
||||
|
||||
@@ -147,7 +148,7 @@ A scrollable view with event throttling.
|
||||
|
||||
### [`Text`](docs/components/Text.md)
|
||||
|
||||
Displays text as an inline block and supports basic press handling.
|
||||
Displays text inline and supports basic press handling.
|
||||
|
||||
### [`TextInput`](docs/components/TextInput.md)
|
||||
|
||||
|
||||
@@ -1,17 +1,21 @@
|
||||
var webpack = require('webpack')
|
||||
|
||||
var DedupePlugin = webpack.optimize.DedupePlugin
|
||||
var EnvironmentPlugin = webpack.EnvironmentPlugin
|
||||
var DefinePlugin = webpack.DefinePlugin
|
||||
var OccurenceOrderPlugin = webpack.optimize.OccurenceOrderPlugin
|
||||
var UglifyJsPlugin = webpack.optimize.UglifyJsPlugin
|
||||
|
||||
var plugins = [
|
||||
new DedupePlugin(),
|
||||
new EnvironmentPlugin('NODE_ENV'),
|
||||
new OccurenceOrderPlugin()
|
||||
]
|
||||
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
plugins.push(
|
||||
new DefinePlugin({
|
||||
'process.env.NODE_ENV': JSON.stringify('production')
|
||||
})
|
||||
)
|
||||
plugins.push(
|
||||
new UglifyJsPlugin({
|
||||
compress: {
|
||||
|
||||
@@ -57,7 +57,7 @@ could be an http address or a base64 encoded image.
|
||||
|
||||
**style**: style
|
||||
|
||||
[View](View.md) style
|
||||
+ ...[View#style](View.md)
|
||||
|
||||
Defaults:
|
||||
|
||||
@@ -76,11 +76,9 @@ Used to locate a view in end-to-end tests.
|
||||
|
||||
```js
|
||||
import placeholderAvatar from './placeholderAvatar.png'
|
||||
import React, { Image, StyleSheet } from 'react-native-web'
|
||||
import React, { Component, Image, PropTypes, StyleSheet } from 'react-native-web'
|
||||
|
||||
const { Component, PropTypes } = React;
|
||||
|
||||
export default class Avatar extends Component {
|
||||
export default class ImageExample extends Component {
|
||||
constructor(props, context) {
|
||||
super(props, context)
|
||||
this.state = { loading: true }
|
||||
@@ -112,7 +110,11 @@ export default class Avatar extends Component {
|
||||
onLoad={this._onLoad.bind(this)}
|
||||
resizeMode='cover'
|
||||
source={{ uri: user.avatarUrl }}
|
||||
style={{ ...styles.base, ...styles[size], ...loadingStyle }}
|
||||
style={{
|
||||
...styles.base,
|
||||
...styles[size],
|
||||
...loadingStyle
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
@@ -121,23 +123,23 @@ export default class Avatar extends Component {
|
||||
const styles = StyleSheet.create({
|
||||
base: {
|
||||
borderColor: 'white',
|
||||
borderRadius: '5px',
|
||||
borderWidth: '5px'
|
||||
borderRadius: 5,
|
||||
borderWidth: 5
|
||||
},
|
||||
loading: {
|
||||
opacity: 0.5
|
||||
},
|
||||
small: {
|
||||
height: '32px',
|
||||
width: '32px'
|
||||
height: 32,
|
||||
width: 32
|
||||
},
|
||||
normal: {
|
||||
height: '48px',
|
||||
width: '48px'
|
||||
height: 48,
|
||||
width: 48
|
||||
},
|
||||
large: {
|
||||
height: '64px',
|
||||
width: '64px'
|
||||
height: 64,
|
||||
width: 64
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
@@ -10,28 +10,17 @@ Content to display over the image.
|
||||
|
||||
**style**: style
|
||||
|
||||
+ `property` type
|
||||
|
||||
Defaults:
|
||||
|
||||
```js
|
||||
{
|
||||
}
|
||||
```
|
||||
+ ...[View#style](View.md)
|
||||
|
||||
## Examples
|
||||
|
||||
```js
|
||||
import React, { ListView } from 'react-native-web'
|
||||
import React, { Component, ListView, PropTypes } from 'react-native-web'
|
||||
|
||||
const { Component, PropTypes } = React;
|
||||
export default class ListViewExample extends Component {
|
||||
static propTypes = {}
|
||||
|
||||
class Example extends Component {
|
||||
static propTypes = {
|
||||
}
|
||||
|
||||
static defaultProps = {
|
||||
}
|
||||
static defaultProps = {}
|
||||
|
||||
render() {
|
||||
return (
|
||||
|
||||
@@ -38,16 +38,15 @@ time the view is scrolled.
|
||||
|
||||
**style**: style
|
||||
|
||||
[View](View.md) style
|
||||
+ ...[View#style](View.md)
|
||||
|
||||
## Examples
|
||||
|
||||
```js
|
||||
import React, { ScrollView, StyleSheet } from 'react-native-web'
|
||||
|
||||
import React, { Component, ScrollView, StyleSheet } from 'react-native-web'
|
||||
import Item from './Item'
|
||||
|
||||
export default class App extends React.Component {
|
||||
export default class ScrollViewExample extends Component {
|
||||
constructor(props, context) {
|
||||
super(props, context)
|
||||
this.state = {
|
||||
@@ -75,10 +74,10 @@ export default class App extends React.Component {
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
root: {
|
||||
borderWidth: '1px'
|
||||
borderWidth: 1
|
||||
},
|
||||
container: {
|
||||
padding: '10px'
|
||||
padding: 10
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
# Text
|
||||
|
||||
`Text` is component for displaying text. It supports style, basic touch
|
||||
handling, and inherits typographic styles from ancestor elements. In a
|
||||
divergence from React Native, components other than `Text` can be children of a
|
||||
`Text` component.
|
||||
handling, and inherits typographic styles from ancestor elements.
|
||||
|
||||
The `Text` is unique relative to layout: child elements use text layout
|
||||
(`inline-block`) rather than flexbox layout. This means that elements inside of
|
||||
a `Text` are not rectangles, as they wrap when reaching the edge of their
|
||||
(`inline`) rather than flexbox layout. This means that elements inside of a
|
||||
`Text` are not rectangles, as they wrap when reaching the edge of their
|
||||
container.
|
||||
|
||||
Unsupported React Native props:
|
||||
@@ -53,22 +51,20 @@ This function is called on press.
|
||||
|
||||
**style**: style
|
||||
|
||||
+ `backgroundColor`
|
||||
+ ...[View#style](View.md)
|
||||
+ `color`
|
||||
+ `direction`
|
||||
+ `fontFamily`
|
||||
+ `fontSize`
|
||||
+ `fontStyle`
|
||||
+ `fontWeight`
|
||||
+ `letterSpacing`
|
||||
+ `lineHeight`
|
||||
+ `margin`
|
||||
+ `padding`
|
||||
+ `textAlign`
|
||||
+ `textDecoration`
|
||||
+ `textTransform`
|
||||
+ `whiteSpace`
|
||||
+ `wordWrap`
|
||||
+ `writingDirection`
|
||||
|
||||
**testID**: string
|
||||
|
||||
@@ -77,18 +73,18 @@ Used to locate this view in end-to-end tests.
|
||||
## Examples
|
||||
|
||||
```js
|
||||
import React, { StyleSheet, Text } from 'react-native-web'
|
||||
import React, { Component, PropTypes, StyleSheet, Text } from 'react-native-web'
|
||||
|
||||
const { Component, PropTypes } = React
|
||||
|
||||
class PrettyText extends Component {
|
||||
export default class PrettyText extends Component {
|
||||
static propTypes = {
|
||||
...Text.propTypes,
|
||||
color: PropTypes.oneOf(['white', 'gray', 'red']),
|
||||
size: PropTypes.oneOf(['small', 'normal', 'large']),
|
||||
weight: PropTypes.oneOf(['light', 'normal', 'bold'])
|
||||
}
|
||||
|
||||
static defaultProps = {
|
||||
...Text.defaultProps,
|
||||
color: 'gray',
|
||||
size: 'normal',
|
||||
weight: 'normal'
|
||||
@@ -102,16 +98,16 @@ class PrettyText extends Component {
|
||||
...other
|
||||
style={{
|
||||
...style,
|
||||
...localStyle.color[color],
|
||||
...localStyle.size[size],
|
||||
...localStyle.weight[weight]
|
||||
...styles.color[color],
|
||||
...styles.size[size],
|
||||
...styles.weight[weight]
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const localStyle = StyleSheet.create({
|
||||
const styles = StyleSheet.create({
|
||||
color: {
|
||||
white: { color: 'white' },
|
||||
gray: { color: 'gray' },
|
||||
|
||||
@@ -48,9 +48,10 @@ updating the `value` prop to keep the controlled state in sync.
|
||||
|
||||
If `false`, text is not editable (i.e., read-only).
|
||||
|
||||
**keyboardType**: oneOf('default', 'email-address', 'numeric', 'phone-pad', 'url') = 'default'
|
||||
**keyboardType**: oneOf('default', 'email-address', 'numeric', 'phone-pad', 'search', 'url', 'web-search') = 'default'
|
||||
|
||||
Determines which keyboard to open.
|
||||
Determines which keyboard to open. (NOTE: Safari iOS requires an ancestral
|
||||
`<form action>` element to display the `search` keyboard).
|
||||
|
||||
(Not available when `multiline` is `true`.)
|
||||
|
||||
@@ -111,11 +112,12 @@ object is passed as an argument to the callback handler.
|
||||
|
||||
**placeholder**: string
|
||||
|
||||
The string that will be rendered before text input has been entered.
|
||||
The string that will be rendered in an empty `TextInput` before text has been
|
||||
entered.
|
||||
|
||||
**placeholderTextColor**: string
|
||||
|
||||
TODO. The text color of the placeholder string.
|
||||
The text color of the placeholder string.
|
||||
|
||||
**secureTextEntry**: bool = false
|
||||
|
||||
@@ -130,19 +132,8 @@ If `true`, all text will automatically be selected on focus.
|
||||
|
||||
**style**: style
|
||||
|
||||
[View](View.md) style
|
||||
|
||||
+ `color`
|
||||
+ `direction`
|
||||
+ `fontFamily`
|
||||
+ `fontSize`
|
||||
+ `fontStyle`
|
||||
+ `fontWeight`
|
||||
+ `letterSpacing`
|
||||
+ `lineHeight`
|
||||
+ `textAlign`
|
||||
+ `textDecoration`
|
||||
+ `textTransform`
|
||||
+ ...[Text#style](Text.md)
|
||||
+ `outline`
|
||||
|
||||
**testID**: string
|
||||
|
||||
@@ -159,14 +150,18 @@ user edits to the value set `editable={false}`.
|
||||
## Examples
|
||||
|
||||
```js
|
||||
import React, { StyleSheet, TextInput } from 'react-native-web'
|
||||
import React, { Component, StyleSheet, TextInput } from 'react-native-web'
|
||||
|
||||
export default class AppTextInput extends React.Component {
|
||||
export default class TextInputExample extends Component {
|
||||
constructor(props, context) {
|
||||
super(props, context)
|
||||
this.state = { isFocused: false }
|
||||
}
|
||||
|
||||
_onBlur(e) {
|
||||
this.setState({ isFocused: false })
|
||||
}
|
||||
|
||||
_onFocus(e) {
|
||||
this.setState({ isFocused: true })
|
||||
}
|
||||
@@ -178,6 +173,7 @@ export default class AppTextInput extends React.Component {
|
||||
maxNumberOfLines={5}
|
||||
multiline
|
||||
numberOfLines={2}
|
||||
onBlur={this._onBlur.bind(this)}
|
||||
onFocus={this._onFocus.bind(this)}
|
||||
placeholder={`What's happening?`}
|
||||
style={{
|
||||
@@ -192,7 +188,7 @@ export default class AppTextInput extends React.Component {
|
||||
const styles = StyleSheet.create({
|
||||
default: {
|
||||
borderColor: 'gray',
|
||||
borderWidth: '0 0 2px 0'
|
||||
borderBottomWidth: 2
|
||||
},
|
||||
focused: {
|
||||
borderColor: 'blue'
|
||||
|
||||
@@ -79,21 +79,17 @@ Delay in ms, from the release of the touch, before `onPressOut` is called.
|
||||
|
||||
**style**: style
|
||||
|
||||
[View](View.md) style
|
||||
+ ...[View#style](View.md)
|
||||
|
||||
## Examples
|
||||
|
||||
```js
|
||||
import React, { Touchable } from 'react-native-web'
|
||||
import React, { Component, PropTypes, Touchable } from 'react-native-web'
|
||||
|
||||
const { Component, PropTypes } = React;
|
||||
export default class Example extends Component {
|
||||
static propTypes = {}
|
||||
|
||||
class Example extends Component {
|
||||
static propTypes = {
|
||||
}
|
||||
|
||||
static defaultProps = {
|
||||
}
|
||||
static defaultProps = {}
|
||||
|
||||
render() {
|
||||
return (
|
||||
|
||||
@@ -109,6 +109,12 @@ from `style`.
|
||||
+ `justifyContent`
|
||||
+ `left`
|
||||
+ `margin`
|
||||
+ `marginBottom`
|
||||
+ `marginHorizontal`
|
||||
+ `marginLeft`
|
||||
+ `marginRight`
|
||||
+ `marginTop`
|
||||
+ `marginVertical`
|
||||
+ `maxHeight`
|
||||
+ `maxWidth`
|
||||
+ `minHeight`
|
||||
@@ -119,6 +125,12 @@ from `style`.
|
||||
+ `overflowX`
|
||||
+ `overflowY`
|
||||
+ `padding`
|
||||
+ `paddingBottom`
|
||||
+ `paddingHorizontal`
|
||||
+ `paddingLeft`
|
||||
+ `paddingRight`
|
||||
+ `paddingTop`
|
||||
+ `paddingVertical`
|
||||
+ `position`
|
||||
+ `right`
|
||||
+ `top`
|
||||
@@ -155,11 +167,9 @@ Used to locate this view in end-to-end tests.
|
||||
## Examples
|
||||
|
||||
```js
|
||||
import React, { StyleSheet, View } from 'react-native-web'
|
||||
import React, { Component, PropTypes, StyleSheet, View } from 'react-native-web'
|
||||
|
||||
const { Component, PropTypes } = React
|
||||
|
||||
class Example extends Component {
|
||||
export default class ViewExample extends Component {
|
||||
render() {
|
||||
return (
|
||||
<View style={styles.row}>
|
||||
@@ -181,6 +191,4 @@ const styles = StyleSheet.create({
|
||||
flexGrow: 1
|
||||
}
|
||||
})
|
||||
|
||||
export default Example
|
||||
```
|
||||
|
||||
@@ -95,10 +95,10 @@ export default class App extends React.Component {
|
||||
/>
|
||||
<TextInput secureTextEntry />
|
||||
<TextInput defaultValue='read only' editable={false} />
|
||||
<TextInput keyboardType='email-address' />
|
||||
<TextInput keyboardType='email-address' placeholder='you@domain.com' placeholderTextColor='red' />
|
||||
<TextInput keyboardType='numeric' />
|
||||
<TextInput keyboardType='phone-pad' />
|
||||
<TextInput keyboardType='url' selectTextOnFocus />
|
||||
<TextInput defaultValue='https://delete-me' keyboardType='url' placeholder='https://www.some-website.com' selectTextOnFocus />
|
||||
<TextInput
|
||||
defaultValue='default value'
|
||||
maxNumberOfLines={10}
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
import React, { StyleSheet, View } from '../../src'
|
||||
|
||||
const { Component, PropTypes } = React
|
||||
import React, { Component, PropTypes, StyleSheet, View } from '../../src'
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
root: {
|
||||
@@ -42,8 +40,8 @@ export default class GridView extends Component {
|
||||
|
||||
const contentContainerStyle = {
|
||||
...styles.contentContainer,
|
||||
margin: `0 calc(-0.5 * ${alley})`,
|
||||
padding: `0 ${gutter}`
|
||||
marginHorizontal: `calc(-0.5 * ${alley})`,
|
||||
paddingHorizontal: `${gutter}`
|
||||
}
|
||||
|
||||
const newChildren = React.Children.map(children, (child) => {
|
||||
@@ -51,7 +49,7 @@ export default class GridView extends Component {
|
||||
style: {
|
||||
...child.props.style,
|
||||
...styles.column,
|
||||
margin: `0 calc(0.5 * ${alley})`
|
||||
marginHorizontal: `calc(0.5 * ${alley})`
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import React from 'react'
|
||||
import { StyleSheet, Text } from '../../src'
|
||||
import React, { StyleSheet, Text } from '../../src'
|
||||
|
||||
const headingStyles = StyleSheet.create({
|
||||
const styles = StyleSheet.create({
|
||||
root: {
|
||||
fontFamily: '"Helvetica Neue", arial, sans-serif'
|
||||
},
|
||||
size: {
|
||||
xlarge: {
|
||||
fontSize: '2rem',
|
||||
@@ -24,7 +26,7 @@ const Heading = ({ children, size = 'normal' }) => (
|
||||
<Text
|
||||
accessibilityRole='heading'
|
||||
children={children}
|
||||
style={headingStyles.size[size]}
|
||||
style={{ ...styles.root, ...styles.size[size] }}
|
||||
/>
|
||||
)
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ const MediaQueryWidget = ({ mediaQuery = {} }) => {
|
||||
return (
|
||||
<View style={styles.root}>
|
||||
<Text style={styles.heading}>Active Media Query</Text>
|
||||
<Text>{`"${active.alias}"`} {active.mql.media}</Text>
|
||||
<Text>{`"${active.alias}"`} {active.mql && active.mql.media}</Text>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
<title>React Native for Web</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="description" content="The core React Native components adapted and expanded upon for the web">
|
||||
<style>html { font-family: sans-serif; }</style>
|
||||
<style id="react-stylesheet"></style>
|
||||
<div id="react-root"></div>
|
||||
<script src="/examples.js"></script>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "react-native-web",
|
||||
"version": "0.0.10",
|
||||
"version": "0.0.12",
|
||||
"description": "React Native for Web",
|
||||
"main": "dist/react-native-web.js",
|
||||
"files": [
|
||||
@@ -10,7 +10,7 @@
|
||||
"build": "rm -rf ./dist && webpack --config config/webpack.config.publish.js --sort-assets-by --progress",
|
||||
"examples": "webpack-dev-server --config config/webpack.config.example.js --inline --hot --colors --quiet",
|
||||
"lint": "eslint config examples src",
|
||||
"prepublish": "NODE_ENV=publish npm run build",
|
||||
"prepublish": "npm run build",
|
||||
"test": "npm run lint && npm run test:unit",
|
||||
"test:unit": "karma start config/karma.config.js",
|
||||
"test:watch": "npm run test:unit -- --no-single-run"
|
||||
|
||||
@@ -11,6 +11,8 @@ const roleComponents = {
|
||||
form: 'form',
|
||||
heading: 'h1',
|
||||
link: 'a',
|
||||
list: 'ul',
|
||||
listitem: 'li',
|
||||
main: 'main',
|
||||
navigation: 'nav',
|
||||
region: 'section'
|
||||
|
||||
@@ -1,35 +1,22 @@
|
||||
import { pickProps } from '../../modules/filterObjectProps'
|
||||
import CoreComponent from '../CoreComponent'
|
||||
import View from '../View'
|
||||
|
||||
export default {
|
||||
...View.stylePropTypes,
|
||||
...pickProps(CoreComponent.stylePropTypes, [
|
||||
'backgroundColor',
|
||||
'color',
|
||||
'direction',
|
||||
'font',
|
||||
'fontFamily',
|
||||
'fontSize',
|
||||
'fontStyle',
|
||||
'fontWeight',
|
||||
'letterSpacing',
|
||||
'lineHeight',
|
||||
'margin',
|
||||
'marginHorizontal',
|
||||
'marginVertical',
|
||||
'marginBottom',
|
||||
'marginLeft',
|
||||
'marginRight',
|
||||
'marginTop',
|
||||
'padding',
|
||||
'paddingHorizontal',
|
||||
'paddingVertical',
|
||||
'paddingBottom',
|
||||
'paddingLeft',
|
||||
'paddingRight',
|
||||
'paddingTop',
|
||||
'textAlign',
|
||||
'textDecoration',
|
||||
'textTransform',
|
||||
'whiteSpace',
|
||||
'wordWrap'
|
||||
'wordWrap',
|
||||
'writingDirection'
|
||||
])
|
||||
}
|
||||
|
||||
@@ -1,20 +1,7 @@
|
||||
import { pickProps } from '../../modules/filterObjectProps'
|
||||
import View from '../View'
|
||||
import CoreComponent from '../CoreComponent'
|
||||
import React from 'react'
|
||||
import Text from '../Text'
|
||||
|
||||
export default {
|
||||
...(View.stylePropTypes),
|
||||
...pickProps(CoreComponent.stylePropTypes, [
|
||||
'color',
|
||||
'direction',
|
||||
'fontFamily',
|
||||
'fontSize',
|
||||
'fontStyle',
|
||||
'fontWeight',
|
||||
'letterSpacing',
|
||||
'lineHeight',
|
||||
'textAlign',
|
||||
'textDecoration',
|
||||
'textTransform'
|
||||
])
|
||||
...Text.stylePropTypes,
|
||||
outline: React.PropTypes.string
|
||||
}
|
||||
|
||||
@@ -7,6 +7,10 @@ import ReactTestUtils from 'react-addons-test-utils'
|
||||
|
||||
import TextInput from '../'
|
||||
|
||||
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]
|
||||
|
||||
suite('components/TextInput', () => {
|
||||
test('prop "accessibilityLabel"', () => {
|
||||
const accessibilityLabel = 'accessibilityLabel'
|
||||
@@ -16,123 +20,120 @@ suite('components/TextInput', () => {
|
||||
|
||||
test('prop "autoComplete"', () => {
|
||||
// off
|
||||
let dom = utils.renderToDOM(<TextInput />)
|
||||
assert.equal(dom.getAttribute('autocomplete'), undefined)
|
||||
let input = findInput(utils.renderToDOM(<TextInput />))
|
||||
assert.equal(input.getAttribute('autocomplete'), undefined)
|
||||
// on
|
||||
dom = utils.renderToDOM(<TextInput autoComplete />)
|
||||
assert.equal(dom.getAttribute('autocomplete'), 'on')
|
||||
input = findInput(utils.renderToDOM(<TextInput autoComplete />))
|
||||
assert.equal(input.getAttribute('autocomplete'), 'on')
|
||||
})
|
||||
|
||||
test('prop "autoFocus"', () => {
|
||||
// false
|
||||
let dom = utils.renderToDOM(<TextInput />)
|
||||
let input = findInput(utils.renderToDOM(<TextInput />))
|
||||
assert.deepEqual(document.activeElement, document.body)
|
||||
// true
|
||||
dom = utils.renderToDOM(<TextInput autoFocus />)
|
||||
assert.deepEqual(document.activeElement, dom)
|
||||
input = findInput(utils.renderToDOM(<TextInput autoFocus />))
|
||||
assert.deepEqual(document.activeElement, input)
|
||||
})
|
||||
|
||||
utils.testIfDocumentFocused('prop "clearTextOnFocus"', () => {
|
||||
const defaultValue = 'defaultValue'
|
||||
// false
|
||||
let dom = utils.renderAndInject(<TextInput defaultValue={defaultValue} />)
|
||||
dom.focus()
|
||||
assert.equal(dom.value, defaultValue)
|
||||
let input = findInput(utils.renderAndInject(<TextInput defaultValue={defaultValue} />))
|
||||
input.focus()
|
||||
assert.equal(input.value, defaultValue)
|
||||
// true
|
||||
dom = utils.renderAndInject(<TextInput clearTextOnFocus defaultValue={defaultValue} />)
|
||||
dom.focus()
|
||||
assert.equal(dom.value, '')
|
||||
input = findInput(utils.renderAndInject(<TextInput clearTextOnFocus defaultValue={defaultValue} />))
|
||||
input.focus()
|
||||
assert.equal(input.value, '')
|
||||
})
|
||||
|
||||
test('prop "defaultValue"', () => {
|
||||
const defaultValue = 'defaultValue'
|
||||
const result = utils.shallowRender(<TextInput defaultValue={defaultValue} />)
|
||||
assert.equal(result.props.defaultValue, defaultValue)
|
||||
const input = findShallowInput(utils.shallowRender(<TextInput defaultValue={defaultValue} />))
|
||||
assert.equal(input.props.defaultValue, defaultValue)
|
||||
})
|
||||
|
||||
test('prop "editable"', () => {
|
||||
// true
|
||||
let dom = utils.renderToDOM(<TextInput />)
|
||||
assert.equal(dom.getAttribute('readonly'), undefined)
|
||||
let input = findInput(utils.renderToDOM(<TextInput />))
|
||||
assert.equal(input.getAttribute('readonly'), undefined)
|
||||
// false
|
||||
dom = utils.renderToDOM(<TextInput editable={false} />)
|
||||
assert.equal(dom.getAttribute('readonly'), '')
|
||||
input = findInput(utils.renderToDOM(<TextInput editable={false} />))
|
||||
assert.equal(input.getAttribute('readonly'), '')
|
||||
})
|
||||
|
||||
test('prop "keyboardType"', () => {
|
||||
// default
|
||||
let dom = utils.renderToDOM(<TextInput />)
|
||||
assert.equal(dom.getAttribute('type'), undefined)
|
||||
dom = utils.renderToDOM(<TextInput keyboardType='default' />)
|
||||
assert.equal(dom.getAttribute('type'), undefined)
|
||||
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)
|
||||
// email-address
|
||||
dom = utils.renderToDOM(<TextInput keyboardType='email-address' />)
|
||||
assert.equal(dom.getAttribute('type'), 'email')
|
||||
input = findInput(utils.renderToDOM(<TextInput keyboardType='email-address' />))
|
||||
assert.equal(input.getAttribute('type'), 'email')
|
||||
// numeric
|
||||
dom = utils.renderToDOM(<TextInput keyboardType='numeric' />)
|
||||
assert.equal(dom.getAttribute('type'), 'number')
|
||||
input = findInput(utils.renderToDOM(<TextInput keyboardType='numeric' />))
|
||||
assert.equal(input.getAttribute('type'), 'number')
|
||||
// phone-pad
|
||||
dom = utils.renderToDOM(<TextInput keyboardType='phone-pad' />)
|
||||
assert.equal(dom.getAttribute('type'), 'tel')
|
||||
input = findInput(utils.renderToDOM(<TextInput keyboardType='phone-pad' />))
|
||||
assert.equal(input.getAttribute('type'), 'tel')
|
||||
// url
|
||||
dom = utils.renderToDOM(<TextInput keyboardType='url' />)
|
||||
assert.equal(dom.getAttribute('type'), 'url')
|
||||
input = findInput(utils.renderToDOM(<TextInput keyboardType='url' />))
|
||||
assert.equal(input.getAttribute('type'), 'url')
|
||||
})
|
||||
|
||||
test('prop "maxLength"', () => {
|
||||
let dom = utils.renderToDOM(<TextInput />)
|
||||
assert.equal(dom.getAttribute('maxlength'), undefined)
|
||||
dom = utils.renderToDOM(<TextInput maxLength={10} />)
|
||||
assert.equal(dom.getAttribute('maxlength'), '10')
|
||||
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')
|
||||
})
|
||||
|
||||
test('prop "maxNumberOfLines"', () => {
|
||||
const style = { borderWidth: 0, fontSize: 20, lineHeight: 1 }
|
||||
const generateValue = () => {
|
||||
let str = ''
|
||||
while (str.length < 100) str += 'x'
|
||||
return str
|
||||
}
|
||||
|
||||
let dom = utils.renderAndInject(
|
||||
let input = findInput(utils.renderAndInject(
|
||||
<TextInput
|
||||
maxNumberOfLines={3}
|
||||
multiline
|
||||
style={style}
|
||||
value={generateValue()}
|
||||
/>
|
||||
)
|
||||
const height = dom.getBoundingClientRect().height
|
||||
))
|
||||
const height = input.getBoundingClientRect().height
|
||||
// need a range because of cross-browser differences
|
||||
assert.ok(height >= 60, height)
|
||||
assert.ok(height <= 66, height)
|
||||
assert.ok(height >= 42, height)
|
||||
assert.ok(height <= 48, height)
|
||||
})
|
||||
|
||||
test('prop "multiline"', () => {
|
||||
// false
|
||||
let dom = utils.renderToDOM(<TextInput />)
|
||||
assert.equal(dom.tagName, 'INPUT')
|
||||
let input = findInput(utils.renderToDOM(<TextInput />))
|
||||
assert.equal(input.tagName, 'INPUT')
|
||||
// true
|
||||
dom = utils.renderToDOM(<TextInput multiline />)
|
||||
assert.equal(dom.tagName, 'TEXTAREA')
|
||||
input = findInput(utils.renderToDOM(<TextInput multiline />))
|
||||
assert.equal(input.tagName, 'TEXTAREA')
|
||||
})
|
||||
|
||||
test('prop "numberOfLines"', () => {
|
||||
const style = { borderWidth: 0, fontSize: 20, lineHeight: 1 }
|
||||
// missing multiline
|
||||
let dom = utils.renderToDOM(<TextInput numberOfLines={2} />)
|
||||
assert.equal(dom.tagName, 'INPUT')
|
||||
let input = findInput(utils.renderToDOM(<TextInput numberOfLines={2} />))
|
||||
assert.equal(input.tagName, 'INPUT')
|
||||
// with multiline
|
||||
dom = utils.renderAndInject(<TextInput multiline numberOfLines={2} style={style} />)
|
||||
assert.equal(dom.tagName, 'TEXTAREA')
|
||||
const height = dom.getBoundingClientRect().height
|
||||
input = findInput(utils.renderAndInject(<TextInput multiline numberOfLines={2} />))
|
||||
assert.equal(input.tagName, 'TEXTAREA')
|
||||
const height = input.getBoundingClientRect().height
|
||||
// need a range because of cross-browser differences
|
||||
assert.ok(height >= 40)
|
||||
assert.ok(height <= 46)
|
||||
assert.ok(height >= 30, height)
|
||||
assert.ok(height <= 36, height)
|
||||
})
|
||||
|
||||
test('prop "onBlur"', (done) => {
|
||||
const input = utils.renderToDOM(<TextInput onBlur={onBlur} />)
|
||||
const input = findInput(utils.renderToDOM(<TextInput onBlur={onBlur} />))
|
||||
ReactTestUtils.Simulate.blur(input)
|
||||
function onBlur(e) {
|
||||
assert.ok(e)
|
||||
@@ -141,7 +142,7 @@ suite('components/TextInput', () => {
|
||||
})
|
||||
|
||||
test('prop "onChange"', (done) => {
|
||||
const input = utils.renderToDOM(<TextInput onChange={onChange} />)
|
||||
const input = findInput(utils.renderToDOM(<TextInput onChange={onChange} />))
|
||||
ReactTestUtils.Simulate.change(input)
|
||||
function onChange(e) {
|
||||
assert.ok(e)
|
||||
@@ -151,7 +152,7 @@ suite('components/TextInput', () => {
|
||||
|
||||
test('prop "onChangeText"', (done) => {
|
||||
const newText = 'newText'
|
||||
const input = utils.renderToDOM(<TextInput onChangeText={onChangeText} />)
|
||||
const input = findInput(utils.renderToDOM(<TextInput onChangeText={onChangeText} />))
|
||||
ReactTestUtils.Simulate.change(input, { target: { value: newText } })
|
||||
function onChangeText(text) {
|
||||
assert.equal(text, newText)
|
||||
@@ -160,7 +161,7 @@ suite('components/TextInput', () => {
|
||||
})
|
||||
|
||||
test('prop "onFocus"', (done) => {
|
||||
const input = utils.renderToDOM(<TextInput onFocus={onFocus} />)
|
||||
const input = findInput(utils.renderToDOM(<TextInput onFocus={onFocus} />))
|
||||
ReactTestUtils.Simulate.focus(input)
|
||||
function onFocus(e) {
|
||||
assert.ok(e)
|
||||
@@ -171,7 +172,7 @@ suite('components/TextInput', () => {
|
||||
test('prop "onLayout"')
|
||||
|
||||
test('prop "onSelectionChange"', (done) => {
|
||||
const input = utils.renderAndInject(<TextInput defaultValue='12345' onSelectionChange={onSelectionChange} />)
|
||||
const input = findInput(utils.renderAndInject(<TextInput defaultValue='12345' onSelectionChange={onSelectionChange} />))
|
||||
ReactTestUtils.Simulate.select(input, { target: { selectionStart: 0, selectionEnd: 3 } })
|
||||
function onSelectionChange(e) {
|
||||
assert.equal(e.selectionEnd, 3)
|
||||
@@ -180,30 +181,42 @@ suite('components/TextInput', () => {
|
||||
}
|
||||
})
|
||||
|
||||
test('prop "placeholder"')
|
||||
test('prop "placeholder"', () => {
|
||||
const placeholder = 'placeholder'
|
||||
const result = findShallowPlaceholder(utils.shallowRender(<TextInput placeholder={placeholder} />))
|
||||
assert.equal(result.props.children, placeholder)
|
||||
})
|
||||
|
||||
test('prop "placeholderTextColor"')
|
||||
test('prop "placeholderTextColor"', () => {
|
||||
const placeholder = 'placeholder'
|
||||
|
||||
let result = findShallowPlaceholder(utils.shallowRender(<TextInput placeholder={placeholder} />))
|
||||
assert.equal(result.props.style.color, 'darkgray')
|
||||
|
||||
result = findShallowPlaceholder(utils.shallowRender(<TextInput placeholder={placeholder} placeholderTextColor='red' />))
|
||||
assert.equal(result.props.style.color, 'red')
|
||||
})
|
||||
|
||||
test('prop "secureTextEntry"', () => {
|
||||
let dom = utils.renderToDOM(<TextInput secureTextEntry />)
|
||||
assert.equal(dom.getAttribute('type'), 'password')
|
||||
let input = findInput(utils.renderToDOM(<TextInput secureTextEntry />))
|
||||
assert.equal(input.getAttribute('type'), 'password')
|
||||
// ignored for multiline
|
||||
dom = utils.renderToDOM(<TextInput multiline secureTextEntry />)
|
||||
assert.equal(dom.getAttribute('type'), undefined)
|
||||
input = findInput(utils.renderToDOM(<TextInput multiline secureTextEntry />))
|
||||
assert.equal(input.getAttribute('type'), undefined)
|
||||
})
|
||||
|
||||
utils.testIfDocumentFocused('prop "selectTextOnFocus"', () => {
|
||||
const text = 'Text'
|
||||
// false
|
||||
let dom = utils.renderAndInject(<TextInput defaultValue={text} />)
|
||||
dom.focus()
|
||||
assert.equal(dom.selectionEnd, 0)
|
||||
assert.equal(dom.selectionStart, 0)
|
||||
let input = findInput(utils.renderAndInject(<TextInput defaultValue={text} />))
|
||||
input.focus()
|
||||
assert.equal(input.selectionEnd, 0)
|
||||
assert.equal(input.selectionStart, 0)
|
||||
// true
|
||||
dom = utils.renderAndInject(<TextInput defaultValue={text} selectTextOnFocus />)
|
||||
dom.focus()
|
||||
assert.equal(dom.selectionEnd, 4)
|
||||
assert.equal(dom.selectionStart, 0)
|
||||
input = findInput(utils.renderAndInject(<TextInput defaultValue={text} selectTextOnFocus />))
|
||||
input.focus()
|
||||
assert.equal(input.selectionEnd, 4)
|
||||
assert.equal(input.selectionStart, 0)
|
||||
})
|
||||
|
||||
test('prop "style"', () => {
|
||||
@@ -218,7 +231,7 @@ suite('components/TextInput', () => {
|
||||
|
||||
test('prop "value"', () => {
|
||||
const value = 'value'
|
||||
const result = utils.shallowRender(<TextInput value={value} />)
|
||||
assert.equal(result.props.value, value)
|
||||
const input = findShallowInput(utils.shallowRender(<TextInput value={value} />))
|
||||
assert.equal(input.props.value, value)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -3,27 +3,50 @@ import CoreComponent from '../CoreComponent'
|
||||
import React, { PropTypes } from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
import StyleSheet from '../../modules/StyleSheet'
|
||||
import Text from '../Text'
|
||||
import TextareaAutosize from 'react-textarea-autosize'
|
||||
import TextInputStylePropTypes from './TextInputStylePropTypes'
|
||||
import View from '../View'
|
||||
|
||||
const textInputStyleKeys = Object.keys(TextInputStylePropTypes)
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
initial: {
|
||||
...View.defaultProps.style,
|
||||
borderColor: 'black',
|
||||
borderWidth: 1
|
||||
},
|
||||
input: {
|
||||
appearance: 'none',
|
||||
backgroundColor: 'transparent',
|
||||
borderColor: 'black',
|
||||
borderWidth: '1px',
|
||||
borderWidth: 0,
|
||||
boxSizing: 'border-box',
|
||||
color: 'inherit',
|
||||
flexGrow: 1,
|
||||
font: 'inherit',
|
||||
padding: 0
|
||||
padding: 0,
|
||||
zIndex: 1
|
||||
},
|
||||
placeholder: {
|
||||
bottom: 0,
|
||||
color: 'darkgray',
|
||||
left: 0,
|
||||
overflow: 'hidden',
|
||||
position: 'absolute',
|
||||
right: 0,
|
||||
top: 0,
|
||||
whiteSpace: 'pre'
|
||||
}
|
||||
})
|
||||
|
||||
class TextInput extends React.Component {
|
||||
constructor(props, context) {
|
||||
super(props, context)
|
||||
this.state = { showPlaceholder: !props.value && !props.defaultValue }
|
||||
}
|
||||
|
||||
static propTypes = {
|
||||
accessibilityLabel: CoreComponent.propTypes.accessibilityLabel,
|
||||
...View.propTypes,
|
||||
autoComplete: PropTypes.bool,
|
||||
autoFocus: PropTypes.bool,
|
||||
clearTextOnFocus: PropTypes.bool,
|
||||
@@ -61,20 +84,26 @@ class TextInput extends React.Component {
|
||||
|
||||
_onBlur(e) {
|
||||
const { onBlur } = this.props
|
||||
const value = e.target.value
|
||||
this.setState({ showPlaceholder: value === '' })
|
||||
if (onBlur) onBlur(e)
|
||||
}
|
||||
|
||||
_onChange(e) {
|
||||
const { onChange, onChangeText } = this.props
|
||||
if (onChangeText) onChangeText(e.target.value)
|
||||
const value = e.target.value
|
||||
this.setState({ showPlaceholder: value === '' })
|
||||
if (onChangeText) onChangeText(value)
|
||||
if (onChange) onChange(e)
|
||||
}
|
||||
|
||||
_onFocus(e) {
|
||||
const { clearTextOnFocus, onFocus, selectTextOnFocus } = this.props
|
||||
const node = ReactDOM.findDOMNode(this)
|
||||
const node = ReactDOM.findDOMNode(this.refs.input)
|
||||
const value = e.target.value
|
||||
if (clearTextOnFocus) node.value = ''
|
||||
if (selectTextOnFocus) node.select()
|
||||
this.setState({ showPlaceholder: value === '' })
|
||||
if (onFocus) onFocus(e)
|
||||
}
|
||||
|
||||
@@ -92,7 +121,9 @@ class TextInput extends React.Component {
|
||||
|
||||
render() {
|
||||
const {
|
||||
/* eslint-disable react/prop-types */
|
||||
accessibilityLabel,
|
||||
/* eslint-enable react/prop-types */
|
||||
autoComplete,
|
||||
autoFocus,
|
||||
defaultValue,
|
||||
@@ -102,11 +133,9 @@ class TextInput extends React.Component {
|
||||
maxNumberOfLines,
|
||||
multiline,
|
||||
numberOfLines,
|
||||
onBlur,
|
||||
onChange,
|
||||
onChangeText,
|
||||
onSelectionChange,
|
||||
placeholder,
|
||||
placeholderTextColor,
|
||||
secureTextEntry,
|
||||
style,
|
||||
testID,
|
||||
@@ -126,6 +155,10 @@ class TextInput extends React.Component {
|
||||
case 'phone-pad':
|
||||
type = 'tel'
|
||||
break
|
||||
case 'search':
|
||||
case 'web-search':
|
||||
type = 'search'
|
||||
break
|
||||
case 'url':
|
||||
type = 'url'
|
||||
break
|
||||
@@ -136,23 +169,16 @@ class TextInput extends React.Component {
|
||||
}
|
||||
|
||||
const propsCommon = {
|
||||
accessibilityLabel,
|
||||
autoComplete: autoComplete && 'on',
|
||||
autoFocus,
|
||||
className: 'TextInput',
|
||||
defaultValue,
|
||||
maxLength,
|
||||
onBlur: onBlur && this._onBlur.bind(this),
|
||||
onChange: (onChange || onChangeText) && this._onChange.bind(this),
|
||||
onBlur: this._onBlur.bind(this),
|
||||
onChange: this._onChange.bind(this),
|
||||
onFocus: this._onFocus.bind(this),
|
||||
onSelect: onSelectionChange && this._onSelectionChange.bind(this),
|
||||
placeholder,
|
||||
readOnly: !editable,
|
||||
style: {
|
||||
...styles.initial,
|
||||
...resolvedStyle
|
||||
},
|
||||
testID,
|
||||
style: { ...styles.input, outline: style.outline },
|
||||
value
|
||||
}
|
||||
|
||||
@@ -172,7 +198,26 @@ class TextInput extends React.Component {
|
||||
const props = multiline ? propsMultiline : propsSingleline
|
||||
|
||||
return (
|
||||
<CoreComponent {...props} />
|
||||
<CoreComponent
|
||||
accessibilityLabel={accessibilityLabel}
|
||||
className='TextInput'
|
||||
style={{
|
||||
...styles.initial,
|
||||
...resolvedStyle
|
||||
}}
|
||||
testID={testID}
|
||||
>
|
||||
<View style={{ flexGrow: 1 }}>
|
||||
<CoreComponent {...props} ref='input' />
|
||||
{placeholder && this.state.showPlaceholder && <Text
|
||||
pointerEvents='none'
|
||||
style={{
|
||||
...styles.placeholder,
|
||||
...(placeholderTextColor && { color: placeholderTextColor })
|
||||
}}
|
||||
>{placeholder}</Text>}
|
||||
</View>
|
||||
</CoreComponent>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
16
src/index.js
16
src/index.js
@@ -11,11 +11,7 @@ import TextInput from './components/TextInput'
|
||||
import Touchable from './components/Touchable'
|
||||
import View from './components/View'
|
||||
|
||||
export default React
|
||||
|
||||
export {
|
||||
StyleSheet,
|
||||
|
||||
const ReactNative = {
|
||||
// components
|
||||
Image,
|
||||
ListView,
|
||||
@@ -23,5 +19,13 @@ export {
|
||||
Text,
|
||||
TextInput,
|
||||
Touchable,
|
||||
View
|
||||
View,
|
||||
|
||||
// apis
|
||||
StyleSheet,
|
||||
|
||||
// React
|
||||
...React
|
||||
}
|
||||
|
||||
module.exports = ReactNative
|
||||
|
||||
@@ -3,6 +3,10 @@ import { PropTypes } from 'react'
|
||||
const { number, string } = PropTypes
|
||||
const numberOrString = PropTypes.oneOfType([ number, string ])
|
||||
|
||||
/**
|
||||
* Any properties marked @private are used internally in resets or property
|
||||
* mappings.
|
||||
*/
|
||||
export default {
|
||||
alignContent: string,
|
||||
alignItems: string,
|
||||
@@ -38,20 +42,21 @@ export default {
|
||||
borderRightWidth: numberOrString,
|
||||
borderTopWidth: numberOrString,
|
||||
bottom: numberOrString,
|
||||
boxShadow: string,
|
||||
boxSizing: string,
|
||||
clear: string,
|
||||
color: string,
|
||||
cursor: string,
|
||||
direction: string,
|
||||
display: string,
|
||||
flex: string,
|
||||
direction: string, /* @private */
|
||||
flex: string, /* @private */
|
||||
flexBasis: string,
|
||||
flexDirection: string,
|
||||
flexGrow: numberOrString,
|
||||
flexShrink: numberOrString,
|
||||
flexWrap: string,
|
||||
float: string,
|
||||
font: string,
|
||||
font: string, /* @private */
|
||||
fontFamily: string,
|
||||
fontSize: numberOrString,
|
||||
fontStyle: string,
|
||||
@@ -75,6 +80,7 @@ export default {
|
||||
minWidth: numberOrString,
|
||||
opacity: numberOrString,
|
||||
order: numberOrString,
|
||||
outline: string,
|
||||
overflow: string,
|
||||
overflowX: string,
|
||||
overflowY: string,
|
||||
@@ -93,9 +99,11 @@ export default {
|
||||
textTransform: string,
|
||||
top: numberOrString,
|
||||
userSelect: string,
|
||||
verticalAlign: string,
|
||||
visibility: string,
|
||||
whiteSpace: string,
|
||||
width: numberOrString,
|
||||
wordWrap: string,
|
||||
writingDirection: string,
|
||||
zIndex: numberOrString
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ export default class Store {
|
||||
const getCssSelector = (property, value) => {
|
||||
let className = this.get(property, value)
|
||||
if (!obfuscate && className) {
|
||||
className = className.replace(/[:?.%\\$#]/g, '\\$&')
|
||||
className = className.replace(/[,":?.%\\$#]/g, '\\$&')
|
||||
}
|
||||
return className
|
||||
}
|
||||
|
||||
@@ -82,8 +82,9 @@ suite('modules/StyleSheet/Store', () => {
|
||||
|
||||
test('replaces space characters', () => {
|
||||
const store = new Store()
|
||||
|
||||
store.set('margin', '0 auto')
|
||||
assert.deepEqual(store.get('margin', '0 auto'), 'margin:0-auto')
|
||||
assert.equal(store.get('margin', '0 auto'), 'margin\:0-auto')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -91,17 +92,17 @@ suite('modules/StyleSheet/Store', () => {
|
||||
test('human-readable style sheet', () => {
|
||||
const store = new Store()
|
||||
store.set('alignItems', 'center')
|
||||
store.set('color', '#fff')
|
||||
store.set('fontFamily', '"Helvetica Neue", Arial, sans-serif')
|
||||
store.set('marginBottom', 0)
|
||||
store.set('margin', 1)
|
||||
store.set('margin', 2)
|
||||
store.set('margin', 3)
|
||||
store.set('width', '100%')
|
||||
|
||||
const expected = '/* 5 unique declarations */\n' +
|
||||
'.alignItems\\:center{align-items:center;}\n' +
|
||||
'.margin\\:1px{margin:1px;}\n' +
|
||||
'.margin\\:2px{margin:2px;}\n' +
|
||||
'.margin\\:3px{margin:3px;}\n' +
|
||||
'.marginBottom\\:0px{margin-bottom:0px;}'
|
||||
'.color\\:\\#fff{color:#fff;}\n' +
|
||||
'.fontFamily\\:\\"Helvetica-Neue\\"\\,-Arial\\,-sans-serif{font-family:"Helvetica Neue", Arial, sans-serif;}\n' +
|
||||
'.marginBottom\\:0px{margin-bottom:0px;}\n' +
|
||||
'.width\\:100\\%{width:100%;}'
|
||||
|
||||
assert.equal(store.toString(), expected)
|
||||
})
|
||||
|
||||
@@ -16,8 +16,9 @@ const fixture = {
|
||||
backgroundSize: 'contain'
|
||||
}
|
||||
},
|
||||
ignored: {
|
||||
pading: 0
|
||||
position: {
|
||||
left: { left: 0 },
|
||||
right: { right: 0 }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +28,9 @@ suite('modules/StyleSheet/getStyleObjects', () => {
|
||||
assert.deepEqual(actual, [
|
||||
{ margin: 0, padding: 0 },
|
||||
{ backgroundSize: 'auto' },
|
||||
{ backgroundSize: 'contain' }
|
||||
{ backgroundSize: 'contain' },
|
||||
{ left: 0 },
|
||||
{ right: 0 }
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
@@ -3,14 +3,27 @@
|
||||
import assert from 'assert'
|
||||
import isStyleObject from '../isStyleObject'
|
||||
|
||||
const style = { margin: 0 }
|
||||
const notStyle = { root: style }
|
||||
const styles = {
|
||||
root: {
|
||||
margin: 0
|
||||
},
|
||||
align: {
|
||||
left: {
|
||||
textAlign: 'left'
|
||||
},
|
||||
right: {
|
||||
textAlign: 'right'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
suite('modules/StyleSheet/isStyleObject', () => {
|
||||
test('returns "true" for style objects', () => {
|
||||
assert.ok(isStyleObject(style) === true)
|
||||
})
|
||||
test('returns "false" for non-style objects', () => {
|
||||
assert.ok(isStyleObject(notStyle) === false)
|
||||
assert.ok(isStyleObject(styles) === false)
|
||||
assert.ok(isStyleObject(styles.align) === false)
|
||||
})
|
||||
test('returns "true" for style objects', () => {
|
||||
assert.ok(isStyleObject(styles.root) === true)
|
||||
assert.ok(isStyleObject(styles.align.left) === true)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -8,7 +8,8 @@ const styleShortHands = {
|
||||
marginVertical: [ 'marginTop', 'marginBottom' ],
|
||||
padding: [ 'paddingTop', 'paddingRight', 'paddingBottom', 'paddingLeft' ],
|
||||
paddingHorizontal: [ 'paddingRight', 'paddingLeft' ],
|
||||
paddingVertical: [ 'paddingTop', 'paddingBottom' ]
|
||||
paddingVertical: [ 'paddingTop', 'paddingBottom' ],
|
||||
writingDirection: [ 'direction' ]
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import { pickProps } from '../filterObjectProps'
|
||||
import StylePropTypes from '../StylePropTypes'
|
||||
import isObject from './isObject'
|
||||
|
||||
const isStyleObject = (obj) => {
|
||||
const declarations = pickProps(obj, Object.keys(StylePropTypes))
|
||||
return Object.keys(declarations).length > 0
|
||||
const values = Object.keys(obj).map((key) => obj[key])
|
||||
for (let i = 0; i < values.length; i += 1) {
|
||||
if (isObject(values[i])) { return false }
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
export default isStyleObject
|
||||
|
||||
@@ -6,7 +6,8 @@ export const resetCSS =
|
||||
html {font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}
|
||||
body {margin:0}
|
||||
button::-moz-focus-inner, input::-moz-focus-inner {border:0;padding:0}
|
||||
input[type="search"]::-webkit-search-cancel-button, input[type="search"]::-webkit-search-decoration {-webkit-appearance:none}`
|
||||
input[type="search"]::-webkit-search-cancel-button, input[type="search"]::-webkit-search-decoration {-webkit-appearance:none}
|
||||
ol,ul,li {list-style:none}`
|
||||
|
||||
/**
|
||||
* Custom pointer event styles
|
||||
|
||||
Reference in New Issue
Block a user