Compare commits

..

23 Commits

Author SHA1 Message Date
Nicolas Gallagher
4cc1c983e8 0.0.63 2017-01-02 23:44:10 -08:00
Nicolas Gallagher
37413fd55f Update Text snapshot 2017-01-02 23:43:39 -08:00
Nicolas Gallagher
07ff0ea104 Use setNativeProps to update ProgressBar 2017-01-02 23:28:14 -08:00
Nicolas Gallagher
1a87657500 [fix] Switch thumb positioning 2017-01-02 23:25:15 -08:00
Nicolas Gallagher
5e4c8e520a [fix] StyleSheet registry key check 2017-01-02 23:24:24 -08:00
Nicolas Gallagher
236121e32c Add unregistered styles benchmark 2017-01-02 22:46:38 -08:00
Nicolas Gallagher
39c76ca50c Minor StyleSheet/injector refactor; small fixes 2017-01-02 15:07:05 -08:00
Nicolas Gallagher
e65f91d849 [change] simplify CSS generation 2017-01-02 13:15:38 -08:00
Nicolas Gallagher
a535c558d8 [change] Move 'onResponderRelease' cancel to 'Touchable'
Moves a fix for double-firing Touchables into 'Touchable'
2017-01-02 13:12:13 -08:00
Nicolas Gallagher
a74be91b7c Minor documentation changes 2017-01-02 11:27:46 -08:00
Nicolas Gallagher
8eaaf28a32 0.0.62 2017-01-01 20:45:45 -08:00
Nicolas Gallagher
16d448dc5b Update various dependencies 2017-01-01 20:45:14 -08:00
Nicolas Gallagher
ea75cced13 [change] ProgressBar using CSS animations
Fix #299
2017-01-01 20:22:42 -08:00
Nicolas Gallagher
cfc56a1354 [change] ActivityIndicator using CSS animations
Ref #299
2017-01-01 19:48:50 -08:00
Nicolas Gallagher
b1cd92a65d [change] update Animated
Fix #309
2017-01-01 18:35:18 -08:00
Nicolas Gallagher
d87f71ebc1 [change] StyleSheet performance rewrite
Improves StyleSheet benchmark performance by 13x. Removes undocumented
`StyleSheet.resolve` API.

Typical mean (and first) task duration.

[benchmark] DeepTree: depth=3, breadth=10, wrap=4)
  -master  2809.76ms (3117.64ms)
  -patch     211.2ms  (364.28ms)

[benchmark] DeepTree: depth=5, breadth=3, wrap=1)
  -master   421.25ms (428.15ms)
  -patch     32.46ms  (47.36ms)

This patch adds memoization of DOM prop resolution (~3-4x faster), and
re-introduces a `className`-based styling strategy (~3-4x faster).
Styles map to "atomic css" rules.

Fix #307
2017-01-01 17:42:25 -08:00
Nicolas Gallagher
a2cafe56fc Add initial performance benchmarks
Simple render tree benchmarks originally developed by @lelandrichardson

Fix #306
2017-01-01 14:43:47 -08:00
Nicolas Gallagher
351c0ac3d4 Minor changes 2016-12-30 22:19:51 -08:00
Nicolas Gallagher
877c0d2818 Simplify StyleSheet's expandStyle 2016-12-30 22:14:39 -08:00
Nicolas Gallagher
3afc5d5de6 Rename style processors to resolvers 2016-12-29 19:17:12 -08:00
Nicolas Gallagher
edf3b9b7ff Move 'flattenStyle' into 'StyleSheet' 2016-12-29 16:31:14 -08:00
Nicolas Gallagher
518a85bf1b Rename 'createReactStyleObject' to 'createReactDOMStyle' 2016-12-29 16:26:31 -08:00
vaukalak
ba75acb66a [add] BackAndroid API stub 2016-12-27 18:14:31 +00:00
87 changed files with 3452 additions and 2862 deletions

View File

@@ -13,5 +13,6 @@ https://github.com/necolas/react-native-web/CONTRIBUTING.md
- [ ] includes documentation
- [ ] includes tests
- [ ] includes benchmark reports
- [ ] includes an interactive example
- [ ] includes screenshots/videos

1
.gitignore vendored
View File

@@ -1,3 +1,4 @@
/dist
/dist-examples
/dist-performance
/node_modules

View File

@@ -1,7 +1,5 @@
# Contributing
We are open to, and grateful for, any contributions made by the community.
## Reporting Issues and Asking Questions
Before opening an issue, please search the [issue
@@ -31,6 +29,12 @@ Run the examples:
npm run examples
```
Run the benchmarks in a browser by opening `./performance/index.html` after running:
```
npm run build:performance
```
### Building
```

View File

@@ -82,6 +82,7 @@ Exported modules:
* [`Vibration`](docs/apis/Vibration.md)
<span id="#why"></span>
## Why?
There are many different teams at Twitter building web applications with React.

View File

@@ -15,9 +15,9 @@ Each key of the object passed to `create` must define a style object.
Flattens an array of styles into a single style object.
**render**: function
**renderToString**: function
Returns a React `<style>` element for use in server-side rendering.
Returns a string of the stylesheet for use in server-side rendering.
## Properties

View File

@@ -65,6 +65,10 @@ AppRegistry.runApplication('App', {
})
```
Setting `process.env.__REACT_NATIVE_DEBUG_ENABLED__` to `true` will expose some
debugging logs. This can help track down when you're rendering without the
performance benefit of cached styles.
## Server-side rendering
Rendering using the `AppRegistry`:

View File

@@ -31,10 +31,9 @@ const styles = StyleSheet.create({
})
```
Using `StyleSheet.create` is optional but provides some key advantages: styles
are immutable in development, certain declarations are automatically converted
to CSS rather than applied as inline styles, and styles are only created once
for the application and not on every render.
Using `StyleSheet.create` is optional but provides the best performance
(`style` is resolved to CSS stylesheets). Avoid creating unregistered style
objects.
The attribute names and values are a subset of CSS. See the `style`
documentation of individual components.
@@ -56,12 +55,6 @@ A common pattern is to conditionally add style based on a condition:
styles.base,
this.state.active && styles.active
]} />
// or
<View style={{
...styles.base,
...(this.state.active && styles.active)
}} />
```
## Composing styles

View File

@@ -1,6 +1,8 @@
const path = require('path')
const webpack = require('webpack')
const DEV = process.env.NODE_ENV !== 'production';
module.exports = {
module: {
loaders: [
@@ -19,13 +21,9 @@ module.exports = {
},
plugins: [
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development')
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development'),
'process.env.__REACT_NATIVE_DEBUG_ENABLED__': DEV
}),
// https://github.com/animatedjs/animated/issues/40
new webpack.NormalModuleReplacementPlugin(
/es6-set/,
path.join(__dirname, '../../src/modules/polyfills/Set.js')
),
new webpack.optimize.OccurenceOrderPlugin()
],
resolve: {

View File

@@ -50,7 +50,8 @@ const ToggleAnimatingActivityIndicator = React.createClass({
return (
<ActivityIndicator
animating={this.state.animating}
style={[styles.centering, {height: 80}]}
style={styles.centering}
hidesWhenStopped={this.props.hidesWhenStopped}
size="large"
/>
);
@@ -121,7 +122,12 @@ const examples = [
{
title: 'Start/stop',
render() {
return <ToggleAnimatingActivityIndicator />;
return (
<View style={[styles.horizontal, styles.centering]}>
<ToggleAnimatingActivityIndicator />
<ToggleAnimatingActivityIndicator hidesWhenStopped={false} />
</View>
);
}
},
{
@@ -129,7 +135,7 @@ const examples = [
render() {
return (
<View style={[styles.horizontal, styles.centering]}>
<ActivityIndicator size="40" />
<ActivityIndicator size={40} />
<ActivityIndicator
style={{ marginLeft: 20, transform: [ {scale: 1.5} ] }}
size="large"

View File

@@ -307,11 +307,11 @@ var TouchableDisabled = React.createClass({
render: function() {
return (
<View>
<TouchableOpacity disabled={true} style={[styles.row, styles.block]}>
<TouchableOpacity disabled={true} style={[styles.row, styles.block]} onPress={action('TouchableOpacity')}>
<Text style={styles.disabledButton}>Disabled TouchableOpacity</Text>
</TouchableOpacity>
<TouchableOpacity disabled={false} style={[styles.row, styles.block]}>
<TouchableOpacity disabled={false} style={[styles.row, styles.block]} onPress={action('TouchableOpacity')}>
<Text style={styles.button}>Enabled TouchableOpacity</Text>
</TouchableOpacity>
@@ -321,7 +321,7 @@ var TouchableDisabled = React.createClass({
animationVelocity={0}
underlayColor="rgb(210, 230, 255)"
style={[styles.row, styles.block]}
onPress={() => console.log('custom THW text - highlight')}>
onPress={action('TouchableHighlight')}>
<Text style={styles.disabledButton}>
Disabled TouchableHighlight
</Text>
@@ -332,7 +332,7 @@ var TouchableDisabled = React.createClass({
animationVelocity={0}
underlayColor="rgb(210, 230, 255)"
style={[styles.row, styles.block]}
onPress={() => console.log('custom THW text - highlight')}>
onPress={action('TouchableHighlight')}>
<Text style={styles.button}>
Enabled TouchableHighlight
</Text>

View File

@@ -113,7 +113,7 @@ var Cell = React.createClass({
case 2:
return styles.cellTextO;
default:
return {};
return null;
}
},

View File

@@ -1,6 +1,6 @@
{
"name": "react-native-web",
"version": "0.0.61",
"version": "0.0.63",
"description": "React Native for Web",
"main": "dist/index.js",
"files": [
@@ -11,23 +11,25 @@
"scripts": {
"build": "del ./dist && mkdir dist && babel src -d dist --ignore **/__tests__",
"build:examples": "build-storybook -o dist-examples -c ./examples/.storybook",
"build:performance": "cd performance && webpack",
"build:umd": "webpack --config webpack.config.js --sort-assets-by --progress",
"deploy:examples": "git checkout gh-pages && rm -rf ./storybook && mv dist-examples storybook && git add -A && git commit -m \"Storybook deploy\" && git push origin gh-pages && git checkout -",
"examples": "start-storybook -p 9001 -c ./examples/.storybook --dont-track",
"lint": "eslint src",
"lint": "eslint performance src",
"prepublish": "npm run build && npm run build:umd",
"test": "npm run lint && npm run test:jest",
"test:jest": "jest",
"test:watch": "npm run test:jest -- --watch"
},
"dependencies": {
"animated": "^0.1.3",
"animated": "^0.1.5",
"array-find-index": "^1.0.2",
"babel-runtime": "^6.11.6",
"asap": "^2.0.5",
"babel-runtime": "^6.20.0",
"debounce": "^1.0.0",
"deep-assign": "^2.0.0",
"fbjs": "^0.8.4",
"inline-style-prefixer": "^2.0.1",
"fbjs": "^0.8.8",
"inline-style-prefixer": "^2.0.5",
"react-dom": "~15.4.1",
"react-textarea-autosize": "^4.0.4",
"react-timer-mixin": "^0.13.3"
@@ -35,12 +37,12 @@
"devDependencies": {
"@kadira/storybook": "^2.5.1",
"babel-cli": "^6.14.0",
"babel-core": "^6.14.0",
"babel-eslint": "^6.1.2",
"babel-loader": "^6.2.5",
"babel-core": "^6.21.0",
"babel-eslint": "^7.1.1",
"babel-loader": "^6.2.10",
"babel-plugin-transform-react-remove-prop-types": "^0.2.11",
"babel-preset-react-native": "^1.9.0",
"del-cli": "^0.2.0",
"babel-preset-react-native": "^1.9.1",
"del-cli": "^0.2.1",
"enzyme": "^2.4.1",
"eslint": "^3.4.0",
"eslint-plugin-jsx-a11y": "^2.2.0",
@@ -48,6 +50,7 @@
"eslint-plugin-react": "^6.1.2",
"file-loader": "^0.9.0",
"jest": "^16.0.2",
"marky": "^1.1.1",
"node-libs-browser": "^0.5.3",
"react": "~15.4.1",
"react-addons-test-utils": "~15.4.1",

65
performance/benchmark.js Normal file
View File

@@ -0,0 +1,65 @@
import * as marky from 'marky';
const fmt = (time) => `${Math.round(time * 100) / 100}ms`;
const measure = (name, fn) => {
marky.mark(name);
fn();
const performanceMeasure = marky.stop(name);
return performanceMeasure;
};
const benchmark = ({ name, description, setup, teardown, task, runs }) => {
return new Promise((resolve) => {
const performanceMeasures = [];
let i = 0;
setup();
const first = measure('first', task);
teardown();
const done = () => {
const mean = performanceMeasures.reduce((sum, performanceMeasure) => {
return sum + performanceMeasure.duration;
}, 0) / runs;
const firstDuration = fmt(first.duration);
const meanDuration = fmt(mean);
console.log(`First: ${firstDuration}`);
console.log(`Mean: ${meanDuration}`);
console.groupEnd();
resolve(mean);
};
const a = () => {
setup();
window.requestAnimationFrame(b);
};
const b = () => {
performanceMeasures.push(measure('mean', task));
window.requestAnimationFrame(c);
};
const c = () => {
teardown();
window.requestAnimationFrame(d);
};
const d = () => {
i += 1;
if (i < runs) {
window.requestAnimationFrame(a);
} else {
window.requestAnimationFrame(done);
}
};
console.group(`[benchmark] ${name}`);
console.log(description);
window.requestAnimationFrame(a);
});
};
module.exports = benchmark;

View File

@@ -0,0 +1,88 @@
import React, { Component, PropTypes } from 'react';
const createDeepTree = ({ StyleSheet, View }, options = {}) => {
class DeepTree extends Component {
static propTypes = {
breadth: PropTypes.number.isRequired,
depth: PropTypes.number.isRequired,
id: PropTypes.number.isRequired,
wrap: PropTypes.number.isRequired
};
render() {
const { breadth, depth, id, wrap } = this.props;
let result = (
<View
style={[
styles.outer,
depth % 2 === 0 ? styles.even : styles.odd,
styles[`custom${id % 3}`]
]}
>
{depth === 0 && (
<View
style={[
styles.terminal,
styles[`terminal${id % 3}`]
]}
/>
)}
{depth !== 0 && Array.from({ length: breadth }).map((el, i) => (
<DeepTree
breadth={breadth}
depth={depth - 1}
id={i}
key={i}
wrap={wrap}
/>
))}
</View>
);
for (let i = 0; i < wrap; i++) {
result = <View>{result}</View>;
}
return result;
}
}
const stylesObject = {
outer: {
padding: 4
},
odd: {
flexDirection: 'row'
},
even: {
flexDirection: 'column'
},
custom0: {
backgroundColor: '#222'
},
custom1: {
backgroundColor: '#666'
},
custom2: {
backgroundColor: '#999'
},
terminal: {
width: 20,
height: 20
},
terminal0: {
backgroundColor: 'blue'
},
terminal1: {
backgroundColor: 'orange'
},
terminal2: {
backgroundColor: 'red'
}
};
const styles = options.registerStyles ? StyleSheet.create(stylesObject) : stylesObject;
return DeepTree;
};
module.exports = createDeepTree;

View File

@@ -0,0 +1,24 @@
import benchmark from '../../benchmark';
import createDeepTree from './createDeepTree';
import React from 'react';
import ReactDOM from 'react-dom';
import ReactNative from 'react-native';
const deepTreeBenchmark = ({ breadth, depth, registerStyles = true, runs, wrap }, node) => () => {
// React Native for Web implementation of the tree
const DeepTree = createDeepTree(ReactNative, { registerStyles });
const setup = () => {};
const teardown = () => ReactDOM.unmountComponentAtNode(node);
return benchmark({
name: `DeepTree (${registerStyles ? 'registered' : 'unregistered'}) styles)`,
description: `depth=${depth}, breadth=${breadth}, wrap=${wrap}`,
runs,
setup,
teardown,
task: () => ReactDOM.render(<DeepTree breadth={breadth} depth={depth} id={0} wrap={wrap} />, node)
});
};
module.exports = deepTreeBenchmark;

11
performance/index.html Normal file
View File

@@ -0,0 +1,11 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div class="root"></div>
<script src="../dist-performance/performance.bundle.js"></script>
</body>
</html>

16
performance/index.js Normal file
View File

@@ -0,0 +1,16 @@
import createDeepTree from './benchmarks/deepTree/createDeepTree';
import deepTree from './benchmarks/deepTree';
import React from 'react';
import ReactDOM from 'react-dom';
import ReactNative from 'react-native';
const node = document.querySelector('.root');
const DeepTree = createDeepTree(ReactNative);
Promise.resolve()
.then(deepTree({ wrap: 4, depth: 3, breadth: 10, runs: 10, registerStyles: false }, node))
.then(deepTree({ wrap: 1, depth: 5, breadth: 3, runs: 20, registerStyles: false }, node))
.then(deepTree({ wrap: 4, depth: 3, breadth: 10, runs: 10 }, node))
.then(deepTree({ wrap: 1, depth: 5, breadth: 3, runs: 20 }, node))
.then(() => ReactDOM.render(<DeepTree breadth={3} depth={5} id={0} wrap={1} />, node));

View File

@@ -0,0 +1,45 @@
const path = require('path');
const webpack = require('webpack');
// const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
module.exports = {
entry: {
performance: './index'
},
output: {
path: path.resolve(__dirname, '../dist-performance'),
filename: 'performance.bundle.js'
},
module: {
loaders: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
query: { cacheDirectory: true }
}
]
},
plugins: [
new webpack.DefinePlugin({ 'process.env.NODE_ENV': JSON.stringify('production') }),
new webpack.optimize.DedupePlugin(),
// https://github.com/animatedjs/animated/issues/40
new webpack.NormalModuleReplacementPlugin(
/es6-set/,
path.join(__dirname, '../src/modules/polyfills/Set.js')
),
new webpack.optimize.OccurenceOrderPlugin(),
new webpack.optimize.UglifyJsPlugin({
compress: {
dead_code: true,
screw_ie8: true,
warnings: true
}
})
],
resolve: {
alias: {
'react-native': path.join(__dirname, '../src')
}
}
};

View File

@@ -0,0 +1,48 @@
exports[`apis/AppRegistry/renderApplication getApplication 1`] = `
"<style id=\"react-native-stylesheet\">
/* React Native StyleSheet*/
html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:rgba(0,0,0,0)}
body{margin:0}
button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}
input::-webkit-inner-spin-button,input::-webkit-outer-spin-button,input::-webkit-search-cancel-button,input::-webkit-search-decoration,input::-webkit-search-results-button,input::-webkit-search-results-decoration{display:none}
@keyframes rn-ActivityIndicator-animation{0%{-webkit-transform: rotate(0deg); transform: rotate(0deg);}100%{-webkit-transform: rotate(360deg); transform: rotate(360deg);}}
@keyframes rn-ProgressBar-animation{0%{-webkit-transform: translateX(-100%); transform: translateX(-100%);}100%{-webkit-transform: translateX(400%); transform: translateX(400%);}}
.rn-pointerEvents\\:auto,.rn_pointerEvents\\:box-only,.rn-pointerEvents\\:box-none *{pointer-events:auto}.rn-pointerEvents\\:none,.rn_pointerEvents\\:box-only *,.rn-pointerEvents\\:box-none{pointer-events:none}
.rn-bottom\\:0px{bottom:0px}
.rn-left\\:0px{left:0px}
.rn-position\\:absolute{position:absolute}
.rn-right\\:0px{right:0px}
.rn-top\\:0px{top:0px}
.rn-alignItems\\:stretch{-ms-flex-align:stretch;-webkit-align-items:stretch;-webkit-box-align:stretch;align-items:stretch}
.rn-backgroundColor\\:transparent{background-color:transparent}
.rn-borderTopStyle\\:solid{border-top-style:solid}
.rn-borderRightStyle\\:solid{border-right-style:solid}
.rn-borderBottomStyle\\:solid{border-bottom-style:solid}
.rn-borderLeftStyle\\:solid{border-left-style:solid}
.rn-borderTopWidth\\:0px{border-top-width:0px}
.rn-borderRightWidth\\:0px{border-right-width:0px}
.rn-borderBottomWidth\\:0px{border-bottom-width:0px}
.rn-borderLeftWidth\\:0px{border-left-width:0px}
.rn-boxSizing\\:border-box{-moz-box-sizing:border-box;box-sizing:border-box}
.rn-color\\:inherit{color:inherit}
.rn-display\\:flex{display:-webkit-box;display:-moz-box;display:-ms-flexbox;display:-webkit-flex;display:flex}
.rn-flexBasis\\:auto{-ms-preferred-size:auto;-webkit-flex-basis:auto;flex-basis:auto}
.rn-flexDirection\\:column{-ms-flex-direction:column;-webkit-box-direction:normal;-webkit-box-orient:vertical;-webkit-flex-direction:column;flex-direction:column}
.rn-font\\:inherit{font:inherit}
.rn-listStyle\\:none{list-style:none}
.rn-marginTop\\:0px{margin-top:0px}
.rn-marginRight\\:0px{margin-right:0px}
.rn-marginBottom\\:0px{margin-bottom:0px}
.rn-marginLeft\\:0px{margin-left:0px}
.rn-minHeight\\:0px{min-height:0px}
.rn-minWidth\\:0px{min-width:0px}
.rn-paddingTop\\:0px{padding-top:0px}
.rn-paddingRight\\:0px{padding-right:0px}
.rn-paddingBottom\\:0px{padding-bottom:0px}
.rn-paddingLeft\\:0px{padding-left:0px}
.rn-position\\:relative{position:relative}
.rn-textAlign\\:inherit{text-align:inherit}
.rn-textDecoration\\:none{text-decoration:none}
.rn-flexShrink\\:0{-ms-flex-negative:0px;-webkit-flex-shrink:0px;flex-shrink:0}
</style>"
`;

View File

@@ -10,6 +10,6 @@ describe('apis/AppRegistry/renderApplication', () => {
const { element, stylesheet } = getApplication(component, {});
expect(element).toBeTruthy();
expect(stylesheet.type).toEqual('style');
expect(stylesheet).toMatchSnapshot();
});
});

View File

@@ -32,6 +32,6 @@ export function getApplication(RootComponent: Component, initialProps: Object):
rootComponent={RootComponent}
/>
);
const stylesheet = StyleSheet.render();
const stylesheet = StyleSheet.renderToString();
return { element, stylesheet };
}

View File

@@ -0,0 +1,28 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* web stub for BackAndroid.android.js
*
* @providesModule BackAndroid
*/
'use strict';
function emptyFunction() {}
const BackAndroid = {
exitApp: emptyFunction,
addEventListener() {
return {
remove: emptyFunction
};
},
removeEventListener: emptyFunction
};
module.exports = BackAndroid;

View File

@@ -0,0 +1,15 @@
exports[`apis/StyleSheet/createReactDOMStyle converts ReactNative style to ReactDOM style 1`] = `
Object {
"borderBottomWidth": "1px",
"borderLeftWidth": "1px",
"borderRightWidth": "1px",
"borderTopWidth": "1px",
"borderWidthLeft": "2px",
"borderWidthRight": "3px",
"boxShadow": "1px 1px 1px 1px #000, 1px 2px 0px rgba(255,0,0,1)",
"display": "flex",
"marginBottom": "0px",
"marginTop": "0px",
"opacity": 0,
}
`;

View File

@@ -0,0 +1,26 @@
exports[`apis/StyleSheet/flattenStyle should merge style objects 1`] = `
Object {
"opacity": 1,
"order": 2,
}
`;
exports[`apis/StyleSheet/flattenStyle should override style properties 1`] = `
Object {
"backgroundColor": "#023c69",
"order": null,
}
`;
exports[`apis/StyleSheet/flattenStyle should overwrite properties with \`undefined\` 1`] = `
Object {
"backgroundColor": undefined,
}
`;
exports[`apis/StyleSheet/flattenStyle should recursively flatten arrays 1`] = `
Object {
"opacity": 1,
"order": 3,
}
`;

View File

@@ -0,0 +1 @@
exports[`apis/StyleSheet/generateCss generates correct css 1`] = `"-webkit-transition-duration:0.1s;border-width-left:2px;border-width-right:3px;box-shadow:1px 1px 1px 1px #000;position:absolute;transition-duration:0.1s"`;

View File

@@ -1,10 +1,14 @@
exports[`apis/StyleSheet resolve 1`] = `
Object {
"className": "test __style_df __style_pebn",
"style": Object {
"display": null,
"opacity": 1,
"pointerEvents": null,
},
}
exports[`apis/StyleSheet renderToString 1`] = `
"<style id=\"react-native-stylesheet\">
.rn-borderTopColor\\:red{border-top-color:red}
.rn-borderRightColor\\:red{border-right-color:red}
.rn-borderBottomColor\\:red{border-bottom-color:red}
.rn-borderLeftColor\\:red{border-left-color:red}
.rn-borderTopWidth\\:0px{border-top-width:0px}
.rn-borderRightWidth\\:0px{border-right-width:0px}
.rn-borderBottomWidth\\:0px{border-bottom-width:0px}
.rn-borderLeftWidth\\:0px{border-left-width:0px}
.rn-left\\:50px{left:50px}
.rn-position\\:absolute{position:absolute}
</style>"
`;

View File

@@ -0,0 +1,179 @@
exports[`apis/StyleSheet/registry resolve with register, resolves to className 1`] = `
Object {
"className": "
rn-borderTopColor:red
rn-borderRightColor:red
rn-borderBottomColor:red
rn-borderLeftColor:red
rn-borderTopWidth:0px
rn-borderRightWidth:0px
rn-borderBottomWidth:0px
rn-borderLeftWidth:0px
rn-left:50px
rn-pointerEvents:box-only
rn-position:absolute
rn-width:100px",
"style": Object {},
}
`;
exports[`apis/StyleSheet/registry resolve with register, resolves to className 2`] = `
Object {
"className": "
rn-borderTopColor:red
rn-borderRightColor:red
rn-borderBottomColor:red
rn-borderLeftColor:red
rn-borderTopWidth:0px
rn-borderRightWidth:0px
rn-borderBottomWidth:0px
rn-borderLeftWidth:0px
rn-left:50px
rn-pointerEvents:box-only
rn-position:absolute
rn-width:200px",
"style": Object {},
}
`;
exports[`apis/StyleSheet/registry resolve with register, resolves to className 3`] = `
Object {
"className": "
rn-borderTopColor:red
rn-borderRightColor:red
rn-borderBottomColor:red
rn-borderLeftColor:red
rn-borderTopWidth:0px
rn-borderRightWidth:0px
rn-borderBottomWidth:0px
rn-borderLeftWidth:0px
rn-left:50px
rn-pointerEvents:box-only
rn-position:absolute
rn-width:100px",
"style": Object {},
}
`;
exports[`apis/StyleSheet/registry resolve with register, resolves to mixed 1`] = `
Object {
"className": "
rn-left:50px
rn-pointerEvents:box-only
rn-position:absolute",
"style": Object {
"borderBottomColor": "red",
"borderBottomWidth": "0px",
"borderLeftColor": "red",
"borderLeftWidth": "0px",
"borderRightColor": "red",
"borderRightWidth": "0px",
"borderTopColor": "red",
"borderTopWidth": "0px",
"width": "100px",
},
}
`;
exports[`apis/StyleSheet/registry resolve with register, resolves to mixed 2`] = `
Object {
"className": "
rn-left:50px
rn-pointerEvents:box-only
rn-position:absolute
rn-width:200px",
"style": Object {
"borderBottomColor": "red",
"borderBottomWidth": "0px",
"borderLeftColor": "red",
"borderLeftWidth": "0px",
"borderRightColor": "red",
"borderRightWidth": "0px",
"borderTopColor": "red",
"borderTopWidth": "0px",
},
}
`;
exports[`apis/StyleSheet/registry resolve with register, resolves to mixed 3`] = `
Object {
"className": "
rn-left:50px
rn-pointerEvents:box-only
rn-position:absolute",
"style": Object {
"borderBottomColor": "red",
"borderBottomWidth": "0px",
"borderLeftColor": "red",
"borderLeftWidth": "0px",
"borderRightColor": "red",
"borderRightWidth": "0px",
"borderTopColor": "red",
"borderTopWidth": "0px",
"width": "100px",
},
}
`;
exports[`apis/StyleSheet/registry resolve without register, resolves to inline styles 1`] = `
Object {
"className": "
",
"style": Object {
"borderBottomColor": "red",
"borderBottomWidth": "0px",
"borderLeftColor": "red",
"borderLeftWidth": "0px",
"borderRightColor": "red",
"borderRightWidth": "0px",
"borderTopColor": "red",
"borderTopWidth": "0px",
"left": "50px",
"pointerEvents": "box-only",
"position": "absolute",
"width": "100px",
},
}
`;
exports[`apis/StyleSheet/registry resolve without register, resolves to inline styles 2`] = `
Object {
"className": "
",
"style": Object {
"borderBottomColor": "red",
"borderBottomWidth": "0px",
"borderLeftColor": "red",
"borderLeftWidth": "0px",
"borderRightColor": "red",
"borderRightWidth": "0px",
"borderTopColor": "red",
"borderTopWidth": "0px",
"left": "50px",
"pointerEvents": "box-only",
"position": "absolute",
"width": "200px",
},
}
`;
exports[`apis/StyleSheet/registry resolve without register, resolves to inline styles 3`] = `
Object {
"className": "
",
"style": Object {
"borderBottomColor": "red",
"borderBottomWidth": "0px",
"borderLeftColor": "red",
"borderLeftWidth": "0px",
"borderRightColor": "red",
"borderRightWidth": "0px",
"borderTopColor": "red",
"borderTopWidth": "0px",
"left": "50px",
"pointerEvents": "box-only",
"position": "absolute",
"width": "100px",
},
}
`;

View File

@@ -0,0 +1,28 @@
/* eslint-env jasmine, jest */
import createReactDOMStyle from '../createReactDOMStyle';
const reactNativeStyle = {
boxShadow: '1px 1px 1px 1px #000',
borderWidthLeft: 2,
borderWidth: 1,
borderWidthRight: 3,
display: 'flex',
marginVertical: 0,
opacity: 0,
shadowColor: 'red',
shadowOffset: { width: 1, height: 2 },
resizeMode: 'contain'
};
describe('apis/StyleSheet/createReactDOMStyle', () => {
test('converts ReactNative style to ReactDOM style', () => {
expect(createReactDOMStyle(reactNativeStyle)).toMatchSnapshot();
});
test('noop on DOM styles', () => {
const firstStyle = createReactDOMStyle(reactNativeStyle);
const secondStyle = createReactDOMStyle(firstStyle);
expect(firstStyle).toEqual(secondStyle);
});
});

View File

@@ -1,12 +0,0 @@
/* eslint-env jasmine, jest */
import createReactStyleObject from '../createReactStyleObject';
describe('apis/StyleSheet/createReactStyleObject', () => {
test('converts ReactNative style to ReactDOM style', () => {
const reactNativeStyle = { display: 'flex', marginVertical: 0, opacity: 0 };
const expectedStyle = { display: 'flex', marginTop: '0px', marginBottom: '0px', opacity: 0 };
expect(createReactStyleObject(reactNativeStyle)).toEqual(expectedStyle);
});
});

View File

@@ -9,9 +9,9 @@
* of patent rights can be found in the PATENTS file in the same directory.
*/
import flattenStyle from '..';
import flattenStyle from '../flattenStyle';
describe('modules/flattenStyle', () => {
describe('apis/StyleSheet/flattenStyle', () => {
test('should merge style objects', () => {
const style = flattenStyle([
{ opacity: 1 },

View File

@@ -0,0 +1,16 @@
/* eslint-env jasmine, jest */
import generateCss from '../generateCss';
describe('apis/StyleSheet/generateCss', () => {
test('generates correct css', () => {
const style = {
boxShadow: '1px 1px 1px 1px #000',
borderWidthLeft: 2,
borderWidthRight: 3,
position: 'absolute',
transitionDuration: '0.1s'
};
expect(generateCss(style)).toMatchSnapshot();
});
});

View File

@@ -1,7 +1,7 @@
/* eslint-env jasmine, jest */
import { getDefaultStyleSheet } from '../css';
import StyleSheet from '..';
import StyleRegistry from '../registry';
const isPlainObject = (x) => {
const toString = Object.prototype.toString;
@@ -16,7 +16,7 @@ const isPlainObject = (x) => {
describe('apis/StyleSheet', () => {
beforeEach(() => {
StyleSheet._reset();
StyleRegistry.reset();
});
test('absoluteFill', () => {
@@ -32,11 +32,6 @@ describe('apis/StyleSheet', () => {
const style = StyleSheet.create({ root: { opacity: 1 } });
expect(Number.isInteger(style.root) === true).toBeTruthy();
});
test('renders a style sheet in the browser', () => {
StyleSheet.create({ root: { color: 'red' } });
expect(document.getElementById('react-native-style__').textContent).toEqual(getDefaultStyleSheet());
});
});
test('flatten', () => {
@@ -47,18 +42,17 @@ describe('apis/StyleSheet', () => {
expect(Number.isInteger(StyleSheet.hairlineWidth) === true).toBeTruthy();
});
test('render', () => {
expect(StyleSheet.render().props.dangerouslySetInnerHTML.__html).toEqual(getDefaultStyleSheet());
});
test('resolve', () => {
expect(StyleSheet.resolve({
className: 'test',
style: {
display: 'flex',
opacity: 1,
pointerEvents: 'box-none'
test('renderToString', () => {
StyleSheet.create({
a: {
borderWidth: 0,
borderColor: 'red'
},
b: {
position: 'absolute',
left: 50
}
})).toMatchSnapshot();
});
expect(StyleSheet.renderToString()).toMatchSnapshot();
});
});

View File

@@ -0,0 +1,22 @@
/* eslint-env jasmine, jest */
import injector from '../injector';
describe('apis/StyleSheet/injector', () => {
beforeEach(() => {
document.head.insertAdjacentHTML('afterbegin', `
<style id="react-native-stylesheet">
.rn-alignItems\\:stretch{align-items:stretch;}
.rn-position\\:top{position:top;}
</style>
`);
});
test('hydrates from SSR', () => {
const classList = injector.getClassNames();
expect(classList).toEqual({
'rn-alignItems\\:stretch': true,
'rn-position\\:top': true
});
});
});

View File

@@ -0,0 +1,13 @@
/* eslint-env jasmine, jest */
import prefixInlineStyles from '../prefixInlineStyles';
describe('apis/StyleSheet/prefixInlineStyles', () => {
test('handles array values', () => {
const style = {
display: [ '-webkit-flex', 'flex' ]
};
expect(prefixInlineStyles(style)).toEqual({ display: 'flex' });
});
});

View File

@@ -1,47 +0,0 @@
/* eslint-env jasmine, jest */
import processBoxShadow from '../processBoxShadow';
describe('apis/StyleSheet/processBoxShadow', () => {
test('missing shadowColor', () => {
const style = {
shadowOffset: { width: 1, height: 2 }
};
expect(processBoxShadow(style)).toEqual({});
});
test('shadowColor only', () => {
const style = {
shadowColor: 'red'
};
expect(processBoxShadow(style)).toEqual({
boxShadow: '0px 0px 0px rgba(255,0,0,1)'
});
});
test('shadowColor and shadowOpacity only', () => {
const style = {
shadowColor: 'red',
shadowOpacity: 0.5
};
expect(processBoxShadow(style)).toEqual({
boxShadow: '0px 0px 0px rgba(255,0,0,0.5)'
});
});
test('shadowOffset, shadowRadius, shadowSpread', () => {
const style = {
shadowColor: 'rgba(50,60,70,0.5)',
shadowOffset: { width: 1, height: 2 },
shadowOpacity: 0.5,
shadowRadius: 3
};
expect(processBoxShadow(style)).toEqual({
boxShadow: '2px 1px 3px rgba(50,60,70,0.25)'
});
});
});

View File

@@ -1,20 +0,0 @@
/* eslint-env jasmine, jest */
import processTextShadow from '../processTextShadow';
describe('apis/StyleSheet/processTextShadow', () => {
test('textShadowOffset', () => {
const style = {
textShadowColor: 'red',
textShadowOffset: { width: 2, height: 2 },
textShadowRadius: 5
};
expect(processTextShadow(style)).toEqual({
textShadow: '2px 2px 5px red',
textShadowColor: null,
textShadowOffset: null,
textShadowRadius: null
});
});
});

View File

@@ -1,28 +0,0 @@
/* eslint-env jasmine, jest */
import processTransform from '../processTransform';
describe('apis/StyleSheet/processTransform', () => {
test('transform', () => {
const style = {
transform: [
{ scaleX: 20 },
{ translateX: 20 },
{ rotate: '20deg' }
]
};
expect(processTransform(style)).toEqual({ transform: 'scaleX(20) translateX(20px) rotate(20deg)' });
});
test('transformMatrix', () => {
const style = {
transformMatrix: [ 1, 2, 3, 4, 5, 6 ]
};
expect(processTransform(style)).toEqual({
transform: 'matrix3d(1,2,3,4,5,6)',
transformMatrix: null
});
});
});

View File

@@ -1,13 +0,0 @@
/* eslint-env jasmine, jest */
import processVendorPrefixes from '../processVendorPrefixes';
describe('apis/StyleSheet/processVendorPrefixes', () => {
test('handles array values', () => {
const style = {
display: [ '-webkit-flex', 'flex' ]
};
expect(processVendorPrefixes(style)).toEqual({ display: 'flex' });
});
});

View File

@@ -0,0 +1,54 @@
/* eslint-env jasmine, jest */
import StyleRegistry from '../registry';
describe('apis/StyleSheet/registry', () => {
beforeEach(() => {
StyleRegistry.reset();
});
test('register', () => {
const style = { opacity: 0 };
const id = StyleRegistry.register(style);
expect(typeof id === 'number').toBe(true);
});
describe('resolve', () => {
const styleA = { borderWidth: 0, borderColor: 'red', width: 100 };
const styleB = { position: 'absolute', left: 50, pointerEvents: 'box-only' };
const styleC = { width: 200 };
const testResolve = (a, b, c) => {
// no common properties, different resolving order, same result
const resolve1 = StyleRegistry.resolve([ a, b ]);
expect(resolve1).toMatchSnapshot();
const resolve2 = StyleRegistry.resolve([ b, a ]);
expect(resolve1).toEqual(resolve2);
// common properties, different resolving order, different result
const resolve3 = StyleRegistry.resolve([ a, b, c ]);
expect(resolve3).toMatchSnapshot();
const resolve4 = StyleRegistry.resolve([ c, a, b ]);
expect(resolve4).toMatchSnapshot();
expect(resolve3).not.toEqual(resolve4);
};
test('with register, resolves to className', () => {
const a = StyleRegistry.register(styleA);
const b = StyleRegistry.register(styleB);
const c = StyleRegistry.register(styleC);
testResolve(a, b, c);
});
test('with register, resolves to mixed', () => {
const a = styleA;
const b = StyleRegistry.register(styleB);
const c = StyleRegistry.register(styleC);
testResolve(a, b, c);
});
test('without register, resolves to inline styles', () => {
testResolve(styleA, styleB, styleC);
});
});
});

View File

@@ -0,0 +1,60 @@
/* eslint-env jasmine, jest */
import resolveBoxShadow from '../resolveBoxShadow';
describe('apis/StyleSheet/resolveBoxShadow', () => {
test('shadowColor only', () => {
const resolvedStyle = {};
const style = { shadowColor: 'red' };
resolveBoxShadow(resolvedStyle, style);
expect(resolvedStyle).toEqual({
boxShadow: '0px 0px 0px rgba(255,0,0,1)'
});
});
test('shadowColor and shadowOpacity only', () => {
const resolvedStyle = {};
const style = { shadowColor: 'red', shadowOpacity: 0.5 };
resolveBoxShadow(resolvedStyle, style);
expect(resolvedStyle).toEqual({
boxShadow: '0px 0px 0px rgba(255,0,0,0.5)'
});
});
test('shadowOffset only', () => {
const resolvedStyle = {};
const style = { shadowOffset: { width: 1, height: 2 } };
resolveBoxShadow(resolvedStyle, style);
expect(resolvedStyle).toEqual({
boxShadow: '1px 2px 0px rgba(0,0,0,0)'
});
});
test('shadowRadius only', () => {
const resolvedStyle = {};
const style = { shadowRadius: 5 };
resolveBoxShadow(resolvedStyle, style);
expect(resolvedStyle).toEqual({
boxShadow: '0px 0px 5px rgba(0,0,0,0)'
});
});
test('shadowOffset, shadowRadius, shadowColor', () => {
const resolvedStyle = {};
const style = {
shadowColor: 'rgba(50,60,70,0.5)',
shadowOffset: { width: 1, height: 2 },
shadowOpacity: 0.5,
shadowRadius: 3
};
resolveBoxShadow(resolvedStyle, style);
expect(resolvedStyle).toEqual({
boxShadow: '1px 2px 3px rgba(50,60,70,0.25)'
});
});
});

View File

@@ -0,0 +1,19 @@
/* eslint-env jasmine, jest */
import resolveTextShadow from '../resolveTextShadow';
describe('apis/StyleSheet/resolveTextShadow', () => {
test('textShadowOffset', () => {
const resolvedStyle = {};
const style = {
textShadowColor: 'red',
textShadowOffset: { width: 1, height: 2 },
textShadowRadius: 5
};
resolveTextShadow(resolvedStyle, style);
expect(resolvedStyle).toEqual({
textShadow: '1px 2px 5px red'
});
});
});

View File

@@ -0,0 +1,31 @@
/* eslint-env jasmine, jest */
import resolveTransform from '../resolveTransform';
describe('apis/StyleSheet/resolveTransform', () => {
test('transform', () => {
const resolvedStyle = {};
const style = {
transform: [
{ scaleX: 20 },
{ translateX: 20 },
{ rotate: '20deg' }
]
};
resolveTransform(resolvedStyle, style);
expect(resolvedStyle).toEqual({
transform: 'scaleX(20) translateX(20px) rotate(20deg)'
});
});
test('transformMatrix', () => {
const resolvedStyle = {};
const style = { transformMatrix: [ 1, 2, 3, 4, 5, 6 ] };
resolveTransform(resolvedStyle, style);
expect(resolvedStyle).toEqual({
transform: 'matrix3d(1,2,3,4,5,6)'
});
});
});

View File

@@ -0,0 +1,6 @@
import expandStyle from './expandStyle';
import i18nStyle from './i18nStyle';
const createReactDOMStyle = (flattenedReactNativeStyle) => expandStyle(i18nStyle(flattenedReactNativeStyle));
module.exports = createReactDOMStyle;

View File

@@ -1,22 +0,0 @@
import expandStyle from './expandStyle';
import flattenStyle from '../../modules/flattenStyle';
import i18nStyle from './i18nStyle';
import processBoxShadow from './processBoxShadow';
import processTextShadow from './processTextShadow';
import processTransform from './processTransform';
import processVendorPrefixes from './processVendorPrefixes';
const processors = [
processBoxShadow,
processTextShadow,
processTransform,
processVendorPrefixes
];
const applyProcessors = (style) => processors.reduce((style, processor) => processor(style), style);
const createReactDOMStyleObject = (reactNativeStyle) => applyProcessors(
expandStyle(i18nStyle(flattenStyle(reactNativeStyle)))
);
module.exports = createReactDOMStyleObject;

View File

@@ -1,42 +0,0 @@
const DISPLAY_FLEX_CLASSNAME = '__style_df';
const POINTER_EVENTS_AUTO_CLASSNAME = '__style_pea';
const POINTER_EVENTS_BOX_NONE_CLASSNAME = '__style_pebn';
const POINTER_EVENTS_BOX_ONLY_CLASSNAME = '__style_pebo';
const POINTER_EVENTS_NONE_CLASSNAME = '__style_pen';
/* eslint-disable max-len */
const CSS_RESET =
// reset unwanted styles
'/* React Native */\n' +
'html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:rgba(0,0,0,0)}\n' +
'body{margin:0}\n' +
'button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}\n' +
'input::-webkit-inner-spin-button,input::-webkit-outer-spin-button,' +
'input::-webkit-search-cancel-button,input::-webkit-search-decoration,' +
'input::-webkit-search-results-button,input::-webkit-search-results-decoration{display:none}';
const CSS_HELPERS =
// vendor prefix 'display:flex' until React supports fallback values for inline styles
`.${DISPLAY_FLEX_CLASSNAME} {display:-webkit-box;display:-moz-box;display:-ms-flexbox;display:-webkit-flex;display:flex}\n` +
// implement React Native's pointer event values
`.${POINTER_EVENTS_AUTO_CLASSNAME}, .${POINTER_EVENTS_BOX_ONLY_CLASSNAME}, .${POINTER_EVENTS_BOX_NONE_CLASSNAME} * {pointer-events:auto}\n` +
`.${POINTER_EVENTS_NONE_CLASSNAME}, .${POINTER_EVENTS_BOX_ONLY_CLASSNAME} *, .${POINTER_EVENTS_NONE_CLASSNAME} {pointer-events:none}`;
/* eslint-enable max-len */
const styleAsClassName = {
display: {
'flex': DISPLAY_FLEX_CLASSNAME
},
pointerEvents: {
'auto': POINTER_EVENTS_AUTO_CLASSNAME,
'box-none': POINTER_EVENTS_BOX_NONE_CLASSNAME,
'box-only': POINTER_EVENTS_BOX_ONLY_CLASSNAME,
'none': POINTER_EVENTS_NONE_CLASSNAME
}
};
export const getDefaultStyleSheet = () => `${CSS_RESET}\n${CSS_HELPERS}`;
export const getStyleAsHelperClassName = (prop, value) => {
return styleAsClassName[prop] && styleAsClassName[prop][value];
};

View File

@@ -10,6 +10,9 @@
*/
import normalizeValue from './normalizeValue';
import resolveBoxShadow from './resolveBoxShadow';
import resolveTextShadow from './resolveTextShadow';
import resolveTransform from './resolveTransform';
const emptyObject = {};
const styleShortFormProperties = {
@@ -28,46 +31,83 @@ const styleShortFormProperties = {
writingDirection: [ 'direction' ]
};
const alphaSort = (arr) => arr.sort((a, b) => {
const alphaSortProps = (propsArray) => propsArray.sort((a, b) => {
if (a < b) { return -1; }
if (a > b) { return 1; }
return 0;
});
const createStyleReducer = (originalStyle) => {
const originalStyleProps = Object.keys(originalStyle);
const expandStyle = (style) => {
if (!style) { return emptyObject; }
const styleProps = Object.keys(style);
const sortedStyleProps = alphaSortProps(styleProps);
let hasResolvedBoxShadow = false;
let hasResolvedTextShadow = false;
return (style, prop) => {
const value = normalizeValue(prop, originalStyle[prop]);
const longFormProperties = styleShortFormProperties[prop];
const reducer = (resolvedStyle, prop) => {
const value = normalizeValue(prop, style[prop]);
if (value == null) { return resolvedStyle; }
// React Native treats `flex:1` like `flex:1 1 auto`
if (prop === 'flex') {
style.flexGrow = value;
style.flexShrink = 1;
style.flexBasis = 'auto';
// React Native accepts 'center' as a value
} else if (prop === 'textAlignVertical') {
style.verticalAlign = (value === 'center' ? 'middle' : value);
} else if (longFormProperties) {
longFormProperties.forEach((longForm, i) => {
// the value of any longform property in the original styles takes
// precedence over the shortform's value
if (originalStyleProps.indexOf(longForm) === -1) {
style[longForm] = value;
switch (prop) {
// ignore React Native styles
case 'elevation':
case 'resizeMode': {
break;
}
case 'flex': {
resolvedStyle.flexGrow = value;
resolvedStyle.flexShrink = 1;
resolvedStyle.flexBasis = 'auto';
break;
}
case 'shadowColor':
case 'shadowOffset':
case 'shadowOpacity':
case 'shadowRadius': {
if (!hasResolvedBoxShadow) {
resolveBoxShadow(resolvedStyle, style);
}
});
} else {
style[prop] = value;
hasResolvedBoxShadow = true;
break;
}
case 'textAlignVertical': {
resolvedStyle.verticalAlign = (value === 'center' ? 'middle' : value);
break;
}
case 'textShadowColor':
case 'textShadowOffset':
case 'textShadowRadius': {
if (!hasResolvedTextShadow) {
resolveTextShadow(resolvedStyle, style);
}
hasResolvedTextShadow = true;
break;
}
case 'transform': {
resolveTransform(resolvedStyle, style);
break;
}
default: {
const longFormProperties = styleShortFormProperties[prop];
if (longFormProperties) {
longFormProperties.forEach((longForm, i) => {
// the value of any longform property in the original styles takes
// precedence over the shortform's value
if (styleProps.indexOf(longForm) === -1) {
resolvedStyle[longForm] = value;
}
});
} else {
resolvedStyle[prop] = value;
}
}
}
return style;
};
};
const expandStyle = (style = emptyObject) => {
const sortedStyleProps = alphaSort(Object.keys(style));
const styleReducer = createStyleReducer(style);
return sortedStyleProps.reduce(styleReducer, {});
return resolvedStyle;
};
const resolvedStyle = sortedStyleProps.reduce(reducer, {});
return resolvedStyle;
};
module.exports = expandStyle;

View File

@@ -1,4 +1,3 @@
/* eslint-disable */
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
@@ -10,10 +9,8 @@
* @providesModule flattenStyle
* @flow
*/
'use strict';
var ReactNativePropRegistry = require('../ReactNativePropRegistry');
var invariant = require('fbjs/lib/invariant');
import ReactNativePropRegistry from '../../modules/ReactNativePropRegistry';
import invariant from 'fbjs/lib/invariant';
function getStyle(style) {
if (typeof style === 'number') {
@@ -22,22 +19,26 @@ function getStyle(style) {
return style;
}
function flattenStyle(style: ?StyleObj): ?Object {
function flattenStyle(style) {
if (!style) {
return undefined;
}
invariant(style !== true, 'style may be false but not true');
if (process.env.NODE !== 'production') {
invariant(style !== true, 'style may be false but not true');
}
if (!Array.isArray(style)) {
return getStyle(style);
}
var result = {};
for (var i = 0, styleLength = style.length; i < styleLength; ++i) {
var computedStyle = flattenStyle(style[i]);
const result = {};
for (let i = 0, styleLength = style.length; i < styleLength; ++i) {
const computedStyle = flattenStyle(style[i]);
if (computedStyle) {
for (var key in computedStyle) {
result[key] = computedStyle[key];
for (const key in computedStyle) {
const value = computedStyle[key];
result[key] = value;
}
}
}

View File

@@ -0,0 +1,23 @@
import hyphenate from './hyphenate';
import mapKeyValue from '../../modules/mapKeyValue';
import normalizeValue from './normalizeValue';
import prefixAll from 'inline-style-prefixer/static';
const createDeclarationString = (prop, val) => {
const name = hyphenate(prop);
const value = normalizeValue(prop, val);
if (Array.isArray(val)) {
return val.map((v) => `${name}:${v}`).join(';');
}
return `${name}:${value}`;
};
/**
* Generates valid CSS rule body from a JS object
*
* generateCss({ width: 20, color: 'blue' });
* // => 'color:blue;width:20px'
*/
const generateCss = (style) => mapKeyValue(prefixAll(style), createDeclarationString).sort().join(';');
module.exports = generateCss;

View File

@@ -0,0 +1,3 @@
const RE_1 = /([A-Z])/g;
const RE_2 = /^ms-/;
module.exports = (s) => s.replace(RE_1, '-$1').toLowerCase().replace(RE_2, '-ms-');

View File

@@ -1,89 +1,26 @@
import * as css from './css';
import createReactStyleObject from './createReactStyleObject';
import ExecutionEnvironment from 'fbjs/lib/ExecutionEnvironment';
import flattenStyle from '../../modules/flattenStyle';
import React from 'react';
import ReactNativePropRegistry from '../../modules/ReactNativePropRegistry';
import flattenStyle from './flattenStyle';
import initialize from './initialize';
import injector from './injector';
import StyleRegistry from './registry';
let styleElement;
let shouldInsertStyleSheet = ExecutionEnvironment.canUseDOM;
const STYLE_SHEET_ID = 'react-native-style__';
initialize();
const absoluteFillObject = { position: 'absolute', left: 0, right: 0, top: 0, bottom: 0 };
const defaultStyleSheet = css.getDefaultStyleSheet();
const insertStyleSheet = () => {
// check if the server rendered the style sheet
styleElement = document.getElementById(STYLE_SHEET_ID);
// if not, inject the style sheet
if (!styleElement) {
document.head.insertAdjacentHTML(
'afterbegin',
`<style id="${STYLE_SHEET_ID}">${defaultStyleSheet}</style>`
);
shouldInsertStyleSheet = false;
}
};
module.exports = {
/**
* For testing
* @private
*/
_reset() {
if (styleElement) {
document.head.removeChild(styleElement);
styleElement = null;
shouldInsertStyleSheet = true;
}
},
absoluteFill: ReactNativePropRegistry.register(absoluteFillObject),
absoluteFill: StyleRegistry.register(absoluteFillObject),
absoluteFillObject,
create(styles) {
if (shouldInsertStyleSheet) {
insertStyleSheet();
}
const result = {};
for (const key in styles) {
Object.keys(styles).forEach((key) => {
if (process.env.NODE_ENV !== 'production') {
require('./StyleSheetValidation').validateStyle(key, styles);
}
result[key] = ReactNativePropRegistry.register(styles[key]);
}
result[key] = StyleRegistry.register(styles[key]);
});
return result;
},
hairlineWidth: 1,
flatten: flattenStyle,
/* @platform web */
render() {
return <style dangerouslySetInnerHTML={{ __html: defaultStyleSheet }} id={STYLE_SHEET_ID} />;
},
/**
* Accepts React props and converts style declarations to classNames when necessary
* @platform web
*/
resolve(props) {
let className = props.className || '';
const style = createReactStyleObject(props.style);
for (const prop in style) {
const value = style[prop];
const replacementClassName = css.getStyleAsHelperClassName(prop, value);
if (replacementClassName) {
className += ` ${replacementClassName}`;
style[prop] = null;
}
}
return { className, style };
}
renderToString: injector.getStyleSheetHtml
};

View File

@@ -0,0 +1,39 @@
import injector from './injector';
import StyleRegistry from './registry';
const initialize = () => {
injector.addRule(
'reset',
'/* React Native StyleSheet*/\n' +
'html{' +
'font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%;' +
'-webkit-tap-highlight-color:rgba(0,0,0,0)' +
'}\n' +
'body{margin:0}\n' +
'button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}\n' +
'input::-webkit-inner-spin-button,input::-webkit-outer-spin-button,' +
'input::-webkit-search-cancel-button,input::-webkit-search-decoration,' +
'input::-webkit-search-results-button,input::-webkit-search-results-decoration{display:none}'
);
injector.addRule(
'keyframes',
'@keyframes rn-ActivityIndicator-animation{' +
'0%{-webkit-transform: rotate(0deg); transform: rotate(0deg);}' +
'100%{-webkit-transform: rotate(360deg); transform: rotate(360deg);}' +
'}\n' +
'@keyframes rn-ProgressBar-animation{' +
'0%{-webkit-transform: translateX(-100%); transform: translateX(-100%);}' +
'100%{-webkit-transform: translateX(400%); transform: translateX(400%);}' +
'}'
);
injector.addRule(
'pointer-events',
'.rn-pointerEvents\\:auto,.rn_pointerEvents\\:box-only,.rn-pointerEvents\\:box-none *{pointer-events:auto}' +
'.rn-pointerEvents\\:none,.rn_pointerEvents\\:box-only *,.rn-pointerEvents\\:box-none{pointer-events:none}'
);
const classNames = injector.getClassNames();
StyleRegistry.initialize(classNames);
};
export default initialize;

View File

@@ -0,0 +1,106 @@
/**
* Based on
* https://github.com/lelandrichardson/react-primitives/blob/master/src/StyleSheet/injector.js
*/
import asap from 'asap';
const emptyObject = {};
const hasOwnProperty = Object.prototype.hasOwnProperty;
const CLASSNAME_REXEP = /\.rn-([^{;\s]+)/g;
const STYLE_ELEMENT_ID = 'react-native-stylesheet';
let registry = {};
let isDirty = false;
/**
* Registers a rule and requests an update to the style sheet
*/
const addRule = (key, rule) => {
if (!registry[key]) {
registry[key] = rule;
isDirty = true;
if (global.document) {
asap(frame);
}
}
};
/**
* Returns a string of the registered rules
*/
const getStyleText = () => {
/* eslint prefer-template:0 */
let result = '\n';
for (const key in registry) {
if (hasOwnProperty.call(registry, key)) {
result += registry[key] + '\n';
}
}
return result;
};
/**
* Returns an HTML string for server rendering
*/
const getStyleSheetHtml = () => `<style id="${STYLE_ELEMENT_ID}">${getStyleText()}</style>`;
const reset = () => { registry = {}; };
/**
* Finds or injects the style sheet when in a browser environment
*/
let styleNode = null;
const getStyleNode = () => {
if (global.document) {
if (!styleNode) {
// look for existing style sheet (could also be server-rendered)
styleNode = document.getElementById(STYLE_ELEMENT_ID);
if (!styleNode) {
// if there is no existing stylesheet, inject it style sheet
document.head.insertAdjacentHTML('afterbegin', getStyleSheetHtml());
styleNode = document.getElementById(STYLE_ELEMENT_ID);
}
}
return styleNode;
}
};
/**
* Determines which classes are available in the existing document. Doesn't
* rely on the registry so it can be used to read class names from a SSR style
* sheet.
*/
const getClassNames = () => {
const styleNode = getStyleNode();
if (styleNode) {
const text = styleNode.textContent;
const matches = text.match(CLASSNAME_REXEP);
if (matches) {
return matches.map((name) => name.slice(1)).reduce((classMap, className) => {
classMap[className] = true;
return classMap;
}, {});
}
}
return emptyObject;
};
const frame = () => {
if (!isDirty || !global.document) { return; }
isDirty = false;
const styleNode = getStyleNode();
if (styleNode) {
const css = getStyleText();
styleNode.textContent = css;
}
};
module.exports = {
addRule,
getClassNames,
getStyleSheetHtml,
reset
};

View File

@@ -1,16 +1,18 @@
import prefixAll from 'inline-style-prefixer/static';
const processVendorPrefixes = (style) => {
const prefixInlineStyles = (style) => {
const prefixedStyles = prefixAll(style);
// React@15 removed undocumented support for fallback values in
// inline-styles. Revert array values to the standard CSS value
for (const prop in prefixedStyles) {
Object.keys(prefixedStyles).forEach((prop) => {
const value = prefixedStyles[prop];
if (Array.isArray(value)) {
prefixedStyles[prop] = value[value.length - 1];
}
}
});
return prefixedStyles;
};
module.exports = processVendorPrefixes;
module.exports = prefixInlineStyles;

View File

@@ -1,33 +0,0 @@
import normalizeColor from '../../modules/normalizeColor';
import normalizeValue from './normalizeValue';
const applyOpacity = (color, opacity) => {
const normalizedColor = normalizeColor(color);
const colorNumber = normalizedColor === null ? 0x00000000 : normalizedColor;
const r = (colorNumber & 0xff000000) >>> 24;
const g = (colorNumber & 0x00ff0000) >>> 16;
const b = (colorNumber & 0x0000ff00) >>> 8;
const a = (((colorNumber & 0x000000ff) >>> 0) / 255).toFixed(2);
return `rgba(${r},${g},${b},${a * opacity})`;
};
// TODO: add inset and spread support
const processBoxShadow = (style) => {
if (style && style.shadowColor) {
const { height, width } = style.shadowOffset || {};
const opacity = style.shadowOpacity != null ? style.shadowOpacity : 1;
const color = applyOpacity(style.shadowColor, opacity);
const blurRadius = normalizeValue(null, style.shadowRadius || 0);
const offsetX = normalizeValue(null, height || 0);
const offsetY = normalizeValue(null, width || 0);
const boxShadow = `${offsetX} ${offsetY} ${blurRadius} ${color}`;
style.boxShadow = style.boxShadow ? `${style.boxShadow}, ${boxShadow}` : boxShadow;
}
delete style.shadowColor;
delete style.shadowOffset;
delete style.shadowOpacity;
delete style.shadowRadius;
return style;
};
module.exports = processBoxShadow;

View File

@@ -1,19 +0,0 @@
import normalizeValue from './normalizeValue';
const processTextShadow = (style) => {
if (style && style.textShadowOffset) {
const { height, width } = style.textShadowOffset;
const offsetX = normalizeValue(null, height || 0);
const offsetY = normalizeValue(null, width || 0);
const blurRadius = normalizeValue(null, style.textShadowRadius || 0);
const color = style.textShadowColor || 'currentcolor';
style.textShadow = `${offsetX} ${offsetY} ${blurRadius} ${color}`;
style.textShadowColor = null;
style.textShadowOffset = null;
style.textShadowRadius = null;
}
return style;
};
module.exports = processTextShadow;

View File

@@ -0,0 +1,212 @@
/**
* WARNING: changes to this file in particular can cause significant changes to
* the results of render performance benchmarks.
*/
import createReactDOMStyle from './createReactDOMStyle';
import flattenArray from '../../modules/flattenArray';
import flattenStyle from './flattenStyle';
import generateCss from './generateCss';
import injector from './injector';
import mapKeyValue from '../../modules/mapKeyValue';
import prefixInlineStyles from './prefixInlineStyles';
import ReactNativePropRegistry from '../../modules/ReactNativePropRegistry';
const prefix = 'r';
const SPACE_REGEXP = /\s/g;
const ESCAPE_SELECTOR_CHARS_REGEXP = /[(),":?.%\\$#]/g;
/**
* Creates an HTML class name for use on elements
*/
const createClassName = (prop, value) => {
const val = `${value}`.replace(SPACE_REGEXP, '-');
return `rn-${prop}:${val}`;
};
/**
* Inject a CSS rule for a given declaration and record the availability of the
* resulting class name.
*/
let injectedClassNames = {};
const injectClassNameIfNeeded = (prop, value) => {
const className = createClassName(prop, value);
if (!injectedClassNames[className]) {
// create a valid CSS selector for a given HTML class name
const selector = className.replace(ESCAPE_SELECTOR_CHARS_REGEXP, '\\$&');
const body = generateCss({ [prop]: value });
const css = `.${selector}{${body}}`;
// this adds the rule to the buffer to be injected into the document
injector.addRule(className, css);
injectedClassNames[className] = true;
}
return className;
};
/**
* Converts a React Native style object to HTML class names
*/
let resolvedPropsCache = {};
const registerStyle = (id, flatStyle) => {
const style = createReactDOMStyle(flatStyle);
const className = mapKeyValue(style, (prop, value) => {
if (value != null) {
return injectClassNameIfNeeded(prop, value);
}
}).join(' ').trim();
const key = `${prefix}-${id}`;
resolvedPropsCache[key] = { className };
return id;
};
/**
* Resolves a React Native style object to DOM props
*/
const resolveProps = (reactNativeStyle) => {
const flatStyle = flattenStyle(reactNativeStyle);
const domStyle = createReactDOMStyle(flatStyle);
const style = {};
const _className = mapKeyValue(domStyle, (prop, value) => {
if (value != null) {
const singleClassName = createClassName(prop, value);
if (injectedClassNames[singleClassName]) {
return singleClassName;
} else {
// 4x slower render
style[prop] = value;
}
}
})
// improves debugging in devtools and snapshots
.join('\n')
.trim();
const className = `\n${_className}`;
const props = {
className,
style: prefixInlineStyles(style)
};
if (process.env.__REACT_NATIVE_DEBUG_ENABLED__) {
console.groupCollapsed('[StyleSheet] resolving uncached styles');
console.log(
'Slow operation. Resolving style objects (uncached result). ' +
'Occurs on first render and when using styles not registered with "StyleSheet.create"'
);
console.log('source => \n', reactNativeStyle);
console.log('flatten => \n', flatStyle);
console.log('resolve => \n', props);
console.groupEnd();
}
return props;
};
/**
* Caching layer over 'resolveProps'
*/
const resolvePropsIfNeeded = (key, style) => {
if (key) {
if (!resolvedPropsCache[key]) {
// slow: convert style object to props and cache
resolvedPropsCache[key] = resolveProps(style);
}
return resolvedPropsCache[key];
}
return resolveProps(style);
};
/**
* Web style registry
*/
const StyleRegistry = {
initialize(classNames) {
injectedClassNames = classNames;
if (process.env.__REACT_NATIVE_DEBUG_ENABLED__) {
if (global.__REACT_NATIVE_DEBUG_ENABLED__styleRegistryTimer) {
clearInterval(global.__REACT_NATIVE_DEBUG_ENABLED__styleRegistryTimer);
}
global.__REACT_NATIVE_DEBUG_ENABLED__styleRegistryTimer = setInterval(() => {
const entryCount = Object.keys(resolvedPropsCache).length;
console.groupCollapsed('[StyleSheet] resolved props cache snapshot:', entryCount, 'entries');
console.log(resolvedPropsCache);
console.groupEnd();
}, 30000);
}
},
reset() {
injectedClassNames = {};
resolvedPropsCache = {};
injector.reset();
},
register(style) {
const id = ReactNativePropRegistry.register(style);
return registerStyle(id, style);
},
resolve(reactNativeStyle) {
if (!reactNativeStyle) {
return undefined;
}
// fast and cachable
if (typeof reactNativeStyle === 'number') {
const key = `${prefix}${reactNativeStyle}`;
return resolvePropsIfNeeded(key, reactNativeStyle);
}
// convert a RN style object to DOM props
if (!Array.isArray(reactNativeStyle)) {
return resolveProps(reactNativeStyle);
}
// flatten the array
// [ 1, [ 2, 3 ], { prop: value }, 4, 5 ] => [ 1, 2, 3, { prop: value }, 4, 5 ];
const flatArray = flattenArray(reactNativeStyle);
let isArrayOfNumbers = true;
for (let i = 0; i < flatArray.length; i++) {
if (typeof flatArray[i] !== 'number') {
isArrayOfNumbers = false;
break;
}
}
// TODO: determine when/if to cache unregistered styles. This produces 2x
// faster benchmark results for unregistered styles. However, the cache
// could be filled with props that are never used again.
//
// let hasValidKey = true;
// let key = flatArray.reduce((keyParts, element) => {
// if (typeof element === 'number') {
// keyParts.push(element);
// } else {
// if (element.transform) {
// hasValidKey = false;
// } else {
// const objectAsKey = Object.keys(element).map((prop) => `${prop}:${element[prop]}`).join(';');
// if (objectAsKey !== '') {
// keyParts.push(objectAsKey);
// }
// }
// }
// return keyParts;
// }, [ prefix ]).join('-');
// if (!hasValidKey) { key = null; }
// cache resolved props when all styles are registered
const key = isArrayOfNumbers ? `${prefix}-${flatArray.join('-')}` : null;
return resolvePropsIfNeeded(key, flatArray);
}
};
module.exports = StyleRegistry;

View File

@@ -0,0 +1,28 @@
import normalizeColor from '../../modules/normalizeColor';
import normalizeValue from './normalizeValue';
const defaultOffset = { height: 0, width: 0 };
const applyOpacity = (color, opacity = 1) => {
const nullableColor = normalizeColor(color);
const colorInt = nullableColor === null ? 0x00000000 : nullableColor;
const r = Math.round(((colorInt & 0xff000000) >>> 24));
const g = Math.round(((colorInt & 0x00ff0000) >>> 16));
const b = Math.round(((colorInt & 0x0000ff00) >>> 8));
const a = (((colorInt & 0x000000ff) >>> 0) / 255).toFixed(2);
return `rgba(${r},${g},${b},${a * opacity})`;
};
// TODO: add inset and spread support
const resolveBoxShadow = (resolvedStyle, style) => {
const { height, width } = style.shadowOffset || defaultOffset;
const offsetX = normalizeValue(null, width);
const offsetY = normalizeValue(null, height);
const blurRadius = normalizeValue(null, style.shadowRadius || 0);
const color = applyOpacity(style.shadowColor, style.shadowOpacity);
const boxShadow = `${offsetX} ${offsetY} ${blurRadius} ${color}`;
resolvedStyle.boxShadow = style.boxShadow ? `${style.boxShadow}, ${boxShadow}` : boxShadow;
};
module.exports = resolveBoxShadow;

View File

@@ -0,0 +1,15 @@
import normalizeValue from './normalizeValue';
const defaultOffset = { height: 0, width: 0 };
const resolveTextShadow = (resolvedStyle, style) => {
const { height, width } = style.textShadowOffset || defaultOffset;
const offsetX = normalizeValue(null, width);
const offsetY = normalizeValue(null, height);
const blurRadius = normalizeValue(null, style.textShadowRadius || 0);
const color = style.textShadowColor || 'currentcolor';
resolvedStyle.textShadow = `${offsetX} ${offsetY} ${blurRadius} ${color}`;
};
module.exports = resolveTextShadow;

View File

@@ -14,16 +14,14 @@ const convertTransformMatrix = (transformMatrix) => {
return `matrix3d(${matrix})`;
};
const processTransform = (style) => {
if (style) {
if (style.transform && Array.isArray(style.transform)) {
style.transform = style.transform.map(mapTransform).join(' ');
} else if (style.transformMatrix) {
style.transform = convertTransformMatrix(style.transformMatrix);
style.transformMatrix = null;
}
const resolveTransform = (resolvedStyle, style) => {
if (Array.isArray(style.transform)) {
const transform = style.transform.map(mapTransform).join(' ');
resolvedStyle.transform = transform;
} else if (style.transformMatrix) {
const transform = convertTransformMatrix(style.transformMatrix);
resolvedStyle.transform = transform;
}
return style;
};
module.exports = processTransform;
module.exports = resolveTransform;

View File

@@ -1,5 +1,7 @@
import createReactStyleObject from '../StyleSheet/createReactStyleObject';
import createReactDOMStyle from '../StyleSheet/createReactDOMStyle';
import flattenStyle from '../StyleSheet/flattenStyle';
import CSSPropertyOperations from 'react-dom/lib/CSSPropertyOperations';
import prefixInlineStyles from '../StyleSheet/prefixInlineStyles';
const _measureLayout = (node, relativeToNativeNode, callback) => {
const relativeNode = relativeToNativeNode || node.parentNode;
@@ -41,14 +43,11 @@ const UIManager = {
const value = props[prop];
switch (prop) {
case 'style':
// convert styles to DOM-styles
CSSPropertyOperations.setValueForStyles(
node,
createReactStyleObject(value),
component._reactInternalInstance
);
case 'style': {
const style = prefixInlineStyles(createReactDOMStyle(flattenStyle(value)));
CSSPropertyOperations.setValueForStyles(node, style, component._reactInternalInstance);
break;
}
case 'class':
case 'className': {
const nativeProp = 'class';

View File

@@ -0,0 +1,226 @@
exports[`components/ActivityIndicator default render 1`] = `
<div
aria-valuemax="1"
aria-valuemin="0"
className="
rn-alignItems:center
rn-backgroundColor:transparent
rn-borderTopStyle:solid
rn-borderRightStyle:solid
rn-borderBottomStyle:solid
rn-borderLeftStyle:solid
rn-borderTopWidth:0px
rn-borderRightWidth:0px
rn-borderBottomWidth:0px
rn-borderLeftWidth:0px
rn-boxSizing:border-box
rn-color:inherit
rn-display:flex
rn-flexBasis:auto
rn-flexDirection:column
rn-flexShrink:0
rn-font:inherit
rn-justifyContent:center
rn-listStyle:none
rn-marginTop:0px
rn-marginRight:0px
rn-marginBottom:0px
rn-marginLeft:0px
rn-minHeight:0px
rn-minWidth:0px
rn-paddingTop:0px
rn-paddingRight:0px
rn-paddingBottom:0px
rn-paddingLeft:0px
rn-position:relative
rn-textAlign:inherit
rn-textDecoration:none"
role="progressbar"
style={Object {}}>
<div
className="
rn-alignItems:stretch
rn-animationDuration:0.75s
rn-animationIterationCount:infinite
rn-animationName:rn-ActivityIndicator-animation
rn-animationTimingFunction:linear
rn-backgroundColor:transparent
rn-borderTopStyle:solid
rn-borderRightStyle:solid
rn-borderBottomStyle:solid
rn-borderLeftStyle:solid
rn-borderTopWidth:0px
rn-borderRightWidth:0px
rn-borderBottomWidth:0px
rn-borderLeftWidth:0px
rn-boxSizing:border-box
rn-color:inherit
rn-display:flex
rn-flexBasis:auto
rn-flexDirection:column
rn-flexShrink:0
rn-font:inherit
rn-height:20px
rn-listStyle:none
rn-marginTop:0px
rn-marginRight:0px
rn-marginBottom:0px
rn-marginLeft:0px
rn-minHeight:0px
rn-minWidth:0px
rn-paddingTop:0px
rn-paddingRight:0px
rn-paddingBottom:0px
rn-paddingLeft:0px
rn-position:relative
rn-textAlign:inherit
rn-textDecoration:none
rn-width:20px"
style={Object {}}>
<svg
height="100%"
viewBox="0 0 32 32"
width="100%">
<circle
cx="16"
cy="16"
fill="none"
r="14"
strokeWidth="4"
style={
Object {
"opacity": 0.2,
"stroke": "#1976D2",
}
} />
<circle
cx="16"
cy="16"
fill="none"
r="14"
strokeWidth="4"
style={
Object {
"stroke": "#1976D2",
"strokeDasharray": 80,
"strokeDashoffset": 60,
}
} />
</svg>
</div>
</div>
`;
exports[`components/ActivityIndicator other render 1`] = `
<div
aria-valuemax="1"
aria-valuemin="0"
className="
rn-alignItems:center
rn-backgroundColor:transparent
rn-borderTopStyle:solid
rn-borderRightStyle:solid
rn-borderBottomStyle:solid
rn-borderLeftStyle:solid
rn-borderTopWidth:0px
rn-borderRightWidth:0px
rn-borderBottomWidth:0px
rn-borderLeftWidth:0px
rn-boxSizing:border-box
rn-color:inherit
rn-display:flex
rn-flexBasis:auto
rn-flexDirection:column
rn-flexShrink:0
rn-font:inherit
rn-justifyContent:center
rn-listStyle:none
rn-marginTop:0px
rn-marginRight:0px
rn-marginBottom:0px
rn-marginLeft:0px
rn-minHeight:0px
rn-minWidth:0px
rn-paddingTop:0px
rn-paddingRight:0px
rn-paddingBottom:0px
rn-paddingLeft:0px
rn-position:relative
rn-textAlign:inherit
rn-textDecoration:none"
role="progressbar"
style={Object {}}>
<div
className="
rn-alignItems:stretch
rn-animationDuration:0.75s
rn-animationIterationCount:infinite
rn-animationName:rn-ActivityIndicator-animation
rn-animationPlayState:paused
rn-animationTimingFunction:linear
rn-backgroundColor:transparent
rn-borderTopStyle:solid
rn-borderRightStyle:solid
rn-borderBottomStyle:solid
rn-borderLeftStyle:solid
rn-borderTopWidth:0px
rn-borderRightWidth:0px
rn-borderBottomWidth:0px
rn-borderLeftWidth:0px
rn-boxSizing:border-box
rn-color:inherit
rn-display:flex
rn-flexBasis:auto
rn-flexDirection:column
rn-flexShrink:0
rn-font:inherit
rn-height:36px
rn-listStyle:none
rn-marginTop:0px
rn-marginRight:0px
rn-marginBottom:0px
rn-marginLeft:0px
rn-minHeight:0px
rn-minWidth:0px
rn-paddingTop:0px
rn-paddingRight:0px
rn-paddingBottom:0px
rn-paddingLeft:0px
rn-position:relative
rn-textAlign:inherit
rn-textDecoration:none
rn-width:36px"
style={Object {}}>
<svg
height="100%"
viewBox="0 0 32 32"
width="100%">
<circle
cx="16"
cy="16"
fill="none"
r="14"
strokeWidth="4"
style={
Object {
"opacity": 0.2,
"stroke": "#1976D2",
}
} />
<circle
cx="16"
cy="16"
fill="none"
r="14"
strokeWidth="4"
style={
Object {
"stroke": "#1976D2",
"strokeDasharray": 80,
"strokeDashoffset": 60,
}
} />
</svg>
</div>
</div>
`;

View File

@@ -1,5 +1,17 @@
/* eslint-env jasmine, jest */
import ActivityIndicator from '..';
import React from 'react';
import renderer from 'react-test-renderer';
describe('components/ActivityIndicator', () => {
test.skip('NO TEST COVERAGE', () => {});
test('default render', () => {
const component = renderer.create(<ActivityIndicator />);
expect(component.toJSON()).toMatchSnapshot();
});
test('other render', () => {
const component = renderer.create(<ActivityIndicator animating={false} hidesWhenStopped={false} size='large' />);
expect(component.toJSON()).toMatchSnapshot();
});
});

View File

@@ -1,12 +1,8 @@
import Animated from '../../apis/Animated';
import applyNativeMethods from '../../modules/applyNativeMethods';
import Easing from 'animated/lib/Easing';
import StyleSheet from '../../apis/StyleSheet';
import View from '../View';
import React, { Component, PropTypes } from 'react';
const rotationInterpolation = { inputRange: [ 0, 1 ], outputRange: [ '0deg', '360deg' ] };
class ActivityIndicator extends Component {
static displayName = 'ActivityIndicator';
@@ -25,21 +21,6 @@ class ActivityIndicator extends Component {
size: 'small'
};
constructor(props) {
super(props);
this.state = {
animation: new Animated.Value(0)
};
}
componentDidMount() {
this._manageAnimation();
}
componentDidUpdate() {
this._manageAnimation();
}
render() {
const {
animating,
@@ -50,8 +31,6 @@ class ActivityIndicator extends Component {
...other
} = this.props;
const { animation } = this.state;
const svg = (
<svg height='100%' viewBox='0 0 32 32' width='100%'>
<circle
@@ -88,47 +67,21 @@ class ActivityIndicator extends Component {
style={[
styles.container,
style,
size && { height: size, width: size }
typeof size === 'number' && { height: size, width: size }
]}
>
<Animated.View
<View
children={svg}
style={[
indicatorStyles[size],
hidesWhenStopped && !animating && styles.hidesWhenStopped,
{
transform: [
{ rotate: animation.interpolate(rotationInterpolation) }
]
}
indicatorSizes[size],
styles.animation,
!animating && styles.animationPause,
!animating && hidesWhenStopped && styles.hidesWhenStopped
]}
/>
</View>
);
}
_manageAnimation() {
const { animation } = this.state;
const cycleAnimation = () => {
animation.setValue(0);
Animated.timing(animation, {
duration: 750,
easing: Easing.inOut(Easing.linear),
toValue: 1
}).start((event) => {
if (event.finished) {
cycleAnimation();
}
});
};
if (this.props.animating) {
cycleAnimation();
} else {
animation.stopAnimation();
}
}
}
const styles = StyleSheet.create({
@@ -138,10 +91,19 @@ const styles = StyleSheet.create({
},
hidesWhenStopped: {
visibility: 'hidden'
},
animation: {
animationDuration: '0.75s',
animationName: 'rn-ActivityIndicator-animation',
animationTimingFunction: 'linear',
animationIterationCount: 'infinite'
},
animationPause: {
animationPlayState: 'paused'
}
});
const indicatorStyles = StyleSheet.create({
const indicatorSizes = StyleSheet.create({
small: {
width: 20,
height: 20

File diff suppressed because it is too large Load Diff

View File

@@ -131,8 +131,8 @@ class Image extends Component {
styles.initial,
imageSizeStyle,
originalStyle,
backgroundImage && { backgroundImage },
resizeModeStyles[finalResizeMode]
resizeModeStyles[finalResizeMode],
backgroundImage && { backgroundImage }
]);
// View doesn't support 'resizeMode' as a style
delete style.resizeMode;

View File

@@ -1,13 +1,9 @@
import Animated from '../../apis/Animated';
import applyNativeMethods from '../../modules/applyNativeMethods';
import ColorPropType from '../../propTypes/ColorPropType';
import StyleSheet from '../../apis/StyleSheet';
import View from '../View';
import React, { Component, PropTypes } from 'react';
const indeterminateWidth = '25%';
const translateInterpolation = { inputRange: [ 0, 1 ], outputRange: [ '-100%', '400%' ] };
class ProgressBar extends Component {
static displayName = 'ProgressBar';
@@ -26,19 +22,12 @@ class ProgressBar extends Component {
trackColor: 'transparent'
};
constructor(props) {
super(props);
this.state = {
animationTranslate: new Animated.Value(0)
};
}
componentDidMount() {
this._manageAnimation();
this._updateProgressWidth();
}
componentDidUpdate() {
this._manageAnimation();
this._updateProgressWidth();
}
render() {
@@ -51,9 +40,7 @@ class ProgressBar extends Component {
...other
} = this.props;
const { animationTranslate } = this.state;
const percentageProgress = indeterminate ? 50 : progress * 100;
const percentageProgress = progress * 100;
return (
<View {...other}
@@ -67,42 +54,29 @@ class ProgressBar extends Component {
{ backgroundColor: trackColor }
]}
>
<Animated.View style={[
styles.progress,
{ backgroundColor: color },
indeterminate ? {
transform: [
{ translateX: animationTranslate.interpolate(translateInterpolation) }
],
width: indeterminateWidth
} : {
width: `${percentageProgress}%`
}
]} />
<View
ref={this._setProgressRef}
style={[
styles.progress,
indeterminate && styles.animation,
{ backgroundColor: color }
]}
/>
</View>
);
}
_manageAnimation() {
const { animationTranslate } = this.state;
_setProgressRef = (component) => {
this._progressRef = component;
}
const cycleAnimation = (animation) => {
animation.setValue(0);
Animated.timing(animation, {
duration: 1000,
toValue: 1
}).start((event) => {
if (event.finished) {
cycleAnimation(animation);
}
});
};
if (this.props.indeterminate) {
cycleAnimation(animationTranslate);
} else {
animationTranslate.stopAnimation();
}
_updateProgressWidth = () => {
const { indeterminate, progress } = this.props;
const percentageProgress = indeterminate ? 50 : progress * 100;
const width = indeterminate ? '25%' : `${percentageProgress}%`;
this._progressRef.setNativeProps({
style: { width }
});
}
}
@@ -114,6 +88,12 @@ const styles = StyleSheet.create({
},
progress: {
height: '100%'
},
animation: {
animationDuration: '1s',
animationName: 'rn-ProgressBar-animation',
animationTimingFunction: 'linear',
animationIterationCount: 'infinite'
}
});

View File

@@ -91,7 +91,6 @@ class Switch extends Component {
{
backgroundColor: thumbCurrentColor,
height: thumbHeight,
transform: [ { translateX: value ? '100%' : '0%' } ],
width: thumbWidth
},
disabled && styles.disabledThumb
@@ -111,7 +110,16 @@ class Switch extends Component {
return (
<View {...other} style={rootStyle}>
<View style={trackStyle} />
<View ref={this._setThumbRef} style={thumbStyle} />
<View
ref={this._setThumbRef}
style={[
thumbStyle,
value && styles.thumbOn,
{
marginLeft: value ? multiplyStyleLengthValue(thumbWidth, -1) : 0
}
]}
/>
{nativeControl}
</View>
);
@@ -162,8 +170,15 @@ const styles = StyleSheet.create({
alignSelf: 'flex-start',
borderRadius: '100%',
boxShadow: thumbDefaultBoxShadow,
left: '0%',
transform: [
{ translateZ: 0 }
],
transitionDuration: '0.1s'
},
thumbOn: {
left: '100%'
},
disabledThumb: {
backgroundColor: '#BDBDBD'
},

View File

@@ -1,26 +1,14 @@
exports[`components/Text prop "children" 1`] = `
<span
className=""
className="rn-borderTopWidth:0px rn-borderRightWidth:0px rn-borderBottomWidth:0px rn-borderLeftWidth:0px rn-color:inherit rn-display:inline rn-font:inherit rn-marginTop:0px rn-marginRight:0px rn-marginBottom:0px rn-marginLeft:0px rn-paddingTop:0px rn-paddingRight:0px rn-paddingBottom:0px rn-paddingLeft:0px rn-textDecoration:none rn-whiteSpace:pre-wrap rn-wordWrap:break-word"
style={
Object {
"borderBottomWidth": "0px",
"borderLeftWidth": "0px",
"borderRightWidth": "0px",
"borderTopWidth": "0px",
"color": "inherit",
"display": "inline",
"font": "inherit",
"marginBottom": "0px",
"marginLeft": "0px",
"marginRight": "0px",
"marginTop": "0px",
"paddingBottom": "0px",
"paddingLeft": "0px",
"paddingRight": "0px",
"paddingTop": "0px",
"textDecoration": "none",
"wordWrap": "break-word",
}
Array [
2,
undefined,
false,
false,
undefined,
]
}>
children
</span>
@@ -28,86 +16,67 @@ exports[`components/Text prop "children" 1`] = `
exports[`components/Text prop "onPress" 1`] = `
<span
className=""
className="
rn-borderTopWidth:0px
rn-borderRightWidth:0px
rn-borderBottomWidth:0px
rn-borderLeftWidth:0px
rn-color:inherit
rn-cursor:pointer
rn-display:inline
rn-font:inherit
rn-marginTop:0px
rn-marginRight:0px
rn-marginBottom:0px
rn-marginLeft:0px
rn-paddingTop:0px
rn-paddingRight:0px
rn-paddingBottom:0px
rn-paddingLeft:0px
rn-textDecoration:none
rn-whiteSpace:pre-wrap
rn-wordWrap:break-word"
onClick={[Function]}
onKeyDown={[Function]}
style={
Object {
"borderBottomWidth": "0px",
"borderLeftWidth": "0px",
"borderRightWidth": "0px",
"borderTopWidth": "0px",
"color": "inherit",
"cursor": "pointer",
"display": "inline",
"font": "inherit",
"marginBottom": "0px",
"marginLeft": "0px",
"marginRight": "0px",
"marginTop": "0px",
"paddingBottom": "0px",
"paddingLeft": "0px",
"paddingRight": "0px",
"paddingTop": "0px",
"textDecoration": "none",
"wordWrap": "break-word",
}
}
style={Object {}}
tabIndex={0} />
`;
exports[`components/Text prop "selectable" 1`] = `
<span
className=""
className="rn-borderTopWidth:0px rn-borderRightWidth:0px rn-borderBottomWidth:0px rn-borderLeftWidth:0px rn-color:inherit rn-display:inline rn-font:inherit rn-marginTop:0px rn-marginRight:0px rn-marginBottom:0px rn-marginLeft:0px rn-paddingTop:0px rn-paddingRight:0px rn-paddingBottom:0px rn-paddingLeft:0px rn-textDecoration:none rn-whiteSpace:pre-wrap rn-wordWrap:break-word"
style={
Object {
"borderBottomWidth": "0px",
"borderLeftWidth": "0px",
"borderRightWidth": "0px",
"borderTopWidth": "0px",
"color": "inherit",
"display": "inline",
"font": "inherit",
"marginBottom": "0px",
"marginLeft": "0px",
"marginRight": "0px",
"marginTop": "0px",
"paddingBottom": "0px",
"paddingLeft": "0px",
"paddingRight": "0px",
"paddingTop": "0px",
"textDecoration": "none",
"wordWrap": "break-word",
}
Array [
2,
undefined,
false,
false,
undefined,
]
} />
`;
exports[`components/Text prop "selectable" 2`] = `
<span
className=""
style={
Object {
"MozUserSelect": "none",
"WebkitUserSelect": "none",
"borderBottomWidth": "0px",
"borderLeftWidth": "0px",
"borderRightWidth": "0px",
"borderTopWidth": "0px",
"color": "inherit",
"display": "inline",
"font": "inherit",
"marginBottom": "0px",
"marginLeft": "0px",
"marginRight": "0px",
"marginTop": "0px",
"msUserSelect": "none",
"paddingBottom": "0px",
"paddingLeft": "0px",
"paddingRight": "0px",
"paddingTop": "0px",
"textDecoration": "none",
"userSelect": "none",
"wordWrap": "break-word",
}
} />
className="
rn-borderTopWidth:0px
rn-borderRightWidth:0px
rn-borderBottomWidth:0px
rn-borderLeftWidth:0px
rn-color:inherit
rn-display:inline
rn-font:inherit
rn-marginTop:0px
rn-marginRight:0px
rn-marginBottom:0px
rn-marginLeft:0px
rn-paddingTop:0px
rn-paddingRight:0px
rn-paddingBottom:0px
rn-paddingLeft:0px
rn-textDecoration:none
rn-userSelect:none
rn-whiteSpace:pre-wrap
rn-wordWrap:break-word"
style={Object {}} />
`;

View File

@@ -78,6 +78,7 @@ const styles = StyleSheet.create({
margin: 0,
padding: 0,
textDecorationLine: 'none',
whiteSpace: 'pre-wrap',
wordWrap: 'break-word'
},
notSelectable: {

View File

@@ -404,6 +404,13 @@ var TouchableMixin = {
*/
touchableHandleResponderRelease: function(e) {
this._receiveSignal(Signals.RESPONDER_RELEASE, e);
// Browsers fire mouse events after touch events. This causes the
// 'onResponderRelease' handler to be called twice for Touchables.
// Auto-fix this issue by calling 'preventDefault' to cancel the mouse
// events.
if (e.cancelable && !e.isDefaultPrevented()) {
e.preventDefault();
}
},
/**

View File

@@ -1,3 +1,4 @@
import AnimationPropTypes from '../../propTypes/AnimationPropTypes';
import BorderPropTypes from '../../propTypes/BorderPropTypes';
import ColorPropType from '../../propTypes/ColorPropType';
import LayoutPropTypes from '../../propTypes/LayoutPropTypes';
@@ -10,6 +11,7 @@ const autoOrHiddenOrVisible = oneOf([ 'auto', 'hidden', 'visible' ]);
const hiddenOrVisible = oneOf([ 'hidden', 'visible' ]);
module.exports = process.env.NODE_ENV !== 'production' ? {
...AnimationPropTypes,
...BorderPropTypes,
...LayoutPropTypes,
...ShadowPropTypes,

View File

@@ -1,525 +1,399 @@
exports[`components/View prop "children" 1`] = `
<div
className=" __style_df"
style={
Object {
"MozBoxSizing": "border-box",
"WebkitAlignItems": "stretch",
"WebkitBoxAlign": "stretch",
"WebkitBoxDirection": "normal",
"WebkitBoxOrient": "vertical",
"WebkitFlexBasis": "auto",
"WebkitFlexDirection": "column",
"WebkitFlexShrink": 0,
"alignItems": "stretch",
"backgroundColor": "transparent",
"borderBottomStyle": "solid",
"borderBottomWidth": "0px",
"borderLeftStyle": "solid",
"borderLeftWidth": "0px",
"borderRightStyle": "solid",
"borderRightWidth": "0px",
"borderTopStyle": "solid",
"borderTopWidth": "0px",
"boxSizing": "border-box",
"color": "inherit",
"display": null,
"flexBasis": "auto",
"flexDirection": "column",
"flexShrink": 0,
"font": "inherit",
"listStyle": "none",
"marginBottom": "0px",
"marginLeft": "0px",
"marginRight": "0px",
"marginTop": "0px",
"minHeight": "0px",
"minWidth": "0px",
"msFlexAlign": "stretch",
"msFlexDirection": "column",
"msFlexNegative": 0,
"msPreferredSize": "auto",
"paddingBottom": "0px",
"paddingLeft": "0px",
"paddingRight": "0px",
"paddingTop": "0px",
"position": "relative",
"textAlign": "inherit",
"textDecoration": "none",
}
}>
className="
rn-alignItems:stretch
rn-backgroundColor:transparent
rn-borderTopStyle:solid
rn-borderRightStyle:solid
rn-borderBottomStyle:solid
rn-borderLeftStyle:solid
rn-borderTopWidth:0px
rn-borderRightWidth:0px
rn-borderBottomWidth:0px
rn-borderLeftWidth:0px
rn-boxSizing:border-box
rn-color:inherit
rn-display:flex
rn-flexBasis:auto
rn-flexDirection:column
rn-flexShrink:0
rn-font:inherit
rn-listStyle:none
rn-marginTop:0px
rn-marginRight:0px
rn-marginBottom:0px
rn-marginLeft:0px
rn-minHeight:0px
rn-minWidth:0px
rn-paddingTop:0px
rn-paddingRight:0px
rn-paddingBottom:0px
rn-paddingLeft:0px
rn-position:relative
rn-textAlign:inherit
rn-textDecoration:none"
style={Object {}}>
<div
className=" __style_df"
className="
rn-alignItems:stretch
rn-backgroundColor:transparent
rn-borderTopStyle:solid
rn-borderRightStyle:solid
rn-borderBottomStyle:solid
rn-borderLeftStyle:solid
rn-borderTopWidth:0px
rn-borderRightWidth:0px
rn-borderBottomWidth:0px
rn-borderLeftWidth:0px
rn-boxSizing:border-box
rn-color:inherit
rn-display:flex
rn-flexBasis:auto
rn-flexDirection:column
rn-flexShrink:0
rn-font:inherit
rn-listStyle:none
rn-marginTop:0px
rn-marginRight:0px
rn-marginBottom:0px
rn-marginLeft:0px
rn-minHeight:0px
rn-minWidth:0px
rn-paddingTop:0px
rn-paddingRight:0px
rn-paddingBottom:0px
rn-paddingLeft:0px
rn-position:relative
rn-textAlign:inherit
rn-textDecoration:none"
data-testid="1"
style={
Object {
"MozBoxSizing": "border-box",
"WebkitAlignItems": "stretch",
"WebkitBoxAlign": "stretch",
"WebkitBoxDirection": "normal",
"WebkitBoxOrient": "vertical",
"WebkitFlexBasis": "auto",
"WebkitFlexDirection": "column",
"WebkitFlexShrink": 0,
"alignItems": "stretch",
"backgroundColor": "transparent",
"borderBottomStyle": "solid",
"borderBottomWidth": "0px",
"borderLeftStyle": "solid",
"borderLeftWidth": "0px",
"borderRightStyle": "solid",
"borderRightWidth": "0px",
"borderTopStyle": "solid",
"borderTopWidth": "0px",
"boxSizing": "border-box",
"color": "inherit",
"display": null,
"flexBasis": "auto",
"flexDirection": "column",
"flexShrink": 0,
"font": "inherit",
"listStyle": "none",
"marginBottom": "0px",
"marginLeft": "0px",
"marginRight": "0px",
"marginTop": "0px",
"minHeight": "0px",
"minWidth": "0px",
"msFlexAlign": "stretch",
"msFlexDirection": "column",
"msFlexNegative": 0,
"msPreferredSize": "auto",
"paddingBottom": "0px",
"paddingLeft": "0px",
"paddingRight": "0px",
"paddingTop": "0px",
"position": "relative",
"textAlign": "inherit",
"textDecoration": "none",
}
} />
style={Object {}} />
</div>
`;
exports[`components/View prop "pointerEvents" 1`] = `
<div
className=" __style_df __style_pebo"
className="
rn-alignItems:stretch
rn-backgroundColor:transparent
rn-borderTopStyle:solid
rn-borderRightStyle:solid
rn-borderBottomStyle:solid
rn-borderLeftStyle:solid
rn-borderTopWidth:0px
rn-borderRightWidth:0px
rn-borderBottomWidth:0px
rn-borderLeftWidth:0px
rn-boxSizing:border-box
rn-color:inherit
rn-display:flex
rn-flexBasis:auto
rn-flexDirection:column
rn-flexShrink:0
rn-font:inherit
rn-listStyle:none
rn-marginTop:0px
rn-marginRight:0px
rn-marginBottom:0px
rn-marginLeft:0px
rn-minHeight:0px
rn-minWidth:0px
rn-paddingTop:0px
rn-paddingRight:0px
rn-paddingBottom:0px
rn-paddingLeft:0px
rn-position:relative
rn-textAlign:inherit
rn-textDecoration:none"
style={
Object {
"MozBoxSizing": "border-box",
"WebkitAlignItems": "stretch",
"WebkitBoxAlign": "stretch",
"WebkitBoxDirection": "normal",
"WebkitBoxOrient": "vertical",
"WebkitFlexBasis": "auto",
"WebkitFlexDirection": "column",
"WebkitFlexShrink": 0,
"alignItems": "stretch",
"backgroundColor": "transparent",
"borderBottomStyle": "solid",
"borderBottomWidth": "0px",
"borderLeftStyle": "solid",
"borderLeftWidth": "0px",
"borderRightStyle": "solid",
"borderRightWidth": "0px",
"borderTopStyle": "solid",
"borderTopWidth": "0px",
"boxSizing": "border-box",
"color": "inherit",
"display": null,
"flexBasis": "auto",
"flexDirection": "column",
"flexShrink": 0,
"font": "inherit",
"listStyle": "none",
"marginBottom": "0px",
"marginLeft": "0px",
"marginRight": "0px",
"marginTop": "0px",
"minHeight": "0px",
"minWidth": "0px",
"msFlexAlign": "stretch",
"msFlexDirection": "column",
"msFlexNegative": 0,
"msPreferredSize": "auto",
"paddingBottom": "0px",
"paddingLeft": "0px",
"paddingRight": "0px",
"paddingTop": "0px",
"pointerEvents": null,
"position": "relative",
"textAlign": "inherit",
"textDecoration": "none",
"pointerEvents": "box-only",
}
} />
`;
exports[`components/View prop "style" 1`] = `
<div
className=" __style_df"
style={
Object {
"MozBoxSizing": "border-box",
"WebkitAlignItems": "stretch",
"WebkitBoxAlign": "stretch",
"WebkitBoxDirection": "normal",
"WebkitBoxOrient": "vertical",
"WebkitFlexBasis": "auto",
"WebkitFlexDirection": "column",
"WebkitFlexShrink": 0,
"alignItems": "stretch",
"backgroundColor": "transparent",
"borderBottomStyle": "solid",
"borderBottomWidth": "0px",
"borderLeftStyle": "solid",
"borderLeftWidth": "0px",
"borderRightStyle": "solid",
"borderRightWidth": "0px",
"borderTopStyle": "solid",
"borderTopWidth": "0px",
"boxSizing": "border-box",
"color": "inherit",
"display": null,
"flexBasis": "auto",
"flexDirection": "column",
"flexShrink": 0,
"font": "inherit",
"listStyle": "none",
"marginBottom": "0px",
"marginLeft": "0px",
"marginRight": "0px",
"marginTop": "0px",
"minHeight": "0px",
"minWidth": "0px",
"msFlexAlign": "stretch",
"msFlexDirection": "column",
"msFlexNegative": 0,
"msPreferredSize": "auto",
"paddingBottom": "0px",
"paddingLeft": "0px",
"paddingRight": "0px",
"paddingTop": "0px",
"position": "relative",
"textAlign": "inherit",
"textDecoration": "none",
}
} />
className="
rn-alignItems:stretch
rn-backgroundColor:transparent
rn-borderTopStyle:solid
rn-borderRightStyle:solid
rn-borderBottomStyle:solid
rn-borderLeftStyle:solid
rn-borderTopWidth:0px
rn-borderRightWidth:0px
rn-borderBottomWidth:0px
rn-borderLeftWidth:0px
rn-boxSizing:border-box
rn-color:inherit
rn-display:flex
rn-flexBasis:auto
rn-flexDirection:column
rn-flexShrink:0
rn-font:inherit
rn-listStyle:none
rn-marginTop:0px
rn-marginRight:0px
rn-marginBottom:0px
rn-marginLeft:0px
rn-minHeight:0px
rn-minWidth:0px
rn-paddingTop:0px
rn-paddingRight:0px
rn-paddingBottom:0px
rn-paddingLeft:0px
rn-position:relative
rn-textAlign:inherit
rn-textDecoration:none"
style={Object {}} />
`;
exports[`components/View prop "style" 2`] = `
<div
className=" __style_df"
className="
rn-alignItems:stretch
rn-backgroundColor:transparent
rn-borderTopStyle:solid
rn-borderRightStyle:solid
rn-borderBottomStyle:solid
rn-borderLeftStyle:solid
rn-borderTopWidth:0px
rn-borderRightWidth:0px
rn-borderBottomWidth:0px
rn-borderLeftWidth:0px
rn-boxSizing:border-box
rn-color:inherit
rn-display:flex
rn-flexBasis:auto
rn-flexDirection:column
rn-font:inherit
rn-listStyle:none
rn-marginTop:0px
rn-marginRight:0px
rn-marginBottom:0px
rn-marginLeft:0px
rn-minHeight:0px
rn-minWidth:0px
rn-paddingTop:0px
rn-paddingRight:0px
rn-paddingBottom:0px
rn-paddingLeft:0px
rn-position:relative
rn-textAlign:inherit
rn-textDecoration:none"
style={
Object {
"MozBoxSizing": "border-box",
"WebkitAlignItems": "stretch",
"WebkitBoxAlign": "stretch",
"WebkitBoxDirection": "normal",
"WebkitBoxOrient": "vertical",
"WebkitFlexBasis": "auto",
"WebkitFlexDirection": "column",
"WebkitFlexGrow": 1,
"WebkitFlexShrink": 1,
"alignItems": "stretch",
"backgroundColor": "transparent",
"borderBottomStyle": "solid",
"borderBottomWidth": "0px",
"borderLeftStyle": "solid",
"borderLeftWidth": "0px",
"borderRightStyle": "solid",
"borderRightWidth": "0px",
"borderTopStyle": "solid",
"borderTopWidth": "0px",
"boxSizing": "border-box",
"color": "inherit",
"display": null,
"flexBasis": "auto",
"flexDirection": "column",
"flexGrow": 1,
"flexShrink": 1,
"font": "inherit",
"listStyle": "none",
"marginBottom": "0px",
"marginLeft": "0px",
"marginRight": "0px",
"marginTop": "0px",
"minHeight": "0px",
"minWidth": "0px",
"msFlexAlign": "stretch",
"msFlexDirection": "column",
"msFlexNegative": 1,
"msFlexPositive": 1,
"msPreferredSize": "auto",
"paddingBottom": "0px",
"paddingLeft": "0px",
"paddingRight": "0px",
"paddingTop": "0px",
"position": "relative",
"textAlign": "inherit",
"textDecoration": "none",
}
} />
`;
exports[`components/View prop "style" 3`] = `
<div
className=" __style_df"
className="
rn-alignItems:stretch
rn-backgroundColor:transparent
rn-borderTopStyle:solid
rn-borderRightStyle:solid
rn-borderBottomStyle:solid
rn-borderLeftStyle:solid
rn-borderTopWidth:0px
rn-borderRightWidth:0px
rn-borderBottomWidth:0px
rn-borderLeftWidth:0px
rn-boxSizing:border-box
rn-color:inherit
rn-display:flex
rn-flexBasis:auto
rn-flexDirection:column
rn-font:inherit
rn-listStyle:none
rn-marginTop:0px
rn-marginRight:0px
rn-marginBottom:0px
rn-marginLeft:0px
rn-minHeight:0px
rn-minWidth:0px
rn-paddingTop:0px
rn-paddingRight:0px
rn-paddingBottom:0px
rn-paddingLeft:0px
rn-position:relative
rn-textAlign:inherit
rn-textDecoration:none"
style={
Object {
"MozBoxSizing": "border-box",
"WebkitAlignItems": "stretch",
"WebkitBoxAlign": "stretch",
"WebkitBoxDirection": "normal",
"WebkitBoxOrient": "vertical",
"WebkitFlexBasis": "auto",
"WebkitFlexDirection": "column",
"WebkitFlexShrink": 1,
"alignItems": "stretch",
"backgroundColor": "transparent",
"borderBottomStyle": "solid",
"borderBottomWidth": "0px",
"borderLeftStyle": "solid",
"borderLeftWidth": "0px",
"borderRightStyle": "solid",
"borderRightWidth": "0px",
"borderTopStyle": "solid",
"borderTopWidth": "0px",
"boxSizing": "border-box",
"color": "inherit",
"display": null,
"flexBasis": "auto",
"flexDirection": "column",
"flexShrink": 1,
"font": "inherit",
"listStyle": "none",
"marginBottom": "0px",
"marginLeft": "0px",
"marginRight": "0px",
"marginTop": "0px",
"minHeight": "0px",
"minWidth": "0px",
"msFlexAlign": "stretch",
"msFlexDirection": "column",
"msFlexNegative": 1,
"msPreferredSize": "auto",
"paddingBottom": "0px",
"paddingLeft": "0px",
"paddingRight": "0px",
"paddingTop": "0px",
"position": "relative",
"textAlign": "inherit",
"textDecoration": "none",
}
} />
`;
exports[`components/View prop "style" 4`] = `
<div
className=" __style_df"
className="
rn-alignItems:stretch
rn-backgroundColor:transparent
rn-borderTopStyle:solid
rn-borderRightStyle:solid
rn-borderBottomStyle:solid
rn-borderLeftStyle:solid
rn-borderTopWidth:0px
rn-borderRightWidth:0px
rn-borderBottomWidth:0px
rn-borderLeftWidth:0px
rn-boxSizing:border-box
rn-color:inherit
rn-display:flex
rn-flexBasis:auto
rn-flexDirection:column
rn-font:inherit
rn-listStyle:none
rn-marginTop:0px
rn-marginRight:0px
rn-marginBottom:0px
rn-marginLeft:0px
rn-minHeight:0px
rn-minWidth:0px
rn-paddingTop:0px
rn-paddingRight:0px
rn-paddingBottom:0px
rn-paddingLeft:0px
rn-position:relative
rn-textAlign:inherit
rn-textDecoration:none"
style={
Object {
"MozBoxSizing": "border-box",
"WebkitAlignItems": "stretch",
"WebkitBoxAlign": "stretch",
"WebkitBoxDirection": "normal",
"WebkitBoxOrient": "vertical",
"WebkitFlexBasis": "auto",
"WebkitFlexDirection": "column",
"WebkitFlexGrow": 1,
"WebkitFlexShrink": 2,
"alignItems": "stretch",
"backgroundColor": "transparent",
"borderBottomStyle": "solid",
"borderBottomWidth": "0px",
"borderLeftStyle": "solid",
"borderLeftWidth": "0px",
"borderRightStyle": "solid",
"borderRightWidth": "0px",
"borderTopStyle": "solid",
"borderTopWidth": "0px",
"boxSizing": "border-box",
"color": "inherit",
"display": null,
"flexBasis": "auto",
"flexDirection": "column",
"flexGrow": 1,
"flexShrink": 2,
"font": "inherit",
"listStyle": "none",
"marginBottom": "0px",
"marginLeft": "0px",
"marginRight": "0px",
"marginTop": "0px",
"minHeight": "0px",
"minWidth": "0px",
"msFlexAlign": "stretch",
"msFlexDirection": "column",
"msFlexNegative": 2,
"msFlexPositive": 1,
"msPreferredSize": "auto",
"paddingBottom": "0px",
"paddingLeft": "0px",
"paddingRight": "0px",
"paddingTop": "0px",
"position": "relative",
"textAlign": "inherit",
"textDecoration": "none",
}
} />
`;
exports[`components/View rendered element is a "div" by default 1`] = `
<div
className=" __style_df"
style={
Object {
"MozBoxSizing": "border-box",
"WebkitAlignItems": "stretch",
"WebkitBoxAlign": "stretch",
"WebkitBoxDirection": "normal",
"WebkitBoxOrient": "vertical",
"WebkitFlexBasis": "auto",
"WebkitFlexDirection": "column",
"WebkitFlexShrink": 0,
"alignItems": "stretch",
"backgroundColor": "transparent",
"borderBottomStyle": "solid",
"borderBottomWidth": "0px",
"borderLeftStyle": "solid",
"borderLeftWidth": "0px",
"borderRightStyle": "solid",
"borderRightWidth": "0px",
"borderTopStyle": "solid",
"borderTopWidth": "0px",
"boxSizing": "border-box",
"color": "inherit",
"display": null,
"flexBasis": "auto",
"flexDirection": "column",
"flexShrink": 0,
"font": "inherit",
"listStyle": "none",
"marginBottom": "0px",
"marginLeft": "0px",
"marginRight": "0px",
"marginTop": "0px",
"minHeight": "0px",
"minWidth": "0px",
"msFlexAlign": "stretch",
"msFlexDirection": "column",
"msFlexNegative": 0,
"msPreferredSize": "auto",
"paddingBottom": "0px",
"paddingLeft": "0px",
"paddingRight": "0px",
"paddingTop": "0px",
"position": "relative",
"textAlign": "inherit",
"textDecoration": "none",
}
} />
className="
rn-alignItems:stretch
rn-backgroundColor:transparent
rn-borderTopStyle:solid
rn-borderRightStyle:solid
rn-borderBottomStyle:solid
rn-borderLeftStyle:solid
rn-borderTopWidth:0px
rn-borderRightWidth:0px
rn-borderBottomWidth:0px
rn-borderLeftWidth:0px
rn-boxSizing:border-box
rn-color:inherit
rn-display:flex
rn-flexBasis:auto
rn-flexDirection:column
rn-flexShrink:0
rn-font:inherit
rn-listStyle:none
rn-marginTop:0px
rn-marginRight:0px
rn-marginBottom:0px
rn-marginLeft:0px
rn-minHeight:0px
rn-minWidth:0px
rn-paddingTop:0px
rn-paddingRight:0px
rn-paddingBottom:0px
rn-paddingLeft:0px
rn-position:relative
rn-textAlign:inherit
rn-textDecoration:none"
style={Object {}} />
`;
exports[`components/View rendered element is a "span" when inside <View accessibilityRole="button" /> 1`] = `
<button
className=" __style_df"
className="
rn-alignItems:stretch
rn-backgroundColor:transparent
rn-borderTopStyle:solid
rn-borderRightStyle:solid
rn-borderBottomStyle:solid
rn-borderLeftStyle:solid
rn-borderTopWidth:0px
rn-borderRightWidth:0px
rn-borderBottomWidth:0px
rn-borderLeftWidth:0px
rn-boxSizing:border-box
rn-color:inherit
rn-display:flex
rn-flexBasis:auto
rn-flexDirection:column
rn-flexShrink:0
rn-font:inherit
rn-listStyle:none
rn-marginTop:0px
rn-marginRight:0px
rn-marginBottom:0px
rn-marginLeft:0px
rn-minHeight:0px
rn-minWidth:0px
rn-paddingTop:0px
rn-paddingRight:0px
rn-paddingBottom:0px
rn-paddingLeft:0px
rn-position:relative
rn-textAlign:inherit
rn-textDecoration:none"
role="button"
style={
Object {
"MozBoxSizing": "border-box",
"WebkitAlignItems": "stretch",
"WebkitBoxAlign": "stretch",
"WebkitBoxDirection": "normal",
"WebkitBoxOrient": "vertical",
"WebkitFlexBasis": "auto",
"WebkitFlexDirection": "column",
"WebkitFlexShrink": 0,
"alignItems": "stretch",
"backgroundColor": "transparent",
"borderBottomStyle": "solid",
"borderBottomWidth": "0px",
"borderLeftStyle": "solid",
"borderLeftWidth": "0px",
"borderRightStyle": "solid",
"borderRightWidth": "0px",
"borderTopStyle": "solid",
"borderTopWidth": "0px",
"boxSizing": "border-box",
"color": "inherit",
"display": null,
"flexBasis": "auto",
"flexDirection": "column",
"flexShrink": 0,
"font": "inherit",
"listStyle": "none",
"marginBottom": "0px",
"marginLeft": "0px",
"marginRight": "0px",
"marginTop": "0px",
"minHeight": "0px",
"minWidth": "0px",
"msFlexAlign": "stretch",
"msFlexDirection": "column",
"msFlexNegative": 0,
"msPreferredSize": "auto",
"paddingBottom": "0px",
"paddingLeft": "0px",
"paddingRight": "0px",
"paddingTop": "0px",
"position": "relative",
"textAlign": "inherit",
"textDecoration": "none",
}
}
style={Object {}}
type="button">
<span
className=" __style_df"
style={
Object {
"MozBoxSizing": "border-box",
"WebkitAlignItems": "stretch",
"WebkitBoxAlign": "stretch",
"WebkitBoxDirection": "normal",
"WebkitBoxOrient": "vertical",
"WebkitFlexBasis": "auto",
"WebkitFlexDirection": "column",
"WebkitFlexShrink": 0,
"alignItems": "stretch",
"backgroundColor": "transparent",
"borderBottomStyle": "solid",
"borderBottomWidth": "0px",
"borderLeftStyle": "solid",
"borderLeftWidth": "0px",
"borderRightStyle": "solid",
"borderRightWidth": "0px",
"borderTopStyle": "solid",
"borderTopWidth": "0px",
"boxSizing": "border-box",
"color": "inherit",
"display": null,
"flexBasis": "auto",
"flexDirection": "column",
"flexShrink": 0,
"font": "inherit",
"listStyle": "none",
"marginBottom": "0px",
"marginLeft": "0px",
"marginRight": "0px",
"marginTop": "0px",
"minHeight": "0px",
"minWidth": "0px",
"msFlexAlign": "stretch",
"msFlexDirection": "column",
"msFlexNegative": 0,
"msPreferredSize": "auto",
"paddingBottom": "0px",
"paddingLeft": "0px",
"paddingRight": "0px",
"paddingTop": "0px",
"position": "relative",
"textAlign": "inherit",
"textDecoration": "none",
}
} />
className="
rn-alignItems:stretch
rn-backgroundColor:transparent
rn-borderTopStyle:solid
rn-borderRightStyle:solid
rn-borderBottomStyle:solid
rn-borderLeftStyle:solid
rn-borderTopWidth:0px
rn-borderRightWidth:0px
rn-borderBottomWidth:0px
rn-borderLeftWidth:0px
rn-boxSizing:border-box
rn-color:inherit
rn-display:flex
rn-flexBasis:auto
rn-flexDirection:column
rn-flexShrink:0
rn-font:inherit
rn-listStyle:none
rn-marginTop:0px
rn-marginRight:0px
rn-marginBottom:0px
rn-marginLeft:0px
rn-minHeight:0px
rn-minWidth:0px
rn-paddingTop:0px
rn-paddingRight:0px
rn-paddingBottom:0px
rn-paddingLeft:0px
rn-position:relative
rn-textAlign:inherit
rn-textDecoration:none"
style={Object {}} />
</button>
`;

View File

@@ -112,7 +112,7 @@ class View extends Component {
eventHandlerNames.reduce((props, handlerName) => {
const handler = this.props[handlerName];
if (typeof handler === 'function') {
props[handlerName] = this._normalizeEventForHandler(handler, handlerName);
props[handlerName] = this._normalizeEventForHandler(handler);
}
return props;
}, otherProps);
@@ -127,20 +127,10 @@ class View extends Component {
return createDOMElement(component, otherProps);
}
_normalizeEventForHandler(handler, handlerName) {
// Browsers fire mouse events after touch events. This causes the
// 'onResponderRelease' handler to be called twice for Touchables.
// Auto-fix this issue by calling 'preventDefault' to cancel the mouse
// events.
const shouldCancelEvent = handlerName === 'onResponderRelease';
_normalizeEventForHandler(handler) {
return (e) => {
e.nativeEvent = normalizeNativeEvent(e.nativeEvent);
const returnValue = handler(e);
if (shouldCancelEvent && e.cancelable) {
e.preventDefault();
}
return returnValue;
return handler(e);
};
}
}

View File

@@ -9,6 +9,7 @@ import Animated from './apis/Animated';
import AppRegistry from './apis/AppRegistry';
import AppState from './apis/AppState';
import AsyncStorage from './apis/AsyncStorage';
import BackAndroid from './apis/BackAndroid';
import Clipboard from './apis/Clipboard';
import Dimensions from './apis/Dimensions';
import Easing from 'animated/lib/Easing';
@@ -59,6 +60,7 @@ const ReactNative = {
AppRegistry,
AppState,
AsyncStorage,
BackAndroid,
Clipboard,
Dimensions,
Easing,

View File

@@ -6,33 +6,9 @@
* @flow
*/
import { Component } from 'react';
import findNodeHandle from '../findNodeHandle';
import UIManager from '../../apis/UIManager';
type MeasureInWindowOnSuccessCallback = (
x: number,
y: number,
width: number,
height: number,
) => void
type MeasureLayoutOnSuccessCallback = (
left: number,
top: number,
width: number,
height: number
) => void
type MeasureOnSuccessCallback = (
x: number,
y: number,
width: number,
height: number,
pageX: number,
pageY: number
) => void
const NativeMethodsMixin = {
/**
* Removes focus from an input or view. This is the opposite of `focus()`.
@@ -52,11 +28,8 @@ const NativeMethodsMixin = {
/**
* Determines the position and dimensions of the view
*/
measure(callback: MeasureOnSuccessCallback) {
UIManager.measure(
findNodeHandle(this),
mountSafeCallback(this, callback)
);
measure(callback) {
UIManager.measure(findNodeHandle(this), callback);
},
/**
@@ -74,50 +47,23 @@ const NativeMethodsMixin = {
* Note that these measurements are not available until after the rendering
* has been completed in native.
*/
measureInWindow(callback: MeasureInWindowOnSuccessCallback) {
UIManager.measureInWindow(
findNodeHandle(this),
mountSafeCallback(this, callback)
);
measureInWindow(callback) {
UIManager.measureInWindow(findNodeHandle(this), callback);
},
/**
* Measures the view relative to another view (usually an ancestor)
*/
measureLayout(
relativeToNativeNode: Object,
onSuccess: MeasureLayoutOnSuccessCallback,
onFail: () => void /* currently unused */
) {
UIManager.measureLayout(
findNodeHandle(this),
relativeToNativeNode,
mountSafeCallback(this, onFail),
mountSafeCallback(this, onSuccess)
);
measureLayout(relativeToNativeNode, onSuccess, onFail) {
UIManager.measureLayout(findNodeHandle(this), relativeToNativeNode, onFail, onSuccess);
},
/**
* This function sends props straight to the underlying DOM node.
*/
setNativeProps(nativeProps: Object) {
UIManager.updateView(
findNodeHandle(this),
nativeProps,
this
);
UIManager.updateView(findNodeHandle(this), nativeProps, this);
}
};
/**
* In the future, we should cleanup callbacks by cancelling them instead of
* using this.
*/
const mountSafeCallback = (context: Component, callback: ?Function) => (...args) => {
if (!callback) {
return undefined;
}
return callback.apply(context, args);
};
module.exports = NativeMethodsMixin;

View File

@@ -14,15 +14,19 @@
const emptyObject = {};
const objects = {};
const prefix = 'r';
let uniqueID = 1;
const createKey = (id) => `${prefix}-${id}`;
class ReactNativePropRegistry {
static register(object: Object): number {
let id = ++uniqueID;
let id = uniqueID++;
if (process.env.NODE_ENV !== 'production') {
Object.freeze(object);
}
objects[id] = object;
const key = createKey(id);
objects[key] = object;
return id;
}
@@ -32,8 +36,8 @@ class ReactNativePropRegistry {
// we want it to be a no-op when the value is false or null
return emptyObject;
}
const object = objects[id];
const key = createKey(id);
const object = objects[key];
if (!object) {
console.warn('Invalid style with id `' + id + '`. Skipping ...');
return emptyObject;

View File

@@ -1,75 +1,45 @@
exports[`modules/createDOMElement prop "accessibilityLabel" 1`] = `
<span
aria-label="accessibilityLabel"
className=""
style={Object {}} />
aria-label="accessibilityLabel" />
`;
exports[`modules/createDOMElement prop "accessibilityLiveRegion" 1`] = `
<span
aria-live="polite"
className=""
style={Object {}} />
aria-live="polite" />
`;
exports[`modules/createDOMElement prop "accessibilityRole" button 1`] = `
<button
className=""
role="button"
style={Object {}}
type="button" />
`;
exports[`modules/createDOMElement prop "accessibilityRole" link and target="_blank" 1`] = `
<a
className=""
rel=" noopener noreferrer"
role="link"
style={Object {}}
target="_blank" />
`;
exports[`modules/createDOMElement prop "accessibilityRole" roles 1`] = `
<header
className=""
role="banner"
style={Object {}} />
role="banner" />
`;
exports[`modules/createDOMElement prop "accessible" 1`] = `
<span
className=""
style={Object {}} />
`;
exports[`modules/createDOMElement prop "accessible" 1`] = `<span />`;
exports[`modules/createDOMElement prop "accessible" 2`] = `
<span
className=""
style={Object {}} />
`;
exports[`modules/createDOMElement prop "accessible" 2`] = `<span />`;
exports[`modules/createDOMElement prop "accessible" 3`] = `
<span
aria-hidden={true}
className=""
style={Object {}} />
aria-hidden={true} />
`;
exports[`modules/createDOMElement prop "testID" 1`] = `
<span
className=""
data-testid="Example.testID"
style={Object {}} />
data-testid="Example.testID" />
`;
exports[`modules/createDOMElement renders correct DOM element 1`] = `
<span
className=""
style={Object {}} />
`;
exports[`modules/createDOMElement renders correct DOM element 1`] = `<span />`;
exports[`modules/createDOMElement renders correct DOM element 2`] = `
<main
className=""
style={Object {}} />
`;
exports[`modules/createDOMElement renders correct DOM element 2`] = `<main />`;

View File

@@ -1,5 +1,5 @@
import React from 'react';
import StyleSheet from '../../apis/StyleSheet';
import StyleRegistry from '../../apis/StyleSheet/registry';
const emptyObject = {};
@@ -33,7 +33,7 @@ const createDOMElement = (component, rnProps = emptyObject) => {
const accessibilityComponent = accessibilityRole && roleComponents[accessibilityRole];
const Component = accessibilityComponent || component;
Object.assign(domProps, StyleSheet.resolve(domProps));
const { className, style } = StyleRegistry.resolve(domProps.style) || emptyObject;
if (!accessible) { domProps['aria-hidden'] = true; }
if (accessibilityLabel) { domProps['aria-label'] = accessibilityLabel; }
@@ -47,6 +47,12 @@ const createDOMElement = (component, rnProps = emptyObject) => {
domProps.rel = `${domProps.rel || ''} noopener noreferrer`;
}
}
if (className && className !== '') {
domProps.className = domProps.className ? `${domProps.className} ${className}` : className;
}
if (style) {
domProps.style = style;
}
if (type) { domProps.type = type; }
return (

View File

@@ -0,0 +1,18 @@
function flattenArray(array) {
function flattenDown(array, result) {
for (let i = 0; i < array.length; i++) {
const value = array[i];
if (Array.isArray(value)) {
flattenDown(value, result);
} else if (value != null && value !== false) {
result.push(value);
}
}
return result;
}
return flattenDown(array, []);
}
module.exports = flattenArray;

View File

@@ -1,26 +0,0 @@
exports[`modules/flattenStyle should merge style objects 1`] = `
Object {
"opacity": 1,
"order": 2,
}
`;
exports[`modules/flattenStyle should override style properties 1`] = `
Object {
"backgroundColor": "#023c69",
"order": null,
}
`;
exports[`modules/flattenStyle should overwrite properties with \`undefined\` 1`] = `
Object {
"backgroundColor": undefined,
}
`;
exports[`modules/flattenStyle should recursively flatten arrays 1`] = `
Object {
"opacity": 1,
"order": 3,
}
`;

View File

@@ -0,0 +1,13 @@
const hasOwnProperty = Object.prototype.hasOwnProperty;
const mapKeyValue = (obj, fn) => {
const result = [];
for (const key in obj) {
if (hasOwnProperty.call(obj, key)) {
result.push(fn(key, obj[key]));
}
}
return result;
};
module.exports = mapKeyValue;

View File

@@ -1,8 +0,0 @@
function SetPolyfill() { this._cache = []; }
SetPolyfill.prototype.add = function (e) {
if (this._cache.indexOf(e) === -1) { this._cache.push(e); }
};
SetPolyfill.prototype.forEach = function (cb) {
this._cache.forEach(cb);
};
module.exports = SetPolyfill;

View File

@@ -0,0 +1,16 @@
import { PropTypes } from 'react';
const { number, oneOf, oneOfType, string } = PropTypes;
const AnimationPropTypes = process.env.NODE_ENV !== 'production' ? {
animationDelay: string,
animationDirection: oneOf([ 'alternate', 'alternate-reverse', 'normal', 'reverse' ]),
animationDuration: string,
animationFillMode: oneOf([ 'none', 'forwards', 'backwards', 'both' ]),
animationIterationCount: oneOfType([ number, oneOf([ 'infinite' ]) ]),
animationName: string,
animationPlayState: oneOf([ 'paused', 'running' ]),
animationTimingFunction: string
} : {};
module.exports = AnimationPropTypes;

View File

@@ -7,7 +7,7 @@
module.exports = process.env.NODE_ENV !== 'production' ? function StyleSheetPropType(shape) {
const createStrictShapeTypeChecker = require('./createStrictShapeTypeChecker');
const flattenStyle = require('../modules/flattenStyle');
const StyleSheet = require('../apis/StyleSheet');
const shapePropType = createStrictShapeTypeChecker(shape);
return function (props, propName, componentName, location?) {
@@ -15,7 +15,7 @@ module.exports = process.env.NODE_ENV !== 'production' ? function StyleSheetProp
if (props[propName]) {
// Just make a dummy prop object with only the flattened style
newProps = {};
newProps[propName] = flattenStyle(props[propName]);
newProps[propName] = StyleSheet.flatten(props[propName]);
}
return shapePropType(newProps, propName, componentName, location);
};

View File

@@ -31,11 +31,6 @@ module.exports = {
}),
new webpack.DefinePlugin({ 'process.env.NODE_ENV': JSON.stringify('production') }),
new webpack.optimize.DedupePlugin(),
// https://github.com/animatedjs/animated/issues/40
new webpack.NormalModuleReplacementPlugin(
/es6-set/,
path.join(__dirname, 'dist/modules/polyfills/Set.js')
),
new webpack.optimize.OccurenceOrderPlugin(),
new webpack.optimize.UglifyJsPlugin({
compress: {

208
yarn.lock
View File

@@ -181,13 +181,18 @@ amdefine@>=0.0.4:
version "1.0.1"
resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5"
animated@^0.1.3:
version "0.1.4"
resolved "https://registry.yarnpkg.com/animated/-/animated-0.1.4.tgz#1e7d119ea0027e1279b96ec309f5cb54935a915a"
animated@^0.1.5:
version "0.1.5"
resolved "https://registry.yarnpkg.com/animated/-/animated-0.1.5.tgz#83df8dc443d57abab7b0bb04818b0b655b31c9b9"
dependencies:
es6-set "^0.1.4"
invariant "^2.2.0"
tinycolor "0.0.1"
normalize-css-color "^1.0.1"
ansi-align@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-1.1.0.tgz#2f0c1658829739add5ebb15e6b0c6e3423f016ba"
dependencies:
string-width "^1.0.1"
ansi-escapes@^1.1.0, ansi-escapes@^1.4.0:
version "1.4.0"
@@ -292,7 +297,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.3:
asap@^2.0.5, asap@~2.0.3:
version "2.0.5"
resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.5.tgz#522765b50c3510490e52d7dcfe085ef9ba96958f"
@@ -378,27 +383,27 @@ babel-cli@^6.14.0:
optionalDependencies:
chokidar "^1.0.0"
babel-code-frame@^6.11.0, babel-code-frame@^6.16.0:
version "6.16.0"
resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.16.0.tgz#f90e60da0862909d3ce098733b5d3987c97cb8de"
babel-code-frame@^6.11.0, babel-code-frame@^6.16.0, babel-code-frame@^6.20.0:
version "6.20.0"
resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.20.0.tgz#b968f839090f9a8bc6d41938fb96cb84f7387b26"
dependencies:
chalk "^1.1.0"
esutils "^2.0.2"
js-tokens "^2.0.0"
babel-core@^6.0.0, babel-core@^6.11.4, babel-core@^6.14.0, babel-core@^6.18.0:
version "6.18.2"
resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.18.2.tgz#d8bb14dd6986fa4f3566a26ceda3964fa0e04e5b"
babel-core@^6.0.0, babel-core@^6.11.4, babel-core@^6.18.0, babel-core@^6.21.0:
version "6.21.0"
resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.21.0.tgz#75525480c21c803f826ef3867d22c19f080a3724"
dependencies:
babel-code-frame "^6.16.0"
babel-generator "^6.18.0"
babel-code-frame "^6.20.0"
babel-generator "^6.21.0"
babel-helpers "^6.16.0"
babel-messages "^6.8.0"
babel-register "^6.18.0"
babel-runtime "^6.9.1"
babel-runtime "^6.20.0"
babel-template "^6.16.0"
babel-traverse "^6.18.0"
babel-types "^6.18.0"
babel-traverse "^6.21.0"
babel-types "^6.21.0"
babylon "^6.11.0"
convert-source-map "^1.1.0"
debug "^2.1.1"
@@ -410,23 +415,23 @@ babel-core@^6.0.0, babel-core@^6.11.4, babel-core@^6.14.0, babel-core@^6.18.0:
slash "^1.0.0"
source-map "^0.5.0"
babel-eslint@^6.1.2:
version "6.1.2"
resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-6.1.2.tgz#5293419fe3672d66598d327da9694567ba6a5f2f"
babel-eslint@^7.1.1:
version "7.1.1"
resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-7.1.1.tgz#8a6a884f085aa7060af69cfc77341c2f99370fb2"
dependencies:
babel-traverse "^6.0.20"
babel-types "^6.0.19"
babylon "^6.0.18"
lodash.assign "^4.0.0"
lodash.pickby "^4.0.0"
babel-code-frame "^6.16.0"
babel-traverse "^6.15.0"
babel-types "^6.15.0"
babylon "^6.13.0"
lodash.pickby "^4.6.0"
babel-generator@^6.18.0:
version "6.19.0"
resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.19.0.tgz#9b2f244204777a3d6810ec127c673c87b349fac5"
babel-generator@^6.18.0, babel-generator@^6.21.0:
version "6.21.0"
resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.21.0.tgz#605f1269c489a1c75deeca7ea16d43d4656c8494"
dependencies:
babel-messages "^6.8.0"
babel-runtime "^6.9.0"
babel-types "^6.19.0"
babel-runtime "^6.20.0"
babel-types "^6.21.0"
detect-indent "^4.0.0"
jsesc "^1.3.0"
lodash "^4.2.0"
@@ -550,9 +555,9 @@ babel-jest@^16.0.0:
babel-plugin-istanbul "^2.0.0"
babel-preset-jest "^16.0.0"
babel-loader@^6.2.4, babel-loader@^6.2.5:
version "6.2.8"
resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-6.2.8.tgz#30d7183aef60afc140b36443676b7acb4c12ac9c"
babel-loader@^6.2.10, babel-loader@^6.2.4:
version "6.2.10"
resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-6.2.10.tgz#adefc2b242320cd5d15e65b31cea0e8b1b02d4b0"
dependencies:
find-cache-dir "^0.1.1"
loader-utils "^0.2.11"
@@ -634,7 +639,7 @@ babel-plugin-transform-async-to-generator@^6.16.0, babel-plugin-transform-async-
babel-plugin-syntax-async-functions "^6.8.0"
babel-runtime "^6.0.0"
babel-plugin-transform-class-properties@6.16.0:
babel-plugin-transform-class-properties@6.16.0, babel-plugin-transform-class-properties@^6.5.0:
version "6.16.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-class-properties/-/babel-plugin-transform-class-properties-6.16.0.tgz#969bca24d34e401d214f36b8af5c1346859bc904"
dependencies:
@@ -642,15 +647,6 @@ babel-plugin-transform-class-properties@6.16.0:
babel-plugin-syntax-class-properties "^6.8.0"
babel-runtime "^6.9.1"
babel-plugin-transform-class-properties@^6.5.0:
version "6.19.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-class-properties/-/babel-plugin-transform-class-properties-6.19.0.tgz#1274b349abaadc835164e2004f4a2444a2788d5f"
dependencies:
babel-helper-function-name "^6.18.0"
babel-plugin-syntax-class-properties "^6.8.0"
babel-runtime "^6.9.1"
babel-template "^6.15.0"
babel-plugin-transform-es2015-arrow-functions@^6.3.13, babel-plugin-transform-es2015-arrow-functions@^6.5.0:
version "6.8.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.8.0.tgz#5b63afc3181bdc9a8c4d481b5a4f3f7d7fef3d9d"
@@ -858,20 +854,13 @@ babel-plugin-transform-object-assign@^6.5.0:
dependencies:
babel-runtime "^6.0.0"
babel-plugin-transform-object-rest-spread@6.16.0:
babel-plugin-transform-object-rest-spread@6.16.0, babel-plugin-transform-object-rest-spread@^6.5.0:
version "6.16.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.16.0.tgz#db441d56fffc1999052fdebe2e2f25ebd28e36a9"
dependencies:
babel-plugin-syntax-object-rest-spread "^6.8.0"
babel-runtime "^6.0.0"
babel-plugin-transform-object-rest-spread@^6.5.0:
version "6.19.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.19.0.tgz#f6ac428ee3cb4c6aa00943ed1422ce813603b34c"
dependencies:
babel-plugin-syntax-object-rest-spread "^6.8.0"
babel-runtime "^6.0.0"
babel-plugin-transform-react-constant-elements@6.9.1:
version "6.9.1"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-constant-elements/-/babel-plugin-transform-react-constant-elements-6.9.1.tgz#125b86d96cb322e2139b607fd749ad5fbb17f005"
@@ -1046,9 +1035,9 @@ babel-preset-react-app@^1.0.0:
babel-preset-react "6.16.0"
babel-runtime "6.11.6"
babel-preset-react-native@^1.9.0:
version "1.9.0"
resolved "https://registry.yarnpkg.com/babel-preset-react-native/-/babel-preset-react-native-1.9.0.tgz#035fc06c65f4f2a02d0336a100b2da142f36dab1"
babel-preset-react-native@^1.9.1:
version "1.9.1"
resolved "https://registry.yarnpkg.com/babel-preset-react-native/-/babel-preset-react-native-1.9.1.tgz#ec8e378274410d78f550fa9f8edd70353f3bb2fe"
dependencies:
babel-plugin-check-es2015-constants "^6.5.0"
babel-plugin-react-transform "2.0.2"
@@ -1111,12 +1100,12 @@ babel-runtime@6.11.6:
core-js "^2.4.0"
regenerator-runtime "^0.9.5"
babel-runtime@6.x.x, babel-runtime@^6.0.0, babel-runtime@^6.11.6, babel-runtime@^6.18.0, babel-runtime@^6.5.0, babel-runtime@^6.9.0, babel-runtime@^6.9.1, babel-runtime@^6.9.2:
version "6.18.0"
resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.18.0.tgz#0f4177ffd98492ef13b9f823e9994a02584c9078"
babel-runtime@6.x.x, babel-runtime@^6.0.0, babel-runtime@^6.11.6, babel-runtime@^6.18.0, babel-runtime@^6.20.0, babel-runtime@^6.5.0, babel-runtime@^6.9.0, babel-runtime@^6.9.1, babel-runtime@^6.9.2:
version "6.20.0"
resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.20.0.tgz#87300bdcf4cd770f09bf0048c64204e17806d16f"
dependencies:
core-js "^2.4.0"
regenerator-runtime "^0.9.5"
regenerator-runtime "^0.10.0"
babel-template@^6.14.0, babel-template@^6.15.0, babel-template@^6.16.0, babel-template@^6.8.0:
version "6.16.0"
@@ -1128,30 +1117,30 @@ babel-template@^6.14.0, babel-template@^6.15.0, babel-template@^6.16.0, babel-te
babylon "^6.11.0"
lodash "^4.2.0"
babel-traverse@^6.0.20, babel-traverse@^6.16.0, babel-traverse@^6.18.0:
version "6.19.0"
resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.19.0.tgz#68363fb821e26247d52a519a84b2ceab8df4f55a"
babel-traverse@^6.15.0, babel-traverse@^6.16.0, babel-traverse@^6.18.0, babel-traverse@^6.21.0:
version "6.21.0"
resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.21.0.tgz#69c6365804f1a4f69eb1213f85b00a818b8c21ad"
dependencies:
babel-code-frame "^6.16.0"
babel-code-frame "^6.20.0"
babel-messages "^6.8.0"
babel-runtime "^6.9.0"
babel-types "^6.19.0"
babel-runtime "^6.20.0"
babel-types "^6.21.0"
babylon "^6.11.0"
debug "^2.2.0"
globals "^9.0.0"
invariant "^2.2.0"
lodash "^4.2.0"
babel-types@^6.0.19, babel-types@^6.16.0, babel-types@^6.18.0, babel-types@^6.19.0, babel-types@^6.8.0, babel-types@^6.9.0:
version "6.19.0"
resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.19.0.tgz#8db2972dbed01f1192a8b602ba1e1e4c516240b9"
babel-types@^6.15.0, babel-types@^6.16.0, babel-types@^6.18.0, babel-types@^6.21.0, babel-types@^6.8.0, babel-types@^6.9.0:
version "6.21.0"
resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.21.0.tgz#314b92168891ef6d3806b7f7a917fdf87c11a4b2"
dependencies:
babel-runtime "^6.9.1"
babel-runtime "^6.20.0"
esutils "^2.0.2"
lodash "^4.2.0"
to-fast-properties "^1.0.1"
babylon@^6.0.18, babylon@^6.11.0, babylon@^6.13.0:
babylon@^6.11.0, babylon@^6.13.0:
version "6.14.1"
resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.14.1.tgz#956275fab72753ad9b3435d7afe58f8bf0a29815"
@@ -1209,11 +1198,14 @@ bowser@^1.0.0:
version "1.5.0"
resolved "https://registry.yarnpkg.com/bowser/-/bowser-1.5.0.tgz#b97414bacbc631f19f1e2e11466566ec19324983"
boxen@^0.3.1:
version "0.3.1"
resolved "https://registry.yarnpkg.com/boxen/-/boxen-0.3.1.tgz#a7d898243ae622f7abb6bb604d740a76c6a5461b"
boxen@^0.6.0:
version "0.6.0"
resolved "https://registry.yarnpkg.com/boxen/-/boxen-0.6.0.tgz#8364d4248ac34ff0ef1b2f2bf49a6c60ce0d81b6"
dependencies:
ansi-align "^1.1.0"
camelcase "^2.1.0"
chalk "^1.1.1"
cli-boxes "^1.0.0"
filled-array "^1.0.0"
object-assign "^4.0.1"
repeating "^2.0.0"
@@ -1308,7 +1300,7 @@ camelcase@^1.0.2:
version "1.2.1"
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39"
camelcase@^2.0.0:
camelcase@^2.0.0, camelcase@^2.1.0:
version "2.1.1"
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f"
@@ -1418,6 +1410,10 @@ classnames@^2.2.3:
version "2.2.5"
resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.5.tgz#fb3801d453467649ef3603c7d61a02bd129bde6d"
cli-boxes@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-1.0.0.tgz#4fa917c3e59c94a004cd61f8ee509da651687143"
cli-cursor@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987"
@@ -1826,13 +1822,13 @@ defined@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693"
del-cli@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/del-cli/-/del-cli-0.2.0.tgz#33dc01793d5a4cd8d64c2ab39c33c3e6658ec4ce"
del-cli@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/del-cli/-/del-cli-0.2.1.tgz#d5f8ca540e8ab89b2d903075ae47113c72a6d937"
dependencies:
del "^2.2.0"
meow "^3.6.0"
update-notifier "^0.6.0"
update-notifier "^1.0.3"
del@^2.0.2, del@^2.2.0:
version "2.2.2"
@@ -2045,7 +2041,7 @@ es6-map@^0.1.3:
es6-symbol "~3.1.0"
event-emitter "~0.3.4"
es6-set@^0.1.4, es6-set@~0.1.3:
es6-set@~0.1.3:
version "0.1.4"
resolved "https://registry.yarnpkg.com/es6-set/-/es6-set-0.1.4.tgz#9516b6761c2964b92ff479456233a247dc707ce8"
dependencies:
@@ -2314,6 +2310,18 @@ fbjs@^0.8.1, fbjs@^0.8.4:
promise "^7.1.1"
ua-parser-js "^0.7.9"
fbjs@^0.8.8:
version "0.8.8"
resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.8.tgz#02f1b6e0ea0d46c24e0b51a2d24df069563a5ad6"
dependencies:
core-js "^1.0.0"
isomorphic-fetch "^2.1.1"
loose-envify "^1.0.0"
object-assign "^4.1.0"
promise "^7.1.1"
setimmediate "^1.0.5"
ua-parser-js "^0.7.9"
figures@^1.3.5:
version "1.7.0"
resolved "https://registry.yarnpkg.com/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e"
@@ -2805,9 +2813,9 @@ ini@~1.3.0:
version "1.3.4"
resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.4.tgz#0537cb79daf59b59a1a517dff706c86ec039162e"
inline-style-prefixer@^2.0.1:
version "2.0.4"
resolved "https://registry.yarnpkg.com/inline-style-prefixer/-/inline-style-prefixer-2.0.4.tgz#3134989ee8723e141161726e0eaaec7db36b413f"
inline-style-prefixer@^2.0.5:
version "2.0.5"
resolved "https://registry.yarnpkg.com/inline-style-prefixer/-/inline-style-prefixer-2.0.5.tgz#c153c7e88fd84fef5c602e95a8168b2770671fe7"
dependencies:
bowser "^1.0.0"
hyphenate-style-name "^1.0.1"
@@ -3463,6 +3471,10 @@ lazy-cache@^1.0.3:
version "1.0.4"
resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e"
lazy-req@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/lazy-req/-/lazy-req-1.1.0.tgz#bdaebead30f8d824039ce0ce149d4daa07ba1fac"
lcid@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835"
@@ -3572,7 +3584,7 @@ lodash.assign@^3.2.0:
lodash._createassigner "^3.0.0"
lodash.keys "^3.0.0"
lodash.assign@^4.0.0, lodash.assign@^4.1.0, lodash.assign@^4.2.0:
lodash.assign@^4.1.0, lodash.assign@^4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-4.2.0.tgz#0d99f3ccd7a6d261d19bdaeb9245005d285808e7"
@@ -3651,7 +3663,7 @@ lodash.pick@^4.2.0, lodash.pick@^4.2.1, lodash.pick@^4.4.0:
version "4.4.0"
resolved "https://registry.yarnpkg.com/lodash.pick/-/lodash.pick-4.4.0.tgz#52f05610fff9ded422611441ed1fc123a03001b3"
lodash.pickby@^4.0.0:
lodash.pickby@^4.6.0:
version "4.6.0"
resolved "https://registry.yarnpkg.com/lodash.pickby/-/lodash.pickby-4.6.0.tgz#7dea21d8c18d7703a27c704c15d3b84a67e33aff"
@@ -3738,6 +3750,10 @@ marked@^0.3.6:
version "0.3.6"
resolved "https://registry.yarnpkg.com/marked/-/marked-0.3.6.tgz#b2c6c618fccece4ef86c4fc6cb8a7cbf5aeda8d7"
marky@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/marky/-/marky-1.1.1.tgz#dcd1eba3e2c6412619a76981f635b3698a8761e8"
math-expression-evaluator@^1.2.14:
version "1.2.14"
resolved "https://registry.yarnpkg.com/math-expression-evaluator/-/math-expression-evaluator-1.2.14.tgz#39511771ed9602405fba9affff17eb4d2a3843ab"
@@ -4013,6 +4029,10 @@ nopt@3.x, nopt@~3.0.6:
dependencies:
abbrev "1"
normalize-css-color@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/normalize-css-color/-/normalize-css-color-1.0.1.tgz#792f59cae25036950a9127cfcfddc073048f4f9d"
normalize-package-data@^2.3.2, normalize-package-data@^2.3.4:
version "2.3.5"
resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.3.5.tgz#8d924f142960e1777e7ffe170543631cc7cb02df"
@@ -4922,6 +4942,10 @@ regenerate@^1.2.1:
version "1.3.2"
resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.3.2.tgz#d1941c67bad437e1be76433add5b385f95b19260"
regenerator-runtime@^0.10.0:
version "0.10.1"
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.1.tgz#257f41961ce44558b18f7814af48c17559f9faeb"
regenerator-runtime@^0.9.5:
version "0.9.6"
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.9.6.tgz#d33eb95d0d2001a4be39659707c51b0cb71ce029"
@@ -5139,6 +5163,10 @@ set-immediate-shim@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61"
setimmediate@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285"
setprototypeof@1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.0.2.tgz#81a552141ec104b88e89ce383103ad5c66564d08"
@@ -5448,10 +5476,6 @@ timers-browserify@^1.0.1:
dependencies:
process "~0.11.0"
tinycolor@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/tinycolor/-/tinycolor-0.0.1.tgz#320b5a52d83abb5978d81a3e887d4aefb15a6164"
tmpl@1.0.x:
version "1.0.4"
resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1"
@@ -5554,16 +5578,18 @@ unzip-response@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/unzip-response/-/unzip-response-1.0.2.tgz#b984f0877fc0a89c2c773cc1ef7b5b232b5b06fe"
update-notifier@^0.6.0:
version "0.6.3"
resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-0.6.3.tgz#776dec8daa13e962a341e8a1d98354306b67ae08"
update-notifier@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-1.0.3.tgz#8f92c515482bd6831b7c93013e70f87552c7cf5a"
dependencies:
boxen "^0.3.1"
boxen "^0.6.0"
chalk "^1.0.0"
configstore "^2.0.0"
is-npm "^1.0.0"
latest-version "^2.0.0"
lazy-req "^1.1.0"
semver-diff "^2.0.0"
xdg-basedir "^2.0.0"
url-loader@^0.5.7:
version "0.5.7"