mirror of
https://github.com/zhigang1992/react-native-web.git
synced 2026-04-23 04:00:04 +08:00
Compare commits
24 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
79456d5920 | ||
|
|
2d1e303a6a | ||
|
|
209ff1fa40 | ||
|
|
34d8160a43 | ||
|
|
ada5651be2 | ||
|
|
9fe9d3c68a | ||
|
|
1e202b6bd5 | ||
|
|
2b77bfd853 | ||
|
|
d0ac55aa4f | ||
|
|
66dd1bd9ef | ||
|
|
6add18c6f0 | ||
|
|
30d7c31b65 | ||
|
|
f7e6b43422 | ||
|
|
4b3f6efb21 | ||
|
|
85e098deec | ||
|
|
c949b0145a | ||
|
|
86b4cf5a51 | ||
|
|
1b7ce4eec6 | ||
|
|
8c8978ff76 | ||
|
|
513b5de881 | ||
|
|
145f80409d | ||
|
|
6d92cc5ec3 | ||
|
|
ec6458c09d | ||
|
|
a84c2ac95e |
11
README.md
11
README.md
@@ -23,10 +23,11 @@ React Native for Web can also render to HTML and critical CSS on the server
|
|||||||
using Node.js.
|
using Node.js.
|
||||||
|
|
||||||
Who is using React Native in production web apps?
|
Who is using React Native in production web apps?
|
||||||
[Twitter](https://mobile.twitter.com), [Major League
|
[Twitter](https://mobile.twitter.com),
|
||||||
Soccer](https://matchcenter.mlssoccer.com),
|
[Major League Soccer](https://matchcenter.mlssoccer.com),
|
||||||
[Flipkart](https://www.flipkart.com/), Uber, [The
|
[Flipkart](https://twitter.com/naqvitalha/status/969577892991549440),
|
||||||
Times](https://github.com/newsuk/times-components).
|
[Uber](https://www.youtube.com/watch?v=RV9rxrNIxnY),
|
||||||
|
[The Times](https://github.com/newsuk/times-components), [DataCamp](https://www.datacamp.com/community/tech/porting-practice-to-web-part1).
|
||||||
|
|
||||||
Browser support: Chrome, Firefox, Edge, Safari 7+, IE 10+.
|
Browser support: Chrome, Firefox, Edge, Safari 7+, IE 10+.
|
||||||
|
|
||||||
@@ -139,7 +140,7 @@ React Native v0.55
|
|||||||
| Picker | ✓ | |
|
| Picker | ✓ | |
|
||||||
| RefreshControl | ✘ | Not started ([#1027](https://github.com/necolas/react-native-web/issues/1027)). |
|
| RefreshControl | ✘ | Not started ([#1027](https://github.com/necolas/react-native-web/issues/1027)). |
|
||||||
| SafeAreaView | ✓ | |
|
| SafeAreaView | ✓ | |
|
||||||
| ScrollView | ✓ | Missing momentum scroll events ([#1021](https://github.com/necolas/react-native-web/issues/1021)) and `pagingEnabled` ([#1057](https://github.com/necolas/react-native-web/issues/1057)). |
|
| ScrollView | ✓ | Missing momentum scroll events ([#1021](https://github.com/necolas/react-native-web/issues/1021)). |
|
||||||
| SectionList | ✓ | |
|
| SectionList | ✓ | |
|
||||||
| Slider | ✘ | Not started ([#1022](https://github.com/necolas/react-native-web/issues/1022)). |
|
| Slider | ✘ | Not started ([#1022](https://github.com/necolas/react-native-web/issues/1022)). |
|
||||||
| StatusBar | (✓) | Mock. No equivalent web APIs. |
|
| StatusBar | (✓) | Mock. No equivalent web APIs. |
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ target platform.
|
|||||||
|
|
||||||
What follows is merely an _example_ of one basic way to package a web app using
|
What follows is merely an _example_ of one basic way to package a web app using
|
||||||
[Webpack](https://webpack.js.org) and [Babel](https://babeljs.io/). (You can
|
[Webpack](https://webpack.js.org) and [Babel](https://babeljs.io/). (You can
|
||||||
also the React Native bundler, [Metro](https://github.com/facebook/metro), to
|
also use the React Native bundler, [Metro](https://github.com/facebook/metro), to
|
||||||
build web apps.)
|
build web apps.)
|
||||||
|
|
||||||
Packaging web apps is subtly different to packaging React Native apps and is
|
Packaging web apps is subtly different to packaging React Native apps and is
|
||||||
|
|||||||
10
package.json
10
package.json
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.9.7",
|
"version": "0.9.12",
|
||||||
"name": "react-native-web-monorepo",
|
"name": "react-native-web-monorepo",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"clean": "del ./packages/*/dist",
|
"clean": "del ./packages/*/dist",
|
||||||
@@ -54,10 +54,10 @@
|
|||||||
"lint-staged": "^7.1.0",
|
"lint-staged": "^7.1.0",
|
||||||
"npm-run-all": "^4.1.3",
|
"npm-run-all": "^4.1.3",
|
||||||
"prettier": "^1.12.1",
|
"prettier": "^1.12.1",
|
||||||
"react": "^16.5.1",
|
"react": "^16.7.0",
|
||||||
"react-art": "^16.5.1",
|
"react-art": "^16.7.0",
|
||||||
"react-dom": "^16.5.1",
|
"react-dom": "^16.7.0",
|
||||||
"react-test-renderer": "^16.5.1"
|
"react-test-renderer": "^16.7.0"
|
||||||
},
|
},
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
"packages/*"
|
"packages/*"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "babel-plugin-react-native-web",
|
"name": "babel-plugin-react-native-web",
|
||||||
"version": "0.9.7",
|
"version": "0.9.12",
|
||||||
"description": "Babel plugin for React Native for Web",
|
"description": "Babel plugin for React Native for Web",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
@@ -1,37 +1,35 @@
|
|||||||
{
|
{
|
||||||
"private": true,
|
"private": true,
|
||||||
"name": "benchmarks",
|
"name": "benchmarks",
|
||||||
"version": "0.9.7",
|
"version": "0.9.12",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "mkdir -p dist && cp -f index.html dist/index.html && ./node_modules/.bin/webpack-cli --config ./webpack.config.js",
|
"build": "mkdir -p dist && cp -f index.html dist/index.html && ./node_modules/.bin/webpack-cli --config ./webpack.config.js",
|
||||||
"release": "yarn build && git checkout gh-pages && rm -rf ../../benchmarks && mv dist ../../benchmarks && git add -A && git commit -m \"Benchmarks deploy\" && git push origin gh-pages && git checkout -"
|
"release": "NODE_ENV=production yarn build && git checkout gh-pages && rm -rf ../../benchmarks && mv dist ../../benchmarks && git add -A && git commit -m \"Benchmarks deploy\" && git push origin gh-pages && git checkout -"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"aphrodite": "^2.2.2",
|
"aphrodite": "^2.2.3",
|
||||||
"classnames": "^2.2.6",
|
"classnames": "^2.2.6",
|
||||||
"d3-scale-chromatic": "^1.3.0",
|
"d3-scale-chromatic": "^1.3.3",
|
||||||
"emotion": "^9.2.4",
|
"emotion": "^10.0.5",
|
||||||
"fela": "^6.1.9",
|
"fela": "^10.0.2",
|
||||||
"glamor": "2.20.40",
|
"react": "^16.7.0",
|
||||||
"radium": "^0.24.0",
|
"react-dom": "^16.7.0",
|
||||||
"react": "^16.5.1",
|
"react-fela": "^10.0.2",
|
||||||
"react-dom": "^16.5.1",
|
|
||||||
"react-fela": "^7.3.1",
|
|
||||||
"react-jss": "^8.6.1",
|
"react-jss": "^8.6.1",
|
||||||
"react-native-web": "0.9.7",
|
"react-native-web": "0.9.12",
|
||||||
"reactxp": "^1.3.0",
|
"reactxp": "^1.5.0",
|
||||||
"styled-components": "^3.3.3",
|
"styled-components": "^4.1.3",
|
||||||
"styled-jsx": "^2.2.7",
|
"styled-jsx": "^3.1.2",
|
||||||
"styletron-engine-atomic": "^1.0.5",
|
"styletron-engine-atomic": "^1.0.13",
|
||||||
"styletron-react": "^4.3.1"
|
"styletron-react": "^4.4.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"babel-plugin-react-native-web": "0.9.7",
|
"babel-plugin-react-native-web": "0.9.12",
|
||||||
"css-loader": "^1.0.0",
|
"css-loader": "^2.0.2",
|
||||||
"style-loader": "^0.21.0",
|
"style-loader": "^0.23.1",
|
||||||
"url-loader": "^1.0.1",
|
"url-loader": "^1.1.2",
|
||||||
"webpack": "^4.15.1",
|
"webpack": "^4.28.1",
|
||||||
"webpack-bundle-analyzer": "^2.13.1",
|
"webpack-bundle-analyzer": "^3.0.3",
|
||||||
"webpack-cli": "^3.0.8"
|
"webpack-cli": "^3.1.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,49 +0,0 @@
|
|||||||
/* eslint-disable react/prop-types */
|
|
||||||
import React from 'react';
|
|
||||||
import View from './View';
|
|
||||||
|
|
||||||
const Box = ({ color, fixed = false, layout = 'column', outer = false, ...other }) => (
|
|
||||||
<View
|
|
||||||
{...other}
|
|
||||||
style={[
|
|
||||||
styles[`color${color}`],
|
|
||||||
fixed && styles.fixed,
|
|
||||||
layout === 'row' && styles.row,
|
|
||||||
outer && styles.outer
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
|
|
||||||
const styles = {
|
|
||||||
outer: {
|
|
||||||
alignSelf: 'flex-start',
|
|
||||||
padding: 4
|
|
||||||
},
|
|
||||||
row: {
|
|
||||||
flexDirection: 'row'
|
|
||||||
},
|
|
||||||
color0: {
|
|
||||||
backgroundColor: '#14171A'
|
|
||||||
},
|
|
||||||
color1: {
|
|
||||||
backgroundColor: '#AAB8C2'
|
|
||||||
},
|
|
||||||
color2: {
|
|
||||||
backgroundColor: '#E6ECF0'
|
|
||||||
},
|
|
||||||
color3: {
|
|
||||||
backgroundColor: '#FFAD1F'
|
|
||||||
},
|
|
||||||
color4: {
|
|
||||||
backgroundColor: '#F45D22'
|
|
||||||
},
|
|
||||||
color5: {
|
|
||||||
backgroundColor: '#E0245E'
|
|
||||||
},
|
|
||||||
fixed: {
|
|
||||||
width: 6,
|
|
||||||
height: 6
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Box;
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
/* eslint-disable react/prop-types */
|
|
||||||
import React from 'react';
|
|
||||||
import { css } from 'glamor';
|
|
||||||
|
|
||||||
const Dot = ({ size, x, y, children, color }) => (
|
|
||||||
<div
|
|
||||||
className={css(styles.root, {
|
|
||||||
borderBottomColor: color,
|
|
||||||
borderRightWidth: `${size / 2}px`,
|
|
||||||
borderBottomWidth: `${size / 2}px`,
|
|
||||||
borderLeftWidth: `${size / 2}px`,
|
|
||||||
marginLeft: `${x}px`,
|
|
||||||
marginTop: `${y}px`
|
|
||||||
})}
|
|
||||||
>
|
|
||||||
{children}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
|
|
||||||
const styles = {
|
|
||||||
root: {
|
|
||||||
position: 'absolute',
|
|
||||||
cursor: 'pointer',
|
|
||||||
width: 0,
|
|
||||||
height: 0,
|
|
||||||
borderColor: 'transparent',
|
|
||||||
borderStyle: 'solid',
|
|
||||||
borderTopWidth: 0,
|
|
||||||
transform: 'translate(50%, 50%)'
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Dot;
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
import View from './View';
|
|
||||||
export default View;
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
/* eslint-disable react/prop-types */
|
|
||||||
import { css } from 'glamor';
|
|
||||||
import React from 'react';
|
|
||||||
|
|
||||||
class View extends React.Component {
|
|
||||||
render() {
|
|
||||||
const { style, ...other } = this.props;
|
|
||||||
return <div {...other} className={css(viewStyle, ...style)} />;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const viewStyle = {
|
|
||||||
alignItems: 'stretch',
|
|
||||||
borderWidth: 0,
|
|
||||||
borderStyle: 'solid',
|
|
||||||
boxSizing: 'border-box',
|
|
||||||
display: 'flex',
|
|
||||||
flexBasis: 'auto',
|
|
||||||
flexDirection: 'column',
|
|
||||||
flexShrink: 0,
|
|
||||||
margin: 0,
|
|
||||||
padding: 0,
|
|
||||||
position: 'relative',
|
|
||||||
// fix flexbox bugs
|
|
||||||
minHeight: 0,
|
|
||||||
minWidth: 0
|
|
||||||
};
|
|
||||||
|
|
||||||
export default View;
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
import Box from './Box';
|
|
||||||
import Dot from './Dot';
|
|
||||||
import Provider from './Provider';
|
|
||||||
import View from './View';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
Box,
|
|
||||||
Dot,
|
|
||||||
Provider,
|
|
||||||
View
|
|
||||||
};
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
/* eslint-disable react/prop-types */
|
|
||||||
import Radium from 'radium';
|
|
||||||
import React from 'react';
|
|
||||||
import View from './View';
|
|
||||||
|
|
||||||
const Box = ({ color, fixed = false, layout = 'column', outer = false, ...other }) => (
|
|
||||||
<View
|
|
||||||
{...other}
|
|
||||||
style={[
|
|
||||||
styles[`color${color}`],
|
|
||||||
fixed && styles.fixed,
|
|
||||||
layout === 'row' && styles.row,
|
|
||||||
outer && styles.outer
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
|
|
||||||
const styles = {
|
|
||||||
outer: {
|
|
||||||
alignSelf: 'flex-start',
|
|
||||||
padding: 4
|
|
||||||
},
|
|
||||||
row: {
|
|
||||||
flexDirection: 'row'
|
|
||||||
},
|
|
||||||
color0: {
|
|
||||||
backgroundColor: '#14171A'
|
|
||||||
},
|
|
||||||
color1: {
|
|
||||||
backgroundColor: '#AAB8C2'
|
|
||||||
},
|
|
||||||
color2: {
|
|
||||||
backgroundColor: '#E6ECF0'
|
|
||||||
},
|
|
||||||
color3: {
|
|
||||||
backgroundColor: '#FFAD1F'
|
|
||||||
},
|
|
||||||
color4: {
|
|
||||||
backgroundColor: '#F45D22'
|
|
||||||
},
|
|
||||||
color5: {
|
|
||||||
backgroundColor: '#E0245E'
|
|
||||||
},
|
|
||||||
fixed: {
|
|
||||||
width: 6,
|
|
||||||
height: 6
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Radium(Box);
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
/* eslint-disable react/prop-types */
|
|
||||||
import Radium from 'radium';
|
|
||||||
import React from 'react';
|
|
||||||
|
|
||||||
const Dot = ({ size, x, y, children, color }) => (
|
|
||||||
<div
|
|
||||||
style={[
|
|
||||||
styles.root,
|
|
||||||
{
|
|
||||||
borderBottomColor: color,
|
|
||||||
borderRightWidth: `${size / 2}px`,
|
|
||||||
borderBottomWidth: `${size / 2}px`,
|
|
||||||
borderLeftWidth: `${size / 2}px`,
|
|
||||||
marginLeft: `${x}px`,
|
|
||||||
marginTop: `${y}px`
|
|
||||||
}
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
{children}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
|
|
||||||
const styles = {
|
|
||||||
root: {
|
|
||||||
position: 'absolute',
|
|
||||||
cursor: 'pointer',
|
|
||||||
width: 0,
|
|
||||||
height: 0,
|
|
||||||
borderColor: 'transparent',
|
|
||||||
borderStyle: 'solid',
|
|
||||||
borderTopWidth: 0,
|
|
||||||
transform: 'translate(50%, 50%)'
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Radium(Dot);
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
import View from './View';
|
|
||||||
export default View;
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
/* eslint-disable react/prop-types */
|
|
||||||
import Radium from 'radium';
|
|
||||||
import React from 'react';
|
|
||||||
|
|
||||||
class View extends React.Component {
|
|
||||||
render() {
|
|
||||||
const { style, ...other } = this.props;
|
|
||||||
return <div {...other} style={[styles.root, style]} />;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const styles = {
|
|
||||||
root: {
|
|
||||||
alignItems: 'stretch',
|
|
||||||
borderWidth: 0,
|
|
||||||
borderStyle: 'solid',
|
|
||||||
boxSizing: 'border-box',
|
|
||||||
display: 'flex',
|
|
||||||
flexBasis: 'auto',
|
|
||||||
flexDirection: 'column',
|
|
||||||
flexShrink: 0,
|
|
||||||
margin: 0,
|
|
||||||
padding: 0,
|
|
||||||
position: 'relative',
|
|
||||||
// fix flexbox bugs
|
|
||||||
minHeight: 0,
|
|
||||||
minWidth: 0
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Radium(View);
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
import Box from './Box';
|
|
||||||
import Dot from './Dot';
|
|
||||||
import Provider from './Provider';
|
|
||||||
import View from './View';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
Box,
|
|
||||||
Dot,
|
|
||||||
Provider,
|
|
||||||
View
|
|
||||||
};
|
|
||||||
@@ -12,6 +12,9 @@ module.exports = {
|
|||||||
path: path.resolve(appDirectory, 'dist'),
|
path: path.resolve(appDirectory, 'dist'),
|
||||||
filename: 'bundle.js'
|
filename: 'bundle.js'
|
||||||
},
|
},
|
||||||
|
optimization: {
|
||||||
|
minimize: process.env.NODE_ENV === 'production'
|
||||||
|
},
|
||||||
module: {
|
module: {
|
||||||
rules: [
|
rules: [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"private": true,
|
"private": true,
|
||||||
"name": "react-native-examples",
|
"name": "react-native-examples",
|
||||||
"version": "0.9.7",
|
"version": "0.9.12",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "mkdir -p dist && cp -f src/index.html dist/index.html && ./node_modules/.bin/webpack-cli --config ./webpack.config.js",
|
"build": "mkdir -p dist && cp -f src/index.html dist/index.html && ./node_modules/.bin/webpack-cli --config ./webpack.config.js",
|
||||||
"release": "yarn build && git checkout gh-pages && rm -rf ../../examples && mv dist ../../examples && git add -A && git commit -m \"Examples deploy\" && git push origin gh-pages && git checkout -"
|
"release": "yarn build && git checkout gh-pages && rm -rf ../../examples && mv dist ../../examples && git add -A && git commit -m \"Examples deploy\" && git push origin gh-pages && git checkout -"
|
||||||
@@ -10,10 +10,10 @@
|
|||||||
"babel-runtime": "^6.26.0",
|
"babel-runtime": "^6.26.0",
|
||||||
"react": "^16.5.1",
|
"react": "^16.5.1",
|
||||||
"react-dom": "^16.5.1",
|
"react-dom": "^16.5.1",
|
||||||
"react-native-web": "0.9.7"
|
"react-native-web": "0.9.12"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"babel-plugin-react-native-web": "0.9.7",
|
"babel-plugin-react-native-web": "0.9.12",
|
||||||
"babel-plugin-transform-runtime": "^6.23.0",
|
"babel-plugin-transform-runtime": "^6.23.0",
|
||||||
"file-loader": "^1.1.11",
|
"file-loader": "^1.1.11",
|
||||||
"webpack": "^4.8.1",
|
"webpack": "^4.8.1",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "react-native-web",
|
"name": "react-native-web",
|
||||||
"version": "0.9.7",
|
"version": "0.9.12",
|
||||||
"description": "React Native for Web",
|
"description": "React Native for Web",
|
||||||
"module": "dist/index.js",
|
"module": "dist/index.js",
|
||||||
"main": "dist/cjs/index.js",
|
"main": "dist/cjs/index.js",
|
||||||
@@ -15,14 +15,14 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"array-find-index": "^1.0.2",
|
"array-find-index": "^1.0.2",
|
||||||
"create-react-class": "^15.6.2",
|
"create-react-class": "^15.6.2",
|
||||||
"debounce": "^1.1.0",
|
"debounce": "^1.2.0",
|
||||||
"deep-assign": "^2.0.0",
|
"deep-assign": "^3.0.0",
|
||||||
"fbjs": "^0.8.16",
|
"fbjs": "^1.0.0",
|
||||||
"hyphenate-style-name": "^1.0.2",
|
"hyphenate-style-name": "^1.0.2",
|
||||||
"inline-style-prefixer": "^4.0.2",
|
"inline-style-prefixer": "^5.0.3",
|
||||||
"normalize-css-color": "^1.0.2",
|
"normalize-css-color": "^1.0.2",
|
||||||
"prop-types": "^15.6.0",
|
"prop-types": "^15.6.0",
|
||||||
"react-timer-mixin": "^0.13.3"
|
"react-timer-mixin": "^0.13.4"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"react": ">=16.5.1",
|
"react": ">=16.5.1",
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`components/ScrollView "pagingEnabled" prop 1`] = `undefined`;
|
||||||
|
|
||||||
|
exports[`components/ScrollView "pagingEnabled" prop 2`] = `"y mandatory"`;
|
||||||
|
|
||||||
|
exports[`components/ScrollView "pagingEnabled" prop 3`] = `"start"`;
|
||||||
@@ -2,7 +2,9 @@
|
|||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import ScrollView from '..';
|
import ScrollView from '..';
|
||||||
import { mount } from 'enzyme';
|
import StyleSheet from '../../StyleSheet';
|
||||||
|
import View from '../../View';
|
||||||
|
import { mount, shallow } from 'enzyme';
|
||||||
|
|
||||||
describe('components/ScrollView', () => {
|
describe('components/ScrollView', () => {
|
||||||
test('instance method setNativeProps', () => {
|
test('instance method setNativeProps', () => {
|
||||||
@@ -11,4 +13,32 @@ describe('components/ScrollView', () => {
|
|||||||
instance.setNativeProps();
|
instance.setNativeProps();
|
||||||
}).not.toThrow();
|
}).not.toThrow();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('"children" prop', () => {
|
||||||
|
const component = shallow(
|
||||||
|
<ScrollView>
|
||||||
|
<View testID="child" />
|
||||||
|
</ScrollView>
|
||||||
|
);
|
||||||
|
expect(component.find({ testID: 'child' }).length).toBe(1);
|
||||||
|
|
||||||
|
component.setProps({ stickyHeaderIndices: [4] });
|
||||||
|
expect(component.find({ testID: 'child' }).length).toBe(1);
|
||||||
|
|
||||||
|
component.setProps({ pagingEnabled: true });
|
||||||
|
expect(component.find({ testID: 'child' }).length).toBe(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('"pagingEnabled" prop', () => {
|
||||||
|
const getStyleProp = (component, prop) => StyleSheet.flatten(component.prop('style'))[prop];
|
||||||
|
|
||||||
|
// false
|
||||||
|
const component = shallow(<ScrollView children={'Child'} />);
|
||||||
|
expect(getStyleProp(component, 'scrollSnapType')).toMatchSnapshot();
|
||||||
|
|
||||||
|
// true
|
||||||
|
component.setProps({ pagingEnabled: true });
|
||||||
|
expect(getStyleProp(component, 'scrollSnapType')).toMatchSnapshot();
|
||||||
|
expect(getStyleProp(component.children().childAt(0), 'scrollSnapAlign')).toMatchSnapshot();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -137,10 +137,10 @@ const ScrollView = createReactClass({
|
|||||||
onContentSizeChange,
|
onContentSizeChange,
|
||||||
refreshControl,
|
refreshControl,
|
||||||
stickyHeaderIndices,
|
stickyHeaderIndices,
|
||||||
|
pagingEnabled,
|
||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
keyboardDismissMode,
|
keyboardDismissMode,
|
||||||
onScroll,
|
onScroll,
|
||||||
pagingEnabled,
|
|
||||||
/* eslint-enable */
|
/* eslint-enable */
|
||||||
...other
|
...other
|
||||||
} = this.props;
|
} = this.props;
|
||||||
@@ -164,11 +164,22 @@ const ScrollView = createReactClass({
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const hasStickyHeaderIndices = !horizontal && Array.isArray(stickyHeaderIndices);
|
||||||
const children =
|
const children =
|
||||||
!horizontal && Array.isArray(stickyHeaderIndices)
|
hasStickyHeaderIndices || pagingEnabled
|
||||||
? React.Children.map(this.props.children, (child, i) => {
|
? React.Children.map(this.props.children, (child, i) => {
|
||||||
if (stickyHeaderIndices.indexOf(i) > -1) {
|
const isSticky = hasStickyHeaderIndices && stickyHeaderIndices.indexOf(i) > -1;
|
||||||
return React.cloneElement(child, { style: [child.props.style, styles.stickyHeader] });
|
if (child != null && (isSticky || pagingEnabled)) {
|
||||||
|
return (
|
||||||
|
<View
|
||||||
|
style={StyleSheet.compose(
|
||||||
|
isSticky && styles.stickyHeader,
|
||||||
|
pagingEnabled && styles.pagingEnabledChild
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{child}
|
||||||
|
</View>
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
return child;
|
return child;
|
||||||
}
|
}
|
||||||
@@ -181,15 +192,21 @@ const ScrollView = createReactClass({
|
|||||||
children={children}
|
children={children}
|
||||||
collapsable={false}
|
collapsable={false}
|
||||||
ref={this._setInnerViewRef}
|
ref={this._setInnerViewRef}
|
||||||
style={[horizontal && styles.contentContainerHorizontal, contentContainerStyle]}
|
style={StyleSheet.compose(
|
||||||
|
horizontal && styles.contentContainerHorizontal,
|
||||||
|
contentContainerStyle
|
||||||
|
)}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
||||||
const baseStyle = horizontal ? styles.baseHorizontal : styles.baseVertical;
|
const baseStyle = horizontal ? styles.baseHorizontal : styles.baseVertical;
|
||||||
|
const pagingEnabledStyle = horizontal
|
||||||
|
? styles.pagingEnabledHorizontal
|
||||||
|
: styles.pagingEnabledVertical;
|
||||||
|
|
||||||
const props = {
|
const props = {
|
||||||
...other,
|
...other,
|
||||||
style: [baseStyle, this.props.style],
|
style: [baseStyle, pagingEnabled && pagingEnabledStyle, this.props.style],
|
||||||
onTouchStart: this.scrollResponderHandleTouchStart,
|
onTouchStart: this.scrollResponderHandleTouchStart,
|
||||||
onTouchMove: this.scrollResponderHandleTouchMove,
|
onTouchMove: this.scrollResponderHandleTouchMove,
|
||||||
onTouchEnd: this.scrollResponderHandleTouchEnd,
|
onTouchEnd: this.scrollResponderHandleTouchEnd,
|
||||||
@@ -223,7 +240,7 @@ const ScrollView = createReactClass({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ScrollViewClass {...props} ref={this._setScrollViewRef} style={props.style}>
|
<ScrollViewClass {...props} ref={this._setScrollViewRef}>
|
||||||
{contentContainer}
|
{contentContainer}
|
||||||
</ScrollViewClass>
|
</ScrollViewClass>
|
||||||
);
|
);
|
||||||
@@ -294,6 +311,15 @@ const styles = StyleSheet.create({
|
|||||||
position: 'sticky',
|
position: 'sticky',
|
||||||
top: 0,
|
top: 0,
|
||||||
zIndex: 10
|
zIndex: 10
|
||||||
|
},
|
||||||
|
pagingEnabledHorizontal: {
|
||||||
|
scrollSnapType: 'x mandatory'
|
||||||
|
},
|
||||||
|
pagingEnabledVertical: {
|
||||||
|
scrollSnapType: 'y mandatory'
|
||||||
|
},
|
||||||
|
pagingEnabledChild: {
|
||||||
|
scrollSnapAlign: 'start'
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -84,15 +84,19 @@ export default class ReactNativeStyleResolver {
|
|||||||
// otherwise fallback to resolving
|
// otherwise fallback to resolving
|
||||||
const flatArray = flattenArray(style);
|
const flatArray = flattenArray(style);
|
||||||
let isArrayOfNumbers = true;
|
let isArrayOfNumbers = true;
|
||||||
|
let cacheKey = '';
|
||||||
for (let i = 0; i < flatArray.length; i++) {
|
for (let i = 0; i < flatArray.length; i++) {
|
||||||
const id = flatArray[i];
|
const id = flatArray[i];
|
||||||
if (typeof id !== 'number') {
|
if (typeof id !== 'number') {
|
||||||
isArrayOfNumbers = false;
|
isArrayOfNumbers = false;
|
||||||
} else {
|
} else {
|
||||||
|
if (isArrayOfNumbers) {
|
||||||
|
cacheKey += (id + '-');
|
||||||
|
}
|
||||||
this._injectRegisteredStyle(id);
|
this._injectRegisteredStyle(id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const key = isArrayOfNumbers ? createCacheKey(flatArray.join('-')) : null;
|
const key = isArrayOfNumbers ? createCacheKey(cacheKey) : null;
|
||||||
return this._resolveStyleIfNeeded(flatArray, key);
|
return this._resolveStyleIfNeeded(flatArray, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -55,7 +55,15 @@ export default class WebStyleSheet {
|
|||||||
// doesn't include styles injected via 'insertRule')
|
// doesn't include styles injected via 'insertRule')
|
||||||
if (this._textContent.indexOf(rule) === -1 && this._sheet) {
|
if (this._textContent.indexOf(rule) === -1 && this._sheet) {
|
||||||
const pos = position || this._sheet.cssRules.length;
|
const pos = position || this._sheet.cssRules.length;
|
||||||
this._sheet.insertRule(rule, pos);
|
try {
|
||||||
|
this._sheet.insertRule(rule, pos);
|
||||||
|
} catch (e) {
|
||||||
|
if (process.env.NODE_ENV !== 'production') {
|
||||||
|
console.warn(
|
||||||
|
`Failed to inject CSS: "${rule}". The browser may have rejecting unrecognized vendor prefixes. (This should have no user-facing impact.)`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,10 +2,10 @@
|
|||||||
|
|
||||||
exports[`StyleSheet/createAtomicRules transforms custom "animationName" declaration 1`] = `
|
exports[`StyleSheet/createAtomicRules transforms custom "animationName" declaration 1`] = `
|
||||||
Array [
|
Array [
|
||||||
"@media all {@-webkit-keyframes rn-anim-2k74q5{0%{top:0px}50%{top:5px}100%{top:10px}}}",
|
"@-webkit-keyframes rn-anim-2k74q5{0%{top:0px}50%{top:5px}100%{top:10px}}",
|
||||||
"@media all {@keyframes rn-anim-2k74q5{0%{top:0px}50%{top:5px}100%{top:10px}}}",
|
"@keyframes rn-anim-2k74q5{0%{top:0px}50%{top:5px}100%{top:10px}}",
|
||||||
"@media all {@-webkit-keyframes rn-anim-zc91cv{from{left:0px}to{left:10px}}}",
|
"@-webkit-keyframes rn-anim-zc91cv{from{left:0px}to{left:10px}}",
|
||||||
"@media all {@keyframes rn-anim-zc91cv{from{left:0px}to{left:10px}}}",
|
"@keyframes rn-anim-zc91cv{from{left:0px}to{left:10px}}",
|
||||||
".test{-webkit-animation-name:rn-anim-2k74q5,rn-anim-zc91cv;animation-name:rn-anim-2k74q5,rn-anim-zc91cv}",
|
".test{-webkit-animation-name:rn-anim-2k74q5,rn-anim-zc91cv;animation-name:rn-anim-2k74q5,rn-anim-zc91cv}",
|
||||||
]
|
]
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ const makeSteps = keyframes =>
|
|||||||
const createKeyframesRules = (keyframes: Object): Array<String> => {
|
const createKeyframesRules = (keyframes: Object): Array<String> => {
|
||||||
const identifier = createIdentifier(keyframes);
|
const identifier = createIdentifier(keyframes);
|
||||||
const rules = prefixes.map(prefix => {
|
const rules = prefixes.map(prefix => {
|
||||||
return `@media all {@${prefix}keyframes ${identifier}{${makeSteps(keyframes)}}}`;
|
return `@${prefix}keyframes ${identifier}{${makeSteps(keyframes)}}`;
|
||||||
});
|
});
|
||||||
return { identifier, rules };
|
return { identifier, rules };
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
import { canUseDOM } from 'fbjs/lib/ExecutionEnvironment';
|
import { canUseDOM } from 'fbjs/lib/ExecutionEnvironment';
|
||||||
import StyleSheet from './StyleSheet';
|
import StyleSheet from './StyleSheet';
|
||||||
|
|
||||||
// allow component styles to be editable in React Dev Tools
|
// allow original component styles to be inspected in React Dev Tools
|
||||||
if (process.env.NODE_ENV !== 'production') {
|
if (canUseDOM && window.__REACT_DEVTOOLS_GLOBAL_HOOK__) {
|
||||||
if (canUseDOM && window.__REACT_DEVTOOLS_GLOBAL_HOOK__) {
|
window.__REACT_DEVTOOLS_GLOBAL_HOOK__.resolveRNStyle = StyleSheet.flatten;
|
||||||
window.__REACT_DEVTOOLS_GLOBAL_HOOK__.resolveRNStyle = StyleSheet.flatten;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default StyleSheet;
|
export default StyleSheet;
|
||||||
|
|||||||
@@ -21,10 +21,12 @@
|
|||||||
import { canUseDOM } from 'fbjs/lib/ExecutionEnvironment';
|
import { canUseDOM } from 'fbjs/lib/ExecutionEnvironment';
|
||||||
import hash from '../../vendor/hash';
|
import hash from '../../vendor/hash';
|
||||||
|
|
||||||
const focusVisibleClass =
|
const focusVisibleAttributeName =
|
||||||
'rn-' + (process.env.NODE_ENV !== 'production' ? 'focusVisible-' : '') + hash('focus-visible');
|
'data-rn-' +
|
||||||
|
(process.env.NODE_ENV !== 'production' ? 'focusvisible-' : '') +
|
||||||
|
hash('focusvisible');
|
||||||
|
|
||||||
const rule = `:focus:not(.${focusVisibleClass}) { outline: none; }`;
|
const rule = `:focus:not([${focusVisibleAttributeName}]){outline: none;}`;
|
||||||
|
|
||||||
const modality = styleElement => {
|
const modality = styleElement => {
|
||||||
if (!canUseDOM) {
|
if (!canUseDOM) {
|
||||||
@@ -71,7 +73,7 @@ const modality = styleElement => {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Computes whether the given element should automatically trigger the
|
* Computes whether the given element should automatically trigger the
|
||||||
* `focus-visible` class being added, i.e. whether it should always match
|
* `focus-visible` attribute being added, i.e. whether it should always match
|
||||||
* `:focus-visible` when focused.
|
* `:focus-visible` when focused.
|
||||||
*/
|
*/
|
||||||
function focusTriggersKeyboardModality(el) {
|
function focusTriggersKeyboardModality(el) {
|
||||||
@@ -95,22 +97,32 @@ const modality = styleElement => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add the `focus-visible` class to the given element if it was not added by
|
* Add the `focus-visible` attribute to the given element if it was not added by
|
||||||
* the author.
|
* the author.
|
||||||
*/
|
*/
|
||||||
function addFocusVisibleClass(el) {
|
function addFocusVisibleAttribute(el) {
|
||||||
if (el.classList.contains(focusVisibleClass)) {
|
if (el.hasAttribute(focusVisibleAttributeName)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
el.classList.add(focusVisibleClass);
|
el.setAttribute(focusVisibleAttributeName, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove the `focus-visible` class from the given element if it was not
|
* Remove the `focus-visible` attribute from the given element if it was not
|
||||||
* originally added by the author.
|
* originally added by the author.
|
||||||
*/
|
*/
|
||||||
function removeFocusVisibleClass(el) {
|
function removeFocusVisibleAttribute(el) {
|
||||||
el.classList.remove(focusVisibleClass);
|
el.removeAttribute(focusVisibleAttributeName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the `focus-visible` attribute from all elements in the document.
|
||||||
|
*/
|
||||||
|
function removeAllFocusVisibleAttributes() {
|
||||||
|
const list = document.querySelectorAll(`[${focusVisibleAttributeName}]`);
|
||||||
|
for (let i = 0; i < list.length; i += 1) {
|
||||||
|
removeFocusVisibleAttribute(list[i]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -124,7 +136,7 @@ const modality = styleElement => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (isValidFocusTarget(document.activeElement)) {
|
if (isValidFocusTarget(document.activeElement)) {
|
||||||
addFocusVisibleClass(document.activeElement);
|
addFocusVisibleAttribute(document.activeElement);
|
||||||
}
|
}
|
||||||
|
|
||||||
hadKeyboardEvent = true;
|
hadKeyboardEvent = true;
|
||||||
@@ -136,13 +148,20 @@ const modality = styleElement => {
|
|||||||
* This avoids the situation where a user presses a key on an already focused
|
* This avoids the situation where a user presses a key on an already focused
|
||||||
* element, and then clicks on a different element, focusing it with a
|
* element, and then clicks on a different element, focusing it with a
|
||||||
* pointing device, while we still think we're in keyboard modality.
|
* pointing device, while we still think we're in keyboard modality.
|
||||||
|
* It also avoids the situation where a user presses on an element within a
|
||||||
|
* previously keyboard-focused element (i.e., `e.target` is not the previously
|
||||||
|
* focused element, but one of its descendants) and we need to remove the
|
||||||
|
* focus ring because a `blur` event doesn't occur.
|
||||||
*/
|
*/
|
||||||
function onPointerDown(e) {
|
function onPointerDown(e) {
|
||||||
|
if (hadKeyboardEvent === true) {
|
||||||
|
removeAllFocusVisibleAttributes();
|
||||||
|
}
|
||||||
hadKeyboardEvent = false;
|
hadKeyboardEvent = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* On `focus`, add the `focus-visible` class to the target if:
|
* On `focus`, add the `focus-visible` attribute to the target if:
|
||||||
* - the target received focus as a result of keyboard navigation, or
|
* - the target received focus as a result of keyboard navigation, or
|
||||||
* - the event target is an element that will likely require interaction
|
* - the event target is an element that will likely require interaction
|
||||||
* via the keyboard (e.g. a text box)
|
* via the keyboard (e.g. a text box)
|
||||||
@@ -154,19 +173,19 @@ const modality = styleElement => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (hadKeyboardEvent || focusTriggersKeyboardModality(e.target)) {
|
if (hadKeyboardEvent || focusTriggersKeyboardModality(e.target)) {
|
||||||
addFocusVisibleClass(e.target);
|
addFocusVisibleAttribute(e.target);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* On `blur`, remove the `focus-visible` class from the target.
|
* On `blur`, remove the `focus-visible` attribute from the target.
|
||||||
*/
|
*/
|
||||||
function onBlur(e) {
|
function onBlur(e) {
|
||||||
if (!isValidFocusTarget(e.target)) {
|
if (!isValidFocusTarget(e.target)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (e.target.classList.contains(focusVisibleClass)) {
|
if (e.target.hasAttribute(focusVisibleAttributeName)) {
|
||||||
// To detect a tab/window switch, we look for a blur event followed
|
// To detect a tab/window switch, we look for a blur event followed
|
||||||
// rapidly by a visibility change.
|
// rapidly by a visibility change.
|
||||||
// If we don't see a visibility change within 100ms, it's probably a
|
// If we don't see a visibility change within 100ms, it's probably a
|
||||||
@@ -177,20 +196,20 @@ const modality = styleElement => {
|
|||||||
hadFocusVisibleRecently = false;
|
hadFocusVisibleRecently = false;
|
||||||
window.clearTimeout(hadFocusVisibleRecentlyTimeout);
|
window.clearTimeout(hadFocusVisibleRecentlyTimeout);
|
||||||
}, 100);
|
}, 100);
|
||||||
removeFocusVisibleClass(e.target);
|
removeFocusVisibleAttribute(e.target);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If the user changes tabs, keep track of whether or not the previously
|
* If the user changes tabs, keep track of whether or not the previously
|
||||||
* focused element had .focus-visible.
|
* focused element had the focus-visible attribute.
|
||||||
*/
|
*/
|
||||||
function onVisibilityChange(e) {
|
function onVisibilityChange(e) {
|
||||||
if (document.visibilityState === 'hidden') {
|
if (document.visibilityState === 'hidden') {
|
||||||
// If the tab becomes active again, the browser will handle calling focus
|
// If the tab becomes active again, the browser will handle calling focus
|
||||||
// on the element (Safari actually calls it twice).
|
// on the element (Safari actually calls it twice).
|
||||||
// If this tab change caused a blur on an element with focus-visible,
|
// If this tab change caused a blur on an element with focus-visible,
|
||||||
// re-apply the class when the user switches back to the tab.
|
// re-apply the attribute when the user switches back to the tab.
|
||||||
if (hadFocusVisibleRecently) {
|
if (hadFocusVisibleRecently) {
|
||||||
hadKeyboardEvent = true;
|
hadKeyboardEvent = true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -180,6 +180,25 @@ describe('components/TextInput', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('prop "onKeyPress"', () => {
|
describe('prop "onKeyPress"', () => {
|
||||||
|
test('arrow key', () => {
|
||||||
|
const onKeyPress = jest.fn();
|
||||||
|
const input = findNativeInput(mount(<TextInput onKeyPress={onKeyPress} />));
|
||||||
|
input.simulate('keyPress', { which: 37 });
|
||||||
|
expect(onKeyPress).toHaveBeenCalledTimes(1);
|
||||||
|
expect(onKeyPress).toBeCalledWith(
|
||||||
|
expect.objectContaining({
|
||||||
|
nativeEvent: {
|
||||||
|
altKey: undefined,
|
||||||
|
ctrlKey: undefined,
|
||||||
|
key: 'ArrowLeft',
|
||||||
|
metaKey: undefined,
|
||||||
|
shiftKey: undefined,
|
||||||
|
target: expect.anything()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
test('backspace key', () => {
|
test('backspace key', () => {
|
||||||
const onKeyPress = jest.fn();
|
const onKeyPress = jest.fn();
|
||||||
const input = findNativeInput(mount(<TextInput onKeyPress={onKeyPress} />));
|
const input = findNativeInput(mount(<TextInput onKeyPress={onKeyPress} />));
|
||||||
@@ -199,25 +218,6 @@ describe('components/TextInput', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('tab key', () => {
|
|
||||||
const onKeyPress = jest.fn();
|
|
||||||
const input = findNativeInput(mount(<TextInput onKeyPress={onKeyPress} />));
|
|
||||||
input.simulate('keyDown', { which: 9 });
|
|
||||||
expect(onKeyPress).toHaveBeenCalledTimes(1);
|
|
||||||
expect(onKeyPress).toBeCalledWith(
|
|
||||||
expect.objectContaining({
|
|
||||||
nativeEvent: {
|
|
||||||
altKey: undefined,
|
|
||||||
ctrlKey: undefined,
|
|
||||||
key: 'Tab',
|
|
||||||
metaKey: undefined,
|
|
||||||
shiftKey: undefined,
|
|
||||||
target: expect.anything()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('enter key', () => {
|
test('enter key', () => {
|
||||||
const onKeyPress = jest.fn();
|
const onKeyPress = jest.fn();
|
||||||
const input = findNativeInput(mount(<TextInput onKeyPress={onKeyPress} />));
|
const input = findNativeInput(mount(<TextInput onKeyPress={onKeyPress} />));
|
||||||
@@ -237,6 +237,25 @@ describe('components/TextInput', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('escape key', () => {
|
||||||
|
const onKeyPress = jest.fn();
|
||||||
|
const input = findNativeInput(mount(<TextInput onKeyPress={onKeyPress} />));
|
||||||
|
input.simulate('keyPress', { which: 27 });
|
||||||
|
expect(onKeyPress).toHaveBeenCalledTimes(1);
|
||||||
|
expect(onKeyPress).toBeCalledWith(
|
||||||
|
expect.objectContaining({
|
||||||
|
nativeEvent: {
|
||||||
|
altKey: undefined,
|
||||||
|
ctrlKey: undefined,
|
||||||
|
key: 'Escape',
|
||||||
|
metaKey: undefined,
|
||||||
|
shiftKey: undefined,
|
||||||
|
target: expect.anything()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
test('space key', () => {
|
test('space key', () => {
|
||||||
const onKeyPress = jest.fn();
|
const onKeyPress = jest.fn();
|
||||||
const input = findNativeInput(mount(<TextInput onKeyPress={onKeyPress} />));
|
const input = findNativeInput(mount(<TextInput onKeyPress={onKeyPress} />));
|
||||||
@@ -256,17 +275,17 @@ describe('components/TextInput', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('arrow key', () => {
|
test('tab key', () => {
|
||||||
const onKeyPress = jest.fn();
|
const onKeyPress = jest.fn();
|
||||||
const input = findNativeInput(mount(<TextInput onKeyPress={onKeyPress} />));
|
const input = findNativeInput(mount(<TextInput onKeyPress={onKeyPress} />));
|
||||||
input.simulate('keyPress', { which: 37 });
|
input.simulate('keyDown', { which: 9 });
|
||||||
expect(onKeyPress).toHaveBeenCalledTimes(1);
|
expect(onKeyPress).toHaveBeenCalledTimes(1);
|
||||||
expect(onKeyPress).toBeCalledWith(
|
expect(onKeyPress).toBeCalledWith(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
nativeEvent: {
|
nativeEvent: {
|
||||||
altKey: undefined,
|
altKey: undefined,
|
||||||
ctrlKey: undefined,
|
ctrlKey: undefined,
|
||||||
key: 'ArrowLeft',
|
key: 'Tab',
|
||||||
metaKey: undefined,
|
metaKey: undefined,
|
||||||
shiftKey: undefined,
|
shiftKey: undefined,
|
||||||
target: expect.anything()
|
target: expect.anything()
|
||||||
|
|||||||
@@ -317,11 +317,13 @@ class TextInput extends Component<*> {
|
|||||||
// Prevent key events bubbling (see #612)
|
// Prevent key events bubbling (see #612)
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
|
|
||||||
// Backspace, Tab, Cmd+Enter, and Arrow keys only fire 'keydown' DOM events
|
// Backspace, Escape, Tab, Cmd+Enter, and Arrow keys only fire 'keydown'
|
||||||
|
// DOM events
|
||||||
if (
|
if (
|
||||||
e.which === 8 ||
|
e.which === 8 ||
|
||||||
e.which === 9 ||
|
e.which === 9 ||
|
||||||
(e.which === 13 && e.metaKey) ||
|
(e.which === 13 && e.metaKey) ||
|
||||||
|
e.which === 27 ||
|
||||||
e.which === 37 ||
|
e.which === 37 ||
|
||||||
e.which === 38 ||
|
e.which === 38 ||
|
||||||
e.which === 39 ||
|
e.which === 39 ||
|
||||||
@@ -348,6 +350,9 @@ class TextInput extends Component<*> {
|
|||||||
case 13:
|
case 13:
|
||||||
keyValue = 'Enter';
|
keyValue = 'Enter';
|
||||||
break;
|
break;
|
||||||
|
case 27:
|
||||||
|
keyValue = 'Escape';
|
||||||
|
break;
|
||||||
case 32:
|
case 32:
|
||||||
keyValue = ' ';
|
keyValue = ' ';
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -51,6 +51,8 @@ const ViewStylePropTypes = {
|
|||||||
overscrollBehavior: overscrollBehaviorType,
|
overscrollBehavior: overscrollBehaviorType,
|
||||||
overscrollBehaviorX: overscrollBehaviorType,
|
overscrollBehaviorX: overscrollBehaviorType,
|
||||||
overscrollBehaviorY: overscrollBehaviorType,
|
overscrollBehaviorY: overscrollBehaviorType,
|
||||||
|
scrollSnapAlign: string,
|
||||||
|
scrollSnapType: string,
|
||||||
WebkitMaskImage: string,
|
WebkitMaskImage: string,
|
||||||
WebkitOverflowScrolling: oneOf(['auto', 'touch'])
|
WebkitOverflowScrolling: oneOf(['auto', 'touch'])
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -375,9 +375,14 @@ const ScrollResponderMixin = {
|
|||||||
({ x, y, animated } = x || emptyObject);
|
({ x, y, animated } = x || emptyObject);
|
||||||
}
|
}
|
||||||
const node = this.scrollResponderGetScrollableNode();
|
const node = this.scrollResponderGetScrollableNode();
|
||||||
UIManager.updateView(node, { style: { scrollBehavior: !animated ? 'auto' : 'smooth' } }, this);
|
const left = x || 0;
|
||||||
node.scrollLeft = x || 0;
|
const top = y || 0;
|
||||||
node.scrollTop = y || 0;
|
if (typeof node.scroll === 'function') {
|
||||||
|
node.scroll({ top, left, behavior: !animated ? 'auto' : 'smooth' });
|
||||||
|
} else {
|
||||||
|
node.scrollLeft = left;
|
||||||
|
node.scrollTop = top;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -23,6 +23,8 @@ const TransformPropTypes = {
|
|||||||
shape({ scale: number }),
|
shape({ scale: number }),
|
||||||
shape({ scaleX: number }),
|
shape({ scaleX: number }),
|
||||||
shape({ scaleY: number }),
|
shape({ scaleY: number }),
|
||||||
|
shape({ scaleZ: number }),
|
||||||
|
shape({ scale3d: string }),
|
||||||
shape({ skewX: string }),
|
shape({ skewX: string }),
|
||||||
shape({ skewY: string }),
|
shape({ skewY: string }),
|
||||||
shape({ translateX: numberOrString }),
|
shape({ translateX: numberOrString }),
|
||||||
|
|||||||
@@ -1561,8 +1561,7 @@ class CellRenderer extends React.Component<
|
|||||||
getItemLayout?: ?Function,
|
getItemLayout?: ?Function,
|
||||||
renderItem: renderItemType,
|
renderItem: renderItemType,
|
||||||
},
|
},
|
||||||
prevCellKey: ?string,
|
prevCellKey: ?string
|
||||||
style: ?DangerouslyImpreciseStyleProp,
|
|
||||||
},
|
},
|
||||||
$FlowFixMeState,
|
$FlowFixMeState,
|
||||||
> {
|
> {
|
||||||
@@ -1631,7 +1630,6 @@ class CellRenderer extends React.Component<
|
|||||||
index,
|
index,
|
||||||
inversionStyle,
|
inversionStyle,
|
||||||
parentProps,
|
parentProps,
|
||||||
style,
|
|
||||||
} = this.props;
|
} = this.props;
|
||||||
const {renderItem, getItemLayout} = parentProps;
|
const {renderItem, getItemLayout} = parentProps;
|
||||||
invariant(renderItem, 'no renderItem!');
|
invariant(renderItem, 'no renderItem!');
|
||||||
@@ -1651,9 +1649,9 @@ class CellRenderer extends React.Component<
|
|||||||
);
|
);
|
||||||
const cellStyle = inversionStyle
|
const cellStyle = inversionStyle
|
||||||
? horizontal
|
? horizontal
|
||||||
? [styles.rowReverse, inversionStyle, style]
|
? [styles.rowReverse, inversionStyle]
|
||||||
: [styles.columnReverse, inversionStyle, style]
|
: [styles.columnReverse, inversionStyle]
|
||||||
: horizontal ? [styles.row, inversionStyle, style] : [inversionStyle, style];
|
: horizontal ? [styles.row, inversionStyle] : inversionStyle;
|
||||||
if (!CellRendererComponent) {
|
if (!CellRendererComponent) {
|
||||||
return (
|
return (
|
||||||
<View style={cellStyle} onLayout={onLayout}>
|
<View style={cellStyle} onLayout={onLayout}>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"private": true,
|
"private": true,
|
||||||
"name": "website",
|
"name": "website",
|
||||||
"version": "0.9.7",
|
"version": "0.9.12",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "build-storybook -o ./dist -c ./storybook/.storybook",
|
"build": "build-storybook -o ./dist -c ./storybook/.storybook",
|
||||||
"start": "start-storybook -p 9001 -c ./storybook/.storybook",
|
"start": "start-storybook -p 9001 -c ./storybook/.storybook",
|
||||||
@@ -12,10 +12,10 @@
|
|||||||
"@storybook/react": "^3.4.3",
|
"@storybook/react": "^3.4.3",
|
||||||
"react": "^16.5.1",
|
"react": "^16.5.1",
|
||||||
"react-dom": "^16.5.1",
|
"react-dom": "^16.5.1",
|
||||||
"react-native-web": "0.9.7"
|
"react-native-web": "0.9.12"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"babel-plugin-react-native-web": "0.9.7",
|
"babel-plugin-react-native-web": "0.9.12",
|
||||||
"url-loader": "^1.0.1",
|
"url-loader": "^1.0.1",
|
||||||
"webpack": "^4.8.1"
|
"webpack": "^4.8.1"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -101,6 +101,12 @@ const ScrollViewScreen = () => (
|
|||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<DocItem
|
||||||
|
name="pagingEnabled"
|
||||||
|
typeInfo="?boolean = false"
|
||||||
|
description="When true, the scroll view snaps to individual items in the list when scrolling."
|
||||||
|
/>
|
||||||
|
|
||||||
<DocItem
|
<DocItem
|
||||||
name="scrollEnabled"
|
name="scrollEnabled"
|
||||||
typeInfo="?boolean = true"
|
typeInfo="?boolean = true"
|
||||||
|
|||||||
Reference in New Issue
Block a user