mirror of
https://github.com/zhigang1992/react-native-web.git
synced 2026-01-12 22:51:09 +08:00
[change] remove 'component' prop; accessibility docs
- infer underlying HTML tag from 'accessibilityRole' - move accessibility props to 'CoreComponent' - remove the 'component' prop from exported Components Fix gh-23
This commit is contained in:
16
README.md
16
README.md
@@ -6,7 +6,7 @@
|
||||
[React Native][react-native-url] components and APIs for the Web.
|
||||
~17.7 KB minified and gzipped.
|
||||
|
||||
* [Slack: reactiflux channel #react-native-web][slack-url]
|
||||
* [Slack: #react-native-web on reactiflux][slack-url]
|
||||
* [Gitter: react-native-web][gitter-url]
|
||||
|
||||
## Table of contents
|
||||
@@ -16,6 +16,7 @@
|
||||
* [APIs](#apis)
|
||||
* [Components](#components)
|
||||
* [Styling](#styling)
|
||||
* [Accessibility](#accessibility)
|
||||
* [Contributing](#contributing)
|
||||
* [Thanks](#thanks)
|
||||
* [License](#license)
|
||||
@@ -171,6 +172,19 @@ flexbox][flexbox-guide-url].
|
||||
Styling components can be achieved with inline styles or the use of
|
||||
[StyleSheet](docs/apis/StyleSheet.md).
|
||||
|
||||
## Accessibility
|
||||
|
||||
Major accessibility features are available through the following props:
|
||||
`accessible`, `accessibilityLabel`, `accessibilityLiveRegion`, and
|
||||
`accessibilityRole`. The `accessibilityRole` prop is used to determine the
|
||||
rendered DOM element. For example:
|
||||
|
||||
* `<View accessibilityRole='banner' />` => `<header role='banner' />`.
|
||||
* `<View accessibilityRole='button' />` => `<button type='button' role='button' />`.
|
||||
* `<Text accessibilityRole='link' href='/' />` => `<a role='link' href='/' />`.
|
||||
|
||||
See the component documentation for more details.
|
||||
|
||||
## Contributing
|
||||
|
||||
Please read the [contribution guidelines][contributing-url]. Contributions are
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
var webpack = require('webpack')
|
||||
|
||||
var DedupePlugin = webpack.optimize.DedupePlugin
|
||||
var EnvironmentPlugin = webpack.EnvironmentPlugin
|
||||
var OccurenceOrderPlugin = webpack.optimize.OccurenceOrderPlugin
|
||||
var UglifyJsPlugin = webpack.optimize.UglifyJsPlugin
|
||||
|
||||
var plugins = [
|
||||
new DedupePlugin(),
|
||||
new EnvironmentPlugin('NODE_ENV'),
|
||||
new OccurenceOrderPlugin()
|
||||
]
|
||||
|
||||
|
||||
@@ -23,6 +23,17 @@ NOTE: `Text` will transfer all other props to the rendered HTML element.
|
||||
Defines the text available to assistive technologies upon interaction with the
|
||||
element. (This is implemented using `aria-label`.)
|
||||
|
||||
(web) **accessibilityRole**: oneOf(roles)
|
||||
|
||||
Allows assistive technologies to present and support interaction with the view
|
||||
in a manner that is consistent with user expectations for similar views of that
|
||||
type. For example, marking a touchable view with an `accessibilityRole` of
|
||||
`button`. (This is implemented using [ARIA roles](http://www.w3.org/TR/wai-aria/roles#role_definitions)).
|
||||
|
||||
Note: Avoid changing `accessibilityRole` values over time or after user
|
||||
actions. Generally, accessibility APIs do not provide a means of notifying
|
||||
assistive technologies of a `role` value change.
|
||||
|
||||
(web) **accessible**: bool = true
|
||||
|
||||
When `false`, the text is hidden from assistive technologies. (This is
|
||||
@@ -32,10 +43,6 @@ implemented using `aria-hidden`.)
|
||||
|
||||
Child content.
|
||||
|
||||
(web) **component**: function | string = 'span'
|
||||
|
||||
Backing component.
|
||||
|
||||
**numberOfLines**: number
|
||||
|
||||
Truncates the text with an ellipsis after this many lines. Currently only supports `1`.
|
||||
@@ -70,7 +77,7 @@ Used to locate this view in end-to-end tests.
|
||||
## Examples
|
||||
|
||||
```js
|
||||
import React, { Text } from 'react-native-web'
|
||||
import React, { StyleSheet, Text } from 'react-native-web'
|
||||
|
||||
const { Component, PropTypes } = React
|
||||
|
||||
@@ -104,7 +111,7 @@ class PrettyText extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
const localStyle = {
|
||||
const localStyle = StyleSheet.create({
|
||||
color: {
|
||||
white: { color: 'white' },
|
||||
gray: { color: 'gray' },
|
||||
@@ -120,5 +127,5 @@ const localStyle = {
|
||||
normal: { fontWeight: '400' },
|
||||
bold: { fontWeight: '700' }
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
@@ -54,10 +54,6 @@ assistive technologies of a `role` value change.
|
||||
When `false`, the view is hidden from assistive technologies. (This is
|
||||
implemented using `aria-hidden`.)
|
||||
|
||||
(web) **component**: function | string = 'div'
|
||||
|
||||
The React Component for this view.
|
||||
|
||||
**onLayout**: function
|
||||
|
||||
(TODO)
|
||||
@@ -159,7 +155,7 @@ Used to locate this view in end-to-end tests.
|
||||
## Examples
|
||||
|
||||
```js
|
||||
import React, { View } from 'react-native-web'
|
||||
import React, { StyleSheet, View } from 'react-native-web'
|
||||
|
||||
const { Component, PropTypes } = React
|
||||
|
||||
@@ -177,14 +173,14 @@ class Example extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
const styles = {
|
||||
const styles = StyleSheet.create({
|
||||
row: {
|
||||
flexDirection: 'row'
|
||||
},
|
||||
cell: {
|
||||
flexGrow: 1
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
export default Example
|
||||
```
|
||||
|
||||
62
src/components/CoreComponent/__tests__/index-test.js
Normal file
62
src/components/CoreComponent/__tests__/index-test.js
Normal file
@@ -0,0 +1,62 @@
|
||||
/* eslint-env mocha */
|
||||
|
||||
import * as utils from '../../../modules/specHelpers'
|
||||
import assert from 'assert'
|
||||
import React from 'react'
|
||||
|
||||
import CoreComponent from '../'
|
||||
|
||||
suite('components/CoreComponent', () => {
|
||||
test('prop "accessibilityLabel"', () => {
|
||||
const accessibilityLabel = 'accessibilityLabel'
|
||||
const dom = utils.renderToDOM(<CoreComponent accessibilityLabel={accessibilityLabel} />)
|
||||
assert.equal(dom.getAttribute('aria-label'), accessibilityLabel)
|
||||
})
|
||||
|
||||
test('prop "accessibilityLiveRegion"', () => {
|
||||
const accessibilityLiveRegion = 'polite'
|
||||
const dom = utils.renderToDOM(<CoreComponent accessibilityLiveRegion={accessibilityLiveRegion} />)
|
||||
assert.equal(dom.getAttribute('aria-live'), accessibilityLiveRegion)
|
||||
})
|
||||
|
||||
test('prop "accessibilityRole"', () => {
|
||||
const accessibilityRole = 'banner'
|
||||
let dom = utils.renderToDOM(<CoreComponent accessibilityRole={accessibilityRole} />)
|
||||
assert.equal(dom.getAttribute('role'), accessibilityRole)
|
||||
assert.equal((dom.tagName).toLowerCase(), 'header')
|
||||
|
||||
const button = 'button'
|
||||
dom = utils.renderToDOM(<CoreComponent accessibilityRole={button} />)
|
||||
assert.equal(dom.getAttribute('type'), button)
|
||||
assert.equal((dom.tagName).toLowerCase(), button)
|
||||
})
|
||||
|
||||
test('prop "accessible"', () => {
|
||||
// accessible (implicit)
|
||||
let dom = utils.renderToDOM(<CoreComponent />)
|
||||
assert.equal(dom.getAttribute('aria-hidden'), null)
|
||||
// accessible (explicit)
|
||||
dom = utils.renderToDOM(<CoreComponent accessible />)
|
||||
assert.equal(dom.getAttribute('aria-hidden'), null)
|
||||
// not accessible
|
||||
dom = utils.renderToDOM(<CoreComponent accessible={false} />)
|
||||
assert.equal(dom.getAttribute('aria-hidden'), 'true')
|
||||
})
|
||||
|
||||
test('prop "component"', () => {
|
||||
const component = 'main'
|
||||
const dom = utils.renderToDOM(<CoreComponent component={component} />)
|
||||
const tagName = (dom.tagName).toLowerCase()
|
||||
assert.equal(tagName, component)
|
||||
})
|
||||
|
||||
test('prop "testID"', () => {
|
||||
// no testID
|
||||
let dom = utils.renderToDOM(<CoreComponent />)
|
||||
assert.equal(dom.getAttribute('data-testid'), null)
|
||||
// with testID
|
||||
const testID = 'Example.testID'
|
||||
dom = utils.renderToDOM(<CoreComponent testID={testID} />)
|
||||
assert.equal(dom.getAttribute('data-testid'), testID)
|
||||
})
|
||||
})
|
||||
@@ -2,18 +2,38 @@ import React, { PropTypes } from 'react'
|
||||
import StylePropTypes from '../../modules/StylePropTypes'
|
||||
import StyleSheet from '../../modules/StyleSheet'
|
||||
|
||||
const roleComponents = {
|
||||
article: 'article',
|
||||
banner: 'header',
|
||||
button: 'button',
|
||||
complementary: 'aside',
|
||||
contentinfo: 'footer',
|
||||
form: 'form',
|
||||
heading: 'h1',
|
||||
link: 'a',
|
||||
main: 'main',
|
||||
navigation: 'nav',
|
||||
region: 'section'
|
||||
}
|
||||
|
||||
class CoreComponent extends React.Component {
|
||||
static propTypes = {
|
||||
accessibilityLabel: PropTypes.string,
|
||||
accessibilityLiveRegion: PropTypes.oneOf(['assertive', 'off', 'polite']),
|
||||
accessibilityRole: PropTypes.string,
|
||||
accessible: PropTypes.bool,
|
||||
className: PropTypes.string,
|
||||
component: PropTypes.oneOfType([
|
||||
PropTypes.func,
|
||||
PropTypes.string
|
||||
]),
|
||||
style: PropTypes.object,
|
||||
testID: PropTypes.string
|
||||
testID: PropTypes.string,
|
||||
type: PropTypes.string
|
||||
}
|
||||
|
||||
static defaultProps = {
|
||||
accessible: true,
|
||||
component: 'div'
|
||||
}
|
||||
|
||||
@@ -21,16 +41,28 @@ class CoreComponent extends React.Component {
|
||||
|
||||
render() {
|
||||
const {
|
||||
component: Component,
|
||||
accessibilityLabel,
|
||||
accessibilityLiveRegion,
|
||||
accessibilityRole,
|
||||
accessible,
|
||||
component,
|
||||
testID,
|
||||
type,
|
||||
...other
|
||||
} = this.props
|
||||
|
||||
const Component = roleComponents[accessibilityRole] || component
|
||||
|
||||
return (
|
||||
<Component
|
||||
{...other}
|
||||
{...StyleSheet.resolve(other)}
|
||||
aria-hidden={accessible ? null : true}
|
||||
aria-label={accessibilityLabel}
|
||||
aria-live={accessibilityLiveRegion}
|
||||
data-testid={testID}
|
||||
role={accessibilityRole}
|
||||
type={accessibilityRole === 'button' ? 'button' : type}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* eslint-env mocha */
|
||||
|
||||
import { assertProps, render, renderToDOM } from '../../../modules/specHelpers'
|
||||
import * as utils from '../../../modules/specHelpers'
|
||||
import assert from 'assert'
|
||||
import React from 'react'
|
||||
|
||||
@@ -8,30 +8,34 @@ import Image from '../'
|
||||
|
||||
suite('components/Image', () => {
|
||||
test('default accessibility', () => {
|
||||
const dom = renderToDOM(<Image />)
|
||||
const dom = utils.renderToDOM(<Image />)
|
||||
assert.equal(dom.getAttribute('role'), 'img')
|
||||
})
|
||||
|
||||
test('prop "accessibilityLabel"', () => {
|
||||
assertProps.accessibilityLabel(Image)
|
||||
const accessibilityLabel = 'accessibilityLabel'
|
||||
const result = utils.shallowRender(<Image accessibilityLabel={accessibilityLabel} />)
|
||||
assert.equal(result.props.accessibilityLabel, accessibilityLabel)
|
||||
})
|
||||
|
||||
test('prop "accessible"', () => {
|
||||
assertProps.accessible(Image)
|
||||
const accessible = false
|
||||
const result = utils.shallowRender(<Image accessible={accessible} />)
|
||||
assert.equal(result.props.accessible, accessible)
|
||||
})
|
||||
|
||||
test('prop "children"')
|
||||
|
||||
test('prop "defaultSource"', () => {
|
||||
const defaultSource = { uri: 'https://google.com/favicon.ico' }
|
||||
const dom = renderToDOM(<Image defaultSource={defaultSource} />)
|
||||
const dom = utils.renderToDOM(<Image defaultSource={defaultSource} />)
|
||||
const backgroundImage = dom.style.backgroundImage
|
||||
assert(backgroundImage.indexOf(defaultSource.uri) > -1)
|
||||
})
|
||||
|
||||
test('prop "onError"', function (done) {
|
||||
this.timeout(5000)
|
||||
render(<Image
|
||||
utils.render(<Image
|
||||
onError={onError}
|
||||
source={{ uri: 'https://google.com/favicon.icox' }}
|
||||
/>)
|
||||
@@ -43,7 +47,7 @@ suite('components/Image', () => {
|
||||
|
||||
test('prop "onLoad"', function (done) {
|
||||
this.timeout(5000)
|
||||
render(<Image
|
||||
utils.render(<Image
|
||||
onLoad={onLoad}
|
||||
source={{ uri: 'https://google.com/favicon.ico' }}
|
||||
/>)
|
||||
@@ -62,10 +66,12 @@ suite('components/Image', () => {
|
||||
test('prop "source"')
|
||||
|
||||
test('prop "style"', () => {
|
||||
assertProps.style(Image)
|
||||
utils.assertProps.style(Image)
|
||||
})
|
||||
|
||||
test('prop "testID"', () => {
|
||||
assertProps.testID(Image)
|
||||
const testID = 'testID'
|
||||
const result = utils.shallowRender(<Image testID={testID} />)
|
||||
assert.equal(result.props.testID, testID)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -64,8 +64,8 @@ class Image extends React.Component {
|
||||
}
|
||||
|
||||
static propTypes = {
|
||||
accessibilityLabel: PropTypes.string,
|
||||
accessible: PropTypes.bool,
|
||||
accessibilityLabel: CoreComponent.propTypes.accessibilityLabel,
|
||||
accessible: CoreComponent.propTypes.accessible,
|
||||
children: PropTypes.any,
|
||||
defaultSource: PropTypes.object,
|
||||
onError: PropTypes.func,
|
||||
@@ -101,8 +101,8 @@ class Image extends React.Component {
|
||||
|
||||
_destroyImageLoader() {
|
||||
if (this.image) {
|
||||
this.image.onload = null
|
||||
this.image.onerror = null
|
||||
this.image.onload = null
|
||||
this.image = null
|
||||
}
|
||||
}
|
||||
@@ -123,8 +123,8 @@ class Image extends React.Component {
|
||||
|
||||
this._destroyImageLoader()
|
||||
this.setState({ status: STATUS_LOADED })
|
||||
this._onLoadEnd()
|
||||
if (onLoad) onLoad(event)
|
||||
this._onLoadEnd()
|
||||
}
|
||||
|
||||
_onLoadEnd() {
|
||||
@@ -193,7 +193,6 @@ class Image extends React.Component {
|
||||
accessibilityLabel={accessibilityLabel}
|
||||
accessibilityRole='img'
|
||||
accessible={accessible}
|
||||
component='div'
|
||||
style={{
|
||||
...styles.initial,
|
||||
...resolvedStyle,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* eslint-env mocha */
|
||||
|
||||
import { assertProps, renderToDOM, shallowRender } from '../../../modules/specHelpers'
|
||||
import * as utils from '../../../modules/specHelpers'
|
||||
import assert from 'assert'
|
||||
import React from 'react'
|
||||
import ReactTestUtils from 'react-addons-test-utils'
|
||||
@@ -9,27 +9,33 @@ import Text from '../'
|
||||
|
||||
suite('components/Text', () => {
|
||||
test('prop "accessibilityLabel"', () => {
|
||||
assertProps.accessibilityLabel(Text)
|
||||
const accessibilityLabel = 'accessibilityLabel'
|
||||
const result = utils.shallowRender(<Text accessibilityLabel={accessibilityLabel} />)
|
||||
assert.equal(result.props.accessibilityLabel, accessibilityLabel)
|
||||
})
|
||||
|
||||
test('prop "accessibilityRole"', () => {
|
||||
const accessibilityRole = 'accessibilityRole'
|
||||
const result = utils.shallowRender(<Text accessibilityRole={accessibilityRole} />)
|
||||
assert.equal(result.props.accessibilityRole, accessibilityRole)
|
||||
})
|
||||
|
||||
test('prop "accessible"', () => {
|
||||
assertProps.accessible(Text)
|
||||
const accessible = false
|
||||
const result = utils.shallowRender(<Text accessible={accessible} />)
|
||||
assert.equal(result.props.accessible, accessible)
|
||||
})
|
||||
|
||||
test('prop "children"', () => {
|
||||
const children = 'children'
|
||||
const result = shallowRender(<Text>{children}</Text>)
|
||||
const result = utils.shallowRender(<Text>{children}</Text>)
|
||||
assert.equal(result.props.children, children)
|
||||
})
|
||||
|
||||
test('prop "component"', () => {
|
||||
assertProps.component(Text, 'span')
|
||||
})
|
||||
|
||||
test('prop "numberOfLines"')
|
||||
|
||||
test('prop "onPress"', (done) => {
|
||||
const dom = renderToDOM(<Text onPress={onPress} />)
|
||||
const dom = utils.renderToDOM(<Text onPress={onPress} />)
|
||||
ReactTestUtils.Simulate.click(dom)
|
||||
function onPress(e) {
|
||||
assert.ok(e.nativeEvent)
|
||||
@@ -38,10 +44,12 @@ suite('components/Text', () => {
|
||||
})
|
||||
|
||||
test('prop "style"', () => {
|
||||
assertProps.style(Text)
|
||||
utils.assertProps.style(Text)
|
||||
})
|
||||
|
||||
test('prop "testID"', () => {
|
||||
assertProps.testID(Text)
|
||||
const testID = 'testID'
|
||||
const result = utils.shallowRender(<Text testID={testID} />)
|
||||
assert.equal(result.props.testID, testID)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -26,10 +26,10 @@ const styles = StyleSheet.create({
|
||||
class Text extends React.Component {
|
||||
static propTypes = {
|
||||
_className: PropTypes.string, // escape-hatch for code migrations
|
||||
accessibilityLabel: PropTypes.string,
|
||||
accessible: PropTypes.bool,
|
||||
accessibilityLabel: CoreComponent.propTypes.accessibilityLabel,
|
||||
accessibilityRole: CoreComponent.propTypes.accessibilityRole,
|
||||
accessible: CoreComponent.propTypes.accessible,
|
||||
children: PropTypes.any,
|
||||
component: CoreComponent.propTypes.component,
|
||||
numberOfLines: PropTypes.number,
|
||||
onPress: PropTypes.func,
|
||||
style: PropTypes.shape(TextStylePropTypes),
|
||||
@@ -41,7 +41,6 @@ class Text extends React.Component {
|
||||
static defaultProps = {
|
||||
_className: '',
|
||||
accessible: true,
|
||||
component: 'span',
|
||||
style: styles.initial
|
||||
}
|
||||
|
||||
@@ -52,14 +51,9 @@ class Text extends React.Component {
|
||||
render() {
|
||||
const {
|
||||
_className,
|
||||
accessibilityLabel,
|
||||
accessible,
|
||||
children,
|
||||
component,
|
||||
numberOfLines,
|
||||
onPress,
|
||||
style,
|
||||
testID,
|
||||
...other
|
||||
} = this.props
|
||||
|
||||
@@ -69,18 +63,14 @@ class Text extends React.Component {
|
||||
return (
|
||||
<CoreComponent
|
||||
{...other}
|
||||
aria-hidden={accessible ? null : true}
|
||||
aria-label={accessibilityLabel}
|
||||
children={children}
|
||||
className={className}
|
||||
component={component}
|
||||
component='span'
|
||||
onClick={this._onPress.bind(this)}
|
||||
style={{
|
||||
...styles.initial,
|
||||
...resolvedStyle,
|
||||
...(numberOfLines === 1 && styles.singleLineStyle)
|
||||
}}
|
||||
testID={testID}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -9,7 +9,9 @@ import TextInput from '../'
|
||||
|
||||
suite('components/TextInput', () => {
|
||||
test('prop "accessibilityLabel"', () => {
|
||||
utils.assertProps.accessibilityLabel(TextInput)
|
||||
const accessibilityLabel = 'accessibilityLabel'
|
||||
const result = utils.shallowRender(<TextInput accessibilityLabel={accessibilityLabel} />)
|
||||
assert.equal(result.props.accessibilityLabel, accessibilityLabel)
|
||||
})
|
||||
|
||||
test('prop "autoComplete"', () => {
|
||||
@@ -208,7 +210,9 @@ suite('components/TextInput', () => {
|
||||
})
|
||||
|
||||
test('prop "testID"', () => {
|
||||
utils.assertProps.testID(TextInput)
|
||||
const testID = 'testID'
|
||||
const result = utils.shallowRender(<TextInput testID={testID} />)
|
||||
assert.equal(result.props.testID, testID)
|
||||
})
|
||||
|
||||
test('prop "value"', () => {
|
||||
|
||||
@@ -23,7 +23,7 @@ const styles = StyleSheet.create({
|
||||
|
||||
class TextInput extends React.Component {
|
||||
static propTypes = {
|
||||
accessibilityLabel: PropTypes.string,
|
||||
accessibilityLabel: CoreComponent.propTypes.accessibilityLabel,
|
||||
autoComplete: PropTypes.bool,
|
||||
autoFocus: PropTypes.bool,
|
||||
clearTextOnFocus: PropTypes.bool,
|
||||
@@ -136,7 +136,7 @@ class TextInput extends React.Component {
|
||||
}
|
||||
|
||||
const propsCommon = {
|
||||
'aria-label': accessibilityLabel,
|
||||
accessibilityLabel,
|
||||
autoComplete: autoComplete && 'on',
|
||||
autoFocus,
|
||||
className: 'TextInput',
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* eslint-env mocha */
|
||||
|
||||
import { assertProps, shallowRender } from '../../../modules/specHelpers'
|
||||
import * as utils from '../../../modules/specHelpers'
|
||||
import assert from 'assert'
|
||||
import React from 'react'
|
||||
|
||||
@@ -11,19 +11,25 @@ const requiredProps = { children }
|
||||
|
||||
suite('components/Touchable', () => {
|
||||
test('prop "accessibilityLabel"', () => {
|
||||
assertProps.accessibilityLabel(Touchable, requiredProps)
|
||||
const accessibilityLabel = 'accessibilityLabel'
|
||||
const result = utils.shallowRender(<Touchable {...requiredProps} accessibilityLabel={accessibilityLabel} />)
|
||||
assert.equal(result.props.accessibilityLabel, accessibilityLabel)
|
||||
})
|
||||
|
||||
test('prop "accessibilityRole"', () => {
|
||||
assertProps.accessibilityRole(Touchable, requiredProps)
|
||||
const accessibilityRole = 'accessibilityRole'
|
||||
const result = utils.shallowRender(<Touchable {...requiredProps} accessibilityRole={accessibilityRole} />)
|
||||
assert.equal(result.props.accessibilityRole, accessibilityRole)
|
||||
})
|
||||
|
||||
test('prop "accessible"', () => {
|
||||
assertProps.accessible(Touchable, requiredProps)
|
||||
const accessible = false
|
||||
const result = utils.shallowRender(<Touchable {...requiredProps} accessible={accessible} />)
|
||||
assert.equal(result.props.accessible, accessible)
|
||||
})
|
||||
|
||||
test('prop "children"', () => {
|
||||
const result = shallowRender(<Touchable {...requiredProps} />)
|
||||
const result = utils.shallowRender(<Touchable {...requiredProps} />)
|
||||
assert.deepEqual(result.props.children, children)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -25,9 +25,9 @@ class Touchable extends React.Component {
|
||||
}
|
||||
|
||||
static propTypes = {
|
||||
accessibilityLabel: PropTypes.string,
|
||||
accessibilityRole: PropTypes.string,
|
||||
accessible: PropTypes.bool,
|
||||
accessibilityLabel: View.propTypes.accessibilityLabel,
|
||||
accessibilityRole: View.propTypes.accessibilityRole,
|
||||
accessible: View.propTypes.accessible,
|
||||
activeOpacity: PropTypes.number,
|
||||
activeUnderlayColor: PropTypes.string,
|
||||
children: PropTypes.element,
|
||||
@@ -45,7 +45,6 @@ class Touchable extends React.Component {
|
||||
accessibilityRole: 'button',
|
||||
activeOpacity: 1,
|
||||
activeUnderlayColor: 'transparent',
|
||||
component: 'div',
|
||||
delayLongPress: 1000,
|
||||
delayPressIn: 0,
|
||||
delayPressOut: 0,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* eslint-env mocha */
|
||||
|
||||
import { assertProps, shallowRender } from '../../../modules/specHelpers'
|
||||
import * as utils from '../../../modules/specHelpers'
|
||||
import assert from 'assert'
|
||||
import React from 'react'
|
||||
|
||||
@@ -8,41 +8,47 @@ import View from '../'
|
||||
|
||||
suite('components/View', () => {
|
||||
test('prop "accessibilityLabel"', () => {
|
||||
assertProps.accessibilityLabel(View)
|
||||
const accessibilityLabel = 'accessibilityLabel'
|
||||
const result = utils.shallowRender(<View accessibilityLabel={accessibilityLabel} />)
|
||||
assert.equal(result.props.accessibilityLabel, accessibilityLabel)
|
||||
})
|
||||
|
||||
test('prop "accessibilityLiveRegion"', () => {
|
||||
assertProps.accessibilityLiveRegion(View)
|
||||
const accessibilityLiveRegion = 'polite'
|
||||
const result = utils.shallowRender(<View accessibilityLiveRegion={accessibilityLiveRegion} />)
|
||||
assert.equal(result.props.accessibilityLiveRegion, accessibilityLiveRegion)
|
||||
})
|
||||
|
||||
test('prop "accessibilityRole"', () => {
|
||||
assertProps.accessibilityRole(View)
|
||||
const accessibilityRole = 'accessibilityRole'
|
||||
const result = utils.shallowRender(<View accessibilityRole={accessibilityRole} />)
|
||||
assert.equal(result.props.accessibilityRole, accessibilityRole)
|
||||
})
|
||||
|
||||
test('prop "accessible"', () => {
|
||||
assertProps.accessible(View)
|
||||
const accessible = false
|
||||
const result = utils.shallowRender(<View accessible={accessible} />)
|
||||
assert.equal(result.props.accessible, accessible)
|
||||
})
|
||||
|
||||
test('prop "children"', () => {
|
||||
const children = 'children'
|
||||
const result = shallowRender(<View>{children}</View>)
|
||||
const result = utils.shallowRender(<View>{children}</View>)
|
||||
assert.equal(result.props.children, children)
|
||||
})
|
||||
|
||||
test('prop "component"', () => {
|
||||
assertProps.component(View)
|
||||
})
|
||||
|
||||
test('prop "pointerEvents"', () => {
|
||||
const result = shallowRender(<View pointerEvents='box-only' />)
|
||||
const result = utils.shallowRender(<View pointerEvents='box-only' />)
|
||||
assert.equal(result.props.style.pointerEvents, 'box-only')
|
||||
})
|
||||
|
||||
test('prop "style"', () => {
|
||||
assertProps.style(View)
|
||||
utils.assertProps.style(View)
|
||||
})
|
||||
|
||||
test('prop "testID"', () => {
|
||||
assertProps.testID(View)
|
||||
const testID = 'testID'
|
||||
const result = utils.shallowRender(<View testID={testID} />)
|
||||
assert.equal(result.props.testID, testID)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -32,12 +32,11 @@ const styles = StyleSheet.create({
|
||||
class View extends React.Component {
|
||||
static propTypes = {
|
||||
_className: PropTypes.string, // escape-hatch for code migrations
|
||||
accessibilityLabel: PropTypes.string,
|
||||
accessibilityLiveRegion: PropTypes.oneOf(['assertive', 'off', 'polite']),
|
||||
accessibilityRole: PropTypes.string,
|
||||
accessible: PropTypes.bool,
|
||||
accessibilityLabel: CoreComponent.propTypes.accessibilityLabel,
|
||||
accessibilityLiveRegion: CoreComponent.propTypes.accessibilityLiveRegion,
|
||||
accessibilityRole: CoreComponent.propTypes.accessibilityRole,
|
||||
accessible: CoreComponent.propTypes.accessible,
|
||||
children: PropTypes.any,
|
||||
component: CoreComponent.propTypes.component,
|
||||
pointerEvents: PropTypes.oneOf(['auto', 'box-none', 'box-only', 'none']),
|
||||
style: PropTypes.shape(ViewStylePropTypes),
|
||||
testID: CoreComponent.propTypes.testID
|
||||
@@ -48,20 +47,14 @@ class View extends React.Component {
|
||||
static defaultProps = {
|
||||
_className: '',
|
||||
accessible: true,
|
||||
component: 'div',
|
||||
style: styles.initial
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
_className,
|
||||
accessibilityLabel,
|
||||
accessibilityLiveRegion,
|
||||
accessibilityRole,
|
||||
accessible,
|
||||
pointerEvents,
|
||||
style,
|
||||
testID,
|
||||
...other
|
||||
} = this.props
|
||||
|
||||
@@ -72,17 +65,12 @@ class View extends React.Component {
|
||||
return (
|
||||
<CoreComponent
|
||||
{...other}
|
||||
aria-hidden={accessible ? null : true}
|
||||
aria-label={accessibilityLabel}
|
||||
aria-live={accessibilityLiveRegion}
|
||||
className={className}
|
||||
role={accessibilityRole}
|
||||
style={{
|
||||
...styles.initial,
|
||||
...resolvedStyle,
|
||||
...pointerEventsStyle
|
||||
}}
|
||||
testID={testID}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import React, { Image, StyleSheet, Text, TextInput, Touchable, View } from '.'
|
||||
import ReactDOM from 'react-dom'
|
||||
|
||||
const Heading = ({ children, level = '1', size = 'normal' }) => (
|
||||
const Heading = ({ children, size = 'normal' }) => (
|
||||
<Text
|
||||
accessibilityRole='heading'
|
||||
children={children}
|
||||
component={`h${level}`}
|
||||
style={headingStyles.size[size]}
|
||||
/>
|
||||
)
|
||||
@@ -36,15 +36,15 @@ class Example extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<View accessibilityRole='main' style={styles.root}>
|
||||
<Heading level='1' size='xlarge'>React Native Web</Heading>
|
||||
<Heading size='xlarge'>React Native Web</Heading>
|
||||
<Text>React Native Web takes the core components from <Text
|
||||
component='a' href='https://facebook.github.io/react-native/'>React
|
||||
accessibilityRole='link' href='https://facebook.github.io/react-native/'>React
|
||||
Native</Text> and brings them to the web. These components provide
|
||||
simple building blocks – touch handling, flexbox layout,
|
||||
scroll views – from which more complex components and apps can be
|
||||
constructed.</Text>
|
||||
|
||||
<Heading level='2' size='large'>Image</Heading>
|
||||
<Heading size='large'>Image</Heading>
|
||||
<Image
|
||||
accessibilityLabel='accessible image'
|
||||
children={<Text>Inner content</Text>}
|
||||
@@ -67,7 +67,7 @@ class Example extends React.Component {
|
||||
testID='Example.image'
|
||||
/>
|
||||
|
||||
<Heading level='2' size='large'>Text</Heading>
|
||||
<Heading size='large'>Text</Heading>
|
||||
<Text
|
||||
onPress={(e) => { console.log('Text.onPress', e) }}
|
||||
testID={'Example.text'}
|
||||
@@ -92,7 +92,7 @@ class Example extends React.Component {
|
||||
hendrerit consequat.
|
||||
</Text>
|
||||
|
||||
<Heading level='2' size='large'>TextInput</Heading>
|
||||
<Heading size='large'>TextInput</Heading>
|
||||
<TextInput
|
||||
keyboardType='default'
|
||||
onBlur={(e) => { console.log('TextInput.onBlur', e) }}
|
||||
@@ -114,7 +114,7 @@ class Example extends React.Component {
|
||||
numberOfLines={5}
|
||||
/>
|
||||
|
||||
<Heading level='2' size='large'>Touchable</Heading>
|
||||
<Heading size='large'>Touchable</Heading>
|
||||
<Touchable
|
||||
accessibilityLabel={'Touchable element'}
|
||||
activeHighlight='lightblue'
|
||||
@@ -129,8 +129,8 @@ class Example extends React.Component {
|
||||
</View>
|
||||
</Touchable>
|
||||
|
||||
<Heading level='2' size='large'>View</Heading>
|
||||
<Heading level='3'>Default layout</Heading>
|
||||
<Heading size='large'>View</Heading>
|
||||
<Heading>Default layout</Heading>
|
||||
<View>
|
||||
{[ 1, 2, 3, 4, 5, 6 ].map((item, i) => {
|
||||
return (
|
||||
@@ -141,7 +141,7 @@ class Example extends React.Component {
|
||||
})}
|
||||
</View>
|
||||
|
||||
<Heading level='3'>Row layout</Heading>
|
||||
<Heading>Row layout</Heading>
|
||||
<View style={styles.row}>
|
||||
{[ 1, 2, 3, 4, 5, 6 ].map((item, i) => {
|
||||
return (
|
||||
@@ -152,13 +152,13 @@ class Example extends React.Component {
|
||||
})}
|
||||
</View>
|
||||
|
||||
<Heading level='3'>pointerEvents</Heading>
|
||||
<Heading>pointerEvents</Heading>
|
||||
<View style={styles.row}>
|
||||
{['box-none', 'box-only', 'none'].map((value, i) => {
|
||||
return (
|
||||
<View
|
||||
accessibilityRole='link'
|
||||
children={value}
|
||||
component='a'
|
||||
href='https://google.com'
|
||||
key={i}
|
||||
pointerEvents={value}
|
||||
|
||||
@@ -6,44 +6,6 @@ import ReactDOM from 'react-dom'
|
||||
import ReactTestUtils from 'react-addons-test-utils'
|
||||
|
||||
export const assertProps = {
|
||||
accessibilityLabel: function (Component, props) {
|
||||
// with label
|
||||
const accessibilityLabel = 'accessibilityLabel'
|
||||
const dom = renderToDOM(<Component {...props} accessibilityLabel={accessibilityLabel} />)
|
||||
assert.equal(dom.getAttribute('aria-label'), accessibilityLabel)
|
||||
},
|
||||
|
||||
accessibilityLiveRegion: function (Component, props) {
|
||||
const accessibilityLiveRegion = 'polite'
|
||||
const dom = renderToDOM(<Component {...props} accessibilityLiveRegion={accessibilityLiveRegion} />)
|
||||
assert.equal(dom.getAttribute('aria-live'), accessibilityLiveRegion)
|
||||
},
|
||||
|
||||
accessibilityRole: function (Component, props) {
|
||||
const accessibilityRole = 'main'
|
||||
const dom = renderToDOM(<Component {...props} accessibilityRole={accessibilityRole} />)
|
||||
assert.equal(dom.getAttribute('role'), accessibilityRole)
|
||||
},
|
||||
|
||||
accessible: function (Component, props) {
|
||||
// accessible (implicit)
|
||||
let dom = renderToDOM(<Component {...props} />)
|
||||
assert.equal(dom.getAttribute('aria-hidden'), null)
|
||||
// accessible (explicit)
|
||||
dom = renderToDOM(<Component {...props} accessible />)
|
||||
assert.equal(dom.getAttribute('aria-hidden'), null)
|
||||
// not accessible
|
||||
dom = renderToDOM(<Component {...props} accessible={false} />)
|
||||
assert.equal(dom.getAttribute('aria-hidden'), 'true')
|
||||
},
|
||||
|
||||
component: function (Component, props) {
|
||||
const component = 'main'
|
||||
const dom = renderToDOM(<Component {...props} component={component} />)
|
||||
const tagName = (dom.tagName).toLowerCase()
|
||||
assert.equal(tagName, component)
|
||||
},
|
||||
|
||||
style: function (Component, props) {
|
||||
let shallow
|
||||
// default styles
|
||||
@@ -67,16 +29,6 @@ export const assertProps = {
|
||||
shallow.props.style,
|
||||
{ ...Component.defaultProps.style, ...styleToMerge }
|
||||
)
|
||||
},
|
||||
|
||||
testID: function (Component, props) {
|
||||
// no testID
|
||||
let dom = renderToDOM(<Component {...props} />)
|
||||
assert.equal(dom.getAttribute('data-testid'), null)
|
||||
// with testID
|
||||
const testID = 'Example.testID'
|
||||
dom = renderToDOM(<Component {...props} testID={testID} />)
|
||||
assert.equal(dom.getAttribute('data-testid'), testID)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user