mirror of
https://github.com/zhigang1992/react-native-web.git
synced 2026-04-23 04:00:04 +08:00
Compare commits
71 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
91472bc3d6 | ||
|
|
7f45c52ce7 | ||
|
|
b6ef1d3a36 | ||
|
|
fd6ccbcfb3 | ||
|
|
17614e348b | ||
|
|
c26ef0eb3b | ||
|
|
b78206d2f4 | ||
|
|
69e0396fb1 | ||
|
|
6d9154196e | ||
|
|
87fdd6c73b | ||
|
|
209bd3aee1 | ||
|
|
46e77d0b00 | ||
|
|
6f10f6be9c | ||
|
|
0d0fdc15ac | ||
|
|
bff3f50ae0 | ||
|
|
85aaa39206 | ||
|
|
b85a7062be | ||
|
|
af47d5f414 | ||
|
|
41d90e0238 | ||
|
|
86263a2fa0 | ||
|
|
f6d1caab9d | ||
|
|
1776891736 | ||
|
|
f52a851972 | ||
|
|
3026465ae3 | ||
|
|
14d87f4b30 | ||
|
|
5881f07323 | ||
|
|
b545fe47a7 | ||
|
|
4da4dd57c4 | ||
|
|
3e12ddfb2b | ||
|
|
3ecf5d2ed2 | ||
|
|
0a5acdb996 | ||
|
|
a712a58eba | ||
|
|
6de892c92b | ||
|
|
495defd69b | ||
|
|
1a20fcfce6 | ||
|
|
ed1e45a43d | ||
|
|
556dc8926e | ||
|
|
66cf45b90b | ||
|
|
d1e49e06e6 | ||
|
|
8bf28dbe43 | ||
|
|
9ae95d0797 | ||
|
|
321051b723 | ||
|
|
5f68542529 | ||
|
|
82c044ee33 | ||
|
|
9bcc67e73a | ||
|
|
f1ce6c2acb | ||
|
|
034108a2a0 | ||
|
|
f96d7b868f | ||
|
|
0dfe319d41 | ||
|
|
b7e970f4e6 | ||
|
|
02e62ad5d6 | ||
|
|
541d2458fb | ||
|
|
b1e860ab40 | ||
|
|
e8eab9b3ec | ||
|
|
6bc76c3c92 | ||
|
|
2acd8e477c | ||
|
|
ff2b0c9bdc | ||
|
|
79208720d1 | ||
|
|
fca04c4125 | ||
|
|
5b5b72cc19 | ||
|
|
217ad97bfd | ||
|
|
3e3cfc5325 | ||
|
|
da86ea98fc | ||
|
|
5f3e422b5c | ||
|
|
1f1f89b062 | ||
|
|
0f79960b85 | ||
|
|
117ce59f27 | ||
|
|
214121480e | ||
|
|
6261536f57 | ||
|
|
a748b7e606 | ||
|
|
92952ee746 |
4
.eslintignore
Normal file
4
.eslintignore
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
coverage
|
||||||
|
dist
|
||||||
|
node_modules
|
||||||
|
packages/**/vendor/*
|
||||||
@@ -56,6 +56,7 @@
|
|||||||
"no-dupe-class-members": 2,
|
"no-dupe-class-members": 2,
|
||||||
"no-dupe-keys": 2,
|
"no-dupe-keys": 2,
|
||||||
"no-duplicate-case": 2,
|
"no-duplicate-case": 2,
|
||||||
|
"no-duplicate-imports": 2,
|
||||||
"no-empty-character-class": 2,
|
"no-empty-character-class": 2,
|
||||||
"no-empty-pattern": 2,
|
"no-empty-pattern": 2,
|
||||||
"no-eval": 2,
|
"no-eval": 2,
|
||||||
|
|||||||
13
.flowconfig
13
.flowconfig
@@ -1,14 +1,17 @@
|
|||||||
|
[version]
|
||||||
|
^0.61.0
|
||||||
|
|
||||||
[ignore]
|
[ignore]
|
||||||
.*/__tests__/.*
|
<PROJECT_ROOT>/.*/__tests__/.*
|
||||||
.*/benchmarks/.*
|
<PROJECT_ROOT>/packages/benchmarks/.*
|
||||||
.*/docs/.*
|
<PROJECT_ROOT>/packages/.*/dist/.*
|
||||||
.*/node_modules/animated/*
|
<PROJECT_ROOT>/website/.*
|
||||||
.*/node_modules/babel-plugin-transform-react-remove-prop-types/*
|
.*/node_modules/babel-plugin-transform-react-remove-prop-types/*
|
||||||
|
|
||||||
[include]
|
[include]
|
||||||
|
|
||||||
[libs]
|
[libs]
|
||||||
types
|
<PROJECT_ROOT>/types
|
||||||
|
|
||||||
[options]
|
[options]
|
||||||
unsafe.enable_getters_and_setters=true
|
unsafe.enable_getters_and_setters=true
|
||||||
|
|||||||
83
.github/CONTRIBUTING.md
vendored
83
.github/CONTRIBUTING.md
vendored
@@ -17,7 +17,7 @@ Fork, then clone the repo:
|
|||||||
git clone https://github.com/your-username/react-native-web.git
|
git clone https://github.com/your-username/react-native-web.git
|
||||||
```
|
```
|
||||||
|
|
||||||
Install dependencies (requires [yarn](https://yarnpkg.com/en/docs/install):
|
Install dependencies (requires [yarn](https://yarnpkg.com/en/docs/install)):
|
||||||
|
|
||||||
```
|
```
|
||||||
yarn
|
yarn
|
||||||
@@ -25,6 +25,12 @@ yarn
|
|||||||
|
|
||||||
## Automated tests
|
## Automated tests
|
||||||
|
|
||||||
|
To run the linter:
|
||||||
|
|
||||||
|
```
|
||||||
|
yarn lint
|
||||||
|
```
|
||||||
|
|
||||||
To run flow:
|
To run flow:
|
||||||
|
|
||||||
```
|
```
|
||||||
@@ -40,16 +46,30 @@ yarn jest
|
|||||||
…in watch mode:
|
…in watch mode:
|
||||||
|
|
||||||
```
|
```
|
||||||
yarn jest:watch
|
yarn jest --watch
|
||||||
```
|
```
|
||||||
|
|
||||||
To run all automated tests:
|
To run all these automated tests:
|
||||||
|
|
||||||
```
|
```
|
||||||
yarn test
|
yarn test
|
||||||
```
|
```
|
||||||
|
|
||||||
## Visual tests
|
## Compile and build
|
||||||
|
|
||||||
|
To compile the `react-native-web` source code:
|
||||||
|
|
||||||
|
```
|
||||||
|
yarn compile
|
||||||
|
```
|
||||||
|
|
||||||
|
…in watch mode:
|
||||||
|
|
||||||
|
```
|
||||||
|
yarn compile --watch
|
||||||
|
```
|
||||||
|
|
||||||
|
## Website and visual tests
|
||||||
|
|
||||||
To run the interactive storybook:
|
To run the interactive storybook:
|
||||||
|
|
||||||
@@ -57,47 +77,20 @@ To run the interactive storybook:
|
|||||||
yarn docs:start
|
yarn docs:start
|
||||||
```
|
```
|
||||||
|
|
||||||
To generate a static build of the storybook:
|
When you're also making changes to the 'react-native-web' source files, run this command in another process:
|
||||||
|
|
||||||
```
|
```
|
||||||
yarn docs:build
|
yarn compile --watch
|
||||||
```
|
```
|
||||||
|
|
||||||
To run the performance benchmarks in a browser (opening `./benchmarks/index.html`):
|
## Benchmarks
|
||||||
|
|
||||||
|
To run the performance benchmarks in a browser (opening `./packages/benchmarks/index.html`):
|
||||||
|
|
||||||
```
|
```
|
||||||
yarn benchmark
|
yarn benchmark
|
||||||
```
|
```
|
||||||
|
|
||||||
## Compile and build
|
|
||||||
|
|
||||||
To compile the source code to `dist`:
|
|
||||||
|
|
||||||
```
|
|
||||||
yarn compile
|
|
||||||
```
|
|
||||||
|
|
||||||
To create a UMD bundle of the library:
|
|
||||||
|
|
||||||
```
|
|
||||||
yarn build
|
|
||||||
```
|
|
||||||
|
|
||||||
### Pre-commit
|
|
||||||
|
|
||||||
To format and lint code before commit:
|
|
||||||
|
|
||||||
```
|
|
||||||
yarn precommit
|
|
||||||
```
|
|
||||||
|
|
||||||
To format and lint the entire project:
|
|
||||||
|
|
||||||
```
|
|
||||||
yarn fmt
|
|
||||||
yarn lint
|
|
||||||
```
|
|
||||||
|
|
||||||
### New Features
|
### New Features
|
||||||
|
|
||||||
Please open an issue with a proposal for a new feature or refactoring before
|
Please open an issue with a proposal for a new feature or refactoring before
|
||||||
@@ -106,13 +99,12 @@ that we won't want to accept.
|
|||||||
|
|
||||||
## Pull requests
|
## Pull requests
|
||||||
|
|
||||||
**Before submitting a pull request,** please make sure the following is done:
|
**Before submitting a pull request**, please make sure the following is done:
|
||||||
|
|
||||||
1. Fork the repository and create your branch from `master`.
|
1. Fork the repository and create your branch from `master`.
|
||||||
2. If you've added code that should be tested, add tests!
|
2. If you've added code that should be tested, add tests!
|
||||||
3. If you've changed APIs, update the documentation.
|
3. If you've changed APIs, update the documentation.
|
||||||
4. Ensure the tests pass (`yarn test`).
|
4. Ensure the tests pass (`yarn test`).
|
||||||
5. Lint and format your code (`yarn fmt && yarn lint`).
|
|
||||||
|
|
||||||
You can now submit a pull request, referencing any issues it addresses.
|
You can now submit a pull request, referencing any issues it addresses.
|
||||||
|
|
||||||
@@ -123,3 +115,18 @@ After you have submitted your pull request, we'll try to get back to you as
|
|||||||
soon as possible. We may suggest some changes or improvements.
|
soon as possible. We may suggest some changes or improvements.
|
||||||
|
|
||||||
Thank you for contributing!
|
Thank you for contributing!
|
||||||
|
|
||||||
|
## Releases
|
||||||
|
|
||||||
|
To commit, publish, and push a final version:
|
||||||
|
|
||||||
|
```
|
||||||
|
yarn release <version>
|
||||||
|
```
|
||||||
|
|
||||||
|
Release candidates or versions that you'd like to publish to npm, but do not
|
||||||
|
want to produce a commit and push it to GitHub:
|
||||||
|
|
||||||
|
```
|
||||||
|
yarn release <version> --skip-git
|
||||||
|
```
|
||||||
|
|||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,2 +1,3 @@
|
|||||||
|
coverage
|
||||||
node_modules
|
node_modules
|
||||||
dist
|
dist
|
||||||
|
|||||||
19
.travis.yml
19
.travis.yml
@@ -1,8 +1,17 @@
|
|||||||
language: node_js
|
language: node_js
|
||||||
|
|
||||||
node_js:
|
node_js:
|
||||||
- "6"
|
- "8"
|
||||||
before_script:
|
|
||||||
- export DISPLAY=:99.0
|
before_install:
|
||||||
- sh -e /etc/init.d/xvfb start
|
# Install Yarn
|
||||||
|
- curl -o- -L https://yarnpkg.com/install.sh | bash
|
||||||
|
- export PATH=$HOME/.yarn/bin:$PATH
|
||||||
|
|
||||||
|
cache:
|
||||||
|
yarn: true
|
||||||
|
directories:
|
||||||
|
- node_modules
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- yarn lint
|
- yarn test
|
||||||
|
|||||||
206
README.md
206
README.md
@@ -1,127 +1,137 @@
|
|||||||
# React Native for Web
|
# React Native for Web
|
||||||
|
|
||||||
[![Build Status][travis-image]][travis-url]
|
[![npm version][package-badge]][package-url] [![Build Status][ci-badge]][ci-url] [](https://reactjs.org/docs/how-to-contribute.html#your-first-pull-request)
|
||||||
[![npm version][npm-image]][npm-url]
|
|
||||||
|
|
||||||
"React Native for Web" brings the platform-agnostic Components and APIs of
|
"React Native for Web" brings the platform-agnostic Components and APIs of
|
||||||
[React Native][react-native-url] to the Web.
|
[React Native][react-native-url] to the Web.
|
||||||
|
|
||||||
Browse the [interactive
|
* **High-quality user interfaces**: React Native for Web makes it easy to
|
||||||
documentation](https://necolas.github.io/react-native-web/storybook/) or [try
|
create [fast](packages/benchmarks/README.md), adaptive web UIs in JavaScript.
|
||||||
it out](https://glitch.com/edit/#!/react-native-web-playground) on Glitch.
|
It provides native-like interactions, support for multiple input modes (touch,
|
||||||
|
mouse, keyboard), optimized vendor-prefixed styles, built-in support for RTL
|
||||||
|
layout, built-in accessibility, and integrates with React Dev Tools.
|
||||||
|
|
||||||
## Features
|
* **Write once, render anywhere**: React Native for Web interoperates with
|
||||||
|
existing React DOM components and is compatible with the majority of the
|
||||||
|
React Native API. You can develop new components for native and web without
|
||||||
|
rewriting existing code. React Native for Web can also render to HTML and
|
||||||
|
critical CSS on the server using Node.js.
|
||||||
|
|
||||||
* Interoperability with ReactDOM components.
|
Who is using React Native for Web? [Twitter](https://mobile.twitter.com),
|
||||||
* Native-like touch handling.
|
[Major League Soccer](https://matchcenter.mlssoccer.com), [The
|
||||||
* Built-in integration with web accessibility APIs.
|
Times](https://github.com/newsuk/times-components), [React Native's
|
||||||
* Built-in support for LTR and RTL layouts.
|
documentation](http://facebook.github.io/react-native/).
|
||||||
* Built-in expressive and reliable subset of CSS.
|
|
||||||
* Optimized, vendor-prefixed CSS with [good runtime performance](benchmarks/README.md).
|
Browser support: Chrome, Firefox, Safari >= 7, IE 10, Edge.
|
||||||
* Server-side rendering of HTML and critical CSS.
|
|
||||||
* Browser support: Chrome, Firefox, Safari >= 7, IE 10, Edge.
|
|
||||||
|
|
||||||
## Quick start
|
## Quick start
|
||||||
|
|
||||||
Install in your existing app using `yarn` or `npm`:
|
The easiest way to get started with React Native for Web is to use this
|
||||||
|
[ready-to-go project on Glitch](https://glitch.com/edit/#!/react-native-web-playground).
|
||||||
|
You don’t need to install anything to try it out.
|
||||||
|
|
||||||
```
|
If you are unfamiliar with setting up a React web project, please follow the
|
||||||
yarn add react react-dom react-native-web
|
recommendations in the [React documentation](https://reactjs.org/).
|
||||||
```
|
|
||||||
|
|
||||||
Add the `react-native-web/babel` plugin to your Babel configuration. This will
|
|
||||||
alias `react-native` to `react-native-web` and exclude any modules not required
|
|
||||||
by the app.
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"plugins": [
|
|
||||||
"react-native-web/babel"
|
|
||||||
],
|
|
||||||
"presets": [
|
|
||||||
"react-native"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
(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
|
## Documentation
|
||||||
|
|
||||||
The [interactive
|
You can find the React Native for Web API documentation [on the
|
||||||
documentation](https://necolas.github.io/react-native-web/storybook/) shows all
|
website][website-url].
|
||||||
the supported APIs and Components.
|
|
||||||
|
|
||||||
Guides:
|
Please refer to the [React Native documentation][react-native-url] for more
|
||||||
|
design details, and for information about the [Gesture Responder
|
||||||
|
system](https://facebook.github.io/react-native/docs/gesture-responder-system.html)
|
||||||
|
and [animations](https://facebook.github.io/react-native/docs/animations.html).
|
||||||
|
|
||||||
* [Getting started](docs/guides/getting-started.md)
|
### Installation
|
||||||
* [Style](docs/guides/style.md)
|
|
||||||
* [Accessibility](docs/guides/accessibility.md)
|
|
||||||
* [Direct manipulation](docs/guides/direct-manipulation.md)
|
|
||||||
* [Internationalization](docs/guides/internationalization.md)
|
|
||||||
* [Advanced use](docs/guides/advanced.md)
|
|
||||||
* [Known issues](docs/guides/known-issues.md)
|
|
||||||
|
|
||||||
## Example code
|
Install using `yarn` or `npm`:
|
||||||
|
|
||||||
```js
|
```
|
||||||
import React from 'react'
|
yarn add react react-dom react-native-web
|
||||||
import { AppRegistry, Image, StyleSheet, Text, View } from 'react-native'
|
yarn add --dev babel-plugin-react-native-web
|
||||||
|
|
||||||
// Components
|
|
||||||
const Card = ({ children }) => <View style={styles.card}>{children}</View>
|
|
||||||
const Title = ({ children }) => <Text style={styles.title}>{children}</Text>
|
|
||||||
const Photo = ({ uri }) => <Image source={{ uri }} style={styles.image} />
|
|
||||||
const App = () => (
|
|
||||||
<Card>
|
|
||||||
<Title>App Card</Title>
|
|
||||||
<Photo uri="/some-photo.jpg" />
|
|
||||||
</Card>
|
|
||||||
)
|
|
||||||
|
|
||||||
// Styles
|
|
||||||
const styles = StyleSheet.create({
|
|
||||||
card: {
|
|
||||||
flexGrow: 1,
|
|
||||||
justifyContent: 'center'
|
|
||||||
},
|
|
||||||
title: {
|
|
||||||
fontSize: '1.25rem',
|
|
||||||
fontWeight: 'bold'
|
|
||||||
},
|
|
||||||
image: {
|
|
||||||
height: 40,
|
|
||||||
marginVertical: 10,
|
|
||||||
width: 40
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// App registration and rendering
|
|
||||||
AppRegistry.registerComponent('MyApp', () => App)
|
|
||||||
AppRegistry.runApplication('MyApp', { rootTag: document.getElementById('react-root') })
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Starter kits
|
### Guides
|
||||||
|
|
||||||
* [Glitch](https://glitch.com/edit/#!/react-native-web-playground)
|
* [Getting started](website/guides/getting-started.md)
|
||||||
* [create-react-app](https://github.com/facebookincubator/create-react-app)
|
* [Style](website/guides/style.md)
|
||||||
* [re-start](https://github.com/react-everywhere/re-start)
|
* [Accessibility](website/guides/accessibility.md)
|
||||||
|
* [Internationalization](website/guides/internationalization.md)
|
||||||
|
* [Direct manipulation](website/guides/direct-manipulation.md)
|
||||||
|
* [Advanced use](website/guides/advanced.md)
|
||||||
|
|
||||||
## Related projects
|
## Examples
|
||||||
|
|
||||||
* [react-primitives](https://github.com/lelandrichardson/react-primitives/)
|
There are several examples [on the website][website-url] and in the [website's
|
||||||
* [react-sketchapp](https://github.com/airbnb/react-sketchapp)
|
source code](./website). Here is an example to get you started:
|
||||||
* [reactxp](https://github.com/microsoft/reactxp)
|
|
||||||
* [react-native-web-player](https://github.com/dabbott/react-native-web-player)
|
```js
|
||||||
|
import React from 'react';
|
||||||
|
import { AppRegistry, StyleSheet, Text, View } from 'react-native';
|
||||||
|
|
||||||
|
class App extends React.Component {
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<View style={styles.box}>
|
||||||
|
<Text style={styles.text}>Hello, world!</Text>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
box: { padding: 10 },
|
||||||
|
text: { fontWeight: 'bold' }
|
||||||
|
});
|
||||||
|
|
||||||
|
AppRegistry.registerComponent('App', () => App);
|
||||||
|
AppRegistry.runApplication('App', { rootTag: document.getElementById('react-root') });
|
||||||
|
```
|
||||||
|
|
||||||
|
This example will render the `App` into a container on the page.
|
||||||
|
|
||||||
|
You'll notice that there is no reference to `react-dom`; the `App` component is
|
||||||
|
defined using the platform-agnostic APIs and Components introduced by React
|
||||||
|
Native. This allows the app to be rendered to web and native platforms.
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
The main purpose of this repository is to help evolve React web and native
|
||||||
|
development towards the platform-agnostic design of React Native, and in the
|
||||||
|
process make it faster and easier to build high-quality experiences for the web
|
||||||
|
with React. Development happens in the open on GitHub, and we are grateful for
|
||||||
|
contributing bugfixes and improvements. Read below to learn how you can take
|
||||||
|
part in improving React Native for Web.
|
||||||
|
|
||||||
|
### Code of conduct
|
||||||
|
|
||||||
|
Facebook has adopted a [Code of Conduct][code-of-conduct] that this project
|
||||||
|
expects all participants to adhere to. Please read the full text so that you
|
||||||
|
can understand what actions will and will not be tolerated.
|
||||||
|
|
||||||
|
### Contributing guide
|
||||||
|
|
||||||
|
Read the [contributing guide][contributing-url] to learn about the
|
||||||
|
development process, how to propose bugfixes and improvements, and how to build
|
||||||
|
and test your changes to React Native for Web.
|
||||||
|
|
||||||
|
### Good first issues
|
||||||
|
|
||||||
|
To help you get you familiar with the contribution process, there is a list of
|
||||||
|
[good first issues][good-first-issue-url] that contain bugs which have a
|
||||||
|
relatively limited scope. This is a great place to get started.
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
React Native for Web is [BSD licensed](LICENSE).
|
React Native for Web is [BSD licensed](./LICENSE).
|
||||||
|
|
||||||
[npm-image]: https://badge.fury.io/js/react-native-web.svg
|
[package-badge]: https://img.shields.io/npm/v/react-native-web.svg?style=flat
|
||||||
[npm-url]: https://npmjs.org/package/react-native-web
|
[package-url]: https://yarnpkg.com/en/package/react-native-web
|
||||||
|
[ci-badge]: https://travis-ci.org/necolas/react-native-web.svg?branch=master
|
||||||
|
[ci-url]: https://travis-ci.org/necolas/react-native-web
|
||||||
|
[website-url]: https://necolas.github.io/react-native-web/storybook/
|
||||||
[react-native-url]: https://facebook.github.io/react-native/
|
[react-native-url]: https://facebook.github.io/react-native/
|
||||||
[travis-image]: https://travis-ci.org/necolas/react-native-web.svg?branch=master
|
[contributing-url]: ./.github/CONTRIBUTING.md
|
||||||
[travis-url]: https://travis-ci.org/necolas/react-native-web
|
[good-first-issue-url]: https://github.com/necolas/react-native-web/labels/good%20first%20issue
|
||||||
|
[code-of-conduct]: https://code.facebook.com/codeofconduct
|
||||||
|
|||||||
@@ -1,161 +0,0 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
||||||
|
|
||||||
exports[`1. Rewrite react-native paths for react-native-web 1`] = `
|
|
||||||
"
|
|
||||||
import { View } from 'react-native';
|
|
||||||
|
|
||||||
↓ ↓ ↓ ↓ ↓ ↓
|
|
||||||
|
|
||||||
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, 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';
|
|
||||||
"
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`3. Rewrite react-native paths for react-native-web 1`] = `
|
|
||||||
"
|
|
||||||
import { createElement, Switch, StyleSheet } from 'react-native';
|
|
||||||
|
|
||||||
↓ ↓ ↓ ↓ ↓ ↓
|
|
||||||
|
|
||||||
import createElement from 'react-native-web/dist/modules/createElement';
|
|
||||||
import Switch from 'react-native-web/dist/components/Switch';
|
|
||||||
import StyleSheet from 'react-native-web/dist/apis/StyleSheet';
|
|
||||||
"
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`4. Rewrite react-native paths for react-native-web 1`] = `
|
|
||||||
"
|
|
||||||
import { InvalidThing, TouchableOpacity } from 'react-native';
|
|
||||||
|
|
||||||
↓ ↓ ↓ ↓ ↓ ↓
|
|
||||||
|
|
||||||
import { InvalidThing } from 'react-native-web';
|
|
||||||
import TouchableOpacity from 'react-native-web/dist/components/Touchable/TouchableOpacity';
|
|
||||||
"
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`5. Rewrite react-native paths for react-native-web 1`] = `
|
|
||||||
"
|
|
||||||
import * as RNW from 'react-native';
|
|
||||||
|
|
||||||
↓ ↓ ↓ ↓ ↓ ↓
|
|
||||||
|
|
||||||
import * as RNW from 'react-native-web';
|
|
||||||
"
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`6. Rewrite react-native paths for react-native-web 1`] = `
|
|
||||||
"
|
|
||||||
const { View } = require('react-native');
|
|
||||||
|
|
||||||
↓ ↓ ↓ ↓ ↓ ↓
|
|
||||||
|
|
||||||
const View = require('react-native-web/dist/components/View');
|
|
||||||
"
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`7. Rewrite react-native paths for react-native-web 1`] = `
|
|
||||||
"
|
|
||||||
let { Switch, Text, View: MyView } = require('react-native');
|
|
||||||
|
|
||||||
↓ ↓ ↓ ↓ ↓ ↓
|
|
||||||
|
|
||||||
let Switch = require('react-native-web/dist/components/Switch');
|
|
||||||
|
|
||||||
let Text = require('react-native-web/dist/components/Text');
|
|
||||||
|
|
||||||
let MyView = require('react-native-web/dist/components/View');
|
|
||||||
"
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`8. Rewrite react-native paths for react-native-web 1`] = `
|
|
||||||
"
|
|
||||||
var { createElement, Switch, StyleSheet } = require('react-native');
|
|
||||||
|
|
||||||
↓ ↓ ↓ ↓ ↓ ↓
|
|
||||||
|
|
||||||
var createElement = require('react-native-web/dist/modules/createElement');
|
|
||||||
|
|
||||||
var Switch = require('react-native-web/dist/components/Switch');
|
|
||||||
|
|
||||||
var StyleSheet = require('react-native-web/dist/apis/StyleSheet');
|
|
||||||
"
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`9. Rewrite react-native paths for react-native-web 1`] = `
|
|
||||||
"
|
|
||||||
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';
|
|
||||||
"
|
|
||||||
`;
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
const plugin = require('..');
|
|
||||||
const pluginTester = require('babel-plugin-tester');
|
|
||||||
|
|
||||||
pluginTester({
|
|
||||||
plugin,
|
|
||||||
snapshot: true,
|
|
||||||
tests: [
|
|
||||||
// import react-native
|
|
||||||
"import { View } 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';",
|
|
||||||
|
|
||||||
// import react-native-web
|
|
||||||
// "import { View } from 'react-native-web';",
|
|
||||||
// "import { Switch, Text, View as MyView } from 'react-native-web';",
|
|
||||||
// "import { createElement, Switch, StyleSheet } from 'react-native-web';",
|
|
||||||
// "import { InvalidThing, TouchableOpacity } from 'react-native-web';",
|
|
||||||
// "import * as RNW from 'react-native-web';",
|
|
||||||
|
|
||||||
// require react-native
|
|
||||||
"const { View } = require('react-native');",
|
|
||||||
"let { Switch, Text, View: MyView } = require('react-native');",
|
|
||||||
"var { createElement, Switch, StyleSheet } = require('react-native');",
|
|
||||||
"const { InvalidThing, TouchableOpacity } = require('react-native');",
|
|
||||||
|
|
||||||
// require react-native-web
|
|
||||||
// "const { View } = require('react-native-web');",
|
|
||||||
// "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');",
|
|
||||||
snapshot: false
|
|
||||||
}
|
|
||||||
]
|
|
||||||
});
|
|
||||||
181
babel/index.js
181
babel/index.js
@@ -1,181 +0,0 @@
|
|||||||
const getDistLocation = importName => {
|
|
||||||
const root = 'react-native-web/dist';
|
|
||||||
|
|
||||||
switch (importName) {
|
|
||||||
// apis
|
|
||||||
case 'Animated':
|
|
||||||
case 'AppRegistry':
|
|
||||||
case 'AppState':
|
|
||||||
case 'AsyncStorage':
|
|
||||||
case 'BackHandler':
|
|
||||||
case 'Clipboard':
|
|
||||||
case 'Dimensions':
|
|
||||||
case 'Easing':
|
|
||||||
case 'I18nManager':
|
|
||||||
case 'InteractionManager':
|
|
||||||
case 'Keyboard':
|
|
||||||
case 'Linking':
|
|
||||||
case 'NetInfo':
|
|
||||||
case 'PanResponder':
|
|
||||||
case 'PixelRatio':
|
|
||||||
case 'Platform':
|
|
||||||
case 'StyleSheet':
|
|
||||||
case 'UIManager':
|
|
||||||
case 'Vibration': {
|
|
||||||
return `${root}/apis/${importName}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
// components
|
|
||||||
case 'ActivityIndicator':
|
|
||||||
case 'Button':
|
|
||||||
case 'FlatList':
|
|
||||||
case 'Image':
|
|
||||||
case 'KeyboardAvoidingView':
|
|
||||||
case 'ListView':
|
|
||||||
case 'Modal':
|
|
||||||
case 'Picker':
|
|
||||||
case 'ProgressBar':
|
|
||||||
case 'RefreshControl':
|
|
||||||
case 'ScrollView':
|
|
||||||
case 'SectionList':
|
|
||||||
case 'Slider':
|
|
||||||
case 'StatusBar':
|
|
||||||
case 'Switch':
|
|
||||||
case 'Text':
|
|
||||||
case 'TextInput':
|
|
||||||
case 'View':
|
|
||||||
case 'VirtualizedList': {
|
|
||||||
return `${root}/components/${importName}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
case 'Touchable':
|
|
||||||
case 'TouchableHighlight':
|
|
||||||
case 'TouchableNativeFeedback':
|
|
||||||
case 'TouchableOpacity':
|
|
||||||
case 'TouchableWithoutFeedback': {
|
|
||||||
return `${root}/components/Touchable/${importName}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
// modules
|
|
||||||
case 'createElement':
|
|
||||||
case 'findNodeHandle':
|
|
||||||
case 'NativeModules':
|
|
||||||
case 'processColor':
|
|
||||||
case 'render':
|
|
||||||
case 'unmountComponentAtNode': {
|
|
||||||
return `${root}/modules/${importName}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
// propTypes
|
|
||||||
case 'ColorPropType':
|
|
||||||
case 'EdgeInsetsPropType':
|
|
||||||
case 'PointPropType': {
|
|
||||||
return `${root}/propTypes/${importName}`;
|
|
||||||
}
|
|
||||||
case 'TextPropTypes': {
|
|
||||||
return `${root}/components/Text/${importName}`;
|
|
||||||
}
|
|
||||||
case 'ViewPropTypes': {
|
|
||||||
return `${root}/components/View/${importName}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const isReactNativeRequire = (t, node) => {
|
|
||||||
const { declarations } = node;
|
|
||||||
if (declarations.length > 1) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
const { id, init } = declarations[0];
|
|
||||||
return (
|
|
||||||
t.isObjectPattern(id) &&
|
|
||||||
t.isCallExpression(init) &&
|
|
||||||
t.isIdentifier(init.callee) &&
|
|
||||||
init.callee.name === 'require' &&
|
|
||||||
init.arguments.length === 1 &&
|
|
||||||
init.arguments[0].value === 'react-native'
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = function({ types: t }) {
|
|
||||||
return {
|
|
||||||
name: 'Rewrite react-native paths for react-native-web',
|
|
||||||
visitor: {
|
|
||||||
ImportDeclaration(path) {
|
|
||||||
const { source, specifiers } = path.node;
|
|
||||||
if (source && source.value === 'react-native' && specifiers.length) {
|
|
||||||
const imports = specifiers
|
|
||||||
.map(specifier => {
|
|
||||||
if (t.isImportSpecifier(specifier)) {
|
|
||||||
const importName = specifier.imported.name;
|
|
||||||
const distLocation = getDistLocation(importName);
|
|
||||||
|
|
||||||
if (distLocation) {
|
|
||||||
return t.importDeclaration(
|
|
||||||
[t.importDefaultSpecifier(t.identifier(specifier.local.name))],
|
|
||||||
t.stringLiteral(distLocation)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return t.importDeclaration([specifier], t.stringLiteral('react-native-web'));
|
|
||||||
})
|
|
||||||
.filter(Boolean);
|
|
||||||
|
|
||||||
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];
|
|
||||||
const imports = id.properties
|
|
||||||
.map(identifier => {
|
|
||||||
const distLocation = getDistLocation(identifier.key.name);
|
|
||||||
if (distLocation) {
|
|
||||||
return t.variableDeclaration(path.node.kind, [
|
|
||||||
t.variableDeclarator(
|
|
||||||
t.identifier(identifier.value.name),
|
|
||||||
t.callExpression(t.identifier('require'), [t.stringLiteral(distLocation)])
|
|
||||||
)
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.filter(Boolean);
|
|
||||||
|
|
||||||
path.replaceWithMultiple(imports);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
# Performance
|
|
||||||
|
|
||||||
To run these benchmarks:
|
|
||||||
|
|
||||||
```
|
|
||||||
npm run build:performance
|
|
||||||
open ./performance/index.html
|
|
||||||
```
|
|
||||||
|
|
||||||
Append `?fastest` to the URL to include the fastest "other libraries", and
|
|
||||||
`?all` to include all the "other libraries".
|
|
||||||
|
|
||||||
## Notes
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
## Benchmark results
|
|
||||||
|
|
||||||
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` |
|
|
||||||
|
|
||||||
Other libraries
|
|
||||||
|
|
||||||
| 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` |
|
|
||||||
|
|
||||||
These results indicate that style render performance is not a significant
|
|
||||||
differentiating factor between `aphrodite`, `css-modules`, `react-native-web`,
|
|
||||||
and `styletron`.
|
|
||||||
|
|
||||||
*MacBook Pro (13-inch, Early 2015); 3.1 GHz Intel Core i7; 16 GB 1867 MHz DDR3. Google Chrome 58 (2x CPU slowdown).
|
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
import aphrodite from './src/aphrodite';
|
|
||||||
import cssModules from './src/css-modules';
|
|
||||||
import emotion from './src/emotion';
|
|
||||||
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 styletron from './src/styletron';
|
|
||||||
import xp from './src/reactxp';
|
|
||||||
|
|
||||||
import renderDeepTree from './tests/renderDeepTree';
|
|
||||||
import renderTweet from './tests/renderTweet';
|
|
||||||
import renderWideTree from './tests/renderWideTree';
|
|
||||||
|
|
||||||
const testAll = window.location.search === '?all';
|
|
||||||
const testFastest = window.location.search === '?fastest';
|
|
||||||
|
|
||||||
const coreTests = [
|
|
||||||
() => renderTweet('react-native-web', reactNative),
|
|
||||||
|
|
||||||
() => 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)
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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('styled-components', styledComponents),
|
|
||||||
() => renderWideTree('styled-components', styledComponents)
|
|
||||||
];
|
|
||||||
|
|
||||||
const tests = [...coreTests];
|
|
||||||
if (testFastest) {
|
|
||||||
tests.push(...fastestTests);
|
|
||||||
}
|
|
||||||
if (testAll) {
|
|
||||||
tests.push(...fastestTests);
|
|
||||||
tests.push(...restTests);
|
|
||||||
}
|
|
||||||
|
|
||||||
// run benchmarks
|
|
||||||
tests.reduce((promise, test) => promise.then(test()), Promise.resolve());
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "benchmarks",
|
|
||||||
"private": true,
|
|
||||||
"dependencies": {
|
|
||||||
"aphrodite": "^1.2.5",
|
|
||||||
"classnames": "^2.2.5",
|
|
||||||
"emotion": "^8.0.9",
|
|
||||||
"glamor": "^2.20.40",
|
|
||||||
"marky": "^1.2.0",
|
|
||||||
"radium": "^0.19.6",
|
|
||||||
"react-jss": "^7.2.0",
|
|
||||||
"react-primitives": "^0.4.3",
|
|
||||||
"reactxp": "^0.42.11",
|
|
||||||
"styled-components": "^2.2.3",
|
|
||||||
"styletron-client": "^2.5.7",
|
|
||||||
"styletron-utils": "^2.5.4"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"css-loader": "^0.28.7",
|
|
||||||
"style-loader": "^0.19.0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
import Box from './components/Box/aphrodite';
|
|
||||||
import View from './components/View/aphrodite';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
Box,
|
|
||||||
View
|
|
||||||
};
|
|
||||||
@@ -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;
|
|
||||||
@@ -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;
|
|
||||||
@@ -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;
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
import Box from './components/Box/css-modules';
|
|
||||||
import View from './components/View/css-modules';
|
|
||||||
|
|
||||||
const api = {
|
|
||||||
Box,
|
|
||||||
View
|
|
||||||
};
|
|
||||||
|
|
||||||
export default api;
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
import Box from './components/Box/emotion';
|
|
||||||
import View from './components/View/emotion';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
Box,
|
|
||||||
View
|
|
||||||
};
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
import Box from './components/Box/glamor';
|
|
||||||
import View from './components/View/glamor';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
Box,
|
|
||||||
View
|
|
||||||
};
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
import Box from './components/Box/jss';
|
|
||||||
import View from './components/View/jss';
|
|
||||||
|
|
||||||
const api = {
|
|
||||||
Box,
|
|
||||||
View
|
|
||||||
};
|
|
||||||
|
|
||||||
export default api;
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
import Box from './components/Box/radium';
|
|
||||||
import View from './components/View/radium';
|
|
||||||
|
|
||||||
const api = {
|
|
||||||
Box,
|
|
||||||
View
|
|
||||||
};
|
|
||||||
|
|
||||||
export default api;
|
|
||||||
9
benchmarks/src/react-native-stylesheet.js
vendored
9
benchmarks/src/react-native-stylesheet.js
vendored
@@ -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;
|
|
||||||
9
benchmarks/src/react-native.js
vendored
9
benchmarks/src/react-native.js
vendored
@@ -1,9 +0,0 @@
|
|||||||
import Box from './components/Box/react-native';
|
|
||||||
import Tweet from './components/Tweet';
|
|
||||||
import { View } from 'react-native';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
Box,
|
|
||||||
Tweet,
|
|
||||||
View
|
|
||||||
};
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
import Box from './components/Box/styled-components';
|
|
||||||
import styled from 'styled-components/primitives';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
Box,
|
|
||||||
View: styled.View
|
|
||||||
};
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
import Box from './components/Box/styled-components';
|
|
||||||
import View from './components/View/styled-components';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
Box,
|
|
||||||
View
|
|
||||||
};
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
import Box from './components/Box/styletron';
|
|
||||||
import View from './components/View/styletron';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
Box,
|
|
||||||
View
|
|
||||||
};
|
|
||||||
1536
benchmarks/yarn.lock
1536
benchmarks/yarn.lock
File diff suppressed because it is too large
Load Diff
@@ -1,31 +0,0 @@
|
|||||||
# Known issues
|
|
||||||
|
|
||||||
## Safari flexbox performance
|
|
||||||
|
|
||||||
Safari version prior to 10.1 can suffer from extremely [poor flexbox
|
|
||||||
performance](https://bugs.webkit.org/show_bug.cgi?id=150445). The recommended
|
|
||||||
way to work around this issue (as used on mobile.twitter.com) is to set
|
|
||||||
`display:block` on Views in your element hierarchy that you know don't need
|
|
||||||
flexbox layout.
|
|
||||||
|
|
||||||
## Missing modules and components
|
|
||||||
|
|
||||||
Not all of the views present on iOS/Android are currently available on Web. We
|
|
||||||
are very much interested in the community's feedback on the next set of modules
|
|
||||||
and views.
|
|
||||||
|
|
||||||
Not all the modules or views for iOS/Android can be implemented on Web. In some
|
|
||||||
cases it will be necessary to use a Web counterpart or to guard the use of a
|
|
||||||
module with `Platform.OS` (e.g. `NativeModules`)
|
|
||||||
|
|
||||||
## Missing component props
|
|
||||||
|
|
||||||
There are properties that do not work across all platforms. All web-specific
|
|
||||||
props are annotated with `(web)` in the documentation.
|
|
||||||
|
|
||||||
## Platform parity
|
|
||||||
|
|
||||||
There are some known issues in React Native where APIs could be made more
|
|
||||||
consistent between platforms. For example, React Native for Web includes
|
|
||||||
`ActivityIndicator` and a horizontal `ProgressBar` for Web use, in anticipation
|
|
||||||
of the convergence between the iOS and Android components in React Native.
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
{
|
|
||||||
"scripts": {
|
|
||||||
"build": "yarn && build-storybook -o ./dist -c ./storybook/.storybook",
|
|
||||||
"start": "start-storybook -p 9001 -c ./storybook/.storybook",
|
|
||||||
"release": "yarn build && git checkout gh-pages && rm -rf ../storybook && mv dist ../storybook && git add -A && git commit -m \"Storybook deploy\" && git push origin gh-pages && git checkout -"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"@storybook/addon-options": "^3.1.6",
|
|
||||||
"@storybook/react": "^3.1.9"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
10
lerna.json
Normal file
10
lerna.json
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"lerna": "2.5.1",
|
||||||
|
"version": "0.3.0",
|
||||||
|
"npmClient": "yarn",
|
||||||
|
"useWorkspaces": true,
|
||||||
|
"packages": [
|
||||||
|
"packages/*",
|
||||||
|
"website"
|
||||||
|
]
|
||||||
|
}
|
||||||
161
package.json
161
package.json
@@ -1,126 +1,71 @@
|
|||||||
{
|
{
|
||||||
"name": "react-native-web",
|
"private": true,
|
||||||
"version": "0.1.13",
|
"name": "react-native-web-monorepo",
|
||||||
"description": "React Native for Web",
|
|
||||||
"main": "dist/index.js",
|
|
||||||
"files": [
|
|
||||||
"babel",
|
|
||||||
"dist",
|
|
||||||
"jest",
|
|
||||||
"src",
|
|
||||||
"!**/__tests__"
|
|
||||||
],
|
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"benchmark": "cd benchmarks && yarn && webpack && open index.html",
|
"benchmark": "cd packages/benchmarks && yarn benchmark",
|
||||||
"build": "yarn clean-dist && yarn compile && webpack --config webpack.config.js --sort-assets-by --progress",
|
"clean": "del ./packages/*/dist",
|
||||||
"clean-dist": "del ./dist && mkdir dist",
|
"compile": "yarn clean && cd packages/react-native-web && babel src --out-dir dist --ignore \"**/__tests__\"",
|
||||||
"compile": "babel src -d dist --ignore *-test.js",
|
"docs:start": "cd website && yarn start",
|
||||||
"docs:build": "cd docs && yarn build",
|
"docs:release": "cd website && yarn release",
|
||||||
"docs:start": "cd docs && yarn && yarn start",
|
|
||||||
"docs:release": "cd docs && yarn release",
|
|
||||||
"flow": "flow",
|
"flow": "flow",
|
||||||
"fmt": "find babel benchmarks docs jest src -name '*.js' | grep -v -E '(node_modules|dist)' | xargs yarn fmt:cmd",
|
"fmt": "find packages scripts types website -name '*.js' | grep -v -E '(node_modules|dist|vendor)' | xargs yarn fmt:cmd",
|
||||||
"fmt:cmd": "prettier --print-width=100 --single-quote --write",
|
"fmt:cmd": "prettier --write",
|
||||||
"jest": "jest",
|
"jest": "jest --config ./scripts/jest/config.js",
|
||||||
"jest:watch": "yarn test -- --watch",
|
"lint": "yarn lint:check --fix",
|
||||||
"lint": "yarn lint:cmd -- babel benchmarks docs jest src",
|
"lint:check": "eslint packages scripts website",
|
||||||
"lint:cmd": "eslint --ignore-path .gitignore --fix",
|
|
||||||
"precommit": "lint-staged",
|
"precommit": "lint-staged",
|
||||||
"release": "yarn lint && yarn test && yarn build && npm publish",
|
"prerelease": "yarn test && yarn compile",
|
||||||
"test": "flow && jest"
|
"release": "node ./scripts/release/publish.js",
|
||||||
},
|
"postrelease": "yarn docs:release",
|
||||||
"babel": {
|
"test": "yarn flow && yarn lint:check && yarn jest"
|
||||||
"presets": [
|
|
||||||
"react-native"
|
|
||||||
],
|
|
||||||
"plugins": [
|
|
||||||
[
|
|
||||||
"transform-react-remove-prop-types",
|
|
||||||
{
|
|
||||||
"mode": "wrap"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"jest": {
|
|
||||||
"testEnvironment": "jsdom",
|
|
||||||
"timers": "fake",
|
|
||||||
"setupFiles": [
|
|
||||||
"raf/polyfill"
|
|
||||||
],
|
|
||||||
"setupTestFrameworkScriptFile": "<rootDir>/jest-setup-framework.js",
|
|
||||||
"snapshotSerializers": [
|
|
||||||
"enzyme-to-json/serializer"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"lint-staged": {
|
|
||||||
"**/*.js": [
|
|
||||||
"fmt:cmd",
|
|
||||||
"git update-index --again",
|
|
||||||
"lint:cmd"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"animated": "^0.2.0",
|
|
||||||
"array-find-index": "^1.0.2",
|
|
||||||
"babel-runtime": "^6.26.0",
|
|
||||||
"create-react-class": "^15.6.2",
|
|
||||||
"debounce": "1.0.2",
|
|
||||||
"deep-assign": "^2.0.0",
|
|
||||||
"fbjs": "^0.8.16",
|
|
||||||
"hyphenate-style-name": "^1.0.2",
|
|
||||||
"inline-style-prefixer": "^3.0.8",
|
|
||||||
"normalize-css-color": "^1.0.2",
|
|
||||||
"prop-types": "^15.6.0",
|
|
||||||
"react-timer-mixin": "^0.13.3"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"babel-cli": "^6.26.0",
|
"babel-cli": "^6.26.0",
|
||||||
"babel-core": "^6.26.0",
|
"babel-core": "^6.26.0",
|
||||||
"babel-eslint": "^7.2.3",
|
"babel-eslint": "^8.0.3",
|
||||||
"babel-loader": "^7.1.2",
|
"babel-loader": "^7.1.2",
|
||||||
"babel-plugin-tester": "^4.0.0",
|
"babel-plugin-transform-class-properties": "^6.24.1",
|
||||||
"babel-plugin-transform-react-remove-prop-types": "^0.4.9",
|
"babel-plugin-transform-object-rest-spread": "^6.26.0",
|
||||||
|
"babel-plugin-transform-react-remove-prop-types": "^0.4.10",
|
||||||
|
"babel-preset-env": "^1.6.1",
|
||||||
|
"babel-preset-flow": "^6.23.0",
|
||||||
|
"babel-preset-react": "^6.24.1",
|
||||||
"babel-preset-react-native": "^4.0.0",
|
"babel-preset-react-native": "^4.0.0",
|
||||||
"caniuse-api": "^2.0.0",
|
"caniuse-api": "^2.0.0",
|
||||||
"del-cli": "^1.1.0",
|
"del-cli": "^1.1.0",
|
||||||
"enzyme": "^3.1.0",
|
"enzyme": "^3.2.0",
|
||||||
"enzyme-adapter-react-16": "^1.0.2",
|
"enzyme-adapter-react-16": "^1.1.0",
|
||||||
"enzyme-to-json": "^3.1.4",
|
"enzyme-to-json": "^3.2.2",
|
||||||
"eslint": "^4.6.1",
|
"eslint": "^4.12.1",
|
||||||
"eslint-config-prettier": "^2.6.0",
|
"eslint-config-prettier": "^2.9.0",
|
||||||
"eslint-plugin-promise": "^3.5.0",
|
"eslint-plugin-promise": "^3.6.0",
|
||||||
"eslint-plugin-react": "^7.4.0",
|
"eslint-plugin-react": "^7.5.1",
|
||||||
"file-loader": "^1.1.4",
|
"flow-bin": "^0.61.0",
|
||||||
"flow-bin": "^0.49.1",
|
"husky": "^0.14.3",
|
||||||
"jest": "^21.2.1",
|
"jest": "^21.2.1",
|
||||||
|
"lerna": "^2.5.1",
|
||||||
"lint-staged": "^4.1.3",
|
"lint-staged": "^4.1.3",
|
||||||
"prettier": "^1.7.3",
|
"prettier": "^1.8.2",
|
||||||
"raf": "^3.3.2",
|
"raf": "^3.4.0",
|
||||||
"react": "^16.0.0",
|
"react": "^16.2.0",
|
||||||
"react-dom": "^16.0.0",
|
"react-dom": "^16.2.0",
|
||||||
"react-test-renderer": "^16.0.0",
|
"react-test-renderer": "^16.2.0"
|
||||||
"url-loader": "^0.5.9",
|
|
||||||
"webpack": "^3.6.0",
|
|
||||||
"webpack-bundle-analyzer": "^2.9.0"
|
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"workspaces": [
|
||||||
"react": "16.x.x",
|
"packages/*",
|
||||||
"react-dom": "16.x.x"
|
"website"
|
||||||
|
],
|
||||||
|
"lint-staged": {
|
||||||
|
"**/*.js": [
|
||||||
|
"fmt:cmd",
|
||||||
|
"git update-index --again",
|
||||||
|
"eslint"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"prettier": {
|
||||||
|
"printWidth": 100,
|
||||||
|
"singleQuote": true
|
||||||
},
|
},
|
||||||
"author": "Nicolas Gallagher",
|
"author": "Nicolas Gallagher",
|
||||||
"license": "BSD-3-Clause",
|
"license": "BSD-3-Clause"
|
||||||
"repository": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "git://github.com/necolas/react-native-web.git"
|
|
||||||
},
|
|
||||||
"tags": [
|
|
||||||
"react"
|
|
||||||
],
|
|
||||||
"keywords": [
|
|
||||||
"react",
|
|
||||||
"react-component",
|
|
||||||
"react-native",
|
|
||||||
"web"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|||||||
39
packages/babel-plugin-react-native-web/README.md
Normal file
39
packages/babel-plugin-react-native-web/README.md
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
# babel-plugin-react-native-web
|
||||||
|
|
||||||
|
A Babel plugin that will alias `react-native` to `react-native-web` and exclude
|
||||||
|
any modules not required by your app (keeping bundle size down).
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
```
|
||||||
|
yarn add --dev babel-plugin-react-native-web
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
**.babelrc**
|
||||||
|
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"plugins": ["react-native-web"]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Example
|
||||||
|
|
||||||
|
NOTE: `react-native-web` internal paths are _not stable_ and you must not rely
|
||||||
|
on them. Always use the Babel plugin to optimize your build. What follows is an
|
||||||
|
example of the rewrite performed by the plugin.
|
||||||
|
|
||||||
|
**Before**
|
||||||
|
|
||||||
|
```js
|
||||||
|
import { StyleSheet, View } from 'react-native';
|
||||||
|
```
|
||||||
|
|
||||||
|
**After**
|
||||||
|
|
||||||
|
```js
|
||||||
|
import StyleSheet from 'react-native-web/dist/apis/StyleSheet';
|
||||||
|
import View from 'react-native-web/dist/components/View';
|
||||||
|
```
|
||||||
1
packages/babel-plugin-react-native-web/index.js
Normal file
1
packages/babel-plugin-react-native-web/index.js
Normal file
@@ -0,0 +1 @@
|
|||||||
|
module.exports = require('./src');
|
||||||
15
packages/babel-plugin-react-native-web/package.json
Normal file
15
packages/babel-plugin-react-native-web/package.json
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"name": "babel-plugin-react-native-web",
|
||||||
|
"version": "0.3.0",
|
||||||
|
"description": "Babel plugin for React Native for Web",
|
||||||
|
"main": "index.js",
|
||||||
|
"devDependencies": {
|
||||||
|
"babel-plugin-tester": "^4.0.0"
|
||||||
|
},
|
||||||
|
"author": "Nicolas Gallagher",
|
||||||
|
"license": "MIT",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git://github.com/necolas/react-native-web.git"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`export from "react-native" 1`] = `
|
||||||
|
"
|
||||||
|
export { View } from 'react-native';
|
||||||
|
export { ColorPropType, StyleSheet, Text, createElement } from 'react-native';
|
||||||
|
|
||||||
|
↓ ↓ ↓ ↓ ↓ ↓
|
||||||
|
|
||||||
|
export { default as View } from 'react-native-web/dist/exports/View';
|
||||||
|
export { default as ColorPropType } from 'react-native-web/dist/exports/ColorPropType';
|
||||||
|
export { default as StyleSheet } from 'react-native-web/dist/exports/StyleSheet';
|
||||||
|
export { default as Text } from 'react-native-web/dist/exports/Text';
|
||||||
|
export { default as createElement } from 'react-native-web/dist/exports/createElement';
|
||||||
|
"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`export from "react-native-web" 1`] = `
|
||||||
|
"
|
||||||
|
export { View } from 'react-native-web';
|
||||||
|
export { ColorPropType, StyleSheet, Text, createElement } from 'react-native-web';
|
||||||
|
|
||||||
|
↓ ↓ ↓ ↓ ↓ ↓
|
||||||
|
|
||||||
|
export { default as View } from 'react-native-web/dist/exports/View';
|
||||||
|
export { default as ColorPropType } from 'react-native-web/dist/exports/ColorPropType';
|
||||||
|
export { default as StyleSheet } from 'react-native-web/dist/exports/StyleSheet';
|
||||||
|
export { default as Text } from 'react-native-web/dist/exports/Text';
|
||||||
|
export { default as createElement } from 'react-native-web/dist/exports/createElement';
|
||||||
|
"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`import from "native-native" 1`] = `
|
||||||
|
"
|
||||||
|
import ReactNative from 'react-native';
|
||||||
|
import { View } from 'react-native';
|
||||||
|
import { Invalid, View as MyView, ViewPropTypes } from 'react-native';
|
||||||
|
import * as ReactNativeModules from 'react-native';
|
||||||
|
|
||||||
|
↓ ↓ ↓ ↓ ↓ ↓
|
||||||
|
|
||||||
|
import ReactNative from 'react-native-web/dist/index';
|
||||||
|
import View from 'react-native-web/dist/exports/View';
|
||||||
|
import Invalid from 'react-native-web/dist/exports/Invalid';
|
||||||
|
import MyView from 'react-native-web/dist/exports/View';
|
||||||
|
import ViewPropTypes from 'react-native-web/dist/exports/ViewPropTypes';
|
||||||
|
import * as ReactNativeModules from 'react-native-web/dist/index';
|
||||||
|
"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`import from "react-native-web" 1`] = `
|
||||||
|
"
|
||||||
|
import { createElement } from 'react-native-web';
|
||||||
|
import { ColorPropType, StyleSheet, View, TouchableOpacity, processColor } from 'react-native-web';
|
||||||
|
import * as ReactNativeModules from 'react-native-web';
|
||||||
|
|
||||||
|
↓ ↓ ↓ ↓ ↓ ↓
|
||||||
|
|
||||||
|
import createElement from 'react-native-web/dist/exports/createElement';
|
||||||
|
import ColorPropType from 'react-native-web/dist/exports/ColorPropType';
|
||||||
|
import StyleSheet from 'react-native-web/dist/exports/StyleSheet';
|
||||||
|
import View from 'react-native-web/dist/exports/View';
|
||||||
|
import TouchableOpacity from 'react-native-web/dist/exports/TouchableOpacity';
|
||||||
|
import processColor from 'react-native-web/dist/exports/processColor';
|
||||||
|
import * as ReactNativeModules from 'react-native-web/dist/index';
|
||||||
|
"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`require "react-native-web" 1`] = `
|
||||||
|
"
|
||||||
|
const ReactNative = require('react-native-web');
|
||||||
|
const { createElement } = require('react-native-web');
|
||||||
|
const { ColorPropType, StyleSheet, View, TouchableOpacity, processColor } = require('react-native-web');
|
||||||
|
|
||||||
|
↓ ↓ ↓ ↓ ↓ ↓
|
||||||
|
|
||||||
|
const ReactNative = require('react-native-web');
|
||||||
|
|
||||||
|
const createElement = require('react-native-web/dist/exports/createElement');
|
||||||
|
|
||||||
|
const ColorPropType = require('react-native-web/dist/exports/ColorPropType');
|
||||||
|
|
||||||
|
const StyleSheet = require('react-native-web/dist/exports/StyleSheet');
|
||||||
|
|
||||||
|
const View = require('react-native-web/dist/exports/View');
|
||||||
|
|
||||||
|
const TouchableOpacity = require('react-native-web/dist/exports/TouchableOpacity');
|
||||||
|
|
||||||
|
const processColor = require('react-native-web/dist/exports/processColor');
|
||||||
|
"
|
||||||
|
`;
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
const plugin = require('..');
|
||||||
|
const pluginTester = require('babel-plugin-tester');
|
||||||
|
|
||||||
|
const tests = [
|
||||||
|
// import react-native
|
||||||
|
{
|
||||||
|
title: 'import from "native-native"',
|
||||||
|
code: `import ReactNative from 'react-native';
|
||||||
|
import { View } from 'react-native';
|
||||||
|
import { Invalid, View as MyView, ViewPropTypes } from 'react-native';
|
||||||
|
import * as ReactNativeModules from 'react-native';`,
|
||||||
|
snapshot: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'import from "react-native-web"',
|
||||||
|
code: `import { createElement } from 'react-native-web';
|
||||||
|
import { ColorPropType, StyleSheet, View, TouchableOpacity, processColor } from 'react-native-web';
|
||||||
|
import * as ReactNativeModules from 'react-native-web';`,
|
||||||
|
snapshot: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'export from "react-native"',
|
||||||
|
code: `export { View } from 'react-native';
|
||||||
|
export { ColorPropType, StyleSheet, Text, createElement } from 'react-native';`,
|
||||||
|
snapshot: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'export from "react-native-web"',
|
||||||
|
code: `export { View } from 'react-native-web';
|
||||||
|
export { ColorPropType, StyleSheet, Text, createElement } from 'react-native-web';`,
|
||||||
|
snapshot: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'require "react-native-web"',
|
||||||
|
code: `const ReactNative = require('react-native-web');
|
||||||
|
const { createElement } = require('react-native-web');
|
||||||
|
const { ColorPropType, StyleSheet, View, TouchableOpacity, processColor } = require('react-native-web');`,
|
||||||
|
snapshot: true
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
pluginTester({
|
||||||
|
plugin,
|
||||||
|
tests
|
||||||
|
});
|
||||||
106
packages/babel-plugin-react-native-web/src/index.js
Normal file
106
packages/babel-plugin-react-native-web/src/index.js
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
const getDistLocation = importName =>
|
||||||
|
importName ? `react-native-web/dist/exports/${importName}` : undefined;
|
||||||
|
|
||||||
|
const isReactNativeRequire = (t, node) => {
|
||||||
|
const { declarations } = node;
|
||||||
|
if (declarations.length > 1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const { id, init } = declarations[0];
|
||||||
|
return (
|
||||||
|
t.isObjectPattern(id) &&
|
||||||
|
t.isCallExpression(init) &&
|
||||||
|
t.isIdentifier(init.callee) &&
|
||||||
|
init.callee.name === 'require' &&
|
||||||
|
init.arguments.length === 1 &&
|
||||||
|
(init.arguments[0].value === 'react-native' || init.arguments[0].value === 'react-native-web')
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const isReactNativeModule = ({ source, specifiers }) =>
|
||||||
|
source &&
|
||||||
|
(source.value === 'react-native' || source.value === 'react-native-web') &&
|
||||||
|
specifiers.length;
|
||||||
|
|
||||||
|
module.exports = function({ types: t }) {
|
||||||
|
return {
|
||||||
|
name: 'Rewrite react-native to react-native-web',
|
||||||
|
visitor: {
|
||||||
|
ImportDeclaration(path, state) {
|
||||||
|
const { specifiers } = path.node;
|
||||||
|
if (isReactNativeModule(path.node)) {
|
||||||
|
const imports = specifiers
|
||||||
|
.map(specifier => {
|
||||||
|
if (t.isImportSpecifier(specifier)) {
|
||||||
|
const importName = specifier.imported.name;
|
||||||
|
const distLocation = getDistLocation(importName);
|
||||||
|
|
||||||
|
if (distLocation) {
|
||||||
|
return t.importDeclaration(
|
||||||
|
[t.importDefaultSpecifier(t.identifier(specifier.local.name))],
|
||||||
|
t.stringLiteral(distLocation)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return t.importDeclaration(
|
||||||
|
[specifier],
|
||||||
|
t.stringLiteral('react-native-web/dist/index')
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.filter(Boolean);
|
||||||
|
|
||||||
|
path.replaceWithMultiple(imports);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
ExportNamedDeclaration(path, state) {
|
||||||
|
const { specifiers } = path.node;
|
||||||
|
if (isReactNativeModule(path.node)) {
|
||||||
|
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/dist/index')
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.filter(Boolean);
|
||||||
|
|
||||||
|
path.replaceWithMultiple(exports);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
VariableDeclaration(path, state) {
|
||||||
|
if (isReactNativeRequire(t, path.node)) {
|
||||||
|
const { id } = path.node.declarations[0];
|
||||||
|
const imports = id.properties
|
||||||
|
.map(identifier => {
|
||||||
|
const distLocation = getDistLocation(identifier.key.name);
|
||||||
|
if (distLocation) {
|
||||||
|
return t.variableDeclaration(path.node.kind, [
|
||||||
|
t.variableDeclarator(
|
||||||
|
t.identifier(identifier.value.name),
|
||||||
|
t.callExpression(t.identifier('require'), [t.stringLiteral(distLocation)])
|
||||||
|
)
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.filter(Boolean);
|
||||||
|
|
||||||
|
path.replaceWithMultiple(imports);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
56
packages/benchmarks/README.md
Normal file
56
packages/benchmarks/README.md
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
# benchmarks
|
||||||
|
|
||||||
|
To run these benchmarks:
|
||||||
|
|
||||||
|
```
|
||||||
|
yarn benchmark
|
||||||
|
```
|
||||||
|
|
||||||
|
To run benchmarks for individual implementations append `?<name>,<name>` to the
|
||||||
|
URL, e.g., `?css-modules,react-native-web`.
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
These benchmarks are crude approximations of extreme cases that libraries may
|
||||||
|
encounter. The deep and wide tree cases look at the performance of mounting and
|
||||||
|
rendering large trees of styled elements. The Triangle case looks at the
|
||||||
|
performance of repeated style updates to a large mounted tree. Some libraries
|
||||||
|
must inject new styles for each "dynamic style", whereas others may not.
|
||||||
|
Libraries without support for dynamic styles (i.e., they rely on user-authored
|
||||||
|
inline styles) do not include the `SierpinskiTriangle` benchmark.
|
||||||
|
|
||||||
|
The components used in the render benchmarks are simple enough to be
|
||||||
|
implemented by multiple UI or style libraries. The benchmark implementations
|
||||||
|
and the features of the style libraries are _only approximately equivalent in
|
||||||
|
functionality_.
|
||||||
|
|
||||||
|
## Results
|
||||||
|
|
||||||
|
Typical render timings*: mean ± two standard deviations.
|
||||||
|
|
||||||
|
| Implementation | Deep tree (ms) | Wide tree (ms) | Triangle (ms) |
|
||||||
|
| :--- | ---: | ---: | ---: |
|
||||||
|
| `react-native-web@0.2.2` | `89.67` `±28.51` | `167.46` `±27.03` | `65.40` `±19.50` |
|
||||||
|
| `css-modules` | `77.42` `±45.50` | `141.44` `±33.96` | - |
|
||||||
|
| `inline-styles` | `236.25` `±95.57` | `477.01` `±88.30` | `40.95` `±23.53` |
|
||||||
|
|
||||||
|
Other libraries
|
||||||
|
|
||||||
|
| Implementation | Deep tree (ms) | Wide tree (ms) | Triangle (ms) |
|
||||||
|
| :--- | ---: | ---: | ---: |
|
||||||
|
| `styletron@3.0.0-rc.5` | `83.53` `±33.55` | `153.12` `±39.13` | `56.47` `±24.22` |
|
||||||
|
| `aphrodite@1.2.5` | `88.23` `±31.22` | `164.03` `±34.70` | - |
|
||||||
|
| `glamor@2.20.40` | `110.09` `±34.20` | `182.06` `±50.39` | ‡ |
|
||||||
|
| `emotion@8.0.12` | `103.44` `±32.12` | `204.45` `±41.00` | `110.28` `±26.94` |
|
||||||
|
| `react-jss@8.2.0` | `136.17` `±59.23` | `270.51` `±69.20` | - |
|
||||||
|
| `styled-components@2.3.2` | `217.57` `±51.90` | `437.57` `±65.74` | `76.99` `±41.79` |
|
||||||
|
| `reactxp@0.46.6` | `240.88` `±79.82` | `467.32` `±74.42` | `70.95` `±32.90`|
|
||||||
|
| `radium@0.19.6` | `400.19` `±94.58` | `816.59` `±91.10` | `71.13` `±27.22` |
|
||||||
|
|
||||||
|
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 2011); 2.3 GHz Intel Core i5; 8 GB 1333 MHz DDR3. Google Chrome 62.
|
||||||
|
|
||||||
|
‡Glamor essentially crashes the browser tab.
|
||||||
33
packages/benchmarks/package.json
Normal file
33
packages/benchmarks/package.json
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
{
|
||||||
|
"private": true,
|
||||||
|
"name": "benchmarks",
|
||||||
|
"version": "0.3.0",
|
||||||
|
"scripts": {
|
||||||
|
"benchmark": "webpack --config ./webpack.config.js && open index.html"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"aphrodite": "^1.2.5",
|
||||||
|
"babel-polyfill": "^6.26.0",
|
||||||
|
"classnames": "^2.2.5",
|
||||||
|
"d3-scale-chromatic": "^1.1.1",
|
||||||
|
"emotion": "^8.0.12",
|
||||||
|
"glamor": "^2.20.40",
|
||||||
|
"marky": "^1.2.0",
|
||||||
|
"radium": "^0.19.6",
|
||||||
|
"react": "^16.2.0",
|
||||||
|
"react-dom": "^16.2.0",
|
||||||
|
"react-jss": "^8.2.0",
|
||||||
|
"react-native-web": "^0.3.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": {
|
||||||
|
"babel-plugin-react-native-web": "^0.3.0",
|
||||||
|
"css-loader": "^0.28.7",
|
||||||
|
"style-loader": "^0.19.1",
|
||||||
|
"webpack": "^3.10.0",
|
||||||
|
"webpack-bundle-analyzer": "^2.9.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -38,30 +38,31 @@ const standardDeviation = values => {
|
|||||||
return Math.sqrt(meanSquareDiff);
|
return Math.sqrt(meanSquareDiff);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const log = (name, description, durations) => {
|
||||||
|
const stdDev = standardDeviation(durations);
|
||||||
|
const formattedMean = fmt(mean(durations));
|
||||||
|
const formattedMedian = fmt(median(durations));
|
||||||
|
const formattedStdDev = fmt(stdDev);
|
||||||
|
|
||||||
|
console.groupCollapsed(`${name}\n${formattedMean} ±${fmt(2 * stdDev)}`);
|
||||||
|
description && console.log(description);
|
||||||
|
console.log(`Median: ${formattedMedian}`);
|
||||||
|
console.log(`Mean: ${formattedMean}`);
|
||||||
|
console.log(`Standard deviation: ${formattedStdDev}`);
|
||||||
|
console.log(durations);
|
||||||
|
console.groupEnd();
|
||||||
|
};
|
||||||
|
|
||||||
const benchmark = ({ name, description, setup, teardown, task, runs }) => {
|
const benchmark = ({ name, description, setup, teardown, task, runs }) => {
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
const durations = [];
|
const durations = [];
|
||||||
let i = 0;
|
let i = 0;
|
||||||
|
|
||||||
setup();
|
setup();
|
||||||
const first = measure('first', task);
|
|
||||||
teardown();
|
teardown();
|
||||||
|
|
||||||
const done = () => {
|
const done = () => {
|
||||||
const stdDev = standardDeviation(durations);
|
log(name, description, durations);
|
||||||
const formattedFirst = fmt(first);
|
|
||||||
const formattedMean = fmt(mean(durations));
|
|
||||||
const formattedMedian = fmt(median(durations));
|
|
||||||
const formattedStdDev = fmt(stdDev);
|
|
||||||
|
|
||||||
console.groupCollapsed(`${name}\n${formattedMean} ±${fmt(2 * stdDev)}`);
|
|
||||||
description && console.log(description);
|
|
||||||
console.log(`First: ${formattedFirst}`);
|
|
||||||
console.log(`Median: ${formattedMedian}`);
|
|
||||||
console.log(`Mean: ${formattedMean}`);
|
|
||||||
console.log(`Standard deviation: ${formattedStdDev}`);
|
|
||||||
console.log(durations);
|
|
||||||
console.groupEnd();
|
|
||||||
resolve();
|
resolve();
|
||||||
};
|
};
|
||||||
|
|
||||||
84
packages/benchmarks/src/cases/SierpinskiTriangle.js
Normal file
84
packages/benchmarks/src/cases/SierpinskiTriangle.js
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import React from 'react';
|
||||||
|
import { interpolatePurples, interpolateBuPu, interpolateRdPu } from 'd3-scale-chromatic';
|
||||||
|
|
||||||
|
const targetSize = 25;
|
||||||
|
|
||||||
|
class SierpinskiTriangle extends React.Component {
|
||||||
|
static propTypes = {
|
||||||
|
Dot: PropTypes.node,
|
||||||
|
depth: PropTypes.number,
|
||||||
|
renderCount: PropTypes.number,
|
||||||
|
s: PropTypes.number,
|
||||||
|
x: PropTypes.number,
|
||||||
|
y: PropTypes.number
|
||||||
|
};
|
||||||
|
|
||||||
|
static defaultProps = {
|
||||||
|
depth: 0,
|
||||||
|
renderCount: 0
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { x, y, depth, renderCount, Dot } = this.props;
|
||||||
|
let { s } = this.props;
|
||||||
|
|
||||||
|
if (s <= targetSize) {
|
||||||
|
let fn;
|
||||||
|
switch (depth) {
|
||||||
|
case 1:
|
||||||
|
fn = interpolatePurples;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
fn = interpolateBuPu;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
default:
|
||||||
|
fn = interpolateRdPu;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dot
|
||||||
|
color={fn(renderCount / 20)}
|
||||||
|
size={targetSize}
|
||||||
|
x={x - targetSize / 2}
|
||||||
|
y={y - targetSize / 2}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
s /= 2;
|
||||||
|
|
||||||
|
return [
|
||||||
|
<SierpinskiTriangle
|
||||||
|
Dot={Dot}
|
||||||
|
depth={1}
|
||||||
|
key={1}
|
||||||
|
renderCount={renderCount}
|
||||||
|
s={s}
|
||||||
|
x={x}
|
||||||
|
y={y - s / 2}
|
||||||
|
/>,
|
||||||
|
<SierpinskiTriangle
|
||||||
|
Dot={Dot}
|
||||||
|
depth={2}
|
||||||
|
key={2}
|
||||||
|
renderCount={renderCount}
|
||||||
|
s={s}
|
||||||
|
x={x - s}
|
||||||
|
y={y + s / 2}
|
||||||
|
/>,
|
||||||
|
<SierpinskiTriangle
|
||||||
|
Dot={Dot}
|
||||||
|
depth={3}
|
||||||
|
key={3}
|
||||||
|
renderCount={renderCount}
|
||||||
|
s={s}
|
||||||
|
x={x + s}
|
||||||
|
y={y + s / 2}
|
||||||
|
/>
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SierpinskiTriangle;
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
import createRenderBenchmark from '../createRenderBenchmark';
|
import createRenderBenchmark from '../createRenderBenchmark';
|
||||||
import NestedTree from '../src/components/NestedTree';
|
import NestedTree from './NestedTree';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
const renderDeepTree = (label, components) =>
|
const renderDeepTree = (label, components) =>
|
||||||
createRenderBenchmark({
|
createRenderBenchmark({
|
||||||
name: `Deep tree [${label}]`,
|
name: `[${label}] Deep tree`,
|
||||||
runs: 20,
|
runs: 20,
|
||||||
getElement() {
|
getElement() {
|
||||||
return <NestedTree breadth={3} components={components} depth={6} id={0} wrap={1} />;
|
return <NestedTree breadth={3} components={components} depth={6} id={0} wrap={1} />;
|
||||||
112
packages/benchmarks/src/cases/renderSierpinskiTriangle.js
Normal file
112
packages/benchmarks/src/cases/renderSierpinskiTriangle.js
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import ReactDOM from 'react-dom';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import SierpinskiTriangle from './SierpinskiTriangle';
|
||||||
|
import { log } from '../benchmark';
|
||||||
|
|
||||||
|
const node = document.querySelector('.root');
|
||||||
|
|
||||||
|
let runs = 20;
|
||||||
|
|
||||||
|
class Speedometer extends React.Component {
|
||||||
|
/* necessary for reactxp to work without errors */
|
||||||
|
static childContextTypes = {
|
||||||
|
focusManager: PropTypes.object
|
||||||
|
};
|
||||||
|
getChildContext() {
|
||||||
|
return {
|
||||||
|
focusManager: {
|
||||||
|
addFocusableComponent() {},
|
||||||
|
removeFocusableComponent() {},
|
||||||
|
restrictFocusWithin() {},
|
||||||
|
removeFocusRestriction() {},
|
||||||
|
limitFocusWithin() {},
|
||||||
|
removeFocusLimitation() {}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
Dot: PropTypes.node.isRequired,
|
||||||
|
description: PropTypes.string,
|
||||||
|
name: PropTypes.string.isRequired,
|
||||||
|
onComplete: PropTypes.node.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
state = { renderCount: -1 };
|
||||||
|
|
||||||
|
async componentDidMount() {
|
||||||
|
const durations = [];
|
||||||
|
|
||||||
|
while ((runs -= 1)) {
|
||||||
|
const prev = window.performance.now();
|
||||||
|
await new Promise(resolve => {
|
||||||
|
this.raf = window.requestAnimationFrame(() => {
|
||||||
|
this.setState({ renderCount: this.state.renderCount + 1 }, () => {
|
||||||
|
const now = window.performance.now();
|
||||||
|
durations.push(now - prev);
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const { description, name } = this.props;
|
||||||
|
log(name, description, durations);
|
||||||
|
|
||||||
|
runs = 20;
|
||||||
|
this.props.onComplete();
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
window.cancelAnimationFrame(this.raf);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div style={styles.wrapper}>
|
||||||
|
<SierpinskiTriangle
|
||||||
|
Dot={this.props.Dot}
|
||||||
|
renderCount={this.state.renderCount}
|
||||||
|
s={1000}
|
||||||
|
x={0}
|
||||||
|
y={0}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = {
|
||||||
|
wrapper: {
|
||||||
|
position: 'absolute',
|
||||||
|
transformOrigin: '0 0',
|
||||||
|
left: '50%',
|
||||||
|
top: '50%',
|
||||||
|
width: '10px',
|
||||||
|
height: '10px',
|
||||||
|
backgroundColor: '#eee',
|
||||||
|
transform: 'scale(0.33)'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const renderSierpinskiTriangle = (name, { Dot }) => () => {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
/* eslint-disable react/jsx-no-bind */
|
||||||
|
ReactDOM.render(
|
||||||
|
<Speedometer
|
||||||
|
Dot={Dot}
|
||||||
|
description="Dynamic styles"
|
||||||
|
name={`[${name}] Triangle`}
|
||||||
|
onComplete={() => {
|
||||||
|
ReactDOM.unmountComponentAtNode(node);
|
||||||
|
resolve();
|
||||||
|
}}
|
||||||
|
/>,
|
||||||
|
node
|
||||||
|
);
|
||||||
|
/* eslint-enable react/jsx-no-bind */
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export default renderSierpinskiTriangle;
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
import createRenderBenchmark from '../createRenderBenchmark';
|
import createRenderBenchmark from '../createRenderBenchmark';
|
||||||
import Tweet from '../src/components/Tweet';
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
const tweet1 = {
|
const tweet1 = {
|
||||||
@@ -96,9 +95,9 @@ const tweet2 = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const renderTweet = label =>
|
const renderTweet = (label, { Tweet }) =>
|
||||||
createRenderBenchmark({
|
createRenderBenchmark({
|
||||||
name: `Tweet [${label}]`,
|
name: `[${label}] Tweet`,
|
||||||
runs: 10,
|
runs: 10,
|
||||||
getElement() {
|
getElement() {
|
||||||
return (
|
return (
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
import createRenderBenchmark from '../createRenderBenchmark';
|
import createRenderBenchmark from '../createRenderBenchmark';
|
||||||
import NestedTree from '../src/components/NestedTree';
|
import NestedTree from './NestedTree';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
const renderWideTree = (label, components) =>
|
const renderWideTree = (label, components) =>
|
||||||
createRenderBenchmark({
|
createRenderBenchmark({
|
||||||
name: `Wide tree [${label}]`,
|
name: `[${label}] Wide tree`,
|
||||||
runs: 20,
|
runs: 20,
|
||||||
getElement() {
|
getElement() {
|
||||||
return <NestedTree breadth={10} components={components} depth={3} id={0} wrap={4} />;
|
return <NestedTree breadth={10} components={components} depth={3} id={0} wrap={4} />;
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
/* eslint-disable react/prop-types */
|
/* eslint-disable react/prop-types */
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import View from '../View/aphrodite';
|
import View from './View';
|
||||||
import { StyleSheet } from 'aphrodite';
|
import { StyleSheet } from 'aphrodite';
|
||||||
|
|
||||||
const Box = ({ color, fixed = false, layout = 'column', outer = false, ...other }) => (
|
const Box = ({ color, fixed = false, layout = 'column', outer = false, ...other }) => (
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
import Box from './Box';
|
||||||
|
import View from './View';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
Box,
|
||||||
|
View
|
||||||
|
};
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
/* eslint-disable react/prop-types */
|
/* eslint-disable react/prop-types */
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import View from '../View/css-modules';
|
import View from './View';
|
||||||
import styles from './styles.css';
|
import styles from './box-styles.css';
|
||||||
|
|
||||||
const Box = ({ color, fixed = false, layout = 'column', outer = false, ...other }) => (
|
const Box = ({ color, fixed = false, layout = 'column', outer = false, ...other }) => (
|
||||||
<View
|
<View
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
/* eslint-disable react/prop-types */
|
/* eslint-disable react/prop-types */
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import styles from './styles.css';
|
import styles from './view-styles.css';
|
||||||
|
|
||||||
class View extends React.Component {
|
class View extends React.Component {
|
||||||
render() {
|
render() {
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
import Box from './Box';
|
||||||
|
import View from './View';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
Box,
|
||||||
|
View
|
||||||
|
};
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
/* eslint-disable react/prop-types */
|
/* eslint-disable react/prop-types */
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import View from '../View/glamor';
|
import View from './View';
|
||||||
|
|
||||||
const Box = ({ color, fixed = false, layout = 'column', outer = false, ...other }) => (
|
const Box = ({ color, fixed = false, layout = 'column', outer = false, ...other }) => (
|
||||||
<View
|
<View
|
||||||
32
packages/benchmarks/src/implementations/emotion/Dot.js
Normal file
32
packages/benchmarks/src/implementations/emotion/Dot.js
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
/* eslint-disable react/prop-types */
|
||||||
|
import React from 'react';
|
||||||
|
import { css } from 'emotion';
|
||||||
|
|
||||||
|
const Dot = ({ size, x, y, children, color }) => (
|
||||||
|
<div
|
||||||
|
className={css(styles.root, {
|
||||||
|
borderBottomColor: color,
|
||||||
|
borderRightWidth: `${size / 2}px`,
|
||||||
|
borderBottomWidth: `${size / 2}px`,
|
||||||
|
borderLeftWidth: `${size / 2}px`,
|
||||||
|
left: `${x}px`,
|
||||||
|
top: `${y}px`
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
const styles = {
|
||||||
|
root: {
|
||||||
|
position: 'absolute',
|
||||||
|
cursor: 'pointer',
|
||||||
|
width: 0,
|
||||||
|
height: 0,
|
||||||
|
borderColor: 'transparent',
|
||||||
|
borderStyle: 'solid',
|
||||||
|
borderTopWidth: 0
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Dot;
|
||||||
@@ -5,7 +5,7 @@ import React from 'react';
|
|||||||
class View extends React.Component {
|
class View extends React.Component {
|
||||||
render() {
|
render() {
|
||||||
const { style, ...other } = this.props;
|
const { style, ...other } = this.props;
|
||||||
return <div {...other} className={css([viewStyle, ...style])} />;
|
return <div {...other} className={css(viewStyle, ...style)} />;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
9
packages/benchmarks/src/implementations/emotion/index.js
Normal file
9
packages/benchmarks/src/implementations/emotion/index.js
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import Box from './Box';
|
||||||
|
import Dot from './Dot';
|
||||||
|
import View from './View';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
Box,
|
||||||
|
Dot,
|
||||||
|
View
|
||||||
|
};
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
/* eslint-disable react/prop-types */
|
/* eslint-disable react/prop-types */
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import View from '../View/emotion';
|
import View from './View';
|
||||||
|
|
||||||
const Box = ({ color, fixed = false, layout = 'column', outer = false, ...other }) => (
|
const Box = ({ color, fixed = false, layout = 'column', outer = false, ...other }) => (
|
||||||
<View
|
<View
|
||||||
32
packages/benchmarks/src/implementations/glamor/Dot.js
Normal file
32
packages/benchmarks/src/implementations/glamor/Dot.js
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
/* eslint-disable react/prop-types */
|
||||||
|
import React from 'react';
|
||||||
|
import { css } from 'glamor';
|
||||||
|
|
||||||
|
const Dot = ({ size, x, y, children, color }) => (
|
||||||
|
<div
|
||||||
|
className={css(styles.root, {
|
||||||
|
borderBottomColor: color,
|
||||||
|
borderRightWidth: `${size / 2}px`,
|
||||||
|
borderBottomWidth: `${size / 2}px`,
|
||||||
|
borderLeftWidth: `${size / 2}px`,
|
||||||
|
left: `${x}px`,
|
||||||
|
top: `${y}px`
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
const styles = {
|
||||||
|
root: {
|
||||||
|
position: 'absolute',
|
||||||
|
cursor: 'pointer',
|
||||||
|
width: 0,
|
||||||
|
height: 0,
|
||||||
|
borderColor: 'transparent',
|
||||||
|
borderStyle: 'solid',
|
||||||
|
borderTopWidth: 0
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Dot;
|
||||||
9
packages/benchmarks/src/implementations/glamor/index.js
Normal file
9
packages/benchmarks/src/implementations/glamor/index.js
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import Box from './Box';
|
||||||
|
import Dot from './Dot';
|
||||||
|
import View from './View';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
Box,
|
||||||
|
Dot,
|
||||||
|
View
|
||||||
|
};
|
||||||
48
packages/benchmarks/src/implementations/inline-styles/Box.js
Normal file
48
packages/benchmarks/src/implementations/inline-styles/Box.js
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
/* eslint-disable react/prop-types */
|
||||||
|
import React from 'react';
|
||||||
|
import View from './View';
|
||||||
|
|
||||||
|
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 = {
|
||||||
|
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;
|
||||||
34
packages/benchmarks/src/implementations/inline-styles/Dot.js
Normal file
34
packages/benchmarks/src/implementations/inline-styles/Dot.js
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
/* eslint-disable react/prop-types */
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
const Dot = ({ size, x, y, children, color }) => (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
...styles.root,
|
||||||
|
...{
|
||||||
|
borderBottomColor: color,
|
||||||
|
borderRightWidth: `${size / 2}px`,
|
||||||
|
borderBottomWidth: `${size / 2}px`,
|
||||||
|
borderLeftWidth: `${size / 2}px`,
|
||||||
|
left: `${x}px`,
|
||||||
|
top: `${y}px`
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
const styles = {
|
||||||
|
root: {
|
||||||
|
position: 'absolute',
|
||||||
|
cursor: 'pointer',
|
||||||
|
width: 0,
|
||||||
|
height: 0,
|
||||||
|
borderColor: 'transparent',
|
||||||
|
borderStyle: 'solid',
|
||||||
|
borderTopWidth: 0
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Dot;
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
/* eslint-disable react/prop-types */
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
const compose = (s1, s2) => {
|
||||||
|
if (s1 && s2) {
|
||||||
|
return { ...s1, ...s2 };
|
||||||
|
} else {
|
||||||
|
return s1 || s2;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class View extends React.Component {
|
||||||
|
render() {
|
||||||
|
const { style, ...other } = this.props;
|
||||||
|
return <div {...other} style={compose(viewStyle, style)} />;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const viewStyle = {
|
||||||
|
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;
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import Box from './Box';
|
||||||
|
import Dot from './Dot';
|
||||||
|
import View from './View';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
Box,
|
||||||
|
Dot,
|
||||||
|
View
|
||||||
|
};
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
import injectSheet from 'react-jss';
|
import injectSheet from 'react-jss';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import View from '../View/jss';
|
import View from './View';
|
||||||
|
|
||||||
const Box = ({ classes, color, fixed = false, layout = 'column', outer = false, ...other }) => (
|
const Box = ({ classes, color, fixed = false, layout = 'column', outer = false, ...other }) => (
|
||||||
<View
|
<View
|
||||||
7
packages/benchmarks/src/implementations/jss/index.js
Normal file
7
packages/benchmarks/src/implementations/jss/index.js
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import Box from './Box';
|
||||||
|
import View from './View';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
Box,
|
||||||
|
View
|
||||||
|
};
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
/* eslint-disable react/prop-types */
|
/* eslint-disable react/prop-types */
|
||||||
import Radium from 'radium';
|
import Radium from 'radium';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import View from '../View/radium';
|
import View from './View';
|
||||||
|
|
||||||
const Box = ({ color, fixed = false, layout = 'column', outer = false, ...other }) => (
|
const Box = ({ color, fixed = false, layout = 'column', outer = false, ...other }) => (
|
||||||
<View
|
<View
|
||||||
35
packages/benchmarks/src/implementations/radium/Dot.js
Normal file
35
packages/benchmarks/src/implementations/radium/Dot.js
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
/* eslint-disable react/prop-types */
|
||||||
|
import Radium from 'radium';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
const Dot = ({ size, x, y, children, color }) => (
|
||||||
|
<div
|
||||||
|
style={[
|
||||||
|
styles.root,
|
||||||
|
{
|
||||||
|
borderBottomColor: color,
|
||||||
|
borderRightWidth: `${size / 2}px`,
|
||||||
|
borderBottomWidth: `${size / 2}px`,
|
||||||
|
borderLeftWidth: `${size / 2}px`,
|
||||||
|
left: `${x}px`,
|
||||||
|
top: `${y}px`
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
const styles = {
|
||||||
|
root: {
|
||||||
|
position: 'absolute',
|
||||||
|
cursor: 'pointer',
|
||||||
|
width: 0,
|
||||||
|
height: 0,
|
||||||
|
borderColor: 'transparent',
|
||||||
|
borderStyle: 'solid',
|
||||||
|
borderTopWidth: 0
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Radium(Dot);
|
||||||
9
packages/benchmarks/src/implementations/radium/index.js
Normal file
9
packages/benchmarks/src/implementations/radium/index.js
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import Box from './Box';
|
||||||
|
import Dot from './Dot';
|
||||||
|
import View from './View';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
Box,
|
||||||
|
Dot,
|
||||||
|
View
|
||||||
|
};
|
||||||
32
packages/benchmarks/src/implementations/react-native-web/Dot.js
vendored
Normal file
32
packages/benchmarks/src/implementations/react-native-web/Dot.js
vendored
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
/* eslint-disable react/prop-types */
|
||||||
|
import { createElement, StyleSheet } from 'react-native';
|
||||||
|
|
||||||
|
const Dot = ({ size, x, y, children, color }) =>
|
||||||
|
createElement('div', {
|
||||||
|
children,
|
||||||
|
style: [
|
||||||
|
styles.root,
|
||||||
|
{
|
||||||
|
borderBottomColor: color,
|
||||||
|
borderRightWidth: size / 2,
|
||||||
|
borderBottomWidth: size / 2,
|
||||||
|
borderLeftWidth: size / 2,
|
||||||
|
left: x,
|
||||||
|
top: y
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
root: {
|
||||||
|
position: 'absolute',
|
||||||
|
cursor: 'pointer',
|
||||||
|
width: 0,
|
||||||
|
height: 0,
|
||||||
|
borderColor: 'transparent',
|
||||||
|
borderStyle: 'solid',
|
||||||
|
borderTopWidth: 0
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export default Dot;
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import theme from '../theme';
|
import theme from './theme';
|
||||||
import React, { PureComponent } from 'react';
|
import React, { PureComponent } from 'react';
|
||||||
import { StyleSheet, Text } from 'react-native';
|
import { StyleSheet, Text } from 'react-native';
|
||||||
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import React, { PureComponent } from 'react';
|
import React, { PureComponent } from 'react';
|
||||||
import { StyleSheet, View } from 'react-native';
|
import { StyleSheet, View, ViewPropTypes } from 'react-native';
|
||||||
|
|
||||||
class AspectRatio extends PureComponent {
|
class AspectRatio extends PureComponent {
|
||||||
static displayName = 'AspectRatio';
|
static displayName = 'AspectRatio';
|
||||||
@@ -8,7 +8,7 @@ class AspectRatio extends PureComponent {
|
|||||||
static propTypes = {
|
static propTypes = {
|
||||||
children: PropTypes.any,
|
children: PropTypes.any,
|
||||||
ratio: PropTypes.number,
|
ratio: PropTypes.number,
|
||||||
style: PropTypes.object
|
style: ViewPropTypes.style
|
||||||
};
|
};
|
||||||
|
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { StyleSheet, View } from 'react-native';
|
import { StyleSheet, View, ViewPropTypes } from 'react-native';
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import theme from '../theme';
|
import theme from './theme';
|
||||||
|
|
||||||
class GridView extends Component {
|
class GridView extends Component {
|
||||||
static displayName = 'GridView';
|
static displayName = 'GridView';
|
||||||
@@ -9,7 +9,7 @@ class GridView extends Component {
|
|||||||
static propTypes = {
|
static propTypes = {
|
||||||
children: PropTypes.node,
|
children: PropTypes.node,
|
||||||
hasGap: PropTypes.bool,
|
hasGap: PropTypes.bool,
|
||||||
style: PropTypes.object
|
style: ViewPropTypes.style
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
import IconReply from '../Icons/Reply';
|
import IconReply from './IconReply';
|
||||||
import IconHeart from '../Icons/Heart';
|
import IconHeart from './IconHeart';
|
||||||
import IconRetweet from '../Icons/Retweet';
|
import IconRetweet from './IconRetweet';
|
||||||
import IconDirectMessage from '../Icons/DirectMessage';
|
import IconDirectMessage from './IconDirectMessage';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import theme from '../theme';
|
import theme from './theme';
|
||||||
import { Text, View, StyleSheet } from 'react-native';
|
import { Text, View, ViewPropTypes, StyleSheet } from 'react-native';
|
||||||
|
|
||||||
const getIcon = (icon, highlighted) => {
|
const getIcon = (icon, highlighted) => {
|
||||||
switch (icon) {
|
switch (icon) {
|
||||||
@@ -30,7 +30,7 @@ export default class TweetAction extends React.Component {
|
|||||||
displayMode: PropTypes.oneOf(['like', 'reply', 'retweet', 'directMessage']),
|
displayMode: PropTypes.oneOf(['like', 'reply', 'retweet', 'directMessage']),
|
||||||
highlighted: PropTypes.bool,
|
highlighted: PropTypes.bool,
|
||||||
onPress: PropTypes.func,
|
onPress: PropTypes.func,
|
||||||
style: PropTypes.object
|
style: ViewPropTypes.style
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import TweetAction from '../TweetAction';
|
import TweetAction from './TweetAction';
|
||||||
import { View, StyleSheet } from 'react-native';
|
import { View, ViewPropTypes, StyleSheet } from 'react-native';
|
||||||
import React, { PureComponent } from 'react';
|
import React, { PureComponent } from 'react';
|
||||||
|
|
||||||
const actionNames = ['reply', 'retweet', 'like', 'directMessage'];
|
const actionNames = ['reply', 'retweet', 'like', 'directMessage'];
|
||||||
@@ -16,7 +16,7 @@ export default class TweetActionsBar extends PureComponent {
|
|||||||
onPress: PropTypes.func
|
onPress: PropTypes.func
|
||||||
})
|
})
|
||||||
),
|
),
|
||||||
style: PropTypes.object
|
style: ViewPropTypes.style
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import AppText from '../AppText';
|
import AppText from './AppText';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import TweetTextPart from '../TweetTextPart';
|
import TweetTextPart from './TweetTextPart';
|
||||||
import { array, number, string } from 'prop-types';
|
import { array, number, string } from 'prop-types';
|
||||||
|
|
||||||
class TweetText extends React.Component {
|
class TweetText extends React.Component {
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
import { Image, StyleSheet, Text } from 'react-native';
|
import { Image, StyleSheet, Text } from 'react-native';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import theme from '../theme';
|
import theme from './theme';
|
||||||
|
|
||||||
const createTextEntity = ({ part }) => <Text>{`${part.prefix}${part.text}`}</Text>;
|
const createTextEntity = ({ part }) => <Text>{`${part.prefix}${part.text}`}</Text>;
|
||||||
|
|
||||||
@@ -106,7 +106,7 @@ const styles = StyleSheet.create({
|
|||||||
width: '1.25em',
|
width: '1.25em',
|
||||||
paddingRight: '0.05em',
|
paddingRight: '0.05em',
|
||||||
paddingLeft: '0.1em',
|
paddingLeft: '0.1em',
|
||||||
verticalAlign: '-0.2em'
|
textAlignVertical: '-0.2em'
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
import AspectRatio from '../AspectRatio';
|
import AspectRatio from './AspectRatio';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { Image, StyleSheet } from 'react-native';
|
import { Image, StyleSheet, ViewPropTypes } from 'react-native';
|
||||||
import React, { PureComponent } from 'react';
|
import React, { PureComponent } from 'react';
|
||||||
import theme from '../theme';
|
import theme from './theme';
|
||||||
|
|
||||||
class UserAvatar extends PureComponent {
|
class UserAvatar extends PureComponent {
|
||||||
static displayName = 'UserAvatar';
|
static displayName = 'UserAvatar';
|
||||||
@@ -10,7 +10,7 @@ class UserAvatar extends PureComponent {
|
|||||||
static propTypes = {
|
static propTypes = {
|
||||||
accessibilityLabel: PropTypes.string,
|
accessibilityLabel: PropTypes.string,
|
||||||
circle: PropTypes.bool,
|
circle: PropTypes.bool,
|
||||||
style: PropTypes.object,
|
style: ViewPropTypes.style,
|
||||||
uri: PropTypes.string
|
uri: PropTypes.string
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import AppText from '../AppText';
|
import AppText from './AppText';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { StyleSheet } from 'react-native';
|
import { StyleSheet, ViewPropTypes } from 'react-native';
|
||||||
import React, { PureComponent } from 'react';
|
import React, { PureComponent } from 'react';
|
||||||
|
|
||||||
class UserNames extends PureComponent {
|
class UserNames extends PureComponent {
|
||||||
@@ -11,7 +11,7 @@ class UserNames extends PureComponent {
|
|||||||
layout: PropTypes.oneOf(['nowrap', 'stack']),
|
layout: PropTypes.oneOf(['nowrap', 'stack']),
|
||||||
onPress: PropTypes.func,
|
onPress: PropTypes.func,
|
||||||
screenName: PropTypes.string,
|
screenName: PropTypes.string,
|
||||||
style: PropTypes.object
|
style: ViewPropTypes.style
|
||||||
};
|
};
|
||||||
|
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
import AspectRatio from '../AspectRatio';
|
import AspectRatio from './AspectRatio';
|
||||||
import GridView from '../GridView';
|
import GridView from './GridView';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import TweetActionsBar from '../TweetActionsBar';
|
import TweetActionsBar from './TweetActionsBar';
|
||||||
import TweetText from '../TweetText';
|
import TweetText from './TweetText';
|
||||||
import UserAvatar from '../UserAvatar';
|
import UserAvatar from './UserAvatar';
|
||||||
import UserNames from '../UserNames';
|
import UserNames from './UserNames';
|
||||||
import { Image, StyleSheet, Text, View } from 'react-native';
|
import { Image, StyleSheet, Text, View } from 'react-native';
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import theme from '../theme';
|
import theme from './theme';
|
||||||
|
|
||||||
export class Tweet extends Component {
|
export class Tweet extends Component {
|
||||||
static displayName = 'Tweet';
|
static displayName = 'Tweet';
|
||||||
@@ -8,7 +8,7 @@ const styles = StyleSheet.create({
|
|||||||
maxWidth: '100%',
|
maxWidth: '100%',
|
||||||
position: 'relative',
|
position: 'relative',
|
||||||
userSelect: 'none',
|
userSelect: 'none',
|
||||||
verticalAlign: 'text-bottom'
|
textAlignVertical: 'text-bottom'
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
9
packages/benchmarks/src/implementations/react-native-web/index.js
vendored
Normal file
9
packages/benchmarks/src/implementations/react-native-web/index.js
vendored
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import Box from './Box';
|
||||||
|
import Dot from './Dot';
|
||||||
|
import { View } from 'react-native';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
Box,
|
||||||
|
Dot,
|
||||||
|
View
|
||||||
|
};
|
||||||
34
packages/benchmarks/src/implementations/reactxp/Dot.js
Normal file
34
packages/benchmarks/src/implementations/reactxp/Dot.js
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
/* eslint-disable react/prop-types */
|
||||||
|
import React from 'react';
|
||||||
|
import { Styles, View } from 'reactxp';
|
||||||
|
|
||||||
|
const Dot = ({ size, x, y, children, color }) => (
|
||||||
|
<View
|
||||||
|
children={children}
|
||||||
|
style={[
|
||||||
|
styles.root,
|
||||||
|
{
|
||||||
|
borderBottomColor: color,
|
||||||
|
borderRightWidth: `${size / 2}px`,
|
||||||
|
borderBottomWidth: `${size / 2}px`,
|
||||||
|
borderLeftWidth: `${size / 2}px`,
|
||||||
|
left: `${x}px`,
|
||||||
|
top: `${y}px`
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
const styles = {
|
||||||
|
root: Styles.createViewStyle({
|
||||||
|
position: 'absolute',
|
||||||
|
cursor: 'pointer',
|
||||||
|
width: 0,
|
||||||
|
height: 0,
|
||||||
|
borderColor: 'transparent',
|
||||||
|
borderStyle: 'solid',
|
||||||
|
borderTopWidth: 0
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Dot;
|
||||||
@@ -1,7 +1,9 @@
|
|||||||
import Box from './components/Box/reactxp';
|
import Box from './Box';
|
||||||
|
import Dot from './Dot';
|
||||||
import { View } from 'reactxp';
|
import { View } from 'reactxp';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
Box,
|
Box,
|
||||||
|
Dot,
|
||||||
View
|
View
|
||||||
};
|
};
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import View from '../View/styled-components';
|
import View from './View';
|
||||||
|
|
||||||
const getColor = color => {
|
const getColor = color => {
|
||||||
switch (color) {
|
switch (color) {
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user