From 3930ff9739e323aebc93fd964a33a8372d7c6e15 Mon Sep 17 00:00:00 2001 From: fortunar Date: Sat, 15 Sep 2018 12:58:13 +0200 Subject: [PATCH] v1.0.0.: webpack used for examples, dependencies reorganized, example code highlighting fix, updated README, hosting example on gh-pages. --- .babelrc | 4 + .eslintrc.json | 39 - .gitignore | Bin 2404 -> 2392 bytes .npmignore | 5 + Procfile | 1 - README.md | 12 +- bower.json | 0 {example/src => demo}/app.less | 1 - {example/src => demo}/example-active-item.js | 28 +- {example/src => demo}/example-custom-click.js | 16 +- .../src => demo}/example-custom-render.js | 16 +- {example/src => demo}/example-custom-theme.js | 16 +- {example/src => demo}/example-no-collapse.js | 19 +- {example/src => demo}/example-normal.js | 16 +- {example/src => demo}/example-rtl.js | 16 +- {example/dist => demo}/index.html | 148 +- demo/index.js | 22 + dist/react-sidemenu.css | 115 - dist/react-sidemenu.js | 1690 -- dist/react-sidemenu.min.css | 1 - dist/react-sidemenu.min.js | 1 - example/dist/app.css | 150 - example/dist/bundle.js | 1687 -- example/dist/common.js | 1929 -- example/dist/example-active-item.js | 17666 ---------------- example/dist/example-custom-click.js | 17636 --------------- example/dist/example-custom-render.js | 17644 --------------- example/dist/example-custom-theme.js | 17634 --------------- example/dist/example-no-collapse.js | 17634 --------------- example/dist/example-normal.js | 17610 --------------- example/dist/example-rtl.js | 17610 --------------- example/src/app.js | 44 - example/src/favicon.ico | Bin 24838 -> 0 bytes example/src/index.html | 308 - example/src/test.js | 0 gulpfile.js | 218 - less/default.less | 1 - lib/SideMenu.js | 533 - package-lock.json | 11374 +++++----- package.json | 60 +- src/{SideMenu.js => index.js} | 3 +- {less => src}/side-menu.less | 0 {less => src}/theme-default.less | 0 webpack.config.js | 43 + 44 files changed, 6353 insertions(+), 135597 deletions(-) create mode 100644 .babelrc delete mode 100644 .eslintrc.json create mode 100644 .npmignore delete mode 100644 Procfile delete mode 100644 bower.json rename {example/src => demo}/app.less (95%) rename {example/src => demo}/example-active-item.js (77%) rename {example/src => demo}/example-custom-click.js (78%) rename {example/src => demo}/example-custom-render.js (78%) rename {example/src => demo}/example-custom-theme.js (77%) rename {example/src => demo}/example-no-collapse.js (76%) rename {example/src => demo}/example-normal.js (74%) rename {example/src => demo}/example-rtl.js (74%) rename {example/dist => demo}/index.html (67%) create mode 100644 demo/index.js delete mode 100644 dist/react-sidemenu.css delete mode 100644 dist/react-sidemenu.js delete mode 100644 dist/react-sidemenu.min.css delete mode 100644 dist/react-sidemenu.min.js delete mode 100644 example/dist/app.css delete mode 100644 example/dist/bundle.js delete mode 100644 example/dist/common.js delete mode 100644 example/dist/example-active-item.js delete mode 100644 example/dist/example-custom-click.js delete mode 100644 example/dist/example-custom-render.js delete mode 100644 example/dist/example-custom-theme.js delete mode 100644 example/dist/example-no-collapse.js delete mode 100644 example/dist/example-normal.js delete mode 100644 example/dist/example-rtl.js delete mode 100644 example/src/app.js delete mode 100644 example/src/favicon.ico delete mode 100644 example/src/index.html delete mode 100644 example/src/test.js delete mode 100644 gulpfile.js delete mode 100644 less/default.less delete mode 100644 lib/SideMenu.js rename src/{SideMenu.js => index.js} (99%) rename {less => src}/side-menu.less (100%) rename {less => src}/theme-default.less (100%) create mode 100644 webpack.config.js diff --git a/.babelrc b/.babelrc new file mode 100644 index 0000000..d94b553 --- /dev/null +++ b/.babelrc @@ -0,0 +1,4 @@ +{ + "presets": ["env", "react", "es2015"], + "plugins": ["transform-object-rest-spread"] +} \ No newline at end of file diff --git a/.eslintrc.json b/.eslintrc.json deleted file mode 100644 index 38fed55..0000000 --- a/.eslintrc.json +++ /dev/null @@ -1,39 +0,0 @@ -{ "extends": "eslint-config-airbnb", - "env": { - "browser": true, - "node": true, - "mocha": true - }, - "rules": { - "react/no-multi-comp": 0, - "react/prop-types": [1, { "ignore": ["children"] }], - "import/default": 0, - "import/no-duplicates": 0, - "import/named": 0, - "import/namespace": 0, - "import/no-unresolved": 0, - "import/no-named-as-default": 2, - "indent": [2, 2, {"SwitchCase": 1}], - "no-console": 0, - "no-alert": 0, - "object-shorthand": 0, - "no-param-reassign": 0, - "react/no-did-mount-set-state": 0, - "react/jsx-filename-extension": 0, - "react/jsx-closing-bracket-location": 0, - "arrow-body-style": 0, - "react/jsx-no-bind": 0, - "react/sort-comp": 0 - }, - "plugins": [ - "react", "import" - ], - "settings": { - "import/parser": "babel-eslint" - }, - "parserOptions":{ - "ecmaFeatures": { - "experimentalObjectRestSpread": true - } - } -} diff --git a/.gitignore b/.gitignore index d4fa0b6ce0c9e90cf905d4791ddec4cc53451df6..f376b2f7f946fae9245e67aab8c3753abe6c46d1 100644 GIT binary patch delta 7 OcmaDNbVF!E1SbFu_yY0( delta 20 bcmca1^h9Vw1Sd~wMPhD2PO5%NW^oAsR4WI~ diff --git a/.npmignore b/.npmignore new file mode 100644 index 0000000..af551b5 --- /dev/null +++ b/.npmignore @@ -0,0 +1,5 @@ +src +examples +.babelrc +.gitignore +webpack.config.js \ No newline at end of file diff --git a/Procfile b/Procfile deleted file mode 100644 index 4f4f20a..0000000 --- a/Procfile +++ /dev/null @@ -1 +0,0 @@ -web: gulp build:examples; gulp copy_favicon; gulp server; diff --git a/README.md b/README.md index d6a46e6..b9a3d5e 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ + # react-sidemenu Lightweight side menu component written in React.js. No jQuery, just CSS3. @@ -24,9 +25,10 @@ ES6 syntax: ES5 syntax: var SideMenu = require('react-sidemenu').SideMenu; -**Styling:** To use default styling include `react-sidemenu.css` to your project. For an idea on how to customize styling see [Demo](http://react-sidemenu-demo.herokuapp.com/). +## Styling! + To use default styling include `side-menu.css` to your project. You can find it in dist folder when installing via `npm`. For an idea on how to customize styling see [Demo](https://fortunar.github.io/react-sidemenu/). ## Demo & Examples -[Demo](http://react-sidemenu-demo.herokuapp.com/) showcasing the functionalities & code examples (wait for it to load a bit as it is on free plan on Heroku). We use Font Awesome as a CDN for the example icons to show. +[Demo](https://fortunar.github.io/react-sidemenu/) showcasing the functionalities & code examples. We use Font Awesome as a CDN for the example icons to show. You can run examples by yourself. Clone the repo and do: @@ -35,7 +37,7 @@ You can run examples by yourself. Clone the repo and do: ## Options -< SideMenu > - main component +`` - main component |**Option**|**Default**|**Description**| | --- | --- | --- | @@ -48,7 +50,7 @@ You can run examples by yourself. Clone the repo and do: | rtl | false | This property enables you to use the sidemenu in a right-to-left page. [Example](http://react-sidemenu-demo.herokuapp.com/) | | shouldTriggerClickOnParents | false | This property enables triggering 'onMenuItemClick' on parent items that have children. | -< Item > - this component is for the non-JSON config of the menu +`` - this component is for the non-JSON config of the menu |**Option**|**Description**| | --- | --- | @@ -63,5 +65,5 @@ You can run examples by yourself. Clone the repo and do: Any contribution is welcome. To be done: - - tests & CI support + - refactor examples code (it's awful, I know) diff --git a/bower.json b/bower.json deleted file mode 100644 index e69de29..0000000 diff --git a/example/src/app.less b/demo/app.less similarity index 95% rename from example/src/app.less rename to demo/app.less index 428035e..e4dccfe 100644 --- a/example/src/app.less +++ b/demo/app.less @@ -1,4 +1,3 @@ -@import "../../less/side-menu.less"; @color-white: #F2F2F2; body { diff --git a/example/src/example-active-item.js b/demo/example-active-item.js similarity index 77% rename from example/src/example-active-item.js rename to demo/example-active-item.js index 2b966a3..4aadfdc 100644 --- a/example/src/example-active-item.js +++ b/demo/example-active-item.js @@ -1,16 +1,14 @@ -import React from 'react'; -import {SideMenu, Item} from 'react-sidemenu'; -import ReactDOM from 'react-dom'; -import createReactClass from 'create-react-class'; +import React, {Component} from 'react'; +import SideMenu, {Item} from 'src'; -let ExampleActiveItem = createReactClass({ +export default class ExampleActiveItem extends Component { + constructor(props) { + super(props); + this.state = {activeItem : 'item1.1.1'}; + } - getInitialState: function() { - return { activeItem: 'item1.1.1'}; - }, - - render: function() { - return ( + render() { + return (

activeItem propery presets the active menu item and opens all the necessary parents. @@ -41,8 +39,6 @@ let ExampleActiveItem = createReactClass({

- ) - } -}); - -ReactDOM.render(, document.getElementById('example-active-item')); + ); + } +} diff --git a/example/src/example-custom-click.js b/demo/example-custom-click.js similarity index 78% rename from example/src/example-custom-click.js rename to demo/example-custom-click.js index 0edd364..3c16ebc 100644 --- a/example/src/example-custom-click.js +++ b/demo/example-custom-click.js @@ -1,10 +1,8 @@ -import React from 'react'; -import {SideMenu, Item} from 'react-sidemenu'; -import ReactDOM from 'react-dom'; -import createReactClass from 'create-react-class'; +import React, {Component} from 'react'; +import SideMenu, {Item} from 'src'; -let Example4 = createReactClass({ - render: function() { +export default class ExampleCustomClick extends Component { + render() { return (

@@ -30,8 +28,6 @@ let Example4 = createReactClass({

- ) + ); } -}); - -ReactDOM.render(, document.getElementById('example-custom-click')); +} diff --git a/example/src/example-custom-render.js b/demo/example-custom-render.js similarity index 78% rename from example/src/example-custom-render.js rename to demo/example-custom-render.js index 5b353c4..2288e0c 100644 --- a/example/src/example-custom-render.js +++ b/demo/example-custom-render.js @@ -1,10 +1,8 @@ -import React from 'react'; -import {SideMenu, Item} from 'react-sidemenu'; -import ReactDOM from 'react-dom'; -import createReactClass from 'create-react-class'; +import React, {Component} from 'react'; +import SideMenu, {Item} from 'src'; -let Example3 = createReactClass({ - render: function() { +export default class ExampleCustomRender extends Component { + render() { return (

@@ -30,8 +28,6 @@ let Example3 = createReactClass({

- ) + ); } -}); - -ReactDOM.render(, document.getElementById('example-custom-render')); +} diff --git a/example/src/example-custom-theme.js b/demo/example-custom-theme.js similarity index 77% rename from example/src/example-custom-theme.js rename to demo/example-custom-theme.js index ec4319c..9a12f61 100644 --- a/example/src/example-custom-theme.js +++ b/demo/example-custom-theme.js @@ -1,10 +1,8 @@ -import React from 'react'; -import {SideMenu, Item} from 'react-sidemenu'; -import ReactDOM from 'react-dom'; -import createReactClass from 'create-react-class'; +import React, {Component} from 'react'; +import SideMenu, {Item} from 'src'; -let ExampleTheme = createReactClass({ - render: function() { +export default class ExampleCustomTheme extends Component { + render() { return (

@@ -30,8 +28,6 @@ let ExampleTheme = createReactClass({

- ) + ); } -}); - -ReactDOM.render(, document.getElementById('example-custom-theme')); +} diff --git a/example/src/example-no-collapse.js b/demo/example-no-collapse.js similarity index 76% rename from example/src/example-no-collapse.js rename to demo/example-no-collapse.js index af91d57..fa8c247 100644 --- a/example/src/example-no-collapse.js +++ b/demo/example-no-collapse.js @@ -1,12 +1,9 @@ -import React from 'react'; -import {SideMenu, Item} from 'react-sidemenu'; -import ReactDOM from 'react-dom'; -import createReactClass from 'create-react-class'; +import React, {Component} from 'react'; +import SideMenu, {Item} from 'src'; -let Example2 = createReactClass({ - render: function() { - return ( -
+export default class ExampleNoCollapse extends Component { + render() { + return(

This propery controls whether sections of menu collapse when you click on other items.

@@ -30,8 +27,6 @@ let Example2 = createReactClass({
- ) + ); } -}); - -ReactDOM.render(, document.getElementById('example-no-collapse')); +} diff --git a/example/src/example-normal.js b/demo/example-normal.js similarity index 74% rename from example/src/example-normal.js rename to demo/example-normal.js index dbd76c4..7a44255 100644 --- a/example/src/example-normal.js +++ b/demo/example-normal.js @@ -1,7 +1,5 @@ -import React from 'react'; -import {SideMenu} from 'react-sidemenu'; -import ReactDOM from 'react-dom'; -import createReactClass from 'create-react-class'; +import React, {Component} from 'react'; +import SideMenu from 'src'; const items = [ {divider: true, label: 'Segment 1', value: 'segment1'}, @@ -23,8 +21,8 @@ const items = [ {label: 'Item 3', value: 'item3', icon: 'fa-beer'} ]; -let Example1 = createReactClass({ - render: function() { +export default class ExampleNormal extends Component { + render() { return (
- ) + ); } -}); - -ReactDOM.render(, document.getElementById('example-normal')); +} diff --git a/example/src/example-rtl.js b/demo/example-rtl.js similarity index 74% rename from example/src/example-rtl.js rename to demo/example-rtl.js index 0773285..04576ea 100644 --- a/example/src/example-rtl.js +++ b/demo/example-rtl.js @@ -1,7 +1,5 @@ -import React from 'react'; -import {SideMenu} from 'react-sidemenu'; -import ReactDOM from 'react-dom'; -import createReactClass from 'create-react-class'; +import React, {Component} from 'react'; +import SideMenu from 'src'; const items = [ {divider: true, label: 'Segment 1', value: 'segment1'}, @@ -23,8 +21,8 @@ const items = [ {label: 'Item 3', value: 'item3', icon: 'fa-beer'} ]; -let Example5 = createReactClass({ - render: function() { +export default class ExampleRTL extends Component { + render() { return (
- ) + ); } -}); - -ReactDOM.render(, document.getElementById('example-rtl')); +} diff --git a/example/dist/index.html b/demo/index.html similarity index 67% rename from example/dist/index.html rename to demo/index.html index 6c292b5..47fa0d6 100644 --- a/example/dist/index.html +++ b/demo/index.html @@ -1,16 +1,19 @@ - React Starter Component + React Side Menu Component - - - - - + + + + + + + + - + |EventPluginHub| | Event | - * | | . | | +-----------+ | Propagators| - * | ReactEvent | . | | |TapEvent | |------------| - * | Emitter | . | |<---+|Plugin | |other plugin| - * | | . | | +-----------+ | utilities | - * | +-----------.--->| | +------------+ - * | | | . +--------------+ - * +-----|------+ . ^ +-----------+ - * | . | |Enter/Leave| - * + . +-------+|Plugin | - * +-------------+ . +-----------+ - * | application | . - * |-------------| . - * | | . - * | | . - * +-------------+ . - * . - * React Core . General Purpose Event Plugin System - */ - -var alreadyListeningTo = {}; -var reactTopListenersCounter = 0; - -/** - * To ensure no conflicts with other potential React instances on the page - */ -var topListenersIDKey = '_reactListenersID' + ('' + Math.random()).slice(2); - -function getListeningForDocument(mountAt) { - // In IE8, `mountAt` is a host object and doesn't have `hasOwnProperty` - // directly. - if (!Object.prototype.hasOwnProperty.call(mountAt, topListenersIDKey)) { - mountAt[topListenersIDKey] = reactTopListenersCounter++; - alreadyListeningTo[mountAt[topListenersIDKey]] = {}; - } - return alreadyListeningTo[mountAt[topListenersIDKey]]; -} - -/** - * We listen for bubbled touch events on the document object. - * - * Firefox v8.01 (and possibly others) exhibited strange behavior when - * mounting `onmousemove` events at some node that was not the document - * element. The symptoms were that if your mouse is not moving over something - * contained within that mount point (for example on the background) the - * top-level listeners for `onmousemove` won't be called. However, if you - * register the `mousemove` on the document object, then it will of course - * catch all `mousemove`s. This along with iOS quirks, justifies restricting - * top-level listeners to the document object only, at least for these - * movement types of events and possibly all events. - * - * @see http://www.quirksmode.org/blog/archives/2010/09/click_event_del.html - * - * Also, `keyup`/`keypress`/`keydown` do not bubble to the window on IE, but - * they bubble to document. - * - * @param {string} registrationName Name of listener (e.g. `onClick`). - * @param {object} contentDocumentHandle Document which owns the container - */ -function listenTo(registrationName, contentDocumentHandle) { - var mountAt = contentDocumentHandle; - var isListening = getListeningForDocument(mountAt); - var dependencies = registrationNameDependencies[registrationName]; - - for (var i = 0; i < dependencies.length; i++) { - var dependency = dependencies[i]; - if (!(isListening.hasOwnProperty(dependency) && isListening[dependency])) { - if (dependency === 'topScroll') { - trapCapturedEvent('topScroll', 'scroll', mountAt); - } else if (dependency === 'topFocus' || dependency === 'topBlur') { - trapCapturedEvent('topFocus', 'focus', mountAt); - trapCapturedEvent('topBlur', 'blur', mountAt); - - // to make sure blur and focus event listeners are only attached once - isListening.topBlur = true; - isListening.topFocus = true; - } else if (dependency === 'topCancel') { - if (isEventSupported('cancel', true)) { - trapCapturedEvent('topCancel', 'cancel', mountAt); - } - isListening.topCancel = true; - } else if (dependency === 'topClose') { - if (isEventSupported('close', true)) { - trapCapturedEvent('topClose', 'close', mountAt); - } - isListening.topClose = true; - } else if (topLevelTypes.hasOwnProperty(dependency)) { - trapBubbledEvent(dependency, topLevelTypes[dependency], mountAt); - } - - isListening[dependency] = true; - } - } -} - -function isListeningToAllDependencies(registrationName, mountAt) { - var isListening = getListeningForDocument(mountAt); - var dependencies = registrationNameDependencies[registrationName]; - for (var i = 0; i < dependencies.length; i++) { - var dependency = dependencies[i]; - if (!(isListening.hasOwnProperty(dependency) && isListening[dependency])) { - return false; - } - } - return true; -} - -/** - * Given any node return the first leaf node without children. - * - * @param {DOMElement|DOMTextNode} node - * @return {DOMElement|DOMTextNode} - */ -function getLeafNode(node) { - while (node && node.firstChild) { - node = node.firstChild; - } - return node; -} - -/** - * Get the next sibling within a container. This will walk up the - * DOM if a node's siblings have been exhausted. - * - * @param {DOMElement|DOMTextNode} node - * @return {?DOMElement|DOMTextNode} - */ -function getSiblingNode(node) { - while (node) { - if (node.nextSibling) { - return node.nextSibling; - } - node = node.parentNode; - } -} - -/** - * Get object describing the nodes which contain characters at offset. - * - * @param {DOMElement|DOMTextNode} root - * @param {number} offset - * @return {?object} - */ -function getNodeForCharacterOffset(root, offset) { - var node = getLeafNode(root); - var nodeStart = 0; - var nodeEnd = 0; - - while (node) { - if (node.nodeType === TEXT_NODE) { - nodeEnd = nodeStart + node.textContent.length; - - if (nodeStart <= offset && nodeEnd >= offset) { - return { - node: node, - offset: offset - nodeStart - }; - } - - nodeStart = nodeEnd; - } - - node = getLeafNode(getSiblingNode(node)); - } -} - -/** - * @param {DOMElement} outerNode - * @return {?object} - */ -function getOffsets(outerNode) { - var selection = window.getSelection && window.getSelection(); - - if (!selection || selection.rangeCount === 0) { - return null; - } - - var anchorNode = selection.anchorNode, - anchorOffset = selection.anchorOffset, - focusNode$$1 = selection.focusNode, - focusOffset = selection.focusOffset; - - // In Firefox, anchorNode and focusNode can be "anonymous divs", e.g. the - // up/down buttons on an . Anonymous divs do not seem to - // expose properties, triggering a "Permission denied error" if any of its - // properties are accessed. The only seemingly possible way to avoid erroring - // is to access a property that typically works for non-anonymous divs and - // catch any error that may otherwise arise. See - // https://bugzilla.mozilla.org/show_bug.cgi?id=208427 - - try { - /* eslint-disable no-unused-expressions */ - anchorNode.nodeType; - focusNode$$1.nodeType; - /* eslint-enable no-unused-expressions */ - } catch (e) { - return null; - } - - return getModernOffsetsFromPoints(outerNode, anchorNode, anchorOffset, focusNode$$1, focusOffset); -} - -/** - * Returns {start, end} where `start` is the character/codepoint index of - * (anchorNode, anchorOffset) within the textContent of `outerNode`, and - * `end` is the index of (focusNode, focusOffset). - * - * Returns null if you pass in garbage input but we should probably just crash. - * - * Exported only for testing. - */ -function getModernOffsetsFromPoints(outerNode, anchorNode, anchorOffset, focusNode$$1, focusOffset) { - var length = 0; - var start = -1; - var end = -1; - var indexWithinAnchor = 0; - var indexWithinFocus = 0; - var node = outerNode; - var parentNode = null; - - outer: while (true) { - var next = null; - - while (true) { - if (node === anchorNode && (anchorOffset === 0 || node.nodeType === TEXT_NODE)) { - start = length + anchorOffset; - } - if (node === focusNode$$1 && (focusOffset === 0 || node.nodeType === TEXT_NODE)) { - end = length + focusOffset; - } - - if (node.nodeType === TEXT_NODE) { - length += node.nodeValue.length; - } - - if ((next = node.firstChild) === null) { - break; - } - // Moving from `node` to its first child `next`. - parentNode = node; - node = next; - } - - while (true) { - if (node === outerNode) { - // If `outerNode` has children, this is always the second time visiting - // it. If it has no children, this is still the first loop, and the only - // valid selection is anchorNode and focusNode both equal to this node - // and both offsets 0, in which case we will have handled above. - break outer; - } - if (parentNode === anchorNode && ++indexWithinAnchor === anchorOffset) { - start = length; - } - if (parentNode === focusNode$$1 && ++indexWithinFocus === focusOffset) { - end = length; - } - if ((next = node.nextSibling) !== null) { - break; - } - node = parentNode; - parentNode = node.parentNode; - } - - // Moving from `node` to its next sibling `next`. - node = next; - } - - if (start === -1 || end === -1) { - // This should never happen. (Would happen if the anchor/focus nodes aren't - // actually inside the passed-in node.) - return null; - } - - return { - start: start, - end: end - }; -} - -/** - * In modern non-IE browsers, we can support both forward and backward - * selections. - * - * Note: IE10+ supports the Selection object, but it does not support - * the `extend` method, which means that even in modern IE, it's not possible - * to programmatically create a backward selection. Thus, for all IE - * versions, we use the old IE API to create our selections. - * - * @param {DOMElement|DOMTextNode} node - * @param {object} offsets - */ -function setOffsets(node, offsets) { - if (!window.getSelection) { - return; - } - - var selection = window.getSelection(); - var length = node[getTextContentAccessor()].length; - var start = Math.min(offsets.start, length); - var end = offsets.end === undefined ? start : Math.min(offsets.end, length); - - // IE 11 uses modern selection, but doesn't support the extend method. - // Flip backward selections, so we can set with a single range. - if (!selection.extend && start > end) { - var temp = end; - end = start; - start = temp; - } - - var startMarker = getNodeForCharacterOffset(node, start); - var endMarker = getNodeForCharacterOffset(node, end); - - if (startMarker && endMarker) { - if (selection.rangeCount === 1 && selection.anchorNode === startMarker.node && selection.anchorOffset === startMarker.offset && selection.focusNode === endMarker.node && selection.focusOffset === endMarker.offset) { - return; - } - var range = document.createRange(); - range.setStart(startMarker.node, startMarker.offset); - selection.removeAllRanges(); - - if (start > end) { - selection.addRange(range); - selection.extend(endMarker.node, endMarker.offset); - } else { - range.setEnd(endMarker.node, endMarker.offset); - selection.addRange(range); - } - } -} - -function isInDocument(node) { - return containsNode(document.documentElement, node); -} - -/** - * @ReactInputSelection: React input selection module. Based on Selection.js, - * but modified to be suitable for react and has a couple of bug fixes (doesn't - * assume buttons have range selections allowed). - * Input selection module for React. - */ - -function hasSelectionCapabilities(elem) { - var nodeName = elem && elem.nodeName && elem.nodeName.toLowerCase(); - return nodeName && (nodeName === 'input' && elem.type === 'text' || nodeName === 'textarea' || elem.contentEditable === 'true'); -} - -function getSelectionInformation() { - var focusedElem = getActiveElement(); - return { - focusedElem: focusedElem, - selectionRange: hasSelectionCapabilities(focusedElem) ? getSelection$1(focusedElem) : null - }; -} - -/** - * @restoreSelection: If any selection information was potentially lost, - * restore it. This is useful when performing operations that could remove dom - * nodes and place them back in, resulting in focus being lost. - */ -function restoreSelection(priorSelectionInformation) { - var curFocusedElem = getActiveElement(); - var priorFocusedElem = priorSelectionInformation.focusedElem; - var priorSelectionRange = priorSelectionInformation.selectionRange; - if (curFocusedElem !== priorFocusedElem && isInDocument(priorFocusedElem)) { - if (hasSelectionCapabilities(priorFocusedElem)) { - setSelection(priorFocusedElem, priorSelectionRange); - } - - // Focusing a node can change the scroll position, which is undesirable - var ancestors = []; - var ancestor = priorFocusedElem; - while (ancestor = ancestor.parentNode) { - if (ancestor.nodeType === ELEMENT_NODE) { - ancestors.push({ - element: ancestor, - left: ancestor.scrollLeft, - top: ancestor.scrollTop - }); - } - } - - focusNode(priorFocusedElem); - - for (var i = 0; i < ancestors.length; i++) { - var info = ancestors[i]; - info.element.scrollLeft = info.left; - info.element.scrollTop = info.top; - } - } -} - -/** - * @getSelection: Gets the selection bounds of a focused textarea, input or - * contentEditable node. - * -@input: Look up selection bounds of this input - * -@return {start: selectionStart, end: selectionEnd} - */ -function getSelection$1(input) { - var selection = void 0; - - if ('selectionStart' in input) { - // Modern browser with input or textarea. - selection = { - start: input.selectionStart, - end: input.selectionEnd - }; - } else { - // Content editable or old IE textarea. - selection = getOffsets(input); - } - - return selection || { start: 0, end: 0 }; -} - -/** - * @setSelection: Sets the selection bounds of a textarea or input and focuses - * the input. - * -@input Set selection bounds of this input or textarea - * -@offsets Object of same form that is returned from get* - */ -function setSelection(input, offsets) { - var start = offsets.start, - end = offsets.end; - - if (end === undefined) { - end = start; - } - - if ('selectionStart' in input) { - input.selectionStart = start; - input.selectionEnd = Math.min(end, input.value.length); - } else { - setOffsets(input, offsets); - } -} - -var skipSelectionChangeEvent = ExecutionEnvironment.canUseDOM && 'documentMode' in document && document.documentMode <= 11; - -var eventTypes$3 = { - select: { - phasedRegistrationNames: { - bubbled: 'onSelect', - captured: 'onSelectCapture' - }, - dependencies: ['topBlur', 'topContextMenu', 'topFocus', 'topKeyDown', 'topKeyUp', 'topMouseDown', 'topMouseUp', 'topSelectionChange'] - } -}; - -var activeElement$1 = null; -var activeElementInst$1 = null; -var lastSelection = null; -var mouseDown = false; - -/** - * Get an object which is a unique representation of the current selection. - * - * The return value will not be consistent across nodes or browsers, but - * two identical selections on the same node will return identical objects. - * - * @param {DOMElement} node - * @return {object} - */ -function getSelection(node) { - if ('selectionStart' in node && hasSelectionCapabilities(node)) { - return { - start: node.selectionStart, - end: node.selectionEnd - }; - } else if (window.getSelection) { - var selection = window.getSelection(); - return { - anchorNode: selection.anchorNode, - anchorOffset: selection.anchorOffset, - focusNode: selection.focusNode, - focusOffset: selection.focusOffset - }; - } -} - -/** - * Poll selection to see whether it's changed. - * - * @param {object} nativeEvent - * @return {?SyntheticEvent} - */ -function constructSelectEvent(nativeEvent, nativeEventTarget) { - // Ensure we have the right element, and that the user is not dragging a - // selection (this matches native `select` event behavior). In HTML5, select - // fires only on input and textarea thus if there's no focused element we - // won't dispatch. - if (mouseDown || activeElement$1 == null || activeElement$1 !== getActiveElement()) { - return null; - } - - // Only fire when selection has actually changed. - var currentSelection = getSelection(activeElement$1); - if (!lastSelection || !shallowEqual(lastSelection, currentSelection)) { - lastSelection = currentSelection; - - var syntheticEvent = SyntheticEvent$1.getPooled(eventTypes$3.select, activeElementInst$1, nativeEvent, nativeEventTarget); - - syntheticEvent.type = 'select'; - syntheticEvent.target = activeElement$1; - - accumulateTwoPhaseDispatches(syntheticEvent); - - return syntheticEvent; - } - - return null; -} - -/** - * This plugin creates an `onSelect` event that normalizes select events - * across form elements. - * - * Supported elements are: - * - input (see `isTextInputElement`) - * - textarea - * - contentEditable - * - * This differs from native browser implementations in the following ways: - * - Fires on contentEditable fields as well as inputs. - * - Fires for collapsed selection. - * - Fires after user input. - */ -var SelectEventPlugin = { - eventTypes: eventTypes$3, - - extractEvents: function (topLevelType, targetInst, nativeEvent, nativeEventTarget) { - var doc = nativeEventTarget.window === nativeEventTarget ? nativeEventTarget.document : nativeEventTarget.nodeType === DOCUMENT_NODE ? nativeEventTarget : nativeEventTarget.ownerDocument; - // Track whether all listeners exists for this plugin. If none exist, we do - // not extract events. See #3639. - if (!doc || !isListeningToAllDependencies('onSelect', doc)) { - return null; - } - - var targetNode = targetInst ? getNodeFromInstance$1(targetInst) : window; - - switch (topLevelType) { - // Track the input node that has focus. - case 'topFocus': - if (isTextInputElement(targetNode) || targetNode.contentEditable === 'true') { - activeElement$1 = targetNode; - activeElementInst$1 = targetInst; - lastSelection = null; - } - break; - case 'topBlur': - activeElement$1 = null; - activeElementInst$1 = null; - lastSelection = null; - break; - // Don't fire the event while the user is dragging. This matches the - // semantics of the native select event. - case 'topMouseDown': - mouseDown = true; - break; - case 'topContextMenu': - case 'topMouseUp': - mouseDown = false; - return constructSelectEvent(nativeEvent, nativeEventTarget); - // Chrome and IE fire non-standard event when selection is changed (and - // sometimes when it hasn't). IE's event fires out of order with respect - // to key and input events on deletion, so we discard it. - // - // Firefox doesn't support selectionchange, so check selection status - // after each key entry. The selection changes after keydown and before - // keyup, but we check on keydown as well in the case of holding down a - // key, when multiple keydown events are fired but only one keyup is. - // This is also our approach for IE handling, for the reason above. - case 'topSelectionChange': - if (skipSelectionChangeEvent) { - break; - } - // falls through - case 'topKeyDown': - case 'topKeyUp': - return constructSelectEvent(nativeEvent, nativeEventTarget); - } - - return null; - } -}; - -/** - * @interface Event - * @see http://www.w3.org/TR/css3-animations/#AnimationEvent-interface - * @see https://developer.mozilla.org/en-US/docs/Web/API/AnimationEvent - */ -var AnimationEventInterface = { - animationName: null, - elapsedTime: null, - pseudoElement: null -}; - -/** - * @param {object} dispatchConfig Configuration used to dispatch this event. - * @param {string} dispatchMarker Marker identifying the event target. - * @param {object} nativeEvent Native browser event. - * @extends {SyntheticEvent} - */ -function SyntheticAnimationEvent(dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget) { - return SyntheticEvent$1.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget); -} - -SyntheticEvent$1.augmentClass(SyntheticAnimationEvent, AnimationEventInterface); - -/** - * @interface Event - * @see http://www.w3.org/TR/clipboard-apis/ - */ -var ClipboardEventInterface = { - clipboardData: function (event) { - return 'clipboardData' in event ? event.clipboardData : window.clipboardData; - } -}; - -/** - * @param {object} dispatchConfig Configuration used to dispatch this event. - * @param {string} dispatchMarker Marker identifying the event target. - * @param {object} nativeEvent Native browser event. - * @extends {SyntheticEvent} - */ -function SyntheticClipboardEvent(dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget) { - return SyntheticEvent$1.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget); -} - -SyntheticEvent$1.augmentClass(SyntheticClipboardEvent, ClipboardEventInterface); - -/** - * @interface FocusEvent - * @see http://www.w3.org/TR/DOM-Level-3-Events/ - */ -var FocusEventInterface = { - relatedTarget: null -}; - -/** - * @param {object} dispatchConfig Configuration used to dispatch this event. - * @param {string} dispatchMarker Marker identifying the event target. - * @param {object} nativeEvent Native browser event. - * @extends {SyntheticUIEvent} - */ -function SyntheticFocusEvent(dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget) { - return SyntheticUIEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget); -} - -SyntheticUIEvent.augmentClass(SyntheticFocusEvent, FocusEventInterface); - -/** - * `charCode` represents the actual "character code" and is safe to use with - * `String.fromCharCode`. As such, only keys that correspond to printable - * characters produce a valid `charCode`, the only exception to this is Enter. - * The Tab-key is considered non-printable and does not have a `charCode`, - * presumably because it does not produce a tab-character in browsers. - * - * @param {object} nativeEvent Native browser event. - * @return {number} Normalized `charCode` property. - */ -function getEventCharCode(nativeEvent) { - var charCode; - var keyCode = nativeEvent.keyCode; - - if ('charCode' in nativeEvent) { - charCode = nativeEvent.charCode; - - // FF does not set `charCode` for the Enter-key, check against `keyCode`. - if (charCode === 0 && keyCode === 13) { - charCode = 13; - } - } else { - // IE8 does not implement `charCode`, but `keyCode` has the correct value. - charCode = keyCode; - } - - // Some non-printable keys are reported in `charCode`/`keyCode`, discard them. - // Must not discard the (non-)printable Enter-key. - if (charCode >= 32 || charCode === 13) { - return charCode; - } - - return 0; -} - -/** - * Normalization of deprecated HTML5 `key` values - * @see https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent#Key_names - */ -var normalizeKey = { - Esc: 'Escape', - Spacebar: ' ', - Left: 'ArrowLeft', - Up: 'ArrowUp', - Right: 'ArrowRight', - Down: 'ArrowDown', - Del: 'Delete', - Win: 'OS', - Menu: 'ContextMenu', - Apps: 'ContextMenu', - Scroll: 'ScrollLock', - MozPrintableKey: 'Unidentified' -}; - -/** - * Translation from legacy `keyCode` to HTML5 `key` - * Only special keys supported, all others depend on keyboard layout or browser - * @see https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent#Key_names - */ -var translateToKey = { - '8': 'Backspace', - '9': 'Tab', - '12': 'Clear', - '13': 'Enter', - '16': 'Shift', - '17': 'Control', - '18': 'Alt', - '19': 'Pause', - '20': 'CapsLock', - '27': 'Escape', - '32': ' ', - '33': 'PageUp', - '34': 'PageDown', - '35': 'End', - '36': 'Home', - '37': 'ArrowLeft', - '38': 'ArrowUp', - '39': 'ArrowRight', - '40': 'ArrowDown', - '45': 'Insert', - '46': 'Delete', - '112': 'F1', - '113': 'F2', - '114': 'F3', - '115': 'F4', - '116': 'F5', - '117': 'F6', - '118': 'F7', - '119': 'F8', - '120': 'F9', - '121': 'F10', - '122': 'F11', - '123': 'F12', - '144': 'NumLock', - '145': 'ScrollLock', - '224': 'Meta' -}; - -/** - * @param {object} nativeEvent Native browser event. - * @return {string} Normalized `key` property. - */ -function getEventKey(nativeEvent) { - if (nativeEvent.key) { - // Normalize inconsistent values reported by browsers due to - // implementations of a working draft specification. - - // FireFox implements `key` but returns `MozPrintableKey` for all - // printable characters (normalized to `Unidentified`), ignore it. - var key = normalizeKey[nativeEvent.key] || nativeEvent.key; - if (key !== 'Unidentified') { - return key; - } - } - - // Browser does not implement `key`, polyfill as much of it as we can. - if (nativeEvent.type === 'keypress') { - var charCode = getEventCharCode(nativeEvent); - - // The enter-key is technically both printable and non-printable and can - // thus be captured by `keypress`, no other non-printable key should. - return charCode === 13 ? 'Enter' : String.fromCharCode(charCode); - } - if (nativeEvent.type === 'keydown' || nativeEvent.type === 'keyup') { - // While user keyboard layout determines the actual meaning of each - // `keyCode` value, almost all function keys have a universal value. - return translateToKey[nativeEvent.keyCode] || 'Unidentified'; - } - return ''; -} - -/** - * @interface KeyboardEvent - * @see http://www.w3.org/TR/DOM-Level-3-Events/ - */ -var KeyboardEventInterface = { - key: getEventKey, - location: null, - ctrlKey: null, - shiftKey: null, - altKey: null, - metaKey: null, - repeat: null, - locale: null, - getModifierState: getEventModifierState, - // Legacy Interface - charCode: function (event) { - // `charCode` is the result of a KeyPress event and represents the value of - // the actual printable character. - - // KeyPress is deprecated, but its replacement is not yet final and not - // implemented in any major browser. Only KeyPress has charCode. - if (event.type === 'keypress') { - return getEventCharCode(event); - } - return 0; - }, - keyCode: function (event) { - // `keyCode` is the result of a KeyDown/Up event and represents the value of - // physical keyboard key. - - // The actual meaning of the value depends on the users' keyboard layout - // which cannot be detected. Assuming that it is a US keyboard layout - // provides a surprisingly accurate mapping for US and European users. - // Due to this, it is left to the user to implement at this time. - if (event.type === 'keydown' || event.type === 'keyup') { - return event.keyCode; - } - return 0; - }, - which: function (event) { - // `which` is an alias for either `keyCode` or `charCode` depending on the - // type of the event. - if (event.type === 'keypress') { - return getEventCharCode(event); - } - if (event.type === 'keydown' || event.type === 'keyup') { - return event.keyCode; - } - return 0; - } -}; - -/** - * @param {object} dispatchConfig Configuration used to dispatch this event. - * @param {string} dispatchMarker Marker identifying the event target. - * @param {object} nativeEvent Native browser event. - * @extends {SyntheticUIEvent} - */ -function SyntheticKeyboardEvent(dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget) { - return SyntheticUIEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget); -} - -SyntheticUIEvent.augmentClass(SyntheticKeyboardEvent, KeyboardEventInterface); - -/** - * @interface DragEvent - * @see http://www.w3.org/TR/DOM-Level-3-Events/ - */ -var DragEventInterface = { - dataTransfer: null -}; - -/** - * @param {object} dispatchConfig Configuration used to dispatch this event. - * @param {string} dispatchMarker Marker identifying the event target. - * @param {object} nativeEvent Native browser event. - * @extends {SyntheticMouseEvent} - */ -function SyntheticDragEvent(dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget) { - return SyntheticMouseEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget); -} - -SyntheticMouseEvent.augmentClass(SyntheticDragEvent, DragEventInterface); - -/** - * @interface TouchEvent - * @see http://www.w3.org/TR/touch-events/ - */ -var TouchEventInterface = { - touches: null, - targetTouches: null, - changedTouches: null, - altKey: null, - metaKey: null, - ctrlKey: null, - shiftKey: null, - getModifierState: getEventModifierState -}; - -/** - * @param {object} dispatchConfig Configuration used to dispatch this event. - * @param {string} dispatchMarker Marker identifying the event target. - * @param {object} nativeEvent Native browser event. - * @extends {SyntheticUIEvent} - */ -function SyntheticTouchEvent(dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget) { - return SyntheticUIEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget); -} - -SyntheticUIEvent.augmentClass(SyntheticTouchEvent, TouchEventInterface); - -/** - * @interface Event - * @see http://www.w3.org/TR/2009/WD-css3-transitions-20090320/#transition-events- - * @see https://developer.mozilla.org/en-US/docs/Web/API/TransitionEvent - */ -var TransitionEventInterface = { - propertyName: null, - elapsedTime: null, - pseudoElement: null -}; - -/** - * @param {object} dispatchConfig Configuration used to dispatch this event. - * @param {string} dispatchMarker Marker identifying the event target. - * @param {object} nativeEvent Native browser event. - * @extends {SyntheticEvent} - */ -function SyntheticTransitionEvent(dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget) { - return SyntheticEvent$1.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget); -} - -SyntheticEvent$1.augmentClass(SyntheticTransitionEvent, TransitionEventInterface); - -/** - * @interface WheelEvent - * @see http://www.w3.org/TR/DOM-Level-3-Events/ - */ -var WheelEventInterface = { - deltaX: function (event) { - return 'deltaX' in event ? event.deltaX : // Fallback to `wheelDeltaX` for Webkit and normalize (right is positive). - 'wheelDeltaX' in event ? -event.wheelDeltaX : 0; - }, - deltaY: function (event) { - return 'deltaY' in event ? event.deltaY : // Fallback to `wheelDeltaY` for Webkit and normalize (down is positive). - 'wheelDeltaY' in event ? -event.wheelDeltaY : // Fallback to `wheelDelta` for IE<9 and normalize (down is positive). - 'wheelDelta' in event ? -event.wheelDelta : 0; - }, - deltaZ: null, - - // Browsers without "deltaMode" is reporting in raw wheel delta where one - // notch on the scroll is always +/- 120, roughly equivalent to pixels. - // A good approximation of DOM_DELTA_LINE (1) is 5% of viewport size or - // ~40 pixels, for DOM_DELTA_SCREEN (2) it is 87.5% of viewport size. - deltaMode: null -}; - -/** - * @param {object} dispatchConfig Configuration used to dispatch this event. - * @param {string} dispatchMarker Marker identifying the event target. - * @param {object} nativeEvent Native browser event. - * @extends {SyntheticMouseEvent} - */ -function SyntheticWheelEvent(dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget) { - return SyntheticMouseEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget); -} - -SyntheticMouseEvent.augmentClass(SyntheticWheelEvent, WheelEventInterface); - -/** - * Turns - * ['abort', ...] - * into - * eventTypes = { - * 'abort': { - * phasedRegistrationNames: { - * bubbled: 'onAbort', - * captured: 'onAbortCapture', - * }, - * dependencies: ['topAbort'], - * }, - * ... - * }; - * topLevelEventsToDispatchConfig = { - * 'topAbort': { sameConfig } - * }; - */ -var eventTypes$4 = {}; -var topLevelEventsToDispatchConfig = {}; -['abort', 'animationEnd', 'animationIteration', 'animationStart', 'blur', 'cancel', 'canPlay', 'canPlayThrough', 'click', 'close', 'contextMenu', 'copy', 'cut', 'doubleClick', 'drag', 'dragEnd', 'dragEnter', 'dragExit', 'dragLeave', 'dragOver', 'dragStart', 'drop', 'durationChange', 'emptied', 'encrypted', 'ended', 'error', 'focus', 'input', 'invalid', 'keyDown', 'keyPress', 'keyUp', 'load', 'loadedData', 'loadedMetadata', 'loadStart', 'mouseDown', 'mouseMove', 'mouseOut', 'mouseOver', 'mouseUp', 'paste', 'pause', 'play', 'playing', 'progress', 'rateChange', 'reset', 'scroll', 'seeked', 'seeking', 'stalled', 'submit', 'suspend', 'timeUpdate', 'toggle', 'touchCancel', 'touchEnd', 'touchMove', 'touchStart', 'transitionEnd', 'volumeChange', 'waiting', 'wheel'].forEach(function (event) { - var capitalizedEvent = event[0].toUpperCase() + event.slice(1); - var onEvent = 'on' + capitalizedEvent; - var topEvent = 'top' + capitalizedEvent; - - var type = { - phasedRegistrationNames: { - bubbled: onEvent, - captured: onEvent + 'Capture' - }, - dependencies: [topEvent] - }; - eventTypes$4[event] = type; - topLevelEventsToDispatchConfig[topEvent] = type; -}); - -// Only used in DEV for exhaustiveness validation. -var knownHTMLTopLevelTypes = ['topAbort', 'topCancel', 'topCanPlay', 'topCanPlayThrough', 'topClose', 'topDurationChange', 'topEmptied', 'topEncrypted', 'topEnded', 'topError', 'topInput', 'topInvalid', 'topLoad', 'topLoadedData', 'topLoadedMetadata', 'topLoadStart', 'topPause', 'topPlay', 'topPlaying', 'topProgress', 'topRateChange', 'topReset', 'topSeeked', 'topSeeking', 'topStalled', 'topSubmit', 'topSuspend', 'topTimeUpdate', 'topToggle', 'topVolumeChange', 'topWaiting']; - -var SimpleEventPlugin = { - eventTypes: eventTypes$4, - - extractEvents: function (topLevelType, targetInst, nativeEvent, nativeEventTarget) { - var dispatchConfig = topLevelEventsToDispatchConfig[topLevelType]; - if (!dispatchConfig) { - return null; - } - var EventConstructor; - switch (topLevelType) { - case 'topKeyPress': - // Firefox creates a keypress event for function keys too. This removes - // the unwanted keypress events. Enter is however both printable and - // non-printable. One would expect Tab to be as well (but it isn't). - if (getEventCharCode(nativeEvent) === 0) { - return null; - } - /* falls through */ - case 'topKeyDown': - case 'topKeyUp': - EventConstructor = SyntheticKeyboardEvent; - break; - case 'topBlur': - case 'topFocus': - EventConstructor = SyntheticFocusEvent; - break; - case 'topClick': - // Firefox creates a click event on right mouse clicks. This removes the - // unwanted click events. - if (nativeEvent.button === 2) { - return null; - } - /* falls through */ - case 'topDoubleClick': - case 'topMouseDown': - case 'topMouseMove': - case 'topMouseUp': - // TODO: Disabled elements should not respond to mouse events - /* falls through */ - case 'topMouseOut': - case 'topMouseOver': - case 'topContextMenu': - EventConstructor = SyntheticMouseEvent; - break; - case 'topDrag': - case 'topDragEnd': - case 'topDragEnter': - case 'topDragExit': - case 'topDragLeave': - case 'topDragOver': - case 'topDragStart': - case 'topDrop': - EventConstructor = SyntheticDragEvent; - break; - case 'topTouchCancel': - case 'topTouchEnd': - case 'topTouchMove': - case 'topTouchStart': - EventConstructor = SyntheticTouchEvent; - break; - case 'topAnimationEnd': - case 'topAnimationIteration': - case 'topAnimationStart': - EventConstructor = SyntheticAnimationEvent; - break; - case 'topTransitionEnd': - EventConstructor = SyntheticTransitionEvent; - break; - case 'topScroll': - EventConstructor = SyntheticUIEvent; - break; - case 'topWheel': - EventConstructor = SyntheticWheelEvent; - break; - case 'topCopy': - case 'topCut': - case 'topPaste': - EventConstructor = SyntheticClipboardEvent; - break; - default: - { - if (knownHTMLTopLevelTypes.indexOf(topLevelType) === -1) { - warning(false, 'SimpleEventPlugin: Unhandled event type, `%s`. This warning ' + 'is likely caused by a bug in React. Please file an issue.', topLevelType); - } - } - // HTML Events - // @see http://www.w3.org/TR/html5/index.html#events-0 - EventConstructor = SyntheticEvent$1; - break; - } - var event = EventConstructor.getPooled(dispatchConfig, targetInst, nativeEvent, nativeEventTarget); - accumulateTwoPhaseDispatches(event); - return event; - } -}; - -setHandleTopLevel(handleTopLevel); - -/** - * Inject modules for resolving DOM hierarchy and plugin ordering. - */ -injection$1.injectEventPluginOrder(DOMEventPluginOrder); -injection$2.injectComponentTree(ReactDOMComponentTree); - -/** - * Some important event plugins included by default (without having to require - * them). - */ -injection$1.injectEventPluginsByName({ - SimpleEventPlugin: SimpleEventPlugin, - EnterLeaveEventPlugin: EnterLeaveEventPlugin, - ChangeEventPlugin: ChangeEventPlugin, - SelectEventPlugin: SelectEventPlugin, - BeforeInputEventPlugin: BeforeInputEventPlugin -}); - -var enableAsyncSubtreeAPI = true; -var enableAsyncSchedulingByDefaultInReactDOM = false; -// Exports ReactDOM.createRoot -var enableCreateRoot = false; -var enableUserTimingAPI = true; - -// Mutating mode (React DOM, React ART, React Native): -var enableMutatingReconciler = true; -// Experimental noop mode (currently unused): -var enableNoopReconciler = false; -// Experimental persistent mode (CS): -var enablePersistentReconciler = false; - -// Helps identify side effects in begin-phase lifecycle hooks and setState reducers: -var debugRenderPhaseSideEffects = false; - -// Only used in www builds. - -var valueStack = []; - -{ - var fiberStack = []; -} - -var index = -1; - -function createCursor(defaultValue) { - return { - current: defaultValue - }; -} - - - -function pop(cursor, fiber) { - if (index < 0) { - { - warning(false, 'Unexpected pop.'); - } - return; - } - - { - if (fiber !== fiberStack[index]) { - warning(false, 'Unexpected Fiber popped.'); - } - } - - cursor.current = valueStack[index]; - - valueStack[index] = null; - - { - fiberStack[index] = null; - } - - index--; -} - -function push(cursor, value, fiber) { - index++; - - valueStack[index] = cursor.current; - - { - fiberStack[index] = fiber; - } - - cursor.current = value; -} - -function reset$1() { - while (index > -1) { - valueStack[index] = null; - - { - fiberStack[index] = null; - } - - index--; - } -} - -var describeComponentFrame = function (name, source, ownerName) { - return '\n in ' + (name || 'Unknown') + (source ? ' (at ' + source.fileName.replace(/^.*[\\\/]/, '') + ':' + source.lineNumber + ')' : ownerName ? ' (created by ' + ownerName + ')' : ''); -}; - -function describeFiber(fiber) { - switch (fiber.tag) { - case IndeterminateComponent: - case FunctionalComponent: - case ClassComponent: - case HostComponent: - var owner = fiber._debugOwner; - var source = fiber._debugSource; - var name = getComponentName(fiber); - var ownerName = null; - if (owner) { - ownerName = getComponentName(owner); - } - return describeComponentFrame(name, source, ownerName); - default: - return ''; - } -} - -// This function can only be called with a work-in-progress fiber and -// only during begin or complete phase. Do not call it under any other -// circumstances. -function getStackAddendumByWorkInProgressFiber(workInProgress) { - var info = ''; - var node = workInProgress; - do { - info += describeFiber(node); - // Otherwise this return pointer might point to the wrong tree: - node = node['return']; - } while (node); - return info; -} - -function getCurrentFiberOwnerName() { - { - var fiber = ReactDebugCurrentFiber.current; - if (fiber === null) { - return null; - } - var owner = fiber._debugOwner; - if (owner !== null && typeof owner !== 'undefined') { - return getComponentName(owner); - } - } - return null; -} - -function getCurrentFiberStackAddendum() { - { - var fiber = ReactDebugCurrentFiber.current; - if (fiber === null) { - return null; - } - // Safe because if current fiber exists, we are reconciling, - // and it is guaranteed to be the work-in-progress version. - return getStackAddendumByWorkInProgressFiber(fiber); - } - return null; -} - -function resetCurrentFiber() { - ReactDebugCurrentFrame.getCurrentStack = null; - ReactDebugCurrentFiber.current = null; - ReactDebugCurrentFiber.phase = null; -} - -function setCurrentFiber(fiber) { - ReactDebugCurrentFrame.getCurrentStack = getCurrentFiberStackAddendum; - ReactDebugCurrentFiber.current = fiber; - ReactDebugCurrentFiber.phase = null; -} - -function setCurrentPhase(phase) { - ReactDebugCurrentFiber.phase = phase; -} - -var ReactDebugCurrentFiber = { - current: null, - phase: null, - resetCurrentFiber: resetCurrentFiber, - setCurrentFiber: setCurrentFiber, - setCurrentPhase: setCurrentPhase, - getCurrentFiberOwnerName: getCurrentFiberOwnerName, - getCurrentFiberStackAddendum: getCurrentFiberStackAddendum -}; - -// Prefix measurements so that it's possible to filter them. -// Longer prefixes are hard to read in DevTools. -var reactEmoji = '\u269B'; -var warningEmoji = '\u26D4'; -var supportsUserTiming = typeof performance !== 'undefined' && typeof performance.mark === 'function' && typeof performance.clearMarks === 'function' && typeof performance.measure === 'function' && typeof performance.clearMeasures === 'function'; - -// Keep track of current fiber so that we know the path to unwind on pause. -// TODO: this looks the same as nextUnitOfWork in scheduler. Can we unify them? -var currentFiber = null; -// If we're in the middle of user code, which fiber and method is it? -// Reusing `currentFiber` would be confusing for this because user code fiber -// can change during commit phase too, but we don't need to unwind it (since -// lifecycles in the commit phase don't resemble a tree). -var currentPhase = null; -var currentPhaseFiber = null; -// Did lifecycle hook schedule an update? This is often a performance problem, -// so we will keep track of it, and include it in the report. -// Track commits caused by cascading updates. -var isCommitting = false; -var hasScheduledUpdateInCurrentCommit = false; -var hasScheduledUpdateInCurrentPhase = false; -var commitCountInCurrentWorkLoop = 0; -var effectCountInCurrentCommit = 0; -var isWaitingForCallback = false; -// During commits, we only show a measurement once per method name -// to avoid stretch the commit phase with measurement overhead. -var labelsInCurrentCommit = new Set(); - -var formatMarkName = function (markName) { - return reactEmoji + ' ' + markName; -}; - -var formatLabel = function (label, warning$$1) { - var prefix = warning$$1 ? warningEmoji + ' ' : reactEmoji + ' '; - var suffix = warning$$1 ? ' Warning: ' + warning$$1 : ''; - return '' + prefix + label + suffix; -}; - -var beginMark = function (markName) { - performance.mark(formatMarkName(markName)); -}; - -var clearMark = function (markName) { - performance.clearMarks(formatMarkName(markName)); -}; - -var endMark = function (label, markName, warning$$1) { - var formattedMarkName = formatMarkName(markName); - var formattedLabel = formatLabel(label, warning$$1); - try { - performance.measure(formattedLabel, formattedMarkName); - } catch (err) {} - // If previous mark was missing for some reason, this will throw. - // This could only happen if React crashed in an unexpected place earlier. - // Don't pile on with more errors. - - // Clear marks immediately to avoid growing buffer. - performance.clearMarks(formattedMarkName); - performance.clearMeasures(formattedLabel); -}; - -var getFiberMarkName = function (label, debugID) { - return label + ' (#' + debugID + ')'; -}; - -var getFiberLabel = function (componentName, isMounted, phase) { - if (phase === null) { - // These are composite component total time measurements. - return componentName + ' [' + (isMounted ? 'update' : 'mount') + ']'; - } else { - // Composite component methods. - return componentName + '.' + phase; - } -}; - -var beginFiberMark = function (fiber, phase) { - var componentName = getComponentName(fiber) || 'Unknown'; - var debugID = fiber._debugID; - var isMounted = fiber.alternate !== null; - var label = getFiberLabel(componentName, isMounted, phase); - - if (isCommitting && labelsInCurrentCommit.has(label)) { - // During the commit phase, we don't show duplicate labels because - // there is a fixed overhead for every measurement, and we don't - // want to stretch the commit phase beyond necessary. - return false; - } - labelsInCurrentCommit.add(label); - - var markName = getFiberMarkName(label, debugID); - beginMark(markName); - return true; -}; - -var clearFiberMark = function (fiber, phase) { - var componentName = getComponentName(fiber) || 'Unknown'; - var debugID = fiber._debugID; - var isMounted = fiber.alternate !== null; - var label = getFiberLabel(componentName, isMounted, phase); - var markName = getFiberMarkName(label, debugID); - clearMark(markName); -}; - -var endFiberMark = function (fiber, phase, warning$$1) { - var componentName = getComponentName(fiber) || 'Unknown'; - var debugID = fiber._debugID; - var isMounted = fiber.alternate !== null; - var label = getFiberLabel(componentName, isMounted, phase); - var markName = getFiberMarkName(label, debugID); - endMark(label, markName, warning$$1); -}; - -var shouldIgnoreFiber = function (fiber) { - // Host components should be skipped in the timeline. - // We could check typeof fiber.type, but does this work with RN? - switch (fiber.tag) { - case HostRoot: - case HostComponent: - case HostText: - case HostPortal: - case ReturnComponent: - case Fragment: - return true; - default: - return false; - } -}; - -var clearPendingPhaseMeasurement = function () { - if (currentPhase !== null && currentPhaseFiber !== null) { - clearFiberMark(currentPhaseFiber, currentPhase); - } - currentPhaseFiber = null; - currentPhase = null; - hasScheduledUpdateInCurrentPhase = false; -}; - -var pauseTimers = function () { - // Stops all currently active measurements so that they can be resumed - // if we continue in a later deferred loop from the same unit of work. - var fiber = currentFiber; - while (fiber) { - if (fiber._debugIsCurrentlyTiming) { - endFiberMark(fiber, null, null); - } - fiber = fiber['return']; - } -}; - -var resumeTimersRecursively = function (fiber) { - if (fiber['return'] !== null) { - resumeTimersRecursively(fiber['return']); - } - if (fiber._debugIsCurrentlyTiming) { - beginFiberMark(fiber, null); - } -}; - -var resumeTimers = function () { - // Resumes all measurements that were active during the last deferred loop. - if (currentFiber !== null) { - resumeTimersRecursively(currentFiber); - } -}; - -function recordEffect() { - if (enableUserTimingAPI) { - effectCountInCurrentCommit++; - } -} - -function recordScheduleUpdate() { - if (enableUserTimingAPI) { - if (isCommitting) { - hasScheduledUpdateInCurrentCommit = true; - } - if (currentPhase !== null && currentPhase !== 'componentWillMount' && currentPhase !== 'componentWillReceiveProps') { - hasScheduledUpdateInCurrentPhase = true; - } - } -} - -function startRequestCallbackTimer() { - if (enableUserTimingAPI) { - if (supportsUserTiming && !isWaitingForCallback) { - isWaitingForCallback = true; - beginMark('(Waiting for async callback...)'); - } - } -} - -function stopRequestCallbackTimer(didExpire) { - if (enableUserTimingAPI) { - if (supportsUserTiming) { - isWaitingForCallback = false; - var warning$$1 = didExpire ? 'React was blocked by main thread' : null; - endMark('(Waiting for async callback...)', '(Waiting for async callback...)', warning$$1); - } - } -} - -function startWorkTimer(fiber) { - if (enableUserTimingAPI) { - if (!supportsUserTiming || shouldIgnoreFiber(fiber)) { - return; - } - // If we pause, this is the fiber to unwind from. - currentFiber = fiber; - if (!beginFiberMark(fiber, null)) { - return; - } - fiber._debugIsCurrentlyTiming = true; - } -} - -function cancelWorkTimer(fiber) { - if (enableUserTimingAPI) { - if (!supportsUserTiming || shouldIgnoreFiber(fiber)) { - return; - } - // Remember we shouldn't complete measurement for this fiber. - // Otherwise flamechart will be deep even for small updates. - fiber._debugIsCurrentlyTiming = false; - clearFiberMark(fiber, null); - } -} - -function stopWorkTimer(fiber) { - if (enableUserTimingAPI) { - if (!supportsUserTiming || shouldIgnoreFiber(fiber)) { - return; - } - // If we pause, its parent is the fiber to unwind from. - currentFiber = fiber['return']; - if (!fiber._debugIsCurrentlyTiming) { - return; - } - fiber._debugIsCurrentlyTiming = false; - endFiberMark(fiber, null, null); - } -} - -function stopFailedWorkTimer(fiber) { - if (enableUserTimingAPI) { - if (!supportsUserTiming || shouldIgnoreFiber(fiber)) { - return; - } - // If we pause, its parent is the fiber to unwind from. - currentFiber = fiber['return']; - if (!fiber._debugIsCurrentlyTiming) { - return; - } - fiber._debugIsCurrentlyTiming = false; - var warning$$1 = 'An error was thrown inside this error boundary'; - endFiberMark(fiber, null, warning$$1); - } -} - -function startPhaseTimer(fiber, phase) { - if (enableUserTimingAPI) { - if (!supportsUserTiming) { - return; - } - clearPendingPhaseMeasurement(); - if (!beginFiberMark(fiber, phase)) { - return; - } - currentPhaseFiber = fiber; - currentPhase = phase; - } -} - -function stopPhaseTimer() { - if (enableUserTimingAPI) { - if (!supportsUserTiming) { - return; - } - if (currentPhase !== null && currentPhaseFiber !== null) { - var warning$$1 = hasScheduledUpdateInCurrentPhase ? 'Scheduled a cascading update' : null; - endFiberMark(currentPhaseFiber, currentPhase, warning$$1); - } - currentPhase = null; - currentPhaseFiber = null; - } -} - -function startWorkLoopTimer(nextUnitOfWork) { - if (enableUserTimingAPI) { - currentFiber = nextUnitOfWork; - if (!supportsUserTiming) { - return; - } - commitCountInCurrentWorkLoop = 0; - // This is top level call. - // Any other measurements are performed within. - beginMark('(React Tree Reconciliation)'); - // Resume any measurements that were in progress during the last loop. - resumeTimers(); - } -} - -function stopWorkLoopTimer(interruptedBy) { - if (enableUserTimingAPI) { - if (!supportsUserTiming) { - return; - } - var warning$$1 = null; - if (interruptedBy !== null) { - if (interruptedBy.tag === HostRoot) { - warning$$1 = 'A top-level update interrupted the previous render'; - } else { - var componentName = getComponentName(interruptedBy) || 'Unknown'; - warning$$1 = 'An update to ' + componentName + ' interrupted the previous render'; - } - } else if (commitCountInCurrentWorkLoop > 1) { - warning$$1 = 'There were cascading updates'; - } - commitCountInCurrentWorkLoop = 0; - // Pause any measurements until the next loop. - pauseTimers(); - endMark('(React Tree Reconciliation)', '(React Tree Reconciliation)', warning$$1); - } -} - -function startCommitTimer() { - if (enableUserTimingAPI) { - if (!supportsUserTiming) { - return; - } - isCommitting = true; - hasScheduledUpdateInCurrentCommit = false; - labelsInCurrentCommit.clear(); - beginMark('(Committing Changes)'); - } -} - -function stopCommitTimer() { - if (enableUserTimingAPI) { - if (!supportsUserTiming) { - return; - } - - var warning$$1 = null; - if (hasScheduledUpdateInCurrentCommit) { - warning$$1 = 'Lifecycle hook scheduled a cascading update'; - } else if (commitCountInCurrentWorkLoop > 0) { - warning$$1 = 'Caused by a cascading update in earlier commit'; - } - hasScheduledUpdateInCurrentCommit = false; - commitCountInCurrentWorkLoop++; - isCommitting = false; - labelsInCurrentCommit.clear(); - - endMark('(Committing Changes)', '(Committing Changes)', warning$$1); - } -} - -function startCommitHostEffectsTimer() { - if (enableUserTimingAPI) { - if (!supportsUserTiming) { - return; - } - effectCountInCurrentCommit = 0; - beginMark('(Committing Host Effects)'); - } -} - -function stopCommitHostEffectsTimer() { - if (enableUserTimingAPI) { - if (!supportsUserTiming) { - return; - } - var count = effectCountInCurrentCommit; - effectCountInCurrentCommit = 0; - endMark('(Committing Host Effects: ' + count + ' Total)', '(Committing Host Effects)', null); - } -} - -function startCommitLifeCyclesTimer() { - if (enableUserTimingAPI) { - if (!supportsUserTiming) { - return; - } - effectCountInCurrentCommit = 0; - beginMark('(Calling Lifecycle Methods)'); - } -} - -function stopCommitLifeCyclesTimer() { - if (enableUserTimingAPI) { - if (!supportsUserTiming) { - return; - } - var count = effectCountInCurrentCommit; - effectCountInCurrentCommit = 0; - endMark('(Calling Lifecycle Methods: ' + count + ' Total)', '(Calling Lifecycle Methods)', null); - } -} - -{ - var warnedAboutMissingGetChildContext = {}; -} - -// A cursor to the current merged context object on the stack. -var contextStackCursor = createCursor(emptyObject); -// A cursor to a boolean indicating whether the context has changed. -var didPerformWorkStackCursor = createCursor(false); -// Keep track of the previous context object that was on the stack. -// We use this to get access to the parent context after we have already -// pushed the next context provider, and now need to merge their contexts. -var previousContext = emptyObject; - -function getUnmaskedContext(workInProgress) { - var hasOwnContext = isContextProvider(workInProgress); - if (hasOwnContext) { - // If the fiber is a context provider itself, when we read its context - // we have already pushed its own child context on the stack. A context - // provider should not "see" its own child context. Therefore we read the - // previous (parent) context instead for a context provider. - return previousContext; - } - return contextStackCursor.current; -} - -function cacheContext(workInProgress, unmaskedContext, maskedContext) { - var instance = workInProgress.stateNode; - instance.__reactInternalMemoizedUnmaskedChildContext = unmaskedContext; - instance.__reactInternalMemoizedMaskedChildContext = maskedContext; -} - -function getMaskedContext(workInProgress, unmaskedContext) { - var type = workInProgress.type; - var contextTypes = type.contextTypes; - if (!contextTypes) { - return emptyObject; - } - - // Avoid recreating masked context unless unmasked context has changed. - // Failing to do this will result in unnecessary calls to componentWillReceiveProps. - // This may trigger infinite loops if componentWillReceiveProps calls setState. - var instance = workInProgress.stateNode; - if (instance && instance.__reactInternalMemoizedUnmaskedChildContext === unmaskedContext) { - return instance.__reactInternalMemoizedMaskedChildContext; - } - - var context = {}; - for (var key in contextTypes) { - context[key] = unmaskedContext[key]; - } - - { - var name = getComponentName(workInProgress) || 'Unknown'; - checkPropTypes(contextTypes, context, 'context', name, ReactDebugCurrentFiber.getCurrentFiberStackAddendum); - } - - // Cache unmasked context so we can avoid recreating masked context unless necessary. - // Context is created before the class component is instantiated so check for instance. - if (instance) { - cacheContext(workInProgress, unmaskedContext, context); - } - - return context; -} - -function hasContextChanged() { - return didPerformWorkStackCursor.current; -} - -function isContextConsumer(fiber) { - return fiber.tag === ClassComponent && fiber.type.contextTypes != null; -} - -function isContextProvider(fiber) { - return fiber.tag === ClassComponent && fiber.type.childContextTypes != null; -} - -function popContextProvider(fiber) { - if (!isContextProvider(fiber)) { - return; - } - - pop(didPerformWorkStackCursor, fiber); - pop(contextStackCursor, fiber); -} - -function popTopLevelContextObject(fiber) { - pop(didPerformWorkStackCursor, fiber); - pop(contextStackCursor, fiber); -} - -function pushTopLevelContextObject(fiber, context, didChange) { - !(contextStackCursor.cursor == null) ? invariant(false, 'Unexpected context found on stack. This error is likely caused by a bug in React. Please file an issue.') : void 0; - - push(contextStackCursor, context, fiber); - push(didPerformWorkStackCursor, didChange, fiber); -} - -function processChildContext(fiber, parentContext) { - var instance = fiber.stateNode; - var childContextTypes = fiber.type.childContextTypes; - - // TODO (bvaughn) Replace this behavior with an invariant() in the future. - // It has only been added in Fiber to match the (unintentional) behavior in Stack. - if (typeof instance.getChildContext !== 'function') { - { - var componentName = getComponentName(fiber) || 'Unknown'; - - if (!warnedAboutMissingGetChildContext[componentName]) { - warnedAboutMissingGetChildContext[componentName] = true; - warning(false, '%s.childContextTypes is specified but there is no getChildContext() method ' + 'on the instance. You can either define getChildContext() on %s or remove ' + 'childContextTypes from it.', componentName, componentName); - } - } - return parentContext; - } - - var childContext = void 0; - { - ReactDebugCurrentFiber.setCurrentPhase('getChildContext'); - } - startPhaseTimer(fiber, 'getChildContext'); - childContext = instance.getChildContext(); - stopPhaseTimer(); - { - ReactDebugCurrentFiber.setCurrentPhase(null); - } - for (var contextKey in childContext) { - !(contextKey in childContextTypes) ? invariant(false, '%s.getChildContext(): key "%s" is not defined in childContextTypes.', getComponentName(fiber) || 'Unknown', contextKey) : void 0; - } - { - var name = getComponentName(fiber) || 'Unknown'; - checkPropTypes(childContextTypes, childContext, 'child context', name, - // In practice, there is one case in which we won't get a stack. It's when - // somebody calls unstable_renderSubtreeIntoContainer() and we process - // context from the parent component instance. The stack will be missing - // because it's outside of the reconciliation, and so the pointer has not - // been set. This is rare and doesn't matter. We'll also remove that API. - ReactDebugCurrentFiber.getCurrentFiberStackAddendum); - } - - return _assign({}, parentContext, childContext); -} - -function pushContextProvider(workInProgress) { - if (!isContextProvider(workInProgress)) { - return false; - } - - var instance = workInProgress.stateNode; - // We push the context as early as possible to ensure stack integrity. - // If the instance does not exist yet, we will push null at first, - // and replace it on the stack later when invalidating the context. - var memoizedMergedChildContext = instance && instance.__reactInternalMemoizedMergedChildContext || emptyObject; - - // Remember the parent context so we can merge with it later. - // Inherit the parent's did-perform-work value to avoid inadvertently blocking updates. - previousContext = contextStackCursor.current; - push(contextStackCursor, memoizedMergedChildContext, workInProgress); - push(didPerformWorkStackCursor, didPerformWorkStackCursor.current, workInProgress); - - return true; -} - -function invalidateContextProvider(workInProgress, didChange) { - var instance = workInProgress.stateNode; - !instance ? invariant(false, 'Expected to have an instance by this point. This error is likely caused by a bug in React. Please file an issue.') : void 0; - - if (didChange) { - // Merge parent and own context. - // Skip this if we're not updating due to sCU. - // This avoids unnecessarily recomputing memoized values. - var mergedContext = processChildContext(workInProgress, previousContext); - instance.__reactInternalMemoizedMergedChildContext = mergedContext; - - // Replace the old (or empty) context with the new one. - // It is important to unwind the context in the reverse order. - pop(didPerformWorkStackCursor, workInProgress); - pop(contextStackCursor, workInProgress); - // Now push the new context and mark that it has changed. - push(contextStackCursor, mergedContext, workInProgress); - push(didPerformWorkStackCursor, didChange, workInProgress); - } else { - pop(didPerformWorkStackCursor, workInProgress); - push(didPerformWorkStackCursor, didChange, workInProgress); - } -} - -function resetContext() { - previousContext = emptyObject; - contextStackCursor.current = emptyObject; - didPerformWorkStackCursor.current = false; -} - -function findCurrentUnmaskedContext(fiber) { - // Currently this is only used with renderSubtreeIntoContainer; not sure if it - // makes sense elsewhere - !(isFiberMounted(fiber) && fiber.tag === ClassComponent) ? invariant(false, 'Expected subtree parent to be a mounted class component. This error is likely caused by a bug in React. Please file an issue.') : void 0; - - var node = fiber; - while (node.tag !== HostRoot) { - if (isContextProvider(node)) { - return node.stateNode.__reactInternalMemoizedMergedChildContext; - } - var parent = node['return']; - !parent ? invariant(false, 'Found unexpected detached subtree parent. This error is likely caused by a bug in React. Please file an issue.') : void 0; - node = parent; - } - return node.stateNode.context; -} - -var NoWork = 0; // TODO: Use an opaque type once ESLint et al support the syntax - -var Sync = 1; -var Never = 2147483647; // Max int32: Math.pow(2, 31) - 1 - -var UNIT_SIZE = 10; -var MAGIC_NUMBER_OFFSET = 2; - -// 1 unit of expiration time represents 10ms. -function msToExpirationTime(ms) { - // Always add an offset so that we don't clash with the magic number for NoWork. - return (ms / UNIT_SIZE | 0) + MAGIC_NUMBER_OFFSET; -} - -function expirationTimeToMs(expirationTime) { - return (expirationTime - MAGIC_NUMBER_OFFSET) * UNIT_SIZE; -} - -function ceiling(num, precision) { - return ((num / precision | 0) + 1) * precision; -} - -function computeExpirationBucket(currentTime, expirationInMs, bucketSizeMs) { - return ceiling(currentTime + expirationInMs / UNIT_SIZE, bucketSizeMs / UNIT_SIZE); -} - -var NoContext = 0; -var AsyncUpdates = 1; - -{ - var hasBadMapPolyfill = false; - try { - var nonExtensibleObject = Object.preventExtensions({}); - /* eslint-disable no-new */ - - /* eslint-enable no-new */ - } catch (e) { - // TODO: Consider warning about bad polyfills - hasBadMapPolyfill = true; - } -} - -// A Fiber is work on a Component that needs to be done or was done. There can -// be more than one per component. - - -{ - var debugCounter = 1; -} - -function FiberNode(tag, key, internalContextTag) { - // Instance - this.tag = tag; - this.key = key; - this.type = null; - this.stateNode = null; - - // Fiber - this['return'] = null; - this.child = null; - this.sibling = null; - this.index = 0; - - this.ref = null; - - this.pendingProps = null; - this.memoizedProps = null; - this.updateQueue = null; - this.memoizedState = null; - - this.internalContextTag = internalContextTag; - - // Effects - this.effectTag = NoEffect; - this.nextEffect = null; - - this.firstEffect = null; - this.lastEffect = null; - - this.expirationTime = NoWork; - - this.alternate = null; - - { - this._debugID = debugCounter++; - this._debugSource = null; - this._debugOwner = null; - this._debugIsCurrentlyTiming = false; - if (!hasBadMapPolyfill && typeof Object.preventExtensions === 'function') { - Object.preventExtensions(this); - } - } -} - -// This is a constructor function, rather than a POJO constructor, still -// please ensure we do the following: -// 1) Nobody should add any instance methods on this. Instance methods can be -// more difficult to predict when they get optimized and they are almost -// never inlined properly in static compilers. -// 2) Nobody should rely on `instanceof Fiber` for type testing. We should -// always know when it is a fiber. -// 3) We might want to experiment with using numeric keys since they are easier -// to optimize in a non-JIT environment. -// 4) We can easily go from a constructor to a createFiber object literal if that -// is faster. -// 5) It should be easy to port this to a C struct and keep a C implementation -// compatible. -var createFiber = function (tag, key, internalContextTag) { - // $FlowFixMe: the shapes are exact here but Flow doesn't like constructors - return new FiberNode(tag, key, internalContextTag); -}; - -function shouldConstruct(Component) { - return !!(Component.prototype && Component.prototype.isReactComponent); -} - -// This is used to create an alternate fiber to do work on. -function createWorkInProgress(current, pendingProps, expirationTime) { - var workInProgress = current.alternate; - if (workInProgress === null) { - // We use a double buffering pooling technique because we know that we'll - // only ever need at most two versions of a tree. We pool the "other" unused - // node that we're free to reuse. This is lazily created to avoid allocating - // extra objects for things that are never updated. It also allow us to - // reclaim the extra memory if needed. - workInProgress = createFiber(current.tag, current.key, current.internalContextTag); - workInProgress.type = current.type; - workInProgress.stateNode = current.stateNode; - - { - // DEV-only fields - workInProgress._debugID = current._debugID; - workInProgress._debugSource = current._debugSource; - workInProgress._debugOwner = current._debugOwner; - } - - workInProgress.alternate = current; - current.alternate = workInProgress; - } else { - // We already have an alternate. - // Reset the effect tag. - workInProgress.effectTag = NoEffect; - - // The effect list is no longer valid. - workInProgress.nextEffect = null; - workInProgress.firstEffect = null; - workInProgress.lastEffect = null; - } - - workInProgress.expirationTime = expirationTime; - workInProgress.pendingProps = pendingProps; - - workInProgress.child = current.child; - workInProgress.memoizedProps = current.memoizedProps; - workInProgress.memoizedState = current.memoizedState; - workInProgress.updateQueue = current.updateQueue; - - // These will be overridden during the parent's reconciliation - workInProgress.sibling = current.sibling; - workInProgress.index = current.index; - workInProgress.ref = current.ref; - - return workInProgress; -} - -function createHostRootFiber() { - var fiber = createFiber(HostRoot, null, NoContext); - return fiber; -} - -function createFiberFromElement(element, internalContextTag, expirationTime) { - var owner = null; - { - owner = element._owner; - } - - var fiber = void 0; - var type = element.type, - key = element.key; - - if (typeof type === 'function') { - fiber = shouldConstruct(type) ? createFiber(ClassComponent, key, internalContextTag) : createFiber(IndeterminateComponent, key, internalContextTag); - fiber.type = type; - fiber.pendingProps = element.props; - } else if (typeof type === 'string') { - fiber = createFiber(HostComponent, key, internalContextTag); - fiber.type = type; - fiber.pendingProps = element.props; - } else if (typeof type === 'object' && type !== null && typeof type.tag === 'number') { - // Currently assumed to be a continuation and therefore is a fiber already. - // TODO: The yield system is currently broken for updates in some cases. - // The reified yield stores a fiber, but we don't know which fiber that is; - // the current or a workInProgress? When the continuation gets rendered here - // we don't know if we can reuse that fiber or if we need to clone it. - // There is probably a clever way to restructure this. - fiber = type; - fiber.pendingProps = element.props; - } else { - var info = ''; - { - if (type === undefined || typeof type === 'object' && type !== null && Object.keys(type).length === 0) { - info += ' You likely forgot to export your component from the file ' + "it's defined in, or you might have mixed up default and named imports."; - } - var ownerName = owner ? getComponentName(owner) : null; - if (ownerName) { - info += '\n\nCheck the render method of `' + ownerName + '`.'; - } - } - invariant(false, 'Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: %s.%s', type == null ? type : typeof type, info); - } - - { - fiber._debugSource = element._source; - fiber._debugOwner = element._owner; - } - - fiber.expirationTime = expirationTime; - - return fiber; -} - -function createFiberFromFragment(elements, internalContextTag, expirationTime, key) { - var fiber = createFiber(Fragment, key, internalContextTag); - fiber.pendingProps = elements; - fiber.expirationTime = expirationTime; - return fiber; -} - -function createFiberFromText(content, internalContextTag, expirationTime) { - var fiber = createFiber(HostText, null, internalContextTag); - fiber.pendingProps = content; - fiber.expirationTime = expirationTime; - return fiber; -} - -function createFiberFromHostInstanceForDeletion() { - var fiber = createFiber(HostComponent, null, NoContext); - fiber.type = 'DELETED'; - return fiber; -} - -function createFiberFromCall(call, internalContextTag, expirationTime) { - var fiber = createFiber(CallComponent, call.key, internalContextTag); - fiber.type = call.handler; - fiber.pendingProps = call; - fiber.expirationTime = expirationTime; - return fiber; -} - -function createFiberFromReturn(returnNode, internalContextTag, expirationTime) { - var fiber = createFiber(ReturnComponent, null, internalContextTag); - fiber.expirationTime = expirationTime; - return fiber; -} - -function createFiberFromPortal(portal, internalContextTag, expirationTime) { - var fiber = createFiber(HostPortal, portal.key, internalContextTag); - fiber.pendingProps = portal.children || []; - fiber.expirationTime = expirationTime; - fiber.stateNode = { - containerInfo: portal.containerInfo, - pendingChildren: null, // Used by persistent updates - implementation: portal.implementation - }; - return fiber; -} - -function createFiberRoot(containerInfo, hydrate) { - // Cyclic construction. This cheats the type system right now because - // stateNode is any. - var uninitializedFiber = createHostRootFiber(); - var root = { - current: uninitializedFiber, - containerInfo: containerInfo, - pendingChildren: null, - remainingExpirationTime: NoWork, - isReadyForCommit: false, - finishedWork: null, - context: null, - pendingContext: null, - hydrate: hydrate, - nextScheduledRoot: null - }; - uninitializedFiber.stateNode = root; - return root; -} - -var onCommitFiberRoot = null; -var onCommitFiberUnmount = null; -var hasLoggedError = false; - -function catchErrors(fn) { - return function (arg) { - try { - return fn(arg); - } catch (err) { - if (true && !hasLoggedError) { - hasLoggedError = true; - warning(false, 'React DevTools encountered an error: %s', err); - } - } - }; -} - -function injectInternals(internals) { - if (typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ === 'undefined') { - // No DevTools - return false; - } - var hook = __REACT_DEVTOOLS_GLOBAL_HOOK__; - if (hook.isDisabled) { - // This isn't a real property on the hook, but it can be set to opt out - // of DevTools integration and associated warnings and logs. - // https://github.com/facebook/react/issues/3877 - return true; - } - if (!hook.supportsFiber) { - { - warning(false, 'The installed version of React DevTools is too old and will not work ' + 'with the current version of React. Please update React DevTools. ' + 'https://fb.me/react-devtools'); - } - // DevTools exists, even though it doesn't support Fiber. - return true; - } - try { - var rendererID = hook.inject(internals); - // We have successfully injected, so now it is safe to set up hooks. - onCommitFiberRoot = catchErrors(function (root) { - return hook.onCommitFiberRoot(rendererID, root); - }); - onCommitFiberUnmount = catchErrors(function (fiber) { - return hook.onCommitFiberUnmount(rendererID, fiber); - }); - } catch (err) { - // Catch all errors because it is unsafe to throw during initialization. - { - warning(false, 'React DevTools encountered an error: %s.', err); - } - } - // DevTools exists - return true; -} - -function onCommitRoot(root) { - if (typeof onCommitFiberRoot === 'function') { - onCommitFiberRoot(root); - } -} - -function onCommitUnmount(fiber) { - if (typeof onCommitFiberUnmount === 'function') { - onCommitFiberUnmount(fiber); - } -} - -{ - var didWarnUpdateInsideUpdate = false; -} - -// Callbacks are not validated until invocation - - -// Singly linked-list of updates. When an update is scheduled, it is added to -// the queue of the current fiber and the work-in-progress fiber. The two queues -// are separate but they share a persistent structure. -// -// During reconciliation, updates are removed from the work-in-progress fiber, -// but they remain on the current fiber. That ensures that if a work-in-progress -// is aborted, the aborted updates are recovered by cloning from current. -// -// The work-in-progress queue is always a subset of the current queue. -// -// When the tree is committed, the work-in-progress becomes the current. - - -function createUpdateQueue(baseState) { - var queue = { - baseState: baseState, - expirationTime: NoWork, - first: null, - last: null, - callbackList: null, - hasForceUpdate: false, - isInitialized: false - }; - { - queue.isProcessing = false; - } - return queue; -} - -function insertUpdateIntoQueue(queue, update) { - // Append the update to the end of the list. - if (queue.last === null) { - // Queue is empty - queue.first = queue.last = update; - } else { - queue.last.next = update; - queue.last = update; - } - if (queue.expirationTime === NoWork || queue.expirationTime > update.expirationTime) { - queue.expirationTime = update.expirationTime; - } -} - -function insertUpdateIntoFiber(fiber, update) { - // We'll have at least one and at most two distinct update queues. - var alternateFiber = fiber.alternate; - var queue1 = fiber.updateQueue; - if (queue1 === null) { - // TODO: We don't know what the base state will be until we begin work. - // It depends on which fiber is the next current. Initialize with an empty - // base state, then set to the memoizedState when rendering. Not super - // happy with this approach. - queue1 = fiber.updateQueue = createUpdateQueue(null); - } - - var queue2 = void 0; - if (alternateFiber !== null) { - queue2 = alternateFiber.updateQueue; - if (queue2 === null) { - queue2 = alternateFiber.updateQueue = createUpdateQueue(null); - } - } else { - queue2 = null; - } - queue2 = queue2 !== queue1 ? queue2 : null; - - // Warn if an update is scheduled from inside an updater function. - { - if ((queue1.isProcessing || queue2 !== null && queue2.isProcessing) && !didWarnUpdateInsideUpdate) { - warning(false, 'An update (setState, replaceState, or forceUpdate) was scheduled ' + 'from inside an update function. Update functions should be pure, ' + 'with zero side-effects. Consider using componentDidUpdate or a ' + 'callback.'); - didWarnUpdateInsideUpdate = true; - } - } - - // If there's only one queue, add the update to that queue and exit. - if (queue2 === null) { - insertUpdateIntoQueue(queue1, update); - return; - } - - // If either queue is empty, we need to add to both queues. - if (queue1.last === null || queue2.last === null) { - insertUpdateIntoQueue(queue1, update); - insertUpdateIntoQueue(queue2, update); - return; - } - - // If both lists are not empty, the last update is the same for both lists - // because of structural sharing. So, we should only append to one of - // the lists. - insertUpdateIntoQueue(queue1, update); - // But we still need to update the `last` pointer of queue2. - queue2.last = update; -} - -function getUpdateExpirationTime(fiber) { - if (fiber.tag !== ClassComponent && fiber.tag !== HostRoot) { - return NoWork; - } - var updateQueue = fiber.updateQueue; - if (updateQueue === null) { - return NoWork; - } - return updateQueue.expirationTime; -} - -function getStateFromUpdate(update, instance, prevState, props) { - var partialState = update.partialState; - if (typeof partialState === 'function') { - var updateFn = partialState; - - // Invoke setState callback an extra time to help detect side-effects. - if (debugRenderPhaseSideEffects) { - updateFn.call(instance, prevState, props); - } - - return updateFn.call(instance, prevState, props); - } else { - return partialState; - } -} - -function processUpdateQueue(current, workInProgress, queue, instance, props, renderExpirationTime) { - if (current !== null && current.updateQueue === queue) { - // We need to create a work-in-progress queue, by cloning the current queue. - var currentQueue = queue; - queue = workInProgress.updateQueue = { - baseState: currentQueue.baseState, - expirationTime: currentQueue.expirationTime, - first: currentQueue.first, - last: currentQueue.last, - isInitialized: currentQueue.isInitialized, - // These fields are no longer valid because they were already committed. - // Reset them. - callbackList: null, - hasForceUpdate: false - }; - } - - { - // Set this flag so we can warn if setState is called inside the update - // function of another setState. - queue.isProcessing = true; - } - - // Reset the remaining expiration time. If we skip over any updates, we'll - // increase this accordingly. - queue.expirationTime = NoWork; - - // TODO: We don't know what the base state will be until we begin work. - // It depends on which fiber is the next current. Initialize with an empty - // base state, then set to the memoizedState when rendering. Not super - // happy with this approach. - var state = void 0; - if (queue.isInitialized) { - state = queue.baseState; - } else { - state = queue.baseState = workInProgress.memoizedState; - queue.isInitialized = true; - } - var dontMutatePrevState = true; - var update = queue.first; - var didSkip = false; - while (update !== null) { - var updateExpirationTime = update.expirationTime; - if (updateExpirationTime > renderExpirationTime) { - // This update does not have sufficient priority. Skip it. - var remainingExpirationTime = queue.expirationTime; - if (remainingExpirationTime === NoWork || remainingExpirationTime > updateExpirationTime) { - // Update the remaining expiration time. - queue.expirationTime = updateExpirationTime; - } - if (!didSkip) { - didSkip = true; - queue.baseState = state; - } - // Continue to the next update. - update = update.next; - continue; - } - - // This update does have sufficient priority. - - // If no previous updates were skipped, drop this update from the queue by - // advancing the head of the list. - if (!didSkip) { - queue.first = update.next; - if (queue.first === null) { - queue.last = null; - } - } - - // Process the update - var _partialState = void 0; - if (update.isReplace) { - state = getStateFromUpdate(update, instance, state, props); - dontMutatePrevState = true; - } else { - _partialState = getStateFromUpdate(update, instance, state, props); - if (_partialState) { - if (dontMutatePrevState) { - // $FlowFixMe: Idk how to type this properly. - state = _assign({}, state, _partialState); - } else { - state = _assign(state, _partialState); - } - dontMutatePrevState = false; - } - } - if (update.isForced) { - queue.hasForceUpdate = true; - } - if (update.callback !== null) { - // Append to list of callbacks. - var _callbackList = queue.callbackList; - if (_callbackList === null) { - _callbackList = queue.callbackList = []; - } - _callbackList.push(update); - } - update = update.next; - } - - if (queue.callbackList !== null) { - workInProgress.effectTag |= Callback; - } else if (queue.first === null && !queue.hasForceUpdate) { - // The queue is empty. We can reset it. - workInProgress.updateQueue = null; - } - - if (!didSkip) { - didSkip = true; - queue.baseState = state; - } - - { - // No longer processing. - queue.isProcessing = false; - } - - return state; -} - -function commitCallbacks(queue, context) { - var callbackList = queue.callbackList; - if (callbackList === null) { - return; - } - // Set the list to null to make sure they don't get called more than once. - queue.callbackList = null; - for (var i = 0; i < callbackList.length; i++) { - var update = callbackList[i]; - var _callback = update.callback; - // This update might be processed again. Clear the callback so it's only - // called once. - update.callback = null; - !(typeof _callback === 'function') ? invariant(false, 'Invalid argument passed as callback. Expected a function. Instead received: %s', _callback) : void 0; - _callback.call(context); - } -} - -var fakeInternalInstance = {}; -var isArray = Array.isArray; - -{ - var didWarnAboutStateAssignmentForComponent = {}; - - var warnOnInvalidCallback = function (callback, callerName) { - warning(callback === null || typeof callback === 'function', '%s(...): Expected the last optional `callback` argument to be a ' + 'function. Instead received: %s.', callerName, callback); - }; - - // This is so gross but it's at least non-critical and can be removed if - // it causes problems. This is meant to give a nicer error message for - // ReactDOM15.unstable_renderSubtreeIntoContainer(reactDOM16Component, - // ...)) which otherwise throws a "_processChildContext is not a function" - // exception. - Object.defineProperty(fakeInternalInstance, '_processChildContext', { - enumerable: false, - value: function () { - invariant(false, '_processChildContext is not available in React 16+. This likely means you have multiple copies of React and are attempting to nest a React 15 tree inside a React 16 tree using unstable_renderSubtreeIntoContainer, which isn\'t supported. Try to make sure you have only one copy of React (and ideally, switch to ReactDOM.createPortal).'); - } - }); - Object.freeze(fakeInternalInstance); -} - -var ReactFiberClassComponent = function (scheduleWork, computeExpirationForFiber, memoizeProps, memoizeState) { - // Class component state updater - var updater = { - isMounted: isMounted, - enqueueSetState: function (instance, partialState, callback) { - var fiber = get(instance); - callback = callback === undefined ? null : callback; - { - warnOnInvalidCallback(callback, 'setState'); - } - var expirationTime = computeExpirationForFiber(fiber); - var update = { - expirationTime: expirationTime, - partialState: partialState, - callback: callback, - isReplace: false, - isForced: false, - nextCallback: null, - next: null - }; - insertUpdateIntoFiber(fiber, update); - scheduleWork(fiber, expirationTime); - }, - enqueueReplaceState: function (instance, state, callback) { - var fiber = get(instance); - callback = callback === undefined ? null : callback; - { - warnOnInvalidCallback(callback, 'replaceState'); - } - var expirationTime = computeExpirationForFiber(fiber); - var update = { - expirationTime: expirationTime, - partialState: state, - callback: callback, - isReplace: true, - isForced: false, - nextCallback: null, - next: null - }; - insertUpdateIntoFiber(fiber, update); - scheduleWork(fiber, expirationTime); - }, - enqueueForceUpdate: function (instance, callback) { - var fiber = get(instance); - callback = callback === undefined ? null : callback; - { - warnOnInvalidCallback(callback, 'forceUpdate'); - } - var expirationTime = computeExpirationForFiber(fiber); - var update = { - expirationTime: expirationTime, - partialState: null, - callback: callback, - isReplace: false, - isForced: true, - nextCallback: null, - next: null - }; - insertUpdateIntoFiber(fiber, update); - scheduleWork(fiber, expirationTime); - } - }; - - function checkShouldComponentUpdate(workInProgress, oldProps, newProps, oldState, newState, newContext) { - if (oldProps === null || workInProgress.updateQueue !== null && workInProgress.updateQueue.hasForceUpdate) { - // If the workInProgress already has an Update effect, return true - return true; - } - - var instance = workInProgress.stateNode; - var type = workInProgress.type; - if (typeof instance.shouldComponentUpdate === 'function') { - startPhaseTimer(workInProgress, 'shouldComponentUpdate'); - var shouldUpdate = instance.shouldComponentUpdate(newProps, newState, newContext); - stopPhaseTimer(); - - // Simulate an async bailout/interruption by invoking lifecycle twice. - if (debugRenderPhaseSideEffects) { - instance.shouldComponentUpdate(newProps, newState, newContext); - } - - { - warning(shouldUpdate !== undefined, '%s.shouldComponentUpdate(): Returned undefined instead of a ' + 'boolean value. Make sure to return true or false.', getComponentName(workInProgress) || 'Unknown'); - } - - return shouldUpdate; - } - - if (type.prototype && type.prototype.isPureReactComponent) { - return !shallowEqual(oldProps, newProps) || !shallowEqual(oldState, newState); - } - - return true; - } - - function checkClassInstance(workInProgress) { - var instance = workInProgress.stateNode; - var type = workInProgress.type; - { - var name = getComponentName(workInProgress); - var renderPresent = instance.render; - - if (!renderPresent) { - if (type.prototype && typeof type.prototype.render === 'function') { - warning(false, '%s(...): No `render` method found on the returned component ' + 'instance: did you accidentally return an object from the constructor?', name); - } else { - warning(false, '%s(...): No `render` method found on the returned component ' + 'instance: you may have forgotten to define `render`.', name); - } - } - - var noGetInitialStateOnES6 = !instance.getInitialState || instance.getInitialState.isReactClassApproved || instance.state; - warning(noGetInitialStateOnES6, 'getInitialState was defined on %s, a plain JavaScript class. ' + 'This is only supported for classes created using React.createClass. ' + 'Did you mean to define a state property instead?', name); - var noGetDefaultPropsOnES6 = !instance.getDefaultProps || instance.getDefaultProps.isReactClassApproved; - warning(noGetDefaultPropsOnES6, 'getDefaultProps was defined on %s, a plain JavaScript class. ' + 'This is only supported for classes created using React.createClass. ' + 'Use a static property to define defaultProps instead.', name); - var noInstancePropTypes = !instance.propTypes; - warning(noInstancePropTypes, 'propTypes was defined as an instance property on %s. Use a static ' + 'property to define propTypes instead.', name); - var noInstanceContextTypes = !instance.contextTypes; - warning(noInstanceContextTypes, 'contextTypes was defined as an instance property on %s. Use a static ' + 'property to define contextTypes instead.', name); - var noComponentShouldUpdate = typeof instance.componentShouldUpdate !== 'function'; - warning(noComponentShouldUpdate, '%s has a method called ' + 'componentShouldUpdate(). Did you mean shouldComponentUpdate()? ' + 'The name is phrased as a question because the function is ' + 'expected to return a value.', name); - if (type.prototype && type.prototype.isPureReactComponent && typeof instance.shouldComponentUpdate !== 'undefined') { - warning(false, '%s has a method called shouldComponentUpdate(). ' + 'shouldComponentUpdate should not be used when extending React.PureComponent. ' + 'Please extend React.Component if shouldComponentUpdate is used.', getComponentName(workInProgress) || 'A pure component'); - } - var noComponentDidUnmount = typeof instance.componentDidUnmount !== 'function'; - warning(noComponentDidUnmount, '%s has a method called ' + 'componentDidUnmount(). But there is no such lifecycle method. ' + 'Did you mean componentWillUnmount()?', name); - var noComponentDidReceiveProps = typeof instance.componentDidReceiveProps !== 'function'; - warning(noComponentDidReceiveProps, '%s has a method called ' + 'componentDidReceiveProps(). But there is no such lifecycle method. ' + 'If you meant to update the state in response to changing props, ' + 'use componentWillReceiveProps(). If you meant to fetch data or ' + 'run side-effects or mutations after React has updated the UI, use componentDidUpdate().', name); - var noComponentWillRecieveProps = typeof instance.componentWillRecieveProps !== 'function'; - warning(noComponentWillRecieveProps, '%s has a method called ' + 'componentWillRecieveProps(). Did you mean componentWillReceiveProps()?', name); - var hasMutatedProps = instance.props !== workInProgress.pendingProps; - warning(instance.props === undefined || !hasMutatedProps, '%s(...): When calling super() in `%s`, make sure to pass ' + "up the same props that your component's constructor was passed.", name, name); - var noInstanceDefaultProps = !instance.defaultProps; - warning(noInstanceDefaultProps, 'Setting defaultProps as an instance property on %s is not supported and will be ignored.' + ' Instead, define defaultProps as a static property on %s.', name, name); - } - - var state = instance.state; - if (state && (typeof state !== 'object' || isArray(state))) { - warning(false, '%s.state: must be set to an object or null', getComponentName(workInProgress)); - } - if (typeof instance.getChildContext === 'function') { - warning(typeof workInProgress.type.childContextTypes === 'object', '%s.getChildContext(): childContextTypes must be defined in order to ' + 'use getChildContext().', getComponentName(workInProgress)); - } - } - - function resetInputPointers(workInProgress, instance) { - instance.props = workInProgress.memoizedProps; - instance.state = workInProgress.memoizedState; - } - - function adoptClassInstance(workInProgress, instance) { - instance.updater = updater; - workInProgress.stateNode = instance; - // The instance needs access to the fiber so that it can schedule updates - set(instance, workInProgress); - { - instance._reactInternalInstance = fakeInternalInstance; - } - } - - function constructClassInstance(workInProgress, props) { - var ctor = workInProgress.type; - var unmaskedContext = getUnmaskedContext(workInProgress); - var needsContext = isContextConsumer(workInProgress); - var context = needsContext ? getMaskedContext(workInProgress, unmaskedContext) : emptyObject; - var instance = new ctor(props, context); - adoptClassInstance(workInProgress, instance); - - // Cache unmasked context so we can avoid recreating masked context unless necessary. - // ReactFiberContext usually updates this cache but can't for newly-created instances. - if (needsContext) { - cacheContext(workInProgress, unmaskedContext, context); - } - - return instance; - } - - function callComponentWillMount(workInProgress, instance) { - startPhaseTimer(workInProgress, 'componentWillMount'); - var oldState = instance.state; - instance.componentWillMount(); - stopPhaseTimer(); - - // Simulate an async bailout/interruption by invoking lifecycle twice. - if (debugRenderPhaseSideEffects) { - instance.componentWillMount(); - } - - if (oldState !== instance.state) { - { - warning(false, '%s.componentWillMount(): Assigning directly to this.state is ' + "deprecated (except inside a component's " + 'constructor). Use setState instead.', getComponentName(workInProgress)); - } - updater.enqueueReplaceState(instance, instance.state, null); - } - } - - function callComponentWillReceiveProps(workInProgress, instance, newProps, newContext) { - startPhaseTimer(workInProgress, 'componentWillReceiveProps'); - var oldState = instance.state; - instance.componentWillReceiveProps(newProps, newContext); - stopPhaseTimer(); - - // Simulate an async bailout/interruption by invoking lifecycle twice. - if (debugRenderPhaseSideEffects) { - instance.componentWillReceiveProps(newProps, newContext); - } - - if (instance.state !== oldState) { - { - var componentName = getComponentName(workInProgress) || 'Component'; - if (!didWarnAboutStateAssignmentForComponent[componentName]) { - warning(false, '%s.componentWillReceiveProps(): Assigning directly to ' + "this.state is deprecated (except inside a component's " + 'constructor). Use setState instead.', componentName); - didWarnAboutStateAssignmentForComponent[componentName] = true; - } - } - updater.enqueueReplaceState(instance, instance.state, null); - } - } - - // Invokes the mount life-cycles on a previously never rendered instance. - function mountClassInstance(workInProgress, renderExpirationTime) { - var current = workInProgress.alternate; - - { - checkClassInstance(workInProgress); - } - - var instance = workInProgress.stateNode; - var state = instance.state || null; - - var props = workInProgress.pendingProps; - !props ? invariant(false, 'There must be pending props for an initial mount. This error is likely caused by a bug in React. Please file an issue.') : void 0; - - var unmaskedContext = getUnmaskedContext(workInProgress); - - instance.props = props; - instance.state = workInProgress.memoizedState = state; - instance.refs = emptyObject; - instance.context = getMaskedContext(workInProgress, unmaskedContext); - - if (enableAsyncSubtreeAPI && workInProgress.type != null && workInProgress.type.prototype != null && workInProgress.type.prototype.unstable_isAsyncReactComponent === true) { - workInProgress.internalContextTag |= AsyncUpdates; - } - - if (typeof instance.componentWillMount === 'function') { - callComponentWillMount(workInProgress, instance); - // If we had additional state updates during this life-cycle, let's - // process them now. - var updateQueue = workInProgress.updateQueue; - if (updateQueue !== null) { - instance.state = processUpdateQueue(current, workInProgress, updateQueue, instance, props, renderExpirationTime); - } - } - if (typeof instance.componentDidMount === 'function') { - workInProgress.effectTag |= Update; - } - } - - // Called on a preexisting class instance. Returns false if a resumed render - // could be reused. - // function resumeMountClassInstance( - // workInProgress: Fiber, - // priorityLevel: PriorityLevel, - // ): boolean { - // const instance = workInProgress.stateNode; - // resetInputPointers(workInProgress, instance); - - // let newState = workInProgress.memoizedState; - // let newProps = workInProgress.pendingProps; - // if (!newProps) { - // // If there isn't any new props, then we'll reuse the memoized props. - // // This could be from already completed work. - // newProps = workInProgress.memoizedProps; - // invariant( - // newProps != null, - // 'There should always be pending or memoized props. This error is ' + - // 'likely caused by a bug in React. Please file an issue.', - // ); - // } - // const newUnmaskedContext = getUnmaskedContext(workInProgress); - // const newContext = getMaskedContext(workInProgress, newUnmaskedContext); - - // const oldContext = instance.context; - // const oldProps = workInProgress.memoizedProps; - - // if ( - // typeof instance.componentWillReceiveProps === 'function' && - // (oldProps !== newProps || oldContext !== newContext) - // ) { - // callComponentWillReceiveProps( - // workInProgress, - // instance, - // newProps, - // newContext, - // ); - // } - - // // Process the update queue before calling shouldComponentUpdate - // const updateQueue = workInProgress.updateQueue; - // if (updateQueue !== null) { - // newState = processUpdateQueue( - // workInProgress, - // updateQueue, - // instance, - // newState, - // newProps, - // priorityLevel, - // ); - // } - - // // TODO: Should we deal with a setState that happened after the last - // // componentWillMount and before this componentWillMount? Probably - // // unsupported anyway. - - // if ( - // !checkShouldComponentUpdate( - // workInProgress, - // workInProgress.memoizedProps, - // newProps, - // workInProgress.memoizedState, - // newState, - // newContext, - // ) - // ) { - // // Update the existing instance's state, props, and context pointers even - // // though we're bailing out. - // instance.props = newProps; - // instance.state = newState; - // instance.context = newContext; - // return false; - // } - - // // Update the input pointers now so that they are correct when we call - // // componentWillMount - // instance.props = newProps; - // instance.state = newState; - // instance.context = newContext; - - // if (typeof instance.componentWillMount === 'function') { - // callComponentWillMount(workInProgress, instance); - // // componentWillMount may have called setState. Process the update queue. - // const newUpdateQueue = workInProgress.updateQueue; - // if (newUpdateQueue !== null) { - // newState = processUpdateQueue( - // workInProgress, - // newUpdateQueue, - // instance, - // newState, - // newProps, - // priorityLevel, - // ); - // } - // } - - // if (typeof instance.componentDidMount === 'function') { - // workInProgress.effectTag |= Update; - // } - - // instance.state = newState; - - // return true; - // } - - // Invokes the update life-cycles and returns false if it shouldn't rerender. - function updateClassInstance(current, workInProgress, renderExpirationTime) { - var instance = workInProgress.stateNode; - resetInputPointers(workInProgress, instance); - - var oldProps = workInProgress.memoizedProps; - var newProps = workInProgress.pendingProps; - if (!newProps) { - // If there aren't any new props, then we'll reuse the memoized props. - // This could be from already completed work. - newProps = oldProps; - !(newProps != null) ? invariant(false, 'There should always be pending or memoized props. This error is likely caused by a bug in React. Please file an issue.') : void 0; - } - var oldContext = instance.context; - var newUnmaskedContext = getUnmaskedContext(workInProgress); - var newContext = getMaskedContext(workInProgress, newUnmaskedContext); - - // Note: During these life-cycles, instance.props/instance.state are what - // ever the previously attempted to render - not the "current". However, - // during componentDidUpdate we pass the "current" props. - - if (typeof instance.componentWillReceiveProps === 'function' && (oldProps !== newProps || oldContext !== newContext)) { - callComponentWillReceiveProps(workInProgress, instance, newProps, newContext); - } - - // Compute the next state using the memoized state and the update queue. - var oldState = workInProgress.memoizedState; - // TODO: Previous state can be null. - var newState = void 0; - if (workInProgress.updateQueue !== null) { - newState = processUpdateQueue(current, workInProgress, workInProgress.updateQueue, instance, newProps, renderExpirationTime); - } else { - newState = oldState; - } - - if (oldProps === newProps && oldState === newState && !hasContextChanged() && !(workInProgress.updateQueue !== null && workInProgress.updateQueue.hasForceUpdate)) { - // If an update was already in progress, we should schedule an Update - // effect even though we're bailing out, so that cWU/cDU are called. - if (typeof instance.componentDidUpdate === 'function') { - if (oldProps !== current.memoizedProps || oldState !== current.memoizedState) { - workInProgress.effectTag |= Update; - } - } - return false; - } - - var shouldUpdate = checkShouldComponentUpdate(workInProgress, oldProps, newProps, oldState, newState, newContext); - - if (shouldUpdate) { - if (typeof instance.componentWillUpdate === 'function') { - startPhaseTimer(workInProgress, 'componentWillUpdate'); - instance.componentWillUpdate(newProps, newState, newContext); - stopPhaseTimer(); - - // Simulate an async bailout/interruption by invoking lifecycle twice. - if (debugRenderPhaseSideEffects) { - instance.componentWillUpdate(newProps, newState, newContext); - } - } - if (typeof instance.componentDidUpdate === 'function') { - workInProgress.effectTag |= Update; - } - } else { - // If an update was already in progress, we should schedule an Update - // effect even though we're bailing out, so that cWU/cDU are called. - if (typeof instance.componentDidUpdate === 'function') { - if (oldProps !== current.memoizedProps || oldState !== current.memoizedState) { - workInProgress.effectTag |= Update; - } - } - - // If shouldComponentUpdate returned false, we should still update the - // memoized props/state to indicate that this work can be reused. - memoizeProps(workInProgress, newProps); - memoizeState(workInProgress, newState); - } - - // Update the existing instance's state, props, and context pointers even - // if shouldComponentUpdate returns false. - instance.props = newProps; - instance.state = newState; - instance.context = newContext; - - return shouldUpdate; - } - - return { - adoptClassInstance: adoptClassInstance, - constructClassInstance: constructClassInstance, - mountClassInstance: mountClassInstance, - // resumeMountClassInstance, - updateClassInstance: updateClassInstance - }; -}; - -// The Symbol used to tag the ReactElement-like types. If there is no native Symbol -// nor polyfill, then a plain number is used for performance. -var hasSymbol = typeof Symbol === 'function' && Symbol['for']; - -var REACT_ELEMENT_TYPE = hasSymbol ? Symbol['for']('react.element') : 0xeac7; -var REACT_CALL_TYPE = hasSymbol ? Symbol['for']('react.call') : 0xeac8; -var REACT_RETURN_TYPE = hasSymbol ? Symbol['for']('react.return') : 0xeac9; -var REACT_PORTAL_TYPE = hasSymbol ? Symbol['for']('react.portal') : 0xeaca; -var REACT_FRAGMENT_TYPE = hasSymbol ? Symbol['for']('react.fragment') : 0xeacb; - -var MAYBE_ITERATOR_SYMBOL = typeof Symbol === 'function' && Symbol.iterator; -var FAUX_ITERATOR_SYMBOL = '@@iterator'; - -function getIteratorFn(maybeIterable) { - if (maybeIterable === null || typeof maybeIterable === 'undefined') { - return null; - } - var maybeIterator = MAYBE_ITERATOR_SYMBOL && maybeIterable[MAYBE_ITERATOR_SYMBOL] || maybeIterable[FAUX_ITERATOR_SYMBOL]; - if (typeof maybeIterator === 'function') { - return maybeIterator; - } - return null; -} - -var getCurrentFiberStackAddendum$1 = ReactDebugCurrentFiber.getCurrentFiberStackAddendum; - - -{ - var didWarnAboutMaps = false; - /** - * Warn if there's no key explicitly set on dynamic arrays of children or - * object keys are not valid. This allows us to keep track of children between - * updates. - */ - var ownerHasKeyUseWarning = {}; - var ownerHasFunctionTypeWarning = {}; - - var warnForMissingKey = function (child) { - if (child === null || typeof child !== 'object') { - return; - } - if (!child._store || child._store.validated || child.key != null) { - return; - } - !(typeof child._store === 'object') ? invariant(false, 'React Component in warnForMissingKey should have a _store. This error is likely caused by a bug in React. Please file an issue.') : void 0; - child._store.validated = true; - - var currentComponentErrorInfo = 'Each child in an array or iterator should have a unique ' + '"key" prop. See https://fb.me/react-warning-keys for ' + 'more information.' + (getCurrentFiberStackAddendum$1() || ''); - if (ownerHasKeyUseWarning[currentComponentErrorInfo]) { - return; - } - ownerHasKeyUseWarning[currentComponentErrorInfo] = true; - - warning(false, 'Each child in an array or iterator should have a unique ' + '"key" prop. See https://fb.me/react-warning-keys for ' + 'more information.%s', getCurrentFiberStackAddendum$1()); - }; -} - -var isArray$1 = Array.isArray; - -function coerceRef(current, element) { - var mixedRef = element.ref; - if (mixedRef !== null && typeof mixedRef !== 'function') { - if (element._owner) { - var owner = element._owner; - var inst = void 0; - if (owner) { - var ownerFiber = owner; - !(ownerFiber.tag === ClassComponent) ? invariant(false, 'Stateless function components cannot have refs.') : void 0; - inst = ownerFiber.stateNode; - } - !inst ? invariant(false, 'Missing owner for string ref %s. This error is likely caused by a bug in React. Please file an issue.', mixedRef) : void 0; - var stringRef = '' + mixedRef; - // Check if previous string ref matches new string ref - if (current !== null && current.ref !== null && current.ref._stringRef === stringRef) { - return current.ref; - } - var ref = function (value) { - var refs = inst.refs === emptyObject ? inst.refs = {} : inst.refs; - if (value === null) { - delete refs[stringRef]; - } else { - refs[stringRef] = value; - } - }; - ref._stringRef = stringRef; - return ref; - } else { - !(typeof mixedRef === 'string') ? invariant(false, 'Expected ref to be a function or a string.') : void 0; - !element._owner ? invariant(false, 'Element ref was specified as a string (%s) but no owner was set. You may have multiple copies of React loaded. (details: https://fb.me/react-refs-must-have-owner).', mixedRef) : void 0; - } - } - return mixedRef; -} - -function throwOnInvalidObjectType(returnFiber, newChild) { - if (returnFiber.type !== 'textarea') { - var addendum = ''; - { - addendum = ' If you meant to render a collection of children, use an array ' + 'instead.' + (getCurrentFiberStackAddendum$1() || ''); - } - invariant(false, 'Objects are not valid as a React child (found: %s).%s', Object.prototype.toString.call(newChild) === '[object Object]' ? 'object with keys {' + Object.keys(newChild).join(', ') + '}' : newChild, addendum); - } -} - -function warnOnFunctionType() { - var currentComponentErrorInfo = 'Functions are not valid as a React child. This may happen if ' + 'you return a Component instead of from render. ' + 'Or maybe you meant to call this function rather than return it.' + (getCurrentFiberStackAddendum$1() || ''); - - if (ownerHasFunctionTypeWarning[currentComponentErrorInfo]) { - return; - } - ownerHasFunctionTypeWarning[currentComponentErrorInfo] = true; - - warning(false, 'Functions are not valid as a React child. This may happen if ' + 'you return a Component instead of from render. ' + 'Or maybe you meant to call this function rather than return it.%s', getCurrentFiberStackAddendum$1() || ''); -} - -// This wrapper function exists because I expect to clone the code in each path -// to be able to optimize each path individually by branching early. This needs -// a compiler or we can do it manually. Helpers that don't need this branching -// live outside of this function. -function ChildReconciler(shouldTrackSideEffects) { - function deleteChild(returnFiber, childToDelete) { - if (!shouldTrackSideEffects) { - // Noop. - return; - } - // Deletions are added in reversed order so we add it to the front. - // At this point, the return fiber's effect list is empty except for - // deletions, so we can just append the deletion to the list. The remaining - // effects aren't added until the complete phase. Once we implement - // resuming, this may not be true. - var last = returnFiber.lastEffect; - if (last !== null) { - last.nextEffect = childToDelete; - returnFiber.lastEffect = childToDelete; - } else { - returnFiber.firstEffect = returnFiber.lastEffect = childToDelete; - } - childToDelete.nextEffect = null; - childToDelete.effectTag = Deletion; - } - - function deleteRemainingChildren(returnFiber, currentFirstChild) { - if (!shouldTrackSideEffects) { - // Noop. - return null; - } - - // TODO: For the shouldClone case, this could be micro-optimized a bit by - // assuming that after the first child we've already added everything. - var childToDelete = currentFirstChild; - while (childToDelete !== null) { - deleteChild(returnFiber, childToDelete); - childToDelete = childToDelete.sibling; - } - return null; - } - - function mapRemainingChildren(returnFiber, currentFirstChild) { - // Add the remaining children to a temporary map so that we can find them by - // keys quickly. Implicit (null) keys get added to this set with their index - var existingChildren = new Map(); - - var existingChild = currentFirstChild; - while (existingChild !== null) { - if (existingChild.key !== null) { - existingChildren.set(existingChild.key, existingChild); - } else { - existingChildren.set(existingChild.index, existingChild); - } - existingChild = existingChild.sibling; - } - return existingChildren; - } - - function useFiber(fiber, pendingProps, expirationTime) { - // We currently set sibling to null and index to 0 here because it is easy - // to forget to do before returning it. E.g. for the single child case. - var clone = createWorkInProgress(fiber, pendingProps, expirationTime); - clone.index = 0; - clone.sibling = null; - return clone; - } - - function placeChild(newFiber, lastPlacedIndex, newIndex) { - newFiber.index = newIndex; - if (!shouldTrackSideEffects) { - // Noop. - return lastPlacedIndex; - } - var current = newFiber.alternate; - if (current !== null) { - var oldIndex = current.index; - if (oldIndex < lastPlacedIndex) { - // This is a move. - newFiber.effectTag = Placement; - return lastPlacedIndex; - } else { - // This item can stay in place. - return oldIndex; - } - } else { - // This is an insertion. - newFiber.effectTag = Placement; - return lastPlacedIndex; - } - } - - function placeSingleChild(newFiber) { - // This is simpler for the single child case. We only need to do a - // placement for inserting new children. - if (shouldTrackSideEffects && newFiber.alternate === null) { - newFiber.effectTag = Placement; - } - return newFiber; - } - - function updateTextNode(returnFiber, current, textContent, expirationTime) { - if (current === null || current.tag !== HostText) { - // Insert - var created = createFiberFromText(textContent, returnFiber.internalContextTag, expirationTime); - created['return'] = returnFiber; - return created; - } else { - // Update - var existing = useFiber(current, textContent, expirationTime); - existing['return'] = returnFiber; - return existing; - } - } - - function updateElement(returnFiber, current, element, expirationTime) { - if (current !== null && current.type === element.type) { - // Move based on index - var existing = useFiber(current, element.props, expirationTime); - existing.ref = coerceRef(current, element); - existing['return'] = returnFiber; - { - existing._debugSource = element._source; - existing._debugOwner = element._owner; - } - return existing; - } else { - // Insert - var created = createFiberFromElement(element, returnFiber.internalContextTag, expirationTime); - created.ref = coerceRef(current, element); - created['return'] = returnFiber; - return created; - } - } - - function updateCall(returnFiber, current, call, expirationTime) { - // TODO: Should this also compare handler to determine whether to reuse? - if (current === null || current.tag !== CallComponent) { - // Insert - var created = createFiberFromCall(call, returnFiber.internalContextTag, expirationTime); - created['return'] = returnFiber; - return created; - } else { - // Move based on index - var existing = useFiber(current, call, expirationTime); - existing['return'] = returnFiber; - return existing; - } - } - - function updateReturn(returnFiber, current, returnNode, expirationTime) { - if (current === null || current.tag !== ReturnComponent) { - // Insert - var created = createFiberFromReturn(returnNode, returnFiber.internalContextTag, expirationTime); - created.type = returnNode.value; - created['return'] = returnFiber; - return created; - } else { - // Move based on index - var existing = useFiber(current, null, expirationTime); - existing.type = returnNode.value; - existing['return'] = returnFiber; - return existing; - } - } - - function updatePortal(returnFiber, current, portal, expirationTime) { - if (current === null || current.tag !== HostPortal || current.stateNode.containerInfo !== portal.containerInfo || current.stateNode.implementation !== portal.implementation) { - // Insert - var created = createFiberFromPortal(portal, returnFiber.internalContextTag, expirationTime); - created['return'] = returnFiber; - return created; - } else { - // Update - var existing = useFiber(current, portal.children || [], expirationTime); - existing['return'] = returnFiber; - return existing; - } - } - - function updateFragment(returnFiber, current, fragment, expirationTime, key) { - if (current === null || current.tag !== Fragment) { - // Insert - var created = createFiberFromFragment(fragment, returnFiber.internalContextTag, expirationTime, key); - created['return'] = returnFiber; - return created; - } else { - // Update - var existing = useFiber(current, fragment, expirationTime); - existing['return'] = returnFiber; - return existing; - } - } - - function createChild(returnFiber, newChild, expirationTime) { - if (typeof newChild === 'string' || typeof newChild === 'number') { - // Text nodes don't have keys. If the previous node is implicitly keyed - // we can continue to replace it without aborting even if it is not a text - // node. - var created = createFiberFromText('' + newChild, returnFiber.internalContextTag, expirationTime); - created['return'] = returnFiber; - return created; - } - - if (typeof newChild === 'object' && newChild !== null) { - switch (newChild.$$typeof) { - case REACT_ELEMENT_TYPE: - { - if (newChild.type === REACT_FRAGMENT_TYPE) { - var _created = createFiberFromFragment(newChild.props.children, returnFiber.internalContextTag, expirationTime, newChild.key); - _created['return'] = returnFiber; - return _created; - } else { - var _created2 = createFiberFromElement(newChild, returnFiber.internalContextTag, expirationTime); - _created2.ref = coerceRef(null, newChild); - _created2['return'] = returnFiber; - return _created2; - } - } - - case REACT_CALL_TYPE: - { - var _created3 = createFiberFromCall(newChild, returnFiber.internalContextTag, expirationTime); - _created3['return'] = returnFiber; - return _created3; - } - - case REACT_RETURN_TYPE: - { - var _created4 = createFiberFromReturn(newChild, returnFiber.internalContextTag, expirationTime); - _created4.type = newChild.value; - _created4['return'] = returnFiber; - return _created4; - } - - case REACT_PORTAL_TYPE: - { - var _created5 = createFiberFromPortal(newChild, returnFiber.internalContextTag, expirationTime); - _created5['return'] = returnFiber; - return _created5; - } - } - - if (isArray$1(newChild) || getIteratorFn(newChild)) { - var _created6 = createFiberFromFragment(newChild, returnFiber.internalContextTag, expirationTime, null); - _created6['return'] = returnFiber; - return _created6; - } - - throwOnInvalidObjectType(returnFiber, newChild); - } - - { - if (typeof newChild === 'function') { - warnOnFunctionType(); - } - } - - return null; - } - - function updateSlot(returnFiber, oldFiber, newChild, expirationTime) { - // Update the fiber if the keys match, otherwise return null. - - var key = oldFiber !== null ? oldFiber.key : null; - - if (typeof newChild === 'string' || typeof newChild === 'number') { - // Text nodes don't have keys. If the previous node is implicitly keyed - // we can continue to replace it without aborting even if it is not a text - // node. - if (key !== null) { - return null; - } - return updateTextNode(returnFiber, oldFiber, '' + newChild, expirationTime); - } - - if (typeof newChild === 'object' && newChild !== null) { - switch (newChild.$$typeof) { - case REACT_ELEMENT_TYPE: - { - if (newChild.key === key) { - if (newChild.type === REACT_FRAGMENT_TYPE) { - return updateFragment(returnFiber, oldFiber, newChild.props.children, expirationTime, key); - } - return updateElement(returnFiber, oldFiber, newChild, expirationTime); - } else { - return null; - } - } - - case REACT_CALL_TYPE: - { - if (newChild.key === key) { - return updateCall(returnFiber, oldFiber, newChild, expirationTime); - } else { - return null; - } - } - - case REACT_RETURN_TYPE: - { - // Returns don't have keys. If the previous node is implicitly keyed - // we can continue to replace it without aborting even if it is not a - // yield. - if (key === null) { - return updateReturn(returnFiber, oldFiber, newChild, expirationTime); - } else { - return null; - } - } - - case REACT_PORTAL_TYPE: - { - if (newChild.key === key) { - return updatePortal(returnFiber, oldFiber, newChild, expirationTime); - } else { - return null; - } - } - } - - if (isArray$1(newChild) || getIteratorFn(newChild)) { - if (key !== null) { - return null; - } - - return updateFragment(returnFiber, oldFiber, newChild, expirationTime, null); - } - - throwOnInvalidObjectType(returnFiber, newChild); - } - - { - if (typeof newChild === 'function') { - warnOnFunctionType(); - } - } - - return null; - } - - function updateFromMap(existingChildren, returnFiber, newIdx, newChild, expirationTime) { - if (typeof newChild === 'string' || typeof newChild === 'number') { - // Text nodes don't have keys, so we neither have to check the old nor - // new node for the key. If both are text nodes, they match. - var matchedFiber = existingChildren.get(newIdx) || null; - return updateTextNode(returnFiber, matchedFiber, '' + newChild, expirationTime); - } - - if (typeof newChild === 'object' && newChild !== null) { - switch (newChild.$$typeof) { - case REACT_ELEMENT_TYPE: - { - var _matchedFiber = existingChildren.get(newChild.key === null ? newIdx : newChild.key) || null; - if (newChild.type === REACT_FRAGMENT_TYPE) { - return updateFragment(returnFiber, _matchedFiber, newChild.props.children, expirationTime, newChild.key); - } - return updateElement(returnFiber, _matchedFiber, newChild, expirationTime); - } - - case REACT_CALL_TYPE: - { - var _matchedFiber2 = existingChildren.get(newChild.key === null ? newIdx : newChild.key) || null; - return updateCall(returnFiber, _matchedFiber2, newChild, expirationTime); - } - - case REACT_RETURN_TYPE: - { - // Returns don't have keys, so we neither have to check the old nor - // new node for the key. If both are returns, they match. - var _matchedFiber3 = existingChildren.get(newIdx) || null; - return updateReturn(returnFiber, _matchedFiber3, newChild, expirationTime); - } - - case REACT_PORTAL_TYPE: - { - var _matchedFiber4 = existingChildren.get(newChild.key === null ? newIdx : newChild.key) || null; - return updatePortal(returnFiber, _matchedFiber4, newChild, expirationTime); - } - } - - if (isArray$1(newChild) || getIteratorFn(newChild)) { - var _matchedFiber5 = existingChildren.get(newIdx) || null; - return updateFragment(returnFiber, _matchedFiber5, newChild, expirationTime, null); - } - - throwOnInvalidObjectType(returnFiber, newChild); - } - - { - if (typeof newChild === 'function') { - warnOnFunctionType(); - } - } - - return null; - } - - /** - * Warns if there is a duplicate or missing key - */ - function warnOnInvalidKey(child, knownKeys) { - { - if (typeof child !== 'object' || child === null) { - return knownKeys; - } - switch (child.$$typeof) { - case REACT_ELEMENT_TYPE: - case REACT_CALL_TYPE: - case REACT_PORTAL_TYPE: - warnForMissingKey(child); - var key = child.key; - if (typeof key !== 'string') { - break; - } - if (knownKeys === null) { - knownKeys = new Set(); - knownKeys.add(key); - break; - } - if (!knownKeys.has(key)) { - knownKeys.add(key); - break; - } - warning(false, 'Encountered two children with the same key, `%s`. ' + 'Keys should be unique so that components maintain their identity ' + 'across updates. Non-unique keys may cause children to be ' + 'duplicated and/or omitted — the behavior is unsupported and ' + 'could change in a future version.%s', key, getCurrentFiberStackAddendum$1()); - break; - default: - break; - } - } - return knownKeys; - } - - function reconcileChildrenArray(returnFiber, currentFirstChild, newChildren, expirationTime) { - // This algorithm can't optimize by searching from boths ends since we - // don't have backpointers on fibers. I'm trying to see how far we can get - // with that model. If it ends up not being worth the tradeoffs, we can - // add it later. - - // Even with a two ended optimization, we'd want to optimize for the case - // where there are few changes and brute force the comparison instead of - // going for the Map. It'd like to explore hitting that path first in - // forward-only mode and only go for the Map once we notice that we need - // lots of look ahead. This doesn't handle reversal as well as two ended - // search but that's unusual. Besides, for the two ended optimization to - // work on Iterables, we'd need to copy the whole set. - - // In this first iteration, we'll just live with hitting the bad case - // (adding everything to a Map) in for every insert/move. - - // If you change this code, also update reconcileChildrenIterator() which - // uses the same algorithm. - - { - // First, validate keys. - var knownKeys = null; - for (var i = 0; i < newChildren.length; i++) { - var child = newChildren[i]; - knownKeys = warnOnInvalidKey(child, knownKeys); - } - } - - var resultingFirstChild = null; - var previousNewFiber = null; - - var oldFiber = currentFirstChild; - var lastPlacedIndex = 0; - var newIdx = 0; - var nextOldFiber = null; - for (; oldFiber !== null && newIdx < newChildren.length; newIdx++) { - if (oldFiber.index > newIdx) { - nextOldFiber = oldFiber; - oldFiber = null; - } else { - nextOldFiber = oldFiber.sibling; - } - var newFiber = updateSlot(returnFiber, oldFiber, newChildren[newIdx], expirationTime); - if (newFiber === null) { - // TODO: This breaks on empty slots like null children. That's - // unfortunate because it triggers the slow path all the time. We need - // a better way to communicate whether this was a miss or null, - // boolean, undefined, etc. - if (oldFiber === null) { - oldFiber = nextOldFiber; - } - break; - } - if (shouldTrackSideEffects) { - if (oldFiber && newFiber.alternate === null) { - // We matched the slot, but we didn't reuse the existing fiber, so we - // need to delete the existing child. - deleteChild(returnFiber, oldFiber); - } - } - lastPlacedIndex = placeChild(newFiber, lastPlacedIndex, newIdx); - if (previousNewFiber === null) { - // TODO: Move out of the loop. This only happens for the first run. - resultingFirstChild = newFiber; - } else { - // TODO: Defer siblings if we're not at the right index for this slot. - // I.e. if we had null values before, then we want to defer this - // for each null value. However, we also don't want to call updateSlot - // with the previous one. - previousNewFiber.sibling = newFiber; - } - previousNewFiber = newFiber; - oldFiber = nextOldFiber; - } - - if (newIdx === newChildren.length) { - // We've reached the end of the new children. We can delete the rest. - deleteRemainingChildren(returnFiber, oldFiber); - return resultingFirstChild; - } - - if (oldFiber === null) { - // If we don't have any more existing children we can choose a fast path - // since the rest will all be insertions. - for (; newIdx < newChildren.length; newIdx++) { - var _newFiber = createChild(returnFiber, newChildren[newIdx], expirationTime); - if (!_newFiber) { - continue; - } - lastPlacedIndex = placeChild(_newFiber, lastPlacedIndex, newIdx); - if (previousNewFiber === null) { - // TODO: Move out of the loop. This only happens for the first run. - resultingFirstChild = _newFiber; - } else { - previousNewFiber.sibling = _newFiber; - } - previousNewFiber = _newFiber; - } - return resultingFirstChild; - } - - // Add all children to a key map for quick lookups. - var existingChildren = mapRemainingChildren(returnFiber, oldFiber); - - // Keep scanning and use the map to restore deleted items as moves. - for (; newIdx < newChildren.length; newIdx++) { - var _newFiber2 = updateFromMap(existingChildren, returnFiber, newIdx, newChildren[newIdx], expirationTime); - if (_newFiber2) { - if (shouldTrackSideEffects) { - if (_newFiber2.alternate !== null) { - // The new fiber is a work in progress, but if there exists a - // current, that means that we reused the fiber. We need to delete - // it from the child list so that we don't add it to the deletion - // list. - existingChildren['delete'](_newFiber2.key === null ? newIdx : _newFiber2.key); - } - } - lastPlacedIndex = placeChild(_newFiber2, lastPlacedIndex, newIdx); - if (previousNewFiber === null) { - resultingFirstChild = _newFiber2; - } else { - previousNewFiber.sibling = _newFiber2; - } - previousNewFiber = _newFiber2; - } - } - - if (shouldTrackSideEffects) { - // Any existing children that weren't consumed above were deleted. We need - // to add them to the deletion list. - existingChildren.forEach(function (child) { - return deleteChild(returnFiber, child); - }); - } - - return resultingFirstChild; - } - - function reconcileChildrenIterator(returnFiber, currentFirstChild, newChildrenIterable, expirationTime) { - // This is the same implementation as reconcileChildrenArray(), - // but using the iterator instead. - - var iteratorFn = getIteratorFn(newChildrenIterable); - !(typeof iteratorFn === 'function') ? invariant(false, 'An object is not an iterable. This error is likely caused by a bug in React. Please file an issue.') : void 0; - - { - // Warn about using Maps as children - if (typeof newChildrenIterable.entries === 'function') { - var possibleMap = newChildrenIterable; - if (possibleMap.entries === iteratorFn) { - warning(didWarnAboutMaps, 'Using Maps as children is unsupported and will likely yield ' + 'unexpected results. Convert it to a sequence/iterable of keyed ' + 'ReactElements instead.%s', getCurrentFiberStackAddendum$1()); - didWarnAboutMaps = true; - } - } - - // First, validate keys. - // We'll get a different iterator later for the main pass. - var _newChildren = iteratorFn.call(newChildrenIterable); - if (_newChildren) { - var knownKeys = null; - var _step = _newChildren.next(); - for (; !_step.done; _step = _newChildren.next()) { - var child = _step.value; - knownKeys = warnOnInvalidKey(child, knownKeys); - } - } - } - - var newChildren = iteratorFn.call(newChildrenIterable); - !(newChildren != null) ? invariant(false, 'An iterable object provided no iterator.') : void 0; - - var resultingFirstChild = null; - var previousNewFiber = null; - - var oldFiber = currentFirstChild; - var lastPlacedIndex = 0; - var newIdx = 0; - var nextOldFiber = null; - - var step = newChildren.next(); - for (; oldFiber !== null && !step.done; newIdx++, step = newChildren.next()) { - if (oldFiber.index > newIdx) { - nextOldFiber = oldFiber; - oldFiber = null; - } else { - nextOldFiber = oldFiber.sibling; - } - var newFiber = updateSlot(returnFiber, oldFiber, step.value, expirationTime); - if (newFiber === null) { - // TODO: This breaks on empty slots like null children. That's - // unfortunate because it triggers the slow path all the time. We need - // a better way to communicate whether this was a miss or null, - // boolean, undefined, etc. - if (!oldFiber) { - oldFiber = nextOldFiber; - } - break; - } - if (shouldTrackSideEffects) { - if (oldFiber && newFiber.alternate === null) { - // We matched the slot, but we didn't reuse the existing fiber, so we - // need to delete the existing child. - deleteChild(returnFiber, oldFiber); - } - } - lastPlacedIndex = placeChild(newFiber, lastPlacedIndex, newIdx); - if (previousNewFiber === null) { - // TODO: Move out of the loop. This only happens for the first run. - resultingFirstChild = newFiber; - } else { - // TODO: Defer siblings if we're not at the right index for this slot. - // I.e. if we had null values before, then we want to defer this - // for each null value. However, we also don't want to call updateSlot - // with the previous one. - previousNewFiber.sibling = newFiber; - } - previousNewFiber = newFiber; - oldFiber = nextOldFiber; - } - - if (step.done) { - // We've reached the end of the new children. We can delete the rest. - deleteRemainingChildren(returnFiber, oldFiber); - return resultingFirstChild; - } - - if (oldFiber === null) { - // If we don't have any more existing children we can choose a fast path - // since the rest will all be insertions. - for (; !step.done; newIdx++, step = newChildren.next()) { - var _newFiber3 = createChild(returnFiber, step.value, expirationTime); - if (_newFiber3 === null) { - continue; - } - lastPlacedIndex = placeChild(_newFiber3, lastPlacedIndex, newIdx); - if (previousNewFiber === null) { - // TODO: Move out of the loop. This only happens for the first run. - resultingFirstChild = _newFiber3; - } else { - previousNewFiber.sibling = _newFiber3; - } - previousNewFiber = _newFiber3; - } - return resultingFirstChild; - } - - // Add all children to a key map for quick lookups. - var existingChildren = mapRemainingChildren(returnFiber, oldFiber); - - // Keep scanning and use the map to restore deleted items as moves. - for (; !step.done; newIdx++, step = newChildren.next()) { - var _newFiber4 = updateFromMap(existingChildren, returnFiber, newIdx, step.value, expirationTime); - if (_newFiber4 !== null) { - if (shouldTrackSideEffects) { - if (_newFiber4.alternate !== null) { - // The new fiber is a work in progress, but if there exists a - // current, that means that we reused the fiber. We need to delete - // it from the child list so that we don't add it to the deletion - // list. - existingChildren['delete'](_newFiber4.key === null ? newIdx : _newFiber4.key); - } - } - lastPlacedIndex = placeChild(_newFiber4, lastPlacedIndex, newIdx); - if (previousNewFiber === null) { - resultingFirstChild = _newFiber4; - } else { - previousNewFiber.sibling = _newFiber4; - } - previousNewFiber = _newFiber4; - } - } - - if (shouldTrackSideEffects) { - // Any existing children that weren't consumed above were deleted. We need - // to add them to the deletion list. - existingChildren.forEach(function (child) { - return deleteChild(returnFiber, child); - }); - } - - return resultingFirstChild; - } - - function reconcileSingleTextNode(returnFiber, currentFirstChild, textContent, expirationTime) { - // There's no need to check for keys on text nodes since we don't have a - // way to define them. - if (currentFirstChild !== null && currentFirstChild.tag === HostText) { - // We already have an existing node so let's just update it and delete - // the rest. - deleteRemainingChildren(returnFiber, currentFirstChild.sibling); - var existing = useFiber(currentFirstChild, textContent, expirationTime); - existing['return'] = returnFiber; - return existing; - } - // The existing first child is not a text node so we need to create one - // and delete the existing ones. - deleteRemainingChildren(returnFiber, currentFirstChild); - var created = createFiberFromText(textContent, returnFiber.internalContextTag, expirationTime); - created['return'] = returnFiber; - return created; - } - - function reconcileSingleElement(returnFiber, currentFirstChild, element, expirationTime) { - var key = element.key; - var child = currentFirstChild; - while (child !== null) { - // TODO: If key === null and child.key === null, then this only applies to - // the first item in the list. - if (child.key === key) { - if (child.tag === Fragment ? element.type === REACT_FRAGMENT_TYPE : child.type === element.type) { - deleteRemainingChildren(returnFiber, child.sibling); - var existing = useFiber(child, element.type === REACT_FRAGMENT_TYPE ? element.props.children : element.props, expirationTime); - existing.ref = coerceRef(child, element); - existing['return'] = returnFiber; - { - existing._debugSource = element._source; - existing._debugOwner = element._owner; - } - return existing; - } else { - deleteRemainingChildren(returnFiber, child); - break; - } - } else { - deleteChild(returnFiber, child); - } - child = child.sibling; - } - - if (element.type === REACT_FRAGMENT_TYPE) { - var created = createFiberFromFragment(element.props.children, returnFiber.internalContextTag, expirationTime, element.key); - created['return'] = returnFiber; - return created; - } else { - var _created7 = createFiberFromElement(element, returnFiber.internalContextTag, expirationTime); - _created7.ref = coerceRef(currentFirstChild, element); - _created7['return'] = returnFiber; - return _created7; - } - } - - function reconcileSingleCall(returnFiber, currentFirstChild, call, expirationTime) { - var key = call.key; - var child = currentFirstChild; - while (child !== null) { - // TODO: If key === null and child.key === null, then this only applies to - // the first item in the list. - if (child.key === key) { - if (child.tag === CallComponent) { - deleteRemainingChildren(returnFiber, child.sibling); - var existing = useFiber(child, call, expirationTime); - existing['return'] = returnFiber; - return existing; - } else { - deleteRemainingChildren(returnFiber, child); - break; - } - } else { - deleteChild(returnFiber, child); - } - child = child.sibling; - } - - var created = createFiberFromCall(call, returnFiber.internalContextTag, expirationTime); - created['return'] = returnFiber; - return created; - } - - function reconcileSingleReturn(returnFiber, currentFirstChild, returnNode, expirationTime) { - // There's no need to check for keys on yields since they're stateless. - var child = currentFirstChild; - if (child !== null) { - if (child.tag === ReturnComponent) { - deleteRemainingChildren(returnFiber, child.sibling); - var existing = useFiber(child, null, expirationTime); - existing.type = returnNode.value; - existing['return'] = returnFiber; - return existing; - } else { - deleteRemainingChildren(returnFiber, child); - } - } - - var created = createFiberFromReturn(returnNode, returnFiber.internalContextTag, expirationTime); - created.type = returnNode.value; - created['return'] = returnFiber; - return created; - } - - function reconcileSinglePortal(returnFiber, currentFirstChild, portal, expirationTime) { - var key = portal.key; - var child = currentFirstChild; - while (child !== null) { - // TODO: If key === null and child.key === null, then this only applies to - // the first item in the list. - if (child.key === key) { - if (child.tag === HostPortal && child.stateNode.containerInfo === portal.containerInfo && child.stateNode.implementation === portal.implementation) { - deleteRemainingChildren(returnFiber, child.sibling); - var existing = useFiber(child, portal.children || [], expirationTime); - existing['return'] = returnFiber; - return existing; - } else { - deleteRemainingChildren(returnFiber, child); - break; - } - } else { - deleteChild(returnFiber, child); - } - child = child.sibling; - } - - var created = createFiberFromPortal(portal, returnFiber.internalContextTag, expirationTime); - created['return'] = returnFiber; - return created; - } - - // This API will tag the children with the side-effect of the reconciliation - // itself. They will be added to the side-effect list as we pass through the - // children and the parent. - function reconcileChildFibers(returnFiber, currentFirstChild, newChild, expirationTime) { - // This function is not recursive. - // If the top level item is an array, we treat it as a set of children, - // not as a fragment. Nested arrays on the other hand will be treated as - // fragment nodes. Recursion happens at the normal flow. - - // Handle top level unkeyed fragments as if they were arrays. - // This leads to an ambiguity between <>{[...]} and <>.... - // We treat the ambiguous cases above the same. - if (typeof newChild === 'object' && newChild !== null && newChild.type === REACT_FRAGMENT_TYPE && newChild.key === null) { - newChild = newChild.props.children; - } - - // Handle object types - var isObject = typeof newChild === 'object' && newChild !== null; - - if (isObject) { - switch (newChild.$$typeof) { - case REACT_ELEMENT_TYPE: - return placeSingleChild(reconcileSingleElement(returnFiber, currentFirstChild, newChild, expirationTime)); - - case REACT_CALL_TYPE: - return placeSingleChild(reconcileSingleCall(returnFiber, currentFirstChild, newChild, expirationTime)); - case REACT_RETURN_TYPE: - return placeSingleChild(reconcileSingleReturn(returnFiber, currentFirstChild, newChild, expirationTime)); - case REACT_PORTAL_TYPE: - return placeSingleChild(reconcileSinglePortal(returnFiber, currentFirstChild, newChild, expirationTime)); - } - } - - if (typeof newChild === 'string' || typeof newChild === 'number') { - return placeSingleChild(reconcileSingleTextNode(returnFiber, currentFirstChild, '' + newChild, expirationTime)); - } - - if (isArray$1(newChild)) { - return reconcileChildrenArray(returnFiber, currentFirstChild, newChild, expirationTime); - } - - if (getIteratorFn(newChild)) { - return reconcileChildrenIterator(returnFiber, currentFirstChild, newChild, expirationTime); - } - - if (isObject) { - throwOnInvalidObjectType(returnFiber, newChild); - } - - { - if (typeof newChild === 'function') { - warnOnFunctionType(); - } - } - if (typeof newChild === 'undefined') { - // If the new child is undefined, and the return fiber is a composite - // component, throw an error. If Fiber return types are disabled, - // we already threw above. - switch (returnFiber.tag) { - case ClassComponent: - { - { - var instance = returnFiber.stateNode; - if (instance.render._isMockFunction) { - // We allow auto-mocks to proceed as if they're returning null. - break; - } - } - } - // Intentionally fall through to the next case, which handles both - // functions and classes - // eslint-disable-next-lined no-fallthrough - case FunctionalComponent: - { - var Component = returnFiber.type; - invariant(false, '%s(...): Nothing was returned from render. This usually means a return statement is missing. Or, to render nothing, return null.', Component.displayName || Component.name || 'Component'); - } - } - } - - // Remaining cases are all treated as empty. - return deleteRemainingChildren(returnFiber, currentFirstChild); - } - - return reconcileChildFibers; -} - -var reconcileChildFibers = ChildReconciler(true); -var mountChildFibers = ChildReconciler(false); - -function cloneChildFibers(current, workInProgress) { - !(current === null || workInProgress.child === current.child) ? invariant(false, 'Resuming work not yet implemented.') : void 0; - - if (workInProgress.child === null) { - return; - } - - var currentChild = workInProgress.child; - var newChild = createWorkInProgress(currentChild, currentChild.pendingProps, currentChild.expirationTime); - workInProgress.child = newChild; - - newChild['return'] = workInProgress; - while (currentChild.sibling !== null) { - currentChild = currentChild.sibling; - newChild = newChild.sibling = createWorkInProgress(currentChild, currentChild.pendingProps, currentChild.expirationTime); - newChild['return'] = workInProgress; - } - newChild.sibling = null; -} - -{ - var warnedAboutStatelessRefs = {}; -} - -var ReactFiberBeginWork = function (config, hostContext, hydrationContext, scheduleWork, computeExpirationForFiber) { - var shouldSetTextContent = config.shouldSetTextContent, - useSyncScheduling = config.useSyncScheduling, - shouldDeprioritizeSubtree = config.shouldDeprioritizeSubtree; - var pushHostContext = hostContext.pushHostContext, - pushHostContainer = hostContext.pushHostContainer; - var enterHydrationState = hydrationContext.enterHydrationState, - resetHydrationState = hydrationContext.resetHydrationState, - tryToClaimNextHydratableInstance = hydrationContext.tryToClaimNextHydratableInstance; - - var _ReactFiberClassCompo = ReactFiberClassComponent(scheduleWork, computeExpirationForFiber, memoizeProps, memoizeState), - adoptClassInstance = _ReactFiberClassCompo.adoptClassInstance, - constructClassInstance = _ReactFiberClassCompo.constructClassInstance, - mountClassInstance = _ReactFiberClassCompo.mountClassInstance, - updateClassInstance = _ReactFiberClassCompo.updateClassInstance; - - // TODO: Remove this and use reconcileChildrenAtExpirationTime directly. - - - function reconcileChildren(current, workInProgress, nextChildren) { - reconcileChildrenAtExpirationTime(current, workInProgress, nextChildren, workInProgress.expirationTime); - } - - function reconcileChildrenAtExpirationTime(current, workInProgress, nextChildren, renderExpirationTime) { - if (current === null) { - // If this is a fresh new component that hasn't been rendered yet, we - // won't update its child set by applying minimal side-effects. Instead, - // we will add them all to the child before it gets rendered. That means - // we can optimize this reconciliation pass by not tracking side-effects. - workInProgress.child = mountChildFibers(workInProgress, null, nextChildren, renderExpirationTime); - } else { - // If the current child is the same as the work in progress, it means that - // we haven't yet started any work on these children. Therefore, we use - // the clone algorithm to create a copy of all the current children. - - // If we had any progressed work already, that is invalid at this point so - // let's throw it out. - workInProgress.child = reconcileChildFibers(workInProgress, current.child, nextChildren, renderExpirationTime); - } - } - - function updateFragment(current, workInProgress) { - var nextChildren = workInProgress.pendingProps; - if (hasContextChanged()) { - // Normally we can bail out on props equality but if context has changed - // we don't do the bailout and we have to reuse existing props instead. - if (nextChildren === null) { - nextChildren = workInProgress.memoizedProps; - } - } else if (nextChildren === null || workInProgress.memoizedProps === nextChildren) { - return bailoutOnAlreadyFinishedWork(current, workInProgress); - } - reconcileChildren(current, workInProgress, nextChildren); - memoizeProps(workInProgress, nextChildren); - return workInProgress.child; - } - - function markRef(current, workInProgress) { - var ref = workInProgress.ref; - if (ref !== null && (!current || current.ref !== ref)) { - // Schedule a Ref effect - workInProgress.effectTag |= Ref; - } - } - - function updateFunctionalComponent(current, workInProgress) { - var fn = workInProgress.type; - var nextProps = workInProgress.pendingProps; - - var memoizedProps = workInProgress.memoizedProps; - if (hasContextChanged()) { - // Normally we can bail out on props equality but if context has changed - // we don't do the bailout and we have to reuse existing props instead. - if (nextProps === null) { - nextProps = memoizedProps; - } - } else { - if (nextProps === null || memoizedProps === nextProps) { - return bailoutOnAlreadyFinishedWork(current, workInProgress); - } - // TODO: consider bringing fn.shouldComponentUpdate() back. - // It used to be here. - } - - var unmaskedContext = getUnmaskedContext(workInProgress); - var context = getMaskedContext(workInProgress, unmaskedContext); - - var nextChildren; - - { - ReactCurrentOwner.current = workInProgress; - ReactDebugCurrentFiber.setCurrentPhase('render'); - nextChildren = fn(nextProps, context); - ReactDebugCurrentFiber.setCurrentPhase(null); - } - // React DevTools reads this flag. - workInProgress.effectTag |= PerformedWork; - reconcileChildren(current, workInProgress, nextChildren); - memoizeProps(workInProgress, nextProps); - return workInProgress.child; - } - - function updateClassComponent(current, workInProgress, renderExpirationTime) { - // Push context providers early to prevent context stack mismatches. - // During mounting we don't know the child context yet as the instance doesn't exist. - // We will invalidate the child context in finishClassComponent() right after rendering. - var hasContext = pushContextProvider(workInProgress); - - var shouldUpdate = void 0; - if (current === null) { - if (!workInProgress.stateNode) { - // In the initial pass we might need to construct the instance. - constructClassInstance(workInProgress, workInProgress.pendingProps); - mountClassInstance(workInProgress, renderExpirationTime); - shouldUpdate = true; - } else { - invariant(false, 'Resuming work not yet implemented.'); - // In a resume, we'll already have an instance we can reuse. - // shouldUpdate = resumeMountClassInstance(workInProgress, renderExpirationTime); - } - } else { - shouldUpdate = updateClassInstance(current, workInProgress, renderExpirationTime); - } - return finishClassComponent(current, workInProgress, shouldUpdate, hasContext); - } - - function finishClassComponent(current, workInProgress, shouldUpdate, hasContext) { - // Refs should update even if shouldComponentUpdate returns false - markRef(current, workInProgress); - - if (!shouldUpdate) { - // Context providers should defer to sCU for rendering - if (hasContext) { - invalidateContextProvider(workInProgress, false); - } - - return bailoutOnAlreadyFinishedWork(current, workInProgress); - } - - var instance = workInProgress.stateNode; - - // Rerender - ReactCurrentOwner.current = workInProgress; - var nextChildren = void 0; - { - ReactDebugCurrentFiber.setCurrentPhase('render'); - nextChildren = instance.render(); - if (debugRenderPhaseSideEffects) { - instance.render(); - } - ReactDebugCurrentFiber.setCurrentPhase(null); - } - // React DevTools reads this flag. - workInProgress.effectTag |= PerformedWork; - reconcileChildren(current, workInProgress, nextChildren); - // Memoize props and state using the values we just used to render. - // TODO: Restructure so we never read values from the instance. - memoizeState(workInProgress, instance.state); - memoizeProps(workInProgress, instance.props); - - // The context might have changed so we need to recalculate it. - if (hasContext) { - invalidateContextProvider(workInProgress, true); - } - - return workInProgress.child; - } - - function pushHostRootContext(workInProgress) { - var root = workInProgress.stateNode; - if (root.pendingContext) { - pushTopLevelContextObject(workInProgress, root.pendingContext, root.pendingContext !== root.context); - } else if (root.context) { - // Should always be set - pushTopLevelContextObject(workInProgress, root.context, false); - } - pushHostContainer(workInProgress, root.containerInfo); - } - - function updateHostRoot(current, workInProgress, renderExpirationTime) { - pushHostRootContext(workInProgress); - var updateQueue = workInProgress.updateQueue; - if (updateQueue !== null) { - var prevState = workInProgress.memoizedState; - var state = processUpdateQueue(current, workInProgress, updateQueue, null, null, renderExpirationTime); - if (prevState === state) { - // If the state is the same as before, that's a bailout because we had - // no work that expires at this time. - resetHydrationState(); - return bailoutOnAlreadyFinishedWork(current, workInProgress); - } - var element = state.element; - var root = workInProgress.stateNode; - if ((current === null || current.child === null) && root.hydrate && enterHydrationState(workInProgress)) { - // If we don't have any current children this might be the first pass. - // We always try to hydrate. If this isn't a hydration pass there won't - // be any children to hydrate which is effectively the same thing as - // not hydrating. - - // This is a bit of a hack. We track the host root as a placement to - // know that we're currently in a mounting state. That way isMounted - // works as expected. We must reset this before committing. - // TODO: Delete this when we delete isMounted and findDOMNode. - workInProgress.effectTag |= Placement; - - // Ensure that children mount into this root without tracking - // side-effects. This ensures that we don't store Placement effects on - // nodes that will be hydrated. - workInProgress.child = mountChildFibers(workInProgress, null, element, renderExpirationTime); - } else { - // Otherwise reset hydration state in case we aborted and resumed another - // root. - resetHydrationState(); - reconcileChildren(current, workInProgress, element); - } - memoizeState(workInProgress, state); - return workInProgress.child; - } - resetHydrationState(); - // If there is no update queue, that's a bailout because the root has no props. - return bailoutOnAlreadyFinishedWork(current, workInProgress); - } - - function updateHostComponent(current, workInProgress, renderExpirationTime) { - pushHostContext(workInProgress); - - if (current === null) { - tryToClaimNextHydratableInstance(workInProgress); - } - - var type = workInProgress.type; - var memoizedProps = workInProgress.memoizedProps; - var nextProps = workInProgress.pendingProps; - if (nextProps === null) { - nextProps = memoizedProps; - !(nextProps !== null) ? invariant(false, 'We should always have pending or current props. This error is likely caused by a bug in React. Please file an issue.') : void 0; - } - var prevProps = current !== null ? current.memoizedProps : null; - - if (hasContextChanged()) { - // Normally we can bail out on props equality but if context has changed - // we don't do the bailout and we have to reuse existing props instead. - } else if (nextProps === null || memoizedProps === nextProps) { - return bailoutOnAlreadyFinishedWork(current, workInProgress); - } - - var nextChildren = nextProps.children; - var isDirectTextChild = shouldSetTextContent(type, nextProps); - - if (isDirectTextChild) { - // We special case a direct text child of a host node. This is a common - // case. We won't handle it as a reified child. We will instead handle - // this in the host environment that also have access to this prop. That - // avoids allocating another HostText fiber and traversing it. - nextChildren = null; - } else if (prevProps && shouldSetTextContent(type, prevProps)) { - // If we're switching from a direct text child to a normal child, or to - // empty, we need to schedule the text content to be reset. - workInProgress.effectTag |= ContentReset; - } - - markRef(current, workInProgress); - - // Check the host config to see if the children are offscreen/hidden. - if (renderExpirationTime !== Never && !useSyncScheduling && shouldDeprioritizeSubtree(type, nextProps)) { - // Down-prioritize the children. - workInProgress.expirationTime = Never; - // Bailout and come back to this fiber later. - return null; - } - - reconcileChildren(current, workInProgress, nextChildren); - memoizeProps(workInProgress, nextProps); - return workInProgress.child; - } - - function updateHostText(current, workInProgress) { - if (current === null) { - tryToClaimNextHydratableInstance(workInProgress); - } - var nextProps = workInProgress.pendingProps; - if (nextProps === null) { - nextProps = workInProgress.memoizedProps; - } - memoizeProps(workInProgress, nextProps); - // Nothing to do here. This is terminal. We'll do the completion step - // immediately after. - return null; - } - - function mountIndeterminateComponent(current, workInProgress, renderExpirationTime) { - !(current === null) ? invariant(false, 'An indeterminate component should never have mounted. This error is likely caused by a bug in React. Please file an issue.') : void 0; - var fn = workInProgress.type; - var props = workInProgress.pendingProps; - var unmaskedContext = getUnmaskedContext(workInProgress); - var context = getMaskedContext(workInProgress, unmaskedContext); - - var value; - - { - if (fn.prototype && typeof fn.prototype.render === 'function') { - var componentName = getComponentName(workInProgress); - warning(false, "The <%s /> component appears to have a render method, but doesn't extend React.Component. " + 'This is likely to cause errors. Change %s to extend React.Component instead.', componentName, componentName); - } - ReactCurrentOwner.current = workInProgress; - value = fn(props, context); - } - // React DevTools reads this flag. - workInProgress.effectTag |= PerformedWork; - - if (typeof value === 'object' && value !== null && typeof value.render === 'function') { - // Proceed under the assumption that this is a class instance - workInProgress.tag = ClassComponent; - - // Push context providers early to prevent context stack mismatches. - // During mounting we don't know the child context yet as the instance doesn't exist. - // We will invalidate the child context in finishClassComponent() right after rendering. - var hasContext = pushContextProvider(workInProgress); - adoptClassInstance(workInProgress, value); - mountClassInstance(workInProgress, renderExpirationTime); - return finishClassComponent(current, workInProgress, true, hasContext); - } else { - // Proceed under the assumption that this is a functional component - workInProgress.tag = FunctionalComponent; - { - var Component = workInProgress.type; - - if (Component) { - warning(!Component.childContextTypes, '%s(...): childContextTypes cannot be defined on a functional component.', Component.displayName || Component.name || 'Component'); - } - if (workInProgress.ref !== null) { - var info = ''; - var ownerName = ReactDebugCurrentFiber.getCurrentFiberOwnerName(); - if (ownerName) { - info += '\n\nCheck the render method of `' + ownerName + '`.'; - } - - var warningKey = ownerName || workInProgress._debugID || ''; - var debugSource = workInProgress._debugSource; - if (debugSource) { - warningKey = debugSource.fileName + ':' + debugSource.lineNumber; - } - if (!warnedAboutStatelessRefs[warningKey]) { - warnedAboutStatelessRefs[warningKey] = true; - warning(false, 'Stateless function components cannot be given refs. ' + 'Attempts to access this ref will fail.%s%s', info, ReactDebugCurrentFiber.getCurrentFiberStackAddendum()); - } - } - } - reconcileChildren(current, workInProgress, value); - memoizeProps(workInProgress, props); - return workInProgress.child; - } - } - - function updateCallComponent(current, workInProgress, renderExpirationTime) { - var nextCall = workInProgress.pendingProps; - if (hasContextChanged()) { - // Normally we can bail out on props equality but if context has changed - // we don't do the bailout and we have to reuse existing props instead. - if (nextCall === null) { - nextCall = current && current.memoizedProps; - !(nextCall !== null) ? invariant(false, 'We should always have pending or current props. This error is likely caused by a bug in React. Please file an issue.') : void 0; - } - } else if (nextCall === null || workInProgress.memoizedProps === nextCall) { - nextCall = workInProgress.memoizedProps; - // TODO: When bailing out, we might need to return the stateNode instead - // of the child. To check it for work. - // return bailoutOnAlreadyFinishedWork(current, workInProgress); - } - - var nextChildren = nextCall.children; - - // The following is a fork of reconcileChildrenAtExpirationTime but using - // stateNode to store the child. - if (current === null) { - workInProgress.stateNode = mountChildFibers(workInProgress, workInProgress.stateNode, nextChildren, renderExpirationTime); - } else { - workInProgress.stateNode = reconcileChildFibers(workInProgress, workInProgress.stateNode, nextChildren, renderExpirationTime); - } - - memoizeProps(workInProgress, nextCall); - // This doesn't take arbitrary time so we could synchronously just begin - // eagerly do the work of workInProgress.child as an optimization. - return workInProgress.stateNode; - } - - function updatePortalComponent(current, workInProgress, renderExpirationTime) { - pushHostContainer(workInProgress, workInProgress.stateNode.containerInfo); - var nextChildren = workInProgress.pendingProps; - if (hasContextChanged()) { - // Normally we can bail out on props equality but if context has changed - // we don't do the bailout and we have to reuse existing props instead. - if (nextChildren === null) { - nextChildren = current && current.memoizedProps; - !(nextChildren != null) ? invariant(false, 'We should always have pending or current props. This error is likely caused by a bug in React. Please file an issue.') : void 0; - } - } else if (nextChildren === null || workInProgress.memoizedProps === nextChildren) { - return bailoutOnAlreadyFinishedWork(current, workInProgress); - } - - if (current === null) { - // Portals are special because we don't append the children during mount - // but at commit. Therefore we need to track insertions which the normal - // flow doesn't do during mount. This doesn't happen at the root because - // the root always starts with a "current" with a null child. - // TODO: Consider unifying this with how the root works. - workInProgress.child = reconcileChildFibers(workInProgress, null, nextChildren, renderExpirationTime); - memoizeProps(workInProgress, nextChildren); - } else { - reconcileChildren(current, workInProgress, nextChildren); - memoizeProps(workInProgress, nextChildren); - } - return workInProgress.child; - } - - /* - function reuseChildrenEffects(returnFiber : Fiber, firstChild : Fiber) { - let child = firstChild; - do { - // Ensure that the first and last effect of the parent corresponds - // to the children's first and last effect. - if (!returnFiber.firstEffect) { - returnFiber.firstEffect = child.firstEffect; - } - if (child.lastEffect) { - if (returnFiber.lastEffect) { - returnFiber.lastEffect.nextEffect = child.firstEffect; - } - returnFiber.lastEffect = child.lastEffect; - } - } while (child = child.sibling); - } - */ - - function bailoutOnAlreadyFinishedWork(current, workInProgress) { - cancelWorkTimer(workInProgress); - - // TODO: We should ideally be able to bail out early if the children have no - // more work to do. However, since we don't have a separation of this - // Fiber's priority and its children yet - we don't know without doing lots - // of the same work we do anyway. Once we have that separation we can just - // bail out here if the children has no more work at this priority level. - // if (workInProgress.priorityOfChildren <= priorityLevel) { - // // If there are side-effects in these children that have not yet been - // // committed we need to ensure that they get properly transferred up. - // if (current && current.child !== workInProgress.child) { - // reuseChildrenEffects(workInProgress, child); - // } - // return null; - // } - - cloneChildFibers(current, workInProgress); - return workInProgress.child; - } - - function bailoutOnLowPriority(current, workInProgress) { - cancelWorkTimer(workInProgress); - - // TODO: Handle HostComponent tags here as well and call pushHostContext()? - // See PR 8590 discussion for context - switch (workInProgress.tag) { - case HostRoot: - pushHostRootContext(workInProgress); - break; - case ClassComponent: - pushContextProvider(workInProgress); - break; - case HostPortal: - pushHostContainer(workInProgress, workInProgress.stateNode.containerInfo); - break; - } - // TODO: What if this is currently in progress? - // How can that happen? How is this not being cloned? - return null; - } - - // TODO: Delete memoizeProps/State and move to reconcile/bailout instead - function memoizeProps(workInProgress, nextProps) { - workInProgress.memoizedProps = nextProps; - } - - function memoizeState(workInProgress, nextState) { - workInProgress.memoizedState = nextState; - // Don't reset the updateQueue, in case there are pending updates. Resetting - // is handled by processUpdateQueue. - } - - function beginWork(current, workInProgress, renderExpirationTime) { - if (workInProgress.expirationTime === NoWork || workInProgress.expirationTime > renderExpirationTime) { - return bailoutOnLowPriority(current, workInProgress); - } - - switch (workInProgress.tag) { - case IndeterminateComponent: - return mountIndeterminateComponent(current, workInProgress, renderExpirationTime); - case FunctionalComponent: - return updateFunctionalComponent(current, workInProgress); - case ClassComponent: - return updateClassComponent(current, workInProgress, renderExpirationTime); - case HostRoot: - return updateHostRoot(current, workInProgress, renderExpirationTime); - case HostComponent: - return updateHostComponent(current, workInProgress, renderExpirationTime); - case HostText: - return updateHostText(current, workInProgress); - case CallHandlerPhase: - // This is a restart. Reset the tag to the initial phase. - workInProgress.tag = CallComponent; - // Intentionally fall through since this is now the same. - case CallComponent: - return updateCallComponent(current, workInProgress, renderExpirationTime); - case ReturnComponent: - // A return component is just a placeholder, we can just run through the - // next one immediately. - return null; - case HostPortal: - return updatePortalComponent(current, workInProgress, renderExpirationTime); - case Fragment: - return updateFragment(current, workInProgress); - default: - invariant(false, 'Unknown unit of work tag. This error is likely caused by a bug in React. Please file an issue.'); - } - } - - function beginFailedWork(current, workInProgress, renderExpirationTime) { - // Push context providers here to avoid a push/pop context mismatch. - switch (workInProgress.tag) { - case ClassComponent: - pushContextProvider(workInProgress); - break; - case HostRoot: - pushHostRootContext(workInProgress); - break; - default: - invariant(false, 'Invalid type of work. This error is likely caused by a bug in React. Please file an issue.'); - } - - // Add an error effect so we can handle the error during the commit phase - workInProgress.effectTag |= Err; - - // This is a weird case where we do "resume" work — work that failed on - // our first attempt. Because we no longer have a notion of "progressed - // deletions," reset the child to the current child to make sure we delete - // it again. TODO: Find a better way to handle this, perhaps during a more - // general overhaul of error handling. - if (current === null) { - workInProgress.child = null; - } else if (workInProgress.child !== current.child) { - workInProgress.child = current.child; - } - - if (workInProgress.expirationTime === NoWork || workInProgress.expirationTime > renderExpirationTime) { - return bailoutOnLowPriority(current, workInProgress); - } - - // If we don't bail out, we're going be recomputing our children so we need - // to drop our effect list. - workInProgress.firstEffect = null; - workInProgress.lastEffect = null; - - // Unmount the current children as if the component rendered null - var nextChildren = null; - reconcileChildrenAtExpirationTime(current, workInProgress, nextChildren, renderExpirationTime); - - if (workInProgress.tag === ClassComponent) { - var instance = workInProgress.stateNode; - workInProgress.memoizedProps = instance.props; - workInProgress.memoizedState = instance.state; - } - - return workInProgress.child; - } - - return { - beginWork: beginWork, - beginFailedWork: beginFailedWork - }; -}; - -var ReactFiberCompleteWork = function (config, hostContext, hydrationContext) { - var createInstance = config.createInstance, - createTextInstance = config.createTextInstance, - appendInitialChild = config.appendInitialChild, - finalizeInitialChildren = config.finalizeInitialChildren, - prepareUpdate = config.prepareUpdate, - mutation = config.mutation, - persistence = config.persistence; - var getRootHostContainer = hostContext.getRootHostContainer, - popHostContext = hostContext.popHostContext, - getHostContext = hostContext.getHostContext, - popHostContainer = hostContext.popHostContainer; - var prepareToHydrateHostInstance = hydrationContext.prepareToHydrateHostInstance, - prepareToHydrateHostTextInstance = hydrationContext.prepareToHydrateHostTextInstance, - popHydrationState = hydrationContext.popHydrationState; - - - function markUpdate(workInProgress) { - // Tag the fiber with an update effect. This turns a Placement into - // an UpdateAndPlacement. - workInProgress.effectTag |= Update; - } - - function markRef(workInProgress) { - workInProgress.effectTag |= Ref; - } - - function appendAllReturns(returns, workInProgress) { - var node = workInProgress.stateNode; - if (node) { - node['return'] = workInProgress; - } - while (node !== null) { - if (node.tag === HostComponent || node.tag === HostText || node.tag === HostPortal) { - invariant(false, 'A call cannot have host component children.'); - } else if (node.tag === ReturnComponent) { - returns.push(node.type); - } else if (node.child !== null) { - node.child['return'] = node; - node = node.child; - continue; - } - while (node.sibling === null) { - if (node['return'] === null || node['return'] === workInProgress) { - return; - } - node = node['return']; - } - node.sibling['return'] = node['return']; - node = node.sibling; - } - } - - function moveCallToHandlerPhase(current, workInProgress, renderExpirationTime) { - var call = workInProgress.memoizedProps; - !call ? invariant(false, 'Should be resolved by now. This error is likely caused by a bug in React. Please file an issue.') : void 0; - - // First step of the call has completed. Now we need to do the second. - // TODO: It would be nice to have a multi stage call represented by a - // single component, or at least tail call optimize nested ones. Currently - // that requires additional fields that we don't want to add to the fiber. - // So this requires nested handlers. - // Note: This doesn't mutate the alternate node. I don't think it needs to - // since this stage is reset for every pass. - workInProgress.tag = CallHandlerPhase; - - // Build up the returns. - // TODO: Compare this to a generator or opaque helpers like Children. - var returns = []; - appendAllReturns(returns, workInProgress); - var fn = call.handler; - var props = call.props; - var nextChildren = fn(props, returns); - - var currentFirstChild = current !== null ? current.child : null; - workInProgress.child = reconcileChildFibers(workInProgress, currentFirstChild, nextChildren, renderExpirationTime); - return workInProgress.child; - } - - function appendAllChildren(parent, workInProgress) { - // We only have the top Fiber that was created but we need recurse down its - // children to find all the terminal nodes. - var node = workInProgress.child; - while (node !== null) { - if (node.tag === HostComponent || node.tag === HostText) { - appendInitialChild(parent, node.stateNode); - } else if (node.tag === HostPortal) { - // If we have a portal child, then we don't want to traverse - // down its children. Instead, we'll get insertions from each child in - // the portal directly. - } else if (node.child !== null) { - node.child['return'] = node; - node = node.child; - continue; - } - if (node === workInProgress) { - return; - } - while (node.sibling === null) { - if (node['return'] === null || node['return'] === workInProgress) { - return; - } - node = node['return']; - } - node.sibling['return'] = node['return']; - node = node.sibling; - } - } - - var updateHostContainer = void 0; - var updateHostComponent = void 0; - var updateHostText = void 0; - if (mutation) { - if (enableMutatingReconciler) { - // Mutation mode - updateHostContainer = function (workInProgress) { - // Noop - }; - updateHostComponent = function (current, workInProgress, updatePayload, type, oldProps, newProps, rootContainerInstance) { - // TODO: Type this specific to this type of component. - workInProgress.updateQueue = updatePayload; - // If the update payload indicates that there is a change or if there - // is a new ref we mark this as an update. All the work is done in commitWork. - if (updatePayload) { - markUpdate(workInProgress); - } - }; - updateHostText = function (current, workInProgress, oldText, newText) { - // If the text differs, mark it as an update. All the work in done in commitWork. - if (oldText !== newText) { - markUpdate(workInProgress); - } - }; - } else { - invariant(false, 'Mutating reconciler is disabled.'); - } - } else if (persistence) { - if (enablePersistentReconciler) { - // Persistent host tree mode - var cloneInstance = persistence.cloneInstance, - createContainerChildSet = persistence.createContainerChildSet, - appendChildToContainerChildSet = persistence.appendChildToContainerChildSet, - finalizeContainerChildren = persistence.finalizeContainerChildren; - - // An unfortunate fork of appendAllChildren because we have two different parent types. - - var appendAllChildrenToContainer = function (containerChildSet, workInProgress) { - // We only have the top Fiber that was created but we need recurse down its - // children to find all the terminal nodes. - var node = workInProgress.child; - while (node !== null) { - if (node.tag === HostComponent || node.tag === HostText) { - appendChildToContainerChildSet(containerChildSet, node.stateNode); - } else if (node.tag === HostPortal) { - // If we have a portal child, then we don't want to traverse - // down its children. Instead, we'll get insertions from each child in - // the portal directly. - } else if (node.child !== null) { - node.child['return'] = node; - node = node.child; - continue; - } - if (node === workInProgress) { - return; - } - while (node.sibling === null) { - if (node['return'] === null || node['return'] === workInProgress) { - return; - } - node = node['return']; - } - node.sibling['return'] = node['return']; - node = node.sibling; - } - }; - updateHostContainer = function (workInProgress) { - var portalOrRoot = workInProgress.stateNode; - var childrenUnchanged = workInProgress.firstEffect === null; - if (childrenUnchanged) { - // No changes, just reuse the existing instance. - } else { - var container = portalOrRoot.containerInfo; - var newChildSet = createContainerChildSet(container); - if (finalizeContainerChildren(container, newChildSet)) { - markUpdate(workInProgress); - } - portalOrRoot.pendingChildren = newChildSet; - // If children might have changed, we have to add them all to the set. - appendAllChildrenToContainer(newChildSet, workInProgress); - // Schedule an update on the container to swap out the container. - markUpdate(workInProgress); - } - }; - updateHostComponent = function (current, workInProgress, updatePayload, type, oldProps, newProps, rootContainerInstance) { - // If there are no effects associated with this node, then none of our children had any updates. - // This guarantees that we can reuse all of them. - var childrenUnchanged = workInProgress.firstEffect === null; - var currentInstance = current.stateNode; - if (childrenUnchanged && updatePayload === null) { - // No changes, just reuse the existing instance. - // Note that this might release a previous clone. - workInProgress.stateNode = currentInstance; - } else { - var recyclableInstance = workInProgress.stateNode; - var newInstance = cloneInstance(currentInstance, updatePayload, type, oldProps, newProps, workInProgress, childrenUnchanged, recyclableInstance); - if (finalizeInitialChildren(newInstance, type, newProps, rootContainerInstance)) { - markUpdate(workInProgress); - } - workInProgress.stateNode = newInstance; - if (childrenUnchanged) { - // If there are no other effects in this tree, we need to flag this node as having one. - // Even though we're not going to use it for anything. - // Otherwise parents won't know that there are new children to propagate upwards. - markUpdate(workInProgress); - } else { - // If children might have changed, we have to add them all to the set. - appendAllChildren(newInstance, workInProgress); - } - } - }; - updateHostText = function (current, workInProgress, oldText, newText) { - if (oldText !== newText) { - // If the text content differs, we'll create a new text instance for it. - var rootContainerInstance = getRootHostContainer(); - var currentHostContext = getHostContext(); - workInProgress.stateNode = createTextInstance(newText, rootContainerInstance, currentHostContext, workInProgress); - // We'll have to mark it as having an effect, even though we won't use the effect for anything. - // This lets the parents know that at least one of their children has changed. - markUpdate(workInProgress); - } - }; - } else { - invariant(false, 'Persistent reconciler is disabled.'); - } - } else { - if (enableNoopReconciler) { - // No host operations - updateHostContainer = function (workInProgress) { - // Noop - }; - updateHostComponent = function (current, workInProgress, updatePayload, type, oldProps, newProps, rootContainerInstance) { - // Noop - }; - updateHostText = function (current, workInProgress, oldText, newText) { - // Noop - }; - } else { - invariant(false, 'Noop reconciler is disabled.'); - } - } - - function completeWork(current, workInProgress, renderExpirationTime) { - // Get the latest props. - var newProps = workInProgress.pendingProps; - if (newProps === null) { - newProps = workInProgress.memoizedProps; - } else if (workInProgress.expirationTime !== Never || renderExpirationTime === Never) { - // Reset the pending props, unless this was a down-prioritization. - workInProgress.pendingProps = null; - } - - switch (workInProgress.tag) { - case FunctionalComponent: - return null; - case ClassComponent: - { - // We are leaving this subtree, so pop context if any. - popContextProvider(workInProgress); - return null; - } - case HostRoot: - { - popHostContainer(workInProgress); - popTopLevelContextObject(workInProgress); - var fiberRoot = workInProgress.stateNode; - if (fiberRoot.pendingContext) { - fiberRoot.context = fiberRoot.pendingContext; - fiberRoot.pendingContext = null; - } - - if (current === null || current.child === null) { - // If we hydrated, pop so that we can delete any remaining children - // that weren't hydrated. - popHydrationState(workInProgress); - // This resets the hacky state to fix isMounted before committing. - // TODO: Delete this when we delete isMounted and findDOMNode. - workInProgress.effectTag &= ~Placement; - } - updateHostContainer(workInProgress); - return null; - } - case HostComponent: - { - popHostContext(workInProgress); - var rootContainerInstance = getRootHostContainer(); - var type = workInProgress.type; - if (current !== null && workInProgress.stateNode != null) { - // If we have an alternate, that means this is an update and we need to - // schedule a side-effect to do the updates. - var oldProps = current.memoizedProps; - // If we get updated because one of our children updated, we don't - // have newProps so we'll have to reuse them. - // TODO: Split the update API as separate for the props vs. children. - // Even better would be if children weren't special cased at all tho. - var instance = workInProgress.stateNode; - var currentHostContext = getHostContext(); - var updatePayload = prepareUpdate(instance, type, oldProps, newProps, rootContainerInstance, currentHostContext); - - updateHostComponent(current, workInProgress, updatePayload, type, oldProps, newProps, rootContainerInstance); - - if (current.ref !== workInProgress.ref) { - markRef(workInProgress); - } - } else { - if (!newProps) { - !(workInProgress.stateNode !== null) ? invariant(false, 'We must have new props for new mounts. This error is likely caused by a bug in React. Please file an issue.') : void 0; - // This can happen when we abort work. - return null; - } - - var _currentHostContext = getHostContext(); - // TODO: Move createInstance to beginWork and keep it on a context - // "stack" as the parent. Then append children as we go in beginWork - // or completeWork depending on we want to add then top->down or - // bottom->up. Top->down is faster in IE11. - var wasHydrated = popHydrationState(workInProgress); - if (wasHydrated) { - // TODO: Move this and createInstance step into the beginPhase - // to consolidate. - if (prepareToHydrateHostInstance(workInProgress, rootContainerInstance, _currentHostContext)) { - // If changes to the hydrated node needs to be applied at the - // commit-phase we mark this as such. - markUpdate(workInProgress); - } - } else { - var _instance = createInstance(type, newProps, rootContainerInstance, _currentHostContext, workInProgress); - - appendAllChildren(_instance, workInProgress); - - // Certain renderers require commit-time effects for initial mount. - // (eg DOM renderer supports auto-focus for certain elements). - // Make sure such renderers get scheduled for later work. - if (finalizeInitialChildren(_instance, type, newProps, rootContainerInstance)) { - markUpdate(workInProgress); - } - workInProgress.stateNode = _instance; - } - - if (workInProgress.ref !== null) { - // If there is a ref on a host node we need to schedule a callback - markRef(workInProgress); - } - } - return null; - } - case HostText: - { - var newText = newProps; - if (current && workInProgress.stateNode != null) { - var oldText = current.memoizedProps; - // If we have an alternate, that means this is an update and we need - // to schedule a side-effect to do the updates. - updateHostText(current, workInProgress, oldText, newText); - } else { - if (typeof newText !== 'string') { - !(workInProgress.stateNode !== null) ? invariant(false, 'We must have new props for new mounts. This error is likely caused by a bug in React. Please file an issue.') : void 0; - // This can happen when we abort work. - return null; - } - var _rootContainerInstance = getRootHostContainer(); - var _currentHostContext2 = getHostContext(); - var _wasHydrated = popHydrationState(workInProgress); - if (_wasHydrated) { - if (prepareToHydrateHostTextInstance(workInProgress)) { - markUpdate(workInProgress); - } - } else { - workInProgress.stateNode = createTextInstance(newText, _rootContainerInstance, _currentHostContext2, workInProgress); - } - } - return null; - } - case CallComponent: - return moveCallToHandlerPhase(current, workInProgress, renderExpirationTime); - case CallHandlerPhase: - // Reset the tag to now be a first phase call. - workInProgress.tag = CallComponent; - return null; - case ReturnComponent: - // Does nothing. - return null; - case Fragment: - return null; - case HostPortal: - popHostContainer(workInProgress); - updateHostContainer(workInProgress); - return null; - // Error cases - case IndeterminateComponent: - invariant(false, 'An indeterminate component should have become determinate before completing. This error is likely caused by a bug in React. Please file an issue.'); - // eslint-disable-next-line no-fallthrough - default: - invariant(false, 'Unknown unit of work tag. This error is likely caused by a bug in React. Please file an issue.'); - } - } - - return { - completeWork: completeWork - }; -}; - -var invokeGuardedCallback$2 = ReactErrorUtils.invokeGuardedCallback; -var hasCaughtError$1 = ReactErrorUtils.hasCaughtError; -var clearCaughtError$1 = ReactErrorUtils.clearCaughtError; - - -var ReactFiberCommitWork = function (config, captureError) { - var getPublicInstance = config.getPublicInstance, - mutation = config.mutation, - persistence = config.persistence; - - - var callComponentWillUnmountWithTimer = function (current, instance) { - startPhaseTimer(current, 'componentWillUnmount'); - instance.props = current.memoizedProps; - instance.state = current.memoizedState; - instance.componentWillUnmount(); - stopPhaseTimer(); - }; - - // Capture errors so they don't interrupt unmounting. - function safelyCallComponentWillUnmount(current, instance) { - { - invokeGuardedCallback$2(null, callComponentWillUnmountWithTimer, null, current, instance); - if (hasCaughtError$1()) { - var unmountError = clearCaughtError$1(); - captureError(current, unmountError); - } - } - } - - function safelyDetachRef(current) { - var ref = current.ref; - if (ref !== null) { - { - invokeGuardedCallback$2(null, ref, null, null); - if (hasCaughtError$1()) { - var refError = clearCaughtError$1(); - captureError(current, refError); - } - } - } - } - - function commitLifeCycles(current, finishedWork) { - switch (finishedWork.tag) { - case ClassComponent: - { - var instance = finishedWork.stateNode; - if (finishedWork.effectTag & Update) { - if (current === null) { - startPhaseTimer(finishedWork, 'componentDidMount'); - instance.props = finishedWork.memoizedProps; - instance.state = finishedWork.memoizedState; - instance.componentDidMount(); - stopPhaseTimer(); - } else { - var prevProps = current.memoizedProps; - var prevState = current.memoizedState; - startPhaseTimer(finishedWork, 'componentDidUpdate'); - instance.props = finishedWork.memoizedProps; - instance.state = finishedWork.memoizedState; - instance.componentDidUpdate(prevProps, prevState); - stopPhaseTimer(); - } - } - var updateQueue = finishedWork.updateQueue; - if (updateQueue !== null) { - commitCallbacks(updateQueue, instance); - } - return; - } - case HostRoot: - { - var _updateQueue = finishedWork.updateQueue; - if (_updateQueue !== null) { - var _instance = finishedWork.child !== null ? finishedWork.child.stateNode : null; - commitCallbacks(_updateQueue, _instance); - } - return; - } - case HostComponent: - { - var _instance2 = finishedWork.stateNode; - - // Renderers may schedule work to be done after host components are mounted - // (eg DOM renderer may schedule auto-focus for inputs and form controls). - // These effects should only be committed when components are first mounted, - // aka when there is no current/alternate. - if (current === null && finishedWork.effectTag & Update) { - var type = finishedWork.type; - var props = finishedWork.memoizedProps; - commitMount(_instance2, type, props, finishedWork); - } - - return; - } - case HostText: - { - // We have no life-cycles associated with text. - return; - } - case HostPortal: - { - // We have no life-cycles associated with portals. - return; - } - default: - { - invariant(false, 'This unit of work tag should not have side-effects. This error is likely caused by a bug in React. Please file an issue.'); - } - } - } - - function commitAttachRef(finishedWork) { - var ref = finishedWork.ref; - if (ref !== null) { - var instance = finishedWork.stateNode; - switch (finishedWork.tag) { - case HostComponent: - ref(getPublicInstance(instance)); - break; - default: - ref(instance); - } - } - } - - function commitDetachRef(current) { - var currentRef = current.ref; - if (currentRef !== null) { - currentRef(null); - } - } - - // User-originating errors (lifecycles and refs) should not interrupt - // deletion, so don't let them throw. Host-originating errors should - // interrupt deletion, so it's okay - function commitUnmount(current) { - if (typeof onCommitUnmount === 'function') { - onCommitUnmount(current); - } - - switch (current.tag) { - case ClassComponent: - { - safelyDetachRef(current); - var instance = current.stateNode; - if (typeof instance.componentWillUnmount === 'function') { - safelyCallComponentWillUnmount(current, instance); - } - return; - } - case HostComponent: - { - safelyDetachRef(current); - return; - } - case CallComponent: - { - commitNestedUnmounts(current.stateNode); - return; - } - case HostPortal: - { - // TODO: this is recursive. - // We are also not using this parent because - // the portal will get pushed immediately. - if (enableMutatingReconciler && mutation) { - unmountHostComponents(current); - } else if (enablePersistentReconciler && persistence) { - emptyPortalContainer(current); - } - return; - } - } - } - - function commitNestedUnmounts(root) { - // While we're inside a removed host node we don't want to call - // removeChild on the inner nodes because they're removed by the top - // call anyway. We also want to call componentWillUnmount on all - // composites before this host node is removed from the tree. Therefore - var node = root; - while (true) { - commitUnmount(node); - // Visit children because they may contain more composite or host nodes. - // Skip portals because commitUnmount() currently visits them recursively. - if (node.child !== null && ( - // If we use mutation we drill down into portals using commitUnmount above. - // If we don't use mutation we drill down into portals here instead. - !mutation || node.tag !== HostPortal)) { - node.child['return'] = node; - node = node.child; - continue; - } - if (node === root) { - return; - } - while (node.sibling === null) { - if (node['return'] === null || node['return'] === root) { - return; - } - node = node['return']; - } - node.sibling['return'] = node['return']; - node = node.sibling; - } - } - - function detachFiber(current) { - // Cut off the return pointers to disconnect it from the tree. Ideally, we - // should clear the child pointer of the parent alternate to let this - // get GC:ed but we don't know which for sure which parent is the current - // one so we'll settle for GC:ing the subtree of this child. This child - // itself will be GC:ed when the parent updates the next time. - current['return'] = null; - current.child = null; - if (current.alternate) { - current.alternate.child = null; - current.alternate['return'] = null; - } - } - - if (!mutation) { - var commitContainer = void 0; - if (persistence) { - var replaceContainerChildren = persistence.replaceContainerChildren, - createContainerChildSet = persistence.createContainerChildSet; - - var emptyPortalContainer = function (current) { - var portal = current.stateNode; - var containerInfo = portal.containerInfo; - - var emptyChildSet = createContainerChildSet(containerInfo); - replaceContainerChildren(containerInfo, emptyChildSet); - }; - commitContainer = function (finishedWork) { - switch (finishedWork.tag) { - case ClassComponent: - { - return; - } - case HostComponent: - { - return; - } - case HostText: - { - return; - } - case HostRoot: - case HostPortal: - { - var portalOrRoot = finishedWork.stateNode; - var containerInfo = portalOrRoot.containerInfo, - _pendingChildren = portalOrRoot.pendingChildren; - - replaceContainerChildren(containerInfo, _pendingChildren); - return; - } - default: - { - invariant(false, 'This unit of work tag should not have side-effects. This error is likely caused by a bug in React. Please file an issue.'); - } - } - }; - } else { - commitContainer = function (finishedWork) { - // Noop - }; - } - if (enablePersistentReconciler || enableNoopReconciler) { - return { - commitResetTextContent: function (finishedWork) {}, - commitPlacement: function (finishedWork) {}, - commitDeletion: function (current) { - // Detach refs and call componentWillUnmount() on the whole subtree. - commitNestedUnmounts(current); - detachFiber(current); - }, - commitWork: function (current, finishedWork) { - commitContainer(finishedWork); - }, - - commitLifeCycles: commitLifeCycles, - commitAttachRef: commitAttachRef, - commitDetachRef: commitDetachRef - }; - } else if (persistence) { - invariant(false, 'Persistent reconciler is disabled.'); - } else { - invariant(false, 'Noop reconciler is disabled.'); - } - } - var commitMount = mutation.commitMount, - commitUpdate = mutation.commitUpdate, - resetTextContent = mutation.resetTextContent, - commitTextUpdate = mutation.commitTextUpdate, - appendChild = mutation.appendChild, - appendChildToContainer = mutation.appendChildToContainer, - insertBefore = mutation.insertBefore, - insertInContainerBefore = mutation.insertInContainerBefore, - removeChild = mutation.removeChild, - removeChildFromContainer = mutation.removeChildFromContainer; - - - function getHostParentFiber(fiber) { - var parent = fiber['return']; - while (parent !== null) { - if (isHostParent(parent)) { - return parent; - } - parent = parent['return']; - } - invariant(false, 'Expected to find a host parent. This error is likely caused by a bug in React. Please file an issue.'); - } - - function isHostParent(fiber) { - return fiber.tag === HostComponent || fiber.tag === HostRoot || fiber.tag === HostPortal; - } - - function getHostSibling(fiber) { - // We're going to search forward into the tree until we find a sibling host - // node. Unfortunately, if multiple insertions are done in a row we have to - // search past them. This leads to exponential search for the next sibling. - var node = fiber; - siblings: while (true) { - // If we didn't find anything, let's try the next sibling. - while (node.sibling === null) { - if (node['return'] === null || isHostParent(node['return'])) { - // If we pop out of the root or hit the parent the fiber we are the - // last sibling. - return null; - } - node = node['return']; - } - node.sibling['return'] = node['return']; - node = node.sibling; - while (node.tag !== HostComponent && node.tag !== HostText) { - // If it is not host node and, we might have a host node inside it. - // Try to search down until we find one. - if (node.effectTag & Placement) { - // If we don't have a child, try the siblings instead. - continue siblings; - } - // If we don't have a child, try the siblings instead. - // We also skip portals because they are not part of this host tree. - if (node.child === null || node.tag === HostPortal) { - continue siblings; - } else { - node.child['return'] = node; - node = node.child; - } - } - // Check if this host node is stable or about to be placed. - if (!(node.effectTag & Placement)) { - // Found it! - return node.stateNode; - } - } - } - - function commitPlacement(finishedWork) { - // Recursively insert all host nodes into the parent. - var parentFiber = getHostParentFiber(finishedWork); - var parent = void 0; - var isContainer = void 0; - switch (parentFiber.tag) { - case HostComponent: - parent = parentFiber.stateNode; - isContainer = false; - break; - case HostRoot: - parent = parentFiber.stateNode.containerInfo; - isContainer = true; - break; - case HostPortal: - parent = parentFiber.stateNode.containerInfo; - isContainer = true; - break; - default: - invariant(false, 'Invalid host parent fiber. This error is likely caused by a bug in React. Please file an issue.'); - } - if (parentFiber.effectTag & ContentReset) { - // Reset the text content of the parent before doing any insertions - resetTextContent(parent); - // Clear ContentReset from the effect tag - parentFiber.effectTag &= ~ContentReset; - } - - var before = getHostSibling(finishedWork); - // We only have the top Fiber that was inserted but we need recurse down its - // children to find all the terminal nodes. - var node = finishedWork; - while (true) { - if (node.tag === HostComponent || node.tag === HostText) { - if (before) { - if (isContainer) { - insertInContainerBefore(parent, node.stateNode, before); - } else { - insertBefore(parent, node.stateNode, before); - } - } else { - if (isContainer) { - appendChildToContainer(parent, node.stateNode); - } else { - appendChild(parent, node.stateNode); - } - } - } else if (node.tag === HostPortal) { - // If the insertion itself is a portal, then we don't want to traverse - // down its children. Instead, we'll get insertions from each child in - // the portal directly. - } else if (node.child !== null) { - node.child['return'] = node; - node = node.child; - continue; - } - if (node === finishedWork) { - return; - } - while (node.sibling === null) { - if (node['return'] === null || node['return'] === finishedWork) { - return; - } - node = node['return']; - } - node.sibling['return'] = node['return']; - node = node.sibling; - } - } - - function unmountHostComponents(current) { - // We only have the top Fiber that was inserted but we need recurse down its - var node = current; - - // Each iteration, currentParent is populated with node's host parent if not - // currentParentIsValid. - var currentParentIsValid = false; - var currentParent = void 0; - var currentParentIsContainer = void 0; - - while (true) { - if (!currentParentIsValid) { - var parent = node['return']; - findParent: while (true) { - !(parent !== null) ? invariant(false, 'Expected to find a host parent. This error is likely caused by a bug in React. Please file an issue.') : void 0; - switch (parent.tag) { - case HostComponent: - currentParent = parent.stateNode; - currentParentIsContainer = false; - break findParent; - case HostRoot: - currentParent = parent.stateNode.containerInfo; - currentParentIsContainer = true; - break findParent; - case HostPortal: - currentParent = parent.stateNode.containerInfo; - currentParentIsContainer = true; - break findParent; - } - parent = parent['return']; - } - currentParentIsValid = true; - } - - if (node.tag === HostComponent || node.tag === HostText) { - commitNestedUnmounts(node); - // After all the children have unmounted, it is now safe to remove the - // node from the tree. - if (currentParentIsContainer) { - removeChildFromContainer(currentParent, node.stateNode); - } else { - removeChild(currentParent, node.stateNode); - } - // Don't visit children because we already visited them. - } else if (node.tag === HostPortal) { - // When we go into a portal, it becomes the parent to remove from. - // We will reassign it back when we pop the portal on the way up. - currentParent = node.stateNode.containerInfo; - // Visit children because portals might contain host components. - if (node.child !== null) { - node.child['return'] = node; - node = node.child; - continue; - } - } else { - commitUnmount(node); - // Visit children because we may find more host components below. - if (node.child !== null) { - node.child['return'] = node; - node = node.child; - continue; - } - } - if (node === current) { - return; - } - while (node.sibling === null) { - if (node['return'] === null || node['return'] === current) { - return; - } - node = node['return']; - if (node.tag === HostPortal) { - // When we go out of the portal, we need to restore the parent. - // Since we don't keep a stack of them, we will search for it. - currentParentIsValid = false; - } - } - node.sibling['return'] = node['return']; - node = node.sibling; - } - } - - function commitDeletion(current) { - // Recursively delete all host nodes from the parent. - // Detach refs and call componentWillUnmount() on the whole subtree. - unmountHostComponents(current); - detachFiber(current); - } - - function commitWork(current, finishedWork) { - switch (finishedWork.tag) { - case ClassComponent: - { - return; - } - case HostComponent: - { - var instance = finishedWork.stateNode; - if (instance != null) { - // Commit the work prepared earlier. - var newProps = finishedWork.memoizedProps; - // For hydration we reuse the update path but we treat the oldProps - // as the newProps. The updatePayload will contain the real change in - // this case. - var oldProps = current !== null ? current.memoizedProps : newProps; - var type = finishedWork.type; - // TODO: Type the updateQueue to be specific to host components. - var updatePayload = finishedWork.updateQueue; - finishedWork.updateQueue = null; - if (updatePayload !== null) { - commitUpdate(instance, updatePayload, type, oldProps, newProps, finishedWork); - } - } - return; - } - case HostText: - { - !(finishedWork.stateNode !== null) ? invariant(false, 'This should have a text node initialized. This error is likely caused by a bug in React. Please file an issue.') : void 0; - var textInstance = finishedWork.stateNode; - var newText = finishedWork.memoizedProps; - // For hydration we reuse the update path but we treat the oldProps - // as the newProps. The updatePayload will contain the real change in - // this case. - var oldText = current !== null ? current.memoizedProps : newText; - commitTextUpdate(textInstance, oldText, newText); - return; - } - case HostRoot: - { - return; - } - default: - { - invariant(false, 'This unit of work tag should not have side-effects. This error is likely caused by a bug in React. Please file an issue.'); - } - } - } - - function commitResetTextContent(current) { - resetTextContent(current.stateNode); - } - - if (enableMutatingReconciler) { - return { - commitResetTextContent: commitResetTextContent, - commitPlacement: commitPlacement, - commitDeletion: commitDeletion, - commitWork: commitWork, - commitLifeCycles: commitLifeCycles, - commitAttachRef: commitAttachRef, - commitDetachRef: commitDetachRef - }; - } else { - invariant(false, 'Mutating reconciler is disabled.'); - } -}; - -var NO_CONTEXT = {}; - -var ReactFiberHostContext = function (config) { - var getChildHostContext = config.getChildHostContext, - getRootHostContext = config.getRootHostContext; - - - var contextStackCursor = createCursor(NO_CONTEXT); - var contextFiberStackCursor = createCursor(NO_CONTEXT); - var rootInstanceStackCursor = createCursor(NO_CONTEXT); - - function requiredContext(c) { - !(c !== NO_CONTEXT) ? invariant(false, 'Expected host context to exist. This error is likely caused by a bug in React. Please file an issue.') : void 0; - return c; - } - - function getRootHostContainer() { - var rootInstance = requiredContext(rootInstanceStackCursor.current); - return rootInstance; - } - - function pushHostContainer(fiber, nextRootInstance) { - // Push current root instance onto the stack; - // This allows us to reset root when portals are popped. - push(rootInstanceStackCursor, nextRootInstance, fiber); - - var nextRootContext = getRootHostContext(nextRootInstance); - - // Track the context and the Fiber that provided it. - // This enables us to pop only Fibers that provide unique contexts. - push(contextFiberStackCursor, fiber, fiber); - push(contextStackCursor, nextRootContext, fiber); - } - - function popHostContainer(fiber) { - pop(contextStackCursor, fiber); - pop(contextFiberStackCursor, fiber); - pop(rootInstanceStackCursor, fiber); - } - - function getHostContext() { - var context = requiredContext(contextStackCursor.current); - return context; - } - - function pushHostContext(fiber) { - var rootInstance = requiredContext(rootInstanceStackCursor.current); - var context = requiredContext(contextStackCursor.current); - var nextContext = getChildHostContext(context, fiber.type, rootInstance); - - // Don't push this Fiber's context unless it's unique. - if (context === nextContext) { - return; - } - - // Track the context and the Fiber that provided it. - // This enables us to pop only Fibers that provide unique contexts. - push(contextFiberStackCursor, fiber, fiber); - push(contextStackCursor, nextContext, fiber); - } - - function popHostContext(fiber) { - // Do not pop unless this Fiber provided the current context. - // pushHostContext() only pushes Fibers that provide unique contexts. - if (contextFiberStackCursor.current !== fiber) { - return; - } - - pop(contextStackCursor, fiber); - pop(contextFiberStackCursor, fiber); - } - - function resetHostContainer() { - contextStackCursor.current = NO_CONTEXT; - rootInstanceStackCursor.current = NO_CONTEXT; - } - - return { - getHostContext: getHostContext, - getRootHostContainer: getRootHostContainer, - popHostContainer: popHostContainer, - popHostContext: popHostContext, - pushHostContainer: pushHostContainer, - pushHostContext: pushHostContext, - resetHostContainer: resetHostContainer - }; -}; - -var ReactFiberHydrationContext = function (config) { - var shouldSetTextContent = config.shouldSetTextContent, - hydration = config.hydration; - - // If this doesn't have hydration mode. - - if (!hydration) { - return { - enterHydrationState: function () { - return false; - }, - resetHydrationState: function () {}, - tryToClaimNextHydratableInstance: function () {}, - prepareToHydrateHostInstance: function () { - invariant(false, 'Expected prepareToHydrateHostInstance() to never be called. This error is likely caused by a bug in React. Please file an issue.'); - }, - prepareToHydrateHostTextInstance: function () { - invariant(false, 'Expected prepareToHydrateHostTextInstance() to never be called. This error is likely caused by a bug in React. Please file an issue.'); - }, - popHydrationState: function (fiber) { - return false; - } - }; - } - - var canHydrateInstance = hydration.canHydrateInstance, - canHydrateTextInstance = hydration.canHydrateTextInstance, - getNextHydratableSibling = hydration.getNextHydratableSibling, - getFirstHydratableChild = hydration.getFirstHydratableChild, - hydrateInstance = hydration.hydrateInstance, - hydrateTextInstance = hydration.hydrateTextInstance, - didNotMatchHydratedContainerTextInstance = hydration.didNotMatchHydratedContainerTextInstance, - didNotMatchHydratedTextInstance = hydration.didNotMatchHydratedTextInstance, - didNotHydrateContainerInstance = hydration.didNotHydrateContainerInstance, - didNotHydrateInstance = hydration.didNotHydrateInstance, - didNotFindHydratableContainerInstance = hydration.didNotFindHydratableContainerInstance, - didNotFindHydratableContainerTextInstance = hydration.didNotFindHydratableContainerTextInstance, - didNotFindHydratableInstance = hydration.didNotFindHydratableInstance, - didNotFindHydratableTextInstance = hydration.didNotFindHydratableTextInstance; - - // The deepest Fiber on the stack involved in a hydration context. - // This may have been an insertion or a hydration. - - var hydrationParentFiber = null; - var nextHydratableInstance = null; - var isHydrating = false; - - function enterHydrationState(fiber) { - var parentInstance = fiber.stateNode.containerInfo; - nextHydratableInstance = getFirstHydratableChild(parentInstance); - hydrationParentFiber = fiber; - isHydrating = true; - return true; - } - - function deleteHydratableInstance(returnFiber, instance) { - { - switch (returnFiber.tag) { - case HostRoot: - didNotHydrateContainerInstance(returnFiber.stateNode.containerInfo, instance); - break; - case HostComponent: - didNotHydrateInstance(returnFiber.type, returnFiber.memoizedProps, returnFiber.stateNode, instance); - break; - } - } - - var childToDelete = createFiberFromHostInstanceForDeletion(); - childToDelete.stateNode = instance; - childToDelete['return'] = returnFiber; - childToDelete.effectTag = Deletion; - - // This might seem like it belongs on progressedFirstDeletion. However, - // these children are not part of the reconciliation list of children. - // Even if we abort and rereconcile the children, that will try to hydrate - // again and the nodes are still in the host tree so these will be - // recreated. - if (returnFiber.lastEffect !== null) { - returnFiber.lastEffect.nextEffect = childToDelete; - returnFiber.lastEffect = childToDelete; - } else { - returnFiber.firstEffect = returnFiber.lastEffect = childToDelete; - } - } - - function insertNonHydratedInstance(returnFiber, fiber) { - fiber.effectTag |= Placement; - { - switch (returnFiber.tag) { - case HostRoot: - { - var parentContainer = returnFiber.stateNode.containerInfo; - switch (fiber.tag) { - case HostComponent: - var type = fiber.type; - var props = fiber.pendingProps; - didNotFindHydratableContainerInstance(parentContainer, type, props); - break; - case HostText: - var text = fiber.pendingProps; - didNotFindHydratableContainerTextInstance(parentContainer, text); - break; - } - break; - } - case HostComponent: - { - var parentType = returnFiber.type; - var parentProps = returnFiber.memoizedProps; - var parentInstance = returnFiber.stateNode; - switch (fiber.tag) { - case HostComponent: - var _type = fiber.type; - var _props = fiber.pendingProps; - didNotFindHydratableInstance(parentType, parentProps, parentInstance, _type, _props); - break; - case HostText: - var _text = fiber.pendingProps; - didNotFindHydratableTextInstance(parentType, parentProps, parentInstance, _text); - break; - } - break; - } - default: - return; - } - } - } - - function tryHydrate(fiber, nextInstance) { - switch (fiber.tag) { - case HostComponent: - { - var type = fiber.type; - var props = fiber.pendingProps; - var instance = canHydrateInstance(nextInstance, type, props); - if (instance !== null) { - fiber.stateNode = instance; - return true; - } - return false; - } - case HostText: - { - var text = fiber.pendingProps; - var textInstance = canHydrateTextInstance(nextInstance, text); - if (textInstance !== null) { - fiber.stateNode = textInstance; - return true; - } - return false; - } - default: - return false; - } - } - - function tryToClaimNextHydratableInstance(fiber) { - if (!isHydrating) { - return; - } - var nextInstance = nextHydratableInstance; - if (!nextInstance) { - // Nothing to hydrate. Make it an insertion. - insertNonHydratedInstance(hydrationParentFiber, fiber); - isHydrating = false; - hydrationParentFiber = fiber; - return; - } - if (!tryHydrate(fiber, nextInstance)) { - // If we can't hydrate this instance let's try the next one. - // We use this as a heuristic. It's based on intuition and not data so it - // might be flawed or unnecessary. - nextInstance = getNextHydratableSibling(nextInstance); - if (!nextInstance || !tryHydrate(fiber, nextInstance)) { - // Nothing to hydrate. Make it an insertion. - insertNonHydratedInstance(hydrationParentFiber, fiber); - isHydrating = false; - hydrationParentFiber = fiber; - return; - } - // We matched the next one, we'll now assume that the first one was - // superfluous and we'll delete it. Since we can't eagerly delete it - // we'll have to schedule a deletion. To do that, this node needs a dummy - // fiber associated with it. - deleteHydratableInstance(hydrationParentFiber, nextHydratableInstance); - } - hydrationParentFiber = fiber; - nextHydratableInstance = getFirstHydratableChild(nextInstance); - } - - function prepareToHydrateHostInstance(fiber, rootContainerInstance, hostContext) { - var instance = fiber.stateNode; - var updatePayload = hydrateInstance(instance, fiber.type, fiber.memoizedProps, rootContainerInstance, hostContext, fiber); - // TODO: Type this specific to this type of component. - fiber.updateQueue = updatePayload; - // If the update payload indicates that there is a change or if there - // is a new ref we mark this as an update. - if (updatePayload !== null) { - return true; - } - return false; - } - - function prepareToHydrateHostTextInstance(fiber) { - var textInstance = fiber.stateNode; - var textContent = fiber.memoizedProps; - var shouldUpdate = hydrateTextInstance(textInstance, textContent, fiber); - { - if (shouldUpdate) { - // We assume that prepareToHydrateHostTextInstance is called in a context where the - // hydration parent is the parent host component of this host text. - var returnFiber = hydrationParentFiber; - if (returnFiber !== null) { - switch (returnFiber.tag) { - case HostRoot: - { - var parentContainer = returnFiber.stateNode.containerInfo; - didNotMatchHydratedContainerTextInstance(parentContainer, textInstance, textContent); - break; - } - case HostComponent: - { - var parentType = returnFiber.type; - var parentProps = returnFiber.memoizedProps; - var parentInstance = returnFiber.stateNode; - didNotMatchHydratedTextInstance(parentType, parentProps, parentInstance, textInstance, textContent); - break; - } - } - } - } - } - return shouldUpdate; - } - - function popToNextHostParent(fiber) { - var parent = fiber['return']; - while (parent !== null && parent.tag !== HostComponent && parent.tag !== HostRoot) { - parent = parent['return']; - } - hydrationParentFiber = parent; - } - - function popHydrationState(fiber) { - if (fiber !== hydrationParentFiber) { - // We're deeper than the current hydration context, inside an inserted - // tree. - return false; - } - if (!isHydrating) { - // If we're not currently hydrating but we're in a hydration context, then - // we were an insertion and now need to pop up reenter hydration of our - // siblings. - popToNextHostParent(fiber); - isHydrating = true; - return false; - } - - var type = fiber.type; - - // If we have any remaining hydratable nodes, we need to delete them now. - // We only do this deeper than head and body since they tend to have random - // other nodes in them. We also ignore components with pure text content in - // side of them. - // TODO: Better heuristic. - if (fiber.tag !== HostComponent || type !== 'head' && type !== 'body' && !shouldSetTextContent(type, fiber.memoizedProps)) { - var nextInstance = nextHydratableInstance; - while (nextInstance) { - deleteHydratableInstance(fiber, nextInstance); - nextInstance = getNextHydratableSibling(nextInstance); - } - } - - popToNextHostParent(fiber); - nextHydratableInstance = hydrationParentFiber ? getNextHydratableSibling(fiber.stateNode) : null; - return true; - } - - function resetHydrationState() { - hydrationParentFiber = null; - nextHydratableInstance = null; - isHydrating = false; - } - - return { - enterHydrationState: enterHydrationState, - resetHydrationState: resetHydrationState, - tryToClaimNextHydratableInstance: tryToClaimNextHydratableInstance, - prepareToHydrateHostInstance: prepareToHydrateHostInstance, - prepareToHydrateHostTextInstance: prepareToHydrateHostTextInstance, - popHydrationState: popHydrationState - }; -}; - -// This lets us hook into Fiber to debug what it's doing. -// See https://github.com/facebook/react/pull/8033. -// This is not part of the public API, not even for React DevTools. -// You may only inject a debugTool if you work on React Fiber itself. -var ReactFiberInstrumentation = { - debugTool: null -}; - -var ReactFiberInstrumentation_1 = ReactFiberInstrumentation; - -var defaultShowDialog = function (capturedError) { - return true; -}; - -var showDialog = defaultShowDialog; - -function logCapturedError(capturedError) { - var logError = showDialog(capturedError); - - // Allow injected showDialog() to prevent default console.error logging. - // This enables renderers like ReactNative to better manage redbox behavior. - if (logError === false) { - return; - } - - var error = capturedError.error; - var suppressLogging = error && error.suppressReactErrorLogging; - if (suppressLogging) { - return; - } - - { - var componentName = capturedError.componentName, - componentStack = capturedError.componentStack, - errorBoundaryName = capturedError.errorBoundaryName, - errorBoundaryFound = capturedError.errorBoundaryFound, - willRetry = capturedError.willRetry; - - - var componentNameMessage = componentName ? 'The above error occurred in the <' + componentName + '> component:' : 'The above error occurred in one of your React components:'; - - var errorBoundaryMessage = void 0; - // errorBoundaryFound check is sufficient; errorBoundaryName check is to satisfy Flow. - if (errorBoundaryFound && errorBoundaryName) { - if (willRetry) { - errorBoundaryMessage = 'React will try to recreate this component tree from scratch ' + ('using the error boundary you provided, ' + errorBoundaryName + '.'); - } else { - errorBoundaryMessage = 'This error was initially handled by the error boundary ' + errorBoundaryName + '.\n' + 'Recreating the tree from scratch failed so React will unmount the tree.'; - } - } else { - errorBoundaryMessage = 'Consider adding an error boundary to your tree to customize error handling behavior.\n' + 'Visit https://fb.me/react-error-boundaries to learn more about error boundaries.'; - } - var combinedMessage = '' + componentNameMessage + componentStack + '\n\n' + ('' + errorBoundaryMessage); - - // In development, we provide our own message with just the component stack. - // We don't include the original error message and JS stack because the browser - // has already printed it. Even if the application swallows the error, it is still - // displayed by the browser thanks to the DEV-only fake event trick in ReactErrorUtils. - console.error(combinedMessage); - } -} - -var invokeGuardedCallback$1 = ReactErrorUtils.invokeGuardedCallback; -var hasCaughtError = ReactErrorUtils.hasCaughtError; -var clearCaughtError = ReactErrorUtils.clearCaughtError; - - -{ - var didWarnAboutStateTransition = false; - var didWarnSetStateChildContext = false; - var didWarnStateUpdateForUnmountedComponent = {}; - - var warnAboutUpdateOnUnmounted = function (fiber) { - var componentName = getComponentName(fiber) || 'ReactClass'; - if (didWarnStateUpdateForUnmountedComponent[componentName]) { - return; - } - warning(false, 'Can only update a mounted or mounting ' + 'component. This usually means you called setState, replaceState, ' + 'or forceUpdate on an unmounted component. This is a no-op.\n\nPlease ' + 'check the code for the %s component.', componentName); - didWarnStateUpdateForUnmountedComponent[componentName] = true; - }; - - var warnAboutInvalidUpdates = function (instance) { - switch (ReactDebugCurrentFiber.phase) { - case 'getChildContext': - if (didWarnSetStateChildContext) { - return; - } - warning(false, 'setState(...): Cannot call setState() inside getChildContext()'); - didWarnSetStateChildContext = true; - break; - case 'render': - if (didWarnAboutStateTransition) { - return; - } - warning(false, 'Cannot update during an existing state transition (such as within ' + "`render` or another component's constructor). Render methods should " + 'be a pure function of props and state; constructor side-effects are ' + 'an anti-pattern, but can be moved to `componentWillMount`.'); - didWarnAboutStateTransition = true; - break; - } - }; -} - -var ReactFiberScheduler = function (config) { - var hostContext = ReactFiberHostContext(config); - var hydrationContext = ReactFiberHydrationContext(config); - var popHostContainer = hostContext.popHostContainer, - popHostContext = hostContext.popHostContext, - resetHostContainer = hostContext.resetHostContainer; - - var _ReactFiberBeginWork = ReactFiberBeginWork(config, hostContext, hydrationContext, scheduleWork, computeExpirationForFiber), - beginWork = _ReactFiberBeginWork.beginWork, - beginFailedWork = _ReactFiberBeginWork.beginFailedWork; - - var _ReactFiberCompleteWo = ReactFiberCompleteWork(config, hostContext, hydrationContext), - completeWork = _ReactFiberCompleteWo.completeWork; - - var _ReactFiberCommitWork = ReactFiberCommitWork(config, captureError), - commitResetTextContent = _ReactFiberCommitWork.commitResetTextContent, - commitPlacement = _ReactFiberCommitWork.commitPlacement, - commitDeletion = _ReactFiberCommitWork.commitDeletion, - commitWork = _ReactFiberCommitWork.commitWork, - commitLifeCycles = _ReactFiberCommitWork.commitLifeCycles, - commitAttachRef = _ReactFiberCommitWork.commitAttachRef, - commitDetachRef = _ReactFiberCommitWork.commitDetachRef; - - var now = config.now, - scheduleDeferredCallback = config.scheduleDeferredCallback, - cancelDeferredCallback = config.cancelDeferredCallback, - useSyncScheduling = config.useSyncScheduling, - prepareForCommit = config.prepareForCommit, - resetAfterCommit = config.resetAfterCommit; - - // Represents the current time in ms. - - var startTime = now(); - var mostRecentCurrentTime = msToExpirationTime(0); - - // Represents the expiration time that incoming updates should use. (If this - // is NoWork, use the default strategy: async updates in async mode, sync - // updates in sync mode.) - var expirationContext = NoWork; - - var isWorking = false; - - // The next work in progress fiber that we're currently working on. - var nextUnitOfWork = null; - var nextRoot = null; - // The time at which we're currently rendering work. - var nextRenderExpirationTime = NoWork; - - // The next fiber with an effect that we're currently committing. - var nextEffect = null; - - // Keep track of which fibers have captured an error that need to be handled. - // Work is removed from this collection after componentDidCatch is called. - var capturedErrors = null; - // Keep track of which fibers have failed during the current batch of work. - // This is a different set than capturedErrors, because it is not reset until - // the end of the batch. This is needed to propagate errors correctly if a - // subtree fails more than once. - var failedBoundaries = null; - // Error boundaries that captured an error during the current commit. - var commitPhaseBoundaries = null; - var firstUncaughtError = null; - var didFatal = false; - - var isCommitting = false; - var isUnmounting = false; - - // Used for performance tracking. - var interruptedBy = null; - - function resetContextStack() { - // Reset the stack - reset$1(); - // Reset the cursors - resetContext(); - resetHostContainer(); - } - - function commitAllHostEffects() { - while (nextEffect !== null) { - { - ReactDebugCurrentFiber.setCurrentFiber(nextEffect); - } - recordEffect(); - - var effectTag = nextEffect.effectTag; - if (effectTag & ContentReset) { - commitResetTextContent(nextEffect); - } - - if (effectTag & Ref) { - var current = nextEffect.alternate; - if (current !== null) { - commitDetachRef(current); - } - } - - // The following switch statement is only concerned about placement, - // updates, and deletions. To avoid needing to add a case for every - // possible bitmap value, we remove the secondary effects from the - // effect tag and switch on that value. - var primaryEffectTag = effectTag & ~(Callback | Err | ContentReset | Ref | PerformedWork); - switch (primaryEffectTag) { - case Placement: - { - commitPlacement(nextEffect); - // Clear the "placement" from effect tag so that we know that this is inserted, before - // any life-cycles like componentDidMount gets called. - // TODO: findDOMNode doesn't rely on this any more but isMounted - // does and isMounted is deprecated anyway so we should be able - // to kill this. - nextEffect.effectTag &= ~Placement; - break; - } - case PlacementAndUpdate: - { - // Placement - commitPlacement(nextEffect); - // Clear the "placement" from effect tag so that we know that this is inserted, before - // any life-cycles like componentDidMount gets called. - nextEffect.effectTag &= ~Placement; - - // Update - var _current = nextEffect.alternate; - commitWork(_current, nextEffect); - break; - } - case Update: - { - var _current2 = nextEffect.alternate; - commitWork(_current2, nextEffect); - break; - } - case Deletion: - { - isUnmounting = true; - commitDeletion(nextEffect); - isUnmounting = false; - break; - } - } - nextEffect = nextEffect.nextEffect; - } - - { - ReactDebugCurrentFiber.resetCurrentFiber(); - } - } - - function commitAllLifeCycles() { - while (nextEffect !== null) { - var effectTag = nextEffect.effectTag; - - if (effectTag & (Update | Callback)) { - recordEffect(); - var current = nextEffect.alternate; - commitLifeCycles(current, nextEffect); - } - - if (effectTag & Ref) { - recordEffect(); - commitAttachRef(nextEffect); - } - - if (effectTag & Err) { - recordEffect(); - commitErrorHandling(nextEffect); - } - - var next = nextEffect.nextEffect; - // Ensure that we clean these up so that we don't accidentally keep them. - // I'm not actually sure this matters because we can't reset firstEffect - // and lastEffect since they're on every node, not just the effectful - // ones. So we have to clean everything as we reuse nodes anyway. - nextEffect.nextEffect = null; - // Ensure that we reset the effectTag here so that we can rely on effect - // tags to reason about the current life-cycle. - nextEffect = next; - } - } - - function commitRoot(finishedWork) { - // We keep track of this so that captureError can collect any boundaries - // that capture an error during the commit phase. The reason these aren't - // local to this function is because errors that occur during cWU are - // captured elsewhere, to prevent the unmount from being interrupted. - isWorking = true; - isCommitting = true; - startCommitTimer(); - - var root = finishedWork.stateNode; - !(root.current !== finishedWork) ? invariant(false, 'Cannot commit the same tree as before. This is probably a bug related to the return field. This error is likely caused by a bug in React. Please file an issue.') : void 0; - root.isReadyForCommit = false; - - // Reset this to null before calling lifecycles - ReactCurrentOwner.current = null; - - var firstEffect = void 0; - if (finishedWork.effectTag > PerformedWork) { - // A fiber's effect list consists only of its children, not itself. So if - // the root has an effect, we need to add it to the end of the list. The - // resulting list is the set that would belong to the root's parent, if - // it had one; that is, all the effects in the tree including the root. - if (finishedWork.lastEffect !== null) { - finishedWork.lastEffect.nextEffect = finishedWork; - firstEffect = finishedWork.firstEffect; - } else { - firstEffect = finishedWork; - } - } else { - // There is no effect on the root. - firstEffect = finishedWork.firstEffect; - } - - prepareForCommit(); - - // Commit all the side-effects within a tree. We'll do this in two passes. - // The first pass performs all the host insertions, updates, deletions and - // ref unmounts. - nextEffect = firstEffect; - startCommitHostEffectsTimer(); - while (nextEffect !== null) { - var didError = false; - var _error = void 0; - { - invokeGuardedCallback$1(null, commitAllHostEffects, null); - if (hasCaughtError()) { - didError = true; - _error = clearCaughtError(); - } - } - if (didError) { - !(nextEffect !== null) ? invariant(false, 'Should have next effect. This error is likely caused by a bug in React. Please file an issue.') : void 0; - captureError(nextEffect, _error); - // Clean-up - if (nextEffect !== null) { - nextEffect = nextEffect.nextEffect; - } - } - } - stopCommitHostEffectsTimer(); - - resetAfterCommit(); - - // The work-in-progress tree is now the current tree. This must come after - // the first pass of the commit phase, so that the previous tree is still - // current during componentWillUnmount, but before the second pass, so that - // the finished work is current during componentDidMount/Update. - root.current = finishedWork; - - // In the second pass we'll perform all life-cycles and ref callbacks. - // Life-cycles happen as a separate pass so that all placements, updates, - // and deletions in the entire tree have already been invoked. - // This pass also triggers any renderer-specific initial effects. - nextEffect = firstEffect; - startCommitLifeCyclesTimer(); - while (nextEffect !== null) { - var _didError = false; - var _error2 = void 0; - { - invokeGuardedCallback$1(null, commitAllLifeCycles, null); - if (hasCaughtError()) { - _didError = true; - _error2 = clearCaughtError(); - } - } - if (_didError) { - !(nextEffect !== null) ? invariant(false, 'Should have next effect. This error is likely caused by a bug in React. Please file an issue.') : void 0; - captureError(nextEffect, _error2); - if (nextEffect !== null) { - nextEffect = nextEffect.nextEffect; - } - } - } - - isCommitting = false; - isWorking = false; - stopCommitLifeCyclesTimer(); - stopCommitTimer(); - if (typeof onCommitRoot === 'function') { - onCommitRoot(finishedWork.stateNode); - } - if (true && ReactFiberInstrumentation_1.debugTool) { - ReactFiberInstrumentation_1.debugTool.onCommitWork(finishedWork); - } - - // If we caught any errors during this commit, schedule their boundaries - // to update. - if (commitPhaseBoundaries) { - commitPhaseBoundaries.forEach(scheduleErrorRecovery); - commitPhaseBoundaries = null; - } - - if (firstUncaughtError !== null) { - var _error3 = firstUncaughtError; - firstUncaughtError = null; - onUncaughtError(_error3); - } - - var remainingTime = root.current.expirationTime; - - if (remainingTime === NoWork) { - capturedErrors = null; - failedBoundaries = null; - } - - return remainingTime; - } - - function resetExpirationTime(workInProgress, renderTime) { - if (renderTime !== Never && workInProgress.expirationTime === Never) { - // The children of this component are hidden. Don't bubble their - // expiration times. - return; - } - - // Check for pending updates. - var newExpirationTime = getUpdateExpirationTime(workInProgress); - - // TODO: Calls need to visit stateNode - - // Bubble up the earliest expiration time. - var child = workInProgress.child; - while (child !== null) { - if (child.expirationTime !== NoWork && (newExpirationTime === NoWork || newExpirationTime > child.expirationTime)) { - newExpirationTime = child.expirationTime; - } - child = child.sibling; - } - workInProgress.expirationTime = newExpirationTime; - } - - function completeUnitOfWork(workInProgress) { - while (true) { - // The current, flushed, state of this fiber is the alternate. - // Ideally nothing should rely on this, but relying on it here - // means that we don't need an additional field on the work in - // progress. - var current = workInProgress.alternate; - { - ReactDebugCurrentFiber.setCurrentFiber(workInProgress); - } - var next = completeWork(current, workInProgress, nextRenderExpirationTime); - { - ReactDebugCurrentFiber.resetCurrentFiber(); - } - - var returnFiber = workInProgress['return']; - var siblingFiber = workInProgress.sibling; - - resetExpirationTime(workInProgress, nextRenderExpirationTime); - - if (next !== null) { - stopWorkTimer(workInProgress); - if (true && ReactFiberInstrumentation_1.debugTool) { - ReactFiberInstrumentation_1.debugTool.onCompleteWork(workInProgress); - } - // If completing this work spawned new work, do that next. We'll come - // back here again. - return next; - } - - if (returnFiber !== null) { - // Append all the effects of the subtree and this fiber onto the effect - // list of the parent. The completion order of the children affects the - // side-effect order. - if (returnFiber.firstEffect === null) { - returnFiber.firstEffect = workInProgress.firstEffect; - } - if (workInProgress.lastEffect !== null) { - if (returnFiber.lastEffect !== null) { - returnFiber.lastEffect.nextEffect = workInProgress.firstEffect; - } - returnFiber.lastEffect = workInProgress.lastEffect; - } - - // If this fiber had side-effects, we append it AFTER the children's - // side-effects. We can perform certain side-effects earlier if - // needed, by doing multiple passes over the effect list. We don't want - // to schedule our own side-effect on our own list because if end up - // reusing children we'll schedule this effect onto itself since we're - // at the end. - var effectTag = workInProgress.effectTag; - // Skip both NoWork and PerformedWork tags when creating the effect list. - // PerformedWork effect is read by React DevTools but shouldn't be committed. - if (effectTag > PerformedWork) { - if (returnFiber.lastEffect !== null) { - returnFiber.lastEffect.nextEffect = workInProgress; - } else { - returnFiber.firstEffect = workInProgress; - } - returnFiber.lastEffect = workInProgress; - } - } - - stopWorkTimer(workInProgress); - if (true && ReactFiberInstrumentation_1.debugTool) { - ReactFiberInstrumentation_1.debugTool.onCompleteWork(workInProgress); - } - - if (siblingFiber !== null) { - // If there is more work to do in this returnFiber, do that next. - return siblingFiber; - } else if (returnFiber !== null) { - // If there's no more work in this returnFiber. Complete the returnFiber. - workInProgress = returnFiber; - continue; - } else { - // We've reached the root. - var root = workInProgress.stateNode; - root.isReadyForCommit = true; - return null; - } - } - - // Without this explicit null return Flow complains of invalid return type - // TODO Remove the above while(true) loop - // eslint-disable-next-line no-unreachable - return null; - } - - function performUnitOfWork(workInProgress) { - // The current, flushed, state of this fiber is the alternate. - // Ideally nothing should rely on this, but relying on it here - // means that we don't need an additional field on the work in - // progress. - var current = workInProgress.alternate; - - // See if beginning this work spawns more work. - startWorkTimer(workInProgress); - { - ReactDebugCurrentFiber.setCurrentFiber(workInProgress); - } - - var next = beginWork(current, workInProgress, nextRenderExpirationTime); - { - ReactDebugCurrentFiber.resetCurrentFiber(); - } - if (true && ReactFiberInstrumentation_1.debugTool) { - ReactFiberInstrumentation_1.debugTool.onBeginWork(workInProgress); - } - - if (next === null) { - // If this doesn't spawn new work, complete the current work. - next = completeUnitOfWork(workInProgress); - } - - ReactCurrentOwner.current = null; - - return next; - } - - function performFailedUnitOfWork(workInProgress) { - // The current, flushed, state of this fiber is the alternate. - // Ideally nothing should rely on this, but relying on it here - // means that we don't need an additional field on the work in - // progress. - var current = workInProgress.alternate; - - // See if beginning this work spawns more work. - startWorkTimer(workInProgress); - { - ReactDebugCurrentFiber.setCurrentFiber(workInProgress); - } - var next = beginFailedWork(current, workInProgress, nextRenderExpirationTime); - { - ReactDebugCurrentFiber.resetCurrentFiber(); - } - if (true && ReactFiberInstrumentation_1.debugTool) { - ReactFiberInstrumentation_1.debugTool.onBeginWork(workInProgress); - } - - if (next === null) { - // If this doesn't spawn new work, complete the current work. - next = completeUnitOfWork(workInProgress); - } - - ReactCurrentOwner.current = null; - - return next; - } - - function workLoop(expirationTime) { - if (capturedErrors !== null) { - // If there are unhandled errors, switch to the slow work loop. - // TODO: How to avoid this check in the fast path? Maybe the renderer - // could keep track of which roots have unhandled errors and call a - // forked version of renderRoot. - slowWorkLoopThatChecksForFailedWork(expirationTime); - return; - } - if (nextRenderExpirationTime === NoWork || nextRenderExpirationTime > expirationTime) { - return; - } - - if (nextRenderExpirationTime <= mostRecentCurrentTime) { - // Flush all expired work. - while (nextUnitOfWork !== null) { - nextUnitOfWork = performUnitOfWork(nextUnitOfWork); - } - } else { - // Flush asynchronous work until the deadline runs out of time. - while (nextUnitOfWork !== null && !shouldYield()) { - nextUnitOfWork = performUnitOfWork(nextUnitOfWork); - } - } - } - - function slowWorkLoopThatChecksForFailedWork(expirationTime) { - if (nextRenderExpirationTime === NoWork || nextRenderExpirationTime > expirationTime) { - return; - } - - if (nextRenderExpirationTime <= mostRecentCurrentTime) { - // Flush all expired work. - while (nextUnitOfWork !== null) { - if (hasCapturedError(nextUnitOfWork)) { - // Use a forked version of performUnitOfWork - nextUnitOfWork = performFailedUnitOfWork(nextUnitOfWork); - } else { - nextUnitOfWork = performUnitOfWork(nextUnitOfWork); - } - } - } else { - // Flush asynchronous work until the deadline runs out of time. - while (nextUnitOfWork !== null && !shouldYield()) { - if (hasCapturedError(nextUnitOfWork)) { - // Use a forked version of performUnitOfWork - nextUnitOfWork = performFailedUnitOfWork(nextUnitOfWork); - } else { - nextUnitOfWork = performUnitOfWork(nextUnitOfWork); - } - } - } - } - - function renderRootCatchBlock(root, failedWork, boundary, expirationTime) { - // We're going to restart the error boundary that captured the error. - // Conceptually, we're unwinding the stack. We need to unwind the - // context stack, too. - unwindContexts(failedWork, boundary); - - // Restart the error boundary using a forked version of - // performUnitOfWork that deletes the boundary's children. The entire - // failed subree will be unmounted. During the commit phase, a special - // lifecycle method is called on the error boundary, which triggers - // a re-render. - nextUnitOfWork = performFailedUnitOfWork(boundary); - - // Continue working. - workLoop(expirationTime); - } - - function renderRoot(root, expirationTime) { - !!isWorking ? invariant(false, 'renderRoot was called recursively. This error is likely caused by a bug in React. Please file an issue.') : void 0; - isWorking = true; - - // We're about to mutate the work-in-progress tree. If the root was pending - // commit, it no longer is: we'll need to complete it again. - root.isReadyForCommit = false; - - // Check if we're starting from a fresh stack, or if we're resuming from - // previously yielded work. - if (root !== nextRoot || expirationTime !== nextRenderExpirationTime || nextUnitOfWork === null) { - // Reset the stack and start working from the root. - resetContextStack(); - nextRoot = root; - nextRenderExpirationTime = expirationTime; - nextUnitOfWork = createWorkInProgress(nextRoot.current, null, expirationTime); - } - - startWorkLoopTimer(nextUnitOfWork); - - var didError = false; - var error = null; - { - invokeGuardedCallback$1(null, workLoop, null, expirationTime); - if (hasCaughtError()) { - didError = true; - error = clearCaughtError(); - } - } - - // An error was thrown during the render phase. - while (didError) { - if (didFatal) { - // This was a fatal error. Don't attempt to recover from it. - firstUncaughtError = error; - break; - } - - var failedWork = nextUnitOfWork; - if (failedWork === null) { - // An error was thrown but there's no current unit of work. This can - // happen during the commit phase if there's a bug in the renderer. - didFatal = true; - continue; - } - - // "Capture" the error by finding the nearest boundary. If there is no - // error boundary, we use the root. - var boundary = captureError(failedWork, error); - !(boundary !== null) ? invariant(false, 'Should have found an error boundary. This error is likely caused by a bug in React. Please file an issue.') : void 0; - - if (didFatal) { - // The error we just captured was a fatal error. This happens - // when the error propagates to the root more than once. - continue; - } - - didError = false; - error = null; - { - invokeGuardedCallback$1(null, renderRootCatchBlock, null, root, failedWork, boundary, expirationTime); - if (hasCaughtError()) { - didError = true; - error = clearCaughtError(); - continue; - } - } - // We're finished working. Exit the error loop. - break; - } - - var uncaughtError = firstUncaughtError; - - // We're done performing work. Time to clean up. - stopWorkLoopTimer(interruptedBy); - interruptedBy = null; - isWorking = false; - didFatal = false; - firstUncaughtError = null; - - if (uncaughtError !== null) { - onUncaughtError(uncaughtError); - } - - return root.isReadyForCommit ? root.current.alternate : null; - } - - // Returns the boundary that captured the error, or null if the error is ignored - function captureError(failedWork, error) { - // It is no longer valid because we exited the user code. - ReactCurrentOwner.current = null; - { - ReactDebugCurrentFiber.resetCurrentFiber(); - } - - // Search for the nearest error boundary. - var boundary = null; - - // Passed to logCapturedError() - var errorBoundaryFound = false; - var willRetry = false; - var errorBoundaryName = null; - - // Host containers are a special case. If the failed work itself is a host - // container, then it acts as its own boundary. In all other cases, we - // ignore the work itself and only search through the parents. - if (failedWork.tag === HostRoot) { - boundary = failedWork; - - if (isFailedBoundary(failedWork)) { - // If this root already failed, there must have been an error when - // attempting to unmount it. This is a worst-case scenario and - // should only be possible if there's a bug in the renderer. - didFatal = true; - } - } else { - var node = failedWork['return']; - while (node !== null && boundary === null) { - if (node.tag === ClassComponent) { - var instance = node.stateNode; - if (typeof instance.componentDidCatch === 'function') { - errorBoundaryFound = true; - errorBoundaryName = getComponentName(node); - - // Found an error boundary! - boundary = node; - willRetry = true; - } - } else if (node.tag === HostRoot) { - // Treat the root like a no-op error boundary - boundary = node; - } - - if (isFailedBoundary(node)) { - // This boundary is already in a failed state. - - // If we're currently unmounting, that means this error was - // thrown while unmounting a failed subtree. We should ignore - // the error. - if (isUnmounting) { - return null; - } - - // If we're in the commit phase, we should check to see if - // this boundary already captured an error during this commit. - // This case exists because multiple errors can be thrown during - // a single commit without interruption. - if (commitPhaseBoundaries !== null && (commitPhaseBoundaries.has(node) || node.alternate !== null && commitPhaseBoundaries.has(node.alternate))) { - // If so, we should ignore this error. - return null; - } - - // The error should propagate to the next boundary -— we keep looking. - boundary = null; - willRetry = false; - } - - node = node['return']; - } - } - - if (boundary !== null) { - // Add to the collection of failed boundaries. This lets us know that - // subsequent errors in this subtree should propagate to the next boundary. - if (failedBoundaries === null) { - failedBoundaries = new Set(); - } - failedBoundaries.add(boundary); - - // This method is unsafe outside of the begin and complete phases. - // We might be in the commit phase when an error is captured. - // The risk is that the return path from this Fiber may not be accurate. - // That risk is acceptable given the benefit of providing users more context. - var _componentStack = getStackAddendumByWorkInProgressFiber(failedWork); - var _componentName = getComponentName(failedWork); - - // Add to the collection of captured errors. This is stored as a global - // map of errors and their component stack location keyed by the boundaries - // that capture them. We mostly use this Map as a Set; it's a Map only to - // avoid adding a field to Fiber to store the error. - if (capturedErrors === null) { - capturedErrors = new Map(); - } - - var capturedError = { - componentName: _componentName, - componentStack: _componentStack, - error: error, - errorBoundary: errorBoundaryFound ? boundary.stateNode : null, - errorBoundaryFound: errorBoundaryFound, - errorBoundaryName: errorBoundaryName, - willRetry: willRetry - }; - - capturedErrors.set(boundary, capturedError); - - try { - logCapturedError(capturedError); - } catch (e) { - // Prevent cycle if logCapturedError() throws. - // A cycle may still occur if logCapturedError renders a component that throws. - var suppressLogging = e && e.suppressReactErrorLogging; - if (!suppressLogging) { - console.error(e); - } - } - - // If we're in the commit phase, defer scheduling an update on the - // boundary until after the commit is complete - if (isCommitting) { - if (commitPhaseBoundaries === null) { - commitPhaseBoundaries = new Set(); - } - commitPhaseBoundaries.add(boundary); - } else { - // Otherwise, schedule an update now. - // TODO: Is this actually necessary during the render phase? Is it - // possible to unwind and continue rendering at the same priority, - // without corrupting internal state? - scheduleErrorRecovery(boundary); - } - return boundary; - } else if (firstUncaughtError === null) { - // If no boundary is found, we'll need to throw the error - firstUncaughtError = error; - } - return null; - } - - function hasCapturedError(fiber) { - // TODO: capturedErrors should store the boundary instance, to avoid needing - // to check the alternate. - return capturedErrors !== null && (capturedErrors.has(fiber) || fiber.alternate !== null && capturedErrors.has(fiber.alternate)); - } - - function isFailedBoundary(fiber) { - // TODO: failedBoundaries should store the boundary instance, to avoid - // needing to check the alternate. - return failedBoundaries !== null && (failedBoundaries.has(fiber) || fiber.alternate !== null && failedBoundaries.has(fiber.alternate)); - } - - function commitErrorHandling(effectfulFiber) { - var capturedError = void 0; - if (capturedErrors !== null) { - capturedError = capturedErrors.get(effectfulFiber); - capturedErrors['delete'](effectfulFiber); - if (capturedError == null) { - if (effectfulFiber.alternate !== null) { - effectfulFiber = effectfulFiber.alternate; - capturedError = capturedErrors.get(effectfulFiber); - capturedErrors['delete'](effectfulFiber); - } - } - } - - !(capturedError != null) ? invariant(false, 'No error for given unit of work. This error is likely caused by a bug in React. Please file an issue.') : void 0; - - switch (effectfulFiber.tag) { - case ClassComponent: - var instance = effectfulFiber.stateNode; - - var info = { - componentStack: capturedError.componentStack - }; - - // Allow the boundary to handle the error, usually by scheduling - // an update to itself - instance.componentDidCatch(capturedError.error, info); - return; - case HostRoot: - if (firstUncaughtError === null) { - firstUncaughtError = capturedError.error; - } - return; - default: - invariant(false, 'Invalid type of work. This error is likely caused by a bug in React. Please file an issue.'); - } - } - - function unwindContexts(from, to) { - var node = from; - while (node !== null) { - switch (node.tag) { - case ClassComponent: - popContextProvider(node); - break; - case HostComponent: - popHostContext(node); - break; - case HostRoot: - popHostContainer(node); - break; - case HostPortal: - popHostContainer(node); - break; - } - if (node === to || node.alternate === to) { - stopFailedWorkTimer(node); - break; - } else { - stopWorkTimer(node); - } - node = node['return']; - } - } - - function computeAsyncExpiration() { - // Given the current clock time, returns an expiration time. We use rounding - // to batch like updates together. - // Should complete within ~1000ms. 1200ms max. - var currentTime = recalculateCurrentTime(); - var expirationMs = 1000; - var bucketSizeMs = 200; - return computeExpirationBucket(currentTime, expirationMs, bucketSizeMs); - } - - function computeExpirationForFiber(fiber) { - var expirationTime = void 0; - if (expirationContext !== NoWork) { - // An explicit expiration context was set; - expirationTime = expirationContext; - } else if (isWorking) { - if (isCommitting) { - // Updates that occur during the commit phase should have sync priority - // by default. - expirationTime = Sync; - } else { - // Updates during the render phase should expire at the same time as - // the work that is being rendered. - expirationTime = nextRenderExpirationTime; - } - } else { - // No explicit expiration context was set, and we're not currently - // performing work. Calculate a new expiration time. - if (useSyncScheduling && !(fiber.internalContextTag & AsyncUpdates)) { - // This is a sync update - expirationTime = Sync; - } else { - // This is an async update - expirationTime = computeAsyncExpiration(); - } - } - return expirationTime; - } - - function scheduleWork(fiber, expirationTime) { - return scheduleWorkImpl(fiber, expirationTime, false); - } - - function checkRootNeedsClearing(root, fiber, expirationTime) { - if (!isWorking && root === nextRoot && expirationTime < nextRenderExpirationTime) { - // Restart the root from the top. - if (nextUnitOfWork !== null) { - // This is an interruption. (Used for performance tracking.) - interruptedBy = fiber; - } - nextRoot = null; - nextUnitOfWork = null; - nextRenderExpirationTime = NoWork; - } - } - - function scheduleWorkImpl(fiber, expirationTime, isErrorRecovery) { - recordScheduleUpdate(); - - { - if (!isErrorRecovery && fiber.tag === ClassComponent) { - var instance = fiber.stateNode; - warnAboutInvalidUpdates(instance); - } - } - - var node = fiber; - while (node !== null) { - // Walk the parent path to the root and update each node's - // expiration time. - if (node.expirationTime === NoWork || node.expirationTime > expirationTime) { - node.expirationTime = expirationTime; - } - if (node.alternate !== null) { - if (node.alternate.expirationTime === NoWork || node.alternate.expirationTime > expirationTime) { - node.alternate.expirationTime = expirationTime; - } - } - if (node['return'] === null) { - if (node.tag === HostRoot) { - var root = node.stateNode; - - checkRootNeedsClearing(root, fiber, expirationTime); - requestWork(root, expirationTime); - checkRootNeedsClearing(root, fiber, expirationTime); - } else { - { - if (!isErrorRecovery && fiber.tag === ClassComponent) { - warnAboutUpdateOnUnmounted(fiber); - } - } - return; - } - } - node = node['return']; - } - } - - function scheduleErrorRecovery(fiber) { - scheduleWorkImpl(fiber, Sync, true); - } - - function recalculateCurrentTime() { - // Subtract initial time so it fits inside 32bits - var ms = now() - startTime; - mostRecentCurrentTime = msToExpirationTime(ms); - return mostRecentCurrentTime; - } - - function deferredUpdates(fn) { - var previousExpirationContext = expirationContext; - expirationContext = computeAsyncExpiration(); - try { - return fn(); - } finally { - expirationContext = previousExpirationContext; - } - } - - function syncUpdates(fn) { - var previousExpirationContext = expirationContext; - expirationContext = Sync; - try { - return fn(); - } finally { - expirationContext = previousExpirationContext; - } - } - - // TODO: Everything below this is written as if it has been lifted to the - // renderers. I'll do this in a follow-up. - - // Linked-list of roots - var firstScheduledRoot = null; - var lastScheduledRoot = null; - - var callbackExpirationTime = NoWork; - var callbackID = -1; - var isRendering = false; - var nextFlushedRoot = null; - var nextFlushedExpirationTime = NoWork; - var deadlineDidExpire = false; - var hasUnhandledError = false; - var unhandledError = null; - var deadline = null; - - var isBatchingUpdates = false; - var isUnbatchingUpdates = false; - - // Use these to prevent an infinite loop of nested updates - var NESTED_UPDATE_LIMIT = 1000; - var nestedUpdateCount = 0; - - var timeHeuristicForUnitOfWork = 1; - - function scheduleCallbackWithExpiration(expirationTime) { - if (callbackExpirationTime !== NoWork) { - // A callback is already scheduled. Check its expiration time (timeout). - if (expirationTime > callbackExpirationTime) { - // Existing callback has sufficient timeout. Exit. - return; - } else { - // Existing callback has insufficient timeout. Cancel and schedule a - // new one. - cancelDeferredCallback(callbackID); - } - // The request callback timer is already running. Don't start a new one. - } else { - startRequestCallbackTimer(); - } - - // Compute a timeout for the given expiration time. - var currentMs = now() - startTime; - var expirationMs = expirationTimeToMs(expirationTime); - var timeout = expirationMs - currentMs; - - callbackExpirationTime = expirationTime; - callbackID = scheduleDeferredCallback(performAsyncWork, { timeout: timeout }); - } - - // requestWork is called by the scheduler whenever a root receives an update. - // It's up to the renderer to call renderRoot at some point in the future. - function requestWork(root, expirationTime) { - if (nestedUpdateCount > NESTED_UPDATE_LIMIT) { - invariant(false, 'Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops.'); - } - - // Add the root to the schedule. - // Check if this root is already part of the schedule. - if (root.nextScheduledRoot === null) { - // This root is not already scheduled. Add it. - root.remainingExpirationTime = expirationTime; - if (lastScheduledRoot === null) { - firstScheduledRoot = lastScheduledRoot = root; - root.nextScheduledRoot = root; - } else { - lastScheduledRoot.nextScheduledRoot = root; - lastScheduledRoot = root; - lastScheduledRoot.nextScheduledRoot = firstScheduledRoot; - } - } else { - // This root is already scheduled, but its priority may have increased. - var remainingExpirationTime = root.remainingExpirationTime; - if (remainingExpirationTime === NoWork || expirationTime < remainingExpirationTime) { - // Update the priority. - root.remainingExpirationTime = expirationTime; - } - } - - if (isRendering) { - // Prevent reentrancy. Remaining work will be scheduled at the end of - // the currently rendering batch. - return; - } - - if (isBatchingUpdates) { - // Flush work at the end of the batch. - if (isUnbatchingUpdates) { - // ...unless we're inside unbatchedUpdates, in which case we should - // flush it now. - nextFlushedRoot = root; - nextFlushedExpirationTime = Sync; - performWorkOnRoot(nextFlushedRoot, nextFlushedExpirationTime); - } - return; - } - - // TODO: Get rid of Sync and use current time? - if (expirationTime === Sync) { - performWork(Sync, null); - } else { - scheduleCallbackWithExpiration(expirationTime); - } - } - - function findHighestPriorityRoot() { - var highestPriorityWork = NoWork; - var highestPriorityRoot = null; - - if (lastScheduledRoot !== null) { - var previousScheduledRoot = lastScheduledRoot; - var root = firstScheduledRoot; - while (root !== null) { - var remainingExpirationTime = root.remainingExpirationTime; - if (remainingExpirationTime === NoWork) { - // This root no longer has work. Remove it from the scheduler. - - // TODO: This check is redudant, but Flow is confused by the branch - // below where we set lastScheduledRoot to null, even though we break - // from the loop right after. - !(previousScheduledRoot !== null && lastScheduledRoot !== null) ? invariant(false, 'Should have a previous and last root. This error is likely caused by a bug in React. Please file an issue.') : void 0; - if (root === root.nextScheduledRoot) { - // This is the only root in the list. - root.nextScheduledRoot = null; - firstScheduledRoot = lastScheduledRoot = null; - break; - } else if (root === firstScheduledRoot) { - // This is the first root in the list. - var next = root.nextScheduledRoot; - firstScheduledRoot = next; - lastScheduledRoot.nextScheduledRoot = next; - root.nextScheduledRoot = null; - } else if (root === lastScheduledRoot) { - // This is the last root in the list. - lastScheduledRoot = previousScheduledRoot; - lastScheduledRoot.nextScheduledRoot = firstScheduledRoot; - root.nextScheduledRoot = null; - break; - } else { - previousScheduledRoot.nextScheduledRoot = root.nextScheduledRoot; - root.nextScheduledRoot = null; - } - root = previousScheduledRoot.nextScheduledRoot; - } else { - if (highestPriorityWork === NoWork || remainingExpirationTime < highestPriorityWork) { - // Update the priority, if it's higher - highestPriorityWork = remainingExpirationTime; - highestPriorityRoot = root; - } - if (root === lastScheduledRoot) { - break; - } - previousScheduledRoot = root; - root = root.nextScheduledRoot; - } - } - } - - // If the next root is the same as the previous root, this is a nested - // update. To prevent an infinite loop, increment the nested update count. - var previousFlushedRoot = nextFlushedRoot; - if (previousFlushedRoot !== null && previousFlushedRoot === highestPriorityRoot) { - nestedUpdateCount++; - } else { - // Reset whenever we switch roots. - nestedUpdateCount = 0; - } - nextFlushedRoot = highestPriorityRoot; - nextFlushedExpirationTime = highestPriorityWork; - } - - function performAsyncWork(dl) { - performWork(NoWork, dl); - } - - function performWork(minExpirationTime, dl) { - deadline = dl; - - // Keep working on roots until there's no more work, or until the we reach - // the deadline. - findHighestPriorityRoot(); - - if (enableUserTimingAPI && deadline !== null) { - var didExpire = nextFlushedExpirationTime < recalculateCurrentTime(); - stopRequestCallbackTimer(didExpire); - } - - while (nextFlushedRoot !== null && nextFlushedExpirationTime !== NoWork && (minExpirationTime === NoWork || nextFlushedExpirationTime <= minExpirationTime) && !deadlineDidExpire) { - performWorkOnRoot(nextFlushedRoot, nextFlushedExpirationTime); - // Find the next highest priority work. - findHighestPriorityRoot(); - } - - // We're done flushing work. Either we ran out of time in this callback, - // or there's no more work left with sufficient priority. - - // If we're inside a callback, set this to false since we just completed it. - if (deadline !== null) { - callbackExpirationTime = NoWork; - callbackID = -1; - } - // If there's work left over, schedule a new callback. - if (nextFlushedExpirationTime !== NoWork) { - scheduleCallbackWithExpiration(nextFlushedExpirationTime); - } - - // Clean-up. - deadline = null; - deadlineDidExpire = false; - nestedUpdateCount = 0; - - if (hasUnhandledError) { - var _error4 = unhandledError; - unhandledError = null; - hasUnhandledError = false; - throw _error4; - } - } - - function performWorkOnRoot(root, expirationTime) { - !!isRendering ? invariant(false, 'performWorkOnRoot was called recursively. This error is likely caused by a bug in React. Please file an issue.') : void 0; - - isRendering = true; - - // Check if this is async work or sync/expired work. - // TODO: Pass current time as argument to renderRoot, commitRoot - if (expirationTime <= recalculateCurrentTime()) { - // Flush sync work. - var finishedWork = root.finishedWork; - if (finishedWork !== null) { - // This root is already complete. We can commit it. - root.finishedWork = null; - root.remainingExpirationTime = commitRoot(finishedWork); - } else { - root.finishedWork = null; - finishedWork = renderRoot(root, expirationTime); - if (finishedWork !== null) { - // We've completed the root. Commit it. - root.remainingExpirationTime = commitRoot(finishedWork); - } - } - } else { - // Flush async work. - var _finishedWork = root.finishedWork; - if (_finishedWork !== null) { - // This root is already complete. We can commit it. - root.finishedWork = null; - root.remainingExpirationTime = commitRoot(_finishedWork); - } else { - root.finishedWork = null; - _finishedWork = renderRoot(root, expirationTime); - if (_finishedWork !== null) { - // We've completed the root. Check the deadline one more time - // before committing. - if (!shouldYield()) { - // Still time left. Commit the root. - root.remainingExpirationTime = commitRoot(_finishedWork); - } else { - // There's no time left. Mark this root as complete. We'll come - // back and commit it later. - root.finishedWork = _finishedWork; - } - } - } - } - - isRendering = false; - } - - // When working on async work, the reconciler asks the renderer if it should - // yield execution. For DOM, we implement this with requestIdleCallback. - function shouldYield() { - if (deadline === null) { - return false; - } - if (deadline.timeRemaining() > timeHeuristicForUnitOfWork) { - // Disregard deadline.didTimeout. Only expired work should be flushed - // during a timeout. This path is only hit for non-expired work. - return false; - } - deadlineDidExpire = true; - return true; - } - - // TODO: Not happy about this hook. Conceptually, renderRoot should return a - // tuple of (isReadyForCommit, didError, error) - function onUncaughtError(error) { - !(nextFlushedRoot !== null) ? invariant(false, 'Should be working on a root. This error is likely caused by a bug in React. Please file an issue.') : void 0; - // Unschedule this root so we don't work on it again until there's - // another update. - nextFlushedRoot.remainingExpirationTime = NoWork; - if (!hasUnhandledError) { - hasUnhandledError = true; - unhandledError = error; - } - } - - // TODO: Batching should be implemented at the renderer level, not inside - // the reconciler. - function batchedUpdates(fn, a) { - var previousIsBatchingUpdates = isBatchingUpdates; - isBatchingUpdates = true; - try { - return fn(a); - } finally { - isBatchingUpdates = previousIsBatchingUpdates; - if (!isBatchingUpdates && !isRendering) { - performWork(Sync, null); - } - } - } - - // TODO: Batching should be implemented at the renderer level, not inside - // the reconciler. - function unbatchedUpdates(fn) { - if (isBatchingUpdates && !isUnbatchingUpdates) { - isUnbatchingUpdates = true; - try { - return fn(); - } finally { - isUnbatchingUpdates = false; - } - } - return fn(); - } - - // TODO: Batching should be implemented at the renderer level, not within - // the reconciler. - function flushSync(fn) { - var previousIsBatchingUpdates = isBatchingUpdates; - isBatchingUpdates = true; - try { - return syncUpdates(fn); - } finally { - isBatchingUpdates = previousIsBatchingUpdates; - !!isRendering ? invariant(false, 'flushSync was called from inside a lifecycle method. It cannot be called when React is already rendering.') : void 0; - performWork(Sync, null); - } - } - - return { - computeAsyncExpiration: computeAsyncExpiration, - computeExpirationForFiber: computeExpirationForFiber, - scheduleWork: scheduleWork, - batchedUpdates: batchedUpdates, - unbatchedUpdates: unbatchedUpdates, - flushSync: flushSync, - deferredUpdates: deferredUpdates - }; -}; - -{ - var didWarnAboutNestedUpdates = false; -} - -// 0 is PROD, 1 is DEV. -// Might add PROFILE later. - - -function getContextForSubtree(parentComponent) { - if (!parentComponent) { - return emptyObject; - } - - var fiber = get(parentComponent); - var parentContext = findCurrentUnmaskedContext(fiber); - return isContextProvider(fiber) ? processChildContext(fiber, parentContext) : parentContext; -} - -var ReactFiberReconciler$1 = function (config) { - var getPublicInstance = config.getPublicInstance; - - var _ReactFiberScheduler = ReactFiberScheduler(config), - computeAsyncExpiration = _ReactFiberScheduler.computeAsyncExpiration, - computeExpirationForFiber = _ReactFiberScheduler.computeExpirationForFiber, - scheduleWork = _ReactFiberScheduler.scheduleWork, - batchedUpdates = _ReactFiberScheduler.batchedUpdates, - unbatchedUpdates = _ReactFiberScheduler.unbatchedUpdates, - flushSync = _ReactFiberScheduler.flushSync, - deferredUpdates = _ReactFiberScheduler.deferredUpdates; - - function scheduleTopLevelUpdate(current, element, callback) { - { - if (ReactDebugCurrentFiber.phase === 'render' && ReactDebugCurrentFiber.current !== null && !didWarnAboutNestedUpdates) { - didWarnAboutNestedUpdates = true; - warning(false, 'Render methods should be a pure function of props and state; ' + 'triggering nested component updates from render is not allowed. ' + 'If necessary, trigger nested updates in componentDidUpdate.\n\n' + 'Check the render method of %s.', getComponentName(ReactDebugCurrentFiber.current) || 'Unknown'); - } - } - - callback = callback === undefined ? null : callback; - { - warning(callback === null || typeof callback === 'function', 'render(...): Expected the last optional `callback` argument to be a ' + 'function. Instead received: %s.', callback); - } - - var expirationTime = void 0; - // Check if the top-level element is an async wrapper component. If so, - // treat updates to the root as async. This is a bit weird but lets us - // avoid a separate `renderAsync` API. - if (enableAsyncSubtreeAPI && element != null && element.type != null && element.type.prototype != null && element.type.prototype.unstable_isAsyncReactComponent === true) { - expirationTime = computeAsyncExpiration(); - } else { - expirationTime = computeExpirationForFiber(current); - } - - var update = { - expirationTime: expirationTime, - partialState: { element: element }, - callback: callback, - isReplace: false, - isForced: false, - nextCallback: null, - next: null - }; - insertUpdateIntoFiber(current, update); - scheduleWork(current, expirationTime); - } - - function findHostInstance(fiber) { - var hostFiber = findCurrentHostFiber(fiber); - if (hostFiber === null) { - return null; - } - return hostFiber.stateNode; - } - - return { - createContainer: function (containerInfo, hydrate) { - return createFiberRoot(containerInfo, hydrate); - }, - updateContainer: function (element, container, parentComponent, callback) { - // TODO: If this is a nested container, this won't be the root. - var current = container.current; - - { - if (ReactFiberInstrumentation_1.debugTool) { - if (current.alternate === null) { - ReactFiberInstrumentation_1.debugTool.onMountContainer(container); - } else if (element === null) { - ReactFiberInstrumentation_1.debugTool.onUnmountContainer(container); - } else { - ReactFiberInstrumentation_1.debugTool.onUpdateContainer(container); - } - } - } - - var context = getContextForSubtree(parentComponent); - if (container.context === null) { - container.context = context; - } else { - container.pendingContext = context; - } - - scheduleTopLevelUpdate(current, element, callback); - }, - - - batchedUpdates: batchedUpdates, - - unbatchedUpdates: unbatchedUpdates, - - deferredUpdates: deferredUpdates, - - flushSync: flushSync, - - getPublicRootInstance: function (container) { - var containerFiber = container.current; - if (!containerFiber.child) { - return null; - } - switch (containerFiber.child.tag) { - case HostComponent: - return getPublicInstance(containerFiber.child.stateNode); - default: - return containerFiber.child.stateNode; - } - }, - - - findHostInstance: findHostInstance, - - findHostInstanceWithNoPortals: function (fiber) { - var hostFiber = findCurrentHostFiberWithNoPortals(fiber); - if (hostFiber === null) { - return null; - } - return hostFiber.stateNode; - }, - injectIntoDevTools: function (devToolsConfig) { - var findFiberByHostInstance = devToolsConfig.findFiberByHostInstance; - - return injectInternals(_assign({}, devToolsConfig, { - findHostInstanceByFiber: function (fiber) { - return findHostInstance(fiber); - }, - findFiberByHostInstance: function (instance) { - if (!findFiberByHostInstance) { - // Might not be implemented by the renderer. - return null; - } - return findFiberByHostInstance(instance); - } - })); - } - }; -}; - -var ReactFiberReconciler$2 = Object.freeze({ - default: ReactFiberReconciler$1 -}); - -var ReactFiberReconciler$3 = ( ReactFiberReconciler$2 && ReactFiberReconciler$1 ) || ReactFiberReconciler$2; - -// TODO: bundle Flow types with the package. - - - -// TODO: decide on the top-level export form. -// This is hacky but makes it work with both Rollup and Jest. -var reactReconciler = ReactFiberReconciler$3['default'] ? ReactFiberReconciler$3['default'] : ReactFiberReconciler$3; - -function createPortal$1(children, containerInfo, -// TODO: figure out the API for cross-renderer implementation. -implementation) { - var key = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null; - - return { - // This tag allow us to uniquely identify this as a React Portal - $$typeof: REACT_PORTAL_TYPE, - key: key == null ? null : '' + key, - children: children, - containerInfo: containerInfo, - implementation: implementation - }; -} - -// TODO: this is special because it gets imported during build. - -var ReactVersion = '16.2.0'; - -// a requestAnimationFrame, storing the time for the start of the frame, then -// scheduling a postMessage which gets scheduled after paint. Within the -// postMessage handler do as much work as possible until time + frame rate. -// By separating the idle call into a separate event tick we ensure that -// layout, paint and other browser work is counted against the available time. -// The frame rate is dynamically adjusted. - -{ - if (ExecutionEnvironment.canUseDOM && typeof requestAnimationFrame !== 'function') { - warning(false, 'React depends on requestAnimationFrame. Make sure that you load a ' + 'polyfill in older browsers. http://fb.me/react-polyfills'); - } -} - -var hasNativePerformanceNow = typeof performance === 'object' && typeof performance.now === 'function'; - -var now = void 0; -if (hasNativePerformanceNow) { - now = function () { - return performance.now(); - }; -} else { - now = function () { - return Date.now(); - }; -} - -// TODO: There's no way to cancel, because Fiber doesn't atm. -var rIC = void 0; -var cIC = void 0; - -if (!ExecutionEnvironment.canUseDOM) { - rIC = function (frameCallback) { - return setTimeout(function () { - frameCallback({ - timeRemaining: function () { - return Infinity; - } - }); - }); - }; - cIC = function (timeoutID) { - clearTimeout(timeoutID); - }; -} else if (typeof requestIdleCallback !== 'function' || typeof cancelIdleCallback !== 'function') { - // Polyfill requestIdleCallback and cancelIdleCallback - - var scheduledRICCallback = null; - var isIdleScheduled = false; - var timeoutTime = -1; - - var isAnimationFrameScheduled = false; - - var frameDeadline = 0; - // We start out assuming that we run at 30fps but then the heuristic tracking - // will adjust this value to a faster fps if we get more frequent animation - // frames. - var previousFrameTime = 33; - var activeFrameTime = 33; - - var frameDeadlineObject; - if (hasNativePerformanceNow) { - frameDeadlineObject = { - didTimeout: false, - timeRemaining: function () { - // We assume that if we have a performance timer that the rAF callback - // gets a performance timer value. Not sure if this is always true. - var remaining = frameDeadline - performance.now(); - return remaining > 0 ? remaining : 0; - } - }; - } else { - frameDeadlineObject = { - didTimeout: false, - timeRemaining: function () { - // Fallback to Date.now() - var remaining = frameDeadline - Date.now(); - return remaining > 0 ? remaining : 0; - } - }; - } - - // We use the postMessage trick to defer idle work until after the repaint. - var messageKey = '__reactIdleCallback$' + Math.random().toString(36).slice(2); - var idleTick = function (event) { - if (event.source !== window || event.data !== messageKey) { - return; - } - - isIdleScheduled = false; - - var currentTime = now(); - if (frameDeadline - currentTime <= 0) { - // There's no time left in this idle period. Check if the callback has - // a timeout and whether it's been exceeded. - if (timeoutTime !== -1 && timeoutTime <= currentTime) { - // Exceeded the timeout. Invoke the callback even though there's no - // time left. - frameDeadlineObject.didTimeout = true; - } else { - // No timeout. - if (!isAnimationFrameScheduled) { - // Schedule another animation callback so we retry later. - isAnimationFrameScheduled = true; - requestAnimationFrame(animationTick); - } - // Exit without invoking the callback. - return; - } - } else { - // There's still time left in this idle period. - frameDeadlineObject.didTimeout = false; - } - - timeoutTime = -1; - var callback = scheduledRICCallback; - scheduledRICCallback = null; - if (callback !== null) { - callback(frameDeadlineObject); - } - }; - // Assumes that we have addEventListener in this environment. Might need - // something better for old IE. - window.addEventListener('message', idleTick, false); - - var animationTick = function (rafTime) { - isAnimationFrameScheduled = false; - var nextFrameTime = rafTime - frameDeadline + activeFrameTime; - if (nextFrameTime < activeFrameTime && previousFrameTime < activeFrameTime) { - if (nextFrameTime < 8) { - // Defensive coding. We don't support higher frame rates than 120hz. - // If we get lower than that, it is probably a bug. - nextFrameTime = 8; - } - // If one frame goes long, then the next one can be short to catch up. - // If two frames are short in a row, then that's an indication that we - // actually have a higher frame rate than what we're currently optimizing. - // We adjust our heuristic dynamically accordingly. For example, if we're - // running on 120hz display or 90hz VR display. - // Take the max of the two in case one of them was an anomaly due to - // missed frame deadlines. - activeFrameTime = nextFrameTime < previousFrameTime ? previousFrameTime : nextFrameTime; - } else { - previousFrameTime = nextFrameTime; - } - frameDeadline = rafTime + activeFrameTime; - if (!isIdleScheduled) { - isIdleScheduled = true; - window.postMessage(messageKey, '*'); - } - }; - - rIC = function (callback, options) { - // This assumes that we only schedule one callback at a time because that's - // how Fiber uses it. - scheduledRICCallback = callback; - if (options != null && typeof options.timeout === 'number') { - timeoutTime = now() + options.timeout; - } - if (!isAnimationFrameScheduled) { - // If rAF didn't already schedule one, we need to schedule a frame. - // TODO: If this rAF doesn't materialize because the browser throttles, we - // might want to still have setTimeout trigger rIC as a backup to ensure - // that we keep performing work. - isAnimationFrameScheduled = true; - requestAnimationFrame(animationTick); - } - return 0; - }; - - cIC = function () { - scheduledRICCallback = null; - isIdleScheduled = false; - timeoutTime = -1; - }; -} else { - rIC = window.requestIdleCallback; - cIC = window.cancelIdleCallback; -} - -/** - * Forked from fbjs/warning: - * https://github.com/facebook/fbjs/blob/e66ba20ad5be433eb54423f2b097d829324d9de6/packages/fbjs/src/__forks__/warning.js - * - * Only change is we use console.warn instead of console.error, - * and do nothing when 'console' is not supported. - * This really simplifies the code. - * --- - * Similar to invariant but only logs a warning if the condition is not met. - * This can be used to log issues in development environments in critical - * paths. Removing the logging code for production environments will keep the - * same logic and follow the same code paths. - */ - -var lowPriorityWarning = function () {}; - -{ - var printWarning = function (format) { - for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { - args[_key - 1] = arguments[_key]; - } - - var argIndex = 0; - var message = 'Warning: ' + format.replace(/%s/g, function () { - return args[argIndex++]; - }); - if (typeof console !== 'undefined') { - console.warn(message); - } - try { - // --- Welcome to debugging React --- - // This error was thrown as a convenience so that you can use this stack - // to find the callsite that caused this warning to fire. - throw new Error(message); - } catch (x) {} - }; - - lowPriorityWarning = function (condition, format) { - if (format === undefined) { - throw new Error('`warning(condition, format, ...args)` requires a warning ' + 'message argument'); - } - if (!condition) { - for (var _len2 = arguments.length, args = Array(_len2 > 2 ? _len2 - 2 : 0), _key2 = 2; _key2 < _len2; _key2++) { - args[_key2 - 2] = arguments[_key2]; - } - - printWarning.apply(undefined, [format].concat(args)); - } - }; -} - -var lowPriorityWarning$1 = lowPriorityWarning; - -// isAttributeNameSafe() is currently duplicated in DOMMarkupOperations. -// TODO: Find a better place for this. -var VALID_ATTRIBUTE_NAME_REGEX = new RegExp('^[' + ATTRIBUTE_NAME_START_CHAR + '][' + ATTRIBUTE_NAME_CHAR + ']*$'); -var illegalAttributeNameCache = {}; -var validatedAttributeNameCache = {}; -function isAttributeNameSafe(attributeName) { - if (validatedAttributeNameCache.hasOwnProperty(attributeName)) { - return true; - } - if (illegalAttributeNameCache.hasOwnProperty(attributeName)) { - return false; - } - if (VALID_ATTRIBUTE_NAME_REGEX.test(attributeName)) { - validatedAttributeNameCache[attributeName] = true; - return true; - } - illegalAttributeNameCache[attributeName] = true; - { - warning(false, 'Invalid attribute name: `%s`', attributeName); - } - return false; -} - -// shouldIgnoreValue() is currently duplicated in DOMMarkupOperations. -// TODO: Find a better place for this. -function shouldIgnoreValue(propertyInfo, value) { - return value == null || propertyInfo.hasBooleanValue && !value || propertyInfo.hasNumericValue && isNaN(value) || propertyInfo.hasPositiveNumericValue && value < 1 || propertyInfo.hasOverloadedBooleanValue && value === false; -} - -/** - * Operations for dealing with DOM properties. - */ - - - - - -/** - * Get the value for a property on a node. Only used in DEV for SSR validation. - * The "expected" argument is used as a hint of what the expected value is. - * Some properties have multiple equivalent values. - */ -function getValueForProperty(node, name, expected) { - { - var propertyInfo = getPropertyInfo(name); - if (propertyInfo) { - var mutationMethod = propertyInfo.mutationMethod; - if (mutationMethod || propertyInfo.mustUseProperty) { - return node[propertyInfo.propertyName]; - } else { - var attributeName = propertyInfo.attributeName; - - var stringValue = null; - - if (propertyInfo.hasOverloadedBooleanValue) { - if (node.hasAttribute(attributeName)) { - var value = node.getAttribute(attributeName); - if (value === '') { - return true; - } - if (shouldIgnoreValue(propertyInfo, expected)) { - return value; - } - if (value === '' + expected) { - return expected; - } - return value; - } - } else if (node.hasAttribute(attributeName)) { - if (shouldIgnoreValue(propertyInfo, expected)) { - // We had an attribute but shouldn't have had one, so read it - // for the error message. - return node.getAttribute(attributeName); - } - if (propertyInfo.hasBooleanValue) { - // If this was a boolean, it doesn't matter what the value is - // the fact that we have it is the same as the expected. - return expected; - } - // Even if this property uses a namespace we use getAttribute - // because we assume its namespaced name is the same as our config. - // To use getAttributeNS we need the local name which we don't have - // in our config atm. - stringValue = node.getAttribute(attributeName); - } - - if (shouldIgnoreValue(propertyInfo, expected)) { - return stringValue === null ? expected : stringValue; - } else if (stringValue === '' + expected) { - return expected; - } else { - return stringValue; - } - } - } - } -} - -/** - * Get the value for a attribute on a node. Only used in DEV for SSR validation. - * The third argument is used as a hint of what the expected value is. Some - * attributes have multiple equivalent values. - */ -function getValueForAttribute(node, name, expected) { - { - if (!isAttributeNameSafe(name)) { - return; - } - if (!node.hasAttribute(name)) { - return expected === undefined ? undefined : null; - } - var value = node.getAttribute(name); - if (value === '' + expected) { - return expected; - } - return value; - } -} - -/** - * Sets the value for a property on a node. - * - * @param {DOMElement} node - * @param {string} name - * @param {*} value - */ -function setValueForProperty(node, name, value) { - var propertyInfo = getPropertyInfo(name); - - if (propertyInfo && shouldSetAttribute(name, value)) { - var mutationMethod = propertyInfo.mutationMethod; - if (mutationMethod) { - mutationMethod(node, value); - } else if (shouldIgnoreValue(propertyInfo, value)) { - deleteValueForProperty(node, name); - return; - } else if (propertyInfo.mustUseProperty) { - // Contrary to `setAttribute`, object properties are properly - // `toString`ed by IE8/9. - node[propertyInfo.propertyName] = value; - } else { - var attributeName = propertyInfo.attributeName; - var namespace = propertyInfo.attributeNamespace; - // `setAttribute` with objects becomes only `[object]` in IE8/9, - // ('' + value) makes it output the correct toString()-value. - if (namespace) { - node.setAttributeNS(namespace, attributeName, '' + value); - } else if (propertyInfo.hasBooleanValue || propertyInfo.hasOverloadedBooleanValue && value === true) { - node.setAttribute(attributeName, ''); - } else { - node.setAttribute(attributeName, '' + value); - } - } - } else { - setValueForAttribute(node, name, shouldSetAttribute(name, value) ? value : null); - return; - } - - { - - } -} - -function setValueForAttribute(node, name, value) { - if (!isAttributeNameSafe(name)) { - return; - } - if (value == null) { - node.removeAttribute(name); - } else { - node.setAttribute(name, '' + value); - } - - { - - } -} - -/** - * Deletes an attributes from a node. - * - * @param {DOMElement} node - * @param {string} name - */ -function deleteValueForAttribute(node, name) { - node.removeAttribute(name); -} - -/** - * Deletes the value for a property on a node. - * - * @param {DOMElement} node - * @param {string} name - */ -function deleteValueForProperty(node, name) { - var propertyInfo = getPropertyInfo(name); - if (propertyInfo) { - var mutationMethod = propertyInfo.mutationMethod; - if (mutationMethod) { - mutationMethod(node, undefined); - } else if (propertyInfo.mustUseProperty) { - var propName = propertyInfo.propertyName; - if (propertyInfo.hasBooleanValue) { - node[propName] = false; - } else { - node[propName] = ''; - } - } else { - node.removeAttribute(propertyInfo.attributeName); - } - } else { - node.removeAttribute(name); - } -} - -var ReactControlledValuePropTypes = { - checkPropTypes: null -}; - -{ - var hasReadOnlyValue = { - button: true, - checkbox: true, - image: true, - hidden: true, - radio: true, - reset: true, - submit: true - }; - - var propTypes = { - value: function (props, propName, componentName) { - if (!props[propName] || hasReadOnlyValue[props.type] || props.onChange || props.readOnly || props.disabled) { - return null; - } - return new Error('You provided a `value` prop to a form field without an ' + '`onChange` handler. This will render a read-only field. If ' + 'the field should be mutable use `defaultValue`. Otherwise, ' + 'set either `onChange` or `readOnly`.'); - }, - checked: function (props, propName, componentName) { - if (!props[propName] || props.onChange || props.readOnly || props.disabled) { - return null; - } - return new Error('You provided a `checked` prop to a form field without an ' + '`onChange` handler. This will render a read-only field. If ' + 'the field should be mutable use `defaultChecked`. Otherwise, ' + 'set either `onChange` or `readOnly`.'); - } - }; - - /** - * Provide a linked `value` attribute for controlled forms. You should not use - * this outside of the ReactDOM controlled form components. - */ - ReactControlledValuePropTypes.checkPropTypes = function (tagName, props, getStack) { - checkPropTypes(propTypes, props, 'prop', tagName, getStack); - }; -} - -// TODO: direct imports like some-package/src/* are bad. Fix me. -var getCurrentFiberOwnerName$2 = ReactDebugCurrentFiber.getCurrentFiberOwnerName; -var getCurrentFiberStackAddendum$3 = ReactDebugCurrentFiber.getCurrentFiberStackAddendum; - -var didWarnValueDefaultValue = false; -var didWarnCheckedDefaultChecked = false; -var didWarnControlledToUncontrolled = false; -var didWarnUncontrolledToControlled = false; - -function isControlled(props) { - var usesChecked = props.type === 'checkbox' || props.type === 'radio'; - return usesChecked ? props.checked != null : props.value != null; -} - -/** - * Implements an host component that allows setting these optional - * props: `checked`, `value`, `defaultChecked`, and `defaultValue`. - * - * If `checked` or `value` are not supplied (or null/undefined), user actions - * that affect the checked state or value will trigger updates to the element. - * - * If they are supplied (and not null/undefined), the rendered element will not - * trigger updates to the element. Instead, the props must change in order for - * the rendered element to be updated. - * - * The rendered element will be initialized as unchecked (or `defaultChecked`) - * with an empty value (or `defaultValue`). - * - * See http://www.w3.org/TR/2012/WD-html5-20121025/the-input-element.html - */ - -function getHostProps(element, props) { - var node = element; - var value = props.value; - var checked = props.checked; - - var hostProps = _assign({ - // Make sure we set .type before any other properties (setting .value - // before .type means .value is lost in IE11 and below) - type: undefined, - // Make sure we set .step before .value (setting .value before .step - // means .value is rounded on mount, based upon step precision) - step: undefined, - // Make sure we set .min & .max before .value (to ensure proper order - // in corner cases such as min or max deriving from value, e.g. Issue #7170) - min: undefined, - max: undefined - }, props, { - defaultChecked: undefined, - defaultValue: undefined, - value: value != null ? value : node._wrapperState.initialValue, - checked: checked != null ? checked : node._wrapperState.initialChecked - }); - - return hostProps; -} - -function initWrapperState(element, props) { - { - ReactControlledValuePropTypes.checkPropTypes('input', props, getCurrentFiberStackAddendum$3); - - if (props.checked !== undefined && props.defaultChecked !== undefined && !didWarnCheckedDefaultChecked) { - warning(false, '%s contains an input of type %s with both checked and defaultChecked props. ' + 'Input elements must be either controlled or uncontrolled ' + '(specify either the checked prop, or the defaultChecked prop, but not ' + 'both). Decide between using a controlled or uncontrolled input ' + 'element and remove one of these props. More info: ' + 'https://fb.me/react-controlled-components', getCurrentFiberOwnerName$2() || 'A component', props.type); - didWarnCheckedDefaultChecked = true; - } - if (props.value !== undefined && props.defaultValue !== undefined && !didWarnValueDefaultValue) { - warning(false, '%s contains an input of type %s with both value and defaultValue props. ' + 'Input elements must be either controlled or uncontrolled ' + '(specify either the value prop, or the defaultValue prop, but not ' + 'both). Decide between using a controlled or uncontrolled input ' + 'element and remove one of these props. More info: ' + 'https://fb.me/react-controlled-components', getCurrentFiberOwnerName$2() || 'A component', props.type); - didWarnValueDefaultValue = true; - } - } - - var defaultValue = props.defaultValue; - var node = element; - node._wrapperState = { - initialChecked: props.checked != null ? props.checked : props.defaultChecked, - initialValue: props.value != null ? props.value : defaultValue, - controlled: isControlled(props) - }; -} - -function updateChecked(element, props) { - var node = element; - var checked = props.checked; - if (checked != null) { - setValueForProperty(node, 'checked', checked); - } -} - -function updateWrapper(element, props) { - var node = element; - { - var controlled = isControlled(props); - - if (!node._wrapperState.controlled && controlled && !didWarnUncontrolledToControlled) { - warning(false, 'A component is changing an uncontrolled input of type %s to be controlled. ' + 'Input elements should not switch from uncontrolled to controlled (or vice versa). ' + 'Decide between using a controlled or uncontrolled input ' + 'element for the lifetime of the component. More info: https://fb.me/react-controlled-components%s', props.type, getCurrentFiberStackAddendum$3()); - didWarnUncontrolledToControlled = true; - } - if (node._wrapperState.controlled && !controlled && !didWarnControlledToUncontrolled) { - warning(false, 'A component is changing a controlled input of type %s to be uncontrolled. ' + 'Input elements should not switch from controlled to uncontrolled (or vice versa). ' + 'Decide between using a controlled or uncontrolled input ' + 'element for the lifetime of the component. More info: https://fb.me/react-controlled-components%s', props.type, getCurrentFiberStackAddendum$3()); - didWarnControlledToUncontrolled = true; - } - } - - updateChecked(element, props); - - var value = props.value; - if (value != null) { - if (value === 0 && node.value === '') { - node.value = '0'; - // Note: IE9 reports a number inputs as 'text', so check props instead. - } else if (props.type === 'number') { - // Simulate `input.valueAsNumber`. IE9 does not support it - var valueAsNumber = parseFloat(node.value) || 0; - - if ( - // eslint-disable-next-line - value != valueAsNumber || - // eslint-disable-next-line - value == valueAsNumber && node.value != value) { - // Cast `value` to a string to ensure the value is set correctly. While - // browsers typically do this as necessary, jsdom doesn't. - node.value = '' + value; - } - } else if (node.value !== '' + value) { - // Cast `value` to a string to ensure the value is set correctly. While - // browsers typically do this as necessary, jsdom doesn't. - node.value = '' + value; - } - } else { - if (props.value == null && props.defaultValue != null) { - // In Chrome, assigning defaultValue to certain input types triggers input validation. - // For number inputs, the display value loses trailing decimal points. For email inputs, - // Chrome raises "The specified value is not a valid email address". - // - // Here we check to see if the defaultValue has actually changed, avoiding these problems - // when the user is inputting text - // - // https://github.com/facebook/react/issues/7253 - if (node.defaultValue !== '' + props.defaultValue) { - node.defaultValue = '' + props.defaultValue; - } - } - if (props.checked == null && props.defaultChecked != null) { - node.defaultChecked = !!props.defaultChecked; - } - } -} - -function postMountWrapper(element, props) { - var node = element; - - // Detach value from defaultValue. We won't do anything if we're working on - // submit or reset inputs as those values & defaultValues are linked. They - // are not resetable nodes so this operation doesn't matter and actually - // removes browser-default values (eg "Submit Query") when no value is - // provided. - - switch (props.type) { - case 'submit': - case 'reset': - break; - case 'color': - case 'date': - case 'datetime': - case 'datetime-local': - case 'month': - case 'time': - case 'week': - // This fixes the no-show issue on iOS Safari and Android Chrome: - // https://github.com/facebook/react/issues/7233 - node.value = ''; - node.value = node.defaultValue; - break; - default: - node.value = node.value; - break; - } - - // Normally, we'd just do `node.checked = node.checked` upon initial mount, less this bug - // this is needed to work around a chrome bug where setting defaultChecked - // will sometimes influence the value of checked (even after detachment). - // Reference: https://bugs.chromium.org/p/chromium/issues/detail?id=608416 - // We need to temporarily unset name to avoid disrupting radio button groups. - var name = node.name; - if (name !== '') { - node.name = ''; - } - node.defaultChecked = !node.defaultChecked; - node.defaultChecked = !node.defaultChecked; - if (name !== '') { - node.name = name; - } -} - -function restoreControlledState$1(element, props) { - var node = element; - updateWrapper(node, props); - updateNamedCousins(node, props); -} - -function updateNamedCousins(rootNode, props) { - var name = props.name; - if (props.type === 'radio' && name != null) { - var queryRoot = rootNode; - - while (queryRoot.parentNode) { - queryRoot = queryRoot.parentNode; - } - - // If `rootNode.form` was non-null, then we could try `form.elements`, - // but that sometimes behaves strangely in IE8. We could also try using - // `form.getElementsByName`, but that will only return direct children - // and won't include inputs that use the HTML5 `form=` attribute. Since - // the input might not even be in a form. It might not even be in the - // document. Let's just use the local `querySelectorAll` to ensure we don't - // miss anything. - var group = queryRoot.querySelectorAll('input[name=' + JSON.stringify('' + name) + '][type="radio"]'); - - for (var i = 0; i < group.length; i++) { - var otherNode = group[i]; - if (otherNode === rootNode || otherNode.form !== rootNode.form) { - continue; - } - // This will throw if radio buttons rendered by different copies of React - // and the same name are rendered into the same form (same as #1939). - // That's probably okay; we don't support it just as we don't support - // mixing React radio buttons with non-React ones. - var otherProps = getFiberCurrentPropsFromNode$1(otherNode); - !otherProps ? invariant(false, 'ReactDOMInput: Mixing React and non-React radio inputs with the same `name` is not supported.') : void 0; - - // We need update the tracked value on the named cousin since the value - // was changed but the input saw no event or value set - updateValueIfChanged(otherNode); - - // If this is a controlled radio button group, forcing the input that - // was previously checked to update will cause it to be come re-checked - // as appropriate. - updateWrapper(otherNode, otherProps); - } - } -} - -function flattenChildren(children) { - var content = ''; - - // Flatten children and warn if they aren't strings or numbers; - // invalid types are ignored. - // We can silently skip them because invalid DOM nesting warning - // catches these cases in Fiber. - React.Children.forEach(children, function (child) { - if (child == null) { - return; - } - if (typeof child === 'string' || typeof child === 'number') { - content += child; - } - }); - - return content; -} - -/** - * Implements an