Compare commits

..

2 Commits

Author SHA1 Message Date
Eli White
a5e5f2a350 Adding test for components rendered with Fabric with Paper's setNativeProps 2019-02-20 15:56:06 -08:00
Eli White
ef52e22e89 Adding ReactNative.setNativeProps that takes a ref 2019-02-20 14:56:59 -08:00
1022 changed files with 29781 additions and 147070 deletions

23
.babelrc Normal file
View File

@@ -0,0 +1,23 @@
{
"presets": ["react"],
"ignore": ["third_party"],
"plugins": [
"transform-class-properties",
"syntax-trailing-function-commas",
["transform-object-rest-spread", { "useBuiltIns": true }],
"transform-es2015-template-literals",
"transform-es2015-literals",
"transform-es2015-arrow-functions",
"transform-es2015-block-scoped-functions",
["transform-es2015-classes", { "loose": true }],
"transform-es2015-object-super",
"transform-es2015-shorthand-properties",
"transform-es2015-computed-properties",
"transform-es2015-for-of",
"check-es2015-constants",
["transform-es2015-spread", { "loose": true }],
"transform-es2015-parameters",
["transform-es2015-destructuring", { "loose": true }],
["transform-es2015-block-scoping", { "throwIfClosureRequired": true }]
]
}

View File

@@ -1,422 +1,48 @@
version: 2
aliases:
- &docker
- image: circleci/openjdk:8-jdk-node-browsers
- &environment
TZ: /usr/share/zoneinfo/America/Los_Angeles
- &restore_yarn_cache
restore_cache:
name: Restore node_modules cache
keys:
- v1-node-{{ arch }}-{{ .Branch }}-{{ checksum "yarn.lock" }}
- v1-node-{{ arch }}-{{ .Branch }}-
- v1-node-{{ arch }}-
- &run_yarn
run:
name: Install Packages
command: yarn --frozen-lockfile
- &attach_workspace
at: build
- &process_artifacts
docker: *docker
environment: *environment
steps:
- checkout
- attach_workspace: *attach_workspace
- *restore_yarn_cache
- *run_yarn
- run: node ./scripts/rollup/consolidateBundleSizes.js
- run: ./scripts/circleci/upload_build.sh
- run: ./scripts/circleci/pack_and_store_artifact.sh
- store_artifacts:
path: ./node_modules.tgz
- store_artifacts:
path: ./build.tgz
- store_artifacts:
path: ./build/bundle-sizes.json
- store_artifacts:
# TODO: Update release script to use local file instead of pulling
# from artifacts.
path: ./scripts/error-codes/codes.json
- persist_to_workspace:
root: build
paths:
- bundle-sizes.json
jobs:
setup:
docker: *docker
environment: *environment
build:
docker:
- image: circleci/openjdk:8-jdk-node-browsers
environment:
TZ: /usr/share/zoneinfo/America/Los_Angeles
TRAVIS_REPO_SLUG: facebook/react
parallelism: 4
steps:
- checkout
- run: echo $CIRCLE_COMPARE_URL | cut -d/ -f7
- restore_cache:
name: Restore node_modules cache
keys:
- v1-node-{{ arch }}-{{ .Branch }}-{{ checksum "yarn.lock" }}
- v1-node-{{ arch }}-{{ .Branch }}-
- v1-node-{{ arch }}-
- run:
name: Nodejs Version
command: node --version
- *restore_yarn_cache
- *run_yarn
- run:
name: Install Packages
command: yarn install --frozen-lockfile
- run:
name: Test Packages
command: ./scripts/circleci/test_entry_point.sh
- save_cache:
name: Save node_modules cache
key: v1-node-{{ arch }}-{{ .Branch }}-{{ checksum "yarn.lock" }}
paths:
- ~/.cache/yarn
lint:
docker: *docker
environment: *environment
steps:
- checkout
- *restore_yarn_cache
- *run_yarn
- run: node ./scripts/prettier/index
- run: node ./scripts/tasks/eslint
- run: ./scripts/circleci/check_license.sh
- run: ./scripts/circleci/check_modules.sh
- run: ./scripts/circleci/test_print_warnings.sh
flow:
docker: *docker
environment: *environment
steps:
- checkout
- *restore_yarn_cache
- *run_yarn
- run: node ./scripts/tasks/flow-ci
test_source:
docker: *docker
environment: *environment
steps:
- checkout
- *restore_yarn_cache
- *run_yarn
- run:
environment:
RELEASE_CHANNEL: stable
command: yarn test --maxWorkers=2
test_source_experimental:
docker: *docker
environment: *environment
steps:
- checkout
- *restore_yarn_cache
- *run_yarn
- run:
environment:
RELEASE_CHANNEL: experimental
command: yarn test --maxWorkers=2
test_source_persistent:
docker: *docker
environment: *environment
steps:
- checkout
- *restore_yarn_cache
- *run_yarn
- run:
environment:
RELEASE_CHANNEL: stable
command: yarn test-persistent --maxWorkers=2
test_source_prod:
docker: *docker
environment: *environment
steps:
- checkout
- *restore_yarn_cache
- *run_yarn
- run:
environment:
RELEASE_CHANNEL: stable
command: yarn test-prod --maxWorkers=2
build:
docker: *docker
environment: *environment
parallelism: 20
steps:
- checkout
- *restore_yarn_cache
- *run_yarn
- run:
environment:
RELEASE_CHANNEL: stable
command: |
./scripts/circleci/add_build_info_json.sh
./scripts/circleci/update_package_versions.sh
yarn build
- run: echo "stable" >> build/RELEASE_CHANNEL
- persist_to_workspace:
root: build
paths:
- RELEASE_CHANNEL
- facebook-www
- node_modules
- react-native
- dist
- sizes/*.json
build_experimental:
docker: *docker
environment: *environment
parallelism: 20
steps:
- checkout
- *restore_yarn_cache
- *run_yarn
- run:
environment:
RELEASE_CHANNEL: experimental
command: |
./scripts/circleci/add_build_info_json.sh
./scripts/circleci/update_package_versions.sh
yarn build
- run: echo "experimental" >> build/RELEASE_CHANNEL
- persist_to_workspace:
root: build
paths:
- RELEASE_CHANNEL
- facebook-www
- node_modules
- react-native
- dist
- sizes/*.json
- store_artifacts:
path: ./node_modules.tgz
# These jobs are named differently so we can distinguish the stable and
# and experimental artifacts
process_artifacts: *process_artifacts
process_artifacts_experimental: *process_artifacts
sizebot:
docker: *docker
environment: *environment
steps:
- checkout
- attach_workspace: *attach_workspace
- *restore_yarn_cache
- *run_yarn
# This runs in the process_artifacts job, too, but it's faster to run
# this step in both jobs instead of running the jobs sequentially
- run: node ./scripts/rollup/consolidateBundleSizes.js
- run:
environment:
RELEASE_CHANNEL: stable
command: node ./scripts/tasks/danger
sizebot_experimental:
docker: *docker
environment: *environment
steps:
- checkout
- attach_workspace: *attach_workspace
- *restore_yarn_cache
- *run_yarn
# This runs in the process_artifacts job, too, but it's faster to run
# this step in both jobs instead of running the jobs sequentially
- run: node ./scripts/rollup/consolidateBundleSizes.js
- run:
environment:
RELEASE_CHANNEL: experimental
command: node ./scripts/tasks/danger
lint_build:
docker: *docker
environment: *environment
steps:
- checkout
- attach_workspace: *attach_workspace
- *restore_yarn_cache
- *run_yarn
- run: yarn lint-build
- run: scripts/circleci/check_minified_errors.sh
test_build:
docker: *docker
environment: *environment
steps:
- checkout
- attach_workspace: *attach_workspace
- *restore_yarn_cache
- *run_yarn
- run:
environment:
RELEASE_CHANNEL: stable
command: yarn test-build --maxWorkers=2
test_build_experimental:
docker: *docker
environment: *environment
steps:
- checkout
- attach_workspace: *attach_workspace
- *restore_yarn_cache
- *run_yarn
- run:
environment:
RELEASE_CHANNEL: experimental
command: yarn test-build --maxWorkers=2
test_build_devtools:
docker: *docker
environment: *environment
steps:
- checkout
- attach_workspace: *attach_workspace
- *restore_yarn_cache
- *run_yarn
- run:
environment:
RELEASE_CHANNEL: stable
command: yarn test-build --maxWorkers=2
test_dom_fixtures:
docker: *docker
environment: *environment
steps:
- checkout
- attach_workspace: *attach_workspace
- *restore_yarn_cache
- run:
name: Run DOM fixture tests
environment:
RELEASE_CHANNEL: stable
command: |
cd fixtures/dom
yarn --frozen-lockfile
yarn prestart
yarn test --maxWorkers=2
test_fuzz:
docker: *docker
environment: *environment
steps:
- checkout
- *restore_yarn_cache
- *run_yarn
- run:
name: Run fuzz tests
command: |
FUZZ_TEST_SEED=$RANDOM yarn test fuzz --maxWorkers=2
FUZZ_TEST_SEED=$RANDOM yarn test-prod fuzz --maxWorkers=2
test_build_prod:
docker: *docker
environment: *environment
steps:
- checkout
- attach_workspace: *attach_workspace
- *restore_yarn_cache
- *run_yarn
- run:
environment:
RELEASE_CHANNEL: stable
command: yarn test-build-prod --maxWorkers=2
test_build_prod_experimental:
docker: *docker
environment: *environment
steps:
- checkout
- attach_workspace: *attach_workspace
- *restore_yarn_cache
- *run_yarn
- run:
environment:
RELEASE_CHANNEL: experimental
command: yarn test-build-prod --maxWorkers=2
workflows:
version: 2
stable:
jobs:
- setup
- lint:
requires:
- setup
- flow:
requires:
- setup
- test_source:
requires:
- setup
- test_source_prod:
requires:
- setup
- test_source_persistent:
requires:
- setup
- build:
requires:
- setup
- process_artifacts:
requires:
- build
- sizebot:
requires:
- build
- lint_build:
requires:
- build
- test_build:
requires:
- build
- test_build_prod:
requires:
- build
- test_build_devtools:
requires:
- build
- test_dom_fixtures:
requires:
- build
experimental:
jobs:
- setup
- test_source_experimental:
requires:
- setup
- build_experimental:
requires:
- setup
- process_artifacts_experimental:
requires:
- build_experimental
- sizebot_experimental:
requires:
- build_experimental
- test_build_experimental:
requires:
- build_experimental
- test_build_prod_experimental:
requires:
- build_experimental
- lint_build:
requires:
- build_experimental
fuzz_tests:
triggers:
- schedule:
# Fuzz tests run hourly
cron: "0 * * * *"
filters:
branches:
only:
- master
jobs:
- setup
- test_fuzz:
requires:
- setup
- store_artifacts:
path: ./scripts/error-codes/codes.json

View File

@@ -12,10 +12,3 @@ scripts/bench/benchmarks/**/*.js
# React repository clone
scripts/bench/remote-repo/
packages/react-devtools-core/dist
packages/react-devtools-extensions/chrome/build
packages/react-devtools-extensions/firefox/build
packages/react-devtools-extensions/shared/build
packages/react-devtools-inline/dist
packages/react-devtools-shell/dist

View File

@@ -12,13 +12,18 @@ module.exports = {
extends: 'fbjs',
// Stop ESLint from looking for a configuration file in parent folders
root: true,
'root': true,
plugins: ['jest', 'no-for-of-loops', 'react', 'react-internal'],
plugins: [
'jest',
'no-for-of-loops',
'react',
'react-internal',
],
parser: 'babel-eslint',
parser: 'espree',
parserOptions: {
ecmaVersion: 8,
ecmaVersion: 2017,
sourceType: 'script',
ecmaFeatures: {
experimentalObjectRestSpread: true,
@@ -35,8 +40,8 @@ module.exports = {
'dot-location': [ERROR, 'property'],
'dot-notation': ERROR,
'eol-last': ERROR,
eqeqeq: [ERROR, 'allow-null'],
indent: OFF,
'eqeqeq': [ERROR, 'allow-null'],
'indent': OFF,
'jsx-quotes': [ERROR, 'prefer-double'],
'keyword-spacing': [ERROR, {after: true, before: true}],
'no-bitwise': OFF,
@@ -46,9 +51,9 @@ module.exports = {
'no-shadow': ERROR,
'no-unused-expressions': ERROR,
'no-unused-vars': [ERROR, {args: 'none'}],
'no-use-before-define': OFF,
'no-use-before-define': [ERROR, {functions: false, variables: false}],
'no-useless-concat': OFF,
quotes: [ERROR, 'single', {avoidEscape: true, allowTemplateLiterals: true}],
'quotes': [ERROR, 'single', {avoidEscape: true, allowTemplateLiterals: true }],
'space-before-blocks': ERROR,
'space-before-function-paren': OFF,
'valid-typeof': [ERROR, {requireStringLiterals: true}],
@@ -60,12 +65,6 @@ module.exports = {
'no-var': ERROR,
strict: ERROR,
// Enforced by Prettier
// TODO: Prettier doesn't handle long strings or long comments. Not a big
// deal. But I turned it off because loading the plugin causes some obscure
// syntax error and it didn't seem worth investigating.
'max-len': OFF,
// React & JSX
// Our transforms set this automatically
'react/jsx-boolean-value': [ERROR, 'always'],
@@ -79,10 +78,7 @@ module.exports = {
'react/react-in-jsx-scope': ERROR,
'react/self-closing-comp': ERROR,
// We don't care to do this
'react/jsx-wrap-multilines': [
ERROR,
{declaration: false, assignment: false},
],
'react/jsx-wrap-multilines': [ERROR, {declaration: false, assignment: false}],
// Prevent for...of loops because they require a Symbol polyfill.
// You can disable this rule for code that isn't shipped (e.g. build scripts and tests).
@@ -116,7 +112,6 @@ module.exports = {
files: esNextPaths,
parser: 'babel-eslint',
parserOptions: {
ecmaVersion: 8,
sourceType: 'module',
},
rules: {
@@ -129,27 +124,15 @@ module.exports = {
rules: {
// https://github.com/jest-community/eslint-plugin-jest
'jest/no-focused-tests': ERROR,
'jest/valid-expect': ERROR,
'jest/valid-expect-in-promise': ERROR,
},
},
{
files: ['packages/react-native-renderer/**/*.js'],
globals: {
nativeFabricUIManager: true,
},
},
}
}
],
globals: {
SharedArrayBuffer: true,
spyOnDev: true,
spyOnDevAndProd: true,
spyOnProd: true,
__PROFILE__: true,
__UMD__: true,
__EXPERIMENTAL__: true,
trustedTypes: true,
},
};

11
.gitignore vendored
View File

@@ -22,14 +22,3 @@ chrome-user-data
.vscode
*.swp
*.swo
packages/react-devtools-core/dist
packages/react-devtools-extensions/chrome/build
packages/react-devtools-extensions/chrome/*.crx
packages/react-devtools-extensions/chrome/*.pem
packages/react-devtools-extensions/firefox/build
packages/react-devtools-extensions/firefox/*.xpi
packages/react-devtools-extensions/firefox/*.pem
packages/react-devtools-extensions/shared/build
packages/react-devtools-inline/dist
packages/react-devtools-shell/dist

2
.nvmrc
View File

@@ -1 +1 @@
v10.16.3
v8.4.0

View File

@@ -1,6 +0,0 @@
packages/react-devtools-core/dist
packages/react-devtools-extensions/chrome/build
packages/react-devtools-extensions/firefox/build
packages/react-devtools-extensions/shared/build
packages/react-devtools-inline/dist
packages/react-devtools-shell/dist

View File

@@ -1 +0,0 @@
{}

View File

@@ -6,125 +6,6 @@
</summary>
</details>
## 16.10.2 (October 3, 2019)
### React DOM
* Fix regression in react-native-web by restoring order of arguments in event plugin extractors ([@necolas](https://github.com/necolas) in [#16978](https://github.com/facebook/react/pull/16978))
## 16.10.1 (September 28, 2019)
### React DOM
* Fix regression in Next.js apps by allowing Suspense mismatch during hydration to silently proceed ([@sebmarkbage](https://github.com/sebmarkbage) in [#16943](https://github.com/facebook/react/pull/16943))
## 16.10.0 (September 27, 2019)
### React DOM
* Fix edge case where a hook update wasn't being memoized. ([@sebmarkbage](http://github.com/sebmarkbage) in [#16359](https://github.com/facebook/react/pull/16359))
* Fix heuristic for determining when to hydrate, so we don't incorrectly hydrate during an update. ([@sebmarkbage](http://github.com/sebmarkbage) in [#16739](https://github.com/facebook/react/pull/16739))
* Clear additional fiber fields during unmount to save memory. ([@trueadm](http://github.com/trueadm) in [#16807](https://github.com/facebook/react/pull/16807))
* Fix bug with required text fields in Firefox. ([@halvves](http://github.com/halvves) in [#16578](https://github.com/facebook/react/pull/16578))
* Prefer `Object.is` instead of inline polyfill, when available. ([@ku8ar](http://github.com/ku8ar) in [#16212](https://github.com/facebook/react/pull/16212))
* Fix bug when mixing Suspense and error handling. ([@acdlite](http://github.com/acdlite) in [#16801](https://github.com/facebook/react/pull/16801))
### Scheduler (Experimental)
* Improve queue performance by switching its internal data structure to a min binary heap. ([@acdlite](http://github.com/acdlite) in [#16245](https://github.com/facebook/react/pull/16245))
* Use `postMessage` loop with short intervals instead of attempting to align to frame boundaries with `requestAnimationFrame`. ([@acdlite](http://github.com/acdlite) in [#16214](https://github.com/facebook/react/pull/16214))
### useSubscription
* Avoid tearing issue when a mutation happens and the previous update is still in progress. ([@bvaughn](http://github.com/bvaughn) in [#16623](https://github.com/facebook/react/pull/16623))
## 16.9.0 (August 8, 2019)
### React
* Add `<React.Profiler>` API for gathering performance measurements programmatically. ([@bvaughn](https://github.com/bvaughn) in [#15172](https://github.com/facebook/react/pull/15172))
* Remove `unstable_ConcurrentMode` in favor of `unstable_createRoot`. ([@acdlite](https://github.com/acdlite) in [#15532](https://github.com/facebook/react/pull/15532))
### React DOM
* Deprecate old names for the `UNSAFE_*` lifecycle methods. ([@bvaughn](https://github.com/bvaughn) in [#15186](https://github.com/facebook/react/pull/15186) and [@threepointone](https://github.com/threepointone) in [#16103](https://github.com/facebook/react/pull/16103))
* Deprecate `javascript:` URLs as a common attack surface. ([@sebmarkbage](https://github.com/sebmarkbage) in [#15047](https://github.com/facebook/react/pull/15047))
* Deprecate uncommon "module pattern" (factory) components. ([@sebmarkbage](https://github.com/sebmarkbage) in [#15145](https://github.com/facebook/react/pull/15145))
* Add support for the `disablePictureInPicture` attribute on `<video>`. ([@eek](https://github.com/eek) in [#15334](https://github.com/facebook/react/pull/15334))
* Add support for `onLoad` event for `<embed>`. ([@cherniavskii](https://github.com/cherniavskii) in [#15614](https://github.com/facebook/react/pull/15614))
* Add support for editing `useState` state from DevTools. ([@bvaughn](https://github.com/bvaughn) in [#14906](https://github.com/facebook/react/pull/14906))
* Add support for toggling Suspense from DevTools. ([@gaearon](https://github.com/gaearon) in [#15232](https://github.com/facebook/react/pull/15232))
* Warn when `setState` is called from `useEffect`, creating a loop. ([@gaearon](https://github.com/gaearon) in [#15180](https://github.com/facebook/react/pull/15180))
* Fix a memory leak. ([@paulshen](https://github.com/paulshen) in [#16115](https://github.com/facebook/react/pull/16115))
* Fix a crash inside `findDOMNode` for components wrapped in `<Suspense>`. ([@acdlite](https://github.com/acdlite) in [#15312](https://github.com/facebook/react/pull/15312))
* Fix pending effects from being flushed too late. ([@acdlite](https://github.com/acdlite) in [#15650](https://github.com/facebook/react/pull/15650))
* Fix incorrect argument order in a warning message. ([@brickspert](https://github.com/brickspert) in [#15345](https://github.com/facebook/react/pull/15345))
* Fix hiding Suspense fallback nodes when there is an `!important` style. ([@acdlite](https://github.com/acdlite) in [#15861](https://github.com/facebook/react/pull/15861) and [#15882](https://github.com/facebook/react/pull/15882))
* Slightly improve hydration performance. ([@bmeurer](https://github.com/bmeurer) in [#15998](https://github.com/facebook/react/pull/15998))
### React DOM Server
* Fix incorrect output for camelCase custom CSS property names. ([@bedakb](https://github.com/bedakb) in [#16167](https://github.com/facebook/react/pull/16167))
### React Test Utilities and Test Renderer
* Add `act(async () => ...)` for testing asynchronous state updates. ([@threepointone](https://github.com/threepointone) in [#14853](https://github.com/facebook/react/pull/14853))
* Add support for nesting `act` from different renderers. ([@threepointone](https://github.com/threepointone) in [#16039](https://github.com/facebook/react/pull/16039) and [#16042](https://github.com/facebook/react/pull/16042))
* Warn in Strict Mode if effects are scheduled outside an `act()` call. ([@threepointone](https://github.com/threepointone) in [#15763](https://github.com/facebook/react/pull/15763) and [#16041](https://github.com/facebook/react/pull/16041))
* Warn when using `act` from the wrong renderer. ([@threepointone](https://github.com/threepointone) in [#15756](https://github.com/facebook/react/pull/15756))
### ESLint Plugin: React Hooks
* Report Hook calls at the top level as a violation. ([gaearon](https://github.com/gaearon) in [#16455](https://github.com/facebook/react/pull/16455))
## 16.8.6 (March 27, 2019)
### React DOM
* Fix an incorrect bailout in `useReducer()`. ([@acdlite](https://github.com/acdlite) in [#15124](https://github.com/facebook/react/pull/15124))
* Fix iframe warnings in Safari DevTools. ([@renanvalentin](https://github.com/renanvalentin) in [#15099](https://github.com/facebook/react/pull/15099))
* Warn if `contextType` is set to `Context.Consumer` instead of `Context`. ([@aweary](https://github.com/aweary) in [#14831](https://github.com/facebook/react/pull/14831))
* Warn if `contextType` is set to invalid values. ([@gaearon](https://github.com/gaearon) in [#15142](https://github.com/facebook/react/pull/15142))
## 16.8.5 (March 22, 2019)
### React DOM
* Don't set the first option as selected in select tag with `size` attribute. ([@kulek1](https://github.com/kulek1) in [#14242](https://github.com/facebook/react/pull/14242))
* Improve the `useEffect(async () => ...)` warning message. ([@gaearon](https://github.com/gaearon) in [#15118](https://github.com/facebook/react/pull/15118))
* Improve the error message sometimes caused by duplicate React. ([@jaredpalmer](https://github.com/jaredpalmer) in [#15139](https://github.com/facebook/react/pull/15139))
### React DOM Server
* Improve the `useLayoutEffect` warning message when server rendering. ([@gaearon](https://github.com/gaearon) in [#15158](https://github.com/facebook/react/pull/15158))
### React Shallow Renderer
* Fix `setState` in shallow renderer to work with Hooks. ([@gaearon](https://github.com/gaearon) in [#15120](https://github.com/facebook/react/pull/15120))
* Fix shallow renderer to support `React.memo`. ([@aweary](https://github.com/aweary) in [#14816](https://github.com/facebook/react/pull/14816))
* Fix shallow renderer to support Hooks inside `forwardRef`. ([@eps1lon](https://github.com/eps1lon) in [#15100](https://github.com/facebook/react/pull/15100))
## 16.8.4 (March 5, 2019)
### React DOM and other renderers
- Fix a bug where DevTools caused a runtime error when inspecting a component that used a `useContext` hook. ([@bvaughn](https://github.com/bvaughn) in [#14940](https://github.com/facebook/react/pull/14940))
## 16.8.3 (February 21, 2019)
### React DOM
* Fix a bug that caused inputs to behave incorrectly in UMD builds. ([@gaearon](https://github.com/gaearon) in [#14914](https://github.com/facebook/react/pull/14914))
* Fix a bug that caused render phase updates to be discarded. ([@gaearon](https://github.com/gaearon) in [#14852](https://github.com/facebook/react/pull/14852))
### React DOM Server
* Unwind the context stack when a stream is destroyed without completing, to prevent incorrect values during a subsequent render. ([@overlookmotel](https://github.com/overlookmotel) in [#14706](https://github.com/facebook/react/pull/14706/))
### ESLint Plugin for React Hooks
* Add a new recommended `exhaustive-deps` rule. ([@gaearon](https://github.com/gaearon) in [#14636](https://github.com/facebook/react/pull/14636))
## 16.8.2 (February 14, 2019)
### React DOM

View File

@@ -1,76 +1,3 @@
# Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to make participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, sex characteristics, gender identity and expression,
level of experience, education, socio-economic status, nationality, personal
appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment
include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or
advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
## Scope
This Code of Conduct applies within all project spaces, and it also applies when
an individual is representing the project or its community in public spaces.
Examples of representing a project or community include using an official
project e-mail address, posting via an official social media account, or acting
as an appointed representative at an online or offline event. Representation of
a project may be further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at <opensource-conduct@fb.com>. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see
https://www.contributor-covenant.org/faq
Facebook has adopted a Code of Conduct that we expect project participants to adhere to. Please [read the full text](https://code.fb.com/codeofconduct/) so that you can understand what actions will and will not be tolerated.

View File

@@ -1,4 +1,4 @@
# [React](https://reactjs.org/) &middot; [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/facebook/react/blob/master/LICENSE) [![npm version](https://img.shields.io/npm/v/react.svg?style=flat)](https://www.npmjs.com/package/react) [![CircleCI Status](https://circleci.com/gh/facebook/react.svg?style=shield&circle-token=:circle-token)](https://circleci.com/gh/facebook/react) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://reactjs.org/docs/how-to-contribute.html#your-first-pull-request)
# [React](https://reactjs.org/) &middot; [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/facebook/react/blob/master/LICENSE) [![npm version](https://img.shields.io/npm/v/react.svg?style=flat)](https://www.npmjs.com/package/react) [![Coverage Status](https://img.shields.io/coveralls/facebook/react/master.svg?style=flat)](https://coveralls.io/github/facebook/react?branch=master) [![CircleCI Status](https://circleci.com/gh/facebook/react.svg?style=shield&circle-token=:circle-token)](https://circleci.com/gh/facebook/react) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://reactjs.org/docs/how-to-contribute.html#your-first-pull-request)
React is a JavaScript library for building user interfaces.

View File

@@ -1,27 +0,0 @@
'use strict';
module.exports = {
plugins: [
'@babel/plugin-syntax-jsx',
'@babel/plugin-transform-react-jsx',
'@babel/plugin-transform-flow-strip-types',
['@babel/plugin-proposal-class-properties', {loose: true}],
'syntax-trailing-function-commas',
[
'@babel/plugin-proposal-object-rest-spread',
{loose: true, useBuiltIns: true},
],
['@babel/plugin-transform-template-literals', {loose: true}],
'@babel/plugin-transform-literals',
'@babel/plugin-transform-arrow-functions',
'@babel/plugin-transform-block-scoped-functions',
'@babel/plugin-transform-object-super',
'@babel/plugin-transform-shorthand-properties',
'@babel/plugin-transform-computed-properties',
'@babel/plugin-transform-for-of',
['@babel/plugin-transform-spread', {loose: true, useBuiltIns: true}],
'@babel/plugin-transform-parameters',
['@babel/plugin-transform-destructuring', {loose: true, useBuiltIns: true}],
['@babel/plugin-transform-block-scoping', {throwIfClosureRequired: true}],
],
};

View File

@@ -25,34 +25,22 @@
//
// `DANGER_GITHUB_API_TOKEN=[ENV_ABOVE] yarn danger pr https://github.com/facebook/react/pull/11865
const {markdown, danger, warn} = require('danger');
const {markdown, danger} = require('danger');
const fetch = require('node-fetch');
const {generateResultsArray} = require('./scripts/rollup/stats');
const {existsSync, readFileSync} = require('fs');
const {exec} = require('child_process');
// This must match the name of the CI job that creates the build artifacts
const RELEASE_CHANNEL =
process.env.RELEASE_CHANNEL === 'experimental' ? 'experimental' : 'stable';
const artifactsJobName =
process.env.RELEASE_CHANNEL === 'experimental'
? 'process_artifacts_experimental'
: 'process_artifacts';
if (!existsSync('./build/bundle-sizes.json')) {
if (!existsSync('./scripts/rollup/results.json')) {
// This indicates the build failed previously.
// In that case, there's nothing for the Dangerfile to do.
// Exit early to avoid leaving a redundant (and potentially confusing) PR comment.
warn(
'No bundle size information found. This indicates the build ' +
'job failed.'
);
process.exit(0);
}
const currentBuildResults = JSON.parse(
readFileSync('./build/bundle-sizes.json')
readFileSync('./scripts/rollup/results.json')
);
/**
@@ -120,75 +108,18 @@ function git(args) {
// Use git locally to grab the commit which represents the place
// where the branches differ
const upstreamRepo = danger.github.pr.base.repo.full_name;
if (upstreamRepo !== 'facebook/react') {
// Exit unless we're running in the main repo
return;
}
markdown(`## Size changes (${RELEASE_CHANNEL})`);
const upstreamRef = danger.github.pr.base.ref;
await git(`remote add upstream https://github.com/facebook/react.git`);
await git(`remote add upstream https://github.com/${upstreamRepo}.git`);
await git('fetch upstream');
const baseCommit = await git(`merge-base HEAD upstream/${upstreamRef}`);
const mergeBaseCommit = await git(`merge-base HEAD upstream/${upstreamRef}`);
let previousBuildResults = null;
try {
let baseCIBuildId = null;
const statusesResponse = await fetch(
`https://api.github.com/repos/facebook/react/commits/${baseCommit}/status`
);
const {statuses, state} = await statusesResponse.json();
if (state === 'failure') {
warn(`Base commit is broken: ${baseCommit}`);
return;
}
for (let i = 0; i < statuses.length; i++) {
const status = statuses[i];
if (status.context === `ci/circleci: ${artifactsJobName}`) {
if (status.state === 'success') {
baseCIBuildId = /\/facebook\/react\/([0-9]+)/.exec(
status.target_url
)[1];
break;
}
if (status.state === 'pending') {
warn(`Build job for base commit is still pending: ${baseCommit}`);
return;
}
}
}
if (baseCIBuildId === null) {
warn(`Could not find build artifacts for base commit: ${baseCommit}`);
return;
}
const baseArtifactsInfoResponse = await fetch(
`https://circleci.com/api/v1.1/project/github/facebook/react/${baseCIBuildId}/artifacts`
);
const baseArtifactsInfo = await baseArtifactsInfoResponse.json();
for (let i = 0; i < baseArtifactsInfo.length; i++) {
const info = baseArtifactsInfo[i];
if (info.path === 'home/circleci/project/build/bundle-sizes.json') {
const resultsResponse = await fetch(info.url);
previousBuildResults = await resultsResponse.json();
break;
}
}
} catch (error) {
warn(`Failed to fetch build artifacts for base commit: ${baseCommit}`);
return;
}
if (previousBuildResults === null) {
warn(`Could not find build artifacts for base commit: ${baseCommit}`);
return;
}
const commitURL = sha =>
`http://react.zpao.com/builds/master/_commits/${sha}/results.json`;
const response = await fetch(commitURL(mergeBaseCommit));
// Take the JSON of the build response and
// make an array comparing the results for printing
const previousBuildResults = await response.json();
const results = generateResultsArray(
currentBuildResults,
previousBuildResults
@@ -281,7 +212,7 @@ function git(args) {
<details>
<summary>Details of bundled changes.</summary>
<p>Comparing: ${baseCommit}...${danger.github.pr.head.sha}</p>
<p>Comparing: ${mergeBaseCommit}...${danger.github.pr.head.sha}</p>
${allTables.join('\n')}
@@ -289,7 +220,5 @@ function git(args) {
</details>
`;
markdown(summary);
} else {
markdown('No significant bundle size changes to report.');
}
})();

View File

@@ -448,11 +448,6 @@ const attributes = [
read: getSVGAttribute('direction'),
},
{name: 'disabled', tagName: 'input'},
{
name: 'disablePictureInPicture',
tagName: 'video',
read: getProperty('disablepictureinpicture'),
},
{
name: 'display',
tagName: 'svg',

View File

@@ -1,38 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>React 14.9</title>
<link rel="stylesheet" href="styles.css" />
<script type="text/javascript">
// Enable DevTools to inspect React inside of an <iframe>
// This must run before React is loaded
__REACT_DEVTOOLS_GLOBAL_HOOK__ = parent.__REACT_DEVTOOLS_GLOBAL_HOOK__;
</script>
<script src="https://unpkg.com/react@0.14.9/dist/react.js"></script>
<script src="https://unpkg.com/react-dom@0.14.9/dist/react-dom.js"></script>
<!-- Don't use this in production: -->
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</head>
<body>
<div id="root">
If you are seeing this message, you are likely viewing this file using the <code>file</code> protocol which does not support cross origin requests.
<br/><br/>
Use the <code>server</code> script instead:
<br/><br/>
<code>node ./fixtures/devtools/regression/server.js</code><br/>
<code>open <a href="http://localhost:3000/14.9.html">http://localhost:3000/14.9.html</a></code>
</div>
<script src="shared.js" type="text/babel"></script>
<!--
This is a great way to try React but it's not suitable for production.
It slowly compiles JSX with Babel in the browser and uses a large development build of React.
Learn more at https://reactjs.org/docs/getting-started.html
-->
</body>
</html>

View File

@@ -1,38 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>React 15.0</title>
<link rel="stylesheet" href="styles.css" />
<script type="text/javascript">
// Enable DevTools to inspect React inside of an <iframe>
// This must run before React is loaded
__REACT_DEVTOOLS_GLOBAL_HOOK__ = parent.__REACT_DEVTOOLS_GLOBAL_HOOK__;
</script>
<script src="https://unpkg.com/react@15.0/dist/react.js"></script>
<script src="https://unpkg.com/react-dom@15.0/dist/react-dom.js"></script>
<!-- Don't use this in production: -->
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</head>
<body>
<div id="root">
If you are seeing this message, you are likely viewing this file using the <code>file</code> protocol which does not support cross origin requests.
<br/><br/>
Use the <code>server</code> script instead:
<br/><br/>
<code>node ./fixtures/devtools/regression/server.js</code><br/>
<code>open <a href="http://localhost:3000/15.0.html">http://localhost:3000/15.0.html</a></code>
</div>
<script src="shared.js" type="text/babel"></script>
<!--
This is a great way to try React but it's not suitable for production.
It slowly compiles JSX with Babel in the browser and uses a large development build of React.
Learn more at https://reactjs.org/docs/getting-started.html
-->
</body>
</html>

View File

@@ -1,38 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>React 15.1</title>
<link rel="stylesheet" href="styles.css" />
<script type="text/javascript">
// Enable DevTools to inspect React inside of an <iframe>
// This must run before React is loaded
__REACT_DEVTOOLS_GLOBAL_HOOK__ = parent.__REACT_DEVTOOLS_GLOBAL_HOOK__;
</script>
<script src="https://unpkg.com/react@15.1/dist/react.js"></script>
<script src="https://unpkg.com/react-dom@15.1/dist/react-dom.js"></script>
<!-- Don't use this in production: -->
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</head>
<body>
<div id="root">
If you are seeing this message, you are likely viewing this file using the <code>file</code> protocol which does not support cross origin requests.
<br/><br/>
Use the <code>server</code> script instead:
<br/><br/>
<code>node ./fixtures/devtools/regression/server.js</code><br/>
<code>open <a href="http://localhost:3000/15.1.html">http://localhost:3000/15.1.html</a></code>
</div>
<script src="shared.js" type="text/babel"></script>
<!--
This is a great way to try React but it's not suitable for production.
It slowly compiles JSX with Babel in the browser and uses a large development build of React.
Learn more at https://reactjs.org/docs/getting-started.html
-->
</body>
</html>

View File

@@ -1,38 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>React 15.2</title>
<link rel="stylesheet" href="styles.css" />
<script type="text/javascript">
// Enable DevTools to inspect React inside of an <iframe>
// This must run before React is loaded
__REACT_DEVTOOLS_GLOBAL_HOOK__ = parent.__REACT_DEVTOOLS_GLOBAL_HOOK__;
</script>
<script src="https://unpkg.com/react@15.2/dist/react.js"></script>
<script src="https://unpkg.com/react-dom@15.2/dist/react-dom.js"></script>
<!-- Don't use this in production: -->
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</head>
<body>
<div id="root">
If you are seeing this message, you are likely viewing this file using the <code>file</code> protocol which does not support cross origin requests.
<br/><br/>
Use the <code>server</code> script instead:
<br/><br/>
<code>node ./fixtures/devtools/regression/server.js</code><br/>
<code>open <a href="http://localhost:3000/15.2.html">http://localhost:3000/15.2.html</a></code>
</div>
<script src="shared.js" type="text/babel"></script>
<!--
This is a great way to try React but it's not suitable for production.
It slowly compiles JSX with Babel in the browser and uses a large development build of React.
Learn more at https://reactjs.org/docs/getting-started.html
-->
</body>
</html>

View File

@@ -1,38 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>React 15.3</title>
<link rel="stylesheet" href="styles.css" />
<script type="text/javascript">
// Enable DevTools to inspect React inside of an <iframe>
// This must run before React is loaded
__REACT_DEVTOOLS_GLOBAL_HOOK__ = parent.__REACT_DEVTOOLS_GLOBAL_HOOK__;
</script>
<script src="https://unpkg.com/react@15.3/dist/react.js"></script>
<script src="https://unpkg.com/react-dom@15.3/dist/react-dom.js"></script>
<!-- Don't use this in production: -->
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</head>
<body>
<div id="root">
If you are seeing this message, you are likely viewing this file using the <code>file</code> protocol which does not support cross origin requests.
<br/><br/>
Use the <code>server</code> script instead:
<br/><br/>
<code>node ./fixtures/devtools/regression/server.js</code><br/>
<code>open <a href="http://localhost:3000/15.3.html">http://localhost:3000/15.3.html</a></code>
</div>
<script src="shared.js" type="text/babel"></script>
<!--
This is a great way to try React but it's not suitable for production.
It slowly compiles JSX with Babel in the browser and uses a large development build of React.
Learn more at https://reactjs.org/docs/getting-started.html
-->
</body>
</html>

View File

@@ -1,38 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>React 15.4</title>
<link rel="stylesheet" href="styles.css" />
<script type="text/javascript">
// Enable DevTools to inspect React inside of an <iframe>
// This must run before React is loaded
__REACT_DEVTOOLS_GLOBAL_HOOK__ = parent.__REACT_DEVTOOLS_GLOBAL_HOOK__;
</script>
<script src="https://unpkg.com/react@15.4/dist/react.js"></script>
<script src="https://unpkg.com/react-dom@15.4/dist/react-dom.js"></script>
<!-- Don't use this in production: -->
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</head>
<body>
<div id="root">
If you are seeing this message, you are likely viewing this file using the <code>file</code> protocol which does not support cross origin requests.
<br/><br/>
Use the <code>server</code> script instead:
<br/><br/>
<code>node ./fixtures/devtools/regression/server.js</code><br/>
<code>open <a href="http://localhost:3000/15.4.html">http://localhost:3000/15.4.html</a></code>
</div>
<script src="shared.js" type="text/babel"></script>
<!--
This is a great way to try React but it's not suitable for production.
It slowly compiles JSX with Babel in the browser and uses a large development build of React.
Learn more at https://reactjs.org/docs/getting-started.html
-->
</body>
</html>

View File

@@ -1,38 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>React 15.5</title>
<link rel="stylesheet" href="styles.css" />
<script type="text/javascript">
// Enable DevTools to inspect React inside of an <iframe>
// This must run before React is loaded
__REACT_DEVTOOLS_GLOBAL_HOOK__ = parent.__REACT_DEVTOOLS_GLOBAL_HOOK__;
</script>
<script src="https://unpkg.com/react@15.5/dist/react.js"></script>
<script src="https://unpkg.com/react-dom@15.5/dist/react-dom.js"></script>
<!-- Don't use this in production: -->
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</head>
<body>
<div id="root">
If you are seeing this message, you are likely viewing this file using the <code>file</code> protocol which does not support cross origin requests.
<br/><br/>
Use the <code>server</code> script instead:
<br/><br/>
<code>node ./fixtures/devtools/regression/server.js</code><br/>
<code>open <a href="http://localhost:3000/15.5.html">http://localhost:3000/15.5.html</a></code>
</div>
<script src="shared.js" type="text/babel"></script>
<!--
This is a great way to try React but it's not suitable for production.
It slowly compiles JSX with Babel in the browser and uses a large development build of React.
Learn more at https://reactjs.org/docs/getting-started.html
-->
</body>
</html>

View File

@@ -1,38 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>React 15.6</title>
<link rel="stylesheet" href="styles.css" />
<script type="text/javascript">
// Enable DevTools to inspect React inside of an <iframe>
// This must run before React is loaded
__REACT_DEVTOOLS_GLOBAL_HOOK__ = parent.__REACT_DEVTOOLS_GLOBAL_HOOK__;
</script>
<script src="https://unpkg.com/react@15.6/dist/react.js"></script>
<script src="https://unpkg.com/react-dom@15.6/dist/react-dom.js"></script>
<!-- Don't use this in production: -->
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</head>
<body>
<div id="root">
If you are seeing this message, you are likely viewing this file using the <code>file</code> protocol which does not support cross origin requests.
<br/><br/>
Use the <code>server</code> script instead:
<br/><br/>
<code>node ./fixtures/devtools/regression/server.js</code><br/>
<code>open <a href="http://localhost:3000/15.6.html">http://localhost:3000/15.6.html</a></code>
</div>
<script src="shared.js" type="text/babel"></script>
<!--
This is a great way to try React but it's not suitable for production.
It slowly compiles JSX with Babel in the browser and uses a large development build of React.
Learn more at https://reactjs.org/docs/getting-started.html
-->
</body>
</html>

View File

@@ -1,38 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>React 16.0</title>
<link rel="stylesheet" href="styles.css" />
<script type="text/javascript">
// Enable DevTools to inspect React inside of an <iframe>
// This must run before React is loaded
__REACT_DEVTOOLS_GLOBAL_HOOK__ = parent.__REACT_DEVTOOLS_GLOBAL_HOOK__;
</script>
<script src="https://unpkg.com/react@16.0/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16.0/umd/react-dom.development.js"></script>
<!-- Don't use this in production: -->
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</head>
<body>
<div id="root">
If you are seeing this message, you are likely viewing this file using the <code>file</code> protocol which does not support cross origin requests.
<br/><br/>
Use the <code>server</code> script instead:
<br/><br/>
<code>node ./fixtures/devtools/regression/server.js</code><br/>
<code>open <a href="http://localhost:3000/16.0.html">http://localhost:3000/16.0.html</a></code>
</div>
<script src="shared.js" type="text/babel"></script>
<!--
This is a great way to try React but it's not suitable for production.
It slowly compiles JSX with Babel in the browser and uses a large development build of React.
Learn more at https://reactjs.org/docs/getting-started.html
-->
</body>
</html>

View File

@@ -1,38 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>React 16.1</title>
<link rel="stylesheet" href="styles.css" />
<script type="text/javascript">
// Enable DevTools to inspect React inside of an <iframe>
// This must run before React is loaded
__REACT_DEVTOOLS_GLOBAL_HOOK__ = parent.__REACT_DEVTOOLS_GLOBAL_HOOK__;
</script>
<script src="https://unpkg.com/react@16.1/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16.1/umd/react-dom.development.js"></script>
<!-- Don't use this in production: -->
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</head>
<body>
<div id="root">
If you are seeing this message, you are likely viewing this file using the <code>file</code> protocol which does not support cross origin requests.
<br/><br/>
Use the <code>server</code> script instead:
<br/><br/>
<code>node ./fixtures/devtools/regression/server.js</code><br/>
<code>open <a href="http://localhost:3000/16.1.html">http://localhost:3000/16.1.html</a></code>
</div>
<script src="shared.js" type="text/babel"></script>
<!--
This is a great way to try React but it's not suitable for production.
It slowly compiles JSX with Babel in the browser and uses a large development build of React.
Learn more at https://reactjs.org/docs/getting-started.html
-->
</body>
</html>

View File

@@ -1,38 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>React 16.2</title>
<link rel="stylesheet" href="styles.css" />
<script type="text/javascript">
// Enable DevTools to inspect React inside of an <iframe>
// This must run before React is loaded
__REACT_DEVTOOLS_GLOBAL_HOOK__ = parent.__REACT_DEVTOOLS_GLOBAL_HOOK__;
</script>
<script src="https://unpkg.com/react@16.2/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16.2/umd/react-dom.development.js"></script>
<!-- Don't use this in production: -->
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</head>
<body>
<div id="root">
If you are seeing this message, you are likely viewing this file using the <code>file</code> protocol which does not support cross origin requests.
<br/><br/>
Use the <code>server</code> script instead:
<br/><br/>
<code>node ./fixtures/devtools/regression/server.js</code><br/>
<code>open <a href="http://localhost:3000/16.2.html">http://localhost:3000/16.2.html</a></code>
</div>
<script src="shared.js" type="text/babel"></script>
<!--
This is a great way to try React but it's not suitable for production.
It slowly compiles JSX with Babel in the browser and uses a large development build of React.
Learn more at https://reactjs.org/docs/getting-started.html
-->
</body>
</html>

View File

@@ -1,38 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>React 16.3</title>
<link rel="stylesheet" href="styles.css" />
<script type="text/javascript">
// Enable DevTools to inspect React inside of an <iframe>
// This must run before React is loaded
__REACT_DEVTOOLS_GLOBAL_HOOK__ = parent.__REACT_DEVTOOLS_GLOBAL_HOOK__;
</script>
<script src="https://unpkg.com/react@16.3/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16.3/umd/react-dom.development.js"></script>
<!-- Don't use this in production: -->
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</head>
<body>
<div id="root">
If you are seeing this message, you are likely viewing this file using the <code>file</code> protocol which does not support cross origin requests.
<br/><br/>
Use the <code>server</code> script instead:
<br/><br/>
<code>node ./fixtures/devtools/regression/server.js</code><br/>
<code>open <a href="http://localhost:3000/16.3.html">http://localhost:3000/16.3.html</a></code>
</div>
<script src="shared.js" type="text/babel"></script>
<!--
This is a great way to try React but it's not suitable for production.
It slowly compiles JSX with Babel in the browser and uses a large development build of React.
Learn more at https://reactjs.org/docs/getting-started.html
-->
</body>
</html>

View File

@@ -1,38 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>React 16.4</title>
<link rel="stylesheet" href="styles.css" />
<script type="text/javascript">
// Enable DevTools to inspect React inside of an <iframe>
// This must run before React is loaded
__REACT_DEVTOOLS_GLOBAL_HOOK__ = parent.__REACT_DEVTOOLS_GLOBAL_HOOK__;
</script>
<script src="https://unpkg.com/react@16.4/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16.4/umd/react-dom.development.js"></script>
<!-- Don't use this in production: -->
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</head>
<body>
<div id="root">
If you are seeing this message, you are likely viewing this file using the <code>file</code> protocol which does not support cross origin requests.
<br/><br/>
Use the <code>server</code> script instead:
<br/><br/>
<code>node ./fixtures/devtools/regression/server.js</code><br/>
<code>open <a href="http://localhost:3000/16.4.html">http://localhost:3000/16.4.html</a></code>
</div>
<script src="shared.js" type="text/babel"></script>
<!--
This is a great way to try React but it's not suitable for production.
It slowly compiles JSX with Babel in the browser and uses a large development build of React.
Learn more at https://reactjs.org/docs/getting-started.html
-->
</body>
</html>

View File

@@ -1,40 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>React 16.5</title>
<link rel="stylesheet" href="styles.css" />
<script type="text/javascript">
// Enable DevTools to inspect React inside of an <iframe>
// This must run before React is loaded
__REACT_DEVTOOLS_GLOBAL_HOOK__ = parent.__REACT_DEVTOOLS_GLOBAL_HOOK__;
</script>
<script src="https://unpkg.com/schedule@0.5.0/umd/schedule.development.js"></script>
<script src="https://unpkg.com/schedule@0.5.0/umd/schedule-tracing.development.js"></script>
<script src="https://unpkg.com/react@16.5/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16.5/umd/react-dom.development.js"></script>
<!-- Don't use this in production: -->
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</head>
<body>
<div id="root">
If you are seeing this message, you are likely viewing this file using the <code>file</code> protocol which does not support cross origin requests.
<br/><br/>
Use the <code>server</code> script instead:
<br/><br/>
<code>node ./fixtures/devtools/regression/server.js</code><br/>
<code>open <a href="http://localhost:3000/16.5.html">http://localhost:3000/16.5.html</a></code>
</div>
<script src="shared.js" type="text/babel"></script>
<!--
This is a great way to try React but it's not suitable for production.
It slowly compiles JSX with Babel in the browser and uses a large development build of React.
Learn more at https://reactjs.org/docs/getting-started.html
-->
</body>
</html>

View File

@@ -1,41 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>React 16.6</title>
<link rel="stylesheet" href="styles.css" />
<script type="text/javascript">
// Enable DevTools to inspect React inside of an <iframe>
// This must run before React is loaded
__REACT_DEVTOOLS_GLOBAL_HOOK__ = parent.__REACT_DEVTOOLS_GLOBAL_HOOK__;
</script>
<script src="https://unpkg.com/scheduler@0.10.0/umd/scheduler.development.js"></script>
<script src="https://unpkg.com/scheduler@0.10.0/umd/scheduler-tracing.development.js"></script>
<script src="https://unpkg.com/react@16.6/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16.6/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/react-cache@2.0.0-alpha.1/umd/react-cache.development.js"></script>
<!-- Don't use this in production: -->
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</head>
<body>
<div id="root">
If you are seeing this message, you are likely viewing this file using the <code>file</code> protocol which does not support cross origin requests.
<br/><br/>
Use the <code>server</code> script instead:
<br/><br/>
<code>node ./fixtures/devtools/regression/server.js</code><br/>
<code>open <a href="http://localhost:3000/16.6.html">http://localhost:3000/16.6.html</a></code>
</div>
<script src="shared.js" type="text/babel"></script>
<!--
This is a great way to try React but it's not suitable for production.
It slowly compiles JSX with Babel in the browser and uses a large development build of React.
Learn more at https://reactjs.org/docs/getting-started.html
-->
</body>
</html>

View File

@@ -1,41 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>React 16.7</title>
<link rel="stylesheet" href="styles.css" />
<script type="text/javascript">
// Enable DevTools to inspect React inside of an <iframe>
// This must run before React is loaded
__REACT_DEVTOOLS_GLOBAL_HOOK__ = parent.__REACT_DEVTOOLS_GLOBAL_HOOK__;
</script>
<script src="https://unpkg.com/scheduler@0.12.0/umd/scheduler.development.js"></script>
<script src="https://unpkg.com/scheduler@0.12.0/umd/scheduler-tracing.development.js"></script>
<script src="https://unpkg.com/react@16.7/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16.7/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/react-cache@2.0.0-alpha.1/umd/react-cache.development.js"></script>
<!-- Don't use this in production: -->
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</head>
<body>
<div id="root">
If you are seeing this message, you are likely viewing this file using the <code>file</code> protocol which does not support cross origin requests.
<br/><br/>
Use the <code>server</code> script instead:
<br/><br/>
<code>node ./fixtures/devtools/regression/server.js</code><br/>
<code>open <a href="http://localhost:3000/16.7.html">http://localhost:3000/16.7.html</a></code>
</div>
<script src="shared.js" type="text/babel"></script>
<!--
This is a great way to try React but it's not suitable for production.
It slowly compiles JSX with Babel in the browser and uses a large development build of React.
Learn more at https://reactjs.org/docs/getting-started.html
-->
</body>
</html>

View File

@@ -1,41 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>React canary</title>
<link rel="stylesheet" href="styles.css" />
<script type="text/javascript">
// Enable DevTools to inspect React inside of an <iframe>
// This must run before React is loaded
__REACT_DEVTOOLS_GLOBAL_HOOK__ = parent.__REACT_DEVTOOLS_GLOBAL_HOOK__;
</script>
<script src="https://unpkg.com/scheduler@canary/umd/scheduler.development.js"></script>
<script src="https://unpkg.com/scheduler@canary/umd/scheduler-tracing.development.js"></script>
<script src="https://unpkg.com/react@canary/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@canary/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/react-cache@next/umd/react-cache.development.js"></script>
<!-- Don't use this in production: -->
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</head>
<body>
<div id="root">
If you are seeing this message, you are likely viewing this file using the <code>file</code> protocol which does not support cross origin requests.
<br/><br/>
Use the <code>server</code> script instead:
<br/><br/>
<code>node ./fixtures/devtools/regression/server.js</code><br/>
<code>open <a href="http://localhost:3000/canary.html">http://localhost:3000/canary.html</a></code>
</div>
<script src="shared.js" type="text/babel"></script>
<!--
This is a great way to try React but it's not suitable for production.
It slowly compiles JSX with Babel in the browser and uses a large development build of React.
Learn more at https://reactjs.org/docs/getting-started.html
-->
</body>
</html>

View File

@@ -1,28 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>React DevTools regression test</title>
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<iframe src="canary.html"></iframe>
<iframe src="next.html"></iframe>
<iframe src="16.7.html"></iframe>
<iframe src="16.6.html"></iframe>
<iframe src="16.5.html"></iframe>
<iframe src="16.4.html"></iframe>
<iframe src="16.3.html"></iframe>
<iframe src="16.2.html"></iframe>
<iframe src="16.1.html"></iframe>
<iframe src="16.0.html"></iframe>
<iframe src="15.6.html"></iframe>
<iframe src="15.5.html"></iframe>
<iframe src="15.4.html"></iframe>
<iframe src="15.3.html"></iframe>
<iframe src="15.2.html"></iframe>
<iframe src="15.1.html"></iframe>
<iframe src="15.0.html"></iframe>
<iframe src="14.9.html"></iframe>
</body>
</html>

View File

@@ -1,41 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>React next</title>
<link rel="stylesheet" href="styles.css" />
<script type="text/javascript">
// Enable DevTools to inspect React inside of an <iframe>
// This must run before React is loaded
__REACT_DEVTOOLS_GLOBAL_HOOK__ = parent.__REACT_DEVTOOLS_GLOBAL_HOOK__;
</script>
<script src="https://unpkg.com/scheduler@next/umd/scheduler.development.js"></script>
<script src="https://unpkg.com/scheduler@next/umd/scheduler-tracing.development.js"></script>
<script src="https://unpkg.com/react@next/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@next/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/react-cache@next/umd/react-cache.development.js"></script>
<!-- Don't use this in production: -->
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</head>
<body>
<div id="root">
If you are seeing this message, you are likely viewing this file using the <code>file</code> protocol which does not support cross origin requests.
<br/><br/>
Use the <code>server</code> script instead:
<br/><br/>
<code>node ./fixtures/devtools/regression/server.js</code><br/>
<code>open <a href="http://localhost:3000/next.html">http://localhost:3000/next.html</a></code>
</div>
<script src="shared.js" type="text/babel"></script>
<!--
This is a great way to try React but it's not suitable for production.
It slowly compiles JSX with Babel in the browser and uses a large development build of React.
Learn more at https://reactjs.org/docs/getting-started.html
-->
</body>
</html>

View File

@@ -1,16 +0,0 @@
#!/usr/bin/env node
const finalhandler = require('finalhandler');
const http = require('http');
const serveStatic = require('serve-static');
// Serve fixtures folder
const serve = serveStatic(__dirname, {index: 'index.html'});
// Create server
const server = http.createServer(function onRequest(req, res) {
serve(req, res, finalhandler(req, res));
});
// Listen
server.listen(3000);

View File

@@ -1,328 +0,0 @@
/* eslint-disable no-fallthrough, react/react-in-jsx-scope, react/jsx-no-undef */
/* global React ReactCache ReactDOM SchedulerTracing ScheduleTracing */
const apps = [];
const pieces = React.version.split('.');
const major =
pieces[0] === '0' ? parseInt(pieces[1], 10) : parseInt(pieces[0], 10);
const minor =
pieces[0] === '0' ? parseInt(pieces[2], 10) : parseInt(pieces[1], 10);
// Convenience wrapper to organize API features in DevTools.
function Feature({children, label, version}) {
return (
<div className="Feature">
<div className="FeatureHeader">
<code className="FeatureCode">{label}</code>
<small>{version}</small>
</div>
{children}
</div>
);
}
// Simplify interaction tracing for tests below.
let trace = null;
if (typeof SchedulerTracing !== 'undefined') {
trace = SchedulerTracing.unstable_trace;
} else if (typeof ScheduleTracing !== 'undefined') {
trace = ScheduleTracing.unstable_trace;
} else {
trace = (_, __, callback) => callback();
}
// https://github.com/facebook/react/blob/master/CHANGELOG.md
switch (major) {
case 16:
switch (minor) {
case 7:
if (typeof React.useState === 'function') {
// Hooks
function Hooks() {
const [count, setCount] = React.useState(0);
const incrementCount = React.useCallback(
() => setCount(count + 1),
[count]
);
return (
<div>
count: {count}{' '}
<button onClick={incrementCount}>increment</button>
</div>
);
}
apps.push(
<Feature key="Hooks" label="Hooks" version="16.7+">
<Hooks />
</Feature>
);
}
case 6:
// memo
function LabelComponent({label}) {
return <label>{label}</label>;
}
const AnonymousMemoized = React.memo(({label}) => (
<label>{label}</label>
));
const Memoized = React.memo(LabelComponent);
const CustomMemoized = React.memo(LabelComponent);
CustomMemoized.displayName = 'MemoizedLabelFunction';
apps.push(
<Feature key="memo" label="memo" version="16.6+">
<AnonymousMemoized label="AnonymousMemoized" />
<Memoized label="Memoized" />
<CustomMemoized label="CustomMemoized" />
</Feature>
);
// Suspense
const loadResource = ([text, ms]) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(text);
}, ms);
});
};
const getResourceKey = ([text, ms]) => text;
const Resource = ReactCache.unstable_createResource(
loadResource,
getResourceKey
);
class Suspending extends React.Component {
state = {useSuspense: false};
useSuspense = () => this.setState({useSuspense: true});
render() {
if (this.state.useSuspense) {
const text = Resource.read(['loaded', 2000]);
return text;
} else {
return <button onClick={this.useSuspense}>load data</button>;
}
}
}
apps.push(
<Feature key="Suspense" label="Suspense" version="16.6+">
<React.Suspense fallback={<div>loading...</div>}>
<Suspending />
</React.Suspense>
</Feature>
);
// lazy
const LazyWithDefaultProps = React.lazy(
() =>
new Promise(resolve => {
function FooWithDefaultProps(props) {
return (
<h1>
{props.greeting}, {props.name}
</h1>
);
}
FooWithDefaultProps.defaultProps = {
name: 'World',
greeting: 'Bonjour',
};
resolve({
default: FooWithDefaultProps,
});
})
);
apps.push(
<Feature key="lazy" label="lazy" version="16.6+">
<React.Suspense fallback={<div>loading...</div>}>
<LazyWithDefaultProps greeting="Hello" />
</React.Suspense>
</Feature>
);
case 5:
case 4:
// unstable_Profiler
class ProfilerChild extends React.Component {
state = {count: 0};
incrementCount = () =>
this.setState(prevState => ({count: prevState.count + 1}));
render() {
return (
<div>
count: {this.state.count}{' '}
<button onClick={this.incrementCount}>increment</button>
</div>
);
}
}
const onRender = (...args) => {};
const Profiler = React.unstable_Profiler || React.Profiler;
apps.push(
<Feature
key="unstable_Profiler"
label="unstable_Profiler"
version="16.4+">
<Profiler id="count" onRender={onRender}>
<div>
<ProfilerChild />
</div>
</Profiler>
</Feature>
);
case 3:
// createContext()
const LocaleContext = React.createContext();
LocaleContext.displayName = 'LocaleContext';
const ThemeContext = React.createContext();
apps.push(
<Feature key="createContext" label="createContext" version="16.3+">
<ThemeContext.Provider value="blue">
<ThemeContext.Consumer>
{theme => <div>theme: {theme}</div>}
</ThemeContext.Consumer>
</ThemeContext.Provider>
<LocaleContext.Provider value="en-US">
<LocaleContext.Consumer>
{locale => <div>locale: {locale}</div>}
</LocaleContext.Consumer>
</LocaleContext.Provider>
</Feature>
);
// forwardRef()
const AnonymousFunction = React.forwardRef((props, ref) => (
<div ref={ref}>{props.children}</div>
));
const NamedFunction = React.forwardRef(function named(props, ref) {
return <div ref={ref}>{props.children}</div>;
});
const CustomName = React.forwardRef((props, ref) => (
<div ref={ref}>{props.children}</div>
));
CustomName.displayName = 'CustomNameForwardRef';
apps.push(
<Feature key="forwardRef" label="forwardRef" version="16.3+">
<AnonymousFunction>AnonymousFunction</AnonymousFunction>
<NamedFunction>NamedFunction</NamedFunction>
<CustomName>CustomName</CustomName>
</Feature>
);
// StrictMode
class StrictModeChild extends React.Component {
render() {
return 'StrictModeChild';
}
}
apps.push(
<Feature key="StrictMode" label="StrictMode" version="16.3+">
<React.StrictMode>
<StrictModeChild />
</React.StrictMode>
</Feature>
);
// unstable_AsyncMode (later renamed to unstable_ConcurrentMode, then ConcurrentMode)
const ConcurrentMode =
React.ConcurrentMode ||
React.unstable_ConcurrentMode ||
React.unstable_AsyncMode;
apps.push(
<Feature
key="AsyncMode/ConcurrentMode"
label="AsyncMode/ConcurrentMode"
version="16.3+">
<ConcurrentMode>
<div>
unstable_AsyncMode was added in 16.3, renamed to
unstable_ConcurrentMode in 16.5, and then renamed to
ConcurrentMode in 16.7
</div>
</ConcurrentMode>
</Feature>
);
case 2:
// Fragment
apps.push(
<Feature key="Fragment" label="Fragment" version="16.4+">
<React.Fragment>
<div>one</div>
<div>two</div>
</React.Fragment>
</Feature>
);
case 1:
case 0:
default:
break;
}
break;
case 15:
break;
case 14:
break;
default:
break;
}
function Even() {
return <small>(even)</small>;
}
// Simple stateful app shared by all React versions
class SimpleApp extends React.Component {
state = {count: 0};
incrementCount = () => {
const updaterFn = prevState => ({count: prevState.count + 1});
trace('Updating count', performance.now(), () => this.setState(updaterFn));
};
render() {
const {count} = this.state;
return (
<div>
{count % 2 === 0 ? (
<span>
count: {count} <Even />
</span>
) : (
<span>count: {count}</span>
)}{' '}
<button onClick={this.incrementCount}>increment</button>
</div>
);
}
}
apps.push(
<Feature key="Simple stateful app" label="Simple stateful app" version="any">
<SimpleApp />
</Feature>
);
// This component, with the version prop, helps organize DevTools at a glance.
function TopLevelWrapperForDevTools({version}) {
let header = <h1>React {version}</h1>;
if (version.includes('canary')) {
const commitSha = version.match(/.+canary-(.+)/)[1];
header = (
<h1>
React canary{' '}
<a href={`https://github.com/facebook/react/commit/${commitSha}`}>
{commitSha}
</a>
</h1>
);
} else if (version.includes('alpha')) {
header = <h1>React next</h1>;
}
return (
<div>
{header}
{apps}
</div>
);
}
TopLevelWrapperForDevTools.displayName = 'React';
ReactDOM.render(
<TopLevelWrapperForDevTools version={React.version} />,
document.getElementById('root')
);

View File

@@ -1,37 +0,0 @@
body {
font-family: sans-serif;
font-size: 12px;
}
h1 {
margin: 0;
font-size: 20px;
}
h2 {
margin: 1rem 0 0;
}
iframe {
border: 1px solid #ddd;
border-radius: 0.5rem;
}
code {
white-space: nowrap;
}
.Feature {
margin: 1rem 0;
border-bottom: 1px solid #eee;
padding-bottom: 1rem;
}
.FeatureHeader {
font-size: 16px;
margin-bottom: 0.5rem;
}
.FeatureCode {
background-color: #eee;
padding: 0.25rem;
border-radius: 0.25rem;
}

View File

@@ -1,313 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>TODO List</title>
<!-- DevTools -->
<script src="http://localhost:8097"></script>
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/immutable@4.0.0-rc.12/dist/immutable.js"></script>
<!-- Don't use this in production: -->
<script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script>
<style type="text/css">
.Input {
font-size: 1rem;
padding: 0.25rem;
}
.IconButton {
padding: 0.25rem;
border: none;
background: none;
cursor: pointer;
}
.List {
margin: 0.5rem 0 0;
padding: 0;
}
.ListItem {
list-style-type: none;
}
.Label {
cursor: pointer;
padding: 0.25rem;
color: #555;
}
.Label:hover {
color: #000;
}
.IconButton {
padding: 0.25rem;
border: none;
background: none;
cursor: pointer;
}
</style>
</head>
<body>
<div id="root"></div>
<script type="text/babel">
const { Fragment, useCallback, useState } = React;
function List(props) {
const [newItemText, setNewItemText] = useState("");
const [items, setItems] = useState([
{ id: 1, isComplete: true, text: "First" },
{ id: 2, isComplete: true, text: "Second" },
{ id: 3, isComplete: false, text: "Third" }
]);
const [uid, setUID] = useState(4);
const handleClick = useCallback(() => {
if (newItemText !== "") {
setItems([
...items,
{
id: uid,
isComplete: false,
text: newItemText
}
]);
setUID(uid + 1);
setNewItemText("");
}
}, [newItemText, items, uid]);
const handleKeyPress = useCallback(
event => {
if (event.key === "Enter") {
handleClick();
}
},
[handleClick]
);
const handleChange = useCallback(
event => {
setNewItemText(event.currentTarget.value);
},
[setNewItemText]
);
const removeItem = useCallback(
itemToRemove => setItems(items.filter(item => item !== itemToRemove)),
[items]
);
const toggleItem = useCallback(
itemToToggle => {
const index = items.indexOf(itemToToggle);
setItems(
items
.slice(0, index)
.concat({
...itemToToggle,
isComplete: !itemToToggle.isComplete
})
.concat(items.slice(index + 1))
);
},
[items]
);
return (
<Fragment>
<h1>List</h1>
<input
type="text"
placeholder="New list item..."
className="Input"
value={newItemText}
onChange={handleChange}
onKeyPress={handleKeyPress}
/>
<button
className="IconButton"
disabled={newItemText === ""}
onClick={handleClick}
>
<span role="img" aria-label="Add item">
</span>
</button>
<ul className="List">
{items.map(item => (
<ListItem
key={item.id}
item={item}
removeItem={removeItem}
toggleItem={toggleItem}
/>
))}
</ul>
</Fragment>
);
}
function ListItem({ item, removeItem, toggleItem }) {
const handleDelete = useCallback(() => {
removeItem(item);
}, [item, removeItem]);
const handleToggle = useCallback(() => {
toggleItem(item);
}, [item, toggleItem]);
return (
<li className="ListItem">
<button className="IconButton" onClick={handleDelete}>
🗑
</button>
<label className="Label">
<input
className="Input"
checked={item.isComplete}
onChange={handleToggle}
type="checkbox"
/>{" "}
{item.text}
</label>
</li>
);
}
function SimpleValues() {
return (
<ChildComponent
string="abc"
emptyString=""
number={123}
undefined={undefined}
null={null}
nan={NaN}
infinity={Infinity}
true={true}
false={false}
/>
);
}
class Custom {
_number = 42;
get number() {
return this._number;
}
}
function CustomObject() {
return <ChildComponent customObject={new Custom()} />;
}
const object = {
string: "abc",
longString: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKJLMNOPQRSTUVWXYZ1234567890",
emptyString: "",
number: 123,
boolean: true,
undefined: undefined,
null: null
};
function ObjectProps() {
return (
<ChildComponent
object={{
outer: {
inner: object
}
}}
array={["first", "second", "third"]}
objectInArray={[object]}
arrayInObject={{ array: ["first", "second", "third"] }}
deepObject={{
// Known limitation: we won't go deeper than several levels.
// In the future, we might offer a way to request deeper access on demand.
a: {
b: {
c: {
d: {
e: {
f: {
g: {
h: {
i: {
j: 10
}
}
}
}
}
}
}
}
}
}}
/>
);
}
const set = new Set(['abc', 123]);
const map = new Map([['name', 'Brian'], ['food', 'sushi']]);
const setOfSets = new Set([new Set(['a', 'b', 'c']), new Set([1, 2, 3])]);
const mapOfMaps = new Map([['first', map], ['second', map]]);
const typedArray = Int8Array.from([100, -100, 0]);
const immutable = Immutable.fromJS({
a: [{ hello: 'there' }, 'fixed', true],
b: 123,
c: {
'1': 'xyz',
xyz: 1,
},
});
function UnserializableProps() {
return (
<ChildComponent
map={map}
set={set}
mapOfMaps={mapOfMaps}
setOfSets={setOfSets}
typedArray={typedArray}
immutable={immutable}
/>
);
}
function ChildComponent(props: any) {
return null;
}
function InspectableElements() {
return (
<Fragment>
<SimpleValues />
<ObjectProps />
<UnserializableProps />
<CustomObject />
</Fragment>
);
}
function App() {
return (
<Fragment>
<List />
<InspectableElements />
</Fragment>
);
}
ReactDOM.render(<App />, document.getElementById("root"));
</script>
</body>
</html>

View File

@@ -8,16 +8,12 @@ coverage
# production
build
public/scheduler-unstable_mock.development.js
public/scheduler-unstable_mock.production.min.js
public/react.development.js
public/react.production.min.js
public/react-dom.development.js
public/react-dom.production.min.js
public/react-dom-server.browser.development.js
public/react-dom-server.browser.production.min.js
public/react-dom-test-utils.development.js
public/react-dom-test-utils.production.min.js
# misc
.DS_Store

View File

@@ -7,11 +7,9 @@
},
"dependencies": {
"@babel/standalone": "^7.0.0",
"art": "^0.10.3",
"classnames": "^2.2.5",
"codemirror": "^5.40.0",
"core-js": "^2.4.1",
"jest-diff": "^24.8.0",
"prop-types": "^15.6.0",
"query-string": "^4.2.3",
"react": "^15.4.1",
@@ -20,7 +18,7 @@
},
"scripts": {
"start": "react-scripts start",
"prestart": "cp ../../build/node_modules/scheduler/umd/scheduler-unstable_mock.development.js ../../build/node_modules/scheduler/umd/scheduler-unstable_mock.production.min.js ../../build/node_modules/react/umd/react.development.js ../../build/node_modules/react-dom/umd/react-dom.development.js ../../build/node_modules/react/umd/react.production.min.js ../../build/node_modules/react-dom/umd/react-dom.production.min.js ../../build/node_modules/react-dom/umd/react-dom-server.browser.development.js ../../build/node_modules/react-dom/umd/react-dom-server.browser.production.min.js ../../build/node_modules/react-dom/umd/react-dom-test-utils.development.js ../../build/node_modules/react-dom/umd/react-dom-test-utils.production.min.js public/ && cp -a ../../build/node_modules/. node_modules",
"prestart": "cp ../../build/node_modules/react/umd/react.development.js ../../build/node_modules/react-dom/umd/react-dom.development.js ../../build/node_modules/react/umd/react.production.min.js ../../build/node_modules/react-dom/umd/react-dom.production.min.js ../../build/node_modules/react-dom/umd/react-dom-server.browser.development.js ../../build/node_modules/react-dom/umd/react-dom-server.browser.production.min.js public/",
"build": "react-scripts build && cp build/index.html build/200.html",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject"

View File

@@ -1,44 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>sanity test for ReactTestUtils.act</title>
</head>
<body>
this page tests whether act runs properly in a browser.
<br />
your console should say "5"
<script src="scheduler-unstable_mock.development.js"></script>
<script src="react.development.js"></script>
<script type="text/javascript">
window.React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.Scheduler =
window.SchedulerMock;
</script>
<script src="react-dom.development.js"></script>
<script src="react-dom-test-utils.development.js"></script>
<script>
// from ReactTestUtilsAct-test.js
function App() {
let [state, setState] = React.useState(0);
async function ticker() {
await null;
setState(x => x + 1);
}
React.useEffect(() => {
ticker();
}, [Math.min(state, 4)]);
return state;
}
async function testAsyncAct() {
const el = document.createElement("div");
await ReactTestUtils.act(async () => {
ReactDOM.render(React.createElement(App), el);
});
// all 5 ticks present and accounted for
console.log(el.innerHTML);
}
testAsyncAct();
</script>
</body>
</html>

View File

@@ -13,30 +13,6 @@
var renders = 0;
var failed = false;
var needsReactDOM = getBooleanQueryParam('needsReactDOM');
var needsCreateElement = getBooleanQueryParam('needsCreateElement');
function unmountComponent(node) {
// ReactDOM was moved into a separate package in 0.14
if (needsReactDOM) {
ReactDOM.unmountComponentAtNode(node);
} else if (React.unmountComponentAtNode) {
React.unmountComponentAtNode(node);
} else {
// Unmounting for React 0.4 and lower
React.unmountAndReleaseReactRootNode(node);
}
}
function createElement(value) {
// React.createElement replaced function invocation in 0.12
if (needsCreateElement) {
return React.createElement(value);
} else {
return value();
}
}
function getQueryParam(key) {
var pattern = new RegExp(key + '=([^&]+)(&|$)');
var matches = window.location.search.match(pattern);
@@ -59,56 +35,20 @@
function prerender() {
setStatus('Generating markup');
return Promise.resolve()
.then(function() {
const element = createElement(Fixture);
output.innerHTML = ReactDOMServer.renderToString(
React.createElement(Fixture)
);
// Server rendering moved to a separate package along with ReactDOM
// in 0.14.0
if (needsReactDOM) {
return ReactDOMServer.renderToString(element);
}
// React.renderComponentToString was renamed in 0.12
if (React.renderToString) {
return React.renderToString(element);
}
// React.renderComponentToString became synchronous in React 0.9.0
if (React.renderComponentToString.length === 1) {
return React.renderComponentToString(element);
}
// Finally, React 0.4 and lower emits markup in a callback
return new Promise(function(resolve) {
React.renderComponentToString(element, resolve);
});
})
.then(function(string) {
output.innerHTML = string;
setStatus('Markup only (No React)');
})
.catch(handleError);
setStatus('Markup only (No React)');
}
function render() {
setStatus('Hydrating');
var element = createElement(Fixture);
// ReactDOM was split out into another package in 0.14
if (needsReactDOM) {
// Hydration changed to a separate method in React 16
if (ReactDOM.hydrate) {
ReactDOM.hydrate(element, output);
} else {
ReactDOM.render(element, output);
}
} else if (React.render) {
// React.renderComponent was renamed in 0.12
React.render(element, output);
if (ReactDOM.hydrate) {
ReactDOM.hydrate(React.createElement(Fixture), output);
} else {
React.renderComponent(element, output);
ReactDOM.render(React.createElement(Fixture), output);
}
setStatus(renders > 0 ? 'Re-rendered (' + renders + 'x)' : 'Hydrated');
@@ -145,17 +85,17 @@
setStatus('Failed');
output.innerHTML = 'Please name your root component "Fixture"';
} else {
prerender().then(function() {
if (getBooleanQueryParam('hydrate')) {
render();
}
});
prerender();
if (getBooleanQueryParam('hydrate')) {
render();
}
}
}
function reloadFixture(code) {
renders = 0;
unmountComponent(output);
ReactDOM.unmountComponentAtNode(output);
injectFixture(code);
}
@@ -169,12 +109,12 @@
loadScript(getQueryParam('reactPath'))
.then(function() {
if (needsReactDOM) {
return Promise.all([
loadScript(getQueryParam('reactDOMPath')),
loadScript(getQueryParam('reactDOMServerPath')),
]);
}
return getBooleanQueryParam('needsReactDOM')
? loadScript(getQueryParam('reactDOMPath'))
: null;
})
.then(function() {
return loadScript(getQueryParam('reactDOMServerPath'));
})
.then(function() {
if (failed) {

View File

@@ -1,97 +0,0 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @emails react-core
*/
let React;
let TestUtils;
let TestRenderer;
global.__DEV__ = process.env.NODE_ENV !== 'production';
expect.extend(require('../toWarnDev'));
describe('unmocked scheduler', () => {
beforeEach(() => {
jest.resetModules();
React = require('react');
TestUtils = require('react-dom/test-utils');
TestRenderer = require('react-test-renderer');
});
it('flushes work only outside the outermost act() corresponding to its own renderer', () => {
let log = [];
function Effecty() {
React.useEffect(() => {
log.push('called');
}, []);
return null;
}
// in legacy mode, this tests whether an act only flushes its own effects
TestRenderer.act(() => {
TestUtils.act(() => {
TestRenderer.create(<Effecty />);
});
expect(log).toEqual([]);
});
expect(log).toEqual(['called']);
log = [];
// for doublechecking, we flip it inside out, and assert on the outermost
TestUtils.act(() => {
TestRenderer.act(() => {
TestRenderer.create(<Effecty />);
});
expect(log).toEqual(['called']);
});
expect(log).toEqual(['called']);
});
});
describe('mocked scheduler', () => {
beforeEach(() => {
jest.resetModules();
jest.mock('scheduler', () =>
require.requireActual('scheduler/unstable_mock')
);
React = require('react');
TestUtils = require('react-dom/test-utils');
TestRenderer = require('react-test-renderer');
});
afterEach(() => {
jest.unmock('scheduler');
});
it('flushes work only outside the outermost act()', () => {
let log = [];
function Effecty() {
React.useEffect(() => {
log.push('called');
}, []);
return null;
}
// with a mocked scheduler, this tests whether it flushes all work only on the outermost act
TestRenderer.act(() => {
TestUtils.act(() => {
TestRenderer.create(<Effecty />);
});
expect(log).toEqual([]);
});
expect(log).toEqual(['called']);
log = [];
// for doublechecking, we flip it inside out, and assert on the outermost
TestUtils.act(() => {
TestRenderer.act(() => {
TestRenderer.create(<Effecty />);
});
expect(log).toEqual([]);
});
expect(log).toEqual(['called']);
});
});

View File

@@ -1,197 +0,0 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @emails react-core
*/
let React;
let ReactDOM;
let ReactART;
let ARTSVGMode;
let ARTCurrentMode;
let TestUtils;
let TestRenderer;
let ARTTest;
global.__DEV__ = process.env.NODE_ENV !== 'production';
global.__EXPERIMENTAL__ = process.env.RELEASE_CHANNEL === 'experimental';
expect.extend(require('../toWarnDev'));
function App(props) {
return 'hello world';
}
beforeEach(() => {
jest.resetModules();
React = require('react');
ReactDOM = require('react-dom');
ReactART = require('react-art');
ARTSVGMode = require('art/modes/svg');
ARTCurrentMode = require('art/modes/current');
TestUtils = require('react-dom/test-utils');
TestRenderer = require('react-test-renderer');
ARTCurrentMode.setCurrent(ARTSVGMode);
ARTTest = function ARTTestComponent(props) {
return (
<ReactART.Surface width={150} height={200}>
<ReactART.Group>
<ReactART.Shape
d="M0,0l50,0l0,50l-50,0z"
fill={new ReactART.LinearGradient(['black', 'white'])}
key="a"
width={50}
height={50}
x={50}
y={50}
opacity={0.1}
/>
<ReactART.Shape
fill="#3C5A99"
key="b"
scale={0.5}
x={50}
y={50}
title="This is an F"
cursor="pointer">
M64.564,38.583H54l0.008-5.834c0-3.035,0.293-4.666,4.657-4.666
h5.833V16.429h-9.33c-11.213,0-15.159,5.654-15.159,15.16v6.994
h-6.99v11.652h6.99v33.815H54V50.235h9.331L64.564,38.583z
</ReactART.Shape>
</ReactART.Group>
</ReactART.Surface>
);
};
});
it("doesn't warn when you use the right act + renderer: dom", () => {
TestUtils.act(() => {
TestUtils.renderIntoDocument(<App />);
});
});
it("doesn't warn when you use the right act + renderer: test", () => {
TestRenderer.act(() => {
TestRenderer.create(<App />);
});
});
it('resets correctly across renderers', () => {
function Effecty() {
React.useEffect(() => {}, []);
return null;
}
TestUtils.act(() => {
TestRenderer.act(() => {});
expect(() => {
TestRenderer.create(<Effecty />);
}).toWarnDev(["It looks like you're using the wrong act()"], {
withoutStack: true,
});
});
});
it('warns when using the wrong act version - test + dom: render', () => {
expect(() => {
TestRenderer.act(() => {
TestUtils.renderIntoDocument(<App />);
});
}).toWarnDev(["It looks like you're using the wrong act()"], {
withoutStack: true,
});
});
it('warns when using the wrong act version - test + dom: updates', () => {
let setCtr;
function Counter(props) {
const [ctr, _setCtr] = React.useState(0);
setCtr = _setCtr;
return ctr;
}
TestUtils.renderIntoDocument(<Counter />);
expect(() => {
TestRenderer.act(() => {
setCtr(1);
});
}).toWarnDev(["It looks like you're using the wrong act()"]);
});
it('warns when using the wrong act version - dom + test: .create()', () => {
expect(() => {
TestUtils.act(() => {
TestRenderer.create(<App />);
});
}).toWarnDev(["It looks like you're using the wrong act()"], {
withoutStack: true,
});
});
it('warns when using the wrong act version - dom + test: .update()', () => {
const root = TestRenderer.create(<App key="one" />);
expect(() => {
TestUtils.act(() => {
root.update(<App key="two" />);
});
}).toWarnDev(["It looks like you're using the wrong act()"], {
withoutStack: true,
});
});
it('warns when using the wrong act version - dom + test: updates', () => {
let setCtr;
function Counter(props) {
const [ctr, _setCtr] = React.useState(0);
setCtr = _setCtr;
return ctr;
}
TestRenderer.create(<Counter />);
expect(() => {
TestUtils.act(() => {
setCtr(1);
});
}).toWarnDev(["It looks like you're using the wrong act()"]);
});
it('does not warn when nesting react-act inside react-dom', () => {
TestUtils.act(() => {
TestUtils.renderIntoDocument(<ARTTest />);
});
});
it('does not warn when nesting react-act inside react-test-renderer', () => {
TestRenderer.act(() => {
TestRenderer.create(<ARTTest />);
});
});
it("doesn't warn if you use nested acts from different renderers", () => {
TestRenderer.act(() => {
TestUtils.act(() => {
TestRenderer.create(<App />);
});
});
});
if (__EXPERIMENTAL__) {
it('warns when using createRoot() + .render', () => {
const root = ReactDOM.createRoot(document.createElement('div'));
expect(() => {
TestRenderer.act(() => {
root.render(<App />);
});
}).toWarnDev(
[
'In Concurrent or Sync modes, the "scheduler" module needs to be mocked',
"It looks like you're using the wrong act()",
],
{
withoutStack: true,
}
);
});
}

View File

@@ -4,15 +4,13 @@ import '../style.css';
const React = window.React;
class App extends React.Component {
render() {
return (
<div>
<Header />
<Fixtures />
</div>
);
}
function App() {
return (
<div>
<Header />
<Fixtures />
</div>
);
}
export default App;

View File

@@ -1,6 +1,5 @@
import {parse, stringify} from 'query-string';
import VersionPicker from './VersionPicker';
import getVersionTags from '../tags';
const React = window.React;
class Header extends React.Component {
@@ -10,12 +9,18 @@ class Header extends React.Component {
const version = query.version || 'local';
const production = query.production || false;
const versions = [version];
this.state = {version, versions, production};
}
handleVersionChange(version) {
componentWillMount() {
getVersionTags().then(tags => {
let versions = tags.map(tag => tag.name.slice(1));
versions = [`local`, ...versions];
this.setState({versions});
});
}
handleVersionChange(event) {
const query = parse(window.location.search);
query.version = version;
query.version = event.target.value;
if (query.version === 'local') {
delete query.version;
}
@@ -43,10 +48,7 @@ class Header extends React.Component {
width="20"
height="20"
/>
<a href="/">
DOM Test Fixtures (v
{React.version})
</a>
<a href="/">DOM Test Fixtures (v{React.version})</a>
</span>
<div className="header-controls">
@@ -88,14 +90,17 @@ class Header extends React.Component {
<option value="/suspense">Suspense</option>
</select>
</label>
<label htmlFor="global_version">
<label htmlFor="react_version">
<span className="sr-only">Select a version to test</span>
<VersionPicker
id="global_version"
name="global_version"
version={this.state.version}
onChange={this.handleVersionChange}
/>
<select
value={this.state.version}
onChange={this.handleVersionChange}>
{this.state.versions.map(version => (
<option key={version} value={version}>
{version}
</option>
))}
</select>
</label>
</div>
</div>

View File

@@ -1,41 +0,0 @@
import getVersionTags from '../tags';
const React = window.React;
class VersionPicker extends React.Component {
constructor(props, context) {
super(props, context);
const version = props.version || 'local';
const versions = [version];
this.state = {versions};
}
componentWillMount() {
getVersionTags().then(tags => {
let versions = tags.map(tag => tag.name.slice(1));
versions = [`local`, ...versions];
this.setState({versions});
});
}
onChange = event => {
this.props.onChange(event.target.value);
};
render() {
const {version, id, name} = this.props;
const {versions} = this.state;
return (
<select id={id} name={name} value={version} onChange={this.onChange}>
{versions.map(version => (
<option key={version} value={version}>
{version}
</option>
))}
</select>
);
}
}
export default VersionPicker;

View File

@@ -1,5 +1,3 @@
import {findDOMNode} from '../../../find-dom-node';
const React = window.React;
export class CodeEditor extends React.Component {
@@ -8,8 +6,6 @@ export class CodeEditor extends React.Component {
}
componentDidMount() {
this.textarea = findDOMNode(this);
// Important: CodeMirror incorrectly lays out the editor
// if it executes before CSS has loaded
// https://github.com/graphql/graphiql/issues/33#issuecomment-318188555
@@ -48,6 +44,7 @@ export class CodeEditor extends React.Component {
render() {
return (
<textarea
ref={ref => (this.textarea = ref)}
defaultValue={this.props.code}
autoComplete="off"
hidden={true}
@@ -75,10 +72,6 @@ export class CodeError extends React.Component {
if (supportsDetails) {
const [summary, ...body] = error.message.split(/\n+/g);
if (body.length >= 0) {
return <div className={className}>{summary}</div>;
}
return (
<details className={className}>
<summary>{summary}</summary>

View File

@@ -22,7 +22,6 @@
.hydration-options label {
font-size: 13px;
margin-right: 10px;
}
.hydration-options input[type=checkbox] {
@@ -31,11 +30,6 @@
vertical-align: middle;
}
.hydration-options select {
margin-left: 10px;
max-width: 100px;
}
.hydration .CodeMirror {
font-size: 13px;
padding-top: 8px;

View File

@@ -1,5 +1,4 @@
import './hydration.css';
import VersionPicker from '../../VersionPicker';
import {SAMPLE_CODE} from './data';
import {CodeEditor, CodeError} from './Code';
import {compile} from './code-transformer';
@@ -7,17 +6,12 @@ import {reactPaths} from '../../../react-loader';
import qs from 'query-string';
const React = window.React;
// The Hydration fixture can render at a different version than the parent
// app. This allows rendering for versions of React older than the DOM
// test fixtures can support.
const initialVersion = qs.parse(window.location.search).version || 'local';
class Hydration extends React.Component {
state = {
error: null,
code: SAMPLE_CODE,
hydrate: true,
version: initialVersion,
};
ready = false;
@@ -78,14 +72,9 @@ class Hydration extends React.Component {
});
};
setVersion = version => {
this.setState({version});
};
render() {
const {code, error, hydrate, version} = this.state;
const src =
'/renderer.html?' + qs.stringify({hydrate, ...reactPaths(version)});
const {code, error, hydrate} = this.state;
const src = '/renderer.html?' + qs.stringify({hydrate, ...reactPaths()});
return (
<div className="hydration">
@@ -100,16 +89,6 @@ class Hydration extends React.Component {
/>
Auto-Hydrate
</label>
<label htmlFor="hydration_version">
Version:
<VersionPicker
id="hydration_version"
name="hyration_version"
version={version}
onChange={this.setVersion}
/>
</label>
</header>
<CodeEditor code={code} onChange={this.setCode} />

View File

@@ -1,6 +1,5 @@
import FixtureSet from '../../FixtureSet';
import MouseMovement from './mouse-movement';
import MouseEnter from './mouse-enter';
const React = window.React;
@@ -9,7 +8,6 @@ class MouseEvents extends React.Component {
return (
<FixtureSet title="Mouse Events">
<MouseMovement />
<MouseEnter />
</FixtureSet>
);
}

View File

@@ -1,73 +0,0 @@
import TestCase from '../../TestCase';
const React = window.React;
const ReactDOM = window.ReactDOM;
const MouseEnter = () => {
const containerRef = React.useRef();
React.useEffect(function() {
const hostEl = containerRef.current;
ReactDOM.render(<MouseEnterDetect />, hostEl, () => {
ReactDOM.render(<MouseEnterDetect />, hostEl.childNodes[1]);
});
}, []);
return (
<TestCase
title="Mouse Enter"
description=""
affectedBrowsers="Chrome, Safari, Firefox">
<TestCase.Steps>
<li>Mouse enter the boxes below, from different borders</li>
</TestCase.Steps>
<TestCase.ExpectedResult>
Mouse enter call count should equal to 1; <br />
Issue{' '}
<a
rel="noopener noreferrer"
target="_blank"
href="https://github.com/facebook/react/issues/16763">
#16763
</a>{' '}
should not happen.
<br />
</TestCase.ExpectedResult>
<div ref={containerRef} />
</TestCase>
);
};
const MouseEnterDetect = () => {
const [log, setLog] = React.useState({});
const firstEl = React.useRef();
const siblingEl = React.useRef();
const onMouseEnter = e => {
const timeStamp = e.timeStamp;
setLog(log => {
const callCount = 1 + (log.timeStamp === timeStamp ? log.callCount : 0);
return {
timeStamp,
callCount,
};
});
};
return (
<React.Fragment>
<div
ref={firstEl}
onMouseEnter={onMouseEnter}
style={{
border: '1px solid #d9d9d9',
padding: '20px 20px',
}}>
Mouse enter call count: {log.callCount || ''}
</div>
<div ref={siblingEl} />
</React.Fragment>
);
};
export default MouseEnter;

View File

@@ -202,34 +202,6 @@ class SelectFixture extends React.Component {
</select>
</div>
</TestCase>
<TestCase
title="A select with the size attribute should not set first option as selected"
relatedIssues="14239"
introducedIn="16.0.0">
<TestCase.ExpectedResult>
No options should be selected.
</TestCase.ExpectedResult>
<div className="test-fixture">
<select size="3">
<option>0</option>
<option>1</option>
<option>2</option>
</select>
</div>
<p className="footnote">
<b>Notes:</b> This happens if <code>size</code> is assigned after
options are selected. The select element picks the first item by
default, then it is expanded to show more options when{' '}
<code>size</code> is assigned, preserving the default selection.
</p>
<p className="footnote">
This was introduced in React 16.0.0 when options were added before
select attribute assignment.
</p>
</TestCase>
</FixtureSet>
);
}

View File

@@ -46,7 +46,7 @@ class SuspendyTreeChild extends React.Component {
render() {
return (
<>
<React.Fragment>
<Suspense fallback={<div>(display: none)</div>}>
<div>
<AsyncStep text={`${this.state.step} + ${this.id}`} ms={500} />
@@ -54,7 +54,7 @@ class SuspendyTreeChild extends React.Component {
</div>
</Suspense>
<button onClick={this.increment}>Hide</button>
</>
</React.Fragment>
);
}
}
@@ -86,22 +86,22 @@ class SuspendyTree extends React.Component {
};
render() {
return (
<>
<React.Fragment>
<div ref={this.parentContainer}>
<div ref={this.container} />
</div>
<div>
{this.container.current !== null
? ReactDOM.createPortal(
<>
<React.Fragment>
<SuspendyTreeChild>{this.props.children}</SuspendyTreeChild>
<button onClick={this.removeAndRestore}>Remove</button>
</>,
</React.Fragment>,
this.container.current
)
: null}
</div>
</>
</React.Fragment>
);
}
}
@@ -169,7 +169,7 @@ class TextInputFixtures extends React.Component {
the "Go" button.
</li>
<li>
Instead of clicking "Go", which switches focus, press Command +
Intead of clicking "Go", which switches focus, press Command +
Enter (or Control + Enter on Windows, Linux).
</li>
</TestCase.Steps>

View File

@@ -1,4 +1,3 @@
import Fixture from '../../Fixture';
import FixtureSet from '../../FixtureSet';
import TestCase from '../../TestCase';
@@ -40,44 +39,6 @@ export default class TextAreaFixtures extends React.Component {
<textarea placeholder="Hello, world" />
</div>
</TestCase>
<TestCase
title="Required Textareas"
affectedBrowsers="Firefox"
relatedIssues="16402">
<TestCase.Steps>
<li>View this test in Firefox</li>
</TestCase.Steps>
<TestCase.ExpectedResult>
You should{' '}
<b>
<i>not</i>
</b>{' '}
see a red aura on initial page load, indicating the textarea is
invalid.
<br />
This aura looks roughly like:
<textarea style={{boxShadow: '0 0 1px 1px red', marginLeft: 8}} />
</TestCase.ExpectedResult>
<Fixture>
<form className="control-box">
<fieldset>
<legend>Empty value prop string</legend>
<textarea value="" required={true} />
</fieldset>
<fieldset>
<legend>No value prop</legend>
<textarea required={true} />
</fieldset>
<fieldset>
<legend>Empty defaultValue prop string</legend>
<textarea required={true} defaultValue="" />
</fieldset>
</form>
</Fixture>
</TestCase>
</FixtureSet>
);
}

View File

@@ -1,20 +0,0 @@
/**
* Provides a standard way to access a DOM node across all versions of
* React.
*/
import {reactPaths} from './react-loader';
const React = window.React;
const ReactDOM = window.ReactDOM;
export function findDOMNode(target) {
const {needsReactDOM} = reactPaths();
if (needsReactDOM) {
return ReactDOM.findDOMNode(target);
} else {
// eslint-disable-next-line
return React.findDOMNode(target);
}
}

View File

@@ -36,29 +36,19 @@ function loadScript(src) {
});
}
function getVersion() {
let query = parseQuery(window.location.search);
return query.version || 'local';
}
export function reactPaths(version = getVersion()) {
export function reactPaths() {
let query = parseQuery(window.location.search);
let version = query.version || 'local';
let isProduction = query.production === 'true';
let environment = isProduction ? 'production.min' : 'development';
let reactPath = `react.${environment}.js`;
let reactDOMPath = `react-dom.${environment}.js`;
let reactDOMServerPath = `react-dom-server.browser.${environment}.js`;
let needsCreateElement = true;
let needsReactDOM = true;
let reactPath = 'react.' + environment + '.js';
let reactDOMPath = 'react-dom.' + environment + '.js';
let reactDOMServerPath = 'react-dom-server.browser.' + environment + '.js';
if (version !== 'local') {
const {major, minor, prerelease} = semver(version);
if (major === 0) {
needsCreateElement = minor >= 12;
needsReactDOM = minor >= 14;
}
const [preReleaseStage] = prerelease;
// The file structure was updated in 16. This wasn't the case for alphas.
// Load the old module location for anything less than 16 RC
@@ -78,27 +68,26 @@ export function reactPaths(version = getVersion()) {
reactDOMServerPath =
'https://unpkg.com/react-dom@' +
version +
'/umd/react-dom-server.browser' +
environment;
} else if (major > 0 || minor > 11) {
reactPath = 'https://unpkg.com/react@' + version + '/dist/react.js';
reactDOMPath =
'https://unpkg.com/react-dom@' + version + '/dist/react-dom.js';
reactDOMServerPath =
'https://unpkg.com/react-dom@' + version + '/dist/react-dom-server.js';
'/umd/react-dom-server.browser.' +
environment +
'.js';
} else {
reactPath =
'https://cdnjs.cloudflare.com/ajax/libs/react/' + version + '/react.js';
let suffix = isProduction ? '.min.js' : '.js';
reactPath = 'https://unpkg.com/react@' + version + '/dist/react' + suffix;
reactDOMPath =
'https://unpkg.com/react-dom@' + version + '/dist/react-dom' + suffix;
reactDOMServerPath =
'https://unpkg.com/react-dom@' +
version +
'/dist/react-dom-server' +
suffix;
}
}
return {
reactPath,
reactDOMPath,
reactDOMServerPath,
needsCreateElement,
needsReactDOM,
};
const needsReactDOM = version === 'local' || parseFloat(version, 10) > 0.13;
return {reactPath, reactDOMPath, reactDOMServerPath, needsReactDOM};
}
export default function loadReact() {

View File

@@ -1,291 +0,0 @@
// copied from scripts/jest/matchers/toWarnDev.js
'use strict';
const jestDiff = require('jest-diff');
const util = require('util');
function shouldIgnoreConsoleError(format, args) {
if (__DEV__) {
if (typeof format === 'string') {
if (format.indexOf('Error: Uncaught [') === 0) {
// This looks like an uncaught error from invokeGuardedCallback() wrapper
// in development that is reported by jsdom. Ignore because it's noisy.
return true;
}
if (format.indexOf('The above error occurred') === 0) {
// This looks like an error addendum from ReactFiberErrorLogger.
// Ignore it too.
return true;
}
}
} else {
if (
format != null &&
typeof format.message === 'string' &&
typeof format.stack === 'string' &&
args.length === 0
) {
// In production, ReactFiberErrorLogger logs error objects directly.
// They are noisy too so we'll try to ignore them.
return true;
}
}
// Looks legit
return false;
}
function normalizeCodeLocInfo(str) {
return str && str.replace(/at .+?:\d+/g, 'at **');
}
const createMatcherFor = consoleMethod =>
function matcher(callback, expectedMessages, options = {}) {
if (__DEV__) {
// Warn about incorrect usage of matcher.
if (typeof expectedMessages === 'string') {
expectedMessages = [expectedMessages];
} else if (!Array.isArray(expectedMessages)) {
throw Error(
`toWarnDev() requires a parameter of type string or an array of strings ` +
`but was given ${typeof expectedMessages}.`
);
}
if (
options != null &&
(typeof options !== 'object' || Array.isArray(options))
) {
throw new Error(
'toWarnDev() second argument, when present, should be an object. ' +
'Did you forget to wrap the messages into an array?'
);
}
if (arguments.length > 3) {
// `matcher` comes from Jest, so it's more than 2 in practice
throw new Error(
'toWarnDev() received more than two arguments. ' +
'Did you forget to wrap the messages into an array?'
);
}
const withoutStack = options.withoutStack;
const warningsWithoutComponentStack = [];
const warningsWithComponentStack = [];
const unexpectedWarnings = [];
let lastWarningWithMismatchingFormat = null;
let lastWarningWithExtraComponentStack = null;
// Catch errors thrown by the callback,
// But only rethrow them if all test expectations have been satisfied.
// Otherwise an Error in the callback can mask a failed expectation,
// and result in a test that passes when it shouldn't.
let caughtError;
const isLikelyAComponentStack = message =>
typeof message === 'string' && message.includes('\n in ');
const consoleSpy = (format, ...args) => {
// Ignore uncaught errors reported by jsdom
// and React addendums because they're too noisy.
if (
consoleMethod === 'error' &&
shouldIgnoreConsoleError(format, args)
) {
return;
}
const message = util.format(format, ...args);
const normalizedMessage = normalizeCodeLocInfo(message);
// Remember if the number of %s interpolations
// doesn't match the number of arguments.
// We'll fail the test if it happens.
let argIndex = 0;
format.replace(/%s/g, () => argIndex++);
if (argIndex !== args.length) {
lastWarningWithMismatchingFormat = {
format,
args,
expectedArgCount: argIndex,
};
}
// Protect against accidentally passing a component stack
// to warning() which already injects the component stack.
if (
args.length >= 2 &&
isLikelyAComponentStack(args[args.length - 1]) &&
isLikelyAComponentStack(args[args.length - 2])
) {
lastWarningWithExtraComponentStack = {
format,
};
}
for (let index = 0; index < expectedMessages.length; index++) {
const expectedMessage = expectedMessages[index];
if (
normalizedMessage === expectedMessage ||
normalizedMessage.includes(expectedMessage)
) {
if (isLikelyAComponentStack(normalizedMessage)) {
warningsWithComponentStack.push(normalizedMessage);
} else {
warningsWithoutComponentStack.push(normalizedMessage);
}
expectedMessages.splice(index, 1);
return;
}
}
let errorMessage;
if (expectedMessages.length === 0) {
errorMessage =
'Unexpected warning recorded: ' +
this.utils.printReceived(normalizedMessage);
} else if (expectedMessages.length === 1) {
errorMessage =
'Unexpected warning recorded: ' +
jestDiff(expectedMessages[0], normalizedMessage);
} else {
errorMessage =
'Unexpected warning recorded: ' +
jestDiff(expectedMessages, [normalizedMessage]);
}
// Record the call stack for unexpected warnings.
// We don't throw an Error here though,
// Because it might be suppressed by ReactFiberScheduler.
unexpectedWarnings.push(new Error(errorMessage));
};
// TODO Decide whether we need to support nested toWarn* expectations.
// If we don't need it, add a check here to see if this is already our spy,
// And throw an error.
const originalMethod = console[consoleMethod];
// Avoid using Jest's built-in spy since it can't be removed.
console[consoleMethod] = consoleSpy;
try {
callback();
} catch (error) {
caughtError = error;
} finally {
// Restore the unspied method so that unexpected errors fail tests.
console[consoleMethod] = originalMethod;
// Any unexpected Errors thrown by the callback should fail the test.
// This should take precedence since unexpected errors could block warnings.
if (caughtError) {
throw caughtError;
}
// Any unexpected warnings should be treated as a failure.
if (unexpectedWarnings.length > 0) {
return {
message: () => unexpectedWarnings[0].stack,
pass: false,
};
}
// Any remaining messages indicate a failed expectations.
if (expectedMessages.length > 0) {
return {
message: () =>
`Expected warning was not recorded:\n ${this.utils.printReceived(
expectedMessages[0]
)}`,
pass: false,
};
}
if (typeof withoutStack === 'number') {
// We're expecting a particular number of warnings without stacks.
if (withoutStack !== warningsWithoutComponentStack.length) {
return {
message: () =>
`Expected ${withoutStack} warnings without a component stack but received ${
warningsWithoutComponentStack.length
}:\n` +
warningsWithoutComponentStack.map(warning =>
this.utils.printReceived(warning)
),
pass: false,
};
}
} else if (withoutStack === true) {
// We're expecting that all warnings won't have the stack.
// If some warnings have it, it's an error.
if (warningsWithComponentStack.length > 0) {
return {
message: () =>
`Received warning unexpectedly includes a component stack:\n ${this.utils.printReceived(
warningsWithComponentStack[0]
)}\nIf this warning intentionally includes the component stack, remove ` +
`{withoutStack: true} from the toWarnDev() call. If you have a mix of ` +
`warnings with and without stack in one toWarnDev() call, pass ` +
`{withoutStack: N} where N is the number of warnings without stacks.`,
pass: false,
};
}
} else if (withoutStack === false || withoutStack === undefined) {
// We're expecting that all warnings *do* have the stack (default).
// If some warnings don't have it, it's an error.
if (warningsWithoutComponentStack.length > 0) {
return {
message: () =>
`Received warning unexpectedly does not include a component stack:\n ${this.utils.printReceived(
warningsWithoutComponentStack[0]
)}\nIf this warning intentionally omits the component stack, add ` +
`{withoutStack: true} to the toWarnDev() call.`,
pass: false,
};
}
} else {
throw Error(
`The second argument for toWarnDev(), when specified, must be an object. It may have a ` +
`property called "withoutStack" whose value may be undefined, boolean, or a number. ` +
`Instead received ${typeof withoutStack}.`
);
}
if (lastWarningWithMismatchingFormat !== null) {
return {
message: () =>
`Received ${
lastWarningWithMismatchingFormat.args.length
} arguments for a message with ${
lastWarningWithMismatchingFormat.expectedArgCount
} placeholders:\n ${this.utils.printReceived(
lastWarningWithMismatchingFormat.format
)}`,
pass: false,
};
}
if (lastWarningWithExtraComponentStack !== null) {
return {
message: () =>
`Received more than one component stack for a warning:\n ${this.utils.printReceived(
lastWarningWithExtraComponentStack.format
)}\nDid you accidentally pass a stack to warning() as the last argument? ` +
`Don't forget warning() already injects the component stack automatically.`,
pass: false,
};
}
return {pass: true};
}
} else {
// Any uncaught errors or warnings should fail tests in production mode.
callback();
return {pass: true};
}
};
module.exports = {
toLowPriorityWarnDev: createMatcherFor('warn'),
toWarnDev: createMatcherFor('error'),
};

View File

@@ -6,40 +6,6 @@
version "7.0.0"
resolved "https://registry.yarnpkg.com/@babel/standalone/-/standalone-7.0.0.tgz#856446641620c1c5f0ca775621d478324ebd1f52"
"@jest/types@^24.8.0":
version "24.8.0"
resolved "https://registry.yarnpkg.com/@jest/types/-/types-24.8.0.tgz#f31e25948c58f0abd8c845ae26fcea1491dea7ad"
integrity sha512-g17UxVr2YfBtaMUxn9u/4+siG1ptg9IGYAYwvpwn61nBg779RXnjE/m7CxYcIzEt0AbHZZAHSEZNhkE2WxURVg==
dependencies:
"@types/istanbul-lib-coverage" "^2.0.0"
"@types/istanbul-reports" "^1.1.1"
"@types/yargs" "^12.0.9"
"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0":
version "2.0.1"
resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.1.tgz#42995b446db9a48a11a07ec083499a860e9138ff"
integrity sha512-hRJD2ahnnpLgsj6KWMYSrmXkM3rm2Dl1qkx6IOFD5FnuNPXJIG5L0dhgKXCYTRMGzU4n0wImQ/xfmRc4POUFlg==
"@types/istanbul-lib-report@*":
version "1.1.1"
resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-1.1.1.tgz#e5471e7fa33c61358dd38426189c037a58433b8c"
integrity sha512-3BUTyMzbZa2DtDI2BkERNC6jJw2Mr2Y0oGI7mRxYNBPxppbtEK1F66u3bKwU2g+wxwWI7PAoRpJnOY1grJqzHg==
dependencies:
"@types/istanbul-lib-coverage" "*"
"@types/istanbul-reports@^1.1.1":
version "1.1.1"
resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-1.1.1.tgz#7a8cbf6a406f36c8add871625b278eaf0b0d255a"
integrity sha512-UpYjBi8xefVChsCoBpKShdxTllC9pwISirfoZsUa2AAdQg/Jd2KQGtSbw+ya7GPo7x/wAPlH6JBhKhAsXUEZNA==
dependencies:
"@types/istanbul-lib-coverage" "*"
"@types/istanbul-lib-report" "*"
"@types/yargs@^12.0.9":
version "12.0.12"
resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-12.0.12.tgz#45dd1d0638e8c8f153e87d296907659296873916"
integrity sha512-SOhuU4wNBxhhTHxYaiG5NY4HBhDIDnJF60GU+2LqHAdKKer86//e4yg69aENCtQ04n0ovz+tq2YPME5t5yp4pw==
abab@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/abab/-/abab-1.0.3.tgz#b81de5f7274ec4e756d797cd834f303642724e5d"
@@ -174,11 +140,6 @@ ansi-regex@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998"
ansi-regex@^4.0.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997"
integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==
ansi-styles@^2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe"
@@ -189,13 +150,6 @@ ansi-styles@^3.0.0, ansi-styles@^3.1.0:
dependencies:
color-convert "^1.9.0"
ansi-styles@^3.2.0, ansi-styles@^3.2.1:
version "3.2.1"
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==
dependencies:
color-convert "^1.9.0"
anymatch@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-1.3.0.tgz#a3e52fa39168c825ff57b0248126ce5a8ff95507"
@@ -295,11 +249,6 @@ arrify@^1.0.0, arrify@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d"
art@^0.10.3:
version "0.10.3"
resolved "https://registry.yarnpkg.com/art/-/art-0.10.3.tgz#b01d84a968ccce6208df55a733838c96caeeaea2"
integrity sha512-HXwbdofRTiJT6qZX/FnchtldzJjS3vkLJxQilc3Xj+ma2MXjY4UAyQ0ls1XZYVnDvVIBiFZbC6QsvtW86TD6tQ==
asap@~2.0.3:
version "2.0.5"
resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.5.tgz#522765b50c3510490e52d7dcfe085ef9ba96958f"
@@ -1517,15 +1466,6 @@ chalk@^2.0.0, chalk@^2.1.0:
escape-string-regexp "^1.0.5"
supports-color "^4.0.0"
chalk@^2.0.1:
version "2.4.2"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
dependencies:
ansi-styles "^3.2.1"
escape-string-regexp "^1.0.5"
supports-color "^5.3.0"
chokidar@^1.6.0, chokidar@^1.7.0:
version "1.7.0"
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.7.0.tgz#798e689778151c8076b4b360e5edd28cda2bb468"
@@ -2118,11 +2058,6 @@ detect-port-alt@1.1.3:
address "^1.0.1"
debug "^2.6.0"
diff-sequences@^24.3.0:
version "24.3.0"
resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-24.3.0.tgz#0f20e8a1df1abddaf4d9c226680952e64118b975"
integrity sha512-xLqpez+Zj9GKSnPWS0WZw1igGocZ+uua8+y+5dDNTT934N3QuY1sp2LkHzwiaYQGz60hMq0pjAshdeXm5VUOEw==
diff@^3.2.0:
version "3.3.0"
resolved "https://registry.yarnpkg.com/diff/-/diff-3.3.0.tgz#056695150d7aa93237ca7e378ac3b1682b7963b9"
@@ -3184,11 +3119,6 @@ has-flag@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-2.0.0.tgz#e8207af1cc7b30d446cc70b734b5e8be18f88d51"
has-flag@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0=
has-unicode@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9"
@@ -3840,16 +3770,6 @@ jest-diff@^20.0.3:
jest-matcher-utils "^20.0.3"
pretty-format "^20.0.3"
jest-diff@^24.8.0:
version "24.8.0"
resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-24.8.0.tgz#146435e7d1e3ffdf293d53ff97e193f1d1546172"
integrity sha512-wxetCEl49zUpJ/bvUmIFjd/o52J+yWcoc5ZyPq4/W1LUKGEhRYDIbP1KcF6t+PvqNrGAFk4/JhtxDq/Nnzs66g==
dependencies:
chalk "^2.0.1"
diff-sequences "^24.3.0"
jest-get-type "^24.8.0"
pretty-format "^24.8.0"
jest-docblock@^20.0.3:
version "20.0.3"
resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-20.0.3.tgz#17bea984342cc33d83c50fbe1545ea0efaa44712"
@@ -3869,11 +3789,6 @@ jest-environment-node@^20.0.3:
jest-mock "^20.0.3"
jest-util "^20.0.3"
jest-get-type@^24.8.0:
version "24.8.0"
resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-24.8.0.tgz#a7440de30b651f5a70ea3ed7ff073a32dfe646fc"
integrity sha512-RR4fo8jEmMD9zSz2nLbs2j0zvPpk/KCEz3a62jJWbd2ayNo0cb+KFRxPHVhE4ZmgGJEQp0fosmNz84IfqM8cMQ==
jest-haste-map@^20.0.4:
version "20.0.5"
resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-20.0.5.tgz#abad74efb1a005974a7b6517e11010709cab9112"
@@ -5328,16 +5243,6 @@ pretty-format@^20.0.3:
ansi-regex "^2.1.1"
ansi-styles "^3.0.0"
pretty-format@^24.8.0:
version "24.8.0"
resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-24.8.0.tgz#8dae7044f58db7cb8be245383b565a963e3c27f2"
integrity sha512-P952T7dkrDEplsR+TuY7q3VXDae5Sr7zmQb12JU/NDQa/3CH7/QW0yvqLcGN6jL+zQFKaoJcPc+yJxMTGmosqw==
dependencies:
"@jest/types" "^24.8.0"
ansi-regex "^4.0.0"
ansi-styles "^3.2.0"
react-is "^16.8.4"
private@^0.1.6:
version "0.1.6"
resolved "https://registry.yarnpkg.com/private/-/private-0.1.6.tgz#55c6a976d0f9bafb9924851350fe47b9b5fbb7c1"
@@ -5524,11 +5429,6 @@ react-error-overlay@^1.0.10:
settle-promise "1.0.0"
source-map "0.5.6"
react-is@^16.8.4:
version "16.8.6"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.8.6.tgz#5bbc1e2d29141c9fbdfed456343fe2bc430a6a16"
integrity sha512-aUk3bHfZ2bRSVFFbbeVS4i+lNPZr3/WM5jT2J5omUVV1zzcs1nAaf3l51ctA5FFvCRbhrH0bdAsRRQddFJZPtA==
react-scripts@^1.0.11:
version "1.0.11"
resolved "https://registry.yarnpkg.com/react-scripts/-/react-scripts-1.0.11.tgz#483d49e27f417ec981ae415a4456120a2a2bc8c1"
@@ -6348,13 +6248,6 @@ supports-color@^4.0.0, supports-color@^4.2.1:
dependencies:
has-flag "^2.0.0"
supports-color@^5.3.0:
version "5.5.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==
dependencies:
has-flag "^3.0.0"
svgo@^0.7.0:
version "0.7.1"
resolved "https://registry.yarnpkg.com/svgo/-/svgo-0.7.1.tgz#287320fed972cb097e72c2bb1685f96fe08f8034"

View File

@@ -1,7 +1,7 @@
{
"root": true,
"parserOptions": {
"ecmaVersion": 8,
"ecmaVersion": 6,
"sourceType": "module",
"ecmaFeatures": {
"jsx": true

View File

@@ -105,51 +105,9 @@
<div><b>Actual:</b></div>
<div id="test-8"></div>
</li>
<li>
<p>Can force a specific framerate</p>
<p><b>IMPORTANT:</b> This test may be flaky if other tests have been run in this js instance. To get a clean test refresh the page before running test 9</p>
<button onClick="runTestNine()">Run Test 9</button>
<div><b>Expected:</b></div>
<div id="test-9-expected">
</div>
<div> -------------------------------------------------</div>
<div> If you see the same above and below it's correct.
<div> -------------------------------------------------</div>
<div><b>Actual:</b></div>
<div id="test-9"></div>
</div>
</li>
<li>
<p>Runs scheduled JS work for 99% of the frame time when nothing else is using the thread.</p>
<p><b>NOTE:</b> Try this test both when nothing else is running and when something is using the compositor thread in another visible tab with video or <a href="https://www.shadertoy.com/view/MtffDX">WebGL content</a> (Shift+Click).</p>
<button onClick="runTestTen()">Run Test 10</button>
<div><b>Expected:</b></div>
<div id="test-10-expected">
</div>
<div> -------------------------------------------------</div>
<div> If you see the same above and below it's correct.
<div> -------------------------------------------------</div>
<div><b>Actual:</b></div>
<div id="test-10"></div>
</div>
</li>
<li>
<p>Runs scheduled JS work more than 95% of the frame time when inserting DOM nodes.</p>
<p><b>NOTE:</b> Try this test both when nothing else is running and when something is using the compositor thread in another visible tab with video or <a href="https://www.shadertoy.com/view/MtffDX">WebGL content</a> (Shift+Click).</p>
<button onClick="runTestEleven()">Run Test 11</button>
<div><b>Expected:</b></div>
<div id="test-11-expected">
</div>
<div> -------------------------------------------------</div>
<div> If you see the same above and below it's correct.
<div> -------------------------------------------------</div>
<div><b>Actual:</b></div>
<div id="test-11"></div>
</div>
</li>
</ol>
<script src="../../build/node_modules/react/umd/react.production.min.js"></script>
<script src="../../build/node_modules/scheduler/umd/scheduler.production.min.js"></script>
<script src="../../build/node_modules/react/umd/react.development.js"></script>
<script src="../../build/node_modules/scheduler/umd/scheduler.development.js"></script>
<script src="https://unpkg.com/babel-standalone@6/babel.js"></script>
<script type="text/babel">
const {
@@ -159,9 +117,6 @@ const {
unstable_getFirstCallbackNode: getFirstCallbackNode,
unstable_pauseExecution: pauseExecution,
unstable_continueExecution: continueExecution,
unstable_forceFrameRate: forceFrameRate,
unstable_shouldYield: shouldYield,
unstable_NormalPriority: NormalPriority,
} = Scheduler;
function displayTestResult(testNumber) {
const expectationNode = document.getElementById('test-' + testNumber + '-expected');
@@ -233,7 +188,7 @@ const expectedResults = [
[
'scheduled Cb1',
'frame 1 started',
'cb1 called with argument of false',
'cb1 called with argument of {"didTimeout":false}',
'frame 2 started',
'frame 3 started... we stop counting now.',
],
@@ -242,8 +197,8 @@ const expectedResults = [
'scheduled CbA',
'scheduled CbB',
'frame 1 started',
'cbA called with argument of false',
'cbB called with argument of false',
'cbA called with argument of {"didTimeout":false}',
'cbB called with argument of {"didTimeout":false}',
'frame 2 started',
'frame 3 started... we stop counting now.',
],
@@ -253,9 +208,9 @@ const expectedResults = [
'scheduled CbB',
'frame 1 started',
'scheduled CbA again',
'cbA0 called with argument of false',
'cbB called with argument of false',
'cbA1 called with argument of false',
'cbA0 called with argument of {"didTimeout":false}',
'cbB called with argument of {"didTimeout":false}',
'cbA1 called with argument of {"didTimeout":false}',
'frame 2 started',
'frame 3 started... we stop counting now.',
],
@@ -267,11 +222,11 @@ const expectedResults = [
'scheduled cbD',
'frame 1 started',
'cbC called with argument of {"didTimeout":true}',
'cbA called with argument of false',
'cbA called with argument of {"didTimeout":false}',
'cbA running and taking some time',
'frame 2 started',
'cbB called with argument of false',
'cbD called with argument of false',
'cbB called with argument of {"didTimeout":false}',
'cbD called with argument of {"didTimeout":false}',
'frame 3 started... we stop counting now.',
],
// test 5
@@ -288,23 +243,6 @@ const expectedResults = [
'Finishing...',
'Done!',
],
// test 9
[
'Forcing new frame times...',
'Using new frame time!',
'Using new frame time!',
'Finished!',
],
// test 10
[
'Running work for 10 seconds...',
'Ran scheduled work for >99% of the time.',
],
// test 11
[
'Running work for 10 seconds...',
'Ran scheduled work for >95% of the time.',
],
];
function runTestOne() {
// Test 1
@@ -315,7 +253,7 @@ function runTestOne() {
const cb1 = (x) => {
updateTestResult(1, 'cb1 called with argument of ' + JSON.stringify(x));
}
scheduleCallback(NormalPriority, cb1);
scheduleCallback(cb1);
updateTestResult(1, 'scheduled Cb1');
logWhenFramesStart(1, () => {
displayTestResult(1);
@@ -333,9 +271,9 @@ function runTestTwo() {
const cbB = (x) => {
updateTestResult(2, 'cbB called with argument of ' + JSON.stringify(x));
}
scheduleCallback(NormalPriority, cbA);
scheduleCallback(cbA);
updateTestResult(2, 'scheduled CbA');
scheduleCallback(NormalPriority, cbB);
scheduleCallback(cbB);
updateTestResult(2, 'scheduled CbB');
logWhenFramesStart(2, () => {
displayTestResult(2);
@@ -350,7 +288,7 @@ function runTestThree() {
let callbackAIterations = 0;
const cbA = (x) => {
if (callbackAIterations < 1) {
scheduleCallback(NormalPriority, cbA);
scheduleCallback(cbA);
updateTestResult(3, 'scheduled CbA again');
}
updateTestResult(3, 'cbA' + callbackAIterations + ' called with argument of ' + JSON.stringify(x));
@@ -359,9 +297,9 @@ function runTestThree() {
const cbB = (x) => {
updateTestResult(3, 'cbB called with argument of ' + JSON.stringify(x));
}
scheduleCallback(NormalPriority, cbA);
scheduleCallback(cbA);
updateTestResult(3, 'scheduled CbA');
scheduleCallback(NormalPriority, cbB);
scheduleCallback(cbB);
updateTestResult(3, 'scheduled CbB');
logWhenFramesStart(3, () => {
displayTestResult(3);
@@ -395,13 +333,13 @@ function runTestFour() {
const cbD = (x) => {
updateTestResult(4, 'cbD called with argument of ' + JSON.stringify(x));
}
scheduleCallback(NormalPriority, cbA); // won't time out
scheduleCallback(cbA); // won't time out
updateTestResult(4, 'scheduled cbA');
scheduleCallback(NormalPriority, cbB, {timeout: 100}); // times out later
scheduleCallback(cbB, {timeout: 100}); // times out later
updateTestResult(4, 'scheduled cbB');
scheduleCallback(NormalPriority, cbC, {timeout: 1}); // will time out fast
scheduleCallback(cbC, {timeout: 1}); // will time out fast
updateTestResult(4, 'scheduled cbC');
scheduleCallback(NormalPriority, cbD); // won't time out
scheduleCallback(cbD); // won't time out
updateTestResult(4, 'scheduled cbD');
// should have run in order of C, A, B, D
@@ -480,15 +418,15 @@ function runTestFive() {
});
});
});
scheduleCallback(NormalPriority, cbA);
scheduleCallback(cbA);
console.log('scheduled cbA');
scheduleCallback(NormalPriority, cbB); // will throw error
scheduleCallback(cbB); // will throw error
console.log('scheduled cbB');
scheduleCallback(NormalPriority, cbC);
scheduleCallback(cbC);
console.log('scheduled cbC');
scheduleCallback(NormalPriority, cbD); // will throw error
scheduleCallback(cbD); // will throw error
console.log('scheduled cbD');
scheduleCallback(NormalPriority, cbE);
scheduleCallback(cbE);
console.log('scheduled cbE');
};
}
@@ -558,15 +496,15 @@ function runTestSix() {
});
});
});
scheduleCallback(NormalPriority, cbA);
scheduleCallback(cbA);
console.log('scheduled cbA');
scheduleCallback(NormalPriority, cbB); // will throw error
scheduleCallback(cbB); // will throw error
console.log('scheduled cbB');
scheduleCallback(NormalPriority, cbC, {timeout: 1});
scheduleCallback(cbC, {timeout: 1});
console.log('scheduled cbC');
scheduleCallback(NormalPriority, cbD, {timeout: 1}); // will throw error
scheduleCallback(cbD, {timeout: 1}); // will throw error
console.log('scheduled cbD');
scheduleCallback(NormalPriority, cbE, {timeout: 1});
scheduleCallback(cbE, {timeout: 1});
console.log('scheduled cbE');
};
}
@@ -582,9 +520,9 @@ function runTestSeven() {
counter++;
counterNode.innerHTML = counter;
waitForTimeToPass(100);
scheduleCallback(NormalPriority, incrementCounterAndScheduleNextCallback);
scheduleCallback(incrementCounterAndScheduleNextCallback);
}
scheduleCallback(NormalPriority, incrementCounterAndScheduleNextCallback);
scheduleCallback(incrementCounterAndScheduleNextCallback);
}
function runTestEight() {
@@ -604,18 +542,18 @@ function runTestEight() {
return count;
}
scheduleCallback(NormalPriority, () => {
scheduleCallback(() => {
// size should be 0
updateTestResult(8, `Queue size: ${countNodesInStack(getFirstCallbackNode())}.`);
updateTestResult(8, 'Pausing... press continue to resume.');
pauseExecution();
scheduleCallback(NormalPriority, function () {
scheduleCallback(function () {
updateTestResult(8, 'Finishing...');
displayTestResult(8);
})
scheduleCallback(NormalPriority, function () {
scheduleCallback(function () {
updateTestResult(8, 'Done!');
displayTestResult(8);
checkTestResult(8);
@@ -631,101 +569,6 @@ function continueTestEight() {
continueExecution();
}
function runTestNine() {
clearTestResult(9);
// We have this to make sure that the thing that goes right after it can get a full frame
var forceFrameFinish = () => {
while (!shouldYield()) {
waitForTimeToPass(1);
}
waitForTimeToPass(100);
}
scheduleCallback(NormalPriority, forceFrameFinish);
scheduleCallback(NormalPriority, () => {
var startTime = now();
while (!shouldYield()) {}
var initialFrameTime = now() - startTime;
var newFrameTime = (initialFrameTime * 2) > 60 ? (initialFrameTime * 2) : 60;
var newFrameRate = Math.floor(1000/newFrameTime);
updateTestResult(9, `Forcing new frame times...`);
displayTestResult(9);
forceFrameRate(newFrameRate);
var toSchedule = (again) => {
var startTime = now();
while (!shouldYield()) {}
var frameTime = now() - startTime;
if (frameTime >= (newFrameTime-8)) {
updateTestResult(9, `Using new frame time!`);
} else {
updateTestResult(9, `Failed to use new frame time. (off by ${newFrameTime - frameTime}ms)`);
}
displayTestResult(9);
if (again) {
scheduleCallback(NormalPriority, forceFrameFinish);
scheduleCallback(NormalPriority, () => {toSchedule(false);});
} else {
updateTestResult(9, `Finished!`);
forceFrameRate(0);
displayTestResult(9);
checkTestResult(9);
}
}
scheduleCallback(NormalPriority, forceFrameFinish);
scheduleCallback(NormalPriority, () => {toSchedule(true);});
});
}
function runTestTen() {
clearTestResult(10);
updateTestResult(10, `Running work for 10 seconds...`);
var testStartTime = now();
var accumulatedWork = 0
function loop() {
var startTime = now();
while (!shouldYield()) {}
var endTime = now();
accumulatedWork += endTime - startTime;
var runTime = endTime - testStartTime;
if (runTime > 10000) {
updateTestResult(10, `Ran scheduled work for ${(100 * accumulatedWork / runTime).toFixed(2)}% of the time.`);
displayTestResult(10);
return;
}
scheduleCallback(NormalPriority, loop);
}
scheduleCallback(NormalPriority, loop);
}
function runTestEleven() {
clearTestResult(11);
updateTestResult(11, `Running work for 10 seconds...`);
var testStartTime = now();
var lastInsertion = 0;
var accumulatedWork = 0
function loop() {
var startTime = now();
var timeSinceLastDOMInteraction = startTime - lastInsertion;
if (timeSinceLastDOMInteraction > 15) {
lastInsertion = startTime;
var node = document.createElement('div');
node.textContent = startTime;
document.body.appendChild(node);
document.body.clientHeight; // force layout
}
while (!shouldYield()) {}
var endTime = now();
accumulatedWork += endTime - startTime;
var runTime = endTime - testStartTime;
if (runTime > 10000) {
updateTestResult(11, `Ran scheduled work for ${(100 * accumulatedWork / runTime).toFixed(2)}% of the time.`);
displayTestResult(11);
return;
}
scheduleCallback(NormalPriority, loop);
}
scheduleCallback(NormalPriority, loop);
}
</script type="text/babel">
</body>
</html>
</html>

View File

@@ -26,16 +26,7 @@ export default class Chrome extends Component {
<Theme.Provider value={this.state.theme}>
{this.props.children}
<div>
<ThemeToggleButton
onChange={theme => {
React.unstable_withSuspenseConfig(
() => {
this.setState({theme});
},
{timeoutMs: 6000}
);
}}
/>
<ThemeToggleButton onChange={theme => this.setState({theme})} />
</div>
</Theme.Provider>
<script

View File

@@ -36,8 +36,7 @@ function checkSchedulerAPI() {
throw 'API is not defined';
}
const abs = Math.abs(Scheduler.unstable_now() - performance.now());
if (typeof abs !== 'number' || Number.isNaN(abs) || abs > 5) {
if (Scheduler.unstable_now() !== performance.now()) {
throw 'API does not work';
}
@@ -176,7 +175,7 @@ function checkEndToEndIntegration() {
SchedulerTracing.unstable_trace('render', 123, () => {
ReactDOM.render(
React.createElement(
React.Profiler,
React.unstable_Profiler,
{id: 'profiler', onRender},
React.createElement('div', null, 'hi')
),

View File

@@ -0,0 +1,14 @@
# See http://help.github.com/ignore-files/ for more about ignoring files.
# dependencies
node_modules
# testing
coverage
# production
build
# misc
.DS_Store
npm-debug.log

View File

@@ -0,0 +1,31 @@
# IO "suspense" demo
## What is this fixture?
This is a demo application based on [Dan Abramov's](https://github.com/gaearon) recent [JSConf Iceland talk](https://reactjs.org/blog/2018/03/01/sneak-peek-beyond-react-16.html) about React.
It depends on a local build of React and enables us to easily test async and "suspense" APIs in a more "real world app" like context.
## Can I use this code in production?
No. The APIs being tested here are unstable and some of them have still not been released to NPM. For now, this fixture is only a test harness.
## How do I run this fixture?
Clone the React repository.
Follow these steps:
```shell
# 1: Build react from source
cd /path/to/react
yarn
yarn build react-dom/index,react/index,react-cache,scheduler --type=NODE
# 2: Install fixture dependencies
cd fixtures/unstable-async/suspense/
yarn
# 3: Run the app
yarn start
```

View File

@@ -0,0 +1,40 @@
{
"name": "io-demo",
"version": "0.1.0",
"private": true,
"homepage": ".",
"devDependencies": {
"gh-pages": "^1.1.0",
"react-scripts": "^1.1.4"
},
"dependencies": {
"clipboard": "^1.7.1",
"github-fork-ribbon-css": "^0.2.1",
"react-draggable": "^3.0.5"
},
"scripts": {
"prestart": "cp -r ../../../build/node_modules/* ./node_modules/",
"prebuild": "cp -r ../../../build/node_modules/* ./node_modules/",
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject",
"deploy": "gh-pages -d build"
},
"eslintConfig": {
"extends": "./node_modules/react-scripts/config/eslint.js"
},
"browserslist": {
"development": [
"last 2 chrome versions",
"last 2 firefox versions",
"last 2 edge versions"
],
"production": [
">1%",
"last 4 versions",
"Firefox ESR",
"not ie < 11"
]
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

View File

@@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="shortcut icon" href="./src/favicon.ico">
<title>React Core Team</title>
</head>
<body>
<div id="root"></div>
<div id="debugger"></div>
</body>
</html>

View File

@@ -0,0 +1,15 @@
{
"short_name": "Emoji Search",
"name": "Emoji Search Example App",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
}
],
"start_url": "./index.html",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}

View File

@@ -0,0 +1,334 @@
export const coreContributorListJSON = [
{
id: 'acdlite',
name: 'Andrew Clark',
},
{
id: 'bvaughn',
name: 'Brian Vaughn',
},
{
id: 'gaearon',
name: 'Dan Abramov',
},
{
id: 'trueadm',
name: 'Dominic Gannaway',
},
{
id: 'flarnie',
name: 'Flarnie Marchan',
},
{
id: 'sebmarkbage',
name: 'Sebastian Markbåge',
},
{
id: 'sophiebits',
name: 'Sophie Alpert',
},
];
export const userProfileJSON = {
acdlite: {
id: 'acdlite',
name: 'Andrew Clark',
image: '/img/acdlite.jpeg',
location: 'Redwood City, CA',
email: 'acdlite@me.com',
tagline: 'React core at Facebook. Hi!',
},
bvaughn: {
id: 'bvaughn',
name: 'Brian Vaughn',
image: '/img/bvaughn.jpeg',
location: 'Mountain View, CA',
email: 'brian.david.vaughn@gmail.com',
tagline:
'React JS core team at @facebook; formerly at @treasure-data and @google.',
},
gaearon: {
id: 'gaearon',
name: 'Dan Abramov',
image: '/img/gaearon.jpeg',
location: 'London, UK',
email: 'dan.abramov@me.com',
tagline:
'Working on @reactjs. Co-author of Redux and Create React App. Building tools for humans.',
},
flarnie: {
id: 'flarnie',
name: 'Flarnie Marchan',
image: '/img/flarnie.jpeg',
location: 'Oakland, CA',
email: null,
tagline:
'Software Engineer at Facebook React Core Team & Co-maintainer of Draft.js',
},
sebmarkbage: {
id: 'sebmarkbage',
name: 'Sebastian Markbåge',
image: '/img/sebmarkbage.jpeg',
location: 'San Francisco',
email: 'sebastian@calyptus.eu',
tagline: null,
},
sophiebits: {
id: 'sophiebits',
name: 'Sophie Alpert',
image: '/img/sophiebits.jpeg',
location: 'California',
email: 'hi@sophiebits.com',
tagline:
'I like fixing things. eng manager of @reactjs at Facebook. ex-@khanacademy. 💎🌸 she/her. kindness, intersectional feminism, music.',
},
trueadm: {
id: 'trueadm',
name: 'Dominic Gannaway',
image: '/img/trueadm.jpeg',
location: 'London, United Kingdom',
email: null,
tagline:
'Currently an engineer on the React core team at @facebook. Author of @infernojs and t7. Enjoys coding + being a Dad.',
},
};
export const userRepositoriesListJSON = {
acdlite: [
{
name: 'recompose',
url: 'https://github.com/acdlite/recompose',
description:
'A React utility belt for function components and higher-order components.',
},
{
name: 'react-fiber-architecture',
url: 'https://github.com/acdlite/react-fiber-architecture',
description: "A description of React's new core algorithm, React Fiber",
},
{
name: 'redux-router',
url: 'https://github.com/acdlite/redux-router',
description:
'Redux bindings for React Router keep your router state inside your Redux store',
},
{
name: 'flummox',
url: 'https://github.com/acdlite/flummox',
description: 'Minimal, isomorphic Flux.',
},
{
name: 'redux-rx',
url: 'https://github.com/acdlite/redux-rx',
description: 'RxJS utilities for Redux.',
},
{
name: 'react-remarkable',
url: 'https://github.com/acdlite/react-remarkable',
description: 'A React component for rendering Markdown with remarkable',
},
],
bvaughn: [
{
name: 'react-virtualized',
url: 'https://github.com/bvaughn/react-virtualized',
description:
'React components for efficiently rendering large lists and tabular data',
},
{
name: 'redux-search',
url: 'https://github.com/bvaughn/redux-search',
description: 'Redux bindings for client-side search',
},
{
name: 'react-window',
url: 'https://github.com/bvaughn/react-window',
description:
'React components for efficiently rendering large lists and tabular data',
},
{
name: 'react-virtualized-select',
url: 'https://github.com/bvaughn/react-virtualized-select',
description:
'HOC that uses react-virtualized and react-select to display large lists of options in a drop-down',
},
{
name: 'js-search',
url: 'https://github.com/bvaughn/js-search',
description:
'JS Search is an efficient, client-side search library for JavaScript and JSON objects',
},
{
name: 'react-highlight-words',
url: 'https://github.com/bvaughn/react-highlight-words',
description:
'React component to highlight words within a larger body of text',
},
],
gaearon: [
{
name: 'facebook/react',
url: 'https://github.com/facebook/react',
description:
'A declarative, efficient, and flexible JavaScript library for building user interfaces.',
},
{
name: 'reduxjs/redux',
url: 'https://github.com/reduxjs/redux',
description: 'Predictable state container for JavaScript apps',
},
{
name: 'facebook/create-react-app',
url: 'https://github.com/facebook/create-react-app',
description: 'Create React apps with no build configuration.',
},
{
name: 'reduxjs/redux-devtools',
url: 'https://github.com/reduxjs/redux-devtools',
description:
'DevTools for Redux with hot reloading, action replay, and customizable UI',
},
{
name: 'react-dnd/react-dnd',
url: 'https://github.com/react-dnd/react-dnd',
description: 'Drag and Drop for React',
},
{
name: 'paularmstrong/normalizr',
url: 'https://github.com/paularmstrong/normalizr',
description: 'Normalizes nested JSON according to a schema',
},
],
flarnie: [
{
name: 'diffux/diffux',
url: 'https://github.com/diffux/diffux',
description: 'Perceptual diffs of responsive screenshots made simple.',
},
{
name: 'facebook/draft-js',
url: 'https://github.com/facebook/draft-js',
description: 'A React framework for building text editors.',
},
{
name: 'facebook/react',
url: 'https://github.com/facebook/react',
description:
'A declarative, efficient, and flexible JavaScript library for building user interfaces.',
},
{
name: 'facebook/jest',
url: 'https://github.com/facebook/jest',
description: '🃏 Delightful JavaScript Testing.',
},
{
name: 'Galooshi/import-js',
url: 'https://github.com/Galooshi/import-js',
description: 'A tool to simplify importing JS modules',
},
{
name: 'webpack_rails_demo',
url: 'https://github.com/flarnie/webpack_rails_demo',
description: 'Setting up webpack with Ruby on Rails: a basic demo',
},
],
sebmarkbage: [
{
name: 'art',
url: 'https://github.com/sebmarkbage/art',
description:
"Retained mode vector drawing API designed for multiple output modes. There's also a built-in SVG parser.",
},
{
name: 'ecmascript-immutable-data-structures',
url:
'https://github.com/sebmarkbage/ecmascript-immutable-data-structures',
description: null,
},
{
name: 'ocamlrun-wasm',
url: 'https://github.com/sebmarkbage/ocamlrun-wasm',
description: 'OCamlrun WebAssembly - OCaml Bytecode Interpreter in WASM',
},
{
name: 'ecmascript-generator-expression',
url: 'https://github.com/sebmarkbage/ecmascript-generator-expression',
description:
'Proposal for do Generator Expressions in ECMAScript. Work in progress. Edit Add topics',
},
{
name: 'ecmascript-undefined-propagation',
url: 'https://github.com/sebmarkbage/ecmascript-undefined-propagation',
description:
'ECMAScript proposal to relax the rules to return `undefined` for property access on `null` or `undefined` instead of throwing.',
},
{
name: 'ecmascript-shallow-equal',
url: 'https://github.com/sebmarkbage/ecmascript-shallow-equal',
description: 'A proposal for ECMAScript for Object.shallowEqual',
},
],
sophiebits: [
{
name: 'facebook/react',
url: 'https://github.com/facebook/react',
description:
'A declarative, efficient, and flexible JavaScript library for building user interfaces.',
},
{
name: 'Khan/KaTeX',
url: 'https://github.com/Khan/KaTeX',
description: 'Fast math typesetting for the web.',
},
{
name: 'facebook/react-devtools',
url: 'https://github.com/facebook/react-devtools',
description:
'An extension that allows inspection of React component hierarchy in the Chrome and Firefox Developer Tools.',
},
{
name: 'vim-awesome/vim-awesome',
url: 'https://github.com/vim-awesome/vim-awesome',
description: 'Awesome Vim plugins from across the universe',
},
{
name: 'facebook/draft-js',
url: 'https://github.com/facebook/draft-js',
description: 'A React framework for building text editors.',
},
{
name: 'es3ify',
url: 'https://github.com/sophiebits/es3ify',
description:
'Browserify transform to convert ES5 syntax to be ES3-compatible.',
},
],
trueadm: [
{
name: 'facebook/react',
url: 'https://github.com/facebook/react',
description:
'A declarative, efficient, and flexible JavaScript library for building user interfaces.',
},
{
name: 'infernojs/inferno',
url: 'https://github.com/infernojs/inferno',
description:
'An extremely fast, React-like JavaScript library for building modern user interfaces',
},
{
name: 'facebook/prepack',
url: 'https://github.com/facebook/prepack',
description: 'A JavaScript bundle optimizer.',
},
{
name: 't7',
url: 'https://github.com/trueadm/t7',
description: 'Lightweight virtual DOM templating library',
},
{
name: 'infernojs/babel-plugin-inferno',
url: 'https://github.com/infernojs/babel-plugin-inferno',
description: null,
},
],
};

View File

@@ -0,0 +1,67 @@
import {
coreContributorListJSON,
userProfileJSON,
userRepositoriesListJSON,
} from './data';
export function fetchCoreContributorListJSON() {
return makeFakeAPICall('/react/contributors', coreContributorListJSON);
}
export function fetchUserProfileJSON(id) {
return makeFakeAPICall(`/${id}/details`, userProfileJSON[id]);
}
export function fetchUserRepositoriesListJSON(id) {
return makeFakeAPICall(`/${id}/repositories`, userRepositoriesListJSON[id]);
}
let fakeRequestTime = 1000;
let onProgress = () => true;
export function setFakeRequestTime(val) {
fakeRequestTime = val;
}
export function setProgressHandler(handler) {
onProgress = handler;
}
export function setPauseNewRequests(value) {
shouldPauseNewRequests = value;
}
let shouldPauseNewRequests = false;
let notifiers = {};
let isPausedUrl = {};
export function setPaused(url, isPaused) {
const wasPaused = isPausedUrl[url];
isPausedUrl[url] = isPaused;
if (isPaused !== wasPaused) {
notifiers[url]();
}
}
function makeFakeAPICall(url, result) {
let i = 1;
return new Promise(resolve => {
isPausedUrl[url] = shouldPauseNewRequests;
function notify() {
if (!isPausedUrl[url]) {
i++;
}
onProgress(url, i, isPausedUrl[url]);
if (isPausedUrl[url]) {
return;
}
if (i === 100) {
resolve(result);
} else {
setTimeout(notify, fakeRequestTime / 100);
}
}
notifiers[url] = notify;
notify();
});
}

View File

@@ -0,0 +1,89 @@
import React, {lazy, Suspense, PureComponent} from 'react';
import {unstable_scheduleCallback} from 'scheduler';
import {
unstable_trace as trace,
unstable_wrap as wrap,
} from 'scheduler/tracing';
import Spinner from './Spinner';
import ContributorListPage from './ContributorListPage';
const UserPage = lazy(() => import('./UserPage'));
export default class App extends PureComponent {
state = {
currentId: null,
showDetail: false,
};
componentDidUpdate(prevProps, prevState) {
if (
prevState.showDetail !== this.state.showDetail ||
(prevState.currentId !== this.state.currentId && this.state.showDetail)
) {
window.scrollTo(0, 0);
}
}
handleUserClick = id => {
trace(`View ${id}`, performance.now(), () => {
trace(`View ${id} (high-pri)`, performance.now(), () =>
this.setState({
currentId: id,
})
);
unstable_scheduleCallback(
wrap(() =>
trace(`View ${id} (low-pri)`, performance.now(), () =>
this.setState({
showDetail: true,
})
)
)
);
});
};
handleBackClick = () =>
trace('View list', performance.now(), () =>
this.setState({
currentId: null,
showDetail: false,
})
);
render() {
const {currentId, showDetail} = this.state;
return showDetail
? this.renderDetail(currentId)
: this.renderList(currentId);
}
renderDetail(id) {
return (
<div>
<button
onClick={this.handleBackClick}
style={{
display: 'block',
marginBottom: '1rem',
}}>
Return to list
</button>
<Suspense maxDuration={2000} fallback={<Spinner size="large" />}>
<UserPage id={id} />
</Suspense>
</div>
);
}
renderList(loadingId) {
return (
<Suspense maxDuration={1500} fallback={<Spinner size="large" />}>
<ContributorListPage
loadingId={loadingId}
onUserClick={this.handleUserClick}
/>
</Suspense>
);
}
}

View File

@@ -0,0 +1,63 @@
import React, {Fragment} from 'react';
import {unstable_createResource} from 'react-cache';
import Spinner from './Spinner';
import {fetchCoreContributorListJSON} from '../api';
const ContributorListResource = unstable_createResource(
fetchCoreContributorListJSON
);
const ContributorListPage = ({loadingId, onUserClick}) => (
<Fragment>
<h1>React Core Team</h1>
<ul
style={{
display: 'grid',
gridGap: '0.5rem',
gridTemplateColumns: 'repeat(auto-fill, 20rem)',
padding: 0,
margin: 0,
}}>
{ContributorListResource.read().map(user => (
<ContributorListItem
key={user.id}
onClick={() => onUserClick(user.id)}
isLoading={loadingId && user.id === loadingId}
user={user}
/>
))}
</ul>
</Fragment>
);
const ContributorListItem = ({isLoading, onClick, user}) => (
<li
onClick={onClick}
style={{
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
padding: '1rem',
backgroundColor: 'var(--color-buttonBg)',
border: '1px solid var(--color-buttonBorder)',
borderRadius: '1rem',
opacity: isLoading === false ? 0.5 : 1,
cursor: isLoading ? 'default' : 'pointer',
}}
tabIndex="0">
<div>
<strong>{user.name}</strong>
<div style={{marginTop: '0.5rem'}}>{user.id}</div>
</div>
{isLoading ? (
<Spinner size="small" />
) : (
<svg width="24" height="24" viewBox="0 0 24 24">
<path fill="none" d="M0 0h24v24H0z" />
<path d="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z" />
</svg>
)}
</li>
);
export default ContributorListPage;

View File

@@ -0,0 +1,75 @@
.Spinner {
animation: rotate 1.3s linear infinite;
}
.SpinnerContainer-large {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
@keyframes rotate {
0% { transform: rotate(0deg); }
100% { transform: rotate(270deg); }
}
.SmallSpinnerPath {
stroke-dasharray: 100;
stroke-dashoffset: 0;
transform-origin: center;
animation:
SmallDash 1.3s ease-in-out infinite;
}
@keyframes SmallDash {
0% { stroke-dashoffset: 100; }
50% {
stroke-dashoffset: 50;
transform:rotate(135deg);
}
100% {
stroke-dashoffset: 100;
transform:rotate(450deg);
}
}
.MediumSpinnerPath {
stroke-dasharray: 150;
stroke-dashoffset: 0;
transform-origin: center;
animation:
MediumDash 1.3s ease-in-out infinite;
}
@keyframes MediumDash {
0% { stroke-dashoffset: 150; }
50% {
stroke-dashoffset: 50;
transform:rotate(135deg);
}
100% {
stroke-dashoffset: 150;
transform:rotate(450deg);
}
}
.LargeSpinnerPath {
stroke-dasharray: 200;
stroke-dashoffset: 0;
transform-origin: center;
animation:
LargeDash 1.3s ease-in-out infinite;
}
@keyframes LargeDash {
0% { stroke-dashoffset: 200; }
50% {
stroke-dashoffset: 50;
transform:rotate(135deg);
}
100% {
stroke-dashoffset: 200;
transform:rotate(450deg);
}
}

View File

@@ -0,0 +1,51 @@
import React from 'react';
import './Spinner.css';
const SPINNER_SIZES = {
small: 30,
medium: 50,
large: 70,
};
const STROKE_WIDTHS = {
small: 4,
medium: 5,
large: 6,
};
const PATH_CLASS_NAMES = {
small: 'SmallSpinnerPath',
medium: 'MediumSpinnerPath',
large: 'LargeSpinnerPath',
};
// Heavily inspired by https://codepen.io/mrrocks/pen/EiplA
export default function Spinner({size = 'small'}) {
const baseSize = SPINNER_SIZES[size];
const pathSize = baseSize / 2;
const strokeWidth = STROKE_WIDTHS[size];
const pathRadius = `${baseSize / 2 - strokeWidth}px`;
const className = PATH_CLASS_NAMES[size];
const containerClassName = `SpinnerContainer SpinnerContainer-${size}`;
return (
<div className={containerClassName}>
<svg
className={className}
width={baseSize}
height={baseSize}
viewBox={`0 0 ${baseSize} ${baseSize}`}>
<circle
className="SpinnerPath"
fill="none"
stroke="currentColor"
strokeWidth={strokeWidth}
strokeLinecap="round"
cx={pathSize}
cy={pathSize}
r={pathRadius}
/>
</svg>
</div>
);
}

View File

@@ -0,0 +1,170 @@
import React, {Suspense} from 'react';
import {unstable_createResource} from 'react-cache';
import Spinner from './Spinner';
import {fetchUserProfileJSON, fetchUserRepositoriesListJSON} from '../api';
export default function UserPage({id}) {
return (
<div
style={{
display: 'grid',
gridTemplateColumns: 'repeat(auto-fill, 20rem)',
gridGap: '1rem',
alignItems: 'start',
}}>
<UserDetails id={id} />
<Suspense maxDuration={1000} fallback={<Spinner size="medium" />}>
<Repositories id={id} />
</Suspense>
</div>
);
}
const UserDetailsResource = unstable_createResource(fetchUserProfileJSON);
function UserDetails({id}) {
const user = UserDetailsResource.read(id);
return (
<div
style={{
display: 'grid',
gridGap: '0.5rem',
width: '20rem',
padding: '1rem',
backgroundColor: 'var(--color-buttonBg)',
border: '1px solid var(--color-buttonBorder)',
borderRadius: '1rem',
}}>
<UserPicture source={user.image} />
<div
style={{
fontSize: '1.5rem',
fontWeight: 'bold',
color: 'var(--color-pageTextDark)',
}}>
{user.name}
</div>
<div style={{fontSize: '1.25rem'}}>{user.id}</div>
{user.tagline !== null && <div>{user.tagline}</div>}
<hr
style={{
width: '100%',
height: '1px',
border: 'none',
backgroundColor: '#ddd',
}}
/>
{user.location && <Location location={user.location} />}
{user.email && <Email email={user.email} />}
</div>
);
}
const Location = ({location}) => (
<div
style={{
display: 'flex',
alignItems: 'center',
}}>
<svg
viewBox="0 0 24 24"
style={{
width: '24px',
height: '24px',
marginRight: '0.5rem',
fill: 'currentColor',
}}>
<path d="M12 2C8.13 2 5 5.13 5 9c0 5.25 7 13 7 13s7-7.75 7-13c0-3.87-3.13-7-7-7zm0 9.5c-1.38 0-2.5-1.12-2.5-2.5s1.12-2.5 2.5-2.5 2.5 1.12 2.5 2.5-1.12 2.5-2.5 2.5z" />
<path d="M0 0h24v24H0z" fill="none" />
</svg>
{location}
</div>
);
const Email = ({email}) => (
<div
style={{
display: 'flex',
alignItems: 'center',
}}>
<svg
viewBox="0 0 24 24"
style={{
width: '24px',
height: '24px',
marginRight: '0.5rem',
fill: 'currentColor',
}}>
<path d="M20 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm0 4l-8 5-8-5V6l8 5 8-5v2z" />
<path d="M0 0h24v24H0z" fill="none" />
</svg>
<a href={`mailto:${email}`}>{email}</a>
</div>
);
const ImageResource = unstable_createResource(
src =>
new Promise(resolve => {
const img = new Image();
img.onload = () => resolve(src);
img.src = src;
})
);
function Img({src, alt, ...rest}) {
return <img src={ImageResource.read(src)} alt={alt} {...rest} />;
}
function UserPicture({source}) {
return (
<Suspense maxDuration={1500} fallback={<img src={source} alt="poster" />}>
<Img
src={source}
alt="profile picture"
style={{
width: '100%',
height: 'auto',
borderRadius: '0.5rem',
}}
/>
</Suspense>
);
}
const UserRepositoriesResource = unstable_createResource(
fetchUserRepositoriesListJSON
);
function Repositories({id}) {
const repos = UserRepositoriesResource.read(id);
return (
<ul
style={{
display: 'grid',
gridGap: '1rem',
padding: 0,
margin: 0,
}}>
{repos.map(repo => <Repository key={repo.name} {...repo} />)}
</ul>
);
}
function Repository({description, name, url}) {
return (
<li
style={{
display: 'grid',
gridGap: '0.5rem',
padding: '1rem',
backgroundColor: 'var(--color-buttonBg)',
border: '1px solid var(--color-buttonBorder)',
borderRadius: '1rem',
}}>
<strong>
<a href={url}>{name}</a>
</strong>
<div>{description}</div>
</li>
);
}

View File

@@ -0,0 +1,90 @@
* { box-sizing: border-box; }
:root {
--color-debuggerBg: #f7f7f7;
--color-debuggerText: #333;
--color-debuggerBorder: #e7e7e7;
--color-panelBg: #f7f7f7;
--color-panelText: #333;
--color-pageTextDark: #000;
--color-pageText: #333;
--color-pageBg: #fff;
--color-buttonBg: #f7f7f7;
--color-buttonBorder: #e7e7e7;
--pt: 8px;
}
body {
margin: 0;
padding: calc(var(--pt)*4);
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
color: var(--color-pageText);
background-color: var(--color-pageBg);
}
/* -------------------------------- */
/* Debugger */
/* -------------------------------- */
#debugger {
position: absolute;
top: 0; left: 0; right: 0; bottom: 0;
/* width: 100vw; */
/* height: 100vh; */
pointer-events: none;
}
.🎛 {
position: fixed;
max-width: calc(var(--pt)*28);
border-radius: var(--pt);
padding: calc(var(--pt)*2);
background-color: var(--color-debuggerBg);
border: 1px solid var(--color-debuggerBorder);
border-radius: 0.5rem;
color: var(--color-debuggerText);
pointer-events: all;
}
.🕹 {
background-color: var(--color-buttonBg);
border: 1px solid var(--color-buttonBorder);
border-radius: var(--pt);
padding: 0;
width: calc(var(--pt)*5);
height: calc(var(--pt)*5);
font-size: calc(var(--pt)*3);
line-height: 1;
font-weight: bold;
cursor: pointer;
user-select: none;
}
.🕹.👶 {
width: calc(var(--pt)*3);
height: calc(var(--pt)*3);
font-size: calc(var(--pt)*2);
}
.🕹.🐘 {
width: auto;
height: calc(var(--pt)*7);
padding: var(--pt) calc(var(--pt)*2);
}
.🕹:hover {
background-color: white;
top: -4px;
left: -4px;
box-shadow: 4px 4px 0 var(--color-buttonBorder);
}
.🕹:active {
box-shadow: none;
top: 0;
left: 0;
}

View File

@@ -0,0 +1,275 @@
import React, {Fragment, PureComponent} from 'react';
import {unstable_createRoot, render} from 'react-dom';
import {unstable_trace as trace} from 'scheduler/tracing';
import {
setFakeRequestTime,
setPaused,
setPauseNewRequests,
setProgressHandler,
} from './api';
import App from './components/App';
import Draggable from 'react-draggable';
import './index.css';
let handleReset;
class Shell extends PureComponent {
state = {
iteration: 0,
};
componentDidMount() {
handleReset = this.handleReset;
}
handleReset = () =>
this.setState(prevState => ({
iteration: prevState.iteration + 1,
}));
render() {
return <App key={this.state.iteration} />;
}
}
class Debugger extends PureComponent {
state = {
iteration: 0,
strategy: 'async',
requestTime: 1,
showDebugger: false,
pauseNewRequests: false,
waitTime: 0,
requests: {},
};
componentDidMount() {
setFakeRequestTime(this.state.requestTime * 1000);
setProgressHandler(this.handleProgress);
window.addEventListener('keydown', e => {
if (e.key.toLowerCase() === '/') {
this.setState(state => ({
showDebugger: !state.showDebugger,
}));
} else if (e.key.toLowerCase() === 'p') {
this.togglePauseRequests();
}
});
}
componentDidUpdate(prevProps, prevState) {
if (prevState.requestTime !== this.state.requestTime) {
setFakeRequestTime(this.state.requestTime * 1000);
}
}
handleReset = () => {
trace('Clear cache', performance.now(), () => {
// TODO: this is not implemented.
// cache.invalidate();
this.setState(state => ({
requests: {},
}));
handleReset();
});
};
handleProgress = (url, progress, isPaused) => {
this.setState(state => ({
requests: {
...state.requests,
[url]: {
url,
progress,
isPaused,
},
},
}));
};
togglePauseRequests = () => {
this.setState(
prevState => {
return {pauseNewRequests: !prevState.pauseNewRequests};
},
() => {
setPauseNewRequests(this.state.pauseNewRequests);
}
);
};
render() {
if (!this.state.showDebugger) {
return null;
}
return (
<Draggable cancel="input">
<div
className="🎛"
style={{
bottom: 20,
right: 20,
}}>
<div>
Latency: {this.state.requestTime} second{this.state.requestTime !==
1
? 's'
: ''}{' '}
<input
type="range"
min="0"
max="3"
step="0.5"
style={{width: '100%'}}
value={this.state.requestTime}
onChange={e => {
e.stopPropagation();
this.setState({requestTime: parseFloat(e.target.value)});
}}
/>
</div>
<label>
<input
type="checkbox"
checked={this.state.pauseNewRequests}
onChange={this.togglePauseRequests}
/>
Pause new requests
</label>
<br />
<br />
{Object.values(this.state.requests).filter(x => x.progress !== 100)
.length > 0 ? (
<Fragment>
<div style={{marginBottom: 10}}>
<b>Loading</b>
</div>
</Fragment>
) : (
<Fragment>
<div style={{marginBottom: 10}}>
<b>Loading</b>
</div>
<small style={{height: 20, display: 'block'}}>(None)</small>
</Fragment>
)}
{Object.keys(this.state.requests)
.reverse()
.map(url => {
const {progress, isPaused} = this.state.requests[url];
if (progress === 100) {
return null;
}
return (
<div
key={url}
style={{
height: 20,
width: '100%',
position: 'relative',
cursor: 'pointer',
title: isPaused ? 'Resume' : 'Pause',
}}
onClick={e => {
setPaused(url, !isPaused);
}}>
<div
style={{
height: '100%',
width: progress + '%',
position: 'absolute',
left: 0,
top: 0,
backgroundColor: isPaused ? '#fbfb0e' : '#61dafb',
zIndex: -1,
opacity: 0.8,
}}
/>
<div
style={{
fontFamily: 'monospace',
fontWeight: 'bold',
color: 'black',
}}>
{url}
</div>
</div>
);
})}
{Object.values(this.state.requests).filter(x => x.progress === 100)
.length > 0 ? (
<Fragment>
<br />
<div style={{marginBottom: 10}}>
<b>Cached</b>{' '}
<button
style={{
height: 16,
outline: 'none',
border: 'none',
background: 'none',
cursor: 'pointer',
}}
onClick={this.handleReset}>
🗑
</button>
</div>
</Fragment>
) : (
<Fragment>
<br />
<div style={{marginBottom: 10}}>
<b>Cached</b>
</div>
<small style={{height: 20, display: 'block'}}>(None)</small>
</Fragment>
)}
{Object.keys(this.state.requests)
.reverse()
.map(url => {
const {progress} = this.state.requests[url];
if (progress !== 100) {
return null;
}
return (
<div
key={url}
style={{
height: 20,
width: '100%',
position: 'relative',
}}>
<div
style={{
height: '100%',
width: progress + '%',
position: 'absolute',
left: 0,
top: 0,
backgroundColor:
progress !== 100 ? '#61dafb' : 'lightgreen',
zIndex: -1,
opacity: 0.8,
}}
/>
<div
style={{
fontFamily: 'monospace',
fontWeight: 'bold',
color: 'black',
}}>
{url}
</div>
</div>
);
})}
</div>
</Draggable>
);
}
}
unstable_createRoot(document.getElementById('root')).render(<Shell />);
render(<Debugger />, document.getElementById('debugger'));

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
import React, {PureComponent} from 'react';
import {flushSync, unstable_createRoot} from 'react-dom';
import Scheduler from 'scheduler';
import {flushSync, render} from 'react-dom';
import {unstable_scheduleCallback} from 'scheduler';
import _ from 'lodash';
import Charts from './Charts';
import Clock from './Clock';
@@ -67,7 +67,7 @@ class App extends PureComponent {
}
this._ignoreClick = true;
Scheduler.unstable_next(() => {
unstable_scheduleCallback(() => {
this.setState({showDemo: true}, () => {
this._ignoreClick = false;
});
@@ -146,5 +146,9 @@ class App extends PureComponent {
}
const container = document.getElementById('root');
const root = ReactDOM.unstable_createRoot(container);
root.render(<App />, container);
render(
<React.unstable_ConcurrentMode>
<App />
</React.unstable_ConcurrentMode>,
container
);

View File

@@ -0,0 +1,14 @@
<html>
<body>
<script src="../../build/node_modules/react/umd/react.development.js"></script>
<script src="../../build/node_modules/react-dom/umd/react-dom-unstable-fire.development.js"></script>
<script src="https://unpkg.com/babel-standalone@6/babel.js"></script>
<div id="container"></div>
<script type="text/babel">
ReactFire.render(
<h1>Hello World!</h1>,
document.getElementById('container')
);
</script>
</body>
</html>

View File

@@ -1,41 +1,40 @@
{
"private": true,
"version": "16.6.1",
"workspaces": [
"packages/*"
],
"devDependencies": {
"@babel/cli": "^7.0.0",
"@babel/code-frame": "^7.0.0",
"@babel/core": "^7.0.0",
"@babel/helper-module-imports": "^7.0.0",
"@babel/plugin-external-helpers": "^7.0.0",
"@babel/plugin-proposal-class-properties": "^7.0.0",
"@babel/plugin-proposal-object-rest-spread": "^7.0.0",
"@babel/plugin-syntax-dynamic-import": "^7.0.0",
"@babel/plugin-syntax-jsx": "^7.2.0",
"@babel/plugin-transform-arrow-functions": "^7.0.0",
"@babel/plugin-transform-async-to-generator": "^7.0.0",
"@babel/plugin-transform-block-scoped-functions": "^7.0.0",
"@babel/plugin-transform-block-scoping": "^7.0.0",
"@babel/plugin-transform-classes": "^7.0.0",
"@babel/plugin-transform-computed-properties": "^7.0.0",
"@babel/plugin-transform-destructuring": "^7.0.0",
"@babel/plugin-transform-for-of": "^7.0.0",
"@babel/plugin-transform-literals": "^7.0.0",
"@babel/plugin-transform-modules-commonjs": "^7.0.0",
"@babel/plugin-transform-object-super": "^7.0.0",
"@babel/plugin-transform-parameters": "^7.0.0",
"@babel/plugin-transform-react-jsx-source": "^7.0.0",
"@babel/plugin-transform-shorthand-properties": "^7.0.0",
"@babel/plugin-transform-spread": "^7.0.0",
"@babel/plugin-transform-template-literals": "^7.0.0",
"@babel/preset-flow": "^7.0.0",
"@babel/preset-react": "^7.0.0",
"@babel/traverse": "^7.0.0",
"@mattiasbuelens/web-streams-polyfill": "0.1.0",
"art": "^0.10.1",
"babel-cli": "^6.6.5",
"babel-code-frame": "^6.26.0",
"babel-core": "^6.0.0",
"babel-eslint": "^10.0.0",
"babel-jest": "^23.0.1",
"babel-plugin-check-es2015-constants": "^6.5.0",
"babel-plugin-external-helpers": "^6.22.0",
"babel-plugin-syntax-trailing-function-commas": "^6.5.0",
"babel-plugin-transform-async-to-generator": "^6.22.0",
"babel-plugin-transform-class-properties": "^6.11.5",
"babel-plugin-transform-es2015-arrow-functions": "^6.5.2",
"babel-plugin-transform-es2015-block-scoped-functions": "^6.5.0",
"babel-plugin-transform-es2015-block-scoping": "^6.23.0",
"babel-plugin-transform-es2015-classes": "^6.5.2",
"babel-plugin-transform-es2015-computed-properties": "^6.5.2",
"babel-plugin-transform-es2015-destructuring": "^6.5.0",
"babel-plugin-transform-es2015-for-of": "^6.5.2",
"babel-plugin-transform-es2015-literals": "^6.5.0",
"babel-plugin-transform-es2015-modules-commonjs": "^6.5.2",
"babel-plugin-transform-es2015-object-super": "^6.5.0",
"babel-plugin-transform-es2015-parameters": "^6.5.0",
"babel-plugin-transform-es2015-shorthand-properties": "^6.5.0",
"babel-plugin-transform-es2015-spread": "^6.5.2",
"babel-plugin-transform-es2015-template-literals": "^6.5.2",
"babel-plugin-transform-object-rest-spread": "^6.6.5",
"babel-plugin-transform-react-jsx-source": "^6.8.0",
"babel-plugin-transform-regenerator": "^6.26.0",
"babel-preset-react": "^6.5.0",
"babel-traverse": "^6.9.0",
"babylon": "6.18.0",
"chalk": "^1.1.3",
"cli-table": "^0.3.1",
@@ -44,40 +43,38 @@
"coveralls": "^2.11.6",
"create-react-class": "^15.6.3",
"cross-env": "^5.1.1",
"danger": "^9.1.8",
"danger": "^3.0.4",
"error-stack-parser": "^2.0.2",
"eslint": "^6.1.0",
"eslint": "^4.1.0",
"eslint-config-fbjs": "^1.1.1",
"eslint-plugin-babel": "^5.3.0",
"eslint-plugin-babel": "^3.3.0",
"eslint-plugin-flowtype": "^2.25.0",
"eslint-plugin-jest": "^22.15.0",
"eslint-plugin-jest": "^21.6.1",
"eslint-plugin-no-for-of-loops": "^1.0.0",
"eslint-plugin-react": "^6.7.1",
"eslint-plugin-react-internal": "link:./scripts/eslint-rules",
"eslint-plugin-react-internal": "link:./scripts/eslint-rules/",
"fbjs-scripts": "^0.8.3",
"filesize": "^3.5.6",
"flow-bin": "^0.72.0",
"glob": "^6.0.4",
"glob-stream": "^6.1.0",
"google-closure-compiler": "20190301.0.0",
"google-closure-compiler": "20190106.0.0",
"gzip-size": "^3.0.0",
"jasmine-check": "^1.0.0-rc.0",
"jest": "^24.9.0",
"jest-diff": "^24.9.0",
"jest-snapshot-serializer-raw": "^1.1.0",
"jest": "^23.1.0",
"jest-diff": "^23.0.1",
"minimatch": "^3.0.4",
"minimist": "^1.2.0",
"mkdirp": "^0.5.1",
"ncp": "^2.0.0",
"object-assign": "^4.1.1",
"pacote": "^9.5.6",
"prettier": "1.13.7",
"prop-types": "^15.6.2",
"random-seed": "^0.3.0",
"react-lifecycles-compat": "^3.0.2",
"rimraf": "^2.6.1",
"rollup": "^0.52.1",
"rollup-plugin-babel": "^4.0.1",
"rollup-plugin-babel": "^3.0.1",
"rollup-plugin-commonjs": "^8.2.6",
"rollup-plugin-node-resolve": "^2.1.1",
"rollup-plugin-prettier": "^0.3.0",
@@ -87,10 +84,11 @@
"targz": "^1.0.1",
"through2": "^2.0.0",
"tmp": "~0.0.28",
"typescript": "~1.8.10"
"typescript": "~1.8.10",
"@mattiasbuelens/web-streams-polyfill": "0.1.0"
},
"devEngines": {
"node": "8.x || 9.x || 10.x || 11.x || 12.x"
"node": "8.x || 9.x || 10.x || 11.x"
},
"jest": {
"testRegex": "/scripts/jest/dont-run-jest-directly\\.js$"
@@ -100,19 +98,15 @@
"linc": "node ./scripts/tasks/linc.js",
"lint": "node ./scripts/tasks/eslint.js",
"lint-build": "node ./scripts/rollup/validate/index.js",
"extract-errors": "yarn build --type=dev --extract-errors",
"postinstall": "node node_modules/fbjs-scripts/node/check-dev-engines.js package.json && node ./scripts/flow/createFlowConfigs.js && node ./scripts/yarn/downloadReactIsForPrettyFormat.js",
"postinstall": "node node_modules/fbjs-scripts/node/check-dev-engines.js package.json && node ./scripts/flow/createFlowConfigs.js",
"debug-test": "cross-env NODE_ENV=development node --inspect-brk node_modules/.bin/jest --config ./scripts/jest/config.source.js --runInBand",
"test": "cross-env NODE_ENV=development jest --config ./scripts/jest/config.source.js",
"test-persistent": "cross-env NODE_ENV=development jest --config ./scripts/jest/config.source-persistent.js",
"debug-test-persistent": "cross-env NODE_ENV=development node --inspect-brk node_modules/.bin/jest --config ./scripts/jest/config.source-persistent.js --runInBand",
"test-fire": "cross-env NODE_ENV=development jest --config ./scripts/jest/config.source-fire.js",
"test-prod": "cross-env NODE_ENV=production jest --config ./scripts/jest/config.source.js",
"test-fire-prod": "cross-env NODE_ENV=production jest --config ./scripts/jest/config.source-fire.js",
"test-prod-build": "yarn test-build-prod",
"test-build": "cross-env NODE_ENV=development jest --config ./scripts/jest/config.build.js",
"test-build-prod": "cross-env NODE_ENV=production jest --config ./scripts/jest/config.build.js",
"test-build-devtools": "cross-env NODE_ENV=development jest --config ./scripts/jest/config.build-devtools.js",
"debug-test-build-devtools": "cross-env NODE_ENV=development node --inspect-brk node_modules/.bin/jest --config ./scripts/jest/config.build-devtools.js",
"test-dom-fixture": "cd fixtures/dom && yarn && yarn prestart && yarn test",
"flow": "node ./scripts/tasks/flow.js",
"flow-ci": "node ./scripts/tasks/flow-ci.js",
"prettier": "node ./scripts/prettier/index.js write-changed",

View File

@@ -1,5 +0,0 @@
This package is intended to eventually replace the current `@babel/plugin-transform-react-jsx`, changing the JSX transform from targeting `React.createElement(type, props, children)` to `React.jsx(types, props, key)`.
https://github.com/reactjs/rfcs/blob/createlement-rfc/text/0000-create-element-changes.md
**This is experimental and not intended to be used directly.**

View File

@@ -1,392 +0,0 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/* eslint-disable quotes */
'use strict';
const babel = require('@babel/core');
const codeFrame = require('@babel/code-frame');
const {wrap} = require('jest-snapshot-serializer-raw');
function transform(input, options) {
return wrap(
babel.transform(input, {
configFile: false,
plugins: [
'@babel/plugin-syntax-jsx',
'@babel/plugin-transform-arrow-functions',
...(options && options.development
? [
'@babel/plugin-transform-react-jsx-source',
'@babel/plugin-transform-react-jsx-self',
]
: []),
[
'./packages/babel-plugin-react-jsx',
{
development: __DEV__,
useBuiltIns: true,
useCreateElement: true,
...options,
},
],
],
}).code
);
}
describe('transform react to jsx', () => {
it('fragment with no children', () => {
expect(transform(`var x = <></>`)).toMatchSnapshot();
});
it('React.Fragment to set keys and source', () => {
expect(
transform(`var x = <React.Fragment key='foo'><div /></React.Fragment>`, {
development: true,
})
).toMatchSnapshot();
});
it('normal fragments not to set key and source', () => {
expect(
transform(`var x = <><div /></>`, {
development: true,
})
).toMatchSnapshot();
});
it('should properly handle comments adjacent to children', () => {
expect(
transform(`
var x = (
<div>
{/* A comment at the beginning */}
{/* A second comment at the beginning */}
<span>
{/* A nested comment */}
</span>
{/* A sandwiched comment */}
<br />
{/* A comment at the end */}
{/* A second comment at the end */}
</div>
);
`)
).toMatchSnapshot();
});
it('adds appropriate new lines when using spread attribute', () => {
expect(transform(`<Component {...props} sound="moo" />`)).toMatchSnapshot();
});
it('arrow functions', () => {
expect(
transform(`
var foo = function () {
return () => <this />;
};
var bar = function () {
return () => <this.foo />;
};
`)
).toMatchSnapshot();
});
it('assignment', () => {
expect(
transform(`var div = <Component {...props} foo="bar" />`)
).toMatchSnapshot();
});
it('concatenates adjacent string literals', () => {
expect(
transform(`
var x =
<div>
foo
{"bar"}
baz
<div>
buz
bang
</div>
qux
{null}
quack
</div>
`)
).toMatchSnapshot();
});
it('should allow constructor as prop', () => {
expect(transform(`<Component constructor="foo" />;`)).toMatchSnapshot();
});
it('should allow deeper js namespacing', () => {
expect(
transform(`<Namespace.DeepNamespace.Component />;`)
).toMatchSnapshot();
});
it('should allow elements as attributes', () => {
expect(transform(`<div attr=<div /> />`)).toMatchSnapshot();
});
it('should allow js namespacing', () => {
expect(transform(`<Namespace.Component />;`)).toMatchSnapshot();
});
it('should allow nested fragments', () => {
expect(
transform(`
<div>
< >
<>
<span>Hello</span>
<span>world</span>
</>
<>
<span>Goodbye</span>
<span>world</span>
</>
</>
</div>
`)
).toMatchSnapshot();
});
it('should avoid wrapping in extra parens if not needed', () => {
expect(
transform(`
var x = <div>
<Component />
</div>;
var x = <div>
{props.children}
</div>;
var x = <Composite>
{props.children}
</Composite>;
var x = <Composite>
<Composite2 />
</Composite>;
`)
).toMatchSnapshot();
});
it('should convert simple tags', () => {
expect(transform(`var x = <div></div>;`)).toMatchSnapshot();
});
it('should convert simple text', () => {
expect(transform(`var x = <div>text</div>;`)).toMatchSnapshot();
});
it('should disallow spread children', () => {
let _error;
const code = `<div>{...children}</div>;`;
try {
transform(code);
} catch (error) {
_error = error;
}
expect(_error).toEqual(
new SyntaxError(
'undefined: Spread children are not supported in React.' +
'\n' +
codeFrame.codeFrameColumns(
code,
{start: {line: 1, column: 6}},
{highlightCode: true}
)
)
);
});
it('should escape xhtml jsxattribute', () => {
expect(
transform(`
<div id="wôw" />;
<div id="\w" />;
<div id="w &lt; w" />;
`)
).toMatchSnapshot();
});
it('should escape xhtml jsxtext', () => {
/* eslint-disable no-irregular-whitespace */
expect(
transform(`
<div>wow</div>;
<div>wôw</div>;
<div>w & w</div>;
<div>w &amp; w</div>;
<div>w &nbsp; w</div>;
<div>this should not parse as unicode: \u00a0</div>;
<div>this should parse as nbsp:   </div>;
<div>this should parse as unicode: {'\u00a0 '}</div>;
<div>w &lt; w</div>;
`)
).toMatchSnapshot();
/*eslint-enable */
});
it('should handle attributed elements', () => {
expect(
transform(`
var HelloMessage = React.createClass({
render: function() {
return <div>Hello {this.props.name}</div>;
}
});
React.render(<HelloMessage name={
<span>
Sebastian
</span>
} />, mountNode);
`)
).toMatchSnapshot();
});
it('should handle has own property correctly', () => {
expect(
transform(`<hasOwnProperty>testing</hasOwnProperty>;`)
).toMatchSnapshot();
});
it('should have correct comma in nested children', () => {
expect(
transform(`
var x = <div>
<div><br /></div>
<Component>{foo}<br />{bar}</Component>
<br />
</div>;
`)
).toMatchSnapshot();
});
it('should insert commas after expressions before whitespace', () => {
expect(
transform(`
var x =
<div
attr1={
"foo" + "bar"
}
attr2={
"foo" + "bar" +
"baz" + "bug"
}
attr3={
"foo" + "bar" +
"baz" + "bug"
}
attr4="baz">
</div>
`)
).toMatchSnapshot();
});
it('should not add quotes to identifier names', () => {
expect(
transform(`var e = <F aaa new const var default foo-bar/>;`)
).toMatchSnapshot();
});
it('should not strip nbsp even couple with other whitespace', () => {
expect(transform(`<div>&nbsp; </div>;`)).toMatchSnapshot();
});
it('should not strip tags with a single child of nbsp', () => {
expect(transform(`<div>&nbsp;</div>;`)).toMatchSnapshot();
});
it('should properly handle comments between props', () => {
expect(
transform(`
var x = (
<div
/* a multi-line
comment */
attr1="foo">
<span // a double-slash comment
attr2="bar"
/>
</div>
);
`)
).toMatchSnapshot();
});
it('should quote jsx attributes', () => {
expect(
transform(`<button data-value='a value'>Button</button>`)
).toMatchSnapshot();
});
it('should support xml namespaces if flag', () => {
expect(
transform('<f:image n:attr />', {throwIfNamespace: false})
).toMatchSnapshot();
});
it('should throw error namespaces if not flag', () => {
let _error;
const code = `<f:image />`;
try {
transform(code);
} catch (error) {
_error = error;
}
expect(_error).toEqual(
new SyntaxError(
"undefined: Namespace tags are not supported by default. React's " +
"JSX doesn't support namespace tags. You can turn on the " +
"'throwIfNamespace' flag to bypass this warning." +
'\n' +
codeFrame.codeFrameColumns(
code,
{start: {line: 1, column: 2}},
{highlightCode: true}
)
)
);
});
it('should transform known hyphenated tags', () => {
expect(transform(`<font-face />`)).toMatchSnapshot();
});
it('wraps props in react spread for first spread attributes', () => {
expect(transform(`<Component {...x} y={2} z />`)).toMatchSnapshot();
});
it('wraps props in react spread for last spread attributes', () => {
expect(transform(`<Component y={2} z { ... x } />`)).toMatchSnapshot();
});
it('wraps props in react spread for middle spread attributes', () => {
expect(transform(`<Component y={2} { ... x } z />`)).toMatchSnapshot();
});
it('useBuiltIns false uses extend instead of Object.assign', () => {
expect(
transform(`<Component y={2} {...x} />`, {useBuiltIns: false})
).toMatchSnapshot();
});
});

View File

@@ -1,504 +0,0 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/* eslint-disable quotes */
'use strict';
const babel = require('@babel/core');
const codeFrame = require('@babel/code-frame');
const {wrap} = require('jest-snapshot-serializer-raw');
function transform(input, options) {
return wrap(
babel.transform(input, {
configFile: false,
plugins: [
'@babel/plugin-syntax-jsx',
'@babel/plugin-transform-arrow-functions',
...(options && options.development
? [
'@babel/plugin-transform-react-jsx-source',
'@babel/plugin-transform-react-jsx-self',
]
: []),
[
'./packages/babel-plugin-react-jsx',
{
useBuiltIns: true,
useCreateElement: false,
...options,
},
],
],
}).code
);
}
describe('transform react to jsx', () => {
it('fragment with no children', () => {
expect(transform(`var x = <></>`)).toMatchSnapshot();
});
it('fragments', () => {
expect(transform(`var x = <><div /></>`)).toMatchSnapshot();
});
it('fragments to set keys', () => {
expect(
transform(`var x = <React.Fragment key="foo"></React.Fragment>`)
).toMatchSnapshot();
});
it('React.fragment to set keys and source', () => {
expect(
transform(`var x = <React.Fragment key='foo'></React.Fragment>`, {
development: true,
})
).toMatchSnapshot();
});
it('fragments in dev mode (no key and source)', () => {
expect(
transform(`var x = <><div /></>`, {
development: true,
})
).toMatchSnapshot();
});
it('nonStatic children', () => {
expect(
transform(
`var x = (
<div>
{[<span key={'0'} />, <span key={'1'} />]}
</div>
);
`,
{
development: true,
}
)
).toMatchSnapshot();
});
it('static children', () => {
expect(
transform(
`var x = (
<div>
<span />
{[<span key={'0'} />, <span key={'1'} />]}
</div>
);
`,
{
development: true,
}
)
).toMatchSnapshot();
});
it('uses jsxDEV instead of jsx in dev mode', () => {
expect(
transform(`var x = <span propOne="one">Hi</span>`, {development: true})
).toMatchSnapshot();
});
it('properly passes in source and self', () => {
expect(
transform(`var x = <div />;`, {development: true})
).toMatchSnapshot();
});
it('should properly handle potentially null variables', () => {
expect(
transform(`
var foo = null;
var x = <div {...foo} />;
`)
).toMatchSnapshot();
});
it('properly handles keys', () => {
expect(
transform(`var x = (
<div>
<div key="1" />
<div key="2" meow="wolf" />
<div key="3" />
</div>
);`)
).toMatchSnapshot();
});
it('uses createElement when the key comes after a spread', () => {
expect(
transform(`var x = (
<div {...props} key="1" foo="bar" />
);`)
).toMatchSnapshot();
});
it('uses jsx when the key comes before a spread', () => {
expect(
transform(`var x = (
<div key="1" {...props} foo="bar" />
);`)
).toMatchSnapshot();
});
it('should properly handle comments adjacent to children', () => {
expect(
transform(`
var x = (
<div>
{/* A comment at the beginning */}
{/* A second comment at the beginning */}
<span>
{/* A nested comment */}
</span>
{/* A sandwiched comment */}
<br />
{/* A comment at the end */}
{/* A second comment at the end */}
</div>
);
`)
).toMatchSnapshot();
});
it('adds appropriate new lines when using spread attribute', () => {
expect(transform(`<Component {...props} sound="moo" />`)).toMatchSnapshot();
});
it('arrow functions', () => {
expect(
transform(`
var foo = function () {
return () => <this />;
};
var bar = function () {
return () => <this.foo />;
};
`)
).toMatchSnapshot();
});
it('assignment', () => {
expect(
transform(`var div = <Component {...props} foo="bar" />`)
).toMatchSnapshot();
});
it('concatenates adjacent string literals', () => {
expect(
transform(`
var x =
<div>
foo
{"bar"}
baz
<div>
buz
bang
</div>
qux
{null}
quack
</div>
`)
).toMatchSnapshot();
});
it('should allow constructor as prop', () => {
expect(transform(`<Component constructor="foo" />;`)).toMatchSnapshot();
});
it('should allow deeper js namespacing', () => {
expect(
transform(`<Namespace.DeepNamespace.Component />;`)
).toMatchSnapshot();
});
it('should allow elements as attributes', () => {
expect(transform(`<div attr=<div /> />`)).toMatchSnapshot();
});
it('should allow js namespacing', () => {
expect(transform(`<Namespace.Component />;`)).toMatchSnapshot();
});
it('should allow nested fragments', () => {
expect(
transform(`
<div>
< >
<>
<span>Hello</span>
<span>world</span>
</>
<>
<span>Goodbye</span>
<span>world</span>
</>
</>
</div>
`)
).toMatchSnapshot();
});
it('should avoid wrapping in extra parens if not needed', () => {
expect(
transform(`
var x = <div>
<Component />
</div>;
var x = <div>
{props.children}
</div>;
var x = <Composite>
{props.children}
</Composite>;
var x = <Composite>
<Composite2 />
</Composite>;
`)
).toMatchSnapshot();
});
it('should convert simple tags', () => {
expect(transform(`var x = <div></div>;`)).toMatchSnapshot();
});
it('should convert simple text', () => {
expect(transform(`var x = <div>text</div>;`)).toMatchSnapshot();
});
it('should disallow spread children', () => {
let _error;
const code = `<div>{...children}</div>;`;
try {
transform(code);
} catch (error) {
_error = error;
}
expect(_error).toEqual(
new SyntaxError(
'undefined: Spread children are not supported in React.' +
'\n' +
codeFrame.codeFrameColumns(
code,
{start: {line: 1, column: 6}},
{highlightCode: true}
)
)
);
});
it('should escape xhtml jsxattribute', () => {
expect(
transform(`
<div id="wôw" />;
<div id="\w" />;
<div id="w &lt; w" />;
`)
).toMatchSnapshot();
});
it('should escape xhtml jsxtext', () => {
/* eslint-disable no-irregular-whitespace */
expect(
transform(`
<div>wow</div>;
<div>wôw</div>;
<div>w & w</div>;
<div>w &amp; w</div>;
<div>w &nbsp; w</div>;
<div>this should not parse as unicode: \u00a0</div>;
<div>this should parse as nbsp:   </div>;
<div>this should parse as unicode: {'\u00a0 '}</div>;
<div>w &lt; w</div>;
`)
).toMatchSnapshot();
/*eslint-enable */
});
it('should handle attributed elements', () => {
expect(
transform(`
var HelloMessage = React.createClass({
render: function() {
return <div>Hello {this.props.name}</div>;
}
});
React.render(<HelloMessage name={
<span>
Sebastian
</span>
} />, mountNode);
`)
).toMatchSnapshot();
});
it('should handle has own property correctly', () => {
expect(
transform(`<hasOwnProperty>testing</hasOwnProperty>;`)
).toMatchSnapshot();
});
it('should have correct comma in nested children', () => {
expect(
transform(`
var x = <div>
<div><br /></div>
<Component>{foo}<br />{bar}</Component>
<br />
</div>;
`)
).toMatchSnapshot();
});
it('should insert commas after expressions before whitespace', () => {
expect(
transform(`
var x =
<div
attr1={
"foo" + "bar"
}
attr2={
"foo" + "bar" +
"baz" + "bug"
}
attr3={
"foo" + "bar" +
"baz" + "bug"
}
attr4="baz">
</div>
`)
).toMatchSnapshot();
});
it('should not add quotes to identifier names', () => {
expect(
transform(`var e = <F aaa new const var default foo-bar/>;`)
).toMatchSnapshot();
});
it('should not strip nbsp even couple with other whitespace', () => {
expect(transform(`<div>&nbsp; </div>;`)).toMatchSnapshot();
});
it('should not strip tags with a single child of nbsp', () => {
expect(transform(`<div>&nbsp;</div>;`)).toMatchSnapshot();
});
it('should properly handle comments between props', () => {
expect(
transform(`
var x = (
<div
/* a multi-line
comment */
attr1="foo">
<span // a double-slash comment
attr2="bar"
/>
</div>
);
`)
).toMatchSnapshot();
});
it('should quote jsx attributes', () => {
expect(
transform(`<button data-value='a value'>Button</button>`)
).toMatchSnapshot();
});
it('should support xml namespaces if flag', () => {
expect(
transform('<f:image n:attr />', {throwIfNamespace: false})
).toMatchSnapshot();
});
it('should throw error namespaces if not flag', () => {
let _error;
const code = `<f:image />`;
try {
transform(code);
} catch (error) {
_error = error;
}
expect(_error).toEqual(
new SyntaxError(
"undefined: Namespace tags are not supported by default. React's " +
"JSX doesn't support namespace tags. You can turn on the " +
"'throwIfNamespace' flag to bypass this warning." +
'\n' +
codeFrame.codeFrameColumns(
code,
{start: {line: 1, column: 2}},
{highlightCode: true}
)
)
);
});
it('should transform known hyphenated tags', () => {
expect(transform(`<font-face />`)).toMatchSnapshot();
});
it('wraps props in react spread for first spread attributes', () => {
expect(transform(`<Component {...x} y={2} z />`)).toMatchSnapshot();
});
it('wraps props in react spread for last spread attributes', () => {
expect(transform(`<Component y={2} z { ... x } />`)).toMatchSnapshot();
});
it('wraps props in react spread for middle spread attributes', () => {
expect(transform(`<Component y={2} { ... x } z />`)).toMatchSnapshot();
});
it('useBuiltIns false uses extend instead of Object.assign', () => {
expect(
transform(`<Component y={2} {...x} />`, {useBuiltIns: false})
).toMatchSnapshot();
});
it('duplicate children prop should transform into sequence expression with actual children', () => {
expect(
transform(`<Component children={1}>2</Component>`)
).toMatchSnapshot();
});
it('duplicate children prop should transform into sequence expression with next prop', () => {
expect(
transform(`<Component children={1} foo={3}>2</Component>`)
).toMatchSnapshot();
});
it('duplicate children props should transform into sequence expression with next prop', () => {
expect(
transform(`<Component children={1} children={4} foo={3}>2</Component>`)
).toMatchSnapshot();
});
it('duplicate children prop should transform into sequence expression with spread', () => {
expect(
transform(`<Component children={1} {...x}>2</Component>`)
).toMatchSnapshot();
});
});

View File

@@ -1,213 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`transform react to jsx React.Fragment to set keys and source 1`] = `
var _jsxFileName = "";
var x = React.createElement(React.Fragment, {
key: "foo",
__source: {
fileName: _jsxFileName,
lineNumber: 1
},
__self: this
}, React.createElement("div", {
__source: {
fileName: _jsxFileName,
lineNumber: 1
},
__self: this
}));
`;
exports[`transform react to jsx adds appropriate new lines when using spread attribute 1`] = `
React.createElement(Component, Object.assign({}, props, {
sound: "moo"
}));
`;
exports[`transform react to jsx arrow functions 1`] = `
var foo = function () {
var _this = this;
return function () {
return React.createElement(_this, null);
};
};
var bar = function () {
var _this2 = this;
return function () {
return React.createElement(_this2.foo, null);
};
};
`;
exports[`transform react to jsx assignment 1`] = `
var div = React.createElement(Component, Object.assign({}, props, {
foo: "bar"
}));
`;
exports[`transform react to jsx concatenates adjacent string literals 1`] = `var x = React.createElement("div", null, "foo", "bar", "baz", React.createElement("div", null, "buz bang"), "qux", null, "quack");`;
exports[`transform react to jsx fragment with no children 1`] = `var x = React.createElement(React.Fragment, null);`;
exports[`transform react to jsx normal fragments not to set key and source 1`] = `
var _jsxFileName = "";
var x = React.createElement(React.Fragment, null, React.createElement("div", {
__source: {
fileName: _jsxFileName,
lineNumber: 1
},
__self: this
}));
`;
exports[`transform react to jsx should allow constructor as prop 1`] = `
React.createElement(Component, {
constructor: "foo"
});
`;
exports[`transform react to jsx should allow deeper js namespacing 1`] = `React.createElement(Namespace.DeepNamespace.Component, null);`;
exports[`transform react to jsx should allow elements as attributes 1`] = `
React.createElement("div", {
attr: React.createElement("div", null)
});
`;
exports[`transform react to jsx should allow js namespacing 1`] = `React.createElement(Namespace.Component, null);`;
exports[`transform react to jsx should allow nested fragments 1`] = `React.createElement("div", null, React.createElement(React.Fragment, null, React.createElement(React.Fragment, null, React.createElement("span", null, "Hello"), React.createElement("span", null, "world")), React.createElement(React.Fragment, null, React.createElement("span", null, "Goodbye"), React.createElement("span", null, "world"))));`;
exports[`transform react to jsx should avoid wrapping in extra parens if not needed 1`] = `
var x = React.createElement("div", null, React.createElement(Component, null));
var x = React.createElement("div", null, props.children);
var x = React.createElement(Composite, null, props.children);
var x = React.createElement(Composite, null, React.createElement(Composite2, null));
`;
exports[`transform react to jsx should convert simple tags 1`] = `var x = React.createElement("div", null);`;
exports[`transform react to jsx should convert simple text 1`] = `var x = React.createElement("div", null, "text");`;
exports[`transform react to jsx should escape xhtml jsxattribute 1`] = `
React.createElement("div", {
id: "w\\xF4w"
});
React.createElement("div", {
id: "w"
});
React.createElement("div", {
id: "w < w"
});
`;
exports[`transform react to jsx should escape xhtml jsxtext 1`] = `
React.createElement("div", null, "wow");
React.createElement("div", null, "w\\xF4w");
React.createElement("div", null, "w & w");
React.createElement("div", null, "w & w");
React.createElement("div", null, "w \\xA0 w");
React.createElement("div", null, "this should not parse as unicode: \\xA0");
React.createElement("div", null, "this should parse as nbsp: \\xA0 ");
React.createElement("div", null, "this should parse as unicode: ", '  ');
React.createElement("div", null, "w < w");
`;
exports[`transform react to jsx should handle attributed elements 1`] = `
var HelloMessage = React.createClass({
render: function () {
return React.createElement("div", null, "Hello ", this.props.name);
}
});
React.render(React.createElement(HelloMessage, {
name: React.createElement("span", null, "Sebastian")
}), mountNode);
`;
exports[`transform react to jsx should handle has own property correctly 1`] = `React.createElement("hasOwnProperty", null, "testing");`;
exports[`transform react to jsx should have correct comma in nested children 1`] = `var x = React.createElement("div", null, React.createElement("div", null, React.createElement("br", null)), React.createElement(Component, null, foo, React.createElement("br", null), bar), React.createElement("br", null));`;
exports[`transform react to jsx should insert commas after expressions before whitespace 1`] = `
var x = React.createElement("div", {
attr1: "foo" + "bar",
attr2: "foo" + "bar" + "baz" + "bug",
attr3: "foo" + "bar" + "baz" + "bug",
attr4: "baz"
});
`;
exports[`transform react to jsx should not add quotes to identifier names 1`] = `
var e = React.createElement(F, {
aaa: true,
new: true,
const: true,
var: true,
default: true,
"foo-bar": true
});
`;
exports[`transform react to jsx should not strip nbsp even couple with other whitespace 1`] = `React.createElement("div", null, "\\xA0 ");`;
exports[`transform react to jsx should not strip tags with a single child of nbsp 1`] = `React.createElement("div", null, "\\xA0");`;
exports[`transform react to jsx should properly handle comments adjacent to children 1`] = `var x = React.createElement("div", null, React.createElement("span", null), React.createElement("br", null));`;
exports[`transform react to jsx should properly handle comments between props 1`] = `
var x = React.createElement("div", {
/* a multi-line
comment */
attr1: "foo"
}, React.createElement("span", {
// a double-slash comment
attr2: "bar"
}));
`;
exports[`transform react to jsx should quote jsx attributes 1`] = `
React.createElement("button", {
"data-value": "a value"
}, "Button");
`;
exports[`transform react to jsx should support xml namespaces if flag 1`] = `
React.createElement("f:image", {
"n:attr": true
});
`;
exports[`transform react to jsx should transform known hyphenated tags 1`] = `React.createElement("font-face", null);`;
exports[`transform react to jsx useBuiltIns false uses extend instead of Object.assign 1`] = `
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
React.createElement(Component, _extends({
y: 2
}, x));
`;
exports[`transform react to jsx wraps props in react spread for first spread attributes 1`] = `
React.createElement(Component, Object.assign({}, x, {
y: 2,
z: true
}));
`;
exports[`transform react to jsx wraps props in react spread for last spread attributes 1`] = `
React.createElement(Component, Object.assign({
y: 2,
z: true
}, x));
`;
exports[`transform react to jsx wraps props in react spread for middle spread attributes 1`] = `
React.createElement(Component, Object.assign({
y: 2
}, x, {
z: true
}));
`;

View File

@@ -1,400 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`transform react to jsx React.fragment to set keys and source 1`] = `
var _jsxFileName = "";
var x = React.jsxDEV(React.Fragment, {}, "foo", false, {
fileName: _jsxFileName,
lineNumber: 1
}, this);
`;
exports[`transform react to jsx adds appropriate new lines when using spread attribute 1`] = `
React.jsx(Component, Object.assign({}, props, {
sound: "moo"
}));
`;
exports[`transform react to jsx arrow functions 1`] = `
var foo = function () {
var _this = this;
return function () {
return React.jsx(_this, {});
};
};
var bar = function () {
var _this2 = this;
return function () {
return React.jsx(_this2.foo, {});
};
};
`;
exports[`transform react to jsx assignment 1`] = `
var div = React.jsx(Component, Object.assign({}, props, {
foo: "bar"
}));
`;
exports[`transform react to jsx concatenates adjacent string literals 1`] = `
var x = React.jsxs("div", {
children: ["foo", "bar", "baz", React.jsx("div", {
children: "buz bang"
}), "qux", null, "quack"]
});
`;
exports[`transform react to jsx duplicate children prop should transform into sequence expression with actual children 1`] = `
React.jsx(Component, {
children: (1, "2")
});
`;
exports[`transform react to jsx duplicate children prop should transform into sequence expression with next prop 1`] = `
React.jsx(Component, {
foo: (1, 3),
children: "2"
});
`;
exports[`transform react to jsx duplicate children prop should transform into sequence expression with spread 1`] = `
React.jsx(Component, Object.assign({}, (1, x), {
children: "2"
}));
`;
exports[`transform react to jsx duplicate children props should transform into sequence expression with next prop 1`] = `
React.jsx(Component, {
foo: (1, 4, 3),
children: "2"
});
`;
exports[`transform react to jsx fragment with no children 1`] = `var x = React.jsx(React.Fragment, {});`;
exports[`transform react to jsx fragments 1`] = `
var x = React.jsx(React.Fragment, {
children: React.jsx("div", {})
});
`;
exports[`transform react to jsx fragments in dev mode (no key and source) 1`] = `
var _jsxFileName = "";
var x = React.jsxDEV(React.Fragment, {
children: React.jsxDEV("div", {}, undefined, false, {
fileName: _jsxFileName,
lineNumber: 1
}, this)
}, undefined, false);
`;
exports[`transform react to jsx fragments to set keys 1`] = `var x = React.jsx(React.Fragment, {}, "foo");`;
exports[`transform react to jsx nonStatic children 1`] = `
var _jsxFileName = "";
var x = React.jsxDEV("div", {
children: [React.jsxDEV("span", {}, '0', false, {
fileName: _jsxFileName,
lineNumber: 3
}, this), React.jsxDEV("span", {}, '1', false, {
fileName: _jsxFileName,
lineNumber: 3
}, this)]
}, undefined, false, {
fileName: _jsxFileName,
lineNumber: 2
}, this);
`;
exports[`transform react to jsx properly handles keys 1`] = `
var x = React.jsxs("div", {
children: [React.jsx("div", {}, "1"), React.jsx("div", {
meow: "wolf"
}, "2"), React.jsx("div", {}, "3")]
});
`;
exports[`transform react to jsx properly passes in source and self 1`] = `
var _jsxFileName = "";
var x = React.jsxDEV("div", {}, undefined, false, {
fileName: _jsxFileName,
lineNumber: 1
}, this);
`;
exports[`transform react to jsx should allow constructor as prop 1`] = `
React.jsx(Component, {
constructor: "foo"
});
`;
exports[`transform react to jsx should allow deeper js namespacing 1`] = `React.jsx(Namespace.DeepNamespace.Component, {});`;
exports[`transform react to jsx should allow elements as attributes 1`] = `
React.jsx("div", {
attr: React.jsx("div", {})
});
`;
exports[`transform react to jsx should allow js namespacing 1`] = `React.jsx(Namespace.Component, {});`;
exports[`transform react to jsx should allow nested fragments 1`] = `
React.jsx("div", {
children: React.jsxs(React.Fragment, {
children: [React.jsxs(React.Fragment, {
children: [React.jsx("span", {
children: "Hello"
}), React.jsx("span", {
children: "world"
})]
}), React.jsxs(React.Fragment, {
children: [React.jsx("span", {
children: "Goodbye"
}), React.jsx("span", {
children: "world"
})]
})]
})
});
`;
exports[`transform react to jsx should avoid wrapping in extra parens if not needed 1`] = `
var x = React.jsx("div", {
children: React.jsx(Component, {})
});
var x = React.jsx("div", {
children: props.children
});
var x = React.jsx(Composite, {
children: props.children
});
var x = React.jsx(Composite, {
children: React.jsx(Composite2, {})
});
`;
exports[`transform react to jsx should convert simple tags 1`] = `var x = React.jsx("div", {});`;
exports[`transform react to jsx should convert simple text 1`] = `
var x = React.jsx("div", {
children: "text"
});
`;
exports[`transform react to jsx should escape xhtml jsxattribute 1`] = `
React.jsx("div", {
id: "w\\xF4w"
});
React.jsx("div", {
id: "w"
});
React.jsx("div", {
id: "w < w"
});
`;
exports[`transform react to jsx should escape xhtml jsxtext 1`] = `
React.jsx("div", {
children: "wow"
});
React.jsx("div", {
children: "w\\xF4w"
});
React.jsx("div", {
children: "w & w"
});
React.jsx("div", {
children: "w & w"
});
React.jsx("div", {
children: "w \\xA0 w"
});
React.jsx("div", {
children: "this should not parse as unicode: \\xA0"
});
React.jsx("div", {
children: "this should parse as nbsp: \\xA0 "
});
React.jsxs("div", {
children: ["this should parse as unicode: ", '  ']
});
React.jsx("div", {
children: "w < w"
});
`;
exports[`transform react to jsx should handle attributed elements 1`] = `
var HelloMessage = React.createClass({
render: function () {
return React.jsxs("div", {
children: ["Hello ", this.props.name]
});
}
});
React.render(React.jsx(HelloMessage, {
name: React.jsx("span", {
children: "Sebastian"
})
}), mountNode);
`;
exports[`transform react to jsx should handle has own property correctly 1`] = `
React.jsx("hasOwnProperty", {
children: "testing"
});
`;
exports[`transform react to jsx should have correct comma in nested children 1`] = `
var x = React.jsxs("div", {
children: [React.jsx("div", {
children: React.jsx("br", {})
}), React.jsxs(Component, {
children: [foo, React.jsx("br", {}), bar]
}), React.jsx("br", {})]
});
`;
exports[`transform react to jsx should insert commas after expressions before whitespace 1`] = `
var x = React.jsx("div", {
attr1: "foo" + "bar",
attr2: "foo" + "bar" + "baz" + "bug",
attr3: "foo" + "bar" + "baz" + "bug",
attr4: "baz"
});
`;
exports[`transform react to jsx should not add quotes to identifier names 1`] = `
var e = React.jsx(F, {
aaa: true,
new: true,
const: true,
var: true,
default: true,
"foo-bar": true
});
`;
exports[`transform react to jsx should not strip nbsp even couple with other whitespace 1`] = `
React.jsx("div", {
children: "\\xA0 "
});
`;
exports[`transform react to jsx should not strip tags with a single child of nbsp 1`] = `
React.jsx("div", {
children: "\\xA0"
});
`;
exports[`transform react to jsx should properly handle comments adjacent to children 1`] = `
var x = React.jsxs("div", {
children: [React.jsx("span", {}), React.jsx("br", {})]
});
`;
exports[`transform react to jsx should properly handle comments between props 1`] = `
var x = React.jsx("div", {
/* a multi-line
comment */
attr1: "foo",
children: React.jsx("span", {
// a double-slash comment
attr2: "bar"
})
});
`;
exports[`transform react to jsx should properly handle potentially null variables 1`] = `
var foo = null;
var x = React.jsx("div", Object.assign({}, foo));
`;
exports[`transform react to jsx should quote jsx attributes 1`] = `
React.jsx("button", {
"data-value": "a value",
children: "Button"
});
`;
exports[`transform react to jsx should support xml namespaces if flag 1`] = `
React.jsx("f:image", {
"n:attr": true
});
`;
exports[`transform react to jsx should transform known hyphenated tags 1`] = `React.jsx("font-face", {});`;
exports[`transform react to jsx static children 1`] = `
var _jsxFileName = "";
var x = React.jsxDEV("div", {
children: [React.jsxDEV("span", {}, undefined, false, {
fileName: _jsxFileName,
lineNumber: 3
}, this), [React.jsxDEV("span", {}, '0', false, {
fileName: _jsxFileName,
lineNumber: 4
}, this), React.jsxDEV("span", {}, '1', false, {
fileName: _jsxFileName,
lineNumber: 4
}, this)]]
}, undefined, true, {
fileName: _jsxFileName,
lineNumber: 2
}, this);
`;
exports[`transform react to jsx useBuiltIns false uses extend instead of Object.assign 1`] = `
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
React.jsx(Component, _extends({
y: 2
}, x));
`;
exports[`transform react to jsx uses createElement when the key comes after a spread 1`] = `
var x = React.createElement("div", Object.assign({}, props, {
key: "1",
foo: "bar"
}));
`;
exports[`transform react to jsx uses jsx when the key comes before a spread 1`] = `
var x = React.jsx("div", Object.assign({}, props, {
foo: "bar"
}), "1");
`;
exports[`transform react to jsx uses jsxDEV instead of jsx in dev mode 1`] = `
var _jsxFileName = "";
var x = React.jsxDEV("span", {
propOne: "one",
children: "Hi"
}, undefined, false, {
fileName: _jsxFileName,
lineNumber: 1
}, this);
`;
exports[`transform react to jsx wraps props in react spread for first spread attributes 1`] = `
React.jsx(Component, Object.assign({}, x, {
y: 2,
z: true
}));
`;
exports[`transform react to jsx wraps props in react spread for last spread attributes 1`] = `
React.jsx(Component, Object.assign({
y: 2,
z: true
}, x));
`;
exports[`transform react to jsx wraps props in react spread for middle spread attributes 1`] = `
React.jsx(Component, Object.assign({
y: 2
}, x, {
z: true
}));
`;

View File

@@ -1,3 +0,0 @@
'use strict';
module.exports = require('./src/TransformJSXToReactBabelPlugin');

View File

@@ -1,7 +0,0 @@
'use strict';
if (process.env.NODE_ENV === 'production') {
module.exports = require('./cjs/react-jsx-babel.production.min.js');
} else {
module.exports = require('./cjs/react-jsx-babel.development.js');
}

View File

@@ -1,18 +0,0 @@
{
"name": "babel-plugin-react-jsx",
"version": "0.1.0",
"private": true,
"description": "@babel/plugin-transform-react-jsx",
"main": "index.js",
"dependencies": {
"esutils": "^2.0.0"
},
"files": [
"README.md",
"index.js",
"build-info.json",
"cjs/",
"umd/"
]
}

View File

@@ -1,658 +0,0 @@
// MIT License
// Copyright (c) 2014-present Sebastian McKenzie and other contributors
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// © 2019 GitHub, Inc.
'use strict';
const esutils = require('esutils');
function helper(babel, opts) {
const {types: t} = babel;
const visitor = {};
visitor.JSXNamespacedName = function(path, state) {
const throwIfNamespace =
state.opts.throwIfNamespace === undefined
? true
: !!state.opts.throwIfNamespace;
if (throwIfNamespace) {
throw path.buildCodeFrameError(
`Namespace tags are not supported by default. React's JSX doesn't support namespace tags. \
You can turn on the 'throwIfNamespace' flag to bypass this warning.`,
);
}
};
visitor.JSXSpreadChild = function(path) {
throw path.buildCodeFrameError(
'Spread children are not supported in React.',
);
};
visitor.JSXElement = {
exit(path, file) {
let callExpr;
if (file.opts.useCreateElement || shouldUseCreateElement(path)) {
callExpr = buildCreateElementCall(path, file);
} else {
callExpr = buildJSXElementCall(path, file);
}
if (callExpr) {
path.replaceWith(t.inherits(callExpr, path.node));
}
},
};
visitor.JSXFragment = {
exit(path, file) {
if (opts.compat) {
throw path.buildCodeFrameError(
'Fragment tags are only supported in React 16 and up.',
);
}
let callExpr;
if (file.opts.useCreateElement) {
callExpr = buildCreateElementFragmentCall(path, file);
} else {
callExpr = buildJSXFragmentCall(path, file);
}
if (callExpr) {
path.replaceWith(t.inherits(callExpr, path.node));
}
},
};
return visitor;
function convertJSXIdentifier(node, parent) {
if (t.isJSXIdentifier(node)) {
if (node.name === 'this' && t.isReferenced(node, parent)) {
return t.thisExpression();
} else if (esutils.keyword.isIdentifierNameES6(node.name)) {
node.type = 'Identifier';
} else {
return t.stringLiteral(node.name);
}
} else if (t.isJSXMemberExpression(node)) {
return t.memberExpression(
convertJSXIdentifier(node.object, node),
convertJSXIdentifier(node.property, node),
);
} else if (t.isJSXNamespacedName(node)) {
/**
* If there is flag "throwIfNamespace"
* print XMLNamespace like string literal
*/
return t.stringLiteral(`${node.namespace.name}:${node.name.name}`);
}
return node;
}
function convertAttributeValue(node) {
if (t.isJSXExpressionContainer(node)) {
return node.expression;
} else {
return node;
}
}
function convertAttribute(node, duplicateChildren) {
let value = convertAttributeValue(node.value || t.booleanLiteral(true));
if (t.isStringLiteral(value) && !t.isJSXExpressionContainer(node.value)) {
value.value = value.value.replace(/\n\s+/g, ' ');
// "raw" JSXText should not be used from a StringLiteral because it needs to be escaped.
if (value.extra && value.extra.raw) {
delete value.extra.raw;
}
}
if (duplicateChildren && duplicateChildren.length > 0) {
value = t.sequenceExpression([...duplicateChildren, value]);
}
if (t.isJSXNamespacedName(node.name)) {
node.name = t.stringLiteral(
node.name.namespace.name + ':' + node.name.name.name,
);
} else if (esutils.keyword.isIdentifierNameES6(node.name.name)) {
node.name.type = 'Identifier';
} else {
node.name = t.stringLiteral(node.name.name);
}
return t.inherits(t.objectProperty(node.name, value), node);
}
// We want to use React.createElement, even in the case of
// jsx, for <div {...props} key={key} /> to distinguish it
// from <div key={key} {...props} />. This is an intermediary
// step while we deprecate key spread from props. Afterwards,
// we will remove createElement entirely
function shouldUseCreateElement(path) {
const openingPath = path.get('openingElement');
const attributes = openingPath.node.attributes;
let seenPropsSpread = false;
for (let i = 0; i < attributes.length; i++) {
const attr = attributes[i];
if (
seenPropsSpread &&
t.isJSXAttribute(attr) &&
attr.name.name === 'key'
) {
return true;
} else if (t.isJSXSpreadAttribute(attr)) {
seenPropsSpread = true;
}
}
return false;
}
// Builds JSX into:
// Production: React.jsx(type, arguments, key)
// Development: React.jsxDEV(type, arguments, key, isStaticChildren, source, self)
function buildJSXElementCall(path, file) {
if (opts.filter && !opts.filter(path.node, file)) {
return;
}
const openingPath = path.get('openingElement');
openingPath.parent.children = t.react.buildChildren(openingPath.parent);
const tagExpr = convertJSXIdentifier(
openingPath.node.name,
openingPath.node,
);
const args = [];
let tagName;
if (t.isIdentifier(tagExpr)) {
tagName = tagExpr.name;
} else if (t.isLiteral(tagExpr)) {
tagName = tagExpr.value;
}
const state = {
tagExpr: tagExpr,
tagName: tagName,
args: args,
};
if (opts.pre) {
opts.pre(state, file);
}
let attribs = [];
let key;
let source;
let self;
// for React.jsx, key, __source (dev), and __self (dev) is passed in as
// a separate argument rather than in the args object. We go through the
// props and filter out these three keywords so we can pass them in
// as separate arguments later
for (let i = 0; i < openingPath.node.attributes.length; i++) {
const attr = openingPath.node.attributes[i];
if (t.isJSXAttribute(attr) && t.isJSXIdentifier(attr.name)) {
if (attr.name.name === 'key') {
key = convertAttribute(attr).value;
} else if (attr.name.name === '__source') {
source = convertAttribute(attr).value;
} else if (attr.name.name === '__self') {
self = convertAttribute(attr).value;
} else {
attribs.push(attr);
}
} else {
attribs.push(attr);
}
}
if (attribs.length || path.node.children.length) {
attribs = buildJSXOpeningElementAttributes(
attribs,
file,
path.node.children,
);
} else {
// attributes should never be null
attribs = t.objectExpression([]);
}
args.push(attribs);
if (!file.opts.development) {
if (key !== undefined) {
args.push(key);
}
} else {
// isStaticChildren, __source, and __self are only used in development
args.push(
key === undefined ? t.identifier('undefined') : key,
t.booleanLiteral(path.node.children.length > 1),
source === undefined ? t.identifier('undefined') : source,
self === undefined ? t.identifier('undefined') : self,
);
}
if (opts.post) {
opts.post(state, file);
}
return (
state.call ||
t.callExpression(
path.node.children.length > 1 ? state.staticCallee : state.callee,
args,
)
);
}
function isChildrenProp(prop) {
return (
t.isJSXAttribute(prop) &&
t.isJSXIdentifier(prop.name) &&
prop.name.name === 'children'
);
}
// Builds props for React.jsx. This function adds children into the props
// and ensures that props is always an object
function buildJSXOpeningElementAttributes(attribs, file, children) {
let _props = [];
const objs = [];
// In order to avoid having duplicate "children" keys, we avoid
// pushing the "children" prop if we have actual children. However,
// the children prop may have side effects, so to be certain
// these side effects are evaluated, we add them to the following prop
// as a sequence expression to preserve order. So:
// <div children={x++} foo={y}>{child}</div> becomes
// React.jsx('div', {foo: (x++, y), children: child});
// duplicateChildren contains the extra children prop values
let duplicateChildren = [];
const hasChildren = children && children.length > 0;
const useBuiltIns = file.opts.useBuiltIns || false;
if (typeof useBuiltIns !== 'boolean') {
throw new Error(
'transform-react-jsx currently only accepts a boolean option for ' +
'useBuiltIns (defaults to false)',
);
}
while (attribs.length) {
const prop = attribs.shift();
if (hasChildren && isChildrenProp(prop)) {
duplicateChildren.push(convertAttributeValue(prop.value));
} else if (t.isJSXSpreadAttribute(prop)) {
_props = pushProps(_props, objs);
if (duplicateChildren.length > 0) {
objs.push(
t.sequenceExpression([...duplicateChildren, prop.argument]),
);
duplicateChildren = [];
} else {
objs.push(prop.argument);
}
} else {
_props.push(convertAttribute(prop, duplicateChildren));
if (duplicateChildren.length > 0) {
duplicateChildren = [];
}
}
}
// In React.JSX, children is no longer a separate argument, but passed in
// through the argument object
if (hasChildren) {
if (children.length === 1) {
_props.push(
t.objectProperty(
t.identifier('children'),
duplicateChildren.length > 0
? t.sequenceExpression([...duplicateChildren, children[0]])
: children[0],
),
);
} else {
_props.push(
t.objectProperty(
t.identifier('children'),
duplicateChildren.length > 0
? t.sequenceExpression([
...duplicateChildren,
t.arrayExpression(children),
])
: t.arrayExpression(children),
),
);
}
}
pushProps(_props, objs);
if (objs.length === 1) {
// only one object
if (!t.isObjectExpression(objs[0])) {
// if the prop object isn't an object, use Object.assign or _extends
// to ensure that the prop will always be an object (as opposed to a variable
// that could be null at some point)
const expressionHelper = useBuiltIns
? t.memberExpression(t.identifier('Object'), t.identifier('assign'))
: file.addHelper('extends');
attribs = t.callExpression(expressionHelper, [
t.objectExpression([]),
objs[0],
]);
} else {
attribs = objs[0];
}
} else {
// looks like we have multiple objects
if (!t.isObjectExpression(objs[0])) {
objs.unshift(t.objectExpression([]));
}
const expressionHelper = useBuiltIns
? t.memberExpression(t.identifier('Object'), t.identifier('assign'))
: file.addHelper('extends');
// spread it
attribs = t.callExpression(expressionHelper, objs);
}
return attribs;
}
// Builds JSX Fragment <></> into
// Production: React.jsx(type, arguments)
// Development: React.jsxDEV(type, { children})
function buildJSXFragmentCall(path, file) {
if (opts.filter && !opts.filter(path.node, file)) {
return;
}
const openingPath = path.get('openingElement');
openingPath.parent.children = t.react.buildChildren(openingPath.parent);
const args = [];
const tagName = null;
const tagExpr = file.get('jsxFragIdentifier')();
const state = {
tagExpr: tagExpr,
tagName: tagName,
args: args,
};
if (opts.pre) {
opts.pre(state, file);
}
let childrenNode;
if (path.node.children.length > 0) {
if (path.node.children.length === 1) {
childrenNode = path.node.children[0];
} else {
childrenNode = t.arrayExpression(path.node.children);
}
}
args.push(
t.objectExpression(
childrenNode !== undefined
? [t.objectProperty(t.identifier('children'), childrenNode)]
: [],
),
);
if (file.opts.development) {
args.push(
t.identifier('undefined'),
t.booleanLiteral(path.node.children.length > 1),
);
}
if (opts.post) {
opts.post(state, file);
}
return (
state.call ||
t.callExpression(
path.node.children.length > 1 ? state.staticCallee : state.callee,
args,
)
);
}
// Builds JSX into:
// Production: React.createElement(type, arguments, children)
// Development: React.createElement(type, arguments, children, source, self)
function buildCreateElementCall(path, file) {
if (opts.filter && !opts.filter(path.node, file)) {
return;
}
const openingPath = path.get('openingElement');
openingPath.parent.children = t.react.buildChildren(openingPath.parent);
const tagExpr = convertJSXIdentifier(
openingPath.node.name,
openingPath.node,
);
const args = [];
let tagName;
if (t.isIdentifier(tagExpr)) {
tagName = tagExpr.name;
} else if (t.isLiteral(tagExpr)) {
tagName = tagExpr.value;
}
const state = {
tagExpr: tagExpr,
tagName: tagName,
args: args,
};
if (opts.pre) {
opts.pre(state, file);
}
let attribs = openingPath.node.attributes;
if (attribs.length) {
attribs = buildCreateElementOpeningElementAttributes(attribs, file);
} else {
attribs = t.nullLiteral();
}
args.push(attribs, ...path.node.children);
if (opts.post) {
opts.post(state, file);
}
return state.call || t.callExpression(state.oldCallee, args);
}
function pushProps(_props, objs) {
if (!_props.length) {
return _props;
}
objs.push(t.objectExpression(_props));
return [];
}
/**
* The logic for this is quite terse. It's because we need to
* support spread elements. We loop over all attributes,
* breaking on spreads, we then push a new object containing
* all prior attributes to an array for later processing.
*/
function buildCreateElementOpeningElementAttributes(attribs, file) {
let _props = [];
const objs = [];
const useBuiltIns = file.opts.useBuiltIns || false;
if (typeof useBuiltIns !== 'boolean') {
throw new Error(
'transform-react-jsx currently only accepts a boolean option for ' +
'useBuiltIns (defaults to false)',
);
}
while (attribs.length) {
const prop = attribs.shift();
if (t.isJSXSpreadAttribute(prop)) {
_props = pushProps(_props, objs);
objs.push(prop.argument);
} else {
const attr = convertAttribute(prop);
_props.push(attr);
}
}
pushProps(_props, objs);
if (objs.length === 1) {
// only one object
attribs = objs[0];
} else {
// looks like we have multiple objects
if (!t.isObjectExpression(objs[0])) {
objs.unshift(t.objectExpression([]));
}
const expressionHelper = useBuiltIns
? t.memberExpression(t.identifier('Object'), t.identifier('assign'))
: file.addHelper('extends');
// spread it
attribs = t.callExpression(expressionHelper, objs);
}
return attribs;
}
function buildCreateElementFragmentCall(path, file) {
if (opts.filter && !opts.filter(path.node, file)) {
return;
}
const openingPath = path.get('openingElement');
openingPath.parent.children = t.react.buildChildren(openingPath.parent);
const args = [];
const tagName = null;
const tagExpr = file.get('jsxFragIdentifier')();
const state = {
tagExpr: tagExpr,
tagName: tagName,
args: args,
};
if (opts.pre) {
opts.pre(state, file);
}
// no attributes are allowed with <> syntax
args.push(t.nullLiteral(), ...path.node.children);
if (opts.post) {
opts.post(state, file);
}
return state.call || t.callExpression(state.oldCallee, args);
}
}
module.exports = function(babel) {
const {types: t} = babel;
const createIdentifierParser = id => () => {
return id
.split('.')
.map(name => t.identifier(name))
.reduce((object, property) => t.memberExpression(object, property));
};
const visitor = helper(babel, {
pre(state) {
const tagName = state.tagName;
const args = state.args;
if (t.react.isCompatTag(tagName)) {
args.push(t.stringLiteral(tagName));
} else {
args.push(state.tagExpr);
}
},
post(state, pass) {
state.callee = pass.get('jsxIdentifier')();
state.staticCallee = pass.get('jsxStaticIdentifier')();
state.oldCallee = pass.get('oldJSXIdentifier')();
},
});
visitor.Program = {
enter(path, state) {
state.set(
'oldJSXIdentifier',
createIdentifierParser('React.createElement'),
);
state.set(
'jsxIdentifier',
createIdentifierParser(
state.opts.development ? 'React.jsxDEV' : 'React.jsx',
),
);
state.set(
'jsxStaticIdentifier',
createIdentifierParser(
state.opts.development ? 'React.jsxDEV' : 'React.jsxs',
),
);
state.set('jsxFragIdentifier', createIdentifierParser('React.Fragment'));
},
};
visitor.JSXAttribute = function(path) {
if (t.isJSXElement(path.node.value)) {
path.node.value = t.jsxExpressionContainer(path.node.value);
}
};
return {
name: 'transform-react-jsx',
visitor,
};
};

View File

@@ -1,7 +1,7 @@
{
"name": "create-subscription",
"description": "utility for subscribing to external data sources inside React components",
"version": "16.10.2",
"version": "16.8.2",
"repository": {
"type": "git",
"url": "https://github.com/facebook/react.git",

View File

@@ -14,7 +14,6 @@ let BehaviorSubject;
let ReactFeatureFlags;
let React;
let ReactNoop;
let Scheduler;
let ReplaySubject;
describe('createSubscription', () => {
@@ -25,7 +24,6 @@ describe('createSubscription', () => {
ReactFeatureFlags.debugRenderPhaseSideEffectsForStrictMode = false;
React = require('react');
ReactNoop = require('react-noop-renderer');
Scheduler = require('scheduler');
BehaviorSubject = require('rxjs/BehaviorSubject').BehaviorSubject;
ReplaySubject = require('rxjs/ReplaySubject').ReplaySubject;
@@ -60,23 +58,23 @@ describe('createSubscription', () => {
ReactNoop.render(
<Subscription source={observable}>
{(value = 'default') => {
Scheduler.unstable_yieldValue(value);
ReactNoop.yield(value);
return null;
}}
</Subscription>,
);
// Updates while subscribed should re-render the child component
expect(Scheduler).toFlushAndYield(['default']);
expect(ReactNoop.flush()).toEqual(['default']);
observable.next(123);
expect(Scheduler).toFlushAndYield([123]);
expect(ReactNoop.flush()).toEqual([123]);
observable.next('abc');
expect(Scheduler).toFlushAndYield(['abc']);
expect(ReactNoop.flush()).toEqual(['abc']);
// Unmounting the subscriber should remove listeners
ReactNoop.render(<div />);
observable.next(456);
expect(Scheduler).toFlushAndYield([]);
expect(ReactNoop.flush()).toEqual([]);
});
it('should support observable types like RxJS ReplaySubject', () => {
@@ -97,20 +95,20 @@ describe('createSubscription', () => {
});
function render(value = 'default') {
Scheduler.unstable_yieldValue(value);
ReactNoop.yield(value);
return null;
}
const observable = createReplaySubject('initial');
ReactNoop.render(<Subscription source={observable}>{render}</Subscription>);
expect(Scheduler).toFlushAndYield(['initial']);
expect(ReactNoop.flush()).toEqual(['initial']);
observable.next('updated');
expect(Scheduler).toFlushAndYield(['updated']);
expect(ReactNoop.flush()).toEqual(['updated']);
// Unsetting the subscriber prop should reset subscribed values
ReactNoop.render(<Subscription>{render}</Subscription>);
expect(Scheduler).toFlushAndYield(['default']);
expect(ReactNoop.flush()).toEqual(['default']);
});
describe('Promises', () => {
@@ -126,9 +124,9 @@ describe('createSubscription', () => {
function render(hasLoaded) {
if (hasLoaded === undefined) {
Scheduler.unstable_yieldValue('loading');
ReactNoop.yield('loading');
} else {
Scheduler.unstable_yieldValue(hasLoaded ? 'finished' : 'failed');
ReactNoop.yield(hasLoaded ? 'finished' : 'failed');
}
return null;
}
@@ -143,19 +141,19 @@ describe('createSubscription', () => {
// Test a promise that resolves after render
ReactNoop.render(<Subscription source={promiseA}>{render}</Subscription>);
expect(Scheduler).toFlushAndYield(['loading']);
expect(ReactNoop.flush()).toEqual(['loading']);
resolveA(true);
await promiseA;
expect(Scheduler).toFlushAndYield(['finished']);
expect(ReactNoop.flush()).toEqual(['finished']);
// Test a promise that resolves before render
// Note that this will require an extra render anyway,
// Because there is no way to synchronously get a Promise's value
rejectB(false);
ReactNoop.render(<Subscription source={promiseB}>{render}</Subscription>);
expect(Scheduler).toFlushAndYield(['loading']);
expect(ReactNoop.flush()).toEqual(['loading']);
await promiseB.catch(() => true);
expect(Scheduler).toFlushAndYield(['failed']);
expect(ReactNoop.flush()).toEqual(['failed']);
});
it('should still work if unsubscription is managed incorrectly', async () => {
@@ -169,7 +167,7 @@ describe('createSubscription', () => {
});
function render(value = 'default') {
Scheduler.unstable_yieldValue(value);
ReactNoop.yield(value);
return null;
}
@@ -179,9 +177,9 @@ describe('createSubscription', () => {
// Subscribe first to Promise A then Promise B
ReactNoop.render(<Subscription source={promiseA}>{render}</Subscription>);
expect(Scheduler).toFlushAndYield(['default']);
expect(ReactNoop.flush()).toEqual(['default']);
ReactNoop.render(<Subscription source={promiseB}>{render}</Subscription>);
expect(Scheduler).toFlushAndYield(['default']);
expect(ReactNoop.flush()).toEqual(['default']);
// Resolve both Promises
resolveB(123);
@@ -189,7 +187,7 @@ describe('createSubscription', () => {
await Promise.all([promiseA, promiseB]);
// Ensure that only Promise B causes an update
expect(Scheduler).toFlushAndYield([123]);
expect(ReactNoop.flush()).toEqual([123]);
});
it('should not call setState for a Promise that resolves after unmount', async () => {
@@ -203,7 +201,7 @@ describe('createSubscription', () => {
});
function render(hasLoaded) {
Scheduler.unstable_yieldValue('rendered');
ReactNoop.yield('rendered');
return null;
}
@@ -213,11 +211,11 @@ describe('createSubscription', () => {
});
ReactNoop.render(<Subscription source={promise}>{render}</Subscription>);
expect(Scheduler).toFlushAndYield(['rendered']);
expect(ReactNoop.flush()).toEqual(['rendered']);
// Unmount
ReactNoop.render(null);
expect(Scheduler).toFlushWithoutYielding();
ReactNoop.flush();
// Resolve Promise should not trigger a setState warning
resolvePromise(true);
@@ -235,7 +233,7 @@ describe('createSubscription', () => {
});
function render(value = 'default') {
Scheduler.unstable_yieldValue(value);
ReactNoop.yield(value);
return null;
}
@@ -247,28 +245,28 @@ describe('createSubscription', () => {
);
// Updates while subscribed should re-render the child component
expect(Scheduler).toFlushAndYield(['a-0']);
expect(ReactNoop.flush()).toEqual(['a-0']);
// Unsetting the subscriber prop should reset subscribed values
ReactNoop.render(
<Subscription source={observableB}>{render}</Subscription>,
);
expect(Scheduler).toFlushAndYield(['b-0']);
expect(ReactNoop.flush()).toEqual(['b-0']);
// Updates to the old subscribable should not re-render the child component
observableA.next('a-1');
expect(Scheduler).toFlushAndYield([]);
expect(ReactNoop.flush()).toEqual([]);
// Updates to the bew subscribable should re-render the child component
observableB.next('b-1');
expect(Scheduler).toFlushAndYield(['b-1']);
expect(ReactNoop.flush()).toEqual(['b-1']);
});
it('should ignore values emitted by a new subscribable until the commit phase', () => {
const log = [];
function Child({value}) {
Scheduler.unstable_yieldValue('Child: ' + value);
ReactNoop.yield('Child: ' + value);
return null;
}
@@ -305,7 +303,7 @@ describe('createSubscription', () => {
return (
<Subscription source={this.state.observed}>
{(value = 'default') => {
Scheduler.unstable_yieldValue('Subscriber: ' + value);
ReactNoop.yield('Subscriber: ' + value);
return <Child value={value} />;
}}
</Subscription>
@@ -317,12 +315,12 @@ describe('createSubscription', () => {
const observableB = createBehaviorSubject('b-0');
ReactNoop.render(<Parent observed={observableA} />);
expect(Scheduler).toFlushAndYield(['Subscriber: a-0', 'Child: a-0']);
expect(ReactNoop.flush()).toEqual(['Subscriber: a-0', 'Child: a-0']);
expect(log).toEqual(['Parent.componentDidMount']);
// Start React update, but don't finish
ReactNoop.render(<Parent observed={observableB} />);
expect(Scheduler).toFlushAndYieldThrough(['Subscriber: b-0']);
ReactNoop.flushThrough(['Subscriber: b-0']);
expect(log).toEqual(['Parent.componentDidMount']);
// Emit some updates from the uncommitted subscribable
@@ -337,7 +335,7 @@ describe('createSubscription', () => {
// We expect the last emitted update to be rendered (because of the commit phase value check)
// But the intermediate ones should be ignored,
// And the final rendered output should be the higher-priority observable.
expect(Scheduler).toFlushAndYield([
expect(ReactNoop.flush()).toEqual([
'Child: b-0',
'Subscriber: b-3',
'Child: b-3',
@@ -355,7 +353,7 @@ describe('createSubscription', () => {
const log = [];
function Child({value}) {
Scheduler.unstable_yieldValue('Child: ' + value);
ReactNoop.yield('Child: ' + value);
return null;
}
@@ -392,7 +390,7 @@ describe('createSubscription', () => {
return (
<Subscription source={this.state.observed}>
{(value = 'default') => {
Scheduler.unstable_yieldValue('Subscriber: ' + value);
ReactNoop.yield('Subscriber: ' + value);
return <Child value={value} />;
}}
</Subscription>
@@ -404,12 +402,12 @@ describe('createSubscription', () => {
const observableB = createBehaviorSubject('b-0');
ReactNoop.render(<Parent observed={observableA} />);
expect(Scheduler).toFlushAndYield(['Subscriber: a-0', 'Child: a-0']);
expect(ReactNoop.flush()).toEqual(['Subscriber: a-0', 'Child: a-0']);
expect(log).toEqual(['Parent.componentDidMount']);
// Start React update, but don't finish
ReactNoop.render(<Parent observed={observableB} />);
expect(Scheduler).toFlushAndYieldThrough(['Subscriber: b-0']);
ReactNoop.flushThrough(['Subscriber: b-0']);
expect(log).toEqual(['Parent.componentDidMount']);
// Emit some updates from the old subscribable
@@ -422,7 +420,7 @@ describe('createSubscription', () => {
// Flush everything and ensure that the correct subscribable is used
// We expect the new subscribable to finish rendering,
// But then the updated values from the old subscribable should be used.
expect(Scheduler).toFlushAndYield([
expect(ReactNoop.flush()).toEqual([
'Child: b-0',
'Subscriber: a-2',
'Child: a-2',
@@ -435,7 +433,7 @@ describe('createSubscription', () => {
// Updates from the new subscribable should be ignored.
observableB.next('b-1');
expect(Scheduler).toFlushAndYield([]);
expect(ReactNoop.flush()).toEqual([]);
expect(log).toEqual([
'Parent.componentDidMount',
'Parent.componentDidUpdate',
@@ -481,7 +479,7 @@ describe('createSubscription', () => {
<Subscription source={observable}>{value => null}</Subscription>,
);
expect(Scheduler).toFlushAndThrow(
expect(ReactNoop.flush).toThrow(
'A subscription must return an unsubscribe function.',
);
});

View File

@@ -28,8 +28,7 @@ Then add it to your ESLint configuration:
],
"rules": {
// ...
"react-hooks/rules-of-hooks": "error",
"react-hooks/exhaustive-deps": "warn"
"react-hooks/rules-of-hooks": "error"
}
}
```
@@ -38,8 +37,6 @@ Then add it to your ESLint configuration:
Please refer to the [Rules of Hooks](https://reactjs.org/docs/hooks-rules.html) documentation and the [Hooks FAQ](https://reactjs.org/docs/hooks-faq.html#what-exactly-do-the-lint-rules-enforce) to learn more about this rule.
For feedback about the `exhaustive-deps` rule, please post in [this thread](https://github.com/facebook/react/issues/14920).
## License
MIT

Some files were not shown because too many files have changed in this diff Show More