Compare commits

...

100 Commits

Author SHA1 Message Date
Nicolas Gallagher
b545fe47a7 0.2.2 2017-12-20 23:07:21 +00:00
Mo Kouli
4da4dd57c4 [fix] AppContainer initial state
Regression introduced in:
217ad97bfd

Close #738
2017-12-20 23:05:00 +00:00
Nicolas Gallagher
3e12ddfb2b 0.2.1 2017-12-20 17:31:25 +00:00
Johannes
3ecf5d2ed2 [fix] corrupt hydrate import 2017-12-20 17:45:45 +01:00
Nicolas Gallagher
0a5acdb996 Update version in benchmark results table 2017-12-20 15:05:58 +00:00
Nicolas Gallagher
a712a58eba 0.2.0 2017-12-20 15:01:12 +00:00
Nicolas Gallagher
6de892c92b [add] CheckBox component
Implements the CheckBox component and adds a web-only 'color' prop to
allow the color of the checkbox to be customized.
2017-12-20 14:51:44 +00:00
Nicolas Gallagher
495defd69b [fix] StyleSheet.hairlineWidth on retina screens 2017-12-20 11:54:13 +00:00
Nicolas Gallagher
1a20fcfce6 [add] StyleSheet.compose
As per the recent addition to React Native.
2017-12-20 11:27:57 +00:00
Nicolas Gallagher
ed1e45a43d Link to yarnpkg website instead of npmjs 2017-12-20 11:13:17 +00:00
Nicolas Gallagher
556dc8926e [fix] ScrollView animated scrollTo
Rely on web's native smooth scrolling mechanism when implemented in the
browser: https://developer.mozilla.org/en-US/docs/Web/CSS/scroll-behavior

Fix #593
2017-12-19 15:52:30 +00:00
Nicolas Gallagher
66cf45b90b Update benchmark libraries and results
* Update all packages.
* Remove 'react-native-stylesheet'; since React 16 it is equivalent in
  performance to using the full 'react-native-web' View implementation.
* Remove 'styled-components/primitives'; it's as slow as
  'styled-components'.
* Record latest benchmark results and hardware.
2017-12-19 15:27:05 +00:00
Nicolas Gallagher
d1e49e06e6 Remove unmaintained starter kit 2017-12-18 17:49:51 +00:00
Nicolas Gallagher
8bf28dbe43 Document more instance methods in Direct Manipulation guide
Fix #704
2017-12-18 17:45:23 +00:00
Nicolas Gallagher
9ae95d0797 Add further details to Getting Started guide
Close #728
2017-12-18 17:33:44 +00:00
Nicolas Gallagher
321051b723 [add] ART export
Improve API compatibility with React Native by exporting 'react-art' as
'ART'.

Fix #602
2017-12-18 17:16:09 +00:00
Nicolas Gallagher
5f68542529 [fix] Touchable use with react-test-renderer
The object returned by 'ReactDOM.findDOMNode' when rendered by
'react-test-renderer' doesn't match the DOM API for an element. Only
attempt to bind the listener if 'addEventListener' is present on the
object.

Fix #720
2017-12-18 16:35:45 +00:00
Nicolas Gallagher
82c044ee33 [fix] use ReactDOM.hydrate in AppRegistry.runApplication
Allows AppRegistry to hydrate server-side rendered apps.

Fix #733
2017-12-18 16:15:47 +00:00
Nicolas Gallagher
9bcc67e73a [fix] top-level API exports
Also fixes importing these APIs from 'react-native' when used with the
Babel plugin.
2017-12-18 16:15:03 +00:00
Nicolas Gallagher
f1ce6c2acb [fix] AppRegistry.getApplication style element keys
Fix #734
2017-12-18 15:26:18 +00:00
Nicolas Gallagher
034108a2a0 [add] SafeAreaView component 2017-12-06 14:34:22 -08:00
Nicolas Gallagher
f96d7b868f [change] update PanResponder implementation
Fix #171
2017-12-06 14:23:35 -08:00
Nicolas Gallagher
0dfe319d41 [change] update the Animated implementation
Replaces the 'animated' package with the latest implementation from
React Native. Requires a few imports to be replaced.

Close #716
Fix #714
Fix #688
2017-12-06 14:01:36 -08:00
Kenneth Kufluk
b7e970f4e6 [add] Picker and Picker.Item components
Close #705
2017-12-04 16:15:23 -08:00
Nicolas Gallagher
02e62ad5d6 Lint fixes 2017-12-02 16:08:56 -08:00
Nicolas Gallagher
541d2458fb [change] Image no longer accepts children
Align with recent changes to the React Native API.
2017-12-02 16:04:27 -08:00
Nicolas Gallagher
b1e860ab40 Add ImageBackground docs 2017-12-02 16:04:27 -08:00
Louis Lagrange
e8eab9b3ec [add] ImageBackground component
Close #696
2017-12-02 16:04:19 -08:00
Nicolas Gallagher
6bc76c3c92 Update yarn script syntax 2017-12-02 15:58:47 -08:00
Nicolas Gallagher
2acd8e477c Update raf and debounce modules 2017-12-02 15:58:47 -08:00
Nicolas Gallagher
ff2b0c9bdc Update to React@16.2 dev dependencies 2017-12-02 15:58:47 -08:00
Nicolas Gallagher
79208720d1 Update webpack tools 2017-12-02 15:58:47 -08:00
Nicolas Gallagher
fca04c4125 Update enzyme 2017-12-02 15:58:47 -08:00
Nicolas Gallagher
5b5b72cc19 Update eslint and prettier 2017-12-02 15:58:47 -08:00
Nicolas Gallagher
217ad97bfd [change] Update Flow and types 2017-12-02 15:58:47 -08:00
Nicolas Gallagher
3e3cfc5325 0.1.16 2017-12-02 14:48:35 -08:00
Nicolas Gallagher
da86ea98fc [fix] NetInfo event listeners and types
* Fix 'addEventListener' handler registration.
* Fix event object provided to handlers.
* Fix event object type - always include 'type' and 'effectiveType'.
* Fix unit test semantics.
* Fix documented NetInfo types.

Close #724
2017-12-02 12:47:12 -08:00
Nicolas Gallagher
5f3e422b5c 0.1.15 2017-12-01 17:55:17 -08:00
Nicolas Gallagher
1f1f89b062 [fix] Image 'onLoad' callback on update
'onLoad' should not be called when a component updates, if the 'uri' is
unchanged.

Fixes a regression introduced by
92952ee746
2017-12-01 17:52:47 -08:00
Nicolas Gallagher
0f79960b85 0.1.14 2017-11-15 15:21:45 -08:00
Nicolas Gallagher
117ce59f27 [fix] TextInput focus/blur management
1. Focusing/blurring a TextInput should update TextInputState.
2. Using the focus/blur instance methods should trigger related events.

Close #715
2017-11-15 15:20:21 -08:00
Louis Lagrange
214121480e [fix] stub for Picker.Item
Add stub function for API compatibility.

Close #690
2017-11-15 14:45:33 -08:00
Li Jie
6261536f57 Fix benchmarks documentation
Close #706
2017-11-15 14:43:13 -08:00
Nicolas Gallagher
a748b7e606 [fix] ScrollView 'setNativeProps'
Fix #709
Close #710
2017-11-15 14:39:58 -08:00
Zero Cho
92952ee746 [fix] call Image 'onLoad' when image is loaded from cache
Fix #452
Close #712
2017-11-15 13:33:13 -08:00
Nicolas Gallagher
c22a9aff7d 0.1.13 2017-10-31 10:56:36 -07:00
Nicolas Gallagher
dd8a3c8d59 [fix] StyleSheet handling of default 'borderWidth'
Problem:

The default border width should be '0px', but setting a border width
value to 'null' would override the default and result in no border width
being applied to the element. This could cause unwanted user agent
styles to be applied.

Solution:

createReactDOMStyle now replaces border width values of 'null' with
'0px'.

Fix #697
2017-10-30 22:42:52 -07:00
Nicolas Gallagher
4a1abee1df Update benchmarks packages 2017-10-30 14:45:13 -07:00
Nicolas Gallagher
92ef3ffbb8 0.1.12 2017-10-20 11:29:45 -07:00
Nicolas Gallagher
899763bc34 [fix] zIndex stacking
React Native simplifies zIndex stacking by making every 'View' a new
stacking context.

Fix #689
2017-10-19 13:16:36 -07:00
Nicolas Gallagher
c69ad3c2d6 Update presentation of Image docs 2017-10-19 12:42:45 -07:00
Nicolas Gallagher
9a5b932139 Flatten styles in test snapshots 2017-10-19 12:42:05 -07:00
Nicolas Gallagher
ba96e457b4 0.1.11 2017-10-18 11:10:59 -07:00
Nicolas Gallagher
bdfe943bd5 0.1.10 2017-10-18 11:08:15 -07:00
Nicolas Gallagher
3870445b7e [add] jest snapshot serializer
Flatten style objects in snapshots
2017-10-17 17:36:34 -07:00
Nicolas Gallagher
5395a3e8bc 0.1.9 2017-10-13 13:25:52 -07:00
Nicolas Gallagher
45b3d8b0df [fix] style warnings for text and SVG
Allow 'fill' as a valid style property.
Allow 'textAlignVertical' to be any string.
2017-10-13 13:17:27 -07:00
Jaco Bovenschen
f1ee3c003a Fix typo in Dimensions doc
Close #682
2017-10-13 10:53:35 -07:00
Nicolas Gallagher
606181406c 0.1.8 2017-10-11 15:14:43 -07:00
Nicolas Gallagher
b537400f38 [fix] remove 'module' from package.json
This is properly supported and there are no ES6 modules in the package at
the moment.
2017-10-11 15:02:58 -07:00
Nicolas Gallagher
0a4fdc155e [fix] babel plugin 'source' check 2017-10-11 15:02:12 -07:00
Nicolas Gallagher
0b8e59974b 0.1.7 2017-10-09 13:14:01 -07:00
Jirat Kijlerdpornpailoj
22eebea633 [fix] babel plugin support for "export" statements
Close #677
2017-10-06 14:22:00 -07:00
Nicolas Gallagher
5dd414f9aa 0.1.6 2017-10-05 19:05:13 -07:00
Louis Lagrange
72c72f6530 [fix] AsyncStorage.flushGetRequests
Add stub function for API compatibility.

Close #676
2017-10-05 19:03:43 -07:00
Nicolas Gallagher
de970f9dbb Add more tests for Switch 2017-10-05 13:59:59 -07:00
Nicolas Gallagher
e8d6c5b4dd Helper function for ActivityIndicator SVGs 2017-10-05 13:59:42 -07:00
Tiaan
e91a5ae13e Add missing comma to example webpack config
Close #671
2017-10-04 11:54:22 -07:00
Nicolas Gallagher
b08bfb9ad5 0.1.5 2017-10-04 11:49:22 -07:00
Nicolas Gallagher
5353011ee4 [fix] BackHandler export; remove BackAndroid
Fix #673
2017-10-04 11:45:28 -07:00
Nicolas Gallagher
5faa3af19a 0.1.4 2017-10-03 10:58:32 -07:00
Jhen
c8461c9c11 [fix] Babel plugin import paths for ViewPropTypes and TextPropTypes
Close #668
2017-10-03 10:53:55 -07:00
Nicolas Gallagher
3112e2ba56 0.1.3 2017-10-02 10:14:18 -07:00
Nicolas Gallagher
fee03e101c [fix] exports from module.js
Fix #666
2017-10-02 10:13:45 -07:00
Nicolas Gallagher
c730a20a26 Update formatter 2017-10-01 17:01:27 -07:00
Nicolas Gallagher
f7ed60ac67 Update test tools 2017-10-01 17:00:04 -07:00
Nicolas Gallagher
417716391a Update build tools 2017-10-01 16:59:00 -07:00
Nicolas Gallagher
ee5e3cb3ca Update eslint packages 2017-10-01 16:54:29 -07:00
Nicolas Gallagher
2298c5d6e3 0.1.2 2017-10-01 16:40:41 -07:00
Jirat Kijlerdpornpailoj
ca9f870ff6 [fix] Image.getSize failure callback
Fix #561
Close #665
2017-10-01 16:33:47 -07:00
Nicolas Gallagher
e9b2fd8bc4 0.1.1 2017-09-29 16:45:48 -07:00
Nicolas Gallagher
09a4985fd2 Remove markdown component and api docs 2017-09-28 14:49:51 -07:00
Nicolas Gallagher
a9e61b4cd5 Docs: allow AppText to inherit font-size 2017-09-28 14:49:51 -07:00
Charlie Croom
6ef19c3ccd [fix] latest NetInfo API
Update the NetInfo API to conform to the latest React Native
implementation. Web-only properties are also included now.

Fix #662
Close #663
2017-09-28 14:49:50 -07:00
Nicolas Gallagher
0d29458874 Remove links to unmaintained starter kits 2017-09-28 13:04:21 -07:00
Amogh Banta
1795bae8b5 Add re-start to starter kits 2017-09-27 09:06:45 -07:00
Nicolas Gallagher
c1152ee09a Update README install instructions 2017-09-26 10:30:48 -07:00
Nicolas Gallagher
182149aac7 0.1.0 2017-09-26 10:21:04 -07:00
Nicolas Gallagher
d6df440987 [change] React 16 support
Fix #364
2017-09-26 10:14:34 -07:00
Nicolas Gallagher
df16c24d68 0.0.130 2017-09-25 14:47:38 -07:00
Nicolas Gallagher
8a2c259235 Update inline-style-prefixer 2017-09-21 14:55:52 -07:00
Nicolas Gallagher
a7f265de11 Update test tools 2017-09-21 14:52:07 -07:00
Nicolas Gallagher
581529540a Update build tools 2017-09-21 14:50:42 -07:00
Nicolas Gallagher
8ad61d9061 Update formatter 2017-09-21 14:49:31 -07:00
Nicolas Gallagher
3d79861970 0.0.129 2017-09-21 14:20:37 -07:00
Nicolas Gallagher
0a84ccb299 [fix] IE10 flexbox support
Add prefixes for flexbox (and other) support in IE10.

Ref #650
2017-09-21 14:18:11 -07:00
Nicolas Gallagher
3aa37450a0 Improve error message for text nodes in View 2017-09-21 14:04:41 -07:00
Nicolas Gallagher
450722153d 0.0.128 2017-09-20 09:45:25 -07:00
Nicolas Gallagher
fbba32defb [fix] cross-browser flex styles
Fix #616
Close #648
2017-09-19 15:44:10 -07:00
Nicolas Gallagher
d762d64b49 Revert SSR Image change
Reverts 3c660e2ad7

See #543
2017-09-19 15:23:09 -07:00
187 changed files with 8909 additions and 3857 deletions

View File

@@ -2,7 +2,6 @@
.*/__tests__/.*
.*/benchmarks/.*
.*/docs/.*
.*/node_modules/animated/*
.*/node_modules/babel-plugin-transform-react-remove-prop-types/*
[include]

View File

@@ -5,5 +5,4 @@ before_script:
- export DISPLAY=:99.0
- sh -e /etc/init.d/xvfb start
script:
- npm run lint
- npm test
- yarn lint

View File

@@ -23,12 +23,10 @@ it out](https://glitch.com/edit/#!/react-native-web-playground) on Glitch.
## Quick start
NOTE: React Native for Web supports React/ReactDOM 15.4, 15.5, or 15.6.
Install in your existing app using `yarn` or `npm`:
```
yarn add react@15.6 react-dom@15.6 react-native-web
yarn add react react-dom react-native-web
```
Add the `react-native-web/babel` plugin to your Babel configuration. This will
@@ -46,6 +44,8 @@ by the app.
}
```
(For React/ReactDOM 15.4 15.6 support, install `react-native-web@<0.1.0`)
See the [Getting Started](docs/guides/getting-started.md) guide for more details.
## Documentation
@@ -64,13 +64,6 @@ Guides:
* [Advanced use](docs/guides/advanced.md)
* [Known issues](docs/guides/known-issues.md)
## Starter kits
* [Glitch](https://glitch.com/edit/#!/react-native-web-playground)
* [create-react-app](https://github.com/facebookincubator/create-react-app)
* [react-native-web-starter](https://github.com/grabcode/react-native-web-starter)
* [react-native-web-webpack](https://github.com/ndbroadbent/react-native-web-webpack)
## Example code
```js
@@ -110,6 +103,11 @@ AppRegistry.registerComponent('MyApp', () => App)
AppRegistry.runApplication('MyApp', { rootTag: document.getElementById('react-root') })
```
## Starter kits
* [Glitch](https://glitch.com/edit/#!/react-native-web-playground)
* [create-react-app](https://github.com/facebookincubator/create-react-app)
## Related projects
* [react-primitives](https://github.com/lelandrichardson/react-primitives/)
@@ -122,7 +120,7 @@ AppRegistry.runApplication('MyApp', { rootTag: document.getElementById('react-ro
React Native for Web is [BSD licensed](LICENSE).
[npm-image]: https://badge.fury.io/js/react-native-web.svg
[npm-url]: https://npmjs.org/package/react-native-web
[npm-url]: https://yarnpkg.com/en/package/react-native-web
[react-native-url]: https://facebook.github.io/react-native/
[travis-image]: https://travis-ci.org/necolas/react-native-web.svg?branch=master
[travis-url]: https://travis-ci.org/necolas/react-native-web

View File

@@ -12,13 +12,14 @@ import View from 'react-native-web/dist/components/View';
exports[`2. Rewrite react-native paths for react-native-web 1`] = `
"
import { Switch, Text, View as MyView } from 'react-native';
import { Switch, Text, View as MyView, ViewPropTypes } from 'react-native';
↓ ↓ ↓ ↓ ↓ ↓
import Switch from 'react-native-web/dist/components/Switch';
import Text from 'react-native-web/dist/components/Text';
import MyView from 'react-native-web/dist/components/View';
import ViewPropTypes from 'react-native-web/dist/components/View/ViewPropTypes';
"
`;
@@ -102,3 +103,59 @@ const { InvalidThing, TouchableOpacity } = require('react-native');
const TouchableOpacity = require('react-native-web/dist/components/Touchable/TouchableOpacity');
"
`;
exports[`10. Rewrite react-native paths for react-native-web 1`] = `
"
export { View } from 'react-native';
↓ ↓ ↓ ↓ ↓ ↓
export { default as View } from 'react-native-web/dist/components/View';
"
`;
exports[`11. Rewrite react-native paths for react-native-web 1`] = `
"
export { Switch, Text, View as MyView, ViewPropTypes } from 'react-native';
↓ ↓ ↓ ↓ ↓ ↓
export { default as Switch } from 'react-native-web/dist/components/Switch';
export { default as Text } from 'react-native-web/dist/components/Text';
export { default as MyView } from 'react-native-web/dist/components/View';
export { default as ViewPropTypes } from 'react-native-web/dist/components/View/ViewPropTypes';
"
`;
exports[`12. Rewrite react-native paths for react-native-web 1`] = `
"
export { createElement, Switch, StyleSheet } from 'react-native';
↓ ↓ ↓ ↓ ↓ ↓
export { default as createElement } from 'react-native-web/dist/modules/createElement';
export { default as Switch } from 'react-native-web/dist/components/Switch';
export { default as StyleSheet } from 'react-native-web/dist/apis/StyleSheet';
"
`;
exports[`13. Rewrite react-native paths for react-native-web 1`] = `
"
export { InvalidThing, TouchableOpacity } from 'react-native';
↓ ↓ ↓ ↓ ↓ ↓
export { InvalidThing } from 'react-native-web';
export { default as TouchableOpacity } from 'react-native-web/dist/components/Touchable/TouchableOpacity';
"
`;
exports[`14. Rewrite react-native paths for react-native-web 1`] = `
"
export { default as RNW } from 'react-native';
↓ ↓ ↓ ↓ ↓ ↓
export { default as RNW } from 'react-native-web';
"
`;

View File

@@ -7,7 +7,7 @@ pluginTester({
tests: [
// import react-native
"import { View } from 'react-native';",
"import { Switch, Text, View as MyView } from 'react-native';",
"import { Switch, Text, View as MyView, ViewPropTypes } from 'react-native';",
"import { createElement, Switch, StyleSheet } from 'react-native';",
"import { InvalidThing, TouchableOpacity } from 'react-native';",
"import * as RNW from 'react-native';",
@@ -30,6 +30,13 @@ pluginTester({
// "let { Switch, Text, View: MyView } = require('react-native-web');",
// "var { createElement, Switch, StyleSheet } = require('react-native-web');",
// "const { InvalidThing, TouchableOpacity } = require('react-native-web');",
// export react-native
"export { View } from 'react-native';",
"export { Switch, Text, View as MyView, ViewPropTypes } from 'react-native';",
"export { createElement, Switch, StyleSheet } from 'react-native';",
"export { InvalidThing, TouchableOpacity } from 'react-native';",
"export { default as RNW } from 'react-native';",
{
code: "const RNW = require('react-native');",
output: "const RNW = require('react-native');",

View File

@@ -7,7 +7,7 @@ const getDistLocation = importName => {
case 'AppRegistry':
case 'AppState':
case 'AsyncStorage':
case 'BackAndroid':
case 'BackHandler':
case 'Clipboard':
case 'Dimensions':
case 'Easing':
@@ -27,6 +27,7 @@ const getDistLocation = importName => {
// components
case 'ActivityIndicator':
case 'ART':
case 'Button':
case 'FlatList':
case 'Image':
@@ -69,11 +70,15 @@ const getDistLocation = importName => {
// propTypes
case 'ColorPropType':
case 'EdgeInsetsPropType':
case 'PointPropType':
case 'TextPropTypes':
case 'ViewPropTypes': {
case 'PointPropType': {
return `${root}/propTypes/${importName}`;
}
case 'TextPropTypes': {
return `${root}/components/Text/${importName}`;
}
case 'ViewPropTypes': {
return `${root}/components/View/${importName}`;
}
default:
return;
@@ -102,7 +107,7 @@ module.exports = function({ types: t }) {
visitor: {
ImportDeclaration(path) {
const { source, specifiers } = path.node;
if (source.value === 'react-native' && specifiers.length) {
if (source && source.value === 'react-native' && specifiers.length) {
const imports = specifiers
.map(specifier => {
if (t.isImportSpecifier(specifier)) {
@@ -123,6 +128,35 @@ module.exports = function({ types: t }) {
path.replaceWithMultiple(imports);
}
},
ExportNamedDeclaration(path) {
const { source, specifiers } = path.node;
if (source && source.value === 'react-native' && specifiers.length) {
const exports = specifiers
.map(specifier => {
if (t.isExportSpecifier(specifier)) {
const exportName = specifier.exported.name;
const localName = specifier.local.name;
const distLocation = getDistLocation(localName);
if (distLocation) {
return t.exportNamedDeclaration(
null,
[t.exportSpecifier(t.identifier('default'), t.identifier(exportName))],
t.stringLiteral(distLocation)
);
}
return t.exportNamedDeclaration(
null,
[specifier],
t.stringLiteral('react-native-web')
);
}
})
.filter(Boolean);
path.replaceWithMultiple(exports);
}
},
VariableDeclaration(path) {
if (isReactNativeRequire(t, path.node)) {
const { id } = path.node.declarations[0];

View File

@@ -1,10 +1,10 @@
# Performance
To run these benchmarks:
To run these benchmarks from the root of the project:
```
npm run build:performance
open ./performance/index.html
yarn benchmark
open ./benchmarks/index.html
```
Append `?fastest` to the URL to include the fastest "other libraries", and
@@ -14,12 +14,9 @@ Append `?fastest` to the URL to include the fastest "other libraries", and
The components used in the render benchmarks are simple enough to be
implemented by multiple UI or style libraries. The implementations are not
equivalent in functionality. For example, React Native for Web's stylesheet is
unique in that it also converts React Native styles to DOM styles, has
deterministic resolution, and supports RTL layout.
`react-native-web/stylesheet` is a comparative baseline that implements a
simple `View` without much of React Native's functionality.
equivalent in functionality. For example, the "React Native for Web" benchmark includes a
complete `View` implementation and the `StyleSheet` also converts React Native
styles to DOM styles, has deterministic resolution, and supports RTL layout.
## Benchmark results
@@ -27,26 +24,24 @@ Typical render timings*: mean ± two standard deviations.
| Implementation | Deep tree (ms) | Wide tree (ms) | Tweets (ms) |
| :--- | ---: | ---: | ---: |
| `css-modules` | `88.83` 18.63` | `198.79` 22.98` | |
| `react-native-web/stylesheet@0.0.121` | `91.17` 19.29` | `209.67` 32.38` | |
| `react-native-web@0.0.121` | `124.21` `±16.84` | `264.55` `±38.75` | `16.90` `±7.30ms` |
| `css-modules` | `80.47` 25.13` | `144.87` 32.70` | |
| `react-native-web@0.2.1` | `88.68` `±28.78` | `178.17` 39.90` | `13.78` `±2.90ms` |
Other libraries
| Implementation | Deep tree (ms) | Wide tree (ms) |
| Implementation | Deep tree (ms) | Wide tree (ms) |
| :--- | ---: | ---: |
| `aphrodite@1.2.3` | `91.73` 41.63` | `197.72` 44.90` |
| `styletron@2.5.1` | `94.73` 37.58` | `201.81` `±57.93` |
| `glamor@2.20.40` | `146.60` `±26.73` | `277.46` 29.17` |
| `emotion@7.2.2` | `150.79` 38.29` | `282.18` 41.79` |
| `react-jss@7.1.0` | `201.83` 34.65` | `428.61` 47.8` |
| `reactxp@0.42.1` | `262.69` `±24.14` | `595.20` 66.17` |
| `styled-components@2.1.2` | `280.59` 31.77` | `599.00` 62.99` |
| `styled-components/primitives@2.1.2` | `291.74` 48.96` | `606.57` 78.18` |
| `radium@0.19.4` | `563.94` `±69.91` | `1139.18` `±152.59` |
| `styletron@3.0.0-rc.5` | `79.41` 27.49` | `152.95` 29.46` |
| `aphrodite@1.2.5` | `85.13` 25.39` | `162.87` 25.91` |
| `glamor@2.20.40` | `109.92` `±29.88` | `193.01` 32.03` |
| `react-jss@8.2.0` | `134.28` 49.00` | `278.78` 50.39` |
| `emotion@8.0.12` | `139.08` 46.18` | `253.45` 52.69` |
| `styled-components@2.3.2` | `194.43` `416.28` | `404.86` 56.59` |
| `reactxp@0.46.6` | `219.46` 57.24` | `424.18` 76.10` |
| `radium@0.19.6` | `359.32` 90.27` | `795.91` 88.93` |
These results indicate that style render performance is not a significant
differentiating factor between `aphrodite`, `css-modules`, `react-native-web`,
and `styletron`.
These results indicate that render times when using `react-native-web`,
`css-modules`, `aphrodite`, and `styletron` are roughly equivalent and
significantly faster than alternatives.
*MacBook Pro (13-inch, Early 2015); 3.1 GHz Intel Core i7; 16 GB 1867 MHz DDR3. Google Chrome 58 (2x CPU slowdown).
*MacBook Pro (13-inch, Early 2011); 2.3 GHz Intel Core i5; 8 GB 1333 MHz DDR3. Google Chrome 62.

View File

@@ -5,9 +5,7 @@ import glamor from './src/glamor';
import jss from './src/jss';
import radium from './src/radium';
import reactNative from './src/react-native';
import reactNativeStyleSheet from './src/react-native-stylesheet';
import styledComponents from './src/styled-components';
import styledComponentsPrimitives from './src/styled-components-primitives';
import styletron from './src/styletron';
import xp from './src/reactxp';
@@ -23,37 +21,33 @@ const coreTests = [
() => renderDeepTree('css-modules', cssModules),
() => renderWideTree('css-modules', cssModules),
() => renderDeepTree('react-native-web/stylesheet', reactNativeStyleSheet),
() => renderWideTree('react-native-web/stylesheet', reactNativeStyleSheet),
() => renderDeepTree('react-native-web', reactNative),
() => renderWideTree('react-native-web', reactNative)
];
const fastestTests = [
() => renderDeepTree('aphrodite', aphrodite),
() => renderWideTree('aphrodite', aphrodite),
() => renderDeepTree('styletron', styletron),
() => renderWideTree('styletron', styletron)
() => renderWideTree('styletron', styletron),
() => renderDeepTree('aphrodite', aphrodite),
() => renderWideTree('aphrodite', aphrodite)
];
/**
* Optionally run tests using other libraries
*/
const restTests = [
() => renderDeepTree('emotion', emotion),
() => renderWideTree('emotion', emotion),
() => renderDeepTree('glamor', glamor),
() => renderWideTree('glamor', glamor),
() => renderDeepTree('radium', radium),
() => renderWideTree('radium', radium),
() => renderDeepTree('reactxp', xp),
() => renderWideTree('reactxp', xp),
() => renderDeepTree('react-jss', jss),
() => renderWideTree('react-jss', jss),
() => renderDeepTree('emotion', emotion),
() => renderWideTree('emotion', emotion),
() => renderDeepTree('styled-components', styledComponents),
() => renderWideTree('styled-components', styledComponents),
() => renderDeepTree('styled-components/primitives', styledComponentsPrimitives),
() => renderWideTree('styled-components/primitives', styledComponentsPrimitives)
() => renderDeepTree('reactxp', xp),
() => renderWideTree('reactxp', xp),
() => renderDeepTree('radium', radium),
() => renderWideTree('radium', radium)
];
const tests = [...coreTests];

View File

@@ -2,21 +2,20 @@
"name": "benchmarks",
"private": true,
"dependencies": {
"aphrodite": "^1.2.3",
"aphrodite": "^1.2.5",
"classnames": "^2.2.5",
"emotion": "^7.2.2",
"emotion": "^8.0.12",
"glamor": "^2.20.40",
"marky": "^1.2.0",
"radium": "^0.19.4",
"react-jss": "^7.1.0",
"react-primitives": "^0.4.3",
"reactxp": "^0.42.1",
"styled-components": "^2.1.2",
"styletron-client": "^2.5.7",
"styletron-utils": "^2.5.4"
"radium": "^0.19.6",
"react-jss": "^8.2.0",
"reactxp": "^0.46.6",
"styled-components": "^2.3.2",
"styletron-client": "^3.0.0-rc.5",
"styletron-utils": "^3.0.0-rc.3"
},
"devDependencies": {
"css-loader": "^0.28.7",
"style-loader": "^0.18.2"
"style-loader": "^0.19.1"
}
}

View File

@@ -1,49 +0,0 @@
/* eslint-disable react/prop-types */
import React from 'react';
import StyleSheet from 'react-native/apis/StyleSheet';
import View from '../View/react-native-stylesheet';
const Box = ({ color, fixed = false, layout = 'column', outer = false, ...other }) => (
<View
{...other}
style={[
styles[`color${color}`],
fixed && styles.fixed,
layout === 'row' && styles.row,
outer && styles.outer
]}
/>
);
const styles = StyleSheet.create({
outer: {
padding: 4
},
row: {
flexDirection: 'row'
},
color0: {
backgroundColor: '#222'
},
color1: {
backgroundColor: '#666'
},
color2: {
backgroundColor: '#999'
},
color3: {
backgroundColor: 'blue'
},
color4: {
backgroundColor: 'orange'
},
color5: {
backgroundColor: 'red'
},
fixed: {
width: 20,
height: 20
}
});
export default Box;

View File

@@ -1,30 +0,0 @@
import styled from 'styled-components/primitives';
const getColor = color => {
switch (color) {
case 0:
return '#222';
case 1:
return '#666';
case 2:
return '#999';
case 3:
return 'blue';
case 4:
return 'orange';
case 5:
return 'red';
default:
return 'transparent';
}
};
const Box = styled.View`
flex-direction: ${props => (props.layout === 'column' ? 'column' : 'row')};
padding: ${props => (props.outer ? '4px' : '0')};
height: ${props => (props.fixed ? '20px' : 'auto')};
width: ${props => (props.fixed ? '20px' : 'auto')};
background-color: ${props => getColor(props.color)};
`;
export default Box;

View File

@@ -1,35 +0,0 @@
/* eslint-disable react/prop-types */
import React from 'react';
import StyleSheet from 'react-native/apis/StyleSheet';
import registry from 'react-native/apis/StyleSheet/registry';
const emptyObject = {};
class View extends React.Component {
render() {
const { style, ...other } = this.props;
const styleProps = registry.resolve([styles.root, style]) || emptyObject;
return <div {...other} {...styleProps} />;
}
}
const styles = StyleSheet.create({
root: {
alignItems: 'stretch',
borderWidth: 0,
borderStyle: 'solid',
boxSizing: 'border-box',
display: 'flex',
flexBasis: 'auto',
flexDirection: 'column',
flexShrink: 0,
margin: 0,
padding: 0,
position: 'relative',
// fix flexbox bugs
minHeight: 0,
minWidth: 0
}
});
export default View;

View File

@@ -1,9 +0,0 @@
import Box from './components/Box/react-native-stylesheet';
import View from './components/View/react-native-stylesheet';
const api = {
Box,
View
};
export default api;

View File

@@ -1,7 +0,0 @@
import Box from './components/Box/styled-components';
import styled from 'styled-components/primitives';
export default {
Box,
View: styled.View
};

View File

@@ -2,10 +2,44 @@
# yarn lockfile v1
"@types/lodash@^4.14.64", "@types/lodash@^4.14.66":
"@babel/helper-module-imports@7.0.0-beta.32":
version "7.0.0-beta.32"
resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.0.0-beta.32.tgz#8126fc024107c226879841b973677a4f4e510a03"
dependencies:
"@babel/types" "7.0.0-beta.32"
lodash "^4.2.0"
"@babel/types@7.0.0-beta.32":
version "7.0.0-beta.32"
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.0.0-beta.32.tgz#c317d0ecc89297b80bbcb2f50608e31f6452a5ff"
dependencies:
esutils "^2.0.2"
lodash "^4.2.0"
to-fast-properties "^2.0.0"
"@types/lodash@^4.14.64":
version "4.14.74"
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.74.tgz#ac3bd8db988e7f7038e5d22bd76a7ba13f876168"
"@types/lodash@^4.14.78":
version "4.14.91"
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.91.tgz#794611b28056d16b5436059c6d800b39d573cd3a"
"@types/node@*":
version "8.5.1"
resolved "https://registry.yarnpkg.com/@types/node/-/node-8.5.1.tgz#4ec3020bcdfe2abffeef9ba3fbf26fca097514b5"
"@types/react-dom@^16.0.0":
version "16.0.3"
resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-16.0.3.tgz#8accad7eabdab4cca3e1a56f5ccb57de2da0ff64"
dependencies:
"@types/node" "*"
"@types/react" "*"
"@types/react@*", "@types/react@^16.0.0":
version "16.0.31"
resolved "https://registry.yarnpkg.com/@types/react/-/react-16.0.31.tgz#5285da62f3ac62b797f6d0729a1d6181f3180c3e"
abbrev@1:
version "1.1.0"
resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.0.tgz#d0554c2256636e2f56e7c2e5ad183f859428d81f"
@@ -23,20 +57,6 @@ alphanum-sort@^1.0.1, alphanum-sort@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/alphanum-sort/-/alphanum-sort-1.0.2.tgz#97a1119649b211ad33691d9f9f486a8ec9fbe0a3"
animated@^0.1.5:
version "0.1.5"
resolved "https://registry.yarnpkg.com/animated/-/animated-0.1.5.tgz#83df8dc443d57abab7b0bb04818b0b655b31c9b9"
dependencies:
invariant "^2.2.0"
normalize-css-color "^1.0.1"
animated@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/animated/-/animated-0.2.0.tgz#1a0e96f097b3fbc5b64d7eddc723bcc0a6f97633"
dependencies:
invariant "^2.2.0"
normalize-css-color "^1.0.1"
ansi-regex@^2.0.0:
version "2.1.1"
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df"
@@ -45,15 +65,9 @@ ansi-styles@^2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe"
ansi-styles@^3.1.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.0.tgz#c159b8d5be0f9e5a6f346dab94f16ce022161b88"
dependencies:
color-convert "^1.9.0"
aphrodite@^1.2.3:
version "1.2.3"
resolved "https://registry.yarnpkg.com/aphrodite/-/aphrodite-1.2.3.tgz#4b161e9eef319b1f90a889501f985d7b5e70b285"
aphrodite@^1.2.5:
version "1.2.5"
resolved "https://registry.yarnpkg.com/aphrodite/-/aphrodite-1.2.5.tgz#8358c36c80bb03aee9b97165aaa70186225b4983"
dependencies:
asap "^2.0.3"
inline-style-prefixer "^3.0.1"
@@ -65,15 +79,11 @@ argparse@^1.0.7:
dependencies:
sprintf-js "~1.0.2"
array-find-index@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1"
array-find@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/array-find/-/array-find-1.0.0.tgz#6c8e286d11ed768327f8e62ecee87353ca3e78b8"
asap@^2.0.3, asap@^2.0.5:
asap@^2.0.3:
version "2.0.6"
resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46"
@@ -98,17 +108,6 @@ autoprefixer@^6.3.1:
postcss "^5.2.15"
postcss-value-parser "^3.2.3"
autoprefixer@^7.1.2:
version "7.1.4"
resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-7.1.4.tgz#960847dbaa4016bc8e8e52ec891cbf8f1257a748"
dependencies:
browserslist "^2.4.0"
caniuse-lite "^1.0.30000726"
normalize-range "^0.1.2"
num2fraction "^1.2.2"
postcss "^6.0.11"
postcss-value-parser "^3.2.3"
babel-code-frame@^6.11.0:
version "6.22.0"
resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.22.0.tgz#027620bee567a88c32561574e7fd0801d33118e4"
@@ -117,29 +116,29 @@ babel-code-frame@^6.11.0:
esutils "^2.0.2"
js-tokens "^3.0.0"
babel-plugin-emotion@^7.2.2:
version "7.2.2"
resolved "https://registry.yarnpkg.com/babel-plugin-emotion/-/babel-plugin-emotion-7.2.2.tgz#eae520ef15e4affd87aab761e1c8b48b3385af3e"
babel-macros@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/babel-macros/-/babel-macros-1.2.0.tgz#39e47ed6d286d4a98f1948d8bab45dac17e4e2d4"
dependencies:
autoprefixer "^7.1.2"
cosmiconfig "3.1.0"
babel-plugin-emotion@^8.0.12:
version "8.0.12"
resolved "https://registry.yarnpkg.com/babel-plugin-emotion/-/babel-plugin-emotion-8.0.12.tgz#2ed844001416b0ae2ff787a06b1804ec5f531c89"
dependencies:
"@babel/helper-module-imports" "7.0.0-beta.32"
babel-macros "^1.2.0"
babel-plugin-syntax-jsx "^6.18.0"
emotion-utils "^7.2.2"
postcss "^6.0.9"
postcss-js "^1.0.0"
postcss-nested "^2.1.1"
convert-source-map "^1.5.0"
emotion-utils "^8.0.12"
find-root "^1.1.0"
source-map "^0.5.7"
touch "^1.0.0"
babel-plugin-syntax-jsx@^6.18.0:
version "6.18.0"
resolved "https://registry.yarnpkg.com/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz#0af32a9a6e13ca7a3fd5069e62d7b0f58d0d8946"
babel-runtime@^6.23.0:
version "6.25.0"
resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.25.0.tgz#33b98eaa5d482bb01a8d1aa6b437ad2b01aec41c"
dependencies:
core-js "^2.4.0"
regenerator-runtime "^0.10.0"
balanced-match@^0.4.2:
version "0.4.2"
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838"
@@ -160,9 +159,13 @@ bowser@^1.6.0:
version "1.7.1"
resolved "https://registry.yarnpkg.com/bowser/-/bowser-1.7.1.tgz#a4de8f18a1a0dc9531eb2a92a1521fb6a9ba96a5"
brcast@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/brcast/-/brcast-2.0.1.tgz#4311508f0634a6f5a2465b6cf2db27f06902aaca"
bowser@^1.7.3:
version "1.8.1"
resolved "https://registry.yarnpkg.com/bowser/-/bowser-1.8.1.tgz#49785777e7302febadb1a5b71d9a646520ed310d"
brcast@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/brcast/-/brcast-3.0.1.tgz#6256a8349b20de9eed44257a9b24d71493cd48dd"
browserslist@^1.0.1, browserslist@^1.5.2, browserslist@^1.7.5:
version "1.7.5"
@@ -171,13 +174,6 @@ browserslist@^1.0.1, browserslist@^1.5.2, browserslist@^1.7.5:
caniuse-db "^1.0.30000624"
electron-to-chromium "^1.2.3"
browserslist@^2.4.0:
version "2.4.0"
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-2.4.0.tgz#693ee93d01e66468a6348da5498e011f578f87f8"
dependencies:
caniuse-lite "^1.0.30000718"
electron-to-chromium "^1.3.18"
buffer@^5.0.3:
version "5.0.5"
resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.0.5.tgz#35c9393244a90aff83581063d16f0882cecc9418"
@@ -185,10 +181,6 @@ buffer@^5.0.3:
base64-js "^1.0.2"
ieee754 "^1.1.4"
camelcase-css@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/camelcase-css/-/camelcase-css-1.0.1.tgz#157c4238265f5cf94a1dffde86446552cbf3f705"
caniuse-api@^1.5.2:
version "1.5.3"
resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-1.5.3.tgz#5018e674b51c393e4d50614275dc017e27c4a2a2"
@@ -202,10 +194,6 @@ caniuse-db@^1.0.30000346, caniuse-db@^1.0.30000624:
version "1.0.30000628"
resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000628.tgz#3d010e2a8e2537a8d135792e90e4f2ce0eb838cc"
caniuse-lite@^1.0.30000718, caniuse-lite@^1.0.30000726:
version "1.0.30000726"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000726.tgz#966a753fa107a09d4131cf8b3d616723a06ccf7e"
chalk@^1.1.0, chalk@^1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98"
@@ -216,14 +204,6 @@ chalk@^1.1.0, chalk@^1.1.3:
strip-ansi "^3.0.0"
supports-color "^2.0.0"
chalk@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.1.0.tgz#ac5becf14fa21b99c6c92ca7a7d7cfd5b17e743e"
dependencies:
ansi-styles "^3.1.0"
escape-string-regexp "^1.0.5"
supports-color "^4.0.0"
clap@^1.0.9:
version "1.1.2"
resolved "https://registry.yarnpkg.com/clap/-/clap-1.1.2.tgz#316545bf22229225a2cecaa6824cd2f56a9709ed"
@@ -248,7 +228,7 @@ coa@~1.0.1:
dependencies:
q "^1.1.2"
color-convert@^1.3.0, color-convert@^1.9.0:
color-convert@^1.3.0:
version "1.9.0"
resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.0.tgz#1accf97dd739b983bf994d56fec8f95853641b7a"
dependencies:
@@ -284,21 +264,22 @@ colors@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63"
convert-source-map@^1.5.0:
version "1.5.0"
resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.0.tgz#9acd70851c6d5dfdd93d9282e5edf94a03ff46b5"
core-js@^1.0.0:
version "1.2.7"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636"
core-js@^2.4.0:
version "2.4.1"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.4.1.tgz#4de911e667b0eae9124e34254b53aea6fc618d3e"
create-react-class@^15.6.0:
version "15.6.0"
resolved "https://registry.yarnpkg.com/create-react-class/-/create-react-class-15.6.0.tgz#ab448497c26566e1e29413e883207d57cfe7bed4"
cosmiconfig@3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-3.1.0.tgz#640a94bf9847f321800403cd273af60665c73397"
dependencies:
fbjs "^0.8.9"
loose-envify "^1.3.1"
object-assign "^4.1.1"
is-directory "^0.3.1"
js-yaml "^3.9.0"
parse-json "^3.0.0"
require-from-string "^2.0.1"
css-color-keywords@^1.0.0:
version "1.0.0"
@@ -314,6 +295,12 @@ css-in-js-utils@^1.0.3:
dependencies:
hyphenate-style-name "^1.0.2"
css-in-js-utils@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/css-in-js-utils/-/css-in-js-utils-2.0.0.tgz#5af1dd70f4b06b331f48d22a3d86e0786c0b9435"
dependencies:
hyphenate-style-name "^1.0.2"
css-loader@^0.28.7:
version "0.28.7"
resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-0.28.7.tgz#5f2ee989dd32edd907717f953317656160999c1b"
@@ -411,61 +398,34 @@ csso@~2.3.1:
clap "^1.0.9"
source-map "^0.5.3"
debounce@1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/debounce/-/debounce-1.0.2.tgz#503cc674d8d7f737099664fb75ddbd36b9626dc6"
decamelize@^1.1.2:
version "1.2.0"
resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
deep-assign@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/deep-assign/-/deep-assign-2.0.0.tgz#ebe06b1f07f08dae597620e3dd1622f371a1c572"
dependencies:
is-obj "^1.0.0"
defined@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693"
deline@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/deline/-/deline-1.0.4.tgz#6c05c87836926e1a1c63e47882f3d2eb2c6f14c9"
electron-to-chromium@^1.2.3:
version "1.2.4"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.2.4.tgz#9751cbea89fa120bf88c226ba41eb8d0b6f1b597"
electron-to-chromium@^1.3.18:
version "1.3.21"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.21.tgz#a967ebdcfe8ed0083fc244d1894022a8e8113ea2"
emojis-list@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389"
emotion-server@^7.2.2:
version "7.2.2"
resolved "https://registry.yarnpkg.com/emotion-server/-/emotion-server-7.2.2.tgz#d1073df1c71ef6fad4ee5e32319deced97b15c6b"
dependencies:
emotion "^7.2.2"
emotion-utils "^7.2.2"
emotion-utils@^8.0.12:
version "8.0.12"
resolved "https://registry.yarnpkg.com/emotion-utils/-/emotion-utils-8.0.12.tgz#5e0fd72db3008f26ce4f80b1972df08841df2168"
emotion-utils@^7.2.2:
version "7.2.2"
resolved "https://registry.yarnpkg.com/emotion-utils/-/emotion-utils-7.2.2.tgz#0057927581bdd0877d6d8fb90a6162a15c75b805"
emotion@^8.0.12:
version "8.0.12"
resolved "https://registry.yarnpkg.com/emotion/-/emotion-8.0.12.tgz#03de11ce26b1b2401c334b94d438652124c514c6"
dependencies:
fbjs "^0.8.12"
emotion@^7.2.2:
version "7.2.2"
resolved "https://registry.yarnpkg.com/emotion/-/emotion-7.2.2.tgz#c89908662f4abb706d488a316ea8bdcad0b29727"
dependencies:
babel-plugin-emotion "^7.2.2"
emotion-server "^7.2.2"
emotion-utils "^7.2.2"
react-emotion "^7.2.2"
babel-plugin-emotion "^8.0.12"
emotion-utils "^8.0.12"
stylis "^3.3.2"
stylis-rule-sheet "^0.0.5"
encoding@^0.1.11:
version "0.1.12"
@@ -473,7 +433,13 @@ encoding@^0.1.11:
dependencies:
iconv-lite "~0.4.13"
escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5:
error-ex@^1.3.1:
version "1.3.1"
resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.1.tgz#f855a86ce61adc4e8621c3cda21e7a7612c3a8dc"
dependencies:
is-arrayish "^0.2.1"
escape-string-regexp@^1.0.2:
version "1.0.5"
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
@@ -481,6 +447,10 @@ esprima@^2.6.0:
version "2.7.3"
resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581"
esprima@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.0.tgz#4499eddcd1110e0b218bacf2fa7f7f59f55ca804"
esutils@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b"
@@ -509,6 +479,18 @@ fbjs@^0.8.12:
setimmediate "^1.0.5"
ua-parser-js "^0.7.9"
fbjs@^0.8.16:
version "0.8.16"
resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.16.tgz#5e67432f550dc41b572bf55847b8aca64e5337db"
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"
fbjs@^0.8.5, fbjs@^0.8.9:
version "0.8.12"
resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.12.tgz#10b5d92f76d45575fd63a217d4ea02bea2f8ed04"
@@ -521,14 +503,14 @@ fbjs@^0.8.5, fbjs@^0.8.9:
setimmediate "^1.0.5"
ua-parser-js "^0.7.9"
find-root@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/find-root/-/find-root-1.1.0.tgz#abcfc8ba76f708c42a97b3d685b7e9450bfb9ce4"
flatten@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/flatten/-/flatten-1.0.2.tgz#dae46a9d78fbe25292258cc1e780a41d95c03782"
flexibility@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/flexibility/-/flexibility-2.0.1.tgz#ad323aafc40f469ce624286518fc4d7cd72b7c77"
function-bind@^1.0.2:
version "1.1.0"
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.0.tgz#16176714c801798e4e8f2cf7f7529467bb4a5771"
@@ -567,6 +549,10 @@ hoist-non-react-statics@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-1.2.0.tgz#aa448cf0986d55cc40773b17174b7dd066cb7cfb"
hoist-non-react-statics@^2.3.1:
version "2.3.1"
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-2.3.1.tgz#343db84c6018c650778898240135a1420ee22ce0"
html-comment-regex@^1.1.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/html-comment-regex/-/html-comment-regex-1.1.1.tgz#668b93776eaae55ebde8f3ad464b307a4963625e"
@@ -605,7 +591,7 @@ inherits@2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1"
inline-style-prefixer@^2.0.1, inline-style-prefixer@^2.0.5:
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:
@@ -619,16 +605,25 @@ inline-style-prefixer@^3.0.1, inline-style-prefixer@^3.0.6:
bowser "^1.6.0"
css-in-js-utils "^1.0.3"
invariant@^2.2.0, invariant@^2.2.1:
version "2.2.2"
resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.2.tgz#9e1f56ac0acdb6bf303306f338be3b204ae60360"
inline-style-prefixer@^3.0.3:
version "3.0.8"
resolved "https://registry.yarnpkg.com/inline-style-prefixer/-/inline-style-prefixer-3.0.8.tgz#8551b8e5b4d573244e66a34b04f7d32076a2b534"
dependencies:
loose-envify "^1.0.0"
bowser "^1.7.3"
css-in-js-utils "^2.0.0"
is-absolute-url@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/is-absolute-url/-/is-absolute-url-2.1.0.tgz#50530dfb84fcc9aa7dbe7852e83a37b93b9f2aa6"
is-arrayish@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
is-directory@^0.3.1:
version "0.3.1"
resolved "https://registry.yarnpkg.com/is-directory/-/is-directory-0.3.1.tgz#61339b6f2475fc772fd9c9d83f5c8575dc154ae1"
is-function@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/is-function/-/is-function-1.0.1.tgz#12cfb98b65b57dd3d193a3121f5f6e2f437602b5"
@@ -637,9 +632,9 @@ is-in-browser@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/is-in-browser/-/is-in-browser-1.0.2.tgz#f688bea8f1e5aadc3244ebc870d188cfb9b613cf"
is-obj@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f"
is-in-browser@^1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/is-in-browser/-/is-in-browser-1.1.3.tgz#56ff4db683a078c6082eb95dad7dc62e1d04f835"
is-plain-obj@^1.0.0:
version "1.1.0"
@@ -680,6 +675,13 @@ js-tokens@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.1.tgz#08e9f132484a2c45a30907e9dc4d5567b7f114d7"
js-yaml@^3.9.0:
version "3.10.0"
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.10.0.tgz#2e78441646bd4682e963f22b6e92823c309c62dc"
dependencies:
argparse "^1.0.7"
esprima "^4.0.0"
js-yaml@~3.7.0:
version "3.7.0"
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.7.0.tgz#5c967ddd837a9bfdca5f2de84253abe8a1c03b80"
@@ -709,69 +711,77 @@ jsonify@~0.0.0:
version "0.0.0"
resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73"
jss-camel-case@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/jss-camel-case/-/jss-camel-case-5.0.0.tgz#886c1fe56a8a11577454d6a8b4133caa6c1f53a0"
jss-compose@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/jss-compose/-/jss-compose-4.0.0.tgz#f0109e8e8301a2678279301c24523dbc76115b9b"
dependencies:
warning "^3.0.0"
jss-default-unit@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/jss-default-unit/-/jss-default-unit-7.0.0.tgz#176c1db91da870e3ad16301f6f4b4cfc6fe1e90a"
jss-expand@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/jss-expand/-/jss-expand-4.0.0.tgz#71ec15386d7839bb23892acf9dcaa40b7fe9c785"
jss-extend@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/jss-extend/-/jss-extend-5.0.0.tgz#08a1d4015d05dfe011e3a281457d471226865387"
dependencies:
warning "^3.0.0"
jss-global@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/jss-global/-/jss-global-2.0.0.tgz#a162f822f17e5d760151d908bdb41d7f2824c28f"
jss-nested@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/jss-nested/-/jss-nested-5.0.0.tgz#c0752f31f2d465110d7de6ac83583dbed669faa0"
dependencies:
warning "^3.0.0"
jss-preset-default@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/jss-preset-default/-/jss-preset-default-3.0.0.tgz#e43ee1ac526f689baf2bfd28ae95a6fdc3a02663"
dependencies:
jss-camel-case "^5.0.0"
jss-compose "^4.0.0"
jss-default-unit "^7.0.0"
jss-expand "^4.0.0"
jss-extend "^5.0.0"
jss-global "^2.0.0"
jss-nested "^5.0.0"
jss-props-sort "^5.0.0"
jss-vendor-prefixer "^6.0.0"
jss-props-sort@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/jss-props-sort/-/jss-props-sort-5.0.0.tgz#8839c88433f64e8c1dab1a7068796f19b84f9195"
jss-vendor-prefixer@^6.0.0:
jss-camel-case@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/jss-vendor-prefixer/-/jss-vendor-prefixer-6.0.0.tgz#be58124f0cbed76e98cc8eb5219dbb260f057d0b"
resolved "https://registry.yarnpkg.com/jss-camel-case/-/jss-camel-case-6.0.0.tgz#7cf8453e395c31fed931d11efbc885edcd61132e"
jss-compose@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/jss-compose/-/jss-compose-5.0.0.tgz#ce01b2e4521d65c37ea42cf49116e5f7ab596484"
dependencies:
warning "^3.0.0"
jss-default-unit@^8.0.0:
version "8.0.2"
resolved "https://registry.yarnpkg.com/jss-default-unit/-/jss-default-unit-8.0.2.tgz#cc1e889bae4c0b9419327b314ab1c8e2826890e6"
jss-expand@^5.0.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/jss-expand/-/jss-expand-5.1.0.tgz#b1ad74ec18631f34f65a2124fcfceb6400610e3d"
jss-extend@^6.0.1:
version "6.1.0"
resolved "https://registry.yarnpkg.com/jss-extend/-/jss-extend-6.1.0.tgz#85f3d39944018e8f44b322c14fa316068aa7bb0b"
dependencies:
warning "^3.0.0"
jss-global@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/jss-global/-/jss-global-3.0.0.tgz#e19e5c91ab2b96353c227e30aa2cbd938cdaafa2"
jss-nested@^6.0.1:
version "6.0.1"
resolved "https://registry.yarnpkg.com/jss-nested/-/jss-nested-6.0.1.tgz#ef992b79d6e8f63d939c4397b9d99b5cbbe824ca"
dependencies:
warning "^3.0.0"
jss-preset-default@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/jss-preset-default/-/jss-preset-default-4.0.1.tgz#822cecb87c27ff91633774422f4c221d61486b65"
dependencies:
jss-camel-case "^6.0.0"
jss-compose "^5.0.0"
jss-default-unit "^8.0.0"
jss-expand "^5.0.0"
jss-extend "^6.0.1"
jss-global "^3.0.0"
jss-nested "^6.0.1"
jss-props-sort "^6.0.0"
jss-template "^1.0.0"
jss-vendor-prefixer "^7.0.0"
jss-props-sort@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/jss-props-sort/-/jss-props-sort-6.0.0.tgz#9105101a3b5071fab61e2d85ea74cc22e9b16323"
jss-template@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/jss-template/-/jss-template-1.0.0.tgz#4b874608706ddceecacdb5567e254aecb6ea69b3"
dependencies:
warning "^3.0.0"
jss-vendor-prefixer@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/jss-vendor-prefixer/-/jss-vendor-prefixer-7.0.0.tgz#0166729650015ef19d9f02437c73667231605c71"
dependencies:
css-vendor "^0.3.8"
jss@^8.1.0:
version "8.1.0"
resolved "https://registry.yarnpkg.com/jss/-/jss-8.1.0.tgz#b32f15efcce22446dfda4c2be09a04f38431da0a"
jss@^9.3.2:
version "9.4.0"
resolved "https://registry.yarnpkg.com/jss/-/jss-9.4.0.tgz#fbfd1a63556c5afd5bfcffd98df3c50eb2614ed3"
dependencies:
is-in-browser "^1.0.2"
is-in-browser "^1.1.3"
symbol-observable "^1.1.0"
warning "^3.0.0"
loader-utils@^1.0.2:
@@ -794,11 +804,11 @@ lodash.uniq@^4.3.0:
version "4.5.0"
resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
lodash@^4.17.1, lodash@^4.17.4:
lodash@^4.17.1, lodash@^4.17.4, lodash@^4.2.0:
version "4.17.4"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae"
loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.3.1:
loose-envify@^1.0.0, loose-envify@^1.3.1:
version "1.3.1"
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848"
dependencies:
@@ -839,10 +849,6 @@ nopt@~1.0.10:
dependencies:
abbrev "1"
normalize-css-color@^1.0.1, normalize-css-color@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/normalize-css-color/-/normalize-css-color-1.0.2.tgz#02991e97cccec6623fe573afbbf0de6a1f3e9f8d"
normalize-range@^0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942"
@@ -864,6 +870,12 @@ object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
parse-json@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-3.0.0.tgz#fa6f47b18e23826ead32f263e744d0e1e847fb13"
dependencies:
error-ex "^1.3.1"
postcss-calc@^5.2.0:
version "5.3.1"
resolved "https://registry.yarnpkg.com/postcss-calc/-/postcss-calc-5.3.1.tgz#77bae7ca928ad85716e2fda42f261bf7c1d65b5e"
@@ -925,13 +937,6 @@ postcss-filter-plugins@^2.0.0:
postcss "^5.0.4"
uniqid "^4.0.0"
postcss-js@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/postcss-js/-/postcss-js-1.0.0.tgz#ccee5aa3b1970dd457008e79438165f66919ba30"
dependencies:
camelcase-css "^1.0.1"
postcss "^6.0.1"
postcss-merge-idents@^2.1.5:
version "2.1.7"
resolved "https://registry.yarnpkg.com/postcss-merge-idents/-/postcss-merge-idents-2.1.7.tgz#4c5530313c08e1d5b3bbf3d2bbc747e278eea270"
@@ -1020,13 +1025,6 @@ postcss-modules-values@^1.1.0:
icss-replace-symbols "^1.0.2"
postcss "^5.0.14"
postcss-nested@^2.1.1:
version "2.1.2"
resolved "https://registry.yarnpkg.com/postcss-nested/-/postcss-nested-2.1.2.tgz#04057281f9631fef684857fb0119bae04ede03c6"
dependencies:
postcss "^6.0.9"
postcss-selector-parser "^2.2.3"
postcss-normalize-charset@^1.1.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/postcss-normalize-charset/-/postcss-normalize-charset-1.1.1.tgz#ef9ee71212d7fe759c78ed162f61ed62b5cb93f1"
@@ -1070,7 +1068,7 @@ postcss-reduce-transforms@^1.0.3:
postcss "^5.0.8"
postcss-value-parser "^3.0.1"
postcss-selector-parser@^2.0.0, postcss-selector-parser@^2.2.2, postcss-selector-parser@^2.2.3:
postcss-selector-parser@^2.0.0, postcss-selector-parser@^2.2.2:
version "2.2.3"
resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-2.2.3.tgz#f9437788606c3c9acee16ffe8d8b16297f27bb90"
dependencies:
@@ -1124,14 +1122,6 @@ postcss@^6.0.1:
source-map "^0.5.6"
supports-color "^4.0.0"
postcss@^6.0.11, postcss@^6.0.9:
version "6.0.11"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-6.0.11.tgz#f48db210b1d37a7f7ab6499b7a54982997ab6f72"
dependencies:
chalk "^2.1.0"
source-map "^0.5.7"
supports-color "^4.4.0"
prepend-http@^1.0.0:
version "1.0.4"
resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc"
@@ -1149,6 +1139,14 @@ prop-types@^15.5.10, prop-types@^15.5.4, prop-types@^15.5.8, prop-types@^15.5.9:
fbjs "^0.8.9"
loose-envify "^1.3.1"
prop-types@^15.6.0:
version "15.6.0"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.0.tgz#ceaf083022fc46b4a35f69e13ef75aed0d639856"
dependencies:
fbjs "^0.8.16"
loose-envify "^1.3.1"
object-assign "^4.1.1"
q@^1.1.2:
version "1.4.1"
resolved "https://registry.yarnpkg.com/q/-/q-1.4.1.tgz#55705bcd93c5f3673530c2c2cbc0c2b3addc286e"
@@ -1160,92 +1158,39 @@ query-string@^4.1.0:
object-assign "^4.1.0"
strict-uri-encode "^1.0.0"
radium@^0.19.4:
version "0.19.4"
resolved "https://registry.yarnpkg.com/radium/-/radium-0.19.4.tgz#56aa49fde6181d2f5e1fa57b4710ffd0c23de820"
radium@^0.19.6:
version "0.19.6"
resolved "https://registry.yarnpkg.com/radium/-/radium-0.19.6.tgz#b86721d08dbd303b061a4ae2ebb06cc6e335ae72"
dependencies:
array-find "^1.0.0"
exenv "^1.2.1"
inline-style-prefixer "^2.0.5"
prop-types "^15.5.8"
react-emotion@^7.2.2:
version "7.2.2"
resolved "https://registry.yarnpkg.com/react-emotion/-/react-emotion-7.2.2.tgz#0401607a0ba011bc16600a2691f5f57cb38ce89d"
react-jss@^8.2.0:
version "8.2.0"
resolved "https://registry.yarnpkg.com/react-jss/-/react-jss-8.2.0.tgz#8440f08aef27d408ba31f63df09167ed22a5b99b"
dependencies:
babel-plugin-emotion "^7.2.2"
emotion "^7.2.2"
emotion-utils "^7.2.2"
hoist-non-react-statics "^2.3.1"
jss "^9.3.2"
jss-preset-default "^4.0.1"
prop-types "^15.6.0"
theming "^1.3.0"
react-jss@^7.1.0:
version "7.1.0"
resolved "https://registry.yarnpkg.com/react-jss/-/react-jss-7.1.0.tgz#de9430cbe01a82f3b2dcf87a03b798130868ff93"
reactxp@^0.46.6:
version "0.46.6"
resolved "https://registry.yarnpkg.com/reactxp/-/reactxp-0.46.6.tgz#166a503a7147f3a1e29efc4469bda32603471a5f"
dependencies:
hoist-non-react-statics "^1.2.0"
jss "^8.1.0"
jss-preset-default "^3.0.0"
prop-types "^15.5.8"
theming "^1.1.0"
react-native-web@0.0.x:
version "0.0.116"
resolved "https://registry.yarnpkg.com/react-native-web/-/react-native-web-0.0.116.tgz#e05e376b34617a54d61826e4bc06b0bdbfd3f4b2"
dependencies:
animated "^0.2.0"
array-find-index "^1.0.2"
babel-runtime "^6.23.0"
create-react-class "^15.6.0"
debounce "1.0.2"
deep-assign "^2.0.0"
fbjs "^0.8.12"
hyphenate-style-name "^1.0.2"
inline-style-prefixer "^3.0.6"
normalize-css-color "^1.0.2"
prop-types "^15.5.10"
react-timer-mixin "^0.13.3"
react-primitives@^0.4.3:
version "0.4.3"
resolved "https://registry.yarnpkg.com/react-primitives/-/react-primitives-0.4.3.tgz#4970afda5a32dccf5ea180380e3a0e16192e4b83"
dependencies:
animated "^0.1.5"
asap "^2.0.5"
deline "^1.0.4"
flexibility "^2.0.1"
inline-style-prefixer "^2.0.5"
invariant "^2.2.1"
normalize-css-color "^1.0.1"
prop-types "^15.5.10"
react-native-web "0.0.x"
react-timer-mixin "^0.13.3"
string-hash "^1.1.3"
react-timer-mixin@^0.13.3:
version "0.13.3"
resolved "https://registry.yarnpkg.com/react-timer-mixin/-/react-timer-mixin-0.13.3.tgz#0da8b9f807ec07dc3e854d082c737c65605b3d22"
react@^15.5.4:
version "15.6.1"
resolved "https://registry.yarnpkg.com/react/-/react-15.6.1.tgz#baa8434ec6780bde997cdc380b79cd33b96393df"
dependencies:
create-react-class "^15.6.0"
fbjs "^0.8.9"
loose-envify "^1.1.0"
object-assign "^4.1.0"
prop-types "^15.5.10"
reactxp@^0.42.1:
version "0.42.1"
resolved "https://registry.yarnpkg.com/reactxp/-/reactxp-0.42.1.tgz#1c142a87f0a82a8da94e5c875525952c35a53a17"
dependencies:
"@types/lodash" "^4.14.66"
"@types/lodash" "^4.14.78"
"@types/react" "^16.0.0"
"@types/react-dom" "^16.0.0"
assert "^1.3.0"
ifvisible.js "^1.0.6"
lodash "^4.17.1"
prop-types "^15.5.9"
rebound "^0.0.13"
subscribableevent "^1.0.0"
synctasks "^0.2.9"
synctasks "^0.3.0"
rebound@^0.0.13:
version "0.0.13"
@@ -1269,10 +1214,6 @@ 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.5"
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz#336c3efc1220adcedda2c9fab67b5a7955a33658"
regexpu-core@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-1.0.0.tgz#86a763f58ee4d7c2f6b102e4764050de7ed90c6b"
@@ -1291,6 +1232,10 @@ regjsparser@^0.1.4:
dependencies:
jsesc "~0.5.0"
require-from-string@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.1.tgz#c545233e9d7da6616e9d59adfb39fc9f588676ff"
sax@~1.2.1:
version "1.2.2"
resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.2.tgz#fd8631a23bc7826bef5d871bdb87378c95647828"
@@ -1341,46 +1286,53 @@ strip-ansi@^3.0.0:
dependencies:
ansi-regex "^2.0.0"
style-loader@^0.18.2:
version "0.18.2"
resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-0.18.2.tgz#cc31459afbcd6d80b7220ee54b291a9fd66ff5eb"
style-loader@^0.19.1:
version "0.19.1"
resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-0.19.1.tgz#591ffc80bcefe268b77c5d9ebc0505d772619f85"
dependencies:
loader-utils "^1.0.2"
schema-utils "^0.3.0"
styled-components@^2.1.2:
version "2.1.2"
resolved "https://registry.yarnpkg.com/styled-components/-/styled-components-2.1.2.tgz#bb419978e1287c5d0d88fa9106b2dd75f66a324c"
styled-components@^2.3.2:
version "2.3.2"
resolved "https://registry.yarnpkg.com/styled-components/-/styled-components-2.3.2.tgz#323d86cc9ac89f3fd233a2dfa0849da236f143e3"
dependencies:
buffer "^5.0.3"
css-to-react-native "^2.0.3"
fbjs "^0.8.9"
hoist-non-react-statics "^1.2.0"
is-function "^1.0.1"
is-plain-object "^2.0.1"
prop-types "^15.5.4"
stylis "^3.2.1"
stylis "^3.4.0"
supports-color "^3.2.3"
styletron-client@^2.5.7:
version "2.5.7"
resolved "https://registry.yarnpkg.com/styletron-client/-/styletron-client-2.5.7.tgz#104fa4dc564cd3fe78eb92488e5ef9039c9e242f"
styletron-client@^3.0.0-rc.5:
version "3.0.0-rc.5"
resolved "https://registry.yarnpkg.com/styletron-client/-/styletron-client-3.0.0-rc.5.tgz#275ca0b5f971d244f0e42079ad570be9c31a2a70"
dependencies:
styletron-core "^2.5.7"
styletron-core "^3.0.0-rc.3"
styletron-core@^2.5.7:
version "2.5.7"
resolved "https://registry.yarnpkg.com/styletron-core/-/styletron-core-2.5.7.tgz#2c4a1fae537b42235462e438c24ab619bbf8993e"
styletron-core@^3.0.0-rc.3:
version "3.0.0-rc.3"
resolved "https://registry.yarnpkg.com/styletron-core/-/styletron-core-3.0.0-rc.3.tgz#9468e275d9085d2e5d6d6468cc6d8733dbfa3cba"
styletron-utils@^2.5.4:
version "2.5.4"
resolved "https://registry.yarnpkg.com/styletron-utils/-/styletron-utils-2.5.4.tgz#f08cca7d58ee0338ce85e408cb32900e65620240"
styletron-utils@^3.0.0-rc.3:
version "3.0.0-rc.3"
resolved "https://registry.yarnpkg.com/styletron-utils/-/styletron-utils-3.0.0-rc.3.tgz#21fef2099f1c368e6ff2b8f76bf7a64bb547b760"
dependencies:
inline-style-prefixer "^2.0.1"
inline-style-prefixer "^3.0.3"
stylis@^3.2.1:
version "3.2.3"
resolved "https://registry.yarnpkg.com/stylis/-/stylis-3.2.3.tgz#fed751d792af3f48a247769f55aca05c1a100a09"
stylis-rule-sheet@^0.0.5:
version "0.0.5"
resolved "https://registry.yarnpkg.com/stylis-rule-sheet/-/stylis-rule-sheet-0.0.5.tgz#ebae935cc1f6fb31b9b62dba47f2ea8b833dad9f"
stylis@^3.3.2:
version "3.4.0"
resolved "https://registry.yarnpkg.com/stylis/-/stylis-3.4.0.tgz#55c6530ebceeca5976d54fb4adc67578afee828d"
stylis@^3.4.0:
version "3.4.5"
resolved "https://registry.yarnpkg.com/stylis/-/stylis-3.4.5.tgz#d7b9595fc18e7b9c8775eca8270a9a1d3e59806e"
subscribableevent@^1.0.0:
version "1.0.0"
@@ -1405,12 +1357,6 @@ supports-color@^4.0.0:
dependencies:
has-flag "^2.0.0"
supports-color@^4.4.0:
version "4.4.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-4.4.0.tgz#883f7ddabc165142b2a61427f3352ded195d1a3e"
dependencies:
has-flag "^2.0.0"
svgo@^0.7.0:
version "0.7.2"
resolved "https://registry.yarnpkg.com/svgo/-/svgo-0.7.2.tgz#9f5772413952135c6fefbf40afe6a4faa88b4bb5"
@@ -1423,24 +1369,31 @@ svgo@^0.7.0:
sax "~1.2.1"
whet.extend "~0.9.9"
synctasks@^0.2.9:
version "0.2.17"
resolved "https://registry.yarnpkg.com/synctasks/-/synctasks-0.2.17.tgz#38852f008878de2e941b6e458ddf552245268da1"
theming@^1.1.0:
symbol-observable@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/theming/-/theming-1.1.0.tgz#0562760b55a1b919c2d5eeb94130351f8958e13a"
resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.1.0.tgz#5c68fd8d54115d9dfb72a84720549222e8db9b32"
synctasks@^0.3.0:
version "0.3.1"
resolved "https://registry.yarnpkg.com/synctasks/-/synctasks-0.3.1.tgz#1f9012b23792ad775ba2693e0cafcfcd65b80d97"
theming@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/theming/-/theming-1.3.0.tgz#286d5bae80be890d0adc645e5ca0498723725bdc"
dependencies:
brcast "^2.0.0"
brcast "^3.0.1"
is-function "^1.0.1"
is-plain-object "^2.0.1"
prop-types "^15.5.8"
react "^15.5.4"
through@^2.3.8:
version "2.3.8"
resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
to-fast-properties@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e"
touch@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/touch/-/touch-1.0.0.tgz#449cbe2dbae5a8c8038e30d71fa0ff464947c4de"

View File

@@ -1,60 +0,0 @@
# AppRegistry
`AppRegistry` is the control point for registering, running, prerendering, and
unmounting all apps. App root components should register themselves with
`AppRegistry.registerComponent`. Apps can be run by invoking
`AppRegistry.runApplication` (see the [getting started guide](../guides/getting-started.md) for more details).
To "stop" an application when a view should be destroyed, call
`AppRegistry.unmountApplicationComponentAtRootTag` with the tag that was passed
into `runApplication`. These should always be used as a pair.
## Methods
(web) static **getApplication**(appKey:string, appParameters: object)
Returns the given application element. Use this for server-side rendering.
Return object is of type `{ element: ReactElement; stylesheets: [ ReactElement ] }`.
static **registerConfig**(config: Array<AppConfig>)
Registry multiple applications. `AppConfig` is of type `{ appKey: string;
component: ComponentProvider; run?: Function }`.
static **registerComponent**(appKey: string, getComponentFunc: ComponentProvider)
Register a component provider under the given `appKey`.
static **registerRunnable**(appKey: string, run: Function)
Register a custom render function for an application. The function will receive
the `appParameters` passed to `runApplication`.
static **getAppKeys**()
Returns all registered app keys.
static **runApplication**(appKey: string, appParameters?: object)
Runs the application that was registered under `appKey`. The `appParameters`
must include the `rootTag` into which the application is rendered, and
optionally any `initialProps`.
On web, if the `rootTag` is a sub-section of your application it should be
styled as `position:relative` and given an explicit height.
static **unmountApplicationComponentAtRootTag**(rootTag: HTMLElement)
To "stop" an application when a view should be destroyed, call
`AppRegistry.unmountApplicationComponentAtRootTag` with the tag that was passed
into `runApplication`
## Example
```js
AppRegistry.registerComponent('MyApp', () => AppComponent)
AppRegistry.runApplication('MyApp', {
initialProps: {},
rootTag: document.getElementById('react-root')
})
```

View File

@@ -1,60 +0,0 @@
## AppState
`AppState` can tell you if the app is in the foreground or background, and
notify you when the state changes.
States
* `active` - The app is running in the foreground
* `background` - The app is running in the background (i.e., the user has not focused the app's tab).
## Properties
static **currentState**
Returns the current state of the app: `active` or `background`.
## Methods
static **addEventListener**(type: string, handler: Function)
Add a handler to `AppState` changes by listening to the `change` event type and
providing the `handler`. The handler is called with the app state value.
static **removeEventListener**(type: string, handler: Function)
Remove a handler by passing the change event `type` and the `handler`.
## Examples
To see the current state, you can check `AppState.currentState`, which will be
kept up-to-date. This example will only ever appear to say "Current state is:
active" because the app is only visible to the user when in the `active` state,
and the null state will happen only momentarily.
```js
class Example extends React.Component {
constructor(props) {
super(props)
this.state = { currentAppState: AppState.currentState }
}
componentDidMount() {
AppState.addEventListener('change', this._handleAppStateChange);
}
componentWillUnmount() {
AppState.removeEventListener('change', this._handleAppStateChange);
}
_handleAppStateChange = (currentAppState) => {
this.setState({ currentAppState });
}
render() {
return (
<Text>Current state is: {this.state.currentAppState}</Text>
)
}
}
```

View File

@@ -1,71 +0,0 @@
# AsyncStorage
`AsyncStorage` is a simple, asynchronous, persistent, key-value storage system
that is global to the domain. It's a facade over, and should be used instead of
`window.localStorage` to provide an asynchronous API and multi functions. Each
method returns a `Promise` object.
It is recommended that you use an abstraction on top of `AsyncStorage` instead
of `AsyncStorage` directly for anything more than light usage since it operates
globally.
The batched functions are useful for executing a lot of operations at once,
allowing for optimizations to provide the convenience of a single promise after
all operations are complete.
## Methods
static **clear**()
Erases all AsyncStorage. You probably don't want to call this - use
`removeItem` or `multiRemove` to clear only your own keys instead. Returns a
Promise object.
static **getAllKeys**()
Gets all known keys. Returns a Promise object.
static **getItem**(key: string)
Fetches the value of the given key. Returns a Promise object.
static **mergeItem**(key: string, value: string)
Merges existing value with input value, assuming they are stringified JSON.
Returns a Promise object.
static **multiGet**(keys: Array<string>)
`multiGet` results in an array of key-value pair arrays that matches the input
format of `multiSet`. Returns a Promise object.
```js
multiGet(['k1', 'k2']) -> [['k1', 'val1'], ['k2', 'val2']]
```
static **multiMerge**(keyValuePairs: Array<Array<string>>)
multiMerge takes an array of key-value array pairs that match the output of
`multiGet`. It merges existing values with input values, assuming they are
stringified JSON. Returns a Promise object.
static **multiRemove**(keys: Array<string>)
Delete all the keys in the keys array. Returns a Promise object.
static **multiSet**(keyValuePairs: Array<Array<string>>)
`multiSet` takes an array of key-value array pairs that match the output of
`multiGet`. Returns a Promise object.
```js
multiSet([['k1', 'val1'], ['k2', 'val2']]);
```
static **removeItem**(key: string)
Removes the value of the given key. Returns a Promise object.
static **setItem**(key: string, value: string)
Sets the value of the given key. Returns a Promise object.

View File

@@ -1,16 +0,0 @@
# Clipboard
Clipboard gives you an interface for setting to the clipboard. (Getting
clipboard content is not supported on web.)
## Methods
static **getString**()
Returns a `Promise` of an empty string.
static **setString**(content: string): boolean
Copies a string to the clipboard. On web, some browsers may not support copying
to the clipboard, therefore, this function returns a boolean to indicate if the
copy was successful.

View File

@@ -1,13 +0,0 @@
# Dimensions
Note: dimensions may change (e.g due to device rotation) so any rendering logic
or styles that depend on these constants should try to call this function on
every render, rather than caching the value.
## Methods
static **get**(dimension: string)
Get a dimension (e.g., `"window"` or `"screen"`).
Example: `const { height, width } = Dimensions.get('window')`

View File

@@ -1,25 +0,0 @@
# I18nManager
Control and set the layout and writing direction of the application.
## Properties
**isRTL**: bool = false
Whether the application is currently in RTL mode.
## Methods
static **allowRTL**(allowRTL: bool)
Allow the application to display in RTL mode.
static **forceRTL**(forceRTL: bool)
Force the application to display in RTL mode.
static **setPreferredLanguageRTL**(isRTL: bool)
Set the application's preferred writing direction to RTL. You will need to
determine the user's preferred locale server-side (from HTTP headers) and
decide whether it's an RTL language.

View File

@@ -1,77 +0,0 @@
# NetInfo
`NetInfo` asynchronously determines the online/offline status of the
application.
Connection types:
* `bluetooth` - The user agent is using a Bluetooth connection.
* `cellular` - The user agent is using a cellular connection (e.g., EDGE, HSPA, LTE, etc.).
* `ethernet` - The user agent is using an Ethernet connection.
* `mixed` - The user agent is using multiple connection types.
* `none` - The user agent will not contact the network (offline).
* `other` - The user agent is using a connection type that is not one of enumerated connection types.
* `unknown` - The user agent has established a network connection, but is unable to determine what is the underlying connection technology.
* `wifi` - The user agent is using a Wi-Fi connection.
* `wimax` - The user agent is using a WiMAX connection.
## Methods
Note that support for retrieving the connection type depends upon browswer
support (and is limited to mobile browsers). It will default to `unknown` when
support is missing.
static **addEventListener**(eventName: ChangeEventName, handler: Function)
static **fetch**(): Promise
static **removeEventListener**(eventName: ChangeEventName, handler: Function)
## Properties
**isConnected**: bool = true
Available on all user agents. Asynchronously fetch a boolean to determine
internet connectivity. Use this if you are only interested with whether the device has internet connectivity.
**isConnected.addEventListener**(eventName: ChangeEventName, handler: Function)
**isConnected.fetch**(): Promise
**isConnected.removeEventListener**(eventName: ChangeEventName, handler: Function)
## Examples
Fetching the connection type:
```js
NetInfo.fetch().then((connectionType) => {
console.log('Connection type:', connectionType);
});
```
Subscribing to changes in the connection type:
```js
const handleConnectivityTypeChange = (connectionType) => {
console.log('Current connection type:', connectionType);
}
NetInfo.addEventListener('change', handleConnectivityTypeChange);
```
Fetching the connection status:
```js
NetInfo.isConnected.fetch().then((isConnected) => {
console.log('Connection status:', (isConnected ? 'online' : 'offline'));
});
```
Subscribing to changes in the connection status:
```js
const handleConnectivityStatusChange = (isConnected) => {
console.log('Current connection status:', (isConnected ? 'online' : 'offline'));
}
NetInfo.isConnected.addEventListener('change', handleConnectivityStatusChange);
```

View File

@@ -1,51 +0,0 @@
# PixelRatio
`PixelRatio` gives access to the device pixel density.
## Methods
static **get**()
Returns the device pixel density. Some examples:
* PixelRatio.get() === 1
* mdpi Android devices (160 dpi)
* PixelRatio.get() === 1.5
* hdpi Android devices (240 dpi)
* PixelRatio.get() === 2
* iPhone 4, 4S
* iPhone 5, 5c, 5s
* iPhone 6
* xhdpi Android devices (320 dpi)
* PixelRatio.get() === 3
* iPhone 6 plus
* xxhdpi Android devices (480 dpi)
* PixelRatio.get() === 3.5
* Nexus 6
static **getPixelSizeForLayoutSize**(layoutSize: number)
Converts a layout size (dp) to pixel size (px). Guaranteed to return an integer
number.
static **roundToNearestPixel**(layoutSize: number)
Rounds a layout size (dp) to the nearest layout size that corresponds to an
integer number of pixels. For example, on a device with a PixelRatio of 3,
`PixelRatio.roundToNearestPixel(8.4)` = `8.33`, which corresponds to exactly
`(8.33 * 3)` = `25` pixels.
## Examples
Fetching a correctly sized image. You should get a higher resolution image if
you are on a high pixel density device. A good rule of thumb is to multiply the
size of the image you display by the pixel ratio.
```js
const image = getImage({
width: PixelRatio.getPixelSizeForLayoutSize(200),
height: PixelRatio.getPixelSizeForLayoutSize(100),
});
<Image source={image} style={{ width: 200, height: 100 }} />
```

View File

@@ -1,45 +0,0 @@
# Platform
Detect what is the platform in which the app is running. This piece of
functionality can be useful when only small parts of a component are platform
specific.
## Properties
**OS**: string
`Platform.OS` will be `web` when running in a Web browser.
```js
import { Platform } from 'react-native';
const styles = StyleSheet.create({
height: (Platform.OS === 'web') ? 200 : 100,
});
```
## Methods
**select**(object): any
`Platform.select` takes an object containing `Platform.OS` as keys and returns
the value for the platform you are currently running on.
```js
import { Platform } from 'react-native';
const containerStyles = {
flex: 1,
...Platform.select({
android: {
backgroundColor: 'blue'
},
ios: {
backgroundColor: 'red'
},
web: {
backgroundColor: 'green'
}
})
});
```

View File

@@ -1,80 +0,0 @@
# StyleSheet
The `StyleSheet` abstraction converts predefined styles to (vendor-prefixed)
CSS without requiring a compile-time step. Styles that cannot be resolved
outside of the render loop (e.g., dynamic positioning) are usually applied as
inline styles. Read more about [how to style your
application](../guides/style.md).
## Methods
**create**(obj: {[key: string]: any})
Each key of the object passed to `create` must define a style object.
**flatten**: function
Flattens an array of styles into a single style object.
(web) **getStyleSheets**: function
Returns an array of stylesheets (`{ id, textContent }`). Useful for
compile-time or server-side rendering.
## Properties
**absoluteFill**: number
A very common pattern is to create overlays with position absolute and zero positioning,
so `absoluteFill` can be used for convenience and to reduce duplication of these repeated
styles.
```js
<View style={StyleSheet.absoluteFill} />
```
**absoluteFillObject**: object
Sometimes you may want `absoluteFill` but with a couple tweaks - `absoluteFillObject` can be
used to create a customized entry in a `StyleSheet`, e.g.:
```js
const styles = StyleSheet.create({
wrapper: {
...StyleSheet.absoluteFillObject,
backgroundColor: 'transparent',
top: 10
}
})
```
**hairlineWidth**: number
## Example
```js
<View style={styles.container}>
<Text
children={'Title text'}
style={[
styles.title,
this.props.isActive && styles.activeTitle
]}
/>
</View>
const styles = StyleSheet.create({
container: {
borderRadius: 4,
borderWidth: 0.5,
borderColor: '#d6d7da',
},
title: {
fontSize: 19,
fontWeight: 'bold',
},
activeTitle: {
color: 'red',
}
})
```

View File

@@ -1,35 +0,0 @@
# Vibration
Vibration is described as a pattern of on-off pulses, which may be of varying
lengths. The pattern may consist of either a single integer, describing the
number of milliseconds to vibrate, or an array of integers describing a pattern
of vibrations and pauses. Vibration is controlled with a single method:
`Vibration.vibrate()`.
The vibration is asynchronous so this method will return immediately. There
will be no effect on devices that do not support vibration.
## Methods
static **cancel**()
Stop the vibration.
static **vibrate**(pattern)
Start the vibration pattern.
## Examples
Vibrate once for 200ms:
```js
Vibration.vibrate(200);
Vibration.vibrate([200]);
```
Vibrate for 200ms, pause for 100ms, vibrate for 200ms:
```js
Vibration.vibrate([200, 100, 200]);
```

View File

@@ -1,70 +0,0 @@
# ActivityIndicator
## Props
[...View props](./View.md)
**animating**: boolean = true
Whether to show the indicator or hide it.
**color**: ?color = '#1976D2'
The foreground color of the spinner.
**hidesWhenStopped**: ?boolean = true
Whether the indicator should hide when not animating.
**size**: ?enum('small, 'large') | number = 'small'
Size of the indicator. Small has a height of `20`, large has a height of `36`.
## Examples
```js
import React, { Component } from 'react'
import { ActivityIndicator, StyleSheet, View } from 'react-native'
class ToggleAnimatingActivityIndicator extends Component {
constructor(props) {
super(props)
this.state = { animating: true }
}
componentDidMount: function() {
this.setToggleTimeout();
}
render() {
return (
<ActivityIndicator
animating={this.state.animating}
size="large"
style={[styles.centering, { height: 80 }]}
/>
);
}
_setToggleTimeout() {
setTimeout(() => {
this.setState({ animating: !this.state.animating })
this._setToggleTimeout()
}, 1200)
}
})
const styles = StyleSheet.create({
centering: {
alignItems: 'center',
justifyContent: 'center'
},
gray: {
backgroundColor: '#cccccc'
},
horizontal: {
flexDirection: 'row',
justifyContent: 'space-around'
}
})
```

View File

@@ -1,43 +0,0 @@
# Button
A basic button component. Supports a minimal level of customization. You can
build your own custom button using `TouchableOpacity` or
`TouchableNativeFeedback`.
## Props
**accessibilityLabel**: ?string
Overrides the text that's read by a screen reader when the user interacts
with the element.
**color**: ?string
Background color of the button.
**disabled**: ?boolean
If `true`, disable all interactions for this element.
**onPress**: function
This function is called on press.
**testID**: ?string
Used to locate this view in end-to-end tests.
**title**: string
Text to display inside the button.
## Examples
```js
<Button
accessibilityLabel="Learn more about this purple button"
color="#841584"
onPress={onPressLearnMore}
title="Learn More"
/>
```

View File

@@ -1,167 +0,0 @@
# Image
An accessibile image component with support for image resizing, default image,
and child content.
Unsupported React Native props:
`capInsets` (ios),
`onProgress` (ios)
## Props
**accessibilityLabel**: ?string
The text that's read by a screenreader when someone interacts with the image.
**accessible**: ?boolean
When `true`, indicates the image is an accessibility element.
**children**: ?any
Content to display over the image.
**defaultSource**: ?object
An image to display as a placeholder while downloading the final image off the
network. `{ uri: string, width, height }`
**onError**: ?function
Invoked on load error with `{nativeEvent: {error}}`.
**onLayout**: ?function
Invoked on mount and layout changes with `{ nativeEvent: { layout: { x, y, width,
height } } }`, where `x` and `y` are the offsets from the parent node.
**onLoad**: ?function
Invoked when load completes successfully.
**onLoadEnd**: ?function
Invoked when load either succeeds or fails,
**onLoadStart**: ?function
Invoked on load start.
**resizeMode**: ?enum('center', 'contain', 'cover', 'none', 'repeat', 'stretch') = 'cover'
Determines how to resize the image when the frame doesn't match the raw image
dimensions.
**source**: ?object
`uri` is a string representing the resource identifier for the image, which
could be an http address or a base64 encoded image. `{ uri: string, width, height }`
**style**: ?style
+ ...[View#style](./View.md)
+ `resizeMode`
**testID**: ?string
Used to locate a view in end-to-end tests.
## Properties
static **resizeMode**: object
Example usage:
```
<Image resizeMode={Image.resizeMode.contain} />
```
## Methods
static **getSize**(uri: string, success: (width, height) => {}, failure: function)
Retrieve the width and height (in pixels) of an image prior to displaying it.
This method can fail if the image cannot be found, or fails to download.
(In order to retrieve the image dimensions, the image may first need to be
loaded or downloaded, after which it will be cached. This means that in
principle you could use this method to preload images, however it is not
optimized for that purpose, and may in future be implemented in a way that does
not fully load/download the image data.)
static **prefetch**(url: string): Promise
Prefetches a remote image for later use by downloading it.
## Examples
```js
import placeholderAvatar from './placeholderAvatar.png'
import React, { Component } from 'react'
import { Image, PropTypes, StyleSheet } from 'react-native'
export default class ImageExample extends Component {
constructor(props, context) {
super(props, context)
this.state = { loading: true }
}
static propTypes = {
size: PropTypes.oneOf(['small', 'normal', 'large']),
testID: Image.propTypes.testID,
user: PropTypes.object
}
static defaultProps = {
size: 'normal'
}
_onLoad(e) {
console.log('Avatar.onLoad', e)
this.setState({ loading: false })
}
render() {
const { size, testID, user } = this.props
const loadingStyle = this.state.loading ? { styles.loading } : { }
return (
<Image
accessibilityLabel={`${user.name}'s profile picture`}
defaultSource={{ uri: placeholderAvatar }}
onLoad={this._onLoad.bind(this)}
resizeMode='cover'
source={{ uri: user.avatarUrl }}
style={[
styles.base,
styles[size],
loadingStyle
]}
/>
)
}
}
const styles = StyleSheet.create({
base: {
borderColor: 'white',
borderRadius: 5,
borderWidth: 5
},
loading: {
opacity: 0.5
},
small: {
height: 32,
width: 32
},
normal: {
height: 48,
width: 48
},
large: {
height: 64,
width: 64
}
})
```

View File

@@ -1,27 +0,0 @@
# ProgressBar
Display an activity progress bar.
## Props
[...View props](./View.md)
**color**: ?string = '#1976D2'
Color of the progress bar.
**indeterminate**: ?boolean = true
Whether the progress bar will show indeterminate progress.
**progress**: ?number
The progress value (between 0 and 1).
**testID**: ?string
Used to locate this view in end-to-end tests.
(web) **trackColor**: ?string = 'transparent'
Color of the track bar.

View File

@@ -1,134 +0,0 @@
# ScrollView
A scrollable `View` that provides itegration with the touch-locking "responder"
system. `ScrollView`'s must have a bounded height: either set the height of the
view directly (discouraged) or make sure all parent views have bounded height
(e.g., transfer `{ flex: 1}` down the view stack).
## Props
[...View props](./View.md)
**contentContainerStyle**: ?style
These styles will be applied to the scroll view content container which wraps
all of the child views.
**horizontal**: ?boolean = false
When `true`, the scroll view's children are arranged horizontally in a row
instead of vertically in a column.
**keyboardDismissMode**: ?enum('none', 'on-drag') = 'none'
Determines whether the keyboard gets dismissed in response to a scroll drag.
* `none` (the default), drags do not dismiss the keyboard.
* `on-drag`, the keyboard is dismissed when a drag begins.
* `interactive` (not supported on web; same as `none`)
**onContentSizeChange**: ?function
Called when scrollable content view of the `ScrollView` changes. It's
implemented using the `onLayout` handler attached to the content container
which this `ScrollView` renders.
**onScroll**: ?function
Fires at most once per frame during scrolling. The frequency of the events can
be contolled using the `scrollEventThrottle` prop.
Invoked on scroll with the following event:
```js
{
nativeEvent: {
contentOffset: { x, y },
contentSize: { height, width },
layoutMeasurement: { height, width }
}
}
```
**refreshControl**: ?element
TODO
A [RefreshControl](../RefreshControl) component, used to provide
pull-to-refresh functionality for the `ScrollView`.
**scrollEnabled**: ?boolean = true
When false, the content does not scroll.
**scrollEventThrottle**: ?number = 0
This controls how often the scroll event will be fired while scrolling (as a
time interval in ms). A lower number yields better accuracy for code that is
tracking the scroll position, but can lead to scroll performance problems. The
default value is `0`, which means the scroll event will be sent only once each
time the view is scrolled.
## Instance methods
**getInnerViewNode()**: any
Returns a reference to the underlying content container DOM node within the `ScrollView`.
**getScrollableNode()**: any
Returns a reference to the underlying scrollable DOM node.
**getScrollResponder()**: Component
Returns a reference to the underlying scroll responder, which supports
operations like `scrollTo`. All `ScrollView`-like components should implement
this method so that they can be composed while providing access to the
underlying scroll responder's methods.
**scrollTo(options: { x: number = 0; y: number = 0; animated: boolean = true })**
Scrolls to a given `x`, `y` offset (animation is not currently supported).
## Examples
```js
import React, { Component } from 'react'
import { ScrollView, StyleSheet } from 'react-native'
import Item from './Item'
export default class ScrollViewExample extends Component {
constructor(props, context) {
super(props, context)
this.state = {
items: Array.from(new Array(20)).map((_, i) => ({ id: i }))
}
}
onScroll(e) {
console.log(e)
}
render() {
return (
<ScrollView
children={this.state.items.map((item) => <Item {...item} />)}
contentContainerStyle={styles.container}
horizontal
onScroll={(e) => this.onScroll(e)}
scrollEventThrottle={100}
style={styles.root}
/>
)
}
}
const styles = StyleSheet.create({
root: {
borderWidth: 1
},
container: {
padding: 10
}
})
```

View File

@@ -1,76 +0,0 @@
# Switch
This is a controlled component that requires an `onValueChange` callback that
updates the value prop in order for the component to reflect user actions. If
the `value` prop is not updated, the component will continue to render the
supplied `value` prop instead of the expected result of any user actions.
## Props
[...View props](./View.md)
**disabled**: ?boolean = false
If `true` the user won't be able to interact with the switch.
**onValueChange**: ?function
Invoked with the new value when the value changes.
**value**: ?boolean = false
The value of the switch. If `true` the switch will be turned on.
(web) **activeThumbColor**: ?color = #009688
The color of the thumb grip when the switch is turned on.
(web) **activeTrackColor**: ?color = #A3D3CF
The color of the track when the switch is turned on.
(web) **thumbColor**: ?color = #FAFAFA
The color of the thumb grip when the switch is turned off.
(web) **trackColor**: ?color = #939393
The color of the track when the switch is turned off.
## Examples
```js
import React, { Component } from 'react'
import { Switch, View } from 'react-native'
class ColorSwitchExample extends Component {
constructor(props) {
super(props)
this.state = {
colorTrueSwitchIsOn: true,
colorFalseSwitchIsOn: false
}
}
render() {
return (
<View>
<Switch
activeThumbColor='#428BCA'
activeTrackColor='#A0C4E3'
onValueChange={(value) => this.setState({ colorFalseSwitchIsOn: value })}
value={this.state.colorFalseSwitchIsOn}
/>
<Switch
activeThumbColor='#5CB85C'
activeTrackColor='#ADDAAD'
onValueChange={(value) => this.setState({ colorTrueSwitchIsOn: value })}
thumbColor='#EBA9A7'
trackColor='#D9534F'
value={this.state.colorTrueSwitchIsOn}
/>
</View>
)
}
}
```

View File

@@ -1,161 +0,0 @@
# Text
`Text` is component for displaying text. It supports style, basic touch
handling, and inherits typographic styles from ancestor elements.
The `Text` is unique relative to layout: child elements use text layout
(`inline`) rather than flexbox layout. This means that elements inside of a
`Text` are not rectangles, as they wrap when reaching the edge of their
container.
Unsupported React Native props:
`allowFontScaling` (ios),
`suppressHighlighting` (ios)
## Props
NOTE: `Text` will transfer all other props to the rendered HTML element.
(web) **accessibilityLabel**: ?string
Overrides the text that's read by a screen reader when the user interacts
with the element. (This is implemented using `aria-label`.)
See the [Accessibility guide](../guides/accessibility) for more information.
(web) **accessibilityRole**: ?oneOf(roles)
Allows assistive technologies to present and support interaction with the view
in a manner that is consistent with user expectations for similar views of that
type. For example, marking a touchable view with an `accessibilityRole` of
`button`. (This is implemented using [ARIA roles](http://www.w3.org/TR/wai-aria/roles#role_definitions)).
See the [Accessibility guide](../guides/accessibility) for more information.
**accessible**: ?boolean
When `true`, indicates that the view is an accessibility element (i.e.,
focusable) and groups its child content. By default, all the touchable elements
and elements with `accessibilityRole` of `button` and `link` are accessible.
(This is implemented using `tabindex`.)
See the [Accessibility guide](../guides/accessibility) for more information.
**children**: ?any
Child content.
**importantForAccessibility**: ?enum('auto', 'no-hide-descendants', 'yes')
A value of `no` will remove the element from the tab flow.
A value of `no-hide-descendants` will hide the element and its children from
assistive technologies. (This is implemented using `aria-hidden`.)
See the [Accessibility guide](../guides/accessibility) for more information.
**numberOfLines**: ?number
Truncates the text with an ellipsis after this many lines. Currently only supports `1`.
**onLayout**: ?function
Invoked on mount and layout changes with `{ nativeEvent: { layout: { x, y, width,
height } } }`, where `x` and `y` are the offsets from the parent node.
**onPress**: ?function
This function is called on press.
**selectable**: ?boolean
When `false`, the text is not selectable.
**style**: ?style
+ ...[View#style](View.md)
+ `color`
+ `fontFamily`
+ `fontFeatureSettings`
+ `fontSize`
+ `fontStyle`
+ `fontWeight`
+ `letterSpacing`
+ `lineHeight`
+ `textAlign`
+ `textAlignVertical`
+ `textDecorationLine`
+ `textIndent`
+ `textOverflow`
+ `textRendering`
+ `textShadowColor`
+ `textShadowOffset`
+ `textShadowRadius`
+ `textTransform`
+ `unicodeBidi`
+ `whiteSpace`
+ `wordWrap`
+ `writingDirection`
‡ web only.
**testID**: ?string
Used to locate this view in end-to-end tests.
## Examples
```js
import React, { Component, PropTypes } from 'react'
import { StyleSheet, Text } from 'react-native'
export default class PrettyText extends Component {
static propTypes = {
...Text.propTypes,
color: PropTypes.oneOf(['white', 'gray', 'red']),
size: PropTypes.oneOf(['small', 'normal', 'large']),
weight: PropTypes.oneOf(['light', 'normal', 'bold'])
};
static defaultProps = {
...Text.defaultProps,
color: 'gray',
size: 'normal',
weight: 'normal'
};
render() {
const { color, size, style, weight, ...other } = this.props;
return (
<Text
...other
style={[
style,
colorStyles[color],
sizeStyles[size],
weightStyles[weight]
]}
/>
);
}
}
const colorStyles = StyleSheet.create({
white: { color: 'white' },
gray: { color: 'gray' },
red: { color: 'red' }
})
const sizeStyles = StyleSheet.create({
small: { fontSize: '0.85rem', padding: '0.5rem' },
normal: { fontSize: '1rem', padding: '0.75rem' },
large: { fontSize: '1.5rem', padding: '1rem' }
})
const weightStyles = StyleSheet.create({
light: { fontWeight: '300' },
normal: { fontWeight: '400' },
bold: { fontWeight: '700' }
})
```

View File

@@ -1,226 +0,0 @@
# TextInput
Accessible single- and multi-line text input via a keyboard. Supports features
such as auto-complete, auto-focus, placeholder text, and event callbacks.
Note: some props are exclusive to or excluded from `multiline`.
Unsupported React Native props:
`onEndEditing`,
`clearButtonMode` (ios),
`enablesReturnKeyAutomatically` (ios),
`placeholderTextColor`,
`returnKeyType` (ios),
`selectionState` (ios),
`underlineColorAndroid` (android)
## Props
[...View props](./View.md)
**autoCapitalize**: ?enum('characters', 'none', 'sentences', 'words') = 'sentences'
Automatically capitalize certain characters (only available in Chrome and iOS Safari).
* `characters`: Automatically capitalize all characters.
* `none`: Completely disables automatic capitalization
* `sentences`: Automatically capitalize the first letter of sentences.
* `words`: Automatically capitalize the first letter of words.
(web) **autoComplete**: ?string
Indicates whether the value of the control can be automatically completed by
the browser. [Accepted values](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input).
**autoCorrect**: ?boolean = true
Automatically correct spelling mistakes (only available in iOS Safari).
**autoFocus**: ?boolean = false
If `true`, focuses the input on `componentDidMount`. Only the first form element
in a document with `autofocus` is focused.
**blurOnSubmit**: ?boolean
If `true`, the text field will blur when submitted. The default value is `true`
for single-line fields and `false` for multiline fields. Note, for multiline
fields setting `blurOnSubmit` to `true` means that pressing return will blur
the field and trigger the `onSubmitEditing` event instead of inserting a
newline into the field.
**clearTextOnFocus**: ?boolean = false
If `true`, clears the text field automatically when focused.
**defaultValue**: ?string
Provides an initial value that will change when the user starts typing. Useful
for simple use-cases where you don't want to deal with listening to events and
updating the `value` prop to keep the controlled state in sync.
**editable**: ?boolean = true
If `false`, text is not editable (i.e., read-only).
**keyboardType**: enum('default', 'email-address', 'numeric', 'phone-pad', 'search', 'url', 'web-search') = 'default'
Determines which keyboard to open. (NOTE: Safari iOS requires an ancestral
`<form action>` element to display the `search` keyboard).
(Not available when `multiline` is `true`.)
**maxLength**: ?number
Limits the maximum number of characters that can be entered.
**multiline**: ?boolean = false
If true, the text input can be multiple lines.
**numberOfLines**: ?number = 2
Sets the number of lines for a multiline `TextInput`.
(Requires `multiline` to be `true`.)
**onBlur**: ?function
Callback that is called when the text input is blurred.
**onChange**: ?function
Callback that is called when the text input's text changes.
**onChangeText**: ?function
Callback that is called when the text input's text changes. The text is passed
as an argument to the callback handler.
**onFocus**: ?function
Callback that is called when the text input is focused.
**onKeyPress**: ?function
Callback that is called when a key is pressed. This will be called with `{
nativeEvent: { key: keyValue } }` where keyValue is 'Enter` or 'Backspace' for
respective keys and the typed-in character otherwise including ' ' for space.
Modifier keys are also included in the nativeEvent. Fires before onChange
callbacks.
**onSelectionChange**: ?function
Callback that is called when the text input's selection changes. This will be called with
`{ nativeEvent: { selection: { start, end } } }`.
**onSubmitEditing**: ?function
Callback that is called when the keyboard's submit button is pressed.
**placeholder**: ?string
The string that will be rendered in an empty `TextInput` before text has been
entered.
**secureTextEntry**: ?boolean = false
If true, the text input obscures the text entered so that sensitive text like
passwords stay secure.
(Not available when `multiline` is `true`.)
**selection**: ?{ start: number, end: ?number }
The start and end of the text input's selection. Set start and end to the same value to position the cursor.
**selectTextOnFocus**: ?boolean = false
If `true`, all text will automatically be selected on focus.
**style**: ?style
+ ...[Text#style](./Text.md)
+ `resize` ‡
‡ web only.
**testID**: ?string
Used to locate this view in end-to-end tests.
**value**: ?string
The value to show for the text input. `TextInput` is a controlled component,
which means the native `value` will be forced to match this prop if provided.
Read about how [React form
components](https://facebook.github.io/react/docs/forms.html) work. To prevent
user edits to the value set `editable={false}`.
## Instance methods
**blur()**
Blur the underlying DOM input.
**clear()**
Clear the text from the underlying DOM input.
**focus()**
Focus the underlying DOM input.
**isFocused()**
Returns `true` if the input is currently focused; `false` otherwise.
## Examples
```js
import React, { Component } from 'react'
import { StyleSheet, TextInput } from 'react-native'
export default class TextInputExample extends Component {
constructor(props, context) {
super(props, context)
this.state = { isFocused: false }
}
_onBlur(e) {
this.setState({ isFocused: false })
}
_onFocus(e) {
this.setState({ isFocused: true })
}
render() {
return (
<TextInput
accessibilityLabel='Write a status update'
maxNumberOfLines={5}
multiline
numberOfLines={2}
onBlur={this._onBlur.bind(this)}
onFocus={this._onFocus.bind(this)}
placeholder={`What's happening?`}
style={[
styles.default
this.state.isFocused && styles.focused
]}
/>
);
}
}
const styles = StyleSheet.create({
default: {
borderColor: 'gray',
borderBottomWidth: 2
},
focused: {
borderColor: 'blue'
}
})
```

View File

@@ -1,46 +0,0 @@
# TouchableWithoutFeedback
Do not use unless you have a very good reason. All the elements that respond to
press should have a visual feedback when touched. This is one of the primary
reason a "web" app doesn't feel "native".
**NOTE: `TouchableWithoutFeedback` supports only one child**. If you wish to have
several child components, wrap them in a View.
## Props
[...View props](./View.md)
**delayLongPress**: ?number
Delay in ms, from `onPressIn`, before `onLongPress` is called.
**delayPressIn**: ?number
Delay in ms, from the start of the touch, before `onPressIn` is called.
**delayPressOut**: ?number
Delay in ms, from the release of the touch, before `onPressOut` is called.
**disabled**: ?boolean
If `true`, disable all interactions for this component.
**onLongPress**: ?function
**onPress**: ?function
Called when the touch is released, but not if cancelled (e.g. by a scroll that steals the responder lock).
**onPressIn**: ?function
**onPressOut**: ?function
**pressRetentionOffset**: ?`{top: number, left: number, bottom: number, right: number}`
When the scroll view is disabled, this defines how far your touch may move off
of the button, before deactivating the button. Once deactivated, try moving it
back and you'll see that the button is once again reactivated! Move it back and
forth several times while the scroll view is disabled. Ensure you pass in a
constant to reduce memory allocations.

View File

@@ -1,317 +0,0 @@
# View
`View` is the fundamental UI building block. It is a component that supports
style, layout with flexbox, and accessibility controls. It can be nested
inside another `View` and has 0-to-many children of any type.
Also, refer to React Native's documentation about the [Gesture Responder
System](http://facebook.github.io/react-native/releases/0.22/docs/gesture-responder-system.html).
Unsupported React Native props: `collapsable`, `onAccessibilityTap`, `onMagicTap`.
## Props
NOTE: `View` will transfer all other props to the rendered HTML element.
**accessibilityLabel**: ?string
Overrides the text that's read by a screen reader when the user interacts
with the element. (This is implemented using `aria-label`.)
See the [Accessibility guide](../guides/accessibility.md) for more information.
**accessibilityLiveRegion**: ?enum('assertive', 'none', 'polite')
Indicates to assistive technologies whether to notify the user when the view
changes. The values of this attribute are expressed in degrees of importance.
When regions are specified as `polite` (recommended), updates take low
priority. When regions are specified as `assertive`, assistive technologies
will interrupt and immediately notify the user. (This is implemented using
[`aria-live`](http://www.w3.org/TR/wai-aria/states_and_properties#aria-live).)
See the [Accessibility guide](../guides/accessibility.md) for more information.
(web) **accessibilityRole**: ?enum(roles)
Allows assistive technologies to present and support interaction with the view
in a manner that is consistent with user expectations for similar views of that
type. For example, marking a touchable view with an `accessibilityRole` of
`button`. (This is implemented using [ARIA roles](http://www.w3.org/TR/wai-aria/roles#role_definitions)).
See the [Accessibility guide](../guides/accessibility.md) for more information.
**accessible**: ?boolean
When `true`, indicates that the view is an accessibility element (i.e.,
focusable) and groups its child content. By default, all the touchable elements
and elements with `accessibilityRole` of `button` and `link` are accessible.
(This is implemented using `tabindex`.)
See the [Accessibility guide](../guides/accessibility.md) for more information.
**children**: ?element
Child content.
**hitSlop**: ?object
This defines how far a touch event can start away from the view (in pixels).
Typical interface guidelines recommend touch targets that are at least 30 - 40
points/density-independent pixels.
For example, if a touchable view has a height of `20` the touchable height can
be extended to `40` with `hitSlop={{top: 10, bottom: 10, left: 0, right: 0}}`.
**importantForAccessibility**: ?enum('auto', 'no', 'no-hide-descendants', 'yes')
A value of `no` will remove the element from the tab flow.
A value of `no-hide-descendants` will hide the element and its children from
assistive technologies. (This is implemented using `aria-hidden`.)
See the [Accessibility guide](../guides/accessibility.md) for more information.
**onLayout**: ?function
Invoked on mount and layout changes with `{ nativeEvent: { layout: { x, y, width,
height } } }`, where `x` and `y` are the offsets from the parent node.
**onMoveShouldSetResponder**: ?function => boolean
Does this view want to "claim" touch responsiveness? This is called for every
touch move on the `View` when it is not the responder.
**onMoveShouldSetResponderCapture**: ?function => boolean
If a parent `View` wants to prevent a child `View` from becoming responder on a
move, it should have this handler return `true`.
**onResponderGrant**: ?function
The `View` is now responding to touch events. This is the time to highlight and
show the user what is happening. For most touch interactions, you'll simply
want to wrap your component in `TouchableHighlight` or `TouchableOpacity`.
**onResponderMove**: ?function
The user is moving their finger.
**onResponderReject**: ?function
Another responder is already active and will not release it to the `View`
asking to be the responder.
**onResponderRelease**: ?function
Fired at the end of the touch.
**onResponderTerminate**: ?function
The responder has been taken from the `View`.
**onResponderTerminationRequest**: ?function
Some other `View` wants to become responder and is asking this `View` to
release its responder. Returning `true` allows its release.
**onStartShouldSetResponder**: ?function => boolean
Does this view want to become responder on the start of a touch?
**onStartShouldSetResponderCapture**: ?function => boolean
If a parent `View` wants to prevent a child `View` from becoming the responder
on a touch start, it should have this handler return `true`.
**pointerEvents**: ?enum('auto', 'box-only', 'box-none', 'none') = 'auto'
Controls whether the View can be the target of touch events. The enhanced
`pointerEvents` modes provided are not part of the CSS spec, therefore,
`pointerEvents` is excluded from `style`.
`box-none` is the equivalent of:
```css
.box-none { pointer-events: none !important; }
.box-none > * { pointer-events: auto; }
```
`box-only` is the equivalent of:
```css
.box-only { pointer-events: auto !important; }
.box-only > * { pointer-events: none; }
```
**style**: ?style
+ `alignContent`
+ `alignItems`
+ `alignSelf`
+ `animationDelay`
+ `animationDirection`
+ `animationDuration`
+ `animationFillMode`
+ `animationIterationCount`
+ `animationName`
+ `animationPlayState`
+ `animationTimingFunction`
+ `backfaceVisibility`
+ `backgroundAttachment`
+ `backgroundBlendMode`
+ `backgroundClip`
+ `backgroundColor`
+ `backgroundImage`
+ `backgroundOrigin`
+ `backgroundPosition`
+ `backgroundRepeat`
+ `backgroundSize`
+ `borderColor` (single value)
+ `borderTopColor`
+ `borderBottomColor`
+ `borderRightColor`
+ `borderLeftColor`
+ `borderRadius` (single value)
+ `borderTopLeftRadius`
+ `borderTopRightRadius`
+ `borderBottomLeftRadius`
+ `borderBottomRightRadius`
+ `borderStyle` (single value)
+ `borderTopStyle`
+ `borderRightStyle`
+ `borderBottomStyle`
+ `borderLeftStyle`
+ `borderWidth` (single value)
+ `borderBottomWidth`
+ `borderLeftWidth`
+ `borderRightWidth`
+ `borderTopWidth`
+ `bottom`
+ `boxShadow`
+ `boxSizing`
+ `clip`
+ `cursor`
+ `display`
+ `filter`
+ `flex` (number)
+ `flexBasis`
+ `flexDirection`
+ `flexGrow`
+ `flexShrink`
+ `flexWrap`
+ `gridAutoColumns`
+ `gridAutoFlow`
+ `gridAutoRows`
+ `gridColumnEnd`
+ `gridColumnGap`
+ `gridColumnStart`
+ `gridRowEnd`
+ `gridRowGap`
+ `gridRowStart`
+ `gridTemplateColumns`
+ `gridTemplateRows`
+ `gridTemplateAreas`
+ `height`
+ `justifyContent`
+ `left`
+ `margin` (single value)
+ `marginBottom`
+ `marginHorizontal`
+ `marginLeft`
+ `marginRight`
+ `marginTop`
+ `marginVertical`
+ `maxHeight`
+ `maxWidth`
+ `minHeight`
+ `minWidth`
+ `opacity`
+ `order`
+ `outline`
+ `outlineColor`
+ `overflow`
+ `overflowX`
+ `overflowY`
+ `padding` (single value)
+ `paddingBottom`
+ `paddingHorizontal`
+ `paddingLeft`
+ `paddingRight`
+ `paddingTop`
+ `paddingVertical`
+ `perspective`
+ `perspectiveOrigin`
+ `position`
+ `right`
+ `shadowColor`
+ `shadowOffset`
+ `shadowOpacity`
+ `shadowRadius`
+ `top`
+ `transform`
+ `transformOrigin`
+ `transitionDelay`
+ `transitionDuration`
+ `transitionProperty`
+ `transitionTimingFunction`
+ `userSelect`
+ `visibility`
+ `width`
+ `willChange`
+ `zIndex`
‡ web only.
Default:
```js
{
alignItems: 'stretch',
borderWidth: 0,
borderStyle: 'solid',
boxSizing: 'border-box',
display: 'flex',
flexBasis: 'auto',
flexDirection: 'column',
flexShrink: 0,
margin: 0,
padding: 0,
position: 'relative'
};
```
(See [facebook/yoga](https://github.com/facebook/yoga)).
**testID**: ?string
Used to locate this view in end-to-end tests.
## Examples
```js
import React, { Component, PropTypes } from 'react'
import { StyleSheet, View } from 'react-native'
export default class ViewExample extends Component {
render() {
return (
<View style={styles.row}>
{
['1', '2', '3', '4', '5'].map((value, i) => {
return <View children={value} key={i} style={styles.cell} />
})
}
</View>
);
}
}
const styles = StyleSheet.create({
row: {
flexDirection: 'row'
},
cell: {
flexGrow: 1
}
})
```

View File

@@ -1,13 +1,13 @@
# Direct manipulation
React Native for Web provides several methods to directly access the underlying
DOM node. This can be useful when you need to make changes directly to a
component without using state/props to trigger a re-render of the entire
subtree, or when you want to focus a view or measure its on-screen dimensions.
React Native provides several methods to directly access the underlying host
node. This can be useful when you need to make changes directly to a component
without using state/props to trigger a re-render of the entire subtree, or when
you want to focus a view or measure its on-screen dimensions.
The methods described are available on most of the default components provided
by React Native for Web. Note, however, that they are *not* available on the
composite components that you define in your own app.
by React Native for Web. Note, however, that they are *not* available on the composite
components that you define in your own app.
## Instance methods
@@ -35,11 +35,17 @@ Like `measure`, but measures the view relative to another view, specified as
`relativeToNativeNode`. This means that the returned `x`, `y` are relative to
the origin `x`, `y` of the ancestor view.
As always, to obtain a native node handle for a component, you can use
`findNodeHandle(component)`.
**measureInWindow**(callback: (x, y, width, height) => void)
Determines the location of the given view in the window and returns the values
via an async callback.
**setNativeProps**(nativeProps: Object)
This function sends props straight to the underlying DOM node. See the [direct
manipulation](../guides/direct-manipulation.md) guide for cases where
`setNativeProps` should be used.
This function sends props straight to the underlying DOM node.
## About `setNativeProps`

View File

@@ -10,14 +10,26 @@ polyfill.
## Web packager
[Webpack](https://webpack.js.org) is a popular build tool for web apps. Below is an
example of how to configure a build that uses [Babel](https://babeljs.io/) to
compile your JavaScript for the web.
_example_ of how to configure a build that uses [Babel](https://babeljs.io/) to
compile your JavaScript for the web. Please refer to the webpack documentation
when setting up your project.
Install webpack-related dependencies, for example:
```
yarn add --dev babel-loader url-loader webpack webpack-dev-server
```
Create a `web/webpack.config.js` file:
```js
// web/webpack.config.js
const path = require('path');
const webpack = require('webpack');
const appDirectory = path.resolve(__dirname, '../');
// This is needed for webpack to compile JavaScript.
// Many OSS React Native packages are not compiled to ES5 before being
// published. If you depend on uncompiled packages they may cause webpack build
@@ -25,25 +37,26 @@ Create a `web/webpack.config.js` file:
// `node_module`.
const babelLoaderConfiguration = {
test: /\.js$/,
// Add every directory that needs to be compiled by Babel during the build
// Add every directory that needs to be compiled by Babel during the build.
include: [
path.resolve(__dirname, 'src'),
path.resolve(__dirname, 'node_modules/react-native-uncompiled')
path.resolve(appDirectory, 'index.web.js'),
path.resolve(appDirectory, 'src'),
path.resolve(appDirectory, 'node_modules/react-native-uncompiled')
],
use: {
loader: 'babel-loader',
options: {
cacheDirectory: true,
// This aliases 'react-native' to 'react-native-web' and includes only
// the modules needed by the app
plugins: ['react-native-web/babel']
// The 'react-native' preset is recommended (or use your own .babelrc)
// the modules needed by the app.
plugins: ['react-native-web/babel', 'transform-runtime'],
// The 'react-native' preset is recommended (or use your own .babelrc).
presets: ['react-native']
}
}
};
// This is needed for webpack to import static images in JavaScript files
// This is needed for webpack to import static images in JavaScript files.
const imageLoaderConfiguration = {
test: /\.(gif|jpe?g|png|svg)$/,
use: {
@@ -55,6 +68,15 @@ const imageLoaderConfiguration = {
};
module.exports = {
// your web-specific entry file
entry: path.resolve(appDirectory, 'index.web.js'),
// configures where the build ends up
output: {
filename: 'bundle.web.js',
path: path.resolve(appDirectory, 'dist')
},
// ...the rest of your config
module: {
@@ -69,7 +91,8 @@ module.exports = {
// builds to eliminate development checks and reduce build size. You may
// wish to include additional optimizations.
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('production')
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development'),
__DEV__: process.env.NODE_ENV === 'production' || true
})
],
@@ -82,24 +105,20 @@ module.exports = {
}
```
To run in development:
To run in development from the root of your application:
```
./node_modules/.bin/webpack-dev-server -d --config web/webpack.config.js --inline --hot --colors
./node_modules/.bin/webpack-dev-server -d --config ./web/webpack.config.js --inline --hot --colors
```
To build for production:
```
./node_modules/.bin/webpack -p --config web/webpack.config.js
./node_modules/.bin/webpack -p --config ./web/webpack.config.js
```
Please refer to the Webpack documentation for more information on configuration.
## Web entry
Create a `index.web.js` file (or simply `index.js` for web-only apps).
### Client-side rendering
Rendering using `AppRegistry`:
@@ -127,6 +146,7 @@ import AppHeader from './src/AppHeader';
import React from 'react';
import ReactNative from 'react-native';
// use .hydrate if hydrating a SSR app
ReactNative.render(<AppHeader />, document.getElementById('react-app-header'))
```
@@ -197,10 +217,20 @@ target platform.
## Testing with Jest
[Jest](https://facebook.github.io/jest/) also needs to map `react-native` to `react-native-web`.
[Jest](https://facebook.github.io/jest/) can be configured to improve snapshots
of `react-native-web` components.
```
"jest": {
{
"snapshotSerializers": [ "enzyme-to-json/serializer", "react-native-web/jest/serializer" ]
}
```
Jest also needs to map `react-native` to `react-native-web` (unless you are
using Babel with the `react-native-web/babel` plugin).
```
{
"moduleNameMapper": {
"react-native": "<rootDir>/node_modules/react-native-web"
}

View File

@@ -0,0 +1,93 @@
/* eslint-disable react/jsx-sort-props */
/**
* @flow
*/
import CustomSize from './examples/CustomSize';
import PropColor from './examples/PropColor';
import PropDisabled from './examples/PropDisabled';
import PropOnValueChange from './examples/PropOnValueChange';
import PropValue from './examples/PropValue';
import React from 'react';
import UIExplorer, {
AppText,
Code,
Description,
DocItem,
Section,
storiesOf
} from '../../ui-explorer';
const CheckBoxScreen = () => (
<UIExplorer title="CheckBox" url="components/CheckBox">
<Description>
<AppText>
This is a controlled component that requires an <Code>onValueChange</Code> callback that
updates the value prop in order for the component to reflect user actions. If the{' '}
<Code>value</Code> prop is not updated, the component will continue to render the supplied{' '}
<Code>value</Code> prop instead of the expected result of any user actions.
</AppText>
</Description>
<Section title="Props">
<DocItem name="...View props" />
<DocItem
description="Customize the color of the checkbox."
example={{
render: () => <PropColor />
}}
label="web"
name="color"
typeInfo="?color"
/>
<DocItem
description="If true, the user won't be able to interact with the checkbox."
example={{
render: () => <PropDisabled />
}}
name="disabled"
typeInfo="?boolean = false"
/>
<DocItem
description="Invoked with the event when the value changes."
name="onChange"
typeInfo="?function"
/>
<DocItem
description="Invoked with the new value when the value changes."
example={{
render: () => <PropOnValueChange />
}}
name="onValueChange"
typeInfo="?function"
/>
<DocItem
description="The value of the checkbox. If `true` the checkbox will be checked."
example={{
render: () => <PropValue />
}}
name="value"
typeInfo="?boolean = false"
/>
</Section>
<Section title="More examples">
<DocItem
description="The checkbox size can be controlled by the 'height' and 'width' style properties"
example={{
code: '<CheckBox style={{ height: 32, width: 32 }} />',
render: () => <CustomSize />
}}
name="Custom size"
/>
</Section>
</UIExplorer>
);
storiesOf('Components', module).add('CheckBox', CheckBoxScreen);

View File

@@ -0,0 +1,20 @@
/**
* @flow
*/
import React from 'react';
import styles from './styles';
import { CheckBox, View } from 'react-native';
const CustomSizeExample = () => (
<View style={styles.row}>
<View style={styles.marginRight}>
<CheckBox style={{ height: 20, width: 20 }} value />
</View>
<View style={styles.marginRight}>
<CheckBox style={{ height: 32, width: 32 }} value />
</View>
</View>
);
export default CustomSizeExample;

View File

@@ -0,0 +1,20 @@
/**
* @flow
*/
import React from 'react';
import styles from './styles';
import { CheckBox, View } from 'react-native';
const CheckBoxColorExample = () => (
<View style={styles.row}>
<View style={styles.marginRight}>
<CheckBox color="#1DA1F2" value />
</View>
<View style={styles.marginRight}>
<CheckBox color="#F45D22" value />
</View>
</View>
);
export default CheckBoxColorExample;

View File

@@ -0,0 +1,20 @@
/**
* @flow
*/
import React from 'react';
import styles from './styles';
import { CheckBox, View } from 'react-native';
const CheckBoxDisabledExample = () => (
<View style={styles.row}>
<View style={styles.marginRight}>
<CheckBox disabled value={false} />
</View>
<View style={styles.marginRight}>
<CheckBox disabled value />
</View>
</View>
);
export default CheckBoxDisabledExample;

View File

@@ -0,0 +1,59 @@
/**
* @flow
*/
import styles from './styles';
import React, { PureComponent } from 'react';
import { CheckBox, Text, View } from 'react-native';
class CheckBoxOnValueChangeExample extends PureComponent {
state = {
eventSwitchIsOn: false,
eventSwitchRegressionIsOn: true
};
render() {
const { eventSwitchIsOn, eventSwitchRegressionIsOn } = this.state;
return (
<View style={styles.row}>
<View style={[styles.alignCenter, styles.marginRight]}>
<CheckBox
onValueChange={this._handleEventSwitch}
style={styles.marginBottom}
value={eventSwitchIsOn}
/>
<CheckBox
onValueChange={this._handleEventSwitch}
style={styles.marginBottom}
value={eventSwitchIsOn}
/>
<Text>{eventSwitchIsOn ? 'On' : 'Off'}</Text>
</View>
<View style={styles.alignCenter}>
<CheckBox
onValueChange={this._handleEventSwitchRegression}
style={styles.marginBottom}
value={eventSwitchRegressionIsOn}
/>
<CheckBox
onValueChange={this._handleEventSwitchRegression}
style={styles.marginBottom}
value={eventSwitchRegressionIsOn}
/>
<Text>{eventSwitchRegressionIsOn ? 'On' : 'Off'}</Text>
</View>
</View>
);
}
_handleEventSwitch = value => {
this.setState({ eventSwitchIsOn: value });
};
_handleEventSwitchRegression = value => {
this.setState({ eventSwitchRegressionIsOn: value });
};
}
export default CheckBoxOnValueChangeExample;

View File

@@ -0,0 +1,20 @@
/**
* @flow
*/
import React from 'react';
import styles from './styles';
import { CheckBox, View } from 'react-native';
const CheckBoxValueExample = () => (
<View style={styles.row}>
<View style={styles.marginRight}>
<CheckBox value={false} />
</View>
<View style={styles.marginRight}>
<CheckBox value />
</View>
</View>
);
export default CheckBoxValueExample;

View File

@@ -0,0 +1,23 @@
/**
* @flow
*/
import { StyleSheet } from 'react-native';
const styles = StyleSheet.create({
row: {
flexDirection: 'row',
flexWrap: 'wrap'
},
marginRight: {
marginRight: 10
},
marginBottom: {
marginBottom: 10
},
alignCenter: {
alignItems: 'center'
}
});
export default styles;

View File

@@ -0,0 +1,36 @@
/**
* @flow
*/
import React from 'react';
import { StyleSheet, View } from 'react-native';
const DividerHorizontal = () => <View style={styles.horizontalDivider} />;
const DividerVertical = () => <View style={styles.verticalDivider} />;
export const styles = StyleSheet.create({
horizontalDivider: {
width: '0.6rem'
},
verticalDivider: {
height: '1.3125rem'
},
row: {
flexDirection: 'row',
flexWrap: 'wrap'
},
marginRight: {
marginRight: 10
},
marginBottom: {
marginBottom: 10
},
marginVertical: {
marginVertical: 5
},
alignCenter: {
alignItems: 'center'
}
});
export { DividerHorizontal, DividerVertical };

View File

@@ -0,0 +1,32 @@
/* eslint-disable react/jsx-sort-props */
/**
* @flow
*/
import React from 'react';
import PropChildren from './examples/PropChildren';
import UIExplorer, { Description, DocItem, Section, storiesOf } from '../../ui-explorer';
const ImageBackgroundScreen = () => (
<UIExplorer title="ImageBackground" url="1-components/ImageBackground">
<Description>A image component with support for child content.</Description>
<Section title="Props">
<DocItem name="...Image props" />
<DocItem
name="children"
typeInfo="?any"
description="Content to display over the image."
example={{
render: () => <PropChildren />
}}
/>
<DocItem name="imageStyle" typeInfo="?style" description="Styles for the inner image." />
</Section>
</UIExplorer>
);
storiesOf('Components', module).add('ImageBackground', ImageBackgroundScreen);

View File

@@ -5,7 +5,6 @@
*/
import React from 'react';
import PropChildren from './examples/PropChildren';
import PropDefaultSource from './examples/PropDefaultSource';
import PropDraggable from './examples/PropDraggable';
import PropOnError from './examples/PropOnError';
@@ -35,15 +34,6 @@ const ImageScreen = () => (
<Section title="Props">
<DocItem name="...View props" />
<DocItem
name="children"
typeInfo="?any"
description="Content to display over the image."
example={{
render: () => <PropChildren />
}}
/>
<DocItem
name="defaultSource"
typeInfo="?object"

View File

@@ -31,7 +31,8 @@ class NetworkImageExample extends PureComponent {
) : null;
return (
<View style={[helpers.styles.row, helpers.styles.centerRow]}>
<View>
{loader}
<Image
defaultSource={sources.placeholder}
onError={this._handleError}
@@ -40,10 +41,8 @@ class NetworkImageExample extends PureComponent {
onLoadStart={this._handleLoadStart}
source={this.props.source}
style={helpers.styles.base}
>
{loader}
</Image>
{this.state.message && <Text style={helpers.styles.marginLeft}>{this.state.message}</Text>}
/>
{this.state.message && <Text style={helpers.styles.marginTop}>{this.state.message}</Text>}
</View>
);
}

View File

@@ -4,25 +4,29 @@
import sources from '../sources';
import React from 'react';
import { Image, StyleSheet, Text } from 'react-native';
import { ImageBackground, StyleSheet, Text } from 'react-native';
const ImageChildrenExample = () => (
<Image source={sources.large} style={styles.image}>
<Text style={styles.text}>React</Text>
</Image>
<ImageBackground source={sources.large} style={styles.image}>
<Text style={styles.text}>Child content</Text>
</ImageBackground>
);
const styles = StyleSheet.create({
image: {
width: 60,
height: 60,
width: 300,
height: 200,
backgroundColor: 'transparent',
justifyContent: 'center',
alignItems: 'center'
},
text: {
backgroundColor: 'transparent',
color: 'white'
color: 'white',
fontWeight: 'bold',
fontSize: 18,
position: 'relative',
top: 50
}
});

View File

@@ -8,11 +8,7 @@ import React from 'react';
import { Image } from 'react-native';
const ImageDefaultSourceExample = () => (
<Image
defaultSource={sources.placeholder}
source={sources.largeAlt}
style={helpers.styles.base}
/>
<Image defaultSource={sources.placeholder} style={helpers.styles.base} />
);
export default ImageDefaultSourceExample;

View File

@@ -17,8 +17,8 @@ const styles = StyleSheet.create({
flexDirection: 'row'
},
image: {
width: 60,
height: 60,
width: 300,
height: 200,
backgroundColor: 'transparent',
marginRight: 10
}

View File

@@ -8,7 +8,7 @@ import React from 'react';
import sources from '../sources';
const ImageOnLoadExample = () => (
<NetworkImage logMethod="onLoad" source={createUncachedURI(sources.small)} />
<NetworkImage logMethod="onLoad" source={createUncachedURI(sources.largeAlt)} />
);
export default ImageOnLoadExample;

View File

@@ -8,7 +8,7 @@ import React from 'react';
import sources from '../sources';
const ImageOnLoadEndExample = () => (
<NetworkImage logMethod="onLoadEnd" source={createUncachedURI(sources.small)} />
<NetworkImage logMethod="onLoadEnd" source={createUncachedURI(sources.largeAlt)} />
);
export default ImageOnLoadEndExample;

View File

@@ -8,7 +8,7 @@ import React from 'react';
import sources from '../sources';
const ImageOnLoadStartExample = () => (
<NetworkImage logMethod="onLoadStart" source={createUncachedURI(sources.small)} />
<NetworkImage logMethod="onLoadStart" source={createUncachedURI(sources.largeAlt)} />
);
export default ImageOnLoadStartExample;

View File

@@ -8,7 +8,7 @@ import { Image, StyleSheet, Text, View } from 'react-native';
const ImageResizeModeExample = () => (
<View>
{[sources.small, sources.large].map((source, i) => {
{[sources.small].map((source, i) => {
return (
<View key={i}>
<View style={styles.horizontal}>
@@ -60,12 +60,11 @@ const styles = StyleSheet.create({
resizeMode: {
borderColor: 'black',
borderWidth: 0.5,
height: 60,
width: 90
height: 120,
width: 120
},
resizeModeText: {
fontSize: 11,
marginBottom: 3
marginBottom: '0.5rem'
},
leftMargin: {
marginLeft: 10

View File

@@ -30,18 +30,22 @@ const ImageSourceExample = () => (
const styles = StyleSheet.create({
row: {
flexDirection: 'row',
flexWrap: 'wrap'
flexWrap: 'wrap',
justifyContent: 'space-between'
},
column: {
marginRight: '1rem'
alignItems: 'flex-start',
marginBottom: '1rem'
},
text: {
marginBottom: '0.5rem'
},
image: {
flex: 1,
height: 50,
resizeMode: 'contain'
borderColor: 'black',
borderWidth: 0.5,
height: 120,
width: 120,
resizeMode: 'cover'
}
});

View File

@@ -13,8 +13,8 @@ const createUncachedURI = source => {
const styles = StyleSheet.create({
base: {
height: 38,
width: 38
height: 200,
width: 300
},
row: {
flexDirection: 'row'
@@ -22,8 +22,8 @@ const styles = StyleSheet.create({
centerRow: {
alignItems: 'center'
},
marginLeft: {
marginLeft: '1rem'
marginTop: {
marginTop: '1rem'
}
});

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

View File

@@ -1,5 +1,5 @@
import placeholder from './bunny.png';
import staticImage from './uie_thumb_normal@2x.png';
import placeholder from './placeholder.jpg';
import staticImage from './ladybug.jpg';
const dataPng =
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEsAAABLCAQAAACSR7JhAAADtUlEQVR4Ac3YA2Bj6QLH0XPT1Fzbtm29tW3btm3bfLZtv7e2ObZnms7d8Uw098tuetPzrxv8wiISrtVudrG2JXQZ4VOv+qUfmqCGGl1mqLhoA52oZlb0mrjsnhKpgeUNEs91Z0pd1kvihA3ULGVHiQO2narKSHKkEMulm9VgUyE60s1aWoMQUbpZOWE+kaqs4eLEjdIlZTcFZB0ndc1+lhB1lZrIuk5P2aib1NBpZaL+JaOGIt0ls47SKzLC7CqrlGF6RZ09HGoNy1lYl2aRSWL5GuzqWU1KafRdoRp0iOQEiDzgZPnG6DbldcomadViflnl/cL93tOoVbsOLVM2jylvdWjXolWX1hmfZbGR/wjypDjFLSZIRov09BgYmtUqPQPlQrPapecLgTIy0jMgPKtTeob2zWtrGH3xvjUkPCtNg/tm1rjwrMa+mdUkPd3hWbH0jArPGiU9ufCsNNWFZ40wpwn+62/66R2RUtoso1OB34tnLOcy7YB1fUdc9e0q3yru8PGM773vXsuZ5YIZX+5xmHwHGVvlrGPN6ZSiP1smOsMMde40wKv2VmwPPVXNut4sVpUreZiLBHi0qln/VQeI/LTMYXpsJtFiclUN+5HVZazim+Ky+7sAvxWnvjXrJFneVtLWLyPJu9K3cXLWeOlbMTlrIelbMDlrLenrjEQOtIF+fuI9xRp9ZBFp6+b6WT8RrxEpdK64BuvHgDk+vUy+b5hYk6zfyfs051gRoNO1usU12WWRWL73/MMEy9pMi9qIrR4ZpV16Rrvduxazmy1FSvuFXRkqTnE7m2kdb5U8xGjLw/spRr1uTov4uOgQE+0N/DvFrG/Jt7i/FzwxbA9kDanhf2w+t4V97G8lrT7wc08aA2QNUkuTfW/KimT01wdlfK4yEw030VfT0RtZbzjeMprNq8m8tnSTASrTLti64oBNdpmMQm0eEwvfPwRbUBywG5TzjPCsdwk3IeAXjQblLCoXnDVeoAz6SfJNk5TTzytCNZk/POtTSV40NwOFWzw86wNJRpubpXsn60NJFlHeqlYRbslqZm2jnEZ3qcSKgm0kTli3zZVS7y/iivZTweYXJ26Y+RTbV1zh3hYkgyFGSTKPfRVbRqWWVReaxYeSLarYv1Qqsmh1s95S7G+eEWK0f3jYKTbV6bOwepjfhtafsvUsqrQvrGC8YhmnO9cSCk3yuY984F1vesdHYhWJ5FvASlacshUsajFt2mUM9pqzvKGcyNJW0arTKN1GGGzQlH0tXwLDgQTurS8eIQAAAABJRU5ErkJggg==';
@@ -12,11 +12,27 @@ const sources = {
'http://38.media.tumblr.com/9e9bd08c6e2d10561dd1fb4197df4c4e/tumblr_mfqekpMktw1rn90umo1_500.gif'
},
broken: { uri: 'http://TYPO_ERROR.github.io/image.png' },
small: { uri: 'http://facebook.github.io/react/img/logo_small_2x.png' },
large: { uri: 'http://facebook.github.io/react/img/logo_og.png' },
largeAlt: { uri: 'http://facebook.github.io/origami/public/images/birds.jpg' },
small: {
uri:
'https://images.unsplash.com/photo-1488584585634-35fc98ccb808?dpr=1&auto=format&fit=crop&w=100&h=66&q=60&cs=tinysrgb'
},
smallAlt: {
uri:
'https://images.unsplash.com/photo-1481595357459-84468f6eeaac?dpr=1&auto=format&fit=crop&w=100&h=66&q=60&cs=tinysrgb'
},
large: {
uri:
'https://images.unsplash.com/photo-1481595357459-84468f6eeaac?dpr=1&auto=format&fit=crop&w=376&h=251&q=60&cs=tinysrgb'
},
largeAlt: {
uri:
'https://images.unsplash.com/photo-1471145653077-54c6f0aae511?dpr=1&auto=format&fit=crop&w=376&h=251&q=60&cs=tinysrgb'
},
placeholder,
prefetchable: { uri: 'http://origami.design/public/images/bird-logo.png' },
prefetchable: {
uri:
'https://images.unsplash.com/photo-1471145653077-54c6f0aae511?dpr=1&auto=format&fit=crop&w=376&h=251&q=60&cs=tinysrgb'
},
static: staticImage,
huge: {
uri: 'https://upload.wikimedia.org/wikipedia/commons/d/d7/Chestnut-mandibled_Toucan.jpg'

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 850 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -0,0 +1,113 @@
/* eslint-disable react/jsx-sort-props, react/jsx-no-bind, no-alert */
/**
* @flow
*/
import React from 'react';
import PickerExample from './examples/PickerExample';
import UIExplorer, {
AppText,
Description,
DocItem,
Section,
StyleList,
storiesOf
} from '../../ui-explorer';
import { View } from 'react-native';
const PickerScreen = () => (
<View>
<UIExplorer title="Picker">
<Description>
<AppText>Renders the native &lt;select&gt; component.</AppText>
</Description>
<Section title="Props">
<DocItem
name="children"
typeInfo="?Array<Picker.Item>"
description="The items to display in the picker."
example={{
code: `<Picker>
<Picker.Item label="Goblet of Fire" />
<Picker.Item label="Order of the Phoenix" />
</Picker>`
}}
/>
<DocItem
name="enabled"
typeInfo="?boolean"
description="If set to false, the picker will be disabled, i.e., the user will not be able to make a selection."
example={{
render: () => <PickerExample enabled={false} />
}}
/>
<DocItem
name="onValueChange"
typeInfo="?(itemValue, itemIndex) => void"
description="Callback for when an item is selected. This is called with the value and index prop of the item that was selected."
example={{
render: () => (
<PickerExample
onValueChange={(itemValue, itemPosition) => {
window.alert(`itemValue: ${itemValue}, itemPosition: ${itemPosition}`);
}}
/>
)
}}
/>
<DocItem
name="selectedValue"
typeInfo="?string"
description="Select the item with the matching value."
example={{
render: () => <PickerExample selectedValue="book-3" />
}}
/>
<DocItem
name="style"
typeInfo="?style"
description={
<StyleList
stylePropTypes={[
{
name: '…View#style'
},
{
name: 'color',
typeInfo: 'color'
}
]}
/>
}
/>
<DocItem
name="testID"
typeInfo="?string"
description="Used to locate this view in end-to-end tests."
/>
</Section>
</UIExplorer>
<UIExplorer title="Picker.Item" url="1-components/Picker">
<Description>Individual selectable item in a Picker.</Description>
<Section title="Props">
<DocItem name="label" typeInfo="string" description="Text to display for this item" />
<DocItem name="testID" typeInfo="?string" />
<DocItem
name="value"
typeInfo="?number | string"
description="The value to be passed to the picker's 'onValueChange' callback when this item is selected."
/>
</Section>
</UIExplorer>
</View>
);
storiesOf('Components', module).add('Picker', PickerScreen);

View File

@@ -0,0 +1,28 @@
/**
* @flow
*/
import React from 'react';
import { Picker, StyleSheet, View } from 'react-native';
const PickerExample = props => (
<View style={styles.root}>
<Picker {...props}>
<Picker.Item label="Sourcerer's Stone" value="book-1" />
<Picker.Item label="Chamber of Secrets" value="book-2" />
<Picker.Item label="Prisoner of Azkaban" value="book-3" />
<Picker.Item label="Goblet of Fire" value="book-4" />
<Picker.Item label="Order of the Phoenix" value="book-5" />
<Picker.Item label="Half-Blood Prince" value="book-6" />
<Picker.Item label="Deathly Hallows" value="book-7" />
</Picker>
</View>
);
const styles = StyleSheet.create({
rootl: {
alignItems: 'flex-start'
}
});
export default PickerExample;

View File

@@ -46,9 +46,11 @@ export default class TextEventsExample extends React.Component {
event.nativeEvent.selection.start +
',' +
event.nativeEvent.selection.end
)}
)
}
onSubmitEditing={event =>
this.updateText('onSubmitEditing text: ' + event.nativeEvent.text)}
this.updateText('onSubmitEditing text: ' + event.nativeEvent.text)
}
placeholder="Enter text to see events"
style={[helperStyles.textinput, { maxWidth: 200 }]}
/>

View File

@@ -43,7 +43,7 @@ const DimensionsScreen = () => (
/>
<DocItem
name="static addEventLitener"
name="static addEventListener"
typeInfo="(type: string, handler: function) => void"
description={[
<AppText>Add an event handler. Supported events:</AppText>,
@@ -65,7 +65,7 @@ const DimensionsScreen = () => (
/>
<DocItem
name="static removeEventLitener"
name="static removeEventListener"
typeInfo="(type: string, handler: function) => void"
description="Remove an event handler."
/>

View File

@@ -8,61 +8,94 @@ import UIExplorer, {
Code,
Description,
DocItem,
ExternalLink,
Section,
storiesOf,
TextList
storiesOf
} from '../../ui-explorer';
const NetInfoScreen = () => (
<UIExplorer title="NetInfo" url="2-apis/NetInfo">
<Description>
<AppText>
NetInfo asynchronously determines the online/offline status of the application.
NetInfo asynchronously determines the online/offline status and additional connection
information (where available) of the application.
</AppText>
<AppText>
Note that support for retrieving the connection type depends upon browser support (and is
limited to mobile browsers). It will default to <Code>unknown</Code> when support is
missing.
Note that connection type information is limited to how well the browser supports the{' '}
<ExternalLink href="https://developer.mozilla.org/en-US/docs/Web/API/NetworkInformation">
NetworkInformation API
</ExternalLink>. Connection types will be <Code>unknown</Code> when support is missing.
</AppText>
</Description>
<Section title="Types">
<DocItem
description={
<AppText>
One of <Code>bluebooth</Code>, <Code>cellular</Code>, <Code>ethernet</Code>,{' '}
<Code>mixed</Code>, <Code>mixed</Code>, <Code>none</Code>, <Code>other</Code>,{' '}
<Code>unknown</Code>, <Code>wifi</Code>, <Code>wimax</Code>
</AppText>
}
name="ConnectionType"
/>
<DocItem
description={
<AppText>
One of <Code>slow-2g</Code>, <Code>2g</Code>, <Code>3g</Code>, <Code>4g</Code>,{' '}
<Code>unknown</Code>.
</AppText>
}
name="EffectiveConnectionType"
/>
<DocItem
description={
<Code>{`{
effectiveType: EffectiveConnectionType;
type: ConnectionType;
downlink?: number;
downlinkMax?: number;
rtt?: number;
}`}</Code>
}
name="ConnectionEventType"
/>
</Section>
<Section title="Methods">
<DocItem
description={[
description={
<AppText>
Invokes the listener whenever network status changes. The listener receives one of the
following connectivity types (from the DOM connection API):
</AppText>,
<TextList
items={[
'bluetooth',
'cellular',
'ethernet',
'mixed',
'none',
'other',
'unknown',
'wifi',
'wimax'
]}
/>
]}
Adds an event handler. The <Code>connectionChange</Code> event fires when the network
status changes. The argument to the event handler is an object of type{' '}
<Code>ConnectionEventType</Code>.
</AppText>
}
example={{
code: "NetInfo.addEventListener('change', (connectionType) => {})"
code: `NetInfo.addEventListener('connectionChange', ({ effectiveType, type }) => {
console.log('Effective connection type:', effectiveType);
console.log('Connection type:', type);
})`
}}
name="static addEventListener"
typeInfo="(eventName, handler) => void"
/>
<DocItem
description="Returns a promise that resolves with one of the connectivity types listed above."
description={
<AppText>
Returns a promise that resolves with an object of type <Code>ConnectionEventType</Code>.
</AppText>
}
example={{
code: `NetInfo.fetch().then((connectionType) => {
console.log('Connection type:', connectionType);
code: `NetInfo.getConnectionInfo().then(({ effectiveType, type }) => {
console.log('Effective connection type:', effectiveType);
console.log('Connection type:', type);
});`
}}
name="static fetch"
typeInfo="() => Promise<string>"
name="static getConnectionInfo"
typeInfo="() => Promise<ConnectionEventType>"
/>
<DocItem
@@ -76,7 +109,7 @@ const NetInfoScreen = () => (
<DocItem
description="An object with the same methods as above but the listener receives a boolean which represents the internet connectivity. Use this if you are only interested with whether the device has internet connectivity."
example={{
code: `NetInfo.isConnected.fetch().then((isConnected) => {
code: `NetInfo.isConnected.getConnectionInfo().then((isConnected) => {
console.log('Connection status:', (isConnected ? 'online' : 'offline'));
});`
}}

View File

@@ -21,6 +21,22 @@ const StyleSheetScreen = () => (
</Description>
<Section title="Methods">
<DocItem
description={
<AppText>
Combines two styles such that <Code>style2</Code> will override any styles in{' '}
<Code>style1</Code>. If either style is falsy, the other one is returned without
allocating an array, saving allocations and maintaining reference equality for{' '}
<Code>PureComponent</Code> checks.
</AppText>
}
example={{
code: 'StyleSheet.compose(style1, style2);'
}}
name="compose"
typeInfo="(style1, style2) => style"
/>
<DocItem
description="Each key of the object passed to `create` must define a style object. The returned object replaces style objects with IDs"
example={{
@@ -88,7 +104,11 @@ StyleSheet.flatten([styles.listItem, styles.selectedListItem]);`
typeInfo="object"
/>
<DocItem name="hairlineWidth" typeInfo="number" />
<DocItem
description="Enables borders of just one physical pixel on retina screens, otherwise it is equal to a CSS value of 1px."
name="hairlineWidth"
typeInfo="number"
/>
</Section>
</UIExplorer>
);

View File

@@ -4,16 +4,27 @@
* @flow
*/
import { bool } from 'prop-types';
import React from 'react';
import { StyleSheet, Text } from 'react-native';
const AppText = ({ style, ...rest }) => (
<Text
{...rest}
accessibilityRole={rest.href ? 'link' : undefined}
style={[styles.baseText, style, rest.href && styles.link]}
/>
);
class AppText extends React.PureComponent {
static contextTypes = {
isInAParentText: bool
};
render() {
const { style, ...rest } = this.props;
const isInAParentText = this.context;
return (
<Text
{...rest}
accessibilityRole={rest.href ? 'link' : undefined}
style={[!isInAParentText && styles.baseText, style, rest.href && styles.link]}
/>
);
}
}
export default AppText;

9
jest-setup-framework.js Normal file
View File

@@ -0,0 +1,9 @@
import Adapter from 'enzyme-adapter-react-16';
import createSerializer from './jest/createSerializer';
import Enzyme from 'enzyme';
import { StyleSheet } from './src';
const serializer = createSerializer(StyleSheet);
Enzyme.configure({ adapter: new Adapter() });
expect.addSnapshotSerializer(serializer);

View File

@@ -0,0 +1,299 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`enzyme.mount complex 1`] = `
<Box
element={
<View>
<View
style={
Object {
"padding": 20,
}
}
/>
<Text>
Nested
</Text>
</View>
}
>
<View
style={
Object {
"backgroundColor": "red",
"padding": 10,
}
}
>
<div
className="rn-alignItems-1oszu61 rn-backgroundColor-1mjtqww rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1pxmb3b rn-flexBasis-7vfszb rn-flexDirection-eqz5dr rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-m611by rn-paddingRight-1qfoi16 rn-paddingBottom-1mi0q7o rn-paddingLeft-1hfyk0a rn-position-bnwqim rn-zIndex-1lgpqti"
>
<Title>
<Text
style={
Object {
"color": "black",
"fontSize": 16,
"textAlignVertical": "center",
}
}
>
<div
className="rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-color-1bodaif rn-display-1471scf rn-font-1lw9tu2 rn-fontFamily-10u92zi rn-fontSize-ubezar rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-verticalAlign-9iso6 rn-textDecoration-bauka4 rn-whiteSpace-q42fyq rn-wordWrap-qvutc0"
dir="auto"
>
Hello World
</div>
</Text>
</Title>
<View>
<div
className="rn-alignItems-1oszu61 rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1pxmb3b rn-flexBasis-7vfszb rn-flexDirection-eqz5dr rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-position-bnwqim rn-zIndex-1lgpqti"
>
<View
style={
Object {
"padding": 20,
}
}
>
<div
className="rn-alignItems-1oszu61 rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1pxmb3b rn-flexBasis-7vfszb rn-flexDirection-eqz5dr rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-1knelpx rn-paddingRight-1ah4tor rn-paddingBottom-k8qxaj rn-paddingLeft-b5h31w rn-position-bnwqim rn-zIndex-1lgpqti"
/>
</View>
<Text>
<div
className="rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-color-homxoj rn-display-1471scf rn-font-1lw9tu2 rn-fontFamily-10u92zi rn-fontSize-1b43r93 rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-textDecoration-bauka4 rn-whiteSpace-q42fyq rn-wordWrap-qvutc0"
dir="auto"
>
Nested
</div>
</Text>
</div>
</View>
</div>
</View>
</Box>
`;
exports[`enzyme.mount composite 1`] = `
<Box>
<View
style={
Object {
"backgroundColor": "red",
"padding": 10,
}
}
>
<div
className="rn-alignItems-1oszu61 rn-backgroundColor-1mjtqww rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1pxmb3b rn-flexBasis-7vfszb rn-flexDirection-eqz5dr rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-m611by rn-paddingRight-1qfoi16 rn-paddingBottom-1mi0q7o rn-paddingLeft-1hfyk0a rn-position-bnwqim rn-zIndex-1lgpqti"
/>
</View>
</Box>
`;
exports[`enzyme.mount nested 1`] = `
<Box>
<View
style={
Object {
"backgroundColor": "red",
"padding": 10,
}
}
>
<div
className="rn-alignItems-1oszu61 rn-backgroundColor-1mjtqww rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1pxmb3b rn-flexBasis-7vfszb rn-flexDirection-eqz5dr rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-m611by rn-paddingRight-1qfoi16 rn-paddingBottom-1mi0q7o rn-paddingLeft-1hfyk0a rn-position-bnwqim rn-zIndex-1lgpqti"
>
<Title>
<Text
style={
Object {
"color": "black",
"fontSize": 16,
"textAlignVertical": "center",
}
}
>
<div
className="rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-color-1bodaif rn-display-1471scf rn-font-1lw9tu2 rn-fontFamily-10u92zi rn-fontSize-ubezar rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-verticalAlign-9iso6 rn-textDecoration-bauka4 rn-whiteSpace-q42fyq rn-wordWrap-qvutc0"
dir="auto"
>
Hello World
</div>
</Text>
</Title>
</div>
</View>
</Box>
`;
exports[`enzyme.mount noop 1`] = `
<View>
<div
className="rn-alignItems-1oszu61 rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1pxmb3b rn-flexBasis-7vfszb rn-flexDirection-eqz5dr rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-position-bnwqim rn-zIndex-1lgpqti"
/>
</View>
`;
exports[`enzyme.render complex 1`] = `
<div
class="rn-alignItems-1oszu61 rn-backgroundColor-1mjtqww rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1pxmb3b rn-flexBasis-7vfszb rn-flexDirection-eqz5dr rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-m611by rn-paddingRight-1qfoi16 rn-paddingBottom-1mi0q7o rn-paddingLeft-1hfyk0a rn-position-bnwqim rn-zIndex-1lgpqti"
>
<div
class="rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-color-1bodaif rn-display-1471scf rn-font-1lw9tu2 rn-fontFamily-10u92zi rn-fontSize-ubezar rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-verticalAlign-9iso6 rn-textDecoration-bauka4 rn-whiteSpace-q42fyq rn-wordWrap-qvutc0"
dir="auto"
>
Hello World
</div>
<div
class="rn-alignItems-1oszu61 rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1pxmb3b rn-flexBasis-7vfszb rn-flexDirection-eqz5dr rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-position-bnwqim rn-zIndex-1lgpqti"
>
<div
class="rn-alignItems-1oszu61 rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1pxmb3b rn-flexBasis-7vfszb rn-flexDirection-eqz5dr rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-1knelpx rn-paddingRight-1ah4tor rn-paddingBottom-k8qxaj rn-paddingLeft-b5h31w rn-position-bnwqim rn-zIndex-1lgpqti"
/>
<div
class="rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-color-homxoj rn-display-1471scf rn-font-1lw9tu2 rn-fontFamily-10u92zi rn-fontSize-1b43r93 rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-textDecoration-bauka4 rn-whiteSpace-q42fyq rn-wordWrap-qvutc0"
dir="auto"
>
Nested
</div>
</div>
</div>
`;
exports[`enzyme.render composite 1`] = `
<div
class="rn-alignItems-1oszu61 rn-backgroundColor-1mjtqww rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1pxmb3b rn-flexBasis-7vfszb rn-flexDirection-eqz5dr rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-m611by rn-paddingRight-1qfoi16 rn-paddingBottom-1mi0q7o rn-paddingLeft-1hfyk0a rn-position-bnwqim rn-zIndex-1lgpqti"
/>
`;
exports[`enzyme.render nested 1`] = `
<div
class="rn-alignItems-1oszu61 rn-backgroundColor-1mjtqww rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1pxmb3b rn-flexBasis-7vfszb rn-flexDirection-eqz5dr rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-m611by rn-paddingRight-1qfoi16 rn-paddingBottom-1mi0q7o rn-paddingLeft-1hfyk0a rn-position-bnwqim rn-zIndex-1lgpqti"
>
<div
class="rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-color-1bodaif rn-display-1471scf rn-font-1lw9tu2 rn-fontFamily-10u92zi rn-fontSize-ubezar rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-verticalAlign-9iso6 rn-textDecoration-bauka4 rn-whiteSpace-q42fyq rn-wordWrap-qvutc0"
dir="auto"
>
Hello World
</div>
</div>
`;
exports[`enzyme.render noop 1`] = `
<div
class="rn-alignItems-1oszu61 rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1pxmb3b rn-flexBasis-7vfszb rn-flexDirection-eqz5dr rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-position-bnwqim rn-zIndex-1lgpqti"
/>
`;
exports[`enzyme.shallow complex 1`] = `
<View
style={
Object {
"backgroundColor": "red",
"padding": 10,
}
}
>
<Title>
Hello World
</Title>
<View>
<View
style={
Object {
"padding": 20,
}
}
/>
<Text>
Nested
</Text>
</View>
</View>
`;
exports[`enzyme.shallow composite 1`] = `
<View
style={
Object {
"backgroundColor": "red",
"padding": 10,
}
}
/>
`;
exports[`enzyme.shallow nested 1`] = `
<View
style={
Object {
"backgroundColor": "red",
"padding": 10,
}
}
>
<Title>
Hello World
</Title>
</View>
`;
exports[`enzyme.shallow noop 1`] = `
<div
className="rn-alignItems-1oszu61 rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1pxmb3b rn-flexBasis-7vfszb rn-flexDirection-eqz5dr rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-position-bnwqim rn-zIndex-1lgpqti"
/>
`;
exports[`react-test-renderer complex 1`] = `
<div
className="rn-alignItems-1oszu61 rn-backgroundColor-1mjtqww rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1pxmb3b rn-flexBasis-7vfszb rn-flexDirection-eqz5dr rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-m611by rn-paddingRight-1qfoi16 rn-paddingBottom-1mi0q7o rn-paddingLeft-1hfyk0a rn-position-bnwqim rn-zIndex-1lgpqti"
>
<div
className="rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-color-1bodaif rn-display-1471scf rn-font-1lw9tu2 rn-fontFamily-10u92zi rn-fontSize-ubezar rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-verticalAlign-9iso6 rn-textDecoration-bauka4 rn-whiteSpace-q42fyq rn-wordWrap-qvutc0"
dir="auto"
>
Hello World
</div>
<div
className="rn-alignItems-1oszu61 rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1pxmb3b rn-flexBasis-7vfszb rn-flexDirection-eqz5dr rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-position-bnwqim rn-zIndex-1lgpqti"
>
<div
className="rn-alignItems-1oszu61 rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1pxmb3b rn-flexBasis-7vfszb rn-flexDirection-eqz5dr rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-1knelpx rn-paddingRight-1ah4tor rn-paddingBottom-k8qxaj rn-paddingLeft-b5h31w rn-position-bnwqim rn-zIndex-1lgpqti"
/>
<div
className="rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-color-homxoj rn-display-1471scf rn-font-1lw9tu2 rn-fontFamily-10u92zi rn-fontSize-1b43r93 rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-textDecoration-bauka4 rn-whiteSpace-q42fyq rn-wordWrap-qvutc0"
dir="auto"
>
Nested
</div>
</div>
</div>
`;
exports[`react-test-renderer composite 1`] = `
<div
className="rn-alignItems-1oszu61 rn-backgroundColor-1mjtqww rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1pxmb3b rn-flexBasis-7vfszb rn-flexDirection-eqz5dr rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-m611by rn-paddingRight-1qfoi16 rn-paddingBottom-1mi0q7o rn-paddingLeft-1hfyk0a rn-position-bnwqim rn-zIndex-1lgpqti"
/>
`;
exports[`react-test-renderer nested 1`] = `
<div
className="rn-alignItems-1oszu61 rn-backgroundColor-1mjtqww rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1pxmb3b rn-flexBasis-7vfszb rn-flexDirection-eqz5dr rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-m611by rn-paddingRight-1qfoi16 rn-paddingBottom-1mi0q7o rn-paddingLeft-1hfyk0a rn-position-bnwqim rn-zIndex-1lgpqti"
>
<div
className="rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-color-1bodaif rn-display-1471scf rn-font-1lw9tu2 rn-fontFamily-10u92zi rn-fontSize-ubezar rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-verticalAlign-9iso6 rn-textDecoration-bauka4 rn-whiteSpace-q42fyq rn-wordWrap-qvutc0"
dir="auto"
>
Hello World
</div>
</div>
`;
exports[`react-test-renderer noop 1`] = `
<div
className="rn-alignItems-1oszu61 rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1pxmb3b rn-flexBasis-7vfszb rn-flexDirection-eqz5dr rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-position-bnwqim rn-zIndex-1lgpqti"
/>
`;

View File

@@ -0,0 +1,92 @@
/* eslint-env jasmine, jest */
/* eslint-disable react/prop-types */
import { mount, render, shallow } from 'enzyme';
import React from 'react';
import renderer from 'react-test-renderer';
import { StyleSheet, Text, View } from '../../src';
import toJson from 'enzyme-to-json';
/**
* Fixtures
*/
const Box = ({ children, element, style, ...rest }) => (
<View {...rest} style={[styles.box, style]}>
{children}
{element}
</View>
);
const Title = ({ style, ...rest }) => <Text {...rest} style={[styles.title, style]} />;
const styles = StyleSheet.create({
box: {
backgroundColor: 'red',
padding: 10
},
boxExtra: {
alignItems: 'center'
},
title: {
color: 'black',
fontSize: 16,
textAlignVertical: 'center'
},
element: {
padding: 20
}
});
/**
* Test cases
*/
const cases = {
noop: <View />,
composite: <Box />,
nested: (
<Box>
<Title>Hello World</Title>
</Box>
),
complex: (
<Box
element={
<View>
<View style={styles.element} />
<Text>Nested</Text>
</View>
}
>
<Title>Hello World</Title>
</Box>
)
};
const caseNames = Object.keys(cases);
describe('enzyme', () => {
caseNames.forEach(caseName => {
test(caseName, () => {
const element = cases[caseName];
const mountTree = mount(element);
const renderTree = render(element);
const shallowTree = shallow(element);
expect(toJson(mountTree)).toMatchSnapshot(`enzyme.mount ${caseName}`);
expect(toJson(renderTree)).toMatchSnapshot(`enzyme.render ${caseName}`);
expect(toJson(shallowTree)).toMatchSnapshot(`enzyme.shallow ${caseName}`);
});
});
});
describe('react-test-renderer', () => {
caseNames.forEach(caseName => {
test(caseName, () => {
const element = cases[caseName];
const tree = renderer.create(element).toJSON();
expect(tree).toMatchSnapshot();
});
});
});

56
jest/createSerializer.js Normal file
View File

@@ -0,0 +1,56 @@
const React = require('react');
function createSerializer(styleSheet) {
function flattenNodeStyles(node) {
if (node && node.props) {
// check for React elements in any props
const nextProps = Object.keys(node.props).reduce((acc, curr) => {
const value = node.props[curr];
if (React.isValidElement(value)) {
acc[curr] = flattenNodeStyles(value);
}
return acc;
}, {});
// flatten styles and avoid empty objects in snapshots
if (node.props.style) {
const style = styleSheet.flatten(node.props.style);
if (Object.keys(style).length > 0) {
nextProps.style = style;
} else {
delete nextProps.style;
}
}
const args = [node, nextProps];
// recurse over children too
const children = node.children || node.props.children;
if (children) {
if (Array.isArray(children)) {
children.forEach(child => {
args.push(flattenNodeStyles(child));
});
} else {
args.push(flattenNodeStyles(children));
}
}
return React.cloneElement.apply(React.cloneElement, args);
}
return node;
}
function test(value) {
return !!value && value.$$typeof === Symbol.for('react.test.json');
}
function print(value, serializer) {
return serializer(flattenNodeStyles(value));
}
return { test, print };
}
module.exports = createSerializer;

6
jest/serializer.js Normal file
View File

@@ -0,0 +1,6 @@
const createSerializer = require('./createSerializer');
const { StyleSheet } = require('../dist');
const serializer = createSerializer(StyleSheet);
module.exports = serializer;

View File

@@ -1,31 +1,32 @@
{
"name": "react-native-web",
"version": "0.0.127",
"version": "0.2.2",
"description": "React Native for Web",
"main": "dist/index.js",
"files": [
"babel",
"dist",
"jest",
"src",
"!**/__tests__"
],
"scripts": {
"benchmark": "cd benchmarks && yarn && webpack && open index.html",
"build": "yarn compile && webpack --config webpack.config.js --sort-assets-by --progress",
"build": "yarn clean-dist && yarn compile && webpack --config webpack.config.js --sort-assets-by --progress",
"clean-dist": "del ./dist && mkdir dist",
"compile": "babel src -d dist --ignore *-test.js",
"docs:build": "cd docs && yarn build",
"docs:start": "cd docs && yarn && yarn start",
"docs:release": "cd docs && yarn release",
"flow": "flow",
"fmt": "find babel benchmarks docs src -name '*.js' | grep -v -E '(node_modules|dist)' | xargs yarn fmt:cmd",
"fmt": "find babel benchmarks docs jest src -name '*.js' | grep -v -E '(node_modules|dist|vendor)' | xargs yarn fmt:cmd",
"fmt:cmd": "prettier --print-width=100 --single-quote --write",
"jest": "jest",
"jest:watch": "yarn test -- --watch",
"lint": "yarn lint:cmd -- babel benchmarks docs src",
"lint:cmd": "eslint --ignore-path .gitignore --fix",
"jest:watch": "yarn test --watch",
"lint": "yarn lint:cmd babel benchmarks docs jest src",
"lint:cmd": "eslint --ignore-path .gitignore --ignore-pattern '/src/vendor/*' --fix",
"precommit": "lint-staged",
"release": "yarn clean-dist && yarn lint && yarn test && yarn build && npm publish",
"release": "yarn lint && yarn test && yarn build && npm publish",
"test": "flow && jest"
},
"babel": {
@@ -44,8 +45,12 @@
"jest": {
"testEnvironment": "jsdom",
"timers": "fake",
"setupFiles": [
"raf/polyfill"
],
"setupTestFrameworkScriptFile": "<rootDir>/jest-setup-framework.js",
"snapshotSerializers": [
"<rootDir>/node_modules/enzyme-to-json/serializer"
"enzyme-to-json/serializer"
]
},
"lint-staged": {
@@ -56,50 +61,52 @@
]
},
"dependencies": {
"animated": "^0.2.0",
"array-find-index": "^1.0.2",
"babel-runtime": "^6.26.0",
"create-react-class": "^15.6.0",
"debounce": "1.0.2",
"create-react-class": "^15.6.2",
"debounce": "^1.1.0",
"deep-assign": "^2.0.0",
"fbjs": "^0.8.14",
"fbjs": "^0.8.16",
"hyphenate-style-name": "^1.0.2",
"inline-style-prefixer": "^3.0.7",
"inline-style-prefixer": "^3.0.8",
"normalize-css-color": "^1.0.2",
"prop-types": "^15.5.10",
"prop-types": "^15.6.0",
"react-art": "^16.2.0",
"react-timer-mixin": "^0.13.3"
},
"devDependencies": {
"babel-cli": "^6.26.0",
"babel-core": "^6.26.0",
"babel-eslint": "^7.2.3",
"babel-eslint": "^8.0.3",
"babel-loader": "^7.1.2",
"babel-plugin-tester": "^4.0.0",
"babel-plugin-transform-react-remove-prop-types": "^0.4.8",
"babel-preset-react-native": "^3.0.2",
"babel-plugin-transform-react-remove-prop-types": "^0.4.10",
"babel-preset-react-native": "^4.0.0",
"caniuse-api": "^2.0.0",
"del-cli": "^1.1.0",
"enzyme": "^2.9.1",
"enzyme-to-json": "^1.5.1",
"eslint": "^4.6.1",
"eslint-config-prettier": "^2.4.0",
"eslint-plugin-promise": "^3.5.0",
"eslint-plugin-react": "^7.3.0",
"file-loader": "^0.11.2",
"flow-bin": "^0.49.1",
"jest": "^21.0.2",
"enzyme": "^3.2.0",
"enzyme-adapter-react-16": "^1.1.0",
"enzyme-to-json": "^3.2.2",
"eslint": "^4.12.1",
"eslint-config-prettier": "^2.9.0",
"eslint-plugin-promise": "^3.6.0",
"eslint-plugin-react": "^7.5.1",
"file-loader": "^1.1.5",
"flow-bin": "^0.60.1",
"jest": "^21.2.1",
"lint-staged": "^4.1.3",
"prettier": "^1.6.1",
"react": "^15.6.1",
"react-dom": "^15.6.1",
"react-test-renderer": "^15.6.1",
"url-loader": "^0.5.9",
"webpack": "^3.5.6",
"webpack-bundle-analyzer": "^2.9.0"
"prettier": "^1.8.2",
"raf": "^3.4.0",
"react": "^16.2.0",
"react-dom": "^16.2.0",
"react-test-renderer": "^16.2.0",
"url-loader": "^0.6.2",
"webpack": "^3.9.1",
"webpack-bundle-analyzer": "^2.9.1"
},
"peerDependencies": {
"react": "15.4.x || 15.5.x || 15.6.x",
"react-dom": "15.4.x || 15.5.x || 15.6.x"
"react": "16.x.x",
"react-dom": "16.x.x"
},
"author": "Nicolas Gallagher",
"license": "BSD-3-Clause",

View File

@@ -7,7 +7,7 @@ const browserList = {
firefox: 40,
ios_saf: 7,
safari: 7,
ie: 11,
ie: 10,
ie_mob: 11,
edge: 12,
opera: 16,

View File

@@ -3,27 +3,25 @@
* 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.
* 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.
*
* @providesModule Animated
* @noflow
* @flow
*/
import Animated from 'animated';
import AnimatedImplementation from '../../vendor/Animated/AnimatedImplementation';
import Image from '../../components/Image';
import ScrollView from '../../components/ScrollView';
import StyleSheet from '../StyleSheet';
import Text from '../../components/Text';
import View from '../../components/View';
Animated.inject.FlattenStyle(StyleSheet.flatten);
const AnimatedImplementation = {
...Animated,
Image: Animated.createAnimatedComponent(Image),
ScrollView: Animated.createAnimatedComponent(ScrollView),
Text: Animated.createAnimatedComponent(Text),
View: Animated.createAnimatedComponent(View)
const Animated = {
...AnimatedImplementation,
Image: AnimatedImplementation.createAnimatedComponent(Image),
ScrollView: AnimatedImplementation.createAnimatedComponent(ScrollView),
View: AnimatedImplementation.createAnimatedComponent(View),
Text: AnimatedImplementation.createAnimatedComponent(Text)
};
export default AnimatedImplementation;
export default Animated;

View File

@@ -19,6 +19,7 @@ type Context = {
};
type Props = {
// $FlowFixMe
children?: React.Children,
rootTag: any
};
@@ -27,9 +28,8 @@ type State = {
mainKey: number
};
export default class AppContainer extends Component {
props: Props;
state: State = { mainKey: 1 };
export default class AppContainer extends Component<Props, State> {
state = { mainKey: 1 };
static childContextTypes = {
rootTag: any

View File

@@ -26,46 +26,163 @@ input::-webkit-inner-spin-button,input::-webkit-outer-spin-button,input::-webkit
exports[`apis/AppRegistry/renderApplication getApplication 3`] = `
"<style id=\\"react-native-stylesheet\\">.rn-bottom-1p0dtai{bottom:0px}
.rn-left-1d2f490{left:0px}
.rn-left-1fe0xdi{left:0%}
.rn-left-7b7h2f{left:100%}
.rn-position-u8s1d{position:absolute}
.rn-position-bnwqim{position:relative}
.rn-right-zchlnj{right:0px}
.rn-top-ipm5af{top:0px}
.rn-cursor-1loqt21{cursor:pointer}
.rn-cursor-7q8q6z{cursor:default}
.rn-cursor-1ei5mc7{cursor:inherit}
.rn-appearance-30o5oe{-moz-appearance:none;-webkit-appearance:none;appearance:none}
.rn-backgroundColor-wib322{background-color:transparent}
.rn-backgroundColor-8ndhhv{background-color:rgba(33,150,243,1)}
.rn-backgroundColor-15al3ab{background-color:rgba(223,223,223,1)}
.rn-backgroundColor-44z8sh{background-color:rgba(255,255,255,1)}
.rn-backgroundColor-5itogg{background-color:rgba(0,150,136,1)}
.rn-backgroundColor-1v82r4u{background-color:rgba(170,184,194,1)}
.rn-backgroundColor-1hj8efq{background-color:rgba(213,213,213,1)}
.rn-backgroundColor-1bgzomc{background-color:rgba(189,189,189,1)}
.rn-color-homxoj{color:inherit}
.rn-color-1qtguxu{color:rgba(255,255,255,1)}
.rn-color-istcb5{color:rgba(161,161,161,1)}
.rn-font-1lw9tu2{font:inherit}
.rn-textAlign-1ttztb7{text-align:inherit}
.rn-textAlign-q4m81j{text-align:center}
.rn-textDecoration-bauka4{text-decoration:none}
.rn-listStyle-1ebb2ja{list-style:none}
.rn-alignItems-1oszu61{-webkit-align-items:stretch;-webkit-box-align:stretch;align-items:stretch}
.rn-alignItems-1oszu61{-ms-flex-align:stretch;-webkit-align-items:stretch;-webkit-box-align:stretch;align-items:stretch}
.rn-alignItems-1awozwy{-ms-flex-align:center;-webkit-align-items:center;-webkit-box-align:center;align-items:center}
.rn-borderTopStyle-1efd50x{border-top-style:solid}
.rn-borderRightStyle-14skgim{border-right-style:solid}
.rn-borderBottomStyle-rull8r{border-bottom-style:solid}
.rn-borderLeftStyle-mm0ijv{border-left-style:solid}
.rn-borderTopWidth-13yce4e{border-top-width:0px}
.rn-borderTopWidth-1jxfwug{border-top-width:2px}
.rn-borderRightWidth-fnigne{border-right-width:0px}
.rn-borderRightWidth-18p6if4{border-right-width:2px}
.rn-borderBottomWidth-ndvcnb{border-bottom-width:0px}
.rn-borderBottomWidth-wgabs5{border-bottom-width:2px}
.rn-borderLeftWidth-gxnn5r{border-left-width:0px}
.rn-borderLeftWidth-dwliz8{border-left-width:2px}
.rn-boxSizing-deolkf{box-sizing:border-box}
.rn-display-6koalj{display:-webkit-box;display:-moz-box;display:-ms-flexbox;display:-webkit-flex;display:flex}
.rn-display-xoduu5{display:-webkit-inline-box;display:-moz-inline-box;display:-ms-inline-flexbox;display:-webkit-inline-flex;display:inline-flex}
.rn-flexShrink-1qe8dj5{-webkit-flex-shrink:0;flex-shrink:0}
.rn-flexShrink-1wbh5a2{-webkit-flex-shrink:1;flex-shrink:1}
.rn-flexBasis-1mlwlqe{-webkit-flex-basis:auto;flex-basis:auto}
.rn-flexBasis-1ro0kt6{-webkit-flex-basis:0%;flex-basis:0%}
.rn-flexDirection-eqz5dr{-webkit-box-direction:normal;-webkit-box-orient:vertical;-webkit-flex-direction:column;flex-direction:column}
.rn-display-1471scf{display:inline}
.rn-flexShrink-1pxmb3b{-ms-flex-negative:0 !important;-webkit-flex-shrink:0 !important;flex-shrink:0 !important}
.rn-flexShrink-1awmn5t{-ms-flex-negative:1 !important;-webkit-flex-shrink:1 !important;flex-shrink:1 !important}
.rn-flexBasis-7vfszb{-ms-flex-preferred-size:auto !important;-webkit-flex-basis:auto !important;flex-basis:auto !important}
.rn-flexDirection-eqz5dr{-ms-flex-direction:column;-webkit-box-direction:normal;-webkit-box-orient:vertical;-webkit-flex-direction:column;flex-direction:column}
.rn-flexDirection-18u37iz{-ms-flex-direction:row;-webkit-box-direction:normal;-webkit-box-orient:horizontal;-webkit-flex-direction:row;flex-direction:row}
.rn-marginTop-1mnahxq{margin-top:0px}
.rn-marginTop-1t01tom{margin-top:auto}
.rn-marginRight-61z16t{margin-right:0px}
.rn-marginRight-lchren{margin-right:auto}
.rn-marginBottom-p1pxzi{margin-bottom:0px}
.rn-marginBottom-1qahzrx{margin-bottom:auto}
.rn-marginLeft-11wrixw{margin-left:0px}
.rn-marginLeft-1jj8364{margin-left:auto}
.rn-minHeight-ifefl9{min-height:0px}
.rn-minWidth-bcqeeo{min-width:0px}
.rn-paddingTop-wk8lta{padding-top:0px}
.rn-paddingTop-tskmnb{padding-top:8px}
.rn-paddingRight-9aemit{padding-right:0px}
.rn-paddingRight-1pyaxff{padding-right:8px}
.rn-paddingBottom-1mdbw0j{padding-bottom:0px}
.rn-paddingBottom-xd6kpl{padding-bottom:8px}
.rn-paddingLeft-gy4na3{padding-left:0px}
.rn-paddingLeft-1m04atk{padding-left:8px}
.rn-zIndex-1lgpqti{z-index:0}
.rn-zIndex-1wyyakw{z-index:-1}
.rn-flexGrow-16y2uox{-webkit-flex-grow:1;flex-grow:1}</style>"
.rn-backgroundPosition-vvn4in{background-position:center}
.rn-backgroundRepeat-u6sd8q{background-repeat:no-repeat}
.rn-backgroundRepeat-17leim2{background-repeat:repeat}
.rn-backgroundSize-4gszlv{background-size:cover}
.rn-backgroundSize-1sxrcry{background-size:auto}
.rn-backgroundSize-ehq7j7{background-size:contain}
.rn-backgroundSize-x3cy2q{background-size:100% 100%}
.rn-height-1pi2tsx{height:100%}
.rn-height-z80fyv{height:20px}
.rn-height-1r8g8re{height:36px}
.rn-height-10ptun7{height:16px}
.rn-height-4v7adb{height:5px}
.rn-height-1dernwh{height:70%}
.rn-opacity-1272l3b{opacity:0}
.rn-opacity-6dt33c{opacity:1}
.rn-width-13qz1uu{width:100%}
.rn-width-19wmn03{width:20px}
.rn-width-1acpoxo{width:36px}
.rn-width-1janqcz{width:16px}
.rn-touchAction-19z077z{-ms-touch-action:none;touch-action:none}
.rn-touchAction-1gvxusu{-ms-touch-action:manipulate;touch-action:manipulate}
.rn-WebkitOverflowScrolling-150rngu{-webkit-overflow-scrolling:touch}
.rn-flex-13awgt0{-ms-flex:1;-webkit-flex:1;flex:1}
.rn-flexGrow-1m1wadx{-ms-flex-positive:1 !important;-webkit-flex-grow:1 !important;flex-grow:1 !important}
.rn-overflowX-11yh6sk{overflow-x:hidden}
.rn-overflowX-lltvgl{overflow-x:auto}
.rn-overflowY-1rnoaur{overflow-y:auto}
.rn-overflowY-buy8e9{overflow-y:hidden}
.rn-transform-emqnss{-webkit-transform:translateZ(0px);transform:translateZ(0px)}
.rn-fontFamily-10u92zi{font-family:-apple-system, BlinkMacSystemFont, \\"Segoe UI\\", Roboto, Ubuntu, \\"Helvetica Neue\\", sans-serif}
.rn-fontFamily-poiln3{font-family:inherit}
.rn-fontSize-1b43r93{font-size:14px}
.rn-fontSize-7cikom{font-size:inherit}
.rn-whiteSpace-q42fyq{white-space:pre-wrap}
.rn-whiteSpace-irrty{white-space:inherit}
.rn-whiteSpace-3s2u2q{white-space:nowrap}
.rn-wordWrap-qvutc0{word-wrap:break-word}
.rn-userSelect-lrvibr{-moz-user-select:none;-ms-user-select:none;-webkit-user-select:none;user-select:none}
.rn-maxWidth-dnmrzs{max-width:100%}
.rn-textOverflow-1udbk01{text-overflow:ellipsis}
.rn-justifyContent-1777fci{-ms-flex-pack:center;-webkit-box-pack:center;-webkit-justify-content:center;justify-content:center}
.rn-visibility-11j9u27{visibility:hidden}
.rn-animationDuration-17bb2tj{-webkit-animation-duration:0.75s;animation-duration:0.75s}
.rn-animationDuration-1ay1djp{-webkit-animation-duration:1s;animation-duration:1s}
.rn-animationIterationCount-1muvv40{-webkit-animation-iteration-count:infinite;animation-iteration-count:infinite}
.rn-animationName-dozj4v{-webkit-animation-name:rn-ActivityIndicator-animation;animation-name:rn-ActivityIndicator-animation}
.rn-animationName-141g9a{-webkit-animation-name:rn-ProgressBar-animation;animation-name:rn-ProgressBar-animation}
.rn-animationTimingFunction-1ldzwu0{-webkit-animation-timing-function:linear;animation-timing-function:linear}
.rn-animationPlayState-1abnn5w{-webkit-animation-play-state:paused;animation-play-state:paused}
.rn-transitionDuration-eafdt9{-webkit-transition-duration:0.15s;transition-duration:0.15s}
.rn-transitionDuration-13tjlyg{-webkit-transition-duration:0.1s;transition-duration:0.1s}
.rn-transitionProperty-1i6wzkk{-moz-transition-property:opacity;-webkit-transition-property:opacity;transition-property:opacity}
.rn-borderTopLeftRadius-1iymjk7{border-top-left-radius:2px}
.rn-borderTopLeftRadius-jt3ufn{border-top-left-radius:100%}
.rn-borderTopLeftRadius-ou6ah9{border-top-left-radius:0px}
.rn-borderTopRightRadius-s2skl2{border-top-right-radius:2px}
.rn-borderTopRightRadius-1e868j9{border-top-right-radius:100%}
.rn-borderTopRightRadius-t12b5v{border-top-right-radius:0px}
.rn-borderBottomRightRadius-l5bh9y{border-bottom-right-radius:2px}
.rn-borderBottomRightRadius-ujv9e3{border-bottom-right-radius:100%}
.rn-borderBottomRightRadius-zmljjp{border-bottom-right-radius:0px}
.rn-borderBottomLeftRadius-101sy47{border-bottom-left-radius:2px}
.rn-borderBottomLeftRadius-1hakmuk{border-bottom-left-radius:100%}
.rn-borderBottomLeftRadius-pm2fo{border-bottom-left-radius:0px}
.rn-fontWeight-majxgm{font-weight:500}
.rn-textTransform-tsynxw{text-transform:uppercase}
.rn-borderTopColor-j4x2lb{border-top-color:rgba(101,119,134,1)}
.rn-borderTopColor-gj2eto{border-top-color:rgba(0,150,136,1)}
.rn-borderTopColor-1j7vz2b{border-top-color:rgba(204,214,221,1)}
.rn-borderTopColor-2dclza{border-top-color:rgba(170,184,194,1)}
.rn-borderTopColor-kqr9px{border-top-color:black}
.rn-borderRightColor-12i18q1{border-right-color:rgba(101,119,134,1)}
.rn-borderRightColor-31ud7z{border-right-color:rgba(0,150,136,1)}
.rn-borderRightColor-10fg1ub{border-right-color:rgba(204,214,221,1)}
.rn-borderRightColor-8jf312{border-right-color:rgba(170,184,194,1)}
.rn-borderRightColor-q0dj5p{border-right-color:black}
.rn-borderBottomColor-mg3rfb{border-bottom-color:rgba(101,119,134,1)}
.rn-borderBottomColor-1bgnb8i{border-bottom-color:rgba(0,150,136,1)}
.rn-borderBottomColor-zxuuv6{border-bottom-color:rgba(204,214,221,1)}
.rn-borderBottomColor-1yeakrt{border-bottom-color:rgba(170,184,194,1)}
.rn-borderBottomColor-1ah7hsa{border-bottom-color:black}
.rn-borderLeftColor-vnhemr{border-left-color:rgba(101,119,134,1)}
.rn-borderLeftColor-tbzcuz{border-left-color:rgba(0,150,136,1)}
.rn-borderLeftColor-1p34dw6{border-left-color:rgba(204,214,221,1)}
.rn-borderLeftColor-bluj2i{border-left-color:rgba(170,184,194,1)}
.rn-borderLeftColor-137uh4u{border-left-color:black}
.rn-backgroundImage-rs94m5{background-image:url(\\"data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcKICAgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIgogICB4bWxuczpjYz0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbnMjIgogICB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiCiAgIHhtbG5zOnN2Zz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgdmVyc2lvbj0iMS4xIgogICB2aWV3Qm94PSIwIDAgMSAxIgogICBwcmVzZXJ2ZUFzcGVjdFJhdGlvPSJ4TWluWU1pbiBtZWV0Ij4KICA8cGF0aAogICAgIGQ9Ik0gMC4wNDAzODA1OSwwLjYyNjc3NjcgMC4xNDY0NDY2MSwwLjUyMDcxMDY4IDAuNDI5Mjg5MzIsMC44MDM1NTMzOSAwLjMyMzIyMzMsMC45MDk2MTk0MSB6IE0gMC4yMTcxNTcyOSwwLjgwMzU1MzM5IDAuODUzNTUzMzksMC4xNjcxNTcyOSAwLjk1OTYxOTQxLDAuMjczMjIzMyAwLjMyMzIyMzMsMC45MDk2MTk0MSB6IgogICAgIGlkPSJyZWN0Mzc4MCIKICAgICBzdHlsZT0iZmlsbDojZmZmZmZmO2ZpbGwtb3BhY2l0eToxO3N0cm9rZTpub25lIiAvPgo8L3N2Zz4K\\")}
.rn-alignSelf-k200y{-ms-flex-item-align:start;-webkit-align-self:flex-start;align-self:flex-start}
.rn-boxShadow-1ewcgjf{box-shadow:0px 1px 3px rgba(0,0,0,0.5)}
.rn-resize-1dz5y72{resize:none}</style>"
`;

View File

@@ -11,18 +11,20 @@
*/
import invariant from 'fbjs/lib/invariant';
import { unmountComponentAtNode } from 'react-dom';
import { unmountComponentAtNode } from '../../modules/unmountComponentAtNode';
import renderApplication, { getApplication } from './renderApplication';
import type { ComponentType } from 'react';
const emptyObject = {};
const runnables = {};
export type ComponentProvider = () => ReactClass<any>;
export type ComponentProvider = () => ComponentType<any>;
export type AppConfig = {
appKey: string,
component?: ComponentProvider,
run?: Function
run?: Function,
section?: boolean
};
/**
@@ -90,7 +92,7 @@ export default class AppRegistry {
runnables[appKey].run(appParameters);
}
static unmountApplicationComponentAtRootTag(rootTag) {
static unmountApplicationComponentAtRootTag(rootTag: Object) {
unmountComponentAtNode(rootTag);
}
}

View File

@@ -10,19 +10,19 @@
*/
import invariant from 'fbjs/lib/invariant';
import { render } from 'react-dom';
import hydrate from '../../modules/hydrate';
import AppContainer from './AppContainer';
import StyleSheet from '../../apis/StyleSheet';
import React from 'react';
import React, { type ComponentType } from 'react';
export default function renderApplication(
RootComponent: ReactClass<Object>,
initialProps: Object,
export default function renderApplication<Props: Object>(
RootComponent: ComponentType<Props>,
initialProps: Props,
rootTag: any
) {
invariant(rootTag, 'Expect to have a valid rootTag, instead got ', rootTag);
render(
hydrate(
<AppContainer rootTag={rootTag}>
<RootComponent {...initialProps} />
</AppContainer>,
@@ -30,7 +30,7 @@ export default function renderApplication(
);
}
export function getApplication(RootComponent: ReactClass<Object>, initialProps: Object): Object {
export function getApplication(RootComponent: ComponentType<Object>, initialProps: Object): Object {
const element = (
<AppContainer rootTag={{}}>
<RootComponent {...initialProps} />
@@ -38,7 +38,7 @@ export function getApplication(RootComponent: ReactClass<Object>, initialProps:
);
const stylesheets = StyleSheet.getStyleSheets().map(sheet => (
// ensure that CSS text is not escaped
<style dangerouslySetInnerHTML={{ __html: sheet.textContent }} id={sheet.id} />
<style dangerouslySetInnerHTML={{ __html: sheet.textContent }} id={sheet.id} key={sheet.id} />
));
return { element, stylesheets };
}

View File

@@ -20,7 +20,7 @@ const mergeLocalStorageItem = (key, value) => {
window.localStorage.setItem(key, nextValue);
};
const createPromise = (getValue, callback) => {
const createPromise = (getValue, callback): Promise<*> => {
return new Promise((resolve, reject) => {
try {
const value = getValue();
@@ -37,7 +37,7 @@ const createPromise = (getValue, callback) => {
});
};
const createPromiseAll = (promises, callback, processResult) => {
const createPromiseAll = (promises, callback, processResult): Promise<*> => {
return Promise.all(promises).then(
result => {
const value = processResult ? processResult(result) : null;
@@ -55,16 +55,21 @@ export default class AsyncStorage {
/**
* Erases *all* AsyncStorage for the domain.
*/
static clear(callback) {
static clear(callback?: Function): Promise<*> {
return createPromise(() => {
window.localStorage.clear();
}, callback);
}
/**
* (stub) Flushes any pending requests using a single batch call to get the data.
*/
static flushGetRequests() {}
/**
* Gets *all* keys known to the app, for all callers, libraries, etc.
*/
static getAllKeys(callback) {
static getAllKeys(callback?: Function): Promise<*> {
return createPromise(() => {
const numberOfKeys = window.localStorage.length;
const keys = [];
@@ -79,7 +84,7 @@ export default class AsyncStorage {
/**
* Fetches `key` value.
*/
static getItem(key: string, callback) {
static getItem(key: string, callback?: Function): Promise<*> {
return createPromise(() => {
return window.localStorage.getItem(key);
}, callback);
@@ -91,7 +96,7 @@ export default class AsyncStorage {
*
* multiGet(['k1', 'k2']) -> [['k1', 'val1'], ['k2', 'val2']]
*/
static multiGet(keys: Array<string>, callback) {
static multiGet(keys: Array<string>, callback?: Function): Promise<*> {
const promises = keys.map(key => AsyncStorage.getItem(key));
const processResult = result => result.map((value, i) => [keys[i], value]);
return createPromiseAll(promises, callback, processResult);
@@ -100,7 +105,7 @@ export default class AsyncStorage {
/**
* Sets `value` for `key`.
*/
static setItem(key: string, value: string, callback) {
static setItem(key: string, value: string, callback?: Function): Promise<*> {
return createPromise(() => {
window.localStorage.setItem(key, value);
}, callback);
@@ -110,7 +115,7 @@ export default class AsyncStorage {
* Takes an array of key-value array pairs.
* multiSet([['k1', 'val1'], ['k2', 'val2']])
*/
static multiSet(keyValuePairs: Array<Array<string>>, callback) {
static multiSet(keyValuePairs: Array<Array<string>>, callback?: Function): Promise<*> {
const promises = keyValuePairs.map(item => AsyncStorage.setItem(item[0], item[1]));
return createPromiseAll(promises, callback);
}
@@ -118,7 +123,7 @@ export default class AsyncStorage {
/**
* Merges existing value with input value, assuming they are stringified JSON.
*/
static mergeItem(key: string, value: string, callback) {
static mergeItem(key: string, value: string, callback?: Function): Promise<*> {
return createPromise(() => {
mergeLocalStorageItem(key, value);
}, callback);
@@ -130,7 +135,7 @@ export default class AsyncStorage {
*
* multiMerge([['k1', 'val1'], ['k2', 'val2']])
*/
static multiMerge(keyValuePairs: Array<Array<string>>, callback) {
static multiMerge(keyValuePairs: Array<Array<string>>, callback?: Function): Promise<*> {
const promises = keyValuePairs.map(item => AsyncStorage.mergeItem(item[0], item[1]));
return createPromiseAll(promises, callback);
}
@@ -138,7 +143,7 @@ export default class AsyncStorage {
/**
* Removes a `key`
*/
static removeItem(key: string, callback) {
static removeItem(key: string, callback?: Function): Promise<*> {
return createPromise(() => {
return window.localStorage.removeItem(key);
}, callback);
@@ -147,7 +152,7 @@ export default class AsyncStorage {
/**
* Delete all the keys in the `keys` array.
*/
static multiRemove(keys: Array<string>, callback) {
static multiRemove(keys: Array<string>, callback?: Function): Promise<*> {
const promises = keys.map(key => AsyncStorage.removeItem(key));
return createPromiseAll(promises, callback);
}

View File

@@ -12,7 +12,7 @@
function emptyFunction() {}
const BackAndroid = {
const BackHandler = {
exitApp: emptyFunction,
addEventListener() {
return {
@@ -22,4 +22,4 @@ const BackAndroid = {
removeEventListener: emptyFunction
};
export default BackAndroid;
export default BackHandler;

View File

@@ -17,11 +17,11 @@ export default class Clipboard {
);
}
static getString() {
static getString(): Promise<string> {
return Promise.resolve('');
}
static setString(text) {
static setString(text: string) {
let success = false;
const body = document.body;

View File

@@ -66,12 +66,12 @@ export default class Dimensions {
}
}
static addEventListener(type, handler): void {
static addEventListener(type: string, handler: Function): void {
listeners[type] = listeners[type] || [];
listeners[type].push(handler);
}
static removeEventListener(type, handler): void {
static removeEventListener(type: string, handler: Function): void {
if (Array.isArray(listeners[type])) {
listeners[type] = listeners[type].filter(_handler => _handler !== handler);
}

View File

@@ -6,8 +6,8 @@
* LICENSE file in the root directory of this source tree.
*
* @providesModule Easing
* @noflow
* @flow
*/
import Easing from 'animated/lib/Easing';
import Easing from '../../vendor/Animated/Easing';
export default Easing;

View File

@@ -17,13 +17,13 @@ const initialURL = canUseDOM ? window.location.href : '';
const Linking = {
addEventListener() {},
removeEventListener() {},
canOpenURL() {
canOpenURL(): Promise<boolean> {
return Promise.resolve(true);
},
getInitialURL() {
getInitialURL(): Promise<string> {
return Promise.resolve(initialURL);
},
openURL(url: string) {
openURL(url: string): Promise<Object | void> {
try {
iframeOpen(url);
return Promise.resolve();

View File

@@ -2,32 +2,56 @@
import NetInfo from '..';
describe('apis/NetInfo', () => {
describe('isConnected', () => {
const handler = () => {};
const handler = () => {};
describe('apis/NetInfo', () => {
describe('getConnectionInfo', () => {
test('fills out basic fields', done => {
NetInfo.getConnectionInfo().then(result => {
expect(result.effectiveType).toBeDefined();
expect(result.type).toBeDefined();
done();
});
});
});
describe('addEventListener', () => {
test('throws if the provided "eventType" is not supported', () => {
expect(() => NetInfo.addEventListener('foo', handler)).toThrow();
});
});
describe('removeEventListener', () => {
test('throws if the provided "eventType" is not supported', () => {
expect(() => NetInfo.removeEventListener('foo', handler)).toThrow();
});
test('throws if the handler is not registered', () => {
expect(() => NetInfo.removeEventListener('connectionChange', handler)).toThrow();
});
});
describe('isConnected', () => {
afterEach(() => {
try {
NetInfo.isConnected.removeEventListener('change', handler);
NetInfo.isConnected.removeEventListener('connectionChange', handler);
} catch (e) {}
});
describe('addEventListener', () => {
test('throws if the provided "eventType" is not supported', () => {
expect(() => NetInfo.isConnected.addEventListener('foo', handler)).toThrow();
expect(() => NetInfo.isConnected.addEventListener('change', handler)).not.toThrow();
});
});
describe('removeEventListener', () => {
test('throws if the handler is not registered', () => {
expect(() => NetInfo.isConnected.removeEventListener('change', handler)).toThrow;
});
test('throws if the provided "eventType" is not supported', () => {
NetInfo.isConnected.addEventListener('change', handler);
expect(() => NetInfo.isConnected.removeEventListener('foo', handler)).toThrow;
expect(() => NetInfo.isConnected.removeEventListener('change', handler)).not.toThrow;
NetInfo.isConnected.addEventListener('connectionChange', handler);
expect(() => NetInfo.isConnected.removeEventListener('foo', handler)).toThrow();
});
test('throws if the handler is not registered', () => {
expect(() =>
NetInfo.isConnected.removeEventListener('connectionChange', handler)
).toThrow();
});
});
});

View File

@@ -20,9 +20,34 @@ const connection =
window.navigator.mozConnection ||
window.navigator.webkitConnection);
const eventTypes = ['change'];
// Prevent the underlying event handlers from leaking and include additional
// properties available in browsers
const getConnectionInfoObject = () => {
const result = {
effectiveType: 'unknown',
type: 'unknown'
};
if (!connection) {
return result;
}
for (const prop in connection) {
const value = connection[prop];
if (typeof value !== 'function' && value != null) {
result[prop] = value;
}
}
return result;
};
// Map React Native events to browser equivalents
const eventTypesMap = {
change: 'change',
connectionChange: 'change'
};
const eventTypes = Object.keys(eventTypesMap);
const connectionListeners = [];
const netInfoListeners = [];
/**
* Navigator online: https://developer.mozilla.org/en-US/docs/Web/API/NavigatorOnLine/onLine
@@ -31,6 +56,9 @@ const connectionListeners = [];
const NetInfo = {
addEventListener(type: string, handler: Function): { remove: () => void } {
invariant(eventTypes.indexOf(type) !== -1, 'Trying to subscribe to unknown event: "%s"', type);
if (type === 'change') {
console.warn('Listening to event `change` is deprecated. Use `connectionChange` instead.');
}
if (!connection) {
console.error(
'Network Connection API is not supported. Not listening for connection type changes.'
@@ -40,21 +68,33 @@ const NetInfo = {
};
}
connection.addEventListener(type, handler);
const wrappedHandler = () => handler(getConnectionInfoObject());
netInfoListeners.push([handler, wrappedHandler]);
connection.addEventListener(eventTypesMap[type], wrappedHandler);
return {
remove: () => NetInfo.removeEventListener(type, handler)
remove: () => NetInfo.removeEventListener(eventTypesMap[type], handler)
};
},
removeEventListener(type: string, handler: Function): void {
invariant(eventTypes.indexOf(type) !== -1, 'Trying to subscribe to unknown event: "%s"', type);
if (!connection) {
return;
invariant(
eventTypes.indexOf(type) !== -1,
'Trying to unsubscribe from unknown event: "%s"',
type
);
if (type === 'change') {
console.warn('Listening to event `change` is deprecated. Use `connectionChange` instead.');
}
connection.removeEventListener(type, handler);
const listenerIndex = findIndex(netInfoListeners, pair => pair[0] === handler);
invariant(listenerIndex !== -1, 'Trying to remove NetInfo listener for unregistered handler');
const [, wrappedHandler] = netInfoListeners[listenerIndex];
connection.removeEventListener(eventTypesMap[type], wrappedHandler);
netInfoListeners.splice(listenerIndex, 1);
},
fetch(): Promise<any> {
console.warn('`fetch` is deprecated. Use `getConnectionInfo` instead.');
return new Promise((resolve, reject) => {
try {
resolve(connection.type);
@@ -64,6 +104,12 @@ const NetInfo = {
});
},
getConnectionInfo(): Promise<Object> {
return new Promise((resolve, reject) => {
resolve(getConnectionInfoObject());
});
},
isConnected: {
addEventListener(type: string, handler: Function): { remove: () => void } {
invariant(
@@ -71,6 +117,10 @@ const NetInfo = {
'Trying to subscribe to unknown event: "%s"',
type
);
if (type === 'change') {
console.warn('Listening to event `change` is deprecated. Use `connectionChange` instead.');
}
const onlineCallback = () => handler(true);
const offlineCallback = () => handler(false);
connectionListeners.push([handler, onlineCallback, offlineCallback]);
@@ -79,7 +129,7 @@ const NetInfo = {
window.addEventListener('offline', offlineCallback, false);
return {
remove: () => NetInfo.isConnected.removeEventListener(type, handler)
remove: () => NetInfo.isConnected.removeEventListener(eventTypesMap[type], handler)
};
},
@@ -89,6 +139,9 @@ const NetInfo = {
'Trying to subscribe to unknown event: "%s"',
type
);
if (type === 'change') {
console.warn('Listening to event `change` is deprecated. Use `connectionChange` instead.');
}
const listenerIndex = findIndex(connectionListeners, pair => pair[0] === handler);
invariant(
@@ -103,7 +156,12 @@ const NetInfo = {
connectionListeners.splice(listenerIndex, 1);
},
fetch(): Promise<any> {
fetch(): Promise<boolean> {
console.warn('`fetch` is deprecated. Use `getConnectionInfo` instead.');
return NetInfo.isConnected.getConnectionInfo();
},
getConnectionInfo(): Promise<boolean> {
return new Promise((resolve, reject) => {
try {
resolve(window.navigator.onLine);

View File

@@ -1,394 +1,2 @@
/**
* Copyright (c) 2016-present, Nicolas Gallagher.
* 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.
*
* @providesModule PanResponder
* @noflow
*/
import TouchHistoryMath from '../../vendor/TouchHistoryMath';
const currentCentroidXOfTouchesChangedAfter =
TouchHistoryMath.currentCentroidXOfTouchesChangedAfter;
const currentCentroidYOfTouchesChangedAfter =
TouchHistoryMath.currentCentroidYOfTouchesChangedAfter;
const previousCentroidXOfTouchesChangedAfter =
TouchHistoryMath.previousCentroidXOfTouchesChangedAfter;
const previousCentroidYOfTouchesChangedAfter =
TouchHistoryMath.previousCentroidYOfTouchesChangedAfter;
const currentCentroidX = TouchHistoryMath.currentCentroidX;
const currentCentroidY = TouchHistoryMath.currentCentroidY;
/**
* `PanResponder` reconciles several touches into a single gesture. It makes
* single-touch gestures resilient to extra touches, and can be used to
* recognize simple multi-touch gestures.
*
* It provides a predictable wrapper of the responder handlers provided by the
* [gesture responder system](docs/gesture-responder-system.html).
* For each handler, it provides a new `gestureState` object alongside the
* native event object:
*
* ```
* onPanResponderMove: (event, gestureState) => {}
* ```
*
* A native event is a synthetic touch event with the following form:
*
* - `nativeEvent`
* + `changedTouches` - Array of all touch events that have changed since the last event
* + `identifier` - The ID of the touch
* + `locationX` - The X position of the touch, relative to the element
* + `locationY` - The Y position of the touch, relative to the element
* + `pageX` - The X position of the touch, relative to the root element
* + `pageY` - The Y position of the touch, relative to the root element
* + `target` - The node id of the element receiving the touch event
* + `timestamp` - A time identifier for the touch, useful for velocity calculation
* + `touches` - Array of all current touches on the screen
*
* A `gestureState` object has the following:
*
* - `stateID` - ID of the gestureState- persisted as long as there at least
* one touch on screen
* - `moveX` - the latest screen coordinates of the recently-moved touch
* - `moveY` - the latest screen coordinates of the recently-moved touch
* - `x0` - the screen coordinates of the responder grant
* - `y0` - the screen coordinates of the responder grant
* - `dx` - accumulated distance of the gesture since the touch started
* - `dy` - accumulated distance of the gesture since the touch started
* - `vx` - current velocity of the gesture
* - `vy` - current velocity of the gesture
* - `numberActiveTouches` - Number of touches currently on screen
*
* ### Basic Usage
*
* ```
* componentWillMount: function() {
* this._panResponder = PanResponder.create({
* // Ask to be the responder:
* onStartShouldSetPanResponder: (evt, gestureState) => true,
* onStartShouldSetPanResponderCapture: (evt, gestureState) => true,
* onMoveShouldSetPanResponder: (evt, gestureState) => true,
* onMoveShouldSetPanResponderCapture: (evt, gestureState) => true,
*
* onPanResponderGrant: (evt, gestureState) => {
* // The guesture has started. Show visual feedback so the user knows
* // what is happening!
*
* // gestureState.{x,y}0 will be set to zero now
* },
* onPanResponderMove: (evt, gestureState) => {
* // The most recent move distance is gestureState.move{X,Y}
*
* // The accumulated gesture distance since becoming responder is
* // gestureState.d{x,y}
* },
* onPanResponderTerminationRequest: (evt, gestureState) => true,
* onPanResponderRelease: (evt, gestureState) => {
* // The user has released all touches while this view is the
* // responder. This typically means a gesture has succeeded
* },
* onPanResponderTerminate: (evt, gestureState) => {
* // Another component has become the responder, so this gesture
* // should be cancelled
* },
* onShouldBlockNativeResponder: (evt, gestureState) => {
* // Returns whether this component should block native components from becoming the JS
* // responder. Returns true by default. Is currently only supported on android.
* return true;
* },
* });
* },
*
* render: function() {
* return (
* <View {...this._panResponder.panHandlers} />
* );
* },
*
* ```
*
* ### Working Example
*
* To see it in action, try the
* [PanResponder example in UIExplorer](https://github.com/facebook/react-native/blob/master/Examples/UIExplorer/PanResponderExample.js)
*/
const PanResponder = {
/**
*
* A graphical explanation of the touch data flow:
*
* +----------------------------+ +--------------------------------+
* | ResponderTouchHistoryStore | |TouchHistoryMath |
* +----------------------------+ +----------+---------------------+
* |Global store of touchHistory| |Allocation-less math util |
* |including activeness, start | |on touch history (centroids |
* |position, prev/cur position.| |and multitouch movement etc) |
* | | | |
* +----^-----------------------+ +----^---------------------------+
* | |
* | (records relevant history |
* | of touches relevant for |
* | implementing higher level |
* | gestures) |
* | |
* +----+-----------------------+ +----|---------------------------+
* | ResponderEventPlugin | | | Your App/Component |
* +----------------------------+ +----|---------------------------+
* |Negotiates which view gets | Low level | | High level |
* |onResponderMove events. | events w/ | +-+-------+ events w/ |
* |Also records history into | touchHistory| | Pan | multitouch + |
* |ResponderTouchHistoryStore. +---------------->Responder+-----> accumulative|
* +----------------------------+ attached to | | | distance and |
* each event | +---------+ velocity. |
* | |
* | |
* +--------------------------------+
*
*
*
* Gesture that calculates cumulative movement over time in a way that just
* "does the right thing" for multiple touches. The "right thing" is very
* nuanced. When moving two touches in opposite directions, the cumulative
* distance is zero in each dimension. When two touches move in parallel five
* pixels in the same direction, the cumulative distance is five, not ten. If
* two touches start, one moves five in a direction, then stops and the other
* touch moves fives in the same direction, the cumulative distance is ten.
*
* This logic requires a kind of processing of time "clusters" of touch events
* so that two touch moves that essentially occur in parallel but move every
* other frame respectively, are considered part of the same movement.
*
* Explanation of some of the non-obvious fields:
*
* - moveX/moveY: If no move event has been observed, then `(moveX, moveY)` is
* invalid. If a move event has been observed, `(moveX, moveY)` is the
* centroid of the most recently moved "cluster" of active touches.
* (Currently all move have the same timeStamp, but later we should add some
* threshold for what is considered to be "moving"). If a palm is
* accidentally counted as a touch, but a finger is moving greatly, the palm
* will move slightly, but we only want to count the single moving touch.
* - x0/y0: Centroid location (non-cumulative) at the time of becoming
* responder.
* - dx/dy: Cumulative touch distance - not the same thing as sum of each touch
* distance. Accounts for touch moves that are clustered together in time,
* moving the same direction. Only valid when currently responder (otherwise,
* it only represents the drag distance below the threshold).
* - vx/vy: Velocity.
*/
_initializeGestureState: function(gestureState) {
gestureState.moveX = 0;
gestureState.moveY = 0;
gestureState.x0 = 0;
gestureState.y0 = 0;
gestureState.dx = 0;
gestureState.dy = 0;
gestureState.vx = 0;
gestureState.vy = 0;
gestureState.numberActiveTouches = 0;
// All `gestureState` accounts for timeStamps up until:
gestureState._accountsForMovesUpTo = 0;
},
/**
* This is nuanced and is necessary. It is incorrect to continuously take all
* active *and* recently moved touches, find the centroid, and track how that
* result changes over time. Instead, we must take all recently moved
* touches, and calculate how the centroid has changed just for those
* recently moved touches, and append that change to an accumulator. This is
* to (at least) handle the case where the user is moving three fingers, and
* then one of the fingers stops but the other two continue.
*
* This is very different than taking all of the recently moved touches and
* storing their centroid as `dx/dy`. For correctness, we must *accumulate
* changes* in the centroid of recently moved touches.
*
* There is also some nuance with how we handle multiple moved touches in a
* single event. With the way `ReactNativeEventEmitter` dispatches touches as
* individual events, multiple touches generate two 'move' events, each of
* them triggering `onResponderMove`. But with the way `PanResponder` works,
* all of the gesture inference is performed on the first dispatch, since it
* looks at all of the touches (even the ones for which there hasn't been a
* native dispatch yet). Therefore, `PanResponder` does not call
* `onResponderMove` passed the first dispatch. This diverges from the
* typical responder callback pattern (without using `PanResponder`), but
* avoids more dispatches than necessary.
*/
_updateGestureStateOnMove: function(gestureState, touchHistory) {
gestureState.numberActiveTouches = touchHistory.numberActiveTouches;
gestureState.moveX = currentCentroidXOfTouchesChangedAfter(
touchHistory,
gestureState._accountsForMovesUpTo
);
gestureState.moveY = currentCentroidYOfTouchesChangedAfter(
touchHistory,
gestureState._accountsForMovesUpTo
);
const movedAfter = gestureState._accountsForMovesUpTo;
const prevX = previousCentroidXOfTouchesChangedAfter(touchHistory, movedAfter);
const x = currentCentroidXOfTouchesChangedAfter(touchHistory, movedAfter);
const prevY = previousCentroidYOfTouchesChangedAfter(touchHistory, movedAfter);
const y = currentCentroidYOfTouchesChangedAfter(touchHistory, movedAfter);
const nextDX = gestureState.dx + (x - prevX);
const nextDY = gestureState.dy + (y - prevY);
// TODO: This must be filtered intelligently.
const dt = touchHistory.mostRecentTimeStamp - gestureState._accountsForMovesUpTo;
gestureState.vx = (nextDX - gestureState.dx) / dt;
gestureState.vy = (nextDY - gestureState.dy) / dt;
gestureState.dx = nextDX;
gestureState.dy = nextDY;
gestureState._accountsForMovesUpTo = touchHistory.mostRecentTimeStamp;
},
/**
* @param {object} config Enhanced versions of all of the responder callbacks
* that provide not only the typical `ResponderSyntheticEvent`, but also the
* `PanResponder` gesture state. Simply replace the word `Responder` with
* `PanResponder` in each of the typical `onResponder*` callbacks. For
* example, the `config` object would look like:
*
* - `onMoveShouldSetPanResponder: (e, gestureState) => {...}`
* - `onMoveShouldSetPanResponderCapture: (e, gestureState) => {...}`
* - `onStartShouldSetPanResponder: (e, gestureState) => {...}`
* - `onStartShouldSetPanResponderCapture: (e, gestureState) => {...}`
* - `onPanResponderReject: (e, gestureState) => {...}`
* - `onPanResponderGrant: (e, gestureState) => {...}`
* - `onPanResponderStart: (e, gestureState) => {...}`
* - `onPanResponderEnd: (e, gestureState) => {...}`
* - `onPanResponderRelease: (e, gestureState) => {...}`
* - `onPanResponderMove: (e, gestureState) => {...}`
* - `onPanResponderTerminate: (e, gestureState) => {...}`
* - `onPanResponderTerminationRequest: (e, gestureState) => {...}`
* - `onShouldBlockNativeResponder: (e, gestureState) => {...}`
*
* In general, for events that have capture equivalents, we update the
* gestureState once in the capture phase and can use it in the bubble phase
* as well.
*
* Be careful with onStartShould* callbacks. They only reflect updated
* `gestureState` for start/end events that bubble/capture to the Node.
* Once the node is the responder, you can rely on every start/end event
* being processed by the gesture and `gestureState` being updated
* accordingly. (numberActiveTouches) may not be totally accurate unless you
* are the responder.
*/
create: function(config) {
const gestureState = {
// Useful for debugging
stateID: Math.random()
};
PanResponder._initializeGestureState(gestureState);
const panHandlers = {
onStartShouldSetResponder: function(e) {
return config.onStartShouldSetPanResponder === undefined
? false
: config.onStartShouldSetPanResponder(e, gestureState);
},
onMoveShouldSetResponder: function(e) {
return config.onMoveShouldSetPanResponder === undefined
? false
: config.onMoveShouldSetPanResponder(e, gestureState);
},
onStartShouldSetResponderCapture: function(e) {
// TODO: Actually, we should reinitialize the state any time
// touches.length increases from 0 active to > 0 active.
if (e.nativeEvent.touches) {
if (e.nativeEvent.touches.length === 1) {
PanResponder._initializeGestureState(gestureState);
}
} else if (
e.nativeEvent.originalEvent &&
e.nativeEvent.originalEvent.type === 'mousedown'
) {
PanResponder._initializeGestureState(gestureState);
}
gestureState.numberActiveTouches = e.touchHistory.numberActiveTouches;
return config.onStartShouldSetPanResponderCapture !== undefined
? config.onStartShouldSetPanResponderCapture(e, gestureState)
: false;
},
onMoveShouldSetResponderCapture: function(e) {
const touchHistory = e.touchHistory;
// Responder system incorrectly dispatches should* to current responder
// Filter out any touch moves past the first one - we would have
// already processed multi-touch geometry during the first event.
if (gestureState._accountsForMovesUpTo === touchHistory.mostRecentTimeStamp) {
return false;
}
PanResponder._updateGestureStateOnMove(gestureState, touchHistory);
return config.onMoveShouldSetPanResponderCapture
? config.onMoveShouldSetPanResponderCapture(e, gestureState)
: false;
},
onResponderGrant: function(e) {
gestureState.x0 = currentCentroidX(e.touchHistory);
gestureState.y0 = currentCentroidY(e.touchHistory);
gestureState.dx = 0;
gestureState.dy = 0;
config.onPanResponderGrant && config.onPanResponderGrant(e, gestureState);
// TODO: t7467124 investigate if this can be removed
return config.onShouldBlockNativeResponder === undefined
? true
: config.onShouldBlockNativeResponder();
},
onResponderReject: function(e) {
config.onPanResponderReject && config.onPanResponderReject(e, gestureState);
},
onResponderRelease: function(e) {
config.onPanResponderRelease && config.onPanResponderRelease(e, gestureState);
PanResponder._initializeGestureState(gestureState);
},
onResponderStart: function(e) {
const touchHistory = e.touchHistory;
gestureState.numberActiveTouches = touchHistory.numberActiveTouches;
config.onPanResponderStart && config.onPanResponderStart(e, gestureState);
},
onResponderMove: function(e) {
const touchHistory = e.touchHistory;
// Guard against the dispatch of two touch moves when there are two
// simultaneously changed touches.
if (gestureState._accountsForMovesUpTo === touchHistory.mostRecentTimeStamp) {
return;
}
// Filter out any touch moves past the first one - we would have
// already processed multi-touch geometry during the first event.
PanResponder._updateGestureStateOnMove(gestureState, touchHistory);
config.onPanResponderMove && config.onPanResponderMove(e, gestureState);
},
onResponderEnd: function(e) {
const touchHistory = e.touchHistory;
gestureState.numberActiveTouches = touchHistory.numberActiveTouches;
config.onPanResponderEnd && config.onPanResponderEnd(e, gestureState);
},
onResponderTerminate: function(e) {
config.onPanResponderTerminate && config.onPanResponderTerminate(e, gestureState);
PanResponder._initializeGestureState(gestureState);
},
onResponderTerminationRequest: function(e) {
return config.onPanResponderTerminationRequest === undefined
? true
: config.onPanResponderTerminationRequest(e, gestureState);
}
};
return { panHandlers: panHandlers };
}
};
import PanResponder from '../../vendor/PanResponder';
export default PanResponder;

View File

@@ -182,7 +182,7 @@ export default class StyleRegistry {
}
/**
* Caching layer over 'resolveStyle'
* Caching layer over 'resolveStyle'
*/
_resolveStyleIfNeeded(style, options, key) {
const dir = I18nManager.isRTL ? 'rtl' : 'ltr';

View File

@@ -24,7 +24,7 @@ import { number, oneOf, string } from 'prop-types';
const ReactPropTypesSecret = 'SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED';
export default class StyleSheetValidation {
static validateStyleProp(prop, style, caller) {
static validateStyleProp(prop: string, style: Object, caller: string) {
if (process.env.NODE_ENV !== 'production') {
const isCustomProperty = prop.indexOf('--') === 0;
if (isCustomProperty) return;
@@ -51,7 +51,7 @@ export default class StyleSheetValidation {
}
}
static validateStyle(name, styles) {
static validateStyle(name: string, styles: Object) {
if (process.env.NODE_ENV !== 'production') {
for (const prop in styles[name]) {
StyleSheetValidation.validateStyleProp(prop, styles[name], 'StyleSheet ' + name);
@@ -59,7 +59,7 @@ export default class StyleSheetValidation {
}
}
static addValidStylePropTypes(stylePropTypes) {
static addValidStylePropTypes(stylePropTypes: Object) {
for (const key in stylePropTypes) {
allStylePropTypes[key] = stylePropTypes[key];
}
@@ -91,6 +91,7 @@ StyleSheetValidation.addValidStylePropTypes({
borderSpacing: oneOf([number, string]),
clear: string,
cursor: string,
fill: string,
float: oneOf(['left', 'none', 'right']),
font: string /* @private */,
listStyle: string,

View File

@@ -21,9 +21,165 @@ input::-webkit-inner-spin-button,input::-webkit-outer-spin-button,input::-webkit
"id": "react-native-stylesheet",
"textContent": ".rn-bottom-1p0dtai{bottom:0px}
.rn-left-1d2f490{left:0px}
.rn-left-1fe0xdi{left:0%}
.rn-left-7b7h2f{left:100%}
.rn-position-u8s1d{position:absolute}
.rn-position-bnwqim{position:relative}
.rn-right-zchlnj{right:0px}
.rn-top-ipm5af{top:0px}",
.rn-top-ipm5af{top:0px}
.rn-cursor-1loqt21{cursor:pointer}
.rn-cursor-7q8q6z{cursor:default}
.rn-cursor-1ei5mc7{cursor:inherit}
.rn-appearance-30o5oe{-moz-appearance:none;-webkit-appearance:none;appearance:none}
.rn-backgroundColor-wib322{background-color:transparent}
.rn-backgroundColor-8ndhhv{background-color:rgba(33,150,243,1)}
.rn-backgroundColor-15al3ab{background-color:rgba(223,223,223,1)}
.rn-backgroundColor-44z8sh{background-color:rgba(255,255,255,1)}
.rn-backgroundColor-5itogg{background-color:rgba(0,150,136,1)}
.rn-backgroundColor-1v82r4u{background-color:rgba(170,184,194,1)}
.rn-backgroundColor-1hj8efq{background-color:rgba(213,213,213,1)}
.rn-backgroundColor-1bgzomc{background-color:rgba(189,189,189,1)}
.rn-color-homxoj{color:inherit}
.rn-color-1qtguxu{color:rgba(255,255,255,1)}
.rn-color-istcb5{color:rgba(161,161,161,1)}
.rn-font-1lw9tu2{font:inherit}
.rn-textAlign-1ttztb7{text-align:inherit}
.rn-textAlign-q4m81j{text-align:center}
.rn-textDecoration-bauka4{text-decoration:none}
.rn-listStyle-1ebb2ja{list-style:none}
.rn-alignItems-1oszu61{-ms-flex-align:stretch;-webkit-align-items:stretch;-webkit-box-align:stretch;align-items:stretch}
.rn-alignItems-1awozwy{-ms-flex-align:center;-webkit-align-items:center;-webkit-box-align:center;align-items:center}
.rn-borderTopStyle-1efd50x{border-top-style:solid}
.rn-borderRightStyle-14skgim{border-right-style:solid}
.rn-borderBottomStyle-rull8r{border-bottom-style:solid}
.rn-borderLeftStyle-mm0ijv{border-left-style:solid}
.rn-borderTopWidth-13yce4e{border-top-width:0px}
.rn-borderTopWidth-1jxfwug{border-top-width:2px}
.rn-borderRightWidth-fnigne{border-right-width:0px}
.rn-borderRightWidth-18p6if4{border-right-width:2px}
.rn-borderBottomWidth-ndvcnb{border-bottom-width:0px}
.rn-borderBottomWidth-wgabs5{border-bottom-width:2px}
.rn-borderLeftWidth-gxnn5r{border-left-width:0px}
.rn-borderLeftWidth-dwliz8{border-left-width:2px}
.rn-boxSizing-deolkf{box-sizing:border-box}
.rn-display-6koalj{display:-webkit-box;display:-moz-box;display:-ms-flexbox;display:-webkit-flex;display:flex}
.rn-display-xoduu5{display:-webkit-inline-box;display:-moz-inline-box;display:-ms-inline-flexbox;display:-webkit-inline-flex;display:inline-flex}
.rn-display-1471scf{display:inline}
.rn-flexShrink-1pxmb3b{-ms-flex-negative:0 !important;-webkit-flex-shrink:0 !important;flex-shrink:0 !important}
.rn-flexShrink-1awmn5t{-ms-flex-negative:1 !important;-webkit-flex-shrink:1 !important;flex-shrink:1 !important}
.rn-flexBasis-7vfszb{-ms-flex-preferred-size:auto !important;-webkit-flex-basis:auto !important;flex-basis:auto !important}
.rn-flexDirection-eqz5dr{-ms-flex-direction:column;-webkit-box-direction:normal;-webkit-box-orient:vertical;-webkit-flex-direction:column;flex-direction:column}
.rn-flexDirection-18u37iz{-ms-flex-direction:row;-webkit-box-direction:normal;-webkit-box-orient:horizontal;-webkit-flex-direction:row;flex-direction:row}
.rn-marginTop-1mnahxq{margin-top:0px}
.rn-marginTop-1t01tom{margin-top:auto}
.rn-marginRight-61z16t{margin-right:0px}
.rn-marginRight-lchren{margin-right:auto}
.rn-marginBottom-p1pxzi{margin-bottom:0px}
.rn-marginBottom-1qahzrx{margin-bottom:auto}
.rn-marginLeft-11wrixw{margin-left:0px}
.rn-marginLeft-1jj8364{margin-left:auto}
.rn-minHeight-ifefl9{min-height:0px}
.rn-minWidth-bcqeeo{min-width:0px}
.rn-paddingTop-wk8lta{padding-top:0px}
.rn-paddingTop-tskmnb{padding-top:8px}
.rn-paddingRight-9aemit{padding-right:0px}
.rn-paddingRight-1pyaxff{padding-right:8px}
.rn-paddingBottom-1mdbw0j{padding-bottom:0px}
.rn-paddingBottom-xd6kpl{padding-bottom:8px}
.rn-paddingLeft-gy4na3{padding-left:0px}
.rn-paddingLeft-1m04atk{padding-left:8px}
.rn-zIndex-1lgpqti{z-index:0}
.rn-zIndex-1wyyakw{z-index:-1}
.rn-backgroundPosition-vvn4in{background-position:center}
.rn-backgroundRepeat-u6sd8q{background-repeat:no-repeat}
.rn-backgroundRepeat-17leim2{background-repeat:repeat}
.rn-backgroundSize-4gszlv{background-size:cover}
.rn-backgroundSize-1sxrcry{background-size:auto}
.rn-backgroundSize-ehq7j7{background-size:contain}
.rn-backgroundSize-x3cy2q{background-size:100% 100%}
.rn-height-1pi2tsx{height:100%}
.rn-height-z80fyv{height:20px}
.rn-height-1r8g8re{height:36px}
.rn-height-10ptun7{height:16px}
.rn-height-4v7adb{height:5px}
.rn-height-1dernwh{height:70%}
.rn-opacity-1272l3b{opacity:0}
.rn-opacity-6dt33c{opacity:1}
.rn-width-13qz1uu{width:100%}
.rn-width-19wmn03{width:20px}
.rn-width-1acpoxo{width:36px}
.rn-width-1janqcz{width:16px}
.rn-touchAction-19z077z{-ms-touch-action:none;touch-action:none}
.rn-touchAction-1gvxusu{-ms-touch-action:manipulate;touch-action:manipulate}
.rn-WebkitOverflowScrolling-150rngu{-webkit-overflow-scrolling:touch}
.rn-flex-13awgt0{-ms-flex:1;-webkit-flex:1;flex:1}
.rn-flexGrow-1m1wadx{-ms-flex-positive:1 !important;-webkit-flex-grow:1 !important;flex-grow:1 !important}
.rn-overflowX-11yh6sk{overflow-x:hidden}
.rn-overflowX-lltvgl{overflow-x:auto}
.rn-overflowY-1rnoaur{overflow-y:auto}
.rn-overflowY-buy8e9{overflow-y:hidden}
.rn-transform-emqnss{-webkit-transform:translateZ(0px);transform:translateZ(0px)}
.rn-fontFamily-10u92zi{font-family:-apple-system, BlinkMacSystemFont, \\"Segoe UI\\", Roboto, Ubuntu, \\"Helvetica Neue\\", sans-serif}
.rn-fontFamily-poiln3{font-family:inherit}
.rn-fontSize-1b43r93{font-size:14px}
.rn-fontSize-7cikom{font-size:inherit}
.rn-whiteSpace-q42fyq{white-space:pre-wrap}
.rn-whiteSpace-irrty{white-space:inherit}
.rn-whiteSpace-3s2u2q{white-space:nowrap}
.rn-wordWrap-qvutc0{word-wrap:break-word}
.rn-userSelect-lrvibr{-moz-user-select:none;-ms-user-select:none;-webkit-user-select:none;user-select:none}
.rn-maxWidth-dnmrzs{max-width:100%}
.rn-textOverflow-1udbk01{text-overflow:ellipsis}
.rn-justifyContent-1777fci{-ms-flex-pack:center;-webkit-box-pack:center;-webkit-justify-content:center;justify-content:center}
.rn-visibility-11j9u27{visibility:hidden}
.rn-animationDuration-17bb2tj{-webkit-animation-duration:0.75s;animation-duration:0.75s}
.rn-animationDuration-1ay1djp{-webkit-animation-duration:1s;animation-duration:1s}
.rn-animationIterationCount-1muvv40{-webkit-animation-iteration-count:infinite;animation-iteration-count:infinite}
.rn-animationName-dozj4v{-webkit-animation-name:rn-ActivityIndicator-animation;animation-name:rn-ActivityIndicator-animation}
.rn-animationName-141g9a{-webkit-animation-name:rn-ProgressBar-animation;animation-name:rn-ProgressBar-animation}
.rn-animationTimingFunction-1ldzwu0{-webkit-animation-timing-function:linear;animation-timing-function:linear}
.rn-animationPlayState-1abnn5w{-webkit-animation-play-state:paused;animation-play-state:paused}
.rn-transitionDuration-eafdt9{-webkit-transition-duration:0.15s;transition-duration:0.15s}
.rn-transitionDuration-13tjlyg{-webkit-transition-duration:0.1s;transition-duration:0.1s}
.rn-transitionProperty-1i6wzkk{-moz-transition-property:opacity;-webkit-transition-property:opacity;transition-property:opacity}
.rn-borderTopLeftRadius-1iymjk7{border-top-left-radius:2px}
.rn-borderTopLeftRadius-jt3ufn{border-top-left-radius:100%}
.rn-borderTopLeftRadius-ou6ah9{border-top-left-radius:0px}
.rn-borderTopRightRadius-s2skl2{border-top-right-radius:2px}
.rn-borderTopRightRadius-1e868j9{border-top-right-radius:100%}
.rn-borderTopRightRadius-t12b5v{border-top-right-radius:0px}
.rn-borderBottomRightRadius-l5bh9y{border-bottom-right-radius:2px}
.rn-borderBottomRightRadius-ujv9e3{border-bottom-right-radius:100%}
.rn-borderBottomRightRadius-zmljjp{border-bottom-right-radius:0px}
.rn-borderBottomLeftRadius-101sy47{border-bottom-left-radius:2px}
.rn-borderBottomLeftRadius-1hakmuk{border-bottom-left-radius:100%}
.rn-borderBottomLeftRadius-pm2fo{border-bottom-left-radius:0px}
.rn-fontWeight-majxgm{font-weight:500}
.rn-textTransform-tsynxw{text-transform:uppercase}
.rn-borderTopColor-j4x2lb{border-top-color:rgba(101,119,134,1)}
.rn-borderTopColor-gj2eto{border-top-color:rgba(0,150,136,1)}
.rn-borderTopColor-1j7vz2b{border-top-color:rgba(204,214,221,1)}
.rn-borderTopColor-2dclza{border-top-color:rgba(170,184,194,1)}
.rn-borderTopColor-kqr9px{border-top-color:black}
.rn-borderRightColor-12i18q1{border-right-color:rgba(101,119,134,1)}
.rn-borderRightColor-31ud7z{border-right-color:rgba(0,150,136,1)}
.rn-borderRightColor-10fg1ub{border-right-color:rgba(204,214,221,1)}
.rn-borderRightColor-8jf312{border-right-color:rgba(170,184,194,1)}
.rn-borderRightColor-q0dj5p{border-right-color:black}
.rn-borderBottomColor-mg3rfb{border-bottom-color:rgba(101,119,134,1)}
.rn-borderBottomColor-1bgnb8i{border-bottom-color:rgba(0,150,136,1)}
.rn-borderBottomColor-zxuuv6{border-bottom-color:rgba(204,214,221,1)}
.rn-borderBottomColor-1yeakrt{border-bottom-color:rgba(170,184,194,1)}
.rn-borderBottomColor-1ah7hsa{border-bottom-color:black}
.rn-borderLeftColor-vnhemr{border-left-color:rgba(101,119,134,1)}
.rn-borderLeftColor-tbzcuz{border-left-color:rgba(0,150,136,1)}
.rn-borderLeftColor-1p34dw6{border-left-color:rgba(204,214,221,1)}
.rn-borderLeftColor-bluj2i{border-left-color:rgba(170,184,194,1)}
.rn-borderLeftColor-137uh4u{border-left-color:black}
.rn-backgroundImage-rs94m5{background-image:url(\\"data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcKICAgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIgogICB4bWxuczpjYz0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbnMjIgogICB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiCiAgIHhtbG5zOnN2Zz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgdmVyc2lvbj0iMS4xIgogICB2aWV3Qm94PSIwIDAgMSAxIgogICBwcmVzZXJ2ZUFzcGVjdFJhdGlvPSJ4TWluWU1pbiBtZWV0Ij4KICA8cGF0aAogICAgIGQ9Ik0gMC4wNDAzODA1OSwwLjYyNjc3NjcgMC4xNDY0NDY2MSwwLjUyMDcxMDY4IDAuNDI5Mjg5MzIsMC44MDM1NTMzOSAwLjMyMzIyMzMsMC45MDk2MTk0MSB6IE0gMC4yMTcxNTcyOSwwLjgwMzU1MzM5IDAuODUzNTUzMzksMC4xNjcxNTcyOSAwLjk1OTYxOTQxLDAuMjczMjIzMyAwLjMyMzIyMzMsMC45MDk2MTk0MSB6IgogICAgIGlkPSJyZWN0Mzc4MCIKICAgICBzdHlsZT0iZmlsbDojZmZmZmZmO2ZpbGwtb3BhY2l0eToxO3N0cm9rZTpub25lIiAvPgo8L3N2Zz4K\\")}
.rn-alignSelf-k200y{-ms-flex-item-align:start;-webkit-align-self:flex-start;align-self:flex-start}
.rn-boxShadow-1ewcgjf{box-shadow:0px 1px 3px rgba(0,0,0,0.5)}
.rn-resize-1dz5y72{resize:none}",
},
]
`;

View File

@@ -22,48 +22,65 @@ describe('apis/StyleSheet/createReactDOMStyle', () => {
expect(firstStyle).toEqual(secondStyle);
});
describe('borderWidth styles', () => {
test('defaults to 0 when "null"', () => {
expect(createReactDOMStyle({ borderWidth: null })).toEqual({
borderTopWidth: '0px',
borderRightWidth: '0px',
borderBottomWidth: '0px',
borderLeftWidth: '0px'
});
expect(createReactDOMStyle({ borderWidth: 2, borderRightWidth: null })).toEqual({
borderTopWidth: '2px',
borderRightWidth: '0px',
borderBottomWidth: '2px',
borderLeftWidth: '2px'
});
});
});
describe('flexbox styles', () => {
test('flex defaults', () => {
expect(createReactDOMStyle({ display: 'flex' })).toEqual({
display: 'flex',
flexShrink: 0,
flexBasis: 'auto'
flexShrink: '0 !important',
flexBasis: 'auto !important'
});
});
test('flex: -1', () => {
expect(createReactDOMStyle({ display: 'flex', flex: -1 })).toEqual({
display: 'flex',
flexGrow: 0,
flexShrink: 1,
flexBasis: 'auto'
flexGrow: '0 !important',
flexShrink: '1 !important',
flexBasis: 'auto !important'
});
});
test('flex: 0', () => {
expect(createReactDOMStyle({ display: 'flex', flex: 0 })).toEqual({
display: 'flex',
flexGrow: 0,
flexShrink: 0,
flexBasis: 'auto'
flexGrow: '0 !important',
flexShrink: '0 !important',
flexBasis: 'auto !important'
});
});
test('flex: 1', () => {
expect(createReactDOMStyle({ display: 'flex', flex: 1 })).toEqual({
display: 'flex',
flexGrow: 1,
flexShrink: 1,
flexBasis: '0%'
flex: 1,
flexGrow: '1 !important',
flexShrink: '1 !important'
});
});
test('flex: 10', () => {
expect(createReactDOMStyle({ display: 'flex', flex: 10 })).toEqual({
display: 'flex',
flexGrow: 10,
flexShrink: 1,
flexBasis: '0%'
flex: 10,
flexGrow: '10 !important',
flexShrink: '1 !important'
});
});
@@ -71,16 +88,17 @@ describe('apis/StyleSheet/createReactDOMStyle', () => {
// is flex-basis applied?
expect(createReactDOMStyle({ display: 'flex', flexBasis: '25%' })).toEqual({
display: 'flex',
flexShrink: 0,
flexBasis: '25%'
flexShrink: '0 !important',
flexBasis: '25% !important'
});
// can flex-basis override the 'flex' expansion?
expect(createReactDOMStyle({ display: 'flex', flex: 1, flexBasis: '25%' })).toEqual({
display: 'flex',
flexGrow: 1,
flexShrink: 1,
flexBasis: '25%'
flex: 1,
flexGrow: '1 !important',
flexShrink: '1 !important',
flexBasis: '25% !important'
});
});
@@ -88,16 +106,16 @@ describe('apis/StyleSheet/createReactDOMStyle', () => {
// is flex-shrink applied?
expect(createReactDOMStyle({ display: 'flex', flexShrink: 1 })).toEqual({
display: 'flex',
flexShrink: 1,
flexBasis: 'auto'
flexShrink: '1 !important',
flexBasis: 'auto !important'
});
// can flex-shrink override the 'flex' expansion?
expect(createReactDOMStyle({ display: 'flex', flex: 1, flexShrink: 2 })).toEqual({
display: 'flex',
flexGrow: 1,
flexShrink: 2,
flexBasis: '0%'
flex: 1,
flexGrow: '1 !important',
flexShrink: '2 !important'
});
});
});

View File

@@ -22,6 +22,18 @@ describe('apis/StyleSheet', () => {
expect(isPlainObject(StyleSheet.absoluteFillObject) === true).toBeTruthy();
});
describe('compose', () => {
test('returns array when neither style is falsey', () => {
expect(StyleSheet.compose(1, 2)).toEqual([1, 2]);
});
test('returns style1 when style2 is falsey', () => {
expect(StyleSheet.compose(1, null)).toBe(1);
});
test('returns style2 when style1 is falsey', () => {
expect(StyleSheet.compose(null, 2)).toBe(2);
});
});
describe('create', () => {
test('replaces styles with numbers', () => {
const style = StyleSheet.create({ root: { position: 'absolute' } });

View File

@@ -52,6 +52,14 @@ const colorProps = {
color: true
};
const borderWidthProps = {
borderWidth: true,
borderTopWidth: true,
borderRightWidth: true,
borderBottomWidth: true,
borderLeftWidth: true
};
const systemFontStack =
'-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Ubuntu, "Helvetica Neue", sans-serif';
@@ -141,13 +149,26 @@ const createReducer = (style, styleProps) => {
let hasResolvedTextShadow = false;
return (resolvedStyle, prop) => {
const value = normalizeValue(prop, style[prop]);
let value = normalizeValue(prop, style[prop]);
// Make sure the default border width is explicitly set to '0' to avoid
// falling back to any unwanted user-agent styles.
if (borderWidthProps[prop]) {
value = value == null ? normalizeValue(null, 0) : value;
}
// Normalize color values
if (colorProps[prop]) {
value = processColor(value);
}
// Ignore everything else with a null value
if (value == null) {
return resolvedStyle;
}
switch (prop) {
// ignore React Native styles
// Ignore some React Native styles
case 'aspectRatio':
case 'elevation':
case 'overlayColor':
@@ -158,29 +179,56 @@ const createReducer = (style, styleProps) => {
case 'display': {
resolvedStyle.display = value;
// defaults of 'flexBasis:auto' and 'flexShrink:0' have lowest precedence
if (style.display === 'flex') {
// A flex container in React Native has these defaults which should be
// set only if there is no otherwise supplied flex style.
if (style.display === 'flex' && style.flex == null) {
if (style.flexShrink == null) {
resolvedStyle.flexShrink = 0;
resolvedStyle.flexShrink = '0 !important';
}
if (style.flexBasis == null) {
resolvedStyle.flexBasis = 'auto';
resolvedStyle.flexBasis = 'auto !important';
}
}
break;
}
// The 'flex' property value in React Native must be a positive integer,
// 0, or -1.
//
// On the web, a positive integer value for 'flex' is complicated by
// browser differences. Although browsers render styles like 'flex:2'
// consistently, they don't all set the same value for the resulting
// 'flexBasis' (See #616). Expanding 'flex' in 'StyleSheet' would mean
// setting different values for different browsers.
//
// This fix instead relies on the browser expanding 'flex' itself. And
// because the 'flex' style is not being expanded the generated CSS is
// likely to contain source order "conflicts". To avoid the browser
// relying on source order to resolve the styles, all the longhand flex
// property values must use '!important'.
case 'flex': {
if (value > 0) {
resolvedStyle.flexGrow = value;
resolvedStyle.flexShrink = 1;
resolvedStyle.flexBasis = '0%';
resolvedStyle.flex = value;
resolvedStyle.flexGrow = `${value} !important`;
resolvedStyle.flexShrink = '1 !important';
} else if (value === 0) {
resolvedStyle.flexGrow = 0;
resolvedStyle.flexShrink = 0;
resolvedStyle.flexGrow = '0 !important';
resolvedStyle.flexShrink = '0 !important';
resolvedStyle.flexBasis = 'auto !important';
} else if (value === -1) {
resolvedStyle.flexGrow = 0;
resolvedStyle.flexShrink = 1;
resolvedStyle.flexGrow = '0 !important';
resolvedStyle.flexShrink = '1 !important';
resolvedStyle.flexBasis = 'auto !important';
}
break;
}
case 'flexGrow':
case 'flexShrink':
case 'flexBasis': {
if (value != null) {
const hasImportant = `${value}`.indexOf('!important') > -1;
resolvedStyle[prop] = hasImportant ? value : `${value} !important`;
}
break;
}
@@ -224,23 +272,17 @@ const createReducer = (style, styleProps) => {
}
default: {
// normalize color values
let finalValue = value;
if (colorProps[prop]) {
finalValue = processColor(value);
}
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
// The value of any longform property in the original styles takes
// precedence over the shortform's value.
if (styleProps.indexOf(longForm) === -1) {
resolvedStyle[longForm] = finalValue;
resolvedStyle[longForm] = value;
}
});
} else {
resolvedStyle[prop] = finalValue;
resolvedStyle[prop] = value;
}
}
}

View File

@@ -0,0 +1,22 @@
/**
* Based on http://dieulot.net/css-retina-hairline
* @noflow
*/
import { canUseDOM } from 'fbjs/lib/ExecutionEnvironment';
const getHairlineWidth = () => {
let hairlineWidth = 1;
if (canUseDOM && window.devicePixelRatio && window.devicePixelRatio >= 2) {
const node = document.createElement('div');
node.style.border = '.5px solid transparent';
document.body.appendChild(node);
if (node.offsetHeight === 1) {
hairlineWidth = 0.5;
}
document.body.removeChild(node);
}
return hairlineWidth;
};
export default getHairlineWidth;

View File

@@ -10,6 +10,7 @@
*/
import flattenStyle from './flattenStyle';
import getHairlineWidth from './getHairlineWidth';
import modality from '../../modules/modality';
import StyleRegistry from './registry';
@@ -36,6 +37,13 @@ const absoluteFill = StyleRegistry.register(absoluteFillObject);
const StyleSheet = {
absoluteFill,
absoluteFillObject,
compose(style1, style2) {
if (style1 && style2) {
return [style1, style2];
} else {
return style1 || style2;
}
},
create(styles) {
const result = {};
Object.keys(styles).forEach(key => {
@@ -51,7 +59,7 @@ const StyleSheet = {
getStyleSheets() {
return StyleRegistry.getStyleSheets();
},
hairlineWidth: 1
hairlineWidth: getHairlineWidth()
};
export default StyleSheet;

Some files were not shown because too many files have changed in this diff Show More