diff --git a/src/components/Image/index.js b/src/components/Image/index.js index 3d7b4128..2e8562c2 100644 --- a/src/components/Image/index.js +++ b/src/components/Image/index.js @@ -1,6 +1,7 @@ /* global window */ import applyNativeMethods from '../../modules/applyNativeMethods' -import createReactDOMComponent from '../../modules/createReactDOMComponent' +import BaseComponentPropTypes from '../../propTypes/BaseComponentPropTypes' +import createDOMElement from '../../modules/createDOMElement' import ImageResizeMode from './ImageResizeMode' import ImageStylePropTypes from './ImageStylePropTypes' import resolveAssetSource from './resolveAssetSource' @@ -26,8 +27,7 @@ class Image extends Component { static displayName = 'Image' static propTypes = { - accessibilityLabel: createReactDOMComponent.propTypes.accessibilityLabel, - accessible: createReactDOMComponent.propTypes.accessible, + ...BaseComponentPropTypes, children: PropTypes.any, defaultSource: ImageSourcePropType, onError: PropTypes.func, @@ -37,8 +37,7 @@ class Image extends Component { onLoadStart: PropTypes.func, resizeMode: PropTypes.oneOf(['center', 'contain', 'cover', 'none', 'repeat', 'stretch']), source: ImageSourcePropType, - style: StyleSheetPropType(ImageStylePropTypes), - testID: createReactDOMComponent.propTypes.testID + style: StyleSheetPropType(ImageStylePropTypes) }; static defaultProps = { @@ -121,7 +120,7 @@ class Image extends Component { ]} testID={testID} > - {createReactDOMComponent({ component: 'img', src: displayImage, style: styles.img })} + {createDOMElement('img', { src: displayImage, style: styles.img })} {children ? ( ) : null} diff --git a/src/components/Text/index.js b/src/components/Text/index.js index 9f9c2ac4..74252321 100644 --- a/src/components/Text/index.js +++ b/src/components/Text/index.js @@ -1,6 +1,7 @@ import applyLayout from '../../modules/applyLayout' import applyNativeMethods from '../../modules/applyNativeMethods' -import createReactDOMComponent from '../../modules/createReactDOMComponent' +import BaseComponentPropTypes from '../../propTypes/BaseComponentPropTypes' +import createDOMElement from '../../modules/createDOMElement' import { Component, PropTypes } from 'react' import StyleSheet from '../../apis/StyleSheet' import StyleSheetPropType from '../../propTypes/StyleSheetPropType' @@ -10,16 +11,14 @@ class Text extends Component { static displayName = 'Text' static propTypes = { - accessibilityLabel: createReactDOMComponent.propTypes.accessibilityLabel, + ...BaseComponentPropTypes, accessibilityRole: PropTypes.oneOf([ 'heading', 'link' ]), - accessible: createReactDOMComponent.propTypes.accessible, children: PropTypes.any, numberOfLines: PropTypes.number, onLayout: PropTypes.func, onPress: PropTypes.func, selectable: PropTypes.bool, - style: StyleSheetPropType(TextStylePropTypes), - testID: createReactDOMComponent.propTypes.testID + style: StyleSheetPropType(TextStylePropTypes) }; static defaultProps = { @@ -37,9 +36,8 @@ class Text extends Component { ...other } = this.props - return createReactDOMComponent({ + return createDOMElement('span', { ...other, - component: 'span', onClick: this._onPress, style: [ styles.initial, diff --git a/src/components/TextInput/index.js b/src/components/TextInput/index.js index 6fa200de..2a84b79f 100644 --- a/src/components/TextInput/index.js +++ b/src/components/TextInput/index.js @@ -1,5 +1,5 @@ import applyNativeMethods from '../../modules/applyNativeMethods' -import createReactDOMComponent from '../../modules/createReactDOMComponent' +import createDOMElement from '../../modules/createDOMElement' import omit from 'lodash/omit' import pick from 'lodash/pick' import React, { Component, PropTypes } from 'react' @@ -135,23 +135,23 @@ class TextInput extends Component { onFocus: this._handleFocus, onSelect: onSelectionChange && this._handleSelectionChange, readOnly: !editable, + ref: 'input', style: [ styles.input, textStyles, { outline: style.outline } ], value } const propsMultiline = { ...propsCommon, - component: TextareaAutosize, maxRows: maxNumberOfLines || numberOfLines, minRows: numberOfLines } const propsSingleline = { ...propsCommon, - component: 'input', type } + const component = multiline ? TextareaAutosize : 'input' const props = multiline ? propsMultiline : propsSingleline const optionalPlaceholder = placeholder && this.state.showPlaceholder && ( @@ -176,7 +176,7 @@ class TextInput extends Component { testID={testID} > - {createReactDOMComponent({ ...props, ref: 'input' })} + {createDOMElement(component, props)} {optionalPlaceholder} diff --git a/src/components/View/index.js b/src/components/View/index.js index 52ad4734..e7b0ba10 100644 --- a/src/components/View/index.js +++ b/src/components/View/index.js @@ -1,6 +1,7 @@ import applyLayout from '../../modules/applyLayout' import applyNativeMethods from '../../modules/applyNativeMethods' -import createReactDOMComponent from '../../modules/createReactDOMComponent' +import BaseComponentPropTypes from '../../propTypes/BaseComponentPropTypes' +import createDOMElement from '../../modules/createDOMElement' import EdgeInsetsPropType from '../../propTypes/EdgeInsetsPropType' import normalizeNativeEvent from '../../modules/normalizeNativeEvent' import { Component, PropTypes } from 'react' @@ -35,10 +36,7 @@ class View extends Component { static displayName = 'View' static propTypes = { - accessibilityLabel: createReactDOMComponent.propTypes.accessibilityLabel, - accessibilityLiveRegion: createReactDOMComponent.propTypes.accessibilityLiveRegion, - accessibilityRole: createReactDOMComponent.propTypes.accessibilityRole, - accessible: createReactDOMComponent.propTypes.accessible, + ...BaseComponentPropTypes, children: PropTypes.any, collapsable: PropTypes.bool, hitSlop: EdgeInsetsPropType, @@ -64,8 +62,7 @@ class View extends Component { onTouchStart: PropTypes.func, onTouchStartCapture: PropTypes.func, pointerEvents: PropTypes.oneOf(['auto', 'box-none', 'box-only', 'none']), - style: StyleSheetPropType(ViewStylePropTypes), - testID: createReactDOMComponent.propTypes.testID + style: StyleSheetPropType(ViewStylePropTypes) }; static defaultProps = { @@ -110,10 +107,10 @@ class View extends Component { return handlerProps }, {}) + const component = this.context.isInAButtonView ? 'span' : 'div' const props = { ...other, ...normalizedEventHandlers, - component: this.context.isInAButtonView ? 'span' : 'div', style: [ styles.initial, style, @@ -122,7 +119,7 @@ class View extends Component { ] } - return createReactDOMComponent(props) + return createDOMElement(component, props) } _normalizeEventForHandler(handler, handlerName) { diff --git a/src/modules/createReactDOMComponent/__tests__/index-test.js b/src/modules/createDOMElement/__tests__/index-test.js similarity index 57% rename from src/modules/createReactDOMComponent/__tests__/index-test.js rename to src/modules/createDOMElement/__tests__/index-test.js index afd01093..554adb64 100644 --- a/src/modules/createReactDOMComponent/__tests__/index-test.js +++ b/src/modules/createDOMElement/__tests__/index-test.js @@ -1,61 +1,60 @@ /* eslint-env mocha */ import assert from 'assert' -import createReactDOMComponent from '..' +import createDOMElement from '..' import { shallow } from 'enzyme' -suite('modules/createReactDOMComponent', () => { +suite('modules/createDOMElement', () => { + test('renders correct DOM element', () => { + let element = shallow(createDOMElement('span')) + assert.equal(element.is('span'), true) + element = shallow(createDOMElement('main')) + assert.equal(element.is('main'), true) + }) + test('prop "accessibilityLabel"', () => { const accessibilityLabel = 'accessibilityLabel' - const element = shallow(createReactDOMComponent({ accessibilityLabel })) + const element = shallow(createDOMElement('span', { accessibilityLabel })) assert.equal(element.prop('aria-label'), accessibilityLabel) }) test('prop "accessibilityLiveRegion"', () => { const accessibilityLiveRegion = 'polite' - const element = shallow(createReactDOMComponent({ accessibilityLiveRegion })) + const element = shallow(createDOMElement('span', { accessibilityLiveRegion })) assert.equal(element.prop('aria-live'), accessibilityLiveRegion) }) test('prop "accessibilityRole"', () => { const accessibilityRole = 'banner' - let element = shallow(createReactDOMComponent({ accessibilityRole })) + let element = shallow(createDOMElement('span', { accessibilityRole })) assert.equal(element.prop('role'), accessibilityRole) assert.equal(element.is('header'), true) const button = 'button' - element = shallow(createReactDOMComponent({ accessibilityRole: 'button' })) + element = shallow(createDOMElement('span', { accessibilityRole: 'button' })) assert.equal(element.prop('type'), button) assert.equal(element.is('button'), true) }) test('prop "accessible"', () => { // accessible (implicit) - let element = shallow(createReactDOMComponent({})) + let element = shallow(createDOMElement('span', {})) assert.equal(element.prop('aria-hidden'), null) // accessible (explicit) - element = shallow(createReactDOMComponent({ accessible: true })) + element = shallow(createDOMElement('span', { accessible: true })) assert.equal(element.prop('aria-hidden'), null) // not accessible - element = shallow(createReactDOMComponent({ accessible: false })) + element = shallow(createDOMElement('span', { accessible: false })) assert.equal(element.prop('aria-hidden'), true) }) - test('prop "component"', () => { - const component = 'main' - let element = shallow(createReactDOMComponent({})) - assert.equal(element.is('span'), true, 'Default element must be a "span"') - element = shallow(createReactDOMComponent({ component })) - assert.equal(element.is('main'), true) - }) - test('prop "testID"', () => { // no testID - let element = shallow(createReactDOMComponent({})) + let element = shallow(createDOMElement('span', {})) assert.equal(element.prop('data-testid'), null) // with testID const testID = 'Example.testID' - element = shallow(createReactDOMComponent({ testID })) + element = shallow(createDOMElement('span', { testID })) assert.equal(element.prop('data-testid'), testID) }) }) diff --git a/src/modules/createDOMElement/index.js b/src/modules/createDOMElement/index.js new file mode 100644 index 00000000..d7f4d436 --- /dev/null +++ b/src/modules/createDOMElement/index.js @@ -0,0 +1,48 @@ +import React from 'react' +import StyleSheet from '../../apis/StyleSheet' + +const roleComponents = { + article: 'article', + banner: 'header', + button: 'button', + complementary: 'aside', + contentinfo: 'footer', + form: 'form', + heading: 'h1', + link: 'a', + list: 'ul', + listitem: 'li', + main: 'main', + navigation: 'nav', + region: 'section' +} + +const createDOMElement = (component, rnProps = {}) => { + const { + accessibilityLabel, + accessibilityLiveRegion, + accessibilityRole, + accessible = true, + testID, + type, + ...other + } = rnProps + + const accessibilityComponent = accessibilityRole && roleComponents[accessibilityRole] + const Component = accessibilityComponent || component + + return ( + + ) +} + +module.exports = createDOMElement diff --git a/src/modules/createReactDOMComponent/index.js b/src/modules/createReactDOMComponent/index.js deleted file mode 100644 index d65483d4..00000000 --- a/src/modules/createReactDOMComponent/index.js +++ /dev/null @@ -1,58 +0,0 @@ -import React, { PropTypes } from 'react' -import StyleSheet from '../../apis/StyleSheet' - -const roleComponents = { - article: 'article', - banner: 'header', - button: 'button', - complementary: 'aside', - contentinfo: 'footer', - form: 'form', - heading: 'h1', - link: 'a', - list: 'ul', - listitem: 'li', - main: 'main', - navigation: 'nav', - region: 'section' -} - -const createReactDOMComponent = ({ - accessibilityLabel, - accessibilityLiveRegion, - accessibilityRole, - accessible = true, - component = 'span', - testID, - type, - ...other -}) => { - const role = accessibilityRole - const Component = role && roleComponents[role] ? roleComponents[role] : component - - return ( - - ) -} - -createReactDOMComponent.propTypes = { - accessibilityLabel: PropTypes.string, - accessibilityLiveRegion: PropTypes.oneOf([ 'assertive', 'off', 'polite' ]), - accessibilityRole: PropTypes.string, - accessible: PropTypes.bool, - component: PropTypes.oneOfType([ PropTypes.func, PropTypes.string ]), - style: PropTypes.oneOfType([ PropTypes.array, PropTypes.object ]), - testID: PropTypes.string, - type: PropTypes.string -} - -module.exports = createReactDOMComponent diff --git a/src/propTypes/BaseComponentPropTypes.js b/src/propTypes/BaseComponentPropTypes.js new file mode 100644 index 00000000..bd3beaa1 --- /dev/null +++ b/src/propTypes/BaseComponentPropTypes.js @@ -0,0 +1,13 @@ +import { PropTypes } from 'react' +const { array, bool, number, object, oneOf, oneOfType, string } = PropTypes + +const BaseComponentPropTypes = { + accessibilityLabel: string, + accessibilityLiveRegion: oneOf([ 'assertive', 'off', 'polite' ]), + accessibilityRole: string, + accessible: bool, + style: oneOfType([ array, number, object ]), + testID: string +} + +module.exports = BaseComponentPropTypes