Compare commits

...

103 Commits

Author SHA1 Message Date
Nicolas Gallagher
f391031fb1 0.0.74 2017-02-27 14:55:34 -08:00
Matthias Le Brun
77799abf9b [fix] Touchable support for 'Enter' keypress event
Close #375
2017-02-27 14:53:27 -08:00
Nicolas Gallagher
2cfd09ecdb [fix] server-side rendering
e1fc253 added deferred image loading but didn't guard the
'requestIdleFallback' shim for use in Node.js

Fix #376
2017-02-27 14:50:29 -08:00
Nicolas Gallagher
89eea2b366 Remove unused style in 'View' 2017-02-27 14:41:47 -08:00
Nicolas Gallagher
18440158b3 Add comparative performance benchmarks
Includes a 'css-modules' implementation of the nested trees to act as a
baseline for comparison.
2017-02-26 17:19:43 -08:00
Nicolas Gallagher
24eda7c4ad 0.0.73 2017-02-24 12:35:18 -08:00
Nicolas Gallagher
44ebd8f5a3 [change] modality-specific focus styles
Remove the default focus ring when the keyboard is not being used. This
provides a superior UX when using touch or mouse.

Fix #310
2017-02-18 13:39:25 -08:00
Matthias Le Brun
a3ed8f05e6 [add] resize 'TextInput' style
Fix #363
2017-02-18 12:49:25 -08:00
Nicolas Gallagher
b653fe0bd3 [add] fontFeatureSettings 'Text' style
Fix #331
2017-02-18 12:18:28 -08:00
Nicolas Gallagher
30da226e4d Update component style docs 2017-02-18 12:07:30 -08:00
Nicolas Gallagher
f1f39bfabd 0.0.72 2017-02-18 11:34:33 -08:00
Nicolas Gallagher
267c5aab7e Allow benchmark to run in Safari
Performing teardown in a new frame was causing Safari to hang on the 2nd
benchmark run.
2017-02-18 11:34:33 -08:00
Nicolas Gallagher
fe71c7efe5 [fix] Image browser context menu
Fix #368
2017-02-18 11:34:28 -08:00
Nicolas Gallagher
eb59875bed [change] defer Image loading
x4 faster render benchmark
2017-02-18 09:46:10 -08:00
Nicolas Gallagher
e1fc253277 Add image benchmark 2017-02-18 09:46:10 -08:00
Nicolas Gallagher
40b03aca52 [change] improve 'View' render performance
1. Register the 'pointerEvents' styles to enable memoization
2. Don't flatten styles in render; move flex reset to 'expandStyle'

Reduces benchmark render times by ~10% on early 2011 MacBook Pro
2017-02-18 09:46:04 -08:00
Nicolas Gallagher
418a1a9516 [change] depend on animated@0.2.0 2017-02-17 13:28:51 -08:00
Nicolas Gallagher
8762f8e9c8 [change] depend on inline-style-prefixer@3.0.0 2017-02-17 13:28:49 -08:00
Nicolas Gallagher
10ef2bfe20 [fix] i18n styles
1. Fix auto-flipping of styles

The StyleRegistry didn't account for LTR/RTL when caching the results of
style resolution. The 'writingDirection' style is no longer flipped; no
clear use case for it.

2. Remove experimental '$noI18n' style prop suffix

This feature is essentially unused, and less likely to be used with the
introduction of 'dir=auto' on 'Text'. Removing also marginally improves
render performance.
2017-02-17 13:25:54 -08:00
Nicolas Gallagher
6d2ae4597e Update babel packages 2017-02-17 12:04:30 -08:00
Nicolas Gallagher
a34b8b149f [fix] V8 deopt in compiled 'createDOMElement'
Fixes V8 "deopt" warning: "Bad value context for arguments value".

This deopt was caused by the babel-compiled output of the ES6 argument
default value for 'rnProps':

    var t = arguments.length > 1 && void 0 !== arguments[1]
      ? arguments[1]
      : l

Not relying on ES6 default arguments avoids the function 'deopt'.
2017-02-17 10:23:59 -08:00
Nicolas Gallagher
6166024d15 [fix] NODE_ENV check in 'flattenStyle' 2017-02-17 09:59:56 -08:00
Nicolas Gallagher
701ecb7c52 0.0.71 2017-02-17 08:54:33 -08:00
Li Hau Tan
75042093c2 [fix] add 'State' static to 'TextInput'
Fix #365
Close #366
2017-02-17 08:51:22 -08:00
Nathan Tran
bb417900a9 [add] willChange style prop type
Close #367
2017-02-17 08:44:12 -08:00
Nicolas Gallagher
89e0a15d1b [fix] add 'timeStamp' to scroll and layout events 2017-02-16 08:18:56 -08:00
Nicolas Gallagher
b2e0a3702f [fix] Linking methods return promises 2017-02-11 14:13:25 -08:00
Rodrigo Moyle
a4644c204d [fix] add shadow style props to Image styles
Fix #357
Close #358
2017-02-11 11:21:45 -08:00
Nicolas Gallagher
1e9536b611 0.0.70 2017-02-06 17:15:43 -08:00
Nicolas Gallagher
d15dafc108 Build UMD bundle from source 2017-02-06 13:14:48 -08:00
Nicolas Gallagher
c9c1aab97e Rearrange propType imports 2017-02-05 16:50:06 -08:00
Nicolas Gallagher
a2903f9d30 Move TextPropTypes to TextStylePropTypes 2017-02-05 16:37:54 -08:00
Nicolas Gallagher
c7771ac64f [change] avoid 'react-dom/lib/*' where possible 2017-02-05 16:36:26 -08:00
Nicolas Gallagher
c8129c2a99 Remove NODE_ENV wrappers 2017-02-05 16:35:04 -08:00
Matthias Le Brun
b793737393 [fix] onLayout calculation
The 0.0.69 release introduced a regression in UIManager's measurement
calculations.

Using `offset` properties returns the offset relative to the closest
positioned ancestor. Make `getRect` iterate over the ancestor chain.

Fix #341
Close #345
2017-02-05 12:09:42 -08:00
Nicolas Gallagher
2a4d1c81d8 0.0.69 2017-01-28 11:01:23 -08:00
Nicolas Gallagher
a8a25d66ea [fix] measure CSS layout independent of transforms
Fix #332
2017-01-28 10:37:49 -08:00
Gethin Webster
e06d7a9650 [fix] Prevent props warnings from ScrollView in ListView 2017-01-28 10:01:16 -08:00
Nicolas Gallagher
c2501f2bc2 Add documentation for webpack@2 *.web.js resolving
Fix #334
2017-01-28 09:57:14 -08:00
Nicolas Gallagher
c51e7f1965 [fix] Linking method names
Fix #339
2017-01-28 09:50:15 -08:00
Nicolas Gallagher
dfff6b3780 [fix] StyleSheet resolving for 'number' style 2017-01-16 14:36:20 -08:00
Nicolas Gallagher
5f6b4a746a Update webpack-bundler-analyzer 2017-01-13 13:21:23 -08:00
Nicolas Gallagher
f077907dd4 Fix AppRegistry/renderApplication snapshot 2017-01-11 13:15:07 -08:00
Nicolas Gallagher
a94367bdcb 0.0.68 2017-01-11 13:12:25 -08:00
Nicolas Gallagher
65febbbc52 [fix] error in setNativeProps when no style
Close #325
Close #327
2017-01-11 13:08:10 -08:00
Nicolas Gallagher
b14d2e5bd8 [fix] CSS pointer event selectors 2017-01-11 12:47:24 -08:00
Nicolas Gallagher
7c83ba162d 0.0.67 2017-01-08 18:40:02 -08:00
Nicolas Gallagher
3ffc005a7b [fix] setNativeProps resolving logic
Since styles are set using both class names and inline styles,
'setNativeProps' needs an additional resolving step that accounts for
the pre-existing state of RN-managed styles on the DOM node.

Fix #321
2017-01-08 18:25:39 -08:00
Nicolas Gallagher
50a70ad02f 0.0.66 2017-01-07 19:05:54 -08:00
Nicolas Gallagher
768e895701 [fix] View transforms; add perspective styles
Fixes a regression introduced by
5db300df35

The `perspective` function is distinct from the `perspective` property.
This patch reverts the regression and adds support for `perspective`,
`perspectiveOrigin`, and `transformOrigin`.

Fix #208
2017-01-07 19:02:57 -08:00
Nicolas Gallagher
af5fde994d Fix yarn.lock 2017-01-07 18:25:54 -08:00
Paul Le Cam
c3d0763944 [fix] ListView imports and 'getRowAndSectionCount'
Close #316
2017-01-07 18:22:47 -08:00
Nicolas Gallagher
0aba506725 Fix UIManager tests 2017-01-07 18:18:56 -08:00
Nicolas Gallagher
91032d8565 [change] allow 'display' in ViewStylePropTypes
Fix #296
2017-01-07 18:15:16 -08:00
Nicolas Gallagher
0696721488 Document transition and animation View styles 2017-01-07 18:12:26 -08:00
Nicolas Gallagher
fe18830ce6 [change] use classList in UIManager
Prevent setting the same class multiple times
2017-01-07 18:03:51 -08:00
Nicolas Gallagher
1b86d02300 [change] wrap layout measurement in 'asap' 2017-01-07 18:03:03 -08:00
Nicolas Gallagher
c56b472258 [change] depend on normalize-css-color
Fix #308
2017-01-07 18:00:17 -08:00
Nicolas Gallagher
b00132f007 [fix] TouchableOpacity transition duration 2017-01-07 17:50:59 -08:00
Nicolas Gallagher
8b8f8f0374 [fix] CSS properties that support unitless numbers 2017-01-05 14:47:10 -08:00
Nicolas Gallagher
8e94af34e1 Remove use of 'keyOf' 2017-01-05 14:47:10 -08:00
Nicolas Gallagher
7ffaf592d5 [fix] Text automatic writing direction detection 2017-01-05 14:47:08 -08:00
Nicolas Gallagher
a1017fa785 0.0.65 2017-01-04 18:25:39 -08:00
Nicolas Gallagher
5db300df35 [fix] transform perspective resolution 2017-01-04 18:04:15 -08:00
Nicolas Gallagher
214d862e61 [add] ScrollView to Animated 2017-01-04 18:04:05 -08:00
Nicolas Gallagher
4ef5453b33 0.0.64 2017-01-04 10:58:15 -08:00
Nicolas Gallagher
a27671d7cf [fix] passing on RN style props in createDOMElement
The 'createDOMElement' function wasn't pulling 'style' out of the
props. A change to the logic that sets DOM props meant that if
'StyleRegistry.resolve' didn't return a 'style' object, the React Native
styles would be passed through to the underlying DOM node.

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

Typical mean (and first) task duration.

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

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

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

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

Fix #306
2017-01-01 14:43:47 -08:00
Nicolas Gallagher
351c0ac3d4 Minor changes 2016-12-30 22:19:51 -08:00
Nicolas Gallagher
877c0d2818 Simplify StyleSheet's expandStyle 2016-12-30 22:14:39 -08:00
Nicolas Gallagher
3afc5d5de6 Rename style processors to resolvers 2016-12-29 19:17:12 -08:00
Nicolas Gallagher
edf3b9b7ff Move 'flattenStyle' into 'StyleSheet' 2016-12-29 16:31:14 -08:00
Nicolas Gallagher
518a85bf1b Rename 'createReactStyleObject' to 'createReactDOMStyle' 2016-12-29 16:26:31 -08:00
vaukalak
ba75acb66a [add] BackAndroid API stub 2016-12-27 18:14:31 +00:00
Nicolas Gallagher
bc68b0b6f4 0.0.61 2016-12-27 18:09:11 +00:00
Nicolas Gallagher
44ecbc072e [change] update React and Touchables
Update to React@15.4. The 'EventConstants' module no longer exports a
key-mirror, which was preventing the 'ResponderEventPlugin' from working
as it did with React@15.3.

Close #255
2016-12-27 17:57:27 +00:00
Nicolas Gallagher
4cf4905fc2 [change] add support for ShadowPropTypes
Fix #44
2016-12-26 13:57:19 +00:00
Nicolas Gallagher
509920be4b [add] Image 'prefetch' and 'getSize' statics
Fix #160
2016-12-26 13:31:40 +00:00
Gethin Webster
04e3c23e67 [fix] ListView updates rows when dataSource changes
Close #295
2016-12-23 12:51:40 +00:00
Nicolas Gallagher
32f454de66 [change] add Platform and Touchable to 'core' module 2016-12-23 12:45:54 +00:00
Nicolas Gallagher
1273bfc7cf Address avoidable object creation 2016-12-23 12:22:32 +00:00
Nicolas Gallagher
dc7f526f6b [fix] TextInput props
- Add missing 'onSubmitEditing' propType and test
- Add 'dir=auto' DOM attribute to allow browser to switch writing
  direction for RTL languages
2016-12-17 23:38:36 +00:00
Nicolas Gallagher
7cda89c5ce 0.0.60 2016-12-16 12:15:23 +00:00
Nicolas Gallagher
695eba45af [add] Clipboard API
Close #125
Fix #122
2016-12-16 11:59:22 +00:00
Nicolas Gallagher
92a2cb274a [fix] remove TextInput default flex value 2016-12-16 11:39:12 +00:00
Nicolas Gallagher
b1ca04d11e Rename I18nManager example 2016-12-16 11:35:11 +00:00
170 changed files with 6232 additions and 4184 deletions

View File

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

6
.gitignore vendored
View File

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

View File

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

View File

@@ -27,7 +27,7 @@ online with [React Native for Web: Playground](http://codepen.io/necolas/pen/PZz
To install in your app:
```
npm install --save react@15.3 react-native-web
npm install --save react@15.4 react-native-web
```
Read the [Client and Server rendering](docs/guides/rendering.md) guide.
@@ -70,6 +70,7 @@ Exported modules:
* [`AppRegistry`](docs/apis/AppRegistry.md)
* [`AppState`](docs/apis/AppState.md)
* [`AsyncStorage`](docs/apis/AsyncStorage.md)
* [`Clipboard`](docs/apis/Clipboard.md)
* [`Dimensions`](docs/apis/Dimensions.md)
* [`I18nManager`](docs/apis/I18nManager.md)
* [`NativeMethods`](docs/apis/NativeMethods.md)
@@ -81,6 +82,7 @@ Exported modules:
* [`Vibration`](docs/apis/Vibration.md)
<span id="#why"></span>
## Why?
There are many different teams at Twitter building web applications with React.

16
docs/apis/Clipboard.md Normal file
View File

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

View File

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

View File

@@ -75,6 +75,23 @@ Example usage:
<Image resizeMode={Image.resizeMode.contain} />
```
## Methods
static **getSize**(uri: string, success: (width, height) => {}, failure: function)
Retrieve the width and height (in pixels) of an image prior to displaying it.
This method can fail if the image cannot be found, or fails to download.
(In order to retrieve the image dimensions, the image may first need to be
loaded or downloaded, after which it will be cached. This means that in
principle you could use this method to preload images, however it is not
optimized for that purpose, and may in future be implemented in a way that does
not fully load/download the image data.)
static **prefetch**(url: string): Promise
Prefetches a remote image for later use by downloading it.
## Examples
```js

View File

@@ -63,27 +63,27 @@ Lets the user select the text.
+ ...[View#style](View.md)
+ `color`
+ `fontFamily`
+ `fontFeatureSettings`
+ `fontSize`
+ `fontStyle`
+ `fontWeight`
+ `letterSpacing`
+ `lineHeight`
+ `textAlign`
+ `textAlign`
+ `textAlignVertical`
+ `textDecorationLine`
+ `textOverflow`
+ `textRendering`
+ `textOverflow`
+ `textRendering`
+ `textShadowColor`
+ `textShadowOffset`
+ `textShadowOffset`
+ `textShadowRadius`
+ `textTransform`
+ `unicodeBidi`
+ `textTransform`
+ `unicodeBidi`
+ `whiteSpace`
+ `wordWrap`
+ `writingDirection`
+ `wordWrap`
+ `writingDirection`
This property can be suffixed with `$noI18n` to prevent automatic
bidi-flipping in RTL mode. This is only supported if `Platform.OS === 'web'`.
web only.
**testID**: string

View File

@@ -144,7 +144,9 @@ If `true`, all text will automatically be selected on focus.
**style**: style
+ ...[Text#style](./Text.md)
+ `outline`
+ `resize`
‡ web only.
**testID**: string

View File

@@ -99,39 +99,48 @@ from `style`.
+ `alignContent`
+ `alignItems`
+ `alignSelf`
+ `animationDelay`
+ `animationDirection`
+ `animationDuration`
+ `animationFillMode`
+ `animationIterationCount`
+ `animationName`
+ `animationPlayState`
+ `animationTimingFunction`
+ `backfaceVisibility`
+ `backgroundAttachment`
+ `backgroundClip`
+ `backgroundAttachment`
+ `backgroundClip`
+ `backgroundColor`
+ `backgroundImage`
+ `backgroundOrigin`
+ `backgroundPosition`
+ `backgroundRepeat`
+ `backgroundSize`
+ `backgroundImage`
+ `backgroundOrigin`
+ `backgroundPosition`
+ `backgroundRepeat`
+ `backgroundSize`
+ `borderColor` (single value)
+ `borderTopColor`
+ `borderBottomColor`
+ `borderRightColor`
+ `borderLeftColor`
+ `borderRightColor`
+ `borderLeftColor`
+ `borderRadius` (single value)
+ `borderTopLeftRadius`
+ `borderTopRightRadius`
+ `borderBottomLeftRadius`
+ `borderBottomRightRadius`
+ `borderTopLeftRadius`
+ `borderTopRightRadius`
+ `borderBottomLeftRadius`
+ `borderBottomRightRadius`
+ `borderStyle` (single value)
+ `borderTopStyle`
+ `borderRightStyle`
+ `borderRightStyle`
+ `borderBottomStyle`
+ `borderLeftStyle`
+ `borderLeftStyle`
+ `borderWidth` (single value)
+ `borderBottomWidth`
+ `borderLeftWidth`
+ `borderRightWidth`
+ `borderLeftWidth`
+ `borderRightWidth`
+ `borderTopWidth`
+ `bottom`
+ `boxShadow`
+ `boxSizing`
+ `cursor`
+ `cursor`
+ `display`
+ `flex` (number)
+ `flexBasis`
+ `flexDirection`
@@ -140,12 +149,12 @@ from `style`.
+ `flexWrap`
+ `height`
+ `justifyContent`
+ `left`
+ `left`
+ `margin` (single value)
+ `marginBottom`
+ `marginHorizontal`
+ `marginLeft`
+ `marginRight`
+ `marginLeft`
+ `marginRight`
+ `marginTop`
+ `marginVertical`
+ `maxHeight`
@@ -154,27 +163,35 @@ from `style`.
+ `minWidth`
+ `opacity`
+ `order`
+ `outline`
+ `overflow`
+ `overflowX`
+ `overflowY`
+ `overflowX`
+ `overflowY`
+ `padding` (single value)
+ `paddingBottom`
+ `paddingHorizontal`
+ `paddingLeft`
+ `paddingRight`
+ `paddingLeft`
+ `paddingRight`
+ `paddingTop`
+ `paddingVertical`
+ `perspective`
+ `perspectiveOrigin`
+ `position`
+ `right`
+ `right`
+ `top`
+ `transform`
+ `userSelect`
+ `visibility`
+ `transformOrigin`
+ `transitionDelay`
+ `transitionDuration`
+ `transitionProperty`
+ `transitionTimingFunction`
+ `userSelect`
+ `visibility`
+ `width`
+ `willChange`
+ `zIndex`
This property can be suffixed with `$noI18n` to prevent automatic
bidi-flipping in RTL mode. This is only supported if `Platform.OS === 'web'`.
web only.
Default:

View File

@@ -4,7 +4,7 @@ It is sometimes necessary to make changes directly to a component without using
state/props to trigger a re-render of the entire subtree in the browser, this
is done by directly modifying a DOM node. `setNativeProps` is the React Native
equivalent to setting properties directly on a DOM node. Use direct
manipulation when frequent re-rendering creates a performance bottleneck Direct
manipulation when frequent re-rendering creates a performance bottleneck. Direct
manipulation will not be a tool that you reach for frequently.
## `setNativeProps` and `shouldComponentUpdate`

View File

@@ -4,11 +4,6 @@ To support right-to-left languages, application layout can be automatically
flipped from LTR to RTL. The `I18nManager` API can be used to help with more
fine-grained control and testing of RTL layouts.
React Native for Web provides an experimental feature to support "true left"
and "true right" styles. For example, `left` will be flipped to `right` in RTL
mode, but `left$noI18n` will not. More information is available in the `Text`
and `View` documentation.
## Working with icons and images
Icons and images that must match the LTR or RTL layout of the app need to be manually flipped.

View File

@@ -27,14 +27,48 @@ the `url-loader` to the webpack config:
module.exports = {
// ...
module: {
loaders: {
test: /\.(gif|jpe?g|png|svg)$/,
loader: 'url-loader',
query: { name: '[name].[hash:16].[ext]' }
}
loaders: [
{
test: /\.(gif|jpe?g|png|svg)$/,
loader: 'url-loader',
query: { name: '[name].[hash:16].[ext]' }
}
]
}
};
```
## Dependencies
Many OSS React Native packages are not compiled to ES5 before being published.
This can result in webpack build errors. To avoid this issue you should
configure webpack (or your bundler of choice) to run
`babel-preset-react-native` over the necessary `node_module`. For example:
```js
// webpack.config.js
module.exports = {
// ...
module: {
loaders: [
{
// transpile to ES5
test: /\.jsx?$/,
include: [
path.resolve(__dirname, 'src'),
path.resolve(__dirname, 'node_modules/react-native-something')
],
loader: 'babel-loader',
query: { cacheDirectory: true }
}
]
}
};
```
Please refer to the webpack documentation for more information.
## Web-specific code
Minor platform differences can use the `Platform` module.
@@ -52,7 +86,19 @@ if (Platform.OS === 'web') {
```
More substantial Web-specific implementation code should be written in files
with the extension `.web.js`, which webpack will automatically resolve.
with the extension `.web.js`. Webpack@1 will automatically resolve these files.
Webpack@2 requires additional configuration.
```js
// webpack.config.js
module.exports = {
// ...
resolve: {
extensions: [ '.web.js', '.js' ]
}
};
```
## Optimizations

View File

@@ -16,8 +16,9 @@ module.exports = {
}
```
The `react-native-web` package also includes a `core` module that exports only
`ReactNative`, `Image`, `StyleSheet`, `Text`, `TextInput`, and `View`.
The `react-native-web` package also includes a `core` module that exports a
subset of modules: `ReactNative`, `I18nManager`, `Platform`, `StyleSheet`,
`Image`, `Text`, `TextInput`, `Touchable`, and `View`.
```js
// webpack.config.js
@@ -64,6 +65,10 @@ AppRegistry.runApplication('App', {
})
```
Setting `process.env.__REACT_NATIVE_DEBUG_ENABLED__` to `true` will expose some
debugging logs. This can help track down when you're rendering without the
performance benefit of cached styles.
## Server-side rendering
Rendering using the `AppRegistry`:

View File

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

View File

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

View File

@@ -0,0 +1,33 @@
import { Clipboard, Text, TextInput, View } from 'react-native'
import React, { Component } from 'react';
import { action, storiesOf } from '@kadira/storybook';
class ClipboardExample extends Component {
render() {
return (
<View style={{ minWidth: 300 }}>
<Text onPress={this._handleSet}>Copy to clipboard</Text>
<TextInput
multiline={true}
placeholder={'Try pasting here afterwards'}
style={{ borderWidth: 1, height: 200, marginVertical: 20 }}
/>
<Text onPress={this._handleGet}>(Clipboard.getString returns a Promise that always resolves to an empty string on web)</Text>
</View>
)
}
_handleGet() {
Clipboard.getString().then((value) => { console.log(`Clipboard value: ${value}`) });
}
_handleSet() {
const success = Clipboard.setString('This text was copied to the clipboard by React Native');
console.log(`Clipboard.setString success? ${success}`);
}
}
storiesOf('api: Clipboard', module)
.add('setString', () => (
<ClipboardExample />
));

View File

@@ -1,8 +1,8 @@
import { storiesOf } from '@kadira/storybook';
import { I18nManager, StyleSheet, TouchableHighlight, Text, View } from 'react-native'
import React, { Component } from 'react';
import { storiesOf, action } from '@kadira/storybook';
class RTLExample extends Component {
class I18nManagerExample extends Component {
componentWillUnmount() {
I18nManager.setPreferredLanguageRTL(false)
}
@@ -14,14 +14,22 @@ class RTLExample extends Component {
LTR/RTL layout example!
</Text>
<Text style={styles.text}>
This is sample text. The writing direction can be changed by pressing the button below.
</Text>
<Text style={[ styles.text, styles.ltrText ]}>
This is text that will always display LTR.
The writing direction of text is automatically determined by the browser, independent of the global writing direction of the app.
</Text>
<Text style={[ styles.text, styles.rtlText ]}>
This is text that will always display RTL.
أحب اللغة العربية
</Text>
<Text style={[ styles.text, styles.textAlign ]}>
textAlign toggles
</Text>
<View style={styles.horizontal}>
<View style={[ styles.box, { backgroundColor: 'lightblue' } ]}>
<Text>One</Text>
</View>
<View style={[ styles.box ]}>
<Text>Two</Text>
</View>
</View>
<TouchableHighlight
onPress={this._handleToggle}
style={styles.toggle}
@@ -34,8 +42,8 @@ class RTLExample extends Component {
}
_handleToggle = () => {
this._isRTL = !this._isRTL
I18nManager.setPreferredLanguageRTL(this._isRTL)
I18nManager.setPreferredLanguageRTL(!I18nManager.isRTL)
this.forceUpdate();
}
}
@@ -55,13 +63,16 @@ const styles = StyleSheet.create({
fontSize: 18,
marginBottom: 5
},
ltrText: {
textAlign$noI18n: 'left',
writingDirection$noI18n: 'ltr'
textAlign: {
textAlign: 'left'
},
rtlText: {
textAlign$noI18n: 'right',
writingDirection$noI18n: 'rtl'
horizontal: {
flexDirection: 'row',
marginVertical: 10
},
box: {
borderWidth: 1,
flex: 1
},
toggle: {
alignSelf: 'center',
@@ -75,5 +86,5 @@ const styles = StyleSheet.create({
storiesOf('api: I18nManager', module)
.add('RTL layout', () => (
<RTLExample />
<I18nManagerExample />
))

View File

@@ -2,11 +2,19 @@ import { Linking, StyleSheet, Text, View } from 'react-native'
import React, { Component } from 'react';
import { storiesOf, action } from '@kadira/storybook';
const url = 'https://mathiasbynens.github.io/rel-noopener/malicious.html';
class LinkingExample extends Component {
handlePress() {
Linking.canOpenURL(url).then((supported) => {
return Linking.openURL(url);
});
}
render() {
return (
<View>
<Text onPress={() => { Linking.openURL('https://mathiasbynens.github.io/rel-noopener/malicious.html'); }} style={styles.text}>
<Text onPress={this.handlePress} style={styles.text}>
Linking.openURL (Expect: "The previous tab is safe and intact")
</Text>
<Text accessibilityRole='link' href='https://mathiasbynens.github.io/rel-noopener/malicious.html' style={styles.text} target='_blank'>

View File

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

View File

@@ -28,10 +28,9 @@ import { ActivityIndicator, Image, Platform, StyleSheet, Text, View } from 'reac
var base64Icon = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEsAAABLCAQAAACSR7JhAAADtUlEQVR4Ac3YA2Bj6QLH0XPT1Fzbtm29tW3btm3bfLZtv7e2ObZnms7d8Uw098tuetPzrxv8wiISrtVudrG2JXQZ4VOv+qUfmqCGGl1mqLhoA52oZlb0mrjsnhKpgeUNEs91Z0pd1kvihA3ULGVHiQO2narKSHKkEMulm9VgUyE60s1aWoMQUbpZOWE+kaqs4eLEjdIlZTcFZB0ndc1+lhB1lZrIuk5P2aib1NBpZaL+JaOGIt0ls47SKzLC7CqrlGF6RZ09HGoNy1lYl2aRSWL5GuzqWU1KafRdoRp0iOQEiDzgZPnG6DbldcomadViflnl/cL93tOoVbsOLVM2jylvdWjXolWX1hmfZbGR/wjypDjFLSZIRov09BgYmtUqPQPlQrPapecLgTIy0jMgPKtTeob2zWtrGH3xvjUkPCtNg/tm1rjwrMa+mdUkPd3hWbH0jArPGiU9ufCsNNWFZ40wpwn+62/66R2RUtoso1OB34tnLOcy7YB1fUdc9e0q3yru8PGM773vXsuZ5YIZX+5xmHwHGVvlrGPN6ZSiP1smOsMMde40wKv2VmwPPVXNut4sVpUreZiLBHi0qln/VQeI/LTMYXpsJtFiclUN+5HVZazim+Ky+7sAvxWnvjXrJFneVtLWLyPJu9K3cXLWeOlbMTlrIelbMDlrLenrjEQOtIF+fuI9xRp9ZBFp6+b6WT8RrxEpdK64BuvHgDk+vUy+b5hYk6zfyfs051gRoNO1usU12WWRWL73/MMEy9pMi9qIrR4ZpV16Rrvduxazmy1FSvuFXRkqTnE7m2kdb5U8xGjLw/spRr1uTov4uOgQE+0N/DvFrG/Jt7i/FzwxbA9kDanhf2w+t4V97G8lrT7wc08aA2QNUkuTfW/KimT01wdlfK4yEw030VfT0RtZbzjeMprNq8m8tnSTASrTLti64oBNdpmMQm0eEwvfPwRbUBywG5TzjPCsdwk3IeAXjQblLCoXnDVeoAz6SfJNk5TTzytCNZk/POtTSV40NwOFWzw86wNJRpubpXsn60NJFlHeqlYRbslqZm2jnEZ3qcSKgm0kTli3zZVS7y/iivZTweYXJ26Y+RTbV1zh3hYkgyFGSTKPfRVbRqWWVReaxYeSLarYv1Qqsmh1s95S7G+eEWK0f3jYKTbV6bOwepjfhtafsvUsqrQvrGC8YhmnO9cSCk3yuY984F1vesdHYhWJ5FvASlacshUsajFt2mUM9pqzvKGcyNJW0arTKN1GGGzQlH0tXwLDgQTurS8eIQAAAABJRU5ErkJggg==';
//var ImageCapInsetsExample = require('./ImageCapInsetsExample');
//const IMAGE_PREFETCH_URL = 'http://facebook.github.io/origami/public/images/blog-hero.jpg?r=1&t=' + Date.now();
//var prefetchTask = Image.prefetch(IMAGE_PREFETCH_URL);
const IMAGE_PREFETCH_URL = 'http://origami.design/public/images/bird-logo.png?r=1&t=' + Date.now();
var prefetchTask = Image.prefetch(IMAGE_PREFETCH_URL);
/*
var NetworkImageCallbackExample = React.createClass({
getInitialState: function() {
return {
@@ -88,7 +87,6 @@ var NetworkImageCallbackExample = React.createClass({
});
}
});
*/
var NetworkImageExample = React.createClass({
getInitialState: function() {
@@ -118,7 +116,6 @@ var NetworkImageExample = React.createClass({
}
});
/*
var ImageSizeExample = React.createClass({
getInitialState: function() {
return {
@@ -133,24 +130,25 @@ var ImageSizeExample = React.createClass({
},
render: function() {
return (
<View style={{flexDirection: 'row'}}>
<Image
style={{
width: 60,
height: 60,
backgroundColor: 'transparent',
marginRight: 10,
}}
source={this.props.source} />
<View>
<Text>
Actual dimensions:{'\n'}
Width: {this.state.width}, Height: {this.state.height}
width: {this.state.width}, height: {this.state.height}
</Text>
<Image
source={this.props.source}
style={{
backgroundColor: '#eee',
height: 227,
marginTop: 10,
width: 323
}}
/>
</View>
);
},
});
*/
/*
var MultipleSourcesExample = React.createClass({
getInitialState: function() {
@@ -239,17 +237,17 @@ const examples = [
);
},
},
/*
{
title: 'Image Loading Events',
render: function() {
return (
<NetworkImageCallbackExample source={{uri: 'http://facebook.github.io/origami/public/images/blog-hero.jpg?r=1&t=' + Date.now()}}
prefetchedSource={{uri: IMAGE_PREFETCH_URL}}/>
<NetworkImageCallbackExample
source={{uri: 'http://origami.design/public/images/bird-logo.png?r=1&t=' + Date.now()}}
prefetchedSource={{uri: IMAGE_PREFETCH_URL}}
/>
);
},
},
*/
{
title: 'Error Handler',
render: function() {
@@ -263,7 +261,7 @@ const examples = [
title: 'Image Download Progress',
render: function() {
return (
<NetworkImageExample source={{uri: 'http://facebook.github.io/origami/public/images/blog-hero.jpg?r=1'}}/>
<NetworkImageExample source={{uri: 'http://origami.design/public/images/bird-logo.png?r=1'}}/>
);
},
platform: 'ios',
@@ -567,14 +565,12 @@ const examples = [
platform: 'ios',
},
*/
/*
{
title: 'Image Size',
render: function() {
return <ImageSizeExample source={fullImage} />;
return <ImageSizeExample source={{ uri: 'https://upload.wikimedia.org/wikipedia/commons/d/d7/Chestnut-mandibled_Toucan.jpg' }} />;
},
},
*/
/*
{
title: 'MultipleSourcesExample',

View File

@@ -271,7 +271,7 @@ const examples = [
<Text>
auto (default) - english LTR
</Text>
<Text style={{ writingDirection$noI18n: 'rtl' }}>
<Text>
أحب اللغة العربية auto (default) - arabic RTL
</Text>
<Text style={{textAlign: 'left'}}>

View File

@@ -59,7 +59,7 @@ class TextEventsExample extends React.Component {
render() {
return (
<View>
<View style={{ alignItems: 'center' }}>
<TextInput
autoCapitalize="none"
placeholder="Enter text to see events"
@@ -83,7 +83,7 @@ class TextEventsExample extends React.Component {
onKeyPress={(event) => {
this.updateText('onKeyPress key: ' + event.nativeEvent.key);
}}
style={styles.default}
style={[ styles.default, { maxWidth: 200 } ]}
/>
<Text style={styles.eventLabel}>
{this.state.curText}{'\n'}

View File

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

View File

@@ -31,6 +31,17 @@ var styles = StyleSheet.create({
borderColor: '#000033',
borderWidth: 1,
},
shadowBox: {
width: 100,
height: 100,
borderWidth: 2,
},
shadow: {
shadowOpacity: 0.5,
shadowColor: 'red',
shadowRadius: 3,
shadowOffset: { width: 3, height: 3 },
},
zIndex: {
justifyContent: 'space-around',
width: 100,
@@ -242,6 +253,19 @@ const examples = [
return <ZIndexExample />;
},
},
{
title: 'Basic shadow',
render() {
return <View style={[ styles.shadowBox, styles.shadow ]} />;
}
},
{
title: 'Shaped shadow',
description: 'borderRadius: 50',
render() {
return <View style={[ styles.shadowBox, styles.shadow, {borderRadius: 50} ]} />;
}
}
];
examples.forEach((example) => {

View File

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

View File

@@ -1,6 +1,6 @@
{
"name": "react-native-web",
"version": "0.0.59",
"version": "0.0.74",
"description": "React Native for Web",
"main": "dist/index.js",
"files": [
@@ -11,36 +11,39 @@
"scripts": {
"build": "del ./dist && mkdir dist && babel src -d dist --ignore **/__tests__",
"build:examples": "build-storybook -o dist-examples -c ./examples/.storybook",
"build:performance": "cd performance && yarn && webpack",
"build:umd": "webpack --config webpack.config.js --sort-assets-by --progress",
"deploy:examples": "git checkout gh-pages && rm -rf ./storybook && mv dist-examples storybook && git add -A && git commit -m \"Storybook deploy\" && git push origin gh-pages && git checkout -",
"examples": "start-storybook -p 9001 -c ./examples/.storybook --dont-track",
"lint": "eslint src",
"lint": "eslint performance src --ignore-path .gitignore",
"prepublish": "npm run build && npm run build:umd",
"test": "npm run lint && npm run test:jest",
"test:jest": "jest",
"test:watch": "npm run test:jest -- --watch"
},
"dependencies": {
"animated": "^0.1.3",
"animated": "^0.2.0",
"array-find-index": "^1.0.2",
"babel-runtime": "^6.11.6",
"asap": "^2.0.5",
"babel-runtime": "^6.23.0",
"debounce": "^1.0.0",
"deep-assign": "^2.0.0",
"fbjs": "^0.8.4",
"inline-style-prefixer": "^2.0.1",
"react-dom": "~15.3.2",
"fbjs": "^0.8.8",
"inline-style-prefixer": "^3.0.0",
"normalize-css-color": "^1.0.2",
"react-dom": "~15.4.1",
"react-textarea-autosize": "^4.0.4",
"react-timer-mixin": "^0.13.3"
},
"devDependencies": {
"@kadira/storybook": "^2.5.1",
"babel-cli": "^6.14.0",
"babel-core": "^6.14.0",
"babel-eslint": "^6.1.2",
"babel-loader": "^6.2.5",
"babel-plugin-transform-react-remove-prop-types": "^0.2.11",
"babel-preset-react-native": "^1.9.0",
"del-cli": "^0.2.0",
"babel-cli": "^6.23.0",
"babel-core": "^6.23.1",
"babel-eslint": "^7.1.1",
"babel-loader": "^6.3.2",
"babel-plugin-transform-react-remove-prop-types": "^0.3.2",
"babel-preset-react-native": "^1.9.1",
"del-cli": "^0.2.1",
"enzyme": "^2.4.1",
"eslint": "^3.4.0",
"eslint-plugin-jsx-a11y": "^2.2.0",
@@ -49,15 +52,15 @@
"file-loader": "^0.9.0",
"jest": "^16.0.2",
"node-libs-browser": "^0.5.3",
"react": "~15.3.2",
"react-addons-test-utils": "~15.3.2",
"react-test-renderer": "~15.3.2",
"react": "~15.4.1",
"react-addons-test-utils": "~15.4.1",
"react-test-renderer": "~15.4.1",
"url-loader": "^0.5.7",
"webpack": "^1.13.2",
"webpack-bundle-analyzer": "^1.5.3"
"webpack-bundle-analyzer": "^2.2.1"
},
"peerDependencies": {
"react": "~15.3.2"
"react": "~15.4.1"
},
"author": "Nicolas Gallagher",
"license": "BSD-3-Clause",

36
performance/README.md Normal file
View File

@@ -0,0 +1,36 @@
# Performance
To run these benchmarks:
```
npm run build:performance
open ./performance/index.html
```
## Notes
The components used in the render benchmarks are simple enough to be
implemented by multiple styling libraries. The implementations are not
equivalent but are useful for framing the relative performance of
`react-native-web` against these tests.
The implementations are not equivalent. For example, the `react-native-web`
implementation of `View` does more than just styling. The
`react-native-web/lite` variant implements a minimal `View` that allows for a
more direct comparison with the `css-modules` baseline.
## Benchmark results
Typical render timings*: mean / two standard deviations
Version: 0.0.73
| Implementation | Deep tree (ms) | Wide tree (ms) |
| :--- | ---: | ---: |
| css-modules | `80.47` `±18.04` | `166.91` `±19.90` |
| react-native-web/lite | `87.91` `±13.37` | `181.45` `±20.06` |
| react-native-web | `113.45` `±09.27` | `237.33` `±38.77` |
| styled-components | `170.86` `±15.67` | `378.83` `±36.11` |
| glamor | `275.41` `±19.56` | `474.76` `±29.02` |
*MacBook Pro (13-inch, Early 2011); 2.7 GHz Intel Core i7; 16 GB 1600 MHz DDR3. Google Chrome 56.

View File

@@ -0,0 +1,21 @@
/* eslint-disable react/prop-types */
import classnames from 'classnames';
import React from 'react';
import View from '../View';
import styles from './styles.css';
const Box = ({ color, fixed = false, layout = 'column', outer = false, ...other }) => (
<View
{...other}
className={classnames(
styles[`color${color}`],
{
[styles.fixed]: fixed,
[styles.outer]: outer,
[styles.row]: layout === 'row'
}
)}
/>
);
module.exports = Box;

View File

@@ -0,0 +1,36 @@
.outer {
padding: 4px;
}
.row {
flex-direction: row;
}
.color0 {
background-color: #222;
}
.color1 {
background-color: #666;
}
.color2 {
background-color: #999;
}
.color3 {
background-color: blue;
}
.color4 {
background-color: orange;
}
.color5 {
background-color: red;
}
.fixed {
width: 20px;
height: 20px;
}

View File

@@ -0,0 +1,8 @@
/* eslint-disable react/prop-types */
import classnames from 'classnames';
import React from 'react';
import styles from './styles.css';
const View = (props) => <div {...props} className={classnames(styles.initial, props.className)} />;
module.exports = View;

View File

@@ -0,0 +1,21 @@
.initial {
align-items: stretch;
border-width: 0;
border-style: solid;
box-sizing: border-box;
display: flex;
flex-basis: auto;
flex-direction: column;
flex-shrink: 0;
margin: 0;
padding: 0;
position: relative;
background-color: transparent;
color: inherit;
font: inherit;
text-align: inherit;
text-decoration: none;
list-style: none;
min-height: 0;
min-width: 0;
};

View File

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

View File

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

View File

@@ -0,0 +1,32 @@
/* eslint-disable react/prop-types */
import { css } from 'glamor';
import React from 'react';
const View = (props) => <div {...props} className={css(viewStyle, props.style)} />;
const viewStyle = {
alignItems: 'stretch',
borderWidth: 0,
borderStyle: 'solid',
boxSizing: 'border-box',
display: 'flex',
flexBasis: 'auto',
flexDirection: 'column',
flexShrink: 0,
margin: 0,
padding: 0,
position: 'relative',
// button and anchor reset
backgroundColor: 'transparent',
color: 'inherit',
font: 'inherit',
textAlign: 'inherit',
textDecorationLine: 'none',
// list reset
listStyle: 'none',
// fix flexbox bugs
minHeight: 0,
minWidth: 0
};
module.exports = View;

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,2 @@
import View from 'react-native/components/View';
export default View;

View File

@@ -0,0 +1,32 @@
import createDOMElement from 'react-native/modules/createDOMElement';
import StyleSheet from 'react-native/apis/StyleSheet';
const View = (props) => createDOMElement('div', { ...props, style: [ styles.initial, props.style ] });
const styles = StyleSheet.create({
initial: {
alignItems: 'stretch',
borderWidth: 0,
borderStyle: 'solid',
boxSizing: 'border-box',
display: 'flex',
flexBasis: 'auto',
flexDirection: 'column',
margin: 0,
padding: 0,
position: 'relative',
// button and anchor reset
backgroundColor: 'transparent',
color: 'inherit',
font: 'inherit',
textAlign: 'inherit',
textDecorationLine: 'none',
// list reset
listStyle: 'none',
// fix flexbox bugs
minHeight: 0,
minWidth: 0
}
});
module.exports = View;

View File

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

View File

@@ -0,0 +1,7 @@
import Box from './Box/lite';
import View from './View/lite';
export default {
Box,
View
};

View File

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

View File

@@ -0,0 +1,25 @@
import styled from 'styled-components';
const View = styled.div`
align-items: stretch;
border-width: 0;
border-style: solid;
box-sizing: border-box;
display: flex;
flex-basis: auto;
flex-direction: column;
flex-shrink: 0;
margin: 0;
padding: 0;
position: relative;
background-color: transparent;
color: inherit;
font: inherit;
text-align: inherit;
text-decoration: none;
list-style: none;
min-height: 0;
min-width: 0;
`;
module.exports = View;

View File

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

11
performance/index.html Normal file
View File

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

28
performance/index.js Normal file
View File

@@ -0,0 +1,28 @@
import cssModules from './implementations/css-modules';
import glamor from './implementations/glamor';
import reactNative from './implementations/react-native-web';
import reactNativeLite from './implementations/react-native-web/lite';
import styledComponents from './implementations/styled-components';
import renderDeepTree from './tests/renderDeepTree';
import renderWideTree from './tests/renderWideTree';
const tests = [
// deep tree
() => renderDeepTree('css-modules', cssModules),
() => renderDeepTree('react-native-web/lite', reactNativeLite),
() => renderDeepTree('react-native-web', reactNative),
() => renderDeepTree('styled-components', styledComponents),
() => renderDeepTree('glamor', glamor),
// wide tree
() => renderWideTree('css-modules', cssModules),
() => renderWideTree('react-native-web/lite', reactNativeLite),
() => renderWideTree('react-native-web', reactNative),
() => renderWideTree('styled-components', styledComponents),
() => renderWideTree('glamor', glamor)
];
// run benchmarks
tests.reduce((promise, test) => {
return promise.then(test());
}, Promise.resolve());

View File

@@ -0,0 +1,49 @@
import React, { Component, PropTypes } from 'react';
class DeepTree extends Component {
static propTypes = {
breadth: PropTypes.number.isRequired,
components: PropTypes.object,
depth: PropTypes.number.isRequired,
id: PropTypes.number.isRequired,
wrap: PropTypes.number.isRequired
};
render() {
const { breadth, components, depth, id, wrap } = this.props;
const { Box } = components;
let result = (
<Box
color={id % 3}
components={components}
layout={depth % 2 === 0 ? 'column' : 'row'}
outer
>
{depth === 0 && (
<Box
color={(id % 3) + 3}
components={components}
fixed
/>
)}
{depth !== 0 && Array.from({ length: breadth }).map((el, i) => (
<DeepTree
breadth={breadth}
components={components}
depth={depth - 1}
id={i}
key={i}
wrap={wrap}
/>
))}
</Box>
);
for (let i = 0; i < wrap; i++) {
result = <Box components={components}>{result}</Box>;
}
return result;
}
}
module.exports = DeepTree;

View File

@@ -0,0 +1,93 @@
import * as marky from 'marky';
const fmt = (time) => `${Math.round(time * 100) / 100}ms`;
const measure = (name, fn) => {
marky.mark(name);
fn();
const performanceMeasure = marky.stop(name);
return performanceMeasure.duration;
};
const mean = (values) => {
const sum = values.reduce((sum, value) => sum + value, 0);
return sum / values.length;
};
const median = (values) => {
if (!Array.isArray(values)) { return 0; }
if (values.length === 1) { return values[0]; }
const numbers = [ ...values ].sort((a, b) => a - b);
return (numbers[(numbers.length - 1) >> 1] + numbers[numbers.length >> 1]) / 2;
};
const standardDeviation = (values) => {
const avg = mean(values);
const squareDiffs = values.map((value) => {
const diff = value - avg;
return diff * diff;
});
const meanSquareDiff = mean(squareDiffs);
return Math.sqrt(meanSquareDiff);
};
const benchmark = ({ name, description, setup, teardown, task, runs }) => {
return new Promise((resolve) => {
const durations = [];
let i = 0;
setup();
const first = measure('first', task);
teardown();
const done = () => {
const stdDev = standardDeviation(durations);
const formattedFirst = fmt(first);
const formattedMean = fmt(mean(durations));
const formattedMedian = fmt(median(durations));
const formattedStdDev = fmt(stdDev);
console.groupCollapsed(`${name}\n${formattedMean} ±${fmt(2 * stdDev)}`);
description && console.log(description);
console.log(`First: ${formattedFirst}`);
console.log(`Median: ${formattedMedian}`);
console.log(`Mean: ${formattedMean}`);
console.log(`Standard deviation: ${formattedStdDev}`);
console.log(durations);
console.groupEnd();
resolve();
};
const a = () => {
setup();
window.requestAnimationFrame(b);
};
const b = () => {
const duration = measure('mean', task);
durations.push(duration);
window.requestAnimationFrame(c);
};
const c = () => {
teardown();
window.requestAnimationFrame(d);
};
const d = () => {
i += 1;
if (i < runs) {
window.requestAnimationFrame(a);
} else {
window.requestAnimationFrame(done);
}
};
window.requestAnimationFrame(a);
});
};
export default benchmark;

View File

@@ -0,0 +1,20 @@
import benchmark from './benchmark';
import ReactDOM from 'react-dom';
const node = document.querySelector('.root');
const createRenderBenchmark = ({ description, getElement, name, runs }) => () => {
const setup = () => {};
const teardown = () => ReactDOM.unmountComponentAtNode(node);
return benchmark({
name,
description,
runs,
setup,
teardown,
task: () => ReactDOM.render(getElement(), node)
});
};
export default createRenderBenchmark;

14
performance/package.json Normal file
View File

@@ -0,0 +1,14 @@
{
"name": "performance",
"private": true,
"dependencies": {
"classnames": "^2.2.5",
"glamor": "^2.20.24",
"marky": "^1.1.3",
"styled-components": "^1.4.3"
},
"devDependencies": {
"css-loader": "^0.26.2",
"style-loader": "^0.13.2"
}
}

View File

@@ -0,0 +1,21 @@
import createRenderBenchmark from '../modules/createRenderBenchmark';
import NestedTree from '../modules/NestedTree';
import React from 'react';
const renderDeepTree = (label, components) => createRenderBenchmark({
name: `Deep tree [${label}]`,
runs: 20,
getElement() {
return (
<NestedTree
breadth={3}
components={components}
depth={6}
id={0}
wrap={1}
/>
);
}
});
export default renderDeepTree;

View File

@@ -0,0 +1,21 @@
import createRenderBenchmark from '../modules/createRenderBenchmark';
import NestedTree from '../modules/NestedTree';
import React from 'react';
const renderWideTree = (label, components) => createRenderBenchmark({
name: `Wide tree [${label}]`,
runs: 20,
getElement() {
return (
<NestedTree
breadth={10}
components={components}
depth={3}
id={0}
wrap={4}
/>
);
}
});
export default renderWideTree;

View File

@@ -0,0 +1,47 @@
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
const path = require('path');
const webpack = require('webpack');
module.exports = {
context: __dirname,
entry: './index',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'performance.bundle.js'
},
module: {
loaders: [
{
test: /\.css$/,
loader: 'style-loader!css-loader?module&localIdentName=[hash:base64:8]'
},
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
query: { cacheDirectory: true }
}
]
},
plugins: [
new BundleAnalyzerPlugin({
analyzerMode: 'static',
openAnalyzer: false
}),
new webpack.DefinePlugin({ 'process.env.NODE_ENV': JSON.stringify('production') }),
new webpack.optimize.DedupePlugin(),
new webpack.optimize.OccurenceOrderPlugin(),
new webpack.optimize.UglifyJsPlugin({
compress: {
dead_code: true,
screw_ie8: true,
warnings: true
}
})
],
resolve: {
alias: {
'react-native': path.join(__dirname, '../src')
}
}
};

970
performance/yarn.lock Normal file
View File

@@ -0,0 +1,970 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
alphanum-sort@^1.0.1, alphanum-sort@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/alphanum-sort/-/alphanum-sort-1.0.2.tgz#97a1119649b211ad33691d9f9f486a8ec9fbe0a3"
ansi-regex@^2.0.0:
version "2.1.1"
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df"
ansi-styles@^2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe"
argparse@^1.0.7:
version "1.0.9"
resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.9.tgz#73d83bc263f86e97f8cc4f6bae1b0e90a7d22c86"
dependencies:
sprintf-js "~1.0.2"
asap@~2.0.3:
version "2.0.5"
resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.5.tgz#522765b50c3510490e52d7dcfe085ef9ba96958f"
autoprefixer@^6.3.1:
version "6.7.5"
resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-6.7.5.tgz#50848f39dc08730091d9495023487e7cc21f518d"
dependencies:
browserslist "^1.7.5"
caniuse-db "^1.0.30000624"
normalize-range "^0.1.2"
num2fraction "^1.2.2"
postcss "^5.2.15"
postcss-value-parser "^3.2.3"
babel-code-frame@^6.11.0:
version "6.22.0"
resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.22.0.tgz#027620bee567a88c32561574e7fd0801d33118e4"
dependencies:
chalk "^1.1.0"
esutils "^2.0.2"
js-tokens "^3.0.0"
babel-runtime@^6.18.0:
version "6.23.0"
resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.23.0.tgz#0a9489f144de70efb3ce4300accdb329e2fc543b"
dependencies:
core-js "^2.4.0"
regenerator-runtime "^0.10.0"
balanced-match@^0.4.2:
version "0.4.2"
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838"
base64-js@^1.0.2:
version "1.2.0"
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.2.0.tgz#a39992d723584811982be5e290bb6a53d86700f1"
big.js@^3.1.3:
version "3.1.3"
resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.1.3.tgz#4cada2193652eb3ca9ec8e55c9015669c9806978"
bowser@^1.0.0:
version "1.6.0"
resolved "https://registry.yarnpkg.com/bowser/-/bowser-1.6.0.tgz#37fc387b616cb6aef370dab4d6bd402b74c5c54d"
browserslist@^1.0.1, browserslist@^1.5.2, browserslist@^1.7.5:
version "1.7.5"
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-1.7.5.tgz#eca4713897b51e444283241facf3985de49a9e2b"
dependencies:
caniuse-db "^1.0.30000624"
electron-to-chromium "^1.2.3"
buffer@^5.0.2:
version "5.0.5"
resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.0.5.tgz#35c9393244a90aff83581063d16f0882cecc9418"
dependencies:
base64-js "^1.0.2"
ieee754 "^1.1.4"
caniuse-api@^1.5.2:
version "1.5.3"
resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-1.5.3.tgz#5018e674b51c393e4d50614275dc017e27c4a2a2"
dependencies:
browserslist "^1.0.1"
caniuse-db "^1.0.30000346"
lodash.memoize "^4.1.0"
lodash.uniq "^4.3.0"
caniuse-db@^1.0.30000346, caniuse-db@^1.0.30000624:
version "1.0.30000628"
resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000628.tgz#3d010e2a8e2537a8d135792e90e4f2ce0eb838cc"
chalk@^1.1.0, chalk@^1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98"
dependencies:
ansi-styles "^2.2.1"
escape-string-regexp "^1.0.2"
has-ansi "^2.0.0"
strip-ansi "^3.0.0"
supports-color "^2.0.0"
clap@^1.0.9:
version "1.1.2"
resolved "https://registry.yarnpkg.com/clap/-/clap-1.1.2.tgz#316545bf22229225a2cecaa6824cd2f56a9709ed"
dependencies:
chalk "^1.1.3"
classnames@^2.2.5:
version "2.2.5"
resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.5.tgz#fb3801d453467649ef3603c7d61a02bd129bde6d"
clone@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.2.tgz#260b7a99ebb1edfe247538175f783243cb19d149"
coa@~1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/coa/-/coa-1.0.1.tgz#7f959346cfc8719e3f7233cd6852854a7c67d8a3"
dependencies:
q "^1.1.2"
color-convert@^1.3.0:
version "1.9.0"
resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.0.tgz#1accf97dd739b983bf994d56fec8f95853641b7a"
dependencies:
color-name "^1.1.1"
color-name@^1.0.0, color-name@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.1.tgz#4b1415304cf50028ea81643643bd82ea05803689"
color-string@^0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/color-string/-/color-string-0.3.0.tgz#27d46fb67025c5c2fa25993bfbf579e47841b991"
dependencies:
color-name "^1.0.0"
color@^0.11.0:
version "0.11.4"
resolved "https://registry.yarnpkg.com/color/-/color-0.11.4.tgz#6d7b5c74fb65e841cd48792ad1ed5e07b904d764"
dependencies:
clone "^1.0.2"
color-convert "^1.3.0"
color-string "^0.3.0"
colormin@^1.0.5:
version "1.1.2"
resolved "https://registry.yarnpkg.com/colormin/-/colormin-1.1.2.tgz#ea2f7420a72b96881a38aae59ec124a6f7298133"
dependencies:
color "^0.11.0"
css-color-names "0.0.4"
has "^1.0.1"
colors@0.5.x:
version "0.5.1"
resolved "https://registry.yarnpkg.com/colors/-/colors-0.5.1.tgz#7d0023eaeb154e8ee9fce75dcb923d0ed1667774"
colors@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63"
core-js@^1.0.0:
version "1.2.7"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636"
core-js@^2.4.0:
version "2.4.1"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.4.1.tgz#4de911e667b0eae9124e34254b53aea6fc618d3e"
css-color-list@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/css-color-list/-/css-color-list-0.0.1.tgz#8718e8695ae7a2cc8787be8715f1c008a7f28b15"
dependencies:
css-color-names "0.0.1"
css-color-names@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/css-color-names/-/css-color-names-0.0.1.tgz#5d0548fa256456ede4a9a0c2ac7ab19d3eb1ad81"
css-color-names@0.0.4:
version "0.0.4"
resolved "https://registry.yarnpkg.com/css-color-names/-/css-color-names-0.0.4.tgz#808adc2e79cf84738069b646cb20ec27beb629e0"
css-loader@^0.26.2:
version "0.26.2"
resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-0.26.2.tgz#a9cd4c2b1a559b45d8efc04fc311ab5d2aaccb9d"
dependencies:
babel-code-frame "^6.11.0"
css-selector-tokenizer "^0.7.0"
cssnano ">=2.6.1 <4"
loader-utils "^1.0.2"
lodash.camelcase "^4.3.0"
object-assign "^4.0.1"
postcss "^5.0.6"
postcss-modules-extract-imports "^1.0.0"
postcss-modules-local-by-default "^1.0.1"
postcss-modules-scope "^1.0.0"
postcss-modules-values "^1.1.0"
source-list-map "^0.1.7"
css-selector-tokenizer@^0.6.0:
version "0.6.0"
resolved "https://registry.yarnpkg.com/css-selector-tokenizer/-/css-selector-tokenizer-0.6.0.tgz#6445f582c7930d241dcc5007a43d6fcb8f073152"
dependencies:
cssesc "^0.1.0"
fastparse "^1.1.1"
regexpu-core "^1.0.0"
css-selector-tokenizer@^0.7.0:
version "0.7.0"
resolved "https://registry.yarnpkg.com/css-selector-tokenizer/-/css-selector-tokenizer-0.7.0.tgz#e6988474ae8c953477bf5e7efecfceccd9cf4c86"
dependencies:
cssesc "^0.1.0"
fastparse "^1.1.1"
regexpu-core "^1.0.0"
css-to-react-native@^1.0.6:
version "1.0.6"
resolved "https://registry.yarnpkg.com/css-to-react-native/-/css-to-react-native-1.0.6.tgz#728c7e774e56536558a0ecaa990d9507c43a4ac4"
dependencies:
css-color-list "0.0.1"
fbjs "^0.8.5"
nearley "^2.7.7"
cssesc@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-0.1.0.tgz#c814903e45623371a0477b40109aaafbeeaddbb4"
"cssnano@>=2.6.1 <4":
version "3.10.0"
resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-3.10.0.tgz#4f38f6cea2b9b17fa01490f23f1dc68ea65c1c38"
dependencies:
autoprefixer "^6.3.1"
decamelize "^1.1.2"
defined "^1.0.0"
has "^1.0.1"
object-assign "^4.0.1"
postcss "^5.0.14"
postcss-calc "^5.2.0"
postcss-colormin "^2.1.8"
postcss-convert-values "^2.3.4"
postcss-discard-comments "^2.0.4"
postcss-discard-duplicates "^2.0.1"
postcss-discard-empty "^2.0.1"
postcss-discard-overridden "^0.1.1"
postcss-discard-unused "^2.2.1"
postcss-filter-plugins "^2.0.0"
postcss-merge-idents "^2.1.5"
postcss-merge-longhand "^2.0.1"
postcss-merge-rules "^2.0.3"
postcss-minify-font-values "^1.0.2"
postcss-minify-gradients "^1.0.1"
postcss-minify-params "^1.0.4"
postcss-minify-selectors "^2.0.4"
postcss-normalize-charset "^1.1.0"
postcss-normalize-url "^3.0.7"
postcss-ordered-values "^2.1.0"
postcss-reduce-idents "^2.2.2"
postcss-reduce-initial "^1.0.0"
postcss-reduce-transforms "^1.0.3"
postcss-svgo "^2.1.1"
postcss-unique-selectors "^2.0.2"
postcss-value-parser "^3.2.3"
postcss-zindex "^2.0.1"
csso@~2.3.1:
version "2.3.1"
resolved "https://registry.yarnpkg.com/csso/-/csso-2.3.1.tgz#4f8d91a156f2f1c2aebb40b8fb1b5eb83d94d3b9"
dependencies:
clap "^1.0.9"
source-map "^0.5.3"
decamelize@^1.1.2:
version "1.2.0"
resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
defined@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693"
discontinuous-range@1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/discontinuous-range/-/discontinuous-range-1.0.0.tgz#e38331f0844bba49b9a9cb71c771585aab1bc65a"
electron-to-chromium@^1.2.3:
version "1.2.4"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.2.4.tgz#9751cbea89fa120bf88c226ba41eb8d0b6f1b597"
emojis-list@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389"
encoding@^0.1.11:
version "0.1.12"
resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb"
dependencies:
iconv-lite "~0.4.13"
escape-string-regexp@^1.0.2:
version "1.0.5"
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
esprima@^2.6.0:
version "2.7.3"
resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581"
esutils@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b"
fastparse@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/fastparse/-/fastparse-1.1.1.tgz#d1e2643b38a94d7583b479060e6c4affc94071f8"
fbjs@^0.8.5, fbjs@^0.8.7, fbjs@^0.8.8:
version "0.8.9"
resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.9.tgz#180247fbd347dcc9004517b904f865400a0c8f14"
dependencies:
core-js "^1.0.0"
isomorphic-fetch "^2.1.1"
loose-envify "^1.0.0"
object-assign "^4.1.0"
promise "^7.1.1"
setimmediate "^1.0.5"
ua-parser-js "^0.7.9"
flatten@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/flatten/-/flatten-1.0.2.tgz#dae46a9d78fbe25292258cc1e780a41d95c03782"
function-bind@^1.0.2:
version "1.1.0"
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.0.tgz#16176714c801798e4e8f2cf7f7529467bb4a5771"
glamor@^2.20.12, glamor@^2.20.24:
version "2.20.24"
resolved "https://registry.yarnpkg.com/glamor/-/glamor-2.20.24.tgz#a299af2eec687322634ba38e4a0854d8743d2041"
dependencies:
babel-runtime "^6.18.0"
fbjs "^0.8.8"
object-assign "^4.1.0"
has-ansi@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91"
dependencies:
ansi-regex "^2.0.0"
has-flag@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa"
has@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/has/-/has-1.0.1.tgz#8461733f538b0837c9361e39a9ab9e9704dc2f28"
dependencies:
function-bind "^1.0.2"
html-comment-regex@^1.1.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/html-comment-regex/-/html-comment-regex-1.1.1.tgz#668b93776eaae55ebde8f3ad464b307a4963625e"
hyphenate-style-name@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/hyphenate-style-name/-/hyphenate-style-name-1.0.2.tgz#31160a36930adaf1fc04c6074f7eb41465d4ec4b"
iconv-lite@~0.4.13:
version "0.4.15"
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.15.tgz#fe265a218ac6a57cfe854927e9d04c19825eddeb"
icss-replace-symbols@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/icss-replace-symbols/-/icss-replace-symbols-1.0.2.tgz#cb0b6054eb3af6edc9ab1d62d01933e2d4c8bfa5"
ieee754@^1.1.4:
version "1.1.8"
resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.8.tgz#be33d40ac10ef1926701f6f08a2d86fbfd1ad3e4"
indexes-of@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/indexes-of/-/indexes-of-1.0.1.tgz#f30f716c8e2bd346c7b67d3df3915566a7c05607"
inline-style-prefixer@^2.0.5:
version "2.0.5"
resolved "https://registry.yarnpkg.com/inline-style-prefixer/-/inline-style-prefixer-2.0.5.tgz#c153c7e88fd84fef5c602e95a8168b2770671fe7"
dependencies:
bowser "^1.0.0"
hyphenate-style-name "^1.0.1"
is-absolute-url@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/is-absolute-url/-/is-absolute-url-2.1.0.tgz#50530dfb84fcc9aa7dbe7852e83a37b93b9f2aa6"
is-function@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/is-function/-/is-function-1.0.1.tgz#12cfb98b65b57dd3d193a3121f5f6e2f437602b5"
is-plain-obj@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e"
is-plain-object@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.1.tgz#4d7ca539bc9db9b737b8acb612f2318ef92f294f"
dependencies:
isobject "^1.0.0"
is-stream@^1.0.1:
version "1.1.0"
resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
is-svg@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/is-svg/-/is-svg-2.1.0.tgz#cf61090da0d9efbcab8722deba6f032208dbb0e9"
dependencies:
html-comment-regex "^1.1.0"
isobject@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/isobject/-/isobject-1.0.2.tgz#f0f9b8ce92dd540fa0740882e3835a2e022ec78a"
isomorphic-fetch@^2.1.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz#611ae1acf14f5e81f729507472819fe9733558a9"
dependencies:
node-fetch "^1.0.1"
whatwg-fetch ">=0.10.0"
js-base64@^2.1.9:
version "2.1.9"
resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.1.9.tgz#f0e80ae039a4bd654b5f281fc93f04a914a7fcce"
js-tokens@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.1.tgz#08e9f132484a2c45a30907e9dc4d5567b7f114d7"
js-yaml@~3.7.0:
version "3.7.0"
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.7.0.tgz#5c967ddd837a9bfdca5f2de84253abe8a1c03b80"
dependencies:
argparse "^1.0.7"
esprima "^2.6.0"
jsesc@~0.5.0:
version "0.5.0"
resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d"
json5@^0.5.0:
version "0.5.1"
resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821"
loader-utils@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.0.2.tgz#a9f923c865a974623391a8602d031137fad74830"
dependencies:
big.js "^3.1.3"
emojis-list "^2.0.0"
json5 "^0.5.0"
lodash.camelcase@^4.3.0:
version "4.3.0"
resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6"
lodash.memoize@^4.1.0:
version "4.1.2"
resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe"
lodash.uniq@^4.3.0:
version "4.5.0"
resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
loose-envify@^1.0.0:
version "1.3.1"
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848"
dependencies:
js-tokens "^3.0.0"
macaddress@^0.2.8:
version "0.2.8"
resolved "https://registry.yarnpkg.com/macaddress/-/macaddress-0.2.8.tgz#5904dc537c39ec6dbefeae902327135fa8511f12"
marky@^1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/marky/-/marky-1.1.3.tgz#b5b914c661f73355862a77acf21aadfc60745e37"
math-expression-evaluator@^1.2.14:
version "1.2.16"
resolved "https://registry.yarnpkg.com/math-expression-evaluator/-/math-expression-evaluator-1.2.16.tgz#b357fa1ca9faefb8e48d10c14ef2bcb2d9f0a7c9"
minimist@0.0.8:
version "0.0.8"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
mkdirp@~0.5.1:
version "0.5.1"
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
dependencies:
minimist "0.0.8"
nearley@^2.7.7:
version "2.7.13"
resolved "https://registry.yarnpkg.com/nearley/-/nearley-2.7.13.tgz#ae19927cc821a4b517de91962db9ed0e90d991fa"
dependencies:
nomnom "~1.6.2"
railroad-diagrams "^1.0.0"
randexp "^0.4.2"
node-fetch@^1.0.1:
version "1.6.3"
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.6.3.tgz#dc234edd6489982d58e8f0db4f695029abcd8c04"
dependencies:
encoding "^0.1.11"
is-stream "^1.0.1"
nomnom@~1.6.2:
version "1.6.2"
resolved "https://registry.yarnpkg.com/nomnom/-/nomnom-1.6.2.tgz#84a66a260174408fc5b77a18f888eccc44fb6971"
dependencies:
colors "0.5.x"
underscore "~1.4.4"
normalize-range@^0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942"
normalize-url@^1.4.0:
version "1.9.0"
resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-1.9.0.tgz#c2bb50035edee62cd81edb2d45da68dc25e3423e"
dependencies:
object-assign "^4.0.1"
prepend-http "^1.0.0"
query-string "^4.1.0"
sort-keys "^1.0.0"
num2fraction@^1.2.2:
version "1.2.2"
resolved "https://registry.yarnpkg.com/num2fraction/-/num2fraction-1.2.2.tgz#6f682b6a027a4e9ddfa4564cd2589d1d4e669ede"
object-assign@^4.0.1, object-assign@^4.1.0:
version "4.1.1"
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
postcss-calc@^5.2.0:
version "5.3.1"
resolved "https://registry.yarnpkg.com/postcss-calc/-/postcss-calc-5.3.1.tgz#77bae7ca928ad85716e2fda42f261bf7c1d65b5e"
dependencies:
postcss "^5.0.2"
postcss-message-helpers "^2.0.0"
reduce-css-calc "^1.2.6"
postcss-colormin@^2.1.8:
version "2.2.2"
resolved "https://registry.yarnpkg.com/postcss-colormin/-/postcss-colormin-2.2.2.tgz#6631417d5f0e909a3d7ec26b24c8a8d1e4f96e4b"
dependencies:
colormin "^1.0.5"
postcss "^5.0.13"
postcss-value-parser "^3.2.3"
postcss-convert-values@^2.3.4:
version "2.6.1"
resolved "https://registry.yarnpkg.com/postcss-convert-values/-/postcss-convert-values-2.6.1.tgz#bbd8593c5c1fd2e3d1c322bb925dcae8dae4d62d"
dependencies:
postcss "^5.0.11"
postcss-value-parser "^3.1.2"
postcss-discard-comments@^2.0.4:
version "2.0.4"
resolved "https://registry.yarnpkg.com/postcss-discard-comments/-/postcss-discard-comments-2.0.4.tgz#befe89fafd5b3dace5ccce51b76b81514be00e3d"
dependencies:
postcss "^5.0.14"
postcss-discard-duplicates@^2.0.1:
version "2.0.2"
resolved "https://registry.yarnpkg.com/postcss-discard-duplicates/-/postcss-discard-duplicates-2.0.2.tgz#02be520e91571ffb10738766a981d5770989bb32"
dependencies:
postcss "^5.0.4"
postcss-discard-empty@^2.0.1:
version "2.1.0"
resolved "https://registry.yarnpkg.com/postcss-discard-empty/-/postcss-discard-empty-2.1.0.tgz#d2b4bd9d5ced5ebd8dcade7640c7d7cd7f4f92b5"
dependencies:
postcss "^5.0.14"
postcss-discard-overridden@^0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/postcss-discard-overridden/-/postcss-discard-overridden-0.1.1.tgz#8b1eaf554f686fb288cd874c55667b0aa3668d58"
dependencies:
postcss "^5.0.16"
postcss-discard-unused@^2.2.1:
version "2.2.3"
resolved "https://registry.yarnpkg.com/postcss-discard-unused/-/postcss-discard-unused-2.2.3.tgz#bce30b2cc591ffc634322b5fb3464b6d934f4433"
dependencies:
postcss "^5.0.14"
uniqs "^2.0.0"
postcss-filter-plugins@^2.0.0:
version "2.0.2"
resolved "https://registry.yarnpkg.com/postcss-filter-plugins/-/postcss-filter-plugins-2.0.2.tgz#6d85862534d735ac420e4a85806e1f5d4286d84c"
dependencies:
postcss "^5.0.4"
uniqid "^4.0.0"
postcss-merge-idents@^2.1.5:
version "2.1.7"
resolved "https://registry.yarnpkg.com/postcss-merge-idents/-/postcss-merge-idents-2.1.7.tgz#4c5530313c08e1d5b3bbf3d2bbc747e278eea270"
dependencies:
has "^1.0.1"
postcss "^5.0.10"
postcss-value-parser "^3.1.1"
postcss-merge-longhand@^2.0.1:
version "2.0.2"
resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-2.0.2.tgz#23d90cd127b0a77994915332739034a1a4f3d658"
dependencies:
postcss "^5.0.4"
postcss-merge-rules@^2.0.3:
version "2.1.2"
resolved "https://registry.yarnpkg.com/postcss-merge-rules/-/postcss-merge-rules-2.1.2.tgz#d1df5dfaa7b1acc3be553f0e9e10e87c61b5f721"
dependencies:
browserslist "^1.5.2"
caniuse-api "^1.5.2"
postcss "^5.0.4"
postcss-selector-parser "^2.2.2"
vendors "^1.0.0"
postcss-message-helpers@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/postcss-message-helpers/-/postcss-message-helpers-2.0.0.tgz#a4f2f4fab6e4fe002f0aed000478cdf52f9ba60e"
postcss-minify-font-values@^1.0.2:
version "1.0.5"
resolved "https://registry.yarnpkg.com/postcss-minify-font-values/-/postcss-minify-font-values-1.0.5.tgz#4b58edb56641eba7c8474ab3526cafd7bbdecb69"
dependencies:
object-assign "^4.0.1"
postcss "^5.0.4"
postcss-value-parser "^3.0.2"
postcss-minify-gradients@^1.0.1:
version "1.0.5"
resolved "https://registry.yarnpkg.com/postcss-minify-gradients/-/postcss-minify-gradients-1.0.5.tgz#5dbda11373703f83cfb4a3ea3881d8d75ff5e6e1"
dependencies:
postcss "^5.0.12"
postcss-value-parser "^3.3.0"
postcss-minify-params@^1.0.4:
version "1.2.2"
resolved "https://registry.yarnpkg.com/postcss-minify-params/-/postcss-minify-params-1.2.2.tgz#ad2ce071373b943b3d930a3fa59a358c28d6f1f3"
dependencies:
alphanum-sort "^1.0.1"
postcss "^5.0.2"
postcss-value-parser "^3.0.2"
uniqs "^2.0.0"
postcss-minify-selectors@^2.0.4:
version "2.1.1"
resolved "https://registry.yarnpkg.com/postcss-minify-selectors/-/postcss-minify-selectors-2.1.1.tgz#b2c6a98c0072cf91b932d1a496508114311735bf"
dependencies:
alphanum-sort "^1.0.2"
has "^1.0.1"
postcss "^5.0.14"
postcss-selector-parser "^2.0.0"
postcss-modules-extract-imports@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-1.0.1.tgz#8fb3fef9a6dd0420d3f6d4353cf1ff73f2b2a341"
dependencies:
postcss "^5.0.4"
postcss-modules-local-by-default@^1.0.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-1.1.1.tgz#29a10673fa37d19251265ca2ba3150d9040eb4ce"
dependencies:
css-selector-tokenizer "^0.6.0"
postcss "^5.0.4"
postcss-modules-scope@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-1.0.2.tgz#ff977395e5e06202d7362290b88b1e8cd049de29"
dependencies:
css-selector-tokenizer "^0.6.0"
postcss "^5.0.4"
postcss-modules-values@^1.1.0:
version "1.2.2"
resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-1.2.2.tgz#f0e7d476fe1ed88c5e4c7f97533a3e772ad94ca1"
dependencies:
icss-replace-symbols "^1.0.2"
postcss "^5.0.14"
postcss-normalize-charset@^1.1.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/postcss-normalize-charset/-/postcss-normalize-charset-1.1.1.tgz#ef9ee71212d7fe759c78ed162f61ed62b5cb93f1"
dependencies:
postcss "^5.0.5"
postcss-normalize-url@^3.0.7:
version "3.0.8"
resolved "https://registry.yarnpkg.com/postcss-normalize-url/-/postcss-normalize-url-3.0.8.tgz#108f74b3f2fcdaf891a2ffa3ea4592279fc78222"
dependencies:
is-absolute-url "^2.0.0"
normalize-url "^1.4.0"
postcss "^5.0.14"
postcss-value-parser "^3.2.3"
postcss-ordered-values@^2.1.0:
version "2.2.3"
resolved "https://registry.yarnpkg.com/postcss-ordered-values/-/postcss-ordered-values-2.2.3.tgz#eec6c2a67b6c412a8db2042e77fe8da43f95c11d"
dependencies:
postcss "^5.0.4"
postcss-value-parser "^3.0.1"
postcss-reduce-idents@^2.2.2:
version "2.4.0"
resolved "https://registry.yarnpkg.com/postcss-reduce-idents/-/postcss-reduce-idents-2.4.0.tgz#c2c6d20cc958284f6abfbe63f7609bf409059ad3"
dependencies:
postcss "^5.0.4"
postcss-value-parser "^3.0.2"
postcss-reduce-initial@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/postcss-reduce-initial/-/postcss-reduce-initial-1.0.1.tgz#68f80695f045d08263a879ad240df8dd64f644ea"
dependencies:
postcss "^5.0.4"
postcss-reduce-transforms@^1.0.3:
version "1.0.4"
resolved "https://registry.yarnpkg.com/postcss-reduce-transforms/-/postcss-reduce-transforms-1.0.4.tgz#ff76f4d8212437b31c298a42d2e1444025771ae1"
dependencies:
has "^1.0.1"
postcss "^5.0.8"
postcss-value-parser "^3.0.1"
postcss-selector-parser@^2.0.0, postcss-selector-parser@^2.2.2:
version "2.2.3"
resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-2.2.3.tgz#f9437788606c3c9acee16ffe8d8b16297f27bb90"
dependencies:
flatten "^1.0.2"
indexes-of "^1.0.1"
uniq "^1.0.1"
postcss-svgo@^2.1.1:
version "2.1.6"
resolved "https://registry.yarnpkg.com/postcss-svgo/-/postcss-svgo-2.1.6.tgz#b6df18aa613b666e133f08adb5219c2684ac108d"
dependencies:
is-svg "^2.0.0"
postcss "^5.0.14"
postcss-value-parser "^3.2.3"
svgo "^0.7.0"
postcss-unique-selectors@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/postcss-unique-selectors/-/postcss-unique-selectors-2.0.2.tgz#981d57d29ddcb33e7b1dfe1fd43b8649f933ca1d"
dependencies:
alphanum-sort "^1.0.1"
postcss "^5.0.4"
uniqs "^2.0.0"
postcss-value-parser@^3.0.1, postcss-value-parser@^3.0.2, postcss-value-parser@^3.1.1, postcss-value-parser@^3.1.2, postcss-value-parser@^3.2.3, postcss-value-parser@^3.3.0:
version "3.3.0"
resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-3.3.0.tgz#87f38f9f18f774a4ab4c8a232f5c5ce8872a9d15"
postcss-zindex@^2.0.1:
version "2.2.0"
resolved "https://registry.yarnpkg.com/postcss-zindex/-/postcss-zindex-2.2.0.tgz#d2109ddc055b91af67fc4cb3b025946639d2af22"
dependencies:
has "^1.0.1"
postcss "^5.0.4"
uniqs "^2.0.0"
postcss@^5.0.10, postcss@^5.0.11, postcss@^5.0.12, postcss@^5.0.13, postcss@^5.0.14, postcss@^5.0.16, postcss@^5.0.2, postcss@^5.0.4, postcss@^5.0.5, postcss@^5.0.6, postcss@^5.0.8, postcss@^5.2.15:
version "5.2.15"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-5.2.15.tgz#a9e8685e50e06cc5b3fdea5297273246c26f5b30"
dependencies:
chalk "^1.1.3"
js-base64 "^2.1.9"
source-map "^0.5.6"
supports-color "^3.2.3"
prepend-http@^1.0.0:
version "1.0.4"
resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc"
promise@^7.1.1:
version "7.1.1"
resolved "https://registry.yarnpkg.com/promise/-/promise-7.1.1.tgz#489654c692616b8aa55b0724fa809bb7db49c5bf"
dependencies:
asap "~2.0.3"
q@^1.1.2:
version "1.4.1"
resolved "https://registry.yarnpkg.com/q/-/q-1.4.1.tgz#55705bcd93c5f3673530c2c2cbc0c2b3addc286e"
query-string@^4.1.0:
version "4.3.2"
resolved "https://registry.yarnpkg.com/query-string/-/query-string-4.3.2.tgz#ec0fd765f58a50031a3968c2431386f8947a5cdd"
dependencies:
object-assign "^4.1.0"
strict-uri-encode "^1.0.0"
railroad-diagrams@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/railroad-diagrams/-/railroad-diagrams-1.0.0.tgz#eb7e6267548ddedfb899c1b90e57374559cddb7e"
randexp@^0.4.2:
version "0.4.4"
resolved "https://registry.yarnpkg.com/randexp/-/randexp-0.4.4.tgz#ba68265f4a9f9e85f5814d34e160291f939f168e"
dependencies:
discontinuous-range "1.0.0"
ret "~0.1.10"
reduce-css-calc@^1.2.6:
version "1.3.0"
resolved "https://registry.yarnpkg.com/reduce-css-calc/-/reduce-css-calc-1.3.0.tgz#747c914e049614a4c9cfbba629871ad1d2927716"
dependencies:
balanced-match "^0.4.2"
math-expression-evaluator "^1.2.14"
reduce-function-call "^1.0.1"
reduce-function-call@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/reduce-function-call/-/reduce-function-call-1.0.2.tgz#5a200bf92e0e37751752fe45b0ab330fd4b6be99"
dependencies:
balanced-match "^0.4.2"
regenerate@^1.2.1:
version "1.3.2"
resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.3.2.tgz#d1941c67bad437e1be76433add5b385f95b19260"
regenerator-runtime@^0.10.0:
version "0.10.3"
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.3.tgz#8c4367a904b51ea62a908ac310bf99ff90a82a3e"
regexpu-core@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-1.0.0.tgz#86a763f58ee4d7c2f6b102e4764050de7ed90c6b"
dependencies:
regenerate "^1.2.1"
regjsgen "^0.2.0"
regjsparser "^0.1.4"
regjsgen@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.2.0.tgz#6c016adeac554f75823fe37ac05b92d5a4edb1f7"
regjsparser@^0.1.4:
version "0.1.5"
resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.1.5.tgz#7ee8f84dc6fa792d3fd0ae228d24bd949ead205c"
dependencies:
jsesc "~0.5.0"
ret@~0.1.10:
version "0.1.13"
resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.13.tgz#38c2702ece654978941edd8b7dfac6aeeef4067d"
sax@~1.2.1:
version "1.2.2"
resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.2.tgz#fd8631a23bc7826bef5d871bdb87378c95647828"
setimmediate@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285"
sort-keys@^1.0.0:
version "1.1.2"
resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-1.1.2.tgz#441b6d4d346798f1b4e49e8920adfba0e543f9ad"
dependencies:
is-plain-obj "^1.0.0"
source-list-map@^0.1.7:
version "0.1.8"
resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-0.1.8.tgz#c550b2ab5427f6b3f21f5afead88c4f5587b2106"
source-map@^0.5.3, source-map@^0.5.6:
version "0.5.6"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412"
sprintf-js@~1.0.2:
version "1.0.3"
resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
strict-uri-encode@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713"
strip-ansi@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf"
dependencies:
ansi-regex "^2.0.0"
style-loader@^0.13.2:
version "0.13.2"
resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-0.13.2.tgz#74533384cf698c7104c7951150b49717adc2f3bb"
dependencies:
loader-utils "^1.0.2"
styled-components@^1.4.3:
version "1.4.3"
resolved "https://registry.yarnpkg.com/styled-components/-/styled-components-1.4.3.tgz#83fa44e553882aaa3ddc4363ccc435814d690706"
dependencies:
buffer "^5.0.2"
css-to-react-native "^1.0.6"
fbjs "^0.8.7"
glamor "^2.20.12"
inline-style-prefixer "^2.0.5"
is-function "^1.0.1"
is-plain-object "^2.0.1"
supports-color "^3.1.2"
supports-color@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7"
supports-color@^3.1.2, supports-color@^3.2.3:
version "3.2.3"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6"
dependencies:
has-flag "^1.0.0"
svgo@^0.7.0:
version "0.7.2"
resolved "https://registry.yarnpkg.com/svgo/-/svgo-0.7.2.tgz#9f5772413952135c6fefbf40afe6a4faa88b4bb5"
dependencies:
coa "~1.0.1"
colors "~1.1.2"
csso "~2.3.1"
js-yaml "~3.7.0"
mkdirp "~0.5.1"
sax "~1.2.1"
whet.extend "~0.9.9"
ua-parser-js@^0.7.9:
version "0.7.12"
resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.12.tgz#04c81a99bdd5dc52263ea29d24c6bf8d4818a4bb"
underscore@~1.4.4:
version "1.4.4"
resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.4.4.tgz#61a6a32010622afa07963bf325203cf12239d604"
uniq@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff"
uniqid@^4.0.0:
version "4.1.1"
resolved "https://registry.yarnpkg.com/uniqid/-/uniqid-4.1.1.tgz#89220ddf6b751ae52b5f72484863528596bb84c1"
dependencies:
macaddress "^0.2.8"
uniqs@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/uniqs/-/uniqs-2.0.0.tgz#ffede4b36b25290696e6e165d4a59edb998e6b02"
vendors@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/vendors/-/vendors-1.0.1.tgz#37ad73c8ee417fb3d580e785312307d274847f22"
whatwg-fetch@>=0.10.0:
version "2.0.2"
resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.2.tgz#fe294d1d89e36c5be8b3195057f2e4bc74fc980e"
whet.extend@~0.9.9:
version "0.9.9"
resolved "https://registry.yarnpkg.com/whet.extend/-/whet.extend-0.9.9.tgz#f877d5bf648c97e5aa542fadc16d6a259b9c11a1"

View File

@@ -1,5 +1,6 @@
import Animated from 'animated';
import Image from '../../components/Image';
import ScrollView from '../../components/ScrollView';
import StyleSheet from '../StyleSheet';
import Text from '../../components/Text';
import View from '../../components/View';
@@ -9,6 +10,7 @@ Animated.inject.FlattenStyle(StyleSheet.flatten);
module.exports = {
...Animated,
Image: Animated.createAnimatedComponent(Image),
ScrollView: Animated.createAnimatedComponent(ScrollView),
Text: Animated.createAnimatedComponent(Text),
View: Animated.createAnimatedComponent(View)
};

View File

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

View File

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

View File

@@ -8,9 +8,10 @@
import { Component } from 'react';
import invariant from 'fbjs/lib/invariant';
import { unmountComponentAtNode } from 'react/lib/ReactMount';
import { unmountComponentAtNode } from 'react-dom';
import renderApplication, { getApplication } from './renderApplication';
const emptyObject = {};
const runnables = {};
type ComponentProvider = () => Component<any, any, any>
@@ -41,8 +42,8 @@ class AppRegistry {
static registerComponent(appKey: string, getComponentFunc: ComponentProvider): string {
runnables[appKey] = {
getApplication: ({ initialProps } = {}) => getApplication(getComponentFunc(), initialProps),
run: ({ initialProps, rootTag }) => renderApplication(getComponentFunc(), initialProps, rootTag)
getApplication: ({ initialProps } = emptyObject) => getApplication(getComponentFunc(), initialProps),
run: ({ initialProps = emptyObject, rootTag }) => renderApplication(getComponentFunc(), initialProps, rootTag)
};
return appKey;
}

View File

@@ -7,7 +7,7 @@
*/
import invariant from 'fbjs/lib/invariant';
import { render } from 'react/lib/ReactMount';
import { render } from 'react-dom/lib/ReactMount';
import ReactNativeApp from './ReactNativeApp';
import StyleSheet from '../../apis/StyleSheet';
import React, { Component } from 'react';
@@ -32,6 +32,6 @@ export function getApplication(RootComponent: Component, initialProps: Object):
rootComponent={RootComponent}
/>
);
const stylesheet = StyleSheet.render();
const stylesheet = StyleSheet.renderToString();
return { element, stylesheet };
}

View File

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

View File

@@ -0,0 +1,21 @@
class Clipboard {
static getString() {
return Promise.resolve('');
}
static setString(text) {
let success = false;
const textField = document.createElement('textarea');
textField.innerText = text;
document.body.appendChild(textField);
textField.select();
try {
document.execCommand('copy');
success = true;
} catch (e) {}
document.body.removeChild(textField);
return success;
}
}
module.exports = Clipboard;

View File

@@ -1,10 +1,19 @@
const Linking = {
addEventListener() {},
removeEventListener() {},
canOpenUrl() { return true; },
getInitialUrl() { return ''; },
canOpenURL() {
return Promise.resolve(true);
},
getInitialURL() {
return Promise.resolve('');
},
openURL(url) {
iframeOpen(url);
try {
iframeOpen(url);
return Promise.resolve();
} catch (e) {
return Promise.reject(e);
}
}
};

View File

@@ -6,7 +6,7 @@
"use strict";
var TouchHistoryMath = require('react/lib/TouchHistoryMath');
var TouchHistoryMath = require('react-dom/lib/TouchHistoryMath');
var currentCentroidXOfTouchesChangedAfter =
TouchHistoryMath.currentCentroidXOfTouchesChangedAfter;

View File

@@ -9,8 +9,9 @@
import { PropTypes } from 'react'
import ImageStylePropTypes from '../../components/Image/ImageStylePropTypes'
import ReactPropTypeLocations from 'react/lib/ReactPropTypeLocations'
import ReactPropTypesSecret from 'react/lib/ReactPropTypesSecret'
import ReactPropTypeLocations from 'react-dom/lib/ReactPropTypeLocations'
import ReactPropTypesSecret from 'react-dom/lib/ReactPropTypesSecret'
import TextInputStylePropTypes from '../../components/TextInput/TextInputStylePropTypes'
import TextStylePropTypes from '../../components/Text/TextStylePropTypes'
import ViewStylePropTypes from '../../components/View/ViewStylePropTypes'
import warning from 'fbjs/lib/warning'
@@ -66,16 +67,16 @@ var allStylePropTypes = {};
StyleSheetValidation.addValidStylePropTypes(ImageStylePropTypes)
StyleSheetValidation.addValidStylePropTypes(TextStylePropTypes)
StyleSheetValidation.addValidStylePropTypes(TextInputStylePropTypes)
StyleSheetValidation.addValidStylePropTypes(ViewStylePropTypes)
StyleSheetValidation.addValidStylePropTypes({
appearance: PropTypes.string,
clear: PropTypes.string,
cursor: PropTypes.string,
display: PropTypes.string,
float: PropTypes.oneOf([ 'left', 'none', 'right' ]),
font: PropTypes.string, /* @private */
listStyle: PropTypes.string,
WebkitOverflowScrolling: PropTypes.string /* @private */
pointerEvents: PropTypes.string
})
module.exports = StyleSheetValidation

View File

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

View File

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

View File

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

View File

@@ -21,34 +21,6 @@ Object {
"height": 10,
"width": "1rem",
},
"writingDirection": "ltr",
}
`;
exports[`apis/StyleSheet/i18nStyle LTR mode normalizes properties 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",
},
"writingDirection": "ltr",
}
`;
@@ -75,33 +47,5 @@ Object {
"height": 10,
"width": "-1rem",
},
"writingDirection": "rtl",
}
`;
exports[`apis/StyleSheet/i18nStyle RTL mode normalizes properties 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",
},
"writingDirection": "ltr",
}
`;

View File

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

View File

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

View File

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

View File

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

View File

@@ -45,4 +45,21 @@ describe('apis/StyleSheet/expandStyle', () => {
expect(expandStyle(initial)).toEqual(expected);
});
test('flex', () => {
expect(expandStyle({ display: 'flex' }))
.toEqual({ display: 'flex', flexShrink: 0 });
expect(expandStyle({ display: 'flex', flex: 1 }))
.toEqual({ display: 'flex', flexGrow: 1, flexShrink: 1, flexBasis: 'auto' });
expect(expandStyle({ display: 'flex', flex: 10 }))
.toEqual({ display: 'flex', flexGrow: 10, flexShrink: 1, flexBasis: 'auto' });
expect(expandStyle({ display: 'flex', flexShrink: 1 }))
.toEqual({ display: 'flex', flexShrink: 1 });
expect(expandStyle({ display: 'flex', flex: 1, flexShrink: 2 }))
.toEqual({ display: 'flex', flexGrow: 1, flexShrink: 2, flexBasis: 'auto' });
});
});

View File

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

View File

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

View File

@@ -21,16 +21,9 @@ const style = {
paddingRight: 10,
right: 2,
textAlign: 'left',
textShadowOffset: { width: '1rem', height: 10 },
writingDirection: 'ltr'
textShadowOffset: { width: '1rem', height: 10 }
};
const styleNoI18n = Object.keys(style).reduce((acc, prop) => {
const newProp = `${prop}$noI18n`;
acc[newProp] = style[prop];
return acc;
}, {});
describe('apis/StyleSheet/i18nStyle', () => {
describe('LTR mode', () => {
beforeEach(() => {
@@ -44,9 +37,6 @@ describe('apis/StyleSheet/i18nStyle', () => {
test('does not auto-flip', () => {
expect(i18nStyle(style)).toMatchSnapshot();
});
test('normalizes properties', () => {
expect(i18nStyle(styleNoI18n)).toMatchSnapshot();
});
});
describe('RTL mode', () => {
@@ -61,8 +51,5 @@ describe('apis/StyleSheet/i18nStyle', () => {
test('does auto-flip', () => {
expect(i18nStyle(style)).toMatchSnapshot();
});
test('normalizes properties', () => {
expect(i18nStyle(styleNoI18n)).toMatchSnapshot();
});
});
});

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,6 +1,8 @@
import I18nManager from '../I18nManager';
import multiplyStyleLengthValue from '../../modules/multiplyStyleLengthValue';
const emptyObject = {};
/**
* Map of property names to their BiDi equivalent.
*/
@@ -29,10 +31,6 @@ const PROPERTIES_SWAP_LEFT_RIGHT = {
'textAlign': true
};
const PROPERTIES_SWAP_LTR_RTL = {
'writingDirection': true
};
/**
* Invert the sign of a numeric-like value
*/
@@ -41,7 +39,7 @@ const additiveInverse = (value: String | Number) => multiplyStyleLengthValue(val
/**
* BiDi flip the given property.
*/
const flipProperty = (prop:String): String => {
const flipProperty = (prop: String): String => {
return PROPERTIES_TO_SWAP.hasOwnProperty(prop) ? PROPERTIES_TO_SWAP[prop] : prop;
};
@@ -60,47 +58,35 @@ const swapLeftRight = (value:String): String => {
return value === 'left' ? 'right' : value === 'right' ? 'left' : value;
};
const swapLtrRtl = (value:String): String => {
return value === 'ltr' ? 'rtl' : value === 'rtl' ? 'ltr' : value;
};
const i18nStyle = (originalStyle) => {
if (!I18nManager.isRTL) {
return originalStyle;
}
const style = originalStyle || emptyObject;
const nextStyle = {};
const i18nStyle = (style = {}) => {
const newStyle = {};
for (const prop in style) {
if (style.hasOwnProperty(prop)) {
const indexOfNoFlip = prop.indexOf('$noI18n');
if (!Object.prototype.hasOwnProperty.call(style, prop)) {
continue;
}
if (I18nManager.isRTL) {
if (PROPERTIES_TO_SWAP[prop]) {
const newProp = flipProperty(prop);
newStyle[newProp] = style[prop];
} else if (PROPERTIES_SWAP_LEFT_RIGHT[prop]) {
newStyle[prop] = swapLeftRight(style[prop]);
} else if (PROPERTIES_SWAP_LTR_RTL[prop]) {
newStyle[prop] = swapLtrRtl(style[prop]);
} else if (prop === 'textShadowOffset') {
newStyle[prop] = style[prop];
newStyle[prop].width = additiveInverse(style[prop].width);
} else if (prop === 'transform') {
newStyle[prop] = style[prop].map(flipTransform);
} else if (indexOfNoFlip > -1) {
const newProp = prop.substring(0, indexOfNoFlip);
newStyle[newProp] = style[prop];
} else {
newStyle[prop] = style[prop];
}
} else {
if (indexOfNoFlip > -1) {
const newProp = prop.substring(0, indexOfNoFlip);
newStyle[newProp] = style[prop];
} else {
newStyle[prop] = style[prop];
}
}
if (PROPERTIES_TO_SWAP[prop]) {
const newProp = flipProperty(prop);
nextStyle[newProp] = style[prop];
} else if (PROPERTIES_SWAP_LEFT_RIGHT[prop]) {
nextStyle[prop] = swapLeftRight(style[prop]);
} else if (prop === 'textShadowOffset') {
nextStyle[prop] = style[prop];
nextStyle[prop].width = additiveInverse(style[prop].width);
} else if (prop === 'transform') {
nextStyle[prop] = style[prop].map(flipTransform);
} else {
nextStyle[prop] = style[prop];
}
}
return newStyle;
return nextStyle;
};
module.exports = i18nStyle;

View File

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

View File

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

View File

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

View File

@@ -1,30 +1,45 @@
const unitlessNumbers = {
animationIterationCount: true,
borderImageOutset: true,
borderImageSlice: true,
borderImageWidth: true,
boxFlex: true,
boxFlexGroup: true,
boxOrdinalGroup: true,
columnCount: true,
flex: true,
flexGrow: true,
flexOrder: true,
flexPositive: true,
flexShrink: true,
flexNegative: true,
fontWeight: true,
gridRow: true,
gridColumn: true,
lineClamp: true,
opacity: true,
order: true,
orphans: true,
tabSize: true,
widows: true,
zIndex: true,
zoom: true,
// SVG-related
fillOpacity: true,
floodOpacity: true,
stopOpacity: true,
strokeDasharray: true,
strokeDashoffset: true,
strokeMiterlimit: true,
strokeOpacity: true,
strokeWidth: true,
// transform types
scale: true,
scaleX: true,
scaleY: true,
scaleZ: true
scaleZ: true,
// RN properties
shadowOpacity: true
};
const normalizeValue = (property, value) => {

View File

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

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