mirror of
https://github.com/zhigang1992/react-native-web.git
synced 2026-04-24 04:25:27 +08:00
Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ed70617e91 | ||
|
|
134114de83 | ||
|
|
08ee7c83bb | ||
|
|
5fad78dcad | ||
|
|
e04343e48e | ||
|
|
5e3a946f8b | ||
|
|
4e3d8dbb02 | ||
|
|
fee909d26a | ||
|
|
9e58a7b5f1 | ||
|
|
20e1febe21 | ||
|
|
ef209ca281 |
16
.github/CONTRIBUTING.md
vendored
16
.github/CONTRIBUTING.md
vendored
@@ -104,13 +104,17 @@ Please open an issue with a proposal for a new feature or refactoring before
|
|||||||
starting on the work. We don't want you to waste your efforts on a pull request
|
starting on the work. We don't want you to waste your efforts on a pull request
|
||||||
that we won't want to accept.
|
that we won't want to accept.
|
||||||
|
|
||||||
## Submitting Changes
|
## Pull requests
|
||||||
|
|
||||||
* Open a new issue in the [Issue tracker](https://github.com/necolas/react-native-web/issues).
|
**Before submitting a pull request,** please make sure the following is done:
|
||||||
* Fork the repo.
|
|
||||||
* Create a new feature branch based off the `master` branch.
|
1. Fork the repository and create your branch from `master`.
|
||||||
* Make sure all tests pass and there are no linting errors.
|
2. If you've added code that should be tested, add tests!
|
||||||
* Submit a pull request, referencing any issues it addresses.
|
3. If you've changed APIs, update the documentation.
|
||||||
|
4. Ensure the tests pass (`yarn test`).
|
||||||
|
5. Lint and format your code (`yarn fmt && yarn lint`).
|
||||||
|
|
||||||
|
You can now submit a pull request, referencing any issues it addresses.
|
||||||
|
|
||||||
Please try to keep your pull request focused in scope and avoid including
|
Please try to keep your pull request focused in scope and avoid including
|
||||||
unrelated commits.
|
unrelated commits.
|
||||||
|
|||||||
34
.github/ISSUE_TEMPLATE.md
vendored
34
.github/ISSUE_TEMPLATE.md
vendored
@@ -1,30 +1,20 @@
|
|||||||
<!--
|
**Do you want to request a *feature* or report a *bug*?**
|
||||||
React Native for Web is an implementation of React Native. If you have feature
|
|
||||||
requests, you should post them to https://productpains.com/product/react-native/.
|
|
||||||
|
|
||||||
GitHub issues should only be used for bugs or Web-specific features you believe
|
|
||||||
React Native requires.
|
|
||||||
|
|
||||||
Make sure to add ALL the information needed to understand the bug so that
|
|
||||||
someone can help. If the info is missing we'll add the 'needs more information'
|
|
||||||
label and close the issue until there is enough information.
|
|
||||||
-->
|
|
||||||
|
|
||||||
**What is the current behavior?**
|
**What is the current behavior?**
|
||||||
|
|
||||||
Link to minimal test case: (template: [codepen](https://codepen.io/necolas/pen/PZzwBR?editors=0010))
|
**If the current behavior is a bug, please provide the steps to reproduce and
|
||||||
|
if a minimal demo of the problem via Glitch or similar (template:
|
||||||
**What is the expected behaviour?**
|
https://glitch.com/edit/#!/react-native-web-playground).**
|
||||||
|
|
||||||
**Steps to reproduce**
|
|
||||||
|
|
||||||
1.
|
1.
|
||||||
2.
|
2.
|
||||||
|
|
||||||
**Environment (include versions)**
|
**What is the expected behavior?**
|
||||||
|
|
||||||
OS:
|
**Environment (include versions). Did this work in previous versions?**
|
||||||
Device:
|
|
||||||
Browser:
|
* OS:
|
||||||
React Native for Web (version):
|
* Device:
|
||||||
React (version):
|
* Browser:
|
||||||
|
* React Native for Web (version):
|
||||||
|
* React (version):
|
||||||
|
|||||||
19
.github/PULL_REQUEST_TEMPLATE.md
vendored
19
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -1,18 +1 @@
|
|||||||
<!--
|
**Before submitting a pull request,** please make sure you have followed the steps the CONTRIBUTING guide.
|
||||||
Thanks for submitting a pull request! Make sure the PR does only one thing.
|
|
||||||
Please provide enough information so that others can review your pull
|
|
||||||
request. Make sure you have read the Contributing Guidelines -
|
|
||||||
https://github.com/necolas/react-native-web/CONTRIBUTING.md
|
|
||||||
-->
|
|
||||||
|
|
||||||
**This patch solves the following problem**
|
|
||||||
|
|
||||||
**Test plan**
|
|
||||||
|
|
||||||
**This pull request**
|
|
||||||
|
|
||||||
- [ ] includes documentation
|
|
||||||
- [ ] includes tests
|
|
||||||
- [ ] includes benchmark reports
|
|
||||||
- [ ] includes an interactive example
|
|
||||||
- [ ] includes screenshots/videos
|
|
||||||
|
|||||||
24
README.md
24
README.md
@@ -25,14 +25,14 @@ Glitch.
|
|||||||
|
|
||||||
## Quick start
|
## Quick start
|
||||||
|
|
||||||
To install in your app:
|
|
||||||
|
|
||||||
```
|
|
||||||
npm install --save react@15.6 react-dom@15.6 react-native-web
|
|
||||||
```
|
|
||||||
|
|
||||||
NOTE: React Native for Web supports React/ReactDOM 15.4, 15.5, or 15.6.
|
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
|
||||||
|
```
|
||||||
|
|
||||||
Then read the [Getting Started](docs/guides/getting-started.md) guide.
|
Then read the [Getting Started](docs/guides/getting-started.md) guide.
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
@@ -50,6 +50,12 @@ Guides:
|
|||||||
* [Advanced use](docs/guides/advanced.md)
|
* [Advanced use](docs/guides/advanced.md)
|
||||||
* [Known issues](docs/guides/known-issues.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
|
## Example code
|
||||||
|
|
||||||
```js
|
```js
|
||||||
@@ -96,12 +102,6 @@ AppRegistry.runApplication('MyApp', { rootTag: document.getElementById('react-ro
|
|||||||
* [reactxp](https://github.com/microsoft/reactxp)
|
* [reactxp](https://github.com/microsoft/reactxp)
|
||||||
* [react-native-web-player](https://github.com/dabbott/react-native-web-player)
|
* [react-native-web-player](https://github.com/dabbott/react-native-web-player)
|
||||||
|
|
||||||
## Start 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)
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
React Native for Web is [BSD licensed](LICENSE).
|
React Native for Web is [BSD licensed](LICENSE).
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"aphrodite": "^1.2.3",
|
"aphrodite": "^1.2.3",
|
||||||
"classnames": "^2.2.5",
|
"classnames": "^2.2.5",
|
||||||
"glamor": "^3.0.0-3",
|
"glamor": "^2.20.37",
|
||||||
"marky": "^1.2.0",
|
"marky": "^1.2.0",
|
||||||
"radium": "^0.19.1",
|
"radium": "^0.19.1",
|
||||||
"react-jss": "^7.0.1",
|
"react-jss": "^7.0.1",
|
||||||
|
|||||||
@@ -59,7 +59,11 @@ array-find@^1.0.0:
|
|||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/array-find/-/array-find-1.0.0.tgz#6c8e286d11ed768327f8e62ecee87353ca3e78b8"
|
resolved "https://registry.yarnpkg.com/array-find/-/array-find-1.0.0.tgz#6c8e286d11ed768327f8e62ecee87353ca3e78b8"
|
||||||
|
|
||||||
asap@^2.0.3, asap@^2.0.5, asap@~2.0.3:
|
asap@^2.0.3, asap@^2.0.5:
|
||||||
|
version "2.0.6"
|
||||||
|
resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46"
|
||||||
|
|
||||||
|
asap@~2.0.3:
|
||||||
version "2.0.5"
|
version "2.0.5"
|
||||||
resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.5.tgz#522765b50c3510490e52d7dcfe085ef9ba96958f"
|
resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.5.tgz#522765b50c3510490e52d7dcfe085ef9ba96958f"
|
||||||
|
|
||||||
@@ -89,8 +93,8 @@ babel-code-frame@^6.11.0:
|
|||||||
js-tokens "^3.0.0"
|
js-tokens "^3.0.0"
|
||||||
|
|
||||||
babel-runtime@^6.23.0:
|
babel-runtime@^6.23.0:
|
||||||
version "6.23.0"
|
version "6.25.0"
|
||||||
resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.23.0.tgz#0a9489f144de70efb3ce4300accdb329e2fc543b"
|
resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.25.0.tgz#33b98eaa5d482bb01a8d1aa6b437ad2b01aec41c"
|
||||||
dependencies:
|
dependencies:
|
||||||
core-js "^2.4.0"
|
core-js "^2.4.0"
|
||||||
regenerator-runtime "^0.10.0"
|
regenerator-runtime "^0.10.0"
|
||||||
@@ -111,10 +115,14 @@ big.js@^3.1.3:
|
|||||||
version "3.1.3"
|
version "3.1.3"
|
||||||
resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.1.3.tgz#4cada2193652eb3ca9ec8e55c9015669c9806978"
|
resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.1.3.tgz#4cada2193652eb3ca9ec8e55c9015669c9806978"
|
||||||
|
|
||||||
bowser@^1.0.0, bowser@^1.6.0:
|
bowser@^1.0.0:
|
||||||
version "1.6.0"
|
version "1.6.0"
|
||||||
resolved "https://registry.yarnpkg.com/bowser/-/bowser-1.6.0.tgz#37fc387b616cb6aef370dab4d6bd402b74c5c54d"
|
resolved "https://registry.yarnpkg.com/bowser/-/bowser-1.6.0.tgz#37fc387b616cb6aef370dab4d6bd402b74c5c54d"
|
||||||
|
|
||||||
|
bowser@^1.6.0:
|
||||||
|
version "1.7.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/bowser/-/bowser-1.7.1.tgz#a4de8f18a1a0dc9531eb2a92a1521fb6a9ba96a5"
|
||||||
|
|
||||||
brace-expansion@^1.1.7:
|
brace-expansion@^1.1.7:
|
||||||
version "1.1.8"
|
version "1.1.8"
|
||||||
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.8.tgz#c07b211c7c952ec1f8efd51a77ef0d1d3990a292"
|
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.8.tgz#c07b211c7c952ec1f8efd51a77ef0d1d3990a292"
|
||||||
@@ -253,7 +261,7 @@ css-color-names@0.0.4:
|
|||||||
|
|
||||||
css-in-js-utils@^1.0.3:
|
css-in-js-utils@^1.0.3:
|
||||||
version "1.0.3"
|
version "1.0.3"
|
||||||
resolved "https://artifactory.twitter.biz:443/api/npm/js-virtual/css-in-js-utils/-/css-in-js-utils-1.0.3.tgz#9ac7e02f763cf85d94017666565ed68a5b5f3215"
|
resolved "https://registry.yarnpkg.com/css-in-js-utils/-/css-in-js-utils-1.0.3.tgz#9ac7e02f763cf85d94017666565ed68a5b5f3215"
|
||||||
dependencies:
|
dependencies:
|
||||||
hyphenate-style-name "^1.0.2"
|
hyphenate-style-name "^1.0.2"
|
||||||
|
|
||||||
@@ -414,7 +422,19 @@ fastparse@^1.1.1:
|
|||||||
version "1.1.1"
|
version "1.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/fastparse/-/fastparse-1.1.1.tgz#d1e2643b38a94d7583b479060e6c4affc94071f8"
|
resolved "https://registry.yarnpkg.com/fastparse/-/fastparse-1.1.1.tgz#d1e2643b38a94d7583b479060e6c4affc94071f8"
|
||||||
|
|
||||||
fbjs@^0.8.12, fbjs@^0.8.4, fbjs@^0.8.5, fbjs@^0.8.9:
|
fbjs@^0.8.12:
|
||||||
|
version "0.8.14"
|
||||||
|
resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.14.tgz#d1dbe2be254c35a91e09f31f9cd50a40b2a0ed1c"
|
||||||
|
dependencies:
|
||||||
|
core-js "^1.0.0"
|
||||||
|
isomorphic-fetch "^2.1.1"
|
||||||
|
loose-envify "^1.0.0"
|
||||||
|
object-assign "^4.1.0"
|
||||||
|
promise "^7.1.1"
|
||||||
|
setimmediate "^1.0.5"
|
||||||
|
ua-parser-js "^0.7.9"
|
||||||
|
|
||||||
|
fbjs@^0.8.4, fbjs@^0.8.5, fbjs@^0.8.9:
|
||||||
version "0.8.12"
|
version "0.8.12"
|
||||||
resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.12.tgz#10b5d92f76d45575fd63a217d4ea02bea2f8ed04"
|
resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.12.tgz#10b5d92f76d45575fd63a217d4ea02bea2f8ed04"
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -442,13 +462,14 @@ function-bind@^1.0.2:
|
|||||||
version "1.1.0"
|
version "1.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.0.tgz#16176714c801798e4e8f2cf7f7529467bb4a5771"
|
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.0.tgz#16176714c801798e4e8f2cf7f7529467bb4a5771"
|
||||||
|
|
||||||
glamor@^3.0.0-3:
|
glamor@^2.20.37:
|
||||||
version "3.0.0-3"
|
version "2.20.37"
|
||||||
resolved "https://registry.yarnpkg.com/glamor/-/glamor-3.0.0-3.tgz#62e1cf2ce70a4db0b247a5f95d4b7d6a89ac83c9"
|
resolved "https://registry.yarnpkg.com/glamor/-/glamor-2.20.37.tgz#3cd576deb760eaaf475dcc1f9b77bf6a7d2f8b26"
|
||||||
dependencies:
|
dependencies:
|
||||||
fbjs "^0.8.12"
|
fbjs "^0.8.12"
|
||||||
inline-style-prefixer "^3.0.3"
|
inline-style-prefixer "^3.0.6"
|
||||||
react-css-property-operations "^15.4.1"
|
object-assign "^4.1.1"
|
||||||
|
prop-types "^15.5.10"
|
||||||
|
|
||||||
glob@^7.0.5:
|
glob@^7.0.5:
|
||||||
version "7.1.2"
|
version "7.1.2"
|
||||||
@@ -537,7 +558,7 @@ inline-style-prefixer@^2.0.1, inline-style-prefixer@^2.0.5:
|
|||||||
bowser "^1.0.0"
|
bowser "^1.0.0"
|
||||||
hyphenate-style-name "^1.0.1"
|
hyphenate-style-name "^1.0.1"
|
||||||
|
|
||||||
inline-style-prefixer@^3.0.1, inline-style-prefixer@^3.0.3, inline-style-prefixer@^3.0.6:
|
inline-style-prefixer@^3.0.1, inline-style-prefixer@^3.0.6:
|
||||||
version "3.0.6"
|
version "3.0.6"
|
||||||
resolved "https://registry.yarnpkg.com/inline-style-prefixer/-/inline-style-prefixer-3.0.6.tgz#b27fe309b4168a31eaf38c8e8c60ab9e7c11731f"
|
resolved "https://registry.yarnpkg.com/inline-style-prefixer/-/inline-style-prefixer-3.0.6.tgz#b27fe309b4168a31eaf38c8e8c60ab9e7c11731f"
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -1090,10 +1111,6 @@ react-addons-perf@^15.4.2:
|
|||||||
fbjs "^0.8.4"
|
fbjs "^0.8.4"
|
||||||
object-assign "^4.1.0"
|
object-assign "^4.1.0"
|
||||||
|
|
||||||
react-css-property-operations@^15.4.1:
|
|
||||||
version "15.4.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/react-css-property-operations/-/react-css-property-operations-15.4.1.tgz#4c0e305df4cc35f0f5fd2d65a79214c8b012db35"
|
|
||||||
|
|
||||||
react-jss@^7.0.1:
|
react-jss@^7.0.1:
|
||||||
version "7.0.1"
|
version "7.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/react-jss/-/react-jss-7.0.1.tgz#36c505c3798993edd46ea01734f171f895348e25"
|
resolved "https://registry.yarnpkg.com/react-jss/-/react-jss-7.0.1.tgz#36c505c3798993edd46ea01734f171f895348e25"
|
||||||
@@ -1105,8 +1122,8 @@ react-jss@^7.0.1:
|
|||||||
theming "^1.1.0"
|
theming "^1.1.0"
|
||||||
|
|
||||||
react-native-web@0.0.x:
|
react-native-web@0.0.x:
|
||||||
version "0.0.106"
|
version "0.0.116"
|
||||||
resolved "https://registry.yarnpkg.com/react-native-web/-/react-native-web-0.0.106.tgz#928427320b5963548b372a32b62459154f1e1d7e"
|
resolved "https://registry.yarnpkg.com/react-native-web/-/react-native-web-0.0.116.tgz#e05e376b34617a54d61826e4bc06b0bdbfd3f4b2"
|
||||||
dependencies:
|
dependencies:
|
||||||
animated "^0.2.0"
|
animated "^0.2.0"
|
||||||
array-find-index "^1.0.2"
|
array-find-index "^1.0.2"
|
||||||
@@ -1184,8 +1201,8 @@ regenerate@^1.2.1:
|
|||||||
resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.3.2.tgz#d1941c67bad437e1be76433add5b385f95b19260"
|
resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.3.2.tgz#d1941c67bad437e1be76433add5b385f95b19260"
|
||||||
|
|
||||||
regenerator-runtime@^0.10.0:
|
regenerator-runtime@^0.10.0:
|
||||||
version "0.10.3"
|
version "0.10.5"
|
||||||
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.3.tgz#8c4367a904b51ea62a908ac310bf99ff90a82a3e"
|
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz#336c3efc1220adcedda2c9fab67b5a7955a33658"
|
||||||
|
|
||||||
regexpu-core@^1.0.0:
|
regexpu-core@^1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
@@ -1249,7 +1266,7 @@ strict-uri-encode@^1.0.0:
|
|||||||
|
|
||||||
string-hash@^1.1.3:
|
string-hash@^1.1.3:
|
||||||
version "1.1.3"
|
version "1.1.3"
|
||||||
resolved "https://artifactory.twitter.biz:443/api/npm/js-virtual/string-hash/-/string-hash-1.1.3.tgz#e8aafc0ac1855b4666929ed7dd1275df5d6c811b"
|
resolved "https://registry.yarnpkg.com/string-hash/-/string-hash-1.1.3.tgz#e8aafc0ac1855b4666929ed7dd1275df5d6c811b"
|
||||||
|
|
||||||
strip-ansi@^3.0.0:
|
strip-ansi@^3.0.0:
|
||||||
version "3.0.1"
|
version "3.0.1"
|
||||||
|
|||||||
@@ -1,25 +1,22 @@
|
|||||||
# Getting started
|
# Getting started
|
||||||
|
|
||||||
This guide will help you to correctly configure build and test tools to work
|
This guide will help you to correctly configure build and test tools to work
|
||||||
with React Native for Web.
|
with React Native for Web. (Alternatively, you can quickly setup a local
|
||||||
|
project using the starter kits listed in the README.)
|
||||||
Alternatively, you can quickly setup a local project using
|
|
||||||
[create-react-app](https://github.com/facebookincubator/create-react-app)
|
|
||||||
(which supports `react-native-web` out-of-the-box once installed),
|
|
||||||
[react-native-web-starter](https://github.com/grabcode/react-native-web-starter),
|
|
||||||
or [react-native-web-webpack](https://github.com/ndbroadbent/react-native-web-webpack).
|
|
||||||
|
|
||||||
It is recommended that your application provide a `Promise` and `Array.from`
|
It is recommended that your application provide a `Promise` and `Array.from`
|
||||||
polyfill.
|
polyfill.
|
||||||
|
|
||||||
## Webpack and Babel
|
## Web packager
|
||||||
|
|
||||||
[Webpack](https://webpack.js.org) is a popular build tool for web apps. Below is an
|
[Webpack](https://webpack.js.org) is a popular build tool for web apps. Below is an
|
||||||
example of how to configure a build that uses [Babel](https://babeljs.io/) to
|
example of how to configure a build that uses [Babel](https://babeljs.io/) to
|
||||||
compile your JavaScript for the web.
|
compile your JavaScript for the web.
|
||||||
|
|
||||||
|
Create a `web/webpack.config.js` file:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
// webpack.config.js
|
// web/webpack.config.js
|
||||||
|
|
||||||
// This is needed for webpack to compile JavaScript.
|
// This is needed for webpack to compile JavaScript.
|
||||||
// Many OSS React Native packages are not compiled to ES5 before being
|
// Many OSS React Native packages are not compiled to ES5 before being
|
||||||
@@ -37,7 +34,7 @@ const babelLoaderConfiguration = {
|
|||||||
loader: 'babel-loader',
|
loader: 'babel-loader',
|
||||||
options: {
|
options: {
|
||||||
cacheDirectory: true,
|
cacheDirectory: true,
|
||||||
// The 'react-native' preset is recommended
|
// The 'react-native' preset is recommended (or use your own .babelrc)
|
||||||
presets: ['react-native']
|
presets: ['react-native']
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -66,7 +63,8 @@ module.exports = {
|
|||||||
|
|
||||||
plugins: [
|
plugins: [
|
||||||
// `process.env.NODE_ENV === 'production'` must be `true` for production
|
// `process.env.NODE_ENV === 'production'` must be `true` for production
|
||||||
// builds to eliminate development checks and reduce build size.
|
// builds to eliminate development checks and reduce build size. You may
|
||||||
|
// wish to include additional optimizations.
|
||||||
new webpack.DefinePlugin({
|
new webpack.DefinePlugin({
|
||||||
'process.env.NODE_ENV': JSON.stringify('production')
|
'process.env.NODE_ENV': JSON.stringify('production')
|
||||||
})
|
})
|
||||||
@@ -85,36 +83,97 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Please refer to the Webpack documentation for more information.
|
To run in development:
|
||||||
|
|
||||||
## Jest
|
|
||||||
|
|
||||||
[Jest](https://facebook.github.io/jest/) also needs to map `react-native` to `react-native-web`.
|
|
||||||
|
|
||||||
```
|
```
|
||||||
"jest": {
|
./node_modules/.bin/webpack-dev-server -d --config web/webpack.config.js --inline --hot --colors
|
||||||
"moduleNameMapper": {
|
|
||||||
"react-native": "<rootDir>/node_modules/react-native-web"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Please refer to the Jest documentation for more information.
|
To build for production:
|
||||||
|
|
||||||
|
```
|
||||||
|
./node_modules/.bin/webpack -p --config web/webpack.config.js
|
||||||
|
```
|
||||||
|
|
||||||
|
Please refer to the Webpack documentation for more information on configuration.
|
||||||
|
|
||||||
|
## Web entry
|
||||||
|
|
||||||
|
Create a `index.web.js` file (or simply `index.js` for web-only apps).
|
||||||
|
|
||||||
|
### Client-side rendering
|
||||||
|
|
||||||
|
Rendering using `AppRegistry`:
|
||||||
|
|
||||||
|
```js
|
||||||
|
// index.web.js
|
||||||
|
|
||||||
|
import App from './src/App';
|
||||||
|
import React from 'react';
|
||||||
|
import ReactNative, { AppRegistry } from 'react-native';
|
||||||
|
|
||||||
|
// register the app
|
||||||
|
AppRegistry.registerComponent('App', () => App);
|
||||||
|
|
||||||
|
AppRegistry.runApplication('App', {
|
||||||
|
initialProps: {},
|
||||||
|
rootTag: document.getElementById('react-app')
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
Rendering within existing web apps is also possible using `ReactNative`:
|
||||||
|
|
||||||
|
```js
|
||||||
|
import AppHeader from './src/AppHeader';
|
||||||
|
import React from 'react';
|
||||||
|
import ReactNative from 'react-native';
|
||||||
|
|
||||||
|
ReactNative.render(<AppHeader />, document.getElementById('react-app-header'))
|
||||||
|
```
|
||||||
|
|
||||||
|
And finally, `react-native-web` components will also be rendering within a tree
|
||||||
|
produced by calling `ReactDOM.render` (i.e., an existing web app), but
|
||||||
|
otherwise it is not recommended.
|
||||||
|
|
||||||
|
### Server-side rendering
|
||||||
|
|
||||||
|
Server-side rendering is supported using the `AppRegistry`:
|
||||||
|
|
||||||
|
```js
|
||||||
|
import App from './src/App';
|
||||||
|
import ReactDOMServer from 'react-dom/server'
|
||||||
|
import ReactNative, { AppRegistry } from 'react-native'
|
||||||
|
|
||||||
|
// register the app
|
||||||
|
AppRegistry.registerComponent('App', () => App)
|
||||||
|
|
||||||
|
// prerender the app
|
||||||
|
const { element, stylesheets } = AppRegistry.getApplication('App', { initialProps });
|
||||||
|
const initialHTML = ReactDOMServer.renderToString(element);
|
||||||
|
const initialStyles = stylesheets.map((sheet) => ReactDOMServer.renderToStaticMarkup(sheet)).join('\n');
|
||||||
|
|
||||||
|
// construct HTML document
|
||||||
|
const document = `
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
${initialStyles}
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
${initialHTML}
|
||||||
|
`
|
||||||
|
```
|
||||||
|
|
||||||
## Web-specific code
|
## Web-specific code
|
||||||
|
|
||||||
Minor platform differences can use the `Platform` module.
|
Minor platform differences can use the `Platform` module.
|
||||||
|
|
||||||
```js
|
```js
|
||||||
import { AppRegistry, Platform } from 'react-native'
|
import { Platform } from 'react-native';
|
||||||
|
|
||||||
AppRegistry.registerComponent('MyApp', () => MyApp)
|
const styles = StyleSheet.create({
|
||||||
|
height: (Platform.OS === 'web') ? 200 : 100,
|
||||||
if (Platform.OS === 'web') {
|
});
|
||||||
AppRegistry.runApplication('MyApp', {
|
|
||||||
rootTag: document.getElementById('react-root')
|
|
||||||
});
|
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
More significant platform differences should use platform-specific files (see
|
More significant platform differences should use platform-specific files (see
|
||||||
@@ -137,68 +196,16 @@ import MyComponent from './MyComponent';
|
|||||||
React Native will automatically import the correct variant for each specific
|
React Native will automatically import the correct variant for each specific
|
||||||
target platform.
|
target platform.
|
||||||
|
|
||||||
## Client-side rendering
|
## Testing with Jest
|
||||||
|
|
||||||
Rendering using `ReactNative`:
|
[Jest](https://facebook.github.io/jest/) also needs to map `react-native` to `react-native-web`.
|
||||||
|
|
||||||
```js
|
```
|
||||||
import React from 'react'
|
"jest": {
|
||||||
import ReactNative from 'react-native'
|
"moduleNameMapper": {
|
||||||
|
"react-native": "<rootDir>/node_modules/react-native-web"
|
||||||
// component that renders the app
|
}
|
||||||
const AppHeaderContainer = (props) => { /* ... */ }
|
}
|
||||||
|
|
||||||
ReactNative.render(<AppHeaderContainer />, document.getElementById('react-app-header'))
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Rendering using `AppRegistry`:
|
Please refer to the Jest documentation for more information.
|
||||||
|
|
||||||
```js
|
|
||||||
import React from 'react'
|
|
||||||
import ReactNative, { AppRegistry } from 'react-native'
|
|
||||||
|
|
||||||
// component that renders the app
|
|
||||||
const AppContainer = (props) => { /* ... */ }
|
|
||||||
|
|
||||||
// register the app
|
|
||||||
AppRegistry.registerComponent('App', () => AppContainer)
|
|
||||||
|
|
||||||
AppRegistry.runApplication('App', {
|
|
||||||
initialProps: {},
|
|
||||||
rootTag: document.getElementById('react-app')
|
|
||||||
})
|
|
||||||
```
|
|
||||||
|
|
||||||
Rendering within `ReactDOM.render` also works when introducing
|
|
||||||
`react-native-web` to an existing web app, but otherwise it is not recommended.
|
|
||||||
|
|
||||||
## Server-side rendering
|
|
||||||
|
|
||||||
Rendering using the `AppRegistry`:
|
|
||||||
|
|
||||||
```js
|
|
||||||
import ReactDOMServer from 'react-dom/server'
|
|
||||||
import ReactNative, { AppRegistry } from 'react-native'
|
|
||||||
|
|
||||||
// component that renders the app
|
|
||||||
const AppContainer = (props) => { /* ... */ }
|
|
||||||
|
|
||||||
// register the app
|
|
||||||
AppRegistry.registerComponent('App', () => AppContainer)
|
|
||||||
|
|
||||||
// prerender the app
|
|
||||||
const { element, stylesheets } = AppRegistry.getApplication('App', { initialProps });
|
|
||||||
const initialHTML = ReactDOMServer.renderToString(element);
|
|
||||||
const initialStyles = stylesheets.map((sheet) => ReactDOMServer.renderToStaticMarkup(sheet)).join('\n');
|
|
||||||
|
|
||||||
// construct HTML document
|
|
||||||
const document = `
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
${initialStyles}
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
${initialHTML}
|
|
||||||
`
|
|
||||||
```
|
|
||||||
|
|||||||
@@ -3,11 +3,11 @@
|
|||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "yarn && build-storybook -o ./dist -c ./storybook/.storybook",
|
"build": "yarn && build-storybook -o ./dist -c ./storybook/.storybook",
|
||||||
"start": "start-storybook -p 9001 -c ./storybook/.storybook --dont-track",
|
"start": "start-storybook -p 9001 -c ./storybook/.storybook",
|
||||||
"publish": "yarn build && git checkout gh-pages && rm -rf ./storybook && mv docs/dist storybook && git add -A && git commit -m \"Storybook deploy\" && git push origin gh-pages && git checkout -"
|
"publish": "yarn build && git checkout gh-pages && rm -rf ./storybook && mv docs/dist storybook && git add -A && git commit -m \"Storybook deploy\" && git push origin gh-pages && git checkout -"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@kadira/storybook": "^2.35.3",
|
"@storybook/addon-options": "^3.1.6",
|
||||||
"@kadira/storybook-addon-options": "^1.0.2"
|
"@storybook/react": "^3.1.9"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
import '@kadira/storybook-addon-options/register';
|
import '@storybook/addon-options/register';
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { setOptions } from '@kadira/storybook-addon-options';
|
import { setOptions } from '@storybook/addon-options';
|
||||||
import centered from './decorator-centered';
|
import centered from './decorator-centered';
|
||||||
import { configure, addDecorator } from '@kadira/storybook';
|
import { configure, addDecorator } from '@storybook/react';
|
||||||
|
|
||||||
const context = require.context('../', true, /Screen\.js$/);
|
const context = require.context('../', true, /Screen\.js$/);
|
||||||
|
|
||||||
|
|||||||
@@ -1,33 +1,36 @@
|
|||||||
const path = require('path');
|
const path = require('path');
|
||||||
const webpack = require('webpack');
|
const webpack = require('webpack');
|
||||||
|
|
||||||
const DEV = process.env.NODE_ENV !== 'production';
|
module.exports = (storybookBaseConfig, configType) => {
|
||||||
|
const DEV = configType === 'DEVELOPMENT';
|
||||||
|
|
||||||
module.exports = {
|
storybookBaseConfig.module.rules.push({
|
||||||
module: {
|
test: /\.js$/,
|
||||||
loaders: [
|
exclude: /node_modules/,
|
||||||
{
|
use: {
|
||||||
test: /\.js$/,
|
loader: 'babel-loader',
|
||||||
exclude: /node_modules/,
|
options: { cacheDirectory: true }
|
||||||
loader: 'babel-loader',
|
}
|
||||||
query: { cacheDirectory: true }
|
});
|
||||||
},
|
|
||||||
{
|
storybookBaseConfig.module.rules.push({
|
||||||
test: /\.(gif|jpe?g|png|svg)$/,
|
test: /\.(gif|jpe?g|png|svg)$/,
|
||||||
loader: 'url-loader',
|
use: {
|
||||||
query: { name: '[name].[ext]' }
|
loader: 'url-loader',
|
||||||
}
|
options: { name: '[name].[ext]' }
|
||||||
]
|
}
|
||||||
},
|
});
|
||||||
plugins: [
|
|
||||||
|
storybookBaseConfig.plugins.push(
|
||||||
new webpack.DefinePlugin({
|
new webpack.DefinePlugin({
|
||||||
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development'),
|
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development'),
|
||||||
'process.env.__REACT_NATIVE_DEBUG_ENABLED__': DEV
|
'process.env.__REACT_NATIVE_DEBUG_ENABLED__': DEV
|
||||||
})
|
})
|
||||||
],
|
);
|
||||||
resolve: {
|
|
||||||
alias: {
|
storybookBaseConfig.resolve.alias = {
|
||||||
'react-native': path.join(__dirname, '../../../src/module')
|
'react-native': path.join(__dirname, '../../../src/module')
|
||||||
}
|
};
|
||||||
}
|
|
||||||
|
return storybookBaseConfig;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -9,8 +9,7 @@ import PropColor from './examples/PropColor';
|
|||||||
import PropHidesWhenStopped from './examples/PropHidesWhenStopped';
|
import PropHidesWhenStopped from './examples/PropHidesWhenStopped';
|
||||||
import PropSize from './examples/PropSize';
|
import PropSize from './examples/PropSize';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { storiesOf } from '@kadira/storybook';
|
import UIExplorer, { Description, DocItem, Section, storiesOf } from '../../ui-explorer';
|
||||||
import UIExplorer, { Description, DocItem, Section } from '../../ui-explorer';
|
|
||||||
|
|
||||||
const ActivityIndicatorScreen = () =>
|
const ActivityIndicatorScreen = () =>
|
||||||
<UIExplorer title="ActivityIndicator" url="components/ActivityIndicator">
|
<UIExplorer title="ActivityIndicator" url="components/ActivityIndicator">
|
||||||
|
|||||||
@@ -8,8 +8,14 @@ import React from 'react';
|
|||||||
import PropColor from './examples/PropColor';
|
import PropColor from './examples/PropColor';
|
||||||
import PropDisabled from './examples/PropDisabled';
|
import PropDisabled from './examples/PropDisabled';
|
||||||
import PropOnPress from './examples/PropOnPress';
|
import PropOnPress from './examples/PropOnPress';
|
||||||
import UIExplorer, { AppText, Code, Description, DocItem, Section } from '../../ui-explorer';
|
import UIExplorer, {
|
||||||
import { storiesOf } from '@kadira/storybook';
|
AppText,
|
||||||
|
Code,
|
||||||
|
Description,
|
||||||
|
DocItem,
|
||||||
|
Section,
|
||||||
|
storiesOf
|
||||||
|
} from '../../ui-explorer';
|
||||||
|
|
||||||
const ButtonScreen = () =>
|
const ButtonScreen = () =>
|
||||||
<UIExplorer title="Button" url="components/Button">
|
<UIExplorer title="Button" url="components/Button">
|
||||||
|
|||||||
@@ -16,8 +16,14 @@ import PropResizeMode from './examples/PropResizeMode';
|
|||||||
import PropSource from './examples/PropSource';
|
import PropSource from './examples/PropSource';
|
||||||
import StaticGetSizeExample from './examples/StaticGetSize';
|
import StaticGetSizeExample from './examples/StaticGetSize';
|
||||||
import StaticPrefetchExample from './examples/StaticPrefetch';
|
import StaticPrefetchExample from './examples/StaticPrefetch';
|
||||||
import { storiesOf } from '@kadira/storybook';
|
import UIExplorer, {
|
||||||
import UIExplorer, { AppText, Code, Description, DocItem, Section } from '../../ui-explorer';
|
AppText,
|
||||||
|
Code,
|
||||||
|
Description,
|
||||||
|
DocItem,
|
||||||
|
Section,
|
||||||
|
storiesOf
|
||||||
|
} from '../../ui-explorer';
|
||||||
|
|
||||||
const ImageScreen = () =>
|
const ImageScreen = () =>
|
||||||
<UIExplorer title="Image" url="components/Image">
|
<UIExplorer title="Image" url="components/Image">
|
||||||
|
|||||||
@@ -8,8 +8,7 @@ import PropIndeterminate from './examples/PropIndeterminate';
|
|||||||
import PropProgress from './examples/PropProgress';
|
import PropProgress from './examples/PropProgress';
|
||||||
import PropTrackColor from './examples/PropTrackColor';
|
import PropTrackColor from './examples/PropTrackColor';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { storiesOf } from '@kadira/storybook';
|
import UIExplorer, { Description, DocItem, Section, storiesOf } from '../../ui-explorer';
|
||||||
import UIExplorer, { Description, DocItem, Section } from '../../ui-explorer';
|
|
||||||
|
|
||||||
const ProgressBarScreen = () =>
|
const ProgressBarScreen = () =>
|
||||||
<UIExplorer title="ProgressBar" url="components/ProgressBar">
|
<UIExplorer title="ProgressBar" url="components/ProgressBar">
|
||||||
|
|||||||
@@ -8,13 +8,13 @@ import { HorizontalExample } from './examples/Horizontal';
|
|||||||
import ScrollToExample from './examples/ScrollTo';
|
import ScrollToExample from './examples/ScrollTo';
|
||||||
import ScrollToEndExample from './examples/ScrollToEnd';
|
import ScrollToEndExample from './examples/ScrollToEnd';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { storiesOf } from '@kadira/storybook';
|
|
||||||
import UIExplorer, {
|
import UIExplorer, {
|
||||||
AppText,
|
AppText,
|
||||||
Code,
|
Code,
|
||||||
Description,
|
Description,
|
||||||
DocItem,
|
DocItem,
|
||||||
Section,
|
Section,
|
||||||
|
storiesOf,
|
||||||
TextList
|
TextList
|
||||||
} from '../../ui-explorer';
|
} from '../../ui-explorer';
|
||||||
|
|
||||||
|
|||||||
@@ -5,10 +5,11 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { action } from '@kadira/storybook';
|
|
||||||
import { ScrollView, StyleSheet, Text, View } from 'react-native';
|
import { ScrollView, StyleSheet, Text, View } from 'react-native';
|
||||||
|
|
||||||
const onScroll = action('ScrollView.onScroll');
|
const onScroll = () => {
|
||||||
|
console.log('ScrollView.onScroll');
|
||||||
|
};
|
||||||
|
|
||||||
const VerticalExample = () =>
|
const VerticalExample = () =>
|
||||||
<View style={styles.scrollViewContainer}>
|
<View style={styles.scrollViewContainer}>
|
||||||
|
|||||||
@@ -13,8 +13,14 @@ import PropThumbColor from './examples/PropThumbColor';
|
|||||||
import PropTrackColor from './examples/PropTrackColor';
|
import PropTrackColor from './examples/PropTrackColor';
|
||||||
import PropValue from './examples/PropValue';
|
import PropValue from './examples/PropValue';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { storiesOf } from '@kadira/storybook';
|
import UIExplorer, {
|
||||||
import UIExplorer, { AppText, Code, Description, DocItem, Section } from '../../ui-explorer';
|
AppText,
|
||||||
|
Code,
|
||||||
|
Description,
|
||||||
|
DocItem,
|
||||||
|
Section,
|
||||||
|
storiesOf
|
||||||
|
} from '../../ui-explorer';
|
||||||
|
|
||||||
const SwitchScreen = () =>
|
const SwitchScreen = () =>
|
||||||
<UIExplorer title="Switch" url="components/Switch">
|
<UIExplorer title="Switch" url="components/Switch">
|
||||||
|
|||||||
@@ -8,13 +8,13 @@ import PropChildren from './examples/PropChildren';
|
|||||||
import PropNumberOfLines from './examples/PropNumberOfLines';
|
import PropNumberOfLines from './examples/PropNumberOfLines';
|
||||||
import PropOnPress from './examples/PropOnPress';
|
import PropOnPress from './examples/PropOnPress';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { storiesOf } from '@kadira/storybook';
|
|
||||||
import UIExplorer, {
|
import UIExplorer, {
|
||||||
AppText,
|
AppText,
|
||||||
Code,
|
Code,
|
||||||
Description,
|
Description,
|
||||||
DocItem,
|
DocItem,
|
||||||
Section,
|
Section,
|
||||||
|
storiesOf,
|
||||||
StyleList
|
StyleList
|
||||||
} from '../../ui-explorer';
|
} from '../../ui-explorer';
|
||||||
|
|
||||||
|
|||||||
@@ -5,8 +5,7 @@
|
|||||||
/*
|
/*
|
||||||
import createReactClass from 'create-react-class';
|
import createReactClass from 'create-react-class';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { storiesOf } from '@kadira/storybook';
|
import UIExplorer, { PropText, storiesOf, StyleList } from '../../ui-explorer';
|
||||||
import UIExplorer, { PropText, StyleList } from '../../ui-explorer';
|
|
||||||
import { Image, Text, View } from 'react-native';
|
import { Image, Text, View } from 'react-native';
|
||||||
|
|
||||||
const AttributeToggler = createReactClass({
|
const AttributeToggler = createReactClass({
|
||||||
|
|||||||
@@ -19,13 +19,13 @@ import PropSelectTextOnFocus from './examples/PropSelectTextOnFocus';
|
|||||||
import TextInputEvents from './examples/TextInputEvents';
|
import TextInputEvents from './examples/TextInputEvents';
|
||||||
import TextInputRewrite, { TextInputRewriteInvalidCharacters } from './examples/Rewrite';
|
import TextInputRewrite, { TextInputRewriteInvalidCharacters } from './examples/Rewrite';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { storiesOf } from '@kadira/storybook';
|
|
||||||
import UIExplorer, {
|
import UIExplorer, {
|
||||||
AppText,
|
AppText,
|
||||||
Code,
|
Code,
|
||||||
Description,
|
Description,
|
||||||
DocItem,
|
DocItem,
|
||||||
Section,
|
Section,
|
||||||
|
storiesOf,
|
||||||
StyleList,
|
StyleList,
|
||||||
TextList
|
TextList
|
||||||
} from '../../ui-explorer';
|
} from '../../ui-explorer';
|
||||||
@@ -226,6 +226,12 @@ nativeEvent: { key: keyValue } }`}</Code>{' '}
|
|||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<DocItem
|
||||||
|
name="onLayout"
|
||||||
|
typeInfo="?function"
|
||||||
|
description="Invoked on mount and layout changes with {x, y, width, height}."
|
||||||
|
/>
|
||||||
|
|
||||||
<DocItem
|
<DocItem
|
||||||
name="onSelectionChange"
|
name="onSelectionChange"
|
||||||
typeInfo="?function"
|
typeInfo="?function"
|
||||||
|
|||||||
@@ -8,9 +8,8 @@ import CustomStyleOverrides from './examples/CustomStyleOverrides';
|
|||||||
import DelayEvents from './examples/DelayEvents';
|
import DelayEvents from './examples/DelayEvents';
|
||||||
import FeedbackEvents from './examples/FeedbackEvents';
|
import FeedbackEvents from './examples/FeedbackEvents';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { storiesOf } from '@kadira/storybook';
|
|
||||||
import { TouchableHighlightDisabled } from './examples/PropDisabled';
|
import { TouchableHighlightDisabled } from './examples/PropDisabled';
|
||||||
import UIExplorer, { AppText, Description, DocItem, Section } from '../../ui-explorer';
|
import UIExplorer, { AppText, Description, DocItem, Section, storiesOf } from '../../ui-explorer';
|
||||||
|
|
||||||
const TouchableHighlightScreen = () =>
|
const TouchableHighlightScreen = () =>
|
||||||
<UIExplorer title="TouchableHighlight" url="components/Touchable">
|
<UIExplorer title="TouchableHighlight" url="components/Touchable">
|
||||||
|
|||||||
@@ -7,9 +7,8 @@
|
|||||||
import DelayEvents from './examples/DelayEvents';
|
import DelayEvents from './examples/DelayEvents';
|
||||||
import FeedbackEvents from './examples/FeedbackEvents';
|
import FeedbackEvents from './examples/FeedbackEvents';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { storiesOf } from '@kadira/storybook';
|
|
||||||
import { TouchableOpacityDisabled } from './examples/PropDisabled';
|
import { TouchableOpacityDisabled } from './examples/PropDisabled';
|
||||||
import UIExplorer, { AppText, Description, DocItem, Section } from '../../ui-explorer';
|
import UIExplorer, { AppText, Description, DocItem, Section, storiesOf } from '../../ui-explorer';
|
||||||
|
|
||||||
const TouchableOpacityScreen = () =>
|
const TouchableOpacityScreen = () =>
|
||||||
<UIExplorer title="TouchableOpacity" url="components/Touchable">
|
<UIExplorer title="TouchableOpacity" url="components/Touchable">
|
||||||
|
|||||||
@@ -8,9 +8,15 @@ import DelayEvents from './examples/DelayEvents';
|
|||||||
import FeedbackEvents from './examples/FeedbackEvents';
|
import FeedbackEvents from './examples/FeedbackEvents';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropHitSlop from './examples/PropHitSlop';
|
import PropHitSlop from './examples/PropHitSlop';
|
||||||
import { storiesOf } from '@kadira/storybook';
|
|
||||||
import { TouchableWithoutFeedbackDisabled } from './examples/PropDisabled';
|
import { TouchableWithoutFeedbackDisabled } from './examples/PropDisabled';
|
||||||
import UIExplorer, { AppText, Code, Description, DocItem, Section } from '../../ui-explorer';
|
import UIExplorer, {
|
||||||
|
AppText,
|
||||||
|
Code,
|
||||||
|
Description,
|
||||||
|
DocItem,
|
||||||
|
Section,
|
||||||
|
storiesOf
|
||||||
|
} from '../../ui-explorer';
|
||||||
|
|
||||||
const TouchableWithoutFeedbackScreen = () =>
|
const TouchableWithoutFeedbackScreen = () =>
|
||||||
<UIExplorer title="TouchableWithoutFeedback" url="components/Touchable">
|
<UIExplorer title="TouchableWithoutFeedback" url="components/Touchable">
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { action } from '@kadira/storybook';
|
|
||||||
import {
|
import {
|
||||||
StyleSheet,
|
StyleSheet,
|
||||||
View,
|
View,
|
||||||
@@ -13,6 +12,10 @@ import {
|
|||||||
TouchableWithoutFeedback
|
TouchableWithoutFeedback
|
||||||
} from 'react-native';
|
} from 'react-native';
|
||||||
|
|
||||||
|
const action = msg => () => {
|
||||||
|
console.log(msg);
|
||||||
|
};
|
||||||
|
|
||||||
class TouchableHighlightDisabled extends React.Component {
|
class TouchableHighlightDisabled extends React.Component {
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -8,13 +8,14 @@ import PropPointerEvents from './examples/PropPointerEvents';
|
|||||||
import transformExamples from './examples/transforms';
|
import transformExamples from './examples/transforms';
|
||||||
import ZIndexExample from './examples/ZIndex';
|
import ZIndexExample from './examples/ZIndex';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { storiesOf } from '@kadira/storybook';
|
|
||||||
import UIExplorer, {
|
import UIExplorer, {
|
||||||
AppText,
|
AppText,
|
||||||
Code,
|
Code,
|
||||||
Description,
|
Description,
|
||||||
DocItem,
|
DocItem,
|
||||||
|
ExternalLink,
|
||||||
Section,
|
Section,
|
||||||
|
storiesOf,
|
||||||
StyleList
|
StyleList
|
||||||
} from '../../ui-explorer';
|
} from '../../ui-explorer';
|
||||||
|
|
||||||
@@ -291,6 +292,12 @@ const ViewScreen = () =>
|
|||||||
</UIExplorer>;
|
</UIExplorer>;
|
||||||
|
|
||||||
const stylePropTypes = [
|
const stylePropTypes = [
|
||||||
|
{
|
||||||
|
label: 'web',
|
||||||
|
name: (
|
||||||
|
<ExternalLink href="https://drafts.csswg.org/css-variables/">Custom properties</ExternalLink>
|
||||||
|
)
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: 'alignContent',
|
name: 'alignContent',
|
||||||
typeInfo: 'string'
|
typeInfo: 'string'
|
||||||
|
|||||||
@@ -3,8 +3,14 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { storiesOf } from '@kadira/storybook';
|
import UIExplorer, {
|
||||||
import UIExplorer, { AppText, Code, Description, DocItem, Section } from '../../ui-explorer';
|
AppText,
|
||||||
|
Code,
|
||||||
|
Description,
|
||||||
|
DocItem,
|
||||||
|
Section,
|
||||||
|
storiesOf
|
||||||
|
} from '../../ui-explorer';
|
||||||
|
|
||||||
const AppRegistryScreen = () =>
|
const AppRegistryScreen = () =>
|
||||||
<UIExplorer title="AppRegistry" url="apis/AppRegistry">
|
<UIExplorer title="AppRegistry" url="apis/AppRegistry">
|
||||||
|
|||||||
@@ -6,8 +6,14 @@
|
|||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import StateChangesExample from './examples/StateChanges';
|
import StateChangesExample from './examples/StateChanges';
|
||||||
import { storiesOf } from '@kadira/storybook';
|
import UIExplorer, {
|
||||||
import UIExplorer, { AppText, Code, Description, DocItem, Section } from '../../ui-explorer';
|
AppText,
|
||||||
|
Code,
|
||||||
|
Description,
|
||||||
|
DocItem,
|
||||||
|
Section,
|
||||||
|
storiesOf
|
||||||
|
} from '../../ui-explorer';
|
||||||
|
|
||||||
const AppStateScreen = () =>
|
const AppStateScreen = () =>
|
||||||
<UIExplorer title="AppState" url="apis/AppState">
|
<UIExplorer title="AppState" url="apis/AppState">
|
||||||
|
|||||||
@@ -3,8 +3,14 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { storiesOf } from '@kadira/storybook';
|
import UIExplorer, {
|
||||||
import UIExplorer, { AppText, Code, Description, DocItem, Section } from '../../ui-explorer';
|
AppText,
|
||||||
|
Code,
|
||||||
|
Description,
|
||||||
|
DocItem,
|
||||||
|
Section,
|
||||||
|
storiesOf
|
||||||
|
} from '../../ui-explorer';
|
||||||
|
|
||||||
const AsyncStorageScreen = () =>
|
const AsyncStorageScreen = () =>
|
||||||
<UIExplorer title="AsyncStorage" url="apis/AsyncStorage">
|
<UIExplorer title="AsyncStorage" url="apis/AsyncStorage">
|
||||||
|
|||||||
@@ -4,8 +4,7 @@
|
|||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import SetStringExample from './examples/SetString';
|
import SetStringExample from './examples/SetString';
|
||||||
import { storiesOf } from '@kadira/storybook';
|
import UIExplorer, { Description, DocItem, Section, storiesOf } from '../../ui-explorer';
|
||||||
import UIExplorer, { Description, DocItem, Section } from '../../ui-explorer';
|
|
||||||
|
|
||||||
const ClipboardScreen = () =>
|
const ClipboardScreen = () =>
|
||||||
<UIExplorer title="Clipboard" url="apis/Clipboard">
|
<UIExplorer title="Clipboard" url="apis/Clipboard">
|
||||||
|
|||||||
@@ -5,13 +5,13 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import DimensionsChange from './examples/DimensionsChange';
|
import DimensionsChange from './examples/DimensionsChange';
|
||||||
import { storiesOf } from '@kadira/storybook';
|
|
||||||
import UIExplorer, {
|
import UIExplorer, {
|
||||||
AppText,
|
AppText,
|
||||||
Code,
|
Code,
|
||||||
Description,
|
Description,
|
||||||
DocItem,
|
DocItem,
|
||||||
Section,
|
Section,
|
||||||
|
storiesOf,
|
||||||
TextList
|
TextList
|
||||||
} from '../../ui-explorer';
|
} from '../../ui-explorer';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|||||||
@@ -6,8 +6,7 @@
|
|||||||
|
|
||||||
import RTLToggle from './examples/RTLToggle';
|
import RTLToggle from './examples/RTLToggle';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { storiesOf } from '@kadira/storybook';
|
import UIExplorer, { Description, DocItem, Section, storiesOf } from '../../ui-explorer';
|
||||||
import UIExplorer, { Description, DocItem, Section } from '../../ui-explorer';
|
|
||||||
|
|
||||||
const I18nManagerScreen = () =>
|
const I18nManagerScreen = () =>
|
||||||
<UIExplorer title="I18nManager" url="apis/I18nManager">
|
<UIExplorer title="I18nManager" url="apis/I18nManager">
|
||||||
|
|||||||
@@ -6,8 +6,7 @@
|
|||||||
|
|
||||||
import OpenURL from './examples/OpenURL';
|
import OpenURL from './examples/OpenURL';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { storiesOf } from '@kadira/storybook';
|
import UIExplorer, { Description, DocItem, Section, storiesOf } from '../../ui-explorer';
|
||||||
import UIExplorer, { Description, DocItem, Section } from '../../ui-explorer';
|
|
||||||
|
|
||||||
const LinkingScreen = () =>
|
const LinkingScreen = () =>
|
||||||
<UIExplorer title="Linking" url="apis/Linking">
|
<UIExplorer title="Linking" url="apis/Linking">
|
||||||
|
|||||||
@@ -3,13 +3,13 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { storiesOf } from '@kadira/storybook';
|
|
||||||
import UIExplorer, {
|
import UIExplorer, {
|
||||||
AppText,
|
AppText,
|
||||||
Code,
|
Code,
|
||||||
Description,
|
Description,
|
||||||
DocItem,
|
DocItem,
|
||||||
Section,
|
Section,
|
||||||
|
storiesOf,
|
||||||
TextList
|
TextList
|
||||||
} from '../../ui-explorer';
|
} from '../../ui-explorer';
|
||||||
|
|
||||||
|
|||||||
@@ -3,9 +3,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import DraggableCircleExample from './examples/DraggableCircle';
|
import DraggableCircleExample from './examples/DraggableCircle';
|
||||||
import { storiesOf } from '@kadira/storybook';
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import UIExplorer, { AppText, Description, DocItem, Section } from '../../ui-explorer';
|
import UIExplorer, { AppText, Description, DocItem, Section, storiesOf } from '../../ui-explorer';
|
||||||
|
|
||||||
const PanResponderScreen = () =>
|
const PanResponderScreen = () =>
|
||||||
<UIExplorer title="PanResponder" url="apis/PanResponder">
|
<UIExplorer title="PanResponder" url="apis/PanResponder">
|
||||||
|
|||||||
@@ -3,8 +3,14 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { storiesOf } from '@kadira/storybook';
|
import UIExplorer, {
|
||||||
import UIExplorer, { AppText, Code, Description, DocItem, Section } from '../../ui-explorer';
|
AppText,
|
||||||
|
Code,
|
||||||
|
Description,
|
||||||
|
DocItem,
|
||||||
|
Section,
|
||||||
|
storiesOf
|
||||||
|
} from '../../ui-explorer';
|
||||||
|
|
||||||
const PixelRatioScreen = () =>
|
const PixelRatioScreen = () =>
|
||||||
<UIExplorer title="PixelRatio" url="apis/PixelRatio">
|
<UIExplorer title="PixelRatio" url="apis/PixelRatio">
|
||||||
|
|||||||
@@ -2,9 +2,8 @@
|
|||||||
* @flow
|
* @flow
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { storiesOf } from '@kadira/storybook';
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import UIExplorer, { Description, DocItem, Section } from '../../ui-explorer';
|
import UIExplorer, { Description, DocItem, Section, storiesOf } from '../../ui-explorer';
|
||||||
|
|
||||||
const PlatformScreen = () =>
|
const PlatformScreen = () =>
|
||||||
<UIExplorer title="Platform" url="apis/Platform">
|
<UIExplorer title="Platform" url="apis/Platform">
|
||||||
|
|||||||
@@ -2,9 +2,15 @@
|
|||||||
* @flow
|
* @flow
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { storiesOf } from '@kadira/storybook';
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import UIExplorer, { AppText, Code, Description, DocItem, Section } from '../../ui-explorer';
|
import UIExplorer, {
|
||||||
|
AppText,
|
||||||
|
Code,
|
||||||
|
Description,
|
||||||
|
DocItem,
|
||||||
|
Section,
|
||||||
|
storiesOf
|
||||||
|
} from '../../ui-explorer';
|
||||||
|
|
||||||
const StyleSheetScreen = () =>
|
const StyleSheetScreen = () =>
|
||||||
<UIExplorer title="StyleSheet" url="apis/StyleSheet">
|
<UIExplorer title="StyleSheet" url="apis/StyleSheet">
|
||||||
|
|||||||
@@ -2,9 +2,15 @@
|
|||||||
* @flow
|
* @flow
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { storiesOf } from '@kadira/storybook';
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import UIExplorer, { AppText, Code, Description, DocItem, Section } from '../../ui-explorer';
|
import UIExplorer, {
|
||||||
|
AppText,
|
||||||
|
Code,
|
||||||
|
Description,
|
||||||
|
DocItem,
|
||||||
|
Section,
|
||||||
|
storiesOf
|
||||||
|
} from '../../ui-explorer';
|
||||||
|
|
||||||
const VibrationScreen = () =>
|
const VibrationScreen = () =>
|
||||||
<UIExplorer title="Vibration" url="apis/Vibration">
|
<UIExplorer title="Vibration" url="apis/Vibration">
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import Calculator from './Calculator';
|
import Calculator from './Calculator';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { storiesOf } from '@kadira/storybook';
|
import { storiesOf } from '../../ui-explorer';
|
||||||
import { StyleSheet, View } from 'react-native';
|
import { StyleSheet, View } from 'react-native';
|
||||||
|
|
||||||
const CalculatorScreen = () =>
|
const CalculatorScreen = () =>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { storiesOf } from '@kadira/storybook';
|
import { storiesOf } from '../../ui-explorer';
|
||||||
import Game2048 from './Game2048';
|
import Game2048 from './Game2048';
|
||||||
|
|
||||||
const Game2048Screen = () => <Game2048 />;
|
const Game2048Screen = () => <Game2048 />;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { storiesOf } from '@kadira/storybook';
|
import { storiesOf } from '../../ui-explorer';
|
||||||
import TicTacToe from './TicTacToe';
|
import TicTacToe from './TicTacToe';
|
||||||
|
|
||||||
const TicTacToeScreen = () => <TicTacToe />;
|
const TicTacToeScreen = () => <TicTacToe />;
|
||||||
|
|||||||
12
docs/storybook/ui-explorer/ExternalLink.js
Normal file
12
docs/storybook/ui-explorer/ExternalLink.js
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
/* eslint-disable react/prop-types */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @flow
|
||||||
|
*/
|
||||||
|
|
||||||
|
import AppText from './AppText';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
const ExternalLink = props => <AppText {...props} accessibilityRole="link" target="_blank" />;
|
||||||
|
|
||||||
|
export default ExternalLink;
|
||||||
@@ -16,10 +16,12 @@ const StyleList = ({ stylePropTypes }) =>
|
|||||||
<Text style={styles.name}>
|
<Text style={styles.name}>
|
||||||
{name}
|
{name}
|
||||||
</Text>
|
</Text>
|
||||||
{': '}
|
{typeInfo ? ': ' : null}
|
||||||
<Text style={styles.code}>
|
{typeInfo
|
||||||
{typeInfo}
|
? <Text style={styles.code}>
|
||||||
</Text>
|
{typeInfo}
|
||||||
|
</Text>
|
||||||
|
: null}
|
||||||
</AppText>
|
</AppText>
|
||||||
)}
|
)}
|
||||||
</View>;
|
</View>;
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import AppText from './AppText';
|
import AppText from './AppText';
|
||||||
|
import ExternalLink from './ExternalLink';
|
||||||
import insertBetween from './insertBetween';
|
import insertBetween from './insertBetween';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { StyleSheet, View } from 'react-native';
|
import { StyleSheet, View } from 'react-native';
|
||||||
@@ -22,14 +23,12 @@ export const Description = ({ children }) =>
|
|||||||
const Divider = () => <View style={styles.divider} />;
|
const Divider = () => <View style={styles.divider} />;
|
||||||
|
|
||||||
const SourceLink = ({ uri }) =>
|
const SourceLink = ({ uri }) =>
|
||||||
<AppText
|
<ExternalLink
|
||||||
accessibilityRole="link"
|
|
||||||
href={`https://github.com/necolas/react-native-web/tree/master/docs/storybook/${uri}`}
|
href={`https://github.com/necolas/react-native-web/tree/master/docs/storybook/${uri}`}
|
||||||
style={styles.link}
|
style={styles.link}
|
||||||
target="_blank"
|
|
||||||
>
|
>
|
||||||
View source code on GitHub
|
View source code on GitHub
|
||||||
</AppText>;
|
</ExternalLink>;
|
||||||
|
|
||||||
const UIExplorer = ({ children, description, sections, title, url }) =>
|
const UIExplorer = ({ children, description, sections, title, url }) =>
|
||||||
<View style={styles.root}>
|
<View style={styles.root}>
|
||||||
|
|||||||
@@ -5,10 +5,22 @@
|
|||||||
import AppText from './AppText';
|
import AppText from './AppText';
|
||||||
import Code from './Code';
|
import Code from './Code';
|
||||||
import DocItem from './DocItem';
|
import DocItem from './DocItem';
|
||||||
|
import ExternalLink from './ExternalLink';
|
||||||
import Section from './Section';
|
import Section from './Section';
|
||||||
|
import { storiesOf } from '@storybook/react';
|
||||||
import StyleList from './StyleList';
|
import StyleList from './StyleList';
|
||||||
import TextList from './TextList';
|
import TextList from './TextList';
|
||||||
import UIExplorer, { Description } from './UIExplorer';
|
import UIExplorer, { Description } from './UIExplorer';
|
||||||
|
|
||||||
export default UIExplorer;
|
export default UIExplorer;
|
||||||
export { AppText, Code, Description, DocItem, Section, StyleList, TextList };
|
export {
|
||||||
|
AppText,
|
||||||
|
Code,
|
||||||
|
Description,
|
||||||
|
DocItem,
|
||||||
|
ExternalLink,
|
||||||
|
Section,
|
||||||
|
storiesOf,
|
||||||
|
StyleList,
|
||||||
|
TextList
|
||||||
|
};
|
||||||
|
|||||||
2007
docs/yarn.lock
2007
docs/yarn.lock
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "react-native-web",
|
"name": "react-native-web",
|
||||||
"version": "0.0.115",
|
"version": "0.0.117",
|
||||||
"description": "React Native for Web",
|
"description": "React Native for Web",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"files": [
|
"files": [
|
||||||
|
|||||||
@@ -10,12 +10,13 @@
|
|||||||
* @noflow
|
* @noflow
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import ExecutionEnvironment from 'fbjs/lib/ExecutionEnvironment';
|
import { canUseDOM } from 'fbjs/lib/ExecutionEnvironment';
|
||||||
import findIndex from 'array-find-index';
|
import findIndex from 'array-find-index';
|
||||||
import invariant from 'fbjs/lib/invariant';
|
import invariant from 'fbjs/lib/invariant';
|
||||||
|
|
||||||
// Android 4.4 browser
|
// Android 4.4 browser
|
||||||
const isPrefixed = !document.hasOwnProperty('hidden') && document.hasOwnProperty('webkitHidden');
|
const isPrefixed =
|
||||||
|
canUseDOM && !document.hasOwnProperty('hidden') && document.hasOwnProperty('webkitHidden');
|
||||||
|
|
||||||
const EVENT_TYPES = ['change'];
|
const EVENT_TYPES = ['change'];
|
||||||
const VISIBILITY_CHANGE_EVENT = isPrefixed ? 'webkitvisibilitychange' : 'visibilitychange';
|
const VISIBILITY_CHANGE_EVENT = isPrefixed ? 'webkitvisibilitychange' : 'visibilitychange';
|
||||||
@@ -29,7 +30,7 @@ const AppStates = {
|
|||||||
const listeners = [];
|
const listeners = [];
|
||||||
|
|
||||||
export default class AppState {
|
export default class AppState {
|
||||||
static isAvailable = ExecutionEnvironment.canUseDOM && document[VISIBILITY_STATE_PROPERTY];
|
static isAvailable = canUseDOM && document[VISIBILITY_STATE_PROPERTY];
|
||||||
|
|
||||||
static get currentState() {
|
static get currentState() {
|
||||||
if (!AppState.isAvailable) {
|
if (!AppState.isAvailable) {
|
||||||
|
|||||||
@@ -26,23 +26,27 @@ const ReactPropTypesSecret = 'SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED';
|
|||||||
export default class StyleSheetValidation {
|
export default class StyleSheetValidation {
|
||||||
static validateStyleProp(prop, style, caller) {
|
static validateStyleProp(prop, style, caller) {
|
||||||
if (process.env.NODE_ENV !== 'production') {
|
if (process.env.NODE_ENV !== 'production') {
|
||||||
|
const isCustomProperty = prop.indexOf('--') === 0;
|
||||||
|
if (isCustomProperty) return;
|
||||||
|
|
||||||
if (allStylePropTypes[prop] === undefined) {
|
if (allStylePropTypes[prop] === undefined) {
|
||||||
const message1 = '"' + prop + '" is not a valid style property.';
|
const message1 = '"' + prop + '" is not a valid style property.';
|
||||||
const message2 =
|
const message2 =
|
||||||
'\nValid style props: ' +
|
'\nValid style props: ' +
|
||||||
JSON.stringify(Object.keys(allStylePropTypes).sort(), null, ' ');
|
JSON.stringify(Object.keys(allStylePropTypes).sort(), null, ' ');
|
||||||
styleError(message1, style, caller, message2);
|
styleError(message1, style, caller, message2);
|
||||||
}
|
} else {
|
||||||
const error = allStylePropTypes[prop](
|
const error = allStylePropTypes[prop](
|
||||||
style,
|
style,
|
||||||
prop,
|
prop,
|
||||||
caller,
|
caller,
|
||||||
'prop',
|
'prop',
|
||||||
null,
|
null,
|
||||||
ReactPropTypesSecret
|
ReactPropTypesSecret
|
||||||
);
|
);
|
||||||
if (error) {
|
if (error) {
|
||||||
styleError(error.message, style, caller);
|
styleError(error.message, style, caller);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -109,105 +109,165 @@ describe('components/TextInput', () => {
|
|||||||
expect(input.prop('rows')).toEqual(3);
|
expect(input.prop('rows')).toEqual(3);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('prop "onBlur"', done => {
|
test('prop "onBlur"', () => {
|
||||||
|
const onBlur = jest.fn();
|
||||||
const input = findNativeInput(mount(<TextInput onBlur={onBlur} />));
|
const input = findNativeInput(mount(<TextInput onBlur={onBlur} />));
|
||||||
input.simulate('blur');
|
input.simulate('blur');
|
||||||
function onBlur(e) {
|
expect(onBlur).toHaveBeenCalledTimes(1);
|
||||||
expect(e).toBeTruthy();
|
|
||||||
done();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('prop "onChange"', done => {
|
test('prop "onChange"', () => {
|
||||||
|
const onChange = jest.fn();
|
||||||
const input = findNativeInput(mount(<TextInput onChange={onChange} />));
|
const input = findNativeInput(mount(<TextInput onChange={onChange} />));
|
||||||
input.simulate('change');
|
input.simulate('change');
|
||||||
function onChange(e) {
|
expect(onChange).toHaveBeenCalledTimes(1);
|
||||||
expect(e).toBeTruthy();
|
|
||||||
done();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('prop "onChangeText"', done => {
|
test('prop "onChangeText"', () => {
|
||||||
|
const onChangeText = jest.fn();
|
||||||
const newText = 'newText';
|
const newText = 'newText';
|
||||||
const input = findNativeInput(mount(<TextInput onChangeText={onChangeText} />));
|
const input = findNativeInput(mount(<TextInput onChangeText={onChangeText} />));
|
||||||
input.simulate('change', { target: { value: newText } });
|
input.simulate('change', { target: { value: newText } });
|
||||||
function onChangeText(text) {
|
expect(onChangeText).toHaveBeenCalledTimes(1);
|
||||||
expect(text).toEqual(newText);
|
expect(onChangeText).toBeCalledWith(newText);
|
||||||
done();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('prop "onFocus"', done => {
|
test('prop "onFocus"', () => {
|
||||||
|
const onFocus = jest.fn();
|
||||||
const input = findNativeInput(mount(<TextInput onFocus={onFocus} />));
|
const input = findNativeInput(mount(<TextInput onFocus={onFocus} />));
|
||||||
input.simulate('focus');
|
input.simulate('focus');
|
||||||
function onFocus(e) {
|
expect(onFocus).toHaveBeenCalledTimes(1);
|
||||||
expect(e).toBeTruthy();
|
|
||||||
done();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('prop "onKeyPress"', () => {
|
describe('prop "onKeyPress"', () => {
|
||||||
test('enter key', done => {
|
test('backspace key', () => {
|
||||||
const input = findNativeInput(mount(<TextInput onKeyPress={onKeyPress} />));
|
const onKeyPress = jest.fn();
|
||||||
input.simulate('keyPress', { which: 13 });
|
|
||||||
function onKeyPress(e) {
|
|
||||||
expect(e.nativeEvent.key).toEqual('Enter');
|
|
||||||
done();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
test('space key', done => {
|
|
||||||
const input = findNativeInput(mount(<TextInput onKeyPress={onKeyPress} />));
|
|
||||||
input.simulate('keyPress', { which: 32 });
|
|
||||||
function onKeyPress(e) {
|
|
||||||
expect(e.nativeEvent.key).toEqual(' ');
|
|
||||||
done();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
test('backspace key', done => {
|
|
||||||
const input = findNativeInput(mount(<TextInput onKeyPress={onKeyPress} />));
|
const input = findNativeInput(mount(<TextInput onKeyPress={onKeyPress} />));
|
||||||
input.simulate('keyDown', { which: 8 });
|
input.simulate('keyDown', { which: 8 });
|
||||||
function onKeyPress(e) {
|
expect(onKeyPress).toHaveBeenCalledTimes(1);
|
||||||
expect(e.nativeEvent.key).toEqual('Backspace');
|
expect(onKeyPress).toBeCalledWith(
|
||||||
done();
|
expect.objectContaining({
|
||||||
}
|
nativeEvent: {
|
||||||
|
altKey: undefined,
|
||||||
|
ctrlKey: undefined,
|
||||||
|
key: 'Backspace',
|
||||||
|
metaKey: undefined,
|
||||||
|
shiftKey: undefined,
|
||||||
|
target: expect.anything()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('text key', done => {
|
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', () => {
|
||||||
|
const onKeyPress = jest.fn();
|
||||||
|
const input = findNativeInput(mount(<TextInput onKeyPress={onKeyPress} />));
|
||||||
|
input.simulate('keyPress', { which: 13 });
|
||||||
|
expect(onKeyPress).toHaveBeenCalledTimes(1);
|
||||||
|
expect(onKeyPress).toBeCalledWith(
|
||||||
|
expect.objectContaining({
|
||||||
|
nativeEvent: {
|
||||||
|
altKey: undefined,
|
||||||
|
ctrlKey: undefined,
|
||||||
|
key: 'Enter',
|
||||||
|
metaKey: undefined,
|
||||||
|
shiftKey: undefined,
|
||||||
|
target: expect.anything()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('space key', () => {
|
||||||
|
const onKeyPress = jest.fn();
|
||||||
|
const input = findNativeInput(mount(<TextInput onKeyPress={onKeyPress} />));
|
||||||
|
input.simulate('keyPress', { which: 32 });
|
||||||
|
expect(onKeyPress).toHaveBeenCalledTimes(1);
|
||||||
|
expect(onKeyPress).toBeCalledWith(
|
||||||
|
expect.objectContaining({
|
||||||
|
nativeEvent: {
|
||||||
|
altKey: undefined,
|
||||||
|
ctrlKey: undefined,
|
||||||
|
key: ' ',
|
||||||
|
metaKey: undefined,
|
||||||
|
shiftKey: undefined,
|
||||||
|
target: expect.anything()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('text key', () => {
|
||||||
|
const onKeyPress = jest.fn();
|
||||||
const input = findNativeInput(mount(<TextInput onKeyPress={onKeyPress} />));
|
const input = findNativeInput(mount(<TextInput onKeyPress={onKeyPress} />));
|
||||||
input.simulate('keyPress', { which: 97 });
|
input.simulate('keyPress', { which: 97 });
|
||||||
function onKeyPress(e) {
|
expect(onKeyPress).toHaveBeenCalledTimes(1);
|
||||||
expect(e.nativeEvent.key).toEqual('a');
|
expect(onKeyPress).toBeCalledWith(
|
||||||
done();
|
expect.objectContaining({
|
||||||
}
|
nativeEvent: {
|
||||||
|
altKey: undefined,
|
||||||
|
ctrlKey: undefined,
|
||||||
|
key: 'a',
|
||||||
|
metaKey: undefined,
|
||||||
|
shiftKey: undefined,
|
||||||
|
target: expect.anything()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('target element is included', done => {
|
test('modifier keys are included', () => {
|
||||||
const input = findNativeInput(mount(<TextInput onKeyPress={onKeyPress} />));
|
const onKeyPress = jest.fn();
|
||||||
input.simulate('keyPress');
|
|
||||||
function onKeyPress(e) {
|
|
||||||
expect(e.nativeEvent.target).toBeDefined();
|
|
||||||
done();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
test('modifier keys are included', done => {
|
|
||||||
const input = findNativeInput(mount(<TextInput onKeyPress={onKeyPress} />));
|
const input = findNativeInput(mount(<TextInput onKeyPress={onKeyPress} />));
|
||||||
input.simulate('keyPress', {
|
input.simulate('keyPress', {
|
||||||
altKey: true,
|
altKey: true,
|
||||||
ctrlKey: true,
|
ctrlKey: true,
|
||||||
metaKey: true,
|
metaKey: true,
|
||||||
shiftKey: true,
|
shiftKey: true,
|
||||||
which: 97
|
which: 32
|
||||||
});
|
});
|
||||||
function onKeyPress(e) {
|
expect(onKeyPress).toHaveBeenCalledTimes(1);
|
||||||
expect(e.nativeEvent.altKey).toEqual(true);
|
expect(onKeyPress).toBeCalledWith(
|
||||||
expect(e.nativeEvent.ctrlKey).toEqual(true);
|
expect.objectContaining({
|
||||||
expect(e.nativeEvent.metaKey).toEqual(true);
|
nativeEvent: {
|
||||||
expect(e.nativeEvent.shiftKey).toEqual(true);
|
altKey: true,
|
||||||
done();
|
ctrlKey: true,
|
||||||
}
|
key: ' ',
|
||||||
|
metaKey: true,
|
||||||
|
shiftKey: true,
|
||||||
|
target: expect.anything()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('meta key + Enter calls "onKeyPress"', () => {
|
||||||
|
const onKeyPress = jest.fn();
|
||||||
|
const input = findNativeInput(mount(<TextInput onKeyPress={onKeyPress} />));
|
||||||
|
input.simulate('keyDown', {
|
||||||
|
metaKey: true,
|
||||||
|
which: 13
|
||||||
|
});
|
||||||
|
expect(onKeyPress).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import applyLayout from '../../modules/applyLayout';
|
|||||||
import applyNativeMethods from '../../modules/applyNativeMethods';
|
import applyNativeMethods from '../../modules/applyNativeMethods';
|
||||||
import { canUseDOM } from 'fbjs/lib/ExecutionEnvironment';
|
import { canUseDOM } from 'fbjs/lib/ExecutionEnvironment';
|
||||||
import { Component } from 'react';
|
import { Component } from 'react';
|
||||||
|
import ColorPropType from '../../propTypes/ColorPropType';
|
||||||
import createDOMElement from '../../modules/createDOMElement';
|
import createDOMElement from '../../modules/createDOMElement';
|
||||||
import findNodeHandle from '../../modules/findNodeHandle';
|
import findNodeHandle from '../../modules/findNodeHandle';
|
||||||
import StyleSheet from '../../apis/StyleSheet';
|
import StyleSheet from '../../apis/StyleSheet';
|
||||||
@@ -21,7 +22,7 @@ import StyleSheetPropType from '../../propTypes/StyleSheetPropType';
|
|||||||
import TextInputStylePropTypes from './TextInputStylePropTypes';
|
import TextInputStylePropTypes from './TextInputStylePropTypes';
|
||||||
import TextInputState from './TextInputState';
|
import TextInputState from './TextInputState';
|
||||||
import ViewPropTypes from '../View/ViewPropTypes';
|
import ViewPropTypes from '../View/ViewPropTypes';
|
||||||
import { bool, func, number, oneOf, shape, string } from 'prop-types';
|
import { any, bool, func, number, oneOf, shape, string } from 'prop-types';
|
||||||
|
|
||||||
const isAndroid = canUseDOM && /Android/i.test(navigator && navigator.userAgent);
|
const isAndroid = canUseDOM && /Android/i.test(navigator && navigator.userAgent);
|
||||||
const emptyObject = {};
|
const emptyObject = {};
|
||||||
@@ -103,7 +104,6 @@ class TextInput extends Component {
|
|||||||
onSelectionChange: func,
|
onSelectionChange: func,
|
||||||
onSubmitEditing: func,
|
onSubmitEditing: func,
|
||||||
placeholder: string,
|
placeholder: string,
|
||||||
placeholderTextColor: string,
|
|
||||||
secureTextEntry: bool,
|
secureTextEntry: bool,
|
||||||
selectTextOnFocus: bool,
|
selectTextOnFocus: bool,
|
||||||
selection: shape({
|
selection: shape({
|
||||||
@@ -111,7 +111,29 @@ class TextInput extends Component {
|
|||||||
end: number
|
end: number
|
||||||
}),
|
}),
|
||||||
style: StyleSheetPropType(TextInputStylePropTypes),
|
style: StyleSheetPropType(TextInputStylePropTypes),
|
||||||
value: string
|
value: string,
|
||||||
|
/* react-native compat */
|
||||||
|
/* eslint-disable */
|
||||||
|
caretHidden: bool,
|
||||||
|
clearButtonMode: string,
|
||||||
|
dataDetectorTypes: string,
|
||||||
|
disableFullscreenUI: bool,
|
||||||
|
enablesReturnKeyAutomatically: bool,
|
||||||
|
keyboardAppearance: string,
|
||||||
|
inlineImageLeft: string,
|
||||||
|
inlineImagePadding: number,
|
||||||
|
onContentSizeChange: func,
|
||||||
|
onEndEditing: func,
|
||||||
|
onScroll: func,
|
||||||
|
placeholderTextColor: ColorPropType,
|
||||||
|
returnKeyLabel: string,
|
||||||
|
returnKeyType: string,
|
||||||
|
selectionColor: ColorPropType,
|
||||||
|
selectionState: any,
|
||||||
|
spellCheck: bool,
|
||||||
|
textBreakStrategy: string,
|
||||||
|
underlineColorAndroid: ColorPropType
|
||||||
|
/* eslint-enable */
|
||||||
};
|
};
|
||||||
|
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
@@ -163,23 +185,30 @@ class TextInput extends Component {
|
|||||||
style,
|
style,
|
||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
blurOnSubmit,
|
blurOnSubmit,
|
||||||
caretHidden,
|
|
||||||
clearButtonMode,
|
|
||||||
clearTextOnFocus,
|
clearTextOnFocus,
|
||||||
dataDetectorTypes,
|
|
||||||
enablesReturnKeyAutomatically,
|
|
||||||
keyboardAppearance,
|
|
||||||
onChangeText,
|
onChangeText,
|
||||||
onContentSizeChange,
|
|
||||||
onEndEditing,
|
|
||||||
onLayout,
|
|
||||||
onSelectionChange,
|
onSelectionChange,
|
||||||
onSubmitEditing,
|
onSubmitEditing,
|
||||||
placeholderTextColor,
|
|
||||||
returnKeyType,
|
|
||||||
selection,
|
selection,
|
||||||
selectionColor,
|
|
||||||
selectTextOnFocus,
|
selectTextOnFocus,
|
||||||
|
/* react-native compat */
|
||||||
|
caretHidden,
|
||||||
|
clearButtonMode,
|
||||||
|
dataDetectorTypes,
|
||||||
|
disableFullscreenUI,
|
||||||
|
enablesReturnKeyAutomatically,
|
||||||
|
inlineImageLeft,
|
||||||
|
inlineImagePadding,
|
||||||
|
keyboardAppearance,
|
||||||
|
onContentSizeChange,
|
||||||
|
onEndEditing,
|
||||||
|
onScroll,
|
||||||
|
placeholderTextColor,
|
||||||
|
returnKeyLabel,
|
||||||
|
returnKeyType,
|
||||||
|
selectionColor,
|
||||||
|
selectionState,
|
||||||
|
spellCheck,
|
||||||
textBreakStrategy,
|
textBreakStrategy,
|
||||||
underlineColorAndroid,
|
underlineColorAndroid,
|
||||||
/* eslint-enable */
|
/* eslint-enable */
|
||||||
@@ -272,9 +301,9 @@ class TextInput extends Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
_handleKeyDown = e => {
|
_handleKeyDown = e => {
|
||||||
const { onKeyPress } = this.props;
|
// Backspace, Tab, and Cmd+Enter only fire 'keydown' DOM events
|
||||||
if (onKeyPress && e.which === 8) {
|
if (e.which === 8 || e.which === 9 || (e.which === 13 && e.metaKey)) {
|
||||||
onKeyPress({ nativeEvent: { key: 'Backspace' } });
|
this._handleKeyPress(e);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -285,23 +314,35 @@ class TextInput extends Component {
|
|||||||
|
|
||||||
if (onKeyPress) {
|
if (onKeyPress) {
|
||||||
let keyValue;
|
let keyValue;
|
||||||
// enter
|
switch (e.which) {
|
||||||
if (e.which === 13) {
|
// backspace
|
||||||
keyValue = 'Enter';
|
case 8:
|
||||||
} else if (e.which === 32) {
|
keyValue = 'Backspace';
|
||||||
// space
|
break;
|
||||||
keyValue = ' ';
|
// tab
|
||||||
} else {
|
case 9:
|
||||||
// we trim to only care about the keys that has a textual representation
|
keyValue = 'Tab';
|
||||||
if (e.shiftKey) {
|
break;
|
||||||
keyValue = String.fromCharCode(e.which).trim();
|
// enter
|
||||||
} else {
|
case 13:
|
||||||
keyValue = String.fromCharCode(e.which).toLowerCase().trim();
|
keyValue = 'Enter';
|
||||||
|
break;
|
||||||
|
// spacebar
|
||||||
|
case 32:
|
||||||
|
keyValue = ' ';
|
||||||
|
break;
|
||||||
|
default: {
|
||||||
|
// we trim to only care about the keys that has a textual representation
|
||||||
|
if (e.shiftKey) {
|
||||||
|
keyValue = String.fromCharCode(e.which).trim();
|
||||||
|
} else {
|
||||||
|
keyValue = String.fromCharCode(e.which).toLowerCase().trim();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (keyValue) {
|
if (keyValue) {
|
||||||
const nativeEvent = {
|
e.nativeEvent = {
|
||||||
altKey: e.altKey,
|
altKey: e.altKey,
|
||||||
ctrlKey: e.ctrlKey,
|
ctrlKey: e.ctrlKey,
|
||||||
key: keyValue,
|
key: keyValue,
|
||||||
@@ -309,7 +350,7 @@ class TextInput extends Component {
|
|||||||
shiftKey: e.shiftKey,
|
shiftKey: e.shiftKey,
|
||||||
target: e.target
|
target: e.target
|
||||||
};
|
};
|
||||||
onKeyPress({ nativeEvent });
|
onKeyPress(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -35,7 +35,8 @@ const colorPropType = function(isRequired, props, propName, componentName, locat
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (color === 'currentcolor' || color === 'inherit') {
|
// Web supports additional color keywords and custom property values
|
||||||
|
if (color === 'currentcolor' || color === 'inherit' || color.indexOf('var(') === 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,15 @@ function StyleSheetPropType(shape: { [key: string]: ReactPropsCheckType }): Reac
|
|||||||
if (props[propName]) {
|
if (props[propName]) {
|
||||||
// Just make a dummy prop object with only the flattened style
|
// Just make a dummy prop object with only the flattened style
|
||||||
newProps = {};
|
newProps = {};
|
||||||
newProps[propName] = StyleSheet.flatten(props[propName]);
|
const flatStyle = StyleSheet.flatten(props[propName]);
|
||||||
|
// Remove custom properties from check
|
||||||
|
const nextStyle = Object.keys(flatStyle).reduce((acc, curr) => {
|
||||||
|
if (curr.indexOf('--') !== 0) {
|
||||||
|
acc[curr] = flatStyle[curr];
|
||||||
|
}
|
||||||
|
return acc;
|
||||||
|
}, {});
|
||||||
|
newProps[propName] = nextStyle;
|
||||||
}
|
}
|
||||||
return shapePropType(newProps, propName, componentName, location, ...rest);
|
return shapePropType(newProps, propName, componentName, location, ...rest);
|
||||||
};
|
};
|
||||||
|
|||||||
53
src/vendor/dangerousStyleValue/index.js
vendored
Normal file
53
src/vendor/dangerousStyleValue/index.js
vendored
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
/* eslint-disable */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copyright 2013-present, Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the BSD-style license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree. An additional grant
|
||||||
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
|
*
|
||||||
|
* @providesModule dangerousStyleValue
|
||||||
|
*/
|
||||||
|
|
||||||
|
import isUnitlessNumber from '../../modules/unitlessNumbers';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a value into the proper css writable value. The style name `name`
|
||||||
|
* should be logical (no hyphens), as specified
|
||||||
|
* in `CSSProperty.isUnitlessNumber`.
|
||||||
|
*
|
||||||
|
* @param {string} name CSS property name such as `topMargin`.
|
||||||
|
* @param {*} value CSS property value such as `10px`.
|
||||||
|
* @return {string} Normalized style value with dimensions applied.
|
||||||
|
*/
|
||||||
|
function dangerousStyleValue(name, value, isCustomProperty) {
|
||||||
|
// Note that we've removed escapeTextForBrowser() calls here since the
|
||||||
|
// whole string will be escaped when the attribute is injected into
|
||||||
|
// the markup. If you provide unsafe user data here they can inject
|
||||||
|
// arbitrary CSS which may be problematic (I couldn't repro this):
|
||||||
|
// https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet
|
||||||
|
// http://www.thespanner.co.uk/2007/11/26/ultimate-xss-css-injection/
|
||||||
|
// This is not an XSS hole but instead a potential CSS injection issue
|
||||||
|
// which has lead to a greater discussion about how we're going to
|
||||||
|
// trust URLs moving forward. See #2115901
|
||||||
|
|
||||||
|
var isEmpty = value == null || typeof value === 'boolean' || value === '';
|
||||||
|
if (isEmpty) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
!isCustomProperty &&
|
||||||
|
typeof value === 'number' &&
|
||||||
|
value !== 0 &&
|
||||||
|
!(isUnitlessNumber.hasOwnProperty(name) && isUnitlessNumber[name])
|
||||||
|
) {
|
||||||
|
return value + 'px'; // Presumes implicit 'px' suffix for unitless numbers
|
||||||
|
}
|
||||||
|
|
||||||
|
return ('' + value).trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
export default dangerousStyleValue;
|
||||||
208
src/vendor/setValueForStyles/index.js
vendored
208
src/vendor/setValueForStyles/index.js
vendored
@@ -10,199 +10,8 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import unitlessNumbers from '../../modules/unitlessNumbers';
|
import dangerousStyleValue from '../dangerousStyleValue';
|
||||||
|
import warnValidStyle from '../warnValidStyle';
|
||||||
if (process.env.NODE_ENV !== 'production') {
|
|
||||||
var camelizeStyleName = require('fbjs/lib/camelizeStyleName');
|
|
||||||
var warning = require('fbjs/lib/warning');
|
|
||||||
|
|
||||||
// 'msTransform' is correct, but the other prefixes should be capitalized
|
|
||||||
var badVendoredStyleNamePattern = /^(?:webkit|moz|o)[A-Z]/;
|
|
||||||
|
|
||||||
// style values shouldn't contain a semicolon
|
|
||||||
var badStyleValueWithSemicolonPattern = /;\s*$/;
|
|
||||||
|
|
||||||
var warnedStyleNames = {};
|
|
||||||
var warnedStyleValues = {};
|
|
||||||
var warnedForNaNValue = false;
|
|
||||||
|
|
||||||
var warnHyphenatedStyleName = function(name, owner) {
|
|
||||||
if (warnedStyleNames.hasOwnProperty(name) && warnedStyleNames[name]) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
warnedStyleNames[name] = true;
|
|
||||||
process.env.NODE_ENV !== 'production'
|
|
||||||
? warning(
|
|
||||||
false,
|
|
||||||
'Unsupported style property %s. Did you mean %s?%s',
|
|
||||||
name,
|
|
||||||
camelizeStyleName(name),
|
|
||||||
checkRenderMessage(owner)
|
|
||||||
)
|
|
||||||
: void 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
var warnBadVendoredStyleName = function(name, owner) {
|
|
||||||
if (warnedStyleNames.hasOwnProperty(name) && warnedStyleNames[name]) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
warnedStyleNames[name] = true;
|
|
||||||
process.env.NODE_ENV !== 'production'
|
|
||||||
? warning(
|
|
||||||
false,
|
|
||||||
'Unsupported vendor-prefixed style property %s. Did you mean %s?%s',
|
|
||||||
name,
|
|
||||||
name.charAt(0).toUpperCase() + name.slice(1),
|
|
||||||
checkRenderMessage(owner)
|
|
||||||
)
|
|
||||||
: void 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
var warnStyleValueWithSemicolon = function(name, value, owner) {
|
|
||||||
if (warnedStyleValues.hasOwnProperty(value) && warnedStyleValues[value]) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
warnedStyleValues[value] = true;
|
|
||||||
process.env.NODE_ENV !== 'production'
|
|
||||||
? warning(
|
|
||||||
false,
|
|
||||||
"Style property values shouldn't contain a semicolon.%s " + 'Try "%s: %s" instead.',
|
|
||||||
checkRenderMessage(owner),
|
|
||||||
name,
|
|
||||||
value.replace(badStyleValueWithSemicolonPattern, '')
|
|
||||||
)
|
|
||||||
: void 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
var warnStyleValueIsNaN = function(name, value, owner) {
|
|
||||||
if (warnedForNaNValue) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
warnedForNaNValue = true;
|
|
||||||
process.env.NODE_ENV !== 'production'
|
|
||||||
? warning(
|
|
||||||
false,
|
|
||||||
'`NaN` is an invalid value for the `%s` css style property.%s',
|
|
||||||
name,
|
|
||||||
checkRenderMessage(owner)
|
|
||||||
)
|
|
||||||
: void 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
var checkRenderMessage = function(owner) {
|
|
||||||
if (owner) {
|
|
||||||
var name = owner.getName();
|
|
||||||
if (name) {
|
|
||||||
return ' Check the render method of `' + name + '`.';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return '';
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {string} name
|
|
||||||
* @param {*} value
|
|
||||||
* @param {ReactDOMComponent} component
|
|
||||||
*/
|
|
||||||
var warnValidStyle = function(name, value, component) {
|
|
||||||
var owner;
|
|
||||||
if (component) {
|
|
||||||
owner = component._currentElement._owner;
|
|
||||||
}
|
|
||||||
if (name.indexOf('-') > -1) {
|
|
||||||
warnHyphenatedStyleName(name, owner);
|
|
||||||
} else if (badVendoredStyleNamePattern.test(name)) {
|
|
||||||
warnBadVendoredStyleName(name, owner);
|
|
||||||
} else if (badStyleValueWithSemicolonPattern.test(value)) {
|
|
||||||
warnStyleValueWithSemicolon(name, value, owner);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof value === 'number' && isNaN(value)) {
|
|
||||||
warnStyleValueIsNaN(name, value, owner);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
var styleWarnings = {};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert a value into the proper css writable value. The style name `name`
|
|
||||||
* should be logical (no hyphens)
|
|
||||||
*
|
|
||||||
* @param {string} name CSS property name such as `topMargin`.
|
|
||||||
* @param {*} value CSS property value such as `10px`.
|
|
||||||
* @param {ReactDOMComponent} component
|
|
||||||
* @return {string} Normalized style value with dimensions applied.
|
|
||||||
*/
|
|
||||||
function dangerousStyleValue(name, value, component) {
|
|
||||||
// Note that we've removed escapeTextForBrowser() calls here since the
|
|
||||||
// whole string will be escaped when the attribute is injected into
|
|
||||||
// the markup. If you provide unsafe user data here they can inject
|
|
||||||
// arbitrary CSS which may be problematic (I couldn't repro this):
|
|
||||||
// https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet
|
|
||||||
// http://www.thespanner.co.uk/2007/11/26/ultimate-xss-css-injection/
|
|
||||||
// This is not an XSS hole but instead a potential CSS injection issue
|
|
||||||
// which has lead to a greater discussion about how we're going to
|
|
||||||
// trust URLs moving forward. See #2115901
|
|
||||||
|
|
||||||
var isEmpty = value == null || typeof value === 'boolean' || value === '';
|
|
||||||
if (isEmpty) {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
var isNonNumeric = isNaN(value);
|
|
||||||
if (
|
|
||||||
isNonNumeric ||
|
|
||||||
value === 0 ||
|
|
||||||
(unitlessNumbers.hasOwnProperty(name) && unitlessNumbers[name])
|
|
||||||
) {
|
|
||||||
return '' + value; // cast to string
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof value === 'string') {
|
|
||||||
if (process.env.NODE_ENV !== 'production') {
|
|
||||||
var warning = require('fbjs/lib/warning');
|
|
||||||
|
|
||||||
// Allow '0' to pass through without warning. 0 is already special and
|
|
||||||
// doesn't require units, so we don't need to warn about it.
|
|
||||||
if (component && value !== '0') {
|
|
||||||
var owner = component._currentElement._owner;
|
|
||||||
var ownerName = owner ? owner.getName() : null;
|
|
||||||
if (ownerName && !styleWarnings[ownerName]) {
|
|
||||||
styleWarnings[ownerName] = {};
|
|
||||||
}
|
|
||||||
var warned = false;
|
|
||||||
if (ownerName) {
|
|
||||||
var warnings = styleWarnings[ownerName];
|
|
||||||
warned = warnings[name];
|
|
||||||
if (!warned) {
|
|
||||||
warnings[name] = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!warned) {
|
|
||||||
process.env.NODE_ENV !== 'production'
|
|
||||||
? warning(
|
|
||||||
false,
|
|
||||||
'a `%s` tag (owner: `%s`) was passed a numeric string value ' +
|
|
||||||
'for CSS property `%s` (value: `%s`) which will be treated ' +
|
|
||||||
'as a unitless number in a future version of React.',
|
|
||||||
component._currentElement.type,
|
|
||||||
ownerName || 'unknown',
|
|
||||||
name,
|
|
||||||
value
|
|
||||||
)
|
|
||||||
: void 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
value = value.trim();
|
|
||||||
}
|
|
||||||
return value + 'px';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the value for multiple styles on a node. If a value is specified as
|
* Sets the value for multiple styles on a node. If a value is specified as
|
||||||
@@ -218,14 +27,19 @@ const setValueForStyles = function(node, styles, component) {
|
|||||||
if (!styles.hasOwnProperty(styleName)) {
|
if (!styles.hasOwnProperty(styleName)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
var isCustomProperty = styleName.indexOf('--') === 0;
|
||||||
if (process.env.NODE_ENV !== 'production') {
|
if (process.env.NODE_ENV !== 'production') {
|
||||||
warnValidStyle(styleName, styles[styleName], component);
|
if (!isCustomProperty) {
|
||||||
|
warnValidStyle(styleName, styles[styleName], component);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
var styleValue = dangerousStyleValue(styleName, styles[styleName], component);
|
var styleValue = dangerousStyleValue(styleName, styles[styleName], isCustomProperty);
|
||||||
if (styleName === 'float' || styleName === 'cssFloat') {
|
if (styleName === 'float') {
|
||||||
styleName = 'cssFloat';
|
styleName = 'cssFloat';
|
||||||
}
|
}
|
||||||
if (styleValue) {
|
if (isCustomProperty) {
|
||||||
|
style.setProperty(styleName, styleValue);
|
||||||
|
} else if (styleValue) {
|
||||||
style[styleName] = styleValue;
|
style[styleName] = styleValue;
|
||||||
} else {
|
} else {
|
||||||
style[styleName] = '';
|
style[styleName] = '';
|
||||||
|
|||||||
170
src/vendor/warnValidStyle/index.js
vendored
Normal file
170
src/vendor/warnValidStyle/index.js
vendored
Normal file
@@ -0,0 +1,170 @@
|
|||||||
|
/* eslint-disable */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copyright 2013-present, Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the BSD-style license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree. An additional grant
|
||||||
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
|
*
|
||||||
|
* @providesModule warnValidStyle
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var emptyFunction = require('fbjs/lib/emptyFunction');
|
||||||
|
|
||||||
|
var warnValidStyle = emptyFunction;
|
||||||
|
|
||||||
|
if (process.env.NODE_ENV !== 'production') {
|
||||||
|
var camelizeStyleName = require('fbjs/lib/camelizeStyleName');
|
||||||
|
var warning = require('fbjs/lib/warning');
|
||||||
|
|
||||||
|
function getComponentName(instanceOrFiber) {
|
||||||
|
if (typeof instanceOrFiber.getName === 'function') {
|
||||||
|
// Stack reconciler
|
||||||
|
const instance = ((instanceOrFiber: any): ReactInstance);
|
||||||
|
return instance.getName();
|
||||||
|
}
|
||||||
|
if (typeof instanceOrFiber.tag === 'number') {
|
||||||
|
// Fiber reconciler
|
||||||
|
const fiber = ((instanceOrFiber: any): Fiber);
|
||||||
|
const { type } = fiber;
|
||||||
|
if (typeof type === 'string') {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
if (typeof type === 'function') {
|
||||||
|
return type.displayName || type.name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 'msTransform' is correct, but the other prefixes should be capitalized
|
||||||
|
var badVendoredStyleNamePattern = /^(?:webkit|moz|o)[A-Z]/;
|
||||||
|
|
||||||
|
// style values shouldn't contain a semicolon
|
||||||
|
var badStyleValueWithSemicolonPattern = /;\s*$/;
|
||||||
|
|
||||||
|
var warnedStyleNames = {};
|
||||||
|
var warnedStyleValues = {};
|
||||||
|
var warnedForNaNValue = false;
|
||||||
|
var warnedForInfinityValue = false;
|
||||||
|
|
||||||
|
var warnHyphenatedStyleName = function(name, owner) {
|
||||||
|
if (warnedStyleNames.hasOwnProperty(name) && warnedStyleNames[name]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
warnedStyleNames[name] = true;
|
||||||
|
warning(
|
||||||
|
false,
|
||||||
|
'Unsupported style property %s. Did you mean %s?%s',
|
||||||
|
name,
|
||||||
|
camelizeStyleName(name),
|
||||||
|
checkRenderMessage(owner)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
var warnBadVendoredStyleName = function(name, owner) {
|
||||||
|
if (warnedStyleNames.hasOwnProperty(name) && warnedStyleNames[name]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
warnedStyleNames[name] = true;
|
||||||
|
warning(
|
||||||
|
false,
|
||||||
|
'Unsupported vendor-prefixed style property %s. Did you mean %s?%s',
|
||||||
|
name,
|
||||||
|
name.charAt(0).toUpperCase() + name.slice(1),
|
||||||
|
checkRenderMessage(owner)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
var warnStyleValueWithSemicolon = function(name, value, owner) {
|
||||||
|
if (warnedStyleValues.hasOwnProperty(value) && warnedStyleValues[value]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
warnedStyleValues[value] = true;
|
||||||
|
warning(
|
||||||
|
false,
|
||||||
|
"Style property values shouldn't contain a semicolon.%s " + 'Try "%s: %s" instead.',
|
||||||
|
checkRenderMessage(owner),
|
||||||
|
name,
|
||||||
|
value.replace(badStyleValueWithSemicolonPattern, '')
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
var warnStyleValueIsNaN = function(name, value, owner) {
|
||||||
|
if (warnedForNaNValue) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
warnedForNaNValue = true;
|
||||||
|
warning(
|
||||||
|
false,
|
||||||
|
'`NaN` is an invalid value for the `%s` css style property.%s',
|
||||||
|
name,
|
||||||
|
checkRenderMessage(owner)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
var warnStyleValueIsInfinity = function(name, value, owner) {
|
||||||
|
if (warnedForInfinityValue) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
warnedForInfinityValue = true;
|
||||||
|
warning(
|
||||||
|
false,
|
||||||
|
'`Infinity` is an invalid value for the `%s` css style property.%s',
|
||||||
|
name,
|
||||||
|
checkRenderMessage(owner)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
var checkRenderMessage = function(owner) {
|
||||||
|
var ownerName;
|
||||||
|
if (owner != null) {
|
||||||
|
// Stack passes the owner manually all the way to CSSPropertyOperations.
|
||||||
|
ownerName = getComponentName(owner);
|
||||||
|
} else {
|
||||||
|
// Fiber doesn't pass it but uses ReactDebugCurrentFiber to track it.
|
||||||
|
// It is only enabled in development and tracks host components too.
|
||||||
|
// var {getCurrentFiberOwnerName} = require('ReactDebugCurrentFiber');
|
||||||
|
// ownerName = getCurrentFiberOwnerName();
|
||||||
|
// TODO: also report the stack.
|
||||||
|
}
|
||||||
|
if (ownerName) {
|
||||||
|
return '\n\nCheck the render method of `' + ownerName + '`.';
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
};
|
||||||
|
|
||||||
|
warnValidStyle = function(name, value, component) {
|
||||||
|
var owner;
|
||||||
|
if (component) {
|
||||||
|
// TODO: this only works with Stack. Seems like we need to add unit tests?
|
||||||
|
// owner = component._currentElement._owner;
|
||||||
|
}
|
||||||
|
if (name.indexOf('-') > -1) {
|
||||||
|
warnHyphenatedStyleName(name, owner);
|
||||||
|
} else if (badVendoredStyleNamePattern.test(name)) {
|
||||||
|
warnBadVendoredStyleName(name, owner);
|
||||||
|
} else if (badStyleValueWithSemicolonPattern.test(value)) {
|
||||||
|
warnStyleValueWithSemicolon(name, value, owner);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof value === 'number') {
|
||||||
|
if (isNaN(value)) {
|
||||||
|
warnStyleValueIsNaN(name, value, owner);
|
||||||
|
} else if (!isFinite(value)) {
|
||||||
|
warnStyleValueIsInfinity(name, value, owner);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export default warnValidStyle;
|
||||||
10
yarn.lock
10
yarn.lock
@@ -896,7 +896,7 @@ browserify-zlib@^0.1.4:
|
|||||||
|
|
||||||
browserslist@^2.0.0:
|
browserslist@^2.0.0:
|
||||||
version "2.2.2"
|
version "2.2.2"
|
||||||
resolved "https://artifactory.twitter.biz:443/api/npm/js-virtual/browserslist/-/browserslist-2.2.2.tgz#e9b4618b8a01c193f9786beea09f6fd10dbe31c3"
|
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-2.2.2.tgz#e9b4618b8a01c193f9786beea09f6fd10dbe31c3"
|
||||||
dependencies:
|
dependencies:
|
||||||
caniuse-lite "^1.0.30000704"
|
caniuse-lite "^1.0.30000704"
|
||||||
electron-to-chromium "^1.3.16"
|
electron-to-chromium "^1.3.16"
|
||||||
@@ -985,7 +985,7 @@ caniuse-api@^2.0.0:
|
|||||||
|
|
||||||
caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000704:
|
caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000704:
|
||||||
version "1.0.30000706"
|
version "1.0.30000706"
|
||||||
resolved "https://artifactory.twitter.biz:443/api/npm/js-virtual/caniuse-lite/-/caniuse-lite-1.0.30000706.tgz#bc59abc41ba7d4a3634dda95befded6114e1f24e"
|
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000706.tgz#bc59abc41ba7d4a3634dda95befded6114e1f24e"
|
||||||
|
|
||||||
capture-stack-trace@^1.0.0:
|
capture-stack-trace@^1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
@@ -1575,7 +1575,7 @@ ejs@^2.5.6:
|
|||||||
|
|
||||||
electron-to-chromium@^1.3.16:
|
electron-to-chromium@^1.3.16:
|
||||||
version "1.3.16"
|
version "1.3.16"
|
||||||
resolved "https://artifactory.twitter.biz:443/api/npm/js-virtual/electron-to-chromium/-/electron-to-chromium-1.3.16.tgz#d0e026735754770901ae301a21664cba45d92f7d"
|
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.16.tgz#d0e026735754770901ae301a21664cba45d92f7d"
|
||||||
|
|
||||||
elegant-spinner@^1.0.1:
|
elegant-spinner@^1.0.1:
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
@@ -3317,7 +3317,7 @@ lodash.map@^4.4.0:
|
|||||||
|
|
||||||
lodash.memoize@^4.1.2:
|
lodash.memoize@^4.1.2:
|
||||||
version "4.1.2"
|
version "4.1.2"
|
||||||
resolved "https://artifactory.twitter.biz:443/api/npm/js-virtual/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe"
|
resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe"
|
||||||
|
|
||||||
lodash.merge@^4.4.0:
|
lodash.merge@^4.4.0:
|
||||||
version "4.6.0"
|
version "4.6.0"
|
||||||
@@ -3349,7 +3349,7 @@ lodash.some@^4.4.0:
|
|||||||
|
|
||||||
lodash.uniq@^4.5.0:
|
lodash.uniq@^4.5.0:
|
||||||
version "4.5.0"
|
version "4.5.0"
|
||||||
resolved "https://artifactory.twitter.biz:443/api/npm/js-virtual/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
|
resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
|
||||||
|
|
||||||
lodash@^4.0.0, lodash@^4.14.0, lodash@^4.17.4, lodash@^4.3.0, lodash@^4.6.1:
|
lodash@^4.0.0, lodash@^4.14.0, lodash@^4.17.4, lodash@^4.3.0, lodash@^4.6.1:
|
||||||
version "4.17.4"
|
version "4.17.4"
|
||||||
|
|||||||
Reference in New Issue
Block a user