Compare commits

...

35 Commits

Author SHA1 Message Date
Nicolas Gallagher
bc68b0b6f4 0.0.61 2016-12-27 18:09:11 +00:00
Nicolas Gallagher
44ecbc072e [change] update React and Touchables
Update to React@15.4. The 'EventConstants' module no longer exports a
key-mirror, which was preventing the 'ResponderEventPlugin' from working
as it did with React@15.3.

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

Ensure lists with small initialListSize render correctly

Changes as requested via PR
2016-12-14 09:39:05 -08:00
Nicolas Gallagher
80ba119b83 Update install command
Close #285
Close #286
2016-12-14 17:05:15 +00:00
Nicolas Gallagher
c30b67f6db 0.0.57 2016-12-12 15:10:39 +00:00
Nicolas Gallagher
4580f93199 Use fbjs requestAnimationFrame in Image 2016-12-12 14:26:07 +00:00
Nicolas Gallagher
4c46126ffe [change] ScrollView event normalization 2016-12-12 14:21:33 +00:00
Calvin Chan
f8d5c15405 [add] Button component 2016-12-12 13:02:16 +00:00
Nicolas Gallagher
dc54e03625 [add] Linking API
Adds support for opening external URLs in a new tab/window. Includes
patches to 'Text' to improve accessibility and 'createDOMElement' to
improve external link security.

Fix #198
2016-12-12 11:45:30 +00:00
Nicolas Gallagher
4d5819ae28 [fix] RTL translateX; Switch transition 2016-12-08 19:40:34 -08:00
Nicolas Gallagher
5c482ef3be 0.0.56 2016-12-08 18:29:38 -08:00
Nicolas Gallagher
f51592f96e [change] TouchableOpacity without Animated
Fix #259
2016-12-08 18:22:25 -08:00
Nicolas Gallagher
6bffe1775f Fix lint error 2016-12-07 16:49:53 -08:00
Nicolas Gallagher
7e75d037f2 [fix] Image passes unknown props to underlying View
Fix #267
2016-12-07 16:37:24 -08:00
Nicolas Gallagher
7536508fe3 Update docs 2016-12-07 16:22:39 -08:00
Maxime Thirouin
945fff0015 Add source files to published package 2016-11-25 12:38:29 -08:00
Nicolas Gallagher
5032ed6fe1 Update AppRegistry docs 2016-11-25 12:36:05 -08:00
Nicolas Gallagher
8c7cdbf4be 0.0.55 2016-11-24 10:24:19 -08:00
Nicolas Gallagher
e5d8857bcc [fix] inject ReactDefaultInjection
Fixes a regression introduced in the following commit to avoid directly
depending on the 'react-dom' entry file:

d65c92eea9

Injecting ReactDefaultInjection adds ~25 KB back to the UMD build.

Fix #263
2016-11-24 10:21:40 -08:00
Nicolas Gallagher
cda8d05bb7 0.0.54 2016-11-24 08:42:53 -08:00
Nicolas Gallagher
049edc4611 [change] don't prefix HTML id's with underscore 2016-11-23 10:28:20 -08:00
Nicolas Gallagher
e76d5a4e6c [change] export createDOMElement helper
Fix #184
2016-11-23 10:25:00 -08:00
Nicolas Gallagher
f71dae7d93 [add] support for vendor-prefixed font-smoothing styles
Fix #240
2016-11-23 09:58:18 -08:00
Nicolas Gallagher
94d31beaf4 [change] ignore unsupported React Native props
Ignores RN props that RN packages commonly applied to elements without
scoping them to supported platforms.

Fix #252
2016-11-23 09:27:27 -08:00
76 changed files with 1753 additions and 591 deletions

View File

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

View File

@@ -57,7 +57,7 @@ To continuously watch and run tests, run the following:
npm run test:watch
```
To perform linting, run the following:
To perform only linting, run the following:
```
npm run lint

View File

@@ -27,7 +27,7 @@ online with [React Native for Web: Playground](http://codepen.io/necolas/pen/PZz
To install in your app:
```
npm install --save react react-native-web
npm install --save react@15.4 react-native-web
```
Read the [Client and Server rendering](docs/guides/rendering.md) guide.
@@ -53,6 +53,7 @@ Exported modules:
* Components
* [`ActivityIndicator`](docs/components/ActivityIndicator.md)
* [`Button`](docs/components/Button.md)
* [`Image`](docs/components/Image.md)
* [`ListView`](docs/components/ListView.md)
* [`ProgressBar`](docs/components/ProgressBar.md)
@@ -69,6 +70,7 @@ Exported modules:
* [`AppRegistry`](docs/apis/AppRegistry.md)
* [`AppState`](docs/apis/AppState.md)
* [`AsyncStorage`](docs/apis/AsyncStorage.md)
* [`Clipboard`](docs/apis/Clipboard.md)
* [`Dimensions`](docs/apis/Dimensions.md)
* [`I18nManager`](docs/apis/I18nManager.md)
* [`NativeMethods`](docs/apis/NativeMethods.md)
@@ -142,6 +144,7 @@ AppRegistry.runApplication('MyApp', { rootTag: document.getElementById('react-ro
* [react-native-web-player](https://github.com/dabbott/react-native-web-player)
* [react-web](https://github.com/taobaofed/react-web)
* [react-native-for-web](https://github.com/KodersLab/react-native-for-web)
* [rhinos-app](https://github.com/rhinos-app/rhinos-app-dev)
## License

View File

@@ -3,8 +3,7 @@
`AppRegistry` is the control point for registering, running, prerendering, and
unmounting all apps. App root components should register themselves with
`AppRegistry.registerComponent`. Apps can be run by invoking
`AppRegistry.runApplication`, and prerendered by invoking
`AppRegistry.prerenderApplication` (see the [client and server rendering
`AppRegistry.runApplication` (see the [client and server rendering
guide](../guides/rendering.md) for more details).
To "stop" an application when a view should be destroyed, call

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

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

39
docs/components/Button.md Normal file
View File

@@ -0,0 +1,39 @@
# Button
A basic button component. Supports a minimal level of customization. You can
build your own custom button using `TouchableOpacity` or
`TouchableNativeFeedback`.
## Props
**accessibilityLabel**: string
Defines the text available to assistive technologies upon interaction with the
element. (This is implemented using `aria-label`.)
**color**: string
Background color of the button.
**disabled**: bool = false
If true, disable all interactions for this component
**onPress**: function
This function is called on press.
**title**: string
Text to display inside the button.
## Examples
```js
<Button
accessibilityLabel="Learn more about this purple button"
color="#841584"
onPress={onPressLearnMore}
title="Learn More"
/>
```

View File

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

View File

@@ -38,6 +38,18 @@ which this `ScrollView` renders.
Fires at most once per frame during scrolling. The frequency of the events can
be contolled using the `scrollEventThrottle` prop.
Invoked on scroll with the following event:
```js
{
nativeEvent: {
contentOffset: { x, y },
contentSize: { height, width },
layoutMeasurement: { height, width }
}
}
```
**refreshControl**: element
TODO
@@ -51,8 +63,8 @@ When false, the content does not scroll.
**scrollEventThrottle**: number = 0
This controls how often the scroll event will be fired while scrolling (in
events per seconds). A higher number yields better accuracy for code that is
This controls how often the scroll event will be fired while scrolling (as a
time interval in ms). A lower number yields better accuracy for code that is
tracking the scroll position, but can lead to scroll performance problems. The
default value is `0`, which means the scroll event will be sent only once each
time the view is scrolled.
@@ -104,7 +116,7 @@ export default class ScrollViewExample extends Component {
contentContainerStyle={styles.container}
horizontal
onScroll={(e) => this.onScroll(e)}
scrollEventThrottle={60}
scrollEventThrottle={100}
style={styles.root}
/>
)

View File

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

View File

@@ -16,8 +16,9 @@ module.exports = {
}
```
The `react-native-web` package also includes a `core` module that exports only
`ReactNative`, `Image`, `StyleSheet`, `Text`, `TextInput`, and `View`.
The `react-native-web` package also includes a `core` module that exports a
subset of modules: `ReactNative`, `I18nManager`, `Platform`, `StyleSheet`,
`Image`, `Text`, `TextInput`, `Touchable`, and `View`.
```js
// webpack.config.js
@@ -62,16 +63,13 @@ AppRegistry.runApplication('App', {
initialProps: {},
rootTag: document.getElementById('react-app')
})
// prerender the app
const { html, styleElement } = AppRegistry.prerenderApplication('App', { initialProps })
```
## Server-side rendering
Rendering using the `AppRegistry`:
```
```js
import ReactDOMServer from 'react-dom/server'
import ReactNative, { AppRegistry } from 'react-native'
@@ -84,4 +82,4 @@ AppRegistry.registerComponent('App', () => AppContainer)
// prerender the app
const { element, stylesheet } = AppRegistry.getApplication('App', { initialProps });
const initialHTML = ReactDOMServer.renderToString(element);
```
```

View File

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

View File

@@ -1,8 +1,8 @@
import { storiesOf } from '@kadira/storybook';
import { I18nManager, StyleSheet, TouchableHighlight, Text, View } from 'react-native'
import React, { Component } from 'react';
import { storiesOf, action } from '@kadira/storybook';
class RTLExample extends Component {
class I18nManagerExample extends Component {
componentWillUnmount() {
I18nManager.setPreferredLanguageRTL(false)
}
@@ -75,5 +75,5 @@ const styles = StyleSheet.create({
storiesOf('api: I18nManager', module)
.add('RTL layout', () => (
<RTLExample />
<I18nManagerExample />
))

View File

@@ -0,0 +1,29 @@
import { Linking, StyleSheet, Text, View } from 'react-native'
import React, { Component } from 'react';
import { storiesOf, action } from '@kadira/storybook';
class LinkingExample extends Component {
render() {
return (
<View>
<Text onPress={() => { Linking.openURL('https://mathiasbynens.github.io/rel-noopener/malicious.html'); }} 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'>
target="_blank" (Expect: "The previous tab is safe and intact")
</Text>
</View>
);
}
}
const styles = StyleSheet.create({
text: {
marginVertical: 10
}
});
storiesOf('api: Linking', module)
.add('Safe linking', () => (
<LinkingExample />
));

View File

@@ -0,0 +1,80 @@
import React from 'react';
import { action, storiesOf } from '@kadira/storybook';
import { Button, StyleSheet, View } from 'react-native';
const onButtonPress = action('Button has been pressed!');
const examples = [
{
title: 'Simple Button',
description: 'The title and onPress handler are required. It is ' +
'recommended to set accessibilityLabel to help make your app usable by ' +
'everyone.',
render: function() {
return (
<Button
onPress={onButtonPress}
title="Press Me"
accessibilityLabel="See an informative alert"
/>
);
},
},
{
title: 'Adjusted color',
description: 'Adjusts the color in a way that looks standard on each ' +
'platform. On iOS, the color prop controls the color of the text. On ' +
'Android, the color adjusts the background color of the button.',
render: function() {
return (
<Button
onPress={onButtonPress}
title="Press Purple"
color="#841584"
accessibilityLabel="Learn more about purple"
/>
);
},
},
{
title: 'Fit to text layout',
description: 'This layout strategy lets the title define the width of ' +
'the button',
render: function() {
return (
<View style={{flexDirection: 'row', justifyContent: 'space-between'}}>
<Button
onPress={onButtonPress}
title="This looks great!"
accessibilityLabel="This sounds great!"
/>
<Button
onPress={onButtonPress}
title="Ok!"
color="#841584"
accessibilityLabel="Ok, Great!"
/>
</View>
);
},
},
{
title: 'Disabled Button',
description: 'All interactions for the component are disabled.',
render: function() {
return (
<Button
disabled
onPress={onButtonPress}
title="I Am Disabled"
accessibilityLabel="See an informative alert"
/>
);
},
},
];
examples.forEach((example) => {
storiesOf('component: Button', module)
.add(example.title, () => example.render());
});

View File

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

View File

@@ -1,4 +1,80 @@
import React from 'react';
import { storiesOf, action } from '@kadira/storybook';
import { ListView } from 'react-native'
import { storiesOf } from '@kadira/storybook';
import { ListView, StyleSheet, Text, View } from 'react-native';
const generateData = (length) => Array.from({ length }).map((item, i) => i);
const dataSource = new ListView.DataSource({ rowHasChanged: (r1, r2) => r1 !== r2 });
storiesOf('component: ListView', module)
.add('vertical', () => (
<View style={styles.scrollViewContainer}>
<ListView
contentContainerStyle={styles.scrollViewContentContainerStyle}
dataSource={dataSource.cloneWithRows(generateData(100))}
initialListSize={100}
// eslint-disable-next-line react/jsx-no-bind
onScroll={(e) => { console.log('ScrollView.onScroll', e); } }
// eslint-disable-next-line react/jsx-no-bind
renderRow={(row) => (
<View><Text>{row}</Text></View>
)}
scrollEventThrottle={1000} // 1 event per second
style={styles.scrollViewStyle}
/>
</View>
))
.add('incremental rendering - large pageSize', () => (
<View style={styles.scrollViewContainer}>
<ListView
contentContainerStyle={styles.scrollViewContentContainerStyle}
dataSource={dataSource.cloneWithRows(generateData(5000))}
initialListSize={100}
// eslint-disable-next-line react/jsx-no-bind
onScroll={(e) => { console.log('ScrollView.onScroll', e); } }
pageSize={50}
// eslint-disable-next-line react/jsx-no-bind
renderRow={(row) => (
<View><Text>{row}</Text></View>
)}
scrollEventThrottle={1000} // 1 event per second
style={styles.scrollViewStyle}
/>
</View>
))
.add('incremental rendering - small pageSize', () => (
<View style={styles.scrollViewContainer}>
<ListView
contentContainerStyle={styles.scrollViewContentContainerStyle}
dataSource={dataSource.cloneWithRows(generateData(5000))}
initialListSize={5}
// eslint-disable-next-line react/jsx-no-bind
onScroll={(e) => { console.log('ScrollView.onScroll', e); } }
pageSize={1}
// eslint-disable-next-line react/jsx-no-bind
renderRow={(row) => (
<View><Text>{row}</Text></View>
)}
scrollEventThrottle={1000} // 1 event per second
style={styles.scrollViewStyle}
/>
</View>
));
const styles = StyleSheet.create({
box: {
flexGrow: 1,
justifyContent: 'center',
borderWidth: 1
},
scrollViewContainer: {
height: '200px',
width: 300
},
scrollViewStyle: {
borderWidth: '1px'
},
scrollViewContentContainerStyle: {
backgroundColor: '#eee',
padding: '10px'
}
});

View File

@@ -1,13 +1,15 @@
import React from 'react';
import { storiesOf, action } from '@kadira/storybook';
import { action, storiesOf } from '@kadira/storybook';
import { ScrollView, StyleSheet, Text, TouchableHighlight, View } from 'react-native'
const onScroll = action('ScrollView.onScroll');
storiesOf('component: ScrollView', module)
.add('vertical', () => (
<View style={styles.scrollViewContainer}>
<ScrollView
contentContainerStyle={styles.scrollViewContentContainerStyle}
onScroll={e => { console.log('ScrollView.onScroll', e); } }
onScroll={onScroll}
scrollEventThrottle={1000} // 1 event per second
style={styles.scrollViewStyle}
>
@@ -24,8 +26,8 @@ storiesOf('component: ScrollView', module)
<ScrollView
contentContainerStyle={styles.scrollViewContentContainerStyle}
horizontal
onScroll={e => console.log('ScrollView.onScroll', e)}
scrollEventThrottle={1} // 1 event per second
onScroll={onScroll}
scrollEventThrottle={16} // ~60 events per second
style={styles.scrollViewStyle}
>
{Array.from({ length: 50 }).map((item, i) => (
@@ -48,10 +50,10 @@ const styles = StyleSheet.create({
width: 300
},
scrollViewStyle: {
borderWidth: '1px'
borderWidth: 1
},
scrollViewContentContainerStyle: {
backgroundColor: '#eee',
padding: '10px'
padding: 10
}
})

View File

@@ -79,7 +79,7 @@ const examples = [
title: 'Wrap',
render: function() {
return (
<Text>
<Text style={{ WebkitFontSmoothing: 'antialiased' }}>
The text should wrap if it goes on multiple lines. See, this is going to
the next line.
</Text>

View File

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

View File

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

View File

@@ -1,10 +1,12 @@
{
"name": "react-native-web",
"version": "0.0.53",
"version": "0.0.61",
"description": "React Native for Web",
"main": "dist/index.js",
"files": [
"dist"
"dist",
"src",
"!**/__tests__"
],
"scripts": {
"build": "del ./dist && mkdir dist && babel src -d dist --ignore **/__tests__",
@@ -14,8 +16,9 @@
"examples": "start-storybook -p 9001 -c ./examples/.storybook --dont-track",
"lint": "eslint src",
"prepublish": "npm run build && npm run build:umd",
"test": "jest",
"test:watch": "npm run test -- --watch"
"test": "npm run lint && npm run test:jest",
"test:jest": "jest",
"test:watch": "npm run test:jest -- --watch"
},
"dependencies": {
"animated": "^0.1.3",
@@ -25,7 +28,7 @@
"deep-assign": "^2.0.0",
"fbjs": "^0.8.4",
"inline-style-prefixer": "^2.0.1",
"react-dom": "~15.3.2",
"react-dom": "~15.4.1",
"react-textarea-autosize": "^4.0.4",
"react-timer-mixin": "^0.13.3"
},
@@ -46,15 +49,15 @@
"file-loader": "^0.9.0",
"jest": "^16.0.2",
"node-libs-browser": "^0.5.3",
"react": "~15.3.2",
"react-addons-test-utils": "~15.3.2",
"react-test-renderer": "~15.3.2",
"react": "~15.4.1",
"react-addons-test-utils": "~15.4.1",
"react-test-renderer": "~15.4.1",
"url-loader": "^0.5.7",
"webpack": "^1.13.2",
"webpack-bundle-analyzer": "^1.5.3"
},
"peerDependencies": {
"react": "~15.3.2"
"react": "~15.4.1"
},
"author": "Nicolas Gallagher",
"license": "BSD-3-Clause",

View File

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

View File

@@ -7,7 +7,7 @@
*/
import invariant from 'fbjs/lib/invariant';
import { render } from 'react/lib/ReactMount';
import { render } from 'react-dom/lib/ReactMount';
import ReactNativeApp from './ReactNativeApp';
import StyleSheet from '../../apis/StyleSheet';
import React, { Component } from 'react';

View File

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

36
src/apis/Linking/index.js Normal file
View File

@@ -0,0 +1,36 @@
const Linking = {
addEventListener() {},
removeEventListener() {},
canOpenUrl() { return true; },
getInitialUrl() { return ''; },
openURL(url) {
iframeOpen(url);
}
};
/**
* Tabs opened using JavaScript may redirect the parent tab using
* `window.opener.location`, ignoring cross-origin restrictions and enabling
* phishing attacks.
*
* Safari requires that we open the url by injecting a hidden iframe that calls
* window.open(), then removes the iframe from the DOM.
*
* https://mathiasbynens.github.io/rel-noopener/
*/
const iframeOpen = (url) => {
const iframe = document.createElement('iframe');
iframe.style.display = 'none';
document.body.appendChild(iframe);
const iframeDoc = iframe.contentDocument || iframe.contentWindow.document;
const script = iframeDoc.createElement('script');
script.text = `
window.parent = null; window.top = null; window.frameElement = null;
var child = window.open("${url}"); child.opener = null;
`;
iframeDoc.body.appendChild(script);
document.body.removeChild(iframe);
};
module.exports = Linking;

View File

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

View File

@@ -9,8 +9,8 @@
import { PropTypes } from 'react'
import ImageStylePropTypes from '../../components/Image/ImageStylePropTypes'
import ReactPropTypeLocations from 'react/lib/ReactPropTypeLocations'
import ReactPropTypesSecret from 'react/lib/ReactPropTypesSecret'
import ReactPropTypeLocations from 'react-dom/lib/ReactPropTypeLocations'
import ReactPropTypesSecret from 'react-dom/lib/ReactPropTypesSecret'
import TextStylePropTypes from '../../components/Text/TextStylePropTypes'
import ViewStylePropTypes from '../../components/View/ViewStylePropTypes'
import warning from 'fbjs/lib/warning'

View File

@@ -35,7 +35,7 @@ describe('apis/StyleSheet', () => {
test('renders a style sheet in the browser', () => {
StyleSheet.create({ root: { color: 'red' } });
expect(document.getElementById('__react-native-style').textContent).toEqual(getDefaultStyleSheet());
expect(document.getElementById('react-native-style__').textContent).toEqual(getDefaultStyleSheet());
});
});

View File

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

View File

@@ -1,11 +1,13 @@
import expandStyle from './expandStyle';
import flattenStyle from '../../modules/flattenStyle';
import i18nStyle from './i18nStyle';
import processBoxShadow from './processBoxShadow';
import processTextShadow from './processTextShadow';
import processTransform from './processTransform';
import processVendorPrefixes from './processVendorPrefixes';
const processors = [
processBoxShadow,
processTextShadow,
processTransform,
processVendorPrefixes

View File

@@ -1,6 +1,8 @@
import I18nManager from '../I18nManager';
import multiplyStyleLengthValue from '../../modules/multiplyStyleLengthValue';
const emptyObject = {};
/**
* Map of property names to their BiDi equivalent.
*/
@@ -64,38 +66,40 @@ const swapLtrRtl = (value:String): String => {
return value === 'ltr' ? 'rtl' : value === 'rtl' ? 'ltr' : value;
};
const i18nStyle = (style = {}) => {
const i18nStyle = (style = emptyObject) => {
const newStyle = {};
for (const prop in style) {
if (style.hasOwnProperty(prop)) {
const indexOfNoFlip = prop.indexOf('$noI18n');
if (!Object.prototype.hasOwnProperty.call(style, prop)) {
continue;
}
if (I18nManager.isRTL) {
if (PROPERTIES_TO_SWAP[prop]) {
const newProp = flipProperty(prop);
newStyle[newProp] = style[prop];
} else if (PROPERTIES_SWAP_LEFT_RIGHT[prop]) {
newStyle[prop] = swapLeftRight(style[prop]);
} else if (PROPERTIES_SWAP_LTR_RTL[prop]) {
newStyle[prop] = swapLtrRtl(style[prop]);
} else if (prop === 'textShadowOffset') {
newStyle[prop] = style[prop];
newStyle[prop].width = additiveInverse(style[prop].width);
} else if (prop === 'transform') {
newStyle[prop] = style[prop].map(flipTransform);
} else if (indexOfNoFlip > -1) {
const newProp = prop.substring(0, indexOfNoFlip);
newStyle[newProp] = style[prop];
} else {
newStyle[prop] = style[prop];
}
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 {
if (indexOfNoFlip > -1) {
const newProp = prop.substring(0, indexOfNoFlip);
newStyle[newProp] = style[prop];
} else {
newStyle[prop] = style[prop];
}
newStyle[prop] = style[prop];
}
} else {
if (indexOfNoFlip > -1) {
const newProp = prop.substring(0, indexOfNoFlip);
newStyle[newProp] = style[prop];
} else {
newStyle[prop] = style[prop];
}
}
}

View File

@@ -8,7 +8,7 @@ import ReactNativePropRegistry from '../../modules/ReactNativePropRegistry';
let styleElement;
let shouldInsertStyleSheet = ExecutionEnvironment.canUseDOM;
const STYLE_SHEET_ID = '__react-native-style';
const STYLE_SHEET_ID = 'react-native-style__';
const absoluteFillObject = { position: 'absolute', left: 0, right: 0, top: 0, bottom: 0 };

View File

@@ -24,7 +24,9 @@ const unitlessNumbers = {
scale: true,
scaleX: true,
scaleY: true,
scaleZ: true
scaleZ: true,
// RN properties
shadowOpacity: true
};
const normalizeValue = (property, value) => {

View File

@@ -0,0 +1,33 @@
import normalizeColor from '../../modules/normalizeColor';
import normalizeValue from './normalizeValue';
const applyOpacity = (color, opacity) => {
const normalizedColor = normalizeColor(color);
const colorNumber = normalizedColor === null ? 0x00000000 : normalizedColor;
const r = (colorNumber & 0xff000000) >>> 24;
const g = (colorNumber & 0x00ff0000) >>> 16;
const b = (colorNumber & 0x0000ff00) >>> 8;
const a = (((colorNumber & 0x000000ff) >>> 0) / 255).toFixed(2);
return `rgba(${r},${g},${b},${a * opacity})`;
};
// TODO: add inset and spread support
const processBoxShadow = (style) => {
if (style && style.shadowColor) {
const { height, width } = style.shadowOffset || {};
const opacity = style.shadowOpacity != null ? style.shadowOpacity : 1;
const color = applyOpacity(style.shadowColor, opacity);
const blurRadius = normalizeValue(null, style.shadowRadius || 0);
const offsetX = normalizeValue(null, height || 0);
const offsetY = normalizeValue(null, width || 0);
const boxShadow = `${offsetX} ${offsetY} ${blurRadius} ${color}`;
style.boxShadow = style.boxShadow ? `${style.boxShadow}, ${boxShadow}` : boxShadow;
}
delete style.shadowColor;
delete style.shadowOffset;
delete style.shadowOpacity;
delete style.shadowRadius;
return style;
};
module.exports = processBoxShadow;

View File

@@ -1,5 +1,5 @@
import createReactStyleObject from '../StyleSheet/createReactStyleObject';
import CSSPropertyOperations from 'react/lib/CSSPropertyOperations';
import CSSPropertyOperations from 'react-dom/lib/CSSPropertyOperations';
const _measureLayout = (node, relativeToNativeNode, callback) => {
const relativeNode = relativeToNativeNode || node.parentNode;
@@ -35,8 +35,11 @@ const UIManager = {
updateView(node, props, component /* only needed to surpress React errors in development */) {
for (const prop in props) {
const value = props[prop];
if (!Object.prototype.hasOwnProperty.call(props, prop)) {
continue;
}
const value = props[prop];
switch (prop) {
case 'style':
// convert styles to DOM-styles

View File

@@ -0,0 +1,5 @@
/* eslint-env jasmine, jest */
describe('components/Button', () => {
test.skip('NO TEST COVERAGE', () => {});
});

View File

@@ -0,0 +1,66 @@
import ColorPropType from '../../propTypes/ColorPropType';
import React, { Component, PropTypes } from 'react';
import StyleSheet from '../../apis/StyleSheet';
import TouchableOpacity from '../Touchable/TouchableOpacity';
import Text from '../Text';
class Button extends Component {
static propTypes = {
accessibilityLabel: PropTypes.string,
color: ColorPropType,
disabled: PropTypes.bool,
onPress: PropTypes.func.isRequired,
title: PropTypes.string.isRequired
};
render() {
const {
accessibilityLabel,
color,
disabled,
onPress,
title
} = this.props;
return (
<TouchableOpacity
accessibilityLabel={accessibilityLabel}
accessibilityRole={'button'}
disabled={disabled}
onPress={onPress}
style={[
styles.button,
color && { backgroundColor: color },
disabled && styles.buttonDisabled
]}>
<Text style={[
styles.text,
disabled && styles.textDisabled
]}>
{title}
</Text>
</TouchableOpacity>
);
}
}
const styles = StyleSheet.create({
button: {
backgroundColor: '#2196F3',
borderRadius: 2
},
text: {
textAlign: 'center',
color: '#fff',
padding: 8,
fontWeight: '500'
},
buttonDisabled: {
backgroundColor: '#dfdfdf'
},
textDisabled: {
color: '#a1a1a1'
}
});
module.exports = Button;

View File

@@ -1,3 +1,60 @@
exports[`components/Image passes other props through to underlying View 1`] = `
<div
className=" __style_df"
onResponderGrant={[Function]}
role="img"
style={
Object {
"MozBoxSizing": "border-box",
"WebkitAlignItems": "stretch",
"WebkitBoxAlign": "stretch",
"WebkitBoxDirection": "normal",
"WebkitBoxOrient": "vertical",
"WebkitFlexBasis": "auto",
"WebkitFlexDirection": "column",
"WebkitFlexShrink": 0,
"alignItems": "stretch",
"backgroundColor": "transparent",
"backgroundPosition": "center",
"backgroundRepeat": "no-repeat",
"backgroundSize": "cover",
"borderBottomStyle": "solid",
"borderBottomWidth": "0px",
"borderLeftStyle": "solid",
"borderLeftWidth": "0px",
"borderRightStyle": "solid",
"borderRightWidth": "0px",
"borderTopStyle": "solid",
"borderTopWidth": "0px",
"boxSizing": "border-box",
"color": "inherit",
"display": null,
"flexBasis": "auto",
"flexDirection": "column",
"flexShrink": 0,
"font": "inherit",
"listStyle": "none",
"marginBottom": "0px",
"marginLeft": "0px",
"marginRight": "0px",
"marginTop": "0px",
"minHeight": "0px",
"minWidth": "0px",
"msFlexAlign": "stretch",
"msFlexDirection": "column",
"msFlexNegative": 0,
"msPreferredSize": "auto",
"paddingBottom": "0px",
"paddingLeft": "0px",
"paddingRight": "0px",
"paddingTop": "0px",
"position": "relative",
"textAlign": "inherit",
"textDecoration": "none",
}
} />
`;
exports[`components/Image prop "accessibilityLabel" 1`] = `
<div
aria-label="accessibilityLabel"

View File

@@ -91,4 +91,10 @@ describe('components/Image', () => {
const component = renderer.create(<Image testID='testID' />);
expect(component.toJSON()).toMatchSnapshot();
});
test('passes other props through to underlying View', () => {
const fn = () => {};
const component = renderer.create(<Image onResponderGrant={fn} />);
expect(component.toJSON()).toMatchSnapshot();
});
});

View File

@@ -1,13 +1,16 @@
/* global window */
import applyNativeMethods from '../../modules/applyNativeMethods';
import BaseComponentPropTypes from '../../propTypes/BaseComponentPropTypes';
import ImageResizeMode from './ImageResizeMode';
import ImageLoader from '../../modules/ImageLoader';
import ImageStylePropTypes from './ImageStylePropTypes';
import requestAnimationFrame from 'fbjs/lib/requestAnimationFrame';
import StyleSheet from '../../apis/StyleSheet';
import StyleSheetPropType from '../../propTypes/StyleSheetPropType';
import View from '../View';
import React, { Component, PropTypes } from 'react';
const emptyObject = {};
const STATUS_ERRORED = 'ERRORED';
const STATUS_LOADED = 'LOADED';
const STATUS_LOADING = 'LOADING';
@@ -38,7 +41,7 @@ class Image extends Component {
static displayName = 'Image';
static propTypes = {
...BaseComponentPropTypes,
...View.propTypes,
children: PropTypes.any,
defaultSource: ImageSourcePropType,
onError: PropTypes.func,
@@ -52,14 +55,22 @@ class Image extends Component {
};
static defaultProps = {
style: {}
style: emptyObject
};
static getSize(uri, success, failure) {
ImageLoader.getSize(uri, success, failure);
}
static prefetch(uri) {
return ImageLoader.prefetch(uri);
}
static resizeMode = ImageResizeMode;
constructor(props, context) {
super(props, context);
this.state = { isLoaded: false };
this.state = { shouldDisplaySource: false };
const uri = resolveAssetSource(props.source);
this._imageState = uri ? STATUS_PENDING : STATUS_IDLE;
this._isMounted = false;
@@ -73,7 +84,7 @@ class Image extends Component {
}
componentDidUpdate() {
if (this._imageState === STATUS_PENDING && !this.image) {
if (this._imageState === STATUS_PENDING) {
this._createImageLoader();
}
}
@@ -91,7 +102,7 @@ class Image extends Component {
}
render() {
const { isLoaded } = this.state;
const { shouldDisplaySource } = this.state;
const {
accessibilityLabel,
accessible,
@@ -99,27 +110,36 @@ class Image extends Component {
defaultSource,
onLayout,
source,
testID
testID,
/* eslint-disable */
onError,
onLoad,
onLoadEnd,
onLoadStart,
resizeMode,
/* eslint-enable */
...other
} = this.props;
const displayImage = resolveAssetSource(!isLoaded ? defaultSource : source);
const imageSizeStyle = resolveAssetDimensions(!isLoaded ? defaultSource : source);
const displayImage = resolveAssetSource(shouldDisplaySource ? source : defaultSource);
const imageSizeStyle = resolveAssetDimensions(shouldDisplaySource ? source : defaultSource);
const backgroundImage = displayImage ? `url("${displayImage}")` : null;
const originalStyle = StyleSheet.flatten(this.props.style);
const resizeMode = this.props.resizeMode || originalStyle.resizeMode || ImageResizeMode.cover;
const finalResizeMode = resizeMode || originalStyle.resizeMode || ImageResizeMode.cover;
const style = StyleSheet.flatten([
styles.initial,
imageSizeStyle,
originalStyle,
backgroundImage && { backgroundImage },
resizeModeStyles[resizeMode]
resizeModeStyles[finalResizeMode]
]);
// View doesn't support 'resizeMode' as a style
delete style.resizeMode;
return (
<View
{...other}
accessibilityLabel={accessibilityLabel}
accessibilityRole='img'
accessible={accessible}
@@ -132,28 +152,21 @@ class Image extends Component {
}
_createImageLoader() {
const uri = resolveAssetSource(this.props.source);
this._destroyImageLoader();
this.image = new window.Image();
this.image.onerror = this._onError;
this.image.onload = this._onLoad;
this.image.src = uri;
const uri = resolveAssetSource(this.props.source);
this._imageRequestId = ImageLoader.load(uri, this._onLoad, this._onError);
this._onLoadStart();
}
_destroyImageLoader() {
if (this.image) {
this.image.onerror = null;
this.image.onload = null;
this.image = null;
if (this._imageRequestId) {
ImageLoader.abort(this._imageRequestId);
this._imageRequestId = null;
}
}
_onError = () => {
const { onError, source } = this.props;
this._destroyImageLoader();
this._onLoadEnd();
this._updateImageState(STATUS_ERRORED);
if (onError) {
onError({
@@ -162,13 +175,13 @@ class Image extends Component {
}
});
}
this._onLoadEnd();
}
_onLoad = (e) => {
const { onLoad } = this.props;
const event = { nativeEvent: e };
this._destroyImageLoader();
this._updateImageState(STATUS_LOADED);
if (onLoad) { onLoad(event); }
this._onLoadEnd();
@@ -187,11 +200,12 @@ class Image extends Component {
_updateImageState(status) {
this._imageState = status;
const isLoaded = this._imageState === STATUS_LOADED;
if (isLoaded !== this.state.isLoaded) {
window.requestAnimationFrame(() => {
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({ isLoaded });
this.setState({ shouldDisplaySource });
}
});
}

View File

@@ -2,18 +2,27 @@ import applyNativeMethods from '../../modules/applyNativeMethods';
import ListViewDataSource from './ListViewDataSource';
import ListViewPropTypes from './ListViewPropTypes';
import ScrollView from '../ScrollView';
import View from '../View';
import React, { Component } from 'react';
import StaticRenderer from '../StaticRenderer';
import React, { Component, isEmpty, merge } from 'react';
import requestAnimationFrame from 'fbjs/lib/requestAnimationFrame';
const DEFAULT_PAGE_SIZE = 1;
const DEFAULT_INITIAL_ROWS = 10;
const DEFAULT_SCROLL_RENDER_AHEAD = 1000;
const DEFAULT_END_REACHED_THRESHOLD = 1000;
const DEFAULT_SCROLL_CALLBACK_THROTTLE = 50;
class ListView extends Component {
static propTypes = ListViewPropTypes;
static defaultProps = {
initialListSize: 10,
pageSize: 1,
initialListSize: DEFAULT_INITIAL_ROWS,
pageSize: DEFAULT_PAGE_SIZE,
renderScrollComponent: (props) => <ScrollView {...props} />,
scrollRenderAheadDistance: 1000,
onEndReachedThreshold: 1000,
scrollRenderAheadDistance: DEFAULT_SCROLL_RENDER_AHEAD,
onEndReachedThreshold: DEFAULT_END_REACHED_THRESHOLD,
scrollEventThrottle: DEFAULT_SCROLL_CALLBACK_THROTTLE,
removeClippedSubviews: true,
stickyHeaderIndices: []
};
@@ -26,6 +35,48 @@ class ListView extends Component {
highlightedRow: {}
};
this.onRowHighlighted = (sectionId, rowId) => this._onRowHighlighted(sectionId, rowId);
this.scrollProperties = {};
}
componentWillMount() {
// this data should never trigger a render pass, so don't put in state
this.scrollProperties = {
visibleLength: null,
contentLength: null,
offset: 0
};
this._childFrames = [];
this._visibleRows = {};
this._prevRenderedRowsCount = 0;
this._sentEndForContentLength = null;
}
componentDidMount() {
// do this in animation frame until componentDidMount actually runs after
// the component is laid out
requestAnimationFrame(() => {
this._measureAndUpdateScrollProps();
});
}
componentWillReceiveProps(nextProps: Object) {
if (this.props.dataSource !== nextProps.dataSource || this.props.initialListSize !== nextProps.initialListSize) {
this.setState((state, props) => {
this._prevRenderedRowsCount = 0;
return {
curRenderedRowsCount: Math.min(
Math.max(state.curRenderedRowsCount, props.initialListSize),
props.enableEmptySections ? props.dataSource.getRowAndSectionCount() : props.dataSource.getRowCount()
)
};
}, () => this._renderMoreRowsIfNeeded());
}
}
componentDidUpdate() {
requestAnimationFrame(() => {
this._measureAndUpdateScrollProps();
});
}
getScrollResponder() {
@@ -40,58 +91,313 @@ class ListView extends Component {
return this._scrollViewRef && this._scrollViewRef.setNativeProps(props);
}
_onRowHighlighted(sectionId, rowId) {
_onRowHighlighted = (sectionId, rowId) => {
this.setState({ highlightedRow: { sectionId, rowId } });
}
renderSectionHeaderFn = (data, sectionID) => {
return () => this.props.renderSectionHeader(data, sectionID);
}
renderRowFn = (data, sectionID, rowID) => {
return () => this.props.renderRow(data, sectionID, rowID, this._onRowHighlighted);
}
render() {
const dataSource = this.props.dataSource;
const header = this.props.renderHeader ? this.props.renderHeader() : undefined;
const footer = this.props.renderFooter ? this.props.renderFooter() : undefined;
// render sections and rows
const children = [];
const sections = dataSource.rowIdentities;
const renderRow = this.props.renderRow;
const renderSectionHeader = this.props.renderSectionHeader;
const renderSeparator = this.props.renderSeparator;
for (let sectionIdx = 0, sectionCnt = sections.length; sectionIdx < sectionCnt; sectionIdx++) {
const rows = sections[sectionIdx];
const sectionId = dataSource.sectionIdentities[sectionIdx];
// render optional section header
if (renderSectionHeader) {
const section = dataSource.getSectionHeaderData(sectionIdx);
const key = `s_${sectionId}`;
const child = <View key={key}>{renderSectionHeader(section, sectionId)}</View>;
children.push(child);
const dataSource = this.props.dataSource;
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();
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) {
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.');
continue;
} else {
const invariant = require('fbjs/lib/invariant');
invariant(
this.props.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.' +
' In this release \'enableEmptySections\' may only have value \'true\'' +
' to allow empty section headers rendering.');
}
}
// render rows
for (let rowIdx = 0, rowCnt = rows.length; rowIdx < rowCnt; rowIdx++) {
const rowId = rows[rowIdx];
const row = dataSource.getRowData(sectionIdx, rowIdx);
const key = `r_${sectionId}_${rowId}`;
const child = <View key={key}>{renderRow(row, sectionId, rowId, this.onRowHighlighted)}</View>;
children.push(child);
if (this.props.renderSectionHeader) {
const shouldUpdateHeader = rowCount >= this._prevRenderedRowsCount &&
dataSource.sectionHeaderShouldUpdate(sectionIdx);
children.push(
<StaticRenderer
key={`s_${sectionID}`}
render={this.renderSectionHeaderFn(
dataSource.getSectionHeaderData(sectionIdx),
sectionID
)}
shouldUpdate={!!shouldUpdateHeader}
/>
);
sectionHeaderIndices.push(totalIndex++);
}
// render optional separator
if (renderSeparator && ((rowIdx !== rows.length - 1) || (sectionIdx === sections.length - 1))) {
for (let rowIdx = 0; rowIdx < rowIDs.length; rowIdx++) {
const rowID = rowIDs[rowIdx];
const comboID = `${sectionID}_${rowID}`;
const shouldUpdateRow = rowCount >= this._prevRenderedRowsCount &&
dataSource.rowShouldUpdate(sectionIdx, rowIdx);
const row =
<StaticRenderer
key={`r_${comboID}`}
render={this.renderRowFn(
dataSource.getRowData(sectionIdx, rowIdx),
sectionID,
rowID
)}
shouldUpdate={!!shouldUpdateRow}
/>;
children.push(row);
totalIndex++;
if (this.props.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 === rows[rowIdx + 1]);
const separator = renderSeparator(sectionId, rowId, adjacentRowHighlighted);
children.push(separator);
this.state.highlightedRow.sectionID === sectionID && (
this.state.highlightedRow.rowID === rowID ||
this.state.highlightedRow.rowID === rowIDs[rowIdx + 1]
);
const separator = this.props.renderSeparator(
sectionID,
rowID,
adjacentRowHighlighted
);
if (separator) {
children.push(separator);
totalIndex++;
}
}
if (++rowCount === this.state.curRenderedRowsCount) {
break;
}
}
if (rowCount >= this.state.curRenderedRowsCount) {
break;
}
}
return React.cloneElement(this.props.renderScrollComponent(this.props), {
ref: this._setScrollViewRef
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), {
ref: this._setScrollViewRef,
onContentSizeChange: this._onContentSizeChange,
onLayout: this._onLayout
}, header, children, footer);
}
_measureAndUpdateScrollProps() {
const scrollComponent = this.getScrollResponder();
if (!scrollComponent || !scrollComponent.getInnerViewNode) {
return;
}
this._updateVisibleRows();
}
_onLayout = (event: Object) => {
const { width, height } = event.nativeEvent.layout;
const visibleLength = !this.props.horizontal ? height : width;
if (visibleLength !== this.scrollProperties.visibleLength) {
this.scrollProperties.visibleLength = visibleLength;
this._updateVisibleRows();
this._renderMoreRowsIfNeeded();
}
this.props.onLayout && this.props.onLayout(event);
}
_updateVisibleRows(updatedFrames?: Array<Object>) {
if (!this.props.onChangeVisibleRows) {
return; // No need to compute visible rows if there is no callback
}
if (updatedFrames) {
updatedFrames.forEach((newFrame) => {
this._childFrames[newFrame.index] = merge(newFrame);
});
}
const isVertical = !this.props.horizontal;
const dataSource = this.props.dataSource;
const visibleMin = this.scrollProperties.offset;
const visibleMax = visibleMin + this.scrollProperties.visibleLength;
const allRowIDs = dataSource.rowIdentities;
const header = this.props.renderHeader && this.props.renderHeader();
let totalIndex = header ? 1 : 0;
let visibilityChanged = false;
const changedRows = {};
for (let sectionIdx = 0; sectionIdx < allRowIDs.length; sectionIdx++) {
const rowIDs = allRowIDs[sectionIdx];
if (rowIDs.length === 0) {
continue;
}
const sectionID = dataSource.sectionIdentities[sectionIdx];
if (this.props.renderSectionHeader) {
totalIndex++;
}
let visibleSection = this._visibleRows[sectionID];
if (!visibleSection) {
visibleSection = {};
}
for (let rowIdx = 0; rowIdx < rowIDs.length; rowIdx++) {
const rowID = rowIDs[rowIdx];
const frame = this._childFrames[totalIndex];
totalIndex++;
if (this.props.renderSeparator &&
(rowIdx !== rowIDs.length - 1 || sectionIdx === allRowIDs.length - 1)) {
totalIndex++;
}
if (!frame) {
break;
}
const rowVisible = visibleSection[rowID];
const min = isVertical ? frame.y : frame.x;
const max = min + (isVertical ? frame.height : frame.width);
if ((!min && !max) || (min === max)) {
break;
}
if (min > visibleMax || max < visibleMin) {
if (rowVisible) {
visibilityChanged = true;
delete visibleSection[rowID];
if (!changedRows[sectionID]) {
changedRows[sectionID] = {};
}
changedRows[sectionID][rowID] = false;
}
} else if (!rowVisible) {
visibilityChanged = true;
visibleSection[rowID] = true;
if (!changedRows[sectionID]) {
changedRows[sectionID] = {};
}
changedRows[sectionID][rowID] = true;
}
}
if (!isEmpty(visibleSection)) {
this._visibleRows[sectionID] = visibleSection;
} else if (this._visibleRows[sectionID]) {
delete this._visibleRows[sectionID];
}
}
visibilityChanged && this.props.onChangeVisibleRows(this._visibleRows, changedRows);
}
_onContentSizeChange = (width: number, height: number) => {
const contentLength = !this.props.horizontal ? height : width;
if (contentLength !== this.scrollProperties.contentLength) {
this.scrollProperties.contentLength = contentLength;
this._updateVisibleRows();
this._renderMoreRowsIfNeeded();
}
this.props.onContentSizeChange && this.props.onContentSizeChange(width, height);
}
_getDistanceFromEnd(scrollProperties: Object) {
return scrollProperties.contentLength - scrollProperties.visibleLength - scrollProperties.offset;
}
_maybeCallOnEndReached(event?: Object) {
if (this.props.onEndReached &&
this.scrollProperties.contentLength !== this._sentEndForContentLength &&
this._getDistanceFromEnd(this.scrollProperties) < this.props.onEndReachedThreshold &&
this.state.curRenderedRowsCount === (this.props.enableEmptySections ?
this.props.dataSource.getRowAndSectionCount() : this.props.dataSource.getRowCount())) {
this._sentEndForContentLength = this.scrollProperties.contentLength;
this.props.onEndReached(event);
return true;
}
return false;
}
_renderMoreRowsIfNeeded() {
if (this.scrollProperties.contentLength === null ||
this.scrollProperties.visibleLength === null ||
this.state.curRenderedRowsCount === (this.props.enableEmptySections ?
this.props.dataSource.getRowAndSectionCount() : this.props.dataSource.getRowCount())) {
this._maybeCallOnEndReached();
return;
}
const distanceFromEnd = this._getDistanceFromEnd(this.scrollProperties);
if (distanceFromEnd < this.props.scrollRenderAheadDistance) {
this._pageInNewRows();
}
}
_pageInNewRows() {
this.setState((state, props) => {
const rowsToRender = Math.min(
state.curRenderedRowsCount + props.pageSize,
(props.enableEmptySections ? props.dataSource.getRowAndSectionCount() : props.dataSource.getRowCount())
);
this._prevRenderedRowsCount = state.curRenderedRowsCount;
return {
curRenderedRowsCount: rowsToRender
};
}, () => {
this._measureAndUpdateScrollProps();
this._prevRenderedRowsCount = this.state.curRenderedRowsCount;
});
}
_onScroll = (e: Object) => {
const isVertical = !this.props.horizontal;
this.scrollProperties.visibleLength = e.nativeEvent.layoutMeasurement[
isVertical ? 'height' : 'width'
];
this.scrollProperties.contentLength = e.nativeEvent.contentSize[
isVertical ? 'height' : 'width'
];
this.scrollProperties.offset = e.nativeEvent.contentOffset[
isVertical ? 'y' : 'x'
];
this._updateVisibleRows(e.nativeEvent.updatedChildFrames);
if (!this._maybeCallOnEndReached(e)) {
this._renderMoreRowsIfNeeded();
}
if (this.props.onEndReached &&
this._getDistanceFromEnd(this.scrollProperties) > this.props.onEndReachedThreshold) {
// Scrolled out of the end zone, so it should be able to trigger again.
this._sentEndForContentLength = null;
}
this.props.onScroll && this.props.onScroll(e);
};
_setScrollViewRef = (component) => {
this._scrollViewRef = component;
}

View File

@@ -10,6 +10,35 @@ import debounce from 'debounce';
import View from '../View';
import React, { Component, PropTypes } from 'react';
const normalizeScrollEvent = (e) => ({
nativeEvent: {
contentOffset: {
get x() {
return e.target.scrollLeft;
},
get y() {
return e.target.scrollTop;
}
},
contentSize: {
get height() {
return e.target.scrollHeight;
},
get width() {
return e.target.scrollWidth;
}
},
layoutMeasurement: {
get height() {
return e.target.offsetHeight;
},
get width() {
return e.target.offsetWidth;
}
}
}
});
/**
* Encapsulates the Web-specific scroll throttling and disabling logic
*/
@@ -75,13 +104,13 @@ export default class ScrollViewBase extends Component {
_handleScrollTick(e) {
const { onScroll } = this.props;
this._state.scrollLastTick = Date.now();
if (onScroll) { onScroll(e); }
if (onScroll) { onScroll(normalizeScrollEvent(e)); }
}
_handleScrollEnd(e) {
const { onScroll } = this.props;
this._state.isScrolling = false;
if (onScroll) { onScroll(e); }
if (onScroll) { onScroll(normalizeScrollEvent(e)); }
}
_shouldEmitScrollEvent(lastTick, eventThrottle) {

View File

@@ -17,6 +17,8 @@ import View from '../View';
import ViewStylePropTypes from '../View/ViewStylePropTypes';
import React, { Component, PropTypes } from 'react';
const emptyObject = {};
/* eslint-disable react/prefer-es6-class */
const ScrollView = React.createClass({
propTypes: {
@@ -79,7 +81,7 @@ const ScrollView = React.createClass({
if (typeof y === 'number') {
console.warn('`scrollTo(y, x, animated)` is deprecated. Use `scrollTo({x: 5, y: 5, animated: true})` instead.');
} else {
({ x, y, animated } = y || {});
({ x, y, animated } = y || emptyObject);
}
this.getScrollResponder().scrollResponderScrollTo({ x: x || 0, y: y || 0, animated: animated !== false });
@@ -236,7 +238,6 @@ const styles = StyleSheet.create({
overflowY: 'hidden'
},
contentContainer: {
flexGrow: 1,
transform: [ { translateZ: 0 } ]
},
contentContainerHorizontal: {

View File

@@ -67,7 +67,7 @@ exports[`components/Switch disabled when "false" a default checkbox is rendered
"WebkitFlexBasis": "auto",
"WebkitFlexDirection": "column",
"WebkitFlexShrink": 0,
"WebkitTransition": "background-color 0.1s",
"WebkitTransitionDuration": "0.1s",
"alignItems": "stretch",
"backgroundColor": "#939393",
"borderBottomLeftRadius": "10px",
@@ -112,7 +112,7 @@ exports[`components/Switch disabled when "false" a default checkbox is rendered
"textAlign": "inherit",
"textDecoration": "none",
"top": "0px",
"transition": "background-color 0.1s",
"transitionDuration": "0.1s",
"width": "90%",
}
} />
@@ -129,7 +129,8 @@ exports[`components/Switch disabled when "false" a default checkbox is rendered
"WebkitFlexBasis": "auto",
"WebkitFlexDirection": "column",
"WebkitFlexShrink": 0,
"WebkitTransition": "background-color 0.1s",
"WebkitTransform": "translateX(0%)",
"WebkitTransitionDuration": "0.1s",
"alignItems": "stretch",
"alignSelf": "flex-start",
"backgroundColor": "#FAFAFA",
@@ -166,6 +167,7 @@ exports[`components/Switch disabled when "false" a default checkbox is rendered
"msFlexItemAlign": "start",
"msFlexNegative": 0,
"msPreferredSize": "auto",
"msTransform": "translateX(0%)",
"paddingBottom": "0px",
"paddingLeft": "0px",
"paddingRight": "0px",
@@ -173,7 +175,8 @@ exports[`components/Switch disabled when "false" a default checkbox is rendered
"position": "relative",
"textAlign": "inherit",
"textDecoration": "none",
"transition": "background-color 0.1s",
"transform": "translateX(0%)",
"transitionDuration": "0.1s",
"width": "20px",
}
} />
@@ -278,7 +281,7 @@ exports[`components/Switch disabled when "true" a disabled checkbox is rendered
"WebkitFlexBasis": "auto",
"WebkitFlexDirection": "column",
"WebkitFlexShrink": 0,
"WebkitTransition": "background-color 0.1s",
"WebkitTransitionDuration": "0.1s",
"alignItems": "stretch",
"backgroundColor": "#D5D5D5",
"borderBottomLeftRadius": "10px",
@@ -323,7 +326,7 @@ exports[`components/Switch disabled when "true" a disabled checkbox is rendered
"textAlign": "inherit",
"textDecoration": "none",
"top": "0px",
"transition": "background-color 0.1s",
"transitionDuration": "0.1s",
"width": "90%",
}
} />
@@ -340,7 +343,8 @@ exports[`components/Switch disabled when "true" a disabled checkbox is rendered
"WebkitFlexBasis": "auto",
"WebkitFlexDirection": "column",
"WebkitFlexShrink": 0,
"WebkitTransition": "background-color 0.1s",
"WebkitTransform": "translateX(0%)",
"WebkitTransitionDuration": "0.1s",
"alignItems": "stretch",
"alignSelf": "flex-start",
"backgroundColor": "#BDBDBD",
@@ -377,6 +381,7 @@ exports[`components/Switch disabled when "true" a disabled checkbox is rendered
"msFlexItemAlign": "start",
"msFlexNegative": 0,
"msPreferredSize": "auto",
"msTransform": "translateX(0%)",
"paddingBottom": "0px",
"paddingLeft": "0px",
"paddingRight": "0px",
@@ -384,7 +389,8 @@ exports[`components/Switch disabled when "true" a disabled checkbox is rendered
"position": "relative",
"textAlign": "inherit",
"textDecoration": "none",
"transition": "background-color 0.1s",
"transform": "translateX(0%)",
"transitionDuration": "0.1s",
"width": "20px",
}
} />
@@ -489,7 +495,7 @@ exports[`components/Switch value when "false" an unchecked checkbox is rendered
"WebkitFlexBasis": "auto",
"WebkitFlexDirection": "column",
"WebkitFlexShrink": 0,
"WebkitTransition": "background-color 0.1s",
"WebkitTransitionDuration": "0.1s",
"alignItems": "stretch",
"backgroundColor": "#939393",
"borderBottomLeftRadius": "10px",
@@ -534,7 +540,7 @@ exports[`components/Switch value when "false" an unchecked checkbox is rendered
"textAlign": "inherit",
"textDecoration": "none",
"top": "0px",
"transition": "background-color 0.1s",
"transitionDuration": "0.1s",
"width": "90%",
}
} />
@@ -551,7 +557,8 @@ exports[`components/Switch value when "false" an unchecked checkbox is rendered
"WebkitFlexBasis": "auto",
"WebkitFlexDirection": "column",
"WebkitFlexShrink": 0,
"WebkitTransition": "background-color 0.1s",
"WebkitTransform": "translateX(0%)",
"WebkitTransitionDuration": "0.1s",
"alignItems": "stretch",
"alignSelf": "flex-start",
"backgroundColor": "#FAFAFA",
@@ -588,6 +595,7 @@ exports[`components/Switch value when "false" an unchecked checkbox is rendered
"msFlexItemAlign": "start",
"msFlexNegative": 0,
"msPreferredSize": "auto",
"msTransform": "translateX(0%)",
"paddingBottom": "0px",
"paddingLeft": "0px",
"paddingRight": "0px",
@@ -595,7 +603,8 @@ exports[`components/Switch value when "false" an unchecked checkbox is rendered
"position": "relative",
"textAlign": "inherit",
"textDecoration": "none",
"transition": "background-color 0.1s",
"transform": "translateX(0%)",
"transitionDuration": "0.1s",
"width": "20px",
}
} />
@@ -700,7 +709,7 @@ exports[`components/Switch value when "true" a checked checkbox is rendered 1`]
"WebkitFlexBasis": "auto",
"WebkitFlexDirection": "column",
"WebkitFlexShrink": 0,
"WebkitTransition": "background-color 0.1s",
"WebkitTransitionDuration": "0.1s",
"alignItems": "stretch",
"backgroundColor": "#A3D3CF",
"borderBottomLeftRadius": "10px",
@@ -745,7 +754,7 @@ exports[`components/Switch value when "true" a checked checkbox is rendered 1`]
"textAlign": "inherit",
"textDecoration": "none",
"top": "0px",
"transition": "background-color 0.1s",
"transitionDuration": "0.1s",
"width": "90%",
}
} />
@@ -755,16 +764,17 @@ exports[`components/Switch value when "true" a checked checkbox is rendered 1`]
Object {
"MozBoxSizing": "border-box",
"WebkitAlignItems": "stretch",
"WebkitAlignSelf": "flex-end",
"WebkitAlignSelf": "flex-start",
"WebkitBoxAlign": "stretch",
"WebkitBoxDirection": "normal",
"WebkitBoxOrient": "vertical",
"WebkitFlexBasis": "auto",
"WebkitFlexDirection": "column",
"WebkitFlexShrink": 0,
"WebkitTransition": "background-color 0.1s",
"WebkitTransform": "translateX(100%)",
"WebkitTransitionDuration": "0.1s",
"alignItems": "stretch",
"alignSelf": "flex-end",
"alignSelf": "flex-start",
"backgroundColor": "#009688",
"borderBottomLeftRadius": "100%",
"borderBottomRightRadius": "100%",
@@ -796,9 +806,10 @@ exports[`components/Switch value when "true" a checked checkbox is rendered 1`]
"minWidth": "0px",
"msFlexAlign": "stretch",
"msFlexDirection": "column",
"msFlexItemAlign": "end",
"msFlexItemAlign": "start",
"msFlexNegative": 0,
"msPreferredSize": "auto",
"msTransform": "translateX(100%)",
"paddingBottom": "0px",
"paddingLeft": "0px",
"paddingRight": "0px",
@@ -806,7 +817,8 @@ exports[`components/Switch value when "true" a checked checkbox is rendered 1`]
"position": "relative",
"textAlign": "inherit",
"textDecoration": "none",
"transition": "background-color 0.1s",
"transform": "translateX(100%)",
"transitionDuration": "0.1s",
"width": "20px",
}
} />

View File

@@ -7,6 +7,7 @@ import UIManager from '../../apis/UIManager';
import View from '../View';
import React, { Component, PropTypes } from 'react';
const emptyObject = {};
const thumbDefaultBoxShadow = '0px 1px 3px rgba(0,0,0,0.5)';
const thumbFocusedBoxShadow = `${thumbDefaultBoxShadow}, 0 0 0 10px rgba(0,0,0,0.1)`;
@@ -28,7 +29,7 @@ class Switch extends Component {
activeThumbColor: '#009688',
activeTrackColor: '#A3D3CF',
disabled: false,
style: {},
style: emptyObject,
thumbColor: '#FAFAFA',
trackColor: '#939393',
value: false
@@ -88,9 +89,9 @@ class Switch extends Component {
const thumbStyle = [
styles.thumb,
{
alignSelf: value ? 'flex-end' : 'flex-start',
backgroundColor: thumbCurrentColor,
height: thumbHeight,
transform: [ { translateX: value ? '100%' : '0%' } ],
width: thumbWidth
},
disabled && styles.disabledThumb
@@ -151,16 +152,17 @@ const styles = StyleSheet.create({
...StyleSheet.absoluteFillObject,
height: '70%',
margin: 'auto',
transition: 'background-color 0.1s',
transitionDuration: '0.1s',
width: '90%'
},
disabledTrack: {
backgroundColor: '#D5D5D5'
},
thumb: {
alignSelf: 'flex-start',
borderRadius: '100%',
boxShadow: thumbDefaultBoxShadow,
transition: 'background-color 0.1s'
transitionDuration: '0.1s'
},
disabledThumb: {
backgroundColor: '#BDBDBD'

View File

@@ -1,7 +1,6 @@
exports[`components/Text prop "children" 1`] = `
<span
className=""
onClick={[Function]}
style={
Object {
"borderBottomWidth": "0px",
@@ -27,10 +26,39 @@ exports[`components/Text prop "children" 1`] = `
</span>
`;
exports[`components/Text prop "selectable" 1`] = `
exports[`components/Text prop "onPress" 1`] = `
<span
className=""
onClick={[Function]}
onKeyDown={[Function]}
style={
Object {
"borderBottomWidth": "0px",
"borderLeftWidth": "0px",
"borderRightWidth": "0px",
"borderTopWidth": "0px",
"color": "inherit",
"cursor": "pointer",
"display": "inline",
"font": "inherit",
"marginBottom": "0px",
"marginLeft": "0px",
"marginRight": "0px",
"marginTop": "0px",
"paddingBottom": "0px",
"paddingLeft": "0px",
"paddingRight": "0px",
"paddingTop": "0px",
"textDecoration": "none",
"wordWrap": "break-word",
}
}
tabIndex={0} />
`;
exports[`components/Text prop "selectable" 1`] = `
<span
className=""
style={
Object {
"borderBottomWidth": "0px",
@@ -57,7 +85,6 @@ exports[`components/Text prop "selectable" 1`] = `
exports[`components/Text prop "selectable" 2`] = `
<span
className=""
onClick={[Function]}
style={
Object {
"MozUserSelect": "none",

View File

@@ -14,6 +14,12 @@ describe('components/Text', () => {
test('prop "numberOfLines"');
test('prop "onPress"', () => {
const onPress = (e) => {};
const component = renderer.create(<Text onPress={onPress} />);
expect(component.toJSON()).toMatchSnapshot();
});
test('prop "selectable"', () => {
let component = renderer.create(<Text />);
expect(component.toJSON()).toMatchSnapshot();

View File

@@ -29,27 +29,43 @@ class Text extends Component {
render() {
const {
numberOfLines,
onLayout, // eslint-disable-line
onPress, // eslint-disable-line
onPress,
selectable,
style,
...other
/* eslint-disable */
adjustsFontSizeToFit,
allowFontScaling,
ellipsizeMode,
minimumFontScale,
onLayout,
suppressHighlighting,
/* eslint-enable */
...otherProps
} = this.props;
return createDOMElement('span', {
...other,
onClick: this._onPress,
style: [
styles.initial,
style,
!selectable && styles.notSelectable,
numberOfLines === 1 && styles.singleLineStyle
]
});
if (onPress) {
otherProps.onClick = onPress;
otherProps.onKeyDown = this._createEnterHandler(onPress);
otherProps.tabIndex = 0;
}
otherProps.style = [
styles.initial,
style,
!selectable && styles.notSelectable,
numberOfLines === 1 && styles.singleLineStyle,
onPress && styles.pressable
];
return createDOMElement('span', otherProps);
}
_onPress = (e) => {
if (this.props.onPress) { this.props.onPress(e); }
_createEnterHandler(fn) {
return (e) => {
if (e.keyCode === 13) {
fn && fn(e);
}
};
}
}
@@ -67,6 +83,9 @@ const styles = StyleSheet.create({
notSelectable: {
userSelect: 'none'
},
pressable: {
cursor: 'pointer'
},
singleLineStyle: {
maxWidth: '100%',
overflow: 'hidden',

View File

@@ -169,8 +169,6 @@ describe('components/TextInput', () => {
}
});
test('prop "onLayout"');
test('prop "onSelectionChange"', (done) => {
const input = findNativeInput(mount(<TextInput defaultValue='12345' onSelectionChange={onSelectionChange} />));
input.simulate('select', { target: { selectionStart: 0, selectionEnd: 3 } });
@@ -181,6 +179,16 @@ describe('components/TextInput', () => {
}
});
describe('prop "onSubmitEditing"', () => {
test('single-line input', (done) => {
const input = findNativeInput(mount(<TextInput defaultValue='12345' onSubmitEditing={onSubmitEditing} />));
input.simulate('keyPress', { which: 13 });
function onSubmitEditing(e) {
done();
}
});
});
test('prop "secureTextEntry"', () => {
let input = findNativeInput(shallow(<TextInput secureTextEntry />));
expect(input.prop('type')).toEqual('password');

View File

@@ -10,6 +10,8 @@ import UIManager from '../../apis/UIManager';
import View from '../View';
import { Component, PropTypes } from 'react';
const emptyObject = {};
/**
* React Native events differ from W3C events.
*/
@@ -72,6 +74,7 @@ class TextInput extends Component {
onFocus: PropTypes.func,
onKeyPress: PropTypes.func,
onSelectionChange: PropTypes.func,
onSubmitEditing: PropTypes.func,
placeholder: PropTypes.string,
placeholderTextColor: PropTypes.string,
secureTextEntry: PropTypes.bool,
@@ -93,7 +96,7 @@ class TextInput extends Component {
multiline: false,
numberOfLines: 2,
secureTextEntry: false,
style: {}
style: emptyObject
};
blur() {
@@ -152,7 +155,7 @@ class TextInput extends Component {
selectionColor,
selectTextOnFocus,
/* eslint-enable */
...other
...otherProps
} = this.props;
let type;
@@ -185,9 +188,9 @@ class TextInput extends Component {
const component = multiline ? TextareaAutosize : 'input';
const props = {
...other,
Object.assign(otherProps, {
autoCorrect: autoCorrect ? 'on' : 'off',
dir: 'auto',
onBlur: normalizeEventHandler(this._handleBlur),
onChange: normalizeEventHandler(this._handleChange),
onFocus: normalizeEventHandler(this._handleFocus),
@@ -199,16 +202,16 @@ class TextInput extends Component {
styles.initial,
style
]
};
});
if (multiline) {
props.maxRows = maxNumberOfLines || numberOfLines;
props.minRows = numberOfLines;
otherProps.maxRows = maxNumberOfLines || numberOfLines;
otherProps.minRows = numberOfLines;
} else {
props.type = type;
otherProps.type = type;
}
return createDOMElement(component, props);
return createDOMElement(component, otherProps);
}
_handleBlur = (e) => {
@@ -243,7 +246,7 @@ class TextInput extends Component {
}
_handleSelectionChange = (e) => {
const { onSelectionChange, selection = {} } = this.props;
const { onSelectionChange, selection = emptyObject } = this.props;
if (onSelectionChange) {
try {
const node = e.target;
@@ -270,7 +273,6 @@ const styles = StyleSheet.create({
borderWidth: 0,
boxSizing: 'border-box',
color: 'inherit',
flex: 1,
font: 'inherit',
padding: 0
}

View File

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

View File

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

View File

@@ -566,13 +566,13 @@ var TouchableMixin = {
* @sideeffects
* @private
*/
_remeasureMetricsOnActivation: function(e) {
/* @edit begin */
UIManager.measure(
e.nativeEvent.target,
this._handleQueryLayout
);
/* @edit end */
_remeasureMetricsOnActivation: function() {
const tag = this.state.touchable.responderID;
if (tag == null) {
return;
}
UIManager.measure(tag, this._handleQueryLayout);
},
_handleQueryLayout: function(l, t, w, h, globalX, globalY) {
@@ -684,7 +684,7 @@ var TouchableMixin = {
}
if (!IsActive[curState] && IsActive[nextState]) {
this._remeasureMetricsOnActivation(e);
this._remeasureMetricsOnActivation();
}
if (IsPressingIn[curState] && signal === Signals.LONG_PRESS_DETECTED) {
@@ -692,16 +692,9 @@ var TouchableMixin = {
}
if (newIsHighlight && !curIsHighlight) {
this._savePressInLocation(e);
this.touchableHandleActivePressIn && this.touchableHandleActivePressIn(e);
} else if (!newIsHighlight && curIsHighlight && this.touchableHandleActivePressOut) {
if (this.touchableGetPressOutDelayMS && this.touchableGetPressOutDelayMS()) {
this.pressOutDelayTimeout = setTimeout(() => {
this.touchableHandleActivePressOut(e);
}, this.touchableGetPressOutDelayMS());
} else {
this.touchableHandleActivePressOut(e);
}
this._startHighlight(e);
} else if (!newIsHighlight && curIsHighlight) {
this._endHighlight(e);
}
if (IsPressingIn[curState] && signal === Signals.RESPONDER_RELEASE) {
@@ -714,49 +707,40 @@ var TouchableMixin = {
var shouldInvokePress = !IsLongPressingIn[curState] || pressIsLongButStillCallOnPress;
if (shouldInvokePress && this.touchableHandlePress) {
if (!newIsHighlight && !curIsHighlight) {
// we never highlighted because of delay, but we should highlight now
this._startHighlight(e);
this._endHighlight(e);
}
this.touchableHandlePress(e);
}
}
this.touchableDelayTimeout && clearTimeout(this.touchableDelayTimeout);
this.touchableDelayTimeout = null;
}
},
_startHighlight: function(e) {
this._savePressInLocation(e);
this.touchableHandleActivePressIn && this.touchableHandleActivePressIn(e);
},
_endHighlight: function(e) {
if (this.touchableHandleActivePressOut) {
if (this.touchableGetPressOutDelayMS && this.touchableGetPressOutDelayMS()) {
this.pressOutDelayTimeout = setTimeout(() => {
this.touchableHandleActivePressOut(e);
}, this.touchableGetPressOutDelayMS());
} else {
this.touchableHandleActivePressOut(e);
}
}
},
};
var Touchable = {
Mixin: TouchableMixin,
TOUCH_TARGET_DEBUG: false, // Highlights all touchable targets. Toggle with Inspector.
/**
* Renders a debugging overlay to visualize touch target with hitSlop (might not work on Android).
*/
renderDebugView: ({color, hitSlop}) => {
if (!Touchable.TOUCH_TARGET_DEBUG) {
return null;
}
if (process.env.NODE_ENV === 'production') {
throw Error('Touchable.TOUCH_TARGET_DEBUG should not be enabled in prod!');
}
const debugHitSlopStyle = {};
hitSlop = hitSlop || {top: 0, bottom: 0, left: 0, right: 0};
for (const key in hitSlop) {
debugHitSlopStyle[key] = -hitSlop[key];
}
const hexColor = '#' + ('00000000' + normalizeColor(color).toString(16)).substr(-8);
return (
<View
pointerEvents="none"
style={{
position: 'absolute',
borderColor: hexColor.slice(0, -2) + '55', // More opaque
borderWidth: 1,
borderStyle: 'dashed',
backgroundColor: hexColor.slice(0, -2) + '0F', // Less opaque
...debugHitSlopStyle
}}
/>
);
}
Mixin: TouchableMixin
};
module.exports = Touchable;

View File

@@ -18,10 +18,12 @@ var ColorPropType = require('../../propTypes/ColorPropType');
var NativeMethodsMixin = require('../../modules/NativeMethodsMixin');
var React = require('react');
var StyleSheet = require('../../apis/StyleSheet');
var StyleSheetPropType = require('../../propTypes/StyleSheetPropType');
var TimerMixin = require('react-timer-mixin');
var Touchable = require('./Touchable');
var TouchableWithoutFeedback = require('./TouchableWithoutFeedback');
var View = require('../View');
var ViewStylePropTypes = require('../View/ViewStylePropTypes');
var ensureComponentIsNative = require('./ensureComponentIsNative');
var ensurePositiveDelayProps = require('./ensurePositiveDelayProps');
@@ -31,7 +33,7 @@ type Event = Object;
var DEFAULT_PROPS = {
accessibilityRole: 'button',
activeOpacity: 0.8,
activeOpacity: 0.85,
underlayColor: 'black'
};
@@ -53,13 +55,13 @@ var PRESS_RETENTION_OFFSET = {top: 20, left: 20, right: 20, bottom: 30};
* <TouchableHighlight onPress={this._onPressButton}>
* <Image
* style={styles.button}
* source={require('image!myButton')}
* source={require('./myButton')}
* />
* </TouchableHighlight>
* );
* },
* ```
* > **NOTE**: TouchableHighlight supports only one child
* > **NOTE**: TouchableHighlight must have one child (not zero or more than one)
* >
* > If you wish to have several child components, wrap them in a View.
*/
@@ -77,7 +79,7 @@ var TouchableHighlight = React.createClass({
* active.
*/
underlayColor: ColorPropType,
style: React.PropTypes.style,
style: StyleSheetPropType(ViewStylePropTypes),
/**
* Called immediately after the underlay is shown
*/

View File

@@ -14,13 +14,13 @@
// Note (avik): add @flow when Flow supports spread properties in propTypes
var Animated = require('../../apis/Animated');
var NativeMethodsMixin = require('../../modules/NativeMethodsMixin');
var React = require('react');
var StyleSheet = require('../../apis/StyleSheet');
var TimerMixin = require('react-timer-mixin');
var Touchable = require('./Touchable');
var TouchableWithoutFeedback = require('./TouchableWithoutFeedback');
var View = require('../View');
var ensurePositiveDelayProps = require('./ensurePositiveDelayProps');
var flattenStyle = StyleSheet.flatten
@@ -43,7 +43,7 @@ var PRESS_RETENTION_OFFSET = {top: 20, left: 20, right: 20, bottom: 30};
* <TouchableOpacity onPress={this._onPressButton}>
* <Image
* style={styles.button}
* source={require('image!myButton')}
* source={require('./myButton')}
* />
* </TouchableOpacity>
* );
@@ -60,20 +60,19 @@ var TouchableOpacity = React.createClass({
* active.
*/
activeOpacity: React.PropTypes.number,
focusedOpacity: React.PropTypes.number
},
getDefaultProps: function() {
return {
accessibilityRole: 'button',
activeOpacity: 0.2,
focusedOpacity: 0.7
};
},
getInitialState: function() {
return {
...this.touchableGetInitialState(),
anim: new Animated.Value(1),
};
return this.touchableGetInitialState();
},
componentDidMount: function() {
@@ -84,11 +83,13 @@ var TouchableOpacity = React.createClass({
ensurePositiveDelayProps(nextProps);
},
setOpacityTo: function(value) {
Animated.timing(
this.state.anim,
{toValue: value, duration: 150}
).start();
setOpacityTo: function(value: number, duration: number) {
this.setNativeProps({
style: {
opacity: value,
transitionDuration: duration
}
});
},
/**
@@ -96,26 +97,20 @@ var TouchableOpacity = React.createClass({
* defined on your component.
*/
touchableHandleActivePressIn: function(e: Event) {
this.clearTimeout(this._hideTimeout);
this._hideTimeout = null;
this._opacityActive();
if (e.dispatchConfig.registrationName === 'onResponderGrant') {
this._opacityActive(0);
} else {
this._opacityActive(150);
}
this.props.onPressIn && this.props.onPressIn(e);
},
touchableHandleActivePressOut: function(e: Event) {
if (!this._hideTimeout) {
this._opacityInactive();
}
this._opacityInactive(250);
this.props.onPressOut && this.props.onPressOut(e);
},
touchableHandlePress: function(e: Event) {
this.clearTimeout(this._hideTimeout);
this._opacityActive();
this._hideTimeout = this.setTimeout(
this._opacityInactive,
this.props.delayPressOut || 100
);
this.props.onPress && this.props.onPress(e);
},
@@ -144,19 +139,22 @@ var TouchableOpacity = React.createClass({
return this.props.delayPressOut;
},
_opacityActive: function() {
this.setOpacityTo(this.props.activeOpacity);
_opacityActive: function(duration: number) {
this.setOpacityTo(this.props.activeOpacity, duration);
},
_opacityInactive: function() {
this.clearTimeout(this._hideTimeout);
this._hideTimeout = null;
_opacityInactive: function(duration: number) {
var childStyle = flattenStyle(this.props.style) || {};
this.setOpacityTo(
childStyle.opacity === undefined ? 1 : childStyle.opacity
childStyle.opacity === undefined ? 1 : childStyle.opacity,
duration
);
},
_opacityFocused: function() {
this.setOpacityTo(this.props.focusedOpacity);
},
_onKeyEnter(e, callback) {
var ENTER = 13
if (e.keyCode === ENTER) {
@@ -166,7 +164,7 @@ var TouchableOpacity = React.createClass({
render: function() {
return (
<Animated.View
<View
accessible={this.props.accessible !== false}
accessibilityLabel={this.props.accessibilityLabel}
accessibilityRole={this.props.accessibilityRole}
@@ -174,8 +172,7 @@ var TouchableOpacity = React.createClass({
style={[
styles.root,
this.props.disabled && styles.disabled,
this.props.style,
{opacity: this.state.anim}
this.props.style
]}
testID={this.props.testID}
onLayout={this.props.onLayout}
@@ -192,7 +189,7 @@ var TouchableOpacity = React.createClass({
tabIndex={this.props.disabled ? null : '0'}
>
{this.props.children}
</Animated.View>
</View>
);
},
});
@@ -200,6 +197,8 @@ var TouchableOpacity = React.createClass({
var styles = StyleSheet.create({
root: {
cursor: 'pointer',
transitionProperty: 'opacity',
transitionDuration: '0.15s',
userSelect: 'none'
},
disabled: {

View File

@@ -22,12 +22,12 @@ var StyleSheet = require('../../apis/StyleSheet');
type Event = Object;
var PRESS_RETENTION_OFFSET = {top: 20, left: 20, right: 20, bottom: 30};
const PRESS_RETENTION_OFFSET = {top: 20, left: 20, right: 20, bottom: 30};
/**
* Do not use unless you have a very good reason. All the elements that
* respond to press should have a visual feedback when touched. This is
* one of the primary reason a "web" app doesn't feel "native".
* one of the primary reasons a "web" app doesn't feel "native".
*
* > **NOTE**: TouchableWithoutFeedback supports only one child
* >
@@ -144,7 +144,7 @@ const TouchableWithoutFeedback = React.createClass({
return this.props.delayPressOut || 0;
},
render: function(): ReactElement<any> {
render: function(): React.Element<any> {
// Note(avik): remove dynamic typecast once Flow has been upgraded
const child = React.Children.only(this.props.children);
let children = child.props.children;
@@ -153,12 +153,6 @@ const TouchableWithoutFeedback = React.createClass({
'TouchableWithoutFeedback does not work well with Text children. Wrap children in a View instead. See ' +
((child._owner && child._owner.getName && child._owner.getName()) || '<unknown>')
);
if (Touchable.TOUCH_TARGET_DEBUG && child.type && child.type.displayName === 'View') {
if (!Array.isArray(children)) {
children = [children];
}
children.push(Touchable.renderDebugView({color: 'red', hitSlop: this.props.hitSlop}));
}
const style = (Touchable.TOUCH_TARGET_DEBUG && child.type && child.type.displayName === 'Text') ?
[
styles.root,

View File

@@ -2,6 +2,7 @@ import BorderPropTypes from '../../propTypes/BorderPropTypes';
import ColorPropType from '../../propTypes/ColorPropType';
import LayoutPropTypes from '../../propTypes/LayoutPropTypes';
import { PropTypes } from 'react';
import ShadowPropTypes from '../../propTypes/ShadowPropTypes';
import TransformPropTypes from '../../propTypes/TransformPropTypes';
const { number, oneOf, string } = PropTypes;
@@ -11,6 +12,7 @@ const hiddenOrVisible = oneOf([ 'hidden', 'visible' ]);
module.exports = process.env.NODE_ENV !== 'production' ? {
...BorderPropTypes,
...LayoutPropTypes,
...ShadowPropTypes,
...TransformPropTypes,
backfaceVisibility: hiddenOrVisible,
backgroundColor: ColorPropType,
@@ -32,7 +34,10 @@ module.exports = process.env.NODE_ENV !== 'production' ? {
outline: string,
overflowX: autoOrHiddenOrVisible,
overflowY: autoOrHiddenOrVisible,
transition: string,
transitionDelay: string,
transitionDuration: string,
transitionProperty: string,
transitionTimingFunction: string,
userSelect: string,
visibility: hiddenOrVisible,
WebkitOverflowScrolling: oneOf([ 'auto', 'touch' ])

View File

@@ -87,12 +87,19 @@ class View extends Component {
render() {
const {
collapsable, // eslint-disable-line
hitSlop, // eslint-disable-line
onLayout, // eslint-disable-line
pointerEvents,
style,
...other
/* eslint-disable */
accessibilityComponentType,
accessibilityTraits,
collapsable,
hitSlop,
onAccessibilityTap,
onLayout,
onMagicTap,
removeClippedSubviews,
/* eslint-enable */
...otherProps
} = this.props;
const flattenedStyle = StyleSheet.flatten(style);
@@ -100,27 +107,24 @@ class View extends Component {
// '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 normalizedEventHandlers = eventHandlerNames.reduce((handlerProps, handlerName) => {
const component = this.context.isInAButtonView ? 'span' : 'div';
eventHandlerNames.reduce((props, handlerName) => {
const handler = this.props[handlerName];
if (typeof handler === 'function') {
handlerProps[handlerName] = this._normalizeEventForHandler(handler, handlerName);
props[handlerName] = this._normalizeEventForHandler(handler, handlerName);
}
return handlerProps;
}, {});
return props;
}, otherProps);
const component = this.context.isInAButtonView ? 'span' : 'div';
const props = {
...other,
...normalizedEventHandlers,
style: [
styles.initial,
style,
needsFlexReset && styles.flexReset,
pointerEventsStyle
]
};
otherProps.style = [
styles.initial,
style,
needsFlexReset && styles.flexReset,
pointerEventsStyle
];
return createDOMElement(component, props);
return createDOMElement(component, otherProps);
}
_normalizeEventForHandler(handler, handlerName) {

View File

@@ -1,27 +1,44 @@
import findNodeHandle from './modules/findNodeHandle';
import { render, unmountComponentAtNode } from 'react/lib/ReactMount';
import ReactDefaultInjection from 'react-dom/lib/ReactDefaultInjection';
import { render, unmountComponentAtNode } from 'react-dom/lib/ReactMount';
ReactDefaultInjection.inject();
// APIs
import I18nManager from './apis/I18nManager';
import Platform from './apis/Platform';
import StyleSheet from './apis/StyleSheet';
// components
import Image from './components/Image';
import Text from './components/Text';
import TextInput from './components/TextInput';
import Touchable from './components/Touchable/Touchable';
import TouchableHighlight from './components/Touchable/TouchableHighlight';
import TouchableOpacity from './components/Touchable/TouchableOpacity';
import TouchableWithoutFeedback from './components/Touchable/TouchableWithoutFeedback';
import View from './components/View';
// modules
import createDOMElement from './modules/createDOMElement';
const ReactNativeCore = {
createDOMElement,
findNodeHandle,
render,
unmountComponentAtNode,
// APIs
I18nManager,
Platform,
StyleSheet,
// components
Image,
Text,
TextInput,
Touchable,
TouchableHighlight,
TouchableOpacity,
TouchableWithoutFeedback,
View
};

View File

@@ -1,15 +1,20 @@
import findNodeHandle from './modules/findNodeHandle';
import { render, unmountComponentAtNode } from 'react/lib/ReactMount';
import ReactDefaultInjection from 'react-dom/lib/ReactDefaultInjection';
import { render, unmountComponentAtNode } from 'react-dom/lib/ReactMount';
ReactDefaultInjection.inject();
// APIs
import Animated from './apis/Animated';
import AppRegistry from './apis/AppRegistry';
import AppState from './apis/AppState';
import AsyncStorage from './apis/AsyncStorage';
import Clipboard from './apis/Clipboard';
import Dimensions from './apis/Dimensions';
import Easing from 'animated/lib/Easing';
import I18nManager from './apis/I18nManager';
import InteractionManager from './apis/InteractionManager';
import Linking from './apis/Linking';
import NetInfo from './apis/NetInfo';
import PanResponder from './apis/PanResponder';
import PixelRatio from './apis/PixelRatio';
@@ -20,6 +25,7 @@ import Vibration from './apis/Vibration';
// components
import ActivityIndicator from './components/ActivityIndicator';
import Button from './components/Button';
import Image from './components/Image';
import ListView from './components/ListView';
import ProgressBar from './components/ProgressBar';
@@ -34,10 +40,10 @@ import TouchableWithoutFeedback from './components/Touchable/TouchableWithoutFee
import View from './components/View';
// modules
import createDOMElement from './modules/createDOMElement';
import NativeModules from './modules/NativeModules';
// propTypes
import ColorPropType from './propTypes/ColorPropType';
import EdgeInsetsPropType from './propTypes/EdgeInsetsPropType';
import PointPropType from './propTypes/PointPropType';
@@ -53,10 +59,12 @@ const ReactNative = {
AppRegistry,
AppState,
AsyncStorage,
Clipboard,
Dimensions,
Easing,
I18nManager,
InteractionManager,
Linking,
NetInfo,
PanResponder,
PixelRatio,
@@ -67,6 +75,7 @@ const ReactNative = {
// components
ActivityIndicator,
Button,
Image,
ListView,
ProgressBar,
@@ -81,6 +90,7 @@ const ReactNative = {
View,
// modules
createDOMElement,
NativeModules,
// propTypes

View File

@@ -0,0 +1,48 @@
let id = 0;
const requests = {};
const ImageLoader = {
abort(requestId: number) {
let image = requests[`${requestId}`];
if (image) {
image.onerror = image.onload = image = null;
delete requests[`${requestId}`];
}
},
getSize(uri, success, failure) {
let complete = false;
const interval = setInterval(callback, 16);
const requestId = ImageLoader.load(uri, callback, callback);
function callback() {
const image = requests[`${requestId}`];
if (image) {
const { naturalHeight, naturalWidth } = image;
if (naturalHeight && naturalWidth) {
success(naturalWidth, naturalHeight);
complete = true;
}
}
if (complete) {
ImageLoader.abort(requestId);
clearInterval(interval);
}
}
},
load(uri, onLoad, onError): number {
id += 1;
const image = new window.Image();
image.onerror = onError;
image.onload = onLoad;
image.src = uri;
requests[`${id}`] = image;
return id;
},
prefetch(uri): Promise {
return new Promise((resolve, reject) => {
ImageLoader.load(uri, resolve, reject);
});
}
};
export default ImageLoader;

View File

@@ -105,6 +105,8 @@ var warning = require('fbjs/lib/warning');
* this.props.onKeyboardDidHide
*/
const emptyObject = {};
var IS_ANIMATING_TOUCH_START_THRESHOLD_MS = 16;
type State = {
@@ -378,7 +380,7 @@ var ScrollResponderMixin = {
if (typeof x === 'number') {
console.warn('`scrollResponderScrollTo(x, y, animated)` is deprecated. Use `scrollResponderScrollTo({x: 5, y: 5, animated: true})` instead.');
} else {
({x, y, animated} = x || {});
({x, y, animated} = x || emptyObject);
}
const node = this.scrollResponderGetScrollableNode()
node.scrollLeft = x || 0

View File

@@ -7,13 +7,15 @@
import emptyFunction from 'fbjs/lib/emptyFunction';
const emptyObject = {};
const applyLayout = (Component) => {
const componentDidMount = Component.prototype.componentDidMount || emptyFunction;
const componentDidUpdate = Component.prototype.componentDidUpdate || emptyFunction;
Component.prototype.componentDidMount = function () {
componentDidMount.call(this);
this._layoutState = {};
this._layoutState = emptyObject;
this._handleLayout();
};

View File

@@ -12,14 +12,7 @@ exports[`modules/createDOMElement prop "accessibilityLiveRegion" 1`] = `
style={Object {}} />
`;
exports[`modules/createDOMElement prop "accessibilityRole" 1`] = `
<header
className=""
role="banner"
style={Object {}} />
`;
exports[`modules/createDOMElement prop "accessibilityRole" 2`] = `
exports[`modules/createDOMElement prop "accessibilityRole" button 1`] = `
<button
className=""
role="button"
@@ -27,6 +20,22 @@ exports[`modules/createDOMElement prop "accessibilityRole" 2`] = `
type="button" />
`;
exports[`modules/createDOMElement prop "accessibilityRole" link and target="_blank" 1`] = `
<a
className=""
rel=" noopener noreferrer"
role="link"
style={Object {}}
target="_blank" />
`;
exports[`modules/createDOMElement prop "accessibilityRole" roles 1`] = `
<header
className=""
role="banner"
style={Object {}} />
`;
exports[`modules/createDOMElement prop "accessible" 1`] = `
<span
className=""

View File

@@ -23,12 +23,21 @@ describe('modules/createDOMElement', () => {
expect(component.toJSON()).toMatchSnapshot();
});
test('prop "accessibilityRole"', () => {
const accessibilityRole = 'banner';
let component = renderer.create(createDOMElement('span', { accessibilityRole }));
expect(component.toJSON()).toMatchSnapshot();
component = renderer.create(createDOMElement('span', { accessibilityRole: 'button' }));
expect(component.toJSON()).toMatchSnapshot();
describe('prop "accessibilityRole"', () => {
test('roles', () => {
const component = renderer.create(createDOMElement('span', { accessibilityRole: 'banner' }));
expect(component.toJSON()).toMatchSnapshot();
});
test('button', () => {
const component = renderer.create(createDOMElement('span', { accessibilityRole: 'button' }));
expect(component.toJSON()).toMatchSnapshot();
});
test('link and target="_blank"', () => {
const component = renderer.create(createDOMElement('span', { accessibilityRole: 'link', target: '_blank' }));
expect(component.toJSON()).toMatchSnapshot();
});
});
test('prop "accessible"', () => {

View File

@@ -1,6 +1,8 @@
import React from 'react';
import StyleSheet from '../../apis/StyleSheet';
const emptyObject = {};
const roleComponents = {
article: 'article',
banner: 'header',
@@ -17,7 +19,7 @@ const roleComponents = {
region: 'section'
};
const createDOMElement = (component, rnProps = {}) => {
const createDOMElement = (component, rnProps = emptyObject) => {
const {
accessibilityLabel,
accessibilityLiveRegion,
@@ -25,15 +27,14 @@ const createDOMElement = (component, rnProps = {}) => {
accessible = true,
testID,
type,
...other
...domProps
} = rnProps;
const accessibilityComponent = accessibilityRole && roleComponents[accessibilityRole];
const Component = accessibilityComponent || component;
const domProps = {
...other,
...StyleSheet.resolve(other)
};
Object.assign(domProps, StyleSheet.resolve(domProps));
if (!accessible) { domProps['aria-hidden'] = true; }
if (accessibilityLabel) { domProps['aria-label'] = accessibilityLabel; }
if (accessibilityLiveRegion) { domProps['aria-live'] = accessibilityLiveRegion; }
@@ -42,6 +43,8 @@ const createDOMElement = (component, rnProps = {}) => {
domProps.role = accessibilityRole;
if (accessibilityRole === 'button') {
domProps.type = 'button';
} else if (accessibilityRole === 'link' && domProps.target === '_blank') {
domProps.rel = `${domProps.rel || ''} noopener noreferrer`;
}
}
if (type) { domProps.type = type; }

View File

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

View File

@@ -1,22 +1,19 @@
// based on https://github.com/facebook/react/pull/4303/files
import EventConstants from 'react/lib/EventConstants';
import EventPluginRegistry from 'react/lib/EventPluginRegistry';
import EventPluginRegistry from 'react-dom/lib/EventPluginRegistry';
import normalizeNativeEvent from './normalizeNativeEvent';
import ResponderEventPlugin from 'react/lib/ResponderEventPlugin';
import ResponderTouchHistoryStore from 'react/lib/ResponderTouchHistoryStore';
import ResponderEventPlugin from 'react-dom/lib/ResponderEventPlugin';
import ResponderTouchHistoryStore from 'react-dom/lib/ResponderTouchHistoryStore';
const {
topMouseDown,
topMouseMove,
topMouseUp,
topScroll,
topSelectionChange,
topTouchCancel,
topTouchEnd,
topTouchMove,
topTouchStart
} = EventConstants.topLevelTypes;
const topMouseDown = 'topMouseDown';
const topMouseMove = 'topMouseMove';
const topMouseUp = 'topMouseUp';
const topScroll = 'topScroll';
const topSelectionChange = 'topSelectionChange';
const topTouchCancel = 'topTouchCancel';
const topTouchEnd = 'topTouchEnd';
const topTouchMove = 'topTouchMove';
const topTouchStart = 'topTouchStart';
const endDependencies = [ topTouchCancel, topTouchEnd, topMouseUp ];
const moveDependencies = [ topTouchMove, topMouseMove ];

View File

@@ -1,4 +1,4 @@
const CSS_UNIT_RE = /^[+-]?\d*(?:\.\d+)?(?:[Ee][+-]?\d+)?(\w*)/;
const CSS_UNIT_RE = /^[+-]?\d*(?:\.\d+)?(?:[Ee][+-]?\d+)?(%|\w*)/;
const getUnit = (str) => str.match(CSS_UNIT_RE)[1];

View File

@@ -1,5 +1,7 @@
const emptyArray = [];
// Mobile Safari re-uses touch objects, so we copy the properties we want and normalize the identifier
const normalizeTouches = (touches = []) => Array.prototype.slice.call(touches).map((touch) => {
const normalizeTouches = (touches = emptyArray) => Array.prototype.slice.call(touches).map((touch) => {
const identifier = touch.identifier > 20 ? (touch.identifier % 20) : touch.identifier;
const rect = touch.target && touch.target.getBoundingClientRect();
@@ -59,21 +61,23 @@ function normalizeTouchEvent(nativeEvent) {
}
function normalizeMouseEvent(nativeEvent) {
const touches = [ {
_normalized: true,
clientX: nativeEvent.clientX,
clientY: nativeEvent.clientY,
force: nativeEvent.force,
locationX: nativeEvent.clientX,
locationY: nativeEvent.clientY,
identifier: 0,
pageX: nativeEvent.pageX,
pageY: nativeEvent.pageY,
screenX: nativeEvent.screenX,
screenY: nativeEvent.screenY,
target: nativeEvent.target,
timestamp: Date.now()
} ];
const touches = [
{
_normalized: true,
clientX: nativeEvent.clientX,
clientY: nativeEvent.clientY,
force: nativeEvent.force,
locationX: nativeEvent.clientX,
locationY: nativeEvent.clientY,
identifier: 0,
pageX: nativeEvent.pageX,
pageY: nativeEvent.pageY,
screenX: nativeEvent.screenX,
screenY: nativeEvent.screenY,
target: nativeEvent.target,
timestamp: Date.now()
}
];
return {
_normalized: true,
changedTouches: touches,
@@ -87,7 +91,7 @@ function normalizeMouseEvent(nativeEvent) {
stopPropagation: nativeEvent.stopPropagation.bind(nativeEvent),
target: nativeEvent.target,
timestamp: touches[0].timestamp,
touches: (nativeEvent.type === 'mouseup') ? [] : touches
touches: (nativeEvent.type === 'mouseup') ? emptyArray : touches
};
}

View File

@@ -14,7 +14,7 @@ import { PropTypes } from 'react'
var colorPropType = function(isRequired, props, propName, componentName, location, propFullName) {
var normalizeColor = require('../modules/normalizeColor');
var ReactPropTypeLocationNames = require('react/lib/ReactPropTypeLocationNames');
var ReactPropTypeLocationNames = require('react-dom/lib/ReactPropTypeLocationNames');
var color = props[propName];
if (color === undefined || color === null) {
if (isRequired) {

View File

@@ -0,0 +1,18 @@
import ColorPropType from './ColorPropType';
import { PropTypes } from 'react';
const { number, oneOfType, shape, string } = PropTypes;
const numberOrString = oneOfType([ number, string ]);
const ShadowPropTypes = {
shadowColor: ColorPropType,
shadowOffset: shape({
width: numberOrString,
height: numberOrString
}),
shadowOpacity: number,
shadowRadius: numberOrString,
shadowSpread: numberOrString
};
module.exports = ShadowPropTypes;

View File

@@ -20,22 +20,19 @@ const TextPropTypes = process.env.NODE_ENV !== 'production' ? {
textAlign: TextAlignPropType,
textAlignVertical: oneOf([ 'auto', 'bottom', 'center', 'top' ]),
textDecorationLine: string,
/* @platform web */
textOverflow: string,
/* @platform web */
textRendering: oneOf([ 'auto', 'geometricPrecision', 'optimizeLegibility', 'optimizeSpeed' ]),
textShadowColor: ColorPropType,
textShadowOffset: ShadowOffsetPropType,
textShadowRadius: number,
/* @platform web */
textTransform: oneOf([ 'capitalize', 'lowercase', 'none', 'uppercase' ]),
/* @platform web */
unicodeBidi: oneOf([ 'normal', 'bidi-override', 'embed', 'isolate', 'isolate-override', 'plaintext' ]),
/* @platform web */
whiteSpace: string,
/* @platform web */
wordWrap: string,
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,

View File

@@ -12,8 +12,8 @@
*/
import invariant from 'fbjs/lib/invariant'
import ReactPropTypeLocationNames from 'react/lib/ReactPropTypeLocationNames'
import ReactPropTypesSecret from 'react/lib/ReactPropTypesSecret'
import ReactPropTypeLocationNames from 'react-dom/lib/ReactPropTypeLocationNames'
import ReactPropTypesSecret from 'react-dom/lib/ReactPropTypesSecret'
function createStrictShapeTypeChecker(
shapeTypes: {[key: string]: ReactPropsCheckType}

View File

@@ -34,7 +34,7 @@ module.exports = {
// https://github.com/animatedjs/animated/issues/40
new webpack.NormalModuleReplacementPlugin(
/es6-set/,
path.join(__dirname, 'src/modules/polyfills/Set.js')
path.join(__dirname, 'dist/modules/polyfills/Set.js')
),
new webpack.optimize.OccurenceOrderPlugin(),
new webpack.optimize.UglifyJsPlugin({

313
yarn.lock
View File

@@ -1,5 +1,7 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
"@kadira/react-split-pane@^1.4.0":
version "1.4.7"
resolved "https://registry.yarnpkg.com/@kadira/react-split-pane/-/react-split-pane-1.4.7.tgz#6d753d4a9fe62fe82056e323a6bcef7f026972b5"
@@ -96,6 +98,10 @@
webpack-dev-middleware "^1.6.0"
webpack-hot-middleware "^2.13.2"
Base64@~0.2.0:
version "0.2.1"
resolved "https://registry.yarnpkg.com/Base64/-/Base64-0.2.1.tgz#ba3a4230708e186705065e66babdd4c35cf60028"
abab@^1.0.0:
version "1.0.3"
resolved "https://registry.yarnpkg.com/abab/-/abab-1.0.3.tgz#b81de5f7274ec4e756d797cd834f303642724e5d"
@@ -316,14 +322,14 @@ async-each@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d"
async@1.x, async@^1.3.0, async@^1.4.0, async@^1.4.2:
version "1.5.2"
resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a"
async@^0.9.0:
version "0.9.2"
resolved "https://registry.yarnpkg.com/async/-/async-0.9.2.tgz#aea74d5e61c1f899613bf64bda66d4c78f2fd17d"
async@^1.3.0, async@^1.4.0, async@^1.4.2, async@1.x:
version "1.5.2"
resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a"
async@~0.2.6:
version "0.2.10"
resolved "https://registry.yarnpkg.com/async/-/async-0.2.10.tgz#b6bbe0b0674b9d719708ca38de8c237cb526c3d1"
@@ -628,6 +634,14 @@ babel-plugin-transform-async-to-generator@^6.16.0, babel-plugin-transform-async-
babel-plugin-syntax-async-functions "^6.8.0"
babel-runtime "^6.0.0"
babel-plugin-transform-class-properties@6.16.0:
version "6.16.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-class-properties/-/babel-plugin-transform-class-properties-6.16.0.tgz#969bca24d34e401d214f36b8af5c1346859bc904"
dependencies:
babel-helper-function-name "^6.8.0"
babel-plugin-syntax-class-properties "^6.8.0"
babel-runtime "^6.9.1"
babel-plugin-transform-class-properties@^6.5.0:
version "6.19.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-class-properties/-/babel-plugin-transform-class-properties-6.19.0.tgz#1274b349abaadc835164e2004f4a2444a2788d5f"
@@ -637,14 +651,6 @@ babel-plugin-transform-class-properties@^6.5.0:
babel-runtime "^6.9.1"
babel-template "^6.15.0"
babel-plugin-transform-class-properties@6.16.0:
version "6.16.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-class-properties/-/babel-plugin-transform-class-properties-6.16.0.tgz#969bca24d34e401d214f36b8af5c1346859bc904"
dependencies:
babel-helper-function-name "^6.8.0"
babel-plugin-syntax-class-properties "^6.8.0"
babel-runtime "^6.9.1"
babel-plugin-transform-es2015-arrow-functions@^6.3.13, babel-plugin-transform-es2015-arrow-functions@^6.5.0:
version "6.8.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.8.0.tgz#5b63afc3181bdc9a8c4d481b5a4f3f7d7fef3d9d"
@@ -689,18 +695,18 @@ babel-plugin-transform-es2015-computed-properties@^6.3.13, babel-plugin-transfor
babel-runtime "^6.0.0"
babel-template "^6.8.0"
babel-plugin-transform-es2015-destructuring@^6.18.0, babel-plugin-transform-es2015-destructuring@^6.5.0, babel-plugin-transform-es2015-destructuring@^6.6.0:
version "6.19.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.19.0.tgz#ff1d911c4b3f4cab621bd66702a869acd1900533"
dependencies:
babel-runtime "^6.9.0"
babel-plugin-transform-es2015-destructuring@6.16.0:
version "6.16.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.16.0.tgz#050fe0866f5d53b36062ee10cdf5bfe64f929627"
dependencies:
babel-runtime "^6.9.0"
babel-plugin-transform-es2015-destructuring@^6.18.0, babel-plugin-transform-es2015-destructuring@^6.5.0, babel-plugin-transform-es2015-destructuring@^6.6.0:
version "6.19.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.19.0.tgz#ff1d911c4b3f4cab621bd66702a869acd1900533"
dependencies:
babel-runtime "^6.9.0"
babel-plugin-transform-es2015-duplicate-keys@^6.6.0:
version "6.8.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.8.0.tgz#fd8f7f7171fc108cc1c70c3164b9f15a81c25f7d"
@@ -768,17 +774,6 @@ babel-plugin-transform-es2015-object-super@^6.3.13:
babel-helper-replace-supers "^6.8.0"
babel-runtime "^6.0.0"
babel-plugin-transform-es2015-parameters@^6.18.0, babel-plugin-transform-es2015-parameters@^6.5.0, babel-plugin-transform-es2015-parameters@^6.6.0:
version "6.18.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.18.0.tgz#9b2cfe238c549f1635ba27fc1daa858be70608b1"
dependencies:
babel-helper-call-delegate "^6.18.0"
babel-helper-get-function-arity "^6.18.0"
babel-runtime "^6.9.0"
babel-template "^6.16.0"
babel-traverse "^6.18.0"
babel-types "^6.18.0"
babel-plugin-transform-es2015-parameters@6.17.0:
version "6.17.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.17.0.tgz#e06d30cef897f46adb4734707bbe128a0d427d58"
@@ -790,6 +785,17 @@ babel-plugin-transform-es2015-parameters@6.17.0:
babel-traverse "^6.16.0"
babel-types "^6.16.0"
babel-plugin-transform-es2015-parameters@^6.18.0, babel-plugin-transform-es2015-parameters@^6.5.0, babel-plugin-transform-es2015-parameters@^6.6.0:
version "6.18.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.18.0.tgz#9b2cfe238c549f1635ba27fc1daa858be70608b1"
dependencies:
babel-helper-call-delegate "^6.18.0"
babel-helper-get-function-arity "^6.18.0"
babel-runtime "^6.9.0"
babel-template "^6.16.0"
babel-traverse "^6.18.0"
babel-types "^6.18.0"
babel-plugin-transform-es2015-shorthand-properties@^6.18.0, babel-plugin-transform-es2015-shorthand-properties@^6.3.13, babel-plugin-transform-es2015-shorthand-properties@^6.5.0:
version "6.18.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.18.0.tgz#e2ede3b7df47bf980151926534d1dd0cbea58f43"
@@ -852,16 +858,16 @@ babel-plugin-transform-object-assign@^6.5.0:
dependencies:
babel-runtime "^6.0.0"
babel-plugin-transform-object-rest-spread@^6.5.0:
version "6.19.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.19.0.tgz#f6ac428ee3cb4c6aa00943ed1422ce813603b34c"
babel-plugin-transform-object-rest-spread@6.16.0:
version "6.16.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.16.0.tgz#db441d56fffc1999052fdebe2e2f25ebd28e36a9"
dependencies:
babel-plugin-syntax-object-rest-spread "^6.8.0"
babel-runtime "^6.0.0"
babel-plugin-transform-object-rest-spread@6.16.0:
version "6.16.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.16.0.tgz#db441d56fffc1999052fdebe2e2f25ebd28e36a9"
babel-plugin-transform-object-rest-spread@^6.5.0:
version "6.19.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.19.0.tgz#f6ac428ee3cb4c6aa00943ed1422ce813603b34c"
dependencies:
babel-plugin-syntax-object-rest-spread "^6.8.0"
babel-runtime "^6.0.0"
@@ -878,14 +884,14 @@ babel-plugin-transform-react-display-name@^6.3.13, babel-plugin-transform-react-
dependencies:
babel-runtime "^6.0.0"
babel-plugin-transform-react-jsx-self@^6.11.0, babel-plugin-transform-react-jsx-self@6.11.0:
babel-plugin-transform-react-jsx-self@6.11.0, babel-plugin-transform-react-jsx-self@^6.11.0:
version "6.11.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-jsx-self/-/babel-plugin-transform-react-jsx-self-6.11.0.tgz#605c9450c1429f97a930f7e1dfe3f0d9d0dbd0f4"
dependencies:
babel-plugin-syntax-jsx "^6.8.0"
babel-runtime "^6.9.0"
babel-plugin-transform-react-jsx-source@^6.3.13, babel-plugin-transform-react-jsx-source@^6.5.0, babel-plugin-transform-react-jsx-source@6.9.0:
babel-plugin-transform-react-jsx-source@6.9.0, babel-plugin-transform-react-jsx-source@^6.3.13, babel-plugin-transform-react-jsx-source@^6.5.0:
version "6.9.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-jsx-source/-/babel-plugin-transform-react-jsx-source-6.9.0.tgz#af684a05c2067a86e0957d4f343295ccf5dccf00"
dependencies:
@@ -904,7 +910,7 @@ 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-regenerator@^6.16.0, babel-plugin-transform-regenerator@^6.5.0, babel-plugin-transform-regenerator@^6.6.0, babel-plugin-transform-regenerator@6.16.1:
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"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.16.1.tgz#a75de6b048a14154aae14b0122756c5bed392f59"
dependencies:
@@ -1098,16 +1104,16 @@ babel-register@^6.18.0:
mkdirp "^0.5.1"
source-map-support "^0.4.2"
babel-runtime@^6.0.0, babel-runtime@^6.11.6, babel-runtime@^6.18.0, babel-runtime@^6.5.0, babel-runtime@^6.9.0, babel-runtime@^6.9.1, babel-runtime@^6.9.2, babel-runtime@6.x.x:
version "6.18.0"
resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.18.0.tgz#0f4177ffd98492ef13b9f823e9994a02584c9078"
babel-runtime@6.11.6:
version "6.11.6"
resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.11.6.tgz#6db707fef2d49c49bfa3cb64efdb436b518b8222"
dependencies:
core-js "^2.4.0"
regenerator-runtime "^0.9.5"
babel-runtime@6.11.6:
version "6.11.6"
resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.11.6.tgz#6db707fef2d49c49bfa3cb64efdb436b518b8222"
babel-runtime@6.x.x, babel-runtime@^6.0.0, babel-runtime@^6.11.6, babel-runtime@^6.18.0, babel-runtime@^6.5.0, babel-runtime@^6.9.0, babel-runtime@^6.9.1, babel-runtime@^6.9.2:
version "6.18.0"
resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.18.0.tgz#0f4177ffd98492ef13b9f823e9994a02584c9078"
dependencies:
core-js "^2.4.0"
regenerator-runtime "^0.9.5"
@@ -1161,17 +1167,13 @@ balanced-match@~0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.1.0.tgz#b504bd05869b39259dd0c5efc35d843176dccc4a"
base64-js@^1.0.2:
version "1.2.0"
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.2.0.tgz#a39992d723584811982be5e290bb6a53d86700f1"
base64-js@0.0.8:
version "0.0.8"
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-0.0.8.tgz#1101e9544f4a76b1bc3b26d452ca96d7a35e7978"
Base64@~0.2.0:
version "0.2.1"
resolved "https://registry.yarnpkg.com/Base64/-/Base64-0.2.1.tgz#ba3a4230708e186705065e66babdd4c35cf60028"
base64-js@^1.0.2:
version "1.2.0"
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.2.0.tgz#a39992d723584811982be5e290bb6a53d86700f1"
bcrypt-pbkdf@^1.0.0:
version "1.0.0"
@@ -1505,14 +1507,14 @@ colormin@^1.0.5:
css-color-names "0.0.4"
has "^1.0.1"
colors@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63"
colors@1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b"
colors@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63"
combined-stream@^1.0.5, combined-stream@~1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.5.tgz#938370a57b4a51dea2c77c15d5c5fdf895164009"
@@ -1733,7 +1735,7 @@ csso@~2.2.1:
clap "^1.0.9"
source-map "^0.5.3"
"cssom@>= 0.3.0 < 0.4.0", cssom@0.3.x:
cssom@0.3.x, "cssom@>= 0.3.0 < 0.4.0":
version "0.3.1"
resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.1.tgz#c9e37ef2490e64f6d1baa10fda852257082c25d3"
@@ -1765,14 +1767,14 @@ dashdash@^1.12.0:
dependencies:
assert-plus "^1.0.0"
date-now@^0.1.4:
version "0.1.4"
resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b"
date-now@1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/date-now/-/date-now-1.0.1.tgz#bb7d086438debe4182a485fb3df3fbfb99d6153c"
date-now@^0.1.4:
version "0.1.4"
resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b"
debounce:
version "1.0.0"
resolved "https://registry.yarnpkg.com/debounce/-/debounce-1.0.0.tgz#0948af513d2e4ce407916f8506a423d3f9cf72d8"
@@ -1877,7 +1879,7 @@ doctrine@^1.2.0, doctrine@^1.2.2:
esutils "^2.0.2"
isarray "^1.0.0"
dom-serializer@~0.1.0, dom-serializer@0:
dom-serializer@0, dom-serializer@~0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.1.0.tgz#073c697546ce0780ce23be4a28e293e40bc30c82"
dependencies:
@@ -1892,7 +1894,7 @@ domain-browser@^1.1.1:
version "1.1.7"
resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.1.7.tgz#867aa4b093faa05f1de08c06f4d7b21fdf8698bc"
domelementtype@^1.3.0, domelementtype@1:
domelementtype@1, domelementtype@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.0.tgz#b17aed82e8ab59e52dd9c19b1756e0fc187204c2"
@@ -1906,7 +1908,7 @@ domhandler@^2.3.0:
dependencies:
domelementtype "1"
domutils@^1.5.1, domutils@1.5.1:
domutils@1.5.1, domutils@^1.5.1:
version "1.5.1"
resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.5.1.tgz#dcd8488a26f563d61079e48c9f7b7e32373682cf"
dependencies:
@@ -1984,7 +1986,7 @@ enzyme@^2.4.1:
object.values "^1.0.3"
uuid "^2.0.3"
errno@^0.1.3, "errno@>=0.1.1 <0.2.0-0":
"errno@>=0.1.1 <0.2.0-0", errno@^0.1.3:
version "0.1.4"
resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.4.tgz#b896e23a9e5e8ba33871fc996abd3635fc9a1c7d"
dependencies:
@@ -2057,7 +2059,7 @@ es6-shim@^0.35.1:
version "0.35.1"
resolved "https://registry.yarnpkg.com/es6-shim/-/es6-shim-0.35.1.tgz#a23524009005b031ab4a352ac196dfdfd1144ab7"
es6-symbol@~3.1, es6-symbol@~3.1.0, es6-symbol@3:
es6-symbol@3, es6-symbol@~3.1, es6-symbol@~3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.0.tgz#94481c655e7a7cad82eba832d97d5433496d7ffa"
dependencies:
@@ -2081,7 +2083,7 @@ escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
escodegen@^1.6.1, escodegen@1.8.x:
escodegen@1.8.x, escodegen@^1.6.1:
version "1.8.1"
resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.8.1.tgz#5a5b53af4693110bebb0867aa3430dd3b70a1018"
dependencies:
@@ -2166,7 +2168,7 @@ espree@^3.3.1:
acorn "^4.0.1"
acorn-jsx "^3.0.0"
esprima@^2.6.0, esprima@^2.7.1, esprima@2.7.x:
esprima@2.7.x, esprima@^2.6.0, esprima@^2.7.1:
version "2.7.3"
resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581"
@@ -2301,7 +2303,7 @@ fb-watchman@^1.8.0, fb-watchman@^1.9.0:
dependencies:
bser "^1.0.2"
fbjs@^0.8.4:
fbjs@^0.8.1, fbjs@^0.8.4:
version "0.8.6"
resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.6.tgz#7eb67d6986b2d5007a9b6e92e0e7cb6f75cad290"
dependencies:
@@ -2536,7 +2538,7 @@ glob-parent@^2.0.0:
dependencies:
is-glob "^2.0.0"
glob@^5.0.15, glob@^5.0.5, glob@5.x:
glob@5.x, glob@^5.0.15, glob@^5.0.5:
version "5.0.15"
resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1"
dependencies:
@@ -2667,7 +2669,7 @@ hoek@2.x.x:
version "2.16.3"
resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed"
hoist-non-react-statics@^1.2.0, hoist-non-react-statics@1.x.x:
hoist-non-react-statics@1.x.x, hoist-non-react-statics@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-1.2.0.tgz#aa448cf0986d55cc40773b17174b7dd066cb7cfb"
@@ -2738,14 +2740,14 @@ hyphenate-style-name@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/hyphenate-style-name/-/hyphenate-style-name-1.0.2.tgz#31160a36930adaf1fc04c6074f7eb41465d4ec4b"
iconv-lite@^0.4.13, iconv-lite@~0.4.13:
version "0.4.15"
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.15.tgz#fe265a218ac6a57cfe854927e9d04c19825eddeb"
iconv-lite@0.4.13:
version "0.4.13"
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.13.tgz#1f88aba4ab0b1508e8312acc39345f36e992e2f2"
iconv-lite@^0.4.13, iconv-lite@~0.4.13:
version "0.4.15"
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.15.tgz#fe265a218ac6a57cfe854927e9d04c19825eddeb"
icss-replace-symbols@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/icss-replace-symbols/-/icss-replace-symbols-1.0.2.tgz#cb0b6054eb3af6edc9ab1d62d01933e2d4c8bfa5"
@@ -2791,7 +2793,7 @@ inflight@^1.0.4:
once "^1.3.0"
wrappy "1"
inherits@^2.0.1, inherits@~2.0.0, inherits@~2.0.1, inherits@2, inherits@2.0.3:
inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@~2.0.0, inherits@~2.0.1:
version "2.0.3"
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
@@ -2836,7 +2838,7 @@ interpret@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.0.1.tgz#d579fb7f693b858004947af39fa0db49f795602c"
invariant@^2.2.0, invariant@2.x.x:
invariant@2.x.x, invariant@^2.2.0:
version "2.2.2"
resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.2.tgz#9e1f56ac0acdb6bf303306f338be3b204ae60360"
dependencies:
@@ -3031,14 +3033,14 @@ is-utf8@^0.2.0:
version "0.2.1"
resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72"
isarray@^1.0.0, isarray@~1.0.0, isarray@1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
isarray@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf"
isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
isexe@^1.1.1:
version "1.1.2"
resolved "https://registry.yarnpkg.com/isexe/-/isexe-1.1.2.tgz#36f3e22e60750920f5e7241a476a8c6a42275ad0"
@@ -3345,7 +3347,7 @@ js-tokens@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-2.0.0.tgz#79903f5563ee778cc1162e6dcf1a0027c97f9cb5"
js-yaml@^3.4.3, js-yaml@^3.5.1, js-yaml@3.x:
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"
dependencies:
@@ -3484,7 +3486,7 @@ load-json-file@^1.0.0:
pinkie-promise "^2.0.0"
strip-bom "^2.0.0"
loader-utils@^0.2.11, loader-utils@^0.2.16, loader-utils@^0.2.7, loader-utils@~0.2.2, loader-utils@~0.2.5, loader-utils@0.2.x:
loader-utils@0.2.x, loader-utils@^0.2.11, loader-utils@^0.2.16, loader-utils@^0.2.7, loader-utils@~0.2.2, loader-utils@~0.2.5:
version "0.2.16"
resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-0.2.16.tgz#f08632066ed8282835dff88dfb52704765adee6d"
dependencies:
@@ -3675,7 +3677,7 @@ lodash.words@^3.0.0:
dependencies:
lodash._root "^3.0.0"
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.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:
version "4.17.2"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.2.tgz#34a3055babe04ce42467b607d700072c7ff6bf42"
@@ -3812,21 +3814,21 @@ mime-types@^2.1.12, mime-types@~2.1.11, mime-types@~2.1.13, mime-types@~2.1.7:
dependencies:
mime-db "~1.25.0"
mime@^1.3.4, mime@1.3.4:
version "1.3.4"
resolved "https://registry.yarnpkg.com/mime/-/mime-1.3.4.tgz#115f9e3b6b3daf2959983cb38f149a2d40eb5d53"
mime@1.2.x:
version "1.2.11"
resolved "https://registry.yarnpkg.com/mime/-/mime-1.2.11.tgz#58203eed86e3a5ef17aed2b7d9ebd47f0a60dd10"
mime@1.3.4, mime@^1.3.4:
version "1.3.4"
resolved "https://registry.yarnpkg.com/mime/-/mime-1.3.4.tgz#115f9e3b6b3daf2959983cb38f149a2d40eb5d53"
min-document@^2.19.0:
version "2.19.0"
resolved "https://registry.yarnpkg.com/min-document/-/min-document-2.19.0.tgz#7bd282e3f5842ed295bb748cdd9f1ffa2c824685"
dependencies:
dom-walk "^0.1.0"
minimatch@^3.0.0, minimatch@^3.0.2, "minimatch@2 || 3":
"minimatch@2 || 3", minimatch@^3.0.0, minimatch@^3.0.2:
version "3.0.3"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.3.tgz#2a4e4090b96b2db06a9d7df01055a62a77c9b774"
dependencies:
@@ -3838,19 +3840,15 @@ minimatch@2.x:
dependencies:
brace-expansion "^1.0.0"
minimist@0.0.8, minimist@~0.0.1:
version "0.0.8"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
minimist@~0.0.1:
version "0.0.10"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf"
minimist@0.0.8:
version "0.0.8"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
mkdirp@^0.5.0, mkdirp@^0.5.1, "mkdirp@>=0.5 0", mkdirp@~0.5.0, mkdirp@~0.5.1, mkdirp@0.5.x:
mkdirp@0.5.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1:
version "0.5.1"
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
dependencies:
@@ -4009,7 +4007,7 @@ nomnom@^1.8.1:
chalk "~0.4.0"
underscore "~1.6.0"
nopt@~3.0.6, nopt@3.x:
nopt@3.x, nopt@~3.0.6:
version "3.0.6"
resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9"
dependencies:
@@ -4130,7 +4128,7 @@ on-finished@~2.3.0:
dependencies:
ee-first "1.1.1"
once@^1.3.0, once@1.x:
once@1.x, once@^1.3.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
dependencies:
@@ -4625,26 +4623,26 @@ prr@~0.0.0:
version "0.0.0"
resolved "https://registry.yarnpkg.com/prr/-/prr-0.0.0.tgz#1a84b85908325501411853d0081ee3fa86e2926a"
punycode@^1.2.4, punycode@^1.4.1:
version "1.4.1"
resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e"
punycode@1.3.2:
version "1.3.2"
resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d"
punycode@^1.2.4, punycode@^1.4.1:
version "1.4.1"
resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e"
q@^1.1.2:
version "1.4.1"
resolved "https://registry.yarnpkg.com/q/-/q-1.4.1.tgz#55705bcd93c5f3673530c2c2cbc0c2b3addc286e"
qs@^6.1.0, qs@^6.2.0, qs@~6.3.0:
version "6.3.0"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.3.0.tgz#f403b264f23bc01228c74131b407f18d5ea5d442"
qs@6.2.0:
version "6.2.0"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.2.0.tgz#3b7848c03c2dece69a9522b0fae8c4126d745f3b"
qs@^6.1.0, qs@^6.2.0, qs@~6.3.0:
version "6.3.0"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.3.0.tgz#f403b264f23bc01228c74131b407f18d5ea5d442"
query-string@^4.1.0:
version "4.2.3"
resolved "https://registry.yarnpkg.com/query-string/-/query-string-4.2.3.tgz#9f27273d207a25a8ee4c7b8c74dcd45d556db822"
@@ -4656,7 +4654,7 @@ querystring-es3@~0.2.0:
version "0.2.1"
resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73"
querystring@^0.2.0, querystring@0.2.0:
querystring@0.2.0, querystring@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620"
@@ -4680,9 +4678,9 @@ rc@^1.0.1, rc@^1.1.6, rc@~1.1.6:
minimist "^1.2.0"
strip-json-comments "~1.0.4"
react-addons-test-utils@~15.3.2:
version "15.3.2"
resolved "https://registry.yarnpkg.com/react-addons-test-utils/-/react-addons-test-utils-15.3.2.tgz#c09a44f583425a4a9c1b38444d7a6c3e6f0f41f6"
react-addons-test-utils@~15.4.1:
version "15.4.1"
resolved "https://registry.yarnpkg.com/react-addons-test-utils/-/react-addons-test-utils-15.4.1.tgz#1e4caab151bf27cce26df5f9cb714f4fd8359ae1"
react-deep-force-update@^1.0.0:
version "1.0.1"
@@ -4700,9 +4698,13 @@ react-docgen@^2.12.1:
nomnom "^1.8.1"
recast "^0.11.5"
react-dom@~15.3.2:
version "15.3.2"
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-15.3.2.tgz#c46b0aa5380d7b838e7a59c4a7beff2ed315531f"
react-dom@~15.4.1:
version "15.4.1"
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-15.4.1.tgz#d54c913261aaedb17adc20410d029dcc18a1344a"
dependencies:
fbjs "^0.8.1"
loose-envify "^1.1.0"
object-assign "^4.1.0"
react-fuzzy@^0.3.3:
version "0.3.3"
@@ -4767,9 +4769,9 @@ react-stubber@^1.0.0:
dependencies:
babel-runtime "^6.5.0"
react-test-renderer@~15.3.2:
version "15.3.2"
resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-15.3.2.tgz#d8f083d37d2d41e97bbdc26a1dd9282f0baf7857"
react-test-renderer@~15.4.1:
version "15.4.1"
resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-15.4.1.tgz#e38cd7057868d4a655d3764689735b4b97260706"
react-textarea-autosize@^4.0.4:
version "4.0.5"
@@ -4786,9 +4788,9 @@ react-transform-hmr@^1.0.4:
global "^4.3.0"
react-proxy "^1.1.7"
react@~15.3.2:
version "15.3.2"
resolved "https://registry.yarnpkg.com/react/-/react-15.3.2.tgz#a7bccd2fee8af126b0317e222c28d1d54528d09e"
react@~15.4.1:
version "15.4.1"
resolved "https://registry.yarnpkg.com/react/-/react-15.4.1.tgz#498e918602677a3983cd0fd206dfe700389a0dd6"
dependencies:
fbjs "^0.8.4"
loose-envify "^1.1.0"
@@ -4825,30 +4827,7 @@ readable-stream@^1.0.27-1, readable-stream@^1.1.13:
isarray "0.0.1"
string_decoder "~0.10.x"
readable-stream@^2.0.0, "readable-stream@^2.0.0 || ^1.1.13", readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.5:
version "2.2.2"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.2.2.tgz#a9e6fec3c7dda85f8bb1b3ba7028604556fc825e"
dependencies:
buffer-shims "^1.0.0"
core-util-is "~1.0.0"
inherits "~2.0.1"
isarray "~1.0.0"
process-nextick-args "~1.0.6"
string_decoder "~0.10.x"
util-deprecate "~1.0.1"
readable-stream@~2.0.0:
version "2.0.6"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.0.6.tgz#8f90341e68a53ccc928788dacfcd11b36eb9b78e"
dependencies:
core-util-is "~1.0.0"
inherits "~2.0.1"
isarray "~1.0.0"
process-nextick-args "~1.0.6"
string_decoder "~0.10.x"
util-deprecate "~1.0.1"
readable-stream@~2.1.4:
readable-stream@^2.0.0, "readable-stream@^2.0.0 || ^1.1.13", readable-stream@^2.0.5, readable-stream@~2.1.4:
version "2.1.5"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.1.5.tgz#66fa8b720e1438b364681f2ad1a63c618448c9d0"
dependencies:
@@ -4860,6 +4839,17 @@ readable-stream@~2.1.4:
string_decoder "~0.10.x"
util-deprecate "~1.0.1"
readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@~2.0.0:
version "2.0.6"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.0.6.tgz#8f90341e68a53ccc928788dacfcd11b36eb9b78e"
dependencies:
core-util-is "~1.0.0"
inherits "~2.0.1"
isarray "~1.0.0"
process-nextick-args "~1.0.6"
string_decoder "~0.10.x"
util-deprecate "~1.0.1"
readdirp@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.1.0.tgz#4ed0ad060df3073300c48440373f72d1cc642d78"
@@ -5043,7 +5033,7 @@ resolve-from@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226"
resolve@^1.1.6, resolve@1.1.7, resolve@1.1.x:
resolve@1.1.7, resolve@1.1.x, resolve@^1.1.6:
version "1.1.7"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b"
@@ -5060,7 +5050,7 @@ right-align@^0.1.1:
dependencies:
align-text "^0.1.1"
rimraf@^2.2.8, rimraf@^2.4.3, rimraf@^2.4.4, rimraf@~2.5.1, rimraf@~2.5.4, rimraf@2:
rimraf@2, rimraf@^2.2.8, rimraf@^2.4.3, rimraf@^2.4.4, rimraf@~2.5.1, rimraf@~2.5.4:
version "2.5.4"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.5.4.tgz#96800093cbf1a0c86bd95b4625467535c29dfa04"
dependencies:
@@ -5101,7 +5091,7 @@ semver-diff@^2.0.0:
dependencies:
semver "^5.0.3"
semver@^5.0.3, semver@^5.1.0, semver@^5.3.0, semver@~5.3.0, "semver@2 || 3 || 4 || 5":
"semver@2 || 3 || 4 || 5", semver@^5.0.3, semver@^5.1.0, semver@^5.3.0, semver@~5.3.0:
version "5.3.0"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f"
@@ -5157,7 +5147,7 @@ sha.js@2.2.6:
version "2.2.6"
resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.2.6.tgz#17ddeddc5f722fb66501658895461977867315ba"
shallowequal@^0.2.2, shallowequal@0.2.x:
shallowequal@0.2.x, shallowequal@^0.2.2:
version "0.2.2"
resolved "https://registry.yarnpkg.com/shallowequal/-/shallowequal-0.2.2.tgz#1e32fd5bcab6ad688a4812cb0cc04efc75c7014e"
dependencies:
@@ -5277,10 +5267,6 @@ strict-uri-encode@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713"
string_decoder@~0.10.25, string_decoder@~0.10.x:
version "0.10.31"
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94"
string-width@^1.0.1, string-width@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3"
@@ -5316,6 +5302,10 @@ string.prototype.padstart@^3.0.0:
es-abstract "^1.4.3"
function-bind "^1.0.2"
string_decoder@~0.10.25, string_decoder@~0.10.x:
version "0.10.31"
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94"
stringstream@~0.0.4:
version "0.0.5"
resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878"
@@ -5609,7 +5599,7 @@ util-deprecate@~1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
util@~0.10.3, util@0.10.3:
util@0.10.3, util@~0.10.3:
version "0.10.3"
resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9"
dependencies:
@@ -5784,13 +5774,17 @@ widest-line@^1.0.0:
dependencies:
string-width "^1.0.1"
window-size@0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d"
window-size@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.2.0.tgz#b4315bb4214a3d7058ebeee892e13fa24d98b075"
window-size@0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d"
wordwrap@0.0.2:
version "0.0.2"
resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f"
wordwrap@^1.0.0, wordwrap@~1.0.0:
version "1.0.0"
@@ -5800,10 +5794,6 @@ wordwrap@~0.0.2:
version "0.0.3"
resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107"
wordwrap@0.0.2:
version "0.0.2"
resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f"
worker-farm@^1.3.1:
version "1.3.1"
resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.3.1.tgz#4333112bb49b17aa050b87895ca6b2cacf40e5ff"
@@ -5845,7 +5835,7 @@ xdg-basedir@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-2.0.1.tgz#4d8b8f1eccd3419aa362061becef515e1e559635"
xtend@^4.0.0, "xtend@>=4.0.0 <4.1.0-0":
"xtend@>=4.0.0 <4.1.0-0", xtend@^4.0.0:
version "4.0.1"
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"
@@ -5887,4 +5877,3 @@ yargs@~3.10.0:
cliui "^2.1.0"
decamelize "^1.0.0"
window-size "0.1.0"