[change] rename createDOMElement to createElement

Allow 'createElement' to be used as a drop-in replacement for
'ReactDOM.createElement'.
This commit is contained in:
Nicolas Gallagher
2017-09-10 10:20:29 -07:00
parent 4a680fd9b6
commit bae4dd806a
16 changed files with 59 additions and 50 deletions
@@ -1,9 +1,10 @@
import { createDOMElement } from 'react-native'; /* eslint-disable react/prop-types */
import { createElement } from 'react-native';
import React from 'react'; import React from 'react';
import styles from './styles'; import styles from './styles';
const IconDirectMessage = props => const IconDirectMessage = props =>
createDOMElement('svg', { createElement('svg', {
children: ( children: (
<g> <g>
<path d="M43.34 14H12.66L28 27.946z" /> <path d="M43.34 14H12.66L28 27.946z" />
+3 -2
View File
@@ -1,9 +1,10 @@
import { createDOMElement } from 'react-native'; /* eslint-disable react/prop-types */
import { createElement } from 'react-native';
import React from 'react'; import React from 'react';
import styles from './styles'; import styles from './styles';
const IconHeart = props => const IconHeart = props =>
createDOMElement('svg', { createElement('svg', {
children: ( children: (
<g> <g>
<path d="M38.723 12c-7.187 0-11.16 7.306-11.723 8.131C26.437 19.306 22.504 12 15.277 12 8.791 12 3.533 18.163 3.533 24.647 3.533 39.964 21.891 55.907 27 56c5.109-.093 23.467-16.036 23.467-31.353C50.467 18.163 45.209 12 38.723 12z" /> <path d="M38.723 12c-7.187 0-11.16 7.306-11.723 8.131C26.437 19.306 22.504 12 15.277 12 8.791 12 3.533 18.163 3.533 24.647 3.533 39.964 21.891 55.907 27 56c5.109-.093 23.467-16.036 23.467-31.353C50.467 18.163 45.209 12 38.723 12z" />
+3 -2
View File
@@ -1,9 +1,10 @@
import { createDOMElement } from 'react-native'; /* eslint-disable react/prop-types */
import { createElement } from 'react-native';
import React from 'react'; import React from 'react';
import styles from './styles'; import styles from './styles';
const IconReply = props => const IconReply = props =>
createDOMElement('svg', { createElement('svg', {
children: ( children: (
<g> <g>
<path d="M41 31h-9V19a2.999 2.999 0 0 0-4.817-2.386l-21 16a3 3 0 0 0-.001 4.773l21 16a3.006 3.006 0 0 0 3.15.301A2.997 2.997 0 0 0 32 51V39h9c5.514 0 10 4.486 10 10a4 4 0 0 0 8 0c0-9.925-8.075-18-18-18z" /> <path d="M41 31h-9V19a2.999 2.999 0 0 0-4.817-2.386l-21 16a3 3 0 0 0-.001 4.773l21 16a3.006 3.006 0 0 0 3.15.301A2.997 2.997 0 0 0 32 51V39h9c5.514 0 10 4.486 10 10a4 4 0 0 0 8 0c0-9.925-8.075-18-18-18z" />
+3 -2
View File
@@ -1,9 +1,10 @@
import { createDOMElement } from 'react-native'; /* eslint-disable react/prop-types */
import { createElement } from 'react-native';
import React from 'react'; import React from 'react';
import styles from './styles'; import styles from './styles';
const IconRetweet = props => const IconRetweet = props =>
createDOMElement('svg', { createElement('svg', {
children: ( children: (
<g> <g>
<path d="M70.676 36.644A3 3 0 0 0 68 35h-7V19a4 4 0 0 0-4-4H34a4 4 0 0 0 0 8h18a1 1 0 0 1 1 .998V35h-7a3.001 3.001 0 0 0-2.419 4.775l11 15a3.003 3.003 0 0 0 4.839-.001l11-15a3.001 3.001 0 0 0 .256-3.13zM40.001 48H22a.995.995 0 0 1-.992-.96L21.001 36h7a3.001 3.001 0 0 0 2.419-4.775l-11-15a3.003 3.003 0 0 0-4.839.001l-11 15A3 3 0 0 0 6.001 36h7l.011 16.003a4 4 0 0 0 4 3.997h22.989a4 4 0 0 0 0-8z" /> <path d="M70.676 36.644A3 3 0 0 0 68 35h-7V19a4 4 0 0 0-4-4H34a4 4 0 0 0 0 8h18a1 1 0 0 1 1 .998V35h-7a3.001 3.001 0 0 0-2.419 4.775l11 15a3.003 3.003 0 0 0 4.839-.001l11-15a3.001 3.001 0 0 0 .256-3.13zM40.001 48H22a.995.995 0 0 1-.992-.96L21.001 36h7a3.001 3.001 0 0 0 2.419-4.775l-11-15a3.003 3.003 0 0 0-4.839.001l-11 15A3 3 0 0 0 6.001 36h7l.011 16.003a4 4 0 0 0 4 3.997h22.989a4 4 0 0 0 0-8z" />
+17 -8
View File
@@ -2,7 +2,7 @@
## Use with existing React DOM components ## Use with existing React DOM components
React Native for Web exports a web-specific module called `createDOMElement`, React Native for Web exports a web-specific module called `createElement`,
which can be used to wrap React DOM components. This allows you to use React which can be used to wrap React DOM components. This allows you to use React
Native's accessibility and style optimizations. Native's accessibility and style optimizations.
@@ -11,9 +11,8 @@ In the example below, `Video` will now accept common React Native props such as
props. props.
```js ```js
import { createDOMElement } from 'react-native'; import { createElement } from 'react-native-web';
const Video = (props) => createElement('video', props);
const Video = (props) => createDOMElement('video', props);
``` ```
This also works with composite components defined in your existing component This also works with composite components defined in your existing component
@@ -21,9 +20,10 @@ gallery or dependencies ([live example](https://www.webpackbin.com/bins/-KiTSGFw
```js ```js
import RaisedButton from 'material-ui/RaisedButton'; import RaisedButton from 'material-ui/RaisedButton';
import { createDOMElement, StyleSheet } from 'react-native'; import { createElement } from 'react-native-web';
import { StyleSheet } from 'react-native';
const CustomButton = (props) => createDOMElement(RaisedButton, { const CustomButton = (props) => createElement(RaisedButton, {
...props, ...props,
style: [ styles.button, props.style ] style: [ styles.button, props.style ]
}); });
@@ -35,6 +35,14 @@ const styles = StyleSheet.create({
}); });
``` ```
And `createElement` can be used as drop-in replacement for `React.createElement`:
```js
/* @jsx createElement */
import { createElement } from 'react-native-web';
const Video = (props) => <video {...props} style={[ { marginVertical: 10 }, props.style ]} />
```
Remember that React Native styles are not the same as React DOM styles, and Remember that React Native styles are not the same as React DOM styles, and
care needs to be taken not to pass React DOM styles into your React Native care needs to be taken not to pass React DOM styles into your React Native
wrapped components. wrapped components.
@@ -47,7 +55,8 @@ an API inspired by styled-components ([live
example](https://www.webpackbin.com/bins/-KjT9ziwv4O7FDZdvsnX)). example](https://www.webpackbin.com/bins/-KjT9ziwv4O7FDZdvsnX)).
```js ```js
const { createDOMElement, StyleSheet } = ReactNative; import { createElement } from 'react-native-web';
import { StyleSheet } from 'react-native';
/** /**
* styled API * styled API
@@ -69,7 +78,7 @@ const styled = (Component, styler) => {
return ( return (
isDOMComponent isDOMComponent
? createDOMElement(Component, nextProps) ? createElement(Component, nextProps)
: <Component {...nextProps} /> : <Component {...nextProps} />
); );
} }
+2 -2
View File
@@ -2,9 +2,9 @@
* @flow * @flow
*/ */
import { createDOMElement, StyleSheet } from 'react-native'; import { createElement, StyleSheet } from 'react-native';
const Code = props => createDOMElement('code', { ...props, style: [styles.code, props.style] }); const Code = props => createElement('code', { ...props, style: [styles.code, props.style] });
export default Code; export default Code;
+4 -3
View File
@@ -12,7 +12,7 @@
import applyNativeMethods from '../../modules/applyNativeMethods'; import applyNativeMethods from '../../modules/applyNativeMethods';
import { canUseDOM } from 'fbjs/lib/ExecutionEnvironment'; import { canUseDOM } from 'fbjs/lib/ExecutionEnvironment';
import createDOMElement from '../../modules/createDOMElement'; import createElement from '../../modules/createElement';
import { getAssetByID } from '../../modules/AssetRegistry'; import { getAssetByID } from '../../modules/AssetRegistry';
import ImageLoader from '../../modules/ImageLoader'; import ImageLoader from '../../modules/ImageLoader';
import ImageResizeMode from './ImageResizeMode'; import ImageResizeMode from './ImageResizeMode';
@@ -209,11 +209,11 @@ class Image extends Component {
// Allows users to trigger the browser's image context menu // Allows users to trigger the browser's image context menu
const hiddenImage = displayImage const hiddenImage = displayImage
? createDOMElement('img', { ? createElement('img', {
alt: accessibilityLabel || '', alt: accessibilityLabel || '',
draggable, draggable,
src: displayImage, src: displayImage,
style: [StyleSheet.absoluteFill, styles.img] style: styles.img
}) })
: null; : null;
@@ -317,6 +317,7 @@ const styles = StyleSheet.create({
display: 'inline-flex' display: 'inline-flex'
}, },
img: { img: {
...StyleSheet.absoluteFillObject,
height: '100%', height: '100%',
opacity: 0, opacity: 0,
width: '100%', width: '100%',
+2 -2
View File
@@ -5,7 +5,7 @@
import applyNativeMethods from '../../modules/applyNativeMethods'; import applyNativeMethods from '../../modules/applyNativeMethods';
import ColorPropType from '../../propTypes/ColorPropType'; import ColorPropType from '../../propTypes/ColorPropType';
import createDOMElement from '../../modules/createDOMElement'; import createElement from '../../modules/createElement';
import multiplyStyleLengthValue from '../../modules/multiplyStyleLengthValue'; import multiplyStyleLengthValue from '../../modules/multiplyStyleLengthValue';
import StyleSheet from '../../apis/StyleSheet'; import StyleSheet from '../../apis/StyleSheet';
import UIManager from '../../apis/UIManager'; import UIManager from '../../apis/UIManager';
@@ -110,7 +110,7 @@ class Switch extends PureComponent {
disabled && styles.disabledThumb disabled && styles.disabledThumb
]; ];
const nativeControl = createDOMElement('input', { const nativeControl = createElement('input', {
checked: value, checked: value,
disabled: disabled, disabled: disabled,
onBlur: this._handleFocusState, onBlur: this._handleFocusState,
+2 -2
View File
@@ -14,7 +14,7 @@ import applyLayout from '../../modules/applyLayout';
import applyNativeMethods from '../../modules/applyNativeMethods'; import applyNativeMethods from '../../modules/applyNativeMethods';
import { bool } from 'prop-types'; import { bool } from 'prop-types';
import { Component } from 'react'; import { Component } from 'react';
import createDOMElement from '../../modules/createDOMElement'; import createElement from '../../modules/createElement';
import StyleSheet from '../../apis/StyleSheet'; import StyleSheet from '../../apis/StyleSheet';
import TextPropTypes from './TextPropTypes'; import TextPropTypes from './TextPropTypes';
@@ -75,7 +75,7 @@ class Text extends Component {
const component = isInAParentText ? 'span' : 'div'; const component = isInAParentText ? 'span' : 'div';
return createDOMElement(component, otherProps); return createElement(component, otherProps);
} }
_createEnterHandler(fn) { _createEnterHandler(fn) {
+2 -2
View File
@@ -15,7 +15,7 @@ import applyNativeMethods from '../../modules/applyNativeMethods';
import { canUseDOM } from 'fbjs/lib/ExecutionEnvironment'; import { canUseDOM } from 'fbjs/lib/ExecutionEnvironment';
import { Component } from 'react'; import { Component } from 'react';
import ColorPropType from '../../propTypes/ColorPropType'; import ColorPropType from '../../propTypes/ColorPropType';
import createDOMElement from '../../modules/createDOMElement'; import createElement from '../../modules/createElement';
import findNodeHandle from '../../modules/findNodeHandle'; import findNodeHandle from '../../modules/findNodeHandle';
import StyleSheet from '../../apis/StyleSheet'; import StyleSheet from '../../apis/StyleSheet';
import StyleSheetPropType from '../../propTypes/StyleSheetPropType'; import StyleSheetPropType from '../../propTypes/StyleSheetPropType';
@@ -265,7 +265,7 @@ class TextInput extends Component {
otherProps.type = type; otherProps.type = type;
} }
return createDOMElement(component, otherProps); return createElement(component, otherProps);
} }
_handleBlur = e => { _handleBlur = e => {
+3 -6
View File
@@ -10,7 +10,7 @@
import applyLayout from '../../modules/applyLayout'; import applyLayout from '../../modules/applyLayout';
import applyNativeMethods from '../../modules/applyNativeMethods'; import applyNativeMethods from '../../modules/applyNativeMethods';
import { bool } from 'prop-types'; import { bool } from 'prop-types';
import createDOMElement from '../../modules/createDOMElement'; import createElement from '../../modules/createElement';
import StyleSheet from '../../apis/StyleSheet'; import StyleSheet from '../../apis/StyleSheet';
import ViewPropTypes from './ViewPropTypes'; import ViewPropTypes from './ViewPropTypes';
import React, { Component } from 'react'; import React, { Component } from 'react';
@@ -55,16 +55,13 @@ class View extends Component {
if (hitSlop) { if (hitSlop) {
const hitSlopStyle = calculateHitSlopStyle(hitSlop); const hitSlopStyle = calculateHitSlopStyle(hitSlop);
const hitSlopChild = createDOMElement('span', { style: [styles.hitSlop, hitSlopStyle] }); const hitSlopChild = createElement('span', { style: [styles.hitSlop, hitSlopStyle] });
otherProps.children = React.Children.toArray(otherProps.children); otherProps.children = React.Children.toArray(otherProps.children);
otherProps.children.unshift(hitSlopChild); otherProps.children.unshift(hitSlopChild);
otherProps.style.unshift(styles.hasHitSlop); otherProps.style.unshift(styles.hasHitSlop);
} }
// avoid HTML validation errors return createElement('div', otherProps);
const component = 'div';
return createDOMElement(component, otherProps);
} }
} }
+2 -2
View File
@@ -5,7 +5,7 @@ import {
unmountComponentAtNode, unmountComponentAtNode,
// modules // modules
createDOMElement, createElement,
NativeModules, NativeModules,
processColor, processColor,
@@ -71,7 +71,7 @@ const ReactNative = {
unmountComponentAtNode, unmountComponentAtNode,
// modules // modules
createDOMElement, createElement,
NativeModules, NativeModules,
processColor, processColor,
+1 -1
View File
@@ -1,4 +1,4 @@
export { default as createDOMElement } from './modules/createDOMElement'; export { default as createElement } from './modules/createElement';
export { default as findNodeHandle } from './modules/findNodeHandle'; export { default as findNodeHandle } from './modules/findNodeHandle';
export { default as NativeModules } from './modules/NativeModules'; export { default as NativeModules } from './modules/NativeModules';
export { default as processColor } from './modules/processColor'; export { default as processColor } from './modules/processColor';
@@ -1,6 +1,6 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP // Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`modules/createDOMElement it normalizes event.nativeEvent 1`] = ` exports[`modules/createElement it normalizes event.nativeEvent 1`] = `
Object { Object {
"_normalized": true, "_normalized": true,
"changedTouches": Array [], "changedTouches": Array [],
@@ -15,6 +15,6 @@ Object {
} }
`; `;
exports[`modules/createDOMElement it renders different DOM elements 1`] = `<span />`; exports[`modules/createElement it renders different DOM elements 1`] = `<span />`;
exports[`modules/createDOMElement it renders different DOM elements 2`] = `<main />`; exports[`modules/createElement it renders different DOM elements 2`] = `<main />`;
@@ -1,13 +1,13 @@
/* eslint-env jasmine, jest */ /* eslint-env jasmine, jest */
import createDOMElement from '..'; import createElement from '..';
import { shallow, render } from 'enzyme'; import { shallow, render } from 'enzyme';
describe('modules/createDOMElement', () => { describe('modules/createElement', () => {
test('it renders different DOM elements', () => { test('it renders different DOM elements', () => {
let component = render(createDOMElement('span')); let component = render(createElement('span'));
expect(component).toMatchSnapshot(); expect(component).toMatchSnapshot();
component = render(createDOMElement('main')); component = render(createElement('main'));
expect(component).toMatchSnapshot(); expect(component).toMatchSnapshot();
}); });
@@ -17,7 +17,7 @@ describe('modules/createDOMElement', () => {
expect(e.nativeEvent).toMatchSnapshot(); expect(e.nativeEvent).toMatchSnapshot();
done(); done();
}; };
const component = shallow(createDOMElement('span', { onClick })); const component = shallow(createElement('span', { onClick }));
component.find('span').simulate('click', { component.find('span').simulate('click', {
nativeEvent: { nativeEvent: {
preventDefault() {}, preventDefault() {},
@@ -34,7 +34,7 @@ describe('modules/createDOMElement', () => {
test(`"onClick" is ${disabled ? 'not ' : ''}called when "${name}" is pressed`, () => { test(`"onClick" is ${disabled ? 'not ' : ''}called when "${name}" is pressed`, () => {
const onClick = jest.fn(); const onClick = jest.fn();
const component = shallow( const component = shallow(
createDOMElement('span', { accessibilityRole: 'button', disabled, onClick }) createElement('span', { accessibilityRole: 'button', disabled, onClick })
); );
component.find('span').simulate('keyPress', { component.find('span').simulate('keyPress', {
isDefaultPrevented() {}, isDefaultPrevented() {},
@@ -80,15 +80,13 @@ const adjustProps = domProps => {
} }
}; };
const createDOMElement = (component, props) => { const createElement = (component, props, ...children) => {
// use equivalent platform elements where possible // use equivalent platform elements where possible
const accessibilityComponent = AccessibilityUtil.propsToAccessibilityComponent(props); const accessibilityComponent = AccessibilityUtil.propsToAccessibilityComponent(props);
const Component = accessibilityComponent || component; const Component = accessibilityComponent || component;
const domProps = createDOMProps(Component, props); const domProps = createDOMProps(Component, props);
adjustProps(domProps); adjustProps(domProps);
return React.createElement(Component, domProps, ...children);
return <Component {...domProps} />;
}; };
export default createDOMElement; export default createElement;