Compare commits

..

55 Commits
0.4.0 ... 0.5.4

Author SHA1 Message Date
Nicolas Gallagher
c122814591 0.5.4 2018-04-01 09:34:51 -07:00
Bruno Lemos
efe18f1b7e [fix] Linking.openURL on Firefox
Fix #883
Close #884
2018-04-01 09:25:16 -07:00
Nicolas Gallagher
e1b576e427 [add] StyleSheet support for 'System' in font stack
Allow 'System' to be used in a font-family stack, e.g., "Noto, System".

Update the 'System' font stack to include "system-ui", which is the
latest keyword for system fonts.
2018-03-31 14:57:29 -07:00
Nicolas Gallagher
5d77d6e30f [fix] TextInput focus management
Defer to the browser's native handling of 'blur' and 'focus'; directly
update the internal state of TextInputState. Fixes an issue with
preserving focus when the tab is backgrounded.

Also ensure the TextInputState is correctly set when a component mounts.
When 'autoFocus' is true, 'onFocus' can be called before the internal
ref is set.

Fix #880
2018-03-31 14:01:19 -07:00
Jesús Darío
8fb9a88ee6 Add webpack-cli to getting started guide 2018-03-29 15:49:43 -07:00
Kyle Goggin
a7cda988ef [fix] ignore 'tvParallaxProperties' prop
Close #867
2018-03-29 15:47:39 -07:00
Nicolas Gallagher
b239cfb04d [fix] update InteractionManager stub
Fix #875
2018-03-29 15:32:38 -07:00
Nicolas Gallagher
8e94d858b2 [fix] Picker prop types
Fix #879
2018-03-29 15:11:16 -07:00
Nicolas Gallagher
aa22b06359 0.5.3 2018-03-15 13:32:24 -07:00
Paul Armstrong
2aa565c7c3 [fix] Picker default fontFamily
Close #860
2018-03-15 13:08:23 -07:00
Sakamoto, Kazunori
7b9b57960d Update getting-started.md
Fix __DEV__ value in example web/webpack.config.js

Close #862
2018-03-15 13:06:58 -07:00
Nicolas Gallagher
eae3ee9dca 0.5.2 2018-03-07 19:56:46 -08:00
Nicolas Gallagher
74e1a196b6 [fix] Linking.openURL works with nonce use
`Linking` no longer uses an iframe hack to add 'noopener' support to
older Safari. Instead it relies on browsers having support for
'noopener'.

Fix #837
Close #846
2018-03-05 11:50:08 -08:00
Nicolas Gallagher
48da9814e7 Update benchmark libraries 2018-03-05 10:40:02 -08:00
Nicolas Gallagher
4d391ef57c Link to example integrations in README 2018-03-05 10:22:26 -08:00
Nicolas Gallagher
780df69a80 Update link to Glitch starter 2018-03-01 19:37:12 -08:00
Nicolas Gallagher
6c229da01f Minor improvement to AppRegistry console.log message 2018-02-26 15:20:35 -08:00
Nicolas Gallagher
ae7aa818fb 0.5.1 2018-02-20 17:48:12 -08:00
Nicolas Gallagher
306cf67932 [add] Image style support for animations, interactions, and filters 2018-02-20 17:45:19 -08:00
Nicolas Gallagher
619c2048be [add] support for 'transformStyle' style prop 2018-02-20 17:44:22 -08:00
Nicolas Gallagher
b9f9a4f8d7 Move some View style propTypes to InteractionPropTypes 2018-02-20 17:43:22 -08:00
Nicolas Gallagher
58bc18c2f5 Group 'transition' style propTypes with animations 2018-02-20 17:42:19 -08:00
Nicolas Gallagher
073940fc4e Group 'perspective' style propType with transforms 2018-02-20 17:40:57 -08:00
Nicolas Gallagher
5c462303de Inline some values in TextStylePropTypes 2018-02-20 17:32:45 -08:00
Nicolas Gallagher
5fb92da317 [fix] Switch layout when left/right do not flip
The I18nManager can now disable the automatic BiDi flipping of
left/right, which caused the Switch layout to break in RTL mode. Change
the styles to use start/end.
2018-02-20 16:44:46 -08:00
Nicolas Gallagher
cafe10d851 Improve View 'pointerEvents' example 2018-02-19 18:48:31 -08:00
Nicolas Gallagher
b28581f44e [fix] Touchable 'touchAction' value 2018-02-19 18:27:49 -08:00
Nicolas Gallagher
9333e7e887 0.5.0 2018-02-19 15:48:05 -08:00
Nicolas Gallagher
b28cbbb37e [fix] TextInput default font styles
Match React Native (and web) expected defaults.
2018-02-19 15:29:05 -08:00
Nicolas Gallagher
a53372ceb3 [fix] babel-plugin only rewrites paths for known modules
Don't rewrite import paths for non-existent modules or types. They will
attempt to be imported from the package's main export. This change
currently requires a module map to be generated for the babel-plugin to
use. The map is automatically regenerated for any commit that alters the
entry file of react-native-web.

Fix #822
2018-02-19 13:05:42 -08:00
Nicolas Gallagher
239a43978f Update yarn.lock 2018-02-18 17:43:22 -08:00
Nicolas Gallagher
b4e4bfbb3c Fix the event handlers with event normalization
Events are now normalized within the responder system, so those handlers
don't need to be listed anymore. Recently added events (blur,
contextmenu, focus) are now also normalized.
2018-02-18 17:42:02 -08:00
Nicolas Gallagher
893963a799 [fix] PanResponder grant firing twice on touch devices
Touch events can produce trailing mouse events, which cause unwanted
events to fire in the responder event system.  This issue is avoided in
`Touchable` by cancelling the event in the responder release callback.
To fix the issue in other areas, like the PaneResponder, this hack is
moved into `createElement` and applied to event `onResponderRelease`
callback.

Fix #802
2018-02-18 17:41:48 -08:00
Nicolas Gallagher
e5adc5a37c Add 'coveragePathIgnorePatterns' to jest config 2018-02-17 18:03:36 -08:00
Nicolas Gallagher
6d908189a7 [fix] Text support for 'fontVariant' style
Fix #824
Close #825
2018-02-17 18:03:31 -08:00
Nicolas Gallagher
31db333ba3 [fix] Image support for SVG base64 data
The previous fix to support inline SVG data in utf-8 format broke images
that were rendering base64 SVGs.
2018-02-17 15:55:45 -08:00
Nicolas Gallagher
9fe089ca21 [add] development warning about using '!important' in styles
React Native for Web may use '!important' as part of the internal
resolving of styles. But user styles should never be allowed to include
'!important' in the value. Print a warning to the console when they do.
2018-02-17 14:46:31 -08:00
Nicolas Gallagher
a314d5b2e4 [change] MIT license
Now possible to license under MIT following the change to React Native's
license.

26684cf3ad

Fix #828
2018-02-17 12:23:45 -08:00
Nicolas Gallagher
fb845ebf44 Update benchmarks dependencies 2018-02-16 19:08:19 -08:00
Nicolas Gallagher
0d0c7e6e27 Document 'onBlur', 'onFocus', and 'onContextMenu' props 2018-02-16 18:53:33 -08:00
Nicolas Gallagher
f37003a079 Add end/start to BorderPropTypes 2018-02-15 19:08:34 -08:00
Nicolas Gallagher
f1fc2a9e37 Rewrite I18nManager and i18nStyle unit tests 2018-02-15 18:46:08 -08:00
Nicolas Gallagher
92794cdc9f [add] I18nManager and StyleSheet support for RTL without left/right flip
I18nManager supports `doLeftAndRightSwapInRTL` and
`swapLeftAndRightInRTL` to query and control the BiDi-flipping of
left/right properties and values. For example, you may choose to use
`end`/`start` for positioning that flips with writing direction, and
then disable `left`/`right` swapping in RTL so that `left` will always
be `left`.

The StyleSheet resolver cache must also account for the third "direction"
variant: RTL with no swapping of left/right.
2018-02-15 18:45:45 -08:00
Nicolas Gallagher
b754776373 [add] StyleSheet support for start/end properties and values
Add support for new style properties and values that automatically
account for the writing direction (as introduced in React Native
0.51.0). The start/end variants are automatically resolved to match the
global writing direction, as defined by I18nManager.isRTL. Start/End
take precedence over Left/Right.

Adds support for the following properties:

* `borderTop{End,Start}Radius`
* `borderBottom{End,Start}Radius`
* `border{End,Start}Color`
* `border{End,Start}Style`
* `border{End,Start}Width`
* `end`
* `margin{End,Start}`
* `padding{End,Start}`
* `start`

And values:

* `clear: "end" | "start"`
* `float: "end" | "start"`
* `textAlign: "end" | "start"`
2018-02-15 18:43:09 -08:00
Nicolas Gallagher
155b34e495 Fix unit test timeouts on Travis CI
Jest recommends using 'runInBand' for Travis CI. It runs all tests
serially in the current process, rather than creating a worker pool of
child processes that run tests.
2018-02-14 14:26:03 -08:00
Nicolas Gallagher
00c9dc4236 [fix] setNativeProps can apply flex styles
Updates the 'setValueForStyle' implementation to support style values
that contain "!important". This allows the 'flex{Basis,Grow,Shrink}'
values created by the style resolver to be applied. They currently use
the important priority as a work-around for browser-inconsistencies in
the 'flex' shorthand.

Upstream fix: https://github.com/facebook/react/pull/12181

Ref #798
Close #813
2018-02-14 13:51:00 -08:00
Nicolas Gallagher
b66aba1a06 website: fix ImageBackground source code link
Close #820
2018-02-14 13:39:14 -08:00
Nicolas Gallagher
17f8a674b8 [fix] ResponderEventPlugin skips 'mouseup' when no touch is active
Prevent the responder system recording 'mouseup' events if there is no
active 'touch'.

Fix #816
2018-02-13 15:02:09 -08:00
Nicolas Gallagher
b8080ba775 [fix] Touchable press events regression in 9ee89bc
Fix a regression introduced by "ResponderEvent event filtering"
9ee89bc7f7. Touchable press events were
firing twice after the event normalization was moved up into
'extractEvents'. The reason is:

1) events were previously not normalized throughout the responder system
2) once they were normalized, the fix introduced by a535c558d8 stopped working
3) because normalized nativeEvent did not include event data like 'cancelable'.

This patch adds more of the original nativeEvent fields to the
normalized event, so that React's synthetic event can return the correct
information for 'bubbles', 'cancelable', 'isDefaultPrevented()', etc.
2018-02-13 13:34:17 -08:00
Nicolas Gallagher
7265736545 [fix] StyleSheet accepts 'space-evenly' value for 'justifyContent' 2018-02-12 10:35:30 -08:00
Bulat Kidasov
399f465e59 [fix] NativeMethodsMixin measure/measureInWindow with scroll
Account for scroll offsets when calculating measurements.

Fix #702
Fix #805
Close #806
2018-02-12 10:27:47 -08:00
Nicolas Gallagher
9ee89bc7f7 [fix] ResponderEventPlugin event filtering
Exclude middle, wheel, and right click mouse events from the responder
system. This fixes the Touchables incorrectly triggering 'onPress' in
response to these events.

Filter mousemove events in the 'extractEvents' methods, and check for
active touches rather than the length of the touch bank. This fixes the
PanResponder not functioning after the first touch in Firefox.

Fix #719
Fix #729
Close #804
2018-02-12 10:08:44 -08:00
Jakub Rimal
748b2d0f3f [fix] Image 'source' prop update when missing in initial render
Close #811
2018-02-12 08:27:48 -08:00
Nicolas Gallagher
fb4635e013 Update README's 2018-02-08 16:09:56 -08:00
Nicolas Gallagher
73b459e770 [add] TextInput onKeyPress support for arrow keys
Close #791
Close #792
2018-02-08 10:57:32 -08:00
180 changed files with 2019 additions and 1580 deletions

45
LICENSE
View File

@@ -1,31 +1,22 @@
BSD License
MIT License
For React Native software
Copyright (c) 2015-present, Nicolas Gallagher.
Copyright (c) 2015-present, Facebook, Inc.
Copyright (c) 2015-present, Nicolas Gallagher. All rights reserved.
Copyright (c) 2015-present, Facebook, Inc. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name Facebook nor the names of its contributors may be used to
endorse or promote products derived from this software without specific
prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -19,21 +19,19 @@ rewriting existing code. React Native for Web can also render to HTML and
critical CSS on the server using Node.js.
Who is using React Native for Web? [Twitter](https://mobile.twitter.com),
[Major League Soccer](https://matchcenter.mlssoccer.com), [The
[Major League Soccer](https://matchcenter.mlssoccer.com),
[Flipkart](https://www.flipkart.com/), Playstation, Uber, [The
Times](https://github.com/newsuk/times-components), [React Native's
documentation](http://facebook.github.io/react-native/).
Browser support: Chrome, Firefox, Safari >= 7, IE 10, Edge.
Browser support: Chrome, Firefox, Edge, Safari 7+, IE 10+.
## Quick start
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).
[ready-to-go project on Glitch](https://glitch.com/edit/#!/react-native).
You dont need to install anything to try it out.
If you are unfamiliar with setting up a React web project, please follow the
recommendations in the [React documentation](https://reactjs.org/).
## Documentation
You can find the React Native for Web API documentation [on the
@@ -97,6 +95,16 @@ 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.
## Integrations
Examples of using React Native for Web with other web tools:
* [Next.js](https://github.com/zeit/next.js/tree/master/examples/with-react-native-web)
* [Storybook](https://github.com/necolas/react-native-web/tree/0.5.1/website/storybook/.storybook)
* [Razzle](https://github.com/jaredpalmer/razzle/tree/master/examples/with-react-native-web)
* [Phenomic](https://github.com/phenomic/phenomic/tree/v1.0.0-alpha.20/docs)
* [Styleguidist](https://github.com/styleguidist/react-styleguidist/tree/v6.2.6/examples/react-native)
## Contributing
The main purpose of this repository is to help evolve React web and native
@@ -126,7 +134,9 @@ relatively limited scope. This is a great place to get started.
## License
React Native for Web is [BSD licensed](./LICENSE).
React Native for Web is [MIT licensed](./LICENSE). By contributing to React
Native for Web, you agree that your contributions will be licensed under its
MIT license.
[package-badge]: https://img.shields.io/npm/v/react-native-web.svg?style=flat
[package-url]: https://yarnpkg.com/en/package/react-native-web

View File

@@ -1,6 +1,6 @@
{
"private": true,
"version": "0.4.0",
"version": "0.5.4",
"name": "react-native-web-monorepo",
"scripts": {
"clean": "del ./packages/*/dist",
@@ -19,7 +19,7 @@
"prerelease": "yarn test && yarn compile",
"release": "node ./scripts/release/publish.js",
"postrelease": "yarn website:release && yarn benchmarks:release",
"test": "yarn flow && yarn lint:check && yarn jest"
"test": "yarn flow && yarn lint:check && yarn jest --runInBand"
},
"devDependencies": {
"babel-cli": "^6.26.0",
@@ -62,6 +62,9 @@
"fmt:cmd",
"git update-index --again",
"eslint"
],
"packages/react-native-web/src/index.js": [
"node ./scripts/babel/createModuleMap.js"
]
},
"prettier": {
@@ -69,5 +72,5 @@
"singleQuote": true
},
"author": "Nicolas Gallagher",
"license": "BSD-3-Clause"
"license": "MIT"
}

View File

@@ -1,6 +1,6 @@
{
"name": "babel-plugin-react-native-web",
"version": "0.4.0",
"version": "0.5.4",
"description": "Babel plugin for React Native for Web",
"main": "index.js",
"devDependencies": {

View File

@@ -41,7 +41,7 @@ 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 { Invalid } from 'react-native-web/dist/index';
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';

View File

@@ -1,5 +1,7 @@
const moduleMap = require('./moduleMap');
const getDistLocation = importName =>
importName ? `react-native-web/dist/exports/${importName}` : undefined;
importName && moduleMap[importName] ? `react-native-web/dist/exports/${importName}` : undefined;
const isReactNativeRequire = (t, node) => {
const { declarations } = node;

View File

@@ -0,0 +1,61 @@
// THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT.
module.exports = {
ART: true,
ActivityIndicator: true,
Animated: true,
AppRegistry: true,
AppState: true,
AsyncStorage: true,
BackHandler: true,
Button: true,
CheckBox: true,
Clipboard: true,
ColorPropType: true,
Dimensions: true,
Easing: true,
EdgeInsetsPropType: true,
FlatList: true,
I18nManager: true,
Image: true,
ImageBackground: true,
InteractionManager: true,
Keyboard: true,
KeyboardAvoidingView: true,
Linking: true,
ListView: true,
Modal: true,
NativeModules: true,
NetInfo: true,
PanResponder: true,
Picker: true,
PixelRatio: true,
Platform: true,
PointPropType: true,
ProgressBar: true,
RefreshControl: true,
SafeAreaView: true,
ScrollView: true,
SectionList: true,
Slider: true,
StatusBar: true,
StyleSheet: true,
Switch: true,
Text: true,
TextInput: true,
TextPropTypes: true,
Touchable: true,
TouchableHighlight: true,
TouchableNativeFeedback: true,
TouchableOpacity: true,
TouchableWithoutFeedback: true,
UIManager: true,
Vibration: true,
View: true,
ViewPropTypes: true,
VirtualizedList: true,
createElement: true,
findNodeHandle: true,
processColor: true,
render: true,
unmountComponentAtNode: true
};

View File

@@ -19,12 +19,9 @@ yarn benchmarks --watch
## Notes
These benchmarks are 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 dynamic 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 a corresponding benchmark.
encounter. Their purpose is to provide an early-warning signal for performance
regressions. Each test report includes the mean and standard deviation of the
timings, and approximations of the time spent in scripting (S) and layout (L).
The components used in the render benchmarks are simple enough to be
implemented by multiple UI or style libraries. The benchmark implementations
@@ -33,6 +30,19 @@ functionality_.
No benchmark will run for more than 20 seconds.
### Mount deep/wide tree
These cases look at the performance of mounting and rendering large trees of
elements that use static styles.
### Update dynamic styles
This case looks at the performance of repeated style updates to a large mounted
tree. Some libraries choose to inject new styles for each "dynamic style",
whereas others choose to use inline styles. Libraries without built-in support
for dynamic styles (i.e., they rely on user-authored inline styles) are not
included.
## Example results
### MacBook Pro (2011)
@@ -41,52 +51,20 @@ MacBook Pro (13-inch, Early 2011); 2.3 GHz Intel Core i5; 8 GB 1333 MHz DDR3 RAM
Typical render timings: mean ± standard deviations.
| Implementation | Mount deep tree (ms) | Mount wide tree (ms) | Dynamic update (ms) |
| Implementation | Mount deep tree (ms) | Mount wide tree (ms) | Dynamic update (ms) |
| :--- | ---: | ---: | ---: |
| `css-modules` | `15.23` `±04.31` | `21.27` `±07.03` | - |
| `react-native-web@0.3.2` | `17.52` `±04.44` | `24.14` `±04.39` | `15.03` `±02.22` |
| `inline-styles` | `50.06` `±06.70` | `76.38` `±09.58` | `06.43` `±02.02` |
Other libraries
| Implementation | Mount deep tree (ms) | Mount wide tree (ms) | Dynamic update (ms) |
| :--- | ---: | ---: | ---: |
| `aphrodite@1.2.5` | `17.27` `±05.96` | `24.89` `±08.36` | - |
| `glamor@2.20.40` | `21.59` `±05.38` | `27.93` `±07.56` | ‡ |
| `emotion@8.0.12` | `21.07` `±04.16` | `31.40` `±09.40` | ‡ `19.80` `±13.56` |
| `styletron-react@3.0.3` | `23.55` `±05.14` | `34.26` `±07.58` | `10.39` `±02.94` |
| `react-fela@5.0.0` | `27.58` `±04.26` | `39.54` `±05.46` | `10.93` `±01.69` |
| `react-jss@8.2.1` | `27.31` `±07.87` | `40.74` `±10.67` | - |
| `styled-jsx@2.2.1` | `27.46` `±07.85` | `41.47` `±11.53` | `29.16` `±09.98` |
| `styled-components@2.4.0` | `43.89` `±06.99` | `63.26` `±09.02` | `16.17` `±03.71` |
| `reactxp@0.51.0-alpha.9` | `51.86` `±07.21` | `78.80` `±11.85` | `15.04` `±03.92` |
| `radium@0.21.0` | `101.06` `±13.00` | `144.46` `±16.94` | `17.44` `±03.59` |
| `css-modules` | `30.19` `±04.84` | `38.25` `±04.85` | - |
| `react-native-web@0.4.0` | `36.40` `±04.98` | `51.28` `±05.58` | `19.36` `±02.56` |
| `inline-styles` | `64.12` `±07.69` | `94.49` `±11.34` | `09.84` `±02.36` |
### Moto G4
Moto G4 (Android 7); Octa-core (4x1.5 GHz & 4x1.2 Ghz); 2 GB RAM. Google Chrome 63
Moto G4 (Android 7); Octa-core (4x1.5 GHz & 4x1.2 Ghz); 2 GB RAM. Google Chrome 63.
Typical render timings: mean ± standard deviations.
| Implementation | Mount deep tree (ms) | Mount wide tree (ms) | Dynamic update (ms) |
| Implementation | Mount deep tree (ms) | Mount wide tree (ms) | Dynamic update (ms) |
| :--- | ---: | ---: | ---: |
| `css-modules` | `56.18` 19.54` | `75.95` `±23.55` | - |
| `react-native-web@0.3.2` | `68.53` 21.00` | `101.03` 25.32` | `60.57` `±09.07` |
| `inline-styles` | `140.32` `±23.91` | `208.55` 35.25` | `20.36` `±04.92` |
Other libraries
| Implementation | Mount deep tree (ms) | Mount wide tree (ms) | Dynamic update (ms) |
| :--- | ---: | ---: | ---: |
| `aphrodite@1.2.5` | `58.77` `±19.73` | `85.83` `±24.64` | - |
| `glamor@2.20.40` | `81.05` `±15.87` | `104.02` `±20.92` | ‡ |
| `emotion@8.0.12` | `77.12` `±19.61` | `112.04` `±24.43` | ‡ `80.40` `±40.56` |
| `styletron-react@3.0.3` | `91.00` `±17.95` | `130.49` `±20.06` | `39.70` `±06.85` |
| `react-fela@5.0.0` | `101.36` `±19.55` | `142.18` `±21.87` | `43.64` `±12.24` |
| `styled-jsx@2.2.1` | `101.60` `±25.26` | `144.12` `±30.79` | `115.63` `±32.77` |
| `react-jss@8.2.1` | `112.46` `±32.07` | `165.96` `±42.54` | - |
| `styled-components@2.4.0` | `159.85` `±24.30` | `231.00` `±31.34` | `53.86` `±13.40` |
| `reactxp@0.51.0-alpha.9` | `182.05` `±30.72` | `261.25` `±35.54` | `58.20` `±08.62` |
| `radium@0.21.0` | `323.93` `±41.46` | `464.70` `±53.93` | `59.13` `±09.76` |
‡Glamor essentially crashes the browser tab. Emotion gets slower every iteration.
| `css-modules` | `98.24` 20.26` | `143.75` `±25.50` | - |
| `react-native-web@0.4.0` | `131.46` 18.96` | `174.70` 14.88` | `60.87` `±06.32` |
| `inline-styles` | `184.58` `±26.23` | `273.86` 26.23` | `30.28` `±07.44` |

View File

@@ -1,7 +1,7 @@
{
"private": true,
"name": "benchmarks",
"version": "0.4.0",
"version": "0.5.4",
"scripts": {
"build": "mkdir -p dist && cp -f index.html dist/index.html && webpack --config ./webpack.config.js",
"release": "yarn build && git checkout gh-pages && rm -rf ../../benchmarks && mv dist ../../benchmarks && git add -A && git commit -m \"Benchmarks deploy\" && git push origin gh-pages && git checkout -"
@@ -9,28 +9,27 @@
"dependencies": {
"aphrodite": "1.2.5",
"classnames": "^2.2.5",
"d3-scale-chromatic": "^1.1.1",
"emotion": "8.0.12",
"fela": "6.1.3",
"d3-scale-chromatic": "^1.2.0",
"emotion": "^9.0.2",
"fela": "^6.1.4",
"glamor": "2.20.40",
"radium": "0.21.2",
"radium": "^0.22.1",
"react": "^16.2.0",
"react-component-benchmark": "^0.0.4",
"react-dom": "^16.2.0",
"react-fela": "6.2.4",
"react-jss": "8.2.1",
"react-native-web": "0.4.0",
"reactxp": "0.51.2",
"style-loader": "0.20.1",
"styled-components": "3.1.2",
"styled-jsx": "2.2.2",
"styletron-client": "3.0.4",
"styletron-react": "3.0.4"
"react-fela": "^7.0.1",
"react-jss": "^8.3.3",
"react-native-web": "0.5.4",
"reactxp": "^1.0.0",
"styled-components": "^3.2.0",
"styled-jsx": "^2.2.5",
"styletron-engine-atomic": "^1.0.0",
"styletron-react": "^4.0.0"
},
"devDependencies": {
"babel-plugin-react-native-web": "0.4.0",
"css-loader": "^0.28.9",
"style-loader": "^0.19.1",
"babel-plugin-react-native-web": "0.5.4",
"css-loader": "^0.28.10",
"style-loader": "^0.20.2",
"webpack": "^3.10.0",
"webpack-bundle-analyzer": "^2.9.2"
}

View File

@@ -40,7 +40,7 @@ class ReportCard extends React.PureComponent {
{fmt(mean)} ±{fmt(stdDev)} ms
</Text>
<Text style={[styles.smallText, styles.monoFont]}>
(S/L) {fmt(meanScripting)} / {fmt(meanLayout)} ms
(S/L) {fmt(meanScripting)}/{fmt(meanLayout)} ms
</Text>
</Fragment>
) : (

View File

@@ -1,8 +1,8 @@
/* eslint-disable react/prop-types */
import { styled } from 'styletron-react';
import { withStyle } from 'styletron-react';
import View from './View';
const Box = styled(
const Box = withStyle(
View,
({ color, fixed = false, layout = 'column', outer = false, ...other }) => ({
...styles[`color${color}`],

View File

@@ -1,7 +1,7 @@
/* eslint-disable react/prop-types */
import React from 'react';
import Styletron from 'styletron-client';
import { StyletronProvider } from 'styletron-react';
import { Client as Styletron } from 'styletron-engine-atomic';
import { Provider as StyletronProvider } from 'styletron-react';
import View from './View';
const styletron = new Styletron();
@@ -9,7 +9,7 @@ const styletron = new Styletron();
class Provider extends React.Component {
render() {
return (
<StyletronProvider styletron={styletron}>
<StyletronProvider value={styletron}>
<View>{this.props.children}</View>
</StyletronProvider>
);

View File

@@ -39,7 +39,7 @@ exports[`enzyme.mount complex 1`] = `
}
>
<div
className="rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-color-1bodaif rn-display-1471scf rn-font-1lw9tu2 rn-fontFamily-10u92zi rn-fontSize-ubezar rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-verticalAlign-9iso6 rn-textDecoration-bauka4 rn-whiteSpace-q42fyq rn-wordWrap-qvutc0"
className="rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-color-1bodaif rn-display-1471scf rn-font-1lw9tu2 rn-fontFamily-14xgk7a rn-fontSize-ubezar rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-verticalAlign-9iso6 rn-textDecoration-bauka4 rn-whiteSpace-q42fyq rn-wordWrap-qvutc0"
dir="auto"
>
Hello World
@@ -63,7 +63,7 @@ exports[`enzyme.mount complex 1`] = `
</View>
<Text>
<div
className="rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-color-homxoj rn-display-1471scf rn-font-1lw9tu2 rn-fontFamily-10u92zi rn-fontSize-1b43r93 rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-textDecoration-bauka4 rn-whiteSpace-q42fyq rn-wordWrap-qvutc0"
className="rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-color-homxoj rn-display-1471scf rn-font-1lw9tu2 rn-fontFamily-14xgk7a rn-fontSize-1b43r93 rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-textDecoration-bauka4 rn-whiteSpace-q42fyq rn-wordWrap-qvutc0"
dir="auto"
>
Nested
@@ -117,7 +117,7 @@ exports[`enzyme.mount nested 1`] = `
}
>
<div
className="rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-color-1bodaif rn-display-1471scf rn-font-1lw9tu2 rn-fontFamily-10u92zi rn-fontSize-ubezar rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-verticalAlign-9iso6 rn-textDecoration-bauka4 rn-whiteSpace-q42fyq rn-wordWrap-qvutc0"
className="rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-color-1bodaif rn-display-1471scf rn-font-1lw9tu2 rn-fontFamily-14xgk7a rn-fontSize-ubezar rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-verticalAlign-9iso6 rn-textDecoration-bauka4 rn-whiteSpace-q42fyq rn-wordWrap-qvutc0"
dir="auto"
>
Hello World
@@ -142,7 +142,7 @@ exports[`enzyme.render complex 1`] = `
class="rn-alignItems-1oszu61 rn-backgroundColor-1mjtqww rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1pxmb3b rn-flexBasis-7vfszb rn-flexDirection-eqz5dr rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-m611by rn-paddingRight-1qfoi16 rn-paddingBottom-1mi0q7o rn-paddingLeft-1hfyk0a rn-position-bnwqim rn-zIndex-1lgpqti"
>
<div
class="rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-color-1bodaif rn-display-1471scf rn-font-1lw9tu2 rn-fontFamily-10u92zi rn-fontSize-ubezar rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-verticalAlign-9iso6 rn-textDecoration-bauka4 rn-whiteSpace-q42fyq rn-wordWrap-qvutc0"
class="rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-color-1bodaif rn-display-1471scf rn-font-1lw9tu2 rn-fontFamily-14xgk7a rn-fontSize-ubezar rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-verticalAlign-9iso6 rn-textDecoration-bauka4 rn-whiteSpace-q42fyq rn-wordWrap-qvutc0"
dir="auto"
>
Hello World
@@ -154,7 +154,7 @@ exports[`enzyme.render complex 1`] = `
class="rn-alignItems-1oszu61 rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1pxmb3b rn-flexBasis-7vfszb rn-flexDirection-eqz5dr rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-1knelpx rn-paddingRight-1ah4tor rn-paddingBottom-k8qxaj rn-paddingLeft-b5h31w rn-position-bnwqim rn-zIndex-1lgpqti"
/>
<div
class="rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-color-homxoj rn-display-1471scf rn-font-1lw9tu2 rn-fontFamily-10u92zi rn-fontSize-1b43r93 rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-textDecoration-bauka4 rn-whiteSpace-q42fyq rn-wordWrap-qvutc0"
class="rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-color-homxoj rn-display-1471scf rn-font-1lw9tu2 rn-fontFamily-14xgk7a rn-fontSize-1b43r93 rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-textDecoration-bauka4 rn-whiteSpace-q42fyq rn-wordWrap-qvutc0"
dir="auto"
>
Nested
@@ -174,7 +174,7 @@ exports[`enzyme.render nested 1`] = `
class="rn-alignItems-1oszu61 rn-backgroundColor-1mjtqww rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1pxmb3b rn-flexBasis-7vfszb rn-flexDirection-eqz5dr rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-m611by rn-paddingRight-1qfoi16 rn-paddingBottom-1mi0q7o rn-paddingLeft-1hfyk0a rn-position-bnwqim rn-zIndex-1lgpqti"
>
<div
class="rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-color-1bodaif rn-display-1471scf rn-font-1lw9tu2 rn-fontFamily-10u92zi rn-fontSize-ubezar rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-verticalAlign-9iso6 rn-textDecoration-bauka4 rn-whiteSpace-q42fyq rn-wordWrap-qvutc0"
class="rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-color-1bodaif rn-display-1471scf rn-font-1lw9tu2 rn-fontFamily-14xgk7a rn-fontSize-ubezar rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-verticalAlign-9iso6 rn-textDecoration-bauka4 rn-whiteSpace-q42fyq rn-wordWrap-qvutc0"
dir="auto"
>
Hello World
@@ -252,7 +252,7 @@ exports[`react-test-renderer complex 1`] = `
className="rn-alignItems-1oszu61 rn-backgroundColor-1mjtqww rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1pxmb3b rn-flexBasis-7vfszb rn-flexDirection-eqz5dr rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-m611by rn-paddingRight-1qfoi16 rn-paddingBottom-1mi0q7o rn-paddingLeft-1hfyk0a rn-position-bnwqim rn-zIndex-1lgpqti"
>
<div
className="rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-color-1bodaif rn-display-1471scf rn-font-1lw9tu2 rn-fontFamily-10u92zi rn-fontSize-ubezar rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-verticalAlign-9iso6 rn-textDecoration-bauka4 rn-whiteSpace-q42fyq rn-wordWrap-qvutc0"
className="rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-color-1bodaif rn-display-1471scf rn-font-1lw9tu2 rn-fontFamily-14xgk7a rn-fontSize-ubezar rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-verticalAlign-9iso6 rn-textDecoration-bauka4 rn-whiteSpace-q42fyq rn-wordWrap-qvutc0"
dir="auto"
>
Hello World
@@ -264,7 +264,7 @@ exports[`react-test-renderer complex 1`] = `
className="rn-alignItems-1oszu61 rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1pxmb3b rn-flexBasis-7vfszb rn-flexDirection-eqz5dr rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-1knelpx rn-paddingRight-1ah4tor rn-paddingBottom-k8qxaj rn-paddingLeft-b5h31w rn-position-bnwqim rn-zIndex-1lgpqti"
/>
<div
className="rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-color-homxoj rn-display-1471scf rn-font-1lw9tu2 rn-fontFamily-10u92zi rn-fontSize-1b43r93 rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-textDecoration-bauka4 rn-whiteSpace-q42fyq rn-wordWrap-qvutc0"
className="rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-color-homxoj rn-display-1471scf rn-font-1lw9tu2 rn-fontFamily-14xgk7a rn-fontSize-1b43r93 rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-textDecoration-bauka4 rn-whiteSpace-q42fyq rn-wordWrap-qvutc0"
dir="auto"
>
Nested
@@ -284,7 +284,7 @@ exports[`react-test-renderer nested 1`] = `
className="rn-alignItems-1oszu61 rn-backgroundColor-1mjtqww rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1pxmb3b rn-flexBasis-7vfszb rn-flexDirection-eqz5dr rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-m611by rn-paddingRight-1qfoi16 rn-paddingBottom-1mi0q7o rn-paddingLeft-1hfyk0a rn-position-bnwqim rn-zIndex-1lgpqti"
>
<div
className="rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-color-1bodaif rn-display-1471scf rn-font-1lw9tu2 rn-fontFamily-10u92zi rn-fontSize-ubezar rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-verticalAlign-9iso6 rn-textDecoration-bauka4 rn-whiteSpace-q42fyq rn-wordWrap-qvutc0"
className="rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-color-1bodaif rn-display-1471scf rn-font-1lw9tu2 rn-fontFamily-14xgk7a rn-fontSize-ubezar rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-verticalAlign-9iso6 rn-textDecoration-bauka4 rn-whiteSpace-q42fyq rn-wordWrap-qvutc0"
dir="auto"
>
Hello World

View File

@@ -1,6 +1,6 @@
{
"name": "react-native-web",
"version": "0.4.0",
"version": "0.5.4",
"description": "React Native for Web",
"main": "dist/index.js",
"files": [
@@ -27,7 +27,7 @@
"react-dom": "16.x.x"
},
"author": "Nicolas Gallagher",
"license": "BSD-3-Clause",
"license": "MIT",
"repository": {
"type": "git",
"url": "git://github.com/necolas/react-native-web.git"

View File

@@ -1,9 +1,8 @@
/**
* Copyright (c) 2016-present, Nicolas Gallagher.
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @providesModule ActivityIndicator

View File

@@ -1,10 +1,8 @@
/**
* Copyright (c) 2016-present, Nicolas Gallagher.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @providesModule Animated
* @flow

View File

@@ -1,9 +1,8 @@
/**
* Copyright (c) 2016-present, Nicolas Gallagher.
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow

View File

@@ -1,9 +1,8 @@
/**
* Copyright (c) 2015-present, Nicolas Gallagher.
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @providesModule AppRegistry
@@ -78,9 +77,9 @@ export default class AppRegistry {
params.rootTag = `#${params.rootTag.id}`;
console.log(
`Running application "${appKey}" with appParams: ${JSON.stringify(params)}. ` +
`development-level warnings are ${isDevelopment ? 'ON' : 'OFF'}, ` +
`performance optimizations are ${isDevelopment ? 'OFF' : 'ON'}`
`Running application "${appKey}" with appParams: ${JSON.stringify(params)}.\n` +
`Development-level warnings: ${isDevelopment ? 'ON' : 'OFF'}.\n` +
`Performance optimizations: ${isDevelopment ? 'OFF' : 'ON'}.`
);
invariant(

View File

@@ -1,9 +1,8 @@
/**
* Copyright (c) 2015-present, Nicolas Gallagher.
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow

View File

@@ -1,9 +1,8 @@
/**
* Copyright (c) 2016-present, Nicolas Gallagher.
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @providesModule AppState

View File

@@ -1,9 +1,8 @@
/**
* Copyright (c) 2015-present, Nicolas Gallagher.
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @providesModule AsyncStorage

View File

@@ -1,9 +1,8 @@
/**
* Copyright (c) 2016-present, Nicolas Gallagher.
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @providesModule BackHandler

View File

@@ -1,9 +1,7 @@
/**
* Copyright (c) 2016-present, Nicolas Gallagher.
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @providesModule Button

View File

@@ -1,9 +1,8 @@
/**
* Copyright (c) 2017-present, Nicolas Gallagher.
* Copyright (c) 2017-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @providesModule CheckBox

View File

@@ -1,9 +1,8 @@
/**
* Copyright (c) 2016-present, Nicolas Gallagher.
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @providesModule Clipboard

View File

@@ -1,10 +1,8 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @providesModule ColorPropType
* @noflow

View File

@@ -1,9 +1,8 @@
/**
* Copyright (c) 2015-present, Nicolas Gallagher.
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @providesModule Dimensions

View File

@@ -1,8 +1,7 @@
/**
* Copyright (c) 2016-present, Nicolas Gallagher.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow

View File

@@ -1,10 +1,8 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @providesModule EdgeInsetsPropType
* @flow

View File

@@ -2,44 +2,100 @@
import I18nManager from '..';
const getDocumentDir = () => document.documentElement.getAttribute('dir');
describe('apis/I18nManager', () => {
describe('when RTL not enabled', () => {
describe('preferred language is LTR', () => {
beforeEach(() => {
I18nManager.setPreferredLanguageRTL(false);
});
test('is "false" by default', () => {
expect(I18nManager.isRTL).toEqual(false);
expect(document.documentElement.getAttribute('dir')).toEqual('ltr');
describe('isRTL', () => {
test('is false', () => {
expect(I18nManager.isRTL).toBe(false);
expect(getDocumentDir()).toEqual('ltr');
});
});
test('is "true" when forced', () => {
I18nManager.forceRTL(true);
expect(I18nManager.isRTL).toEqual(true);
expect(document.documentElement.getAttribute('dir')).toEqual('rtl');
I18nManager.forceRTL(false);
describe('forceRTL', () => {
test('when set to false, "isRTL" is false', () => {
I18nManager.forceRTL(false);
expect(I18nManager.isRTL).toBe(false);
expect(getDocumentDir()).toEqual('ltr');
});
test('when set to true, "isRTL" is true', () => {
I18nManager.forceRTL(true);
expect(I18nManager.isRTL).toBe(true);
expect(getDocumentDir()).toEqual('rtl');
I18nManager.forceRTL(false);
});
});
describe('swapLeftAndRightInRTL', () => {
test('when set to false, "doLeftAndRightSwapInRTL" is false', () => {
I18nManager.swapLeftAndRightInRTL(false);
expect(I18nManager.doLeftAndRightSwapInRTL).toBe(false);
});
test('when set to true, "doLeftAndRightSwapInRTL" is true', () => {
I18nManager.swapLeftAndRightInRTL(true);
expect(I18nManager.doLeftAndRightSwapInRTL).toBe(true);
});
});
});
describe('when RTL is enabled', () => {
describe('preferred language is RTL', () => {
beforeEach(() => {
I18nManager.setPreferredLanguageRTL(true);
});
afterEach(() => {
afterAll(() => {
I18nManager.setPreferredLanguageRTL(false);
});
test('is "true" by default', () => {
expect(I18nManager.isRTL).toEqual(true);
expect(document.documentElement.getAttribute('dir')).toEqual('rtl');
describe('isRTL', () => {
test('is true', () => {
expect(I18nManager.isRTL).toBe(true);
expect(getDocumentDir()).toEqual('rtl');
});
});
test('is "false" when not allowed', () => {
I18nManager.allowRTL(false);
expect(I18nManager.isRTL).toEqual(false);
expect(document.documentElement.getAttribute('dir')).toEqual('ltr');
I18nManager.allowRTL(true);
describe('allowRTL', () => {
test('when set to false, "isRTL" is false', () => {
I18nManager.allowRTL(false);
expect(I18nManager.isRTL).toBe(false);
expect(getDocumentDir()).toEqual('ltr');
I18nManager.allowRTL(true);
});
test('when set to true, "isRTL" is true', () => {
I18nManager.allowRTL(true);
expect(I18nManager.isRTL).toBe(true);
expect(getDocumentDir()).toEqual('rtl');
});
});
describe('forceRTL', () => {
test('when set to false, "isRTL" is true', () => {
I18nManager.forceRTL(false);
expect(I18nManager.isRTL).toBe(true);
expect(getDocumentDir()).toEqual('rtl');
});
test('when set to true, "isRTL" is true', () => {
I18nManager.forceRTL(true);
expect(I18nManager.isRTL).toBe(true);
expect(getDocumentDir()).toEqual('rtl');
I18nManager.forceRTL(false);
});
});
describe('swapLeftAndRightInRTL', () => {
test('when set to false, "doLeftAndRightSwapInRTL" is false', () => {
I18nManager.swapLeftAndRightInRTL(false);
expect(I18nManager.doLeftAndRightSwapInRTL).toBe(false);
});
test('when set to true, "doLeftAndRightSwapInRTL" is true', () => {
I18nManager.swapLeftAndRightInRTL(true);
expect(I18nManager.doLeftAndRightSwapInRTL).toBe(true);
});
});
});
});

View File

@@ -1,9 +1,8 @@
/**
* Copyright (c) 2016-present, Nicolas Gallagher.
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @providesModule I18nManager
@@ -14,11 +13,14 @@ import ExecutionEnvironment from 'fbjs/lib/ExecutionEnvironment';
type I18nManagerStatus = {
allowRTL: (allowRTL: boolean) => void,
doLeftAndRightSwapInRTL: boolean,
forceRTL: (forceRTL: boolean) => void,
isRTL: boolean,
setPreferredLanguageRTL: (setRTL: boolean) => void,
isRTL: boolean
swapLeftAndRightInRTL: (flipStyles: boolean) => void
};
let doLeftAndRightSwapInRTL = true;
let isPreferredLanguageRTL = false;
let isRTLAllowed = true;
let isRTLForced = false;
@@ -30,7 +32,7 @@ const isRTL = () => {
return isRTLAllowed && isPreferredLanguageRTL;
};
const onChange = () => {
const onDirectionChange = () => {
if (ExecutionEnvironment.canUseDOM) {
if (document.documentElement && document.documentElement.setAttribute) {
document.documentElement.setAttribute('dir', isRTL() ? 'rtl' : 'ltr');
@@ -41,15 +43,21 @@ const onChange = () => {
const I18nManager: I18nManagerStatus = {
allowRTL(bool) {
isRTLAllowed = bool;
onChange();
onDirectionChange();
},
forceRTL(bool) {
isRTLForced = bool;
onChange();
onDirectionChange();
},
setPreferredLanguageRTL(bool) {
isPreferredLanguageRTL = bool;
onChange();
onDirectionChange();
},
swapLeftAndRightInRTL(bool) {
doLeftAndRightSwapInRTL = bool;
},
get doLeftAndRightSwapInRTL() {
return doLeftAndRightSwapInRTL;
},
get isRTL() {
return isRTL();

View File

@@ -2,16 +2,20 @@
* @flow
*/
import AnimationPropTypes from '../../modules/AnimationPropTypes';
import BorderPropTypes from '../../modules/BorderPropTypes';
import ColorPropType from '../ColorPropType';
import ImageResizeMode from './ImageResizeMode';
import InteractionPropTypes from '../../modules/InteractionPropTypes';
import LayoutPropTypes from '../../modules/LayoutPropTypes';
import ShadowPropTypes from '../../modules/ShadowPropTypes';
import TransformPropTypes from '../../modules/TransformPropTypes';
import { number, oneOf, string } from 'prop-types';
const ImageStylePropTypes = {
...AnimationPropTypes,
...BorderPropTypes,
...InteractionPropTypes,
...LayoutPropTypes,
...ShadowPropTypes,
...TransformPropTypes,
@@ -26,7 +30,8 @@ const ImageStylePropTypes = {
/**
* @platform web
*/
boxShadow: string
boxShadow: string,
filter: string
};
export default ImageStylePropTypes;

View File

@@ -180,6 +180,20 @@ describe('components/Image', () => {
.attr('src')
).toBe(uriTwo);
});
test('is correctly updated when missing in initial render', () => {
jest.useFakeTimers();
const uri = 'https://testing.com/img.jpg';
const component = mount(<Image />);
component.setProps({ source: { uri } });
jest.runOnlyPendingTimers();
expect(
component
.render()
.find('img')
.attr('src')
).toBe(uri);
});
});
describe('prop "style"', () => {

View File

@@ -1,9 +1,8 @@
/**
* Copyright (c) 2016-present, Nicolas Gallagher.
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @providesModule Image
@@ -57,7 +56,7 @@ const resolveAssetDimensions = source => {
}
};
const svgDataUriPattern = /^data:image\/svg\+xml;/;
const svgDataUriPattern = /^(data:image\/svg\+xml;utf8,)(.*)/;
const resolveAssetSource = source => {
let uri;
if (typeof source === 'number') {
@@ -72,12 +71,12 @@ const resolveAssetSource = source => {
uri = source || '';
}
// SVG data may contain characters (e.g., #, ") that need to be escaped
if (svgDataUriPattern.test(uri)) {
const parts = uri.split('<svg');
const [prefix, ...svgFragment] = parts;
const svg = encodeURIComponent(`<svg${svgFragment.join('<svg')}`);
return `${prefix}${svg}`;
const match = uri.match(svgDataUriPattern);
// inline SVG markup may contain characters (e.g., #, ") that need to be escaped
if (match) {
const [, prefix, svg] = match;
const encodedSvg = encodeURIComponent(svg);
return `${prefix}${encodedSvg}`;
}
return uri;
@@ -168,8 +167,8 @@ class Image extends Component<*, State> {
if (uri !== nextUri) {
ImageUriCache.remove(uri);
const isPreviouslyLoaded = ImageUriCache.has(nextUri);
isPreviouslyLoaded && ImageUriCache.add(uri);
this._updateImageState(getImageState(uri, isPreviouslyLoaded));
isPreviouslyLoaded && ImageUriCache.add(nextUri);
this._updateImageState(getImageState(nextUri, isPreviouslyLoaded));
}
}

View File

@@ -1,10 +1,8 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/

View File

@@ -1,9 +1,8 @@
/**
* Copyright (c) 2016-present, Nicolas Gallagher.
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @providesModule InteractionManager
@@ -21,9 +20,18 @@ const InteractionManager = {
/**
* Schedule a function to run after all interactions have completed.
*/
runAfterInteractions(callback: Function) {
invariant(typeof callback === 'function', 'Must specify a function to schedule.');
callback();
runAfterInteractions(task: ?Function): { then: Function, done: Function, cancel: Function } {
console.warn('InteractionManager is not supported on web');
const promise = new Promise(resolve => {
if (task) {
resolve(task());
}
});
return {
then: promise.then.bind(promise),
done: () => {},
cancel: () => {}
};
},
/**

View File

@@ -1,9 +1,8 @@
/**
* Copyright (c) 2016-present, Nicolas Gallagher.
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @providesModule Keyboard

View File

@@ -1,9 +1,8 @@
/**
* Copyright (c) 2017-present, Nicolas Gallagher.
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @providesModule KeyboardAvoidingView

View File

@@ -1,9 +1,8 @@
/**
* Copyright (c) 2016-present, Nicolas Gallagher.
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @providesModule Linking
@@ -25,7 +24,7 @@ const Linking = {
},
openURL(url: string): Promise<Object | void> {
try {
iframeOpen(url);
open(url);
return Promise.resolve();
} catch (e) {
return Promise.reject(e);
@@ -33,36 +32,16 @@ const Linking = {
}
};
/**
* Tabs opened using JavaScript may redirect the parent tab using
* `window.opener.location`, ignoring cross-origin restrictions and enabling
* phishing attacks.
*
* Safari requires that we open the url by injecting a hidden iframe that calls
* window.open(), then removes the iframe from the DOM.
*
* https://mathiasbynens.github.io/rel-noopener/
*/
const iframeOpen = url => {
const noOpener = url.indexOf('mailto:') !== 0;
const open = url => {
const anchor = document.createElement('a');
anchor.target = '_blank'; // :(
anchor.rel = 'noopener';
anchor.href = url;
const body = document.body;
if (body) {
const iframe = document.createElement('iframe');
iframe.style.display = 'none';
body.appendChild(iframe);
const iframeDoc = iframe.contentDocument || iframe.contentWindow.document;
const iframeBody = iframeDoc.body;
if (iframeBody) {
const script = iframeDoc.createElement('script');
const openerExpression = noOpener ? 'child.opener = null' : '';
script.text = `
window.parent = null; window.top = null; window.frameElement = null;
var child = window.open("${url}"); ${openerExpression};
`;
iframeBody.appendChild(script);
}
body.removeChild(iframe);
body.appendChild(anchor);
anchor.click();
body.removeChild(anchor);
}
};

View File

@@ -1,9 +1,8 @@
/**
* Copyright (c) 2015-present, Nicolas Gallagher.
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @providesModule NetInfo

View File

@@ -1,9 +1,8 @@
/**
* Copyright (c) 2017-present, Nicolas Gallagher.
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow

View File

@@ -1,9 +1,8 @@
/**
* Copyright (c) 2017-present, Nicolas Gallagher.
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow

View File

@@ -10,7 +10,7 @@ exports[`components/Picker prop "children" items 1`] = `
exports[`components/Picker prop "children" renders items 1`] = `
<select
className="rn-fontFamily-poiln3 rn-fontSize-7cikom rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw"
className="rn-fontFamily-14xgk7a rn-fontSize-7cikom rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw"
onChange={[Function]}
>
<PickerItem

View File

@@ -1,9 +1,8 @@
/**
* Copyright (c) 2017-present, Nicolas Gallagher.
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @providesModule Picker
@@ -24,7 +23,7 @@ import { arrayOf, bool, func, number, oneOfType, string } from 'prop-types';
const pickerStyleType = StyleSheetPropType(PickerStylePropTypes);
type Props = {
children?: Array<typeof PickerItem>,
children?: PickerItem | Array<typeof PickerItem>,
enabled?: boolean,
onValueChange?: Function,
selectedValue?: number | string,
@@ -38,7 +37,7 @@ type Props = {
class Picker extends Component<Props> {
static propTypes = {
children: arrayOf(PickerItemPropType),
children: oneOfType([PickerItemPropType, arrayOf(PickerItemPropType)]),
enabled: bool,
onValueChange: func,
selectedValue: oneOfType([number, string]),
@@ -83,7 +82,7 @@ class Picker extends Component<Props> {
const styles = StyleSheet.create({
initial: {
fontFamily: 'inherit',
fontFamily: 'System',
fontSize: 'inherit',
margin: 0
}

View File

@@ -1,9 +1,8 @@
/**
* Copyright (c) 2015-present, Nicolas Gallagher.
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @providesModule PixelRatio

View File

@@ -1,9 +1,8 @@
/**
* Copyright (c) 2016-present, Nicolas Gallagher.
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @providesModule Platform

View File

@@ -1,10 +1,8 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @providesModule PointPropType
* @flow

View File

@@ -1,8 +1,7 @@
/**
* Copyright (c) 2016-present, Nicolas Gallagher.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @providesModule ProgressBar

View File

@@ -1,9 +1,8 @@
/**
* Copyright (c) 2017-present, Nicolas Gallagher.
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @providesModule RefreshControl

View File

@@ -1,10 +1,8 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @providesModule SafeAreaView
* @flow

View File

@@ -1,8 +1,7 @@
/**
* Copyright (c) 2016-present, Nicolas Gallagher.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow

View File

@@ -1,9 +1,8 @@
/**
* Copyright (c) 2016-present, Nicolas Gallagher.
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @providesModule ScrollView

View File

@@ -1,8 +1,7 @@
/**
* Copyright (c) 2016-present, Nicolas Gallagher.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @providesModule StatusBar

View File

@@ -1,14 +1,15 @@
/**
* Copyright (c) 2016-present, Nicolas Gallagher.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @noflow
*/
/**
* WARNING: changes to this file in particular can cause significant changes to
* the results of render performance benchmarks.
*
* @noflow
*/
import { canUseDOM } from 'fbjs/lib/ExecutionEnvironment';
@@ -24,8 +25,8 @@ const emptyObject = {};
export default class ReactNativeStyleResolver {
_init() {
this.cache = { ltr: {}, rtl: {} };
this.injectedCache = { ltr: {}, rtl: {} };
this.cache = { ltr: {}, rtl: {}, rtlNoSwap: {} };
this.injectedCache = { ltr: {}, rtl: {}, rtlNoSwap: {} };
this.styleSheetManager = new StyleSheetManager();
}
@@ -43,7 +44,8 @@ export default class ReactNativeStyleResolver {
}
_injectRegisteredStyle(id) {
const dir = I18nManager.isRTL ? 'rtl' : 'ltr';
const { doLeftAndRightSwapInRTL, isRTL } = I18nManager;
const dir = isRTL ? (doLeftAndRightSwapInRTL ? 'rtl' : 'rtlNoSwap') : 'ltr';
if (!this.injectedCache[dir][id]) {
const style = flattenStyle(id);
const domStyle = createReactDOMStyle(i18nStyle(style));
@@ -120,7 +122,7 @@ export default class ReactNativeStyleResolver {
// Create next DOM style props from current and next RN styles
const { classList: rdomClassListNext, style: rdomStyleNext } = this.resolve([
I18nManager.isRTL ? i18nStyle(rnStyle) : rnStyle,
i18nStyle(rnStyle),
rnStyleNext
]);
@@ -196,7 +198,8 @@ export default class ReactNativeStyleResolver {
*/
_resolveStyleIfNeeded(style, key) {
if (key) {
const dir = I18nManager.isRTL ? 'rtl' : 'ltr';
const { doLeftAndRightSwapInRTL, isRTL } = I18nManager;
const dir = isRTL ? (doLeftAndRightSwapInRTL ? 'rtl' : 'rtlNoSwap') : 'ltr';
if (!this.cache[dir][key]) {
// slow: convert style object to props and cache
this.cache[dir][key] = this._resolveStyle(style);

View File

@@ -1,8 +1,7 @@
/**
* Copyright (c) 2016-present, Nicolas Gallagher.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @providesModule StyleSheet

View File

@@ -1,8 +1,7 @@
/**
* Copyright (c) 2016-present, Nicolas Gallagher.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @noflow

View File

@@ -1,9 +1,8 @@
/**
* Copyright (c) 2016-present, Nicolas Gallagher.
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @providesModule StyleSheetValidation
@@ -26,6 +25,8 @@ const ReactPropTypesSecret = 'SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED';
export default class StyleSheetValidation {
static validateStyleProp(prop: string, style: Object, caller: string) {
if (process.env.NODE_ENV !== 'production') {
const value = style[prop];
const isCustomProperty = prop.indexOf('--') === 0;
if (isCustomProperty) return;
@@ -35,6 +36,12 @@ export default class StyleSheetValidation {
'\nValid style props: ' +
JSON.stringify(Object.keys(allStylePropTypes).sort(), null, ' ');
styleError(message1, style, caller, message2);
} else if (typeof value === 'string' && value.indexOf('!important') > -1) {
styleError(
`Invalid value of "${value}" set on prop "${prop}". Values cannot include "!important"`,
style,
caller
);
} else {
const error = allStylePropTypes[prop](
style,
@@ -92,7 +99,7 @@ StyleSheetValidation.addValidStylePropTypes({
clear: string,
cursor: string,
fill: string,
float: oneOf(['left', 'none', 'right']),
float: oneOf(['end', 'left', 'none', 'right', 'start']),
listStyle: string,
pointerEvents: string,
tableLayout: string,

View File

@@ -1,8 +1,7 @@
/**
* Copyright (c) 2016-present, Nicolas Gallagher.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow

View File

@@ -42,14 +42,22 @@ describe('StyleSheet/ReactNativeStyleResolver', () => {
testResolve(a, b, c);
});
test('with register before RTL, resolves to className', () => {
test('with register before RTL, resolves to correct className', () => {
const a = ReactNativePropRegistry.register({ left: '12.34%' });
const b = ReactNativePropRegistry.register({ textAlign: 'left' });
const c = ReactNativePropRegistry.register({ marginLeft: 10 });
I18nManager.forceRTL(true);
const resolved = styleResolver.resolve([a, b, c]);
const resolved1 = styleResolver.resolve([a, b, c]);
expect(resolved1).toMatchSnapshot();
I18nManager.swapLeftAndRightInRTL(false);
const resolved2 = styleResolver.resolve([a, b, c]);
expect(resolved2).toMatchSnapshot();
I18nManager.swapLeftAndRightInRTL(true);
I18nManager.forceRTL(false);
expect(resolved).toMatchSnapshot();
});
test('with register, resolves to mixed', () => {
@@ -102,7 +110,7 @@ describe('StyleSheet/ReactNativeStyleResolver', () => {
expect(resolved).toMatchSnapshot();
});
test('when RTL=true, resolves to flipped inline styles', () => {
test('when isRTL=true, resolves to flipped inline styles', () => {
// note: DOM state resolved from { marginLeft: 5, left: 5 } in RTL mode
node.style.cssText = 'margin-right: 5px; right: 5px;';
I18nManager.forceRTL(true);
@@ -111,8 +119,8 @@ describe('StyleSheet/ReactNativeStyleResolver', () => {
expect(resolved).toMatchSnapshot();
});
test('when RTL=true, resolves to flipped classNames', () => {
// note: DOM state resolved from { marginLeft: 5, left: 5 } in RTL mode
test('when isRTL=true, resolves to flipped classNames', () => {
// note: DOM state resolved from { marginLeft: 5, left: 5 }
node.style.cssText = 'margin-right: 5px; right: 5px;';
const nextStyle = ReactNativePropRegistry.register({ marginLeft: 10, right: 1 });
@@ -121,5 +129,19 @@ describe('StyleSheet/ReactNativeStyleResolver', () => {
I18nManager.forceRTL(false);
expect(resolved).toMatchSnapshot();
});
test('when isRTL=true & doLeftAndRightSwapInRTL=false, resolves to non-flipped inline styles', () => {
// note: DOM state resolved from { marginRight 5, right: 5, paddingEnd: 5 }
node.style.cssText = 'margin-right: 5px; right: 5px; padding-left: 5px';
I18nManager.forceRTL(true);
I18nManager.swapLeftAndRightInRTL(false);
const resolved = styleResolver.resolveWithNode(
{ marginRight: 10, right: 10, paddingEnd: 10 },
node
);
I18nManager.forceRTL(false);
I18nManager.swapLeftAndRightInRTL(true);
expect(resolved).toMatchSnapshot();
});
});
});

View File

@@ -9,7 +9,7 @@ Object {
}
`;
exports[`StyleSheet/ReactNativeStyleResolver resolve with register before RTL, resolves to className 1`] = `
exports[`StyleSheet/ReactNativeStyleResolver resolve with register before RTL, resolves to correct className 1`] = `
Object {
"classList": Array [
"rn-marginRight-zso239",
@@ -20,6 +20,17 @@ Object {
}
`;
exports[`StyleSheet/ReactNativeStyleResolver resolve with register before RTL, resolves to correct className 2`] = `
Object {
"classList": Array [
"rn-left-2s0hu9",
"rn-marginLeft-1n0xq6e",
"rn-textAlign-fdjqy7",
],
"className": "rn-left-2s0hu9 rn-marginLeft-1n0xq6e rn-textAlign-fdjqy7",
}
`;
exports[`StyleSheet/ReactNativeStyleResolver resolve with register, resolves to className 1`] = `
Object {
"classList": Array [
@@ -246,7 +257,18 @@ Object {
}
`;
exports[`StyleSheet/ReactNativeStyleResolver resolveWithNode when RTL=true, resolves to flipped classNames 1`] = `
exports[`StyleSheet/ReactNativeStyleResolver resolveWithNode when isRTL=true & doLeftAndRightSwapInRTL=false, resolves to non-flipped inline styles 1`] = `
Object {
"className": "",
"style": Object {
"marginRight": "10px",
"paddingLeft": "10px",
"right": "10px",
},
}
`;
exports[`StyleSheet/ReactNativeStyleResolver resolveWithNode when isRTL=true, resolves to flipped classNames 1`] = `
Object {
"className": "rn-left-1u10d71 rn-marginRight-zso239",
"style": Object {
@@ -256,7 +278,7 @@ Object {
}
`;
exports[`StyleSheet/ReactNativeStyleResolver resolveWithNode when RTL=true, resolves to flipped inline styles 1`] = `
exports[`StyleSheet/ReactNativeStyleResolver resolveWithNode when isRTL=true, resolves to flipped inline styles 1`] = `
Object {
"className": "",
"style": Object {

View File

@@ -1,12 +1,18 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`StyleSheet/createReactDOMStyle fontFamily fontFamily: "System" 1`] = `
exports[`StyleSheet/createReactDOMStyle fontFamily "Noto, System" 1`] = `
Object {
"fontFamily": "-apple-system, BlinkMacSystemFont, \\"Segoe UI\\", Roboto, Ubuntu, \\"Helvetica Neue\\", sans-serif",
"fontFamily": "Noto, system-ui, -apple-system, BlinkMacSystemFont, \\"Segoe UI\\", Roboto, Ubuntu, \\"Helvetica Neue\\", sans-serif",
}
`;
exports[`StyleSheet/createReactDOMStyle fontFamily fontFamily: "monospace" 1`] = `
exports[`StyleSheet/createReactDOMStyle fontFamily "System" 1`] = `
Object {
"fontFamily": "system-ui, -apple-system, BlinkMacSystemFont, \\"Segoe UI\\", Roboto, Ubuntu, \\"Helvetica Neue\\", sans-serif",
}
`;
exports[`StyleSheet/createReactDOMStyle fontFamily "monospace" 1`] = `
Object {
"fontFamily": "monospace, monospace",
}

View File

@@ -1,53 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`StyleSheet/i18nStyle LTR mode does not auto-flip 1`] = `
Object {
"borderBottomLeftRadius": 20,
"borderBottomRightRadius": "2rem",
"borderLeftColor": "red",
"borderLeftStyle": "solid",
"borderLeftWidth": 5,
"borderRightColor": "blue",
"borderRightStyle": "dotted",
"borderRightWidth": 6,
"borderTopLeftRadius": 10,
"borderTopRightRadius": "1rem",
"left": 1,
"marginLeft": 7,
"marginRight": 8,
"paddingLeft": 9,
"paddingRight": 10,
"right": 2,
"textAlign": "left",
"textShadowOffset": Object {
"height": 10,
"width": "1rem",
},
}
`;
exports[`StyleSheet/i18nStyle RTL mode does auto-flip 1`] = `
Object {
"borderBottomLeftRadius": "2rem",
"borderBottomRightRadius": 20,
"borderLeftColor": "blue",
"borderLeftStyle": "dotted",
"borderLeftWidth": 6,
"borderRightColor": "red",
"borderRightStyle": "solid",
"borderRightWidth": 5,
"borderTopLeftRadius": "1rem",
"borderTopRightRadius": 10,
"left": 2,
"marginLeft": 8,
"marginRight": 7,
"paddingLeft": 10,
"paddingRight": 9,
"right": 1,
"textAlign": "right",
"textShadowOffset": Object {
"height": 10,
"width": "-1rem",
},
}
`;

View File

@@ -22,6 +22,23 @@ describe('StyleSheet/createReactDOMStyle', () => {
expect(firstStyle).toEqual(secondStyle);
});
test('shortform -> longform', () => {
const style = {
borderStyle: 'solid',
boxSizing: 'border-box',
borderBottomColor: 'white',
borderBottomWidth: 1,
borderWidth: 0,
marginTop: 50,
marginVertical: 25,
margin: 10,
overflow: 'hidden',
overscrollBehavior: 'contain'
};
expect(createReactDOMStyle(style)).toMatchSnapshot();
});
describe('borderWidth styles', () => {
test('defaults to 0 when "null"', () => {
expect(createReactDOMStyle({ borderWidth: null })).toEqual({
@@ -125,30 +142,23 @@ describe('StyleSheet/createReactDOMStyle', () => {
expect(createReactDOMStyle({ fontFamily: 'Georgia, Times, serif' })).toMatchSnapshot();
});
test('fontFamily: "monospace"', () => {
test('"monospace"', () => {
expect(createReactDOMStyle({ fontFamily: 'monospace' })).toMatchSnapshot();
});
test('fontFamily: "System"', () => {
test('"System"', () => {
expect(createReactDOMStyle({ fontFamily: 'System' })).toMatchSnapshot();
});
test('"Noto, System"', () => {
expect(createReactDOMStyle({ fontFamily: 'Noto, System' })).toMatchSnapshot();
});
});
test('shortform -> longform', () => {
const style = {
borderStyle: 'solid',
boxSizing: 'border-box',
borderBottomColor: 'white',
borderBottomWidth: 1,
borderWidth: 0,
marginTop: 50,
marginVertical: 25,
margin: 10,
overflow: 'hidden',
overscrollBehavior: 'contain'
};
expect(createReactDOMStyle(style)).toMatchSnapshot();
test('fontVariant', () => {
expect(createReactDOMStyle({ fontVariant: ['common-ligatures', 'small-caps'] })).toEqual({
fontVariant: 'common-ligatures small-caps'
});
});
describe('shadow styles', () => {

View File

@@ -2,11 +2,9 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import flattenStyle from '../flattenStyle';

View File

@@ -3,29 +3,8 @@
import I18nManager from '../../I18nManager';
import i18nStyle from '../i18nStyle';
const style = {
borderLeftColor: 'red',
borderRightColor: 'blue',
borderTopLeftRadius: 10,
borderTopRightRadius: '1rem',
borderBottomLeftRadius: 20,
borderBottomRightRadius: '2rem',
borderLeftStyle: 'solid',
borderRightStyle: 'dotted',
borderLeftWidth: 5,
borderRightWidth: 6,
left: 1,
marginLeft: 7,
marginRight: 8,
paddingLeft: 9,
paddingRight: 10,
right: 2,
textAlign: 'left',
textShadowOffset: { width: '1rem', height: 10 }
};
describe('StyleSheet/i18nStyle', () => {
describe('LTR mode', () => {
describe('isRTL is false', () => {
beforeEach(() => {
I18nManager.allowRTL(false);
});
@@ -34,12 +13,73 @@ describe('StyleSheet/i18nStyle', () => {
I18nManager.allowRTL(true);
});
test('does not auto-flip', () => {
expect(i18nStyle(style)).toMatchSnapshot();
test('converts end/start properties', () => {
const initial = {
borderStartColor: 'red',
start: 1,
marginStart: 5,
paddingEnd: 10
};
const expected = {
borderLeftColor: 'red',
left: 1,
marginLeft: 5,
paddingRight: 10
};
expect(i18nStyle(initial)).toEqual(expected);
});
test('converts end/start values', () => {
const initial = {
float: 'start',
textAlign: 'end'
};
const expected = {
float: 'left',
textAlign: 'right'
};
expect(i18nStyle(initial)).toEqual(expected);
});
test('noop on left/right properties', () => {
const initial = {
paddingLeft: 0,
left: 0,
marginRight: 0,
paddingRight: 10
};
expect(i18nStyle(initial)).toEqual(initial);
});
test('noop on left/right values', () => {
const initial = {
clear: 'left',
float: 'left',
textAlign: 'right',
textShadowOffset: { width: '1rem', height: 10 }
};
expect(i18nStyle(initial)).toEqual(initial);
});
test('end/start properties take precedence', () => {
const initial = {
borderStartWidth: 10,
borderLeftWidth: 0,
end: 10,
right: 0,
marginStart: 10,
marginLeft: 0
};
const expected = {
borderLeftWidth: 10,
marginLeft: 10,
right: 10
};
expect(i18nStyle(initial)).toEqual(expected);
});
});
describe('RTL mode', () => {
describe('isRTL is true', () => {
beforeEach(() => {
I18nManager.forceRTL(true);
});
@@ -48,8 +88,156 @@ describe('StyleSheet/i18nStyle', () => {
I18nManager.forceRTL(false);
});
test('does auto-flip', () => {
expect(i18nStyle(style)).toMatchSnapshot();
describe('doLeftAndRightSwapInRTL is false', () => {
beforeEach(() => {
I18nManager.swapLeftAndRightInRTL(false);
});
afterEach(() => {
I18nManager.swapLeftAndRightInRTL(true);
});
test('converts end/start properties', () => {
const initial = {
borderStartColor: 'red',
start: 1,
marginStart: 5,
paddingEnd: 10
};
const expected = {
borderRightColor: 'red',
right: 1,
marginRight: 5,
paddingLeft: 10
};
expect(i18nStyle(initial)).toEqual(expected);
});
test('converts end/start values', () => {
const initial = {
float: 'start',
textAlign: 'end'
};
const expected = {
float: 'right',
textAlign: 'left'
};
expect(i18nStyle(initial)).toEqual(expected);
});
test('noop on left/right properties', () => {
const initial = {
paddingLeft: 0,
left: 0,
marginRight: 0,
paddingRight: 10
};
expect(i18nStyle(initial)).toEqual(initial);
});
test('noop on left/right values', () => {
const initial = {
clear: 'left',
float: 'left',
textAlign: 'right',
textShadowOffset: { width: '1rem', height: 10 }
};
expect(i18nStyle(initial)).toEqual(initial);
});
test('end/start properties take precedence', () => {
const style = {
borderStartWidth: 10,
borderRightWidth: 0,
end: 10,
left: 0,
marginStart: 10,
marginRight: 0
};
const expected = {
borderRightWidth: 10,
marginRight: 10,
left: 10
};
expect(i18nStyle(style)).toEqual(expected);
});
});
describe('doLeftAndRightSwapInRTL is true', () => {
test('converts end/start properties', () => {
const initial = {
borderStartColor: 'red',
start: 1,
marginStart: 5,
paddingEnd: 10
};
const expected = {
borderRightColor: 'red',
right: 1,
marginRight: 5,
paddingLeft: 10
};
expect(i18nStyle(initial)).toEqual(expected);
});
test('converts end/start values', () => {
const initial = {
float: 'start',
textAlign: 'end'
};
const expected = {
float: 'right',
textAlign: 'left'
};
expect(i18nStyle(initial)).toEqual(expected);
});
test('converts left/right properties', () => {
const initial = {
borderLeftColor: 'red',
left: 1,
marginLeft: 5,
paddingRight: 10
};
const expected = {
borderRightColor: 'red',
right: 1,
marginRight: 5,
paddingLeft: 10
};
expect(i18nStyle(initial)).toEqual(expected);
});
test('converts left/right values', () => {
const initial = {
float: 'left',
textAlign: 'right',
textShadowOffset: { width: '1rem', height: 10 }
};
const expected = {
float: 'right',
textAlign: 'left',
textShadowOffset: { width: '-1rem', height: 10 }
};
expect(i18nStyle(initial)).toEqual(expected);
});
test('end/start properties take precedence', () => {
const style = {
borderStartWidth: 10,
borderLeftWidth: 0,
end: 10,
right: 0,
marginStart: 10,
marginLeft: 0
};
const expected = {
borderRightWidth: 10,
marginRight: 10,
left: 10
};
expect(i18nStyle(style)).toEqual(expected);
});
});
});
});

View File

@@ -1,10 +1,16 @@
/**
* Copyright (c) 2016-present, Nicolas Gallagher.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @noflow
*/
import normalizeValue from './normalizeValue';
import processColor from '../processColor';
/**
* The browser implements the CSS cascade, where the order of properties is a
* factor in determining which styles to paint. React Native is different. It
* gives giving precedence to the more specific style property. For example,
@@ -13,13 +19,8 @@
* This module creates mutally exclusive style declarations by expanding all of
* React Native's supported shortform properties (e.g. `padding`) to their
* longfrom equivalents.
*
* @noflow
*/
import normalizeValue from './normalizeValue';
import processColor from '../processColor';
const emptyObject = {};
const styleShortFormProperties = {
borderColor: ['borderTopColor', 'borderRightColor', 'borderBottomColor', 'borderLeftColor'],
@@ -63,7 +64,7 @@ const borderWidthProps = {
const monospaceFontStack = 'monospace, monospace';
const systemFontStack =
'-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Ubuntu, "Helvetica Neue", sans-serif';
'system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Ubuntu, "Helvetica Neue", sans-serif';
const alphaSortProps = propsArray =>
propsArray.sort((a, b) => {
@@ -236,8 +237,10 @@ const createReducer = (style, styleProps) => {
}
case 'fontFamily': {
if (value === 'System') {
resolvedStyle.fontFamily = systemFontStack;
if (value.indexOf('System') > -1) {
const stack = value.split(/\s*,\s*/);
stack[stack.indexOf('System')] = systemFontStack;
resolvedStyle.fontFamily = stack.join(', ');
} else if (value === 'monospace') {
resolvedStyle.fontFamily = monospaceFontStack;
} else {
@@ -246,6 +249,13 @@ const createReducer = (style, styleProps) => {
break;
}
case 'fontVariant': {
if (Array.isArray(value) && value.length > 0) {
resolvedStyle.fontVariant = value.join(' ');
}
break;
}
case 'shadowColor':
case 'shadowOffset':
case 'shadowOpacity':

View File

@@ -1,8 +1,7 @@
/**
* Copyright (c) 2016-present, Nicolas Gallagher.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @noflow

View File

@@ -1,9 +1,8 @@
/**
* Copyright (c) 2015-present, Nicolas Gallagher.
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @providesModule flattenStyle

View File

@@ -1,8 +1,7 @@
/**
* Copyright (c) 2016-present, Nicolas Gallagher.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @noflow
@@ -13,75 +12,119 @@ import multiplyStyleLengthValue from '../../modules/multiplyStyleLengthValue';
const emptyObject = {};
/**
* Map of property names to their BiDi equivalent.
*/
const PROPERTIES_TO_SWAP = {
borderTopLeftRadius: 'borderTopRightRadius',
borderTopRightRadius: 'borderTopLeftRadius',
borderBottomLeftRadius: 'borderBottomRightRadius',
borderBottomRightRadius: 'borderBottomLeftRadius',
borderLeftColor: 'borderRightColor',
borderLeftStyle: 'borderRightStyle',
borderLeftWidth: 'borderRightWidth',
borderRightColor: 'borderLeftColor',
borderRightWidth: 'borderLeftWidth',
borderRightStyle: 'borderLeftStyle',
left: 'right',
marginLeft: 'marginRight',
marginRight: 'marginLeft',
paddingLeft: 'paddingRight',
paddingRight: 'paddingLeft',
right: 'left'
const borderTopLeftRadius = 'borderTopLeftRadius';
const borderTopRightRadius = 'borderTopRightRadius';
const borderBottomLeftRadius = 'borderBottomLeftRadius';
const borderBottomRightRadius = 'borderBottomRightRadius';
const borderLeftColor = 'borderLeftColor';
const borderLeftStyle = 'borderLeftStyle';
const borderLeftWidth = 'borderLeftWidth';
const borderRightColor = 'borderRightColor';
const borderRightStyle = 'borderRightStyle';
const borderRightWidth = 'borderRightWidth';
const right = 'right';
const marginLeft = 'marginLeft';
const marginRight = 'marginRight';
const paddingLeft = 'paddingLeft';
const paddingRight = 'paddingRight';
const left = 'left';
// Map of LTR property names to their BiDi equivalent.
const PROPERTIES_FLIP = {
borderTopLeftRadius: borderTopRightRadius,
borderTopRightRadius: borderTopLeftRadius,
borderBottomLeftRadius: borderBottomRightRadius,
borderBottomRightRadius: borderBottomLeftRadius,
borderLeftColor: borderRightColor,
borderLeftStyle: borderRightStyle,
borderLeftWidth: borderRightWidth,
borderRightColor: borderLeftColor,
borderRightStyle: borderLeftStyle,
borderRightWidth: borderLeftWidth,
left: right,
marginLeft: marginRight,
marginRight: marginLeft,
paddingLeft: paddingRight,
paddingRight: paddingLeft,
right: left
};
const PROPERTIES_SWAP_LEFT_RIGHT = {
// Map of I18N property names to their LTR equivalent.
const PROPERTIES_I18N = {
borderTopStartRadius: borderTopLeftRadius,
borderTopEndRadius: borderTopRightRadius,
borderBottomStartRadius: borderBottomLeftRadius,
borderBottomEndRadius: borderBottomRightRadius,
borderStartColor: borderLeftColor,
borderStartStyle: borderLeftStyle,
borderStartWidth: borderLeftWidth,
borderEndColor: borderRightColor,
borderEndStyle: borderRightStyle,
borderEndWidth: borderRightWidth,
end: right,
marginStart: marginLeft,
marginEnd: marginRight,
paddingStart: paddingLeft,
paddingEnd: paddingRight,
start: left
};
const PROPERTIES_VALUE = {
clear: true,
float: true,
textAlign: true
};
/**
* Invert the sign of a numeric-like value
*/
// Invert the sign of a numeric-like value
const additiveInverse = (value: String | Number) => multiplyStyleLengthValue(value, -1);
/**
* BiDi flip the given property.
*/
const flipProperty = (prop: String): String => {
return PROPERTIES_TO_SWAP.hasOwnProperty(prop) ? PROPERTIES_TO_SWAP[prop] : prop;
};
const swapLeftRight = (value: String): String => {
return value === 'left' ? 'right' : value === 'right' ? 'left' : value;
};
const i18nStyle = originalStyle => {
if (!I18nManager.isRTL) {
return originalStyle;
}
const { doLeftAndRightSwapInRTL, isRTL } = I18nManager;
const style = originalStyle || emptyObject;
const frozenProps = {};
const nextStyle = {};
for (const prop in style) {
if (!Object.prototype.hasOwnProperty.call(style, prop)) {
for (const originalProp in style) {
if (!Object.prototype.hasOwnProperty.call(style, originalProp)) {
continue;
}
const originalValue = style[originalProp];
let prop = originalProp;
let value = originalValue;
const value = style[prop];
// BiDi flip properties
if (PROPERTIES_I18N.hasOwnProperty(originalProp)) {
// convert start/end
const convertedProp = PROPERTIES_I18N[originalProp];
prop = isRTL ? PROPERTIES_FLIP[convertedProp] : convertedProp;
} else if (isRTL && doLeftAndRightSwapInRTL && PROPERTIES_FLIP[originalProp]) {
prop = PROPERTIES_FLIP[originalProp];
}
if (PROPERTIES_TO_SWAP[prop]) {
const newProp = flipProperty(prop);
nextStyle[newProp] = value;
} else if (PROPERTIES_SWAP_LEFT_RIGHT[prop]) {
nextStyle[prop] = swapLeftRight(value);
} else if (prop === 'textShadowOffset') {
// BiDi flip values
if (PROPERTIES_VALUE.hasOwnProperty(originalProp)) {
if (originalValue === 'start') {
value = isRTL ? 'right' : 'left';
} else if (originalValue === 'end') {
value = isRTL ? 'left' : 'right';
} else if (isRTL && doLeftAndRightSwapInRTL) {
if (originalValue === 'left') {
value = 'right';
} else if (originalValue === 'right') {
value = 'left';
}
}
}
if (isRTL && prop === 'textShadowOffset') {
nextStyle[prop] = value;
nextStyle[prop].width = additiveInverse(value.width);
} else {
nextStyle[prop] = style[prop];
} else if (!frozenProps[prop]) {
nextStyle[prop] = value;
}
if (PROPERTIES_I18N[originalProp]) {
frozenProps[prop] = true;
}
}

View File

@@ -1,8 +1,7 @@
/**
* Copyright (c) 2016-present, Nicolas Gallagher.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow

View File

@@ -1,8 +1,7 @@
/**
* Copyright (c) 2016-present, Nicolas Gallagher.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @noflow

View File

@@ -1,8 +1,7 @@
/**
* Copyright (c) 2016-present, Nicolas Gallagher.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow

View File

@@ -1,8 +1,7 @@
/**
* Copyright (c) 2016-present, Nicolas Gallagher.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @providesModule Switch
@@ -136,7 +135,7 @@ class Switch extends Component<*> {
thumbStyle,
value && styles.thumbOn,
{
marginLeft: value ? multiplyStyleLengthValue(thumbWidth, -1) : 0
marginStart: value ? multiplyStyleLengthValue(thumbWidth, -1) : 0
}
]}
/>
@@ -192,12 +191,12 @@ const styles = StyleSheet.create({
alignSelf: 'flex-start',
borderRadius: '100%',
boxShadow: thumbDefaultBoxShadow,
left: '0%',
start: '0%',
transform: [{ translateZ: 0 }],
transitionDuration: '0.1s'
},
thumbOn: {
left: '100%'
start: '100%'
},
disabledThumb: {
backgroundColor: '#BDBDBD'

View File

@@ -1,9 +1,8 @@
/**
* Copyright (c) 2015-present, Nicolas Gallagher.
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @providesModule TextPropTypes
@@ -24,6 +23,9 @@ const TextPropTypes = {
children: any,
importantForAccessibility: oneOf(['auto', 'no', 'no-hide-descendants', 'yes']),
numberOfLines: number,
onBlur: func,
onContextMenu: func,
onFocus: func,
onLayout: func,
onPress: func,
selectable: bool,

View File

@@ -1,9 +1,8 @@
/**
* Copyright (c) 2015-present, Nicolas Gallagher.
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
@@ -11,14 +10,10 @@
import ColorPropType from '../ColorPropType';
import ViewStylePropTypes from '../View/ViewStylePropTypes';
import { number, oneOf, oneOfType, shape, string } from 'prop-types';
import { array, number, oneOf, oneOfType, shape, string } from 'prop-types';
const numberOrString = oneOfType([number, string]);
const ShadowOffsetPropType = shape({ width: number, height: number });
const TextAlignPropType = oneOf(['center', 'inherit', 'justify', 'justify-all', 'left', 'right']);
const WritingDirectionPropType = oneOf(['auto', 'ltr', 'rtl']);
const TextStylePropTypes = {
...ViewStylePropTypes,
color: ColorPropType,
@@ -27,17 +22,27 @@ const TextStylePropTypes = {
fontSize: numberOrString,
fontStyle: string,
fontWeight: string,
fontVariant: array,
letterSpacing: numberOrString,
lineHeight: numberOrString,
textAlign: TextAlignPropType,
textAlign: oneOf([
'center',
'end',
'inherit',
'justify',
'justify-all',
'left',
'right',
'start'
]),
textAlignVertical: string,
textDecorationColor: ColorPropType,
textDecorationLine: string,
textDecorationStyle: string,
textShadowColor: ColorPropType,
textShadowOffset: ShadowOffsetPropType,
textShadowOffset: shape({ width: number, height: number }),
textShadowRadius: number,
writingDirection: WritingDirectionPropType,
writingDirection: oneOf(['auto', 'ltr', 'rtl']),
/* @platform web */
textIndent: numberOrString,
textOverflow: string,

View File

@@ -2,7 +2,7 @@
exports[`components/Text prop "onPress" 1`] = `
<div
className="rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-color-homxoj rn-cursor-1loqt21 rn-display-1471scf rn-font-1lw9tu2 rn-fontFamily-10u92zi rn-fontSize-1b43r93 rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-textDecoration-bauka4 rn-whiteSpace-q42fyq rn-wordWrap-qvutc0"
className="rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-color-homxoj rn-cursor-1loqt21 rn-display-1471scf rn-font-1lw9tu2 rn-fontFamily-14xgk7a rn-fontSize-1b43r93 rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-textDecoration-bauka4 rn-whiteSpace-q42fyq rn-wordWrap-qvutc0"
dir="auto"
onClick={[Function]}
onKeyDown={[Function]}
@@ -12,14 +12,14 @@ exports[`components/Text prop "onPress" 1`] = `
exports[`components/Text prop "selectable" 1`] = `
<div
className="rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-color-homxoj rn-display-1471scf rn-font-1lw9tu2 rn-fontFamily-10u92zi rn-fontSize-1b43r93 rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-textDecoration-bauka4 rn-whiteSpace-q42fyq rn-wordWrap-qvutc0"
className="rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-color-homxoj rn-display-1471scf rn-font-1lw9tu2 rn-fontFamily-14xgk7a rn-fontSize-1b43r93 rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-textDecoration-bauka4 rn-whiteSpace-q42fyq rn-wordWrap-qvutc0"
dir="auto"
/>
`;
exports[`components/Text prop "selectable" 2`] = `
<div
className="rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-color-homxoj rn-display-1471scf rn-font-1lw9tu2 rn-fontFamily-10u92zi rn-fontSize-1b43r93 rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-textDecoration-bauka4 rn-userSelect-lrvibr rn-whiteSpace-q42fyq rn-wordWrap-qvutc0"
className="rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-color-homxoj rn-display-1471scf rn-font-1lw9tu2 rn-fontFamily-14xgk7a rn-fontSize-1b43r93 rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-textDecoration-bauka4 rn-userSelect-lrvibr rn-whiteSpace-q42fyq rn-wordWrap-qvutc0"
dir="auto"
/>
`;

View File

@@ -1,9 +1,8 @@
/**
* Copyright (c) 2015-present, Nicolas Gallagher.
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @providesModule Text
@@ -54,6 +53,7 @@ class Text extends Component<*> {
selectionColor,
suppressHighlighting,
textBreakStrategy,
tvParallaxProperties,
/* eslint-enable */
...otherProps
} = this.props;
@@ -110,6 +110,7 @@ const styles = StyleSheet.create({
// inherit parent font styles
fontFamily: 'inherit',
fontSize: 'inherit',
fontVariant: ['inherit'],
whiteSpace: 'inherit'
},
notSelectable: {

View File

@@ -1,8 +1,7 @@
/**
* Copyright (c) 2015-present, Nicolas Gallagher.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow

View File

@@ -1,6 +1,7 @@
/* eslint-env jasmine, jest */
import React from 'react';
import ReactDOM from 'react-dom';
import TextInput from '..';
import { mount, shallow } from 'enzyme';
@@ -112,8 +113,14 @@ describe('components/TextInput', () => {
test('prop "onBlur"', () => {
const onBlur = jest.fn();
const input = findNativeInput(mount(<TextInput onBlur={onBlur} />));
const node = ReactDOM.findDOMNode(input.instance());
// more accurate blur simulation
input.simulate('blur');
node.blur();
expect(onBlur).toHaveBeenCalledTimes(1);
expect(TextInput.State.currentlyFocusedField()).toBe(null);
});
test('prop "onChange"', () => {
@@ -135,8 +142,14 @@ describe('components/TextInput', () => {
test('prop "onFocus"', () => {
const onFocus = jest.fn();
const input = findNativeInput(mount(<TextInput onFocus={onFocus} />));
const node = ReactDOM.findDOMNode(input.instance());
// more accurate focus simulation
input.simulate('focus');
node.focus();
expect(onFocus).toHaveBeenCalledTimes(1);
expect(TextInput.State.currentlyFocusedField()).toBe(node);
});
describe('prop "onKeyPress"', () => {
@@ -216,6 +229,25 @@ describe('components/TextInput', () => {
);
});
test('arrow key', () => {
const onKeyPress = jest.fn();
const input = findNativeInput(mount(<TextInput onKeyPress={onKeyPress} />));
input.simulate('keyPress', { which: 37 });
expect(onKeyPress).toHaveBeenCalledTimes(1);
expect(onKeyPress).toBeCalledWith(
expect.objectContaining({
nativeEvent: {
altKey: undefined,
ctrlKey: undefined,
key: 'ArrowLeft',
metaKey: undefined,
shiftKey: undefined,
target: expect.anything()
}
})
);
});
test('text key', () => {
const onKeyPress = jest.fn();
const input = findNativeInput(mount(<TextInput onKeyPress={onKeyPress} />));

View File

@@ -1,9 +1,8 @@
/**
* Copyright (c) 2015-present, Nicolas Gallagher.
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @providesModule TextInput
@@ -162,6 +161,9 @@ class TextInput extends Component<*> {
componentDidMount() {
setSelection(this._node, this.props.selection);
if (document.activeElement === this._node) {
TextInputState._currentlyFocusedNode = this._node;
}
}
componentDidUpdate() {
@@ -264,7 +266,7 @@ class TextInput extends Component<*> {
_handleBlur = e => {
const { onBlur } = this.props;
TextInputState.blurTextInput(this._node);
TextInputState._currentlyFocusedNode = null;
if (onBlur) {
onBlur(e);
}
@@ -284,7 +286,7 @@ class TextInput extends Component<*> {
_handleFocus = e => {
const { clearTextOnFocus, onFocus, selectTextOnFocus } = this.props;
const node = this._node;
TextInputState.focusTextInput(this._node);
TextInputState._currentlyFocusedNode = this._node;
if (onFocus) {
onFocus(e);
}
@@ -297,11 +299,19 @@ class TextInput extends Component<*> {
};
_handleKeyDown = e => {
// prevent key events bubbling (see #612)
// Prevent key events bubbling (see #612)
e.stopPropagation();
// Backspace, Tab, and Cmd+Enter only fire 'keydown' DOM events
if (e.which === 8 || e.which === 9 || (e.which === 13 && e.metaKey)) {
// Backspace, Tab, Cmd+Enter, and Arrow keys only fire 'keydown' DOM events
if (
e.which === 8 ||
e.which === 9 ||
(e.which === 13 && e.metaKey) ||
e.which === 37 ||
e.which === 38 ||
e.which === 39 ||
e.which === 40
) {
this._handleKeyPress(e);
}
};
@@ -314,24 +324,32 @@ class TextInput extends Component<*> {
if (onKeyPress) {
let keyValue;
switch (e.which) {
// backspace
case 8:
keyValue = 'Backspace';
break;
// tab
case 9:
keyValue = 'Tab';
break;
// enter
case 13:
keyValue = 'Enter';
break;
// spacebar
case 32:
keyValue = ' ';
break;
case 37:
keyValue = 'ArrowLeft';
break;
case 38:
keyValue = 'ArrowUp';
break;
case 39:
keyValue = 'ArrowRight';
break;
case 40:
keyValue = 'ArrowDown';
break;
default: {
// we trim to only care about the keys that has a textual representation
// Trim to only care about the keys that have a textual representation
if (e.shiftKey) {
keyValue = String.fromCharCode(e.which).trim();
} else {
@@ -398,8 +416,8 @@ const styles = StyleSheet.create({
borderStyle: 'solid',
borderWidth: 0,
boxSizing: 'border-box',
color: 'inherit',
font: 'inherit',
fontFamily: 'System',
fontSize: 14,
padding: 0,
resize: 'none'
}

View File

@@ -1,8 +1,7 @@
/**
* Copyright (c) 2015-present, Nicolas Gallagher.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow

View File

@@ -1,8 +1,7 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @noflow

View File

@@ -1,8 +1,7 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @providesModule ensurePositiveDelayProps

View File

@@ -3,9 +3,8 @@
/**
* Copyright (c) 2016-present, Nicolas Gallagher.
* Copyright (c) 2013-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @providesModule Touchable
@@ -425,13 +424,6 @@ const TouchableMixin = {
*/
touchableHandleResponderRelease: function(e: Event) {
this._receiveSignal(Signals.RESPONDER_RELEASE, e);
// Browsers fire mouse events after touch events. This causes the
// 'onResponderRelease' handler to be called twice for Touchables.
// Auto-fix this issue by calling 'preventDefault' to cancel the mouse
// events.
if (e.cancelable && !e.isDefaultPrevented()) {
e.preventDefault();
}
},
/**

View File

@@ -1,9 +1,8 @@
/**
* Copyright (c) 2016-present, Nicolas Gallagher.
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @providesModule TouchableHighlight
@@ -287,7 +286,7 @@ const styles = StyleSheet.create({
},
actionable: {
cursor: 'pointer',
touchAction: 'manipulate'
touchAction: 'manipulation'
}
});

View File

@@ -1,8 +1,7 @@
/**
* Copyright 2017-present, Nicolas Gallagher
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow

View File

@@ -1,9 +1,8 @@
/**
* Copyright (c) 2016-present, Nicolas Gallagher.
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @providesModule TouchableOpacity
@@ -204,7 +203,7 @@ const styles = StyleSheet.create({
},
actionable: {
cursor: 'pointer',
touchAction: 'manipulate'
touchAction: 'manipulation'
}
});

View File

@@ -1,9 +1,8 @@
/**
* Copyright (c) 2016-present, Nicolas Gallagher.
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @providesModule TouchableWithoutFeedback
@@ -202,7 +201,7 @@ const TouchableWithoutFeedback = createReactClass({
const styles = StyleSheet.create({
actionable: {
cursor: 'pointer',
touchAction: 'manipulate'
touchAction: 'manipulation'
}
});

View File

@@ -1,8 +1,7 @@
/**
* Copyright (c) 2016-present, Nicolas Gallagher.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @providesModule UIManager
@@ -16,11 +15,13 @@ import setValueForStyles from '../../vendor/setValueForStyles';
const getRect = node => {
const height = node.offsetHeight;
const width = node.offsetWidth;
let left = 0;
let top = 0;
let left = node.offsetLeft;
let top = node.offsetTop;
node = node.offsetParent;
while (node && node.nodeType === 1 /* Node.ELEMENT_NODE */) {
left += node.offsetLeft;
top += node.offsetTop;
left += node.offsetLeft - node.scrollLeft;
top += node.offsetTop - node.scrollTop;
node = node.offsetParent;
}
return { height, left, top, width };

View File

@@ -1,9 +1,8 @@
/**
* Copyright (c) 2016-present, Nicolas Gallagher.
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @providesModule Vibration

View File

@@ -1,9 +1,8 @@
/**
* Copyright (c) 2015-present, Nicolas Gallagher.
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @providesModule ViewPropTypes
@@ -13,7 +12,7 @@
import EdgeInsetsPropType, { type EdgeInsetsProp } from '../EdgeInsetsPropType';
import StyleSheetPropType from '../../modules/StyleSheetPropType';
import ViewStylePropTypes from './ViewStylePropTypes';
import { any, array, bool, func, oneOf, oneOfType, string } from 'prop-types';
import { any, array, bool, func, object, oneOf, oneOfType, string } from 'prop-types';
const stylePropType = StyleSheetPropType(ViewStylePropTypes);
@@ -40,8 +39,11 @@ export type ViewProps = {
children?: any,
hitSlop?: EdgeInsetsProp,
importantForAccessibility?: 'auto' | 'yes' | 'no' | 'no-hide-descendants',
onBlur?: Function,
onClick?: Function,
onClickCapture?: Function,
onContextMenu?: Function,
onFocus?: Function,
onLayout?: (event: ViewLayoutEvent) => void,
onResponderGrant?: Function,
onResponderMove?: Function,
@@ -72,7 +74,8 @@ export type ViewProps = {
onMagicTap?: Function,
removeClippedSubviews?: boolean,
renderToHardwareTextureAndroid?: boolean,
shouldRasterizeIOS?: boolean
shouldRasterizeIOS?: boolean,
tvParallaxProperties?: {}
};
const ViewPropTypes = {
@@ -85,8 +88,11 @@ const ViewPropTypes = {
children: any,
hitSlop: EdgeInsetsPropType,
importantForAccessibility: oneOf(['auto', 'no', 'no-hide-descendants', 'yes']),
onBlur: func,
onClick: func,
onClickCapture: func,
onContextMenu: func,
onFocus: func,
onLayout: func,
onMoveShouldSetResponder: func,
onMoveShouldSetResponderCapture: func,
@@ -117,7 +123,8 @@ const ViewPropTypes = {
onMagicTap: func,
removeClippedSubviews: bool,
renderToHardwareTextureAndroid: bool,
shouldRasterizeIOS: bool
shouldRasterizeIOS: bool,
tvParallaxProperties: object
};
export default ViewPropTypes;

View File

@@ -1,9 +1,8 @@
/**
* Copyright (c) 2015-present, Nicolas Gallagher.
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
@@ -12,16 +11,18 @@
import AnimationPropTypes from '../../modules/AnimationPropTypes';
import BorderPropTypes from '../../modules/BorderPropTypes';
import ColorPropType from '../ColorPropType';
import InteractionPropTypes from '../../modules/InteractionPropTypes';
import LayoutPropTypes from '../../modules/LayoutPropTypes';
import ShadowPropTypes from '../../modules/ShadowPropTypes';
import TransformPropTypes from '../../modules/TransformPropTypes';
import { number, oneOf, oneOfType, string } from 'prop-types';
import { number, oneOf, string } from 'prop-types';
const overscrollBehaviorType = oneOf(['auto', 'contain', 'none']);
const ViewStylePropTypes = {
...AnimationPropTypes,
...BorderPropTypes,
...InteractionPropTypes,
...LayoutPropTypes,
...ShadowPropTypes,
...TransformPropTypes,
@@ -44,22 +45,12 @@ const ViewStylePropTypes = {
backgroundSize: string,
boxShadow: string,
clip: string,
cursor: string,
filter: string,
outline: string,
outlineColor: ColorPropType,
overscrollBehavior: overscrollBehaviorType,
overscrollBehaviorX: overscrollBehaviorType,
overscrollBehaviorY: overscrollBehaviorType,
perspective: oneOfType([number, string]),
perspectiveOrigin: string,
touchAction: string,
transitionDelay: string,
transitionDuration: string,
transitionProperty: string,
transitionTimingFunction: string,
userSelect: string,
willChange: string,
WebkitMaskImage: string,
WebkitOverflowScrolling: oneOf(['auto', 'touch'])
};

View File

@@ -49,6 +49,7 @@ class View extends Component<ViewProps> {
removeClippedSubviews,
renderToHardwareTextureAndroid,
shouldRasterizeIOS,
tvParallaxProperties,
/* eslint-enable */
...otherProps
} = this.props;

View File

@@ -3,7 +3,10 @@
exports[`modules/createElement it normalizes event.nativeEvent 1`] = `
Object {
"_normalized": true,
"bubbles": undefined,
"cancelable": undefined,
"changedTouches": Array [],
"defaultPrevented": undefined,
"identifier": undefined,
"locationX": undefined,
"locationY": undefined,
@@ -15,6 +18,8 @@ Object {
"target": undefined,
"timestamp": 1496876171255,
"touches": Array [],
"type": undefined,
"which": undefined,
}
`;

View File

@@ -1,8 +1,7 @@
/**
* Copyright (c) 2015-present, Nicolas Gallagher.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @noflow
@@ -22,18 +21,12 @@ import React from 'react';
* and remove event handlers when disabled.
*/
const eventHandlerNames = {
onBlur: true,
onClick: true,
onClickCapture: true,
onMoveShouldSetResponder: true,
onMoveShouldSetResponderCapture: true,
onResponderGrant: true,
onResponderMove: true,
onResponderReject: true,
onContextMenu: true,
onFocus: true,
onResponderRelease: true,
onResponderTerminate: true,
onResponderTerminationRequest: true,
onStartShouldSetResponder: true,
onStartShouldSetResponderCapture: true,
onTouchCancel: true,
onTouchCancelCapture: true,
onTouchEnd: true,
@@ -53,6 +46,17 @@ const adjustProps = domProps => {
if (isEventHandler) {
if (isButtonRole && isDisabled) {
domProps[propName] = undefined;
} else if (propName === 'onResponderRelease') {
// Browsers fire mouse events after touch events. This causes the
// 'onResponderRelease' handler to be called twice for Touchables.
// Auto-fix this issue by calling 'preventDefault' to cancel the mouse
// events.
domProps[propName] = e => {
if (e.cancelable && !e.isDefaultPrevented()) {
e.preventDefault();
}
return prop(e);
};
} else {
// TODO: move this out of the render path
domProps[propName] = e => {

View File

@@ -1,8 +1,7 @@
/**
* Copyright (c) 2016-present, Nicolas Gallagher.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @providesModule findNodeHandle

View File

@@ -1,9 +1,8 @@
/**
* Copyright (c) 2016-present, Nicolas Gallagher.
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @providesModule processColor

View File

@@ -1,8 +1,7 @@
/**
* Copyright (c) 2016-present, Nicolas Gallagher.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @noflow

View File

@@ -1,8 +1,7 @@
/**
* Copyright (c) 2016-present, Nicolas Gallagher.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @noflow

View File

@@ -1,8 +1,7 @@
/**
* Copyright (c) 2017-present, Nicolas Gallagher.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow

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