mirror of
https://github.com/zhigang1992/react-native-web.git
synced 2026-04-11 11:29:48 +08:00
Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ec2db3e2a3 | ||
|
|
e6f00f7592 | ||
|
|
976320916e | ||
|
|
808790505e | ||
|
|
89ad493ce5 |
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "react-native-web",
|
||||
"version": "0.0.77",
|
||||
"version": "0.0.78",
|
||||
"description": "React Native for Web",
|
||||
"main": "dist/index.js",
|
||||
"files": [
|
||||
@@ -25,7 +25,6 @@
|
||||
"dependencies": {
|
||||
"animated": "^0.2.0",
|
||||
"array-find-index": "^1.0.2",
|
||||
"asap": "^2.0.5",
|
||||
"babel-runtime": "^6.23.0",
|
||||
"debounce": "^1.0.0",
|
||||
"deep-assign": "^2.0.0",
|
||||
|
||||
@@ -10,27 +10,18 @@ open ./performance/index.html
|
||||
## Notes
|
||||
|
||||
The components used in the render benchmarks are simple enough to be
|
||||
implemented by multiple styling libraries. The implementations are not
|
||||
equivalent but are useful for framing the relative performance of
|
||||
`react-native-web` against these tests.
|
||||
|
||||
The implementations are not equivalent. For example, the `react-native-web`
|
||||
implementation of `View` does more than just styling. The
|
||||
`react-native-web/lite` variant implements a minimal `View` that allows for a
|
||||
more direct comparison with the `css-modules` baseline.
|
||||
implemented by multiple UI or style libraries. The implementations are not
|
||||
equivalent in functionality.
|
||||
|
||||
## Benchmark results
|
||||
|
||||
Typical render timings*: mean / two standard deviations
|
||||
Typical render timings*: mean ± two standard deviations
|
||||
|
||||
Version: 0.0.73
|
||||
|
||||
| Implementation | Deep tree (ms) | Wide tree (ms) |
|
||||
| Implementation | Deep tree (ms) | Wide tree (ms) |
|
||||
| :--- | ---: | ---: |
|
||||
| css-modules | `80.47` `±18.04` | `166.91` `±19.90` |
|
||||
| react-native-web/lite | `87.91` `±13.37` | `181.45` `±20.06` |
|
||||
| react-native-web | `113.45` `±09.27` | `237.33` `±38.77` |
|
||||
| styled-components | `170.86` `±15.67` | `378.83` `±36.11` |
|
||||
| glamor | `275.41` `±19.56` | `474.76` `±29.02` |
|
||||
| `css-modules` | `76.66` `±18.46` | `157.03` `±19.79` |
|
||||
| `react-native-web@0.0.78` | `90.13` `±20.91` | `198.72` `±24.44` |
|
||||
| `styled-components@2.0.0-7` | `263.06` `±31.87` | `564.53` `±27.62` |
|
||||
| `glamor@3.0.0-1` | `267.49` `±35.12` | `451.99` `±37.32` |
|
||||
|
||||
*MacBook Pro (13-inch, Early 2011); 2.7 GHz Intel Core i7; 16 GB 1600 MHz DDR3. Google Chrome 56.
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
/* eslint-disable react/prop-types */
|
||||
import React from 'react';
|
||||
import StyleSheet from 'react-native/apis/StyleSheet';
|
||||
import View from '../View/lite';
|
||||
|
||||
const Box = ({ color, fixed = false, layout = 'column', outer = false, ...other }) => (
|
||||
<View
|
||||
{...other}
|
||||
style={[
|
||||
styles[`color${color}`],
|
||||
fixed && styles.fixed,
|
||||
layout === 'row' && styles.row,
|
||||
outer && styles.outer
|
||||
]}
|
||||
/>
|
||||
);
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
outer: {
|
||||
padding: 4
|
||||
},
|
||||
row: {
|
||||
flexDirection: 'row'
|
||||
},
|
||||
color0: {
|
||||
backgroundColor: '#222'
|
||||
},
|
||||
color1: {
|
||||
backgroundColor: '#666'
|
||||
},
|
||||
color2: {
|
||||
backgroundColor: '#999'
|
||||
},
|
||||
color3: {
|
||||
backgroundColor: 'blue'
|
||||
},
|
||||
color4: {
|
||||
backgroundColor: 'orange'
|
||||
},
|
||||
color5: {
|
||||
backgroundColor: 'red'
|
||||
},
|
||||
fixed: {
|
||||
width: 20,
|
||||
height: 20
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = Box;
|
||||
@@ -1,32 +0,0 @@
|
||||
import createDOMElement from 'react-native/modules/createDOMElement';
|
||||
import StyleSheet from 'react-native/apis/StyleSheet';
|
||||
|
||||
const View = props => createDOMElement('div', { ...props, style: [styles.initial, props.style] });
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
initial: {
|
||||
alignItems: 'stretch',
|
||||
borderWidth: 0,
|
||||
borderStyle: 'solid',
|
||||
boxSizing: 'border-box',
|
||||
display: 'flex',
|
||||
flexBasis: 'auto',
|
||||
flexDirection: 'column',
|
||||
margin: 0,
|
||||
padding: 0,
|
||||
position: 'relative',
|
||||
// button and anchor reset
|
||||
backgroundColor: 'transparent',
|
||||
color: 'inherit',
|
||||
font: 'inherit',
|
||||
textAlign: 'inherit',
|
||||
textDecorationLine: 'none',
|
||||
// list reset
|
||||
listStyle: 'none',
|
||||
// fix flexbox bugs
|
||||
minHeight: 0,
|
||||
minWidth: 0
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = View;
|
||||
@@ -1,7 +0,0 @@
|
||||
import Box from './Box/lite';
|
||||
import View from './View/lite';
|
||||
|
||||
export default {
|
||||
Box,
|
||||
View
|
||||
};
|
||||
@@ -1,7 +1,6 @@
|
||||
import cssModules from './implementations/css-modules';
|
||||
import glamor from './implementations/glamor';
|
||||
import reactNative from './implementations/react-native-web';
|
||||
import reactNativeLite from './implementations/react-native-web/lite';
|
||||
import styledComponents from './implementations/styled-components';
|
||||
|
||||
import renderDeepTree from './tests/renderDeepTree';
|
||||
@@ -10,13 +9,11 @@ import renderWideTree from './tests/renderWideTree';
|
||||
const tests = [
|
||||
// deep tree
|
||||
() => renderDeepTree('css-modules', cssModules),
|
||||
() => renderDeepTree('react-native-web/lite', reactNativeLite),
|
||||
() => renderDeepTree('react-native-web', reactNative),
|
||||
() => renderDeepTree('styled-components', styledComponents),
|
||||
() => renderDeepTree('glamor', glamor),
|
||||
// wide tree
|
||||
() => renderWideTree('css-modules', cssModules),
|
||||
() => renderWideTree('react-native-web/lite', reactNativeLite),
|
||||
() => renderWideTree('react-native-web', reactNative),
|
||||
() => renderWideTree('styled-components', styledComponents),
|
||||
() => renderWideTree('glamor', glamor)
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"classnames": "^2.2.5",
|
||||
"glamor": "^2.20.24",
|
||||
"glamor": "3.0.0-1",
|
||||
"marky": "^1.1.3",
|
||||
"styled-components": "2.0.0-5"
|
||||
"styled-components": "2.0.0-7"
|
||||
},
|
||||
"devDependencies": {
|
||||
"css-loader": "^0.26.2",
|
||||
|
||||
@@ -19,7 +19,9 @@ module.exports = {
|
||||
test: /\.js$/,
|
||||
exclude: /node_modules/,
|
||||
loader: 'babel-loader',
|
||||
query: { cacheDirectory: true }
|
||||
query: {
|
||||
cacheDirectory: true
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@@ -155,10 +155,6 @@ colormin@^1.0.5:
|
||||
css-color-names "0.0.4"
|
||||
has "^1.0.1"
|
||||
|
||||
colors@0.5.x:
|
||||
version "0.5.1"
|
||||
resolved "https://registry.yarnpkg.com/colors/-/colors-0.5.1.tgz#7d0023eaeb154e8ee9fce75dcb923d0ed1667774"
|
||||
|
||||
colors@~1.1.2:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63"
|
||||
@@ -171,15 +167,9 @@ core-js@^2.4.0:
|
||||
version "2.4.1"
|
||||
resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.4.1.tgz#4de911e667b0eae9124e34254b53aea6fc618d3e"
|
||||
|
||||
css-color-list@0.0.1:
|
||||
version "0.0.1"
|
||||
resolved "https://registry.yarnpkg.com/css-color-list/-/css-color-list-0.0.1.tgz#8718e8695ae7a2cc8787be8715f1c008a7f28b15"
|
||||
dependencies:
|
||||
css-color-names "0.0.1"
|
||||
|
||||
css-color-names@0.0.1:
|
||||
version "0.0.1"
|
||||
resolved "https://registry.yarnpkg.com/css-color-names/-/css-color-names-0.0.1.tgz#5d0548fa256456ede4a9a0c2ac7ab19d3eb1ad81"
|
||||
css-color-keywords@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/css-color-keywords/-/css-color-keywords-1.0.0.tgz#fea2616dc676b2962686b3af8dbdbe180b244e05"
|
||||
|
||||
css-color-names@0.0.4:
|
||||
version "0.0.4"
|
||||
@@ -218,13 +208,13 @@ css-selector-tokenizer@^0.7.0:
|
||||
fastparse "^1.1.1"
|
||||
regexpu-core "^1.0.0"
|
||||
|
||||
css-to-react-native@^1.0.6:
|
||||
version "1.0.6"
|
||||
resolved "https://registry.yarnpkg.com/css-to-react-native/-/css-to-react-native-1.0.6.tgz#728c7e774e56536558a0ecaa990d9507c43a4ac4"
|
||||
css-to-react-native@2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/css-to-react-native/-/css-to-react-native-2.0.1.tgz#179b25cba8cab7798118b1679b81f4d6b3fa0de3"
|
||||
dependencies:
|
||||
css-color-list "0.0.1"
|
||||
css-color-keywords "^1.0.0"
|
||||
fbjs "^0.8.5"
|
||||
nearley "^2.7.7"
|
||||
postcss-value-parser "^3.3.0"
|
||||
|
||||
cssesc@^0.1.0:
|
||||
version "0.1.0"
|
||||
@@ -282,10 +272,6 @@ defined@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693"
|
||||
|
||||
discontinuous-range@1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/discontinuous-range/-/discontinuous-range-1.0.0.tgz#e38331f0844bba49b9a9cb71c771585aab1bc65a"
|
||||
|
||||
electron-to-chromium@^1.2.3:
|
||||
version "1.2.4"
|
||||
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.2.4.tgz#9751cbea89fa120bf88c226ba41eb8d0b6f1b597"
|
||||
@@ -336,7 +322,15 @@ function-bind@^1.0.2:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.0.tgz#16176714c801798e4e8f2cf7f7529467bb4a5771"
|
||||
|
||||
glamor@^2.20.22, glamor@^2.20.24:
|
||||
glamor@3.0.0-1:
|
||||
version "3.0.0-1"
|
||||
resolved "https://registry.yarnpkg.com/glamor/-/glamor-3.0.0-1.tgz#60f489e96d96c12620803d3677ac26413cb76a95"
|
||||
dependencies:
|
||||
babel-runtime "^6.18.0"
|
||||
fbjs "^0.8.8"
|
||||
object-assign "^4.1.0"
|
||||
|
||||
glamor@^2.20.22:
|
||||
version "2.20.24"
|
||||
resolved "https://registry.yarnpkg.com/glamor/-/glamor-2.20.24.tgz#a299af2eec687322634ba38e4a0854d8743d2041"
|
||||
dependencies:
|
||||
@@ -501,14 +495,6 @@ mkdirp@~0.5.1:
|
||||
dependencies:
|
||||
minimist "0.0.8"
|
||||
|
||||
nearley@^2.7.7:
|
||||
version "2.7.13"
|
||||
resolved "https://registry.yarnpkg.com/nearley/-/nearley-2.7.13.tgz#ae19927cc821a4b517de91962db9ed0e90d991fa"
|
||||
dependencies:
|
||||
nomnom "~1.6.2"
|
||||
railroad-diagrams "^1.0.0"
|
||||
randexp "^0.4.2"
|
||||
|
||||
node-fetch@^1.0.1:
|
||||
version "1.6.3"
|
||||
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.6.3.tgz#dc234edd6489982d58e8f0db4f695029abcd8c04"
|
||||
@@ -516,13 +502,6 @@ node-fetch@^1.0.1:
|
||||
encoding "^0.1.11"
|
||||
is-stream "^1.0.1"
|
||||
|
||||
nomnom@~1.6.2:
|
||||
version "1.6.2"
|
||||
resolved "https://registry.yarnpkg.com/nomnom/-/nomnom-1.6.2.tgz#84a66a260174408fc5b77a18f888eccc44fb6971"
|
||||
dependencies:
|
||||
colors "0.5.x"
|
||||
underscore "~1.4.4"
|
||||
|
||||
normalize-range@^0.1.2:
|
||||
version "0.1.2"
|
||||
resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942"
|
||||
@@ -803,17 +782,6 @@ query-string@^4.1.0:
|
||||
object-assign "^4.1.0"
|
||||
strict-uri-encode "^1.0.0"
|
||||
|
||||
railroad-diagrams@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/railroad-diagrams/-/railroad-diagrams-1.0.0.tgz#eb7e6267548ddedfb899c1b90e57374559cddb7e"
|
||||
|
||||
randexp@^0.4.2:
|
||||
version "0.4.4"
|
||||
resolved "https://registry.yarnpkg.com/randexp/-/randexp-0.4.4.tgz#ba68265f4a9f9e85f5814d34e160291f939f168e"
|
||||
dependencies:
|
||||
discontinuous-range "1.0.0"
|
||||
ret "~0.1.10"
|
||||
|
||||
reduce-css-calc@^1.2.6:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/reduce-css-calc/-/reduce-css-calc-1.3.0.tgz#747c914e049614a4c9cfbba629871ad1d2927716"
|
||||
@@ -854,10 +822,6 @@ regjsparser@^0.1.4:
|
||||
dependencies:
|
||||
jsesc "~0.5.0"
|
||||
|
||||
ret@~0.1.10:
|
||||
version "0.1.13"
|
||||
resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.13.tgz#38c2702ece654978941edd8b7dfac6aeeef4067d"
|
||||
|
||||
sax@~1.2.1:
|
||||
version "1.2.2"
|
||||
resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.2.tgz#fd8631a23bc7826bef5d871bdb87378c95647828"
|
||||
@@ -900,23 +864,23 @@ style-loader@^0.13.2:
|
||||
dependencies:
|
||||
loader-utils "^1.0.2"
|
||||
|
||||
styled-components@2.0.0-5:
|
||||
version "2.0.0-5"
|
||||
resolved "https://registry.yarnpkg.com/styled-components/-/styled-components-2.0.0-5.tgz#df802d110cfb1a08a37e7746ecff11c765075e34"
|
||||
styled-components@2.0.0-7:
|
||||
version "2.0.0-7"
|
||||
resolved "https://registry.yarnpkg.com/styled-components/-/styled-components-2.0.0-7.tgz#a420b99622eacec26ae3d62c1c75985791d9691b"
|
||||
dependencies:
|
||||
buffer "^5.0.3"
|
||||
css-to-react-native "^1.0.6"
|
||||
css-to-react-native "2.0.1"
|
||||
fbjs "^0.8.9"
|
||||
glamor "^2.20.22"
|
||||
inline-style-prefixer "^2.0.5"
|
||||
is-function "^1.0.1"
|
||||
is-plain-object "^2.0.1"
|
||||
stylis "^1.1.13"
|
||||
stylis "^1.2.0"
|
||||
supports-color "^3.2.3"
|
||||
|
||||
stylis@^1.1.13:
|
||||
version "1.1.13"
|
||||
resolved "https://registry.yarnpkg.com/stylis/-/stylis-1.1.13.tgz#e15095d0027f49683f7556e31df184c1eafe1d6d"
|
||||
stylis@^1.2.0:
|
||||
version "1.2.6"
|
||||
resolved "https://registry.yarnpkg.com/stylis/-/stylis-1.2.6.tgz#d7e72d3c8de52684a4f6cc82b3086e3634dc3c13"
|
||||
|
||||
supports-color@^2.0.0:
|
||||
version "2.0.0"
|
||||
@@ -944,10 +908,6 @@ ua-parser-js@^0.7.9:
|
||||
version "0.7.12"
|
||||
resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.12.tgz#04c81a99bdd5dc52263ea29d24c6bf8d4818a4bb"
|
||||
|
||||
underscore@~1.4.4:
|
||||
version "1.4.4"
|
||||
resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.4.4.tgz#61a6a32010622afa07963bf325203cf12239d604"
|
||||
|
||||
uniq@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff"
|
||||
|
||||
@@ -6,11 +6,11 @@
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import { canUseDOM } from 'fbjs/lib/ExecutionEnvironment';
|
||||
import debounce from 'debounce';
|
||||
import ExecutionEnvironment from 'fbjs/lib/ExecutionEnvironment';
|
||||
import invariant from 'fbjs/lib/invariant';
|
||||
|
||||
const win = ExecutionEnvironment.canUseDOM ? window : { screen: {} };
|
||||
const win = canUseDOM ? window : { screen: {} };
|
||||
|
||||
const dimensions = {};
|
||||
|
||||
@@ -38,6 +38,9 @@ class Dimensions {
|
||||
}
|
||||
|
||||
Dimensions.set();
|
||||
ExecutionEnvironment.canUseDOM && window.addEventListener('resize', debounce(Dimensions.set, 50));
|
||||
|
||||
if (canUseDOM) {
|
||||
window.addEventListener('resize', debounce(Dimensions.set, 16), false);
|
||||
}
|
||||
|
||||
module.exports = Dimensions;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
const Platform = {
|
||||
OS: 'web',
|
||||
select: (obj: Object) => obj.web
|
||||
select: (obj: Object) => 'web' in obj ? obj.web : obj.default
|
||||
};
|
||||
|
||||
module.exports = Platform;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import asap from 'asap';
|
||||
import { canUseDOM } from 'fbjs/lib/ExecutionEnvironment';
|
||||
import generateCss from './generateCss';
|
||||
import hash from './hash';
|
||||
import requestAnimationFrame from 'fbjs/lib/requestAnimationFrame';
|
||||
import staticCss from './staticCss';
|
||||
|
||||
const emptyObject = {};
|
||||
@@ -111,7 +111,7 @@ class StyleManager {
|
||||
className = createClassName(prop, value);
|
||||
this._addToCache(className, prop, value);
|
||||
if (canUseDOM) {
|
||||
asap(() => {
|
||||
requestAnimationFrame(() => {
|
||||
const sheet = this.mainSheet.sheet;
|
||||
// avoid injecting if the rule already exists (e.g., server rendered, hot reload)
|
||||
if (this.mainSheet.textContent.indexOf(className) === -1) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import asap from 'asap';
|
||||
import CSSPropertyOperations from 'react-dom/lib/CSSPropertyOperations';
|
||||
import requestAnimationFrame from 'fbjs/lib/requestAnimationFrame';
|
||||
|
||||
const getRect = node => {
|
||||
const height = node.offsetHeight;
|
||||
@@ -15,13 +15,15 @@ const getRect = node => {
|
||||
};
|
||||
|
||||
const measureLayout = (node, relativeToNativeNode, callback) => {
|
||||
asap(() => {
|
||||
const relativeNode = relativeToNativeNode || node.parentNode;
|
||||
const relativeRect = getRect(relativeNode);
|
||||
const { height, left, top, width } = getRect(node);
|
||||
const x = left - relativeRect.left;
|
||||
const y = top - relativeRect.top;
|
||||
callback(x, y, width, height, left, top);
|
||||
requestAnimationFrame(() => {
|
||||
const relativeNode = relativeToNativeNode || (node && node.parentNode);
|
||||
if (node && relativeNode) {
|
||||
const relativeRect = getRect(relativeNode);
|
||||
const { height, left, top, width } = getRect(node);
|
||||
const x = left - relativeRect.left;
|
||||
const y = top - relativeRect.top;
|
||||
callback(x, y, width, height, left, top);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
@@ -43,13 +45,16 @@ const UIManager = {
|
||||
},
|
||||
|
||||
measureInWindow(node, callback) {
|
||||
const { height, left, top, width } = getRect(node);
|
||||
callback(left, top, width, height);
|
||||
requestAnimationFrame(() => {
|
||||
if (node) {
|
||||
const { height, left, top, width } = getRect(node);
|
||||
callback(left, top, width, height);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
measureLayout(node, relativeToNativeNode, onFail, onSuccess) {
|
||||
const relativeTo = relativeToNativeNode || node.parentNode;
|
||||
measureLayout(node, relativeTo, onSuccess);
|
||||
measureLayout(node, relativeToNativeNode, onSuccess);
|
||||
},
|
||||
|
||||
updateView(node, props, component /* only needed to surpress React errors in development */) {
|
||||
|
||||
@@ -1,49 +1,11 @@
|
||||
import '../../modules/injectResponderEventPlugin';
|
||||
|
||||
import applyLayout from '../../modules/applyLayout';
|
||||
import applyNativeMethods from '../../modules/applyNativeMethods';
|
||||
import createDOMElement from '../../modules/createDOMElement';
|
||||
import normalizeNativeEvent from '../../modules/normalizeNativeEvent';
|
||||
import StyleSheet from '../../apis/StyleSheet';
|
||||
import ViewPropTypes from './ViewPropTypes';
|
||||
import { Component, PropTypes } from 'react';
|
||||
|
||||
const eventHandlerNames = [
|
||||
'onClick',
|
||||
'onClickCapture',
|
||||
'onMoveShouldSetResponder',
|
||||
'onMoveShouldSetResponderCapture',
|
||||
'onResponderGrant',
|
||||
'onResponderMove',
|
||||
'onResponderReject',
|
||||
'onResponderRelease',
|
||||
'onResponderTerminate',
|
||||
'onResponderTerminationRequest',
|
||||
'onStartShouldSetResponder',
|
||||
'onStartShouldSetResponderCapture',
|
||||
'onTouchCancel',
|
||||
'onTouchCancelCapture',
|
||||
'onTouchEnd',
|
||||
'onTouchEndCapture',
|
||||
'onTouchMove',
|
||||
'onTouchMoveCapture',
|
||||
'onTouchStart',
|
||||
'onTouchStartCapture'
|
||||
];
|
||||
|
||||
const _normalizeEventForHandler = handler => e => {
|
||||
e.nativeEvent = normalizeNativeEvent(e.nativeEvent);
|
||||
return handler(e);
|
||||
};
|
||||
|
||||
const normalizeEventHandlers = props => {
|
||||
eventHandlerNames.forEach(handlerName => {
|
||||
const handler = props[handlerName];
|
||||
if (typeof handler === 'function') {
|
||||
props[handlerName] = _normalizeEventForHandler(handler);
|
||||
}
|
||||
});
|
||||
};
|
||||
const emptyObject = {};
|
||||
|
||||
class View extends Component {
|
||||
static displayName = 'View';
|
||||
@@ -63,9 +25,9 @@ class View extends Component {
|
||||
};
|
||||
|
||||
getChildContext() {
|
||||
return {
|
||||
isInAButtonView: this.props.accessibilityRole === 'button'
|
||||
};
|
||||
const isInAButtonView = this.props.accessibilityRole === 'button' ||
|
||||
this.context.isInAButtonView;
|
||||
return isInAButtonView ? { isInAButtonView } : emptyObject;
|
||||
}
|
||||
|
||||
render() {
|
||||
@@ -87,9 +49,6 @@ class View extends Component {
|
||||
|
||||
const component = this.context.isInAButtonView ? 'span' : 'div';
|
||||
|
||||
// DOM events need to be normalized to expect RN format
|
||||
normalizeEventHandlers(otherProps);
|
||||
|
||||
otherProps.style = [styles.initial, style, pointerEvents && pointerEventStyles[pointerEvents]];
|
||||
|
||||
return createDOMElement(component, otherProps);
|
||||
|
||||
@@ -5,24 +5,66 @@
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import emptyFunction from 'fbjs/lib/emptyFunction';
|
||||
import { canUseDOM } from 'fbjs/lib/ExecutionEnvironment';
|
||||
import debounce from 'debounce';
|
||||
|
||||
const emptyObject = {};
|
||||
const registry = {};
|
||||
|
||||
let id = 1;
|
||||
const guid = () => `r-${id++}`;
|
||||
|
||||
if (canUseDOM) {
|
||||
const triggerAll = () => {
|
||||
Object.keys(registry).forEach(key => {
|
||||
const instance = registry[key];
|
||||
instance._handleLayout();
|
||||
});
|
||||
};
|
||||
|
||||
window.addEventListener('resize', debounce(triggerAll, 16), false);
|
||||
}
|
||||
|
||||
const safeOverride = (original, next) => {
|
||||
if (original) {
|
||||
return function prototypeOverride() {
|
||||
original.call(this);
|
||||
next.call(this);
|
||||
};
|
||||
}
|
||||
return next;
|
||||
};
|
||||
|
||||
const applyLayout = Component => {
|
||||
const componentDidMount = Component.prototype.componentDidMount || emptyFunction;
|
||||
const componentDidUpdate = Component.prototype.componentDidUpdate || emptyFunction;
|
||||
const componentDidMount = Component.prototype.componentDidMount;
|
||||
const componentDidUpdate = Component.prototype.componentDidUpdate;
|
||||
const componentWillUnmount = Component.prototype.componentWillUnmount;
|
||||
|
||||
Component.prototype.componentDidMount = function() {
|
||||
componentDidMount.call(this);
|
||||
this._layoutState = emptyObject;
|
||||
this._handleLayout();
|
||||
};
|
||||
Component.prototype.componentDidMount = safeOverride(
|
||||
componentDidMount,
|
||||
function componentDidMount() {
|
||||
this._layoutState = emptyObject;
|
||||
this._isMounted = true;
|
||||
this._onLayoutId = guid();
|
||||
registry[this._onLayoutId] = this;
|
||||
this._handleLayout();
|
||||
}
|
||||
);
|
||||
|
||||
Component.prototype.componentDidUpdate = function() {
|
||||
componentDidUpdate.call(this);
|
||||
this._handleLayout();
|
||||
};
|
||||
Component.prototype.componentDidUpdate = safeOverride(
|
||||
componentDidUpdate,
|
||||
function componentDidUpdate() {
|
||||
this._handleLayout();
|
||||
}
|
||||
);
|
||||
|
||||
Component.prototype.componentWillUnmount = safeOverride(
|
||||
componentWillUnmount,
|
||||
function componentWillUnmount() {
|
||||
this._isMounted = false;
|
||||
delete registry[this._onLayoutId];
|
||||
}
|
||||
);
|
||||
|
||||
Component.prototype._handleLayout = function() {
|
||||
const layout = this._layoutState;
|
||||
@@ -30,13 +72,14 @@ const applyLayout = Component => {
|
||||
|
||||
if (onLayout) {
|
||||
this.measure((x, y, width, height) => {
|
||||
if (!this._isMounted) return;
|
||||
|
||||
if (
|
||||
layout.x !== x || layout.y !== y || layout.width !== width || layout.height !== height
|
||||
) {
|
||||
const nextLayout = { x, y, width, height };
|
||||
const nativeEvent = { layout: nextLayout };
|
||||
this._layoutState = { x, y, width, height };
|
||||
const nativeEvent = { layout: this._layoutState };
|
||||
onLayout({ nativeEvent, timeStamp: Date.now() });
|
||||
this._layoutState = nextLayout;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
import '../injectResponderEventPlugin';
|
||||
|
||||
import normalizeNativeEvent from '../normalizeNativeEvent';
|
||||
import React from 'react';
|
||||
import StyleRegistry from '../../apis/StyleSheet/registry';
|
||||
|
||||
@@ -19,23 +22,64 @@ const roleComponents = {
|
||||
region: 'section'
|
||||
};
|
||||
|
||||
const eventHandlerNames = {
|
||||
onClick: true,
|
||||
onClickCapture: true,
|
||||
onMoveShouldSetResponder: true,
|
||||
onMoveShouldSetResponderCapture: true,
|
||||
onResponderGrant: true,
|
||||
onResponderMove: true,
|
||||
onResponderReject: true,
|
||||
onResponderRelease: true,
|
||||
onResponderTerminate: true,
|
||||
onResponderTerminationRequest: true,
|
||||
onStartShouldSetResponder: true,
|
||||
onStartShouldSetResponderCapture: true,
|
||||
onTouchCancel: true,
|
||||
onTouchCancelCapture: true,
|
||||
onTouchEnd: true,
|
||||
onTouchEndCapture: true,
|
||||
onTouchMove: true,
|
||||
onTouchMoveCapture: true,
|
||||
onTouchStart: true,
|
||||
onTouchStartCapture: true
|
||||
};
|
||||
|
||||
const wrapEventHandler = handler => e => {
|
||||
e.nativeEvent = normalizeNativeEvent(e.nativeEvent);
|
||||
return handler(e);
|
||||
};
|
||||
|
||||
const createDOMElement = (component, rnProps) => {
|
||||
const {
|
||||
accessibilityLabel,
|
||||
accessibilityLiveRegion,
|
||||
accessibilityRole,
|
||||
accessible = true,
|
||||
style: rnStyle, // we need to remove the RN styles from 'domProps'
|
||||
style: rnStyle,
|
||||
testID,
|
||||
type,
|
||||
...domProps
|
||||
} = rnProps || emptyObject;
|
||||
|
||||
// use equivalent platform elements where possible
|
||||
const accessibilityComponent = accessibilityRole && roleComponents[accessibilityRole];
|
||||
const Component = accessibilityComponent || component;
|
||||
|
||||
// convert React Native styles to DOM styles
|
||||
const { className, style } = StyleRegistry.resolve(rnStyle) || emptyObject;
|
||||
|
||||
// normalize DOM events to match React Native events
|
||||
// TODO: move this out of the render path
|
||||
for (const prop in domProps) {
|
||||
if (Object.prototype.hasOwnProperty.call(domProps, prop)) {
|
||||
const isEventHandler = typeof prop === 'function' && eventHandlerNames[prop];
|
||||
if (isEventHandler) {
|
||||
domProps[prop] = wrapEventHandler(prop);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!accessible) {
|
||||
domProps['aria-hidden'] = true;
|
||||
}
|
||||
|
||||
@@ -303,7 +303,7 @@ arrify@^1.0.0, arrify@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d"
|
||||
|
||||
asap@^2.0.5, asap@~2.0.3:
|
||||
asap@~2.0.3:
|
||||
version "2.0.5"
|
||||
resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.5.tgz#522765b50c3510490e52d7dcfe085ef9ba96958f"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user