Compare commits

...

43 Commits

Author SHA1 Message Date
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
68 changed files with 998 additions and 1013 deletions

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,47 +99,48 @@ from `style`.
+ `alignContent`
+ `alignItems`
+ `alignSelf`
+ `animationDelay`
+ `animationDirection`
+ `animationDuration`
+ `animationFillMode`
+ `animationIterationCount`
+ `animationName`
+ `animationPlayState`
+ `animationTimingFunction`
+ `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`
@@ -148,12 +149,12 @@ from `style`.
+ `flexWrap`
+ `height`
+ `justifyContent`
+ `left`
+ `left`
+ `margin` (single value)
+ `marginBottom`
+ `marginHorizontal`
+ `marginLeft`
+ `marginRight`
+ `marginLeft`
+ `marginRight`
+ `marginTop`
+ `marginVertical`
+ `maxHeight`
@@ -162,34 +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`
+ `perspective`
+ `perspectiveOrigin`
+ `position`
+ `right`
+ `right`
+ `top`
+ `transform`
+ `transformOrigin`
+ `transitionDelay`
+ `transitionDuration`
+ `transitionProperty`
+ `transitionTimingFunction`
+ `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

@@ -86,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

@@ -14,14 +14,22 @@ class I18nManagerExample 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 I18nManagerExample 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',

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

@@ -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

@@ -1,6 +1,6 @@
{
"name": "react-native-web",
"version": "0.0.66",
"version": "0.0.73",
"description": "React Native for Web",
"main": "dist/index.js",
"files": [
@@ -22,14 +22,14 @@
"test:watch": "npm run test:jest -- --watch"
},
"dependencies": {
"animated": "^0.1.5",
"animated": "^0.2.0",
"array-find-index": "^1.0.2",
"asap": "^2.0.5",
"babel-runtime": "^6.20.0",
"babel-runtime": "^6.23.0",
"debounce": "^1.0.0",
"deep-assign": "^2.0.0",
"fbjs": "^0.8.8",
"inline-style-prefixer": "^2.0.5",
"inline-style-prefixer": "^3.0.0",
"normalize-css-color": "^1.0.2",
"react-dom": "~15.4.1",
"react-textarea-autosize": "^4.0.4",
@@ -37,11 +37,11 @@
},
"devDependencies": {
"@kadira/storybook": "^2.5.1",
"babel-cli": "^6.14.0",
"babel-core": "^6.21.0",
"babel-cli": "^6.23.0",
"babel-core": "^6.23.1",
"babel-eslint": "^7.1.1",
"babel-loader": "^6.2.10",
"babel-plugin-transform-react-remove-prop-types": "^0.2.11",
"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",
@@ -58,7 +58,7 @@
"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.4.1"

View File

@@ -6,24 +6,27 @@ const measure = (name, fn) => {
marky.mark(name);
fn();
const performanceMeasure = marky.stop(name);
return performanceMeasure;
return performanceMeasure.duration;
};
const benchmark = ({ name, description, setup, teardown, task, runs }) => {
return new Promise((resolve) => {
const performanceMeasures = [];
const durations = [];
let i = 0;
console.group(`[benchmark] ${name}`);
console.log(description);
setup();
const first = measure('first', task);
teardown();
const done = () => {
const mean = performanceMeasures.reduce((sum, performanceMeasure) => {
return sum + performanceMeasure.duration;
const mean = durations.reduce((sum, duration) => {
return sum + duration;
}, 0) / runs;
const firstDuration = fmt(first.duration);
const firstDuration = fmt(first);
const meanDuration = fmt(mean);
console.log(`First: ${firstDuration}`);
@@ -38,8 +41,9 @@ const benchmark = ({ name, description, setup, teardown, task, runs }) => {
};
const b = () => {
performanceMeasures.push(measure('mean', task));
window.requestAnimationFrame(c);
const duration = measure('mean', task);
durations.push(duration);
c();
};
const c = () => {
@@ -56,8 +60,6 @@ const benchmark = ({ name, description, setup, teardown, task, runs }) => {
}
};
console.group(`[benchmark] ${name}`);
console.log(description);
window.requestAnimationFrame(a);
});
};

View File

@@ -1,6 +1,13 @@
import React, { Component, PropTypes } from 'react';
const createDeepTree = ({ StyleSheet, View }, options = {}) => {
/* eslint-disable */
const 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==';
/* eslint-enable */
const createDeepTree = (implementation, options = {}) => {
const { Image, StyleSheet, View } = implementation;
const TerminalComponent = options.leafComponent ? implementation[options.leafComponent] : View;
class DeepTree extends Component {
static propTypes = {
breadth: PropTypes.number.isRequired,
@@ -21,7 +28,8 @@ const createDeepTree = ({ StyleSheet, View }, options = {}) => {
]}
>
{depth === 0 && (
<View
<TerminalComponent
source={TerminalComponent === Image && { uri: base64Icon }}
style={[
styles.terminal,
styles[`terminal${id % 3}`]

View File

@@ -4,15 +4,22 @@ import React from 'react';
import ReactDOM from 'react-dom';
import ReactNative from 'react-native';
const deepTreeBenchmark = ({ breadth, depth, registerStyles = true, runs, wrap }, node) => () => {
const deepTreeBenchmark = (config, node) => () => {
const { breadth, depth, leafComponent = 'View', registerStyles = true, runs, wrap } = config;
// React Native for Web implementation of the tree
const DeepTree = createDeepTree(ReactNative, { registerStyles });
const setup = () => {};
const teardown = () => ReactDOM.unmountComponentAtNode(node);
let name = `DeepTree: ${leafComponent}`;
if (!registerStyles) {
name += ' (unregistered styles)';
}
return benchmark({
name: `DeepTree (${registerStyles ? 'registered' : 'unregistered'}) styles)`,
name,
description: `depth=${depth}, breadth=${breadth}, wrap=${wrap}`,
runs,
setup,

View File

@@ -8,9 +8,9 @@ const node = document.querySelector('.root');
const DeepTree = createDeepTree(ReactNative);
Promise.resolve()
.then(deepTree({ wrap: 4, depth: 3, breadth: 10, runs: 10, registerStyles: false }, node))
.then(deepTree({ wrap: 1, depth: 5, breadth: 3, runs: 20, registerStyles: false }, node))
.then(deepTree({ wrap: 4, depth: 3, breadth: 10, runs: 10 }, node))
.then(deepTree({ wrap: 1, depth: 5, breadth: 3, runs: 20 }, node))
.then(deepTree({ wrap: 4, depth: 3, breadth: 10, runs: 5, registerStyles: false }, node))
.then(deepTree({ wrap: 4, depth: 3, breadth: 10, runs: 5 }, node))
.then(deepTree({ wrap: 4, depth: 3, breadth: 10, runs: 5, leafComponent: 'Image' }, node))
.then(deepTree({ wrap: 1, depth: 5, breadth: 3, runs: 10 }, node))
.then(() => ReactDOM.render(<DeepTree breadth={3} depth={5} id={0} wrap={1} />, node));

View File

@@ -7,13 +7,13 @@ 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-pointerEvents\\:auto,.rn-pointerEvents\\:box-only,.rn-pointerEvents\\:box-none *{pointer-events:auto}.rn-pointerEvents\\:none,.rn-pointerEvents\\:box-only *,.rn-pointerEvents\\:box-none{pointer-events:none}
.rn-bottom\\:0px{bottom:0px}
.rn-left\\:0px{left:0px}
.rn-position\\:absolute{position:absolute}
.rn-right\\:0px{right:0px}
.rn-top\\:0px{top:0px}
.rn-alignItems\\:stretch{-ms-flex-align:stretch;-webkit-align-items:stretch;-webkit-box-align:stretch;align-items:stretch}
.rn-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}
@@ -23,11 +23,12 @@ input::-webkit-inner-spin-button,input::-webkit-outer-spin-button,input::-webkit
.rn-borderRightWidth\\:0px{border-right-width:0px}
.rn-borderBottomWidth\\:0px{border-bottom-width:0px}
.rn-borderLeftWidth\\:0px{border-left-width:0px}
.rn-boxSizing\\:border-box{-moz-box-sizing:border-box;box-sizing:border-box}
.rn-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-flexBasis\\:auto{-ms-preferred-size:auto;-webkit-flex-basis:auto;flex-basis:auto}
.rn-flexDirection\\:column{-ms-flex-direction:column;-webkit-box-direction:normal;-webkit-box-orient:vertical;-webkit-flex-direction:column;flex-direction:column}
.rn-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}
@@ -43,6 +44,9 @@ input::-webkit-inner-spin-button,input::-webkit-outer-spin-button,input::-webkit
.rn-position\\:relative{position:relative}
.rn-textAlign\\:inherit{text-align:inherit}
.rn-textDecoration\\:none{text-decoration:none}
.rn-flexShrink\\:0{-ms-flex-negative:0px;-webkit-flex-shrink:0px;flex-shrink:0}
.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

@@ -8,7 +8,7 @@
import { Component } from 'react';
import invariant from 'fbjs/lib/invariant';
import { unmountComponentAtNode } from 'react-dom/lib/ReactMount';
import { unmountComponentAtNode } from 'react-dom';
import renderApplication, { getApplication } from './renderApplication';
const emptyObject = {};

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

@@ -11,6 +11,7 @@ import { PropTypes } from 'react'
import ImageStylePropTypes from '../../components/Image/ImageStylePropTypes'
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

@@ -8,6 +8,7 @@ Object {
"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

@@ -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

@@ -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

@@ -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

@@ -37,18 +37,27 @@ const alphaSortProps = (propsArray) => propsArray.sort((a, b) => {
return 0;
});
const expandStyle = (style) => {
if (!style) { return emptyObject; }
const styleProps = Object.keys(style);
const sortedStyleProps = alphaSortProps(styleProps);
const createReducer = (style, styleProps) => {
let hasResolvedBoxShadow = false;
let hasResolvedTextShadow = false;
const reducer = (resolvedStyle, prop) => {
return (resolvedStyle, prop) => {
const value = normalizeValue(prop, style[prop]);
if (value == null) { return resolvedStyle; }
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;
}
break;
}
// ignore React Native styles
case 'elevation':
case 'resizeMode': {
@@ -105,7 +114,13 @@ const expandStyle = (style) => {
return resolvedStyle;
};
};
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;
};

View File

@@ -24,7 +24,7 @@ function flattenStyle(style) {
return undefined;
}
if (process.env.NODE !== 'production') {
if (process.env.NODE_ENV !== 'production') {
invariant(style !== true, 'style may be false but not true');
}

View File

@@ -31,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
*/
@@ -43,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;
};
@@ -62,49 +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 = emptyObject) => {
const newStyle = {};
for (const prop in style) {
if (!Object.prototype.hasOwnProperty.call(style, prop)) {
continue;
}
const indexOfNoFlip = prop.indexOf('$noI18n');
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];
}
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 {
if (indexOfNoFlip > -1) {
const newProp = prop.substring(0, indexOfNoFlip);
newStyle[newProp] = style[prop];
} else {
newStyle[prop] = style[prop];
}
nextStyle[prop] = style[prop];
}
}
return newStyle;
return nextStyle;
};
module.exports = i18nStyle;

View File

@@ -28,8 +28,8 @@ const initialize = () => {
);
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}'
'.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();

View File

@@ -7,15 +7,20 @@ import createReactDOMStyle from './createReactDOMStyle';
import flattenArray from '../../modules/flattenArray';
import flattenStyle from './flattenStyle';
import generateCss from './generateCss';
import I18nManager from '../I18nManager';
import injector from './injector';
import mapKeyValue from '../../modules/mapKeyValue';
import prefixInlineStyles from './prefixInlineStyles';
import ReactNativePropRegistry from '../../modules/ReactNativePropRegistry';
const prefix = 'r';
const SPACE_REGEXP = /\s/g;
const ESCAPE_SELECTOR_CHARS_REGEXP = /[(),":?.%\\$#*]/g;
const createCacheKey = (id) => {
const prefix = I18nManager.isRTL ? 'rtl' : 'ltr';
return `${prefix}-${id}`;
};
/**
* Creates an HTML class name for use on elements
*/
@@ -64,7 +69,7 @@ const registerStyle = (id, flatStyle) => {
}
});
const key = `${prefix}-${id}`;
const key = createCacheKey(id);
resolvedPropsCache[key] = { className };
return id;
@@ -95,6 +100,7 @@ const resolveProps = (reactNativeStyle) => {
style: prefixInlineStyles(style)
};
/*
if (process.env.__REACT_NATIVE_DEBUG_ENABLED__) {
console.groupCollapsed('[StyleSheet] resolving uncached styles');
console.log(
@@ -106,6 +112,7 @@ const resolveProps = (reactNativeStyle) => {
console.log('resolve => \n', props);
console.groupEnd();
}
*/
return props;
};
@@ -131,6 +138,7 @@ const StyleRegistry = {
initialize(classNames) {
injectedClassNames = classNames;
/*
if (process.env.__REACT_NATIVE_DEBUG_ENABLED__) {
if (global.__REACT_NATIVE_DEBUG_ENABLED__styleRegistryTimer) {
clearInterval(global.__REACT_NATIVE_DEBUG_ENABLED__styleRegistryTimer);
@@ -142,6 +150,7 @@ const StyleRegistry = {
console.groupEnd();
}, 30000);
}
*/
},
reset() {
@@ -162,7 +171,7 @@ const StyleRegistry = {
// fast and cachable
if (typeof reactNativeStyle === 'number') {
const key = `${prefix}${reactNativeStyle}`;
const key = createCacheKey(reactNativeStyle);
return resolvePropsIfNeeded(key, reactNativeStyle);
}
@@ -183,30 +192,8 @@ const StyleRegistry = {
}
}
// TODO: determine when/if to cache unregistered styles. This produces 2x
// faster benchmark results for unregistered styles. However, the cache
// could be filled with props that are never used again.
//
// let hasValidKey = true;
// let key = flatArray.reduce((keyParts, element) => {
// if (typeof element === 'number') {
// keyParts.push(element);
// } else {
// if (element.transform) {
// hasValidKey = false;
// } else {
// const objectAsKey = Object.keys(element).map((prop) => `${prop}:${element[prop]}`).join(';');
// if (objectAsKey !== '') {
// keyParts.push(objectAsKey);
// }
// }
// }
// return keyParts;
// }, [ prefix ]).join('-');
// if (!hasValidKey) { key = null; }
// cache resolved props when all styles are registered
const key = isArrayOfNumbers ? `${prefix}-${flatArray.join('-')}` : null;
const key = isArrayOfNumbers ? createCacheKey(flatArray.join('-')) : null;
return resolvePropsIfNeeded(key, flatArray);
}

View File

@@ -10,114 +10,7 @@ const createNode = (style = {}) => {
return root;
};
let defaultBodyMargin;
describe('apis/UIManager', () => {
beforeEach(() => {
// remove default body margin so we can predict the measured offsets
defaultBodyMargin = document.body.style.margin;
document.body.style.margin = 0;
});
afterEach(() => {
document.body.style.margin = defaultBodyMargin;
});
describe('measure', () => {
test('provides correct layout to callback', (done) => {
const node = createNode({ height: '5000px', left: '100px', position: 'relative', top: '100px', width: '5000px' });
document.body.appendChild(node);
node.getBoundingClientRect = jest.fn(() => ({ width: 5000, height: 5000, top: 100, left: 100 }));
UIManager.measure(node, (x, y, width, height, pageX, pageY) => {
expect(x).toEqual(100);
expect(y).toEqual(100);
expect(width).toEqual(5000);
expect(height).toEqual(5000);
expect(pageX).toEqual(100);
expect(pageY).toEqual(100);
done();
document.body.removeChild(node);
});
});
test('provides correct layout to callback', (done) => {
const node = createNode({ height: '5000px', left: '100px', position: 'relative', top: '100px', width: '5000px' });
document.body.appendChild(node);
// test values account for scroll position
window.scrollTo(200, 200);
node.getBoundingClientRect = jest.fn(() => ({ width: 5000, height: 5000, top: -100, left: -100 }));
node.parentNode.getBoundingClientRect = jest.fn(() => ({ top: -200, left: -200 }));
UIManager.measure(node, (x, y, width, height, pageX, pageY) => {
expect(x).toEqual(100);
expect(y).toEqual(100);
expect(width).toEqual(5000);
expect(height).toEqual(5000);
expect(pageX).toEqual(-100);
expect(pageY).toEqual(-100);
done();
document.body.removeChild(node);
});
});
});
describe('measureLayout', () => {
test('provides correct layout to onSuccess callback', (done) => {
const node = createNode({ height: '10px', width: '10px' });
const middle = createNode({ padding: '20px' });
const context = createNode({ padding: '20px' });
middle.appendChild(node);
context.appendChild(middle);
document.body.appendChild(context);
node.getBoundingClientRect = jest.fn(() => ({
width: 10,
height: 10,
top: 40,
left: 40
}));
UIManager.measureLayout(node, context, () => {}, (x, y, width, height) => {
expect(x).toEqual(40);
expect(y).toEqual(40);
expect(width).toEqual(10);
expect(height).toEqual(10);
done();
document.body.removeChild(context);
});
});
});
describe('measureInWindow', () => {
test('provides correct layout to callback', (done) => {
const node = createNode({ height: '10px', width: '10px' });
const middle = createNode({ padding: '20px' });
const context = createNode({ padding: '20px' });
middle.appendChild(node);
context.appendChild(middle);
document.body.appendChild(context);
node.getBoundingClientRect = jest.fn(() => ({
width: 10,
height: 10,
top: 40,
left: 40
}));
UIManager.measureInWindow(node, (x, y, width, height) => {
expect(x).toEqual(40);
expect(y).toEqual(40);
expect(width).toEqual(10);
expect(height).toEqual(10);
done();
document.body.removeChild(context);
});
});
});
describe('updateView', () => {
const componentStub = {
_reactInternalInstance: {
@@ -126,17 +19,16 @@ describe('apis/UIManager', () => {
}
};
test('add new className to existing className', () => {
test('supports className alias for class', () => {
const node = createNode();
node.className = 'existing';
const props = { className: 'extra' };
UIManager.updateView(node, props, componentStub);
expect(node.getAttribute('class')).toEqual('existing extra');
expect(node.getAttribute('class')).toEqual('extra');
});
test('adds correct DOM styles to existing style', () => {
const node = createNode({ color: 'red' });
const props = { style: { marginVertical: 0, opacity: 0 } };
const props = { style: { marginTop: 0, marginBottom: 0, opacity: 0 } };
UIManager.updateView(node, props, componentStub);
expect(node.getAttribute('style')).toEqual('color: red; margin-top: 0px; margin-bottom: 0px; opacity: 0;');
});

View File

@@ -1,14 +1,24 @@
import asap from 'asap';
import createReactDOMStyle from '../StyleSheet/createReactDOMStyle';
import flattenStyle from '../StyleSheet/flattenStyle';
import CSSPropertyOperations from 'react-dom/lib/CSSPropertyOperations';
import prefixInlineStyles from '../StyleSheet/prefixInlineStyles';
const _measureLayout = (node, relativeToNativeNode, callback) => {
const getRect = (node) => {
const height = node.offsetHeight;
const width = node.offsetWidth;
let left = 0;
let top = 0;
while (node && node.nodeType === 1 /* Node.ELEMENT_NODE */) {
left += node.offsetLeft;
top += node.offsetTop;
node = node.offsetParent;
}
return { height, left, top, width };
};
const measureLayout = (node, relativeToNativeNode, callback) => {
asap(() => {
const relativeNode = relativeToNativeNode || node.parentNode;
const relativeRect = relativeNode.getBoundingClientRect();
const { height, left, top, width } = node.getBoundingClientRect();
const relativeRect = getRect(relativeNode);
const { height, left, top, width } = getRect(node);
const x = left - relativeRect.left;
const y = top - relativeRect.top;
callback(x, y, width, height, left, top);
@@ -25,17 +35,17 @@ const UIManager = {
},
measure(node, callback) {
_measureLayout(node, null, callback);
measureLayout(node, null, callback);
},
measureInWindow(node, callback) {
const { height, left, top, width } = node.getBoundingClientRect();
const { height, left, top, width } = getRect(node);
callback(left, top, width, height);
},
measureLayout(node, relativeToNativeNode, onFail, onSuccess) {
const relativeTo = relativeToNativeNode || node.parentNode;
_measureLayout(node, relativeTo, onSuccess);
measureLayout(node, relativeTo, onSuccess);
},
updateView(node, props, component /* only needed to surpress React errors in development */) {
@@ -47,13 +57,12 @@ const UIManager = {
const value = props[prop];
switch (prop) {
case 'style': {
const style = prefixInlineStyles(createReactDOMStyle(flattenStyle(value)));
CSSPropertyOperations.setValueForStyles(node, style, component._reactInternalInstance);
CSSPropertyOperations.setValueForStyles(node, value, component._reactInternalInstance);
break;
}
case 'class':
case 'className': {
node.classList.add(value);
node.setAttribute('class', value);
break;
}
case 'text':

View File

@@ -16,9 +16,9 @@ rn-borderLeftWidth:0px
rn-boxSizing:border-box
rn-color:inherit
rn-display:flex
rn-flexShrink:0
rn-flexBasis:auto
rn-flexDirection:column
rn-flexShrink:0
rn-font:inherit
rn-justifyContent:center
rn-listStyle:none
@@ -56,9 +56,9 @@ rn-textDecoration:none"
rn-boxSizing:border-box
rn-color:inherit
rn-display:flex
rn-flexShrink:0
rn-flexBasis:auto
rn-flexDirection:column
rn-flexShrink:0
rn-font:inherit
rn-height:20px
rn-listStyle:none
@@ -129,9 +129,9 @@ rn-borderLeftWidth:0px
rn-boxSizing:border-box
rn-color:inherit
rn-display:flex
rn-flexShrink:0
rn-flexBasis:auto
rn-flexDirection:column
rn-flexShrink:0
rn-font:inherit
rn-justifyContent:center
rn-listStyle:none
@@ -170,9 +170,9 @@ rn-textDecoration:none"
rn-boxSizing:border-box
rn-color:inherit
rn-display:flex
rn-flexShrink:0
rn-flexBasis:auto
rn-flexDirection:column
rn-flexShrink:0
rn-font:inherit
rn-height:36px
rn-listStyle:none

View File

@@ -1,13 +1,14 @@
import applyNativeMethods from '../../modules/applyNativeMethods';
import StyleSheet from '../../apis/StyleSheet';
import View from '../View';
import ViewPropTypes from '../View/ViewPropTypes';
import React, { Component, PropTypes } from 'react';
class ActivityIndicator extends Component {
static displayName = 'ActivityIndicator';
static propTypes = {
...View.propTypes,
...ViewPropTypes,
animating: PropTypes.bool,
color: PropTypes.string,
hidesWhenStopped: PropTypes.bool,

View File

@@ -3,13 +3,15 @@ import ColorPropType from '../../propTypes/ColorPropType';
import ImageResizeMode from './ImageResizeMode';
import LayoutPropTypes from '../../propTypes/LayoutPropTypes';
import { PropTypes } from 'react';
import ShadowPropTypes from '../../propTypes/ShadowPropTypes';
import TransformPropTypes from '../../propTypes/TransformPropTypes';
const hiddenOrVisible = PropTypes.oneOf([ 'hidden', 'visible' ]);
module.exports = process.env.NODE_ENV !== 'production' ? {
module.exports = {
...BorderPropTypes,
...LayoutPropTypes,
...ShadowPropTypes,
...TransformPropTypes,
backfaceVisibility: hiddenOrVisible,
backgroundColor: ColorPropType,
@@ -24,4 +26,4 @@ module.exports = process.env.NODE_ENV !== 'production' ? {
* @platform web
*/
visibility: hiddenOrVisible
} : {};
};

View File

@@ -17,9 +17,9 @@ rn-borderLeftWidth:0px
rn-boxSizing:border-box
rn-color:inherit
rn-display:flex
rn-flexShrink:0
rn-flexBasis:auto
rn-flexDirection:column
rn-flexShrink:0
rn-font:inherit
rn-listStyle:none
rn-marginTop:0px
@@ -34,9 +34,9 @@ rn-paddingBottom:0px
rn-paddingLeft:0px
rn-position:relative
rn-textAlign:inherit
rn-textDecoration:none"
rn-textDecoration:none
rn-zIndex:0"
onResponderGrant={[Function]}
role="img"
style={Object {}} />
`;
@@ -60,9 +60,9 @@ rn-borderLeftWidth:0px
rn-boxSizing:border-box
rn-color:inherit
rn-display:flex
rn-flexShrink:0
rn-flexBasis:auto
rn-flexDirection:column
rn-flexShrink:0
rn-font:inherit
rn-listStyle:none
rn-marginTop:0px
@@ -77,8 +77,8 @@ rn-paddingBottom:0px
rn-paddingLeft:0px
rn-position:relative
rn-textAlign:inherit
rn-textDecoration:none"
role="img"
rn-textDecoration:none
rn-zIndex:0"
style={Object {}} />
`;
@@ -102,9 +102,9 @@ rn-borderLeftWidth:0px
rn-boxSizing:border-box
rn-color:inherit
rn-display:flex
rn-flexShrink:0
rn-flexBasis:auto
rn-flexDirection:column
rn-flexShrink:0
rn-font:inherit
rn-listStyle:none
rn-marginTop:0px
@@ -119,8 +119,8 @@ rn-paddingBottom:0px
rn-paddingLeft:0px
rn-position:relative
rn-textAlign:inherit
rn-textDecoration:none"
role="img"
rn-textDecoration:none
rn-zIndex:0"
style={Object {}} />
`;
@@ -143,9 +143,9 @@ rn-borderLeftWidth:0px
rn-boxSizing:border-box
rn-color:inherit
rn-display:flex
rn-flexShrink:0
rn-flexBasis:auto
rn-flexDirection:column
rn-flexShrink:0
rn-font:inherit
rn-listStyle:none
rn-marginTop:0px
@@ -160,8 +160,8 @@ rn-paddingBottom:0px
rn-paddingLeft:0px
rn-position:relative
rn-textAlign:inherit
rn-textDecoration:none"
role="img"
rn-textDecoration:none
rn-zIndex:0"
style={Object {}}>
<div
className="unique" />
@@ -173,7 +173,6 @@ exports[`components/Image prop "defaultSource" does not override "height" and "w
className="
rn-alignItems:stretch
rn-backgroundColor:transparent
rn-backgroundPosition:center
rn-backgroundRepeat:no-repeat
rn-backgroundSize:cover
@@ -188,11 +187,10 @@ rn-borderLeftWidth:0px
rn-boxSizing:border-box
rn-color:inherit
rn-display:flex
rn-flexShrink:0
rn-flexBasis:auto
rn-flexDirection:column
rn-flexShrink:0
rn-font:inherit
rn-listStyle:none
rn-marginTop:0px
rn-marginRight:0px
@@ -206,15 +204,29 @@ rn-paddingBottom:0px
rn-paddingLeft:0px
rn-position:relative
rn-textAlign:inherit
rn-textDecoration:none"
role="img"
rn-textDecoration:none
rn-zIndex:0"
style={
Object {
"backgroundImage": "url(\"https://google.com/favicon.ico\")",
"height": "20px",
"width": "40px",
}
} />
}>
<img
className="
rn-bottom:0px
rn-height:100%
rn-left:0px
rn-opacity:0
rn-position:absolute
rn-right:0px
rn-top:0px
rn-width:100%
rn-zIndex:-1"
src="https://google.com/favicon.ico"
style={Object {}} />
</div>
`;
exports[`components/Image prop "defaultSource" sets "height" and "width" styles if missing 1`] = `
@@ -222,7 +234,6 @@ exports[`components/Image prop "defaultSource" sets "height" and "width" styles
className="
rn-alignItems:stretch
rn-backgroundColor:transparent
rn-backgroundPosition:center
rn-backgroundRepeat:no-repeat
rn-backgroundSize:cover
@@ -237,11 +248,10 @@ rn-borderLeftWidth:0px
rn-boxSizing:border-box
rn-color:inherit
rn-display:flex
rn-flexShrink:0
rn-flexBasis:auto
rn-flexDirection:column
rn-flexShrink:0
rn-font:inherit
rn-listStyle:none
rn-marginTop:0px
rn-marginRight:0px
@@ -255,15 +265,29 @@ rn-paddingBottom:0px
rn-paddingLeft:0px
rn-position:relative
rn-textAlign:inherit
rn-textDecoration:none"
role="img"
rn-textDecoration:none
rn-zIndex:0"
style={
Object {
"backgroundImage": "url(\"https://google.com/favicon.ico\")",
"height": "10px",
"width": "20px",
}
} />
}>
<img
className="
rn-bottom:0px
rn-height:100%
rn-left:0px
rn-opacity:0
rn-position:absolute
rn-right:0px
rn-top:0px
rn-width:100%
rn-zIndex:-1"
src="https://google.com/favicon.ico"
style={Object {}} />
</div>
`;
exports[`components/Image prop "defaultSource" sets background image when value is a string 1`] = `
@@ -271,7 +295,6 @@ exports[`components/Image prop "defaultSource" sets background image when value
className="
rn-alignItems:stretch
rn-backgroundColor:transparent
rn-backgroundPosition:center
rn-backgroundRepeat:no-repeat
rn-backgroundSize:cover
@@ -286,9 +309,9 @@ rn-borderLeftWidth:0px
rn-boxSizing:border-box
rn-color:inherit
rn-display:flex
rn-flexShrink:0
rn-flexBasis:auto
rn-flexDirection:column
rn-flexShrink:0
rn-font:inherit
rn-listStyle:none
rn-marginTop:0px
@@ -303,13 +326,27 @@ rn-paddingBottom:0px
rn-paddingLeft:0px
rn-position:relative
rn-textAlign:inherit
rn-textDecoration:none"
role="img"
rn-textDecoration:none
rn-zIndex:0"
style={
Object {
"backgroundImage": "url(\"https://google.com/favicon.ico\")",
}
} />
}>
<img
className="
rn-bottom:0px
rn-height:100%
rn-left:0px
rn-opacity:0
rn-position:absolute
rn-right:0px
rn-top:0px
rn-width:100%
rn-zIndex:-1"
src="https://google.com/favicon.ico"
style={Object {}} />
</div>
`;
exports[`components/Image prop "defaultSource" sets background image when value is an object 1`] = `
@@ -317,7 +354,6 @@ exports[`components/Image prop "defaultSource" sets background image when value
className="
rn-alignItems:stretch
rn-backgroundColor:transparent
rn-backgroundPosition:center
rn-backgroundRepeat:no-repeat
rn-backgroundSize:cover
@@ -332,9 +368,9 @@ rn-borderLeftWidth:0px
rn-boxSizing:border-box
rn-color:inherit
rn-display:flex
rn-flexShrink:0
rn-flexBasis:auto
rn-flexDirection:column
rn-flexShrink:0
rn-font:inherit
rn-listStyle:none
rn-marginTop:0px
@@ -349,13 +385,27 @@ rn-paddingBottom:0px
rn-paddingLeft:0px
rn-position:relative
rn-textAlign:inherit
rn-textDecoration:none"
role="img"
rn-textDecoration:none
rn-zIndex:0"
style={
Object {
"backgroundImage": "url(\"https://google.com/favicon.ico\")",
}
} />
}>
<img
className="
rn-bottom:0px
rn-height:100%
rn-left:0px
rn-opacity:0
rn-position:absolute
rn-right:0px
rn-top:0px
rn-width:100%
rn-zIndex:-1"
src="https://google.com/favicon.ico"
style={Object {}} />
</div>
`;
exports[`components/Image prop "resizeMode" value "contain" 1`] = `
@@ -377,9 +427,9 @@ rn-borderLeftWidth:0px
rn-boxSizing:border-box
rn-color:inherit
rn-display:flex
rn-flexShrink:0
rn-flexBasis:auto
rn-flexDirection:column
rn-flexShrink:0
rn-font:inherit
rn-listStyle:none
rn-marginTop:0px
@@ -394,8 +444,8 @@ rn-paddingBottom:0px
rn-paddingLeft:0px
rn-position:relative
rn-textAlign:inherit
rn-textDecoration:none"
role="img"
rn-textDecoration:none
rn-zIndex:0"
style={Object {}} />
`;
@@ -418,9 +468,9 @@ rn-borderLeftWidth:0px
rn-boxSizing:border-box
rn-color:inherit
rn-display:flex
rn-flexShrink:0
rn-flexBasis:auto
rn-flexDirection:column
rn-flexShrink:0
rn-font:inherit
rn-listStyle:none
rn-marginTop:0px
@@ -435,8 +485,8 @@ rn-paddingBottom:0px
rn-paddingLeft:0px
rn-position:relative
rn-textAlign:inherit
rn-textDecoration:none"
role="img"
rn-textDecoration:none
rn-zIndex:0"
style={Object {}} />
`;
@@ -459,9 +509,9 @@ rn-borderLeftWidth:0px
rn-boxSizing:border-box
rn-color:inherit
rn-display:flex
rn-flexShrink:0
rn-flexBasis:auto
rn-flexDirection:column
rn-flexShrink:0
rn-font:inherit
rn-listStyle:none
rn-marginTop:0px
@@ -476,8 +526,8 @@ rn-paddingBottom:0px
rn-paddingLeft:0px
rn-position:relative
rn-textAlign:inherit
rn-textDecoration:none"
role="img"
rn-textDecoration:none
rn-zIndex:0"
style={Object {}} />
`;
@@ -500,9 +550,9 @@ rn-borderLeftWidth:0px
rn-boxSizing:border-box
rn-color:inherit
rn-display:flex
rn-flexShrink:0
rn-flexBasis:auto
rn-flexDirection:column
rn-flexShrink:0
rn-font:inherit
rn-listStyle:none
rn-marginTop:0px
@@ -517,8 +567,8 @@ rn-paddingBottom:0px
rn-paddingLeft:0px
rn-position:relative
rn-textAlign:inherit
rn-textDecoration:none"
role="img"
rn-textDecoration:none
rn-zIndex:0"
style={Object {}} />
`;
@@ -541,9 +591,9 @@ rn-borderLeftWidth:0px
rn-boxSizing:border-box
rn-color:inherit
rn-display:flex
rn-flexShrink:0
rn-flexBasis:auto
rn-flexDirection:column
rn-flexShrink:0
rn-font:inherit
rn-listStyle:none
rn-marginTop:0px
@@ -558,8 +608,8 @@ rn-paddingBottom:0px
rn-paddingLeft:0px
rn-position:relative
rn-textAlign:inherit
rn-textDecoration:none"
role="img"
rn-textDecoration:none
rn-zIndex:0"
style={Object {}} />
`;
@@ -582,9 +632,9 @@ rn-borderLeftWidth:0px
rn-boxSizing:border-box
rn-color:inherit
rn-display:flex
rn-flexShrink:0
rn-flexBasis:auto
rn-flexDirection:column
rn-flexShrink:0
rn-font:inherit
rn-listStyle:none
rn-marginTop:0px
@@ -599,8 +649,8 @@ rn-paddingBottom:0px
rn-paddingLeft:0px
rn-position:relative
rn-textAlign:inherit
rn-textDecoration:none"
role="img"
rn-textDecoration:none
rn-zIndex:0"
style={Object {}} />
`;
@@ -623,9 +673,9 @@ rn-borderLeftWidth:0px
rn-boxSizing:border-box
rn-color:inherit
rn-display:flex
rn-flexShrink:0
rn-flexBasis:auto
rn-flexDirection:column
rn-flexShrink:0
rn-font:inherit
rn-listStyle:none
rn-marginTop:0px
@@ -640,9 +690,9 @@ rn-paddingBottom:0px
rn-paddingLeft:0px
rn-position:relative
rn-textAlign:inherit
rn-textDecoration:none"
rn-textDecoration:none
rn-zIndex:0"
data-testid="testID"
role="img"
style={Object {}} />
`;
@@ -665,9 +715,9 @@ rn-borderLeftWidth:0px
rn-boxSizing:border-box
rn-color:inherit
rn-display:flex
rn-flexShrink:0
rn-flexBasis:auto
rn-flexDirection:column
rn-flexShrink:0
rn-font:inherit
rn-listStyle:none
rn-marginTop:0px
@@ -682,7 +732,7 @@ rn-paddingBottom:0px
rn-paddingLeft:0px
rn-position:relative
rn-textAlign:inherit
rn-textDecoration:none"
role="img"
rn-textDecoration:none
rn-zIndex:0"
style={Object {}} />
`;

View File

@@ -1,12 +1,14 @@
/* global window */
import applyNativeMethods from '../../modules/applyNativeMethods';
import createDOMElement from '../../modules/createDOMElement';
import ImageResizeMode from './ImageResizeMode';
import ImageLoader from '../../modules/ImageLoader';
import ImageStylePropTypes from './ImageStylePropTypes';
import requestAnimationFrame from 'fbjs/lib/requestAnimationFrame';
import requestIdleCallback, { cancelIdleCallback } from '../../modules/requestIdleCallback';
import StyleSheet from '../../apis/StyleSheet';
import StyleSheetPropType from '../../propTypes/StyleSheetPropType';
import View from '../View';
import ViewPropTypes from '../View/ViewPropTypes';
import React, { Component, PropTypes } from 'react';
const emptyObject = {};
@@ -41,7 +43,7 @@ class Image extends Component {
static displayName = 'Image';
static propTypes = {
...View.propTypes,
...ViewPropTypes,
children: PropTypes.any,
defaultSource: ImageSourcePropType,
onError: PropTypes.func,
@@ -137,28 +139,42 @@ class Image extends Component {
// View doesn't support 'resizeMode' as a style
delete style.resizeMode;
// Allows users to trigger the browser's image context menu
const hiddenImage = displayImage ? createDOMElement('img', {
src: displayImage,
style: [ StyleSheet.absoluteFill, styles.img ]
}) : null;
return (
<View
{...other}
accessibilityLabel={accessibilityLabel}
accessibilityRole='img'
accessible={accessible}
children={children}
onLayout={onLayout}
style={style}
testID={testID}
/>
>
{hiddenImage}
{children}
</View>
);
}
_createImageLoader() {
this._destroyImageLoader();
const uri = resolveAssetSource(this.props.source);
this._imageRequestId = ImageLoader.load(uri, this._onLoad, this._onError);
this._onLoadStart();
this._loadRequest = requestIdleCallback(() => {
this._destroyImageLoader();
const uri = resolveAssetSource(this.props.source);
this._imageRequestId = ImageLoader.load(uri, this._onLoad, this._onError);
this._onLoadStart();
});
}
_destroyImageLoader() {
if (this._loadRequest) {
cancelIdleCallback(this._loadRequest);
this._loadRequest = null;
}
if (this._imageRequestId) {
ImageLoader.abort(this._imageRequestId);
this._imageRequestId = null;
@@ -203,11 +219,9 @@ class Image extends Component {
const shouldDisplaySource = this._imageState === STATUS_LOADED || this._imageState === STATUS_LOADING;
// only triggers a re-render when the image is loading (to support PJEG), loaded, or failed
if (shouldDisplaySource !== this.state.shouldDisplaySource) {
requestAnimationFrame(() => {
if (this._isMounted) {
this.setState({ shouldDisplaySource });
}
});
if (this._isMounted) {
this.setState(() => ({ shouldDisplaySource }));
}
}
}
}
@@ -217,7 +231,14 @@ const styles = StyleSheet.create({
backgroundColor: 'transparent',
backgroundPosition: 'center',
backgroundRepeat: 'no-repeat',
backgroundSize: 'cover'
backgroundSize: 'cover',
zIndex: 0
},
img: {
height: '100%',
opacity: 0,
width: '100%',
zIndex: -1
}
});

View File

@@ -107,20 +107,42 @@ class ListView extends Component {
render() {
const children = [];
const dataSource = this.props.dataSource;
const {
dataSource,
enableEmptySections,
renderFooter,
renderHeader,
renderScrollComponent,
renderSectionHeader,
renderSeparator,
/* eslint-disable */
initialListSize,
onEndReachedThreshold,
onKeyboardDidHide,
onKeyboardDidShow,
onKeyboardWillHide,
onKeyboardWillShow,
pageSize,
renderRow,
scrollRenderAheadDistance,
stickyHeaderIndices,
/* eslint-enable */
...scrollProps
} = this.props;
const allRowIDs = dataSource.rowIdentities;
let rowCount = 0;
const sectionHeaderIndices = [];
const header = this.props.renderHeader && this.props.renderHeader();
const footer = this.props.renderFooter && this.props.renderFooter();
const header = renderHeader && renderHeader();
const footer = renderFooter && renderFooter();
let totalIndex = header ? 1 : 0;
for (let sectionIdx = 0; sectionIdx < allRowIDs.length; sectionIdx++) {
const sectionID = dataSource.sectionIdentities[sectionIdx];
const rowIDs = allRowIDs[sectionIdx];
if (rowIDs.length === 0) {
if (this.props.enableEmptySections === undefined) {
if (enableEmptySections === undefined) {
const warning = require('fbjs/lib/warning');
warning(false, 'In next release empty section headers will be rendered.' +
' In this release you can use \'enableEmptySections\' flag to render empty section headers.');
@@ -128,7 +150,7 @@ class ListView extends Component {
} else {
const invariant = require('fbjs/lib/invariant');
invariant(
this.props.enableEmptySections,
enableEmptySections,
'In next release \'enableEmptySections\' flag will be deprecated,' +
' empty section headers will always be rendered. If empty section headers' +
' are not desirable their indices should be excluded from sectionIDs object.' +
@@ -137,7 +159,7 @@ class ListView extends Component {
}
}
if (this.props.renderSectionHeader) {
if (renderSectionHeader) {
const shouldUpdateHeader = rowCount >= this._prevRenderedRowsCount &&
dataSource.sectionHeaderShouldUpdate(sectionIdx);
children.push(
@@ -171,14 +193,14 @@ class ListView extends Component {
children.push(row);
totalIndex++;
if (this.props.renderSeparator &&
if (renderSeparator &&
(rowIdx !== rowIDs.length - 1 || sectionIdx === allRowIDs.length - 1)) {
const adjacentRowHighlighted =
this.state.highlightedRow.sectionID === sectionID && (
this.state.highlightedRow.rowID === rowID ||
this.state.highlightedRow.rowID === rowIDs[rowIdx + 1]
);
const separator = this.props.renderSeparator(
const separator = renderSeparator(
sectionID,
rowID,
adjacentRowHighlighted
@@ -196,24 +218,9 @@ class ListView extends Component {
break;
}
}
scrollProps.onScroll = this._onScroll;
const {
renderScrollComponent,
...props
} = this.props;
Object.assign(props, {
onScroll: this._onScroll,
stickyHeaderIndices: this.props.stickyHeaderIndices.concat(sectionHeaderIndices),
// Do not pass these events downstream to ScrollView since they will be
// registered in ListView's own ScrollResponder.Mixin
onKeyboardWillShow: undefined,
onKeyboardWillHide: undefined,
onKeyboardDidShow: undefined,
onKeyboardDidHide: undefined
});
return React.cloneElement(renderScrollComponent(props), {
return React.cloneElement(renderScrollComponent(scrollProps), {
ref: this._setScrollViewRef,
onContentSizeChange: this._onContentSizeChange,
onLayout: this._onLayout

View File

@@ -2,13 +2,14 @@ import applyNativeMethods from '../../modules/applyNativeMethods';
import ColorPropType from '../../propTypes/ColorPropType';
import StyleSheet from '../../apis/StyleSheet';
import View from '../View';
import ViewPropTypes from '../View/ViewPropTypes';
import React, { Component, PropTypes } from 'react';
class ProgressBar extends Component {
static displayName = 'ProgressBar';
static propTypes = {
...View.propTypes,
...ViewPropTypes,
color: ColorPropType,
indeterminate: PropTypes.bool,
progress: PropTypes.number,

View File

@@ -8,6 +8,7 @@
import debounce from 'debounce';
import View from '../View';
import ViewPropTypes from '../View/ViewPropTypes';
import React, { Component, PropTypes } from 'react';
const normalizeScrollEvent = (e) => ({
@@ -36,7 +37,8 @@ const normalizeScrollEvent = (e) => ({
return e.target.offsetWidth;
}
}
}
},
timeStamp: Date.now()
});
/**
@@ -44,7 +46,7 @@ const normalizeScrollEvent = (e) => ({
*/
export default class ScrollViewBase extends Component {
static propTypes = {
...View.propTypes,
...ViewPropTypes,
onMomentumScrollBegin: PropTypes.func,
onMomentumScrollEnd: PropTypes.func,
onScroll: PropTypes.func,

View File

@@ -14,6 +14,7 @@ import ScrollViewBase from './ScrollViewBase';
import StyleSheet from '../../apis/StyleSheet';
import StyleSheetPropType from '../../propTypes/StyleSheetPropType';
import View from '../View';
import ViewPropTypes from '../View/ViewPropTypes';
import ViewStylePropTypes from '../View/ViewStylePropTypes';
import React, { Component, PropTypes } from 'react';
@@ -22,7 +23,7 @@ const emptyObject = {};
/* eslint-disable react/prefer-es6-class */
const ScrollView = React.createClass({
propTypes: {
...View.propTypes,
...ViewPropTypes,
contentContainerStyle: StyleSheetPropType(ViewStylePropTypes),
horizontal: PropTypes.bool,
keyboardDismissMode: PropTypes.oneOf([ 'none', 'interactive', 'on-drag' ]),

View File

@@ -15,11 +15,10 @@ rn-boxSizing:border-box
rn-color:inherit
rn-cursor:pointer
rn-display:flex
rn-flexShrink:0
rn-flexBasis:auto
rn-flexDirection:column
rn-flexShrink:0
rn-font:inherit
rn-listStyle:none
rn-marginTop:0px
rn-marginRight:0px
@@ -44,11 +43,6 @@ rn-userSelect:none"
<div
className="
rn-alignItems:stretch
rn-borderTopStyle:solid
rn-borderRightStyle:solid
rn-borderBottomStyle:solid
@@ -61,9 +55,9 @@ rn-userSelect:none"
rn-boxSizing:border-box
rn-color:inherit
rn-display:flex
rn-flexShrink:0
rn-flexBasis:auto
rn-flexDirection:column
rn-flexShrink:0
rn-font:inherit
rn-height:70%
rn-left:0px
@@ -98,7 +92,6 @@ rn-userSelect:none"
className="
rn-alignItems:stretch
rn-alignSelf:flex-start
rn-borderTopLeftRadius:100%
rn-borderTopRightRadius:100%
rn-borderBottomRightRadius:100%
@@ -115,11 +108,10 @@ rn-userSelect:none"
rn-boxSizing:border-box
rn-color:inherit
rn-display:flex
rn-flexShrink:0
rn-flexBasis:auto
rn-flexDirection:column
rn-flexShrink:0
rn-font:inherit
rn-left:0%
rn-listStyle:none
rn-marginTop:0px
@@ -190,11 +182,10 @@ rn-boxSizing:border-box
rn-color:inherit
rn-cursor:default
rn-display:flex
rn-flexShrink:0
rn-flexBasis:auto
rn-flexDirection:column
rn-flexShrink:0
rn-font:inherit
rn-listStyle:none
rn-marginTop:0px
rn-marginRight:0px
@@ -220,10 +211,6 @@ rn-userSelect:none"
className="
rn-alignItems:stretch
rn-backgroundColor:#D5D5D5
rn-borderTopStyle:solid
rn-borderRightStyle:solid
rn-borderBottomStyle:solid
@@ -236,9 +223,9 @@ rn-userSelect:none"
rn-boxSizing:border-box
rn-color:inherit
rn-display:flex
rn-flexShrink:0
rn-flexBasis:auto
rn-flexDirection:column
rn-flexShrink:0
rn-font:inherit
rn-height:70%
rn-left:0px
@@ -289,11 +276,10 @@ rn-userSelect:none"
rn-boxSizing:border-box
rn-color:inherit
rn-display:flex
rn-flexShrink:0
rn-flexBasis:auto
rn-flexDirection:column
rn-flexShrink:0
rn-font:inherit
rn-left:0%
rn-listStyle:none
rn-marginTop:0px
@@ -363,11 +349,10 @@ rn-boxSizing:border-box
rn-color:inherit
rn-cursor:pointer
rn-display:flex
rn-flexShrink:0
rn-flexBasis:auto
rn-flexDirection:column
rn-flexShrink:0
rn-font:inherit
rn-listStyle:none
rn-marginTop:0px
rn-marginRight:0px
@@ -392,11 +377,6 @@ rn-userSelect:none"
<div
className="
rn-alignItems:stretch
rn-borderTopStyle:solid
rn-borderRightStyle:solid
rn-borderBottomStyle:solid
@@ -409,9 +389,9 @@ rn-userSelect:none"
rn-boxSizing:border-box
rn-color:inherit
rn-display:flex
rn-flexShrink:0
rn-flexBasis:auto
rn-flexDirection:column
rn-flexShrink:0
rn-font:inherit
rn-height:70%
rn-left:0px
@@ -446,7 +426,6 @@ rn-userSelect:none"
className="
rn-alignItems:stretch
rn-alignSelf:flex-start
rn-borderTopLeftRadius:100%
rn-borderTopRightRadius:100%
rn-borderBottomRightRadius:100%
@@ -463,11 +442,10 @@ rn-userSelect:none"
rn-boxSizing:border-box
rn-color:inherit
rn-display:flex
rn-flexShrink:0
rn-flexBasis:auto
rn-flexDirection:column
rn-flexShrink:0
rn-font:inherit
rn-left:0%
rn-listStyle:none
rn-marginTop:0px
@@ -538,11 +516,10 @@ rn-boxSizing:border-box
rn-color:inherit
rn-cursor:pointer
rn-display:flex
rn-flexShrink:0
rn-flexBasis:auto
rn-flexDirection:column
rn-flexShrink:0
rn-font:inherit
rn-listStyle:none
rn-marginTop:0px
rn-marginRight:0px
@@ -567,11 +544,6 @@ rn-userSelect:none"
<div
className="
rn-alignItems:stretch
rn-borderTopStyle:solid
rn-borderRightStyle:solid
rn-borderBottomStyle:solid
@@ -584,9 +556,9 @@ rn-userSelect:none"
rn-boxSizing:border-box
rn-color:inherit
rn-display:flex
rn-flexShrink:0
rn-flexBasis:auto
rn-flexDirection:column
rn-flexShrink:0
rn-font:inherit
rn-height:70%
rn-left:0px
@@ -621,7 +593,6 @@ rn-userSelect:none"
className="
rn-alignItems:stretch
rn-alignSelf:flex-start
rn-borderTopLeftRadius:100%
rn-borderTopRightRadius:100%
rn-borderBottomRightRadius:100%
@@ -638,17 +609,15 @@ rn-userSelect:none"
rn-boxSizing:border-box
rn-color:inherit
rn-display:flex
rn-flexShrink:0
rn-flexBasis:auto
rn-flexDirection:column
rn-flexShrink:0
rn-font:inherit
rn-left:100%
rn-listStyle:none
rn-marginTop:0px
rn-marginRight:0px
rn-marginBottom:0px
rn-minHeight:0px
rn-minWidth:0px
rn-paddingTop:0px

View File

@@ -5,6 +5,7 @@ import multiplyStyleLengthValue from '../../modules/multiplyStyleLengthValue';
import StyleSheet from '../../apis/StyleSheet';
import UIManager from '../../apis/UIManager';
import View from '../View';
import ViewPropTypes from '../View/ViewPropTypes';
import React, { Component, PropTypes } from 'react';
const emptyObject = {};
@@ -15,7 +16,7 @@ class Switch extends Component {
static displayName = 'Switch';
static propTypes = {
...View.propTypes,
...ViewPropTypes,
activeThumbColor: ColorPropType,
activeTrackColor: ColorPropType,
disabled: PropTypes.bool,

View File

@@ -1,7 +1,42 @@
import TextPropTypes from '../../propTypes/TextPropTypes';
import ColorPropType from '../../propTypes/ColorPropType';
import { PropTypes } from 'react';
import ViewStylePropTypes from '../View/ViewStylePropTypes';
module.exports = process.env.NODE_ENV !== 'production' ? {
const { number, oneOf, oneOfType, shape, string } = PropTypes;
const numberOrString = oneOfType([ number, string ]);
const ShadowOffsetPropType = shape({ width: number, height: number });
const TextAlignPropType = oneOf([ 'center', 'inherit', 'justify', 'justify-all', 'left', 'right' ]);
const WritingDirectionPropType = oneOf([ 'auto', 'ltr', 'rtl' ]);
const TextOnlyStylePropTypes = {
color: ColorPropType,
fontFamily: string,
fontFeatureSettings: string,
fontSize: numberOrString,
fontStyle: string,
fontWeight: string,
letterSpacing: numberOrString,
lineHeight: numberOrString,
textAlign: TextAlignPropType,
textAlignVertical: oneOf([ 'auto', 'bottom', 'center', 'top' ]),
textDecorationLine: string,
textShadowColor: ColorPropType,
textShadowOffset: ShadowOffsetPropType,
textShadowRadius: number,
writingDirection: WritingDirectionPropType,
/* @platform web */
textOverflow: string,
textRendering: oneOf([ 'auto', 'geometricPrecision', 'optimizeLegibility', 'optimizeSpeed' ]),
textTransform: oneOf([ 'capitalize', 'lowercase', 'none', 'uppercase' ]),
unicodeBidi: oneOf([ 'normal', 'bidi-override', 'embed', 'isolate', 'isolate-override', 'plaintext' ]),
whiteSpace: string,
wordWrap: string,
MozOsxFontSmoothing: string,
WebkitFontSmoothing: string
};
module.exports = {
...ViewStylePropTypes,
...TextPropTypes
} : {};
...TextOnlyStylePropTypes
};

View File

@@ -0,0 +1,14 @@
import TextStylePropTypes from '../Text/TextStylePropTypes';
import { PropTypes } from 'react';
const { oneOf } = PropTypes;
const TextInputOnlyStylePropTypes = {
/* @platform web */
resize: oneOf([ 'none', 'vertical', 'horizontal', 'both' ])
};
module.exports = {
...TextStylePropTypes,
...TextInputOnlyStylePropTypes
};

View File

@@ -1,13 +1,14 @@
import applyLayout from '../../modules/applyLayout';
import applyNativeMethods from '../../modules/applyNativeMethods';
import NativeMethodsMixin from '../../modules/NativeMethodsMixin';
import createDOMElement from '../../modules/createDOMElement';
import findNodeHandle from '../../modules/findNodeHandle';
import StyleSheet from '../../apis/StyleSheet';
import Text from '../Text';
import StyleSheetPropType from '../../propTypes/StyleSheetPropType';
import TextInputStylePropTypes from './TextInputStylePropTypes';
import TextareaAutosize from 'react-textarea-autosize';
import TextInputState from './TextInputState';
import UIManager from '../../apis/UIManager';
import View from '../View';
import ViewPropTypes from '../View/ViewPropTypes';
import { Component, PropTypes } from 'react';
const emptyObject = {};
@@ -52,7 +53,7 @@ class TextInput extends Component {
static displayName = 'TextInput';
static propTypes = {
...View.propTypes,
...ViewPropTypes,
autoCapitalize: PropTypes.oneOf([ 'characters', 'none', 'sentences', 'words' ]),
autoComplete: PropTypes.string,
autoCorrect: PropTypes.bool,
@@ -83,7 +84,7 @@ class TextInput extends Component {
start: PropTypes.number.isRequired,
end: PropTypes.number
}),
style: Text.propTypes.style,
style: StyleSheetPropType(TextInputStylePropTypes),
value: PropTypes.string
};
@@ -99,6 +100,8 @@ class TextInput extends Component {
style: emptyObject
};
static State = TextInputState;
blur() {
TextInputState.blurTextInput(this._node);
}
@@ -116,7 +119,7 @@ class TextInput extends Component {
}
setNativeProps(props) {
UIManager.updateView(this._node, props, this);
NativeMethodsMixin.setNativeProps.call(this, props);
}
componentDidMount() {
@@ -274,7 +277,8 @@ const styles = StyleSheet.create({
boxSizing: 'border-box',
color: 'inherit',
font: 'inherit',
padding: 0
padding: 0,
resize: 'none'
}
});

View File

@@ -0,0 +1,37 @@
import BaseComponentPropTypes from '../../propTypes/BaseComponentPropTypes';
import EdgeInsetsPropType from '../../propTypes/EdgeInsetsPropType';
import StyleSheetPropType from '../../propTypes/StyleSheetPropType';
import ViewStylePropTypes from './ViewStylePropTypes';
import { PropTypes } from 'react';
const ViewPropTypes = {
...BaseComponentPropTypes,
children: PropTypes.any,
collapsable: PropTypes.bool,
hitSlop: EdgeInsetsPropType,
onClick: PropTypes.func,
onClickCapture: PropTypes.func,
onLayout: PropTypes.func,
onMoveShouldSetResponder: PropTypes.func,
onMoveShouldSetResponderCapture: PropTypes.func,
onResponderGrant: PropTypes.func,
onResponderMove: PropTypes.func,
onResponderReject: PropTypes.func,
onResponderRelease: PropTypes.func,
onResponderTerminate: PropTypes.func,
onResponderTerminationRequest: PropTypes.func,
onStartShouldSetResponder: PropTypes.func,
onStartShouldSetResponderCapture: PropTypes.func,
onTouchCancel: PropTypes.func,
onTouchCancelCapture: PropTypes.func,
onTouchEnd: PropTypes.func,
onTouchEndCapture: PropTypes.func,
onTouchMove: PropTypes.func,
onTouchMoveCapture: PropTypes.func,
onTouchStart: PropTypes.func,
onTouchStartCapture: PropTypes.func,
pointerEvents: PropTypes.oneOf([ 'auto', 'box-none', 'box-only', 'none' ]),
style: StyleSheetPropType(ViewStylePropTypes)
};
module.exports = ViewPropTypes;

View File

@@ -10,7 +10,7 @@ const { number, oneOf, string } = PropTypes;
const autoOrHiddenOrVisible = oneOf([ 'auto', 'hidden', 'visible' ]);
const hiddenOrVisible = oneOf([ 'hidden', 'visible' ]);
module.exports = process.env.NODE_ENV !== 'production' ? {
module.exports = {
...AnimationPropTypes,
...BorderPropTypes,
...LayoutPropTypes,
@@ -33,7 +33,6 @@ module.exports = process.env.NODE_ENV !== 'production' ? {
backgroundSize: string,
boxShadow: string,
cursor: string,
display: string,
outline: string,
overflowX: autoOrHiddenOrVisible,
overflowY: autoOrHiddenOrVisible,
@@ -45,5 +44,6 @@ module.exports = process.env.NODE_ENV !== 'production' ? {
transitionTimingFunction: string,
userSelect: string,
visibility: hiddenOrVisible,
willChange: string,
WebkitOverflowScrolling: oneOf([ 'auto', 'touch' ])
} : {};
};

View File

@@ -14,9 +14,9 @@ rn-borderLeftWidth:0px
rn-boxSizing:border-box
rn-color:inherit
rn-display:flex
rn-flexShrink:0
rn-flexBasis:auto
rn-flexDirection:column
rn-flexShrink:0
rn-font:inherit
rn-listStyle:none
rn-marginTop:0px
@@ -31,8 +31,7 @@ rn-paddingBottom:0px
rn-paddingLeft:0px
rn-position:relative
rn-textAlign:inherit
rn-textDecoration:none"
style={Object {}}>
rn-textDecoration:none">
<div
className="
rn-alignItems:stretch
@@ -48,9 +47,9 @@ rn-textDecoration:none"
rn-boxSizing:border-box
rn-color:inherit
rn-display:flex
rn-flexShrink:0
rn-flexBasis:auto
rn-flexDirection:column
rn-flexShrink:0
rn-font:inherit
rn-listStyle:none
rn-marginTop:0px
@@ -66,8 +65,7 @@ rn-textDecoration:none"
rn-position:relative
rn-textAlign:inherit
rn-textDecoration:none"
data-testid="1"
style={Object {}} />
data-testid="1" />
</div>
`;
@@ -87,51 +85,9 @@ rn-borderLeftWidth:0px
rn-boxSizing:border-box
rn-color:inherit
rn-display:flex
rn-flexShrink:0
rn-flexBasis:auto
rn-flexDirection:column
rn-flexShrink:0
rn-font:inherit
rn-listStyle:none
rn-marginTop:0px
rn-marginRight:0px
rn-marginBottom:0px
rn-marginLeft:0px
rn-minHeight:0px
rn-minWidth:0px
rn-paddingTop:0px
rn-paddingRight:0px
rn-paddingBottom:0px
rn-paddingLeft:0px
rn-position:relative
rn-textAlign:inherit
rn-textDecoration:none"
style={
Object {
"pointerEvents": "box-only",
}
} />
`;
exports[`components/View prop "style" 1`] = `
<div
className="
rn-alignItems:stretch
rn-backgroundColor:transparent
rn-borderTopStyle:solid
rn-borderRightStyle:solid
rn-borderBottomStyle:solid
rn-borderLeftStyle:solid
rn-borderTopWidth:0px
rn-borderRightWidth:0px
rn-borderBottomWidth:0px
rn-borderLeftWidth:0px
rn-boxSizing:border-box
rn-color:inherit
rn-display:flex
rn-flexBasis:auto
rn-flexDirection:column
rn-flexShrink:0
rn-font:inherit
rn-listStyle:none
rn-marginTop:0px
@@ -144,149 +100,13 @@ rn-paddingTop:0px
rn-paddingRight:0px
rn-paddingBottom:0px
rn-paddingLeft:0px
rn-pointerEvents:box-only
rn-position:relative
rn-textAlign:inherit
rn-textDecoration:none"
style={Object {}} />
`;
exports[`components/View prop "style" 2`] = `
<div
className="
rn-alignItems:stretch
rn-backgroundColor:transparent
rn-borderTopStyle:solid
rn-borderRightStyle:solid
rn-borderBottomStyle:solid
rn-borderLeftStyle:solid
rn-borderTopWidth:0px
rn-borderRightWidth:0px
rn-borderBottomWidth:0px
rn-borderLeftWidth:0px
rn-boxSizing:border-box
rn-color:inherit
rn-display:flex
rn-flexBasis:auto
rn-flexDirection:column
rn-font:inherit
rn-listStyle:none
rn-marginTop:0px
rn-marginRight:0px
rn-marginBottom:0px
rn-marginLeft:0px
rn-minHeight:0px
rn-minWidth:0px
rn-paddingTop:0px
rn-paddingRight:0px
rn-paddingBottom:0px
rn-paddingLeft:0px
rn-position:relative
rn-textAlign:inherit
rn-textDecoration:none"
style={
Object {
"WebkitFlexGrow": 1,
"WebkitFlexShrink": 1,
"flexGrow": 1,
"flexShrink": 1,
"msFlexNegative": 1,
"msFlexPositive": 1,
}
} />
`;
exports[`components/View prop "style" 3`] = `
<div
className="
rn-alignItems:stretch
rn-backgroundColor:transparent
rn-borderTopStyle:solid
rn-borderRightStyle:solid
rn-borderBottomStyle:solid
rn-borderLeftStyle:solid
rn-borderTopWidth:0px
rn-borderRightWidth:0px
rn-borderBottomWidth:0px
rn-borderLeftWidth:0px
rn-boxSizing:border-box
rn-color:inherit
rn-display:flex
rn-flexBasis:auto
rn-flexDirection:column
rn-font:inherit
rn-listStyle:none
rn-marginTop:0px
rn-marginRight:0px
rn-marginBottom:0px
rn-marginLeft:0px
rn-minHeight:0px
rn-minWidth:0px
rn-paddingTop:0px
rn-paddingRight:0px
rn-paddingBottom:0px
rn-paddingLeft:0px
rn-position:relative
rn-textAlign:inherit
rn-textDecoration:none"
style={
Object {
"WebkitFlexShrink": 1,
"flexShrink": 1,
"msFlexNegative": 1,
}
} />
`;
exports[`components/View prop "style" 4`] = `
<div
className="
rn-alignItems:stretch
rn-backgroundColor:transparent
rn-borderTopStyle:solid
rn-borderRightStyle:solid
rn-borderBottomStyle:solid
rn-borderLeftStyle:solid
rn-borderTopWidth:0px
rn-borderRightWidth:0px
rn-borderBottomWidth:0px
rn-borderLeftWidth:0px
rn-boxSizing:border-box
rn-color:inherit
rn-display:flex
rn-flexBasis:auto
rn-flexDirection:column
rn-font:inherit
rn-listStyle:none
rn-marginTop:0px
rn-marginRight:0px
rn-marginBottom:0px
rn-marginLeft:0px
rn-minHeight:0px
rn-minWidth:0px
rn-paddingTop:0px
rn-paddingRight:0px
rn-paddingBottom:0px
rn-paddingLeft:0px
rn-position:relative
rn-textAlign:inherit
rn-textDecoration:none"
style={
Object {
"WebkitFlexGrow": 1,
"WebkitFlexShrink": 2,
"flexGrow": 1,
"flexShrink": 2,
"msFlexNegative": 2,
"msFlexPositive": 1,
}
} />
`;
exports[`components/View rendered element is a "div" by default 1`] = `
<div
className="
@@ -303,9 +123,9 @@ rn-borderLeftWidth:0px
rn-boxSizing:border-box
rn-color:inherit
rn-display:flex
rn-flexShrink:0
rn-flexBasis:auto
rn-flexDirection:column
rn-flexShrink:0
rn-font:inherit
rn-listStyle:none
rn-marginTop:0px
@@ -320,8 +140,7 @@ rn-paddingBottom:0px
rn-paddingLeft:0px
rn-position:relative
rn-textAlign:inherit
rn-textDecoration:none"
style={Object {}} />
rn-textDecoration:none" />
`;
exports[`components/View rendered element is a "span" when inside <View accessibilityRole="button" /> 1`] = `
@@ -340,9 +159,9 @@ rn-borderLeftWidth:0px
rn-boxSizing:border-box
rn-color:inherit
rn-display:flex
rn-flexShrink:0
rn-flexBasis:auto
rn-flexDirection:column
rn-flexShrink:0
rn-font:inherit
rn-listStyle:none
rn-marginTop:0px
@@ -359,7 +178,6 @@ rn-position:relative
rn-textAlign:inherit
rn-textDecoration:none"
role="button"
style={Object {}}
type="button">
<span
className="
@@ -376,9 +194,9 @@ rn-textDecoration:none"
rn-boxSizing:border-box
rn-color:inherit
rn-display:flex
rn-flexShrink:0
rn-flexBasis:auto
rn-flexDirection:column
rn-flexShrink:0
rn-font:inherit
rn-listStyle:none
rn-marginTop:0px
@@ -393,7 +211,6 @@ rn-textDecoration:none"
rn-paddingLeft:0px
rn-position:relative
rn-textAlign:inherit
rn-textDecoration:none"
style={Object {}} />
rn-textDecoration:none" />
</button>
`;

View File

@@ -29,18 +29,4 @@ describe('components/View', () => {
const component = renderer.create(<View pointerEvents='box-only' />);
expect(component.toJSON()).toMatchSnapshot();
});
test('prop "style"', () => {
let component = renderer.create(<View />);
expect(component.toJSON()).toMatchSnapshot();
component = renderer.create(<View style={{ flex: 1 }} />);
expect(component.toJSON()).toMatchSnapshot();
component = renderer.create(<View style={{ flexShrink: 1 }} />);
expect(component.toJSON()).toMatchSnapshot();
component = renderer.create(<View style={{ flex: 1, flexShrink: 2 }} />);
expect(component.toJSON()).toMatchSnapshot();
});
});

View File

@@ -2,13 +2,10 @@ import '../../modules/injectResponderEventPlugin';
import applyLayout from '../../modules/applyLayout';
import applyNativeMethods from '../../modules/applyNativeMethods';
import BaseComponentPropTypes from '../../propTypes/BaseComponentPropTypes';
import createDOMElement from '../../modules/createDOMElement';
import EdgeInsetsPropType from '../../propTypes/EdgeInsetsPropType';
import normalizeNativeEvent from '../../modules/normalizeNativeEvent';
import StyleSheet from '../../apis/StyleSheet';
import StyleSheetPropType from '../../propTypes/StyleSheetPropType';
import ViewStylePropTypes from './ViewStylePropTypes';
import ViewPropTypes from './ViewPropTypes';
import { Component, PropTypes } from 'react';
const eventHandlerNames = [
@@ -34,38 +31,24 @@ const eventHandlerNames = [
'onTouchStartCapture'
];
const _normalizeEventForHandler = (handler) => (e) => {
e.nativeEvent = normalizeNativeEvent(e.nativeEvent);
return handler(e);
};
const normalizeEventHandlers = (props) => {
eventHandlerNames.forEach((handlerName) => {
const handler = props[handlerName];
if (typeof handler === 'function') {
props[handlerName] = _normalizeEventForHandler(handler);
}
});
};
class View extends Component {
static displayName = 'View';
static propTypes = {
...BaseComponentPropTypes,
children: PropTypes.any,
collapsable: PropTypes.bool,
hitSlop: EdgeInsetsPropType,
onClick: PropTypes.func,
onClickCapture: PropTypes.func,
onLayout: PropTypes.func,
onMoveShouldSetResponder: PropTypes.func,
onMoveShouldSetResponderCapture: PropTypes.func,
onResponderGrant: PropTypes.func,
onResponderMove: PropTypes.func,
onResponderReject: PropTypes.func,
onResponderRelease: PropTypes.func,
onResponderTerminate: PropTypes.func,
onResponderTerminationRequest: PropTypes.func,
onStartShouldSetResponder: PropTypes.func,
onStartShouldSetResponderCapture: PropTypes.func,
onTouchCancel: PropTypes.func,
onTouchCancelCapture: PropTypes.func,
onTouchEnd: PropTypes.func,
onTouchEndCapture: PropTypes.func,
onTouchMove: PropTypes.func,
onTouchMoveCapture: PropTypes.func,
onTouchStart: PropTypes.func,
onTouchStartCapture: PropTypes.func,
pointerEvents: PropTypes.oneOf([ 'auto', 'box-none', 'box-only', 'none' ]),
style: StyleSheetPropType(ViewStylePropTypes)
};
static propTypes = ViewPropTypes;
static defaultProps = {
accessible: true
@@ -102,37 +85,19 @@ class View extends Component {
...otherProps
} = this.props;
const flattenedStyle = StyleSheet.flatten(style);
const pointerEventsStyle = pointerEvents && { pointerEvents };
// 'View' needs to set 'flexShrink:0' only when there is no 'flex' or 'flexShrink' style provided
const needsFlexReset = !flattenedStyle || (flattenedStyle.flex == null && flattenedStyle.flexShrink == null);
const component = this.context.isInAButtonView ? 'span' : 'div';
eventHandlerNames.reduce((props, handlerName) => {
const handler = this.props[handlerName];
if (typeof handler === 'function') {
props[handlerName] = this._normalizeEventForHandler(handler);
}
return props;
}, otherProps);
// DOM events need to be normalized to expect RN format
normalizeEventHandlers(otherProps);
otherProps.style = [
styles.initial,
style,
needsFlexReset && styles.flexReset,
pointerEventsStyle
pointerEvents && pointerEventStyles[pointerEvents]
];
return createDOMElement(component, otherProps);
}
_normalizeEventForHandler(handler) {
return (e) => {
e.nativeEvent = normalizeNativeEvent(e.nativeEvent);
return handler(e);
};
}
}
const styles = StyleSheet.create({
@@ -165,4 +130,19 @@ const styles = StyleSheet.create({
}
});
const pointerEventStyles = StyleSheet.create({
'auto': {
pointerEvents: 'auto'
},
'box-none': {
pointerEvents: 'box-none'
},
'box-only': {
pointerEvents: 'box-only'
},
'none': {
pointerEvents: 'none'
}
});
module.exports = applyLayout(applyNativeMethods(View));

View File

@@ -1,8 +1,5 @@
import findNodeHandle from './modules/findNodeHandle';
import ReactDefaultInjection from 'react-dom/lib/ReactDefaultInjection';
import { render, unmountComponentAtNode } from 'react-dom/lib/ReactMount';
ReactDefaultInjection.inject();
import { render, unmountComponentAtNode } from 'react-dom';
// APIs
import I18nManager from './apis/I18nManager';
@@ -21,6 +18,9 @@ import View from './components/View';
// modules
import createDOMElement from './modules/createDOMElement';
import modality from './modules/modality';
modality();
const ReactNativeCore = {
createDOMElement,

View File

@@ -1,8 +1,5 @@
import findNodeHandle from './modules/findNodeHandle';
import ReactDefaultInjection from 'react-dom/lib/ReactDefaultInjection';
import { render, unmountComponentAtNode } from 'react-dom/lib/ReactMount';
ReactDefaultInjection.inject();
import { render, unmountComponentAtNode } from 'react-dom';
// APIs
import Animated from './apis/Animated';
@@ -42,6 +39,7 @@ import View from './components/View';
// modules
import createDOMElement from './modules/createDOMElement';
import modality from './modules/modality';
import NativeModules from './modules/NativeModules';
// propTypes
@@ -49,6 +47,8 @@ import ColorPropType from './propTypes/ColorPropType';
import EdgeInsetsPropType from './propTypes/EdgeInsetsPropType';
import PointPropType from './propTypes/PointPropType';
modality();
const ReactNative = {
// top-level API
findNodeHandle,

View File

@@ -7,8 +7,22 @@
*/
import findNodeHandle from '../findNodeHandle';
import StyleRegistry from '../../apis/StyleSheet/registry';
import UIManager from '../../apis/UIManager';
const emptyObject = {};
const REGEX_CLASSNAME_SPLIT = /\s+/;
const REGEX_STYLE_PROP = /rn-(.*):.*/;
const classNameFilter = (className) => { return className !== ''; };
const classNameToList = (className = '') => className.split(REGEX_CLASSNAME_SPLIT).filter(classNameFilter);
const getStyleProp = (className) => {
const match = className.match(REGEX_STYLE_PROP);
if (match) {
return match[1];
}
};
const NativeMethodsMixin = {
/**
* Removes focus from an input or view. This is the opposite of `focus()`.
@@ -45,7 +59,7 @@ const NativeMethodsMixin = {
* - height
*
* Note that these measurements are not available until after the rendering
* has been completed in native.
* has been completed.
*/
measureInWindow(callback) {
UIManager.measureInWindow(findNodeHandle(this), callback);
@@ -60,9 +74,50 @@ const NativeMethodsMixin = {
/**
* This function sends props straight to the underlying DOM node.
* This works as if all styles were set as inline styles. Since a DOM node
* may aleady be styled with class names and inline styles, we need to get
* the initial styles from the DOM node and merge them with incoming props.
*/
setNativeProps(nativeProps: Object) {
UIManager.updateView(findNodeHandle(this), nativeProps, this);
// DOM state
const node = findNodeHandle(this);
const domClassList = [ ...node.classList ];
// Resolved state
const resolvedProps = StyleRegistry.resolve(nativeProps.style) || emptyObject;
const resolvedClassList = classNameToList(resolvedProps.className);
// Merged state
const classList = [];
const style = { ...resolvedProps.style };
// The node has class names that we need to override.
// Only pass on a class name when the style is unchanged.
domClassList.forEach((c) => {
const prop = getStyleProp(c);
const className = resolvedProps.className;
if (!className || className.indexOf(prop) === -1) {
classList.push(c);
}
});
// The node has styles that we need to override.
// Remove any inline style that may collide with a new class name.
resolvedClassList.forEach((c) => {
const prop = getStyleProp(c);
classList.push(c);
style[prop] = null;
});
const className = `\n${classList.sort().join('\n')}`;
const props = {
...nativeProps,
className,
style
};
UIManager.updateView(node, props, this);
}
};

View File

@@ -33,7 +33,7 @@ const applyLayout = (Component) => {
if (layout.x !== x || layout.y !== y || layout.width !== width || layout.height !== height) {
const nextLayout = { x, y, width, height };
const nativeEvent = { layout: nextLayout };
onLayout({ nativeEvent });
onLayout({ nativeEvent, timeStamp: Date.now() });
this._layoutState = nextLayout;
}
});

View File

@@ -19,7 +19,7 @@ const roleComponents = {
region: 'section'
};
const createDOMElement = (component, rnProps = emptyObject) => {
const createDOMElement = (component, rnProps) => {
const {
accessibilityLabel,
accessibilityLiveRegion,
@@ -29,7 +29,7 @@ const createDOMElement = (component, rnProps = emptyObject) => {
testID,
type,
...domProps
} = rnProps;
} = rnProps || emptyObject;
const accessibilityComponent = accessibilityRole && roleComponents[accessibilityRole];
const Component = accessibilityComponent || component;

View File

@@ -1,2 +1,2 @@
import findNodeHandle from 'react-dom/lib/findDOMNode';
export default findNodeHandle;
import { findDOMNode } from 'react-dom';
export default findDOMNode;

View File

@@ -4,7 +4,8 @@ const mapKeyValue = (obj, fn) => {
const result = [];
for (const key in obj) {
if (hasOwnProperty.call(obj, key)) {
result.push(fn(key, obj[key]));
const r = fn(key, obj[key]);
r && result.push(r);
}
}
return result;

View File

@@ -0,0 +1,97 @@
/* global document, window */
/**
* Adapts focus styles based on the user's active input modality (i.e., how
* they are interacting with the UI right now).
*
* Focus styles are only relevant when using the keyboard to interact with the
* page. If we only show the focus ring when relevant, we can avoid user
* confusion without compromising accessibility.
*
* The script uses two heuristics to determine whether the keyboard is being used:
*
* 1. a keydown event occurred immediately before a focus event;
* 2. a focus event happened on an element which requires keyboard interaction (e.g., a text field);
*
* Based on https://github.com/WICG/modality
*/
const modality = () => {
/**
* Determine whether the keyboard is required when an element is focused
*/
const proto = window.Element.prototype;
const matcher = proto.matches || proto.mozMatchesSelector || proto.msMatchesSelector || proto.webkitMatchesSelector;
const keyboardModalityWhitelist = [
'input:not([type])',
'input[type=text]',
'input[type=number]',
'input[type=date]',
'input[type=time]',
'input[type=datetime]',
'textarea',
'[role=textbox]',
// indicates that a custom element supports the keyboard
'[supports-modality=keyboard]'
].join(',');
const focusTriggersKeyboardModality = (el) => {
if (matcher) {
return matcher.call(el, keyboardModalityWhitelist) && matcher.call(el, ':not([readonly])');
} else {
return false;
}
};
/**
* Disable the focus ring by default
*/
const id = 'modality__';
const style = `<style id="${id}">:focus { outline: none; }</style>`;
document.head.insertAdjacentHTML('afterbegin', style);
const styleElement = document.getElementById(id);
const disableFocus = () => {
if (styleElement) {
styleElement.disabled = false;
}
};
const enableFocus = () => {
if (styleElement) {
styleElement.disabled = true;
}
};
/**
* Manage the modality focus state
*/
let keyboardTimer;
let hadKeyboardEvent = false;
// track when the keyboard is in use
document.body.addEventListener('keydown', () => {
hadKeyboardEvent = true;
if (keyboardTimer) {
clearTimeout(keyboardTimer);
}
keyboardTimer = setTimeout(() => {
hadKeyboardEvent = false;
}, 100);
}, true);
// disable focus style reset when the keyboard is in use
document.body.addEventListener('focus', (e) => {
if (hadKeyboardEvent || focusTriggersKeyboardModality(e.target)) {
enableFocus();
}
}, true);
// enable focus style reset when keyboard is no longer in use
document.body.addEventListener('blur', () => {
if (!hadKeyboardEvent) {
disableFocus();
}
}, true);
};
export default modality;

View File

@@ -0,0 +1,21 @@
const _requestIdleCallback = function (cb) {
return setTimeout(() => {
const start = Date.now();
cb({
didTimeout: false,
timeRemaining() {
return Math.max(0, 50 - (Date.now() - start));
}
});
}, 1);
};
const _cancelIdleCallback = function (id) {
clearTimeout(id);
};
const requestIdleCallback = window.requestIdleCallback || _requestIdleCallback;
const cancelIdleCallback = window.cancelIdleCallback || _cancelIdleCallback;
export default requestIdleCallback;
export { cancelIdleCallback };

View File

@@ -2,7 +2,7 @@ import { PropTypes } from 'react';
const { number, oneOf, oneOfType, string } = PropTypes;
const AnimationPropTypes = process.env.NODE_ENV !== 'production' ? {
const AnimationPropTypes = {
animationDelay: string,
animationDirection: oneOf([ 'alternate', 'alternate-reverse', 'normal', 'reverse' ]),
animationDuration: string,
@@ -11,6 +11,6 @@ const AnimationPropTypes = process.env.NODE_ENV !== 'production' ? {
animationName: string,
animationPlayState: oneOf([ 'paused', 'running' ]),
animationTimingFunction: string
} : {};
};
module.exports = AnimationPropTypes;

View File

@@ -1,13 +1,13 @@
import { PropTypes } from 'react';
const { array, bool, number, object, oneOf, oneOfType, string } = PropTypes;
const BaseComponentPropTypes = process.env.NODE_ENV !== 'production' ? {
const BaseComponentPropTypes = {
accessibilityLabel: string,
accessibilityLiveRegion: oneOf([ 'assertive', 'off', 'polite' ]),
accessibilityRole: string,
accessible: bool,
style: oneOfType([ array, number, object ]),
testID: string
} : {};
};
module.exports = BaseComponentPropTypes;

View File

@@ -4,7 +4,7 @@ import { PropTypes } from 'react';
const numberOrString = PropTypes.oneOfType([ PropTypes.number, PropTypes.string ]);
const BorderStylePropType = PropTypes.oneOf([ 'solid', 'dotted', 'dashed' ]);
const BorderPropTypes = process.env.NODE_ENV !== 'production' ? {
const BorderPropTypes = {
borderColor: ColorPropType,
borderTopColor: ColorPropType,
borderRightColor: ColorPropType,
@@ -19,16 +19,7 @@ const BorderPropTypes = process.env.NODE_ENV !== 'production' ? {
borderTopStyle: BorderStylePropType,
borderRightStyle: BorderStylePropType,
borderBottomStyle: BorderStylePropType,
borderLeftStyle: BorderStylePropType,
/* Props to opt-out of RTL flipping */
borderLeftColor$noI18n: ColorPropType,
borderRightColor$noI18n: ColorPropType,
borderTopLeftRadius$noI18n: numberOrString,
borderTopRightRadius$noI18n: numberOrString,
borderBottomLeftRadius$noI18n: numberOrString,
borderBottomRightRadius$noI18n: numberOrString,
borderLeftStyle$noI18n: BorderStylePropType,
borderRightStyle$noI18n: BorderStylePropType
} : {};
borderLeftStyle: BorderStylePropType
};
module.exports = BorderPropTypes;

View File

@@ -14,11 +14,11 @@
var PropTypes = require('react').PropTypes;
var EdgeInsetsPropType = process.env.NODE_ENV !== 'production' ? require('./createStrictShapeTypeChecker')({
var EdgeInsetsPropType = require('./createStrictShapeTypeChecker')({
top: PropTypes.number,
left: PropTypes.number,
bottom: PropTypes.number,
right: PropTypes.number,
}) : function () {};
});
module.exports = EdgeInsetsPropType;

View File

@@ -3,7 +3,7 @@ import { PropTypes } from 'react';
const { number, oneOf, oneOfType, string } = PropTypes;
const numberOrString = oneOfType([ number, string ]);
const LayoutPropTypes = process.env.NODE_ENV !== 'production' ? {
const LayoutPropTypes = {
// box model
borderWidth: numberOrString,
borderBottomWidth: numberOrString,
@@ -11,6 +11,7 @@ const LayoutPropTypes = process.env.NODE_ENV !== 'production' ? {
borderRightWidth: numberOrString,
borderTopWidth: numberOrString,
boxSizing: string,
display: string,
height: numberOrString,
margin: numberOrString,
marginBottom: numberOrString,
@@ -48,16 +49,7 @@ const LayoutPropTypes = process.env.NODE_ENV !== 'production' ? {
left: numberOrString,
position: oneOf([ 'absolute', 'fixed', 'relative', 'static' ]),
right: numberOrString,
top: numberOrString,
// opt-out of RTL flipping
borderLeftWidth$noI18n: numberOrString,
borderRightWidth$noI18n: numberOrString,
left$noI18n: numberOrString,
marginLeft$noI18n: numberOrString,
marginRight$noI18n: numberOrString,
paddingLeft$noI18n: numberOrString,
paddingRight$noI18n: numberOrString,
right$noI18n: numberOrString
} : {};
top: numberOrString
};
module.exports = LayoutPropTypes;

View File

@@ -14,9 +14,9 @@
var PropTypes = require('react').PropTypes;
var PointPropType = process.env.NODE_ENV !== 'production' ? require('./createStrictShapeTypeChecker')({
var PointPropType = require('./createStrictShapeTypeChecker')({
x: PropTypes.number,
y: PropTypes.number,
}) : function () {};
});
module.exports = PointPropType;

View File

@@ -5,7 +5,7 @@
* @flow
*/
module.exports = process.env.NODE_ENV !== 'production' ? function StyleSheetPropType(shape) {
module.exports = function StyleSheetPropType(shape) {
const createStrictShapeTypeChecker = require('./createStrictShapeTypeChecker');
const StyleSheet = require('../apis/StyleSheet');
@@ -19,4 +19,4 @@ module.exports = process.env.NODE_ENV !== 'production' ? function StyleSheetProp
}
return shapePropType(newProps, propName, componentName, location);
};
} : function () {};
};

View File

@@ -1,42 +0,0 @@
import ColorPropType from './ColorPropType';
import { PropTypes } from 'react';
const { number, oneOf, oneOfType, shape, string } = PropTypes;
const numberOrString = oneOfType([ number, string ]);
const ShadowOffsetPropType = shape({ width: number, height: number });
const TextAlignPropType = oneOf([ 'center', 'inherit', 'justify', 'justify-all', 'left', 'right' ]);
const WritingDirectionPropType = oneOf([ 'auto', 'ltr', 'rtl' ]);
const TextPropTypes = process.env.NODE_ENV !== 'production' ? {
// box model
color: ColorPropType,
fontFamily: string,
fontSize: numberOrString,
fontStyle: string,
fontWeight: string,
letterSpacing: numberOrString,
lineHeight: numberOrString,
textAlign: TextAlignPropType,
textAlignVertical: oneOf([ 'auto', 'bottom', 'center', 'top' ]),
textDecorationLine: string,
textShadowColor: ColorPropType,
textShadowOffset: ShadowOffsetPropType,
textShadowRadius: number,
writingDirection: WritingDirectionPropType,
/* @platform web */
textOverflow: string,
textRendering: oneOf([ 'auto', 'geometricPrecision', 'optimizeLegibility', 'optimizeSpeed' ]),
textTransform: oneOf([ 'capitalize', 'lowercase', 'none', 'uppercase' ]),
unicodeBidi: oneOf([ 'normal', 'bidi-override', 'embed', 'isolate', 'isolate-override', 'plaintext' ]),
whiteSpace: string,
wordWrap: string,
MozOsxFontSmoothing: string,
WebkitFontSmoothing: string,
// opt-out of RTL flipping
textAlign$noI18n: TextAlignPropType,
textShadowOffset$noI18n: ShadowOffsetPropType,
writingDirection$noI18n: WritingDirectionPropType
} : {};
module.exports = TextPropTypes;

View File

@@ -10,7 +10,7 @@ import { PropTypes } from 'react';
const { arrayOf, number, oneOfType, shape, string } = PropTypes;
const numberOrString = oneOfType([ number, string ]);
const TransformPropTypes = process.env.NODE_ENV !== 'production' ? {
const TransformPropTypes = {
transform: arrayOf(
oneOfType([
shape({ perspective: numberOrString }),
@@ -30,6 +30,6 @@ const TransformPropTypes = process.env.NODE_ENV !== 'production' ? {
])
),
transformOrigin: string
} : {};
};
module.exports = TransformPropTypes;

View File

@@ -2,12 +2,11 @@ const path = require('path')
const webpack = require('webpack')
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
const SRC_DIRECTORY = './src'
const DIST_DIRECTORY = './dist'
module.exports = {
entry: {
main: DIST_DIRECTORY
},
entry: SRC_DIRECTORY,
externals: [
{
react: {
@@ -18,6 +17,21 @@ module.exports = {
}
}
],
module: {
loaders: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
query: { cacheDirectory: true }
},
{
test: /\.(gif|jpe?g|png|svg)$/,
loader: 'url-loader',
query: { name: '[name].[ext]' }
}
]
},
output: {
filename: 'ReactNative.js',
library: 'ReactNative',

245
yarn.lock
View File

@@ -181,9 +181,9 @@ amdefine@>=0.0.4:
version "1.0.1"
resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5"
animated@^0.1.5:
version "0.1.5"
resolved "https://registry.yarnpkg.com/animated/-/animated-0.1.5.tgz#83df8dc443d57abab7b0bb04818b0b655b31c9b9"
animated@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/animated/-/animated-0.2.0.tgz#1a0e96f097b3fbc5b64d7eddc723bcc0a6f97633"
dependencies:
invariant "^2.2.0"
normalize-css-color "^1.0.1"
@@ -362,18 +362,18 @@ aws4@^1.2.1:
version "1.5.0"
resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.5.0.tgz#0a29ffb79c31c9e712eeb087e8e7a64b4a56d755"
babel-cli@^6.14.0:
version "6.18.0"
resolved "https://registry.yarnpkg.com/babel-cli/-/babel-cli-6.18.0.tgz#92117f341add9dead90f6fa7d0a97c0cc08ec186"
babel-cli@^6.23.0:
version "6.23.0"
resolved "https://registry.yarnpkg.com/babel-cli/-/babel-cli-6.23.0.tgz#52ff946a2b0f64645c35e7bd5eea267aa0948c0f"
dependencies:
babel-core "^6.18.0"
babel-polyfill "^6.16.0"
babel-register "^6.18.0"
babel-runtime "^6.9.0"
babel-core "^6.23.0"
babel-polyfill "^6.23.0"
babel-register "^6.23.0"
babel-runtime "^6.22.0"
commander "^2.8.1"
convert-source-map "^1.1.0"
fs-readdir-recursive "^1.0.0"
glob "^5.0.5"
glob "^7.0.0"
lodash "^4.2.0"
output-file-sync "^1.1.0"
path-is-absolute "^1.0.0"
@@ -381,29 +381,29 @@ babel-cli@^6.14.0:
source-map "^0.5.0"
v8flags "^2.0.10"
optionalDependencies:
chokidar "^1.0.0"
chokidar "^1.6.1"
babel-code-frame@^6.11.0, babel-code-frame@^6.16.0, babel-code-frame@^6.20.0:
version "6.20.0"
resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.20.0.tgz#b968f839090f9a8bc6d41938fb96cb84f7387b26"
babel-code-frame@^6.11.0, babel-code-frame@^6.16.0, babel-code-frame@^6.22.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 "^2.0.0"
js-tokens "^3.0.0"
babel-core@^6.0.0, babel-core@^6.11.4, babel-core@^6.18.0, babel-core@^6.21.0:
version "6.21.0"
resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.21.0.tgz#75525480c21c803f826ef3867d22c19f080a3724"
babel-core@^6.0.0, babel-core@^6.11.4, babel-core@^6.23.0, babel-core@^6.23.1:
version "6.23.1"
resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.23.1.tgz#c143cb621bb2f621710c220c5d579d15b8a442df"
dependencies:
babel-code-frame "^6.20.0"
babel-generator "^6.21.0"
babel-helpers "^6.16.0"
babel-messages "^6.8.0"
babel-register "^6.18.0"
babel-runtime "^6.20.0"
babel-template "^6.16.0"
babel-traverse "^6.21.0"
babel-types "^6.21.0"
babel-code-frame "^6.22.0"
babel-generator "^6.23.0"
babel-helpers "^6.23.0"
babel-messages "^6.23.0"
babel-register "^6.23.0"
babel-runtime "^6.22.0"
babel-template "^6.23.0"
babel-traverse "^6.23.1"
babel-types "^6.23.0"
babylon "^6.11.0"
convert-source-map "^1.1.0"
debug "^2.1.1"
@@ -425,17 +425,18 @@ babel-eslint@^7.1.1:
babylon "^6.13.0"
lodash.pickby "^4.6.0"
babel-generator@^6.18.0, babel-generator@^6.21.0:
version "6.21.0"
resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.21.0.tgz#605f1269c489a1c75deeca7ea16d43d4656c8494"
babel-generator@^6.18.0, babel-generator@^6.23.0:
version "6.23.0"
resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.23.0.tgz#6b8edab956ef3116f79d8c84c5a3c05f32a74bc5"
dependencies:
babel-messages "^6.8.0"
babel-runtime "^6.20.0"
babel-types "^6.21.0"
babel-messages "^6.23.0"
babel-runtime "^6.22.0"
babel-types "^6.23.0"
detect-indent "^4.0.0"
jsesc "^1.3.0"
lodash "^4.2.0"
source-map "^0.5.0"
trim-right "^1.0.1"
babel-helper-builder-binary-assignment-operator-visitor@^6.8.0:
version "6.18.0"
@@ -540,12 +541,12 @@ babel-helper-replace-supers@^6.18.0, babel-helper-replace-supers@^6.8.0:
babel-traverse "^6.18.0"
babel-types "^6.18.0"
babel-helpers@^6.16.0:
version "6.16.0"
resolved "https://registry.yarnpkg.com/babel-helpers/-/babel-helpers-6.16.0.tgz#1095ec10d99279460553e67eb3eee9973d3867e3"
babel-helpers@^6.23.0:
version "6.23.0"
resolved "https://registry.yarnpkg.com/babel-helpers/-/babel-helpers-6.23.0.tgz#4f8f2e092d0b6a8808a4bde79c27f1e2ecf0d992"
dependencies:
babel-runtime "^6.0.0"
babel-template "^6.16.0"
babel-runtime "^6.22.0"
babel-template "^6.23.0"
babel-jest@^16.0.0:
version "16.0.0"
@@ -555,20 +556,20 @@ babel-jest@^16.0.0:
babel-plugin-istanbul "^2.0.0"
babel-preset-jest "^16.0.0"
babel-loader@^6.2.10, babel-loader@^6.2.4:
version "6.2.10"
resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-6.2.10.tgz#adefc2b242320cd5d15e65b31cea0e8b1b02d4b0"
babel-loader@^6.2.4, babel-loader@^6.3.2:
version "6.3.2"
resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-6.3.2.tgz#18de4566385578c1b4f8ffe6cbc668f5e2a5ef03"
dependencies:
find-cache-dir "^0.1.1"
loader-utils "^0.2.11"
loader-utils "^0.2.16"
mkdirp "^0.5.1"
object-assign "^4.0.1"
babel-messages@^6.8.0:
version "6.8.0"
resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.8.0.tgz#bf504736ca967e6d65ef0adb5a2a5f947c8e0eb9"
babel-messages@^6.23.0, babel-messages@^6.8.0:
version "6.23.0"
resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e"
dependencies:
babel-runtime "^6.0.0"
babel-runtime "^6.22.0"
babel-plugin-check-es2015-constants@^6.3.13, babel-plugin-check-es2015-constants@^6.5.0:
version "6.8.0"
@@ -895,9 +896,9 @@ babel-plugin-transform-react-jsx@^6.3.13, babel-plugin-transform-react-jsx@^6.5.
babel-plugin-syntax-jsx "^6.8.0"
babel-runtime "^6.0.0"
babel-plugin-transform-react-remove-prop-types:
version "0.2.11"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-remove-prop-types/-/babel-plugin-transform-react-remove-prop-types-0.2.11.tgz#05eb7cc4670d6506d801680576589c7abcd51b00"
babel-plugin-transform-react-remove-prop-types@^0.3.2:
version "0.3.2"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-remove-prop-types/-/babel-plugin-transform-react-remove-prop-types-0.3.2.tgz#6da8d834c6d7ad8ab02f956509790cfaa01ffe19"
babel-plugin-transform-regenerator@6.16.1, babel-plugin-transform-regenerator@^6.16.0, babel-plugin-transform-regenerator@^6.5.0, babel-plugin-transform-regenerator@^6.6.0:
version "6.16.1"
@@ -920,13 +921,13 @@ babel-plugin-transform-strict-mode@^6.18.0:
babel-runtime "^6.0.0"
babel-types "^6.18.0"
babel-polyfill@^6.16.0:
version "6.16.0"
resolved "https://registry.yarnpkg.com/babel-polyfill/-/babel-polyfill-6.16.0.tgz#2d45021df87e26a374b6d4d1a9c65964d17f2422"
babel-polyfill@^6.23.0:
version "6.23.0"
resolved "https://registry.yarnpkg.com/babel-polyfill/-/babel-polyfill-6.23.0.tgz#8364ca62df8eafb830499f699177466c3b03499d"
dependencies:
babel-runtime "^6.9.1"
babel-runtime "^6.22.0"
core-js "^2.4.0"
regenerator-runtime "^0.9.5"
regenerator-runtime "^0.10.0"
babel-preset-env@0.0.6:
version "0.0.6"
@@ -1081,12 +1082,12 @@ babel-preset-react@6.16.0:
babel-plugin-transform-react-jsx-self "^6.11.0"
babel-plugin-transform-react-jsx-source "^6.3.13"
babel-register@^6.18.0:
version "6.18.0"
resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.18.0.tgz#892e2e03865078dd90ad2c715111ec4449b32a68"
babel-register@^6.23.0:
version "6.23.0"
resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.23.0.tgz#c9aa3d4cca94b51da34826c4a0f9e08145d74ff3"
dependencies:
babel-core "^6.18.0"
babel-runtime "^6.11.6"
babel-core "^6.23.0"
babel-runtime "^6.22.0"
core-js "^2.4.0"
home-or-tmp "^2.0.0"
lodash "^4.2.0"
@@ -1100,42 +1101,42 @@ babel-runtime@6.11.6:
core-js "^2.4.0"
regenerator-runtime "^0.9.5"
babel-runtime@6.x.x, babel-runtime@^6.0.0, babel-runtime@^6.11.6, babel-runtime@^6.18.0, babel-runtime@^6.20.0, babel-runtime@^6.5.0, babel-runtime@^6.9.0, babel-runtime@^6.9.1, babel-runtime@^6.9.2:
version "6.20.0"
resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.20.0.tgz#87300bdcf4cd770f09bf0048c64204e17806d16f"
babel-runtime@6.x.x, babel-runtime@^6.0.0, babel-runtime@^6.11.6, babel-runtime@^6.18.0, babel-runtime@^6.22.0, babel-runtime@^6.23.0, babel-runtime@^6.5.0, babel-runtime@^6.9.0, babel-runtime@^6.9.1, babel-runtime@^6.9.2:
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"
babel-template@^6.14.0, babel-template@^6.15.0, babel-template@^6.16.0, babel-template@^6.8.0:
version "6.16.0"
resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.16.0.tgz#e149dd1a9f03a35f817ddbc4d0481988e7ebc8ca"
babel-template@^6.14.0, babel-template@^6.15.0, babel-template@^6.16.0, babel-template@^6.23.0, babel-template@^6.8.0:
version "6.23.0"
resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.23.0.tgz#04d4f270adbb3aa704a8143ae26faa529238e638"
dependencies:
babel-runtime "^6.9.0"
babel-traverse "^6.16.0"
babel-types "^6.16.0"
babel-runtime "^6.22.0"
babel-traverse "^6.23.0"
babel-types "^6.23.0"
babylon "^6.11.0"
lodash "^4.2.0"
babel-traverse@^6.15.0, babel-traverse@^6.16.0, babel-traverse@^6.18.0, babel-traverse@^6.21.0:
version "6.21.0"
resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.21.0.tgz#69c6365804f1a4f69eb1213f85b00a818b8c21ad"
babel-traverse@^6.15.0, babel-traverse@^6.16.0, babel-traverse@^6.18.0, babel-traverse@^6.23.0, babel-traverse@^6.23.1:
version "6.23.1"
resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.23.1.tgz#d3cb59010ecd06a97d81310065f966b699e14f48"
dependencies:
babel-code-frame "^6.20.0"
babel-messages "^6.8.0"
babel-runtime "^6.20.0"
babel-types "^6.21.0"
babylon "^6.11.0"
babel-code-frame "^6.22.0"
babel-messages "^6.23.0"
babel-runtime "^6.22.0"
babel-types "^6.23.0"
babylon "^6.15.0"
debug "^2.2.0"
globals "^9.0.0"
invariant "^2.2.0"
lodash "^4.2.0"
babel-types@^6.15.0, babel-types@^6.16.0, babel-types@^6.18.0, babel-types@^6.21.0, babel-types@^6.8.0, babel-types@^6.9.0:
version "6.21.0"
resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.21.0.tgz#314b92168891ef6d3806b7f7a917fdf87c11a4b2"
babel-types@^6.15.0, babel-types@^6.16.0, babel-types@^6.18.0, babel-types@^6.23.0, babel-types@^6.8.0, babel-types@^6.9.0:
version "6.23.0"
resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.23.0.tgz#bb17179d7538bad38cd0c9e115d340f77e7e9acf"
dependencies:
babel-runtime "^6.20.0"
babel-runtime "^6.22.0"
esutils "^2.0.2"
lodash "^4.2.0"
to-fast-properties "^1.0.1"
@@ -1144,6 +1145,10 @@ babylon@^6.11.0, babylon@^6.13.0:
version "6.14.1"
resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.14.1.tgz#956275fab72753ad9b3435d7afe58f8bf0a29815"
babylon@^6.15.0:
version "6.15.0"
resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.15.0.tgz#ba65cfa1a80e1759b0e89fb562e27dccae70348e"
babylon@~5.8.3:
version "5.8.38"
resolved "https://registry.yarnpkg.com/babylon/-/babylon-5.8.38.tgz#ec9b120b11bf6ccd4173a18bf217e60b79859ffd"
@@ -1194,9 +1199,9 @@ boom@2.x.x:
dependencies:
hoek "2.x.x"
bowser@^1.0.0:
version "1.5.0"
resolved "https://registry.yarnpkg.com/bowser/-/bowser-1.5.0.tgz#b97414bacbc631f19f1e2e11466566ec19324983"
bowser@^1.6.0:
version "1.6.0"
resolved "https://registry.yarnpkg.com/bowser/-/bowser-1.6.0.tgz#37fc387b616cb6aef370dab4d6bd402b74c5c54d"
boxen@^0.6.0:
version "0.6.0"
@@ -1377,7 +1382,7 @@ cheerio@^0.22.0:
lodash.reject "^4.4.0"
lodash.some "^4.4.0"
chokidar@^1.0.0:
chokidar@^1.0.0, chokidar@^1.6.1:
version "1.6.1"
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.6.1.tgz#2f4447ab5e96e50fb3d789fd90d4c72e0e4c70c2"
dependencies:
@@ -1645,6 +1650,13 @@ 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-in-js-utils@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/css-in-js-utils/-/css-in-js-utils-1.0.2.tgz#f7e46b172fd994f2cd6745858c9eda9065f9bc6b"
dependencies:
hyphenate-style-name "^1.0.2"
unitless-css-property "^1.0.2"
css-loader@0.25.0:
version "0.25.0"
resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-0.25.0.tgz#c3febc8ce28f4c83576b6b13707f47f90c390223"
@@ -1923,6 +1935,10 @@ duplexer2@^0.1.4:
dependencies:
readable-stream "^2.0.2"
duplexer@^0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.1.tgz#ace6ff808c1ce66b57d1ebf97977acb02334cfc1"
ecc-jsbn@~0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505"
@@ -1933,9 +1949,9 @@ ee-first@1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
ejs@^2.5.2:
version "2.5.2"
resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.5.2.tgz#21444ba09386f0c65b6eafb96a3d51bcb3be80d1"
ejs@^2.5.5:
version "2.5.5"
resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.5.5.tgz#6ef4e954ea7dcf54f66aad2fe7aa421932d9ed77"
element-class@^0.2.0:
version "0.2.2"
@@ -2535,7 +2551,7 @@ glob-parent@^2.0.0:
dependencies:
is-glob "^2.0.0"
glob@5.x, glob@^5.0.15, glob@^5.0.5:
glob@5.x, glob@^5.0.15:
version "5.0.15"
resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1"
dependencies:
@@ -2610,6 +2626,12 @@ growly@^1.2.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081"
gzip-size@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/gzip-size/-/gzip-size-3.0.0.tgz#546188e9bdc337f673772f81660464b389dce520"
dependencies:
duplexer "^0.1.1"
handlebars@^4.0.1, handlebars@^4.0.3:
version "4.0.6"
resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.6.tgz#2ce4484850537f9c97a8026d5399b935c4ed4ed7"
@@ -2733,7 +2755,7 @@ https-browserify@0.0.0:
version "0.0.0"
resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-0.0.0.tgz#b3ffdfe734b2a3d4a9efd58e8654c91fce86eafd"
hyphenate-style-name@^1.0.1:
hyphenate-style-name@^1.0.1, hyphenate-style-name@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/hyphenate-style-name/-/hyphenate-style-name-1.0.2.tgz#31160a36930adaf1fc04c6074f7eb41465d4ec4b"
@@ -2802,12 +2824,12 @@ ini@~1.3.0:
version "1.3.4"
resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.4.tgz#0537cb79daf59b59a1a517dff706c86ec039162e"
inline-style-prefixer@^2.0.5:
version "2.0.5"
resolved "https://registry.yarnpkg.com/inline-style-prefixer/-/inline-style-prefixer-2.0.5.tgz#c153c7e88fd84fef5c602e95a8168b2770671fe7"
inline-style-prefixer@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/inline-style-prefixer/-/inline-style-prefixer-3.0.0.tgz#4feb44053c29aa2fe2aaecac4fb3e9459f871239"
dependencies:
bowser "^1.0.0"
hyphenate-style-name "^1.0.1"
bowser "^1.6.0"
css-in-js-utils "^1.0.0"
inquirer@^0.12.0:
version "0.12.0"
@@ -3344,6 +3366,10 @@ js-tokens@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-2.0.0.tgz#79903f5563ee778cc1162e6dcf1a0027c97f9cb5"
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.x, js-yaml@^3.4.3, js-yaml@^3.5.1:
version "3.7.0"
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.7.0.tgz#5c967ddd837a9bfdca5f2de84253abe8a1c03b80"
@@ -3678,7 +3704,7 @@ lodash.words@^3.0.0:
dependencies:
lodash._root "^3.0.0"
lodash@4.x.x, lodash@^4.0.0, lodash@^4.16.4, lodash@^4.2.0, lodash@^4.2.1, lodash@^4.3.0, lodash@^4.6.1:
lodash@4.x.x, lodash@^4.0.0, lodash@^4.16.4, lodash@^4.17.2, lodash@^4.2.0, lodash@^4.2.1, lodash@^4.3.0, lodash@^4.6.1:
version "4.17.2"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.2.tgz#34a3055babe04ce42467b607d700072c7ff6bf42"
@@ -4018,11 +4044,7 @@ nopt@3.x, nopt@~3.0.6:
dependencies:
abbrev "1"
normalize-css-color@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/normalize-css-color/-/normalize-css-color-1.0.1.tgz#792f59cae25036950a9127cfcfddc073048f4f9d"
normalize-css-color@^1.0.2:
normalize-css-color@^1.0.1, normalize-css-color@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/normalize-css-color/-/normalize-css-color-1.0.2.tgz#02991e97cccec6623fe573afbbf0de6a1f3e9f8d"
@@ -5491,6 +5513,10 @@ trim-newlines@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613"
trim-right@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003"
tryit@^1.0.1:
version "1.0.3"
resolved "https://registry.yarnpkg.com/tryit/-/tryit-1.0.3.tgz#393be730a9446fd1ead6da59a014308f36c289cb"
@@ -5563,6 +5589,12 @@ uniqs@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/uniqs/-/uniqs-2.0.0.tgz#ffede4b36b25290696e6e165d4a59edb998e6b02"
unitless-css-property@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/unitless-css-property/-/unitless-css-property-1.0.2.tgz#dd4b666172fba241fcf50b6b31aee126700b170a"
dependencies:
hyphenate-style-name "^1.0.1"
unpipe@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"
@@ -5691,17 +5723,18 @@ webidl-conversions@^3.0.0, webidl-conversions@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871"
webpack-bundle-analyzer:
version "1.5.3"
resolved "https://registry.yarnpkg.com/webpack-bundle-analyzer/-/webpack-bundle-analyzer-1.5.3.tgz#d1109bdd0a0067bba88ea6aa642533b4de926965"
webpack-bundle-analyzer@^2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/webpack-bundle-analyzer/-/webpack-bundle-analyzer-2.2.1.tgz#a90edc00eb9cea917d2af009529decf71d7f4a84"
dependencies:
acorn "^4.0.3"
chalk "^1.1.3"
commander "^2.9.0"
ejs "^2.5.2"
ejs "^2.5.5"
express "^4.14.0"
filesize "^3.3.0"
lodash "^4.16.4"
gzip-size "^3.0.0"
lodash "^4.17.2"
mkdirp "^0.5.1"
opener "^1.4.2"