mirror of
https://github.com/zhigang1992/react-native-web.git
synced 2026-03-30 09:24:09 +08:00
Compare commits
68 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5395a3e8bc | ||
|
|
45b3d8b0df | ||
|
|
f1ee3c003a | ||
|
|
606181406c | ||
|
|
b537400f38 | ||
|
|
0a4fdc155e | ||
|
|
0b8e59974b | ||
|
|
22eebea633 | ||
|
|
5dd414f9aa | ||
|
|
72c72f6530 | ||
|
|
de970f9dbb | ||
|
|
e8d6c5b4dd | ||
|
|
e91a5ae13e | ||
|
|
b08bfb9ad5 | ||
|
|
5353011ee4 | ||
|
|
5faa3af19a | ||
|
|
c8461c9c11 | ||
|
|
3112e2ba56 | ||
|
|
fee03e101c | ||
|
|
c730a20a26 | ||
|
|
f7ed60ac67 | ||
|
|
417716391a | ||
|
|
ee5e3cb3ca | ||
|
|
2298c5d6e3 | ||
|
|
ca9f870ff6 | ||
|
|
e9b2fd8bc4 | ||
|
|
09a4985fd2 | ||
|
|
a9e61b4cd5 | ||
|
|
6ef19c3ccd | ||
|
|
0d29458874 | ||
|
|
1795bae8b5 | ||
|
|
c1152ee09a | ||
|
|
182149aac7 | ||
|
|
d6df440987 | ||
|
|
df16c24d68 | ||
|
|
8a2c259235 | ||
|
|
a7f265de11 | ||
|
|
581529540a | ||
|
|
8ad61d9061 | ||
|
|
3d79861970 | ||
|
|
0a84ccb299 | ||
|
|
3aa37450a0 | ||
|
|
450722153d | ||
|
|
fbba32defb | ||
|
|
d762d64b49 | ||
|
|
a5b1dda62d | ||
|
|
aad904b550 | ||
|
|
a01e895e30 | ||
|
|
52e5d41518 | ||
|
|
77a40b6237 | ||
|
|
4bbe1a40aa | ||
|
|
6942e4e417 | ||
|
|
63daff7f80 | ||
|
|
662b7c3d6e | ||
|
|
12fb588596 | ||
|
|
5cb09b1a9e | ||
|
|
c03cfdf8bd | ||
|
|
997b598de8 | ||
|
|
6fe796f9da | ||
|
|
0ad6ab948b | ||
|
|
32a23136af | ||
|
|
96f48226cb | ||
|
|
f1ef0f21af | ||
|
|
d42e8907ca | ||
|
|
90724b2cef | ||
|
|
dd0f1de3d1 | ||
|
|
fc751ed715 | ||
|
|
917b06a690 |
70
README.md
70
README.md
@@ -3,36 +3,56 @@
|
||||
[![Build Status][travis-image]][travis-url]
|
||||
[![npm version][npm-image]][npm-url]
|
||||
|
||||
"React Native for Web" brings [React Native][react-native-url]'s
|
||||
building blocks and touch handling to the Web.
|
||||
"React Native for Web" brings the platform-agnostic Components and APIs of
|
||||
[React Native][react-native-url] to the Web.
|
||||
|
||||
* [UI Explorer and documentation](https://necolas.github.io/react-native-web/storybook/).
|
||||
* [React Native for Web: Playground](https://glitch.com/edit/#!/react-native-web-playground) using create-react-app.
|
||||
Browse the [interactive
|
||||
documentation](https://necolas.github.io/react-native-web/storybook/) or [try
|
||||
it out](https://glitch.com/edit/#!/react-native-web-playground) on Glitch.
|
||||
|
||||
Browser support: Chrome, Firefox, Safari >= 7, IE 10, Edge.
|
||||
## Features
|
||||
|
||||
[npm-image]: https://badge.fury.io/js/react-native-web.svg
|
||||
[npm-url]: https://npmjs.org/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
|
||||
* Interoperability with ReactDOM components.
|
||||
* Native-like touch handling.
|
||||
* Built-in integration with web accessibility APIs.
|
||||
* Built-in support for LTR and RTL layouts.
|
||||
* Built-in expressive and reliable subset of CSS.
|
||||
* Optimized, vendor-prefixed CSS with [good runtime performance](benchmarks/README.md).
|
||||
* Server-side rendering of HTML and critical CSS.
|
||||
* Browser support: Chrome, Firefox, Safari >= 7, IE 10, Edge.
|
||||
|
||||
## Quick start
|
||||
|
||||
NOTE: React Native for Web supports React/ReactDOM 15.4, 15.5, or 15.6.
|
||||
|
||||
Install in your existing app using `yarn` or `npm`:
|
||||
|
||||
```
|
||||
yarn add react@15.6 react-dom@15.6 react-native-web
|
||||
yarn add react react-dom react-native-web
|
||||
```
|
||||
|
||||
Then read the [Getting Started](docs/guides/getting-started.md) guide.
|
||||
Add the `react-native-web/babel` plugin to your Babel configuration. This will
|
||||
alias `react-native` to `react-native-web` and exclude any modules not required
|
||||
by the app.
|
||||
|
||||
```json
|
||||
{
|
||||
"plugins": [
|
||||
"react-native-web/babel"
|
||||
],
|
||||
"presets": [
|
||||
"react-native"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
(For React/ReactDOM 15.4 – 15.6 support, install `react-native-web@<0.1.0`)
|
||||
|
||||
See the [Getting Started](docs/guides/getting-started.md) guide for more details.
|
||||
|
||||
## Documentation
|
||||
|
||||
The [UI Explorer](https://necolas.github.io/react-native-web/storybook/)
|
||||
interactively documents all the supported APIs and Components.
|
||||
The [interactive
|
||||
documentation](https://necolas.github.io/react-native-web/storybook/) shows all
|
||||
the supported APIs and Components.
|
||||
|
||||
Guides:
|
||||
|
||||
@@ -44,12 +64,6 @@ Guides:
|
||||
* [Advanced use](docs/guides/advanced.md)
|
||||
* [Known issues](docs/guides/known-issues.md)
|
||||
|
||||
## Starter kits
|
||||
|
||||
* [create-react-app](https://github.com/facebookincubator/create-react-app) ([on Glitch](https://glitch.com/edit/#!/react-native-web-playground))
|
||||
* [react-native-web-starter](https://github.com/grabcode/react-native-web-starter)
|
||||
* [react-native-web-webpack](https://github.com/ndbroadbent/react-native-web-webpack)
|
||||
|
||||
## Example code
|
||||
|
||||
```js
|
||||
@@ -89,6 +103,12 @@ AppRegistry.registerComponent('MyApp', () => App)
|
||||
AppRegistry.runApplication('MyApp', { rootTag: document.getElementById('react-root') })
|
||||
```
|
||||
|
||||
## Starter kits
|
||||
|
||||
* [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
|
||||
|
||||
* [react-primitives](https://github.com/lelandrichardson/react-primitives/)
|
||||
@@ -99,3 +119,9 @@ AppRegistry.runApplication('MyApp', { rootTag: document.getElementById('react-ro
|
||||
## License
|
||||
|
||||
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
|
||||
[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
|
||||
|
||||
@@ -12,13 +12,14 @@ import View from 'react-native-web/dist/components/View';
|
||||
|
||||
exports[`2. Rewrite react-native paths for react-native-web 1`] = `
|
||||
"
|
||||
import { Switch, Text, View as MyView } from 'react-native';
|
||||
import { Switch, Text, View as MyView, ViewPropTypes } from 'react-native';
|
||||
|
||||
↓ ↓ ↓ ↓ ↓ ↓
|
||||
|
||||
import Switch from 'react-native-web/dist/components/Switch';
|
||||
import Text from 'react-native-web/dist/components/Text';
|
||||
import MyView from 'react-native-web/dist/components/View';
|
||||
import ViewPropTypes from 'react-native-web/dist/components/View/ViewPropTypes';
|
||||
"
|
||||
`;
|
||||
|
||||
@@ -102,3 +103,59 @@ const { InvalidThing, TouchableOpacity } = require('react-native');
|
||||
const TouchableOpacity = require('react-native-web/dist/components/Touchable/TouchableOpacity');
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`10. Rewrite react-native paths for react-native-web 1`] = `
|
||||
"
|
||||
export { View } from 'react-native';
|
||||
|
||||
↓ ↓ ↓ ↓ ↓ ↓
|
||||
|
||||
export { default as View } from 'react-native-web/dist/components/View';
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`11. Rewrite react-native paths for react-native-web 1`] = `
|
||||
"
|
||||
export { Switch, Text, View as MyView, ViewPropTypes } from 'react-native';
|
||||
|
||||
↓ ↓ ↓ ↓ ↓ ↓
|
||||
|
||||
export { default as Switch } from 'react-native-web/dist/components/Switch';
|
||||
export { default as Text } from 'react-native-web/dist/components/Text';
|
||||
export { default as MyView } from 'react-native-web/dist/components/View';
|
||||
export { default as ViewPropTypes } from 'react-native-web/dist/components/View/ViewPropTypes';
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`12. Rewrite react-native paths for react-native-web 1`] = `
|
||||
"
|
||||
export { createElement, Switch, StyleSheet } from 'react-native';
|
||||
|
||||
↓ ↓ ↓ ↓ ↓ ↓
|
||||
|
||||
export { default as createElement } from 'react-native-web/dist/modules/createElement';
|
||||
export { default as Switch } from 'react-native-web/dist/components/Switch';
|
||||
export { default as StyleSheet } from 'react-native-web/dist/apis/StyleSheet';
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`13. Rewrite react-native paths for react-native-web 1`] = `
|
||||
"
|
||||
export { InvalidThing, TouchableOpacity } from 'react-native';
|
||||
|
||||
↓ ↓ ↓ ↓ ↓ ↓
|
||||
|
||||
export { InvalidThing } from 'react-native-web';
|
||||
export { default as TouchableOpacity } from 'react-native-web/dist/components/Touchable/TouchableOpacity';
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`14. Rewrite react-native paths for react-native-web 1`] = `
|
||||
"
|
||||
export { default as RNW } from 'react-native';
|
||||
|
||||
↓ ↓ ↓ ↓ ↓ ↓
|
||||
|
||||
export { default as RNW } from 'react-native-web';
|
||||
"
|
||||
`;
|
||||
|
||||
@@ -7,7 +7,7 @@ pluginTester({
|
||||
tests: [
|
||||
// import react-native
|
||||
"import { View } from 'react-native';",
|
||||
"import { Switch, Text, View as MyView } from 'react-native';",
|
||||
"import { Switch, Text, View as MyView, ViewPropTypes } from 'react-native';",
|
||||
"import { createElement, Switch, StyleSheet } from 'react-native';",
|
||||
"import { InvalidThing, TouchableOpacity } from 'react-native';",
|
||||
"import * as RNW from 'react-native';",
|
||||
@@ -30,6 +30,13 @@ pluginTester({
|
||||
// "let { Switch, Text, View: MyView } = require('react-native-web');",
|
||||
// "var { createElement, Switch, StyleSheet } = require('react-native-web');",
|
||||
// "const { InvalidThing, TouchableOpacity } = require('react-native-web');",
|
||||
|
||||
// export react-native
|
||||
"export { View } from 'react-native';",
|
||||
"export { Switch, Text, View as MyView, ViewPropTypes } from 'react-native';",
|
||||
"export { createElement, Switch, StyleSheet } from 'react-native';",
|
||||
"export { InvalidThing, TouchableOpacity } from 'react-native';",
|
||||
"export { default as RNW } from 'react-native';",
|
||||
{
|
||||
code: "const RNW = require('react-native');",
|
||||
output: "const RNW = require('react-native');",
|
||||
|
||||
@@ -7,7 +7,7 @@ const getDistLocation = importName => {
|
||||
case 'AppRegistry':
|
||||
case 'AppState':
|
||||
case 'AsyncStorage':
|
||||
case 'BackAndroid':
|
||||
case 'BackHandler':
|
||||
case 'Clipboard':
|
||||
case 'Dimensions':
|
||||
case 'Easing':
|
||||
@@ -69,11 +69,15 @@ const getDistLocation = importName => {
|
||||
// propTypes
|
||||
case 'ColorPropType':
|
||||
case 'EdgeInsetsPropType':
|
||||
case 'PointPropType':
|
||||
case 'TextPropTypes':
|
||||
case 'ViewPropTypes': {
|
||||
case 'PointPropType': {
|
||||
return `${root}/propTypes/${importName}`;
|
||||
}
|
||||
case 'TextPropTypes': {
|
||||
return `${root}/components/Text/${importName}`;
|
||||
}
|
||||
case 'ViewPropTypes': {
|
||||
return `${root}/components/View/${importName}`;
|
||||
}
|
||||
|
||||
default:
|
||||
return;
|
||||
@@ -102,7 +106,7 @@ module.exports = function({ types: t }) {
|
||||
visitor: {
|
||||
ImportDeclaration(path) {
|
||||
const { source, specifiers } = path.node;
|
||||
if (source.value === 'react-native' && specifiers.length) {
|
||||
if (source && source.value === 'react-native' && specifiers.length) {
|
||||
const imports = specifiers
|
||||
.map(specifier => {
|
||||
if (t.isImportSpecifier(specifier)) {
|
||||
@@ -123,6 +127,35 @@ module.exports = function({ types: t }) {
|
||||
path.replaceWithMultiple(imports);
|
||||
}
|
||||
},
|
||||
ExportNamedDeclaration(path) {
|
||||
const { source, specifiers } = path.node;
|
||||
if (source && source.value === 'react-native' && specifiers.length) {
|
||||
const exports = specifiers
|
||||
.map(specifier => {
|
||||
if (t.isExportSpecifier(specifier)) {
|
||||
const exportName = specifier.exported.name;
|
||||
const localName = specifier.local.name;
|
||||
const distLocation = getDistLocation(localName);
|
||||
|
||||
if (distLocation) {
|
||||
return t.exportNamedDeclaration(
|
||||
null,
|
||||
[t.exportSpecifier(t.identifier('default'), t.identifier(exportName))],
|
||||
t.stringLiteral(distLocation)
|
||||
);
|
||||
}
|
||||
return t.exportNamedDeclaration(
|
||||
null,
|
||||
[specifier],
|
||||
t.stringLiteral('react-native-web')
|
||||
);
|
||||
}
|
||||
})
|
||||
.filter(Boolean);
|
||||
|
||||
path.replaceWithMultiple(exports);
|
||||
}
|
||||
},
|
||||
VariableDeclaration(path) {
|
||||
if (isReactNativeRequire(t, path.node)) {
|
||||
const { id } = path.node.declarations[0];
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
# AppRegistry
|
||||
|
||||
`AppRegistry` is the control point for registering, running, prerendering, and
|
||||
unmounting all apps. App root components should register themselves with
|
||||
`AppRegistry.registerComponent`. Apps can be run by invoking
|
||||
`AppRegistry.runApplication` (see the [getting started guide](../guides/getting-started.md) for more details).
|
||||
|
||||
To "stop" an application when a view should be destroyed, call
|
||||
`AppRegistry.unmountApplicationComponentAtRootTag` with the tag that was passed
|
||||
into `runApplication`. These should always be used as a pair.
|
||||
|
||||
## Methods
|
||||
|
||||
(web) static **getApplication**(appKey:string, appParameters: object)
|
||||
|
||||
Returns the given application element. Use this for server-side rendering.
|
||||
Return object is of type `{ element: ReactElement; stylesheets: [ ReactElement ] }`.
|
||||
|
||||
static **registerConfig**(config: Array<AppConfig>)
|
||||
|
||||
Registry multiple applications. `AppConfig` is of type `{ appKey: string;
|
||||
component: ComponentProvider; run?: Function }`.
|
||||
|
||||
static **registerComponent**(appKey: string, getComponentFunc: ComponentProvider)
|
||||
|
||||
Register a component provider under the given `appKey`.
|
||||
|
||||
static **registerRunnable**(appKey: string, run: Function)
|
||||
|
||||
Register a custom render function for an application. The function will receive
|
||||
the `appParameters` passed to `runApplication`.
|
||||
|
||||
static **getAppKeys**()
|
||||
|
||||
Returns all registered app keys.
|
||||
|
||||
static **runApplication**(appKey: string, appParameters?: object)
|
||||
|
||||
Runs the application that was registered under `appKey`. The `appParameters`
|
||||
must include the `rootTag` into which the application is rendered, and
|
||||
optionally any `initialProps`.
|
||||
|
||||
On web, if the `rootTag` is a sub-section of your application it should be
|
||||
styled as `position:relative` and given an explicit height.
|
||||
|
||||
static **unmountApplicationComponentAtRootTag**(rootTag: HTMLElement)
|
||||
|
||||
To "stop" an application when a view should be destroyed, call
|
||||
`AppRegistry.unmountApplicationComponentAtRootTag` with the tag that was passed
|
||||
into `runApplication`
|
||||
|
||||
## Example
|
||||
|
||||
```js
|
||||
AppRegistry.registerComponent('MyApp', () => AppComponent)
|
||||
AppRegistry.runApplication('MyApp', {
|
||||
initialProps: {},
|
||||
rootTag: document.getElementById('react-root')
|
||||
})
|
||||
```
|
||||
@@ -1,60 +0,0 @@
|
||||
## AppState
|
||||
|
||||
`AppState` can tell you if the app is in the foreground or background, and
|
||||
notify you when the state changes.
|
||||
|
||||
States
|
||||
|
||||
* `active` - The app is running in the foreground
|
||||
* `background` - The app is running in the background (i.e., the user has not focused the app's tab).
|
||||
|
||||
## Properties
|
||||
|
||||
static **currentState**
|
||||
|
||||
Returns the current state of the app: `active` or `background`.
|
||||
|
||||
## Methods
|
||||
|
||||
static **addEventListener**(type: string, handler: Function)
|
||||
|
||||
Add a handler to `AppState` changes by listening to the `change` event type and
|
||||
providing the `handler`. The handler is called with the app state value.
|
||||
|
||||
static **removeEventListener**(type: string, handler: Function)
|
||||
|
||||
Remove a handler by passing the change event `type` and the `handler`.
|
||||
|
||||
## Examples
|
||||
|
||||
To see the current state, you can check `AppState.currentState`, which will be
|
||||
kept up-to-date. This example will only ever appear to say "Current state is:
|
||||
active" because the app is only visible to the user when in the `active` state,
|
||||
and the null state will happen only momentarily.
|
||||
|
||||
```js
|
||||
class Example extends React.Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.state = { currentAppState: AppState.currentState }
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
AppState.addEventListener('change', this._handleAppStateChange);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
AppState.removeEventListener('change', this._handleAppStateChange);
|
||||
}
|
||||
|
||||
_handleAppStateChange = (currentAppState) => {
|
||||
this.setState({ currentAppState });
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Text>Current state is: {this.state.currentAppState}</Text>
|
||||
)
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -1,71 +0,0 @@
|
||||
# AsyncStorage
|
||||
|
||||
`AsyncStorage` is a simple, asynchronous, persistent, key-value storage system
|
||||
that is global to the domain. It's a facade over, and should be used instead of
|
||||
`window.localStorage` to provide an asynchronous API and multi functions. Each
|
||||
method returns a `Promise` object.
|
||||
|
||||
It is recommended that you use an abstraction on top of `AsyncStorage` instead
|
||||
of `AsyncStorage` directly for anything more than light usage since it operates
|
||||
globally.
|
||||
|
||||
The batched functions are useful for executing a lot of operations at once,
|
||||
allowing for optimizations to provide the convenience of a single promise after
|
||||
all operations are complete.
|
||||
|
||||
## Methods
|
||||
|
||||
static **clear**()
|
||||
|
||||
Erases all AsyncStorage. You probably don't want to call this - use
|
||||
`removeItem` or `multiRemove` to clear only your own keys instead. Returns a
|
||||
Promise object.
|
||||
|
||||
static **getAllKeys**()
|
||||
|
||||
Gets all known keys. Returns a Promise object.
|
||||
|
||||
static **getItem**(key: string)
|
||||
|
||||
Fetches the value of the given key. Returns a Promise object.
|
||||
|
||||
static **mergeItem**(key: string, value: string)
|
||||
|
||||
Merges existing value with input value, assuming they are stringified JSON.
|
||||
Returns a Promise object.
|
||||
|
||||
static **multiGet**(keys: Array<string>)
|
||||
|
||||
`multiGet` results in an array of key-value pair arrays that matches the input
|
||||
format of `multiSet`. Returns a Promise object.
|
||||
|
||||
```js
|
||||
multiGet(['k1', 'k2']) -> [['k1', 'val1'], ['k2', 'val2']]
|
||||
```
|
||||
|
||||
static **multiMerge**(keyValuePairs: Array<Array<string>>)
|
||||
|
||||
multiMerge takes an array of key-value array pairs that match the output of
|
||||
`multiGet`. It merges existing values with input values, assuming they are
|
||||
stringified JSON. Returns a Promise object.
|
||||
|
||||
static **multiRemove**(keys: Array<string>)
|
||||
|
||||
Delete all the keys in the keys array. Returns a Promise object.
|
||||
|
||||
static **multiSet**(keyValuePairs: Array<Array<string>>)
|
||||
|
||||
`multiSet` takes an array of key-value array pairs that match the output of
|
||||
`multiGet`. Returns a Promise object.
|
||||
|
||||
```js
|
||||
multiSet([['k1', 'val1'], ['k2', 'val2']]);
|
||||
```
|
||||
|
||||
static **removeItem**(key: string)
|
||||
|
||||
Removes the value of the given key. Returns a Promise object.
|
||||
|
||||
static **setItem**(key: string, value: string)
|
||||
|
||||
Sets the value of the given key. Returns a Promise object.
|
||||
@@ -1,16 +0,0 @@
|
||||
# Clipboard
|
||||
|
||||
Clipboard gives you an interface for setting to the clipboard. (Getting
|
||||
clipboard content is not supported on web.)
|
||||
|
||||
## Methods
|
||||
|
||||
static **getString**()
|
||||
|
||||
Returns a `Promise` of an empty string.
|
||||
|
||||
static **setString**(content: string): boolean
|
||||
|
||||
Copies a string to the clipboard. On web, some browsers may not support copying
|
||||
to the clipboard, therefore, this function returns a boolean to indicate if the
|
||||
copy was successful.
|
||||
@@ -1,13 +0,0 @@
|
||||
# Dimensions
|
||||
|
||||
Note: dimensions may change (e.g due to device rotation) so any rendering logic
|
||||
or styles that depend on these constants should try to call this function on
|
||||
every render, rather than caching the value.
|
||||
|
||||
## Methods
|
||||
|
||||
static **get**(dimension: string)
|
||||
|
||||
Get a dimension (e.g., `"window"` or `"screen"`).
|
||||
|
||||
Example: `const { height, width } = Dimensions.get('window')`
|
||||
@@ -1,25 +0,0 @@
|
||||
# I18nManager
|
||||
|
||||
Control and set the layout and writing direction of the application.
|
||||
|
||||
## Properties
|
||||
|
||||
**isRTL**: bool = false
|
||||
|
||||
Whether the application is currently in RTL mode.
|
||||
|
||||
## Methods
|
||||
|
||||
static **allowRTL**(allowRTL: bool)
|
||||
|
||||
Allow the application to display in RTL mode.
|
||||
|
||||
static **forceRTL**(forceRTL: bool)
|
||||
|
||||
Force the application to display in RTL mode.
|
||||
|
||||
static **setPreferredLanguageRTL**(isRTL: bool)
|
||||
|
||||
Set the application's preferred writing direction to RTL. You will need to
|
||||
determine the user's preferred locale server-side (from HTTP headers) and
|
||||
decide whether it's an RTL language.
|
||||
@@ -1,77 +0,0 @@
|
||||
# NetInfo
|
||||
|
||||
`NetInfo` asynchronously determines the online/offline status of the
|
||||
application.
|
||||
|
||||
Connection types:
|
||||
|
||||
* `bluetooth` - The user agent is using a Bluetooth connection.
|
||||
* `cellular` - The user agent is using a cellular connection (e.g., EDGE, HSPA, LTE, etc.).
|
||||
* `ethernet` - The user agent is using an Ethernet connection.
|
||||
* `mixed` - The user agent is using multiple connection types.
|
||||
* `none` - The user agent will not contact the network (offline).
|
||||
* `other` - The user agent is using a connection type that is not one of enumerated connection types.
|
||||
* `unknown` - The user agent has established a network connection, but is unable to determine what is the underlying connection technology.
|
||||
* `wifi` - The user agent is using a Wi-Fi connection.
|
||||
* `wimax` - The user agent is using a WiMAX connection.
|
||||
|
||||
## Methods
|
||||
|
||||
Note that support for retrieving the connection type depends upon browswer
|
||||
support (and is limited to mobile browsers). It will default to `unknown` when
|
||||
support is missing.
|
||||
|
||||
static **addEventListener**(eventName: ChangeEventName, handler: Function)
|
||||
|
||||
static **fetch**(): Promise
|
||||
|
||||
static **removeEventListener**(eventName: ChangeEventName, handler: Function)
|
||||
|
||||
## Properties
|
||||
|
||||
**isConnected**: bool = true
|
||||
|
||||
Available on all user agents. Asynchronously fetch a boolean to determine
|
||||
internet connectivity. Use this if you are only interested with whether the device has internet connectivity.
|
||||
|
||||
**isConnected.addEventListener**(eventName: ChangeEventName, handler: Function)
|
||||
|
||||
**isConnected.fetch**(): Promise
|
||||
|
||||
**isConnected.removeEventListener**(eventName: ChangeEventName, handler: Function)
|
||||
|
||||
## Examples
|
||||
|
||||
Fetching the connection type:
|
||||
|
||||
```js
|
||||
NetInfo.fetch().then((connectionType) => {
|
||||
console.log('Connection type:', connectionType);
|
||||
});
|
||||
```
|
||||
|
||||
Subscribing to changes in the connection type:
|
||||
|
||||
```js
|
||||
const handleConnectivityTypeChange = (connectionType) => {
|
||||
console.log('Current connection type:', connectionType);
|
||||
}
|
||||
NetInfo.addEventListener('change', handleConnectivityTypeChange);
|
||||
```
|
||||
|
||||
Fetching the connection status:
|
||||
|
||||
```js
|
||||
NetInfo.isConnected.fetch().then((isConnected) => {
|
||||
console.log('Connection status:', (isConnected ? 'online' : 'offline'));
|
||||
});
|
||||
```
|
||||
|
||||
Subscribing to changes in the connection status:
|
||||
|
||||
```js
|
||||
const handleConnectivityStatusChange = (isConnected) => {
|
||||
console.log('Current connection status:', (isConnected ? 'online' : 'offline'));
|
||||
}
|
||||
NetInfo.isConnected.addEventListener('change', handleConnectivityStatusChange);
|
||||
```
|
||||
@@ -1,51 +0,0 @@
|
||||
# PixelRatio
|
||||
|
||||
`PixelRatio` gives access to the device pixel density.
|
||||
|
||||
## Methods
|
||||
|
||||
static **get**()
|
||||
|
||||
Returns the device pixel density. Some examples:
|
||||
|
||||
* PixelRatio.get() === 1
|
||||
* mdpi Android devices (160 dpi)
|
||||
* PixelRatio.get() === 1.5
|
||||
* hdpi Android devices (240 dpi)
|
||||
* PixelRatio.get() === 2
|
||||
* iPhone 4, 4S
|
||||
* iPhone 5, 5c, 5s
|
||||
* iPhone 6
|
||||
* xhdpi Android devices (320 dpi)
|
||||
* PixelRatio.get() === 3
|
||||
* iPhone 6 plus
|
||||
* xxhdpi Android devices (480 dpi)
|
||||
* PixelRatio.get() === 3.5
|
||||
* Nexus 6
|
||||
|
||||
static **getPixelSizeForLayoutSize**(layoutSize: number)
|
||||
|
||||
Converts a layout size (dp) to pixel size (px). Guaranteed to return an integer
|
||||
number.
|
||||
|
||||
static **roundToNearestPixel**(layoutSize: number)
|
||||
|
||||
Rounds a layout size (dp) to the nearest layout size that corresponds to an
|
||||
integer number of pixels. For example, on a device with a PixelRatio of 3,
|
||||
`PixelRatio.roundToNearestPixel(8.4)` = `8.33`, which corresponds to exactly
|
||||
`(8.33 * 3)` = `25` pixels.
|
||||
|
||||
## Examples
|
||||
|
||||
Fetching a correctly sized image. You should get a higher resolution image if
|
||||
you are on a high pixel density device. A good rule of thumb is to multiply the
|
||||
size of the image you display by the pixel ratio.
|
||||
|
||||
```js
|
||||
const image = getImage({
|
||||
width: PixelRatio.getPixelSizeForLayoutSize(200),
|
||||
height: PixelRatio.getPixelSizeForLayoutSize(100),
|
||||
});
|
||||
|
||||
<Image source={image} style={{ width: 200, height: 100 }} />
|
||||
```
|
||||
@@ -1,45 +0,0 @@
|
||||
# Platform
|
||||
|
||||
Detect what is the platform in which the app is running. This piece of
|
||||
functionality can be useful when only small parts of a component are platform
|
||||
specific.
|
||||
|
||||
## Properties
|
||||
|
||||
**OS**: string
|
||||
|
||||
`Platform.OS` will be `web` when running in a Web browser.
|
||||
|
||||
```js
|
||||
import { Platform } from 'react-native';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
height: (Platform.OS === 'web') ? 200 : 100,
|
||||
});
|
||||
```
|
||||
|
||||
## Methods
|
||||
|
||||
**select**(object): any
|
||||
|
||||
`Platform.select` takes an object containing `Platform.OS` as keys and returns
|
||||
the value for the platform you are currently running on.
|
||||
|
||||
```js
|
||||
import { Platform } from 'react-native';
|
||||
|
||||
const containerStyles = {
|
||||
flex: 1,
|
||||
...Platform.select({
|
||||
android: {
|
||||
backgroundColor: 'blue'
|
||||
},
|
||||
ios: {
|
||||
backgroundColor: 'red'
|
||||
},
|
||||
web: {
|
||||
backgroundColor: 'green'
|
||||
}
|
||||
})
|
||||
});
|
||||
```
|
||||
@@ -1,80 +0,0 @@
|
||||
# StyleSheet
|
||||
|
||||
The `StyleSheet` abstraction converts predefined styles to (vendor-prefixed)
|
||||
CSS without requiring a compile-time step. Styles that cannot be resolved
|
||||
outside of the render loop (e.g., dynamic positioning) are usually applied as
|
||||
inline styles. Read more about [how to style your
|
||||
application](../guides/style.md).
|
||||
|
||||
## Methods
|
||||
|
||||
**create**(obj: {[key: string]: any})
|
||||
|
||||
Each key of the object passed to `create` must define a style object.
|
||||
|
||||
**flatten**: function
|
||||
|
||||
Flattens an array of styles into a single style object.
|
||||
|
||||
(web) **getStyleSheets**: function
|
||||
|
||||
Returns an array of stylesheets (`{ id, textContent }`). Useful for
|
||||
compile-time or server-side rendering.
|
||||
|
||||
## Properties
|
||||
|
||||
**absoluteFill**: number
|
||||
|
||||
A very common pattern is to create overlays with position absolute and zero positioning,
|
||||
so `absoluteFill` can be used for convenience and to reduce duplication of these repeated
|
||||
styles.
|
||||
|
||||
```js
|
||||
<View style={StyleSheet.absoluteFill} />
|
||||
```
|
||||
|
||||
**absoluteFillObject**: object
|
||||
|
||||
Sometimes you may want `absoluteFill` but with a couple tweaks - `absoluteFillObject` can be
|
||||
used to create a customized entry in a `StyleSheet`, e.g.:
|
||||
|
||||
```js
|
||||
const styles = StyleSheet.create({
|
||||
wrapper: {
|
||||
...StyleSheet.absoluteFillObject,
|
||||
backgroundColor: 'transparent',
|
||||
top: 10
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
**hairlineWidth**: number
|
||||
|
||||
## Example
|
||||
|
||||
```js
|
||||
<View style={styles.container}>
|
||||
<Text
|
||||
children={'Title text'}
|
||||
style={[
|
||||
styles.title,
|
||||
this.props.isActive && styles.activeTitle
|
||||
]}
|
||||
/>
|
||||
</View>
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
borderRadius: 4,
|
||||
borderWidth: 0.5,
|
||||
borderColor: '#d6d7da',
|
||||
},
|
||||
title: {
|
||||
fontSize: 19,
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
activeTitle: {
|
||||
color: 'red',
|
||||
}
|
||||
})
|
||||
```
|
||||
@@ -1,35 +0,0 @@
|
||||
# Vibration
|
||||
|
||||
Vibration is described as a pattern of on-off pulses, which may be of varying
|
||||
lengths. The pattern may consist of either a single integer, describing the
|
||||
number of milliseconds to vibrate, or an array of integers describing a pattern
|
||||
of vibrations and pauses. Vibration is controlled with a single method:
|
||||
`Vibration.vibrate()`.
|
||||
|
||||
The vibration is asynchronous so this method will return immediately. There
|
||||
will be no effect on devices that do not support vibration.
|
||||
|
||||
## Methods
|
||||
|
||||
static **cancel**()
|
||||
|
||||
Stop the vibration.
|
||||
|
||||
static **vibrate**(pattern)
|
||||
|
||||
Start the vibration pattern.
|
||||
|
||||
## Examples
|
||||
|
||||
Vibrate once for 200ms:
|
||||
|
||||
```js
|
||||
Vibration.vibrate(200);
|
||||
Vibration.vibrate([200]);
|
||||
```
|
||||
|
||||
Vibrate for 200ms, pause for 100ms, vibrate for 200ms:
|
||||
|
||||
```js
|
||||
Vibration.vibrate([200, 100, 200]);
|
||||
```
|
||||
@@ -1,70 +0,0 @@
|
||||
# ActivityIndicator
|
||||
|
||||
## Props
|
||||
|
||||
[...View props](./View.md)
|
||||
|
||||
**animating**: boolean = true
|
||||
|
||||
Whether to show the indicator or hide it.
|
||||
|
||||
**color**: ?color = '#1976D2'
|
||||
|
||||
The foreground color of the spinner.
|
||||
|
||||
**hidesWhenStopped**: ?boolean = true
|
||||
|
||||
Whether the indicator should hide when not animating.
|
||||
|
||||
**size**: ?enum('small, 'large') | number = 'small'
|
||||
|
||||
Size of the indicator. Small has a height of `20`, large has a height of `36`.
|
||||
|
||||
## Examples
|
||||
|
||||
```js
|
||||
import React, { Component } from 'react'
|
||||
import { ActivityIndicator, StyleSheet, View } from 'react-native'
|
||||
|
||||
class ToggleAnimatingActivityIndicator extends Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.state = { animating: true }
|
||||
}
|
||||
|
||||
componentDidMount: function() {
|
||||
this.setToggleTimeout();
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<ActivityIndicator
|
||||
animating={this.state.animating}
|
||||
size="large"
|
||||
style={[styles.centering, { height: 80 }]}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
_setToggleTimeout() {
|
||||
setTimeout(() => {
|
||||
this.setState({ animating: !this.state.animating })
|
||||
this._setToggleTimeout()
|
||||
}, 1200)
|
||||
}
|
||||
})
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
centering: {
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center'
|
||||
},
|
||||
gray: {
|
||||
backgroundColor: '#cccccc'
|
||||
},
|
||||
horizontal: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-around'
|
||||
}
|
||||
})
|
||||
```
|
||||
@@ -1,43 +0,0 @@
|
||||
# Button
|
||||
|
||||
A basic button component. Supports a minimal level of customization. You can
|
||||
build your own custom button using `TouchableOpacity` or
|
||||
`TouchableNativeFeedback`.
|
||||
|
||||
## Props
|
||||
|
||||
**accessibilityLabel**: ?string
|
||||
|
||||
Overrides the text that's read by a screen reader when the user interacts
|
||||
with the element.
|
||||
|
||||
**color**: ?string
|
||||
|
||||
Background color of the button.
|
||||
|
||||
**disabled**: ?boolean
|
||||
|
||||
If `true`, disable all interactions for this element.
|
||||
|
||||
**onPress**: function
|
||||
|
||||
This function is called on press.
|
||||
|
||||
**testID**: ?string
|
||||
|
||||
Used to locate this view in end-to-end tests.
|
||||
|
||||
**title**: string
|
||||
|
||||
Text to display inside the button.
|
||||
|
||||
## Examples
|
||||
|
||||
```js
|
||||
<Button
|
||||
accessibilityLabel="Learn more about this purple button"
|
||||
color="#841584"
|
||||
onPress={onPressLearnMore}
|
||||
title="Learn More"
|
||||
/>
|
||||
```
|
||||
@@ -1,167 +0,0 @@
|
||||
# Image
|
||||
|
||||
An accessibile image component with support for image resizing, default image,
|
||||
and child content.
|
||||
|
||||
Unsupported React Native props:
|
||||
`capInsets` (ios),
|
||||
`onProgress` (ios)
|
||||
|
||||
## Props
|
||||
|
||||
**accessibilityLabel**: ?string
|
||||
|
||||
The text that's read by a screenreader when someone interacts with the image.
|
||||
|
||||
**accessible**: ?boolean
|
||||
|
||||
When `true`, indicates the image is an accessibility element.
|
||||
|
||||
**children**: ?any
|
||||
|
||||
Content to display over the image.
|
||||
|
||||
**defaultSource**: ?object
|
||||
|
||||
An image to display as a placeholder while downloading the final image off the
|
||||
network. `{ uri: string, width, height }`
|
||||
|
||||
**onError**: ?function
|
||||
|
||||
Invoked on load error with `{nativeEvent: {error}}`.
|
||||
|
||||
**onLayout**: ?function
|
||||
|
||||
Invoked on mount and layout changes with `{ nativeEvent: { layout: { x, y, width,
|
||||
height } } }`, where `x` and `y` are the offsets from the parent node.
|
||||
|
||||
**onLoad**: ?function
|
||||
|
||||
Invoked when load completes successfully.
|
||||
|
||||
**onLoadEnd**: ?function
|
||||
|
||||
Invoked when load either succeeds or fails,
|
||||
|
||||
**onLoadStart**: ?function
|
||||
|
||||
Invoked on load start.
|
||||
|
||||
**resizeMode**: ?enum('center', 'contain', 'cover', 'none', 'repeat', 'stretch') = 'cover'
|
||||
|
||||
Determines how to resize the image when the frame doesn't match the raw image
|
||||
dimensions.
|
||||
|
||||
**source**: ?object
|
||||
|
||||
`uri` is a string representing the resource identifier for the image, which
|
||||
could be an http address or a base64 encoded image. `{ uri: string, width, height }`
|
||||
|
||||
**style**: ?style
|
||||
|
||||
+ ...[View#style](./View.md)
|
||||
+ `resizeMode`
|
||||
|
||||
**testID**: ?string
|
||||
|
||||
Used to locate a view in end-to-end tests.
|
||||
|
||||
## Properties
|
||||
|
||||
static **resizeMode**: object
|
||||
|
||||
Example usage:
|
||||
|
||||
```
|
||||
<Image resizeMode={Image.resizeMode.contain} />
|
||||
```
|
||||
|
||||
## Methods
|
||||
|
||||
static **getSize**(uri: string, success: (width, height) => {}, failure: function)
|
||||
|
||||
Retrieve the width and height (in pixels) of an image prior to displaying it.
|
||||
This method can fail if the image cannot be found, or fails to download.
|
||||
|
||||
(In order to retrieve the image dimensions, the image may first need to be
|
||||
loaded or downloaded, after which it will be cached. This means that in
|
||||
principle you could use this method to preload images, however it is not
|
||||
optimized for that purpose, and may in future be implemented in a way that does
|
||||
not fully load/download the image data.)
|
||||
|
||||
static **prefetch**(url: string): Promise
|
||||
|
||||
Prefetches a remote image for later use by downloading it.
|
||||
|
||||
## Examples
|
||||
|
||||
```js
|
||||
import placeholderAvatar from './placeholderAvatar.png'
|
||||
import React, { Component } from 'react'
|
||||
import { Image, PropTypes, StyleSheet } from 'react-native'
|
||||
|
||||
export default class ImageExample extends Component {
|
||||
constructor(props, context) {
|
||||
super(props, context)
|
||||
this.state = { loading: true }
|
||||
}
|
||||
|
||||
static propTypes = {
|
||||
size: PropTypes.oneOf(['small', 'normal', 'large']),
|
||||
testID: Image.propTypes.testID,
|
||||
user: PropTypes.object
|
||||
}
|
||||
|
||||
static defaultProps = {
|
||||
size: 'normal'
|
||||
}
|
||||
|
||||
_onLoad(e) {
|
||||
console.log('Avatar.onLoad', e)
|
||||
this.setState({ loading: false })
|
||||
}
|
||||
|
||||
render() {
|
||||
const { size, testID, user } = this.props
|
||||
const loadingStyle = this.state.loading ? { styles.loading } : { }
|
||||
|
||||
return (
|
||||
<Image
|
||||
accessibilityLabel={`${user.name}'s profile picture`}
|
||||
defaultSource={{ uri: placeholderAvatar }}
|
||||
onLoad={this._onLoad.bind(this)}
|
||||
resizeMode='cover'
|
||||
source={{ uri: user.avatarUrl }}
|
||||
style={[
|
||||
styles.base,
|
||||
styles[size],
|
||||
loadingStyle
|
||||
]}
|
||||
/>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
base: {
|
||||
borderColor: 'white',
|
||||
borderRadius: 5,
|
||||
borderWidth: 5
|
||||
},
|
||||
loading: {
|
||||
opacity: 0.5
|
||||
},
|
||||
small: {
|
||||
height: 32,
|
||||
width: 32
|
||||
},
|
||||
normal: {
|
||||
height: 48,
|
||||
width: 48
|
||||
},
|
||||
large: {
|
||||
height: 64,
|
||||
width: 64
|
||||
}
|
||||
})
|
||||
```
|
||||
@@ -1,27 +0,0 @@
|
||||
# ProgressBar
|
||||
|
||||
Display an activity progress bar.
|
||||
|
||||
## Props
|
||||
|
||||
[...View props](./View.md)
|
||||
|
||||
**color**: ?string = '#1976D2'
|
||||
|
||||
Color of the progress bar.
|
||||
|
||||
**indeterminate**: ?boolean = true
|
||||
|
||||
Whether the progress bar will show indeterminate progress.
|
||||
|
||||
**progress**: ?number
|
||||
|
||||
The progress value (between 0 and 1).
|
||||
|
||||
**testID**: ?string
|
||||
|
||||
Used to locate this view in end-to-end tests.
|
||||
|
||||
(web) **trackColor**: ?string = 'transparent'
|
||||
|
||||
Color of the track bar.
|
||||
@@ -1,134 +0,0 @@
|
||||
# ScrollView
|
||||
|
||||
A scrollable `View` that provides itegration with the touch-locking "responder"
|
||||
system. `ScrollView`'s must have a bounded height: either set the height of the
|
||||
view directly (discouraged) or make sure all parent views have bounded height
|
||||
(e.g., transfer `{ flex: 1}` down the view stack).
|
||||
|
||||
## Props
|
||||
|
||||
[...View props](./View.md)
|
||||
|
||||
**contentContainerStyle**: ?style
|
||||
|
||||
These styles will be applied to the scroll view content container which wraps
|
||||
all of the child views.
|
||||
|
||||
**horizontal**: ?boolean = false
|
||||
|
||||
When `true`, the scroll view's children are arranged horizontally in a row
|
||||
instead of vertically in a column.
|
||||
|
||||
**keyboardDismissMode**: ?enum('none', 'on-drag') = 'none'
|
||||
|
||||
Determines whether the keyboard gets dismissed in response to a scroll drag.
|
||||
|
||||
* `none` (the default), drags do not dismiss the keyboard.
|
||||
* `on-drag`, the keyboard is dismissed when a drag begins.
|
||||
* `interactive` (not supported on web; same as `none`)
|
||||
|
||||
**onContentSizeChange**: ?function
|
||||
|
||||
Called when scrollable content view of the `ScrollView` changes. It's
|
||||
implemented using the `onLayout` handler attached to the content container
|
||||
which this `ScrollView` renders.
|
||||
|
||||
**onScroll**: ?function
|
||||
|
||||
Fires at most once per frame during scrolling. The frequency of the events can
|
||||
be contolled using the `scrollEventThrottle` prop.
|
||||
|
||||
Invoked on scroll with the following event:
|
||||
|
||||
```js
|
||||
{
|
||||
nativeEvent: {
|
||||
contentOffset: { x, y },
|
||||
contentSize: { height, width },
|
||||
layoutMeasurement: { height, width }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**refreshControl**: ?element
|
||||
|
||||
TODO
|
||||
|
||||
A [RefreshControl](../RefreshControl) component, used to provide
|
||||
pull-to-refresh functionality for the `ScrollView`.
|
||||
|
||||
**scrollEnabled**: ?boolean = true
|
||||
|
||||
When false, the content does not scroll.
|
||||
|
||||
**scrollEventThrottle**: ?number = 0
|
||||
|
||||
This controls how often the scroll event will be fired while scrolling (as a
|
||||
time interval in ms). A lower number yields better accuracy for code that is
|
||||
tracking the scroll position, but can lead to scroll performance problems. The
|
||||
default value is `0`, which means the scroll event will be sent only once each
|
||||
time the view is scrolled.
|
||||
|
||||
## Instance methods
|
||||
|
||||
**getInnerViewNode()**: any
|
||||
|
||||
Returns a reference to the underlying content container DOM node within the `ScrollView`.
|
||||
|
||||
**getScrollableNode()**: any
|
||||
|
||||
Returns a reference to the underlying scrollable DOM node.
|
||||
|
||||
**getScrollResponder()**: Component
|
||||
|
||||
Returns a reference to the underlying scroll responder, which supports
|
||||
operations like `scrollTo`. All `ScrollView`-like components should implement
|
||||
this method so that they can be composed while providing access to the
|
||||
underlying scroll responder's methods.
|
||||
|
||||
**scrollTo(options: { x: number = 0; y: number = 0; animated: boolean = true })**
|
||||
|
||||
Scrolls to a given `x`, `y` offset (animation is not currently supported).
|
||||
|
||||
## Examples
|
||||
|
||||
```js
|
||||
import React, { Component } from 'react'
|
||||
import { ScrollView, StyleSheet } from 'react-native'
|
||||
import Item from './Item'
|
||||
|
||||
export default class ScrollViewExample extends Component {
|
||||
constructor(props, context) {
|
||||
super(props, context)
|
||||
this.state = {
|
||||
items: Array.from(new Array(20)).map((_, i) => ({ id: i }))
|
||||
}
|
||||
}
|
||||
|
||||
onScroll(e) {
|
||||
console.log(e)
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<ScrollView
|
||||
children={this.state.items.map((item) => <Item {...item} />)}
|
||||
contentContainerStyle={styles.container}
|
||||
horizontal
|
||||
onScroll={(e) => this.onScroll(e)}
|
||||
scrollEventThrottle={100}
|
||||
style={styles.root}
|
||||
/>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
root: {
|
||||
borderWidth: 1
|
||||
},
|
||||
container: {
|
||||
padding: 10
|
||||
}
|
||||
})
|
||||
```
|
||||
@@ -1,76 +0,0 @@
|
||||
# Switch
|
||||
|
||||
This is a controlled component that requires an `onValueChange` callback that
|
||||
updates the value prop in order for the component to reflect user actions. If
|
||||
the `value` prop is not updated, the component will continue to render the
|
||||
supplied `value` prop instead of the expected result of any user actions.
|
||||
|
||||
## Props
|
||||
|
||||
[...View props](./View.md)
|
||||
|
||||
**disabled**: ?boolean = false
|
||||
|
||||
If `true` the user won't be able to interact with the switch.
|
||||
|
||||
**onValueChange**: ?function
|
||||
|
||||
Invoked with the new value when the value changes.
|
||||
|
||||
**value**: ?boolean = false
|
||||
|
||||
The value of the switch. If `true` the switch will be turned on.
|
||||
|
||||
(web) **activeThumbColor**: ?color = #009688
|
||||
|
||||
The color of the thumb grip when the switch is turned on.
|
||||
|
||||
(web) **activeTrackColor**: ?color = #A3D3CF
|
||||
|
||||
The color of the track when the switch is turned on.
|
||||
|
||||
(web) **thumbColor**: ?color = #FAFAFA
|
||||
|
||||
The color of the thumb grip when the switch is turned off.
|
||||
|
||||
(web) **trackColor**: ?color = #939393
|
||||
|
||||
The color of the track when the switch is turned off.
|
||||
|
||||
## Examples
|
||||
|
||||
```js
|
||||
import React, { Component } from 'react'
|
||||
import { Switch, View } from 'react-native'
|
||||
|
||||
class ColorSwitchExample extends Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.state = {
|
||||
colorTrueSwitchIsOn: true,
|
||||
colorFalseSwitchIsOn: false
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<View>
|
||||
<Switch
|
||||
activeThumbColor='#428BCA'
|
||||
activeTrackColor='#A0C4E3'
|
||||
onValueChange={(value) => this.setState({ colorFalseSwitchIsOn: value })}
|
||||
value={this.state.colorFalseSwitchIsOn}
|
||||
/>
|
||||
<Switch
|
||||
activeThumbColor='#5CB85C'
|
||||
activeTrackColor='#ADDAAD'
|
||||
onValueChange={(value) => this.setState({ colorTrueSwitchIsOn: value })}
|
||||
thumbColor='#EBA9A7'
|
||||
trackColor='#D9534F'
|
||||
value={this.state.colorTrueSwitchIsOn}
|
||||
/>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -1,161 +0,0 @@
|
||||
# Text
|
||||
|
||||
`Text` is component for displaying text. It supports style, basic touch
|
||||
handling, and inherits typographic styles from ancestor elements.
|
||||
|
||||
The `Text` is unique relative to layout: child elements use text layout
|
||||
(`inline`) rather than flexbox layout. This means that elements inside of a
|
||||
`Text` are not rectangles, as they wrap when reaching the edge of their
|
||||
container.
|
||||
|
||||
Unsupported React Native props:
|
||||
`allowFontScaling` (ios),
|
||||
`suppressHighlighting` (ios)
|
||||
|
||||
## Props
|
||||
|
||||
NOTE: `Text` will transfer all other props to the rendered HTML element.
|
||||
|
||||
(web) **accessibilityLabel**: ?string
|
||||
|
||||
Overrides the text that's read by a screen reader when the user interacts
|
||||
with the element. (This is implemented using `aria-label`.)
|
||||
|
||||
See the [Accessibility guide](../guides/accessibility) for more information.
|
||||
|
||||
(web) **accessibilityRole**: ?oneOf(roles)
|
||||
|
||||
Allows assistive technologies to present and support interaction with the view
|
||||
in a manner that is consistent with user expectations for similar views of that
|
||||
type. For example, marking a touchable view with an `accessibilityRole` of
|
||||
`button`. (This is implemented using [ARIA roles](http://www.w3.org/TR/wai-aria/roles#role_definitions)).
|
||||
|
||||
See the [Accessibility guide](../guides/accessibility) for more information.
|
||||
|
||||
**accessible**: ?boolean
|
||||
|
||||
When `true`, indicates that the view is an accessibility element (i.e.,
|
||||
focusable) and groups its child content. By default, all the touchable elements
|
||||
and elements with `accessibilityRole` of `button` and `link` are accessible.
|
||||
(This is implemented using `tabindex`.)
|
||||
|
||||
See the [Accessibility guide](../guides/accessibility) for more information.
|
||||
|
||||
**children**: ?any
|
||||
|
||||
Child content.
|
||||
|
||||
**importantForAccessibility**: ?enum('auto', 'no-hide-descendants', 'yes')
|
||||
|
||||
A value of `no` will remove the element from the tab flow.
|
||||
|
||||
A value of `no-hide-descendants` will hide the element and its children from
|
||||
assistive technologies. (This is implemented using `aria-hidden`.)
|
||||
|
||||
See the [Accessibility guide](../guides/accessibility) for more information.
|
||||
|
||||
**numberOfLines**: ?number
|
||||
|
||||
Truncates the text with an ellipsis after this many lines. Currently only supports `1`.
|
||||
|
||||
**onLayout**: ?function
|
||||
|
||||
Invoked on mount and layout changes with `{ nativeEvent: { layout: { x, y, width,
|
||||
height } } }`, where `x` and `y` are the offsets from the parent node.
|
||||
|
||||
**onPress**: ?function
|
||||
|
||||
This function is called on press.
|
||||
|
||||
**selectable**: ?boolean
|
||||
|
||||
When `false`, the text is not selectable.
|
||||
|
||||
**style**: ?style
|
||||
|
||||
+ ...[View#style](View.md)
|
||||
+ `color`
|
||||
+ `fontFamily`
|
||||
+ `fontFeatureSettings` ‡
|
||||
+ `fontSize`
|
||||
+ `fontStyle`
|
||||
+ `fontWeight`
|
||||
+ `letterSpacing`
|
||||
+ `lineHeight`
|
||||
+ `textAlign`
|
||||
+ `textAlignVertical`
|
||||
+ `textDecorationLine`
|
||||
+ `textIndent` ‡
|
||||
+ `textOverflow` ‡
|
||||
+ `textRendering` ‡
|
||||
+ `textShadowColor`
|
||||
+ `textShadowOffset`
|
||||
+ `textShadowRadius`
|
||||
+ `textTransform` ‡
|
||||
+ `unicodeBidi` ‡
|
||||
+ `whiteSpace`
|
||||
+ `wordWrap` ‡
|
||||
+ `writingDirection`
|
||||
|
||||
‡ web only.
|
||||
|
||||
**testID**: ?string
|
||||
|
||||
Used to locate this view in end-to-end tests.
|
||||
|
||||
## Examples
|
||||
|
||||
```js
|
||||
import React, { Component, PropTypes } from 'react'
|
||||
import { StyleSheet, Text } from 'react-native'
|
||||
|
||||
export default class PrettyText extends Component {
|
||||
static propTypes = {
|
||||
...Text.propTypes,
|
||||
color: PropTypes.oneOf(['white', 'gray', 'red']),
|
||||
size: PropTypes.oneOf(['small', 'normal', 'large']),
|
||||
weight: PropTypes.oneOf(['light', 'normal', 'bold'])
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
...Text.defaultProps,
|
||||
color: 'gray',
|
||||
size: 'normal',
|
||||
weight: 'normal'
|
||||
};
|
||||
|
||||
render() {
|
||||
const { color, size, style, weight, ...other } = this.props;
|
||||
|
||||
return (
|
||||
<Text
|
||||
...other
|
||||
style={[
|
||||
style,
|
||||
colorStyles[color],
|
||||
sizeStyles[size],
|
||||
weightStyles[weight]
|
||||
]}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const colorStyles = StyleSheet.create({
|
||||
white: { color: 'white' },
|
||||
gray: { color: 'gray' },
|
||||
red: { color: 'red' }
|
||||
})
|
||||
|
||||
const sizeStyles = StyleSheet.create({
|
||||
small: { fontSize: '0.85rem', padding: '0.5rem' },
|
||||
normal: { fontSize: '1rem', padding: '0.75rem' },
|
||||
large: { fontSize: '1.5rem', padding: '1rem' }
|
||||
})
|
||||
|
||||
const weightStyles = StyleSheet.create({
|
||||
light: { fontWeight: '300' },
|
||||
normal: { fontWeight: '400' },
|
||||
bold: { fontWeight: '700' }
|
||||
})
|
||||
```
|
||||
@@ -1,226 +0,0 @@
|
||||
# TextInput
|
||||
|
||||
Accessible single- and multi-line text input via a keyboard. Supports features
|
||||
such as auto-complete, auto-focus, placeholder text, and event callbacks.
|
||||
|
||||
Note: some props are exclusive to or excluded from `multiline`.
|
||||
|
||||
Unsupported React Native props:
|
||||
`onEndEditing`,
|
||||
`clearButtonMode` (ios),
|
||||
`enablesReturnKeyAutomatically` (ios),
|
||||
`placeholderTextColor`,
|
||||
`returnKeyType` (ios),
|
||||
`selectionState` (ios),
|
||||
`underlineColorAndroid` (android)
|
||||
|
||||
## Props
|
||||
|
||||
[...View props](./View.md)
|
||||
|
||||
**autoCapitalize**: ?enum('characters', 'none', 'sentences', 'words') = 'sentences'
|
||||
|
||||
Automatically capitalize certain characters (only available in Chrome and iOS Safari).
|
||||
|
||||
* `characters`: Automatically capitalize all characters.
|
||||
* `none`: Completely disables automatic capitalization
|
||||
* `sentences`: Automatically capitalize the first letter of sentences.
|
||||
* `words`: Automatically capitalize the first letter of words.
|
||||
|
||||
(web) **autoComplete**: ?string
|
||||
|
||||
Indicates whether the value of the control can be automatically completed by
|
||||
the browser. [Accepted values](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input).
|
||||
|
||||
**autoCorrect**: ?boolean = true
|
||||
|
||||
Automatically correct spelling mistakes (only available in iOS Safari).
|
||||
|
||||
**autoFocus**: ?boolean = false
|
||||
|
||||
If `true`, focuses the input on `componentDidMount`. Only the first form element
|
||||
in a document with `autofocus` is focused.
|
||||
|
||||
**blurOnSubmit**: ?boolean
|
||||
|
||||
If `true`, the text field will blur when submitted. The default value is `true`
|
||||
for single-line fields and `false` for multiline fields. Note, for multiline
|
||||
fields setting `blurOnSubmit` to `true` means that pressing return will blur
|
||||
the field and trigger the `onSubmitEditing` event instead of inserting a
|
||||
newline into the field.
|
||||
|
||||
**clearTextOnFocus**: ?boolean = false
|
||||
|
||||
If `true`, clears the text field automatically when focused.
|
||||
|
||||
**defaultValue**: ?string
|
||||
|
||||
Provides an initial value that will change when the user starts typing. Useful
|
||||
for simple use-cases where you don't want to deal with listening to events and
|
||||
updating the `value` prop to keep the controlled state in sync.
|
||||
|
||||
**editable**: ?boolean = true
|
||||
|
||||
If `false`, text is not editable (i.e., read-only).
|
||||
|
||||
**keyboardType**: enum('default', 'email-address', 'numeric', 'phone-pad', 'search', 'url', 'web-search') = 'default'
|
||||
|
||||
Determines which keyboard to open. (NOTE: Safari iOS requires an ancestral
|
||||
`<form action>` element to display the `search` keyboard).
|
||||
|
||||
(Not available when `multiline` is `true`.)
|
||||
|
||||
**maxLength**: ?number
|
||||
|
||||
Limits the maximum number of characters that can be entered.
|
||||
|
||||
**multiline**: ?boolean = false
|
||||
|
||||
If true, the text input can be multiple lines.
|
||||
|
||||
**numberOfLines**: ?number = 2
|
||||
|
||||
Sets the number of lines for a multiline `TextInput`.
|
||||
|
||||
(Requires `multiline` to be `true`.)
|
||||
|
||||
**onBlur**: ?function
|
||||
|
||||
Callback that is called when the text input is blurred.
|
||||
|
||||
**onChange**: ?function
|
||||
|
||||
Callback that is called when the text input's text changes.
|
||||
|
||||
**onChangeText**: ?function
|
||||
|
||||
Callback that is called when the text input's text changes. The text is passed
|
||||
as an argument to the callback handler.
|
||||
|
||||
**onFocus**: ?function
|
||||
|
||||
Callback that is called when the text input is focused.
|
||||
|
||||
**onKeyPress**: ?function
|
||||
|
||||
Callback that is called when a key is pressed. This will be called with `{
|
||||
nativeEvent: { key: keyValue } }` where keyValue is 'Enter` or 'Backspace' for
|
||||
respective keys and the typed-in character otherwise including ' ' for space.
|
||||
Modifier keys are also included in the nativeEvent. Fires before onChange
|
||||
callbacks.
|
||||
|
||||
**onSelectionChange**: ?function
|
||||
|
||||
Callback that is called when the text input's selection changes. This will be called with
|
||||
`{ nativeEvent: { selection: { start, end } } }`.
|
||||
|
||||
**onSubmitEditing**: ?function
|
||||
|
||||
Callback that is called when the keyboard's submit button is pressed.
|
||||
|
||||
**placeholder**: ?string
|
||||
|
||||
The string that will be rendered in an empty `TextInput` before text has been
|
||||
entered.
|
||||
|
||||
**secureTextEntry**: ?boolean = false
|
||||
|
||||
If true, the text input obscures the text entered so that sensitive text like
|
||||
passwords stay secure.
|
||||
|
||||
(Not available when `multiline` is `true`.)
|
||||
|
||||
**selection**: ?{ start: number, end: ?number }
|
||||
|
||||
The start and end of the text input's selection. Set start and end to the same value to position the cursor.
|
||||
|
||||
**selectTextOnFocus**: ?boolean = false
|
||||
|
||||
If `true`, all text will automatically be selected on focus.
|
||||
|
||||
**style**: ?style
|
||||
|
||||
+ ...[Text#style](./Text.md)
|
||||
+ `resize` ‡
|
||||
|
||||
‡ web only.
|
||||
|
||||
**testID**: ?string
|
||||
|
||||
Used to locate this view in end-to-end tests.
|
||||
|
||||
**value**: ?string
|
||||
|
||||
The value to show for the text input. `TextInput` is a controlled component,
|
||||
which means the native `value` will be forced to match this prop if provided.
|
||||
Read about how [React form
|
||||
components](https://facebook.github.io/react/docs/forms.html) work. To prevent
|
||||
user edits to the value set `editable={false}`.
|
||||
|
||||
## Instance methods
|
||||
|
||||
**blur()**
|
||||
|
||||
Blur the underlying DOM input.
|
||||
|
||||
**clear()**
|
||||
|
||||
Clear the text from the underlying DOM input.
|
||||
|
||||
**focus()**
|
||||
|
||||
Focus the underlying DOM input.
|
||||
|
||||
**isFocused()**
|
||||
|
||||
Returns `true` if the input is currently focused; `false` otherwise.
|
||||
|
||||
## Examples
|
||||
|
||||
```js
|
||||
import React, { Component } from 'react'
|
||||
import { StyleSheet, TextInput } from 'react-native'
|
||||
|
||||
export default class TextInputExample extends Component {
|
||||
constructor(props, context) {
|
||||
super(props, context)
|
||||
this.state = { isFocused: false }
|
||||
}
|
||||
|
||||
_onBlur(e) {
|
||||
this.setState({ isFocused: false })
|
||||
}
|
||||
|
||||
_onFocus(e) {
|
||||
this.setState({ isFocused: true })
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<TextInput
|
||||
accessibilityLabel='Write a status update'
|
||||
maxNumberOfLines={5}
|
||||
multiline
|
||||
numberOfLines={2}
|
||||
onBlur={this._onBlur.bind(this)}
|
||||
onFocus={this._onFocus.bind(this)}
|
||||
placeholder={`What's happening?`}
|
||||
style={[
|
||||
styles.default
|
||||
this.state.isFocused && styles.focused
|
||||
]}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
default: {
|
||||
borderColor: 'gray',
|
||||
borderBottomWidth: 2
|
||||
},
|
||||
focused: {
|
||||
borderColor: 'blue'
|
||||
}
|
||||
})
|
||||
```
|
||||
@@ -1,46 +0,0 @@
|
||||
# TouchableWithoutFeedback
|
||||
|
||||
Do not use unless you have a very good reason. All the elements that respond to
|
||||
press should have a visual feedback when touched. This is one of the primary
|
||||
reason a "web" app doesn't feel "native".
|
||||
|
||||
**NOTE: `TouchableWithoutFeedback` supports only one child**. If you wish to have
|
||||
several child components, wrap them in a View.
|
||||
|
||||
## Props
|
||||
|
||||
[...View props](./View.md)
|
||||
|
||||
**delayLongPress**: ?number
|
||||
|
||||
Delay in ms, from `onPressIn`, before `onLongPress` is called.
|
||||
|
||||
**delayPressIn**: ?number
|
||||
|
||||
Delay in ms, from the start of the touch, before `onPressIn` is called.
|
||||
|
||||
**delayPressOut**: ?number
|
||||
|
||||
Delay in ms, from the release of the touch, before `onPressOut` is called.
|
||||
|
||||
**disabled**: ?boolean
|
||||
|
||||
If `true`, disable all interactions for this component.
|
||||
|
||||
**onLongPress**: ?function
|
||||
|
||||
**onPress**: ?function
|
||||
|
||||
Called when the touch is released, but not if cancelled (e.g. by a scroll that steals the responder lock).
|
||||
|
||||
**onPressIn**: ?function
|
||||
|
||||
**onPressOut**: ?function
|
||||
|
||||
**pressRetentionOffset**: ?`{top: number, left: number, bottom: number, right: number}`
|
||||
|
||||
When the scroll view is disabled, this defines how far your touch may move off
|
||||
of the button, before deactivating the button. Once deactivated, try moving it
|
||||
back and you'll see that the button is once again reactivated! Move it back and
|
||||
forth several times while the scroll view is disabled. Ensure you pass in a
|
||||
constant to reduce memory allocations.
|
||||
@@ -1,317 +0,0 @@
|
||||
# View
|
||||
|
||||
`View` is the fundamental UI building block. It is a component that supports
|
||||
style, layout with flexbox, and accessibility controls. It can be nested
|
||||
inside another `View` and has 0-to-many children of any type.
|
||||
|
||||
Also, refer to React Native's documentation about the [Gesture Responder
|
||||
System](http://facebook.github.io/react-native/releases/0.22/docs/gesture-responder-system.html).
|
||||
|
||||
Unsupported React Native props: `collapsable`, `onAccessibilityTap`, `onMagicTap`.
|
||||
|
||||
## Props
|
||||
|
||||
NOTE: `View` will transfer all other props to the rendered HTML element.
|
||||
|
||||
**accessibilityLabel**: ?string
|
||||
|
||||
Overrides the text that's read by a screen reader when the user interacts
|
||||
with the element. (This is implemented using `aria-label`.)
|
||||
|
||||
See the [Accessibility guide](../guides/accessibility.md) for more information.
|
||||
|
||||
**accessibilityLiveRegion**: ?enum('assertive', 'none', 'polite')
|
||||
|
||||
Indicates to assistive technologies whether to notify the user when the view
|
||||
changes. The values of this attribute are expressed in degrees of importance.
|
||||
When regions are specified as `polite` (recommended), updates take low
|
||||
priority. When regions are specified as `assertive`, assistive technologies
|
||||
will interrupt and immediately notify the user. (This is implemented using
|
||||
[`aria-live`](http://www.w3.org/TR/wai-aria/states_and_properties#aria-live).)
|
||||
|
||||
See the [Accessibility guide](../guides/accessibility.md) for more information.
|
||||
|
||||
(web) **accessibilityRole**: ?enum(roles)
|
||||
|
||||
Allows assistive technologies to present and support interaction with the view
|
||||
in a manner that is consistent with user expectations for similar views of that
|
||||
type. For example, marking a touchable view with an `accessibilityRole` of
|
||||
`button`. (This is implemented using [ARIA roles](http://www.w3.org/TR/wai-aria/roles#role_definitions)).
|
||||
|
||||
See the [Accessibility guide](../guides/accessibility.md) for more information.
|
||||
|
||||
**accessible**: ?boolean
|
||||
|
||||
When `true`, indicates that the view is an accessibility element (i.e.,
|
||||
focusable) and groups its child content. By default, all the touchable elements
|
||||
and elements with `accessibilityRole` of `button` and `link` are accessible.
|
||||
(This is implemented using `tabindex`.)
|
||||
|
||||
See the [Accessibility guide](../guides/accessibility.md) for more information.
|
||||
|
||||
**children**: ?element
|
||||
|
||||
Child content.
|
||||
|
||||
**hitSlop**: ?object
|
||||
|
||||
This defines how far a touch event can start away from the view (in pixels).
|
||||
Typical interface guidelines recommend touch targets that are at least 30 - 40
|
||||
points/density-independent pixels.
|
||||
|
||||
For example, if a touchable view has a height of `20` the touchable height can
|
||||
be extended to `40` with `hitSlop={{top: 10, bottom: 10, left: 0, right: 0}}`.
|
||||
|
||||
**importantForAccessibility**: ?enum('auto', 'no', 'no-hide-descendants', 'yes')
|
||||
|
||||
A value of `no` will remove the element from the tab flow.
|
||||
|
||||
A value of `no-hide-descendants` will hide the element and its children from
|
||||
assistive technologies. (This is implemented using `aria-hidden`.)
|
||||
|
||||
See the [Accessibility guide](../guides/accessibility.md) for more information.
|
||||
|
||||
**onLayout**: ?function
|
||||
|
||||
Invoked on mount and layout changes with `{ nativeEvent: { layout: { x, y, width,
|
||||
height } } }`, where `x` and `y` are the offsets from the parent node.
|
||||
|
||||
**onMoveShouldSetResponder**: ?function => boolean
|
||||
|
||||
Does this view want to "claim" touch responsiveness? This is called for every
|
||||
touch move on the `View` when it is not the responder.
|
||||
|
||||
**onMoveShouldSetResponderCapture**: ?function => boolean
|
||||
|
||||
If a parent `View` wants to prevent a child `View` from becoming responder on a
|
||||
move, it should have this handler return `true`.
|
||||
|
||||
**onResponderGrant**: ?function
|
||||
|
||||
The `View` is now responding to touch events. This is the time to highlight and
|
||||
show the user what is happening. For most touch interactions, you'll simply
|
||||
want to wrap your component in `TouchableHighlight` or `TouchableOpacity`.
|
||||
|
||||
**onResponderMove**: ?function
|
||||
|
||||
The user is moving their finger.
|
||||
|
||||
**onResponderReject**: ?function
|
||||
|
||||
Another responder is already active and will not release it to the `View`
|
||||
asking to be the responder.
|
||||
|
||||
**onResponderRelease**: ?function
|
||||
|
||||
Fired at the end of the touch.
|
||||
|
||||
**onResponderTerminate**: ?function
|
||||
|
||||
The responder has been taken from the `View`.
|
||||
|
||||
**onResponderTerminationRequest**: ?function
|
||||
|
||||
Some other `View` wants to become responder and is asking this `View` to
|
||||
release its responder. Returning `true` allows its release.
|
||||
|
||||
**onStartShouldSetResponder**: ?function => boolean
|
||||
|
||||
Does this view want to become responder on the start of a touch?
|
||||
|
||||
**onStartShouldSetResponderCapture**: ?function => boolean
|
||||
|
||||
If a parent `View` wants to prevent a child `View` from becoming the responder
|
||||
on a touch start, it should have this handler return `true`.
|
||||
|
||||
**pointerEvents**: ?enum('auto', 'box-only', 'box-none', 'none') = 'auto'
|
||||
|
||||
Controls whether the View can be the target of touch events. The enhanced
|
||||
`pointerEvents` modes provided are not part of the CSS spec, therefore,
|
||||
`pointerEvents` is excluded from `style`.
|
||||
|
||||
`box-none` is the equivalent of:
|
||||
|
||||
```css
|
||||
.box-none { pointer-events: none !important; }
|
||||
.box-none > * { pointer-events: auto; }
|
||||
```
|
||||
|
||||
`box-only` is the equivalent of:
|
||||
|
||||
```css
|
||||
.box-only { pointer-events: auto !important; }
|
||||
.box-only > * { pointer-events: none; }
|
||||
```
|
||||
|
||||
**style**: ?style
|
||||
|
||||
+ `alignContent`
|
||||
+ `alignItems`
|
||||
+ `alignSelf`
|
||||
+ `animationDelay` ‡
|
||||
+ `animationDirection` ‡
|
||||
+ `animationDuration` ‡
|
||||
+ `animationFillMode` ‡
|
||||
+ `animationIterationCount` ‡
|
||||
+ `animationName` ‡
|
||||
+ `animationPlayState` ‡
|
||||
+ `animationTimingFunction` ‡
|
||||
+ `backfaceVisibility`
|
||||
+ `backgroundAttachment` ‡
|
||||
+ `backgroundBlendMode` ‡
|
||||
+ `backgroundClip` ‡
|
||||
+ `backgroundColor`
|
||||
+ `backgroundImage` ‡
|
||||
+ `backgroundOrigin` ‡
|
||||
+ `backgroundPosition` ‡
|
||||
+ `backgroundRepeat` ‡
|
||||
+ `backgroundSize` ‡
|
||||
+ `borderColor` (single value)
|
||||
+ `borderTopColor`
|
||||
+ `borderBottomColor`
|
||||
+ `borderRightColor`
|
||||
+ `borderLeftColor`
|
||||
+ `borderRadius` (single value)
|
||||
+ `borderTopLeftRadius`
|
||||
+ `borderTopRightRadius`
|
||||
+ `borderBottomLeftRadius`
|
||||
+ `borderBottomRightRadius`
|
||||
+ `borderStyle` (single value)
|
||||
+ `borderTopStyle`
|
||||
+ `borderRightStyle`
|
||||
+ `borderBottomStyle`
|
||||
+ `borderLeftStyle`
|
||||
+ `borderWidth` (single value)
|
||||
+ `borderBottomWidth`
|
||||
+ `borderLeftWidth`
|
||||
+ `borderRightWidth`
|
||||
+ `borderTopWidth`
|
||||
+ `bottom`
|
||||
+ `boxShadow` ‡
|
||||
+ `boxSizing`
|
||||
+ `clip` ‡
|
||||
+ `cursor` ‡
|
||||
+ `display`
|
||||
+ `filter` ‡
|
||||
+ `flex` (number)
|
||||
+ `flexBasis`
|
||||
+ `flexDirection`
|
||||
+ `flexGrow`
|
||||
+ `flexShrink`
|
||||
+ `flexWrap`
|
||||
+ `gridAutoColumns` ‡
|
||||
+ `gridAutoFlow` ‡
|
||||
+ `gridAutoRows` ‡
|
||||
+ `gridColumnEnd` ‡
|
||||
+ `gridColumnGap` ‡
|
||||
+ `gridColumnStart` ‡
|
||||
+ `gridRowEnd` ‡
|
||||
+ `gridRowGap` ‡
|
||||
+ `gridRowStart` ‡
|
||||
+ `gridTemplateColumns` ‡
|
||||
+ `gridTemplateRows` ‡
|
||||
+ `gridTemplateAreas` ‡
|
||||
+ `height`
|
||||
+ `justifyContent`
|
||||
+ `left`
|
||||
+ `margin` (single value)
|
||||
+ `marginBottom`
|
||||
+ `marginHorizontal`
|
||||
+ `marginLeft`
|
||||
+ `marginRight`
|
||||
+ `marginTop`
|
||||
+ `marginVertical`
|
||||
+ `maxHeight`
|
||||
+ `maxWidth`
|
||||
+ `minHeight`
|
||||
+ `minWidth`
|
||||
+ `opacity`
|
||||
+ `order`
|
||||
+ `outline` ‡
|
||||
+ `outlineColor` ‡
|
||||
+ `overflow`
|
||||
+ `overflowX` ‡
|
||||
+ `overflowY` ‡
|
||||
+ `padding` (single value)
|
||||
+ `paddingBottom`
|
||||
+ `paddingHorizontal`
|
||||
+ `paddingLeft`
|
||||
+ `paddingRight`
|
||||
+ `paddingTop`
|
||||
+ `paddingVertical`
|
||||
+ `perspective` ‡
|
||||
+ `perspectiveOrigin` ‡
|
||||
+ `position`
|
||||
+ `right`
|
||||
+ `shadowColor`
|
||||
+ `shadowOffset`
|
||||
+ `shadowOpacity`
|
||||
+ `shadowRadius`
|
||||
+ `top`
|
||||
+ `transform`
|
||||
+ `transformOrigin` ‡
|
||||
+ `transitionDelay` ‡
|
||||
+ `transitionDuration` ‡
|
||||
+ `transitionProperty` ‡
|
||||
+ `transitionTimingFunction` ‡
|
||||
+ `userSelect` ‡
|
||||
+ `visibility` ‡
|
||||
+ `width`
|
||||
+ `willChange` ‡
|
||||
+ `zIndex`
|
||||
|
||||
‡ web only.
|
||||
|
||||
Default:
|
||||
|
||||
```js
|
||||
{
|
||||
alignItems: 'stretch',
|
||||
borderWidth: 0,
|
||||
borderStyle: 'solid',
|
||||
boxSizing: 'border-box',
|
||||
display: 'flex',
|
||||
flexBasis: 'auto',
|
||||
flexDirection: 'column',
|
||||
flexShrink: 0,
|
||||
margin: 0,
|
||||
padding: 0,
|
||||
position: 'relative'
|
||||
};
|
||||
```
|
||||
|
||||
(See [facebook/yoga](https://github.com/facebook/yoga)).
|
||||
|
||||
**testID**: ?string
|
||||
|
||||
Used to locate this view in end-to-end tests.
|
||||
|
||||
## Examples
|
||||
|
||||
```js
|
||||
import React, { Component, PropTypes } from 'react'
|
||||
import { StyleSheet, View } from 'react-native'
|
||||
|
||||
export default class ViewExample extends Component {
|
||||
render() {
|
||||
return (
|
||||
<View style={styles.row}>
|
||||
{
|
||||
['1', '2', '3', '4', '5'].map((value, i) => {
|
||||
return <View children={value} key={i} style={styles.cell} />
|
||||
})
|
||||
}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
row: {
|
||||
flexDirection: 'row'
|
||||
},
|
||||
cell: {
|
||||
flexGrow: 1
|
||||
}
|
||||
})
|
||||
```
|
||||
@@ -36,7 +36,7 @@ const babelLoaderConfiguration = {
|
||||
cacheDirectory: true,
|
||||
// This aliases 'react-native' to 'react-native-web' and includes only
|
||||
// the modules needed by the app
|
||||
plugins: ['react-native-web/babel']
|
||||
plugins: ['react-native-web/babel'],
|
||||
// The 'react-native' preset is recommended (or use your own .babelrc)
|
||||
presets: ['react-native']
|
||||
}
|
||||
@@ -127,6 +127,7 @@ import AppHeader from './src/AppHeader';
|
||||
import React from 'react';
|
||||
import ReactNative from 'react-native';
|
||||
|
||||
// use .hydrate if hydrating a SSR app
|
||||
ReactNative.render(<AppHeader />, document.getElementById('react-app-header'))
|
||||
```
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ const DimensionsScreen = () => (
|
||||
/>
|
||||
|
||||
<DocItem
|
||||
name="static addEventLitener"
|
||||
name="static addEventListener"
|
||||
typeInfo="(type: string, handler: function) => void"
|
||||
description={[
|
||||
<AppText>Add an event handler. Supported events:</AppText>,
|
||||
@@ -65,7 +65,7 @@ const DimensionsScreen = () => (
|
||||
/>
|
||||
|
||||
<DocItem
|
||||
name="static removeEventLitener"
|
||||
name="static removeEventListener"
|
||||
typeInfo="(type: string, handler: function) => void"
|
||||
description="Remove an event handler."
|
||||
/>
|
||||
|
||||
@@ -8,61 +8,94 @@ import UIExplorer, {
|
||||
Code,
|
||||
Description,
|
||||
DocItem,
|
||||
ExternalLink,
|
||||
Section,
|
||||
storiesOf,
|
||||
TextList
|
||||
storiesOf
|
||||
} from '../../ui-explorer';
|
||||
|
||||
const NetInfoScreen = () => (
|
||||
<UIExplorer title="NetInfo" url="2-apis/NetInfo">
|
||||
<Description>
|
||||
<AppText>
|
||||
NetInfo asynchronously determines the online/offline status of the application.
|
||||
NetInfo asynchronously determines the online/offline status and additional connection
|
||||
information (where available) of the application.
|
||||
</AppText>
|
||||
<AppText>
|
||||
Note that support for retrieving the connection type depends upon browswer support (and is
|
||||
limited to mobile browsers). It will default to <Code>unknown</Code> when support is
|
||||
missing.
|
||||
Note that connection type information is limited to how well the browser supports the{' '}
|
||||
<ExternalLink href="https://developer.mozilla.org/en-US/docs/Web/API/NetworkInformation">
|
||||
NetworkInformation API
|
||||
</ExternalLink>. Connection types will be <Code>unknown</Code> when support is missing.
|
||||
</AppText>
|
||||
</Description>
|
||||
|
||||
<Section title="Types">
|
||||
<DocItem
|
||||
description={
|
||||
<AppText>
|
||||
One of <Code>slow-2g</Code>, <Code>2g</Code>, <Code>3g</Code>, <Code>4g</Code>,{' '}
|
||||
<Code>unknown</Code>.
|
||||
</AppText>
|
||||
}
|
||||
name="ConnectionType"
|
||||
/>
|
||||
<DocItem
|
||||
description={
|
||||
<AppText>
|
||||
One of <Code>bluebooth</Code>, <Code>cellular</Code>, <Code>ethernet</Code>,{' '}
|
||||
<Code>mixed</Code>, <Code>mixed</Code>, <Code>none</Code>, <Code>other</Code>,{' '}
|
||||
<Code>unknown</Code>, <Code>wifi</Code>, <Code>wimax</Code>
|
||||
</AppText>
|
||||
}
|
||||
name="EffectiveConnectionType"
|
||||
/>
|
||||
|
||||
<DocItem
|
||||
description={
|
||||
<Code>{`{
|
||||
effectiveType: EffectiveConnectionType;
|
||||
type: ConnectionType;
|
||||
downlink?: number;
|
||||
downlinkMax?: number;
|
||||
rtt?: number;
|
||||
}`}</Code>
|
||||
}
|
||||
name="ConnectionEventType"
|
||||
/>
|
||||
</Section>
|
||||
|
||||
<Section title="Methods">
|
||||
<DocItem
|
||||
description={[
|
||||
description={
|
||||
<AppText>
|
||||
Invokes the listener whenever network status changes. The listener receives one of the
|
||||
following connectivity types (from the DOM connection API):
|
||||
</AppText>,
|
||||
<TextList
|
||||
items={[
|
||||
'bluetooth',
|
||||
'cellular',
|
||||
'ethernet',
|
||||
'mixed',
|
||||
'none',
|
||||
'other',
|
||||
'unknown',
|
||||
'wifi',
|
||||
'wimax'
|
||||
]}
|
||||
/>
|
||||
]}
|
||||
Adds an event handler. The <Code>connectionChange</Code> event fires when the network
|
||||
status changes. The argument to the event handler is an object of type{' '}
|
||||
<Code>ConnectionEventType</Code>.
|
||||
</AppText>
|
||||
}
|
||||
example={{
|
||||
code: "NetInfo.addEventListener('change', (connectionType) => {})"
|
||||
code: `NetInfo.addEventListener('connectionChange', ({ effectiveType, type }) => {
|
||||
console.log('Effective connection type:', effectiveType);
|
||||
console.log('Connection type:', type);
|
||||
})`
|
||||
}}
|
||||
name="static addEventListener"
|
||||
typeInfo="(eventName, handler) => void"
|
||||
/>
|
||||
|
||||
<DocItem
|
||||
description="Returns a promise that resolves with one of the connectivity types listed above."
|
||||
description={
|
||||
<AppText>
|
||||
Returns a promise that resolves with an object of type <Code>ConnectionEventType</Code>.
|
||||
</AppText>
|
||||
}
|
||||
example={{
|
||||
code: `NetInfo.fetch().then((connectionType) => {
|
||||
console.log('Connection type:', connectionType);
|
||||
code: `NetInfo.getConnectionInfo().then(({ effectiveType, type }) => {
|
||||
console.log('Effective connection type:', effectiveType);
|
||||
console.log('Connection type:', type);
|
||||
});`
|
||||
}}
|
||||
name="static fetch"
|
||||
typeInfo="() => Promise<string>"
|
||||
name="static getConnectionInfo"
|
||||
typeInfo="() => Promise<ConnectionEventType>"
|
||||
/>
|
||||
|
||||
<DocItem
|
||||
@@ -76,7 +109,7 @@ const NetInfoScreen = () => (
|
||||
<DocItem
|
||||
description="An object with the same methods as above but the listener receives a boolean which represents the internet connectivity. Use this if you are only interested with whether the device has internet connectivity."
|
||||
example={{
|
||||
code: `NetInfo.isConnected.fetch().then((isConnected) => {
|
||||
code: `NetInfo.isConnected.getConnectionInfo().then((isConnected) => {
|
||||
console.log('Connection status:', (isConnected ? 'online' : 'offline'));
|
||||
});`
|
||||
}}
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
* @providesModule Game2048
|
||||
* @flow
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
import { any, func, object } from 'prop-types';
|
||||
import GameBoard from './GameBoard';
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
* @providesModule GameBoard
|
||||
* @flow
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
// NB: Taken straight from: https://github.com/IvanVergiliev/2048-react/blob/master/src/board.js
|
||||
// with no modification except to format it for CommonJS and fix lint/flow errors
|
||||
|
||||
@@ -4,16 +4,27 @@
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import { bool } from 'prop-types';
|
||||
import React from 'react';
|
||||
import { StyleSheet, Text } from 'react-native';
|
||||
|
||||
const AppText = ({ style, ...rest }) => (
|
||||
<Text
|
||||
{...rest}
|
||||
accessibilityRole={rest.href ? 'link' : undefined}
|
||||
style={[styles.baseText, style, rest.href && styles.link]}
|
||||
/>
|
||||
);
|
||||
class AppText extends React.PureComponent {
|
||||
static contextTypes = {
|
||||
isInAParentText: bool
|
||||
};
|
||||
|
||||
render() {
|
||||
const { style, ...rest } = this.props;
|
||||
const isInAParentText = this.context;
|
||||
return (
|
||||
<Text
|
||||
{...rest}
|
||||
accessibilityRole={rest.href ? 'link' : undefined}
|
||||
style={[!isInAParentText && styles.baseText, style, rest.href && styles.link]}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default AppText;
|
||||
|
||||
|
||||
4
jest-setup-framework.js
Normal file
4
jest-setup-framework.js
Normal file
@@ -0,0 +1,4 @@
|
||||
import Enzyme from 'enzyme';
|
||||
import Adapter from 'enzyme-adapter-react-16';
|
||||
|
||||
Enzyme.configure({ adapter: new Adapter() });
|
||||
52
package.json
52
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "react-native-web",
|
||||
"version": "0.0.124",
|
||||
"version": "0.1.9",
|
||||
"description": "React Native for Web",
|
||||
"main": "dist/index.js",
|
||||
"files": [
|
||||
@@ -11,7 +11,7 @@
|
||||
],
|
||||
"scripts": {
|
||||
"benchmark": "cd benchmarks && yarn && webpack && open index.html",
|
||||
"build": "webpack --config webpack.config.js --sort-assets-by --progress",
|
||||
"build": "yarn compile && webpack --config webpack.config.js --sort-assets-by --progress",
|
||||
"clean-dist": "del ./dist && mkdir dist",
|
||||
"compile": "babel src -d dist --ignore *-test.js",
|
||||
"docs:build": "cd docs && yarn build",
|
||||
@@ -25,7 +25,7 @@
|
||||
"lint": "yarn lint:cmd -- babel benchmarks docs src",
|
||||
"lint:cmd": "eslint --ignore-path .gitignore --fix",
|
||||
"precommit": "lint-staged",
|
||||
"release": "yarn clean-dist && yarn lint && yarn test && yarn compile && yarn build && npm publish",
|
||||
"release": "yarn clean-dist && yarn lint && yarn test && yarn build && npm publish",
|
||||
"test": "flow && jest"
|
||||
},
|
||||
"babel": {
|
||||
@@ -44,8 +44,12 @@
|
||||
"jest": {
|
||||
"testEnvironment": "jsdom",
|
||||
"timers": "fake",
|
||||
"setupFiles": [
|
||||
"raf/polyfill"
|
||||
],
|
||||
"setupTestFrameworkScriptFile": "<rootDir>/jest-setup-framework.js",
|
||||
"snapshotSerializers": [
|
||||
"<rootDir>/node_modules/enzyme-to-json/serializer"
|
||||
"enzyme-to-json/serializer"
|
||||
]
|
||||
},
|
||||
"lint-staged": {
|
||||
@@ -59,14 +63,14 @@
|
||||
"animated": "^0.2.0",
|
||||
"array-find-index": "^1.0.2",
|
||||
"babel-runtime": "^6.26.0",
|
||||
"create-react-class": "^15.6.0",
|
||||
"create-react-class": "^15.6.2",
|
||||
"debounce": "1.0.2",
|
||||
"deep-assign": "^2.0.0",
|
||||
"fbjs": "^0.8.14",
|
||||
"fbjs": "^0.8.16",
|
||||
"hyphenate-style-name": "^1.0.2",
|
||||
"inline-style-prefixer": "^3.0.7",
|
||||
"inline-style-prefixer": "^3.0.8",
|
||||
"normalize-css-color": "^1.0.2",
|
||||
"prop-types": "^15.5.10",
|
||||
"prop-types": "^15.6.0",
|
||||
"react-timer-mixin": "^0.13.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -75,31 +79,33 @@
|
||||
"babel-eslint": "^7.2.3",
|
||||
"babel-loader": "^7.1.2",
|
||||
"babel-plugin-tester": "^4.0.0",
|
||||
"babel-plugin-transform-react-remove-prop-types": "^0.4.8",
|
||||
"babel-preset-react-native": "^3.0.2",
|
||||
"babel-plugin-transform-react-remove-prop-types": "^0.4.9",
|
||||
"babel-preset-react-native": "^4.0.0",
|
||||
"caniuse-api": "^2.0.0",
|
||||
"del-cli": "^1.1.0",
|
||||
"enzyme": "^2.9.1",
|
||||
"enzyme-to-json": "^1.5.1",
|
||||
"enzyme": "^3.0.0",
|
||||
"enzyme-adapter-react-16": "^1.0.0",
|
||||
"enzyme-to-json": "^3.0.1",
|
||||
"eslint": "^4.6.1",
|
||||
"eslint-config-prettier": "^2.4.0",
|
||||
"eslint-config-prettier": "^2.6.0",
|
||||
"eslint-plugin-promise": "^3.5.0",
|
||||
"eslint-plugin-react": "^7.3.0",
|
||||
"file-loader": "^0.11.2",
|
||||
"eslint-plugin-react": "^7.4.0",
|
||||
"file-loader": "^1.1.4",
|
||||
"flow-bin": "^0.49.1",
|
||||
"jest": "^21.0.2",
|
||||
"jest": "^21.2.1",
|
||||
"lint-staged": "^4.1.3",
|
||||
"prettier": "^1.6.1",
|
||||
"react": "^15.6.1",
|
||||
"react-dom": "^15.6.1",
|
||||
"react-test-renderer": "^15.6.1",
|
||||
"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.5.6",
|
||||
"webpack": "^3.6.0",
|
||||
"webpack-bundle-analyzer": "^2.9.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "15.4.x || 15.5.x || 15.6.x",
|
||||
"react-dom": "15.4.x || 15.5.x || 15.6.x"
|
||||
"react": "16.x.x",
|
||||
"react-dom": "16.x.x"
|
||||
},
|
||||
"author": "Nicolas Gallagher",
|
||||
"license": "BSD-3-Clause",
|
||||
|
||||
@@ -7,7 +7,7 @@ const browserList = {
|
||||
firefox: 40,
|
||||
ios_saf: 7,
|
||||
safari: 7,
|
||||
ie: 11,
|
||||
ie: 10,
|
||||
ie_mob: 11,
|
||||
edge: 12,
|
||||
opera: 16,
|
||||
|
||||
@@ -38,7 +38,7 @@ exports[`apis/AppRegistry/renderApplication getApplication 3`] = `
|
||||
.rn-textAlign-1ttztb7{text-align:inherit}
|
||||
.rn-textDecoration-bauka4{text-decoration:none}
|
||||
.rn-listStyle-1ebb2ja{list-style:none}
|
||||
.rn-alignItems-1oszu61{-webkit-align-items:stretch;-webkit-box-align:stretch;align-items:stretch}
|
||||
.rn-alignItems-1oszu61{-ms-flex-align:stretch;-webkit-align-items:stretch;-webkit-box-align:stretch;align-items:stretch}
|
||||
.rn-borderTopStyle-1efd50x{border-top-style:solid}
|
||||
.rn-borderRightStyle-14skgim{border-right-style:solid}
|
||||
.rn-borderBottomStyle-rull8r{border-bottom-style:solid}
|
||||
@@ -50,11 +50,10 @@ exports[`apis/AppRegistry/renderApplication getApplication 3`] = `
|
||||
.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}
|
||||
.rn-flexShrink-1qe8dj5{-webkit-flex-shrink:0;flex-shrink:0}
|
||||
.rn-flexShrink-1wbh5a2{-webkit-flex-shrink:1;flex-shrink:1}
|
||||
.rn-flexBasis-1mlwlqe{-webkit-flex-basis:auto;flex-basis:auto}
|
||||
.rn-flexBasis-1ro0kt6{-webkit-flex-basis:0%;flex-basis:0%}
|
||||
.rn-flexDirection-eqz5dr{-webkit-box-direction:normal;-webkit-box-orient:vertical;-webkit-flex-direction:column;flex-direction:column}
|
||||
.rn-flexShrink-1pxmb3b{-ms-flex-negative:0 !important;-webkit-flex-shrink:0 !important;flex-shrink:0 !important}
|
||||
.rn-flexShrink-1awmn5t{-ms-flex-negative:1 !important;-webkit-flex-shrink:1 !important;flex-shrink:1 !important}
|
||||
.rn-flexBasis-7vfszb{-ms-flex-preferred-size:auto !important;-webkit-flex-basis:auto !important;flex-basis:auto !important}
|
||||
.rn-flexDirection-eqz5dr{-ms-flex-direction:column;-webkit-box-direction:normal;-webkit-box-orient:vertical;-webkit-flex-direction:column;flex-direction:column}
|
||||
.rn-marginTop-1mnahxq{margin-top:0px}
|
||||
.rn-marginRight-61z16t{margin-right:0px}
|
||||
.rn-marginBottom-p1pxzi{margin-bottom:0px}
|
||||
@@ -67,5 +66,6 @@ exports[`apis/AppRegistry/renderApplication getApplication 3`] = `
|
||||
.rn-paddingLeft-gy4na3{padding-left:0px}
|
||||
.rn-zIndex-1lgpqti{z-index:0}
|
||||
.rn-zIndex-1wyyakw{z-index:-1}
|
||||
.rn-flexGrow-16y2uox{-webkit-flex-grow:1;flex-grow:1}</style>"
|
||||
.rn-flex-13awgt0{-ms-flex:1;-webkit-flex:1;flex:1}
|
||||
.rn-flexGrow-1m1wadx{-ms-flex-positive:1 !important;-webkit-flex-grow:1 !important;flex-grow:1 !important}</style>"
|
||||
`;
|
||||
|
||||
@@ -61,6 +61,11 @@ export default class AsyncStorage {
|
||||
}, callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* (stub) Flushes any pending requests using a single batch call to get the data.
|
||||
*/
|
||||
static flushGetRequests() {}
|
||||
|
||||
/**
|
||||
* Gets *all* keys known to the app, for all callers, libraries, etc.
|
||||
*/
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
function emptyFunction() {}
|
||||
|
||||
const BackAndroid = {
|
||||
const BackHandler = {
|
||||
exitApp: emptyFunction,
|
||||
addEventListener() {
|
||||
return {
|
||||
@@ -22,4 +22,4 @@ const BackAndroid = {
|
||||
removeEventListener: emptyFunction
|
||||
};
|
||||
|
||||
export default BackAndroid;
|
||||
export default BackHandler;
|
||||
13
src/apis/Easing/index.js
Normal file
13
src/apis/Easing/index.js
Normal file
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* 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 Easing
|
||||
* @noflow
|
||||
*/
|
||||
|
||||
import Easing from 'animated/lib/Easing';
|
||||
export default Easing;
|
||||
@@ -13,7 +13,9 @@
|
||||
import dismissKeyboard from '../../modules/dismissKeyboard';
|
||||
|
||||
const Keyboard = {
|
||||
addListener() {},
|
||||
addListener() {
|
||||
return { remove: () => {} };
|
||||
},
|
||||
dismiss() {
|
||||
dismissKeyboard();
|
||||
},
|
||||
|
||||
@@ -3,31 +3,44 @@
|
||||
import NetInfo from '..';
|
||||
|
||||
describe('apis/NetInfo', () => {
|
||||
describe('getConnectionInfo', () => {
|
||||
test('fills out basic fields', done => {
|
||||
NetInfo.getConnectionInfo().then(result => {
|
||||
expect(result.effectiveType).toBeDefined();
|
||||
expect(result.type).toBeDefined();
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('isConnected', () => {
|
||||
const handler = () => {};
|
||||
|
||||
afterEach(() => {
|
||||
try {
|
||||
NetInfo.isConnected.removeEventListener('change', handler);
|
||||
NetInfo.isConnected.removeEventListener('connectionChange', handler);
|
||||
} catch (e) {}
|
||||
});
|
||||
|
||||
describe('addEventListener', () => {
|
||||
test('throws if the provided "eventType" is not supported', () => {
|
||||
expect(() => NetInfo.isConnected.addEventListener('foo', handler)).toThrow();
|
||||
expect(() => NetInfo.isConnected.addEventListener('change', handler)).not.toThrow();
|
||||
expect(() =>
|
||||
NetInfo.isConnected.addEventListener('connectionChange', handler)
|
||||
).not.toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
describe('removeEventListener', () => {
|
||||
test('throws if the handler is not registered', () => {
|
||||
expect(() => NetInfo.isConnected.removeEventListener('change', handler)).toThrow;
|
||||
expect(() => NetInfo.isConnected.removeEventListener('connectionChange', handler)).toThrow;
|
||||
});
|
||||
|
||||
test('throws if the provided "eventType" is not supported', () => {
|
||||
NetInfo.isConnected.addEventListener('change', handler);
|
||||
NetInfo.isConnected.addEventListener('connectionChange', handler);
|
||||
expect(() => NetInfo.isConnected.removeEventListener('foo', handler)).toThrow;
|
||||
expect(() => NetInfo.isConnected.removeEventListener('change', handler)).not.toThrow;
|
||||
expect(() => NetInfo.isConnected.removeEventListener('connectionChange', handler)).not
|
||||
.toThrow;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -20,7 +20,27 @@ const connection =
|
||||
window.navigator.mozConnection ||
|
||||
window.navigator.webkitConnection);
|
||||
|
||||
const eventTypes = ['change'];
|
||||
// Prevent the underlying event handlers from leaking and include additional
|
||||
// properties available in browsers
|
||||
const getConnectionInfoObject = () => {
|
||||
const result = {};
|
||||
if (!connection) {
|
||||
return result;
|
||||
}
|
||||
for (const prop in connection) {
|
||||
if (typeof connection[prop] !== 'function') {
|
||||
result[prop] = connection[prop];
|
||||
}
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
// Map React Native events to browser equivalents
|
||||
const eventTypesMap = {
|
||||
change: 'change',
|
||||
connectionChange: 'change'
|
||||
};
|
||||
const eventTypes = Object.keys(eventTypesMap);
|
||||
|
||||
const connectionListeners = [];
|
||||
|
||||
@@ -31,6 +51,9 @@ const connectionListeners = [];
|
||||
const NetInfo = {
|
||||
addEventListener(type: string, handler: Function): { remove: () => void } {
|
||||
invariant(eventTypes.indexOf(type) !== -1, 'Trying to subscribe to unknown event: "%s"', type);
|
||||
if (type === 'change') {
|
||||
console.warn('Listening to event `change` is deprecated. Use `connectionChange` instead.');
|
||||
}
|
||||
if (!connection) {
|
||||
console.error(
|
||||
'Network Connection API is not supported. Not listening for connection type changes.'
|
||||
@@ -40,21 +63,25 @@ const NetInfo = {
|
||||
};
|
||||
}
|
||||
|
||||
connection.addEventListener(type, handler);
|
||||
connection.addEventListener(eventTypesMap[type], handler);
|
||||
return {
|
||||
remove: () => NetInfo.removeEventListener(type, handler)
|
||||
remove: () => NetInfo.removeEventListener(eventTypesMap[type], handler)
|
||||
};
|
||||
},
|
||||
|
||||
removeEventListener(type: string, handler: Function): void {
|
||||
invariant(eventTypes.indexOf(type) !== -1, 'Trying to subscribe to unknown event: "%s"', type);
|
||||
if (type === 'change') {
|
||||
console.warn('Listening to event `change` is deprecated. Use `connectionChange` instead.');
|
||||
}
|
||||
if (!connection) {
|
||||
return;
|
||||
}
|
||||
connection.removeEventListener(type, handler);
|
||||
connection.removeEventListener(eventTypesMap[type], handler);
|
||||
},
|
||||
|
||||
fetch(): Promise<any> {
|
||||
console.warn('`fetch` is deprecated. Use `getConnectionInfo` instead.');
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
resolve(connection.type);
|
||||
@@ -64,6 +91,16 @@ const NetInfo = {
|
||||
});
|
||||
},
|
||||
|
||||
getConnectionInfo(): Promise<Object> {
|
||||
return new Promise((resolve, reject) => {
|
||||
resolve({
|
||||
effectiveType: 'unknown',
|
||||
type: 'unknown',
|
||||
...getConnectionInfoObject()
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
isConnected: {
|
||||
addEventListener(type: string, handler: Function): { remove: () => void } {
|
||||
invariant(
|
||||
@@ -71,6 +108,10 @@ const NetInfo = {
|
||||
'Trying to subscribe to unknown event: "%s"',
|
||||
type
|
||||
);
|
||||
if (type === 'change') {
|
||||
console.warn('Listening to event `change` is deprecated. Use `connectionChange` instead.');
|
||||
}
|
||||
|
||||
const onlineCallback = () => handler(true);
|
||||
const offlineCallback = () => handler(false);
|
||||
connectionListeners.push([handler, onlineCallback, offlineCallback]);
|
||||
@@ -79,7 +120,7 @@ const NetInfo = {
|
||||
window.addEventListener('offline', offlineCallback, false);
|
||||
|
||||
return {
|
||||
remove: () => NetInfo.isConnected.removeEventListener(type, handler)
|
||||
remove: () => NetInfo.isConnected.removeEventListener(eventTypesMap[type], handler)
|
||||
};
|
||||
},
|
||||
|
||||
@@ -89,6 +130,9 @@ const NetInfo = {
|
||||
'Trying to subscribe to unknown event: "%s"',
|
||||
type
|
||||
);
|
||||
if (type === 'change') {
|
||||
console.warn('Listening to event `change` is deprecated. Use `connectionChange` instead.');
|
||||
}
|
||||
|
||||
const listenerIndex = findIndex(connectionListeners, pair => pair[0] === handler);
|
||||
invariant(
|
||||
@@ -103,7 +147,12 @@ const NetInfo = {
|
||||
connectionListeners.splice(listenerIndex, 1);
|
||||
},
|
||||
|
||||
fetch(): Promise<any> {
|
||||
fetch(): Promise<boolean> {
|
||||
console.warn('`fetch` is deprecated. Use `getConnectionInfo` instead.');
|
||||
return NetInfo.isConnected.getConnectionInfo();
|
||||
},
|
||||
|
||||
getConnectionInfo(): Promise<boolean> {
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
resolve(window.navigator.onLine);
|
||||
|
||||
@@ -91,6 +91,7 @@ StyleSheetValidation.addValidStylePropTypes({
|
||||
borderSpacing: oneOf([number, string]),
|
||||
clear: string,
|
||||
cursor: string,
|
||||
fill: string,
|
||||
float: oneOf(['left', 'none', 'right']),
|
||||
font: string /* @private */,
|
||||
listStyle: string,
|
||||
|
||||
@@ -26,44 +26,44 @@ describe('apis/StyleSheet/createReactDOMStyle', () => {
|
||||
test('flex defaults', () => {
|
||||
expect(createReactDOMStyle({ display: 'flex' })).toEqual({
|
||||
display: 'flex',
|
||||
flexShrink: 0,
|
||||
flexBasis: 'auto'
|
||||
flexShrink: '0 !important',
|
||||
flexBasis: 'auto !important'
|
||||
});
|
||||
});
|
||||
|
||||
test('flex: -1', () => {
|
||||
expect(createReactDOMStyle({ display: 'flex', flex: -1 })).toEqual({
|
||||
display: 'flex',
|
||||
flexGrow: 0,
|
||||
flexShrink: 1,
|
||||
flexBasis: 'auto'
|
||||
flexGrow: '0 !important',
|
||||
flexShrink: '1 !important',
|
||||
flexBasis: 'auto !important'
|
||||
});
|
||||
});
|
||||
|
||||
test('flex: 0', () => {
|
||||
expect(createReactDOMStyle({ display: 'flex', flex: 0 })).toEqual({
|
||||
display: 'flex',
|
||||
flexGrow: 0,
|
||||
flexShrink: 0,
|
||||
flexBasis: 'auto'
|
||||
flexGrow: '0 !important',
|
||||
flexShrink: '0 !important',
|
||||
flexBasis: 'auto !important'
|
||||
});
|
||||
});
|
||||
|
||||
test('flex: 1', () => {
|
||||
expect(createReactDOMStyle({ display: 'flex', flex: 1 })).toEqual({
|
||||
display: 'flex',
|
||||
flexGrow: 1,
|
||||
flexShrink: 1,
|
||||
flexBasis: '0%'
|
||||
flex: 1,
|
||||
flexGrow: '1 !important',
|
||||
flexShrink: '1 !important'
|
||||
});
|
||||
});
|
||||
|
||||
test('flex: 10', () => {
|
||||
expect(createReactDOMStyle({ display: 'flex', flex: 10 })).toEqual({
|
||||
display: 'flex',
|
||||
flexGrow: 10,
|
||||
flexShrink: 1,
|
||||
flexBasis: '0%'
|
||||
flex: 10,
|
||||
flexGrow: '10 !important',
|
||||
flexShrink: '1 !important'
|
||||
});
|
||||
});
|
||||
|
||||
@@ -71,16 +71,17 @@ describe('apis/StyleSheet/createReactDOMStyle', () => {
|
||||
// is flex-basis applied?
|
||||
expect(createReactDOMStyle({ display: 'flex', flexBasis: '25%' })).toEqual({
|
||||
display: 'flex',
|
||||
flexShrink: 0,
|
||||
flexBasis: '25%'
|
||||
flexShrink: '0 !important',
|
||||
flexBasis: '25% !important'
|
||||
});
|
||||
|
||||
// can flex-basis override the 'flex' expansion?
|
||||
expect(createReactDOMStyle({ display: 'flex', flex: 1, flexBasis: '25%' })).toEqual({
|
||||
display: 'flex',
|
||||
flexGrow: 1,
|
||||
flexShrink: 1,
|
||||
flexBasis: '25%'
|
||||
flex: 1,
|
||||
flexGrow: '1 !important',
|
||||
flexShrink: '1 !important',
|
||||
flexBasis: '25% !important'
|
||||
});
|
||||
});
|
||||
|
||||
@@ -88,16 +89,16 @@ describe('apis/StyleSheet/createReactDOMStyle', () => {
|
||||
// is flex-shrink applied?
|
||||
expect(createReactDOMStyle({ display: 'flex', flexShrink: 1 })).toEqual({
|
||||
display: 'flex',
|
||||
flexShrink: 1,
|
||||
flexBasis: 'auto'
|
||||
flexShrink: '1 !important',
|
||||
flexBasis: 'auto !important'
|
||||
});
|
||||
|
||||
// can flex-shrink override the 'flex' expansion?
|
||||
expect(createReactDOMStyle({ display: 'flex', flex: 1, flexShrink: 2 })).toEqual({
|
||||
display: 'flex',
|
||||
flexGrow: 1,
|
||||
flexShrink: 2,
|
||||
flexBasis: '0%'
|
||||
flex: 1,
|
||||
flexGrow: '1 !important',
|
||||
flexShrink: '2 !important'
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -158,29 +158,56 @@ const createReducer = (style, styleProps) => {
|
||||
|
||||
case 'display': {
|
||||
resolvedStyle.display = value;
|
||||
// defaults of 'flexBasis:auto' and 'flexShrink:0' have lowest precedence
|
||||
if (style.display === 'flex') {
|
||||
// A flex container in React Native has these defaults which should be
|
||||
// set only if there is no otherwise supplied flex style.
|
||||
if (style.display === 'flex' && style.flex == null) {
|
||||
if (style.flexShrink == null) {
|
||||
resolvedStyle.flexShrink = 0;
|
||||
resolvedStyle.flexShrink = '0 !important';
|
||||
}
|
||||
if (style.flexBasis == null) {
|
||||
resolvedStyle.flexBasis = 'auto';
|
||||
resolvedStyle.flexBasis = 'auto !important';
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// The 'flex' property value in React Native must be a positive integer,
|
||||
// 0, or -1.
|
||||
//
|
||||
// On the web, a positive integer value for 'flex' is complicated by
|
||||
// browser differences. Although browsers render styles like 'flex:2'
|
||||
// consistently, they don't all set the same value for the resulting
|
||||
// 'flexBasis' (See #616). Expanding 'flex' in 'StyleSheet' would mean
|
||||
// setting different values for different browsers.
|
||||
//
|
||||
// This fix instead relies on the browser expanding 'flex' itself. And
|
||||
// because the 'flex' style is not being expanded the generated CSS is
|
||||
// likely to contain source order "conflicts". To avoid the browser
|
||||
// relying on source order to resolve the styles, all the longhand flex
|
||||
// property values must use '!important'.
|
||||
case 'flex': {
|
||||
if (value > 0) {
|
||||
resolvedStyle.flexGrow = value;
|
||||
resolvedStyle.flexShrink = 1;
|
||||
resolvedStyle.flexBasis = '0%';
|
||||
resolvedStyle.flex = value;
|
||||
resolvedStyle.flexGrow = `${value} !important`;
|
||||
resolvedStyle.flexShrink = '1 !important';
|
||||
} else if (value === 0) {
|
||||
resolvedStyle.flexGrow = 0;
|
||||
resolvedStyle.flexShrink = 0;
|
||||
resolvedStyle.flexGrow = '0 !important';
|
||||
resolvedStyle.flexShrink = '0 !important';
|
||||
resolvedStyle.flexBasis = 'auto !important';
|
||||
} else if (value === -1) {
|
||||
resolvedStyle.flexGrow = 0;
|
||||
resolvedStyle.flexShrink = 1;
|
||||
resolvedStyle.flexGrow = '0 !important';
|
||||
resolvedStyle.flexShrink = '1 !important';
|
||||
resolvedStyle.flexBasis = 'auto !important';
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 'flexGrow':
|
||||
case 'flexShrink':
|
||||
case 'flexBasis': {
|
||||
if (value != null) {
|
||||
const hasImportant = `${value}`.indexOf('!important') > -1;
|
||||
resolvedStyle[prop] = hasImportant ? value : `${value} !important`;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1,18 +1,30 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`components/ActivityIndicator prop "animating" is "false" 1`] = `
|
||||
<div
|
||||
<View
|
||||
accessibilityRole="progressbar"
|
||||
aria-valuemax="1"
|
||||
aria-valuemin="0"
|
||||
class="rn-alignItems-1awozwy rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1qe8dj5 rn-flexBasis-1mlwlqe rn-flexDirection-eqz5dr rn-justifyContent-1777fci rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-position-bnwqim"
|
||||
role="progressbar"
|
||||
style={
|
||||
Array [
|
||||
15,
|
||||
undefined,
|
||||
]
|
||||
}
|
||||
>
|
||||
<div
|
||||
class="rn-alignItems-1oszu61 rn-animationDuration-17bb2tj rn-animationIterationCount-1muvv40 rn-animationName-dozj4v rn-animationPlayState-1abnn5w rn-animationTimingFunction-1ldzwu0 rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1qe8dj5 rn-flexBasis-1mlwlqe rn-flexDirection-eqz5dr rn-height-z80fyv rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-position-bnwqim rn-visibility-11j9u27 rn-width-19wmn03"
|
||||
<View
|
||||
style={
|
||||
Array [
|
||||
19,
|
||||
17,
|
||||
18,
|
||||
16,
|
||||
]
|
||||
}
|
||||
>
|
||||
<svg
|
||||
height="100%"
|
||||
viewbox="0 0 32 32"
|
||||
viewBox="0 0 32 32"
|
||||
width="100%"
|
||||
>
|
||||
<circle
|
||||
@@ -20,35 +32,58 @@ exports[`components/ActivityIndicator prop "animating" is "false" 1`] = `
|
||||
cy="16"
|
||||
fill="none"
|
||||
r="14"
|
||||
stroke-width="4"
|
||||
style="stroke:#1976D2;opacity:0.2;"
|
||||
strokeWidth="4"
|
||||
style={
|
||||
Object {
|
||||
"opacity": 0.2,
|
||||
"stroke": "#1976D2",
|
||||
}
|
||||
}
|
||||
/>
|
||||
<circle
|
||||
cx="16"
|
||||
cy="16"
|
||||
fill="none"
|
||||
r="14"
|
||||
stroke-width="4"
|
||||
style="stroke:#1976D2;stroke-dasharray:80;stroke-dashoffset:60;"
|
||||
strokeWidth="4"
|
||||
style={
|
||||
Object {
|
||||
"stroke": "#1976D2",
|
||||
"strokeDasharray": 80,
|
||||
"strokeDashoffset": 60,
|
||||
}
|
||||
}
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
</View>
|
||||
</View>
|
||||
`;
|
||||
|
||||
exports[`components/ActivityIndicator prop "animating" is "true" 1`] = `
|
||||
<div
|
||||
<View
|
||||
accessibilityRole="progressbar"
|
||||
aria-valuemax="1"
|
||||
aria-valuemin="0"
|
||||
class="rn-alignItems-1awozwy rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1qe8dj5 rn-flexBasis-1mlwlqe rn-flexDirection-eqz5dr rn-justifyContent-1777fci rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-position-bnwqim"
|
||||
role="progressbar"
|
||||
style={
|
||||
Array [
|
||||
15,
|
||||
undefined,
|
||||
]
|
||||
}
|
||||
>
|
||||
<div
|
||||
class="rn-alignItems-1oszu61 rn-animationDuration-17bb2tj rn-animationIterationCount-1muvv40 rn-animationName-dozj4v rn-animationTimingFunction-1ldzwu0 rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1qe8dj5 rn-flexBasis-1mlwlqe rn-flexDirection-eqz5dr rn-height-z80fyv rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-position-bnwqim rn-width-19wmn03"
|
||||
<View
|
||||
style={
|
||||
Array [
|
||||
19,
|
||||
17,
|
||||
false,
|
||||
false,
|
||||
]
|
||||
}
|
||||
>
|
||||
<svg
|
||||
height="100%"
|
||||
viewbox="0 0 32 32"
|
||||
viewBox="0 0 32 32"
|
||||
width="100%"
|
||||
>
|
||||
<circle
|
||||
@@ -56,71 +91,94 @@ exports[`components/ActivityIndicator prop "animating" is "true" 1`] = `
|
||||
cy="16"
|
||||
fill="none"
|
||||
r="14"
|
||||
stroke-width="4"
|
||||
style="stroke:#1976D2;opacity:0.2;"
|
||||
strokeWidth="4"
|
||||
style={
|
||||
Object {
|
||||
"opacity": 0.2,
|
||||
"stroke": "#1976D2",
|
||||
}
|
||||
}
|
||||
/>
|
||||
<circle
|
||||
cx="16"
|
||||
cy="16"
|
||||
fill="none"
|
||||
r="14"
|
||||
stroke-width="4"
|
||||
style="stroke:#1976D2;stroke-dasharray:80;stroke-dashoffset:60;"
|
||||
strokeWidth="4"
|
||||
style={
|
||||
Object {
|
||||
"stroke": "#1976D2",
|
||||
"strokeDasharray": 80,
|
||||
"strokeDashoffset": 60,
|
||||
}
|
||||
}
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
</View>
|
||||
</View>
|
||||
`;
|
||||
|
||||
exports[`components/ActivityIndicator prop "color" 1`] = `
|
||||
<div
|
||||
aria-valuemax="1"
|
||||
aria-valuemin="0"
|
||||
class="rn-alignItems-1awozwy rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1qe8dj5 rn-flexBasis-1mlwlqe rn-flexDirection-eqz5dr rn-justifyContent-1777fci rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-position-bnwqim"
|
||||
role="progressbar"
|
||||
<svg
|
||||
height="100%"
|
||||
viewBox="0 0 32 32"
|
||||
width="100%"
|
||||
>
|
||||
<div
|
||||
class="rn-alignItems-1oszu61 rn-animationDuration-17bb2tj rn-animationIterationCount-1muvv40 rn-animationName-dozj4v rn-animationTimingFunction-1ldzwu0 rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1qe8dj5 rn-flexBasis-1mlwlqe rn-flexDirection-eqz5dr rn-height-z80fyv rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-position-bnwqim rn-width-19wmn03"
|
||||
>
|
||||
<svg
|
||||
height="100%"
|
||||
viewbox="0 0 32 32"
|
||||
width="100%"
|
||||
>
|
||||
<circle
|
||||
cx="16"
|
||||
cy="16"
|
||||
fill="none"
|
||||
r="14"
|
||||
stroke-width="4"
|
||||
style="stroke:red;opacity:0.2;"
|
||||
/>
|
||||
<circle
|
||||
cx="16"
|
||||
cy="16"
|
||||
fill="none"
|
||||
r="14"
|
||||
stroke-width="4"
|
||||
style="stroke:red;stroke-dasharray:80;stroke-dashoffset:60;"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<circle
|
||||
cx="16"
|
||||
cy="16"
|
||||
fill="none"
|
||||
r="14"
|
||||
strokeWidth="4"
|
||||
style={
|
||||
Object {
|
||||
"opacity": 0.2,
|
||||
"stroke": "red",
|
||||
}
|
||||
}
|
||||
/>
|
||||
<circle
|
||||
cx="16"
|
||||
cy="16"
|
||||
fill="none"
|
||||
r="14"
|
||||
strokeWidth="4"
|
||||
style={
|
||||
Object {
|
||||
"stroke": "red",
|
||||
"strokeDasharray": 80,
|
||||
"strokeDashoffset": 60,
|
||||
}
|
||||
}
|
||||
/>
|
||||
</svg>
|
||||
`;
|
||||
|
||||
exports[`components/ActivityIndicator prop "hidesWhenStopped" is "false" 1`] = `
|
||||
<div
|
||||
<View
|
||||
accessibilityRole="progressbar"
|
||||
aria-valuemax="1"
|
||||
aria-valuemin="0"
|
||||
class="rn-alignItems-1awozwy rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1qe8dj5 rn-flexBasis-1mlwlqe rn-flexDirection-eqz5dr rn-justifyContent-1777fci rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-position-bnwqim"
|
||||
role="progressbar"
|
||||
style={
|
||||
Array [
|
||||
15,
|
||||
undefined,
|
||||
]
|
||||
}
|
||||
>
|
||||
<div
|
||||
class="rn-alignItems-1oszu61 rn-animationDuration-17bb2tj rn-animationIterationCount-1muvv40 rn-animationName-dozj4v rn-animationPlayState-1abnn5w rn-animationTimingFunction-1ldzwu0 rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1qe8dj5 rn-flexBasis-1mlwlqe rn-flexDirection-eqz5dr rn-height-z80fyv rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-position-bnwqim rn-width-19wmn03"
|
||||
<View
|
||||
style={
|
||||
Array [
|
||||
19,
|
||||
17,
|
||||
18,
|
||||
false,
|
||||
]
|
||||
}
|
||||
>
|
||||
<svg
|
||||
height="100%"
|
||||
viewbox="0 0 32 32"
|
||||
viewBox="0 0 32 32"
|
||||
width="100%"
|
||||
>
|
||||
<circle
|
||||
@@ -128,35 +186,58 @@ exports[`components/ActivityIndicator prop "hidesWhenStopped" is "false" 1`] = `
|
||||
cy="16"
|
||||
fill="none"
|
||||
r="14"
|
||||
stroke-width="4"
|
||||
style="stroke:#1976D2;opacity:0.2;"
|
||||
strokeWidth="4"
|
||||
style={
|
||||
Object {
|
||||
"opacity": 0.2,
|
||||
"stroke": "#1976D2",
|
||||
}
|
||||
}
|
||||
/>
|
||||
<circle
|
||||
cx="16"
|
||||
cy="16"
|
||||
fill="none"
|
||||
r="14"
|
||||
stroke-width="4"
|
||||
style="stroke:#1976D2;stroke-dasharray:80;stroke-dashoffset:60;"
|
||||
strokeWidth="4"
|
||||
style={
|
||||
Object {
|
||||
"stroke": "#1976D2",
|
||||
"strokeDasharray": 80,
|
||||
"strokeDashoffset": 60,
|
||||
}
|
||||
}
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
</View>
|
||||
</View>
|
||||
`;
|
||||
|
||||
exports[`components/ActivityIndicator prop "hidesWhenStopped" is "true" 1`] = `
|
||||
<div
|
||||
<View
|
||||
accessibilityRole="progressbar"
|
||||
aria-valuemax="1"
|
||||
aria-valuemin="0"
|
||||
class="rn-alignItems-1awozwy rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1qe8dj5 rn-flexBasis-1mlwlqe rn-flexDirection-eqz5dr rn-justifyContent-1777fci rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-position-bnwqim"
|
||||
role="progressbar"
|
||||
style={
|
||||
Array [
|
||||
15,
|
||||
undefined,
|
||||
]
|
||||
}
|
||||
>
|
||||
<div
|
||||
class="rn-alignItems-1oszu61 rn-animationDuration-17bb2tj rn-animationIterationCount-1muvv40 rn-animationName-dozj4v rn-animationPlayState-1abnn5w rn-animationTimingFunction-1ldzwu0 rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1qe8dj5 rn-flexBasis-1mlwlqe rn-flexDirection-eqz5dr rn-height-z80fyv rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-position-bnwqim rn-visibility-11j9u27 rn-width-19wmn03"
|
||||
<View
|
||||
style={
|
||||
Array [
|
||||
19,
|
||||
17,
|
||||
18,
|
||||
16,
|
||||
]
|
||||
}
|
||||
>
|
||||
<svg
|
||||
height="100%"
|
||||
viewbox="0 0 32 32"
|
||||
viewBox="0 0 32 32"
|
||||
width="100%"
|
||||
>
|
||||
<circle
|
||||
@@ -164,35 +245,58 @@ exports[`components/ActivityIndicator prop "hidesWhenStopped" is "true" 1`] = `
|
||||
cy="16"
|
||||
fill="none"
|
||||
r="14"
|
||||
stroke-width="4"
|
||||
style="stroke:#1976D2;opacity:0.2;"
|
||||
strokeWidth="4"
|
||||
style={
|
||||
Object {
|
||||
"opacity": 0.2,
|
||||
"stroke": "#1976D2",
|
||||
}
|
||||
}
|
||||
/>
|
||||
<circle
|
||||
cx="16"
|
||||
cy="16"
|
||||
fill="none"
|
||||
r="14"
|
||||
stroke-width="4"
|
||||
style="stroke:#1976D2;stroke-dasharray:80;stroke-dashoffset:60;"
|
||||
strokeWidth="4"
|
||||
style={
|
||||
Object {
|
||||
"stroke": "#1976D2",
|
||||
"strokeDasharray": 80,
|
||||
"strokeDashoffset": 60,
|
||||
}
|
||||
}
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
</View>
|
||||
</View>
|
||||
`;
|
||||
|
||||
exports[`components/ActivityIndicator prop "size" is "large" 1`] = `
|
||||
<div
|
||||
<View
|
||||
accessibilityRole="progressbar"
|
||||
aria-valuemax="1"
|
||||
aria-valuemin="0"
|
||||
class="rn-alignItems-1awozwy rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1qe8dj5 rn-flexBasis-1mlwlqe rn-flexDirection-eqz5dr rn-justifyContent-1777fci rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-position-bnwqim"
|
||||
role="progressbar"
|
||||
style={
|
||||
Array [
|
||||
15,
|
||||
undefined,
|
||||
]
|
||||
}
|
||||
>
|
||||
<div
|
||||
class="rn-alignItems-1oszu61 rn-animationDuration-17bb2tj rn-animationIterationCount-1muvv40 rn-animationName-dozj4v rn-animationTimingFunction-1ldzwu0 rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1qe8dj5 rn-flexBasis-1mlwlqe rn-flexDirection-eqz5dr rn-height-1r8g8re rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-position-bnwqim rn-width-1acpoxo"
|
||||
<View
|
||||
style={
|
||||
Array [
|
||||
20,
|
||||
17,
|
||||
false,
|
||||
false,
|
||||
]
|
||||
}
|
||||
>
|
||||
<svg
|
||||
height="100%"
|
||||
viewbox="0 0 32 32"
|
||||
viewBox="0 0 32 32"
|
||||
width="100%"
|
||||
>
|
||||
<circle
|
||||
@@ -200,36 +304,61 @@ exports[`components/ActivityIndicator prop "size" is "large" 1`] = `
|
||||
cy="16"
|
||||
fill="none"
|
||||
r="14"
|
||||
stroke-width="4"
|
||||
style="stroke:#1976D2;opacity:0.2;"
|
||||
strokeWidth="4"
|
||||
style={
|
||||
Object {
|
||||
"opacity": 0.2,
|
||||
"stroke": "#1976D2",
|
||||
}
|
||||
}
|
||||
/>
|
||||
<circle
|
||||
cx="16"
|
||||
cy="16"
|
||||
fill="none"
|
||||
r="14"
|
||||
stroke-width="4"
|
||||
style="stroke:#1976D2;stroke-dasharray:80;stroke-dashoffset:60;"
|
||||
strokeWidth="4"
|
||||
style={
|
||||
Object {
|
||||
"stroke": "#1976D2",
|
||||
"strokeDasharray": 80,
|
||||
"strokeDashoffset": 60,
|
||||
}
|
||||
}
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
</View>
|
||||
</View>
|
||||
`;
|
||||
|
||||
exports[`components/ActivityIndicator prop "size" is a number 1`] = `
|
||||
<div
|
||||
<View
|
||||
accessibilityRole="progressbar"
|
||||
aria-valuemax="1"
|
||||
aria-valuemin="0"
|
||||
class="rn-alignItems-1awozwy rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1qe8dj5 rn-flexBasis-1mlwlqe rn-flexDirection-eqz5dr rn-justifyContent-1777fci rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-position-bnwqim"
|
||||
role="progressbar"
|
||||
style={
|
||||
Array [
|
||||
15,
|
||||
undefined,
|
||||
]
|
||||
}
|
||||
>
|
||||
<div
|
||||
class="rn-alignItems-1oszu61 rn-animationDuration-17bb2tj rn-animationIterationCount-1muvv40 rn-animationName-dozj4v rn-animationTimingFunction-1ldzwu0 rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1qe8dj5 rn-flexBasis-1mlwlqe rn-flexDirection-eqz5dr rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-position-bnwqim"
|
||||
style="height:30px;width:30px;"
|
||||
<View
|
||||
style={
|
||||
Array [
|
||||
Object {
|
||||
"height": 30,
|
||||
"width": 30,
|
||||
},
|
||||
17,
|
||||
false,
|
||||
false,
|
||||
]
|
||||
}
|
||||
>
|
||||
<svg
|
||||
height="100%"
|
||||
viewbox="0 0 32 32"
|
||||
viewBox="0 0 32 32"
|
||||
width="100%"
|
||||
>
|
||||
<circle
|
||||
@@ -237,18 +366,29 @@ exports[`components/ActivityIndicator prop "size" is a number 1`] = `
|
||||
cy="16"
|
||||
fill="none"
|
||||
r="14"
|
||||
stroke-width="4"
|
||||
style="stroke:#1976D2;opacity:0.2;"
|
||||
strokeWidth="4"
|
||||
style={
|
||||
Object {
|
||||
"opacity": 0.2,
|
||||
"stroke": "#1976D2",
|
||||
}
|
||||
}
|
||||
/>
|
||||
<circle
|
||||
cx="16"
|
||||
cy="16"
|
||||
fill="none"
|
||||
r="14"
|
||||
stroke-width="4"
|
||||
style="stroke:#1976D2;stroke-dasharray:80;stroke-dashoffset:60;"
|
||||
strokeWidth="4"
|
||||
style={
|
||||
Object {
|
||||
"stroke": "#1976D2",
|
||||
"strokeDasharray": 80,
|
||||
"strokeDashoffset": 60,
|
||||
}
|
||||
}
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
</View>
|
||||
</View>
|
||||
`;
|
||||
|
||||
@@ -2,46 +2,46 @@
|
||||
|
||||
import ActivityIndicator from '..';
|
||||
import React from 'react';
|
||||
import { render } from 'enzyme';
|
||||
import { shallow } from 'enzyme';
|
||||
|
||||
describe('components/ActivityIndicator', () => {
|
||||
describe('prop "animating"', () => {
|
||||
test('is "true"', () => {
|
||||
const component = render(<ActivityIndicator animating={true} />);
|
||||
const component = shallow(<ActivityIndicator animating={true} />);
|
||||
expect(component).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('is "false"', () => {
|
||||
const component = render(<ActivityIndicator animating={false} />);
|
||||
const component = shallow(<ActivityIndicator animating={false} />);
|
||||
expect(component).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
test('prop "color"', () => {
|
||||
const component = render(<ActivityIndicator color="red" />);
|
||||
const component = shallow(<ActivityIndicator color="red" />).find('svg');
|
||||
expect(component).toMatchSnapshot();
|
||||
});
|
||||
|
||||
describe('prop "hidesWhenStopped"', () => {
|
||||
test('is "true"', () => {
|
||||
const component = render(<ActivityIndicator animating={false} hidesWhenStopped={true} />);
|
||||
const component = shallow(<ActivityIndicator animating={false} hidesWhenStopped={true} />);
|
||||
expect(component).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('is "false"', () => {
|
||||
const component = render(<ActivityIndicator animating={false} hidesWhenStopped={false} />);
|
||||
const component = shallow(<ActivityIndicator animating={false} hidesWhenStopped={false} />);
|
||||
expect(component).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
describe('prop "size"', () => {
|
||||
test('is "large"', () => {
|
||||
const component = render(<ActivityIndicator size="large" />);
|
||||
const component = shallow(<ActivityIndicator size="large" />);
|
||||
expect(component).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('is a number', () => {
|
||||
const component = render(<ActivityIndicator size={30} />);
|
||||
const component = shallow(<ActivityIndicator size={30} />);
|
||||
expect(component).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -17,6 +17,10 @@ import ViewPropTypes from '../View/ViewPropTypes';
|
||||
import { bool, number, oneOf, oneOfType, string } from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
|
||||
const createSvgCircle = style => (
|
||||
<circle cx="16" cy="16" fill="none" r="14" strokeWidth="4" style={style} />
|
||||
);
|
||||
|
||||
class ActivityIndicator extends Component {
|
||||
static displayName = 'ActivityIndicator';
|
||||
|
||||
@@ -40,29 +44,15 @@ class ActivityIndicator extends Component {
|
||||
|
||||
const svg = (
|
||||
<svg height="100%" viewBox="0 0 32 32" width="100%">
|
||||
<circle
|
||||
cx="16"
|
||||
cy="16"
|
||||
fill="none"
|
||||
r="14"
|
||||
strokeWidth="4"
|
||||
style={{
|
||||
stroke: color,
|
||||
opacity: 0.2
|
||||
}}
|
||||
/>
|
||||
<circle
|
||||
cx="16"
|
||||
cy="16"
|
||||
fill="none"
|
||||
r="14"
|
||||
strokeWidth="4"
|
||||
style={{
|
||||
stroke: color,
|
||||
strokeDasharray: 80,
|
||||
strokeDashoffset: 60
|
||||
}}
|
||||
/>
|
||||
{createSvgCircle({
|
||||
stroke: color,
|
||||
opacity: 0.2
|
||||
})}
|
||||
{createSvgCircle({
|
||||
stroke: color,
|
||||
strokeDasharray: 80,
|
||||
strokeDashoffset: 60
|
||||
})}
|
||||
</svg>
|
||||
);
|
||||
|
||||
|
||||
@@ -1,138 +1,17 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`components/Image passes other props through to underlying View 1`] = `
|
||||
<div
|
||||
class="rn-alignItems-1oszu61 rn-backgroundColor-wib322 rn-backgroundPosition-vvn4in rn-backgroundRepeat-u6sd8q rn-backgroundSize-4gszlv rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1qe8dj5 rn-flexBasis-1mlwlqe rn-flexDirection-eqz5dr rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-position-bnwqim rn-zIndex-1lgpqti"
|
||||
/>
|
||||
`;
|
||||
exports[`components/Image prop "defaultSource" sets background image when value is a string 1`] = `"url(\\"https://google.com/favicon.ico\\")"`;
|
||||
|
||||
exports[`components/Image prop "accessibilityLabel" 1`] = `
|
||||
<div
|
||||
aria-label="accessibilityLabel"
|
||||
class="rn-alignItems-1oszu61 rn-backgroundColor-wib322 rn-backgroundPosition-vvn4in rn-backgroundRepeat-u6sd8q rn-backgroundSize-4gszlv rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1qe8dj5 rn-flexBasis-1mlwlqe rn-flexDirection-eqz5dr rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-position-bnwqim rn-zIndex-1lgpqti"
|
||||
style="background-image:url(\\"https://google.com/favicon.ico\\");"
|
||||
>
|
||||
<img
|
||||
alt="accessibilityLabel"
|
||||
class="rn-bottom-1p0dtai rn-height-1pi2tsx rn-left-1d2f490 rn-opacity-1272l3b rn-position-u8s1d rn-right-zchlnj rn-top-ipm5af rn-width-13qz1uu rn-zIndex-1wyyakw"
|
||||
src="https://google.com/favicon.ico"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
exports[`components/Image prop "defaultSource" sets background image when value is an object 1`] = `"url(\\"https://google.com/favicon.ico\\")"`;
|
||||
|
||||
exports[`components/Image prop "accessible" 1`] = `
|
||||
<div
|
||||
class="rn-alignItems-1oszu61 rn-backgroundColor-wib322 rn-backgroundPosition-vvn4in rn-backgroundRepeat-u6sd8q rn-backgroundSize-4gszlv rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1qe8dj5 rn-flexBasis-1mlwlqe rn-flexDirection-eqz5dr rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-position-bnwqim rn-zIndex-1lgpqti"
|
||||
/>
|
||||
`;
|
||||
exports[`components/Image prop "resizeMode" value "contain" 1`] = `"contain"`;
|
||||
|
||||
exports[`components/Image prop "children" 1`] = `
|
||||
<div
|
||||
class="rn-alignItems-1oszu61 rn-backgroundColor-wib322 rn-backgroundPosition-vvn4in rn-backgroundRepeat-u6sd8q rn-backgroundSize-4gszlv rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1qe8dj5 rn-flexBasis-1mlwlqe rn-flexDirection-eqz5dr rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-position-bnwqim rn-zIndex-1lgpqti"
|
||||
>
|
||||
<div
|
||||
class="unique"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
exports[`components/Image prop "resizeMode" value "cover" 1`] = `"cover"`;
|
||||
|
||||
exports[`components/Image prop "defaultSource" does not override "height" and "width" styles 1`] = `
|
||||
<div
|
||||
class="rn-alignItems-1oszu61 rn-backgroundColor-wib322 rn-backgroundPosition-vvn4in rn-backgroundRepeat-u6sd8q rn-backgroundSize-4gszlv rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1qe8dj5 rn-flexBasis-1mlwlqe rn-flexDirection-eqz5dr rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-position-bnwqim rn-zIndex-1lgpqti"
|
||||
style="background-image:url(\\"https://google.com/favicon.ico\\");height:20px;width:40px;"
|
||||
>
|
||||
<img
|
||||
alt=""
|
||||
class="rn-bottom-1p0dtai rn-height-1pi2tsx rn-left-1d2f490 rn-opacity-1272l3b rn-position-u8s1d rn-right-zchlnj rn-top-ipm5af rn-width-13qz1uu rn-zIndex-1wyyakw"
|
||||
src="https://google.com/favicon.ico"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
exports[`components/Image prop "resizeMode" value "none" 1`] = `"auto"`;
|
||||
|
||||
exports[`components/Image prop "defaultSource" sets "height" and "width" styles if missing 1`] = `
|
||||
<div
|
||||
class="rn-alignItems-1oszu61 rn-backgroundColor-wib322 rn-backgroundPosition-vvn4in rn-backgroundRepeat-u6sd8q rn-backgroundSize-4gszlv rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1qe8dj5 rn-flexBasis-1mlwlqe rn-flexDirection-eqz5dr rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-position-bnwqim rn-zIndex-1lgpqti"
|
||||
style="background-image:url(\\"https://google.com/favicon.ico\\");height:10px;width:20px;"
|
||||
>
|
||||
<img
|
||||
alt=""
|
||||
class="rn-bottom-1p0dtai rn-height-1pi2tsx rn-left-1d2f490 rn-opacity-1272l3b rn-position-u8s1d rn-right-zchlnj rn-top-ipm5af rn-width-13qz1uu rn-zIndex-1wyyakw"
|
||||
src="https://google.com/favicon.ico"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
exports[`components/Image prop "resizeMode" value "stretch" 1`] = `"100% 100%"`;
|
||||
|
||||
exports[`components/Image prop "defaultSource" sets background image when value is a string 1`] = `
|
||||
<div
|
||||
class="rn-alignItems-1oszu61 rn-backgroundColor-wib322 rn-backgroundPosition-vvn4in rn-backgroundRepeat-u6sd8q rn-backgroundSize-4gszlv rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1qe8dj5 rn-flexBasis-1mlwlqe rn-flexDirection-eqz5dr rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-position-bnwqim rn-zIndex-1lgpqti"
|
||||
style="background-image:url(\\"https://google.com/favicon.ico\\");"
|
||||
>
|
||||
<img
|
||||
alt=""
|
||||
class="rn-bottom-1p0dtai rn-height-1pi2tsx rn-left-1d2f490 rn-opacity-1272l3b rn-position-u8s1d rn-right-zchlnj rn-top-ipm5af rn-width-13qz1uu rn-zIndex-1wyyakw"
|
||||
src="https://google.com/favicon.ico"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
exports[`components/Image prop "resizeMode" value "undefined" 1`] = `"cover"`;
|
||||
|
||||
exports[`components/Image prop "defaultSource" sets background image when value is an object 1`] = `
|
||||
<div
|
||||
class="rn-alignItems-1oszu61 rn-backgroundColor-wib322 rn-backgroundPosition-vvn4in rn-backgroundRepeat-u6sd8q rn-backgroundSize-4gszlv rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1qe8dj5 rn-flexBasis-1mlwlqe rn-flexDirection-eqz5dr rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-position-bnwqim rn-zIndex-1lgpqti"
|
||||
style="background-image:url(\\"https://google.com/favicon.ico\\");"
|
||||
>
|
||||
<img
|
||||
alt=""
|
||||
class="rn-bottom-1p0dtai rn-height-1pi2tsx rn-left-1d2f490 rn-opacity-1272l3b rn-position-u8s1d rn-right-zchlnj rn-top-ipm5af rn-width-13qz1uu rn-zIndex-1wyyakw"
|
||||
src="https://google.com/favicon.ico"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`components/Image prop "resizeMode" value "contain" 1`] = `
|
||||
<div
|
||||
class="rn-alignItems-1oszu61 rn-backgroundColor-wib322 rn-backgroundPosition-vvn4in rn-backgroundRepeat-u6sd8q rn-backgroundSize-ehq7j7 rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1qe8dj5 rn-flexBasis-1mlwlqe rn-flexDirection-eqz5dr rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-position-bnwqim rn-zIndex-1lgpqti"
|
||||
/>
|
||||
`;
|
||||
|
||||
exports[`components/Image prop "resizeMode" value "cover" 1`] = `
|
||||
<div
|
||||
class="rn-alignItems-1oszu61 rn-backgroundColor-wib322 rn-backgroundPosition-vvn4in rn-backgroundRepeat-u6sd8q rn-backgroundSize-4gszlv rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1qe8dj5 rn-flexBasis-1mlwlqe rn-flexDirection-eqz5dr rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-position-bnwqim rn-zIndex-1lgpqti"
|
||||
/>
|
||||
`;
|
||||
|
||||
exports[`components/Image prop "resizeMode" value "none" 1`] = `
|
||||
<div
|
||||
class="rn-alignItems-1oszu61 rn-backgroundColor-wib322 rn-backgroundPosition-vvn4in rn-backgroundRepeat-u6sd8q rn-backgroundSize-1sxrcry rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1qe8dj5 rn-flexBasis-1mlwlqe rn-flexDirection-eqz5dr rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-position-bnwqim rn-zIndex-1lgpqti"
|
||||
/>
|
||||
`;
|
||||
|
||||
exports[`components/Image prop "resizeMode" value "stretch" 1`] = `
|
||||
<div
|
||||
class="rn-alignItems-1oszu61 rn-backgroundColor-wib322 rn-backgroundPosition-vvn4in rn-backgroundRepeat-u6sd8q rn-backgroundSize-x3cy2q rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1qe8dj5 rn-flexBasis-1mlwlqe rn-flexDirection-eqz5dr rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-position-bnwqim rn-zIndex-1lgpqti"
|
||||
/>
|
||||
`;
|
||||
|
||||
exports[`components/Image prop "resizeMode" value "undefined" 1`] = `
|
||||
<div
|
||||
class="rn-alignItems-1oszu61 rn-backgroundColor-wib322 rn-backgroundPosition-vvn4in rn-backgroundRepeat-u6sd8q rn-backgroundSize-4gszlv rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1qe8dj5 rn-flexBasis-1mlwlqe rn-flexDirection-eqz5dr rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-position-bnwqim rn-zIndex-1lgpqti"
|
||||
/>
|
||||
`;
|
||||
|
||||
exports[`components/Image prop "style" correctly supports "resizeMode" property 1`] = `
|
||||
<div
|
||||
class="rn-alignItems-1oszu61 rn-backgroundColor-wib322 rn-backgroundPosition-vvn4in rn-backgroundRepeat-u6sd8q rn-backgroundSize-ehq7j7 rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1qe8dj5 rn-flexBasis-1mlwlqe rn-flexDirection-eqz5dr rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-position-bnwqim rn-zIndex-1lgpqti"
|
||||
/>
|
||||
`;
|
||||
|
||||
exports[`components/Image prop "testID" 1`] = `
|
||||
<div
|
||||
class="rn-alignItems-1oszu61 rn-backgroundColor-wib322 rn-backgroundPosition-vvn4in rn-backgroundRepeat-u6sd8q rn-backgroundSize-4gszlv rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1qe8dj5 rn-flexBasis-1mlwlqe rn-flexDirection-eqz5dr rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-position-bnwqim rn-zIndex-1lgpqti"
|
||||
data-testid="testID"
|
||||
/>
|
||||
`;
|
||||
|
||||
exports[`components/Image sets correct accessibility role" 1`] = `
|
||||
<div
|
||||
class="rn-alignItems-1oszu61 rn-backgroundColor-wib322 rn-backgroundPosition-vvn4in rn-backgroundRepeat-u6sd8q rn-backgroundSize-4gszlv rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1qe8dj5 rn-flexBasis-1mlwlqe rn-flexDirection-eqz5dr rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-position-bnwqim rn-zIndex-1lgpqti"
|
||||
/>
|
||||
`;
|
||||
exports[`components/Image prop "style" correctly supports "resizeMode" property 1`] = `"contain"`;
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
/* eslint-env jasmine, jest */
|
||||
|
||||
import ExecutionEnvironment from 'fbjs/lib/ExecutionEnvironment';
|
||||
import Image from '../';
|
||||
import ImageUriCache from '../ImageUriCache';
|
||||
import React from 'react';
|
||||
import { mount, render, shallow } from 'enzyme';
|
||||
import { mount, shallow } from 'enzyme';
|
||||
|
||||
const originalCanUseDOM = ExecutionEnvironment.canUseDOM;
|
||||
const originalImage = window.Image;
|
||||
|
||||
describe('components/Image', () => {
|
||||
@@ -18,42 +16,39 @@ describe('components/Image', () => {
|
||||
window.Image = originalImage;
|
||||
});
|
||||
|
||||
test('sets correct accessibility role"', () => {
|
||||
const component = render(<Image />);
|
||||
expect(component).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('prop "accessibilityLabel"', () => {
|
||||
const defaultSource = { uri: 'https://google.com/favicon.ico' };
|
||||
const component = render(
|
||||
const component = shallow(
|
||||
<Image accessibilityLabel="accessibilityLabel" defaultSource={defaultSource} />
|
||||
);
|
||||
expect(component).toMatchSnapshot();
|
||||
const img = component.find('img');
|
||||
expect(component.prop('accessibilityLabel')).toBe('accessibilityLabel');
|
||||
expect(img.prop('alt')).toBe('accessibilityLabel');
|
||||
});
|
||||
|
||||
test('prop "accessible"', () => {
|
||||
const component = render(<Image accessible={false} />);
|
||||
expect(component).toMatchSnapshot();
|
||||
const component = shallow(<Image accessible={false} />);
|
||||
expect(component.prop('accessible')).toBe(false);
|
||||
});
|
||||
|
||||
test('prop "children"', () => {
|
||||
const children = <div className="unique" />;
|
||||
const component = render(<Image children={children} />);
|
||||
expect(component).toMatchSnapshot();
|
||||
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' };
|
||||
const component = render(<Image defaultSource={defaultSource} />);
|
||||
expect(component).toMatchSnapshot();
|
||||
const component = shallow(<Image defaultSource={defaultSource} />);
|
||||
expect(component.prop('style').backgroundImage).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('sets background image when value is a string', () => {
|
||||
// emulate require-ed asset
|
||||
const defaultSource = 'https://google.com/favicon.ico';
|
||||
const component = render(<Image defaultSource={defaultSource} />);
|
||||
expect(component).toMatchSnapshot();
|
||||
const component = shallow(<Image defaultSource={defaultSource} />);
|
||||
expect(component.prop('style').backgroundImage).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('sets "height" and "width" styles if missing', () => {
|
||||
@@ -62,8 +57,10 @@ describe('components/Image', () => {
|
||||
height: 10,
|
||||
width: 20
|
||||
};
|
||||
const component = render(<Image defaultSource={defaultSource} />);
|
||||
expect(component).toMatchSnapshot();
|
||||
const component = shallow(<Image defaultSource={defaultSource} />);
|
||||
const { height, width } = component.prop('style');
|
||||
expect(height).toBe(10);
|
||||
expect(width).toBe(20);
|
||||
});
|
||||
|
||||
test('does not override "height" and "width" styles', () => {
|
||||
@@ -72,10 +69,12 @@ describe('components/Image', () => {
|
||||
height: 10,
|
||||
width: 20
|
||||
};
|
||||
const component = render(
|
||||
const component = shallow(
|
||||
<Image defaultSource={defaultSource} style={{ height: 20, width: 40 }} />
|
||||
);
|
||||
expect(component).toMatchSnapshot();
|
||||
const { height, width } = component.prop('style');
|
||||
expect(height).toBe(20);
|
||||
expect(width).toBe(40);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -96,8 +95,8 @@ describe('components/Image', () => {
|
||||
undefined
|
||||
].forEach(resizeMode => {
|
||||
test(`value "${resizeMode}"`, () => {
|
||||
const component = render(<Image resizeMode={resizeMode} />);
|
||||
expect(component).toMatchSnapshot();
|
||||
const component = shallow(<Image resizeMode={resizeMode} />);
|
||||
expect(component.prop('style').backgroundSize).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -106,7 +105,7 @@ describe('components/Image', () => {
|
||||
test('is not set immediately if the image has not already been loaded', () => {
|
||||
const uri = 'https://google.com/favicon.ico';
|
||||
const source = { uri };
|
||||
const component = render(<Image source={source} />);
|
||||
const component = shallow(<Image source={source} />);
|
||||
expect(component.find('img')).toBeUndefined;
|
||||
});
|
||||
|
||||
@@ -136,21 +135,12 @@ describe('components/Image', () => {
|
||||
.attr('src')
|
||||
).toBe(uriTwo);
|
||||
});
|
||||
|
||||
test('is set immediately when rendered on the server', () => {
|
||||
ExecutionEnvironment.canUseDOM = false;
|
||||
const uri = 'https://google.com/favicon.ico';
|
||||
const component = render(<Image source={{ uri }} />);
|
||||
expect(component.find('img').attr('src')).toBe(uri);
|
||||
expect(ImageUriCache.has(uri)).toBe(true);
|
||||
ExecutionEnvironment.canUseDOM = originalCanUseDOM;
|
||||
});
|
||||
});
|
||||
|
||||
describe('prop "style"', () => {
|
||||
test('correctly supports "resizeMode" property', () => {
|
||||
const component = render(<Image style={{ resizeMode: Image.resizeMode.contain }} />);
|
||||
expect(component).toMatchSnapshot();
|
||||
const component = shallow(<Image style={{ resizeMode: Image.resizeMode.contain }} />);
|
||||
expect(component.prop('style').backgroundSize).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('removes other unsupported View styles', () => {
|
||||
@@ -161,13 +151,13 @@ describe('components/Image', () => {
|
||||
});
|
||||
|
||||
test('prop "testID"', () => {
|
||||
const component = render(<Image testID="testID" />);
|
||||
expect(component).toMatchSnapshot();
|
||||
const component = shallow(<Image testID="testID" />);
|
||||
expect(component.prop('testID')).toBe('testID');
|
||||
});
|
||||
|
||||
test('passes other props through to underlying View', () => {
|
||||
const fn = () => {};
|
||||
const component = render(<Image onResponderGrant={fn} />);
|
||||
expect(component).toMatchSnapshot();
|
||||
const component = shallow(<Image onResponderGrant={fn} />);
|
||||
expect(component.prop('onResponderGrant')).toBe(fn);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
*/
|
||||
|
||||
import applyNativeMethods from '../../modules/applyNativeMethods';
|
||||
import { canUseDOM } from 'fbjs/lib/ExecutionEnvironment';
|
||||
import createElement from '../../modules/createElement';
|
||||
import { getAssetByID } from '../../modules/AssetRegistry';
|
||||
import ImageLoader from '../../modules/ImageLoader';
|
||||
@@ -131,7 +130,7 @@ class Image extends Component {
|
||||
super(props, context);
|
||||
// If an image has been loaded before, render it immediately
|
||||
const uri = resolveAssetSource(props.source);
|
||||
const shouldDisplaySource = ImageUriCache.has(uri) || !canUseDOM;
|
||||
const shouldDisplaySource = ImageUriCache.has(uri);
|
||||
this.state = { shouldDisplaySource };
|
||||
this._imageState = getImageState(uri, shouldDisplaySource);
|
||||
shouldDisplaySource && ImageUriCache.add(uri);
|
||||
|
||||
@@ -1,2 +1,55 @@
|
||||
import UnimplementedView from '../UnimplementedView';
|
||||
export default UnimplementedView;
|
||||
/**
|
||||
* 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 RefreshControl
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import ColorPropType from '../../propTypes/ColorPropType';
|
||||
import View from '../View';
|
||||
import ViewPropTypes from '../View/ViewPropTypes';
|
||||
import { arrayOf, bool, func, number, oneOf, string } from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
|
||||
class RefreshControl extends Component {
|
||||
static propTypes = {
|
||||
...ViewPropTypes,
|
||||
colors: arrayOf(ColorPropType),
|
||||
enabled: bool,
|
||||
onRefresh: func,
|
||||
progressBackgroundColor: ColorPropType,
|
||||
progressViewOffset: number,
|
||||
refreshing: bool.isRequired,
|
||||
size: oneOf([0, 1]),
|
||||
tintColor: ColorPropType,
|
||||
title: string,
|
||||
titleColor: ColorPropType
|
||||
};
|
||||
|
||||
render() {
|
||||
const {
|
||||
/* eslint-disable */
|
||||
colors,
|
||||
enabled,
|
||||
onRefresh,
|
||||
progressBackgroundColor,
|
||||
progressViewOffset,
|
||||
refreshing,
|
||||
size,
|
||||
tintColor,
|
||||
title,
|
||||
titleColor,
|
||||
/* eslint-enable */
|
||||
...rest
|
||||
} = this.props;
|
||||
|
||||
return <View {...rest} />;
|
||||
}
|
||||
}
|
||||
|
||||
export default RefreshControl;
|
||||
|
||||
@@ -134,14 +134,39 @@ export default class ScrollViewBase extends Component {
|
||||
scrollEnabled,
|
||||
style,
|
||||
/* eslint-disable */
|
||||
alwaysBounceHorizontal,
|
||||
alwaysBounceVertical,
|
||||
automaticallyAdjustContentInsets,
|
||||
bounces,
|
||||
bouncesZoom,
|
||||
canCancelContentTouches,
|
||||
centerContent,
|
||||
contentInset,
|
||||
contentInsetAdjustmentBehavior,
|
||||
contentOffset,
|
||||
decelerationRate,
|
||||
directionalLockEnabled,
|
||||
endFillColor,
|
||||
indicatorStyle,
|
||||
keyboardShouldPersistTaps,
|
||||
maximumZoomScale,
|
||||
minimumZoomScale,
|
||||
onMomentumScrollBegin,
|
||||
onMomentumScrollEnd,
|
||||
onScrollBeginDrag,
|
||||
onScrollEndDrag,
|
||||
overScrollMode,
|
||||
pinchGestureEnabled,
|
||||
removeClippedSubviews,
|
||||
scrollEventThrottle,
|
||||
scrollIndicatorInsets,
|
||||
scrollPerfTag,
|
||||
scrollsToTop,
|
||||
showsHorizontalScrollIndicator,
|
||||
showsVerticalScrollIndicator,
|
||||
snapToInterval,
|
||||
snapToAlignment,
|
||||
zoomScale,
|
||||
/* eslint-enable */
|
||||
...other
|
||||
} = this.props;
|
||||
|
||||
@@ -137,6 +137,7 @@ const ScrollView = createReactClass({
|
||||
keyboardDismissMode,
|
||||
onScroll,
|
||||
pagingEnabled,
|
||||
stickyHeaderIndices,
|
||||
/* eslint-enable */
|
||||
...other
|
||||
} = this.props;
|
||||
|
||||
@@ -1,84 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`components/Switch disabled when "false" a default checkbox is rendered 1`] = `
|
||||
<div
|
||||
class="rn-alignItems-1oszu61 rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-cursor-1loqt21 rn-display-6koalj rn-flexShrink-1qe8dj5 rn-flexBasis-1mlwlqe rn-flexDirection-eqz5dr rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-position-bnwqim rn-userSelect-lrvibr"
|
||||
style="height:20px;width:40px;"
|
||||
>
|
||||
<div
|
||||
class="rn-alignItems-1oszu61 rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-bottom-1p0dtai rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1qe8dj5 rn-flexBasis-1mlwlqe rn-flexDirection-eqz5dr rn-height-1dernwh rn-left-1d2f490 rn-marginTop-1t01tom rn-marginRight-lchren rn-marginBottom-1qahzrx rn-marginLeft-1jj8364 rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-position-u8s1d rn-right-zchlnj rn-top-ipm5af rn-transitionDuration-13tjlyg rn-width-13qz1uu"
|
||||
style="background-color:rgba(147,147,147,1);border-top-left-radius:10px;border-top-right-radius:10px;border-bottom-right-radius:10px;border-bottom-left-radius:10px;"
|
||||
/>
|
||||
<div
|
||||
class="rn-alignItems-1oszu61 rn-alignSelf-k200y rn-borderTopLeftRadius-jt3ufn rn-borderTopRightRadius-1e868j9 rn-borderBottomRightRadius-ujv9e3 rn-borderBottomLeftRadius-1hakmuk rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxShadow-1ewcgjf rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1qe8dj5 rn-flexBasis-1mlwlqe rn-flexDirection-eqz5dr rn-left-1fe0xdi rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-position-bnwqim rn-transform-emqnss rn-transitionDuration-13tjlyg"
|
||||
style="background-color:rgba(250,250,250,1);height:20px;width:20px;"
|
||||
/>
|
||||
<input
|
||||
class="rn-bottom-1p0dtai rn-cursor-1ei5mc7 rn-height-1pi2tsx rn-left-1d2f490 rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-opacity-1272l3b rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-position-u8s1d rn-right-zchlnj rn-top-ipm5af rn-width-13qz1uu"
|
||||
type="checkbox"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`components/Switch disabled when "true" a disabled checkbox is rendered 1`] = `
|
||||
<div
|
||||
class="rn-alignItems-1oszu61 rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-cursor-7q8q6z rn-display-6koalj rn-flexShrink-1qe8dj5 rn-flexBasis-1mlwlqe rn-flexDirection-eqz5dr rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-position-bnwqim rn-userSelect-lrvibr"
|
||||
style="height:20px;width:40px;"
|
||||
>
|
||||
<div
|
||||
class="rn-alignItems-1oszu61 rn-backgroundColor-1hj8efq rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-bottom-1p0dtai rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1qe8dj5 rn-flexBasis-1mlwlqe rn-flexDirection-eqz5dr rn-height-1dernwh rn-left-1d2f490 rn-marginTop-1t01tom rn-marginRight-lchren rn-marginBottom-1qahzrx rn-marginLeft-1jj8364 rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-position-u8s1d rn-right-zchlnj rn-top-ipm5af rn-transitionDuration-13tjlyg rn-width-13qz1uu"
|
||||
style="border-top-left-radius:10px;border-top-right-radius:10px;border-bottom-right-radius:10px;border-bottom-left-radius:10px;"
|
||||
/>
|
||||
<div
|
||||
class="rn-alignItems-1oszu61 rn-alignSelf-k200y rn-backgroundColor-1bgzomc rn-borderTopLeftRadius-jt3ufn rn-borderTopRightRadius-1e868j9 rn-borderBottomRightRadius-ujv9e3 rn-borderBottomLeftRadius-1hakmuk rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxShadow-1ewcgjf rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1qe8dj5 rn-flexBasis-1mlwlqe rn-flexDirection-eqz5dr rn-left-1fe0xdi rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-position-bnwqim rn-transform-emqnss rn-transitionDuration-13tjlyg"
|
||||
style="height:20px;width:20px;"
|
||||
/>
|
||||
<input
|
||||
aria-disabled="true"
|
||||
class="rn-bottom-1p0dtai rn-cursor-1ei5mc7 rn-height-1pi2tsx rn-left-1d2f490 rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-opacity-1272l3b rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-position-u8s1d rn-right-zchlnj rn-top-ipm5af rn-width-13qz1uu"
|
||||
disabled=""
|
||||
type="checkbox"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`components/Switch value when "false" an unchecked checkbox is rendered 1`] = `
|
||||
<div
|
||||
class="rn-alignItems-1oszu61 rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-cursor-1loqt21 rn-display-6koalj rn-flexShrink-1qe8dj5 rn-flexBasis-1mlwlqe rn-flexDirection-eqz5dr rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-position-bnwqim rn-userSelect-lrvibr"
|
||||
style="height:20px;width:40px;"
|
||||
>
|
||||
<div
|
||||
class="rn-alignItems-1oszu61 rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-bottom-1p0dtai rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1qe8dj5 rn-flexBasis-1mlwlqe rn-flexDirection-eqz5dr rn-height-1dernwh rn-left-1d2f490 rn-marginTop-1t01tom rn-marginRight-lchren rn-marginBottom-1qahzrx rn-marginLeft-1jj8364 rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-position-u8s1d rn-right-zchlnj rn-top-ipm5af rn-transitionDuration-13tjlyg rn-width-13qz1uu"
|
||||
style="background-color:rgba(147,147,147,1);border-top-left-radius:10px;border-top-right-radius:10px;border-bottom-right-radius:10px;border-bottom-left-radius:10px;"
|
||||
/>
|
||||
<div
|
||||
class="rn-alignItems-1oszu61 rn-alignSelf-k200y rn-borderTopLeftRadius-jt3ufn rn-borderTopRightRadius-1e868j9 rn-borderBottomRightRadius-ujv9e3 rn-borderBottomLeftRadius-1hakmuk rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxShadow-1ewcgjf rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1qe8dj5 rn-flexBasis-1mlwlqe rn-flexDirection-eqz5dr rn-left-1fe0xdi rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-position-bnwqim rn-transform-emqnss rn-transitionDuration-13tjlyg"
|
||||
style="background-color:rgba(250,250,250,1);height:20px;width:20px;"
|
||||
/>
|
||||
<input
|
||||
class="rn-bottom-1p0dtai rn-cursor-1ei5mc7 rn-height-1pi2tsx rn-left-1d2f490 rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-opacity-1272l3b rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-position-u8s1d rn-right-zchlnj rn-top-ipm5af rn-width-13qz1uu"
|
||||
type="checkbox"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`components/Switch value when "true" a checked checkbox is rendered 1`] = `
|
||||
<div
|
||||
class="rn-alignItems-1oszu61 rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-cursor-1loqt21 rn-display-6koalj rn-flexShrink-1qe8dj5 rn-flexBasis-1mlwlqe rn-flexDirection-eqz5dr rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-position-bnwqim rn-userSelect-lrvibr"
|
||||
style="height:20px;width:40px;"
|
||||
>
|
||||
<div
|
||||
class="rn-alignItems-1oszu61 rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-bottom-1p0dtai rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1qe8dj5 rn-flexBasis-1mlwlqe rn-flexDirection-eqz5dr rn-height-1dernwh rn-left-1d2f490 rn-marginTop-1t01tom rn-marginRight-lchren rn-marginBottom-1qahzrx rn-marginLeft-1jj8364 rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-position-u8s1d rn-right-zchlnj rn-top-ipm5af rn-transitionDuration-13tjlyg rn-width-13qz1uu"
|
||||
style="background-color:rgba(163,211,207,1);border-top-left-radius:10px;border-top-right-radius:10px;border-bottom-right-radius:10px;border-bottom-left-radius:10px;"
|
||||
/>
|
||||
<div
|
||||
class="rn-alignItems-1oszu61 rn-alignSelf-k200y rn-borderTopLeftRadius-jt3ufn rn-borderTopRightRadius-1e868j9 rn-borderBottomRightRadius-ujv9e3 rn-borderBottomLeftRadius-1hakmuk rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxShadow-1ewcgjf rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1qe8dj5 rn-flexBasis-1mlwlqe rn-flexDirection-eqz5dr rn-left-7b7h2f rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-position-bnwqim rn-transform-emqnss rn-transitionDuration-13tjlyg"
|
||||
style="background-color:rgba(0,150,136,1);height:20px;margin-left:-20px;width:20px;"
|
||||
/>
|
||||
<input
|
||||
checked=""
|
||||
class="rn-bottom-1p0dtai rn-cursor-1ei5mc7 rn-height-1pi2tsx rn-left-1d2f490 rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-opacity-1272l3b rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-position-u8s1d rn-right-zchlnj rn-top-ipm5af rn-width-13qz1uu"
|
||||
type="checkbox"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
@@ -1,47 +1,49 @@
|
||||
/* eslint-env jasmine, jest */
|
||||
|
||||
import React from 'react';
|
||||
import { render } from 'enzyme';
|
||||
import { shallow } from 'enzyme';
|
||||
import Switch from '..';
|
||||
|
||||
const checkboxSelector = 'input[type="checkbox"]';
|
||||
|
||||
describe('components/Switch', () => {
|
||||
describe('disabled', () => {
|
||||
test('when "false" a default checkbox is rendered', () => {
|
||||
const component = render(<Switch />);
|
||||
expect(component).toMatchSnapshot();
|
||||
const component = shallow(<Switch />);
|
||||
expect(component.find(checkboxSelector).prop('disabled')).toBe(false);
|
||||
});
|
||||
|
||||
test('when "true" a disabled checkbox is rendered', () => {
|
||||
const component = render(<Switch disabled />);
|
||||
expect(component).toMatchSnapshot();
|
||||
const component = shallow(<Switch disabled />);
|
||||
expect(component.find(checkboxSelector).prop('disabled')).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
/*
|
||||
describe('onValueChange', () => {
|
||||
test('when value is "false" it receives "true"', () => {
|
||||
const handleValueChange = (value) => expect(value === true).toBeTruthy();
|
||||
const component = shallow(<Switch onValueChange={handleValueChange} value={false} />);
|
||||
component.find('input').simulate('click');
|
||||
const onValueChange = jest.fn();
|
||||
const component = shallow(<Switch 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 handleValueChange = (value) => expect(value === false).toBeTruthy();
|
||||
const component = shallow(<Switch onValueChange={handleValueChange} value />);
|
||||
component.find('input').simulate('click');
|
||||
const onValueChange = jest.fn();
|
||||
const component = shallow(<Switch 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 = render(<Switch value={false} />);
|
||||
expect(component).toMatchSnapshot();
|
||||
const component = shallow(<Switch value={false} />);
|
||||
expect(component.find(checkboxSelector).prop('checked')).toBe(false);
|
||||
});
|
||||
|
||||
test('when "true" a checked checkbox is rendered', () => {
|
||||
const component = render(<Switch value />);
|
||||
expect(component).toMatchSnapshot();
|
||||
const component = shallow(<Switch value />);
|
||||
expect(component.find(checkboxSelector).prop('checked')).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -17,7 +17,7 @@ import { any, bool, func, number, oneOf } from 'prop-types';
|
||||
|
||||
const TextPropTypes = {
|
||||
...BaseComponentPropTypes,
|
||||
accessibilityRole: oneOf(['button', 'heading', 'link', 'listitem']),
|
||||
accessibilityRole: oneOf(['button', 'heading', 'label', 'link', 'listitem']),
|
||||
children: any,
|
||||
numberOfLines: number,
|
||||
onLayout: func,
|
||||
|
||||
@@ -30,7 +30,7 @@ const TextStylePropTypes = {
|
||||
letterSpacing: numberOrString,
|
||||
lineHeight: numberOrString,
|
||||
textAlign: TextAlignPropType,
|
||||
textAlignVertical: oneOf(['auto', 'bottom', 'center', 'top']),
|
||||
textAlignVertical: string,
|
||||
textDecorationColor: ColorPropType,
|
||||
textDecorationLine: string,
|
||||
textDecorationStyle: string,
|
||||
|
||||
@@ -366,12 +366,12 @@ describe('components/TextInput', () => {
|
||||
);
|
||||
|
||||
// default selection is 0
|
||||
expect(inputDefaultSelection.node.selectionStart).toEqual(0);
|
||||
expect(inputDefaultSelection.node.selectionEnd).toEqual(0);
|
||||
expect(inputDefaultSelection.instance().selectionStart).toEqual(0);
|
||||
expect(inputDefaultSelection.instance().selectionEnd).toEqual(0);
|
||||
|
||||
// custom selection sets cursor at custom position
|
||||
expect(inputCustomSelection.node.selectionStart).toEqual(cursorLocation.start);
|
||||
expect(inputCustomSelection.node.selectionEnd).toEqual(cursorLocation.end);
|
||||
expect(inputCustomSelection.instance().selectionStart).toEqual(cursorLocation.start);
|
||||
expect(inputCustomSelection.instance().selectionEnd).toEqual(cursorLocation.end);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import AccessibilityUtil from '../../modules/AccessibilityUtil';
|
||||
import BoundingDimensions from './BoundingDimensions';
|
||||
import findNodeHandle from '../../modules/findNodeHandle';
|
||||
import normalizeColor from 'normalize-css-color';
|
||||
@@ -819,7 +820,11 @@ const TouchableMixin = {
|
||||
}
|
||||
}
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
// prevent the default behaviour unless the Touchable functions as a link
|
||||
// and Enter is pressed
|
||||
if (!(which === ENTER && AccessibilityUtil.propsToAriaRole(this.props) === 'link')) {
|
||||
e.preventDefault();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -19,7 +19,7 @@ import StyleSheet from '../../apis/StyleSheet';
|
||||
import TimerMixin from 'react-timer-mixin';
|
||||
import Touchable from './Touchable';
|
||||
import warning from 'fbjs/lib/warning';
|
||||
import { bool, element, func, number, string } from 'prop-types';
|
||||
import { bool, func, number, string } from 'prop-types';
|
||||
|
||||
type Event = Object;
|
||||
|
||||
@@ -33,7 +33,7 @@ const PRESS_RETENTION_OFFSET = { top: 20, left: 20, right: 20, bottom: 30 };
|
||||
* If you wish to have several child components, wrap them in a View.
|
||||
*/
|
||||
|
||||
/* eslint-disable react/prefer-es6-class */
|
||||
/* eslint-disable react/prefer-es6-class, react/prop-types */
|
||||
const TouchableWithoutFeedback = createReactClass({
|
||||
displayName: 'TouchableWithoutFeedback',
|
||||
mixins: [TimerMixin, Touchable.Mixin],
|
||||
@@ -44,7 +44,6 @@ const TouchableWithoutFeedback = createReactClass({
|
||||
accessibilityRole: BaseComponentPropTypes.accessibilityRole,
|
||||
accessibilityTraits: BaseComponentPropTypes.accessibilityTraits,
|
||||
accessible: bool,
|
||||
children: element,
|
||||
/**
|
||||
* Delay in ms, from onPressIn, before onLongPress is called.
|
||||
*/
|
||||
@@ -161,6 +160,7 @@ const TouchableWithoutFeedback = createReactClass({
|
||||
} = this.props;
|
||||
|
||||
// Note(avik): remove dynamic typecast once Flow has been upgraded
|
||||
// $FlowFixMe
|
||||
const child = React.Children.only(this.props.children);
|
||||
let children = child.props.children;
|
||||
warning(
|
||||
|
||||
@@ -11,18 +11,13 @@
|
||||
*/
|
||||
|
||||
import View from '../View';
|
||||
import { any, object } from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
|
||||
/**
|
||||
* Common implementation for a simple stubbed view.
|
||||
*/
|
||||
/* eslint-disable react/prop-types */
|
||||
class UnimplementedView extends Component {
|
||||
static propTypes = {
|
||||
children: any,
|
||||
style: object
|
||||
};
|
||||
|
||||
setNativeProps() {
|
||||
// Do nothing.
|
||||
// This method is required in order to use this view as a Touchable* child.
|
||||
|
||||
@@ -1,29 +1,16 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`components/View prop "hitSlop" handles partial offsets 1`] = `
|
||||
<div
|
||||
class="rn-alignItems-1oszu61 rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1qe8dj5 rn-flexBasis-1mlwlqe rn-flexDirection-eqz5dr rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-position-bnwqim rn-zIndex-1lgpqti"
|
||||
>
|
||||
<span
|
||||
class="rn-bottom-1p0dtai rn-left-1d2f490 rn-position-u8s1d rn-right-zchlnj rn-zIndex-1wyyakw"
|
||||
style="top:-10px;"
|
||||
/>
|
||||
</div>
|
||||
Object {
|
||||
"top": "-10px",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`components/View prop "hitSlop" renders a span with negative position offsets 1`] = `
|
||||
<div
|
||||
class="rn-alignItems-1oszu61 rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1qe8dj5 rn-flexBasis-1mlwlqe rn-flexDirection-eqz5dr rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-position-bnwqim rn-zIndex-1lgpqti"
|
||||
>
|
||||
<span
|
||||
class="rn-position-u8s1d rn-zIndex-1wyyakw"
|
||||
style="bottom:-10px;left:-5px;right:-5px;top:-10px;"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`components/View prop "pointerEvents" 1`] = `
|
||||
<div
|
||||
class="rn-alignItems-1oszu61 rn-borderTopStyle-1efd50x rn-borderRightStyle-14skgim rn-borderBottomStyle-rull8r rn-borderLeftStyle-mm0ijv rn-borderTopWidth-13yce4e rn-borderRightWidth-fnigne rn-borderBottomWidth-ndvcnb rn-borderLeftWidth-gxnn5r rn-boxSizing-deolkf rn-display-6koalj rn-flexShrink-1qe8dj5 rn-flexBasis-1mlwlqe rn-flexDirection-eqz5dr rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw rn-minHeight-ifefl9 rn-minWidth-bcqeeo rn-paddingTop-wk8lta rn-paddingRight-9aemit rn-paddingBottom-1mdbw0j rn-paddingLeft-gy4na3 rn-pointerEvents-ah5dr5 rn-position-bnwqim"
|
||||
/>
|
||||
Object {
|
||||
"bottom": "-10px",
|
||||
"left": "-5px",
|
||||
"right": "-5px",
|
||||
"top": "-10px",
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* eslint-env jasmine, jest */
|
||||
|
||||
import React from 'react';
|
||||
import { render, shallow } from 'enzyme';
|
||||
import { shallow } from 'enzyme';
|
||||
import View from '../';
|
||||
|
||||
describe('components/View', () => {
|
||||
@@ -12,26 +12,48 @@ describe('components/View', () => {
|
||||
});
|
||||
});
|
||||
|
||||
test('prop "children"', () => {
|
||||
const children = <View testID="1" />;
|
||||
const component = shallow(<View>{children}</View>);
|
||||
expect(component.contains(children)).toEqual(true);
|
||||
describe('prop "children"', () => {
|
||||
test('text node throws error (single)', () => {
|
||||
const render = () => shallow(<View>'hello'</View>);
|
||||
expect(render).toThrow();
|
||||
});
|
||||
|
||||
test('text node throws error (array)', () => {
|
||||
const render = () =>
|
||||
shallow(
|
||||
<View>
|
||||
<View />
|
||||
'hello'
|
||||
<View />
|
||||
</View>
|
||||
);
|
||||
expect(render).toThrow();
|
||||
});
|
||||
|
||||
test('non-text is rendered', () => {
|
||||
const children = <View testID="1" />;
|
||||
const component = shallow(<View>{children}</View>);
|
||||
expect(component.contains(children)).toEqual(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('prop "hitSlop"', () => {
|
||||
it('renders a span with negative position offsets', () => {
|
||||
const component = render(<View hitSlop={{ top: 10, bottom: 10, right: 5, left: 5 }} />);
|
||||
expect(component).toMatchSnapshot();
|
||||
const component = shallow(<View hitSlop={{ top: 10, bottom: 10, right: 5, left: 5 }} />);
|
||||
const span = component.find('span');
|
||||
expect(span.length).toBe(1);
|
||||
expect(span.prop('style')).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('handles partial offsets', () => {
|
||||
const component = render(<View hitSlop={{ top: 10 }} />);
|
||||
expect(component).toMatchSnapshot();
|
||||
const component = shallow(<View hitSlop={{ top: 10 }} />);
|
||||
const span = component.find('span');
|
||||
expect(span.prop('style')).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
test('prop "pointerEvents"', () => {
|
||||
const component = render(<View pointerEvents="box-only" />);
|
||||
expect(component).toMatchSnapshot();
|
||||
const component = shallow(<View pointerEvents="box-only" />);
|
||||
expect(component.prop('className').indexOf('pointerEvents') > -1).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -11,6 +11,7 @@ import applyLayout from '../../modules/applyLayout';
|
||||
import applyNativeMethods from '../../modules/applyNativeMethods';
|
||||
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 React, { Component } from 'react';
|
||||
@@ -49,6 +50,15 @@ class View extends Component {
|
||||
...otherProps
|
||||
} = this.props;
|
||||
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
React.Children.toArray(this.props.children).forEach(item => {
|
||||
invariant(
|
||||
typeof item !== 'string',
|
||||
`Unexpected text node: ${item}. A text node cannot be a child of a <View>.`
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
const { isInAParentText } = this.context;
|
||||
|
||||
otherProps.style = [styles.initial, isInAParentText && styles.inline, style];
|
||||
|
||||
134
src/index.js
134
src/index.js
@@ -1,134 +1,2 @@
|
||||
import {
|
||||
// top-level API
|
||||
findNodeHandle,
|
||||
render,
|
||||
unmountComponentAtNode,
|
||||
|
||||
// modules
|
||||
createElement,
|
||||
NativeModules,
|
||||
processColor,
|
||||
|
||||
// APIs
|
||||
Animated,
|
||||
AppRegistry,
|
||||
AppState,
|
||||
AsyncStorage,
|
||||
BackAndroid,
|
||||
Clipboard,
|
||||
Dimensions,
|
||||
Easing,
|
||||
I18nManager,
|
||||
InteractionManager,
|
||||
Keyboard,
|
||||
Linking,
|
||||
NetInfo,
|
||||
PanResponder,
|
||||
PixelRatio,
|
||||
Platform,
|
||||
StyleSheet,
|
||||
UIManager,
|
||||
Vibration,
|
||||
|
||||
// components
|
||||
ActivityIndicator,
|
||||
Button,
|
||||
FlatList,
|
||||
Image,
|
||||
KeyboardAvoidingView,
|
||||
ListView,
|
||||
Modal,
|
||||
Picker,
|
||||
ProgressBar,
|
||||
RefreshControl,
|
||||
ScrollView,
|
||||
SectionList,
|
||||
Slider,
|
||||
StatusBar,
|
||||
Switch,
|
||||
Text,
|
||||
TextInput,
|
||||
Touchable,
|
||||
TouchableHighlight,
|
||||
TouchableNativeFeedback,
|
||||
TouchableOpacity,
|
||||
TouchableWithoutFeedback,
|
||||
View,
|
||||
VirtualizedList,
|
||||
|
||||
// propTypes
|
||||
ColorPropType,
|
||||
EdgeInsetsPropType,
|
||||
PointPropType,
|
||||
TextPropTypes,
|
||||
ViewPropTypes
|
||||
} from './module';
|
||||
|
||||
const ReactNative = {
|
||||
// top-level API
|
||||
findNodeHandle,
|
||||
render,
|
||||
unmountComponentAtNode,
|
||||
|
||||
// modules
|
||||
createElement,
|
||||
NativeModules,
|
||||
processColor,
|
||||
|
||||
// APIs
|
||||
Animated,
|
||||
AppRegistry,
|
||||
AppState,
|
||||
AsyncStorage,
|
||||
BackAndroid,
|
||||
BackHandler: BackAndroid,
|
||||
Clipboard,
|
||||
Dimensions,
|
||||
Easing,
|
||||
I18nManager,
|
||||
InteractionManager,
|
||||
Keyboard,
|
||||
Linking,
|
||||
NetInfo,
|
||||
PanResponder,
|
||||
PixelRatio,
|
||||
Platform,
|
||||
StyleSheet,
|
||||
UIManager,
|
||||
Vibration,
|
||||
|
||||
// components
|
||||
ActivityIndicator,
|
||||
Button,
|
||||
FlatList,
|
||||
Image,
|
||||
KeyboardAvoidingView,
|
||||
ListView,
|
||||
Modal,
|
||||
Picker,
|
||||
ProgressBar,
|
||||
RefreshControl,
|
||||
ScrollView,
|
||||
SectionList,
|
||||
Slider,
|
||||
StatusBar,
|
||||
Switch,
|
||||
Text,
|
||||
TextInput,
|
||||
Touchable,
|
||||
TouchableHighlight,
|
||||
TouchableNativeFeedback,
|
||||
TouchableOpacity,
|
||||
TouchableWithoutFeedback,
|
||||
View,
|
||||
VirtualizedList,
|
||||
|
||||
// propTypes
|
||||
ColorPropType,
|
||||
EdgeInsetsPropType,
|
||||
PointPropType,
|
||||
TextPropTypes,
|
||||
ViewPropTypes
|
||||
};
|
||||
|
||||
import ReactNative from './module';
|
||||
module.exports = ReactNative;
|
||||
|
||||
240
src/module.js
240
src/module.js
@@ -1,61 +1,191 @@
|
||||
export { default as createElement } from './modules/createElement';
|
||||
export { default as findNodeHandle } from './modules/findNodeHandle';
|
||||
export { default as NativeModules } from './modules/NativeModules';
|
||||
export { default as processColor } from './modules/processColor';
|
||||
export { render, unmountComponentAtNode } from 'react-dom';
|
||||
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';
|
||||
|
||||
// APIs
|
||||
export { default as Animated } from './apis/Animated';
|
||||
export { default as AppRegistry } from './apis/AppRegistry';
|
||||
export { default as AppState } from './apis/AppState';
|
||||
export { default as AsyncStorage } from './apis/AsyncStorage';
|
||||
export { default as BackAndroid } from './apis/BackAndroid';
|
||||
export { default as Clipboard } from './apis/Clipboard';
|
||||
export { default as Dimensions } from './apis/Dimensions';
|
||||
export { default as Easing } from 'animated/lib/Easing';
|
||||
export { default as I18nManager } from './apis/I18nManager';
|
||||
export { default as Keyboard } from './apis/Keyboard';
|
||||
export { default as InteractionManager } from './apis/InteractionManager';
|
||||
export { default as Linking } from './apis/Linking';
|
||||
export { default as NetInfo } from './apis/NetInfo';
|
||||
export { default as PanResponder } from './apis/PanResponder';
|
||||
export { default as PixelRatio } from './apis/PixelRatio';
|
||||
export { default as Platform } from './apis/Platform';
|
||||
export { default as StyleSheet } from './apis/StyleSheet';
|
||||
export { default as UIManager } from './apis/UIManager';
|
||||
export { default as Vibration } from './apis/Vibration';
|
||||
import Animated from './apis/Animated';
|
||||
import AppRegistry from './apis/AppRegistry';
|
||||
import AppState from './apis/AppState';
|
||||
import AsyncStorage from './apis/AsyncStorage';
|
||||
import BackHandler from './apis/BackHandler';
|
||||
import Clipboard from './apis/Clipboard';
|
||||
import Dimensions from './apis/Dimensions';
|
||||
import Easing from './apis/Easing';
|
||||
import I18nManager from './apis/I18nManager';
|
||||
import Keyboard from './apis/Keyboard';
|
||||
import InteractionManager from './apis/InteractionManager';
|
||||
import Linking from './apis/Linking';
|
||||
import NetInfo from './apis/NetInfo';
|
||||
import PanResponder from './apis/PanResponder';
|
||||
import PixelRatio from './apis/PixelRatio';
|
||||
import Platform from './apis/Platform';
|
||||
import StyleSheet from './apis/StyleSheet';
|
||||
import UIManager from './apis/UIManager';
|
||||
import Vibration from './apis/Vibration';
|
||||
|
||||
// components
|
||||
export { default as ActivityIndicator } from './components/ActivityIndicator';
|
||||
export { default as Button } from './components/Button';
|
||||
export { default as FlatList } from './components/FlatList';
|
||||
export { default as Image } from './components/Image';
|
||||
export { default as KeyboardAvoidingView } from './components/KeyboardAvoidingView';
|
||||
export { default as ListView } from './components/ListView';
|
||||
export { default as Modal } from './components/Modal';
|
||||
export { default as Picker } from './components/Picker';
|
||||
export { default as ProgressBar } from './components/ProgressBar';
|
||||
export { default as RefreshControl } from './components/RefreshControl';
|
||||
export { default as ScrollView } from './components/ScrollView';
|
||||
export { default as SectionList } from './components/SectionList';
|
||||
export { default as Slider } from './components/Slider';
|
||||
export { default as StatusBar } from './components/StatusBar';
|
||||
export { default as Switch } from './components/Switch';
|
||||
export { default as Text } from './components/Text';
|
||||
export { default as TextInput } from './components/TextInput';
|
||||
export { default as Touchable } from './components/Touchable/Touchable';
|
||||
export { default as TouchableHighlight } from './components/Touchable/TouchableHighlight';
|
||||
export { default as TouchableNativeFeedback } from './components/Touchable/TouchableNativeFeedback';
|
||||
export { default as TouchableOpacity } from './components/Touchable/TouchableOpacity';
|
||||
export {
|
||||
default as TouchableWithoutFeedback
|
||||
} from './components/Touchable/TouchableWithoutFeedback';
|
||||
export { default as View } from './components/View';
|
||||
export { default as VirtualizedList } from './components/VirtualizedList';
|
||||
import ActivityIndicator from './components/ActivityIndicator';
|
||||
import Button from './components/Button';
|
||||
import FlatList from './components/FlatList';
|
||||
import Image from './components/Image';
|
||||
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 ScrollView from './components/ScrollView';
|
||||
import SectionList from './components/SectionList';
|
||||
import Slider from './components/Slider';
|
||||
import StatusBar from './components/StatusBar';
|
||||
import Switch from './components/Switch';
|
||||
import Text from './components/Text';
|
||||
import TextInput from './components/TextInput';
|
||||
import Touchable from './components/Touchable/Touchable';
|
||||
import TouchableHighlight from './components/Touchable/TouchableHighlight';
|
||||
import TouchableNativeFeedback from './components/Touchable/TouchableNativeFeedback';
|
||||
import TouchableOpacity from './components/Touchable/TouchableOpacity';
|
||||
import TouchableWithoutFeedback from './components/Touchable/TouchableWithoutFeedback';
|
||||
import View from './components/View';
|
||||
import VirtualizedList from './components/VirtualizedList';
|
||||
|
||||
// propTypes
|
||||
export { default as ColorPropType } from './propTypes/ColorPropType';
|
||||
export { default as EdgeInsetsPropType } from './propTypes/EdgeInsetsPropType';
|
||||
export { default as PointPropType } from './propTypes/PointPropType';
|
||||
export { default as TextPropTypes } from './components/Text/TextPropTypes';
|
||||
export { default as ViewPropTypes } from './components/View/ViewPropTypes';
|
||||
import ColorPropType from './propTypes/ColorPropType';
|
||||
import EdgeInsetsPropType from './propTypes/EdgeInsetsPropType';
|
||||
import PointPropType from './propTypes/PointPropType';
|
||||
import TextPropTypes from './components/Text/TextPropTypes';
|
||||
import ViewPropTypes from './components/View/ViewPropTypes';
|
||||
|
||||
export {
|
||||
// top-level API
|
||||
findNodeHandle,
|
||||
hydrate,
|
||||
render,
|
||||
unmountComponentAtNode,
|
||||
// modules
|
||||
createElement,
|
||||
NativeModules,
|
||||
processColor,
|
||||
// APIs
|
||||
Animated,
|
||||
AppRegistry,
|
||||
AppState,
|
||||
AsyncStorage,
|
||||
BackHandler,
|
||||
Clipboard,
|
||||
Dimensions,
|
||||
Easing,
|
||||
I18nManager,
|
||||
InteractionManager,
|
||||
Keyboard,
|
||||
Linking,
|
||||
NetInfo,
|
||||
PanResponder,
|
||||
PixelRatio,
|
||||
Platform,
|
||||
StyleSheet,
|
||||
UIManager,
|
||||
Vibration,
|
||||
// components
|
||||
ActivityIndicator,
|
||||
Button,
|
||||
FlatList,
|
||||
Image,
|
||||
KeyboardAvoidingView,
|
||||
ListView,
|
||||
Modal,
|
||||
Picker,
|
||||
ProgressBar,
|
||||
RefreshControl,
|
||||
ScrollView,
|
||||
SectionList,
|
||||
Slider,
|
||||
StatusBar,
|
||||
Switch,
|
||||
Text,
|
||||
TextInput,
|
||||
Touchable,
|
||||
TouchableHighlight,
|
||||
TouchableNativeFeedback,
|
||||
TouchableOpacity,
|
||||
TouchableWithoutFeedback,
|
||||
View,
|
||||
VirtualizedList,
|
||||
// propTypes
|
||||
ColorPropType,
|
||||
EdgeInsetsPropType,
|
||||
PointPropType,
|
||||
TextPropTypes,
|
||||
ViewPropTypes
|
||||
};
|
||||
|
||||
const ReactNative = {
|
||||
// top-level API
|
||||
findNodeHandle,
|
||||
hydrate,
|
||||
render,
|
||||
unmountComponentAtNode,
|
||||
|
||||
// modules
|
||||
createElement,
|
||||
NativeModules,
|
||||
processColor,
|
||||
|
||||
// APIs
|
||||
Animated,
|
||||
AppRegistry,
|
||||
AppState,
|
||||
AsyncStorage,
|
||||
BackHandler,
|
||||
Clipboard,
|
||||
Dimensions,
|
||||
Easing,
|
||||
I18nManager,
|
||||
InteractionManager,
|
||||
Keyboard,
|
||||
Linking,
|
||||
NetInfo,
|
||||
PanResponder,
|
||||
PixelRatio,
|
||||
Platform,
|
||||
StyleSheet,
|
||||
UIManager,
|
||||
Vibration,
|
||||
|
||||
// components
|
||||
ActivityIndicator,
|
||||
Button,
|
||||
FlatList,
|
||||
Image,
|
||||
KeyboardAvoidingView,
|
||||
ListView,
|
||||
Modal,
|
||||
Picker,
|
||||
ProgressBar,
|
||||
RefreshControl,
|
||||
ScrollView,
|
||||
SectionList,
|
||||
Slider,
|
||||
StatusBar,
|
||||
Switch,
|
||||
Text,
|
||||
TextInput,
|
||||
Touchable,
|
||||
TouchableHighlight,
|
||||
TouchableNativeFeedback,
|
||||
TouchableOpacity,
|
||||
TouchableWithoutFeedback,
|
||||
View,
|
||||
VirtualizedList,
|
||||
|
||||
// propTypes
|
||||
ColorPropType,
|
||||
EdgeInsetsPropType,
|
||||
PointPropType,
|
||||
TextPropTypes,
|
||||
ViewPropTypes
|
||||
};
|
||||
|
||||
export default ReactNative;
|
||||
|
||||
@@ -22,7 +22,7 @@ const ImageLoader = {
|
||||
getSize(uri, success, failure) {
|
||||
let complete = false;
|
||||
const interval = setInterval(callback, 16);
|
||||
const requestId = ImageLoader.load(uri, callback, callback);
|
||||
const requestId = ImageLoader.load(uri, callback, errorCallback);
|
||||
|
||||
function callback() {
|
||||
const image = requests[`${requestId}`];
|
||||
@@ -38,6 +38,14 @@ const ImageLoader = {
|
||||
clearInterval(interval);
|
||||
}
|
||||
}
|
||||
|
||||
function errorCallback() {
|
||||
if (typeof failure === 'function') {
|
||||
failure();
|
||||
}
|
||||
ImageLoader.abort(requestId);
|
||||
clearInterval(interval);
|
||||
}
|
||||
},
|
||||
load(uri, onLoad, onError): number {
|
||||
id += 1;
|
||||
|
||||
@@ -4,6 +4,9 @@ exports[`modules/createElement it normalizes event.nativeEvent 1`] = `
|
||||
Object {
|
||||
"_normalized": true,
|
||||
"changedTouches": Array [],
|
||||
"identifier": undefined,
|
||||
"locationX": undefined,
|
||||
"locationY": undefined,
|
||||
"pageX": undefined,
|
||||
"pageY": undefined,
|
||||
"preventDefault": [Function],
|
||||
|
||||
@@ -19,11 +19,7 @@ describe('modules/createElement', () => {
|
||||
};
|
||||
const component = shallow(createElement('span', { onClick }));
|
||||
component.find('span').simulate('click', {
|
||||
nativeEvent: {
|
||||
preventDefault() {},
|
||||
stopImmediatePropagation() {},
|
||||
stopPropagation() {}
|
||||
}
|
||||
nativeEvent: {}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -38,11 +34,7 @@ describe('modules/createElement', () => {
|
||||
);
|
||||
component.find('span').simulate('keyPress', {
|
||||
isDefaultPrevented() {},
|
||||
nativeEvent: {
|
||||
preventDefault() {},
|
||||
stopImmediatePropagation() {},
|
||||
stopPropagation() {}
|
||||
},
|
||||
nativeEvent: {},
|
||||
preventDefault() {},
|
||||
which
|
||||
});
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
// based on https://github.com/facebook/react/pull/4303/files
|
||||
|
||||
import EventPluginHub from 'react-dom/lib/EventPluginHub';
|
||||
import normalizeNativeEvent from '../normalizeNativeEvent';
|
||||
import ResponderEventPlugin from 'react-dom/lib/ResponderEventPlugin';
|
||||
import ResponderTouchHistoryStore from 'react-dom/lib/ResponderTouchHistoryStore';
|
||||
import ReactDOM from 'react-dom';
|
||||
import ReactDOMUnstableNativeDependencies from 'react-dom/unstable-native-dependencies';
|
||||
|
||||
const { EventPluginHub } = ReactDOM.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
|
||||
const { ResponderEventPlugin, ResponderTouchHistoryStore } = ReactDOMUnstableNativeDependencies;
|
||||
|
||||
const topMouseDown = 'topMouseDown';
|
||||
const topMouseMove = 'topMouseMove';
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`modules/normalizeNativeEvent mouse events simulated event 1`] = `
|
||||
Object {
|
||||
"_normalized": true,
|
||||
"changedTouches": Array [
|
||||
Object {
|
||||
"_normalized": true,
|
||||
"clientX": undefined,
|
||||
"clientY": undefined,
|
||||
"force": undefined,
|
||||
"identifier": 0,
|
||||
"locationX": undefined,
|
||||
"locationY": undefined,
|
||||
"pageX": undefined,
|
||||
"pageY": undefined,
|
||||
"screenX": undefined,
|
||||
"screenY": undefined,
|
||||
"target": undefined,
|
||||
"timestamp": 1496876171255,
|
||||
},
|
||||
],
|
||||
"identifier": 0,
|
||||
"locationX": undefined,
|
||||
"locationY": undefined,
|
||||
"pageX": undefined,
|
||||
"pageY": undefined,
|
||||
"preventDefault": [Function],
|
||||
"stopImmediatePropagation": [Function],
|
||||
"stopPropagation": [Function],
|
||||
"target": undefined,
|
||||
"timestamp": 1496876171255,
|
||||
"touches": Array [],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`modules/normalizeNativeEvent mouse events synthetic event 1`] = `
|
||||
Object {
|
||||
"_normalized": true,
|
||||
"changedTouches": Array [
|
||||
Object {
|
||||
"_normalized": true,
|
||||
"clientX": 100,
|
||||
"clientY": 100,
|
||||
"force": false,
|
||||
"identifier": 0,
|
||||
"locationX": 100,
|
||||
"locationY": 100,
|
||||
"pageX": 300,
|
||||
"pageY": 300,
|
||||
"screenX": 400,
|
||||
"screenY": 400,
|
||||
"target": undefined,
|
||||
"timestamp": 1496876171255,
|
||||
},
|
||||
],
|
||||
"identifier": 0,
|
||||
"locationX": 200,
|
||||
"locationY": 200,
|
||||
"pageX": 300,
|
||||
"pageY": 300,
|
||||
"preventDefault": [Function],
|
||||
"stopImmediatePropagation": [Function],
|
||||
"stopPropagation": [Function],
|
||||
"target": undefined,
|
||||
"timestamp": 1496876171255,
|
||||
"touches": Array [],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`modules/normalizeNativeEvent touch events simulated event 1`] = `
|
||||
Object {
|
||||
"_normalized": true,
|
||||
"changedTouches": Array [],
|
||||
"identifier": undefined,
|
||||
"locationX": undefined,
|
||||
"locationY": undefined,
|
||||
"pageX": undefined,
|
||||
"pageY": undefined,
|
||||
"preventDefault": [Function],
|
||||
"stopImmediatePropagation": [Function],
|
||||
"stopPropagation": [Function],
|
||||
"target": undefined,
|
||||
"timestamp": 1496876171255,
|
||||
"touches": Array [],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`modules/normalizeNativeEvent touch events synthetic event 1`] = `
|
||||
Object {
|
||||
"_normalized": true,
|
||||
"changedTouches": Array [
|
||||
Object {
|
||||
"_normalized": true,
|
||||
"clientX": 100,
|
||||
"clientY": 100,
|
||||
"force": false,
|
||||
"identifier": undefined,
|
||||
"locationX": undefined,
|
||||
"locationY": undefined,
|
||||
"pageX": 300,
|
||||
"pageY": 300,
|
||||
"radiusX": 10,
|
||||
"radiusY": 10,
|
||||
"rotationAngle": 45,
|
||||
"screenX": 400,
|
||||
"screenY": 400,
|
||||
"target": undefined,
|
||||
"timestamp": 1496876171255,
|
||||
},
|
||||
],
|
||||
"identifier": undefined,
|
||||
"locationX": undefined,
|
||||
"locationY": undefined,
|
||||
"pageX": 300,
|
||||
"pageY": 300,
|
||||
"preventDefault": [Function],
|
||||
"stopImmediatePropagation": [Function],
|
||||
"stopPropagation": [Function],
|
||||
"target": undefined,
|
||||
"timestamp": 1496876171255,
|
||||
"touches": Array [],
|
||||
}
|
||||
`;
|
||||
82
src/modules/normalizeNativeEvent/__tests__/index-test.js
Normal file
82
src/modules/normalizeNativeEvent/__tests__/index-test.js
Normal file
@@ -0,0 +1,82 @@
|
||||
/* eslint-env jasmine, jest */
|
||||
|
||||
import normalizeNativeEvent from '..';
|
||||
|
||||
const normalizeEvent = nativeEvent => {
|
||||
const result = normalizeNativeEvent(nativeEvent);
|
||||
result.timestamp = 1496876171255;
|
||||
if (result.changedTouches && result.changedTouches[0]) {
|
||||
result.changedTouches[0].timestamp = 1496876171255;
|
||||
}
|
||||
if (result.touches && result.touches[0]) {
|
||||
result.touches[0].timestamp = 1496876171255;
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
describe('modules/normalizeNativeEvent', () => {
|
||||
describe('mouse events', () => {
|
||||
test('simulated event', () => {
|
||||
const nativeEvent = {
|
||||
type: 'mouseup'
|
||||
};
|
||||
|
||||
const result = normalizeEvent(nativeEvent);
|
||||
expect(result).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('synthetic event', () => {
|
||||
const nativeEvent = {
|
||||
type: 'mouseup',
|
||||
clientX: 100,
|
||||
clientY: 100,
|
||||
force: false,
|
||||
offsetX: 200,
|
||||
offsetY: 200,
|
||||
pageX: 300,
|
||||
pageY: 300,
|
||||
screenX: 400,
|
||||
screenY: 400
|
||||
};
|
||||
|
||||
const result = normalizeEvent(nativeEvent);
|
||||
expect(result).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
describe('touch events', () => {
|
||||
test('simulated event', () => {
|
||||
const nativeEvent = {
|
||||
type: 'touchstart'
|
||||
};
|
||||
|
||||
const result = normalizeEvent(nativeEvent);
|
||||
expect(result).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('synthetic event', () => {
|
||||
const nativeEvent = {
|
||||
type: 'touchstart',
|
||||
changedTouches: [
|
||||
{
|
||||
clientX: 100,
|
||||
clientY: 100,
|
||||
force: false,
|
||||
pageX: 300,
|
||||
pageY: 300,
|
||||
radiusX: 10,
|
||||
radiusY: 10,
|
||||
rotationAngle: 45,
|
||||
screenX: 400,
|
||||
screenY: 400
|
||||
}
|
||||
],
|
||||
pageX: 300,
|
||||
pageY: 300
|
||||
};
|
||||
|
||||
const result = normalizeEvent(nativeEvent);
|
||||
expect(result).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -5,19 +5,31 @@
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @noflow
|
||||
* @flow
|
||||
*/
|
||||
|
||||
const emptyArray = [];
|
||||
const emptyFunction = () => {};
|
||||
|
||||
// Mobile Safari re-uses touch objects, so we copy the properties we want and normalize the identifier
|
||||
const normalizeTouches = (touches = emptyArray) =>
|
||||
Array.prototype.slice.call(touches).map(touch => {
|
||||
const identifier = touch.identifier > 20 ? touch.identifier % 20 : touch.identifier;
|
||||
const normalizeTouches = touches => {
|
||||
if (!touches) {
|
||||
return emptyArray;
|
||||
}
|
||||
|
||||
const rect = touch.target && touch.target.getBoundingClientRect();
|
||||
const locationX = touch.pageX - rect.left;
|
||||
const locationY = touch.pageY - rect.top;
|
||||
return Array.prototype.slice.call(touches).map(touch => {
|
||||
const identifier = touch.identifier > 20 ? touch.identifier % 20 : touch.identifier;
|
||||
let locationX, locationY;
|
||||
|
||||
const node = touch.target;
|
||||
if (node) {
|
||||
const isElement = node.nodeType === 1 /* Node.ELEMENT_NODE */;
|
||||
if (isElement && typeof node.getBoundingClientRect === 'function') {
|
||||
const rect = node.getBoundingClientRect();
|
||||
locationX = touch.pageX - rect.left;
|
||||
locationY = touch.pageY - rect.top;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
_normalized: true,
|
||||
@@ -40,19 +52,36 @@ const normalizeTouches = (touches = emptyArray) =>
|
||||
timestamp: Date.now()
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
function normalizeTouchEvent(nativeEvent) {
|
||||
const changedTouches = normalizeTouches(nativeEvent.changedTouches);
|
||||
const touches = normalizeTouches(nativeEvent.touches);
|
||||
|
||||
const preventDefault =
|
||||
typeof nativeEvent.preventDefault === 'function'
|
||||
? nativeEvent.preventDefault.bind(nativeEvent)
|
||||
: emptyFunction;
|
||||
const stopImmediatePropagation =
|
||||
typeof nativeEvent.stopImmediatePropagation === 'function'
|
||||
? nativeEvent.stopImmediatePropagation.bind(nativeEvent)
|
||||
: emptyFunction;
|
||||
const stopPropagation =
|
||||
typeof nativeEvent.stopPropagation === 'function'
|
||||
? nativeEvent.stopPropagation.bind(nativeEvent)
|
||||
: emptyFunction;
|
||||
|
||||
const event = {
|
||||
_normalized: true,
|
||||
changedTouches,
|
||||
identifier: undefined,
|
||||
locationX: undefined,
|
||||
locationY: undefined,
|
||||
pageX: nativeEvent.pageX,
|
||||
pageY: nativeEvent.pageY,
|
||||
preventDefault: nativeEvent.preventDefault.bind(nativeEvent),
|
||||
stopImmediatePropagation: nativeEvent.stopImmediatePropagation.bind(nativeEvent),
|
||||
stopPropagation: nativeEvent.stopPropagation.bind(nativeEvent),
|
||||
preventDefault,
|
||||
stopImmediatePropagation,
|
||||
stopPropagation,
|
||||
target: nativeEvent.target,
|
||||
// normalize the timestamp
|
||||
// https://stackoverflow.com/questions/26177087/ios-8-mobile-safari-wrong-timestamp-on-touch-events
|
||||
@@ -89,6 +118,20 @@ function normalizeMouseEvent(nativeEvent) {
|
||||
timestamp: Date.now()
|
||||
}
|
||||
];
|
||||
|
||||
const preventDefault =
|
||||
typeof nativeEvent.preventDefault === 'function'
|
||||
? nativeEvent.preventDefault.bind(nativeEvent)
|
||||
: emptyFunction;
|
||||
const stopImmediatePropagation =
|
||||
typeof nativeEvent.stopImmediatePropagation === 'function'
|
||||
? nativeEvent.stopImmediatePropagation.bind(nativeEvent)
|
||||
: emptyFunction;
|
||||
const stopPropagation =
|
||||
typeof nativeEvent.stopPropagation === 'function'
|
||||
? nativeEvent.stopPropagation.bind(nativeEvent)
|
||||
: emptyFunction;
|
||||
|
||||
return {
|
||||
_normalized: true,
|
||||
changedTouches: touches,
|
||||
@@ -97,22 +140,27 @@ function normalizeMouseEvent(nativeEvent) {
|
||||
locationY: nativeEvent.offsetY,
|
||||
pageX: nativeEvent.pageX,
|
||||
pageY: nativeEvent.pageY,
|
||||
preventDefault: nativeEvent.preventDefault.bind(nativeEvent),
|
||||
stopImmediatePropagation: nativeEvent.stopImmediatePropagation.bind(nativeEvent),
|
||||
stopPropagation: nativeEvent.stopPropagation.bind(nativeEvent),
|
||||
preventDefault,
|
||||
stopImmediatePropagation,
|
||||
stopPropagation,
|
||||
target: nativeEvent.target,
|
||||
timestamp: touches[0].timestamp,
|
||||
touches: nativeEvent.type === 'mouseup' ? emptyArray : touches
|
||||
};
|
||||
}
|
||||
|
||||
function normalizeNativeEvent(nativeEvent) {
|
||||
if (nativeEvent._normalized) {
|
||||
// TODO: how to best handle keyboard events?
|
||||
function normalizeNativeEvent(nativeEvent: Object) {
|
||||
if (!nativeEvent || nativeEvent._normalized) {
|
||||
return nativeEvent;
|
||||
}
|
||||
const eventType = nativeEvent.type || '';
|
||||
const mouse = eventType.indexOf('mouse') >= 0;
|
||||
return mouse ? normalizeMouseEvent(nativeEvent) : normalizeTouchEvent(nativeEvent);
|
||||
if (mouse) {
|
||||
return normalizeMouseEvent(nativeEvent);
|
||||
} else {
|
||||
return normalizeTouchEvent(nativeEvent);
|
||||
}
|
||||
}
|
||||
|
||||
export default normalizeNativeEvent;
|
||||
|
||||
@@ -2,6 +2,7 @@ import crossFade from 'inline-style-prefixer/static/plugins/crossFade';
|
||||
import cursor from 'inline-style-prefixer/static/plugins/cursor';
|
||||
import filter from 'inline-style-prefixer/static/plugins/filter';
|
||||
import flex from 'inline-style-prefixer/static/plugins/flex';
|
||||
import flexboxIE from 'inline-style-prefixer/static/plugins/flexboxIE';
|
||||
import flexboxOld from 'inline-style-prefixer/static/plugins/flexboxOld';
|
||||
import gradient from 'inline-style-prefixer/static/plugins/gradient';
|
||||
import imageSet from 'inline-style-prefixer/static/plugins/imageSet';
|
||||
@@ -21,6 +22,7 @@ export default {
|
||||
cursor,
|
||||
filter,
|
||||
flex,
|
||||
flexboxIE,
|
||||
flexboxOld,
|
||||
gradient,
|
||||
imageSet,
|
||||
@@ -82,13 +84,13 @@ export default {
|
||||
columns: wm,
|
||||
columnSpan: wm,
|
||||
columnWidth: wm,
|
||||
flex: w,
|
||||
flex: wms,
|
||||
flexBasis: w,
|
||||
flexDirection: w,
|
||||
flexDirection: wms,
|
||||
flexGrow: w,
|
||||
flexFlow: w,
|
||||
flexFlow: wms,
|
||||
flexShrink: w,
|
||||
flexWrap: w,
|
||||
flexWrap: wms,
|
||||
alignContent: w,
|
||||
alignItems: w,
|
||||
alignSelf: w,
|
||||
@@ -122,6 +124,7 @@ export default {
|
||||
wrapFlow: ms,
|
||||
wrapThrough: ms,
|
||||
wrapMargin: ms,
|
||||
touchAction: ms,
|
||||
gridTemplateColumns: ms,
|
||||
gridTemplateRows: ms,
|
||||
gridTemplateAreas: ms,
|
||||
|
||||
@@ -10,6 +10,9 @@
|
||||
* @flow
|
||||
*/
|
||||
|
||||
const isWebColor = (color: string) =>
|
||||
color === 'currentcolor' || color === 'inherit' || color.indexOf('var(') === 0;
|
||||
|
||||
const colorPropType = function(isRequired, props, propName, componentName, location, propFullName) {
|
||||
const normalizeColor = require('normalize-css-color');
|
||||
const color = props[propName];
|
||||
@@ -35,8 +38,8 @@ const colorPropType = function(isRequired, props, propName, componentName, locat
|
||||
return;
|
||||
}
|
||||
|
||||
// Web supports additional color keywords and custom property values
|
||||
if (color === 'currentcolor' || color === 'inherit' || color.indexOf('var(') === 0) {
|
||||
if (typeof color === 'string' && isWebColor(color)) {
|
||||
// Web supports additional color keywords and custom property values. Ignore them.
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
2
src/vendor/warnValidStyle/index.js
vendored
2
src/vendor/warnValidStyle/index.js
vendored
@@ -11,8 +11,6 @@
|
||||
* @providesModule warnValidStyle
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
var emptyFunction = require('fbjs/lib/emptyFunction');
|
||||
|
||||
var warnValidStyle = emptyFunction;
|
||||
|
||||
Reference in New Issue
Block a user