mirror of
https://github.com/zhigang1992/react-native-web.git
synced 2026-04-01 22:42:19 +08:00
Compare commits
33 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3e12ddfb2b | ||
|
|
3ecf5d2ed2 | ||
|
|
0a5acdb996 | ||
|
|
a712a58eba | ||
|
|
6de892c92b | ||
|
|
495defd69b | ||
|
|
1a20fcfce6 | ||
|
|
ed1e45a43d | ||
|
|
556dc8926e | ||
|
|
66cf45b90b | ||
|
|
d1e49e06e6 | ||
|
|
8bf28dbe43 | ||
|
|
9ae95d0797 | ||
|
|
321051b723 | ||
|
|
5f68542529 | ||
|
|
82c044ee33 | ||
|
|
9bcc67e73a | ||
|
|
f1ce6c2acb | ||
|
|
034108a2a0 | ||
|
|
f96d7b868f | ||
|
|
0dfe319d41 | ||
|
|
b7e970f4e6 | ||
|
|
02e62ad5d6 | ||
|
|
541d2458fb | ||
|
|
b1e860ab40 | ||
|
|
e8eab9b3ec | ||
|
|
6bc76c3c92 | ||
|
|
2acd8e477c | ||
|
|
ff2b0c9bdc | ||
|
|
79208720d1 | ||
|
|
fca04c4125 | ||
|
|
5b5b72cc19 | ||
|
|
217ad97bfd |
@@ -2,7 +2,6 @@
|
||||
.*/__tests__/.*
|
||||
.*/benchmarks/.*
|
||||
.*/docs/.*
|
||||
.*/node_modules/animated/*
|
||||
.*/node_modules/babel-plugin-transform-react-remove-prop-types/*
|
||||
|
||||
[include]
|
||||
|
||||
@@ -107,7 +107,6 @@ AppRegistry.runApplication('MyApp', { rootTag: document.getElementById('react-ro
|
||||
|
||||
* [Glitch](https://glitch.com/edit/#!/react-native-web-playground)
|
||||
* [create-react-app](https://github.com/facebookincubator/create-react-app)
|
||||
* [re-start](https://github.com/react-everywhere/re-start)
|
||||
|
||||
## Related projects
|
||||
|
||||
@@ -121,7 +120,7 @@ AppRegistry.runApplication('MyApp', { rootTag: document.getElementById('react-ro
|
||||
React Native for Web is [BSD licensed](LICENSE).
|
||||
|
||||
[npm-image]: https://badge.fury.io/js/react-native-web.svg
|
||||
[npm-url]: https://npmjs.org/package/react-native-web
|
||||
[npm-url]: https://yarnpkg.com/en/package/react-native-web
|
||||
[react-native-url]: https://facebook.github.io/react-native/
|
||||
[travis-image]: https://travis-ci.org/necolas/react-native-web.svg?branch=master
|
||||
[travis-url]: https://travis-ci.org/necolas/react-native-web
|
||||
|
||||
@@ -27,6 +27,7 @@ const getDistLocation = importName => {
|
||||
|
||||
// components
|
||||
case 'ActivityIndicator':
|
||||
case 'ART':
|
||||
case 'Button':
|
||||
case 'FlatList':
|
||||
case 'Image':
|
||||
|
||||
@@ -14,12 +14,9 @@ Append `?fastest` to the URL to include the fastest "other libraries", and
|
||||
|
||||
The components used in the render benchmarks are simple enough to be
|
||||
implemented by multiple UI or style libraries. The implementations are not
|
||||
equivalent in functionality. For example, React Native for Web's stylesheet is
|
||||
unique in that it also converts React Native styles to DOM styles, has
|
||||
deterministic resolution, and supports RTL layout.
|
||||
|
||||
`react-native-web/stylesheet` is a comparative baseline that implements a
|
||||
simple `View` without much of React Native's functionality.
|
||||
equivalent in functionality. For example, the "React Native for Web" benchmark includes a
|
||||
complete `View` implementation and the `StyleSheet` also converts React Native
|
||||
styles to DOM styles, has deterministic resolution, and supports RTL layout.
|
||||
|
||||
## Benchmark results
|
||||
|
||||
@@ -27,26 +24,24 @@ Typical render timings*: mean ± two standard deviations.
|
||||
|
||||
| Implementation | Deep tree (ms) | Wide tree (ms) | Tweets (ms) |
|
||||
| :--- | ---: | ---: | ---: |
|
||||
| `css-modules` | `88.83` `±18.63` | `198.79` `±22.98` | |
|
||||
| `react-native-web/stylesheet@0.0.121` | `91.17` `±19.29` | `209.67` `±32.38` | |
|
||||
| `react-native-web@0.0.121` | `124.21` `±16.84` | `264.55` `±38.75` | `16.90` `±7.30ms` |
|
||||
| `css-modules` | `80.47` `±25.13` | `144.87` `±32.70` | |
|
||||
| `react-native-web@0.2.1` | `88.68` `±28.78` | `178.17` `±39.90` | `13.78` `±2.90ms` |
|
||||
|
||||
Other libraries
|
||||
|
||||
| Implementation | Deep tree (ms) | Wide tree (ms) |
|
||||
| Implementation | Deep tree (ms) | Wide tree (ms) |
|
||||
| :--- | ---: | ---: |
|
||||
| `aphrodite@1.2.3` | `91.73` `±41.63` | `197.72` `±44.90` |
|
||||
| `styletron@2.5.1` | `94.73` `±37.58` | `201.81` `±57.93` |
|
||||
| `glamor@2.20.40` | `146.60` `±26.73` | `277.46` `±29.17` |
|
||||
| `emotion@7.2.2` | `150.79` `±38.29` | `282.18` `±41.79` |
|
||||
| `react-jss@7.1.0` | `201.83` `±34.65` | `428.61` `±47.8` |
|
||||
| `reactxp@0.42.1` | `262.69` `±24.14` | `595.20` `±66.17` |
|
||||
| `styled-components@2.1.2` | `280.59` `±31.77` | `599.00` `±62.99` |
|
||||
| `styled-components/primitives@2.1.2` | `291.74` `±48.96` | `606.57` `±78.18` |
|
||||
| `radium@0.19.4` | `563.94` `±69.91` | `1139.18` `±152.59` |
|
||||
| `styletron@3.0.0-rc.5` | `79.41` `±27.49` | `152.95` `±29.46` |
|
||||
| `aphrodite@1.2.5` | `85.13` `±25.39` | `162.87` `±25.91` |
|
||||
| `glamor@2.20.40` | `109.92` `±29.88` | `193.01` `±32.03` |
|
||||
| `react-jss@8.2.0` | `134.28` `±49.00` | `278.78` `±50.39` |
|
||||
| `emotion@8.0.12` | `139.08` `±46.18` | `253.45` `±52.69` |
|
||||
| `styled-components@2.3.2` | `194.43` `416.28` | `404.86` `±56.59` |
|
||||
| `reactxp@0.46.6` | `219.46` `±57.24` | `424.18` `±76.10` |
|
||||
| `radium@0.19.6` | `359.32` `±90.27` | `795.91` `±88.93` |
|
||||
|
||||
These results indicate that style render performance is not a significant
|
||||
differentiating factor between `aphrodite`, `css-modules`, `react-native-web`,
|
||||
and `styletron`.
|
||||
These results indicate that render times when using `react-native-web`,
|
||||
`css-modules`, `aphrodite`, and `styletron` are roughly equivalent and
|
||||
significantly faster than alternatives.
|
||||
|
||||
*MacBook Pro (13-inch, Early 2015); 3.1 GHz Intel Core i7; 16 GB 1867 MHz DDR3. Google Chrome 58 (2x CPU slowdown).
|
||||
*MacBook Pro (13-inch, Early 2011); 2.3 GHz Intel Core i5; 8 GB 1333 MHz DDR3. Google Chrome 62.
|
||||
|
||||
@@ -5,7 +5,6 @@ import glamor from './src/glamor';
|
||||
import jss from './src/jss';
|
||||
import radium from './src/radium';
|
||||
import reactNative from './src/react-native';
|
||||
import reactNativeStyleSheet from './src/react-native-stylesheet';
|
||||
import styledComponents from './src/styled-components';
|
||||
import styletron from './src/styletron';
|
||||
import xp from './src/reactxp';
|
||||
@@ -22,35 +21,33 @@ const coreTests = [
|
||||
|
||||
() => renderDeepTree('css-modules', cssModules),
|
||||
() => renderWideTree('css-modules', cssModules),
|
||||
() => renderDeepTree('react-native-web/stylesheet', reactNativeStyleSheet),
|
||||
() => renderWideTree('react-native-web/stylesheet', reactNativeStyleSheet),
|
||||
() => renderDeepTree('react-native-web', reactNative),
|
||||
() => renderWideTree('react-native-web', reactNative)
|
||||
];
|
||||
|
||||
const fastestTests = [
|
||||
() => renderDeepTree('aphrodite', aphrodite),
|
||||
() => renderWideTree('aphrodite', aphrodite),
|
||||
() => renderDeepTree('styletron', styletron),
|
||||
() => renderWideTree('styletron', styletron)
|
||||
() => renderWideTree('styletron', styletron),
|
||||
() => renderDeepTree('aphrodite', aphrodite),
|
||||
() => renderWideTree('aphrodite', aphrodite)
|
||||
];
|
||||
|
||||
/**
|
||||
* Optionally run tests using other libraries
|
||||
*/
|
||||
const restTests = [
|
||||
() => renderDeepTree('emotion', emotion),
|
||||
() => renderWideTree('emotion', emotion),
|
||||
() => renderDeepTree('glamor', glamor),
|
||||
() => renderWideTree('glamor', glamor),
|
||||
() => renderDeepTree('radium', radium),
|
||||
() => renderWideTree('radium', radium),
|
||||
() => renderDeepTree('reactxp', xp),
|
||||
() => renderWideTree('reactxp', xp),
|
||||
() => renderDeepTree('react-jss', jss),
|
||||
() => renderWideTree('react-jss', jss),
|
||||
() => renderDeepTree('emotion', emotion),
|
||||
() => renderWideTree('emotion', emotion),
|
||||
() => renderDeepTree('styled-components', styledComponents),
|
||||
() => renderWideTree('styled-components', styledComponents)
|
||||
() => renderWideTree('styled-components', styledComponents),
|
||||
() => renderDeepTree('reactxp', xp),
|
||||
() => renderWideTree('reactxp', xp),
|
||||
() => renderDeepTree('radium', radium),
|
||||
() => renderWideTree('radium', radium)
|
||||
];
|
||||
|
||||
const tests = [...coreTests];
|
||||
|
||||
@@ -4,19 +4,18 @@
|
||||
"dependencies": {
|
||||
"aphrodite": "^1.2.5",
|
||||
"classnames": "^2.2.5",
|
||||
"emotion": "^8.0.9",
|
||||
"emotion": "^8.0.12",
|
||||
"glamor": "^2.20.40",
|
||||
"marky": "^1.2.0",
|
||||
"radium": "^0.19.6",
|
||||
"react-jss": "^7.2.0",
|
||||
"react-primitives": "^0.4.3",
|
||||
"reactxp": "^0.42.11",
|
||||
"styled-components": "^2.2.3",
|
||||
"styletron-client": "^2.5.7",
|
||||
"styletron-utils": "^2.5.4"
|
||||
"react-jss": "^8.2.0",
|
||||
"reactxp": "^0.46.6",
|
||||
"styled-components": "^2.3.2",
|
||||
"styletron-client": "^3.0.0-rc.5",
|
||||
"styletron-utils": "^3.0.0-rc.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"css-loader": "^0.28.7",
|
||||
"style-loader": "^0.19.0"
|
||||
"style-loader": "^0.19.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
/* eslint-disable react/prop-types */
|
||||
import React from 'react';
|
||||
import StyleSheet from 'react-native/apis/StyleSheet';
|
||||
import View from '../View/react-native-stylesheet';
|
||||
|
||||
const Box = ({ color, fixed = false, layout = 'column', outer = false, ...other }) => (
|
||||
<View
|
||||
{...other}
|
||||
style={[
|
||||
styles[`color${color}`],
|
||||
fixed && styles.fixed,
|
||||
layout === 'row' && styles.row,
|
||||
outer && styles.outer
|
||||
]}
|
||||
/>
|
||||
);
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
outer: {
|
||||
padding: 4
|
||||
},
|
||||
row: {
|
||||
flexDirection: 'row'
|
||||
},
|
||||
color0: {
|
||||
backgroundColor: '#222'
|
||||
},
|
||||
color1: {
|
||||
backgroundColor: '#666'
|
||||
},
|
||||
color2: {
|
||||
backgroundColor: '#999'
|
||||
},
|
||||
color3: {
|
||||
backgroundColor: 'blue'
|
||||
},
|
||||
color4: {
|
||||
backgroundColor: 'orange'
|
||||
},
|
||||
color5: {
|
||||
backgroundColor: 'red'
|
||||
},
|
||||
fixed: {
|
||||
width: 20,
|
||||
height: 20
|
||||
}
|
||||
});
|
||||
|
||||
export default Box;
|
||||
@@ -1,30 +0,0 @@
|
||||
import styled from 'styled-components/primitives';
|
||||
|
||||
const getColor = color => {
|
||||
switch (color) {
|
||||
case 0:
|
||||
return '#222';
|
||||
case 1:
|
||||
return '#666';
|
||||
case 2:
|
||||
return '#999';
|
||||
case 3:
|
||||
return 'blue';
|
||||
case 4:
|
||||
return 'orange';
|
||||
case 5:
|
||||
return 'red';
|
||||
default:
|
||||
return 'transparent';
|
||||
}
|
||||
};
|
||||
|
||||
const Box = styled.View`
|
||||
flex-direction: ${props => (props.layout === 'column' ? 'column' : 'row')};
|
||||
padding: ${props => (props.outer ? '4px' : '0')};
|
||||
height: ${props => (props.fixed ? '20px' : 'auto')};
|
||||
width: ${props => (props.fixed ? '20px' : 'auto')};
|
||||
background-color: ${props => getColor(props.color)};
|
||||
`;
|
||||
|
||||
export default Box;
|
||||
@@ -1,35 +0,0 @@
|
||||
/* eslint-disable react/prop-types */
|
||||
import React from 'react';
|
||||
import StyleSheet from 'react-native/apis/StyleSheet';
|
||||
import registry from 'react-native/apis/StyleSheet/registry';
|
||||
|
||||
const emptyObject = {};
|
||||
|
||||
class View extends React.Component {
|
||||
render() {
|
||||
const { style, ...other } = this.props;
|
||||
const styleProps = registry.resolve([styles.root, style]) || emptyObject;
|
||||
return <div {...other} {...styleProps} />;
|
||||
}
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
root: {
|
||||
alignItems: 'stretch',
|
||||
borderWidth: 0,
|
||||
borderStyle: 'solid',
|
||||
boxSizing: 'border-box',
|
||||
display: 'flex',
|
||||
flexBasis: 'auto',
|
||||
flexDirection: 'column',
|
||||
flexShrink: 0,
|
||||
margin: 0,
|
||||
padding: 0,
|
||||
position: 'relative',
|
||||
// fix flexbox bugs
|
||||
minHeight: 0,
|
||||
minWidth: 0
|
||||
}
|
||||
});
|
||||
|
||||
export default View;
|
||||
9
benchmarks/src/react-native-stylesheet.js
vendored
9
benchmarks/src/react-native-stylesheet.js
vendored
@@ -1,9 +0,0 @@
|
||||
import Box from './components/Box/react-native-stylesheet';
|
||||
import View from './components/View/react-native-stylesheet';
|
||||
|
||||
const api = {
|
||||
Box,
|
||||
View
|
||||
};
|
||||
|
||||
export default api;
|
||||
@@ -1,7 +0,0 @@
|
||||
import Box from './components/Box/styled-components';
|
||||
import styled from 'styled-components/primitives';
|
||||
|
||||
export default {
|
||||
Box,
|
||||
View: styled.View
|
||||
};
|
||||
@@ -2,14 +2,44 @@
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
"@types/lodash@4.14.66":
|
||||
version "4.14.66"
|
||||
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.66.tgz#3dbb83477becf130611f8fac82a8fdb199805981"
|
||||
"@babel/helper-module-imports@7.0.0-beta.32":
|
||||
version "7.0.0-beta.32"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.0.0-beta.32.tgz#8126fc024107c226879841b973677a4f4e510a03"
|
||||
dependencies:
|
||||
"@babel/types" "7.0.0-beta.32"
|
||||
lodash "^4.2.0"
|
||||
|
||||
"@babel/types@7.0.0-beta.32":
|
||||
version "7.0.0-beta.32"
|
||||
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.0.0-beta.32.tgz#c317d0ecc89297b80bbcb2f50608e31f6452a5ff"
|
||||
dependencies:
|
||||
esutils "^2.0.2"
|
||||
lodash "^4.2.0"
|
||||
to-fast-properties "^2.0.0"
|
||||
|
||||
"@types/lodash@^4.14.64":
|
||||
version "4.14.74"
|
||||
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.74.tgz#ac3bd8db988e7f7038e5d22bd76a7ba13f876168"
|
||||
|
||||
"@types/lodash@^4.14.78":
|
||||
version "4.14.91"
|
||||
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.91.tgz#794611b28056d16b5436059c6d800b39d573cd3a"
|
||||
|
||||
"@types/node@*":
|
||||
version "8.5.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-8.5.1.tgz#4ec3020bcdfe2abffeef9ba3fbf26fca097514b5"
|
||||
|
||||
"@types/react-dom@^16.0.0":
|
||||
version "16.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-16.0.3.tgz#8accad7eabdab4cca3e1a56f5ccb57de2da0ff64"
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
"@types/react" "*"
|
||||
|
||||
"@types/react@*", "@types/react@^16.0.0":
|
||||
version "16.0.31"
|
||||
resolved "https://registry.yarnpkg.com/@types/react/-/react-16.0.31.tgz#5285da62f3ac62b797f6d0729a1d6181f3180c3e"
|
||||
|
||||
abbrev@1:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.0.tgz#d0554c2256636e2f56e7c2e5ad183f859428d81f"
|
||||
@@ -27,20 +57,6 @@ alphanum-sort@^1.0.1, alphanum-sort@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/alphanum-sort/-/alphanum-sort-1.0.2.tgz#97a1119649b211ad33691d9f9f486a8ec9fbe0a3"
|
||||
|
||||
animated@^0.1.5:
|
||||
version "0.1.5"
|
||||
resolved "https://registry.yarnpkg.com/animated/-/animated-0.1.5.tgz#83df8dc443d57abab7b0bb04818b0b655b31c9b9"
|
||||
dependencies:
|
||||
invariant "^2.2.0"
|
||||
normalize-css-color "^1.0.1"
|
||||
|
||||
animated@^0.2.0:
|
||||
version "0.2.0"
|
||||
resolved "https://registry.yarnpkg.com/animated/-/animated-0.2.0.tgz#1a0e96f097b3fbc5b64d7eddc723bcc0a6f97633"
|
||||
dependencies:
|
||||
invariant "^2.2.0"
|
||||
normalize-css-color "^1.0.1"
|
||||
|
||||
ansi-regex@^2.0.0:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df"
|
||||
@@ -63,15 +79,11 @@ argparse@^1.0.7:
|
||||
dependencies:
|
||||
sprintf-js "~1.0.2"
|
||||
|
||||
array-find-index@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1"
|
||||
|
||||
array-find@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/array-find/-/array-find-1.0.0.tgz#6c8e286d11ed768327f8e62ecee87353ca3e78b8"
|
||||
|
||||
asap@^2.0.3, asap@^2.0.5:
|
||||
asap@^2.0.3:
|
||||
version "2.0.6"
|
||||
resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46"
|
||||
|
||||
@@ -104,40 +116,22 @@ babel-code-frame@^6.11.0:
|
||||
esutils "^2.0.2"
|
||||
js-tokens "^3.0.0"
|
||||
|
||||
babel-generator@^6.26.0:
|
||||
version "6.26.0"
|
||||
resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.26.0.tgz#ac1ae20070b79f6e3ca1d3269613053774f20dc5"
|
||||
dependencies:
|
||||
babel-messages "^6.23.0"
|
||||
babel-runtime "^6.26.0"
|
||||
babel-types "^6.26.0"
|
||||
detect-indent "^4.0.0"
|
||||
jsesc "^1.3.0"
|
||||
lodash "^4.17.4"
|
||||
source-map "^0.5.6"
|
||||
trim-right "^1.0.1"
|
||||
|
||||
babel-macros@^1.0.2:
|
||||
babel-macros@^1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/babel-macros/-/babel-macros-1.2.0.tgz#39e47ed6d286d4a98f1948d8bab45dac17e4e2d4"
|
||||
dependencies:
|
||||
cosmiconfig "3.1.0"
|
||||
|
||||
babel-messages@^6.23.0:
|
||||
version "6.23.0"
|
||||
resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e"
|
||||
babel-plugin-emotion@^8.0.12:
|
||||
version "8.0.12"
|
||||
resolved "https://registry.yarnpkg.com/babel-plugin-emotion/-/babel-plugin-emotion-8.0.12.tgz#2ed844001416b0ae2ff787a06b1804ec5f531c89"
|
||||
dependencies:
|
||||
babel-runtime "^6.22.0"
|
||||
|
||||
babel-plugin-emotion@^8.0.9:
|
||||
version "8.0.9"
|
||||
resolved "https://registry.yarnpkg.com/babel-plugin-emotion/-/babel-plugin-emotion-8.0.9.tgz#65a9ead1e9a574fa1b0390ebcea942739761713c"
|
||||
dependencies:
|
||||
babel-generator "^6.26.0"
|
||||
babel-macros "^1.0.2"
|
||||
"@babel/helper-module-imports" "7.0.0-beta.32"
|
||||
babel-macros "^1.2.0"
|
||||
babel-plugin-syntax-jsx "^6.18.0"
|
||||
convert-source-map "^1.5.0"
|
||||
emotion-utils "^8.0.9"
|
||||
emotion-utils "^8.0.12"
|
||||
find-root "^1.1.0"
|
||||
source-map "^0.5.7"
|
||||
touch "^1.0.0"
|
||||
|
||||
@@ -145,29 +139,6 @@ babel-plugin-syntax-jsx@^6.18.0:
|
||||
version "6.18.0"
|
||||
resolved "https://registry.yarnpkg.com/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz#0af32a9a6e13ca7a3fd5069e62d7b0f58d0d8946"
|
||||
|
||||
babel-runtime@^6.22.0, babel-runtime@^6.26.0:
|
||||
version "6.26.0"
|
||||
resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe"
|
||||
dependencies:
|
||||
core-js "^2.4.0"
|
||||
regenerator-runtime "^0.11.0"
|
||||
|
||||
babel-runtime@^6.23.0:
|
||||
version "6.25.0"
|
||||
resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.25.0.tgz#33b98eaa5d482bb01a8d1aa6b437ad2b01aec41c"
|
||||
dependencies:
|
||||
core-js "^2.4.0"
|
||||
regenerator-runtime "^0.10.0"
|
||||
|
||||
babel-types@^6.26.0:
|
||||
version "6.26.0"
|
||||
resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.26.0.tgz#a3b073f94ab49eb6fa55cd65227a334380632497"
|
||||
dependencies:
|
||||
babel-runtime "^6.26.0"
|
||||
esutils "^2.0.2"
|
||||
lodash "^4.17.4"
|
||||
to-fast-properties "^1.0.3"
|
||||
|
||||
balanced-match@^0.4.2:
|
||||
version "0.4.2"
|
||||
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838"
|
||||
@@ -188,9 +159,13 @@ bowser@^1.6.0:
|
||||
version "1.7.1"
|
||||
resolved "https://registry.yarnpkg.com/bowser/-/bowser-1.7.1.tgz#a4de8f18a1a0dc9531eb2a92a1521fb6a9ba96a5"
|
||||
|
||||
brcast@^2.0.0:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/brcast/-/brcast-2.0.1.tgz#4311508f0634a6f5a2465b6cf2db27f06902aaca"
|
||||
bowser@^1.7.3:
|
||||
version "1.8.1"
|
||||
resolved "https://registry.yarnpkg.com/bowser/-/bowser-1.8.1.tgz#49785777e7302febadb1a5b71d9a646520ed310d"
|
||||
|
||||
brcast@^3.0.1:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/brcast/-/brcast-3.0.1.tgz#6256a8349b20de9eed44257a9b24d71493cd48dd"
|
||||
|
||||
browserslist@^1.0.1, browserslist@^1.5.2, browserslist@^1.7.5:
|
||||
version "1.7.5"
|
||||
@@ -297,10 +272,6 @@ core-js@^1.0.0:
|
||||
version "1.2.7"
|
||||
resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636"
|
||||
|
||||
core-js@^2.4.0:
|
||||
version "2.4.1"
|
||||
resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.4.1.tgz#4de911e667b0eae9124e34254b53aea6fc618d3e"
|
||||
|
||||
cosmiconfig@3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-3.1.0.tgz#640a94bf9847f321800403cd273af60665c73397"
|
||||
@@ -310,14 +281,6 @@ cosmiconfig@3.1.0:
|
||||
parse-json "^3.0.0"
|
||||
require-from-string "^2.0.1"
|
||||
|
||||
create-react-class@^15.6.0:
|
||||
version "15.6.0"
|
||||
resolved "https://registry.yarnpkg.com/create-react-class/-/create-react-class-15.6.0.tgz#ab448497c26566e1e29413e883207d57cfe7bed4"
|
||||
dependencies:
|
||||
fbjs "^0.8.9"
|
||||
loose-envify "^1.3.1"
|
||||
object-assign "^4.1.1"
|
||||
|
||||
css-color-keywords@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/css-color-keywords/-/css-color-keywords-1.0.0.tgz#fea2616dc676b2962686b3af8dbdbe180b244e05"
|
||||
@@ -332,6 +295,12 @@ css-in-js-utils@^1.0.3:
|
||||
dependencies:
|
||||
hyphenate-style-name "^1.0.2"
|
||||
|
||||
css-in-js-utils@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/css-in-js-utils/-/css-in-js-utils-2.0.0.tgz#5af1dd70f4b06b331f48d22a3d86e0786c0b9435"
|
||||
dependencies:
|
||||
hyphenate-style-name "^1.0.2"
|
||||
|
||||
css-loader@^0.28.7:
|
||||
version "0.28.7"
|
||||
resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-0.28.7.tgz#5f2ee989dd32edd907717f953317656160999c1b"
|
||||
@@ -429,34 +398,14 @@ csso@~2.3.1:
|
||||
clap "^1.0.9"
|
||||
source-map "^0.5.3"
|
||||
|
||||
debounce@1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/debounce/-/debounce-1.0.2.tgz#503cc674d8d7f737099664fb75ddbd36b9626dc6"
|
||||
|
||||
decamelize@^1.1.2:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
|
||||
|
||||
deep-assign@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/deep-assign/-/deep-assign-2.0.0.tgz#ebe06b1f07f08dae597620e3dd1622f371a1c572"
|
||||
dependencies:
|
||||
is-obj "^1.0.0"
|
||||
|
||||
defined@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693"
|
||||
|
||||
deline@^1.0.4:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/deline/-/deline-1.0.4.tgz#6c05c87836926e1a1c63e47882f3d2eb2c6f14c9"
|
||||
|
||||
detect-indent@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208"
|
||||
dependencies:
|
||||
repeating "^2.0.0"
|
||||
|
||||
electron-to-chromium@^1.2.3:
|
||||
version "1.2.4"
|
||||
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.2.4.tgz#9751cbea89fa120bf88c226ba41eb8d0b6f1b597"
|
||||
@@ -465,16 +414,16 @@ emojis-list@^2.0.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389"
|
||||
|
||||
emotion-utils@^8.0.9:
|
||||
version "8.0.9"
|
||||
resolved "https://registry.yarnpkg.com/emotion-utils/-/emotion-utils-8.0.9.tgz#458c7676de2f5206b0b796f7c96c53a5970ed9f2"
|
||||
emotion-utils@^8.0.12:
|
||||
version "8.0.12"
|
||||
resolved "https://registry.yarnpkg.com/emotion-utils/-/emotion-utils-8.0.12.tgz#5e0fd72db3008f26ce4f80b1972df08841df2168"
|
||||
|
||||
emotion@^8.0.9:
|
||||
version "8.0.9"
|
||||
resolved "https://registry.yarnpkg.com/emotion/-/emotion-8.0.9.tgz#788cf2c3ccd59becbd3e78eb01bef22ff20cf381"
|
||||
emotion@^8.0.12:
|
||||
version "8.0.12"
|
||||
resolved "https://registry.yarnpkg.com/emotion/-/emotion-8.0.12.tgz#03de11ce26b1b2401c334b94d438652124c514c6"
|
||||
dependencies:
|
||||
babel-plugin-emotion "^8.0.9"
|
||||
emotion-utils "^8.0.9"
|
||||
babel-plugin-emotion "^8.0.12"
|
||||
emotion-utils "^8.0.12"
|
||||
stylis "^3.3.2"
|
||||
stylis-rule-sheet "^0.0.5"
|
||||
|
||||
@@ -530,6 +479,18 @@ fbjs@^0.8.12:
|
||||
setimmediate "^1.0.5"
|
||||
ua-parser-js "^0.7.9"
|
||||
|
||||
fbjs@^0.8.16:
|
||||
version "0.8.16"
|
||||
resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.16.tgz#5e67432f550dc41b572bf55847b8aca64e5337db"
|
||||
dependencies:
|
||||
core-js "^1.0.0"
|
||||
isomorphic-fetch "^2.1.1"
|
||||
loose-envify "^1.0.0"
|
||||
object-assign "^4.1.0"
|
||||
promise "^7.1.1"
|
||||
setimmediate "^1.0.5"
|
||||
ua-parser-js "^0.7.9"
|
||||
|
||||
fbjs@^0.8.5, fbjs@^0.8.9:
|
||||
version "0.8.12"
|
||||
resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.12.tgz#10b5d92f76d45575fd63a217d4ea02bea2f8ed04"
|
||||
@@ -542,14 +503,14 @@ fbjs@^0.8.5, fbjs@^0.8.9:
|
||||
setimmediate "^1.0.5"
|
||||
ua-parser-js "^0.7.9"
|
||||
|
||||
find-root@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/find-root/-/find-root-1.1.0.tgz#abcfc8ba76f708c42a97b3d685b7e9450bfb9ce4"
|
||||
|
||||
flatten@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/flatten/-/flatten-1.0.2.tgz#dae46a9d78fbe25292258cc1e780a41d95c03782"
|
||||
|
||||
flexibility@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/flexibility/-/flexibility-2.0.1.tgz#ad323aafc40f469ce624286518fc4d7cd72b7c77"
|
||||
|
||||
function-bind@^1.0.2:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.0.tgz#16176714c801798e4e8f2cf7f7529467bb4a5771"
|
||||
@@ -588,6 +549,10 @@ 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"
|
||||
|
||||
hoist-non-react-statics@^2.3.1:
|
||||
version "2.3.1"
|
||||
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-2.3.1.tgz#343db84c6018c650778898240135a1420ee22ce0"
|
||||
|
||||
html-comment-regex@^1.1.0:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/html-comment-regex/-/html-comment-regex-1.1.1.tgz#668b93776eaae55ebde8f3ad464b307a4963625e"
|
||||
@@ -626,7 +591,7 @@ inherits@2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1"
|
||||
|
||||
inline-style-prefixer@^2.0.1, inline-style-prefixer@^2.0.5:
|
||||
inline-style-prefixer@^2.0.5:
|
||||
version "2.0.5"
|
||||
resolved "https://registry.yarnpkg.com/inline-style-prefixer/-/inline-style-prefixer-2.0.5.tgz#c153c7e88fd84fef5c602e95a8168b2770671fe7"
|
||||
dependencies:
|
||||
@@ -640,11 +605,12 @@ inline-style-prefixer@^3.0.1, inline-style-prefixer@^3.0.6:
|
||||
bowser "^1.6.0"
|
||||
css-in-js-utils "^1.0.3"
|
||||
|
||||
invariant@^2.2.0, invariant@^2.2.1:
|
||||
version "2.2.2"
|
||||
resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.2.tgz#9e1f56ac0acdb6bf303306f338be3b204ae60360"
|
||||
inline-style-prefixer@^3.0.3:
|
||||
version "3.0.8"
|
||||
resolved "https://registry.yarnpkg.com/inline-style-prefixer/-/inline-style-prefixer-3.0.8.tgz#8551b8e5b4d573244e66a34b04f7d32076a2b534"
|
||||
dependencies:
|
||||
loose-envify "^1.0.0"
|
||||
bowser "^1.7.3"
|
||||
css-in-js-utils "^2.0.0"
|
||||
|
||||
is-absolute-url@^2.0.0:
|
||||
version "2.1.0"
|
||||
@@ -658,12 +624,6 @@ is-directory@^0.3.1:
|
||||
version "0.3.1"
|
||||
resolved "https://registry.yarnpkg.com/is-directory/-/is-directory-0.3.1.tgz#61339b6f2475fc772fd9c9d83f5c8575dc154ae1"
|
||||
|
||||
is-finite@^1.0.0:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa"
|
||||
dependencies:
|
||||
number-is-nan "^1.0.0"
|
||||
|
||||
is-function@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/is-function/-/is-function-1.0.1.tgz#12cfb98b65b57dd3d193a3121f5f6e2f437602b5"
|
||||
@@ -672,9 +632,9 @@ is-in-browser@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/is-in-browser/-/is-in-browser-1.0.2.tgz#f688bea8f1e5aadc3244ebc870d188cfb9b613cf"
|
||||
|
||||
is-obj@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f"
|
||||
is-in-browser@^1.1.3:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/is-in-browser/-/is-in-browser-1.1.3.tgz#56ff4db683a078c6082eb95dad7dc62e1d04f835"
|
||||
|
||||
is-plain-obj@^1.0.0:
|
||||
version "1.1.0"
|
||||
@@ -729,10 +689,6 @@ js-yaml@~3.7.0:
|
||||
argparse "^1.0.7"
|
||||
esprima "^2.6.0"
|
||||
|
||||
jsesc@^1.3.0:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b"
|
||||
|
||||
jsesc@~0.5.0:
|
||||
version "0.5.0"
|
||||
resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d"
|
||||
@@ -755,69 +711,77 @@ jsonify@~0.0.0:
|
||||
version "0.0.0"
|
||||
resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73"
|
||||
|
||||
jss-camel-case@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/jss-camel-case/-/jss-camel-case-5.0.0.tgz#886c1fe56a8a11577454d6a8b4133caa6c1f53a0"
|
||||
|
||||
jss-compose@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/jss-compose/-/jss-compose-4.0.0.tgz#f0109e8e8301a2678279301c24523dbc76115b9b"
|
||||
dependencies:
|
||||
warning "^3.0.0"
|
||||
|
||||
jss-default-unit@^7.0.0:
|
||||
version "7.0.0"
|
||||
resolved "https://registry.yarnpkg.com/jss-default-unit/-/jss-default-unit-7.0.0.tgz#176c1db91da870e3ad16301f6f4b4cfc6fe1e90a"
|
||||
|
||||
jss-expand@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/jss-expand/-/jss-expand-4.0.0.tgz#71ec15386d7839bb23892acf9dcaa40b7fe9c785"
|
||||
|
||||
jss-extend@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/jss-extend/-/jss-extend-5.0.0.tgz#08a1d4015d05dfe011e3a281457d471226865387"
|
||||
dependencies:
|
||||
warning "^3.0.0"
|
||||
|
||||
jss-global@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/jss-global/-/jss-global-2.0.0.tgz#a162f822f17e5d760151d908bdb41d7f2824c28f"
|
||||
|
||||
jss-nested@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/jss-nested/-/jss-nested-5.0.0.tgz#c0752f31f2d465110d7de6ac83583dbed669faa0"
|
||||
dependencies:
|
||||
warning "^3.0.0"
|
||||
|
||||
jss-preset-default@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/jss-preset-default/-/jss-preset-default-3.0.0.tgz#e43ee1ac526f689baf2bfd28ae95a6fdc3a02663"
|
||||
dependencies:
|
||||
jss-camel-case "^5.0.0"
|
||||
jss-compose "^4.0.0"
|
||||
jss-default-unit "^7.0.0"
|
||||
jss-expand "^4.0.0"
|
||||
jss-extend "^5.0.0"
|
||||
jss-global "^2.0.0"
|
||||
jss-nested "^5.0.0"
|
||||
jss-props-sort "^5.0.0"
|
||||
jss-vendor-prefixer "^6.0.0"
|
||||
|
||||
jss-props-sort@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/jss-props-sort/-/jss-props-sort-5.0.0.tgz#8839c88433f64e8c1dab1a7068796f19b84f9195"
|
||||
|
||||
jss-vendor-prefixer@^6.0.0:
|
||||
jss-camel-case@^6.0.0:
|
||||
version "6.0.0"
|
||||
resolved "https://registry.yarnpkg.com/jss-vendor-prefixer/-/jss-vendor-prefixer-6.0.0.tgz#be58124f0cbed76e98cc8eb5219dbb260f057d0b"
|
||||
resolved "https://registry.yarnpkg.com/jss-camel-case/-/jss-camel-case-6.0.0.tgz#7cf8453e395c31fed931d11efbc885edcd61132e"
|
||||
|
||||
jss-compose@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/jss-compose/-/jss-compose-5.0.0.tgz#ce01b2e4521d65c37ea42cf49116e5f7ab596484"
|
||||
dependencies:
|
||||
warning "^3.0.0"
|
||||
|
||||
jss-default-unit@^8.0.0:
|
||||
version "8.0.2"
|
||||
resolved "https://registry.yarnpkg.com/jss-default-unit/-/jss-default-unit-8.0.2.tgz#cc1e889bae4c0b9419327b314ab1c8e2826890e6"
|
||||
|
||||
jss-expand@^5.0.0:
|
||||
version "5.1.0"
|
||||
resolved "https://registry.yarnpkg.com/jss-expand/-/jss-expand-5.1.0.tgz#b1ad74ec18631f34f65a2124fcfceb6400610e3d"
|
||||
|
||||
jss-extend@^6.0.1:
|
||||
version "6.1.0"
|
||||
resolved "https://registry.yarnpkg.com/jss-extend/-/jss-extend-6.1.0.tgz#85f3d39944018e8f44b322c14fa316068aa7bb0b"
|
||||
dependencies:
|
||||
warning "^3.0.0"
|
||||
|
||||
jss-global@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/jss-global/-/jss-global-3.0.0.tgz#e19e5c91ab2b96353c227e30aa2cbd938cdaafa2"
|
||||
|
||||
jss-nested@^6.0.1:
|
||||
version "6.0.1"
|
||||
resolved "https://registry.yarnpkg.com/jss-nested/-/jss-nested-6.0.1.tgz#ef992b79d6e8f63d939c4397b9d99b5cbbe824ca"
|
||||
dependencies:
|
||||
warning "^3.0.0"
|
||||
|
||||
jss-preset-default@^4.0.1:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/jss-preset-default/-/jss-preset-default-4.0.1.tgz#822cecb87c27ff91633774422f4c221d61486b65"
|
||||
dependencies:
|
||||
jss-camel-case "^6.0.0"
|
||||
jss-compose "^5.0.0"
|
||||
jss-default-unit "^8.0.0"
|
||||
jss-expand "^5.0.0"
|
||||
jss-extend "^6.0.1"
|
||||
jss-global "^3.0.0"
|
||||
jss-nested "^6.0.1"
|
||||
jss-props-sort "^6.0.0"
|
||||
jss-template "^1.0.0"
|
||||
jss-vendor-prefixer "^7.0.0"
|
||||
|
||||
jss-props-sort@^6.0.0:
|
||||
version "6.0.0"
|
||||
resolved "https://registry.yarnpkg.com/jss-props-sort/-/jss-props-sort-6.0.0.tgz#9105101a3b5071fab61e2d85ea74cc22e9b16323"
|
||||
|
||||
jss-template@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/jss-template/-/jss-template-1.0.0.tgz#4b874608706ddceecacdb5567e254aecb6ea69b3"
|
||||
dependencies:
|
||||
warning "^3.0.0"
|
||||
|
||||
jss-vendor-prefixer@^7.0.0:
|
||||
version "7.0.0"
|
||||
resolved "https://registry.yarnpkg.com/jss-vendor-prefixer/-/jss-vendor-prefixer-7.0.0.tgz#0166729650015ef19d9f02437c73667231605c71"
|
||||
dependencies:
|
||||
css-vendor "^0.3.8"
|
||||
|
||||
jss@^8.1.0:
|
||||
version "8.1.0"
|
||||
resolved "https://registry.yarnpkg.com/jss/-/jss-8.1.0.tgz#b32f15efcce22446dfda4c2be09a04f38431da0a"
|
||||
jss@^9.3.2:
|
||||
version "9.4.0"
|
||||
resolved "https://registry.yarnpkg.com/jss/-/jss-9.4.0.tgz#fbfd1a63556c5afd5bfcffd98df3c50eb2614ed3"
|
||||
dependencies:
|
||||
is-in-browser "^1.0.2"
|
||||
is-in-browser "^1.1.3"
|
||||
symbol-observable "^1.1.0"
|
||||
warning "^3.0.0"
|
||||
|
||||
loader-utils@^1.0.2:
|
||||
@@ -840,11 +804,11 @@ lodash.uniq@^4.3.0:
|
||||
version "4.5.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
|
||||
|
||||
lodash@^4.17.1, lodash@^4.17.4:
|
||||
lodash@^4.17.1, lodash@^4.17.4, lodash@^4.2.0:
|
||||
version "4.17.4"
|
||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae"
|
||||
|
||||
loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.3.1:
|
||||
loose-envify@^1.0.0, loose-envify@^1.3.1:
|
||||
version "1.3.1"
|
||||
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848"
|
||||
dependencies:
|
||||
@@ -885,10 +849,6 @@ nopt@~1.0.10:
|
||||
dependencies:
|
||||
abbrev "1"
|
||||
|
||||
normalize-css-color@^1.0.1, normalize-css-color@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/normalize-css-color/-/normalize-css-color-1.0.2.tgz#02991e97cccec6623fe573afbbf0de6a1f3e9f8d"
|
||||
|
||||
normalize-range@^0.1.2:
|
||||
version "0.1.2"
|
||||
resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942"
|
||||
@@ -906,10 +866,6 @@ num2fraction@^1.2.2:
|
||||
version "1.2.2"
|
||||
resolved "https://registry.yarnpkg.com/num2fraction/-/num2fraction-1.2.2.tgz#6f682b6a027a4e9ddfa4564cd2589d1d4e669ede"
|
||||
|
||||
number-is-nan@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d"
|
||||
|
||||
object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
|
||||
@@ -1183,6 +1139,14 @@ prop-types@^15.5.10, prop-types@^15.5.4, prop-types@^15.5.8, prop-types@^15.5.9:
|
||||
fbjs "^0.8.9"
|
||||
loose-envify "^1.3.1"
|
||||
|
||||
prop-types@^15.6.0:
|
||||
version "15.6.0"
|
||||
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.0.tgz#ceaf083022fc46b4a35f69e13ef75aed0d639856"
|
||||
dependencies:
|
||||
fbjs "^0.8.16"
|
||||
loose-envify "^1.3.1"
|
||||
object-assign "^4.1.1"
|
||||
|
||||
q@^1.1.2:
|
||||
version "1.4.1"
|
||||
resolved "https://registry.yarnpkg.com/q/-/q-1.4.1.tgz#55705bcd93c5f3673530c2c2cbc0c2b3addc286e"
|
||||
@@ -1203,75 +1167,30 @@ radium@^0.19.6:
|
||||
inline-style-prefixer "^2.0.5"
|
||||
prop-types "^15.5.8"
|
||||
|
||||
react-jss@^7.2.0:
|
||||
version "7.2.0"
|
||||
resolved "https://registry.yarnpkg.com/react-jss/-/react-jss-7.2.0.tgz#30a5ed51d8388a33767c6d19790b222c1f33f48f"
|
||||
react-jss@^8.2.0:
|
||||
version "8.2.0"
|
||||
resolved "https://registry.yarnpkg.com/react-jss/-/react-jss-8.2.0.tgz#8440f08aef27d408ba31f63df09167ed22a5b99b"
|
||||
dependencies:
|
||||
hoist-non-react-statics "^1.2.0"
|
||||
jss "^8.1.0"
|
||||
jss-preset-default "^3.0.0"
|
||||
prop-types "^15.5.8"
|
||||
theming "^1.1.0"
|
||||
hoist-non-react-statics "^2.3.1"
|
||||
jss "^9.3.2"
|
||||
jss-preset-default "^4.0.1"
|
||||
prop-types "^15.6.0"
|
||||
theming "^1.3.0"
|
||||
|
||||
react-native-web@0.0.x:
|
||||
version "0.0.116"
|
||||
resolved "https://registry.yarnpkg.com/react-native-web/-/react-native-web-0.0.116.tgz#e05e376b34617a54d61826e4bc06b0bdbfd3f4b2"
|
||||
reactxp@^0.46.6:
|
||||
version "0.46.6"
|
||||
resolved "https://registry.yarnpkg.com/reactxp/-/reactxp-0.46.6.tgz#166a503a7147f3a1e29efc4469bda32603471a5f"
|
||||
dependencies:
|
||||
animated "^0.2.0"
|
||||
array-find-index "^1.0.2"
|
||||
babel-runtime "^6.23.0"
|
||||
create-react-class "^15.6.0"
|
||||
debounce "1.0.2"
|
||||
deep-assign "^2.0.0"
|
||||
fbjs "^0.8.12"
|
||||
hyphenate-style-name "^1.0.2"
|
||||
inline-style-prefixer "^3.0.6"
|
||||
normalize-css-color "^1.0.2"
|
||||
prop-types "^15.5.10"
|
||||
react-timer-mixin "^0.13.3"
|
||||
|
||||
react-primitives@^0.4.3:
|
||||
version "0.4.3"
|
||||
resolved "https://registry.yarnpkg.com/react-primitives/-/react-primitives-0.4.3.tgz#4970afda5a32dccf5ea180380e3a0e16192e4b83"
|
||||
dependencies:
|
||||
animated "^0.1.5"
|
||||
asap "^2.0.5"
|
||||
deline "^1.0.4"
|
||||
flexibility "^2.0.1"
|
||||
inline-style-prefixer "^2.0.5"
|
||||
invariant "^2.2.1"
|
||||
normalize-css-color "^1.0.1"
|
||||
prop-types "^15.5.10"
|
||||
react-native-web "0.0.x"
|
||||
react-timer-mixin "^0.13.3"
|
||||
string-hash "^1.1.3"
|
||||
|
||||
react-timer-mixin@^0.13.3:
|
||||
version "0.13.3"
|
||||
resolved "https://registry.yarnpkg.com/react-timer-mixin/-/react-timer-mixin-0.13.3.tgz#0da8b9f807ec07dc3e854d082c737c65605b3d22"
|
||||
|
||||
react@^15.5.4:
|
||||
version "15.6.1"
|
||||
resolved "https://registry.yarnpkg.com/react/-/react-15.6.1.tgz#baa8434ec6780bde997cdc380b79cd33b96393df"
|
||||
dependencies:
|
||||
create-react-class "^15.6.0"
|
||||
fbjs "^0.8.9"
|
||||
loose-envify "^1.1.0"
|
||||
object-assign "^4.1.0"
|
||||
prop-types "^15.5.10"
|
||||
|
||||
reactxp@^0.42.11:
|
||||
version "0.42.11"
|
||||
resolved "https://registry.yarnpkg.com/reactxp/-/reactxp-0.42.11.tgz#ec88014e354ddc627fea61ab6639e5970edb85ae"
|
||||
dependencies:
|
||||
"@types/lodash" "4.14.66"
|
||||
"@types/lodash" "^4.14.78"
|
||||
"@types/react" "^16.0.0"
|
||||
"@types/react-dom" "^16.0.0"
|
||||
assert "^1.3.0"
|
||||
ifvisible.js "^1.0.6"
|
||||
lodash "^4.17.1"
|
||||
prop-types "^15.5.9"
|
||||
rebound "^0.0.13"
|
||||
subscribableevent "^1.0.0"
|
||||
synctasks "^0.2.9"
|
||||
synctasks "^0.3.0"
|
||||
|
||||
rebound@^0.0.13:
|
||||
version "0.0.13"
|
||||
@@ -1295,14 +1214,6 @@ regenerate@^1.2.1:
|
||||
version "1.3.2"
|
||||
resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.3.2.tgz#d1941c67bad437e1be76433add5b385f95b19260"
|
||||
|
||||
regenerator-runtime@^0.10.0:
|
||||
version "0.10.5"
|
||||
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz#336c3efc1220adcedda2c9fab67b5a7955a33658"
|
||||
|
||||
regenerator-runtime@^0.11.0:
|
||||
version "0.11.0"
|
||||
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.0.tgz#7e54fe5b5ccd5d6624ea6255c3473be090b802e1"
|
||||
|
||||
regexpu-core@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-1.0.0.tgz#86a763f58ee4d7c2f6b102e4764050de7ed90c6b"
|
||||
@@ -1321,12 +1232,6 @@ regjsparser@^0.1.4:
|
||||
dependencies:
|
||||
jsesc "~0.5.0"
|
||||
|
||||
repeating@^2.0.0:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda"
|
||||
dependencies:
|
||||
is-finite "^1.0.0"
|
||||
|
||||
require-from-string@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.1.tgz#c545233e9d7da6616e9d59adfb39fc9f588676ff"
|
||||
@@ -1381,51 +1286,54 @@ strip-ansi@^3.0.0:
|
||||
dependencies:
|
||||
ansi-regex "^2.0.0"
|
||||
|
||||
style-loader@^0.19.0:
|
||||
version "0.19.0"
|
||||
resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-0.19.0.tgz#7258e788f0fee6a42d710eaf7d6c2412a4c50759"
|
||||
style-loader@^0.19.1:
|
||||
version "0.19.1"
|
||||
resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-0.19.1.tgz#591ffc80bcefe268b77c5d9ebc0505d772619f85"
|
||||
dependencies:
|
||||
loader-utils "^1.0.2"
|
||||
schema-utils "^0.3.0"
|
||||
|
||||
styled-components@^2.2.3:
|
||||
version "2.2.3"
|
||||
resolved "https://registry.yarnpkg.com/styled-components/-/styled-components-2.2.3.tgz#154575c269880c840f903f580287dab155cf684c"
|
||||
styled-components@^2.3.2:
|
||||
version "2.3.2"
|
||||
resolved "https://registry.yarnpkg.com/styled-components/-/styled-components-2.3.2.tgz#323d86cc9ac89f3fd233a2dfa0849da236f143e3"
|
||||
dependencies:
|
||||
buffer "^5.0.3"
|
||||
css-to-react-native "^2.0.3"
|
||||
fbjs "^0.8.9"
|
||||
hoist-non-react-statics "^1.2.0"
|
||||
is-function "^1.0.1"
|
||||
is-plain-object "^2.0.1"
|
||||
prop-types "^15.5.4"
|
||||
stylis "3.x"
|
||||
stylis "^3.4.0"
|
||||
supports-color "^3.2.3"
|
||||
|
||||
styletron-client@^2.5.7:
|
||||
version "2.5.7"
|
||||
resolved "https://registry.yarnpkg.com/styletron-client/-/styletron-client-2.5.7.tgz#104fa4dc564cd3fe78eb92488e5ef9039c9e242f"
|
||||
styletron-client@^3.0.0-rc.5:
|
||||
version "3.0.0-rc.5"
|
||||
resolved "https://registry.yarnpkg.com/styletron-client/-/styletron-client-3.0.0-rc.5.tgz#275ca0b5f971d244f0e42079ad570be9c31a2a70"
|
||||
dependencies:
|
||||
styletron-core "^2.5.7"
|
||||
styletron-core "^3.0.0-rc.3"
|
||||
|
||||
styletron-core@^2.5.7:
|
||||
version "2.5.7"
|
||||
resolved "https://registry.yarnpkg.com/styletron-core/-/styletron-core-2.5.7.tgz#2c4a1fae537b42235462e438c24ab619bbf8993e"
|
||||
styletron-core@^3.0.0-rc.3:
|
||||
version "3.0.0-rc.3"
|
||||
resolved "https://registry.yarnpkg.com/styletron-core/-/styletron-core-3.0.0-rc.3.tgz#9468e275d9085d2e5d6d6468cc6d8733dbfa3cba"
|
||||
|
||||
styletron-utils@^2.5.4:
|
||||
version "2.5.4"
|
||||
resolved "https://registry.yarnpkg.com/styletron-utils/-/styletron-utils-2.5.4.tgz#f08cca7d58ee0338ce85e408cb32900e65620240"
|
||||
styletron-utils@^3.0.0-rc.3:
|
||||
version "3.0.0-rc.3"
|
||||
resolved "https://registry.yarnpkg.com/styletron-utils/-/styletron-utils-3.0.0-rc.3.tgz#21fef2099f1c368e6ff2b8f76bf7a64bb547b760"
|
||||
dependencies:
|
||||
inline-style-prefixer "^2.0.1"
|
||||
inline-style-prefixer "^3.0.3"
|
||||
|
||||
stylis-rule-sheet@^0.0.5:
|
||||
version "0.0.5"
|
||||
resolved "https://registry.yarnpkg.com/stylis-rule-sheet/-/stylis-rule-sheet-0.0.5.tgz#ebae935cc1f6fb31b9b62dba47f2ea8b833dad9f"
|
||||
|
||||
stylis@3.x, stylis@^3.3.2:
|
||||
stylis@^3.3.2:
|
||||
version "3.4.0"
|
||||
resolved "https://registry.yarnpkg.com/stylis/-/stylis-3.4.0.tgz#55c6530ebceeca5976d54fb4adc67578afee828d"
|
||||
|
||||
stylis@^3.4.0:
|
||||
version "3.4.5"
|
||||
resolved "https://registry.yarnpkg.com/stylis/-/stylis-3.4.5.tgz#d7b9595fc18e7b9c8775eca8270a9a1d3e59806e"
|
||||
|
||||
subscribableevent@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/subscribableevent/-/subscribableevent-1.0.0.tgz#bde9500fa9009c7740c924109bac6119cd9898e6"
|
||||
@@ -1461,27 +1369,30 @@ svgo@^0.7.0:
|
||||
sax "~1.2.1"
|
||||
whet.extend "~0.9.9"
|
||||
|
||||
synctasks@^0.2.9:
|
||||
version "0.2.17"
|
||||
resolved "https://registry.yarnpkg.com/synctasks/-/synctasks-0.2.17.tgz#38852f008878de2e941b6e458ddf552245268da1"
|
||||
|
||||
theming@^1.1.0:
|
||||
symbol-observable@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/theming/-/theming-1.1.0.tgz#0562760b55a1b919c2d5eeb94130351f8958e13a"
|
||||
resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.1.0.tgz#5c68fd8d54115d9dfb72a84720549222e8db9b32"
|
||||
|
||||
synctasks@^0.3.0:
|
||||
version "0.3.1"
|
||||
resolved "https://registry.yarnpkg.com/synctasks/-/synctasks-0.3.1.tgz#1f9012b23792ad775ba2693e0cafcfcd65b80d97"
|
||||
|
||||
theming@^1.3.0:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/theming/-/theming-1.3.0.tgz#286d5bae80be890d0adc645e5ca0498723725bdc"
|
||||
dependencies:
|
||||
brcast "^2.0.0"
|
||||
brcast "^3.0.1"
|
||||
is-function "^1.0.1"
|
||||
is-plain-object "^2.0.1"
|
||||
prop-types "^15.5.8"
|
||||
react "^15.5.4"
|
||||
|
||||
through@^2.3.8:
|
||||
version "2.3.8"
|
||||
resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
|
||||
|
||||
to-fast-properties@^1.0.3:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47"
|
||||
to-fast-properties@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e"
|
||||
|
||||
touch@^1.0.0:
|
||||
version "1.0.0"
|
||||
@@ -1489,10 +1400,6 @@ touch@^1.0.0:
|
||||
dependencies:
|
||||
nopt "~1.0.10"
|
||||
|
||||
trim-right@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003"
|
||||
|
||||
ua-parser-js@^0.7.9:
|
||||
version "0.7.12"
|
||||
resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.12.tgz#04c81a99bdd5dc52263ea29d24c6bf8d4818a4bb"
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
# Direct manipulation
|
||||
|
||||
React Native for Web provides several methods to directly access the underlying
|
||||
DOM node. This can be useful when you need to make changes directly to a
|
||||
component without using state/props to trigger a re-render of the entire
|
||||
subtree, or when you want to focus a view or measure its on-screen dimensions.
|
||||
React Native provides several methods to directly access the underlying host
|
||||
node. This can be useful when you need to make changes directly to a component
|
||||
without using state/props to trigger a re-render of the entire subtree, or when
|
||||
you want to focus a view or measure its on-screen dimensions.
|
||||
|
||||
The methods described are available on most of the default components provided
|
||||
by React Native for Web. Note, however, that they are *not* available on the
|
||||
composite components that you define in your own app.
|
||||
by React Native for Web. Note, however, that they are *not* available on the composite
|
||||
components that you define in your own app.
|
||||
|
||||
## Instance methods
|
||||
|
||||
@@ -35,11 +35,17 @@ Like `measure`, but measures the view relative to another view, specified as
|
||||
`relativeToNativeNode`. This means that the returned `x`, `y` are relative to
|
||||
the origin `x`, `y` of the ancestor view.
|
||||
|
||||
As always, to obtain a native node handle for a component, you can use
|
||||
`findNodeHandle(component)`.
|
||||
|
||||
**measureInWindow**(callback: (x, y, width, height) => void)
|
||||
|
||||
Determines the location of the given view in the window and returns the values
|
||||
via an async callback.
|
||||
|
||||
**setNativeProps**(nativeProps: Object)
|
||||
|
||||
This function sends props straight to the underlying DOM node. See the [direct
|
||||
manipulation](../guides/direct-manipulation.md) guide for cases where
|
||||
`setNativeProps` should be used.
|
||||
This function sends props straight to the underlying DOM node.
|
||||
|
||||
## About `setNativeProps`
|
||||
|
||||
|
||||
@@ -10,14 +10,26 @@ polyfill.
|
||||
## Web packager
|
||||
|
||||
[Webpack](https://webpack.js.org) is a popular build tool for web apps. Below is an
|
||||
example of how to configure a build that uses [Babel](https://babeljs.io/) to
|
||||
compile your JavaScript for the web.
|
||||
_example_ of how to configure a build that uses [Babel](https://babeljs.io/) to
|
||||
compile your JavaScript for the web. Please refer to the webpack documentation
|
||||
when setting up your project.
|
||||
|
||||
Install webpack-related dependencies, for example:
|
||||
|
||||
```
|
||||
yarn add --dev babel-loader url-loader webpack webpack-dev-server
|
||||
```
|
||||
|
||||
Create a `web/webpack.config.js` file:
|
||||
|
||||
```js
|
||||
// web/webpack.config.js
|
||||
|
||||
const path = require('path');
|
||||
const webpack = require('webpack');
|
||||
|
||||
const appDirectory = path.resolve(__dirname, '../');
|
||||
|
||||
// This is needed for webpack to compile JavaScript.
|
||||
// Many OSS React Native packages are not compiled to ES5 before being
|
||||
// published. If you depend on uncompiled packages they may cause webpack build
|
||||
@@ -25,25 +37,26 @@ Create a `web/webpack.config.js` file:
|
||||
// `node_module`.
|
||||
const babelLoaderConfiguration = {
|
||||
test: /\.js$/,
|
||||
// Add every directory that needs to be compiled by Babel during the build
|
||||
// Add every directory that needs to be compiled by Babel during the build.
|
||||
include: [
|
||||
path.resolve(__dirname, 'src'),
|
||||
path.resolve(__dirname, 'node_modules/react-native-uncompiled')
|
||||
path.resolve(appDirectory, 'index.web.js'),
|
||||
path.resolve(appDirectory, 'src'),
|
||||
path.resolve(appDirectory, 'node_modules/react-native-uncompiled')
|
||||
],
|
||||
use: {
|
||||
loader: 'babel-loader',
|
||||
options: {
|
||||
cacheDirectory: true,
|
||||
// This aliases 'react-native' to 'react-native-web' and includes only
|
||||
// the modules needed by the app
|
||||
plugins: ['react-native-web/babel'],
|
||||
// The 'react-native' preset is recommended (or use your own .babelrc)
|
||||
// the modules needed by the app.
|
||||
plugins: ['react-native-web/babel', 'transform-runtime'],
|
||||
// The 'react-native' preset is recommended (or use your own .babelrc).
|
||||
presets: ['react-native']
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// This is needed for webpack to import static images in JavaScript files
|
||||
// This is needed for webpack to import static images in JavaScript files.
|
||||
const imageLoaderConfiguration = {
|
||||
test: /\.(gif|jpe?g|png|svg)$/,
|
||||
use: {
|
||||
@@ -55,6 +68,15 @@ const imageLoaderConfiguration = {
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
// your web-specific entry file
|
||||
entry: path.resolve(appDirectory, 'index.web.js'),
|
||||
|
||||
// configures where the build ends up
|
||||
output: {
|
||||
filename: 'bundle.web.js',
|
||||
path: path.resolve(appDirectory, 'dist')
|
||||
},
|
||||
|
||||
// ...the rest of your config
|
||||
|
||||
module: {
|
||||
@@ -69,7 +91,8 @@ module.exports = {
|
||||
// builds to eliminate development checks and reduce build size. You may
|
||||
// wish to include additional optimizations.
|
||||
new webpack.DefinePlugin({
|
||||
'process.env.NODE_ENV': JSON.stringify('production')
|
||||
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development'),
|
||||
__DEV__: process.env.NODE_ENV === 'production' || true
|
||||
})
|
||||
],
|
||||
|
||||
@@ -82,24 +105,20 @@ module.exports = {
|
||||
}
|
||||
```
|
||||
|
||||
To run in development:
|
||||
To run in development from the root of your application:
|
||||
|
||||
```
|
||||
./node_modules/.bin/webpack-dev-server -d --config web/webpack.config.js --inline --hot --colors
|
||||
./node_modules/.bin/webpack-dev-server -d --config ./web/webpack.config.js --inline --hot --colors
|
||||
```
|
||||
|
||||
To build for production:
|
||||
|
||||
```
|
||||
./node_modules/.bin/webpack -p --config web/webpack.config.js
|
||||
./node_modules/.bin/webpack -p --config ./web/webpack.config.js
|
||||
```
|
||||
|
||||
Please refer to the Webpack documentation for more information on configuration.
|
||||
|
||||
## Web entry
|
||||
|
||||
Create a `index.web.js` file (or simply `index.js` for web-only apps).
|
||||
|
||||
### Client-side rendering
|
||||
|
||||
Rendering using `AppRegistry`:
|
||||
|
||||
93
docs/storybook/1-components/CheckBox/CheckBoxScreen.js
Normal file
93
docs/storybook/1-components/CheckBox/CheckBoxScreen.js
Normal file
@@ -0,0 +1,93 @@
|
||||
/* eslint-disable react/jsx-sort-props */
|
||||
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import CustomSize from './examples/CustomSize';
|
||||
import PropColor from './examples/PropColor';
|
||||
import PropDisabled from './examples/PropDisabled';
|
||||
import PropOnValueChange from './examples/PropOnValueChange';
|
||||
import PropValue from './examples/PropValue';
|
||||
import React from 'react';
|
||||
import UIExplorer, {
|
||||
AppText,
|
||||
Code,
|
||||
Description,
|
||||
DocItem,
|
||||
Section,
|
||||
storiesOf
|
||||
} from '../../ui-explorer';
|
||||
|
||||
const CheckBoxScreen = () => (
|
||||
<UIExplorer title="CheckBox" url="components/CheckBox">
|
||||
<Description>
|
||||
<AppText>
|
||||
This is a controlled component that requires an <Code>onValueChange</Code> callback that
|
||||
updates the value prop in order for the component to reflect user actions. If the{' '}
|
||||
<Code>value</Code> prop is not updated, the component will continue to render the supplied{' '}
|
||||
<Code>value</Code> prop instead of the expected result of any user actions.
|
||||
</AppText>
|
||||
</Description>
|
||||
|
||||
<Section title="Props">
|
||||
<DocItem name="...View props" />
|
||||
|
||||
<DocItem
|
||||
description="Customize the color of the checkbox."
|
||||
example={{
|
||||
render: () => <PropColor />
|
||||
}}
|
||||
label="web"
|
||||
name="color"
|
||||
typeInfo="?color"
|
||||
/>
|
||||
|
||||
<DocItem
|
||||
description="If true, the user won't be able to interact with the checkbox."
|
||||
example={{
|
||||
render: () => <PropDisabled />
|
||||
}}
|
||||
name="disabled"
|
||||
typeInfo="?boolean = false"
|
||||
/>
|
||||
|
||||
<DocItem
|
||||
description="Invoked with the event when the value changes."
|
||||
name="onChange"
|
||||
typeInfo="?function"
|
||||
/>
|
||||
|
||||
<DocItem
|
||||
description="Invoked with the new value when the value changes."
|
||||
example={{
|
||||
render: () => <PropOnValueChange />
|
||||
}}
|
||||
name="onValueChange"
|
||||
typeInfo="?function"
|
||||
/>
|
||||
|
||||
<DocItem
|
||||
description="The value of the checkbox. If `true` the checkbox will be checked."
|
||||
example={{
|
||||
render: () => <PropValue />
|
||||
}}
|
||||
name="value"
|
||||
typeInfo="?boolean = false"
|
||||
/>
|
||||
</Section>
|
||||
|
||||
<Section title="More examples">
|
||||
<DocItem
|
||||
description="The checkbox size can be controlled by the 'height' and 'width' style properties"
|
||||
example={{
|
||||
code: '<CheckBox style={{ height: 32, width: 32 }} />',
|
||||
render: () => <CustomSize />
|
||||
}}
|
||||
name="Custom size"
|
||||
/>
|
||||
</Section>
|
||||
</UIExplorer>
|
||||
);
|
||||
|
||||
storiesOf('Components', module).add('CheckBox', CheckBoxScreen);
|
||||
20
docs/storybook/1-components/CheckBox/examples/CustomSize.js
Normal file
20
docs/storybook/1-components/CheckBox/examples/CustomSize.js
Normal file
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import styles from './styles';
|
||||
import { CheckBox, View } from 'react-native';
|
||||
|
||||
const CustomSizeExample = () => (
|
||||
<View style={styles.row}>
|
||||
<View style={styles.marginRight}>
|
||||
<CheckBox style={{ height: 20, width: 20 }} value />
|
||||
</View>
|
||||
<View style={styles.marginRight}>
|
||||
<CheckBox style={{ height: 32, width: 32 }} value />
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
|
||||
export default CustomSizeExample;
|
||||
20
docs/storybook/1-components/CheckBox/examples/PropColor.js
Normal file
20
docs/storybook/1-components/CheckBox/examples/PropColor.js
Normal file
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import styles from './styles';
|
||||
import { CheckBox, View } from 'react-native';
|
||||
|
||||
const CheckBoxColorExample = () => (
|
||||
<View style={styles.row}>
|
||||
<View style={styles.marginRight}>
|
||||
<CheckBox color="#1DA1F2" value />
|
||||
</View>
|
||||
<View style={styles.marginRight}>
|
||||
<CheckBox color="#F45D22" value />
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
|
||||
export default CheckBoxColorExample;
|
||||
20
docs/storybook/1-components/CheckBox/examples/PropDisabled.js
Executable file
20
docs/storybook/1-components/CheckBox/examples/PropDisabled.js
Executable file
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import styles from './styles';
|
||||
import { CheckBox, View } from 'react-native';
|
||||
|
||||
const CheckBoxDisabledExample = () => (
|
||||
<View style={styles.row}>
|
||||
<View style={styles.marginRight}>
|
||||
<CheckBox disabled value={false} />
|
||||
</View>
|
||||
<View style={styles.marginRight}>
|
||||
<CheckBox disabled value />
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
|
||||
export default CheckBoxDisabledExample;
|
||||
59
docs/storybook/1-components/CheckBox/examples/PropOnValueChange.js
Executable file
59
docs/storybook/1-components/CheckBox/examples/PropOnValueChange.js
Executable file
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import styles from './styles';
|
||||
import React, { PureComponent } from 'react';
|
||||
import { CheckBox, Text, View } from 'react-native';
|
||||
|
||||
class CheckBoxOnValueChangeExample extends PureComponent {
|
||||
state = {
|
||||
eventSwitchIsOn: false,
|
||||
eventSwitchRegressionIsOn: true
|
||||
};
|
||||
|
||||
render() {
|
||||
const { eventSwitchIsOn, eventSwitchRegressionIsOn } = this.state;
|
||||
|
||||
return (
|
||||
<View style={styles.row}>
|
||||
<View style={[styles.alignCenter, styles.marginRight]}>
|
||||
<CheckBox
|
||||
onValueChange={this._handleEventSwitch}
|
||||
style={styles.marginBottom}
|
||||
value={eventSwitchIsOn}
|
||||
/>
|
||||
<CheckBox
|
||||
onValueChange={this._handleEventSwitch}
|
||||
style={styles.marginBottom}
|
||||
value={eventSwitchIsOn}
|
||||
/>
|
||||
<Text>{eventSwitchIsOn ? 'On' : 'Off'}</Text>
|
||||
</View>
|
||||
<View style={styles.alignCenter}>
|
||||
<CheckBox
|
||||
onValueChange={this._handleEventSwitchRegression}
|
||||
style={styles.marginBottom}
|
||||
value={eventSwitchRegressionIsOn}
|
||||
/>
|
||||
<CheckBox
|
||||
onValueChange={this._handleEventSwitchRegression}
|
||||
style={styles.marginBottom}
|
||||
value={eventSwitchRegressionIsOn}
|
||||
/>
|
||||
<Text>{eventSwitchRegressionIsOn ? 'On' : 'Off'}</Text>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
_handleEventSwitch = value => {
|
||||
this.setState({ eventSwitchIsOn: value });
|
||||
};
|
||||
|
||||
_handleEventSwitchRegression = value => {
|
||||
this.setState({ eventSwitchRegressionIsOn: value });
|
||||
};
|
||||
}
|
||||
|
||||
export default CheckBoxOnValueChangeExample;
|
||||
20
docs/storybook/1-components/CheckBox/examples/PropValue.js
Executable file
20
docs/storybook/1-components/CheckBox/examples/PropValue.js
Executable file
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import styles from './styles';
|
||||
import { CheckBox, View } from 'react-native';
|
||||
|
||||
const CheckBoxValueExample = () => (
|
||||
<View style={styles.row}>
|
||||
<View style={styles.marginRight}>
|
||||
<CheckBox value={false} />
|
||||
</View>
|
||||
<View style={styles.marginRight}>
|
||||
<CheckBox value />
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
|
||||
export default CheckBoxValueExample;
|
||||
23
docs/storybook/1-components/CheckBox/examples/styles.js
Executable file
23
docs/storybook/1-components/CheckBox/examples/styles.js
Executable file
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import { StyleSheet } from 'react-native';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
row: {
|
||||
flexDirection: 'row',
|
||||
flexWrap: 'wrap'
|
||||
},
|
||||
marginRight: {
|
||||
marginRight: 10
|
||||
},
|
||||
marginBottom: {
|
||||
marginBottom: 10
|
||||
},
|
||||
alignCenter: {
|
||||
alignItems: 'center'
|
||||
}
|
||||
});
|
||||
|
||||
export default styles;
|
||||
36
docs/storybook/1-components/CheckBox/helpers.js
Normal file
36
docs/storybook/1-components/CheckBox/helpers.js
Normal file
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { StyleSheet, View } from 'react-native';
|
||||
|
||||
const DividerHorizontal = () => <View style={styles.horizontalDivider} />;
|
||||
const DividerVertical = () => <View style={styles.verticalDivider} />;
|
||||
|
||||
export const styles = StyleSheet.create({
|
||||
horizontalDivider: {
|
||||
width: '0.6rem'
|
||||
},
|
||||
verticalDivider: {
|
||||
height: '1.3125rem'
|
||||
},
|
||||
row: {
|
||||
flexDirection: 'row',
|
||||
flexWrap: 'wrap'
|
||||
},
|
||||
marginRight: {
|
||||
marginRight: 10
|
||||
},
|
||||
marginBottom: {
|
||||
marginBottom: 10
|
||||
},
|
||||
marginVertical: {
|
||||
marginVertical: 5
|
||||
},
|
||||
alignCenter: {
|
||||
alignItems: 'center'
|
||||
}
|
||||
});
|
||||
|
||||
export { DividerHorizontal, DividerVertical };
|
||||
32
docs/storybook/1-components/Image/ImageBackgroundScreen.js
Normal file
32
docs/storybook/1-components/Image/ImageBackgroundScreen.js
Normal file
@@ -0,0 +1,32 @@
|
||||
/* eslint-disable react/jsx-sort-props */
|
||||
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import PropChildren from './examples/PropChildren';
|
||||
import UIExplorer, { Description, DocItem, Section, storiesOf } from '../../ui-explorer';
|
||||
|
||||
const ImageBackgroundScreen = () => (
|
||||
<UIExplorer title="ImageBackground" url="1-components/ImageBackground">
|
||||
<Description>A image component with support for child content.</Description>
|
||||
|
||||
<Section title="Props">
|
||||
<DocItem name="...Image props" />
|
||||
|
||||
<DocItem
|
||||
name="children"
|
||||
typeInfo="?any"
|
||||
description="Content to display over the image."
|
||||
example={{
|
||||
render: () => <PropChildren />
|
||||
}}
|
||||
/>
|
||||
|
||||
<DocItem name="imageStyle" typeInfo="?style" description="Styles for the inner image." />
|
||||
</Section>
|
||||
</UIExplorer>
|
||||
);
|
||||
|
||||
storiesOf('Components', module).add('ImageBackground', ImageBackgroundScreen);
|
||||
@@ -5,7 +5,6 @@
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import PropChildren from './examples/PropChildren';
|
||||
import PropDefaultSource from './examples/PropDefaultSource';
|
||||
import PropDraggable from './examples/PropDraggable';
|
||||
import PropOnError from './examples/PropOnError';
|
||||
@@ -35,15 +34,6 @@ const ImageScreen = () => (
|
||||
<Section title="Props">
|
||||
<DocItem name="...View props" />
|
||||
|
||||
<DocItem
|
||||
name="children"
|
||||
typeInfo="?any"
|
||||
description="Content to display over the image."
|
||||
example={{
|
||||
render: () => <PropChildren />
|
||||
}}
|
||||
/>
|
||||
|
||||
<DocItem
|
||||
name="defaultSource"
|
||||
typeInfo="?object"
|
||||
|
||||
@@ -32,6 +32,7 @@ class NetworkImageExample extends PureComponent {
|
||||
|
||||
return (
|
||||
<View>
|
||||
{loader}
|
||||
<Image
|
||||
defaultSource={sources.placeholder}
|
||||
onError={this._handleError}
|
||||
@@ -40,9 +41,7 @@ class NetworkImageExample extends PureComponent {
|
||||
onLoadStart={this._handleLoadStart}
|
||||
source={this.props.source}
|
||||
style={helpers.styles.base}
|
||||
>
|
||||
{loader}
|
||||
</Image>
|
||||
/>
|
||||
{this.state.message && <Text style={helpers.styles.marginTop}>{this.state.message}</Text>}
|
||||
</View>
|
||||
);
|
||||
|
||||
@@ -4,12 +4,12 @@
|
||||
|
||||
import sources from '../sources';
|
||||
import React from 'react';
|
||||
import { Image, StyleSheet, Text } from 'react-native';
|
||||
import { ImageBackground, StyleSheet, Text } from 'react-native';
|
||||
|
||||
const ImageChildrenExample = () => (
|
||||
<Image source={sources.large} style={styles.image}>
|
||||
<ImageBackground source={sources.large} style={styles.image}>
|
||||
<Text style={styles.text}>Child content</Text>
|
||||
</Image>
|
||||
</ImageBackground>
|
||||
);
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
|
||||
113
docs/storybook/1-components/Picker/PickerScreen.js
Normal file
113
docs/storybook/1-components/Picker/PickerScreen.js
Normal file
@@ -0,0 +1,113 @@
|
||||
/* eslint-disable react/jsx-sort-props, react/jsx-no-bind, no-alert */
|
||||
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import PickerExample from './examples/PickerExample';
|
||||
import UIExplorer, {
|
||||
AppText,
|
||||
Description,
|
||||
DocItem,
|
||||
Section,
|
||||
StyleList,
|
||||
storiesOf
|
||||
} from '../../ui-explorer';
|
||||
import { View } from 'react-native';
|
||||
|
||||
const PickerScreen = () => (
|
||||
<View>
|
||||
<UIExplorer title="Picker">
|
||||
<Description>
|
||||
<AppText>Renders the native <select> component.</AppText>
|
||||
</Description>
|
||||
<Section title="Props">
|
||||
<DocItem
|
||||
name="children"
|
||||
typeInfo="?Array<Picker.Item>"
|
||||
description="The items to display in the picker."
|
||||
example={{
|
||||
code: `<Picker>
|
||||
<Picker.Item label="Goblet of Fire" />
|
||||
<Picker.Item label="Order of the Phoenix" />
|
||||
</Picker>`
|
||||
}}
|
||||
/>
|
||||
|
||||
<DocItem
|
||||
name="enabled"
|
||||
typeInfo="?boolean"
|
||||
description="If set to false, the picker will be disabled, i.e., the user will not be able to make a selection."
|
||||
example={{
|
||||
render: () => <PickerExample enabled={false} />
|
||||
}}
|
||||
/>
|
||||
|
||||
<DocItem
|
||||
name="onValueChange"
|
||||
typeInfo="?(itemValue, itemIndex) => void"
|
||||
description="Callback for when an item is selected. This is called with the value and index prop of the item that was selected."
|
||||
example={{
|
||||
render: () => (
|
||||
<PickerExample
|
||||
onValueChange={(itemValue, itemPosition) => {
|
||||
window.alert(`itemValue: ${itemValue}, itemPosition: ${itemPosition}`);
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
|
||||
<DocItem
|
||||
name="selectedValue"
|
||||
typeInfo="?string"
|
||||
description="Select the item with the matching value."
|
||||
example={{
|
||||
render: () => <PickerExample selectedValue="book-3" />
|
||||
}}
|
||||
/>
|
||||
|
||||
<DocItem
|
||||
name="style"
|
||||
typeInfo="?style"
|
||||
description={
|
||||
<StyleList
|
||||
stylePropTypes={[
|
||||
{
|
||||
name: '…View#style'
|
||||
},
|
||||
{
|
||||
name: 'color',
|
||||
typeInfo: 'color'
|
||||
}
|
||||
]}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<DocItem
|
||||
name="testID"
|
||||
typeInfo="?string"
|
||||
description="Used to locate this view in end-to-end tests."
|
||||
/>
|
||||
</Section>
|
||||
</UIExplorer>
|
||||
|
||||
<UIExplorer title="Picker.Item" url="1-components/Picker">
|
||||
<Description>Individual selectable item in a Picker.</Description>
|
||||
|
||||
<Section title="Props">
|
||||
<DocItem name="label" typeInfo="string" description="Text to display for this item" />
|
||||
<DocItem name="testID" typeInfo="?string" />
|
||||
<DocItem
|
||||
name="value"
|
||||
typeInfo="?number | string"
|
||||
description="The value to be passed to the picker's 'onValueChange' callback when this item is selected."
|
||||
/>
|
||||
</Section>
|
||||
</UIExplorer>
|
||||
</View>
|
||||
);
|
||||
|
||||
storiesOf('Components', module).add('Picker', PickerScreen);
|
||||
28
docs/storybook/1-components/Picker/examples/PickerExample.js
Normal file
28
docs/storybook/1-components/Picker/examples/PickerExample.js
Normal file
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { Picker, StyleSheet, View } from 'react-native';
|
||||
|
||||
const PickerExample = props => (
|
||||
<View style={styles.root}>
|
||||
<Picker {...props}>
|
||||
<Picker.Item label="Sourcerer's Stone" value="book-1" />
|
||||
<Picker.Item label="Chamber of Secrets" value="book-2" />
|
||||
<Picker.Item label="Prisoner of Azkaban" value="book-3" />
|
||||
<Picker.Item label="Goblet of Fire" value="book-4" />
|
||||
<Picker.Item label="Order of the Phoenix" value="book-5" />
|
||||
<Picker.Item label="Half-Blood Prince" value="book-6" />
|
||||
<Picker.Item label="Deathly Hallows" value="book-7" />
|
||||
</Picker>
|
||||
</View>
|
||||
);
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
rootl: {
|
||||
alignItems: 'flex-start'
|
||||
}
|
||||
});
|
||||
|
||||
export default PickerExample;
|
||||
@@ -46,9 +46,11 @@ export default class TextEventsExample extends React.Component {
|
||||
event.nativeEvent.selection.start +
|
||||
',' +
|
||||
event.nativeEvent.selection.end
|
||||
)}
|
||||
)
|
||||
}
|
||||
onSubmitEditing={event =>
|
||||
this.updateText('onSubmitEditing text: ' + event.nativeEvent.text)}
|
||||
this.updateText('onSubmitEditing text: ' + event.nativeEvent.text)
|
||||
}
|
||||
placeholder="Enter text to see events"
|
||||
style={[helperStyles.textinput, { maxWidth: 200 }]}
|
||||
/>
|
||||
|
||||
@@ -21,6 +21,22 @@ const StyleSheetScreen = () => (
|
||||
</Description>
|
||||
|
||||
<Section title="Methods">
|
||||
<DocItem
|
||||
description={
|
||||
<AppText>
|
||||
Combines two styles such that <Code>style2</Code> will override any styles in{' '}
|
||||
<Code>style1</Code>. If either style is falsy, the other one is returned without
|
||||
allocating an array, saving allocations and maintaining reference equality for{' '}
|
||||
<Code>PureComponent</Code> checks.
|
||||
</AppText>
|
||||
}
|
||||
example={{
|
||||
code: 'StyleSheet.compose(style1, style2);'
|
||||
}}
|
||||
name="compose"
|
||||
typeInfo="(style1, style2) => style"
|
||||
/>
|
||||
|
||||
<DocItem
|
||||
description="Each key of the object passed to `create` must define a style object. The returned object replaces style objects with IDs"
|
||||
example={{
|
||||
@@ -88,7 +104,11 @@ StyleSheet.flatten([styles.listItem, styles.selectedListItem]);`
|
||||
typeInfo="object"
|
||||
/>
|
||||
|
||||
<DocItem name="hairlineWidth" typeInfo="number" />
|
||||
<DocItem
|
||||
description="Enables borders of just one physical pixel on retina screens, otherwise it is equal to a CSS value of 1px."
|
||||
name="hairlineWidth"
|
||||
typeInfo="number"
|
||||
/>
|
||||
</Section>
|
||||
</UIExplorer>
|
||||
);
|
||||
|
||||
52
package.json
52
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "react-native-web",
|
||||
"version": "0.1.16",
|
||||
"version": "0.2.1",
|
||||
"description": "React Native for Web",
|
||||
"main": "dist/index.js",
|
||||
"files": [
|
||||
@@ -19,12 +19,12 @@
|
||||
"docs:start": "cd docs && yarn && yarn start",
|
||||
"docs:release": "cd docs && yarn release",
|
||||
"flow": "flow",
|
||||
"fmt": "find babel benchmarks docs jest src -name '*.js' | grep -v -E '(node_modules|dist)' | xargs yarn fmt:cmd",
|
||||
"fmt": "find babel benchmarks docs jest src -name '*.js' | grep -v -E '(node_modules|dist|vendor)' | xargs yarn fmt:cmd",
|
||||
"fmt:cmd": "prettier --print-width=100 --single-quote --write",
|
||||
"jest": "jest",
|
||||
"jest:watch": "yarn test -- --watch",
|
||||
"lint": "yarn lint:cmd -- babel benchmarks docs jest src",
|
||||
"lint:cmd": "eslint --ignore-path .gitignore --fix",
|
||||
"jest:watch": "yarn test --watch",
|
||||
"lint": "yarn lint:cmd babel benchmarks docs jest src",
|
||||
"lint:cmd": "eslint --ignore-path .gitignore --ignore-pattern '/src/vendor/*' --fix",
|
||||
"precommit": "lint-staged",
|
||||
"release": "yarn lint && yarn test && yarn build && npm publish",
|
||||
"test": "flow && jest"
|
||||
@@ -61,48 +61,48 @@
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"animated": "^0.2.0",
|
||||
"array-find-index": "^1.0.2",
|
||||
"babel-runtime": "^6.26.0",
|
||||
"create-react-class": "^15.6.2",
|
||||
"debounce": "1.0.2",
|
||||
"debounce": "^1.1.0",
|
||||
"deep-assign": "^2.0.0",
|
||||
"fbjs": "^0.8.16",
|
||||
"hyphenate-style-name": "^1.0.2",
|
||||
"inline-style-prefixer": "^3.0.8",
|
||||
"normalize-css-color": "^1.0.2",
|
||||
"prop-types": "^15.6.0",
|
||||
"react-art": "^16.2.0",
|
||||
"react-timer-mixin": "^0.13.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-cli": "^6.26.0",
|
||||
"babel-core": "^6.26.0",
|
||||
"babel-eslint": "^7.2.3",
|
||||
"babel-eslint": "^8.0.3",
|
||||
"babel-loader": "^7.1.2",
|
||||
"babel-plugin-tester": "^4.0.0",
|
||||
"babel-plugin-transform-react-remove-prop-types": "^0.4.9",
|
||||
"babel-plugin-transform-react-remove-prop-types": "^0.4.10",
|
||||
"babel-preset-react-native": "^4.0.0",
|
||||
"caniuse-api": "^2.0.0",
|
||||
"del-cli": "^1.1.0",
|
||||
"enzyme": "^3.1.0",
|
||||
"enzyme-adapter-react-16": "^1.0.2",
|
||||
"enzyme-to-json": "^3.1.4",
|
||||
"eslint": "^4.6.1",
|
||||
"eslint-config-prettier": "^2.6.0",
|
||||
"eslint-plugin-promise": "^3.5.0",
|
||||
"eslint-plugin-react": "^7.4.0",
|
||||
"file-loader": "^1.1.4",
|
||||
"flow-bin": "^0.49.1",
|
||||
"enzyme": "^3.2.0",
|
||||
"enzyme-adapter-react-16": "^1.1.0",
|
||||
"enzyme-to-json": "^3.2.2",
|
||||
"eslint": "^4.12.1",
|
||||
"eslint-config-prettier": "^2.9.0",
|
||||
"eslint-plugin-promise": "^3.6.0",
|
||||
"eslint-plugin-react": "^7.5.1",
|
||||
"file-loader": "^1.1.5",
|
||||
"flow-bin": "^0.60.1",
|
||||
"jest": "^21.2.1",
|
||||
"lint-staged": "^4.1.3",
|
||||
"prettier": "^1.7.3",
|
||||
"raf": "^3.3.2",
|
||||
"react": "^16.0.0",
|
||||
"react-dom": "^16.0.0",
|
||||
"react-test-renderer": "^16.0.0",
|
||||
"url-loader": "^0.5.9",
|
||||
"webpack": "^3.6.0",
|
||||
"webpack-bundle-analyzer": "^2.9.0"
|
||||
"prettier": "^1.8.2",
|
||||
"raf": "^3.4.0",
|
||||
"react": "^16.2.0",
|
||||
"react-dom": "^16.2.0",
|
||||
"react-test-renderer": "^16.2.0",
|
||||
"url-loader": "^0.6.2",
|
||||
"webpack": "^3.9.1",
|
||||
"webpack-bundle-analyzer": "^2.9.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "16.x.x",
|
||||
|
||||
@@ -3,27 +3,25 @@
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule Animated
|
||||
* @noflow
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import Animated from 'animated';
|
||||
import AnimatedImplementation from '../../vendor/Animated/AnimatedImplementation';
|
||||
import Image from '../../components/Image';
|
||||
import ScrollView from '../../components/ScrollView';
|
||||
import StyleSheet from '../StyleSheet';
|
||||
import Text from '../../components/Text';
|
||||
import View from '../../components/View';
|
||||
|
||||
Animated.inject.FlattenStyle(StyleSheet.flatten);
|
||||
|
||||
const AnimatedImplementation = {
|
||||
...Animated,
|
||||
Image: Animated.createAnimatedComponent(Image),
|
||||
ScrollView: Animated.createAnimatedComponent(ScrollView),
|
||||
Text: Animated.createAnimatedComponent(Text),
|
||||
View: Animated.createAnimatedComponent(View)
|
||||
const Animated = {
|
||||
...AnimatedImplementation,
|
||||
Image: AnimatedImplementation.createAnimatedComponent(Image),
|
||||
ScrollView: AnimatedImplementation.createAnimatedComponent(ScrollView),
|
||||
View: AnimatedImplementation.createAnimatedComponent(View),
|
||||
Text: AnimatedImplementation.createAnimatedComponent(Text)
|
||||
};
|
||||
|
||||
export default AnimatedImplementation;
|
||||
export default Animated;
|
||||
|
||||
@@ -19,6 +19,7 @@ type Context = {
|
||||
};
|
||||
|
||||
type Props = {
|
||||
// $FlowFixMe
|
||||
children?: React.Children,
|
||||
rootTag: any
|
||||
};
|
||||
@@ -27,10 +28,7 @@ type State = {
|
||||
mainKey: number
|
||||
};
|
||||
|
||||
export default class AppContainer extends Component {
|
||||
props: Props;
|
||||
state: State = { mainKey: 1 };
|
||||
|
||||
export default class AppContainer extends Component<Props, State> {
|
||||
static childContextTypes = {
|
||||
rootTag: any
|
||||
};
|
||||
|
||||
@@ -39,6 +39,9 @@ exports[`apis/AppRegistry/renderApplication getApplication 3`] = `
|
||||
.rn-backgroundColor-wib322{background-color:transparent}
|
||||
.rn-backgroundColor-8ndhhv{background-color:rgba(33,150,243,1)}
|
||||
.rn-backgroundColor-15al3ab{background-color:rgba(223,223,223,1)}
|
||||
.rn-backgroundColor-44z8sh{background-color:rgba(255,255,255,1)}
|
||||
.rn-backgroundColor-5itogg{background-color:rgba(0,150,136,1)}
|
||||
.rn-backgroundColor-1v82r4u{background-color:rgba(170,184,194,1)}
|
||||
.rn-backgroundColor-1hj8efq{background-color:rgba(213,213,213,1)}
|
||||
.rn-backgroundColor-1bgzomc{background-color:rgba(189,189,189,1)}
|
||||
.rn-color-homxoj{color:inherit}
|
||||
@@ -56,9 +59,13 @@ exports[`apis/AppRegistry/renderApplication getApplication 3`] = `
|
||||
.rn-borderBottomStyle-rull8r{border-bottom-style:solid}
|
||||
.rn-borderLeftStyle-mm0ijv{border-left-style:solid}
|
||||
.rn-borderTopWidth-13yce4e{border-top-width:0px}
|
||||
.rn-borderTopWidth-1jxfwug{border-top-width:2px}
|
||||
.rn-borderRightWidth-fnigne{border-right-width:0px}
|
||||
.rn-borderRightWidth-18p6if4{border-right-width:2px}
|
||||
.rn-borderBottomWidth-ndvcnb{border-bottom-width:0px}
|
||||
.rn-borderBottomWidth-wgabs5{border-bottom-width:2px}
|
||||
.rn-borderLeftWidth-gxnn5r{border-left-width:0px}
|
||||
.rn-borderLeftWidth-dwliz8{border-left-width:2px}
|
||||
.rn-boxSizing-deolkf{box-sizing:border-box}
|
||||
.rn-display-6koalj{display:-webkit-box;display:-moz-box;display:-ms-flexbox;display:-webkit-flex;display:flex}
|
||||
.rn-display-xoduu5{display:-webkit-inline-box;display:-moz-inline-box;display:-ms-inline-flexbox;display:-webkit-inline-flex;display:inline-flex}
|
||||
@@ -98,6 +105,7 @@ exports[`apis/AppRegistry/renderApplication getApplication 3`] = `
|
||||
.rn-height-1pi2tsx{height:100%}
|
||||
.rn-height-z80fyv{height:20px}
|
||||
.rn-height-1r8g8re{height:36px}
|
||||
.rn-height-10ptun7{height:16px}
|
||||
.rn-height-4v7adb{height:5px}
|
||||
.rn-height-1dernwh{height:70%}
|
||||
.rn-opacity-1272l3b{opacity:0}
|
||||
@@ -105,6 +113,7 @@ exports[`apis/AppRegistry/renderApplication getApplication 3`] = `
|
||||
.rn-width-13qz1uu{width:100%}
|
||||
.rn-width-19wmn03{width:20px}
|
||||
.rn-width-1acpoxo{width:36px}
|
||||
.rn-width-1janqcz{width:16px}
|
||||
.rn-touchAction-19z077z{-ms-touch-action:none;touch-action:none}
|
||||
.rn-touchAction-1gvxusu{-ms-touch-action:manipulate;touch-action:manipulate}
|
||||
.rn-WebkitOverflowScrolling-150rngu{-webkit-overflow-scrolling:touch}
|
||||
@@ -152,11 +161,28 @@ exports[`apis/AppRegistry/renderApplication getApplication 3`] = `
|
||||
.rn-borderBottomLeftRadius-pm2fo{border-bottom-left-radius:0px}
|
||||
.rn-fontWeight-majxgm{font-weight:500}
|
||||
.rn-textTransform-tsynxw{text-transform:uppercase}
|
||||
.rn-borderTopColor-j4x2lb{border-top-color:rgba(101,119,134,1)}
|
||||
.rn-borderTopColor-gj2eto{border-top-color:rgba(0,150,136,1)}
|
||||
.rn-borderTopColor-1j7vz2b{border-top-color:rgba(204,214,221,1)}
|
||||
.rn-borderTopColor-2dclza{border-top-color:rgba(170,184,194,1)}
|
||||
.rn-borderTopColor-kqr9px{border-top-color:black}
|
||||
.rn-borderRightColor-12i18q1{border-right-color:rgba(101,119,134,1)}
|
||||
.rn-borderRightColor-31ud7z{border-right-color:rgba(0,150,136,1)}
|
||||
.rn-borderRightColor-10fg1ub{border-right-color:rgba(204,214,221,1)}
|
||||
.rn-borderRightColor-8jf312{border-right-color:rgba(170,184,194,1)}
|
||||
.rn-borderRightColor-q0dj5p{border-right-color:black}
|
||||
.rn-borderBottomColor-mg3rfb{border-bottom-color:rgba(101,119,134,1)}
|
||||
.rn-borderBottomColor-1bgnb8i{border-bottom-color:rgba(0,150,136,1)}
|
||||
.rn-borderBottomColor-zxuuv6{border-bottom-color:rgba(204,214,221,1)}
|
||||
.rn-borderBottomColor-1yeakrt{border-bottom-color:rgba(170,184,194,1)}
|
||||
.rn-borderBottomColor-1ah7hsa{border-bottom-color:black}
|
||||
.rn-borderLeftColor-vnhemr{border-left-color:rgba(101,119,134,1)}
|
||||
.rn-borderLeftColor-tbzcuz{border-left-color:rgba(0,150,136,1)}
|
||||
.rn-borderLeftColor-1p34dw6{border-left-color:rgba(204,214,221,1)}
|
||||
.rn-borderLeftColor-bluj2i{border-left-color:rgba(170,184,194,1)}
|
||||
.rn-borderLeftColor-137uh4u{border-left-color:black}
|
||||
.rn-backgroundImage-rs94m5{background-image:url(\\"data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcKICAgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIgogICB4bWxuczpjYz0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbnMjIgogICB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiCiAgIHhtbG5zOnN2Zz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgdmVyc2lvbj0iMS4xIgogICB2aWV3Qm94PSIwIDAgMSAxIgogICBwcmVzZXJ2ZUFzcGVjdFJhdGlvPSJ4TWluWU1pbiBtZWV0Ij4KICA8cGF0aAogICAgIGQ9Ik0gMC4wNDAzODA1OSwwLjYyNjc3NjcgMC4xNDY0NDY2MSwwLjUyMDcxMDY4IDAuNDI5Mjg5MzIsMC44MDM1NTMzOSAwLjMyMzIyMzMsMC45MDk2MTk0MSB6IE0gMC4yMTcxNTcyOSwwLjgwMzU1MzM5IDAuODUzNTUzMzksMC4xNjcxNTcyOSAwLjk1OTYxOTQxLDAuMjczMjIzMyAwLjMyMzIyMzMsMC45MDk2MTk0MSB6IgogICAgIGlkPSJyZWN0Mzc4MCIKICAgICBzdHlsZT0iZmlsbDojZmZmZmZmO2ZpbGwtb3BhY2l0eToxO3N0cm9rZTpub25lIiAvPgo8L3N2Zz4K\\")}
|
||||
.rn-alignSelf-k200y{-ms-flex-item-align:start;-webkit-align-self:flex-start;align-self:flex-start}
|
||||
.rn-boxShadow-1ewcgjf{box-shadow:0px 1px 3px rgba(0,0,0,0.5)}
|
||||
.rn-borderTopColor-kqr9px{border-top-color:black}
|
||||
.rn-borderRightColor-q0dj5p{border-right-color:black}
|
||||
.rn-borderBottomColor-1ah7hsa{border-bottom-color:black}
|
||||
.rn-borderLeftColor-137uh4u{border-left-color:black}
|
||||
.rn-resize-1dz5y72{resize:none}</style>"
|
||||
`;
|
||||
|
||||
@@ -11,18 +11,20 @@
|
||||
*/
|
||||
|
||||
import invariant from 'fbjs/lib/invariant';
|
||||
import { unmountComponentAtNode } from 'react-dom';
|
||||
import { unmountComponentAtNode } from '../../modules/unmountComponentAtNode';
|
||||
import renderApplication, { getApplication } from './renderApplication';
|
||||
import type { ComponentType } from 'react';
|
||||
|
||||
const emptyObject = {};
|
||||
const runnables = {};
|
||||
|
||||
export type ComponentProvider = () => ReactClass<any>;
|
||||
export type ComponentProvider = () => ComponentType<any>;
|
||||
|
||||
export type AppConfig = {
|
||||
appKey: string,
|
||||
component?: ComponentProvider,
|
||||
run?: Function
|
||||
run?: Function,
|
||||
section?: boolean
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -90,7 +92,7 @@ export default class AppRegistry {
|
||||
runnables[appKey].run(appParameters);
|
||||
}
|
||||
|
||||
static unmountApplicationComponentAtRootTag(rootTag) {
|
||||
static unmountApplicationComponentAtRootTag(rootTag: Object) {
|
||||
unmountComponentAtNode(rootTag);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,19 +10,19 @@
|
||||
*/
|
||||
|
||||
import invariant from 'fbjs/lib/invariant';
|
||||
import { render } from 'react-dom';
|
||||
import hydrate from '../../modules/hydrate';
|
||||
import AppContainer from './AppContainer';
|
||||
import StyleSheet from '../../apis/StyleSheet';
|
||||
import React from 'react';
|
||||
import React, { type ComponentType } from 'react';
|
||||
|
||||
export default function renderApplication(
|
||||
RootComponent: ReactClass<Object>,
|
||||
initialProps: Object,
|
||||
export default function renderApplication<Props: Object>(
|
||||
RootComponent: ComponentType<Props>,
|
||||
initialProps: Props,
|
||||
rootTag: any
|
||||
) {
|
||||
invariant(rootTag, 'Expect to have a valid rootTag, instead got ', rootTag);
|
||||
|
||||
render(
|
||||
hydrate(
|
||||
<AppContainer rootTag={rootTag}>
|
||||
<RootComponent {...initialProps} />
|
||||
</AppContainer>,
|
||||
@@ -30,7 +30,7 @@ export default function renderApplication(
|
||||
);
|
||||
}
|
||||
|
||||
export function getApplication(RootComponent: ReactClass<Object>, initialProps: Object): Object {
|
||||
export function getApplication(RootComponent: ComponentType<Object>, initialProps: Object): Object {
|
||||
const element = (
|
||||
<AppContainer rootTag={{}}>
|
||||
<RootComponent {...initialProps} />
|
||||
@@ -38,7 +38,7 @@ export function getApplication(RootComponent: ReactClass<Object>, initialProps:
|
||||
);
|
||||
const stylesheets = StyleSheet.getStyleSheets().map(sheet => (
|
||||
// ensure that CSS text is not escaped
|
||||
<style dangerouslySetInnerHTML={{ __html: sheet.textContent }} id={sheet.id} />
|
||||
<style dangerouslySetInnerHTML={{ __html: sheet.textContent }} id={sheet.id} key={sheet.id} />
|
||||
));
|
||||
return { element, stylesheets };
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ const mergeLocalStorageItem = (key, value) => {
|
||||
window.localStorage.setItem(key, nextValue);
|
||||
};
|
||||
|
||||
const createPromise = (getValue, callback) => {
|
||||
const createPromise = (getValue, callback): Promise<*> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
const value = getValue();
|
||||
@@ -37,7 +37,7 @@ const createPromise = (getValue, callback) => {
|
||||
});
|
||||
};
|
||||
|
||||
const createPromiseAll = (promises, callback, processResult) => {
|
||||
const createPromiseAll = (promises, callback, processResult): Promise<*> => {
|
||||
return Promise.all(promises).then(
|
||||
result => {
|
||||
const value = processResult ? processResult(result) : null;
|
||||
@@ -55,7 +55,7 @@ export default class AsyncStorage {
|
||||
/**
|
||||
* Erases *all* AsyncStorage for the domain.
|
||||
*/
|
||||
static clear(callback) {
|
||||
static clear(callback?: Function): Promise<*> {
|
||||
return createPromise(() => {
|
||||
window.localStorage.clear();
|
||||
}, callback);
|
||||
@@ -69,7 +69,7 @@ export default class AsyncStorage {
|
||||
/**
|
||||
* Gets *all* keys known to the app, for all callers, libraries, etc.
|
||||
*/
|
||||
static getAllKeys(callback) {
|
||||
static getAllKeys(callback?: Function): Promise<*> {
|
||||
return createPromise(() => {
|
||||
const numberOfKeys = window.localStorage.length;
|
||||
const keys = [];
|
||||
@@ -84,7 +84,7 @@ export default class AsyncStorage {
|
||||
/**
|
||||
* Fetches `key` value.
|
||||
*/
|
||||
static getItem(key: string, callback) {
|
||||
static getItem(key: string, callback?: Function): Promise<*> {
|
||||
return createPromise(() => {
|
||||
return window.localStorage.getItem(key);
|
||||
}, callback);
|
||||
@@ -96,7 +96,7 @@ export default class AsyncStorage {
|
||||
*
|
||||
* multiGet(['k1', 'k2']) -> [['k1', 'val1'], ['k2', 'val2']]
|
||||
*/
|
||||
static multiGet(keys: Array<string>, callback) {
|
||||
static multiGet(keys: Array<string>, callback?: Function): Promise<*> {
|
||||
const promises = keys.map(key => AsyncStorage.getItem(key));
|
||||
const processResult = result => result.map((value, i) => [keys[i], value]);
|
||||
return createPromiseAll(promises, callback, processResult);
|
||||
@@ -105,7 +105,7 @@ export default class AsyncStorage {
|
||||
/**
|
||||
* Sets `value` for `key`.
|
||||
*/
|
||||
static setItem(key: string, value: string, callback) {
|
||||
static setItem(key: string, value: string, callback?: Function): Promise<*> {
|
||||
return createPromise(() => {
|
||||
window.localStorage.setItem(key, value);
|
||||
}, callback);
|
||||
@@ -115,7 +115,7 @@ export default class AsyncStorage {
|
||||
* Takes an array of key-value array pairs.
|
||||
* multiSet([['k1', 'val1'], ['k2', 'val2']])
|
||||
*/
|
||||
static multiSet(keyValuePairs: Array<Array<string>>, callback) {
|
||||
static multiSet(keyValuePairs: Array<Array<string>>, callback?: Function): Promise<*> {
|
||||
const promises = keyValuePairs.map(item => AsyncStorage.setItem(item[0], item[1]));
|
||||
return createPromiseAll(promises, callback);
|
||||
}
|
||||
@@ -123,7 +123,7 @@ export default class AsyncStorage {
|
||||
/**
|
||||
* Merges existing value with input value, assuming they are stringified JSON.
|
||||
*/
|
||||
static mergeItem(key: string, value: string, callback) {
|
||||
static mergeItem(key: string, value: string, callback?: Function): Promise<*> {
|
||||
return createPromise(() => {
|
||||
mergeLocalStorageItem(key, value);
|
||||
}, callback);
|
||||
@@ -135,7 +135,7 @@ export default class AsyncStorage {
|
||||
*
|
||||
* multiMerge([['k1', 'val1'], ['k2', 'val2']])
|
||||
*/
|
||||
static multiMerge(keyValuePairs: Array<Array<string>>, callback) {
|
||||
static multiMerge(keyValuePairs: Array<Array<string>>, callback?: Function): Promise<*> {
|
||||
const promises = keyValuePairs.map(item => AsyncStorage.mergeItem(item[0], item[1]));
|
||||
return createPromiseAll(promises, callback);
|
||||
}
|
||||
@@ -143,7 +143,7 @@ export default class AsyncStorage {
|
||||
/**
|
||||
* Removes a `key`
|
||||
*/
|
||||
static removeItem(key: string, callback) {
|
||||
static removeItem(key: string, callback?: Function): Promise<*> {
|
||||
return createPromise(() => {
|
||||
return window.localStorage.removeItem(key);
|
||||
}, callback);
|
||||
@@ -152,7 +152,7 @@ export default class AsyncStorage {
|
||||
/**
|
||||
* Delete all the keys in the `keys` array.
|
||||
*/
|
||||
static multiRemove(keys: Array<string>, callback) {
|
||||
static multiRemove(keys: Array<string>, callback?: Function): Promise<*> {
|
||||
const promises = keys.map(key => AsyncStorage.removeItem(key));
|
||||
return createPromiseAll(promises, callback);
|
||||
}
|
||||
|
||||
@@ -17,11 +17,11 @@ export default class Clipboard {
|
||||
);
|
||||
}
|
||||
|
||||
static getString() {
|
||||
static getString(): Promise<string> {
|
||||
return Promise.resolve('');
|
||||
}
|
||||
|
||||
static setString(text) {
|
||||
static setString(text: string) {
|
||||
let success = false;
|
||||
const body = document.body;
|
||||
|
||||
|
||||
@@ -66,12 +66,12 @@ export default class Dimensions {
|
||||
}
|
||||
}
|
||||
|
||||
static addEventListener(type, handler): void {
|
||||
static addEventListener(type: string, handler: Function): void {
|
||||
listeners[type] = listeners[type] || [];
|
||||
listeners[type].push(handler);
|
||||
}
|
||||
|
||||
static removeEventListener(type, handler): void {
|
||||
static removeEventListener(type: string, handler: Function): void {
|
||||
if (Array.isArray(listeners[type])) {
|
||||
listeners[type] = listeners[type].filter(_handler => _handler !== handler);
|
||||
}
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @providesModule Easing
|
||||
* @noflow
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import Easing from 'animated/lib/Easing';
|
||||
import Easing from '../../vendor/Animated/Easing';
|
||||
export default Easing;
|
||||
|
||||
@@ -17,13 +17,13 @@ const initialURL = canUseDOM ? window.location.href : '';
|
||||
const Linking = {
|
||||
addEventListener() {},
|
||||
removeEventListener() {},
|
||||
canOpenURL() {
|
||||
canOpenURL(): Promise<boolean> {
|
||||
return Promise.resolve(true);
|
||||
},
|
||||
getInitialURL() {
|
||||
getInitialURL(): Promise<string> {
|
||||
return Promise.resolve(initialURL);
|
||||
},
|
||||
openURL(url: string) {
|
||||
openURL(url: string): Promise<Object | void> {
|
||||
try {
|
||||
iframeOpen(url);
|
||||
return Promise.resolve();
|
||||
|
||||
@@ -1,394 +1,2 @@
|
||||
/**
|
||||
* Copyright (c) 2016-present, Nicolas Gallagher.
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @providesModule PanResponder
|
||||
* @noflow
|
||||
*/
|
||||
|
||||
import TouchHistoryMath from '../../vendor/TouchHistoryMath';
|
||||
|
||||
const currentCentroidXOfTouchesChangedAfter =
|
||||
TouchHistoryMath.currentCentroidXOfTouchesChangedAfter;
|
||||
const currentCentroidYOfTouchesChangedAfter =
|
||||
TouchHistoryMath.currentCentroidYOfTouchesChangedAfter;
|
||||
const previousCentroidXOfTouchesChangedAfter =
|
||||
TouchHistoryMath.previousCentroidXOfTouchesChangedAfter;
|
||||
const previousCentroidYOfTouchesChangedAfter =
|
||||
TouchHistoryMath.previousCentroidYOfTouchesChangedAfter;
|
||||
const currentCentroidX = TouchHistoryMath.currentCentroidX;
|
||||
const currentCentroidY = TouchHistoryMath.currentCentroidY;
|
||||
|
||||
/**
|
||||
* `PanResponder` reconciles several touches into a single gesture. It makes
|
||||
* single-touch gestures resilient to extra touches, and can be used to
|
||||
* recognize simple multi-touch gestures.
|
||||
*
|
||||
* It provides a predictable wrapper of the responder handlers provided by the
|
||||
* [gesture responder system](docs/gesture-responder-system.html).
|
||||
* For each handler, it provides a new `gestureState` object alongside the
|
||||
* native event object:
|
||||
*
|
||||
* ```
|
||||
* onPanResponderMove: (event, gestureState) => {}
|
||||
* ```
|
||||
*
|
||||
* A native event is a synthetic touch event with the following form:
|
||||
*
|
||||
* - `nativeEvent`
|
||||
* + `changedTouches` - Array of all touch events that have changed since the last event
|
||||
* + `identifier` - The ID of the touch
|
||||
* + `locationX` - The X position of the touch, relative to the element
|
||||
* + `locationY` - The Y position of the touch, relative to the element
|
||||
* + `pageX` - The X position of the touch, relative to the root element
|
||||
* + `pageY` - The Y position of the touch, relative to the root element
|
||||
* + `target` - The node id of the element receiving the touch event
|
||||
* + `timestamp` - A time identifier for the touch, useful for velocity calculation
|
||||
* + `touches` - Array of all current touches on the screen
|
||||
*
|
||||
* A `gestureState` object has the following:
|
||||
*
|
||||
* - `stateID` - ID of the gestureState- persisted as long as there at least
|
||||
* one touch on screen
|
||||
* - `moveX` - the latest screen coordinates of the recently-moved touch
|
||||
* - `moveY` - the latest screen coordinates of the recently-moved touch
|
||||
* - `x0` - the screen coordinates of the responder grant
|
||||
* - `y0` - the screen coordinates of the responder grant
|
||||
* - `dx` - accumulated distance of the gesture since the touch started
|
||||
* - `dy` - accumulated distance of the gesture since the touch started
|
||||
* - `vx` - current velocity of the gesture
|
||||
* - `vy` - current velocity of the gesture
|
||||
* - `numberActiveTouches` - Number of touches currently on screen
|
||||
*
|
||||
* ### Basic Usage
|
||||
*
|
||||
* ```
|
||||
* componentWillMount: function() {
|
||||
* this._panResponder = PanResponder.create({
|
||||
* // Ask to be the responder:
|
||||
* onStartShouldSetPanResponder: (evt, gestureState) => true,
|
||||
* onStartShouldSetPanResponderCapture: (evt, gestureState) => true,
|
||||
* onMoveShouldSetPanResponder: (evt, gestureState) => true,
|
||||
* onMoveShouldSetPanResponderCapture: (evt, gestureState) => true,
|
||||
*
|
||||
* onPanResponderGrant: (evt, gestureState) => {
|
||||
* // The guesture has started. Show visual feedback so the user knows
|
||||
* // what is happening!
|
||||
*
|
||||
* // gestureState.{x,y}0 will be set to zero now
|
||||
* },
|
||||
* onPanResponderMove: (evt, gestureState) => {
|
||||
* // The most recent move distance is gestureState.move{X,Y}
|
||||
*
|
||||
* // The accumulated gesture distance since becoming responder is
|
||||
* // gestureState.d{x,y}
|
||||
* },
|
||||
* onPanResponderTerminationRequest: (evt, gestureState) => true,
|
||||
* onPanResponderRelease: (evt, gestureState) => {
|
||||
* // The user has released all touches while this view is the
|
||||
* // responder. This typically means a gesture has succeeded
|
||||
* },
|
||||
* onPanResponderTerminate: (evt, gestureState) => {
|
||||
* // Another component has become the responder, so this gesture
|
||||
* // should be cancelled
|
||||
* },
|
||||
* onShouldBlockNativeResponder: (evt, gestureState) => {
|
||||
* // Returns whether this component should block native components from becoming the JS
|
||||
* // responder. Returns true by default. Is currently only supported on android.
|
||||
* return true;
|
||||
* },
|
||||
* });
|
||||
* },
|
||||
*
|
||||
* render: function() {
|
||||
* return (
|
||||
* <View {...this._panResponder.panHandlers} />
|
||||
* );
|
||||
* },
|
||||
*
|
||||
* ```
|
||||
*
|
||||
* ### Working Example
|
||||
*
|
||||
* To see it in action, try the
|
||||
* [PanResponder example in UIExplorer](https://github.com/facebook/react-native/blob/master/Examples/UIExplorer/PanResponderExample.js)
|
||||
*/
|
||||
|
||||
const PanResponder = {
|
||||
/**
|
||||
*
|
||||
* A graphical explanation of the touch data flow:
|
||||
*
|
||||
* +----------------------------+ +--------------------------------+
|
||||
* | ResponderTouchHistoryStore | |TouchHistoryMath |
|
||||
* +----------------------------+ +----------+---------------------+
|
||||
* |Global store of touchHistory| |Allocation-less math util |
|
||||
* |including activeness, start | |on touch history (centroids |
|
||||
* |position, prev/cur position.| |and multitouch movement etc) |
|
||||
* | | | |
|
||||
* +----^-----------------------+ +----^---------------------------+
|
||||
* | |
|
||||
* | (records relevant history |
|
||||
* | of touches relevant for |
|
||||
* | implementing higher level |
|
||||
* | gestures) |
|
||||
* | |
|
||||
* +----+-----------------------+ +----|---------------------------+
|
||||
* | ResponderEventPlugin | | | Your App/Component |
|
||||
* +----------------------------+ +----|---------------------------+
|
||||
* |Negotiates which view gets | Low level | | High level |
|
||||
* |onResponderMove events. | events w/ | +-+-------+ events w/ |
|
||||
* |Also records history into | touchHistory| | Pan | multitouch + |
|
||||
* |ResponderTouchHistoryStore. +---------------->Responder+-----> accumulative|
|
||||
* +----------------------------+ attached to | | | distance and |
|
||||
* each event | +---------+ velocity. |
|
||||
* | |
|
||||
* | |
|
||||
* +--------------------------------+
|
||||
*
|
||||
*
|
||||
*
|
||||
* Gesture that calculates cumulative movement over time in a way that just
|
||||
* "does the right thing" for multiple touches. The "right thing" is very
|
||||
* nuanced. When moving two touches in opposite directions, the cumulative
|
||||
* distance is zero in each dimension. When two touches move in parallel five
|
||||
* pixels in the same direction, the cumulative distance is five, not ten. If
|
||||
* two touches start, one moves five in a direction, then stops and the other
|
||||
* touch moves fives in the same direction, the cumulative distance is ten.
|
||||
*
|
||||
* This logic requires a kind of processing of time "clusters" of touch events
|
||||
* so that two touch moves that essentially occur in parallel but move every
|
||||
* other frame respectively, are considered part of the same movement.
|
||||
*
|
||||
* Explanation of some of the non-obvious fields:
|
||||
*
|
||||
* - moveX/moveY: If no move event has been observed, then `(moveX, moveY)` is
|
||||
* invalid. If a move event has been observed, `(moveX, moveY)` is the
|
||||
* centroid of the most recently moved "cluster" of active touches.
|
||||
* (Currently all move have the same timeStamp, but later we should add some
|
||||
* threshold for what is considered to be "moving"). If a palm is
|
||||
* accidentally counted as a touch, but a finger is moving greatly, the palm
|
||||
* will move slightly, but we only want to count the single moving touch.
|
||||
* - x0/y0: Centroid location (non-cumulative) at the time of becoming
|
||||
* responder.
|
||||
* - dx/dy: Cumulative touch distance - not the same thing as sum of each touch
|
||||
* distance. Accounts for touch moves that are clustered together in time,
|
||||
* moving the same direction. Only valid when currently responder (otherwise,
|
||||
* it only represents the drag distance below the threshold).
|
||||
* - vx/vy: Velocity.
|
||||
*/
|
||||
|
||||
_initializeGestureState: function(gestureState) {
|
||||
gestureState.moveX = 0;
|
||||
gestureState.moveY = 0;
|
||||
gestureState.x0 = 0;
|
||||
gestureState.y0 = 0;
|
||||
gestureState.dx = 0;
|
||||
gestureState.dy = 0;
|
||||
gestureState.vx = 0;
|
||||
gestureState.vy = 0;
|
||||
gestureState.numberActiveTouches = 0;
|
||||
// All `gestureState` accounts for timeStamps up until:
|
||||
gestureState._accountsForMovesUpTo = 0;
|
||||
},
|
||||
|
||||
/**
|
||||
* This is nuanced and is necessary. It is incorrect to continuously take all
|
||||
* active *and* recently moved touches, find the centroid, and track how that
|
||||
* result changes over time. Instead, we must take all recently moved
|
||||
* touches, and calculate how the centroid has changed just for those
|
||||
* recently moved touches, and append that change to an accumulator. This is
|
||||
* to (at least) handle the case where the user is moving three fingers, and
|
||||
* then one of the fingers stops but the other two continue.
|
||||
*
|
||||
* This is very different than taking all of the recently moved touches and
|
||||
* storing their centroid as `dx/dy`. For correctness, we must *accumulate
|
||||
* changes* in the centroid of recently moved touches.
|
||||
*
|
||||
* There is also some nuance with how we handle multiple moved touches in a
|
||||
* single event. With the way `ReactNativeEventEmitter` dispatches touches as
|
||||
* individual events, multiple touches generate two 'move' events, each of
|
||||
* them triggering `onResponderMove`. But with the way `PanResponder` works,
|
||||
* all of the gesture inference is performed on the first dispatch, since it
|
||||
* looks at all of the touches (even the ones for which there hasn't been a
|
||||
* native dispatch yet). Therefore, `PanResponder` does not call
|
||||
* `onResponderMove` passed the first dispatch. This diverges from the
|
||||
* typical responder callback pattern (without using `PanResponder`), but
|
||||
* avoids more dispatches than necessary.
|
||||
*/
|
||||
_updateGestureStateOnMove: function(gestureState, touchHistory) {
|
||||
gestureState.numberActiveTouches = touchHistory.numberActiveTouches;
|
||||
gestureState.moveX = currentCentroidXOfTouchesChangedAfter(
|
||||
touchHistory,
|
||||
gestureState._accountsForMovesUpTo
|
||||
);
|
||||
gestureState.moveY = currentCentroidYOfTouchesChangedAfter(
|
||||
touchHistory,
|
||||
gestureState._accountsForMovesUpTo
|
||||
);
|
||||
const movedAfter = gestureState._accountsForMovesUpTo;
|
||||
const prevX = previousCentroidXOfTouchesChangedAfter(touchHistory, movedAfter);
|
||||
const x = currentCentroidXOfTouchesChangedAfter(touchHistory, movedAfter);
|
||||
const prevY = previousCentroidYOfTouchesChangedAfter(touchHistory, movedAfter);
|
||||
const y = currentCentroidYOfTouchesChangedAfter(touchHistory, movedAfter);
|
||||
const nextDX = gestureState.dx + (x - prevX);
|
||||
const nextDY = gestureState.dy + (y - prevY);
|
||||
|
||||
// TODO: This must be filtered intelligently.
|
||||
const dt = touchHistory.mostRecentTimeStamp - gestureState._accountsForMovesUpTo;
|
||||
gestureState.vx = (nextDX - gestureState.dx) / dt;
|
||||
gestureState.vy = (nextDY - gestureState.dy) / dt;
|
||||
|
||||
gestureState.dx = nextDX;
|
||||
gestureState.dy = nextDY;
|
||||
gestureState._accountsForMovesUpTo = touchHistory.mostRecentTimeStamp;
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {object} config Enhanced versions of all of the responder callbacks
|
||||
* that provide not only the typical `ResponderSyntheticEvent`, but also the
|
||||
* `PanResponder` gesture state. Simply replace the word `Responder` with
|
||||
* `PanResponder` in each of the typical `onResponder*` callbacks. For
|
||||
* example, the `config` object would look like:
|
||||
*
|
||||
* - `onMoveShouldSetPanResponder: (e, gestureState) => {...}`
|
||||
* - `onMoveShouldSetPanResponderCapture: (e, gestureState) => {...}`
|
||||
* - `onStartShouldSetPanResponder: (e, gestureState) => {...}`
|
||||
* - `onStartShouldSetPanResponderCapture: (e, gestureState) => {...}`
|
||||
* - `onPanResponderReject: (e, gestureState) => {...}`
|
||||
* - `onPanResponderGrant: (e, gestureState) => {...}`
|
||||
* - `onPanResponderStart: (e, gestureState) => {...}`
|
||||
* - `onPanResponderEnd: (e, gestureState) => {...}`
|
||||
* - `onPanResponderRelease: (e, gestureState) => {...}`
|
||||
* - `onPanResponderMove: (e, gestureState) => {...}`
|
||||
* - `onPanResponderTerminate: (e, gestureState) => {...}`
|
||||
* - `onPanResponderTerminationRequest: (e, gestureState) => {...}`
|
||||
* - `onShouldBlockNativeResponder: (e, gestureState) => {...}`
|
||||
*
|
||||
* In general, for events that have capture equivalents, we update the
|
||||
* gestureState once in the capture phase and can use it in the bubble phase
|
||||
* as well.
|
||||
*
|
||||
* Be careful with onStartShould* callbacks. They only reflect updated
|
||||
* `gestureState` for start/end events that bubble/capture to the Node.
|
||||
* Once the node is the responder, you can rely on every start/end event
|
||||
* being processed by the gesture and `gestureState` being updated
|
||||
* accordingly. (numberActiveTouches) may not be totally accurate unless you
|
||||
* are the responder.
|
||||
*/
|
||||
create: function(config) {
|
||||
const gestureState = {
|
||||
// Useful for debugging
|
||||
stateID: Math.random()
|
||||
};
|
||||
PanResponder._initializeGestureState(gestureState);
|
||||
const panHandlers = {
|
||||
onStartShouldSetResponder: function(e) {
|
||||
return config.onStartShouldSetPanResponder === undefined
|
||||
? false
|
||||
: config.onStartShouldSetPanResponder(e, gestureState);
|
||||
},
|
||||
onMoveShouldSetResponder: function(e) {
|
||||
return config.onMoveShouldSetPanResponder === undefined
|
||||
? false
|
||||
: config.onMoveShouldSetPanResponder(e, gestureState);
|
||||
},
|
||||
onStartShouldSetResponderCapture: function(e) {
|
||||
// TODO: Actually, we should reinitialize the state any time
|
||||
// touches.length increases from 0 active to > 0 active.
|
||||
if (e.nativeEvent.touches) {
|
||||
if (e.nativeEvent.touches.length === 1) {
|
||||
PanResponder._initializeGestureState(gestureState);
|
||||
}
|
||||
} else if (
|
||||
e.nativeEvent.originalEvent &&
|
||||
e.nativeEvent.originalEvent.type === 'mousedown'
|
||||
) {
|
||||
PanResponder._initializeGestureState(gestureState);
|
||||
}
|
||||
gestureState.numberActiveTouches = e.touchHistory.numberActiveTouches;
|
||||
return config.onStartShouldSetPanResponderCapture !== undefined
|
||||
? config.onStartShouldSetPanResponderCapture(e, gestureState)
|
||||
: false;
|
||||
},
|
||||
|
||||
onMoveShouldSetResponderCapture: function(e) {
|
||||
const touchHistory = e.touchHistory;
|
||||
// Responder system incorrectly dispatches should* to current responder
|
||||
// Filter out any touch moves past the first one - we would have
|
||||
// already processed multi-touch geometry during the first event.
|
||||
if (gestureState._accountsForMovesUpTo === touchHistory.mostRecentTimeStamp) {
|
||||
return false;
|
||||
}
|
||||
PanResponder._updateGestureStateOnMove(gestureState, touchHistory);
|
||||
return config.onMoveShouldSetPanResponderCapture
|
||||
? config.onMoveShouldSetPanResponderCapture(e, gestureState)
|
||||
: false;
|
||||
},
|
||||
|
||||
onResponderGrant: function(e) {
|
||||
gestureState.x0 = currentCentroidX(e.touchHistory);
|
||||
gestureState.y0 = currentCentroidY(e.touchHistory);
|
||||
gestureState.dx = 0;
|
||||
gestureState.dy = 0;
|
||||
config.onPanResponderGrant && config.onPanResponderGrant(e, gestureState);
|
||||
// TODO: t7467124 investigate if this can be removed
|
||||
return config.onShouldBlockNativeResponder === undefined
|
||||
? true
|
||||
: config.onShouldBlockNativeResponder();
|
||||
},
|
||||
|
||||
onResponderReject: function(e) {
|
||||
config.onPanResponderReject && config.onPanResponderReject(e, gestureState);
|
||||
},
|
||||
|
||||
onResponderRelease: function(e) {
|
||||
config.onPanResponderRelease && config.onPanResponderRelease(e, gestureState);
|
||||
PanResponder._initializeGestureState(gestureState);
|
||||
},
|
||||
|
||||
onResponderStart: function(e) {
|
||||
const touchHistory = e.touchHistory;
|
||||
gestureState.numberActiveTouches = touchHistory.numberActiveTouches;
|
||||
config.onPanResponderStart && config.onPanResponderStart(e, gestureState);
|
||||
},
|
||||
|
||||
onResponderMove: function(e) {
|
||||
const touchHistory = e.touchHistory;
|
||||
// Guard against the dispatch of two touch moves when there are two
|
||||
// simultaneously changed touches.
|
||||
if (gestureState._accountsForMovesUpTo === touchHistory.mostRecentTimeStamp) {
|
||||
return;
|
||||
}
|
||||
// Filter out any touch moves past the first one - we would have
|
||||
// already processed multi-touch geometry during the first event.
|
||||
PanResponder._updateGestureStateOnMove(gestureState, touchHistory);
|
||||
config.onPanResponderMove && config.onPanResponderMove(e, gestureState);
|
||||
},
|
||||
|
||||
onResponderEnd: function(e) {
|
||||
const touchHistory = e.touchHistory;
|
||||
gestureState.numberActiveTouches = touchHistory.numberActiveTouches;
|
||||
config.onPanResponderEnd && config.onPanResponderEnd(e, gestureState);
|
||||
},
|
||||
|
||||
onResponderTerminate: function(e) {
|
||||
config.onPanResponderTerminate && config.onPanResponderTerminate(e, gestureState);
|
||||
PanResponder._initializeGestureState(gestureState);
|
||||
},
|
||||
|
||||
onResponderTerminationRequest: function(e) {
|
||||
return config.onPanResponderTerminationRequest === undefined
|
||||
? true
|
||||
: config.onPanResponderTerminationRequest(e, gestureState);
|
||||
}
|
||||
};
|
||||
return { panHandlers: panHandlers };
|
||||
}
|
||||
};
|
||||
|
||||
import PanResponder from '../../vendor/PanResponder';
|
||||
export default PanResponder;
|
||||
|
||||
@@ -182,7 +182,7 @@ export default class StyleRegistry {
|
||||
}
|
||||
|
||||
/**
|
||||
* Caching layer over 'resolveStyle'
|
||||
* Caching layer over 'resolveStyle'
|
||||
*/
|
||||
_resolveStyleIfNeeded(style, options, key) {
|
||||
const dir = I18nManager.isRTL ? 'rtl' : 'ltr';
|
||||
|
||||
@@ -24,7 +24,7 @@ import { number, oneOf, string } from 'prop-types';
|
||||
const ReactPropTypesSecret = 'SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED';
|
||||
|
||||
export default class StyleSheetValidation {
|
||||
static validateStyleProp(prop, style, caller) {
|
||||
static validateStyleProp(prop: string, style: Object, caller: string) {
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
const isCustomProperty = prop.indexOf('--') === 0;
|
||||
if (isCustomProperty) return;
|
||||
@@ -51,7 +51,7 @@ export default class StyleSheetValidation {
|
||||
}
|
||||
}
|
||||
|
||||
static validateStyle(name, styles) {
|
||||
static validateStyle(name: string, styles: Object) {
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
for (const prop in styles[name]) {
|
||||
StyleSheetValidation.validateStyleProp(prop, styles[name], 'StyleSheet ' + name);
|
||||
@@ -59,7 +59,7 @@ export default class StyleSheetValidation {
|
||||
}
|
||||
}
|
||||
|
||||
static addValidStylePropTypes(stylePropTypes) {
|
||||
static addValidStylePropTypes(stylePropTypes: Object) {
|
||||
for (const key in stylePropTypes) {
|
||||
allStylePropTypes[key] = stylePropTypes[key];
|
||||
}
|
||||
|
||||
@@ -34,6 +34,9 @@ input::-webkit-inner-spin-button,input::-webkit-outer-spin-button,input::-webkit
|
||||
.rn-backgroundColor-wib322{background-color:transparent}
|
||||
.rn-backgroundColor-8ndhhv{background-color:rgba(33,150,243,1)}
|
||||
.rn-backgroundColor-15al3ab{background-color:rgba(223,223,223,1)}
|
||||
.rn-backgroundColor-44z8sh{background-color:rgba(255,255,255,1)}
|
||||
.rn-backgroundColor-5itogg{background-color:rgba(0,150,136,1)}
|
||||
.rn-backgroundColor-1v82r4u{background-color:rgba(170,184,194,1)}
|
||||
.rn-backgroundColor-1hj8efq{background-color:rgba(213,213,213,1)}
|
||||
.rn-backgroundColor-1bgzomc{background-color:rgba(189,189,189,1)}
|
||||
.rn-color-homxoj{color:inherit}
|
||||
@@ -51,9 +54,13 @@ input::-webkit-inner-spin-button,input::-webkit-outer-spin-button,input::-webkit
|
||||
.rn-borderBottomStyle-rull8r{border-bottom-style:solid}
|
||||
.rn-borderLeftStyle-mm0ijv{border-left-style:solid}
|
||||
.rn-borderTopWidth-13yce4e{border-top-width:0px}
|
||||
.rn-borderTopWidth-1jxfwug{border-top-width:2px}
|
||||
.rn-borderRightWidth-fnigne{border-right-width:0px}
|
||||
.rn-borderRightWidth-18p6if4{border-right-width:2px}
|
||||
.rn-borderBottomWidth-ndvcnb{border-bottom-width:0px}
|
||||
.rn-borderBottomWidth-wgabs5{border-bottom-width:2px}
|
||||
.rn-borderLeftWidth-gxnn5r{border-left-width:0px}
|
||||
.rn-borderLeftWidth-dwliz8{border-left-width:2px}
|
||||
.rn-boxSizing-deolkf{box-sizing:border-box}
|
||||
.rn-display-6koalj{display:-webkit-box;display:-moz-box;display:-ms-flexbox;display:-webkit-flex;display:flex}
|
||||
.rn-display-xoduu5{display:-webkit-inline-box;display:-moz-inline-box;display:-ms-inline-flexbox;display:-webkit-inline-flex;display:inline-flex}
|
||||
@@ -93,6 +100,7 @@ input::-webkit-inner-spin-button,input::-webkit-outer-spin-button,input::-webkit
|
||||
.rn-height-1pi2tsx{height:100%}
|
||||
.rn-height-z80fyv{height:20px}
|
||||
.rn-height-1r8g8re{height:36px}
|
||||
.rn-height-10ptun7{height:16px}
|
||||
.rn-height-4v7adb{height:5px}
|
||||
.rn-height-1dernwh{height:70%}
|
||||
.rn-opacity-1272l3b{opacity:0}
|
||||
@@ -100,6 +108,7 @@ input::-webkit-inner-spin-button,input::-webkit-outer-spin-button,input::-webkit
|
||||
.rn-width-13qz1uu{width:100%}
|
||||
.rn-width-19wmn03{width:20px}
|
||||
.rn-width-1acpoxo{width:36px}
|
||||
.rn-width-1janqcz{width:16px}
|
||||
.rn-touchAction-19z077z{-ms-touch-action:none;touch-action:none}
|
||||
.rn-touchAction-1gvxusu{-ms-touch-action:manipulate;touch-action:manipulate}
|
||||
.rn-WebkitOverflowScrolling-150rngu{-webkit-overflow-scrolling:touch}
|
||||
@@ -147,12 +156,29 @@ input::-webkit-inner-spin-button,input::-webkit-outer-spin-button,input::-webkit
|
||||
.rn-borderBottomLeftRadius-pm2fo{border-bottom-left-radius:0px}
|
||||
.rn-fontWeight-majxgm{font-weight:500}
|
||||
.rn-textTransform-tsynxw{text-transform:uppercase}
|
||||
.rn-borderTopColor-j4x2lb{border-top-color:rgba(101,119,134,1)}
|
||||
.rn-borderTopColor-gj2eto{border-top-color:rgba(0,150,136,1)}
|
||||
.rn-borderTopColor-1j7vz2b{border-top-color:rgba(204,214,221,1)}
|
||||
.rn-borderTopColor-2dclza{border-top-color:rgba(170,184,194,1)}
|
||||
.rn-borderTopColor-kqr9px{border-top-color:black}
|
||||
.rn-borderRightColor-12i18q1{border-right-color:rgba(101,119,134,1)}
|
||||
.rn-borderRightColor-31ud7z{border-right-color:rgba(0,150,136,1)}
|
||||
.rn-borderRightColor-10fg1ub{border-right-color:rgba(204,214,221,1)}
|
||||
.rn-borderRightColor-8jf312{border-right-color:rgba(170,184,194,1)}
|
||||
.rn-borderRightColor-q0dj5p{border-right-color:black}
|
||||
.rn-borderBottomColor-mg3rfb{border-bottom-color:rgba(101,119,134,1)}
|
||||
.rn-borderBottomColor-1bgnb8i{border-bottom-color:rgba(0,150,136,1)}
|
||||
.rn-borderBottomColor-zxuuv6{border-bottom-color:rgba(204,214,221,1)}
|
||||
.rn-borderBottomColor-1yeakrt{border-bottom-color:rgba(170,184,194,1)}
|
||||
.rn-borderBottomColor-1ah7hsa{border-bottom-color:black}
|
||||
.rn-borderLeftColor-vnhemr{border-left-color:rgba(101,119,134,1)}
|
||||
.rn-borderLeftColor-tbzcuz{border-left-color:rgba(0,150,136,1)}
|
||||
.rn-borderLeftColor-1p34dw6{border-left-color:rgba(204,214,221,1)}
|
||||
.rn-borderLeftColor-bluj2i{border-left-color:rgba(170,184,194,1)}
|
||||
.rn-borderLeftColor-137uh4u{border-left-color:black}
|
||||
.rn-backgroundImage-rs94m5{background-image:url(\\"data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcKICAgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIgogICB4bWxuczpjYz0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbnMjIgogICB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiCiAgIHhtbG5zOnN2Zz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgdmVyc2lvbj0iMS4xIgogICB2aWV3Qm94PSIwIDAgMSAxIgogICBwcmVzZXJ2ZUFzcGVjdFJhdGlvPSJ4TWluWU1pbiBtZWV0Ij4KICA8cGF0aAogICAgIGQ9Ik0gMC4wNDAzODA1OSwwLjYyNjc3NjcgMC4xNDY0NDY2MSwwLjUyMDcxMDY4IDAuNDI5Mjg5MzIsMC44MDM1NTMzOSAwLjMyMzIyMzMsMC45MDk2MTk0MSB6IE0gMC4yMTcxNTcyOSwwLjgwMzU1MzM5IDAuODUzNTUzMzksMC4xNjcxNTcyOSAwLjk1OTYxOTQxLDAuMjczMjIzMyAwLjMyMzIyMzMsMC45MDk2MTk0MSB6IgogICAgIGlkPSJyZWN0Mzc4MCIKICAgICBzdHlsZT0iZmlsbDojZmZmZmZmO2ZpbGwtb3BhY2l0eToxO3N0cm9rZTpub25lIiAvPgo8L3N2Zz4K\\")}
|
||||
.rn-alignSelf-k200y{-ms-flex-item-align:start;-webkit-align-self:flex-start;align-self:flex-start}
|
||||
.rn-boxShadow-1ewcgjf{box-shadow:0px 1px 3px rgba(0,0,0,0.5)}
|
||||
.rn-borderTopColor-kqr9px{border-top-color:black}
|
||||
.rn-borderRightColor-q0dj5p{border-right-color:black}
|
||||
.rn-borderBottomColor-1ah7hsa{border-bottom-color:black}
|
||||
.rn-borderLeftColor-137uh4u{border-left-color:black}
|
||||
.rn-resize-1dz5y72{resize:none}",
|
||||
},
|
||||
]
|
||||
|
||||
@@ -22,6 +22,18 @@ describe('apis/StyleSheet', () => {
|
||||
expect(isPlainObject(StyleSheet.absoluteFillObject) === true).toBeTruthy();
|
||||
});
|
||||
|
||||
describe('compose', () => {
|
||||
test('returns array when neither style is falsey', () => {
|
||||
expect(StyleSheet.compose(1, 2)).toEqual([1, 2]);
|
||||
});
|
||||
test('returns style1 when style2 is falsey', () => {
|
||||
expect(StyleSheet.compose(1, null)).toBe(1);
|
||||
});
|
||||
test('returns style2 when style1 is falsey', () => {
|
||||
expect(StyleSheet.compose(null, 2)).toBe(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('create', () => {
|
||||
test('replaces styles with numbers', () => {
|
||||
const style = StyleSheet.create({ root: { position: 'absolute' } });
|
||||
|
||||
22
src/apis/StyleSheet/getHairlineWidth.js
Normal file
22
src/apis/StyleSheet/getHairlineWidth.js
Normal file
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* Based on http://dieulot.net/css-retina-hairline
|
||||
* @noflow
|
||||
*/
|
||||
|
||||
import { canUseDOM } from 'fbjs/lib/ExecutionEnvironment';
|
||||
|
||||
const getHairlineWidth = () => {
|
||||
let hairlineWidth = 1;
|
||||
if (canUseDOM && window.devicePixelRatio && window.devicePixelRatio >= 2) {
|
||||
const node = document.createElement('div');
|
||||
node.style.border = '.5px solid transparent';
|
||||
document.body.appendChild(node);
|
||||
if (node.offsetHeight === 1) {
|
||||
hairlineWidth = 0.5;
|
||||
}
|
||||
document.body.removeChild(node);
|
||||
}
|
||||
return hairlineWidth;
|
||||
};
|
||||
|
||||
export default getHairlineWidth;
|
||||
@@ -10,6 +10,7 @@
|
||||
*/
|
||||
|
||||
import flattenStyle from './flattenStyle';
|
||||
import getHairlineWidth from './getHairlineWidth';
|
||||
import modality from '../../modules/modality';
|
||||
import StyleRegistry from './registry';
|
||||
|
||||
@@ -36,6 +37,13 @@ const absoluteFill = StyleRegistry.register(absoluteFillObject);
|
||||
const StyleSheet = {
|
||||
absoluteFill,
|
||||
absoluteFillObject,
|
||||
compose(style1, style2) {
|
||||
if (style1 && style2) {
|
||||
return [style1, style2];
|
||||
} else {
|
||||
return style1 || style2;
|
||||
}
|
||||
},
|
||||
create(styles) {
|
||||
const result = {};
|
||||
Object.keys(styles).forEach(key => {
|
||||
@@ -51,7 +59,7 @@ const StyleSheet = {
|
||||
getStyleSheets() {
|
||||
return StyleRegistry.getStyleSheets();
|
||||
},
|
||||
hairlineWidth: 1
|
||||
hairlineWidth: getHairlineWidth()
|
||||
};
|
||||
|
||||
export default StyleSheet;
|
||||
|
||||
2
src/components/ART/index.js
Normal file
2
src/components/ART/index.js
Normal file
@@ -0,0 +1,2 @@
|
||||
import ART from 'react-art';
|
||||
export default ART;
|
||||
@@ -21,7 +21,7 @@ const createSvgCircle = style => (
|
||||
<circle cx="16" cy="16" fill="none" r="14" strokeWidth="4" style={style} />
|
||||
);
|
||||
|
||||
class ActivityIndicator extends Component {
|
||||
class ActivityIndicator extends Component<*> {
|
||||
static displayName = 'ActivityIndicator';
|
||||
|
||||
static propTypes = {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/* eslint-env jasmine, jest */
|
||||
/* eslint-disable react/jsx-no-bind */
|
||||
|
||||
import React from 'react';
|
||||
import Button from '..';
|
||||
|
||||
@@ -17,7 +17,7 @@ import Text from '../Text';
|
||||
import { bool, func, string } from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
|
||||
class Button extends Component {
|
||||
class Button extends Component<*> {
|
||||
static propTypes = {
|
||||
accessibilityLabel: string,
|
||||
color: ColorPropType,
|
||||
|
||||
60
src/components/CheckBox/__tests__/index-test.js
Normal file
60
src/components/CheckBox/__tests__/index-test.js
Normal file
@@ -0,0 +1,60 @@
|
||||
/* eslint-env jest */
|
||||
|
||||
import CheckBox from '../';
|
||||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
|
||||
const checkboxSelector = 'input[type="checkbox"]';
|
||||
|
||||
describe('CheckBox', () => {
|
||||
describe('disabled', () => {
|
||||
test('when "false" a default checkbox is rendered', () => {
|
||||
const component = shallow(<CheckBox />);
|
||||
expect(component.find(checkboxSelector).prop('disabled')).toBe(false);
|
||||
});
|
||||
|
||||
test('when "true" a disabled checkbox is rendered', () => {
|
||||
const component = shallow(<CheckBox disabled />);
|
||||
expect(component.find(checkboxSelector).prop('disabled')).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('onChange', () => {
|
||||
test('is called with the event object', () => {
|
||||
const onChange = jest.fn();
|
||||
const component = shallow(<CheckBox onChange={onChange} value={false} />);
|
||||
component.find('input').simulate('change', { nativeEvent: { target: { checked: true } } });
|
||||
expect(onChange).toHaveBeenCalledWith({
|
||||
nativeEvent: { target: { checked: true }, value: true }
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('onValueChange', () => {
|
||||
test('when value is "false" it receives "true"', () => {
|
||||
const onValueChange = jest.fn();
|
||||
const component = shallow(<CheckBox onValueChange={onValueChange} value={false} />);
|
||||
component.find('input').simulate('change', { nativeEvent: { target: { checked: true } } });
|
||||
expect(onValueChange).toHaveBeenCalledWith(true);
|
||||
});
|
||||
|
||||
test('when value is "true" it receives "false"', () => {
|
||||
const onValueChange = jest.fn();
|
||||
const component = shallow(<CheckBox onValueChange={onValueChange} value />);
|
||||
component.find('input').simulate('change', { nativeEvent: { target: { checked: false } } });
|
||||
expect(onValueChange).toHaveBeenCalledWith(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('value', () => {
|
||||
test('when "false" an unchecked checkbox is rendered', () => {
|
||||
const component = shallow(<CheckBox value={false} />);
|
||||
expect(component.find(checkboxSelector).prop('checked')).toBe(false);
|
||||
});
|
||||
|
||||
test('when "true" a checked checkbox is rendered', () => {
|
||||
const component = shallow(<CheckBox value />);
|
||||
expect(component.find(checkboxSelector).prop('checked')).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
162
src/components/CheckBox/index.js
Normal file
162
src/components/CheckBox/index.js
Normal file
@@ -0,0 +1,162 @@
|
||||
/**
|
||||
* Copyright (c) 2017-present, Nicolas Gallagher.
|
||||
* Copyright (c) 2017-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @providesModule CheckBox
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import applyNativeMethods from '../../modules/applyNativeMethods';
|
||||
import ColorPropType from '../../propTypes/ColorPropType';
|
||||
import createElement from '../../modules/createElement';
|
||||
import StyleSheet from '../../apis/StyleSheet';
|
||||
import UIManager from '../../apis/UIManager';
|
||||
import View from '../View';
|
||||
import ViewPropTypes, { type ViewProps } from '../View/ViewPropTypes';
|
||||
import React, { Component } from 'react';
|
||||
import { bool, func } from 'prop-types';
|
||||
|
||||
type Props = ViewProps & {
|
||||
color?: ColorPropType,
|
||||
disabled?: boolean,
|
||||
onChange?: Function,
|
||||
onValueChange?: Function,
|
||||
value?: boolean
|
||||
};
|
||||
|
||||
class CheckBox extends Component<Props> {
|
||||
_checkboxElement: HTMLInputElement;
|
||||
|
||||
static displayName = 'CheckBox';
|
||||
|
||||
static propTypes = {
|
||||
...ViewPropTypes,
|
||||
color: ColorPropType,
|
||||
disabled: bool,
|
||||
onChange: func,
|
||||
onValueChange: func,
|
||||
value: bool
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
disabled: false,
|
||||
value: false
|
||||
};
|
||||
|
||||
blur() {
|
||||
UIManager.blur(this._checkboxElement);
|
||||
}
|
||||
|
||||
focus() {
|
||||
UIManager.focus(this._checkboxElement);
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
color,
|
||||
disabled,
|
||||
/* eslint-disable */
|
||||
onChange,
|
||||
onValueChange,
|
||||
/* eslint-enable */
|
||||
style,
|
||||
value,
|
||||
...other
|
||||
} = this.props;
|
||||
|
||||
const fakeControl = (
|
||||
<View
|
||||
style={[
|
||||
styles.fakeControl,
|
||||
value && styles.fakeControlChecked,
|
||||
// custom color
|
||||
value && color && { backgroundColor: color, borderColor: color },
|
||||
disabled && styles.fakeControlDisabled,
|
||||
value && disabled && styles.fakeControlCheckedAndDisabled
|
||||
]}
|
||||
/>
|
||||
);
|
||||
|
||||
const nativeControl = createElement('input', {
|
||||
checked: value,
|
||||
disabled: disabled,
|
||||
onChange: this._handleChange,
|
||||
ref: this._setCheckboxRef,
|
||||
style: [styles.nativeControl, styles.cursorInherit],
|
||||
type: 'checkbox'
|
||||
});
|
||||
|
||||
return (
|
||||
<View {...other} style={[styles.root, style, disabled && styles.cursorDefault]}>
|
||||
{fakeControl}
|
||||
{nativeControl}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
_handleChange = (event: Object) => {
|
||||
const { onChange, onValueChange } = this.props;
|
||||
const value = event.nativeEvent.target.checked;
|
||||
event.nativeEvent.value = value;
|
||||
onChange && onChange(event);
|
||||
onValueChange && onValueChange(value);
|
||||
};
|
||||
|
||||
_setCheckboxRef = element => {
|
||||
this._checkboxElement = element;
|
||||
};
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
root: {
|
||||
cursor: 'pointer',
|
||||
height: 16,
|
||||
userSelect: 'none',
|
||||
width: 16
|
||||
},
|
||||
cursorDefault: {
|
||||
cursor: 'default'
|
||||
},
|
||||
cursorInherit: {
|
||||
cursor: 'inherit'
|
||||
},
|
||||
fakeControl: {
|
||||
alignItems: 'center',
|
||||
backgroundColor: '#fff',
|
||||
borderColor: '#657786',
|
||||
borderRadius: 2,
|
||||
borderStyle: 'solid',
|
||||
borderWidth: 2,
|
||||
height: '100%',
|
||||
justifyContent: 'center',
|
||||
width: '100%'
|
||||
},
|
||||
fakeControlChecked: {
|
||||
backgroundColor: '#009688',
|
||||
backgroundImage:
|
||||
'url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcKICAgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIgogICB4bWxuczpjYz0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbnMjIgogICB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiCiAgIHhtbG5zOnN2Zz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgdmVyc2lvbj0iMS4xIgogICB2aWV3Qm94PSIwIDAgMSAxIgogICBwcmVzZXJ2ZUFzcGVjdFJhdGlvPSJ4TWluWU1pbiBtZWV0Ij4KICA8cGF0aAogICAgIGQ9Ik0gMC4wNDAzODA1OSwwLjYyNjc3NjcgMC4xNDY0NDY2MSwwLjUyMDcxMDY4IDAuNDI5Mjg5MzIsMC44MDM1NTMzOSAwLjMyMzIyMzMsMC45MDk2MTk0MSB6IE0gMC4yMTcxNTcyOSwwLjgwMzU1MzM5IDAuODUzNTUzMzksMC4xNjcxNTcyOSAwLjk1OTYxOTQxLDAuMjczMjIzMyAwLjMyMzIyMzMsMC45MDk2MTk0MSB6IgogICAgIGlkPSJyZWN0Mzc4MCIKICAgICBzdHlsZT0iZmlsbDojZmZmZmZmO2ZpbGwtb3BhY2l0eToxO3N0cm9rZTpub25lIiAvPgo8L3N2Zz4K")',
|
||||
backgroundRepeat: 'no-repeat',
|
||||
borderColor: '#009688'
|
||||
},
|
||||
fakeControlDisabled: {
|
||||
borderColor: '#CCD6DD'
|
||||
},
|
||||
fakeControlCheckedAndDisabled: {
|
||||
backgroundColor: '#AAB8C2',
|
||||
borderColor: '#AAB8C2'
|
||||
},
|
||||
nativeControl: {
|
||||
...StyleSheet.absoluteFillObject,
|
||||
height: '100%',
|
||||
margin: 0,
|
||||
opacity: 0,
|
||||
padding: 0,
|
||||
width: '100%'
|
||||
}
|
||||
});
|
||||
|
||||
export default applyNativeMethods(CheckBox);
|
||||
79
src/components/Image/ImageBackground.js
Normal file
79
src/components/Image/ImageBackground.js
Normal file
@@ -0,0 +1,79 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @flow
|
||||
*/
|
||||
import ensureComponentIsNative from '../Touchable/ensureComponentIsNative';
|
||||
import Image from './';
|
||||
import StyleSheet from '../../apis/StyleSheet';
|
||||
import View from '../View';
|
||||
import ViewPropTypes from '../View/ViewPropTypes';
|
||||
import React, { Component } from 'react';
|
||||
|
||||
const emptyObject = {};
|
||||
|
||||
/**
|
||||
* Very simple drop-in replacement for <Image> which supports nesting views.
|
||||
*/
|
||||
class ImageBackground extends Component<*> {
|
||||
static propTypes = {
|
||||
...Image.propTypes,
|
||||
imageStyle: Image.propTypes.style,
|
||||
style: ViewPropTypes.style
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
style: emptyObject
|
||||
};
|
||||
|
||||
setNativeProps(props: Object) {
|
||||
// Work-around flow
|
||||
const viewRef = this._viewRef;
|
||||
if (viewRef) {
|
||||
ensureComponentIsNative(viewRef);
|
||||
viewRef.setNativeProps(props);
|
||||
}
|
||||
}
|
||||
|
||||
_viewRef: ?View = null;
|
||||
|
||||
_captureRef = (ref: View) => {
|
||||
this._viewRef = ref;
|
||||
};
|
||||
|
||||
render() {
|
||||
const { children, style, imageStyle, imageRef, ...props } = this.props;
|
||||
|
||||
return (
|
||||
<View ref={this._captureRef} style={style}>
|
||||
<Image
|
||||
{...props}
|
||||
ref={imageRef}
|
||||
style={[
|
||||
StyleSheet.absoluteFill,
|
||||
{
|
||||
// Temporary Workaround:
|
||||
// Current (imperfect yet) implementation of <Image> overwrites width and height styles
|
||||
// (which is not quite correct), and these styles conflict with explicitly set styles
|
||||
// of <ImageBackground> and with our internal layout model here.
|
||||
// So, we have to proxy/reapply these styles explicitly for actual <Image> component.
|
||||
// This workaround should be removed after implementing proper support of
|
||||
// intrinsic content size of the <Image>.
|
||||
width: style.width,
|
||||
height: style.height
|
||||
},
|
||||
imageStyle
|
||||
]}
|
||||
/>
|
||||
{children}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default ImageBackground;
|
||||
36
src/components/Image/__tests__/ImageBackground-test.js
Normal file
36
src/components/Image/__tests__/ImageBackground-test.js
Normal file
@@ -0,0 +1,36 @@
|
||||
/* eslint-env jasmine, jest */
|
||||
|
||||
import Image from '..';
|
||||
import ImageBackground from '../ImageBackground';
|
||||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
import Text from '../../Text';
|
||||
|
||||
describe('components/ImageBackground', () => {
|
||||
describe('prop "children"', () => {
|
||||
it('render child content', () => {
|
||||
const component = shallow(
|
||||
<ImageBackground>
|
||||
<Text>Hello World!</Text>
|
||||
</ImageBackground>
|
||||
);
|
||||
expect(component.find(Text)).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('prop "imageStyle"', () => {
|
||||
it('sets the style of the underlying Image', () => {
|
||||
const imageStyle = { width: 40, height: 60 };
|
||||
const component = shallow(<ImageBackground imageStyle={imageStyle} />);
|
||||
expect(component.find(Image).prop('style')).toContain(imageStyle);
|
||||
});
|
||||
});
|
||||
|
||||
describe('prop "style"', () => {
|
||||
it('sets the style of the container View', () => {
|
||||
const style = { margin: 40 };
|
||||
const component = shallow(<ImageBackground style={style} />);
|
||||
expect(component.prop('style')).toEqual(style);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,4 +1,5 @@
|
||||
/* eslint-env jasmine, jest */
|
||||
/* eslint-disable react/jsx-no-bind */
|
||||
|
||||
import Image from '../';
|
||||
import ImageLoader from '../../../modules/ImageLoader';
|
||||
@@ -32,12 +33,6 @@ describe('components/Image', () => {
|
||||
expect(component.prop('accessible')).toBe(false);
|
||||
});
|
||||
|
||||
test('prop "children"', () => {
|
||||
const children = <div className="unique" />;
|
||||
const component = shallow(<Image children={children} />);
|
||||
expect(component.find('.unique').length).toBe(1);
|
||||
});
|
||||
|
||||
describe('prop "defaultSource"', () => {
|
||||
test('sets background image when value is an object', () => {
|
||||
const defaultSource = { uri: 'https://google.com/favicon.ico' };
|
||||
@@ -120,7 +115,7 @@ describe('components/Image', () => {
|
||||
const onLoadStub = jest.fn();
|
||||
const uri = 'https://test.com/img.jpg';
|
||||
const component = mount(<Image onLoad={onLoadStub} source={uri} />);
|
||||
component.setProps({ source: `https://blah.com/img.png` });
|
||||
component.setProps({ source: 'https://blah.com/img.png' });
|
||||
jest.runOnlyPendingTimers();
|
||||
expect(onLoadStub.mock.calls.length).toBe(2);
|
||||
});
|
||||
|
||||
@@ -22,7 +22,7 @@ import StyleSheet from '../../apis/StyleSheet';
|
||||
import StyleSheetPropType from '../../propTypes/StyleSheetPropType';
|
||||
import View from '../View';
|
||||
import ViewPropTypes from '../View/ViewPropTypes';
|
||||
import { any, bool, func, number, oneOf, oneOfType, shape, string } from 'prop-types';
|
||||
import { bool, func, number, oneOf, oneOfType, shape, string } from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
|
||||
const emptyObject = {};
|
||||
@@ -83,9 +83,11 @@ const resolveAssetSource = source => {
|
||||
return uri;
|
||||
};
|
||||
|
||||
class Image extends Component {
|
||||
state: { shouldDisplaySource: boolean };
|
||||
type State = {
|
||||
shouldDisplaySource: boolean
|
||||
};
|
||||
|
||||
class Image extends Component<*, State> {
|
||||
static displayName = 'Image';
|
||||
|
||||
static contextTypes = {
|
||||
@@ -94,7 +96,6 @@ class Image extends Component {
|
||||
|
||||
static propTypes = {
|
||||
...ViewPropTypes,
|
||||
children: any,
|
||||
defaultSource: ImageSourcePropType,
|
||||
draggable: bool,
|
||||
onError: func,
|
||||
@@ -174,7 +175,6 @@ class Image extends Component {
|
||||
const {
|
||||
accessibilityLabel,
|
||||
accessible,
|
||||
children,
|
||||
defaultSource,
|
||||
draggable,
|
||||
onLayout,
|
||||
@@ -219,6 +219,18 @@ class Image extends Component {
|
||||
})
|
||||
: null;
|
||||
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
if (this.props.src) {
|
||||
console.warn('The <Image> component requires a `source` property rather than `src`.');
|
||||
}
|
||||
|
||||
if (this.props.children) {
|
||||
throw new Error(
|
||||
'The <Image> component cannot contain children. If you want to render content on top of the image, consider using the <ImageBackground> component or absolute positioning.'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<View
|
||||
{...other}
|
||||
@@ -229,7 +241,6 @@ class Image extends Component {
|
||||
testID={testID}
|
||||
>
|
||||
{hiddenImage}
|
||||
{children}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ import React, { Component } from 'react';
|
||||
|
||||
import type { ViewLayout, ViewLayoutEvent } from '../View/ViewPropTypes';
|
||||
|
||||
class KeyboardAvoidingView extends Component {
|
||||
class KeyboardAvoidingView extends Component<*> {
|
||||
static propTypes = {
|
||||
...ViewPropTypes,
|
||||
behavior: oneOf(['height', 'padding', 'position']),
|
||||
|
||||
26
src/components/Picker/PickerItemPropType.js
Normal file
26
src/components/Picker/PickerItemPropType.js
Normal file
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* Copyright (c) 2017-present, Nicolas Gallagher.
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import Picker from './';
|
||||
|
||||
const PickerItemPropType = (props: Object, propName: string, componentName: string) => {
|
||||
const prop = props[propName];
|
||||
let error = null;
|
||||
React.Children.forEach(prop, function(child) {
|
||||
if (child.type !== Picker.Item) {
|
||||
error = new Error('`Picker` children must be of type `Picker.Item`.');
|
||||
}
|
||||
});
|
||||
return error;
|
||||
};
|
||||
|
||||
export default PickerItemPropType;
|
||||
20
src/components/Picker/PickerStylePropTypes.js
Normal file
20
src/components/Picker/PickerStylePropTypes.js
Normal file
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* Copyright (c) 2017-present, Nicolas Gallagher.
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import ColorPropType from '../../propTypes/ColorPropType';
|
||||
import ViewStylePropTypes from '../View/ViewStylePropTypes';
|
||||
|
||||
const PickerStylePropTypes = {
|
||||
...ViewStylePropTypes,
|
||||
color: ColorPropType
|
||||
};
|
||||
|
||||
export default PickerStylePropTypes;
|
||||
@@ -0,0 +1,17 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`components/Picker prop "children" renders items 1`] = `
|
||||
<select
|
||||
className="rn-fontFamily-poiln3 rn-fontSize-7cikom rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw"
|
||||
onChange={[Function]}
|
||||
>
|
||||
<PickerItem
|
||||
label="label-1"
|
||||
value="value-1"
|
||||
/>
|
||||
<PickerItem
|
||||
label="label-2"
|
||||
value="value-2"
|
||||
/>
|
||||
</select>
|
||||
`;
|
||||
74
src/components/Picker/__tests__/index-test.js
Normal file
74
src/components/Picker/__tests__/index-test.js
Normal file
@@ -0,0 +1,74 @@
|
||||
/* eslint-env jasmine, jest */
|
||||
|
||||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
import Picker from '..';
|
||||
|
||||
describe('components/Picker', () => {
|
||||
describe('prop "children"', () => {
|
||||
test('renders items', () => {
|
||||
const picker = (
|
||||
<Picker>
|
||||
<Picker.Item label="label-1" value="value-1" />
|
||||
<Picker.Item label="label-2" value="value-2" />
|
||||
</Picker>
|
||||
);
|
||||
const component = shallow(picker);
|
||||
expect(component).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
describe('prop "enabled"', () => {
|
||||
test('picker is disabled if false', () => {
|
||||
const picker = (
|
||||
<Picker enabled={false}>
|
||||
<Picker.Item label="label-1" value="value-1" />
|
||||
<Picker.Item label="label-2" value="value-2" />
|
||||
</Picker>
|
||||
);
|
||||
const component = shallow(picker);
|
||||
expect(component.find('select').props().disabled).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('prop "onValueChange"', () => {
|
||||
test('is called with (value, index)', () => {
|
||||
const onValueChange = jest.fn();
|
||||
const picker = (
|
||||
<Picker onValueChange={onValueChange} selectedValue="value-1">
|
||||
<Picker.Item label="label-1" value="value-1" />
|
||||
<Picker.Item label="label-2" value="value-2" />
|
||||
</Picker>
|
||||
);
|
||||
const component = shallow(picker);
|
||||
component.find('select').simulate('change', {
|
||||
target: { selectedIndex: '1', value: 'value-2' }
|
||||
});
|
||||
expect(onValueChange).toHaveBeenCalledWith('value-2', '1');
|
||||
});
|
||||
});
|
||||
|
||||
describe('prop "selectedValue"', () => {
|
||||
test('selects the correct item (string)', () => {
|
||||
const picker = (
|
||||
<Picker selectedValue="value-2">
|
||||
<Picker.Item label="label-1" value="value-1" />
|
||||
<Picker.Item label="label-2" value="value-2" />
|
||||
</Picker>
|
||||
);
|
||||
const component = shallow(picker);
|
||||
expect(component.find('select').prop('value')).toBe('value-2');
|
||||
});
|
||||
|
||||
test('selects the correct item (number)', () => {
|
||||
const picker = (
|
||||
<Picker selectedValue={22}>
|
||||
<Picker.Item label="label-1" value={11} />
|
||||
<Picker.Item label="label-2" value={22} />
|
||||
</Picker>
|
||||
);
|
||||
const component = shallow(picker);
|
||||
expect(component.find('select').prop('value')).toBe(22);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,4 +1,114 @@
|
||||
import UnimplementedView from '../UnimplementedView';
|
||||
const Picker = UnimplementedView;
|
||||
Picker.Item = UnimplementedView;
|
||||
export default Picker;
|
||||
/**
|
||||
* Copyright (c) 2017-present, Nicolas Gallagher.
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @providesModule Picker
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import applyNativeMethods from '../../modules/applyNativeMethods';
|
||||
import { Component } from 'react';
|
||||
import ColorPropType from '../../propTypes/ColorPropType';
|
||||
import createElement from '../../modules/createElement';
|
||||
import PickerItemPropType from './PickerItemPropType';
|
||||
import PickerStylePropTypes from './PickerStylePropTypes';
|
||||
import StyleSheetPropType from '../../propTypes/StyleSheetPropType';
|
||||
import StyleSheet from '../../apis/StyleSheet';
|
||||
import TextStylePropTypes from '../Text/TextStylePropTypes';
|
||||
import { arrayOf, bool, func, number, oneOfType, string } from 'prop-types';
|
||||
|
||||
const pickerStyleType = StyleSheetPropType(PickerStylePropTypes);
|
||||
const itemStylePropType = StyleSheetPropType(TextStylePropTypes);
|
||||
|
||||
type ItemProps = {
|
||||
color?: ColorPropType,
|
||||
label: string,
|
||||
testID?: string,
|
||||
value?: number | string
|
||||
};
|
||||
|
||||
class PickerItem extends Component<ItemProps> {
|
||||
static propTypes = {
|
||||
color: ColorPropType,
|
||||
label: string.isRequired,
|
||||
testID: string,
|
||||
value: oneOfType([number, string])
|
||||
};
|
||||
|
||||
render() {
|
||||
const { label, testID, value } = this.props;
|
||||
return createElement('option', { label, testID, value });
|
||||
}
|
||||
}
|
||||
|
||||
type Props = {
|
||||
children?: Array<typeof PickerItem>,
|
||||
enabled?: boolean,
|
||||
onValueChange?: Function,
|
||||
selectedValue?: number | string,
|
||||
style?: pickerStyleType,
|
||||
testID?: string,
|
||||
/* compat */
|
||||
itemStyle?: itemStylePropType,
|
||||
mode?: string,
|
||||
prompt?: string
|
||||
};
|
||||
|
||||
class Picker extends Component<Props> {
|
||||
static propTypes = {
|
||||
children: arrayOf(PickerItemPropType),
|
||||
enabled: bool,
|
||||
onValueChange: func,
|
||||
selectedValue: oneOfType([number, string]),
|
||||
style: pickerStyleType,
|
||||
testID: string
|
||||
};
|
||||
|
||||
static Item = PickerItem;
|
||||
|
||||
render() {
|
||||
const {
|
||||
children,
|
||||
enabled,
|
||||
selectedValue,
|
||||
style,
|
||||
testID,
|
||||
/* eslint-disable */
|
||||
itemStyle,
|
||||
mode,
|
||||
prompt
|
||||
/* eslint-enable */
|
||||
} = this.props;
|
||||
|
||||
return createElement('select', {
|
||||
children,
|
||||
disabled: enabled === false ? true : undefined,
|
||||
onChange: this._handleChange,
|
||||
style: [styles.initial, style],
|
||||
testID,
|
||||
value: selectedValue
|
||||
});
|
||||
}
|
||||
|
||||
_handleChange = (e: Object) => {
|
||||
const { onValueChange } = this.props;
|
||||
const { selectedIndex, value } = e.target;
|
||||
if (onValueChange) {
|
||||
onValueChange(value, selectedIndex);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
initial: {
|
||||
fontFamily: 'inherit',
|
||||
fontSize: 'inherit',
|
||||
margin: 0
|
||||
}
|
||||
});
|
||||
|
||||
export default applyNativeMethods(Picker);
|
||||
|
||||
@@ -17,7 +17,7 @@ import ViewPropTypes from '../View/ViewPropTypes';
|
||||
import React, { Component } from 'react';
|
||||
import { bool, number } from 'prop-types';
|
||||
|
||||
class ProgressBar extends Component {
|
||||
class ProgressBar extends Component<*> {
|
||||
_progressElement: View;
|
||||
|
||||
static displayName = 'ProgressBar';
|
||||
|
||||
@@ -16,7 +16,7 @@ import ViewPropTypes from '../View/ViewPropTypes';
|
||||
import { arrayOf, bool, func, number, oneOf, string } from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
|
||||
class RefreshControl extends Component {
|
||||
class RefreshControl extends Component<*> {
|
||||
static propTypes = {
|
||||
...ViewPropTypes,
|
||||
colors: arrayOf(ColorPropType),
|
||||
|
||||
14
src/components/SafeAreaView/index.js
Normal file
14
src/components/SafeAreaView/index.js
Normal file
@@ -0,0 +1,14 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule SafeAreaView
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import View from '../View';
|
||||
export default View;
|
||||
@@ -48,7 +48,7 @@ const normalizeScrollEvent = e => ({
|
||||
/**
|
||||
* Encapsulates the Web-specific scroll throttling and disabling logic
|
||||
*/
|
||||
export default class ScrollViewBase extends Component {
|
||||
export default class ScrollViewBase extends Component<*> {
|
||||
_viewRef: View;
|
||||
|
||||
static propTypes = {
|
||||
@@ -148,7 +148,7 @@ export default class ScrollViewBase extends Component {
|
||||
};
|
||||
};
|
||||
|
||||
_handleScroll = (e: SyntheticEvent) => {
|
||||
_handleScroll = (e: Object) => {
|
||||
e.persist();
|
||||
e.stopPropagation();
|
||||
const { scrollEventThrottle } = this.props;
|
||||
|
||||
@@ -28,7 +28,13 @@ import { Children, Component } from 'react';
|
||||
* Typically, you will not need to use this component and should opt for normal
|
||||
* React reconciliation.
|
||||
*/
|
||||
export default class StaticContainer extends Component {
|
||||
|
||||
type Props = {
|
||||
children: any,
|
||||
shouldUpdate: boolean
|
||||
};
|
||||
|
||||
export default class StaticContainer extends Component<Props> {
|
||||
static propTypes = {
|
||||
children: any.isRequired,
|
||||
shouldUpdate: bool.isRequired
|
||||
|
||||
@@ -27,7 +27,12 @@ import { bool, func } from 'prop-types';
|
||||
* React reconciliation.
|
||||
*/
|
||||
|
||||
export default class StaticRenderer extends Component {
|
||||
type Props = {
|
||||
render: Function,
|
||||
shouldUpdate: boolean
|
||||
};
|
||||
|
||||
export default class StaticRenderer extends Component<Props> {
|
||||
static propTypes = {
|
||||
render: func.isRequired,
|
||||
shouldUpdate: bool.isRequired
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
import { Component } from 'react';
|
||||
|
||||
export default class StatusBar extends Component {
|
||||
export default class StatusBar extends Component<*> {
|
||||
static setBackgroundColor() {}
|
||||
static setBarStyle() {}
|
||||
static setHidden() {}
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
/**
|
||||
* Copyright (c) 2016-present, Nicolas Gallagher.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @providesModule Switch
|
||||
* @flow
|
||||
*/
|
||||
@@ -11,14 +17,14 @@ import StyleSheet from '../../apis/StyleSheet';
|
||||
import UIManager from '../../apis/UIManager';
|
||||
import View from '../View';
|
||||
import ViewPropTypes from '../View/ViewPropTypes';
|
||||
import React, { PureComponent } from 'react';
|
||||
import React, { Component } from 'react';
|
||||
import { bool, func } from 'prop-types';
|
||||
|
||||
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)`;
|
||||
|
||||
class Switch extends PureComponent {
|
||||
class Switch extends Component<*> {
|
||||
_checkboxElement: HTMLInputElement;
|
||||
_thumbElement: View;
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/* eslint-env jasmine, jest */
|
||||
/* eslint-disable react/jsx-no-bind */
|
||||
|
||||
import React from 'react';
|
||||
import { render, shallow } from 'enzyme';
|
||||
|
||||
@@ -18,7 +18,7 @@ import createElement from '../../modules/createElement';
|
||||
import StyleSheet from '../../apis/StyleSheet';
|
||||
import TextPropTypes from './TextPropTypes';
|
||||
|
||||
class Text extends Component {
|
||||
class Text extends Component<*> {
|
||||
static displayName = 'Text';
|
||||
|
||||
static propTypes = TextPropTypes;
|
||||
|
||||
@@ -68,7 +68,7 @@ const setSelection = (node, selection) => {
|
||||
} catch (e) {}
|
||||
};
|
||||
|
||||
class TextInput extends Component {
|
||||
class TextInput extends Component<*> {
|
||||
_node: HTMLInputElement;
|
||||
|
||||
static displayName = 'TextInput';
|
||||
|
||||
@@ -316,27 +316,32 @@ const LONG_PRESS_ALLOWED_MOVEMENT = 10;
|
||||
* @lends Touchable.prototype
|
||||
*/
|
||||
const TouchableMixin = {
|
||||
// HACK (part 1): basic support for touchable interactions using a keyboard
|
||||
componentDidMount: function() {
|
||||
this._touchableNode = findNodeHandle(this);
|
||||
this._touchableBlurListener = e => {
|
||||
if (this._isTouchableKeyboardActive) {
|
||||
if (
|
||||
this.state.touchable.touchState &&
|
||||
this.state.touchable.touchState !== States.NOT_RESPONDER
|
||||
) {
|
||||
this.touchableHandleResponderTerminate({ nativeEvent: e });
|
||||
if (this._touchableNode && this._touchableNode.addEventListener) {
|
||||
this._touchableBlurListener = e => {
|
||||
if (this._isTouchableKeyboardActive) {
|
||||
if (
|
||||
this.state.touchable.touchState &&
|
||||
this.state.touchable.touchState !== States.NOT_RESPONDER
|
||||
) {
|
||||
this.touchableHandleResponderTerminate({ nativeEvent: e });
|
||||
}
|
||||
this._isTouchableKeyboardActive = false;
|
||||
}
|
||||
this._isTouchableKeyboardActive = false;
|
||||
}
|
||||
};
|
||||
this._touchableNode.addEventListener('blur', this._touchableBlurListener);
|
||||
};
|
||||
this._touchableNode.addEventListener('blur', this._touchableBlurListener);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Clear all timeouts on unmount
|
||||
*/
|
||||
componentWillUnmount: function() {
|
||||
this._touchableNode.removeEventListener('blur', this._touchableBlurListener);
|
||||
if (this._touchableNode && this._touchableNode.addEventListener) {
|
||||
this._touchableNode.removeEventListener('blur', this._touchableBlurListener);
|
||||
}
|
||||
this.touchableDelayTimeout && clearTimeout(this.touchableDelayTimeout);
|
||||
this.longPressDelayTimeout && clearTimeout(this.longPressDelayTimeout);
|
||||
this.pressOutDelayTimeout && clearTimeout(this.pressOutDelayTimeout);
|
||||
@@ -791,7 +796,7 @@ const TouchableMixin = {
|
||||
}
|
||||
},
|
||||
|
||||
// HACK: basic support for touchable interactions using a keyboard (including
|
||||
// HACK (part 2): basic support for touchable interactions using a keyboard (including
|
||||
// delays and longPress)
|
||||
touchableHandleKeyEvent: function(e: Event) {
|
||||
const ENTER = 13;
|
||||
|
||||
@@ -14,12 +14,12 @@ import BaseComponentPropTypes from '../../propTypes/BaseComponentPropTypes';
|
||||
import createReactClass from 'create-react-class';
|
||||
import EdgeInsetsPropType from '../../propTypes/EdgeInsetsPropType';
|
||||
import ensurePositiveDelayProps from './ensurePositiveDelayProps';
|
||||
import React from 'react';
|
||||
import React, { type Element } from 'react';
|
||||
import StyleSheet from '../../apis/StyleSheet';
|
||||
import TimerMixin from 'react-timer-mixin';
|
||||
import Touchable from './Touchable';
|
||||
import warning from 'fbjs/lib/warning';
|
||||
import { bool, func, number, string } from 'prop-types';
|
||||
import { any, bool, func, number, string } from 'prop-types';
|
||||
|
||||
type Event = Object;
|
||||
|
||||
@@ -44,6 +44,7 @@ const TouchableWithoutFeedback = createReactClass({
|
||||
accessibilityRole: BaseComponentPropTypes.accessibilityRole,
|
||||
accessibilityTraits: BaseComponentPropTypes.accessibilityTraits,
|
||||
accessible: bool,
|
||||
children: any,
|
||||
/**
|
||||
* Delay in ms, from onPressIn, before onLongPress is called.
|
||||
*/
|
||||
@@ -144,7 +145,7 @@ const TouchableWithoutFeedback = createReactClass({
|
||||
return this.props.delayPressOut || 0;
|
||||
},
|
||||
|
||||
render: function(): React.Element<any> {
|
||||
render: function(): Element<any> {
|
||||
const {
|
||||
/* eslint-disable */
|
||||
delayLongPress,
|
||||
|
||||
@@ -17,7 +17,7 @@ import React, { Component } from 'react';
|
||||
* Common implementation for a simple stubbed view.
|
||||
*/
|
||||
/* eslint-disable react/prop-types */
|
||||
class UnimplementedView extends Component {
|
||||
class UnimplementedView extends Component<*, *> {
|
||||
setNativeProps() {
|
||||
// Do nothing.
|
||||
// This method is required in order to use this view as a Touchable* child.
|
||||
|
||||
@@ -11,11 +11,13 @@
|
||||
*/
|
||||
|
||||
import BaseComponentPropTypes from '../../propTypes/BaseComponentPropTypes';
|
||||
import EdgeInsetsPropType from '../../propTypes/EdgeInsetsPropType';
|
||||
import EdgeInsetsPropType, { type EdgeInsetsProp } from '../../propTypes/EdgeInsetsPropType';
|
||||
import StyleSheetPropType from '../../propTypes/StyleSheetPropType';
|
||||
import ViewStylePropTypes from './ViewStylePropTypes';
|
||||
import { any, bool, func, oneOf } from 'prop-types';
|
||||
|
||||
const stylePropType = StyleSheetPropType(ViewStylePropTypes);
|
||||
|
||||
export type ViewLayout = {
|
||||
x: number,
|
||||
y: number,
|
||||
@@ -29,6 +31,46 @@ export type ViewLayoutEvent = {
|
||||
}
|
||||
};
|
||||
|
||||
export type ViewProps = {
|
||||
accessibilityComponentType?: string,
|
||||
accessibilityLabel?: string,
|
||||
accessibilityLiveRegion?: 'none' | 'polite' | 'assertive',
|
||||
accessibilityRole?: string,
|
||||
accessibilityTraits?: string | Array<string>,
|
||||
accessible?: boolean,
|
||||
children?: any,
|
||||
collapsable?: boolean,
|
||||
hitSlop?: EdgeInsetsProp,
|
||||
importantForAccessibility?: 'auto' | 'yes' | 'no' | 'no-hide-descendants',
|
||||
onAccessibilityTap?: Function,
|
||||
onClick?: Function,
|
||||
onClickCapture?: Function,
|
||||
onLayout?: (event: ViewLayoutEvent) => void,
|
||||
onMagicTap?: Function,
|
||||
onResponderGrant?: Function,
|
||||
onResponderMove?: Function,
|
||||
onResponderReject?: Function,
|
||||
onResponderRelease?: Function,
|
||||
onResponderTerminate?: Function,
|
||||
onResponderTerminationRequest?: Function,
|
||||
onStartShouldSetResponder?: Function,
|
||||
onStartShouldSetResponderCapture?: Function,
|
||||
onMoveShouldSetResponder?: Function,
|
||||
onMoveShouldSetResponderCapture?: Function,
|
||||
onTouchCancel?: Function,
|
||||
onTouchCancelCapture?: Function,
|
||||
onTouchEnd?: Function,
|
||||
onTouchEndCapture?: Function,
|
||||
onTouchMove?: Function,
|
||||
onTouchMoveCapture?: Function,
|
||||
onTouchStart?: Function,
|
||||
onTouchStartCapture?: Function,
|
||||
pointerEvents?: 'box-none' | 'none' | 'box-only' | 'auto',
|
||||
removeClippedSubviews?: boolean,
|
||||
style?: stylePropType,
|
||||
testID?: string
|
||||
};
|
||||
|
||||
const ViewPropTypes = {
|
||||
...BaseComponentPropTypes,
|
||||
children: any,
|
||||
@@ -56,7 +98,7 @@ const ViewPropTypes = {
|
||||
onTouchStart: func,
|
||||
onTouchStartCapture: func,
|
||||
pointerEvents: oneOf(['auto', 'box-none', 'box-only', 'none']),
|
||||
style: StyleSheetPropType(ViewStylePropTypes)
|
||||
style: stylePropType
|
||||
};
|
||||
|
||||
export default ViewPropTypes;
|
||||
|
||||
@@ -13,7 +13,7 @@ import { bool } from 'prop-types';
|
||||
import createElement from '../../modules/createElement';
|
||||
import invariant from 'fbjs/lib/invariant';
|
||||
import StyleSheet from '../../apis/StyleSheet';
|
||||
import ViewPropTypes from './ViewPropTypes';
|
||||
import ViewPropTypes, { type ViewProps } from './ViewPropTypes';
|
||||
import React, { Component } from 'react';
|
||||
|
||||
const calculateHitSlopStyle = hitSlop => {
|
||||
@@ -27,7 +27,7 @@ const calculateHitSlopStyle = hitSlop => {
|
||||
return hitStyle;
|
||||
};
|
||||
|
||||
class View extends Component {
|
||||
class View extends Component<ViewProps> {
|
||||
static displayName = 'View';
|
||||
|
||||
static contextTypes = {
|
||||
@@ -39,7 +39,6 @@ class View extends Component {
|
||||
render() {
|
||||
const {
|
||||
hitSlop,
|
||||
style,
|
||||
/* eslint-disable */
|
||||
collapsable,
|
||||
onAccessibilityTap,
|
||||
@@ -61,7 +60,7 @@ class View extends Component {
|
||||
|
||||
const { isInAParentText } = this.context;
|
||||
|
||||
otherProps.style = [styles.initial, isInAParentText && styles.inline, style];
|
||||
otherProps.style = [styles.initial, isInAParentText && styles.inline, this.props.style];
|
||||
|
||||
if (hitSlop) {
|
||||
const hitSlopStyle = calculateHitSlopStyle(hitSlop);
|
||||
|
||||
@@ -2,7 +2,8 @@ import createElement from './modules/createElement';
|
||||
import findNodeHandle from './modules/findNodeHandle';
|
||||
import NativeModules from './modules/NativeModules';
|
||||
import processColor from './modules/processColor';
|
||||
import { hydrate, render, unmountComponentAtNode } from 'react-dom';
|
||||
import render from './modules/render';
|
||||
import unmountComponentAtNode from './modules/unmountComponentAtNode';
|
||||
|
||||
// APIs
|
||||
import Animated from './apis/Animated';
|
||||
@@ -27,15 +28,19 @@ import Vibration from './apis/Vibration';
|
||||
|
||||
// components
|
||||
import ActivityIndicator from './components/ActivityIndicator';
|
||||
import ART from './components/ART';
|
||||
import Button from './components/Button';
|
||||
import CheckBox from './components/CheckBox';
|
||||
import FlatList from './components/FlatList';
|
||||
import Image from './components/Image';
|
||||
import ImageBackground from './components/Image/ImageBackground';
|
||||
import KeyboardAvoidingView from './components/KeyboardAvoidingView';
|
||||
import ListView from './components/ListView';
|
||||
import Modal from './components/Modal';
|
||||
import Picker from './components/Picker';
|
||||
import ProgressBar from './components/ProgressBar';
|
||||
import RefreshControl from './components/RefreshControl';
|
||||
import SafeAreaView from './components/SafeAreaView';
|
||||
import ScrollView from './components/ScrollView';
|
||||
import SectionList from './components/SectionList';
|
||||
import Slider from './components/Slider';
|
||||
@@ -61,7 +66,6 @@ import ViewPropTypes from './components/View/ViewPropTypes';
|
||||
export {
|
||||
// top-level API
|
||||
findNodeHandle,
|
||||
hydrate,
|
||||
render,
|
||||
unmountComponentAtNode,
|
||||
// modules
|
||||
@@ -90,15 +94,19 @@ export {
|
||||
Vibration,
|
||||
// components
|
||||
ActivityIndicator,
|
||||
ART,
|
||||
Button,
|
||||
CheckBox,
|
||||
FlatList,
|
||||
Image,
|
||||
ImageBackground,
|
||||
KeyboardAvoidingView,
|
||||
ListView,
|
||||
Modal,
|
||||
Picker,
|
||||
ProgressBar,
|
||||
RefreshControl,
|
||||
SafeAreaView,
|
||||
ScrollView,
|
||||
SectionList,
|
||||
Slider,
|
||||
@@ -124,7 +132,6 @@ export {
|
||||
const ReactNative = {
|
||||
// top-level API
|
||||
findNodeHandle,
|
||||
hydrate,
|
||||
render,
|
||||
unmountComponentAtNode,
|
||||
|
||||
@@ -156,15 +163,19 @@ const ReactNative = {
|
||||
|
||||
// components
|
||||
ActivityIndicator,
|
||||
ART,
|
||||
Button,
|
||||
CheckBox,
|
||||
FlatList,
|
||||
Image,
|
||||
ImageBackground,
|
||||
KeyboardAvoidingView,
|
||||
ListView,
|
||||
Modal,
|
||||
Picker,
|
||||
ProgressBar,
|
||||
RefreshControl,
|
||||
SafeAreaView,
|
||||
ScrollView,
|
||||
SectionList,
|
||||
Slider,
|
||||
|
||||
25
src/modules/NativeEventEmitter/index.js
Normal file
25
src/modules/NativeEventEmitter/index.js
Normal file
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule NativeEventEmitter
|
||||
* @noflow
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
class NativeEventEmitter {
|
||||
addListener() {}
|
||||
emit() {}
|
||||
listeners() {}
|
||||
once() {}
|
||||
removeAllListeners() {}
|
||||
removeCurrentListener() {}
|
||||
removeListener() {}
|
||||
removeSubscription() {}
|
||||
}
|
||||
|
||||
module.exports = NativeEventEmitter;
|
||||
@@ -1,3 +1,3 @@
|
||||
// NativeModules shim
|
||||
const NativeModules = {};
|
||||
export default NativeModules;
|
||||
module.exports = NativeModules;
|
||||
|
||||
@@ -354,7 +354,7 @@ const ScrollResponderMixin = {
|
||||
},
|
||||
|
||||
/**
|
||||
* A helper function to scroll to a specific point in the scrollview.
|
||||
* A helper function to scroll to a specific point in the scrollview.
|
||||
* This is currently used to help focus on child textviews, but can also
|
||||
* be used to quickly scroll to any element we want to focus. Syntax:
|
||||
*
|
||||
@@ -377,6 +377,7 @@ const ScrollResponderMixin = {
|
||||
({ x, y, animated } = x || emptyObject);
|
||||
}
|
||||
const node = this.scrollResponderGetScrollableNode();
|
||||
UIManager.updateView(node, { style: { scrollBehavior: !animated ? 'auto' : 'smooth' } }, this);
|
||||
node.scrollLeft = x || 0;
|
||||
node.scrollTop = y || 0;
|
||||
},
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow
|
||||
* @noflow
|
||||
*/
|
||||
|
||||
import { canUseDOM } from 'fbjs/lib/ExecutionEnvironment';
|
||||
@@ -38,7 +38,7 @@ const safeOverride = (original, next) => {
|
||||
return next;
|
||||
};
|
||||
|
||||
const applyLayout = (Component: ReactClass<any>) => {
|
||||
const applyLayout = Component => {
|
||||
const componentDidMount = Component.prototype.componentDidMount;
|
||||
const componentDidUpdate = Component.prototype.componentDidUpdate;
|
||||
const componentWillUnmount = Component.prototype.componentWillUnmount;
|
||||
|
||||
@@ -5,12 +5,12 @@
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow
|
||||
* @noflow
|
||||
*/
|
||||
|
||||
import NativeMethodsMixin from '../NativeMethodsMixin';
|
||||
|
||||
const applyNativeMethods = (Component: ReactClass<any>) => {
|
||||
const applyNativeMethods = Component => {
|
||||
Object.keys(NativeMethodsMixin).forEach(method => {
|
||||
if (!Component.prototype[method]) {
|
||||
Component.prototype[method] = NativeMethodsMixin[method];
|
||||
|
||||
12
src/modules/hydrate/index.js
Normal file
12
src/modules/hydrate/index.js
Normal file
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* Copyright (c) 2016-present, Nicolas Gallagher.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @noflow
|
||||
*/
|
||||
|
||||
import { hydrate } from 'react-dom';
|
||||
export default hydrate;
|
||||
12
src/modules/render/index.js
Normal file
12
src/modules/render/index.js
Normal file
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* Copyright (c) 2016-present, Nicolas Gallagher.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @noflow
|
||||
*/
|
||||
|
||||
import { render } from 'react-dom';
|
||||
export default render;
|
||||
12
src/modules/unmountComponentAtNode/index.js
Normal file
12
src/modules/unmountComponentAtNode/index.js
Normal file
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* Copyright (c) 2016-present, Nicolas Gallagher.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @noflow
|
||||
*/
|
||||
|
||||
import { unmountComponentAtNode } from 'react-dom';
|
||||
export default unmountComponentAtNode;
|
||||
@@ -7,7 +7,7 @@
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule ColorPropType
|
||||
* @flow
|
||||
* @noflow
|
||||
*/
|
||||
|
||||
const isWebColor = (color: string) =>
|
||||
|
||||
196
src/vendor/Animated/AnimatedEvent.js
vendored
Normal file
196
src/vendor/Animated/AnimatedEvent.js
vendored
Normal file
@@ -0,0 +1,196 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule AnimatedEvent
|
||||
* @noflow
|
||||
* @format
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
const AnimatedValue = require('./nodes/AnimatedValue');
|
||||
const NativeAnimatedHelper = require('./NativeAnimatedHelper');
|
||||
const findNodeHandle = require('../../modules/findNodeHandle').default;
|
||||
|
||||
const invariant = require('fbjs/lib/invariant');
|
||||
const {shouldUseNativeDriver} = require('./NativeAnimatedHelper');
|
||||
|
||||
export type Mapping = {[key: string]: Mapping} | AnimatedValue;
|
||||
export type EventConfig = {
|
||||
listener?: ?Function,
|
||||
useNativeDriver?: boolean,
|
||||
};
|
||||
|
||||
function attachNativeEvent(
|
||||
viewRef: any,
|
||||
eventName: string,
|
||||
argMapping: Array<?Mapping>,
|
||||
) {
|
||||
// Find animated values in `argMapping` and create an array representing their
|
||||
// key path inside the `nativeEvent` object. Ex.: ['contentOffset', 'x'].
|
||||
const eventMappings = [];
|
||||
|
||||
const traverse = (value, path) => {
|
||||
if (value instanceof AnimatedValue) {
|
||||
value.__makeNative();
|
||||
|
||||
eventMappings.push({
|
||||
nativeEventPath: path,
|
||||
animatedValueTag: value.__getNativeTag(),
|
||||
});
|
||||
} else if (typeof value === 'object') {
|
||||
for (const key in value) {
|
||||
traverse(value[key], path.concat(key));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
invariant(
|
||||
argMapping[0] && argMapping[0].nativeEvent,
|
||||
'Native driven events only support animated values contained inside `nativeEvent`.',
|
||||
);
|
||||
|
||||
// Assume that the event containing `nativeEvent` is always the first argument.
|
||||
traverse(argMapping[0].nativeEvent, []);
|
||||
|
||||
const viewTag = findNodeHandle(viewRef);
|
||||
|
||||
eventMappings.forEach(mapping => {
|
||||
NativeAnimatedHelper.API.addAnimatedEventToView(
|
||||
viewTag,
|
||||
eventName,
|
||||
mapping,
|
||||
);
|
||||
});
|
||||
|
||||
return {
|
||||
detach() {
|
||||
eventMappings.forEach(mapping => {
|
||||
NativeAnimatedHelper.API.removeAnimatedEventFromView(
|
||||
viewTag,
|
||||
eventName,
|
||||
mapping.animatedValueTag,
|
||||
);
|
||||
});
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
class AnimatedEvent {
|
||||
_argMapping: Array<?Mapping>;
|
||||
_listeners: Array<Function> = [];
|
||||
_callListeners: Function;
|
||||
_attachedEvent: ?{
|
||||
detach: () => void,
|
||||
};
|
||||
__isNative: boolean;
|
||||
|
||||
constructor(argMapping: Array<?Mapping>, config?: EventConfig = {}) {
|
||||
this._argMapping = argMapping;
|
||||
if (config.listener) {
|
||||
this.__addListener(config.listener);
|
||||
}
|
||||
this._callListeners = this._callListeners.bind(this);
|
||||
this._attachedEvent = null;
|
||||
this.__isNative = shouldUseNativeDriver(config);
|
||||
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
this._validateMapping();
|
||||
}
|
||||
}
|
||||
|
||||
__addListener(callback: Function): void {
|
||||
this._listeners.push(callback);
|
||||
}
|
||||
|
||||
__removeListener(callback: Function): void {
|
||||
this._listeners = this._listeners.filter(listener => listener !== callback);
|
||||
}
|
||||
|
||||
__attach(viewRef: any, eventName: string) {
|
||||
invariant(
|
||||
this.__isNative,
|
||||
'Only native driven events need to be attached.',
|
||||
);
|
||||
|
||||
this._attachedEvent = attachNativeEvent(
|
||||
viewRef,
|
||||
eventName,
|
||||
this._argMapping,
|
||||
);
|
||||
}
|
||||
|
||||
__detach(viewTag: any, eventName: string) {
|
||||
invariant(
|
||||
this.__isNative,
|
||||
'Only native driven events need to be detached.',
|
||||
);
|
||||
|
||||
this._attachedEvent && this._attachedEvent.detach();
|
||||
}
|
||||
|
||||
__getHandler() {
|
||||
if (this.__isNative) {
|
||||
return this._callListeners;
|
||||
}
|
||||
|
||||
return (...args: any) => {
|
||||
const traverse = (recMapping, recEvt, key) => {
|
||||
if (typeof recEvt === 'number' && recMapping instanceof AnimatedValue) {
|
||||
recMapping.setValue(recEvt);
|
||||
} else if (typeof recMapping === 'object') {
|
||||
for (const mappingKey in recMapping) {
|
||||
/* $FlowFixMe(>=0.53.0 site=react_native_fb,react_native_oss) This
|
||||
* comment suppresses an error when upgrading Flow's support for
|
||||
* React. To see the error delete this comment and run Flow. */
|
||||
traverse(recMapping[mappingKey], recEvt[mappingKey], mappingKey);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (!this.__isNative) {
|
||||
this._argMapping.forEach((mapping, idx) => {
|
||||
traverse(mapping, args[idx], 'arg' + idx);
|
||||
});
|
||||
}
|
||||
this._callListeners(...args);
|
||||
};
|
||||
}
|
||||
|
||||
_callListeners(...args) {
|
||||
this._listeners.forEach(listener => listener(...args));
|
||||
}
|
||||
|
||||
_validateMapping() {
|
||||
const traverse = (recMapping, recEvt, key) => {
|
||||
if (typeof recEvt === 'number') {
|
||||
invariant(
|
||||
recMapping instanceof AnimatedValue,
|
||||
'Bad mapping of type ' +
|
||||
typeof recMapping +
|
||||
' for key ' +
|
||||
key +
|
||||
', event value must map to AnimatedValue',
|
||||
);
|
||||
return;
|
||||
}
|
||||
invariant(
|
||||
typeof recMapping === 'object',
|
||||
'Bad mapping of type ' + typeof recMapping + ' for key ' + key,
|
||||
);
|
||||
invariant(
|
||||
typeof recEvt === 'object',
|
||||
'Bad event of type ' + typeof recEvt + ' for key ' + key,
|
||||
);
|
||||
for (const mappingKey in recMapping) {
|
||||
traverse(recMapping[mappingKey], recEvt[mappingKey], mappingKey);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {AnimatedEvent, attachNativeEvent};
|
||||
676
src/vendor/Animated/AnimatedImplementation.js
vendored
Normal file
676
src/vendor/Animated/AnimatedImplementation.js
vendored
Normal file
@@ -0,0 +1,676 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule AnimatedImplementation
|
||||
* @flow
|
||||
* @format
|
||||
* @preventMunge
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
const {AnimatedEvent, attachNativeEvent} = require('./AnimatedEvent');
|
||||
const AnimatedAddition = require('./nodes/AnimatedAddition');
|
||||
const AnimatedDiffClamp = require('./nodes/AnimatedDiffClamp');
|
||||
const AnimatedDivision = require('./nodes/AnimatedDivision');
|
||||
const AnimatedInterpolation = require('./nodes/AnimatedInterpolation');
|
||||
const AnimatedModulo = require('./nodes/AnimatedModulo');
|
||||
const AnimatedMultiplication = require('./nodes/AnimatedMultiplication');
|
||||
const AnimatedNode = require('./nodes/AnimatedNode');
|
||||
const AnimatedProps = require('./nodes/AnimatedProps');
|
||||
const AnimatedTracking = require('./nodes/AnimatedTracking');
|
||||
const AnimatedValue = require('./nodes/AnimatedValue');
|
||||
const AnimatedValueXY = require('./nodes/AnimatedValueXY');
|
||||
const DecayAnimation = require('./animations/DecayAnimation');
|
||||
const SpringAnimation = require('./animations/SpringAnimation');
|
||||
const TimingAnimation = require('./animations/TimingAnimation');
|
||||
|
||||
const createAnimatedComponent = require('./createAnimatedComponent');
|
||||
|
||||
import type {
|
||||
AnimationConfig,
|
||||
EndCallback,
|
||||
EndResult,
|
||||
} from './animations/Animation';
|
||||
import type {TimingAnimationConfig} from './animations/TimingAnimation';
|
||||
import type {DecayAnimationConfig} from './animations/DecayAnimation';
|
||||
import type {SpringAnimationConfig} from './animations/SpringAnimation';
|
||||
import type {Mapping, EventConfig} from './AnimatedEvent';
|
||||
|
||||
type CompositeAnimation = {
|
||||
start: (callback?: ?EndCallback) => void,
|
||||
stop: () => void,
|
||||
reset: () => void,
|
||||
_startNativeLoop: (iterations?: number) => void,
|
||||
_isUsingNativeDriver: () => boolean,
|
||||
};
|
||||
|
||||
const add = function(
|
||||
a: AnimatedNode | number,
|
||||
b: AnimatedNode | number,
|
||||
): AnimatedAddition {
|
||||
return new AnimatedAddition(a, b);
|
||||
};
|
||||
|
||||
const divide = function(
|
||||
a: AnimatedNode | number,
|
||||
b: AnimatedNode | number,
|
||||
): AnimatedDivision {
|
||||
return new AnimatedDivision(a, b);
|
||||
};
|
||||
|
||||
const multiply = function(
|
||||
a: AnimatedNode | number,
|
||||
b: AnimatedNode | number,
|
||||
): AnimatedMultiplication {
|
||||
return new AnimatedMultiplication(a, b);
|
||||
};
|
||||
|
||||
const modulo = function(a: AnimatedNode, modulus: number): AnimatedModulo {
|
||||
return new AnimatedModulo(a, modulus);
|
||||
};
|
||||
|
||||
const diffClamp = function(
|
||||
a: AnimatedNode,
|
||||
min: number,
|
||||
max: number,
|
||||
): AnimatedDiffClamp {
|
||||
return new AnimatedDiffClamp(a, min, max);
|
||||
};
|
||||
|
||||
const _combineCallbacks = function(
|
||||
callback: ?EndCallback,
|
||||
config: AnimationConfig,
|
||||
) {
|
||||
if (callback && config.onComplete) {
|
||||
return (...args) => {
|
||||
config.onComplete && config.onComplete(...args);
|
||||
callback && callback(...args);
|
||||
};
|
||||
} else {
|
||||
return callback || config.onComplete;
|
||||
}
|
||||
};
|
||||
|
||||
const maybeVectorAnim = function(
|
||||
value: AnimatedValue | AnimatedValueXY,
|
||||
config: Object,
|
||||
anim: (value: AnimatedValue, config: Object) => CompositeAnimation,
|
||||
): ?CompositeAnimation {
|
||||
if (value instanceof AnimatedValueXY) {
|
||||
const configX = {...config};
|
||||
const configY = {...config};
|
||||
for (const key in config) {
|
||||
const {x, y} = config[key];
|
||||
if (x !== undefined && y !== undefined) {
|
||||
configX[key] = x;
|
||||
configY[key] = y;
|
||||
}
|
||||
}
|
||||
const aX = anim((value: AnimatedValueXY).x, configX);
|
||||
const aY = anim((value: AnimatedValueXY).y, configY);
|
||||
// We use `stopTogether: false` here because otherwise tracking will break
|
||||
// because the second animation will get stopped before it can update.
|
||||
return parallel([aX, aY], {stopTogether: false});
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
const spring = function(
|
||||
value: AnimatedValue | AnimatedValueXY,
|
||||
config: SpringAnimationConfig,
|
||||
): CompositeAnimation {
|
||||
const start = function(
|
||||
animatedValue: AnimatedValue | AnimatedValueXY,
|
||||
configuration: SpringAnimationConfig,
|
||||
callback?: ?EndCallback,
|
||||
): void {
|
||||
callback = _combineCallbacks(callback, configuration);
|
||||
const singleValue: any = animatedValue;
|
||||
const singleConfig: any = configuration;
|
||||
singleValue.stopTracking();
|
||||
if (configuration.toValue instanceof AnimatedNode) {
|
||||
singleValue.track(
|
||||
new AnimatedTracking(
|
||||
singleValue,
|
||||
configuration.toValue,
|
||||
SpringAnimation,
|
||||
singleConfig,
|
||||
callback,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
singleValue.animate(new SpringAnimation(singleConfig), callback);
|
||||
}
|
||||
};
|
||||
return (
|
||||
maybeVectorAnim(value, config, spring) || {
|
||||
start: function(callback?: ?EndCallback): void {
|
||||
start(value, config, callback);
|
||||
},
|
||||
|
||||
stop: function(): void {
|
||||
value.stopAnimation();
|
||||
},
|
||||
|
||||
reset: function(): void {
|
||||
value.resetAnimation();
|
||||
},
|
||||
|
||||
_startNativeLoop: function(iterations?: number): void {
|
||||
const singleConfig = {...config, iterations};
|
||||
start(value, singleConfig);
|
||||
},
|
||||
|
||||
_isUsingNativeDriver: function(): boolean {
|
||||
return config.useNativeDriver || false;
|
||||
},
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
const timing = function(
|
||||
value: AnimatedValue | AnimatedValueXY,
|
||||
config: TimingAnimationConfig,
|
||||
): CompositeAnimation {
|
||||
const start = function(
|
||||
animatedValue: AnimatedValue | AnimatedValueXY,
|
||||
configuration: TimingAnimationConfig,
|
||||
callback?: ?EndCallback,
|
||||
): void {
|
||||
callback = _combineCallbacks(callback, configuration);
|
||||
const singleValue: any = animatedValue;
|
||||
const singleConfig: any = configuration;
|
||||
singleValue.stopTracking();
|
||||
if (configuration.toValue instanceof AnimatedNode) {
|
||||
singleValue.track(
|
||||
new AnimatedTracking(
|
||||
singleValue,
|
||||
configuration.toValue,
|
||||
TimingAnimation,
|
||||
singleConfig,
|
||||
callback,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
singleValue.animate(new TimingAnimation(singleConfig), callback);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
maybeVectorAnim(value, config, timing) || {
|
||||
start: function(callback?: ?EndCallback): void {
|
||||
start(value, config, callback);
|
||||
},
|
||||
|
||||
stop: function(): void {
|
||||
value.stopAnimation();
|
||||
},
|
||||
|
||||
reset: function(): void {
|
||||
value.resetAnimation();
|
||||
},
|
||||
|
||||
_startNativeLoop: function(iterations?: number): void {
|
||||
const singleConfig = {...config, iterations};
|
||||
start(value, singleConfig);
|
||||
},
|
||||
|
||||
_isUsingNativeDriver: function(): boolean {
|
||||
return config.useNativeDriver || false;
|
||||
},
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
const decay = function(
|
||||
value: AnimatedValue | AnimatedValueXY,
|
||||
config: DecayAnimationConfig,
|
||||
): CompositeAnimation {
|
||||
const start = function(
|
||||
animatedValue: AnimatedValue | AnimatedValueXY,
|
||||
configuration: DecayAnimationConfig,
|
||||
callback?: ?EndCallback,
|
||||
): void {
|
||||
callback = _combineCallbacks(callback, configuration);
|
||||
const singleValue: any = animatedValue;
|
||||
const singleConfig: any = configuration;
|
||||
singleValue.stopTracking();
|
||||
singleValue.animate(new DecayAnimation(singleConfig), callback);
|
||||
};
|
||||
|
||||
return (
|
||||
maybeVectorAnim(value, config, decay) || {
|
||||
start: function(callback?: ?EndCallback): void {
|
||||
start(value, config, callback);
|
||||
},
|
||||
|
||||
stop: function(): void {
|
||||
value.stopAnimation();
|
||||
},
|
||||
|
||||
reset: function(): void {
|
||||
value.resetAnimation();
|
||||
},
|
||||
|
||||
_startNativeLoop: function(iterations?: number): void {
|
||||
const singleConfig = {...config, iterations};
|
||||
start(value, singleConfig);
|
||||
},
|
||||
|
||||
_isUsingNativeDriver: function(): boolean {
|
||||
return config.useNativeDriver || false;
|
||||
},
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
const sequence = function(
|
||||
animations: Array<CompositeAnimation>,
|
||||
): CompositeAnimation {
|
||||
let current = 0;
|
||||
return {
|
||||
start: function(callback?: ?EndCallback) {
|
||||
const onComplete = function(result) {
|
||||
if (!result.finished) {
|
||||
callback && callback(result);
|
||||
return;
|
||||
}
|
||||
|
||||
current++;
|
||||
|
||||
if (current === animations.length) {
|
||||
callback && callback(result);
|
||||
return;
|
||||
}
|
||||
|
||||
animations[current].start(onComplete);
|
||||
};
|
||||
|
||||
if (animations.length === 0) {
|
||||
callback && callback({finished: true});
|
||||
} else {
|
||||
animations[current].start(onComplete);
|
||||
}
|
||||
},
|
||||
|
||||
stop: function() {
|
||||
if (current < animations.length) {
|
||||
animations[current].stop();
|
||||
}
|
||||
},
|
||||
|
||||
reset: function() {
|
||||
animations.forEach((animation, idx) => {
|
||||
if (idx <= current) {
|
||||
animation.reset();
|
||||
}
|
||||
});
|
||||
current = 0;
|
||||
},
|
||||
|
||||
_startNativeLoop: function() {
|
||||
throw new Error(
|
||||
'Loops run using the native driver cannot contain Animated.sequence animations',
|
||||
);
|
||||
},
|
||||
|
||||
_isUsingNativeDriver: function(): boolean {
|
||||
return false;
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
type ParallelConfig = {
|
||||
stopTogether?: boolean, // If one is stopped, stop all. default: true
|
||||
};
|
||||
const parallel = function(
|
||||
animations: Array<CompositeAnimation>,
|
||||
config?: ?ParallelConfig,
|
||||
): CompositeAnimation {
|
||||
let doneCount = 0;
|
||||
// Make sure we only call stop() at most once for each animation
|
||||
const hasEnded = {};
|
||||
const stopTogether = !(config && config.stopTogether === false);
|
||||
|
||||
const result = {
|
||||
start: function(callback?: ?EndCallback) {
|
||||
if (doneCount === animations.length) {
|
||||
callback && callback({finished: true});
|
||||
return;
|
||||
}
|
||||
|
||||
animations.forEach((animation, idx) => {
|
||||
const cb = function(endResult) {
|
||||
hasEnded[idx] = true;
|
||||
doneCount++;
|
||||
if (doneCount === animations.length) {
|
||||
doneCount = 0;
|
||||
callback && callback(endResult);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!endResult.finished && stopTogether) {
|
||||
result.stop();
|
||||
}
|
||||
};
|
||||
|
||||
if (!animation) {
|
||||
cb({finished: true});
|
||||
} else {
|
||||
animation.start(cb);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
stop: function(): void {
|
||||
animations.forEach((animation, idx) => {
|
||||
!hasEnded[idx] && animation.stop();
|
||||
hasEnded[idx] = true;
|
||||
});
|
||||
},
|
||||
|
||||
reset: function(): void {
|
||||
animations.forEach((animation, idx) => {
|
||||
animation.reset();
|
||||
hasEnded[idx] = false;
|
||||
doneCount = 0;
|
||||
});
|
||||
},
|
||||
|
||||
_startNativeLoop: function() {
|
||||
throw new Error(
|
||||
'Loops run using the native driver cannot contain Animated.parallel animations',
|
||||
);
|
||||
},
|
||||
|
||||
_isUsingNativeDriver: function(): boolean {
|
||||
return false;
|
||||
},
|
||||
};
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
const delay = function(time: number): CompositeAnimation {
|
||||
// Would be nice to make a specialized implementation
|
||||
return timing(new AnimatedValue(0), {toValue: 0, delay: time, duration: 0});
|
||||
};
|
||||
|
||||
const stagger = function(
|
||||
time: number,
|
||||
animations: Array<CompositeAnimation>,
|
||||
): CompositeAnimation {
|
||||
return parallel(
|
||||
animations.map((animation, i) => {
|
||||
return sequence([delay(time * i), animation]);
|
||||
}),
|
||||
);
|
||||
};
|
||||
|
||||
type LoopAnimationConfig = {iterations: number};
|
||||
|
||||
const loop = function(
|
||||
animation: CompositeAnimation,
|
||||
{iterations = -1}: LoopAnimationConfig = {},
|
||||
): CompositeAnimation {
|
||||
let isFinished = false;
|
||||
let iterationsSoFar = 0;
|
||||
return {
|
||||
start: function(callback?: ?EndCallback) {
|
||||
const restart = function(result: EndResult = {finished: true}): void {
|
||||
if (
|
||||
isFinished ||
|
||||
iterationsSoFar === iterations ||
|
||||
result.finished === false
|
||||
) {
|
||||
callback && callback(result);
|
||||
} else {
|
||||
iterationsSoFar++;
|
||||
animation.reset();
|
||||
animation.start(restart);
|
||||
}
|
||||
};
|
||||
if (!animation || iterations === 0) {
|
||||
callback && callback({finished: true});
|
||||
} else {
|
||||
if (animation._isUsingNativeDriver()) {
|
||||
animation._startNativeLoop(iterations);
|
||||
} else {
|
||||
restart(); // Start looping recursively on the js thread
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
stop: function(): void {
|
||||
isFinished = true;
|
||||
animation.stop();
|
||||
},
|
||||
|
||||
reset: function(): void {
|
||||
iterationsSoFar = 0;
|
||||
isFinished = false;
|
||||
animation.reset();
|
||||
},
|
||||
|
||||
_startNativeLoop: function() {
|
||||
throw new Error(
|
||||
'Loops run using the native driver cannot contain Animated.loop animations',
|
||||
);
|
||||
},
|
||||
|
||||
_isUsingNativeDriver: function(): boolean {
|
||||
return animation._isUsingNativeDriver();
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
function forkEvent(
|
||||
event: ?AnimatedEvent | ?Function,
|
||||
listener: Function,
|
||||
): AnimatedEvent | Function {
|
||||
if (!event) {
|
||||
return listener;
|
||||
} else if (event instanceof AnimatedEvent) {
|
||||
event.__addListener(listener);
|
||||
return event;
|
||||
} else {
|
||||
return (...args) => {
|
||||
typeof event === 'function' && event(...args);
|
||||
listener(...args);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function unforkEvent(
|
||||
event: ?AnimatedEvent | ?Function,
|
||||
listener: Function,
|
||||
): void {
|
||||
if (event && event instanceof AnimatedEvent) {
|
||||
event.__removeListener(listener);
|
||||
}
|
||||
}
|
||||
|
||||
const event = function(argMapping: Array<?Mapping>, config?: EventConfig): any {
|
||||
const animatedEvent = new AnimatedEvent(argMapping, config);
|
||||
if (animatedEvent.__isNative) {
|
||||
return animatedEvent;
|
||||
} else {
|
||||
return animatedEvent.__getHandler();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* The `Animated` library is designed to make animations fluid, powerful, and
|
||||
* easy to build and maintain. `Animated` focuses on declarative relationships
|
||||
* between inputs and outputs, with configurable transforms in between, and
|
||||
* simple `start`/`stop` methods to control time-based animation execution.
|
||||
*
|
||||
* See http://facebook.github.io/react-native/docs/animated.html
|
||||
*/
|
||||
module.exports = {
|
||||
/**
|
||||
* Standard value class for driving animations. Typically initialized with
|
||||
* `new Animated.Value(0);`
|
||||
*
|
||||
* See http://facebook.github.io/react-native/docs/animated.html#value
|
||||
*/
|
||||
Value: AnimatedValue,
|
||||
/**
|
||||
* 2D value class for driving 2D animations, such as pan gestures.
|
||||
*
|
||||
* See https://facebook.github.io/react-native/releases/next/docs/animatedvaluexy.html
|
||||
*/
|
||||
ValueXY: AnimatedValueXY,
|
||||
/**
|
||||
* Exported to use the Interpolation type in flow.
|
||||
*
|
||||
* See http://facebook.github.io/react-native/docs/animated.html#interpolation
|
||||
*/
|
||||
Interpolation: AnimatedInterpolation,
|
||||
/**
|
||||
* Exported for ease of type checking. All animated values derive from this
|
||||
* class.
|
||||
*
|
||||
* See http://facebook.github.io/react-native/docs/animated.html#node
|
||||
*/
|
||||
Node: AnimatedNode,
|
||||
|
||||
/**
|
||||
* Animates a value from an initial velocity to zero based on a decay
|
||||
* coefficient.
|
||||
*
|
||||
* See http://facebook.github.io/react-native/docs/animated.html#decay
|
||||
*/
|
||||
decay,
|
||||
/**
|
||||
* Animates a value along a timed easing curve. The Easing module has tons of
|
||||
* predefined curves, or you can use your own function.
|
||||
*
|
||||
* See http://facebook.github.io/react-native/docs/animated.html#timing
|
||||
*/
|
||||
timing,
|
||||
/**
|
||||
* Animates a value according to an analytical spring model based on
|
||||
* damped harmonic oscillation.
|
||||
*
|
||||
* See http://facebook.github.io/react-native/docs/animated.html#spring
|
||||
*/
|
||||
spring,
|
||||
|
||||
/**
|
||||
* Creates a new Animated value composed from two Animated values added
|
||||
* together.
|
||||
*
|
||||
* See http://facebook.github.io/react-native/docs/animated.html#add
|
||||
*/
|
||||
add,
|
||||
|
||||
/**
|
||||
* Creates a new Animated value composed by dividing the first Animated value
|
||||
* by the second Animated value.
|
||||
*
|
||||
* See http://facebook.github.io/react-native/docs/animated.html#divide
|
||||
*/
|
||||
divide,
|
||||
|
||||
/**
|
||||
* Creates a new Animated value composed from two Animated values multiplied
|
||||
* together.
|
||||
*
|
||||
* See http://facebook.github.io/react-native/docs/animated.html#multiply
|
||||
*/
|
||||
multiply,
|
||||
|
||||
/**
|
||||
* Creates a new Animated value that is the (non-negative) modulo of the
|
||||
* provided Animated value.
|
||||
*
|
||||
* See http://facebook.github.io/react-native/docs/animated.html#modulo
|
||||
*/
|
||||
modulo,
|
||||
|
||||
/**
|
||||
* Create a new Animated value that is limited between 2 values. It uses the
|
||||
* difference between the last value so even if the value is far from the
|
||||
* bounds it will start changing when the value starts getting closer again.
|
||||
*
|
||||
* See http://facebook.github.io/react-native/docs/animated.html#diffclamp
|
||||
*/
|
||||
diffClamp,
|
||||
|
||||
/**
|
||||
* Starts an animation after the given delay.
|
||||
*
|
||||
* See http://facebook.github.io/react-native/docs/animated.html#delay
|
||||
*/
|
||||
delay,
|
||||
/**
|
||||
* Starts an array of animations in order, waiting for each to complete
|
||||
* before starting the next. If the current running animation is stopped, no
|
||||
* following animations will be started.
|
||||
*
|
||||
* See http://facebook.github.io/react-native/docs/animated.html#sequence
|
||||
*/
|
||||
sequence,
|
||||
/**
|
||||
* Starts an array of animations all at the same time. By default, if one
|
||||
* of the animations is stopped, they will all be stopped. You can override
|
||||
* this with the `stopTogether` flag.
|
||||
*
|
||||
* See http://facebook.github.io/react-native/docs/animated.html#parallel
|
||||
*/
|
||||
parallel,
|
||||
/**
|
||||
* Array of animations may run in parallel (overlap), but are started in
|
||||
* sequence with successive delays. Nice for doing trailing effects.
|
||||
*
|
||||
* See http://facebook.github.io/react-native/docs/animated.html#stagger
|
||||
*/
|
||||
stagger,
|
||||
/**
|
||||
* Loops a given animation continuously, so that each time it reaches the
|
||||
* end, it resets and begins again from the start.
|
||||
*
|
||||
* See http://facebook.github.io/react-native/docs/animated.html#loop
|
||||
*/
|
||||
loop,
|
||||
|
||||
/**
|
||||
* Takes an array of mappings and extracts values from each arg accordingly,
|
||||
* then calls `setValue` on the mapped outputs.
|
||||
*
|
||||
* See http://facebook.github.io/react-native/docs/animated.html#event
|
||||
*/
|
||||
event,
|
||||
|
||||
/**
|
||||
* Make any React component Animatable. Used to create `Animated.View`, etc.
|
||||
*
|
||||
* See http://facebook.github.io/react-native/docs/animated.html#createanimatedcomponent
|
||||
*/
|
||||
createAnimatedComponent,
|
||||
|
||||
/**
|
||||
* Imperative API to attach an animated value to an event on a view. Prefer
|
||||
* using `Animated.event` with `useNativeDrive: true` if possible.
|
||||
*
|
||||
* See http://facebook.github.io/react-native/docs/animated.html#attachnativeevent
|
||||
*/
|
||||
attachNativeEvent,
|
||||
|
||||
/**
|
||||
* Advanced imperative API for snooping on animated events that are passed in
|
||||
* through props. Use values directly where possible.
|
||||
*
|
||||
* See http://facebook.github.io/react-native/docs/animated.html#forkevent
|
||||
*/
|
||||
forkEvent,
|
||||
unforkEvent,
|
||||
|
||||
__PropsOnlyForTests: AnimatedProps,
|
||||
};
|
||||
303
src/vendor/Animated/Easing.js
vendored
Normal file
303
src/vendor/Animated/Easing.js
vendored
Normal file
@@ -0,0 +1,303 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule Easing
|
||||
* @flow
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
let ease;
|
||||
|
||||
/**
|
||||
* The `Easing` module implements common easing functions. This module is used
|
||||
* by [Animate.timing()](docs/animate.html#timing) to convey physically
|
||||
* believable motion in animations.
|
||||
*
|
||||
* You can find a visualization of some common easing functions at
|
||||
* http://easings.net/
|
||||
*
|
||||
* ### Predefined animations
|
||||
*
|
||||
* The `Easing` module provides several predefined animations through the
|
||||
* following methods:
|
||||
*
|
||||
* - [`back`](docs/easing.html#back) provides a simple animation where the
|
||||
* object goes slightly back before moving forward
|
||||
* - [`bounce`](docs/easing.html#bounce) provides a bouncing animation
|
||||
* - [`ease`](docs/easing.html#ease) provides a simple inertial animation
|
||||
* - [`elastic`](docs/easing.html#elastic) provides a simple spring interaction
|
||||
*
|
||||
* ### Standard functions
|
||||
*
|
||||
* Three standard easing functions are provided:
|
||||
*
|
||||
* - [`linear`](docs/easing.html#linear)
|
||||
* - [`quad`](docs/easing.html#quad)
|
||||
* - [`cubic`](docs/easing.html#cubic)
|
||||
*
|
||||
* The [`poly`](docs/easing.html#poly) function can be used to implement
|
||||
* quartic, quintic, and other higher power functions.
|
||||
*
|
||||
* ### Additional functions
|
||||
*
|
||||
* Additional mathematical functions are provided by the following methods:
|
||||
*
|
||||
* - [`bezier`](docs/easing.html#bezier) provides a cubic bezier curve
|
||||
* - [`circle`](docs/easing.html#circle) provides a circular function
|
||||
* - [`sin`](docs/easing.html#sin) provides a sinusoidal function
|
||||
* - [`exp`](docs/easing.html#exp) provides an exponential function
|
||||
*
|
||||
* The following helpers are used to modify other easing functions.
|
||||
*
|
||||
* - [`in`](docs/easing.html#in) runs an easing function forwards
|
||||
* - [`inOut`](docs/easing.html#inout) makes any easing function symmetrical
|
||||
* - [`out`](docs/easing.html#out) runs an easing function backwards
|
||||
*/
|
||||
class Easing {
|
||||
/**
|
||||
* A stepping function, returns 1 for any positive value of `n`.
|
||||
*/
|
||||
/* $FlowFixMe(>=0.59.0 site=react_native_fb) This comment suppresses an error
|
||||
* caught by Flow 0.59 which was not caught before. Most likely, this error
|
||||
* is because an exported function parameter is missing an annotation.
|
||||
* Without an annotation, these parameters are uncovered by Flow. */
|
||||
static step0(n) {
|
||||
return n > 0 ? 1 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* A stepping function, returns 1 if `n` is greater than or equal to 1.
|
||||
*/
|
||||
/* $FlowFixMe(>=0.59.0 site=react_native_fb) This comment suppresses an error
|
||||
* caught by Flow 0.59 which was not caught before. Most likely, this error
|
||||
* is because an exported function parameter is missing an annotation.
|
||||
* Without an annotation, these parameters are uncovered by Flow. */
|
||||
static step1(n) {
|
||||
return n >= 1 ? 1 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* A linear function, `f(t) = t`. Position correlates to elapsed time one to
|
||||
* one.
|
||||
*
|
||||
* http://cubic-bezier.com/#0,0,1,1
|
||||
*/
|
||||
/* $FlowFixMe(>=0.59.0 site=react_native_fb) This comment suppresses an error
|
||||
* caught by Flow 0.59 which was not caught before. Most likely, this error
|
||||
* is because an exported function parameter is missing an annotation.
|
||||
* Without an annotation, these parameters are uncovered by Flow. */
|
||||
static linear(t) {
|
||||
return t;
|
||||
}
|
||||
|
||||
/**
|
||||
* A simple inertial interaction, similar to an object slowly accelerating to
|
||||
* speed.
|
||||
*
|
||||
* http://cubic-bezier.com/#.42,0,1,1
|
||||
*/
|
||||
static ease(t: number): number {
|
||||
if (!ease) {
|
||||
ease = Easing.bezier(0.42, 0, 1, 1);
|
||||
}
|
||||
return ease(t);
|
||||
}
|
||||
|
||||
/**
|
||||
* A quadratic function, `f(t) = t * t`. Position equals the square of elapsed
|
||||
* time.
|
||||
*
|
||||
* http://easings.net/#easeInQuad
|
||||
*/
|
||||
/* $FlowFixMe(>=0.59.0 site=react_native_fb) This comment suppresses an error
|
||||
* caught by Flow 0.59 which was not caught before. Most likely, this error
|
||||
* is because an exported function parameter is missing an annotation.
|
||||
* Without an annotation, these parameters are uncovered by Flow. */
|
||||
static quad(t) {
|
||||
return t * t;
|
||||
}
|
||||
|
||||
/**
|
||||
* A cubic function, `f(t) = t * t * t`. Position equals the cube of elapsed
|
||||
* time.
|
||||
*
|
||||
* http://easings.net/#easeInCubic
|
||||
*/
|
||||
/* $FlowFixMe(>=0.59.0 site=react_native_fb) This comment suppresses an error
|
||||
* caught by Flow 0.59 which was not caught before. Most likely, this error
|
||||
* is because an exported function parameter is missing an annotation.
|
||||
* Without an annotation, these parameters are uncovered by Flow. */
|
||||
static cubic(t) {
|
||||
return t * t * t;
|
||||
}
|
||||
|
||||
/**
|
||||
* A power function. Position is equal to the Nth power of elapsed time.
|
||||
*
|
||||
* n = 4: http://easings.net/#easeInQuart
|
||||
* n = 5: http://easings.net/#easeInQuint
|
||||
*/
|
||||
/* $FlowFixMe(>=0.59.0 site=react_native_fb) This comment suppresses an error
|
||||
* caught by Flow 0.59 which was not caught before. Most likely, this error
|
||||
* is because an exported function parameter is missing an annotation.
|
||||
* Without an annotation, these parameters are uncovered by Flow. */
|
||||
static poly(n) {
|
||||
/* $FlowFixMe(>=0.59.0 site=react_native_fb) This comment suppresses an
|
||||
* error caught by Flow 0.59 which was not caught before. Most likely, this
|
||||
* error is because an exported function parameter is missing an
|
||||
* annotation. Without an annotation, these parameters are uncovered by
|
||||
* Flow. */
|
||||
return (t) => Math.pow(t, n);
|
||||
}
|
||||
|
||||
/**
|
||||
* A sinusoidal function.
|
||||
*
|
||||
* http://easings.net/#easeInSine
|
||||
*/
|
||||
/* $FlowFixMe(>=0.59.0 site=react_native_fb) This comment suppresses an error
|
||||
* caught by Flow 0.59 which was not caught before. Most likely, this error
|
||||
* is because an exported function parameter is missing an annotation.
|
||||
* Without an annotation, these parameters are uncovered by Flow. */
|
||||
static sin(t) {
|
||||
return 1 - Math.cos(t * Math.PI / 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* A circular function.
|
||||
*
|
||||
* http://easings.net/#easeInCirc
|
||||
*/
|
||||
/* $FlowFixMe(>=0.59.0 site=react_native_fb) This comment suppresses an error
|
||||
* caught by Flow 0.59 which was not caught before. Most likely, this error
|
||||
* is because an exported function parameter is missing an annotation.
|
||||
* Without an annotation, these parameters are uncovered by Flow. */
|
||||
static circle(t) {
|
||||
return 1 - Math.sqrt(1 - t * t);
|
||||
}
|
||||
|
||||
/**
|
||||
* An exponential function.
|
||||
*
|
||||
* http://easings.net/#easeInExpo
|
||||
*/
|
||||
/* $FlowFixMe(>=0.59.0 site=react_native_fb) This comment suppresses an error
|
||||
* caught by Flow 0.59 which was not caught before. Most likely, this error
|
||||
* is because an exported function parameter is missing an annotation.
|
||||
* Without an annotation, these parameters are uncovered by Flow. */
|
||||
static exp(t) {
|
||||
return Math.pow(2, 10 * (t - 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* A simple elastic interaction, similar to a spring oscillating back and
|
||||
* forth.
|
||||
*
|
||||
* Default bounciness is 1, which overshoots a little bit once. 0 bounciness
|
||||
* doesn't overshoot at all, and bounciness of N > 1 will overshoot about N
|
||||
* times.
|
||||
*
|
||||
* http://easings.net/#easeInElastic
|
||||
*/
|
||||
static elastic(bounciness: number = 1): (t: number) => number {
|
||||
const p = bounciness * Math.PI;
|
||||
return (t) => 1 - Math.pow(Math.cos(t * Math.PI / 2), 3) * Math.cos(t * p);
|
||||
}
|
||||
|
||||
/**
|
||||
* Use with `Animated.parallel()` to create a simple effect where the object
|
||||
* animates back slightly as the animation starts.
|
||||
*
|
||||
* Wolfram Plot:
|
||||
*
|
||||
* - http://tiny.cc/back_default (s = 1.70158, default)
|
||||
*/
|
||||
static back(s: number): (t: number) => number {
|
||||
if (s === undefined) {
|
||||
s = 1.70158;
|
||||
}
|
||||
return (t) => t * t * ((s + 1) * t - s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a simple bouncing effect.
|
||||
*
|
||||
* http://easings.net/#easeInBounce
|
||||
*/
|
||||
static bounce(t: number): number {
|
||||
if (t < 1 / 2.75) {
|
||||
return 7.5625 * t * t;
|
||||
}
|
||||
|
||||
if (t < 2 / 2.75) {
|
||||
t -= 1.5 / 2.75;
|
||||
return 7.5625 * t * t + 0.75;
|
||||
}
|
||||
|
||||
if (t < 2.5 / 2.75) {
|
||||
t -= 2.25 / 2.75;
|
||||
return 7.5625 * t * t + 0.9375;
|
||||
}
|
||||
|
||||
t -= 2.625 / 2.75;
|
||||
return 7.5625 * t * t + 0.984375;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a cubic bezier curve, equivalent to CSS Transitions'
|
||||
* `transition-timing-function`.
|
||||
*
|
||||
* A useful tool to visualize cubic bezier curves can be found at
|
||||
* http://cubic-bezier.com/
|
||||
*/
|
||||
static bezier(
|
||||
x1: number,
|
||||
y1: number,
|
||||
x2: number,
|
||||
y2: number
|
||||
): (t: number) => number {
|
||||
const _bezier = require('./bezier');
|
||||
return _bezier(x1, y1, x2, y2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs an easing function forwards.
|
||||
*/
|
||||
static in(
|
||||
easing: (t: number) => number,
|
||||
): (t: number) => number {
|
||||
return easing;
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs an easing function backwards.
|
||||
*/
|
||||
static out(
|
||||
easing: (t: number) => number,
|
||||
): (t: number) => number {
|
||||
return (t) => 1 - easing(1 - t);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes any easing function symmetrical. The easing function will run
|
||||
* forwards for half of the duration, then backwards for the rest of the
|
||||
* duration.
|
||||
*/
|
||||
static inOut(
|
||||
easing: (t: number) => number,
|
||||
): (t: number) => number {
|
||||
return (t) => {
|
||||
if (t < 0.5) {
|
||||
return easing(t * 2) / 2;
|
||||
}
|
||||
return 1 - easing((1 - t) * 2) / 2;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Easing;
|
||||
259
src/vendor/Animated/NativeAnimatedHelper.js
vendored
Normal file
259
src/vendor/Animated/NativeAnimatedHelper.js
vendored
Normal file
@@ -0,0 +1,259 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule NativeAnimatedHelper
|
||||
* @flow
|
||||
* @format
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
const invariant = require('fbjs/lib/invariant');
|
||||
const NativeModules = require('../../modules/NativeModules');
|
||||
const NativeEventEmitter = require('../../modules/NativeEventEmitter');
|
||||
|
||||
import type {AnimationConfig} from './animations/Animation';
|
||||
import type {EventConfig} from './AnimatedEvent';
|
||||
|
||||
const NativeAnimatedModule = NativeModules.NativeAnimatedModule;
|
||||
|
||||
let __nativeAnimatedNodeTagCount = 1; /* used for animated nodes */
|
||||
let __nativeAnimationIdCount = 1; /* used for started animations */
|
||||
|
||||
type EndResult = {finished: boolean};
|
||||
type EndCallback = (result: EndResult) => void;
|
||||
type EventMapping = {
|
||||
nativeEventPath: Array<string>,
|
||||
animatedValueTag: ?number,
|
||||
};
|
||||
|
||||
let nativeEventEmitter;
|
||||
|
||||
/**
|
||||
* Simple wrappers around NativeAnimatedModule to provide flow and autocmplete support for
|
||||
* the native module methods
|
||||
*/
|
||||
const API = {
|
||||
createAnimatedNode: function(tag: ?number, config: Object): void {
|
||||
assertNativeAnimatedModule();
|
||||
NativeAnimatedModule.createAnimatedNode(tag, config);
|
||||
},
|
||||
startListeningToAnimatedNodeValue: function(tag: ?number) {
|
||||
assertNativeAnimatedModule();
|
||||
NativeAnimatedModule.startListeningToAnimatedNodeValue(tag);
|
||||
},
|
||||
stopListeningToAnimatedNodeValue: function(tag: ?number) {
|
||||
assertNativeAnimatedModule();
|
||||
NativeAnimatedModule.stopListeningToAnimatedNodeValue(tag);
|
||||
},
|
||||
connectAnimatedNodes: function(parentTag: ?number, childTag: ?number): void {
|
||||
assertNativeAnimatedModule();
|
||||
NativeAnimatedModule.connectAnimatedNodes(parentTag, childTag);
|
||||
},
|
||||
disconnectAnimatedNodes: function(
|
||||
parentTag: ?number,
|
||||
childTag: ?number,
|
||||
): void {
|
||||
assertNativeAnimatedModule();
|
||||
NativeAnimatedModule.disconnectAnimatedNodes(parentTag, childTag);
|
||||
},
|
||||
startAnimatingNode: function(
|
||||
animationId: ?number,
|
||||
nodeTag: ?number,
|
||||
config: Object,
|
||||
endCallback: EndCallback,
|
||||
): void {
|
||||
assertNativeAnimatedModule();
|
||||
NativeAnimatedModule.startAnimatingNode(
|
||||
animationId,
|
||||
nodeTag,
|
||||
config,
|
||||
endCallback,
|
||||
);
|
||||
},
|
||||
stopAnimation: function(animationId: ?number) {
|
||||
assertNativeAnimatedModule();
|
||||
NativeAnimatedModule.stopAnimation(animationId);
|
||||
},
|
||||
setAnimatedNodeValue: function(nodeTag: ?number, value: ?number): void {
|
||||
assertNativeAnimatedModule();
|
||||
NativeAnimatedModule.setAnimatedNodeValue(nodeTag, value);
|
||||
},
|
||||
setAnimatedNodeOffset: function(nodeTag: ?number, offset: ?number): void {
|
||||
assertNativeAnimatedModule();
|
||||
NativeAnimatedModule.setAnimatedNodeOffset(nodeTag, offset);
|
||||
},
|
||||
flattenAnimatedNodeOffset: function(nodeTag: ?number): void {
|
||||
assertNativeAnimatedModule();
|
||||
NativeAnimatedModule.flattenAnimatedNodeOffset(nodeTag);
|
||||
},
|
||||
extractAnimatedNodeOffset: function(nodeTag: ?number): void {
|
||||
assertNativeAnimatedModule();
|
||||
NativeAnimatedModule.extractAnimatedNodeOffset(nodeTag);
|
||||
},
|
||||
connectAnimatedNodeToView: function(
|
||||
nodeTag: ?number,
|
||||
viewTag: ?number,
|
||||
): void {
|
||||
assertNativeAnimatedModule();
|
||||
NativeAnimatedModule.connectAnimatedNodeToView(nodeTag, viewTag);
|
||||
},
|
||||
disconnectAnimatedNodeFromView: function(
|
||||
nodeTag: ?number,
|
||||
viewTag: ?number,
|
||||
): void {
|
||||
assertNativeAnimatedModule();
|
||||
NativeAnimatedModule.disconnectAnimatedNodeFromView(nodeTag, viewTag);
|
||||
},
|
||||
dropAnimatedNode: function(tag: ?number): void {
|
||||
assertNativeAnimatedModule();
|
||||
NativeAnimatedModule.dropAnimatedNode(tag);
|
||||
},
|
||||
addAnimatedEventToView: function(
|
||||
viewTag: ?number,
|
||||
eventName: string,
|
||||
eventMapping: EventMapping,
|
||||
) {
|
||||
assertNativeAnimatedModule();
|
||||
NativeAnimatedModule.addAnimatedEventToView(
|
||||
viewTag,
|
||||
eventName,
|
||||
eventMapping,
|
||||
);
|
||||
},
|
||||
removeAnimatedEventFromView(
|
||||
viewTag: ?number,
|
||||
eventName: string,
|
||||
animatedNodeTag: ?number,
|
||||
) {
|
||||
assertNativeAnimatedModule();
|
||||
NativeAnimatedModule.removeAnimatedEventFromView(
|
||||
viewTag,
|
||||
eventName,
|
||||
animatedNodeTag,
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Styles allowed by the native animated implementation.
|
||||
*
|
||||
* In general native animated implementation should support any numeric property that doesn't need
|
||||
* to be updated through the shadow view hierarchy (all non-layout properties).
|
||||
*/
|
||||
const STYLES_WHITELIST = {
|
||||
opacity: true,
|
||||
transform: true,
|
||||
/* ios styles */
|
||||
shadowOpacity: true,
|
||||
shadowRadius: true,
|
||||
/* legacy android transform properties */
|
||||
scaleX: true,
|
||||
scaleY: true,
|
||||
translateX: true,
|
||||
translateY: true,
|
||||
};
|
||||
|
||||
const TRANSFORM_WHITELIST = {
|
||||
translateX: true,
|
||||
translateY: true,
|
||||
scale: true,
|
||||
scaleX: true,
|
||||
scaleY: true,
|
||||
rotate: true,
|
||||
rotateX: true,
|
||||
rotateY: true,
|
||||
perspective: true,
|
||||
};
|
||||
|
||||
function validateTransform(configs: Array<Object>): void {
|
||||
configs.forEach(config => {
|
||||
if (!TRANSFORM_WHITELIST.hasOwnProperty(config.property)) {
|
||||
throw new Error(
|
||||
`Property '${config.property}' is not supported by native animated module`,
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function validateStyles(styles: Object): void {
|
||||
for (var key in styles) {
|
||||
if (!STYLES_WHITELIST.hasOwnProperty(key)) {
|
||||
throw new Error(
|
||||
`Style property '${key}' is not supported by native animated module`,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function validateInterpolation(config: Object): void {
|
||||
var SUPPORTED_INTERPOLATION_PARAMS = {
|
||||
inputRange: true,
|
||||
outputRange: true,
|
||||
extrapolate: true,
|
||||
extrapolateRight: true,
|
||||
extrapolateLeft: true,
|
||||
};
|
||||
for (var key in config) {
|
||||
if (!SUPPORTED_INTERPOLATION_PARAMS.hasOwnProperty(key)) {
|
||||
throw new Error(
|
||||
`Interpolation property '${key}' is not supported by native animated module`,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function generateNewNodeTag(): number {
|
||||
return __nativeAnimatedNodeTagCount++;
|
||||
}
|
||||
|
||||
function generateNewAnimationId(): number {
|
||||
return __nativeAnimationIdCount++;
|
||||
}
|
||||
|
||||
function assertNativeAnimatedModule(): void {
|
||||
invariant(NativeAnimatedModule, 'Native animated module is not available');
|
||||
}
|
||||
|
||||
let _warnedMissingNativeAnimated = false;
|
||||
|
||||
function shouldUseNativeDriver(config: AnimationConfig | EventConfig): boolean {
|
||||
if (config.useNativeDriver && !NativeAnimatedModule) {
|
||||
if (!_warnedMissingNativeAnimated) {
|
||||
console.warn(
|
||||
'Animated: `useNativeDriver` is not supported because the native ' +
|
||||
'animated module is missing. Falling back to JS-based animation. To ' +
|
||||
'resolve this, add `RCTAnimation` module to this app, or remove ' +
|
||||
'`useNativeDriver`. ' +
|
||||
'More info: https://github.com/facebook/react-native/issues/11094#issuecomment-263240420',
|
||||
);
|
||||
_warnedMissingNativeAnimated = true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return config.useNativeDriver || false;
|
||||
}
|
||||
|
||||
const NativeAnimatedHelper = {
|
||||
API,
|
||||
validateStyles,
|
||||
validateTransform,
|
||||
validateInterpolation,
|
||||
generateNewNodeTag,
|
||||
generateNewAnimationId,
|
||||
assertNativeAnimatedModule,
|
||||
shouldUseNativeDriver,
|
||||
get nativeEventEmitter() {
|
||||
if (!nativeEventEmitter) {
|
||||
nativeEventEmitter = new NativeEventEmitter(NativeAnimatedModule);
|
||||
}
|
||||
return nativeEventEmitter;
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = NativeAnimatedHelper;
|
||||
1
src/vendor/Animated/SHA
vendored
Normal file
1
src/vendor/Animated/SHA
vendored
Normal file
@@ -0,0 +1 @@
|
||||
facebook/react-native@71006f74cdafdae7212c8a10603fb972c6ee338c
|
||||
102
src/vendor/Animated/SpringConfig.js
vendored
Normal file
102
src/vendor/Animated/SpringConfig.js
vendored
Normal file
@@ -0,0 +1,102 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule SpringConfig
|
||||
* @flow
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
type SpringConfigType = {
|
||||
stiffness: number,
|
||||
damping: number,
|
||||
};
|
||||
|
||||
function stiffnessFromOrigamiValue(oValue) {
|
||||
return (oValue - 30) * 3.62 + 194;
|
||||
}
|
||||
|
||||
function dampingFromOrigamiValue(oValue) {
|
||||
return (oValue - 8) * 3 + 25;
|
||||
}
|
||||
|
||||
function fromOrigamiTensionAndFriction(
|
||||
tension: number,
|
||||
friction: number,
|
||||
): SpringConfigType {
|
||||
return {
|
||||
stiffness: stiffnessFromOrigamiValue(tension),
|
||||
damping: dampingFromOrigamiValue(friction),
|
||||
};
|
||||
}
|
||||
|
||||
function fromBouncinessAndSpeed(
|
||||
bounciness: number,
|
||||
speed: number,
|
||||
): SpringConfigType {
|
||||
function normalize(value, startValue, endValue) {
|
||||
return (value - startValue) / (endValue - startValue);
|
||||
}
|
||||
|
||||
function projectNormal(n, start, end) {
|
||||
return start + (n * (end - start));
|
||||
}
|
||||
|
||||
function linearInterpolation(t, start, end) {
|
||||
return t * end + (1 - t) * start;
|
||||
}
|
||||
|
||||
function quadraticOutInterpolation(t, start, end) {
|
||||
return linearInterpolation(2 * t - t * t, start, end);
|
||||
}
|
||||
|
||||
function b3Friction1(x) {
|
||||
return (0.0007 * Math.pow(x, 3)) -
|
||||
(0.031 * Math.pow(x, 2)) + 0.64 * x + 1.28;
|
||||
}
|
||||
|
||||
function b3Friction2(x) {
|
||||
return (0.000044 * Math.pow(x, 3)) -
|
||||
(0.006 * Math.pow(x, 2)) + 0.36 * x + 2;
|
||||
}
|
||||
|
||||
function b3Friction3(x) {
|
||||
return (0.00000045 * Math.pow(x, 3)) -
|
||||
(0.000332 * Math.pow(x, 2)) + 0.1078 * x + 5.84;
|
||||
}
|
||||
|
||||
function b3Nobounce(tension) {
|
||||
if (tension <= 18) {
|
||||
return b3Friction1(tension);
|
||||
} else if (tension > 18 && tension <= 44) {
|
||||
return b3Friction2(tension);
|
||||
} else {
|
||||
return b3Friction3(tension);
|
||||
}
|
||||
}
|
||||
|
||||
var b = normalize(bounciness / 1.7, 0, 20);
|
||||
b = projectNormal(b, 0, 0.8);
|
||||
var s = normalize(speed / 1.7, 0, 20);
|
||||
var bouncyTension = projectNormal(s, 0.5, 200);
|
||||
var bouncyFriction = quadraticOutInterpolation(
|
||||
b,
|
||||
b3Nobounce(bouncyTension),
|
||||
0.01
|
||||
);
|
||||
|
||||
return {
|
||||
stiffness: stiffnessFromOrigamiValue(bouncyTension),
|
||||
damping: dampingFromOrigamiValue(bouncyFriction),
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
fromOrigamiTensionAndFriction,
|
||||
fromBouncinessAndSpeed,
|
||||
};
|
||||
73
src/vendor/Animated/animations/Animation.js
vendored
Normal file
73
src/vendor/Animated/animations/Animation.js
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule Animation
|
||||
* @flow
|
||||
* @format
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
const NativeAnimatedHelper = require('../NativeAnimatedHelper');
|
||||
|
||||
import type AnimatedValue from '../nodes/AnimatedValue';
|
||||
|
||||
export type EndResult = {finished: boolean};
|
||||
export type EndCallback = (result: EndResult) => void;
|
||||
|
||||
export type AnimationConfig = {
|
||||
isInteraction?: boolean,
|
||||
useNativeDriver?: boolean,
|
||||
onComplete?: ?EndCallback,
|
||||
iterations?: number,
|
||||
};
|
||||
|
||||
// Important note: start() and stop() will only be called at most once.
|
||||
// Once an animation has been stopped or finished its course, it will
|
||||
// not be reused.
|
||||
class Animation {
|
||||
__active: boolean;
|
||||
__isInteraction: boolean;
|
||||
__nativeId: number;
|
||||
__onEnd: ?EndCallback;
|
||||
__iterations: number;
|
||||
start(
|
||||
fromValue: number,
|
||||
onUpdate: (value: number) => void,
|
||||
onEnd: ?EndCallback,
|
||||
previousAnimation: ?Animation,
|
||||
animatedValue: AnimatedValue,
|
||||
): void {}
|
||||
stop(): void {
|
||||
if (this.__nativeId) {
|
||||
NativeAnimatedHelper.API.stopAnimation(this.__nativeId);
|
||||
}
|
||||
}
|
||||
__getNativeAnimationConfig(): any {
|
||||
// Subclasses that have corresponding animation implementation done in native
|
||||
// should override this method
|
||||
throw new Error('This animation type cannot be offloaded to native');
|
||||
}
|
||||
// Helper function for subclasses to make sure onEnd is only called once.
|
||||
__debouncedOnEnd(result: EndResult): void {
|
||||
const onEnd = this.__onEnd;
|
||||
this.__onEnd = null;
|
||||
onEnd && onEnd(result);
|
||||
}
|
||||
__startNativeAnimation(animatedValue: AnimatedValue): void {
|
||||
animatedValue.__makeNative();
|
||||
this.__nativeId = NativeAnimatedHelper.generateNewAnimationId();
|
||||
NativeAnimatedHelper.API.startAnimatingNode(
|
||||
this.__nativeId,
|
||||
animatedValue.__getNativeTag(),
|
||||
this.__getNativeAnimationConfig(),
|
||||
this.__debouncedOnEnd.bind(this),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Animation;
|
||||
112
src/vendor/Animated/animations/DecayAnimation.js
vendored
Normal file
112
src/vendor/Animated/animations/DecayAnimation.js
vendored
Normal file
@@ -0,0 +1,112 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule DecayAnimation
|
||||
* @flow
|
||||
* @format
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
const Animation = require('./Animation');
|
||||
|
||||
const {shouldUseNativeDriver} = require('../NativeAnimatedHelper');
|
||||
|
||||
import type {AnimationConfig, EndCallback} from './Animation';
|
||||
import type AnimatedValue from '../nodes/AnimatedValue';
|
||||
|
||||
export type DecayAnimationConfig = AnimationConfig & {
|
||||
velocity: number | {x: number, y: number},
|
||||
deceleration?: number,
|
||||
};
|
||||
|
||||
export type DecayAnimationConfigSingle = AnimationConfig & {
|
||||
velocity: number,
|
||||
deceleration?: number,
|
||||
};
|
||||
|
||||
class DecayAnimation extends Animation {
|
||||
_startTime: number;
|
||||
_lastValue: number;
|
||||
_fromValue: number;
|
||||
_deceleration: number;
|
||||
_velocity: number;
|
||||
_onUpdate: (value: number) => void;
|
||||
_animationFrame: any;
|
||||
_useNativeDriver: boolean;
|
||||
|
||||
constructor(config: DecayAnimationConfigSingle) {
|
||||
super();
|
||||
this._deceleration =
|
||||
config.deceleration !== undefined ? config.deceleration : 0.998;
|
||||
this._velocity = config.velocity;
|
||||
this._useNativeDriver = shouldUseNativeDriver(config);
|
||||
this.__isInteraction =
|
||||
config.isInteraction !== undefined ? config.isInteraction : true;
|
||||
this.__iterations = config.iterations !== undefined ? config.iterations : 1;
|
||||
}
|
||||
|
||||
__getNativeAnimationConfig() {
|
||||
return {
|
||||
type: 'decay',
|
||||
deceleration: this._deceleration,
|
||||
velocity: this._velocity,
|
||||
iterations: this.__iterations,
|
||||
};
|
||||
}
|
||||
|
||||
start(
|
||||
fromValue: number,
|
||||
onUpdate: (value: number) => void,
|
||||
onEnd: ?EndCallback,
|
||||
previousAnimation: ?Animation,
|
||||
animatedValue: AnimatedValue,
|
||||
): void {
|
||||
this.__active = true;
|
||||
this._lastValue = fromValue;
|
||||
this._fromValue = fromValue;
|
||||
this._onUpdate = onUpdate;
|
||||
this.__onEnd = onEnd;
|
||||
this._startTime = Date.now();
|
||||
if (this._useNativeDriver) {
|
||||
this.__startNativeAnimation(animatedValue);
|
||||
} else {
|
||||
this._animationFrame = requestAnimationFrame(this.onUpdate.bind(this));
|
||||
}
|
||||
}
|
||||
|
||||
onUpdate(): void {
|
||||
const now = Date.now();
|
||||
|
||||
const value =
|
||||
this._fromValue +
|
||||
this._velocity /
|
||||
(1 - this._deceleration) *
|
||||
(1 - Math.exp(-(1 - this._deceleration) * (now - this._startTime)));
|
||||
|
||||
this._onUpdate(value);
|
||||
|
||||
if (Math.abs(this._lastValue - value) < 0.1) {
|
||||
this.__debouncedOnEnd({finished: true});
|
||||
return;
|
||||
}
|
||||
|
||||
this._lastValue = value;
|
||||
if (this.__active) {
|
||||
this._animationFrame = requestAnimationFrame(this.onUpdate.bind(this));
|
||||
}
|
||||
}
|
||||
|
||||
stop(): void {
|
||||
super.stop();
|
||||
this.__active = false;
|
||||
global.cancelAnimationFrame(this._animationFrame);
|
||||
this.__debouncedOnEnd({finished: false});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = DecayAnimation;
|
||||
342
src/vendor/Animated/animations/SpringAnimation.js
vendored
Normal file
342
src/vendor/Animated/animations/SpringAnimation.js
vendored
Normal file
@@ -0,0 +1,342 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule SpringAnimation
|
||||
* @flow
|
||||
* @format
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
const AnimatedValue = require('../nodes/AnimatedValue');
|
||||
const AnimatedValueXY = require('../nodes/AnimatedValueXY');
|
||||
const Animation = require('./Animation');
|
||||
const SpringConfig = require('../SpringConfig');
|
||||
|
||||
const invariant = require('fbjs/lib/invariant');
|
||||
const {shouldUseNativeDriver} = require('../NativeAnimatedHelper');
|
||||
|
||||
import type {AnimationConfig, EndCallback} from './Animation';
|
||||
|
||||
export type SpringAnimationConfig = AnimationConfig & {
|
||||
toValue: number | AnimatedValue | {x: number, y: number} | AnimatedValueXY,
|
||||
overshootClamping?: boolean,
|
||||
restDisplacementThreshold?: number,
|
||||
restSpeedThreshold?: number,
|
||||
velocity?: number | {x: number, y: number},
|
||||
bounciness?: number,
|
||||
speed?: number,
|
||||
tension?: number,
|
||||
friction?: number,
|
||||
stiffness?: number,
|
||||
damping?: number,
|
||||
mass?: number,
|
||||
delay?: number,
|
||||
};
|
||||
|
||||
export type SpringAnimationConfigSingle = AnimationConfig & {
|
||||
toValue: number | AnimatedValue,
|
||||
overshootClamping?: boolean,
|
||||
restDisplacementThreshold?: number,
|
||||
restSpeedThreshold?: number,
|
||||
velocity?: number,
|
||||
bounciness?: number,
|
||||
speed?: number,
|
||||
tension?: number,
|
||||
friction?: number,
|
||||
stiffness?: number,
|
||||
damping?: number,
|
||||
mass?: number,
|
||||
delay?: number,
|
||||
};
|
||||
|
||||
function withDefault<T>(value: ?T, defaultValue: T): T {
|
||||
if (value === undefined || value === null) {
|
||||
return defaultValue;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
class SpringAnimation extends Animation {
|
||||
_overshootClamping: boolean;
|
||||
_restDisplacementThreshold: number;
|
||||
_restSpeedThreshold: number;
|
||||
_lastVelocity: number;
|
||||
_startPosition: number;
|
||||
_lastPosition: number;
|
||||
_fromValue: number;
|
||||
_toValue: any;
|
||||
_stiffness: number;
|
||||
_damping: number;
|
||||
_mass: number;
|
||||
_initialVelocity: number;
|
||||
_delay: number;
|
||||
_timeout: any;
|
||||
_startTime: number;
|
||||
_lastTime: number;
|
||||
_frameTime: number;
|
||||
_onUpdate: (value: number) => void;
|
||||
_animationFrame: any;
|
||||
_useNativeDriver: boolean;
|
||||
|
||||
constructor(config: SpringAnimationConfigSingle) {
|
||||
super();
|
||||
|
||||
this._overshootClamping = withDefault(config.overshootClamping, false);
|
||||
this._restDisplacementThreshold = withDefault(
|
||||
config.restDisplacementThreshold,
|
||||
0.001,
|
||||
);
|
||||
this._restSpeedThreshold = withDefault(config.restSpeedThreshold, 0.001);
|
||||
this._initialVelocity = withDefault(config.velocity, 0);
|
||||
this._lastVelocity = withDefault(config.velocity, 0);
|
||||
this._toValue = config.toValue;
|
||||
this._delay = withDefault(config.delay, 0);
|
||||
this._useNativeDriver = shouldUseNativeDriver(config);
|
||||
this.__isInteraction =
|
||||
config.isInteraction !== undefined ? config.isInteraction : true;
|
||||
this.__iterations = config.iterations !== undefined ? config.iterations : 1;
|
||||
|
||||
if (
|
||||
config.stiffness !== undefined ||
|
||||
config.damping !== undefined ||
|
||||
config.mass !== undefined
|
||||
) {
|
||||
invariant(
|
||||
config.bounciness === undefined &&
|
||||
config.speed === undefined &&
|
||||
config.tension === undefined &&
|
||||
config.friction === undefined,
|
||||
'You can define one of bounciness/speed, tension/friction, or stiffness/damping/mass, but not more than one',
|
||||
);
|
||||
this._stiffness = withDefault(config.stiffness, 100);
|
||||
this._damping = withDefault(config.damping, 10);
|
||||
this._mass = withDefault(config.mass, 1);
|
||||
} else if (config.bounciness !== undefined || config.speed !== undefined) {
|
||||
// Convert the origami bounciness/speed values to stiffness/damping
|
||||
// We assume mass is 1.
|
||||
invariant(
|
||||
config.tension === undefined &&
|
||||
config.friction === undefined &&
|
||||
config.stiffness === undefined &&
|
||||
config.damping === undefined &&
|
||||
config.mass === undefined,
|
||||
'You can define one of bounciness/speed, tension/friction, or stiffness/damping/mass, but not more than one',
|
||||
);
|
||||
const springConfig = SpringConfig.fromBouncinessAndSpeed(
|
||||
withDefault(config.bounciness, 8),
|
||||
withDefault(config.speed, 12),
|
||||
);
|
||||
this._stiffness = springConfig.stiffness;
|
||||
this._damping = springConfig.damping;
|
||||
this._mass = 1;
|
||||
} else {
|
||||
// Convert the origami tension/friction values to stiffness/damping
|
||||
// We assume mass is 1.
|
||||
const springConfig = SpringConfig.fromOrigamiTensionAndFriction(
|
||||
withDefault(config.tension, 40),
|
||||
withDefault(config.friction, 7),
|
||||
);
|
||||
this._stiffness = springConfig.stiffness;
|
||||
this._damping = springConfig.damping;
|
||||
this._mass = 1;
|
||||
}
|
||||
|
||||
invariant(this._stiffness > 0, 'Stiffness value must be greater than 0');
|
||||
invariant(this._damping > 0, 'Damping value must be greater than 0');
|
||||
invariant(this._mass > 0, 'Mass value must be greater than 0');
|
||||
}
|
||||
|
||||
__getNativeAnimationConfig() {
|
||||
return {
|
||||
type: 'spring',
|
||||
overshootClamping: this._overshootClamping,
|
||||
restDisplacementThreshold: this._restDisplacementThreshold,
|
||||
restSpeedThreshold: this._restSpeedThreshold,
|
||||
stiffness: this._stiffness,
|
||||
damping: this._damping,
|
||||
mass: this._mass,
|
||||
initialVelocity: withDefault(this._initialVelocity, this._lastVelocity),
|
||||
toValue: this._toValue,
|
||||
iterations: this.__iterations,
|
||||
};
|
||||
}
|
||||
|
||||
start(
|
||||
fromValue: number,
|
||||
onUpdate: (value: number) => void,
|
||||
onEnd: ?EndCallback,
|
||||
previousAnimation: ?Animation,
|
||||
animatedValue: AnimatedValue,
|
||||
): void {
|
||||
this.__active = true;
|
||||
this._startPosition = fromValue;
|
||||
this._lastPosition = this._startPosition;
|
||||
|
||||
this._onUpdate = onUpdate;
|
||||
this.__onEnd = onEnd;
|
||||
this._lastTime = Date.now();
|
||||
this._frameTime = 0.0;
|
||||
|
||||
if (previousAnimation instanceof SpringAnimation) {
|
||||
const internalState = previousAnimation.getInternalState();
|
||||
this._lastPosition = internalState.lastPosition;
|
||||
this._lastVelocity = internalState.lastVelocity;
|
||||
// Set the initial velocity to the last velocity
|
||||
this._initialVelocity = this._lastVelocity;
|
||||
this._lastTime = internalState.lastTime;
|
||||
}
|
||||
|
||||
const start = () => {
|
||||
if (this._useNativeDriver) {
|
||||
this.__startNativeAnimation(animatedValue);
|
||||
} else {
|
||||
this.onUpdate();
|
||||
}
|
||||
};
|
||||
|
||||
// If this._delay is more than 0, we start after the timeout.
|
||||
if (this._delay) {
|
||||
this._timeout = setTimeout(start, this._delay);
|
||||
} else {
|
||||
start();
|
||||
}
|
||||
}
|
||||
|
||||
getInternalState(): Object {
|
||||
return {
|
||||
lastPosition: this._lastPosition,
|
||||
lastVelocity: this._lastVelocity,
|
||||
lastTime: this._lastTime,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* This spring model is based off of a damped harmonic oscillator
|
||||
* (https://en.wikipedia.org/wiki/Harmonic_oscillator#Damped_harmonic_oscillator).
|
||||
*
|
||||
* We use the closed form of the second order differential equation:
|
||||
*
|
||||
* x'' + (2ζ⍵_0)x' + ⍵^2x = 0
|
||||
*
|
||||
* where
|
||||
* ⍵_0 = √(k / m) (undamped angular frequency of the oscillator),
|
||||
* ζ = c / 2√mk (damping ratio),
|
||||
* c = damping constant
|
||||
* k = stiffness
|
||||
* m = mass
|
||||
*
|
||||
* The derivation of the closed form is described in detail here:
|
||||
* http://planetmath.org/sites/default/files/texpdf/39745.pdf
|
||||
*
|
||||
* This algorithm happens to match the algorithm used by CASpringAnimation,
|
||||
* a QuartzCore (iOS) API that creates spring animations.
|
||||
*/
|
||||
onUpdate(): void {
|
||||
// If for some reason we lost a lot of frames (e.g. process large payload or
|
||||
// stopped in the debugger), we only advance by 4 frames worth of
|
||||
// computation and will continue on the next frame. It's better to have it
|
||||
// running at faster speed than jumping to the end.
|
||||
const MAX_STEPS = 64;
|
||||
let now = Date.now();
|
||||
if (now > this._lastTime + MAX_STEPS) {
|
||||
now = this._lastTime + MAX_STEPS;
|
||||
}
|
||||
|
||||
const deltaTime = (now - this._lastTime) / 1000;
|
||||
this._frameTime += deltaTime;
|
||||
|
||||
const c: number = this._damping;
|
||||
const m: number = this._mass;
|
||||
const k: number = this._stiffness;
|
||||
const v0: number = -this._initialVelocity;
|
||||
|
||||
const zeta = c / (2 * Math.sqrt(k * m)); // damping ratio
|
||||
const omega0 = Math.sqrt(k / m); // undamped angular frequency of the oscillator (rad/ms)
|
||||
const omega1 = omega0 * Math.sqrt(1.0 - zeta * zeta); // exponential decay
|
||||
const x0 = this._toValue - this._startPosition; // calculate the oscillation from x0 = 1 to x = 0
|
||||
|
||||
let position = 0.0;
|
||||
let velocity = 0.0;
|
||||
const t = this._frameTime;
|
||||
if (zeta < 1) {
|
||||
// Under damped
|
||||
const envelope = Math.exp(-zeta * omega0 * t);
|
||||
position =
|
||||
this._toValue -
|
||||
envelope *
|
||||
((v0 + zeta * omega0 * x0) / omega1 * Math.sin(omega1 * t) +
|
||||
x0 * Math.cos(omega1 * t));
|
||||
// This looks crazy -- it's actually just the derivative of the
|
||||
// oscillation function
|
||||
velocity =
|
||||
zeta *
|
||||
omega0 *
|
||||
envelope *
|
||||
(Math.sin(omega1 * t) * (v0 + zeta * omega0 * x0) / omega1 +
|
||||
x0 * Math.cos(omega1 * t)) -
|
||||
envelope *
|
||||
(Math.cos(omega1 * t) * (v0 + zeta * omega0 * x0) -
|
||||
omega1 * x0 * Math.sin(omega1 * t));
|
||||
} else {
|
||||
// Critically damped
|
||||
const envelope = Math.exp(-omega0 * t);
|
||||
position = this._toValue - envelope * (x0 + (v0 + omega0 * x0) * t);
|
||||
velocity =
|
||||
envelope * (v0 * (t * omega0 - 1) + t * x0 * (omega0 * omega0));
|
||||
}
|
||||
|
||||
this._lastTime = now;
|
||||
this._lastPosition = position;
|
||||
this._lastVelocity = velocity;
|
||||
|
||||
this._onUpdate(position);
|
||||
if (!this.__active) {
|
||||
// a listener might have stopped us in _onUpdate
|
||||
return;
|
||||
}
|
||||
|
||||
// Conditions for stopping the spring animation
|
||||
let isOvershooting = false;
|
||||
if (this._overshootClamping && this._stiffness !== 0) {
|
||||
if (this._startPosition < this._toValue) {
|
||||
isOvershooting = position > this._toValue;
|
||||
} else {
|
||||
isOvershooting = position < this._toValue;
|
||||
}
|
||||
}
|
||||
const isVelocity = Math.abs(velocity) <= this._restSpeedThreshold;
|
||||
let isDisplacement = true;
|
||||
if (this._stiffness !== 0) {
|
||||
isDisplacement =
|
||||
Math.abs(this._toValue - position) <= this._restDisplacementThreshold;
|
||||
}
|
||||
|
||||
if (isOvershooting || (isVelocity && isDisplacement)) {
|
||||
if (this._stiffness !== 0) {
|
||||
// Ensure that we end up with a round value
|
||||
this._lastPosition = this._toValue;
|
||||
this._lastVelocity = 0;
|
||||
this._onUpdate(this._toValue);
|
||||
}
|
||||
|
||||
this.__debouncedOnEnd({finished: true});
|
||||
return;
|
||||
}
|
||||
this._animationFrame = requestAnimationFrame(this.onUpdate.bind(this));
|
||||
}
|
||||
|
||||
stop(): void {
|
||||
super.stop();
|
||||
this.__active = false;
|
||||
clearTimeout(this._timeout);
|
||||
global.cancelAnimationFrame(this._animationFrame);
|
||||
this.__debouncedOnEnd({finished: false});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = SpringAnimation;
|
||||
155
src/vendor/Animated/animations/TimingAnimation.js
vendored
Normal file
155
src/vendor/Animated/animations/TimingAnimation.js
vendored
Normal file
@@ -0,0 +1,155 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule TimingAnimation
|
||||
* @flow
|
||||
* @format
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
const AnimatedValue = require('../nodes/AnimatedValue');
|
||||
const AnimatedValueXY = require('../nodes/AnimatedValueXY');
|
||||
const Animation = require('./Animation');
|
||||
|
||||
const {shouldUseNativeDriver} = require('../NativeAnimatedHelper');
|
||||
|
||||
import type {AnimationConfig, EndCallback} from './Animation';
|
||||
|
||||
export type TimingAnimationConfig = AnimationConfig & {
|
||||
toValue: number | AnimatedValue | {x: number, y: number} | AnimatedValueXY,
|
||||
easing?: (value: number) => number,
|
||||
duration?: number,
|
||||
delay?: number,
|
||||
};
|
||||
|
||||
export type TimingAnimationConfigSingle = AnimationConfig & {
|
||||
toValue: number | AnimatedValue,
|
||||
easing?: (value: number) => number,
|
||||
duration?: number,
|
||||
delay?: number,
|
||||
};
|
||||
|
||||
let _easeInOut;
|
||||
function easeInOut() {
|
||||
if (!_easeInOut) {
|
||||
const Easing = require('../Easing');
|
||||
_easeInOut = Easing.inOut(Easing.ease);
|
||||
}
|
||||
return _easeInOut;
|
||||
}
|
||||
|
||||
class TimingAnimation extends Animation {
|
||||
_startTime: number;
|
||||
_fromValue: number;
|
||||
_toValue: any;
|
||||
_duration: number;
|
||||
_delay: number;
|
||||
_easing: (value: number) => number;
|
||||
_onUpdate: (value: number) => void;
|
||||
_animationFrame: any;
|
||||
_timeout: any;
|
||||
_useNativeDriver: boolean;
|
||||
|
||||
constructor(config: TimingAnimationConfigSingle) {
|
||||
super();
|
||||
this._toValue = config.toValue;
|
||||
this._easing = config.easing !== undefined ? config.easing : easeInOut();
|
||||
this._duration = config.duration !== undefined ? config.duration : 500;
|
||||
this._delay = config.delay !== undefined ? config.delay : 0;
|
||||
this.__iterations = config.iterations !== undefined ? config.iterations : 1;
|
||||
this.__isInteraction =
|
||||
config.isInteraction !== undefined ? config.isInteraction : true;
|
||||
this._useNativeDriver = shouldUseNativeDriver(config);
|
||||
}
|
||||
|
||||
__getNativeAnimationConfig(): any {
|
||||
const frameDuration = 1000.0 / 60.0;
|
||||
const frames = [];
|
||||
for (let dt = 0.0; dt < this._duration; dt += frameDuration) {
|
||||
frames.push(this._easing(dt / this._duration));
|
||||
}
|
||||
frames.push(this._easing(1));
|
||||
return {
|
||||
type: 'frames',
|
||||
frames,
|
||||
toValue: this._toValue,
|
||||
iterations: this.__iterations,
|
||||
};
|
||||
}
|
||||
|
||||
start(
|
||||
fromValue: number,
|
||||
onUpdate: (value: number) => void,
|
||||
onEnd: ?EndCallback,
|
||||
previousAnimation: ?Animation,
|
||||
animatedValue: AnimatedValue,
|
||||
): void {
|
||||
this.__active = true;
|
||||
this._fromValue = fromValue;
|
||||
this._onUpdate = onUpdate;
|
||||
this.__onEnd = onEnd;
|
||||
|
||||
const start = () => {
|
||||
// Animations that sometimes have 0 duration and sometimes do not
|
||||
// still need to use the native driver when duration is 0 so as to
|
||||
// not cause intermixed JS and native animations.
|
||||
if (this._duration === 0 && !this._useNativeDriver) {
|
||||
this._onUpdate(this._toValue);
|
||||
this.__debouncedOnEnd({finished: true});
|
||||
} else {
|
||||
this._startTime = Date.now();
|
||||
if (this._useNativeDriver) {
|
||||
this.__startNativeAnimation(animatedValue);
|
||||
} else {
|
||||
this._animationFrame = requestAnimationFrame(
|
||||
this.onUpdate.bind(this),
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
if (this._delay) {
|
||||
this._timeout = setTimeout(start, this._delay);
|
||||
} else {
|
||||
start();
|
||||
}
|
||||
}
|
||||
|
||||
onUpdate(): void {
|
||||
const now = Date.now();
|
||||
if (now >= this._startTime + this._duration) {
|
||||
if (this._duration === 0) {
|
||||
this._onUpdate(this._toValue);
|
||||
} else {
|
||||
this._onUpdate(
|
||||
this._fromValue + this._easing(1) * (this._toValue - this._fromValue),
|
||||
);
|
||||
}
|
||||
this.__debouncedOnEnd({finished: true});
|
||||
return;
|
||||
}
|
||||
|
||||
this._onUpdate(
|
||||
this._fromValue +
|
||||
this._easing((now - this._startTime) / this._duration) *
|
||||
(this._toValue - this._fromValue),
|
||||
);
|
||||
if (this.__active) {
|
||||
this._animationFrame = requestAnimationFrame(this.onUpdate.bind(this));
|
||||
}
|
||||
}
|
||||
|
||||
stop(): void {
|
||||
super.stop();
|
||||
this.__active = false;
|
||||
clearTimeout(this._timeout);
|
||||
global.cancelAnimationFrame(this._animationFrame);
|
||||
this.__debouncedOnEnd({finished: false});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = TimingAnimation;
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user