diff options
Diffstat (limited to 'node_modules/react-dom/umd/react-dom.development.js')
-rw-r--r-- | node_modules/react-dom/umd/react-dom.development.js | 23049 |
1 files changed, 10345 insertions, 12704 deletions
diff --git a/node_modules/react-dom/umd/react-dom.development.js b/node_modules/react-dom/umd/react-dom.development.js index eea5c11c5..371c3816e 100644 --- a/node_modules/react-dom/umd/react-dom.development.js +++ b/node_modules/react-dom/umd/react-dom.development.js @@ -1,4 +1,4 @@ -/** @license React v16.0.0 +/** @license React v16.2.0 * react-dom.development.js * * Copyright (c) 2013-present, Facebook, Inc. @@ -7,20 +7,19 @@ * LICENSE file in the root directory of this source tree. */ +'use strict'; + (function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('react')) : typeof define === 'function' && define.amd ? define(['react'], factory) : (global.ReactDOM = factory(global.React)); -}(this, (function (require$$0) { 'use strict'; +}(this, (function (React) { 'use strict'; /** - * Copyright (c) 2013-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @providesModule reactProdInvariant - * + * WARNING: DO NOT manually require this module. + * This is a replacement for `invariant(...)` used by the error code system + * and will _only_ be required by the corresponding babel pass. + * It always throws. */ /** @@ -31,6 +30,8 @@ * */ + + /** * Use invariant() to assert state which your program assumes to be true. * @@ -75,110 +76,578 @@ function invariant(condition, format, a, b, c, d, e, f) { var invariant_1 = invariant; -/** - * Copyright (c) 2013-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @providesModule checkReact - * - */ +!React ? invariant_1(false, 'ReactDOM was loaded before React. Make sure you load the React package before loading ReactDOM.') : void 0; +// These attributes should be all lowercase to allow for +// case insensitive checks +var RESERVED_PROPS = { + children: true, + dangerouslySetInnerHTML: true, + defaultValue: true, + defaultChecked: true, + innerHTML: true, + suppressContentEditableWarning: true, + suppressHydrationWarning: true, + style: true +}; +function checkMask(value, bitmask) { + return (value & bitmask) === bitmask; +} +var DOMPropertyInjection = { + /** + * Mapping from normalized, camelcased property names to a configuration that + * specifies how the associated DOM property should be accessed or rendered. + */ + MUST_USE_PROPERTY: 0x1, + HAS_BOOLEAN_VALUE: 0x4, + HAS_NUMERIC_VALUE: 0x8, + HAS_POSITIVE_NUMERIC_VALUE: 0x10 | 0x8, + HAS_OVERLOADED_BOOLEAN_VALUE: 0x20, + HAS_STRING_BOOLEAN_VALUE: 0x40, -!require$$0 ? invariant_1(false, 'ReactDOM was loaded before React. Make sure you load the React package before loading ReactDOM.') : void 0; + /** + * Inject some specialized knowledge about the DOM. This takes a config object + * with the following properties: + * + * Properties: object mapping DOM property name to one of the + * DOMPropertyInjection constants or null. If your attribute isn't in here, + * it won't get written to the DOM. + * + * DOMAttributeNames: object mapping React attribute name to the DOM + * attribute name. Attribute names not specified use the **lowercase** + * normalized name. + * + * DOMAttributeNamespaces: object mapping React attribute name to the DOM + * attribute namespace URL. (Attribute names not specified use no namespace.) + * + * DOMPropertyNames: similar to DOMAttributeNames but for DOM properties. + * Property names not specified use the normalized name. + * + * DOMMutationMethods: Properties that require special mutation methods. If + * `value` is undefined, the mutation method should unset the property. + * + * @param {object} domPropertyConfig the config as described above. + */ + injectDOMPropertyConfig: function (domPropertyConfig) { + var Injection = DOMPropertyInjection; + var Properties = domPropertyConfig.Properties || {}; + var DOMAttributeNamespaces = domPropertyConfig.DOMAttributeNamespaces || {}; + var DOMAttributeNames = domPropertyConfig.DOMAttributeNames || {}; + var DOMMutationMethods = domPropertyConfig.DOMMutationMethods || {}; -/** - * Copyright (c) 2013-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @providesModule DOMNamespaces - */ + for (var propName in Properties) { + !!properties.hasOwnProperty(propName) ? invariant_1(false, "injectDOMPropertyConfig(...): You're trying to inject DOM property '%s' which has already been injected. You may be accidentally injecting the same DOM property config twice, or you may be injecting two configs that have conflicting property names.", propName) : void 0; -var HTML_NAMESPACE = 'http://www.w3.org/1999/xhtml'; -var MATH_NAMESPACE = 'http://www.w3.org/1998/Math/MathML'; -var SVG_NAMESPACE = 'http://www.w3.org/2000/svg'; + var lowerCased = propName.toLowerCase(); + var propConfig = Properties[propName]; -var Namespaces = { - html: HTML_NAMESPACE, - mathml: MATH_NAMESPACE, - svg: SVG_NAMESPACE + var propertyInfo = { + attributeName: lowerCased, + attributeNamespace: null, + propertyName: propName, + mutationMethod: null, + + mustUseProperty: checkMask(propConfig, Injection.MUST_USE_PROPERTY), + hasBooleanValue: checkMask(propConfig, Injection.HAS_BOOLEAN_VALUE), + hasNumericValue: checkMask(propConfig, Injection.HAS_NUMERIC_VALUE), + hasPositiveNumericValue: checkMask(propConfig, Injection.HAS_POSITIVE_NUMERIC_VALUE), + hasOverloadedBooleanValue: checkMask(propConfig, Injection.HAS_OVERLOADED_BOOLEAN_VALUE), + hasStringBooleanValue: checkMask(propConfig, Injection.HAS_STRING_BOOLEAN_VALUE) + }; + !(propertyInfo.hasBooleanValue + propertyInfo.hasNumericValue + propertyInfo.hasOverloadedBooleanValue <= 1) ? invariant_1(false, "DOMProperty: Value can be one of boolean, overloaded boolean, or numeric value, but not a combination: %s", propName) : void 0; + + if (DOMAttributeNames.hasOwnProperty(propName)) { + var attributeName = DOMAttributeNames[propName]; + + propertyInfo.attributeName = attributeName; + } + + if (DOMAttributeNamespaces.hasOwnProperty(propName)) { + propertyInfo.attributeNamespace = DOMAttributeNamespaces[propName]; + } + + if (DOMMutationMethods.hasOwnProperty(propName)) { + propertyInfo.mutationMethod = DOMMutationMethods[propName]; + } + + // Downcase references to whitelist properties to check for membership + // without case-sensitivity. This allows the whitelist to pick up + // `allowfullscreen`, which should be written using the property configuration + // for `allowFullscreen` + properties[propName] = propertyInfo; + } + } }; -// Assumes there is no parent namespace. -function getIntrinsicNamespace(type) { - switch (type) { - case 'svg': - return SVG_NAMESPACE; - case 'math': - return MATH_NAMESPACE; +/* eslint-disable max-len */ +var ATTRIBUTE_NAME_START_CHAR = ":A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD"; +/* eslint-enable max-len */ +var ATTRIBUTE_NAME_CHAR = ATTRIBUTE_NAME_START_CHAR + "\\-.0-9\\u00B7\\u0300-\\u036F\\u203F-\\u2040"; + + +var ROOT_ATTRIBUTE_NAME = 'data-reactroot'; + +/** + * Map from property "standard name" to an object with info about how to set + * the property in the DOM. Each object contains: + * + * attributeName: + * Used when rendering markup or with `*Attribute()`. + * attributeNamespace + * propertyName: + * Used on DOM node instances. (This includes properties that mutate due to + * external factors.) + * mutationMethod: + * If non-null, used instead of the property or `setAttribute()` after + * initial render. + * mustUseProperty: + * Whether the property must be accessed and mutated as an object property. + * hasBooleanValue: + * Whether the property should be removed when set to a falsey value. + * hasNumericValue: + * Whether the property must be numeric or parse as a numeric and should be + * removed when set to a falsey value. + * hasPositiveNumericValue: + * Whether the property must be positive numeric or parse as a positive + * numeric and should be removed when set to a falsey value. + * hasOverloadedBooleanValue: + * Whether the property can be used as a flag as well as with a value. + * Removed when strictly equal to false; present without a value when + * strictly equal to true; present with a value otherwise. + */ +var properties = {}; + +/** + * Checks whether a property name is a writeable attribute. + * @method + */ +function shouldSetAttribute(name, value) { + if (isReservedProp(name)) { + return false; + } + if (name.length > 2 && (name[0] === 'o' || name[0] === 'O') && (name[1] === 'n' || name[1] === 'N')) { + return false; + } + if (value === null) { + return true; + } + switch (typeof value) { + case 'boolean': + return shouldAttributeAcceptBooleanValue(name); + case 'undefined': + case 'number': + case 'string': + case 'object': + return true; default: - return HTML_NAMESPACE; + // function, symbol + return false; } } -function getChildNamespace$1(parentNamespace, type) { - if (parentNamespace == null || parentNamespace === HTML_NAMESPACE) { - // No (or default) parent namespace: potential entry point. - return getIntrinsicNamespace(type); +function getPropertyInfo(name) { + return properties.hasOwnProperty(name) ? properties[name] : null; +} + +function shouldAttributeAcceptBooleanValue(name) { + if (isReservedProp(name)) { + return true; } - if (parentNamespace === SVG_NAMESPACE && type === 'foreignObject') { - // We're leaving SVG. - return HTML_NAMESPACE; + var propertyInfo = getPropertyInfo(name); + if (propertyInfo) { + return propertyInfo.hasBooleanValue || propertyInfo.hasStringBooleanValue || propertyInfo.hasOverloadedBooleanValue; } - // By default, pass namespace below. - return parentNamespace; + var prefix = name.toLowerCase().slice(0, 5); + return prefix === 'data-' || prefix === 'aria-'; } -var Namespaces_1 = Namespaces; -var getIntrinsicNamespace_1 = getIntrinsicNamespace; -var getChildNamespace_1 = getChildNamespace$1; +/** + * Checks to see if a property name is within the list of properties + * reserved for internal React operations. These properties should + * not be set on an HTML element. + * + * @private + * @param {string} name + * @return {boolean} If the name is within reserved props + */ +function isReservedProp(name) { + return RESERVED_PROPS.hasOwnProperty(name); +} + +var injection = DOMPropertyInjection; + +var MUST_USE_PROPERTY = injection.MUST_USE_PROPERTY; +var HAS_BOOLEAN_VALUE = injection.HAS_BOOLEAN_VALUE; +var HAS_NUMERIC_VALUE = injection.HAS_NUMERIC_VALUE; +var HAS_POSITIVE_NUMERIC_VALUE = injection.HAS_POSITIVE_NUMERIC_VALUE; +var HAS_OVERLOADED_BOOLEAN_VALUE = injection.HAS_OVERLOADED_BOOLEAN_VALUE; +var HAS_STRING_BOOLEAN_VALUE = injection.HAS_STRING_BOOLEAN_VALUE; -var DOMNamespaces = { - Namespaces: Namespaces_1, - getIntrinsicNamespace: getIntrinsicNamespace_1, - getChildNamespace: getChildNamespace_1 +var HTMLDOMPropertyConfig = { + // When adding attributes to this list, be sure to also add them to + // the `possibleStandardNames` module to ensure casing and incorrect + // name warnings. + Properties: { + allowFullScreen: HAS_BOOLEAN_VALUE, + // specifies target context for links with `preload` type + async: HAS_BOOLEAN_VALUE, + // Note: there is a special case that prevents it from being written to the DOM + // on the client side because the browsers are inconsistent. Instead we call focus(). + autoFocus: HAS_BOOLEAN_VALUE, + autoPlay: HAS_BOOLEAN_VALUE, + capture: HAS_OVERLOADED_BOOLEAN_VALUE, + checked: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE, + cols: HAS_POSITIVE_NUMERIC_VALUE, + contentEditable: HAS_STRING_BOOLEAN_VALUE, + controls: HAS_BOOLEAN_VALUE, + 'default': HAS_BOOLEAN_VALUE, + defer: HAS_BOOLEAN_VALUE, + disabled: HAS_BOOLEAN_VALUE, + download: HAS_OVERLOADED_BOOLEAN_VALUE, + draggable: HAS_STRING_BOOLEAN_VALUE, + formNoValidate: HAS_BOOLEAN_VALUE, + hidden: HAS_BOOLEAN_VALUE, + loop: HAS_BOOLEAN_VALUE, + // Caution; `option.selected` is not updated if `select.multiple` is + // disabled with `removeAttribute`. + multiple: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE, + muted: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE, + noValidate: HAS_BOOLEAN_VALUE, + open: HAS_BOOLEAN_VALUE, + playsInline: HAS_BOOLEAN_VALUE, + readOnly: HAS_BOOLEAN_VALUE, + required: HAS_BOOLEAN_VALUE, + reversed: HAS_BOOLEAN_VALUE, + rows: HAS_POSITIVE_NUMERIC_VALUE, + rowSpan: HAS_NUMERIC_VALUE, + scoped: HAS_BOOLEAN_VALUE, + seamless: HAS_BOOLEAN_VALUE, + selected: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE, + size: HAS_POSITIVE_NUMERIC_VALUE, + start: HAS_NUMERIC_VALUE, + // support for projecting regular DOM Elements via V1 named slots ( shadow dom ) + span: HAS_POSITIVE_NUMERIC_VALUE, + spellCheck: HAS_STRING_BOOLEAN_VALUE, + // Style must be explicitly set in the attribute list. React components + // expect a style object + style: 0, + // Keep it in the whitelist because it is case-sensitive for SVG. + tabIndex: 0, + // itemScope is for for Microdata support. + // See http://schema.org/docs/gs.html + itemScope: HAS_BOOLEAN_VALUE, + // These attributes must stay in the white-list because they have + // different attribute names (see DOMAttributeNames below) + acceptCharset: 0, + className: 0, + htmlFor: 0, + httpEquiv: 0, + // Attributes with mutation methods must be specified in the whitelist + // Set the string boolean flag to allow the behavior + value: HAS_STRING_BOOLEAN_VALUE + }, + DOMAttributeNames: { + acceptCharset: 'accept-charset', + className: 'class', + htmlFor: 'for', + httpEquiv: 'http-equiv' + }, + DOMMutationMethods: { + value: function (node, value) { + if (value == null) { + return node.removeAttribute('value'); + } + + // Number inputs get special treatment due to some edge cases in + // Chrome. Let everything else assign the value attribute as normal. + // https://github.com/facebook/react/issues/7253#issuecomment-236074326 + if (node.type !== 'number' || node.hasAttribute('value') === false) { + node.setAttribute('value', '' + value); + } else if (node.validity && !node.validity.badInput && node.ownerDocument.activeElement !== node) { + // Don't assign an attribute if validation reports bad + // input. Chrome will clear the value. Additionally, don't + // operate on inputs that have focus, otherwise Chrome might + // strip off trailing decimal places and cause the user's + // cursor position to jump to the beginning of the input. + // + // In ReactDOMInput, we have an onBlur event that will trigger + // this function again when focus is lost. + node.setAttribute('value', '' + value); + } + } + } +}; + +var HAS_STRING_BOOLEAN_VALUE$1 = injection.HAS_STRING_BOOLEAN_VALUE; + + +var NS = { + xlink: 'http://www.w3.org/1999/xlink', + xml: 'http://www.w3.org/XML/1998/namespace' }; /** - * Copyright (c) 2013-present, Facebook, Inc. + * This is a list of all SVG attributes that need special casing, + * namespacing, or boolean value assignment. * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. + * When adding attributes to this list, be sure to also add them to + * the `possibleStandardNames` module to ensure casing and incorrect + * name warnings. * + * SVG Attributes List: + * https://www.w3.org/TR/SVG/attindex.html + * SMIL Spec: + * https://www.w3.org/TR/smil */ +var ATTRS = ['accent-height', 'alignment-baseline', 'arabic-form', 'baseline-shift', 'cap-height', 'clip-path', 'clip-rule', 'color-interpolation', 'color-interpolation-filters', 'color-profile', 'color-rendering', 'dominant-baseline', 'enable-background', 'fill-opacity', 'fill-rule', 'flood-color', 'flood-opacity', 'font-family', 'font-size', 'font-size-adjust', 'font-stretch', 'font-style', 'font-variant', 'font-weight', 'glyph-name', 'glyph-orientation-horizontal', 'glyph-orientation-vertical', 'horiz-adv-x', 'horiz-origin-x', 'image-rendering', 'letter-spacing', 'lighting-color', 'marker-end', 'marker-mid', 'marker-start', 'overline-position', 'overline-thickness', 'paint-order', 'panose-1', 'pointer-events', 'rendering-intent', 'shape-rendering', 'stop-color', 'stop-opacity', 'strikethrough-position', 'strikethrough-thickness', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'text-anchor', 'text-decoration', 'text-rendering', 'underline-position', 'underline-thickness', 'unicode-bidi', 'unicode-range', 'units-per-em', 'v-alphabetic', 'v-hanging', 'v-ideographic', 'v-mathematical', 'vector-effect', 'vert-adv-y', 'vert-origin-x', 'vert-origin-y', 'word-spacing', 'writing-mode', 'x-height', 'xlink:actuate', 'xlink:arcrole', 'xlink:href', 'xlink:role', 'xlink:show', 'xlink:title', 'xlink:type', 'xml:base', 'xmlns:xlink', 'xml:lang', 'xml:space']; -var canUseDOM = !!(typeof window !== 'undefined' && window.document && window.document.createElement); +var SVGDOMPropertyConfig = { + Properties: { + autoReverse: HAS_STRING_BOOLEAN_VALUE$1, + externalResourcesRequired: HAS_STRING_BOOLEAN_VALUE$1, + preserveAlpha: HAS_STRING_BOOLEAN_VALUE$1 + }, + DOMAttributeNames: { + autoReverse: 'autoReverse', + externalResourcesRequired: 'externalResourcesRequired', + preserveAlpha: 'preserveAlpha' + }, + DOMAttributeNamespaces: { + xlinkActuate: NS.xlink, + xlinkArcrole: NS.xlink, + xlinkHref: NS.xlink, + xlinkRole: NS.xlink, + xlinkShow: NS.xlink, + xlinkTitle: NS.xlink, + xlinkType: NS.xlink, + xmlBase: NS.xml, + xmlLang: NS.xml, + xmlSpace: NS.xml + } +}; -/** - * Simple, lightweight module assisting with the detection and context of - * Worker. Helps avoid circular dependencies and allows code to reason about - * whether or not they are in a Worker, even if they never include the main - * `ReactWorker` dependency. - */ -var ExecutionEnvironment = { +var CAMELIZE = /[\-\:]([a-z])/g; +var capitalize = function (token) { + return token[1].toUpperCase(); +}; - canUseDOM: canUseDOM, +ATTRS.forEach(function (original) { + var reactName = original.replace(CAMELIZE, capitalize); - canUseWorkers: typeof Worker !== 'undefined', + SVGDOMPropertyConfig.Properties[reactName] = 0; + SVGDOMPropertyConfig.DOMAttributeNames[reactName] = original; +}); - canUseEventListeners: canUseDOM && !!(window.addEventListener || window.attachEvent), +injection.injectDOMPropertyConfig(HTMLDOMPropertyConfig); +injection.injectDOMPropertyConfig(SVGDOMPropertyConfig); - canUseViewport: canUseDOM && !!window.screen, +var ReactErrorUtils = { + // Used by Fiber to simulate a try-catch. + _caughtError: null, + _hasCaughtError: false, - isInWorker: !canUseDOM // For now, this is true - might change in the future. + // Used by event system to capture/rethrow the first error. + _rethrowError: null, + _hasRethrowError: false, + + injection: { + injectErrorUtils: function (injectedErrorUtils) { + !(typeof injectedErrorUtils.invokeGuardedCallback === 'function') ? invariant_1(false, 'Injected invokeGuardedCallback() must be a function.') : void 0; + invokeGuardedCallback = injectedErrorUtils.invokeGuardedCallback; + } + }, + + /** + * Call a function while guarding against errors that happens within it. + * Returns an error if it throws, otherwise null. + * + * In production, this is implemented using a try-catch. The reason we don't + * use a try-catch directly is so that we can swap out a different + * implementation in DEV mode. + * + * @param {String} name of the guard to use for logging or debugging + * @param {Function} func The function to invoke + * @param {*} context The context to use when calling the function + * @param {...*} args Arguments for function + */ + invokeGuardedCallback: function (name, func, context, a, b, c, d, e, f) { + invokeGuardedCallback.apply(ReactErrorUtils, arguments); + }, + + /** + * Same as invokeGuardedCallback, but instead of returning an error, it stores + * it in a global so it can be rethrown by `rethrowCaughtError` later. + * TODO: See if _caughtError and _rethrowError can be unified. + * + * @param {String} name of the guard to use for logging or debugging + * @param {Function} func The function to invoke + * @param {*} context The context to use when calling the function + * @param {...*} args Arguments for function + */ + invokeGuardedCallbackAndCatchFirstError: function (name, func, context, a, b, c, d, e, f) { + ReactErrorUtils.invokeGuardedCallback.apply(this, arguments); + if (ReactErrorUtils.hasCaughtError()) { + var error = ReactErrorUtils.clearCaughtError(); + if (!ReactErrorUtils._hasRethrowError) { + ReactErrorUtils._hasRethrowError = true; + ReactErrorUtils._rethrowError = error; + } + } + }, + /** + * During execution of guarded functions we will capture the first error which + * we will rethrow to be handled by the top level error handler. + */ + rethrowCaughtError: function () { + return rethrowCaughtError.apply(ReactErrorUtils, arguments); + }, + + hasCaughtError: function () { + return ReactErrorUtils._hasCaughtError; + }, + + clearCaughtError: function () { + if (ReactErrorUtils._hasCaughtError) { + var error = ReactErrorUtils._caughtError; + ReactErrorUtils._caughtError = null; + ReactErrorUtils._hasCaughtError = false; + return error; + } else { + invariant_1(false, 'clearCaughtError was called but no error was captured. This error is likely caused by a bug in React. Please file an issue.'); + } + } }; -var ExecutionEnvironment_1 = ExecutionEnvironment; +var invokeGuardedCallback = function (name, func, context, a, b, c, d, e, f) { + ReactErrorUtils._hasCaughtError = false; + ReactErrorUtils._caughtError = null; + var funcArgs = Array.prototype.slice.call(arguments, 3); + try { + func.apply(context, funcArgs); + } catch (error) { + ReactErrorUtils._caughtError = error; + ReactErrorUtils._hasCaughtError = true; + } +}; -var ReactInternals = require$$0.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; +{ + // In DEV mode, we swap out invokeGuardedCallback for a special version + // that plays more nicely with the browser's DevTools. The idea is to preserve + // "Pause on exceptions" behavior. Because React wraps all user-provided + // functions in invokeGuardedCallback, and the production version of + // invokeGuardedCallback uses a try-catch, all user exceptions are treated + // like caught exceptions, and the DevTools won't pause unless the developer + // takes the extra step of enabling pause on caught exceptions. This is + // untintuitive, though, because even though React has caught the error, from + // the developer's perspective, the error is uncaught. + // + // To preserve the expected "Pause on exceptions" behavior, we don't use a + // try-catch in DEV. Instead, we synchronously dispatch a fake event to a fake + // DOM node, and call the user-provided callback from inside an event handler + // for that fake event. If the callback throws, the error is "captured" using + // a global event handler. But because the error happens in a different + // event loop context, it does not interrupt the normal program flow. + // Effectively, this gives us try-catch behavior without actually using + // try-catch. Neat! -var assign = ReactInternals.assign; + // Check that the browser supports the APIs we need to implement our special + // DEV version of invokeGuardedCallback + if (typeof window !== 'undefined' && typeof window.dispatchEvent === 'function' && typeof document !== 'undefined' && typeof document.createEvent === 'function') { + var fakeNode = document.createElement('react'); + + var invokeGuardedCallbackDev = function (name, func, context, a, b, c, d, e, f) { + // Keeps track of whether the user-provided callback threw an error. We + // set this to true at the beginning, then set it to false right after + // calling the function. If the function errors, `didError` will never be + // set to false. This strategy works even if the browser is flaky and + // fails to call our global error handler, because it doesn't rely on + // the error event at all. + var didError = true; + + // Create an event handler for our fake event. We will synchronously + // dispatch our fake event using `dispatchEvent`. Inside the handler, we + // call the user-provided callback. + var funcArgs = Array.prototype.slice.call(arguments, 3); + function callCallback() { + // We immediately remove the callback from event listeners so that + // nested `invokeGuardedCallback` calls do not clash. Otherwise, a + // nested call would trigger the fake event handlers of any call higher + // in the stack. + fakeNode.removeEventListener(evtType, callCallback, false); + func.apply(context, funcArgs); + didError = false; + } + + // Create a global error event handler. We use this to capture the value + // that was thrown. It's possible that this error handler will fire more + // than once; for example, if non-React code also calls `dispatchEvent` + // and a handler for that event throws. We should be resilient to most of + // those cases. Even if our error event handler fires more than once, the + // last error event is always used. If the callback actually does error, + // we know that the last error event is the correct one, because it's not + // possible for anything else to have happened in between our callback + // erroring and the code that follows the `dispatchEvent` call below. If + // the callback doesn't error, but the error event was fired, we know to + // ignore it because `didError` will be false, as described above. + var error = void 0; + // Use this to track whether the error event is ever called. + var didSetError = false; + var isCrossOriginError = false; + + function onError(event) { + error = event.error; + didSetError = true; + if (error === null && event.colno === 0 && event.lineno === 0) { + isCrossOriginError = true; + } + } + + // Create a fake event type. + var evtType = 'react-' + (name ? name : 'invokeguardedcallback'); + + // Attach our event handlers + window.addEventListener('error', onError); + fakeNode.addEventListener(evtType, callCallback, false); + + // Synchronously dispatch our fake event. If the user-provided function + // errors, it will trigger our global error handler. + var evt = document.createEvent('Event'); + evt.initEvent(evtType, false, false); + fakeNode.dispatchEvent(evt); + + if (didError) { + if (!didSetError) { + // The callback errored, but the error event never fired. + error = new Error('An error was thrown inside one of your components, but React ' + "doesn't know what it was. This is likely due to browser " + 'flakiness. React does its best to preserve the "Pause on ' + 'exceptions" behavior of the DevTools, which requires some ' + "DEV-mode only tricks. It's possible that these don't work in " + 'your browser. Try triggering the error in production mode, ' + 'or switching to a modern browser. If you suspect that this is ' + 'actually an issue with React, please file an issue.'); + } else if (isCrossOriginError) { + error = new Error("A cross-origin error was thrown. React doesn't have access to " + 'the actual error object in development. ' + 'See https://fb.me/react-crossorigin-error for more information.'); + } + ReactErrorUtils._hasCaughtError = true; + ReactErrorUtils._caughtError = error; + } else { + ReactErrorUtils._hasCaughtError = false; + ReactErrorUtils._caughtError = null; + } + + // Remove our event listeners + window.removeEventListener('error', onError); + }; + + invokeGuardedCallback = invokeGuardedCallbackDev; + } +} + +var rethrowCaughtError = function () { + if (ReactErrorUtils._hasRethrowError) { + var error = ReactErrorUtils._rethrowError; + ReactErrorUtils._rethrowError = null; + ReactErrorUtils._hasRethrowError = false; + throw error; + } +}; /** * Injectable ordering of event plugins. @@ -204,11 +673,11 @@ function recomputePluginOrdering() { var pluginModule = namesToPlugins[pluginName]; var pluginIndex = eventPluginOrder.indexOf(pluginName); !(pluginIndex > -1) ? invariant_1(false, 'EventPluginRegistry: Cannot inject event plugins that do not exist in the plugin ordering, `%s`.', pluginName) : void 0; - if (EventPluginRegistry.plugins[pluginIndex]) { + if (plugins[pluginIndex]) { continue; } !pluginModule.extractEvents ? invariant_1(false, 'EventPluginRegistry: Event plugins must implement an `extractEvents` method, but `%s` does not.', pluginName) : void 0; - EventPluginRegistry.plugins[pluginIndex] = pluginModule; + plugins[pluginIndex] = pluginModule; var publishedEvents = pluginModule.eventTypes; for (var eventName in publishedEvents) { !publishEventForPlugin(publishedEvents[eventName], pluginModule, eventName) ? invariant_1(false, 'EventPluginRegistry: Failed to publish event `%s` for plugin `%s`.', eventName, pluginName) : void 0; @@ -225,8 +694,8 @@ function recomputePluginOrdering() { * @private */ function publishEventForPlugin(dispatchConfig, pluginModule, eventName) { - !!EventPluginRegistry.eventNameDispatchConfigs.hasOwnProperty(eventName) ? invariant_1(false, 'EventPluginHub: More than one plugin attempted to publish the same event name, `%s`.', eventName) : void 0; - EventPluginRegistry.eventNameDispatchConfigs[eventName] = dispatchConfig; + !!eventNameDispatchConfigs.hasOwnProperty(eventName) ? invariant_1(false, 'EventPluginHub: More than one plugin attempted to publish the same event name, `%s`.', eventName) : void 0; + eventNameDispatchConfigs[eventName] = dispatchConfig; var phasedRegistrationNames = dispatchConfig.phasedRegistrationNames; if (phasedRegistrationNames) { @@ -252,16 +721,16 @@ function publishEventForPlugin(dispatchConfig, pluginModule, eventName) { * @private */ function publishRegistrationName(registrationName, pluginModule, eventName) { - !!EventPluginRegistry.registrationNameModules[registrationName] ? invariant_1(false, 'EventPluginHub: More than one plugin attempted to publish the same registration name, `%s`.', registrationName) : void 0; - EventPluginRegistry.registrationNameModules[registrationName] = pluginModule; - EventPluginRegistry.registrationNameDependencies[registrationName] = pluginModule.eventTypes[eventName].dependencies; + !!registrationNameModules[registrationName] ? invariant_1(false, 'EventPluginHub: More than one plugin attempted to publish the same registration name, `%s`.', registrationName) : void 0; + registrationNameModules[registrationName] = pluginModule; + registrationNameDependencies[registrationName] = pluginModule.eventTypes[eventName].dependencies; { var lowerCasedName = registrationName.toLowerCase(); - EventPluginRegistry.possibleRegistrationNames[lowerCasedName] = registrationName; + possibleRegistrationNames[lowerCasedName] = registrationName; if (registrationName === 'onDoubleClick') { - EventPluginRegistry.possibleRegistrationNames.ondblclick = registrationName; + possibleRegistrationNames.ondblclick = registrationName; } } } @@ -271,82 +740,89 @@ function publishRegistrationName(registrationName, pluginModule, eventName) { * * @see {EventPluginHub} */ -var EventPluginRegistry = { - /** - * Ordered list of injected plugins. - */ - plugins: [], - /** - * Mapping from event name to dispatch config - */ - eventNameDispatchConfigs: {}, +/** + * Ordered list of injected plugins. + */ +var plugins = []; - /** - * Mapping from registration name to plugin module - */ - registrationNameModules: {}, +/** + * Mapping from event name to dispatch config + */ +var eventNameDispatchConfigs = {}; - /** - * Mapping from registration name to event name - */ - registrationNameDependencies: {}, +/** + * Mapping from registration name to plugin module + */ +var registrationNameModules = {}; - /** - * Mapping from lowercase registration names to the properly cased version, - * used to warn in the case of missing event handlers. Available - * only in true. - * @type {Object} - */ - possibleRegistrationNames: {}, - // Trust the developer to only use possibleRegistrationNames in true +/** + * Mapping from registration name to event name + */ +var registrationNameDependencies = {}; - /** - * Injects an ordering of plugins (by plugin name). This allows the ordering - * to be decoupled from injection of the actual plugins so that ordering is - * always deterministic regardless of packaging, on-the-fly injection, etc. - * - * @param {array} InjectedEventPluginOrder - * @internal - * @see {EventPluginHub.injection.injectEventPluginOrder} - */ - injectEventPluginOrder: function (injectedEventPluginOrder) { - !!eventPluginOrder ? invariant_1(false, 'EventPluginRegistry: Cannot inject event plugin ordering more than once. You are likely trying to load more than one copy of React.') : void 0; - // Clone the ordering so it cannot be dynamically mutated. - eventPluginOrder = Array.prototype.slice.call(injectedEventPluginOrder); - recomputePluginOrdering(); - }, +/** + * Mapping from lowercase registration names to the properly cased version, + * used to warn in the case of missing event handlers. Available + * only in true. + * @type {Object} + */ +var possibleRegistrationNames = {}; +// Trust the developer to only use possibleRegistrationNames in true - /** - * Injects plugins to be used by `EventPluginHub`. The plugin names must be - * in the ordering injected by `injectEventPluginOrder`. - * - * Plugins can be injected as part of page initialization or on-the-fly. - * - * @param {object} injectedNamesToPlugins Map from names to plugin modules. - * @internal - * @see {EventPluginHub.injection.injectEventPluginsByName} - */ - injectEventPluginsByName: function (injectedNamesToPlugins) { - var isOrderingDirty = false; - for (var pluginName in injectedNamesToPlugins) { - if (!injectedNamesToPlugins.hasOwnProperty(pluginName)) { - continue; - } - var pluginModule = injectedNamesToPlugins[pluginName]; - if (!namesToPlugins.hasOwnProperty(pluginName) || namesToPlugins[pluginName] !== pluginModule) { - !!namesToPlugins[pluginName] ? invariant_1(false, 'EventPluginRegistry: Cannot inject two different event plugins using the same name, `%s`.', pluginName) : void 0; - namesToPlugins[pluginName] = pluginModule; - isOrderingDirty = true; - } +/** + * Injects an ordering of plugins (by plugin name). This allows the ordering + * to be decoupled from injection of the actual plugins so that ordering is + * always deterministic regardless of packaging, on-the-fly injection, etc. + * + * @param {array} InjectedEventPluginOrder + * @internal + * @see {EventPluginHub.injection.injectEventPluginOrder} + */ +function injectEventPluginOrder(injectedEventPluginOrder) { + !!eventPluginOrder ? invariant_1(false, 'EventPluginRegistry: Cannot inject event plugin ordering more than once. You are likely trying to load more than one copy of React.') : void 0; + // Clone the ordering so it cannot be dynamically mutated. + eventPluginOrder = Array.prototype.slice.call(injectedEventPluginOrder); + recomputePluginOrdering(); +} + +/** + * Injects plugins to be used by `EventPluginHub`. The plugin names must be + * in the ordering injected by `injectEventPluginOrder`. + * + * Plugins can be injected as part of page initialization or on-the-fly. + * + * @param {object} injectedNamesToPlugins Map from names to plugin modules. + * @internal + * @see {EventPluginHub.injection.injectEventPluginsByName} + */ +function injectEventPluginsByName(injectedNamesToPlugins) { + var isOrderingDirty = false; + for (var pluginName in injectedNamesToPlugins) { + if (!injectedNamesToPlugins.hasOwnProperty(pluginName)) { + continue; } - if (isOrderingDirty) { - recomputePluginOrdering(); + var pluginModule = injectedNamesToPlugins[pluginName]; + if (!namesToPlugins.hasOwnProperty(pluginName) || namesToPlugins[pluginName] !== pluginModule) { + !!namesToPlugins[pluginName] ? invariant_1(false, 'EventPluginRegistry: Cannot inject two different event plugins using the same name, `%s`.', pluginName) : void 0; + namesToPlugins[pluginName] = pluginModule; + isOrderingDirty = true; } } -}; + if (isOrderingDirty) { + recomputePluginOrdering(); + } +} -var EventPluginRegistry_1 = EventPluginRegistry; +var EventPluginRegistry = Object.freeze({ + plugins: plugins, + eventNameDispatchConfigs: eventNameDispatchConfigs, + registrationNameModules: registrationNameModules, + registrationNameDependencies: registrationNameDependencies, + possibleRegistrationNames: possibleRegistrationNames, + injectEventPluginOrder: injectEventPluginOrder, + injectEventPluginsByName: injectEventPluginsByName +}); /** * Copyright (c) 2013-present, Facebook, Inc. @@ -384,462 +860,424 @@ emptyFunction.thatReturnsArgument = function (arg) { var emptyFunction_1 = emptyFunction; /** - * Copyright (c) 2013-present, Facebook, Inc. + * Copyright (c) 2014-present, Facebook, Inc. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @typechecks */ + + /** - * Upstream version of event listener. Does not take into account specific - * nature of platform. + * 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 EventListener = { - /** - * Listen to DOM events during the bubble phase. - * - * @param {DOMEventTarget} target DOM element to register listener on. - * @param {string} eventType Event type, e.g. 'click' or 'mouseover'. - * @param {function} callback Callback function. - * @return {object} Object with a `remove` method. - */ - listen: function listen(target, eventType, callback) { - if (target.addEventListener) { - target.addEventListener(eventType, callback, false); - return { - remove: function remove() { - target.removeEventListener(eventType, callback, false); - } - }; - } else if (target.attachEvent) { - target.attachEvent('on' + eventType, callback); - return { - remove: function remove() { - target.detachEvent('on' + eventType, callback); - } - }; + +var warning = emptyFunction_1; + +{ + var printWarning = function printWarning(format) { + for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { + args[_key - 1] = arguments[_key]; } - }, - /** - * Listen to DOM events during the capture phase. - * - * @param {DOMEventTarget} target DOM element to register listener on. - * @param {string} eventType Event type, e.g. 'click' or 'mouseover'. - * @param {function} callback Callback function. - * @return {object} Object with a `remove` method. - */ - capture: function capture(target, eventType, callback) { - if (target.addEventListener) { - target.addEventListener(eventType, callback, true); - return { - remove: function remove() { - target.removeEventListener(eventType, callback, true); - } - }; - } else { - { - console.error('Attempted to listen to events during the capture phase on a ' + 'browser that does not support the capture phase. Your application ' + 'will not receive some events.'); + var argIndex = 0; + var message = 'Warning: ' + format.replace(/%s/g, function () { + return args[argIndex++]; + }); + if (typeof console !== 'undefined') { + console.error(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) {} + }; + + warning = function warning(condition, format) { + if (format === undefined) { + throw new Error('`warning(condition, format, ...args)` requires a warning ' + 'message argument'); + } + + if (format.indexOf('Failed Composite propType: ') === 0) { + return; // Ignore CompositeComponent proptype check. + } + + if (!condition) { + for (var _len2 = arguments.length, args = Array(_len2 > 2 ? _len2 - 2 : 0), _key2 = 2; _key2 < _len2; _key2++) { + args[_key2 - 2] = arguments[_key2]; } - return { - remove: emptyFunction_1 - }; + + printWarning.apply(undefined, [format].concat(args)); } - }, + }; +} - registerDefault: function registerDefault() {} -}; +var warning_1 = warning; -var EventListener_1 = EventListener; +var getFiberCurrentPropsFromNode = null; +var getInstanceFromNode = null; +var getNodeFromInstance = null; -// These attributes should be all lowercase to allow for -// case insensitive checks -var RESERVED_PROPS = { - children: true, - dangerouslySetInnerHTML: true, - autoFocus: true, - defaultValue: true, - defaultChecked: true, - innerHTML: true, - suppressContentEditableWarning: true, - style: true +var injection$2 = { + injectComponentTree: function (Injected) { + getFiberCurrentPropsFromNode = Injected.getFiberCurrentPropsFromNode; + getInstanceFromNode = Injected.getInstanceFromNode; + getNodeFromInstance = Injected.getNodeFromInstance; + + { + warning_1(getNodeFromInstance && getInstanceFromNode, 'EventPluginUtils.injection.injectComponentTree(...): Injected ' + 'module is missing getNodeFromInstance or getInstanceFromNode.'); + } + } }; -function checkMask(value, bitmask) { - return (value & bitmask) === bitmask; -} -var DOMPropertyInjection = { - /** - * Mapping from normalized, camelcased property names to a configuration that - * specifies how the associated DOM property should be accessed or rendered. - */ - MUST_USE_PROPERTY: 0x1, - HAS_BOOLEAN_VALUE: 0x4, - HAS_NUMERIC_VALUE: 0x8, - HAS_POSITIVE_NUMERIC_VALUE: 0x10 | 0x8, - HAS_OVERLOADED_BOOLEAN_VALUE: 0x20, - HAS_STRING_BOOLEAN_VALUE: 0x40, - /** - * Inject some specialized knowledge about the DOM. This takes a config object - * with the following properties: - * - * Properties: object mapping DOM property name to one of the - * DOMPropertyInjection constants or null. If your attribute isn't in here, - * it won't get written to the DOM. - * - * DOMAttributeNames: object mapping React attribute name to the DOM - * attribute name. Attribute names not specified use the **lowercase** - * normalized name. - * - * DOMAttributeNamespaces: object mapping React attribute name to the DOM - * attribute namespace URL. (Attribute names not specified use no namespace.) - * - * DOMPropertyNames: similar to DOMAttributeNames but for DOM properties. - * Property names not specified use the normalized name. - * - * DOMMutationMethods: Properties that require special mutation methods. If - * `value` is undefined, the mutation method should unset the property. - * - * @param {object} domPropertyConfig the config as described above. - */ - injectDOMPropertyConfig: function (domPropertyConfig) { - var Injection = DOMPropertyInjection; - var Properties = domPropertyConfig.Properties || {}; - var DOMAttributeNamespaces = domPropertyConfig.DOMAttributeNamespaces || {}; - var DOMAttributeNames = domPropertyConfig.DOMAttributeNames || {}; - var DOMMutationMethods = domPropertyConfig.DOMMutationMethods || {}; - for (var propName in Properties) { - !!DOMProperty.properties.hasOwnProperty(propName) ? invariant_1(false, 'injectDOMPropertyConfig(...): You\'re trying to inject DOM property \'%s\' which has already been injected. You may be accidentally injecting the same DOM property config twice, or you may be injecting two configs that have conflicting property names.', propName) : void 0; - var lowerCased = propName.toLowerCase(); - var propConfig = Properties[propName]; - var propertyInfo = { - attributeName: lowerCased, - attributeNamespace: null, - propertyName: propName, - mutationMethod: null, +var validateEventDispatches; +{ + validateEventDispatches = function (event) { + var dispatchListeners = event._dispatchListeners; + var dispatchInstances = event._dispatchInstances; - mustUseProperty: checkMask(propConfig, Injection.MUST_USE_PROPERTY), - hasBooleanValue: checkMask(propConfig, Injection.HAS_BOOLEAN_VALUE), - hasNumericValue: checkMask(propConfig, Injection.HAS_NUMERIC_VALUE), - hasPositiveNumericValue: checkMask(propConfig, Injection.HAS_POSITIVE_NUMERIC_VALUE), - hasOverloadedBooleanValue: checkMask(propConfig, Injection.HAS_OVERLOADED_BOOLEAN_VALUE), - hasStringBooleanValue: checkMask(propConfig, Injection.HAS_STRING_BOOLEAN_VALUE) - }; - !(propertyInfo.hasBooleanValue + propertyInfo.hasNumericValue + propertyInfo.hasOverloadedBooleanValue <= 1) ? invariant_1(false, 'DOMProperty: Value can be one of boolean, overloaded boolean, or numeric value, but not a combination: %s', propName) : void 0; + var listenersIsArr = Array.isArray(dispatchListeners); + var listenersLen = listenersIsArr ? dispatchListeners.length : dispatchListeners ? 1 : 0; - if (DOMAttributeNames.hasOwnProperty(propName)) { - var attributeName = DOMAttributeNames[propName]; + var instancesIsArr = Array.isArray(dispatchInstances); + var instancesLen = instancesIsArr ? dispatchInstances.length : dispatchInstances ? 1 : 0; - propertyInfo.attributeName = attributeName; - } + warning_1(instancesIsArr === listenersIsArr && instancesLen === listenersLen, 'EventPluginUtils: Invalid `event`.'); + }; +} - if (DOMAttributeNamespaces.hasOwnProperty(propName)) { - propertyInfo.attributeNamespace = DOMAttributeNamespaces[propName]; - } +/** + * Dispatch the event to the listener. + * @param {SyntheticEvent} event SyntheticEvent to handle + * @param {boolean} simulated If the event is simulated (changes exn behavior) + * @param {function} listener Application-level callback + * @param {*} inst Internal component instance + */ +function executeDispatch(event, simulated, listener, inst) { + var type = event.type || 'unknown-event'; + event.currentTarget = getNodeFromInstance(inst); + ReactErrorUtils.invokeGuardedCallbackAndCatchFirstError(type, listener, undefined, event); + event.currentTarget = null; +} - if (DOMMutationMethods.hasOwnProperty(propName)) { - propertyInfo.mutationMethod = DOMMutationMethods[propName]; +/** + * Standard/simple iteration through an event's collected dispatches. + */ +function executeDispatchesInOrder(event, simulated) { + var dispatchListeners = event._dispatchListeners; + var dispatchInstances = event._dispatchInstances; + { + validateEventDispatches(event); + } + if (Array.isArray(dispatchListeners)) { + for (var i = 0; i < dispatchListeners.length; i++) { + if (event.isPropagationStopped()) { + break; } - - // Downcase references to whitelist properties to check for membership - // without case-sensitivity. This allows the whitelist to pick up - // `allowfullscreen`, which should be written using the property configuration - // for `allowFullscreen` - DOMProperty.properties[propName] = propertyInfo; + // Listeners and Instances are two parallel arrays that are always in sync. + executeDispatch(event, simulated, dispatchListeners[i], dispatchInstances[i]); } + } else if (dispatchListeners) { + executeDispatch(event, simulated, dispatchListeners, dispatchInstances); } -}; + event._dispatchListeners = null; + event._dispatchInstances = null; +} + +/** + * @see executeDispatchesInOrderStopAtTrueImpl + */ -/* eslint-disable max-len */ -var ATTRIBUTE_NAME_START_CHAR = ':A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD'; -/* eslint-enable max-len */ /** - * DOMProperty exports lookup objects that can be used like functions: + * Execution of a "direct" dispatch - there must be at most one dispatch + * accumulated on the event or it is considered an error. It doesn't really make + * sense for an event with multiple dispatches (bubbled) to keep track of the + * return values at each dispatch execution, but it does tend to make sense when + * dealing with "direct" dispatches. * - * > DOMProperty.isValid['id'] - * true - * > DOMProperty.isValid['foobar'] - * undefined + * @return {*} The return value of executing the single dispatch. + */ + + +/** + * @param {SyntheticEvent} event + * @return {boolean} True iff number of dispatches accumulated is greater than 0. + */ + +/** + * Accumulates items that must not be null or undefined into the first one. This + * is used to conserve memory by avoiding array allocations, and thus sacrifices + * API cleanness. Since `current` can be null before being passed in and not + * null after this function, make sure to assign it back to `current`: * - * Although this may be confusing, it performs better in general. + * `a = accumulateInto(a, b);` + * + * This API should be sparingly used. Try `accumulate` for something cleaner. * - * @see http://jsperf.com/key-exists - * @see http://jsperf.com/key-missing + * @return {*|array<*>} An accumulation of items. */ -var DOMProperty = { - ID_ATTRIBUTE_NAME: 'data-reactid', - ROOT_ATTRIBUTE_NAME: 'data-reactroot', - - ATTRIBUTE_NAME_START_CHAR: ATTRIBUTE_NAME_START_CHAR, - ATTRIBUTE_NAME_CHAR: ATTRIBUTE_NAME_START_CHAR + '\\-.0-9\\u00B7\\u0300-\\u036F\\u203F-\\u2040', - /** - * Map from property "standard name" to an object with info about how to set - * the property in the DOM. Each object contains: - * - * attributeName: - * Used when rendering markup or with `*Attribute()`. - * attributeNamespace - * propertyName: - * Used on DOM node instances. (This includes properties that mutate due to - * external factors.) - * mutationMethod: - * If non-null, used instead of the property or `setAttribute()` after - * initial render. - * mustUseProperty: - * Whether the property must be accessed and mutated as an object property. - * hasBooleanValue: - * Whether the property should be removed when set to a falsey value. - * hasNumericValue: - * Whether the property must be numeric or parse as a numeric and should be - * removed when set to a falsey value. - * hasPositiveNumericValue: - * Whether the property must be positive numeric or parse as a positive - * numeric and should be removed when set to a falsey value. - * hasOverloadedBooleanValue: - * Whether the property can be used as a flag as well as with a value. - * Removed when strictly equal to false; present without a value when - * strictly equal to true; present with a value otherwise. - */ - properties: {}, +function accumulateInto(current, next) { + !(next != null) ? invariant_1(false, 'accumulateInto(...): Accumulated items must not be null or undefined.') : void 0; - /** - * Checks whether a property name is a writeable attribute. - * @method - */ - shouldSetAttribute: function (name, value) { - if (DOMProperty.isReservedProp(name)) { - return false; - } - if ((name[0] === 'o' || name[0] === 'O') && (name[1] === 'n' || name[1] === 'N')) { - return false; - } - if (value === null) { - return true; - } - switch (typeof value) { - case 'boolean': - return DOMProperty.shouldAttributeAcceptBooleanValue(name); - case 'undefined': - case 'number': - case 'string': - case 'object': - return true; - default: - // function, symbol - return false; - } - }, + if (current == null) { + return next; + } - getPropertyInfo: function (name) { - return DOMProperty.properties.hasOwnProperty(name) ? DOMProperty.properties[name] : null; - }, - shouldAttributeAcceptBooleanValue: function (name) { - if (DOMProperty.isReservedProp(name)) { - return true; - } - var propertyInfo = DOMProperty.getPropertyInfo(name); - if (propertyInfo) { - return propertyInfo.hasBooleanValue || propertyInfo.hasStringBooleanValue || propertyInfo.hasOverloadedBooleanValue; + // Both are not empty. Warning: Never call x.concat(y) when you are not + // certain that x is an Array (x could be a string with concat method). + if (Array.isArray(current)) { + if (Array.isArray(next)) { + current.push.apply(current, next); + return current; } - var prefix = name.toLowerCase().slice(0, 5); - return prefix === 'data-' || prefix === 'aria-'; - }, - + current.push(next); + return current; + } - /** - * Checks to see if a property name is within the list of properties - * reserved for internal React operations. These properties should - * not be set on an HTML element. - * - * @private - * @param {string} name - * @return {boolean} If the name is within reserved props - */ - isReservedProp: function (name) { - return RESERVED_PROPS.hasOwnProperty(name); - }, + if (Array.isArray(next)) { + // A bit too dangerous to mutate `next`. + return [current].concat(next); + } + return [current, next]; +} - injection: DOMPropertyInjection -}; +/** + * @param {array} arr an "accumulation" of items which is either an Array or + * a single item. Useful when paired with the `accumulate` module. This is a + * simple utility that allows us to reason about a collection of items, but + * handling the case when there is exactly one item (and we do not need to + * allocate an array). + * @param {function} cb Callback invoked with each element or a collection. + * @param {?} [scope] Scope used as `this` in a callback. + */ +function forEachAccumulated(arr, cb, scope) { + if (Array.isArray(arr)) { + arr.forEach(cb, scope); + } else if (arr) { + cb.call(scope, arr); + } +} -var DOMProperty_1 = DOMProperty; +/** + * Internal queue of events that have accumulated their dispatches and are + * waiting to have their dispatches executed. + */ +var eventQueue = null; /** - * Copyright (c) 2015-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. + * Dispatches an event and releases it back into the pool, unless persistent. * - * @providesModule ReactDOMComponentFlags + * @param {?object} event Synthetic event to be dispatched. + * @param {boolean} simulated If the event is simulated (changes exn behavior) + * @private */ +var executeDispatchesAndRelease = function (event, simulated) { + if (event) { + executeDispatchesInOrder(event, simulated); -var ReactDOMComponentFlags = { - hasCachedChildNodes: 1 << 0 + if (!event.isPersistent()) { + event.constructor.release(event); + } + } +}; +var executeDispatchesAndReleaseSimulated = function (e) { + return executeDispatchesAndRelease(e, true); +}; +var executeDispatchesAndReleaseTopLevel = function (e) { + return executeDispatchesAndRelease(e, false); }; -var ReactDOMComponentFlags_1 = ReactDOMComponentFlags; +function isInteractive(tag) { + return tag === 'button' || tag === 'input' || tag === 'select' || tag === 'textarea'; +} + +function shouldPreventMouseEvent(name, type, props) { + switch (name) { + case 'onClick': + case 'onClickCapture': + case 'onDoubleClick': + case 'onDoubleClickCapture': + case 'onMouseDown': + case 'onMouseDownCapture': + case 'onMouseMove': + case 'onMouseMoveCapture': + case 'onMouseUp': + case 'onMouseUpCapture': + return !!(props.disabled && isInteractive(type)); + default: + return false; + } +} /** - * Copyright (c) 2013-present, Facebook, Inc. + * This is a unified interface for event plugins to be installed and configured. * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. + * Event plugins can implement the following properties: * - * @providesModule ReactTypeOfWork - * - */ - -var ReactTypeOfWork = { - IndeterminateComponent: 0, // Before we know whether it is functional or class - FunctionalComponent: 1, - ClassComponent: 2, - HostRoot: 3, // Root of a host tree. Could be nested inside another node. - HostPortal: 4, // A subtree. Could be an entry point to a different renderer. - HostComponent: 5, - HostText: 6, - CoroutineComponent: 7, - CoroutineHandlerPhase: 8, - YieldComponent: 9, - Fragment: 10 -}; - -/** - * Copyright (c) 2013-present, Facebook, Inc. + * `extractEvents` {function(string, DOMEventTarget, string, object): *} + * Required. When a top-level event is fired, this method is expected to + * extract synthetic events that will in turn be queued and dispatched. * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. + * `eventTypes` {object} + * Optional, plugins that fire events must publish a mapping of registration + * names that are used to register listeners. Values of this mapping must + * be objects that contain `registrationName` or `phasedRegistrationNames`. * - * @providesModule HTMLNodeType + * `executeDispatch` {function(object, function, string)} + * Optional, allows plugins to override how an event gets dispatched. By + * default, the listener is simply invoked. + * + * Each plugin that is injected into `EventsPluginHub` is immediately operable. + * + * @public */ /** - * HTML nodeType values that represent the type of the node + * Methods for injecting dependencies. */ +var injection$1 = { + /** + * @param {array} InjectedEventPluginOrder + * @public + */ + injectEventPluginOrder: injectEventPluginOrder, -var HTMLNodeType = { - ELEMENT_NODE: 1, - TEXT_NODE: 3, - COMMENT_NODE: 8, - DOCUMENT_NODE: 9, - DOCUMENT_FRAGMENT_NODE: 11 + /** + * @param {object} injectedNamesToPlugins Map from names to plugin modules. + */ + injectEventPluginsByName: injectEventPluginsByName }; -var HTMLNodeType_1 = HTMLNodeType; - -var HostComponent = ReactTypeOfWork.HostComponent; -var HostText = ReactTypeOfWork.HostText; - -var ELEMENT_NODE$1 = HTMLNodeType_1.ELEMENT_NODE; -var COMMENT_NODE$1 = HTMLNodeType_1.COMMENT_NODE; - - - -var ATTR_NAME = DOMProperty_1.ID_ATTRIBUTE_NAME; -var Flags = ReactDOMComponentFlags_1; - -var randomKey = Math.random().toString(36).slice(2); - -var internalInstanceKey = '__reactInternalInstance$' + randomKey; - -var internalEventHandlersKey = '__reactEventHandlers$' + randomKey; - /** - * Check if a given node should be cached. + * @param {object} inst The instance, which is the source of events. + * @param {string} registrationName Name of listener (e.g. `onClick`). + * @return {?function} The stored callback. */ -function shouldPrecacheNode(node, nodeID) { - return node.nodeType === ELEMENT_NODE$1 && node.getAttribute(ATTR_NAME) === '' + nodeID || node.nodeType === COMMENT_NODE$1 && node.nodeValue === ' react-text: ' + nodeID + ' ' || node.nodeType === COMMENT_NODE$1 && node.nodeValue === ' react-empty: ' + nodeID + ' '; +function getListener(inst, registrationName) { + var listener; + + // TODO: shouldPreventMouseEvent is DOM-specific and definitely should not + // live here; needs to be moved to a better place soon + var stateNode = inst.stateNode; + if (!stateNode) { + // Work in progress (ex: onload events in incremental mode). + return null; + } + var props = getFiberCurrentPropsFromNode(stateNode); + if (!props) { + // Work in progress. + return null; + } + listener = props[registrationName]; + if (shouldPreventMouseEvent(registrationName, inst.type, props)) { + return null; + } + !(!listener || typeof listener === 'function') ? invariant_1(false, 'Expected `%s` listener to be a function, instead got a value of `%s` type.', registrationName, typeof listener) : void 0; + return listener; } /** - * Drill down (through composites and empty components) until we get a host or - * host text component. + * Allows registered plugins an opportunity to extract events from top-level + * native browser events. * - * This is pretty polymorphic but unavoidable with the current structure we have - * for `_renderedChildren`. + * @return {*} An accumulation of synthetic events. + * @internal */ -function getRenderedHostOrTextFromComponent(component) { - var rendered; - while (rendered = component._renderedComponent) { - component = rendered; +function extractEvents(topLevelType, targetInst, nativeEvent, nativeEventTarget) { + var events; + for (var i = 0; i < plugins.length; i++) { + // Not every plugin in the ordering may be loaded at runtime. + var possiblePlugin = plugins[i]; + if (possiblePlugin) { + var extractedEvents = possiblePlugin.extractEvents(topLevelType, targetInst, nativeEvent, nativeEventTarget); + if (extractedEvents) { + events = accumulateInto(events, extractedEvents); + } + } } - return component; + return events; } /** - * Populate `_hostNode` on the rendered host/text component with the given - * DOM node. The passed `inst` can be a composite. + * Enqueues a synthetic event that should be dispatched when + * `processEventQueue` is invoked. + * + * @param {*} events An accumulation of synthetic events. + * @internal */ -function precacheNode(inst, node) { - var hostInst = getRenderedHostOrTextFromComponent(inst); - hostInst._hostNode = node; - node[internalInstanceKey] = hostInst; -} - -function precacheFiberNode$1(hostInst, node) { - node[internalInstanceKey] = hostInst; -} - -function uncacheNode(inst) { - var node = inst._hostNode; - if (node) { - delete node[internalInstanceKey]; - inst._hostNode = null; +function enqueueEvents(events) { + if (events) { + eventQueue = accumulateInto(eventQueue, events); } } /** - * Populate `_hostNode` on each child of `inst`, assuming that the children - * match up with the DOM (element) children of `node`. - * - * We cache entire levels at once to avoid an n^2 problem where we access the - * children of a node sequentially and have to walk from the start to our target - * node every time. + * Dispatches all synthetic events on the event queue. * - * Since we update `_renderedChildren` and the actual DOM at (slightly) - * different times, we could race here and see a newer `_renderedChildren` than - * the DOM nodes we see. To avoid this, ReactMultiChild calls - * `prepareToManageChildren` before we change `_renderedChildren`, at which - * time the container's child nodes are always cached (until it unmounts). + * @internal */ -function precacheChildNodes(inst, node) { - if (inst._flags & Flags.hasCachedChildNodes) { +function processEventQueue(simulated) { + // Set `eventQueue` to null before processing it so that we can tell if more + // events get enqueued while processing. + var processingEventQueue = eventQueue; + eventQueue = null; + + if (!processingEventQueue) { return; } - var children = inst._renderedChildren; - var childNode = node.firstChild; - outer: for (var name in children) { - if (!children.hasOwnProperty(name)) { - continue; - } - var childInst = children[name]; - var childID = getRenderedHostOrTextFromComponent(childInst)._domID; - if (childID === 0) { - // We're currently unmounting this child in ReactMultiChild; skip it. - continue; - } - // We assume the child nodes are in the same order as the child instances. - for (; childNode !== null; childNode = childNode.nextSibling) { - if (shouldPrecacheNode(childNode, childID)) { - precacheNode(childInst, childNode); - continue outer; - } - } - // We reached the end of the DOM children without finding an ID match. - invariant_1(false, 'Unable to find element with ID %s.', childID); + + if (simulated) { + forEachAccumulated(processingEventQueue, executeDispatchesAndReleaseSimulated); + } else { + forEachAccumulated(processingEventQueue, executeDispatchesAndReleaseTopLevel); } - inst._flags |= Flags.hasCachedChildNodes; + !!eventQueue ? invariant_1(false, 'processEventQueue(): Additional events were enqueued while processing an event queue. Support for this has not yet been implemented.') : void 0; + // This would be a good time to rethrow if any of the event handlers threw. + ReactErrorUtils.rethrowCaughtError(); +} + +var EventPluginHub = Object.freeze({ + injection: injection$1, + getListener: getListener, + extractEvents: extractEvents, + enqueueEvents: enqueueEvents, + processEventQueue: processEventQueue +}); + +var IndeterminateComponent = 0; // Before we know whether it is functional or class +var FunctionalComponent = 1; +var ClassComponent = 2; +var HostRoot = 3; // Root of a host tree. Could be nested inside another node. +var HostPortal = 4; // A subtree. Could be an entry point to a different renderer. +var HostComponent = 5; +var HostText = 6; +var CallComponent = 7; +var CallHandlerPhase = 8; +var ReturnComponent = 9; +var Fragment = 10; + +var randomKey = Math.random().toString(36).slice(2); +var internalInstanceKey = '__reactInternalInstance$' + randomKey; +var internalEventHandlersKey = '__reactEventHandlers$' + randomKey; + +function precacheFiberNode$1(hostInst, node) { + node[internalInstanceKey] = hostInst; } /** @@ -864,7 +1302,7 @@ function getClosestInstanceFromNode(node) { } } - var closest; + var closest = void 0; var inst = node[internalInstanceKey]; if (inst.tag === HostComponent || inst.tag === HostText) { // In Fiber, this will always be the deepest root. @@ -872,9 +1310,6 @@ function getClosestInstanceFromNode(node) { } for (; node && (inst = node[internalInstanceKey]); node = parents.pop()) { closest = inst; - if (parents.length) { - precacheChildNodes(inst, node); - } } return closest; @@ -884,30 +1319,23 @@ function getClosestInstanceFromNode(node) { * Given a DOM node, return the ReactDOMComponent or ReactDOMTextComponent * instance, or null if the node was not rendered by this React. */ -function getInstanceFromNode(node) { +function getInstanceFromNode$1(node) { var inst = node[internalInstanceKey]; if (inst) { if (inst.tag === HostComponent || inst.tag === HostText) { return inst; - } else if (inst._hostNode === node) { - return inst; } else { return null; } } - inst = getClosestInstanceFromNode(node); - if (inst != null && inst._hostNode === node) { - return inst; - } else { - return null; - } + return null; } /** * Given a ReactDOMComponent or ReactDOMTextComponent, return the corresponding * DOM node. */ -function getNodeFromInstance(inst) { +function getNodeFromInstance$1(inst) { if (inst.tag === HostComponent || inst.tag === HostText) { // In Fiber this, is just the state node right now. We assume it will be // a host component or host text. @@ -916,50 +1344,265 @@ function getNodeFromInstance(inst) { // Without this first invariant, passing a non-DOM-component triggers the next // invariant for a missing parent, which is super confusing. - !(inst._hostNode !== undefined) ? invariant_1(false, 'getNodeFromInstance: Invalid argument.') : void 0; + invariant_1(false, 'getNodeFromInstance: Invalid argument.'); +} + +function getFiberCurrentPropsFromNode$1(node) { + return node[internalEventHandlersKey] || null; +} + +function updateFiberProps$1(node, props) { + node[internalEventHandlersKey] = props; +} + +var ReactDOMComponentTree = Object.freeze({ + precacheFiberNode: precacheFiberNode$1, + getClosestInstanceFromNode: getClosestInstanceFromNode, + getInstanceFromNode: getInstanceFromNode$1, + getNodeFromInstance: getNodeFromInstance$1, + getFiberCurrentPropsFromNode: getFiberCurrentPropsFromNode$1, + updateFiberProps: updateFiberProps$1 +}); - if (inst._hostNode) { - return inst._hostNode; +function getParent(inst) { + do { + inst = inst['return']; + // TODO: If this is a HostRoot we might want to bail out. + // That is depending on if we want nested subtrees (layers) to bubble + // events to their parent. We could also go through parentNode on the + // host node but that wouldn't work for React Native and doesn't let us + // do the portal feature. + } while (inst && inst.tag !== HostComponent); + if (inst) { + return inst; } + return null; +} - // Walk up the tree until we find an ancestor whose DOM node we have cached. - var parents = []; - while (!inst._hostNode) { - parents.push(inst); - !inst._hostParent ? invariant_1(false, 'React DOM tree root should always have a node reference.') : void 0; - inst = inst._hostParent; +/** + * Return the lowest common ancestor of A and B, or null if they are in + * different trees. + */ +function getLowestCommonAncestor(instA, instB) { + var depthA = 0; + for (var tempA = instA; tempA; tempA = getParent(tempA)) { + depthA++; + } + var depthB = 0; + for (var tempB = instB; tempB; tempB = getParent(tempB)) { + depthB++; + } + + // If A is deeper, crawl up. + while (depthA - depthB > 0) { + instA = getParent(instA); + depthA--; } - // Now parents contains each ancestor that does *not* have a cached native - // node, and `inst` is the deepest ancestor that does. - for (; parents.length; inst = parents.pop()) { - precacheChildNodes(inst, inst._hostNode); + // If B is deeper, crawl up. + while (depthB - depthA > 0) { + instB = getParent(instB); + depthB--; } - return inst._hostNode; + // Walk in lockstep until we find a match. + var depth = depthA; + while (depth--) { + if (instA === instB || instA === instB.alternate) { + return instA; + } + instA = getParent(instA); + instB = getParent(instB); + } + return null; } -function getFiberCurrentPropsFromNode(node) { - return node[internalEventHandlersKey] || null; +/** + * Return if A is an ancestor of B. + */ + + +/** + * Return the parent instance of the passed-in instance. + */ +function getParentInstance(inst) { + return getParent(inst); } -function updateFiberProps$1(node, props) { - node[internalEventHandlersKey] = props; +/** + * Simulates the traversal of a two-phase, capture/bubble event dispatch. + */ +function traverseTwoPhase(inst, fn, arg) { + var path = []; + while (inst) { + path.push(inst); + inst = getParent(inst); + } + var i; + for (i = path.length; i-- > 0;) { + fn(path[i], 'captured', arg); + } + for (i = 0; i < path.length; i++) { + fn(path[i], 'bubbled', arg); + } } -var ReactDOMComponentTree = { - getClosestInstanceFromNode: getClosestInstanceFromNode, - getInstanceFromNode: getInstanceFromNode, - getNodeFromInstance: getNodeFromInstance, - precacheChildNodes: precacheChildNodes, - precacheNode: precacheNode, - uncacheNode: uncacheNode, - precacheFiberNode: precacheFiberNode$1, - getFiberCurrentPropsFromNode: getFiberCurrentPropsFromNode, - updateFiberProps: updateFiberProps$1 -}; +/** + * Traverses the ID hierarchy and invokes the supplied `cb` on any IDs that + * should would receive a `mouseEnter` or `mouseLeave` event. + * + * Does not invoke the callback on the nearest common ancestor because nothing + * "entered" or "left" that element. + */ +function traverseEnterLeave(from, to, fn, argFrom, argTo) { + var common = from && to ? getLowestCommonAncestor(from, to) : null; + var pathFrom = []; + while (true) { + if (!from) { + break; + } + if (from === common) { + break; + } + var alternate = from.alternate; + if (alternate !== null && alternate === common) { + break; + } + pathFrom.push(from); + from = getParent(from); + } + var pathTo = []; + while (true) { + if (!to) { + break; + } + if (to === common) { + break; + } + var _alternate = to.alternate; + if (_alternate !== null && _alternate === common) { + break; + } + pathTo.push(to); + to = getParent(to); + } + for (var i = 0; i < pathFrom.length; i++) { + fn(pathFrom[i], 'bubbled', argFrom); + } + for (var _i = pathTo.length; _i-- > 0;) { + fn(pathTo[_i], 'captured', argTo); + } +} + +/** + * Some event types have a notion of different registration names for different + * "phases" of propagation. This finds listeners by a given phase. + */ +function listenerAtPhase(inst, event, propagationPhase) { + var registrationName = event.dispatchConfig.phasedRegistrationNames[propagationPhase]; + return getListener(inst, registrationName); +} + +/** + * A small set of propagation patterns, each of which will accept a small amount + * of information, and generate a set of "dispatch ready event objects" - which + * are sets of events that have already been annotated with a set of dispatched + * listener functions/ids. The API is designed this way to discourage these + * propagation strategies from actually executing the dispatches, since we + * always want to collect the entire set of dispatches before executing even a + * single one. + */ + +/** + * Tags a `SyntheticEvent` with dispatched listeners. Creating this function + * here, allows us to not have to bind or create functions for each event. + * Mutating the event's members allows us to not have to create a wrapping + * "dispatch" object that pairs the event with the listener. + */ +function accumulateDirectionalDispatches(inst, phase, event) { + { + warning_1(inst, 'Dispatching inst must not be null'); + } + var listener = listenerAtPhase(inst, event, phase); + if (listener) { + event._dispatchListeners = accumulateInto(event._dispatchListeners, listener); + event._dispatchInstances = accumulateInto(event._dispatchInstances, inst); + } +} + +/** + * Collect dispatches (must be entirely collected before dispatching - see unit + * tests). Lazily allocate the array to conserve memory. We must loop through + * each event and perform the traversal for each one. We cannot perform a + * single traversal for the entire collection of events because each event may + * have a different target. + */ +function accumulateTwoPhaseDispatchesSingle(event) { + if (event && event.dispatchConfig.phasedRegistrationNames) { + traverseTwoPhase(event._targetInst, accumulateDirectionalDispatches, event); + } +} + +/** + * Same as `accumulateTwoPhaseDispatchesSingle`, but skips over the targetID. + */ +function accumulateTwoPhaseDispatchesSingleSkipTarget(event) { + if (event && event.dispatchConfig.phasedRegistrationNames) { + var targetInst = event._targetInst; + var parentInst = targetInst ? getParentInstance(targetInst) : null; + traverseTwoPhase(parentInst, accumulateDirectionalDispatches, event); + } +} + +/** + * Accumulates without regard to direction, does not look for phased + * registration names. Same as `accumulateDirectDispatchesSingle` but without + * requiring that the `dispatchMarker` be the same as the dispatched ID. + */ +function accumulateDispatches(inst, ignoredDirection, event) { + if (inst && event && event.dispatchConfig.registrationName) { + var registrationName = event.dispatchConfig.registrationName; + var listener = getListener(inst, registrationName); + if (listener) { + event._dispatchListeners = accumulateInto(event._dispatchListeners, listener); + event._dispatchInstances = accumulateInto(event._dispatchInstances, inst); + } + } +} + +/** + * Accumulates dispatches on an `SyntheticEvent`, but only for the + * `dispatchMarker`. + * @param {SyntheticEvent} event + */ +function accumulateDirectDispatchesSingle(event) { + if (event && event.dispatchConfig.registrationName) { + accumulateDispatches(event._targetInst, null, event); + } +} + +function accumulateTwoPhaseDispatches(events) { + forEachAccumulated(events, accumulateTwoPhaseDispatchesSingle); +} + +function accumulateTwoPhaseDispatchesSkipTarget(events) { + forEachAccumulated(events, accumulateTwoPhaseDispatchesSingleSkipTarget); +} + +function accumulateEnterLeaveDispatches(leave, enter, from, to) { + traverseEnterLeave(from, to, accumulateDispatches, leave, enter); +} + +function accumulateDirectDispatches(events) { + forEachAccumulated(events, accumulateDirectDispatchesSingle); +} -var ReactDOMComponentTree_1 = ReactDOMComponentTree; +var EventPropagators = Object.freeze({ + accumulateTwoPhaseDispatches: accumulateTwoPhaseDispatches, + accumulateTwoPhaseDispatchesSkipTarget: accumulateTwoPhaseDispatchesSkipTarget, + accumulateEnterLeaveDispatches: accumulateEnterLeaveDispatches, + accumulateDirectDispatches: accumulateDirectDispatches +}); /** * Copyright (c) 2013-present, Facebook, Inc. @@ -967,183 +1610,1604 @@ var ReactDOMComponentTree_1 = ReactDOMComponentTree; * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule ReactInstanceMap */ + + +var canUseDOM = !!(typeof window !== 'undefined' && window.document && window.document.createElement); + /** - * `ReactInstanceMap` maintains a mapping from a public facing stateful - * instance (key) and the internal representation (value). This allows public - * methods to accept the user facing instance as an argument and map them back - * to internal methods. + * Simple, lightweight module assisting with the detection and context of + * Worker. Helps avoid circular dependencies and allows code to reason about + * whether or not they are in a Worker, even if they never include the main + * `ReactWorker` dependency. */ +var ExecutionEnvironment = { -// TODO: Replace this with ES6: var ReactInstanceMap = new Map(); + canUseDOM: canUseDOM, -var ReactInstanceMap = { - /** - * This API should be called `delete` but we'd have to make sure to always - * transform these to strings for IE support. When this transform is fully - * supported we can rename it. - */ - remove: function (key) { - key._reactInternalFiber = undefined; + canUseWorkers: typeof Worker !== 'undefined', + + canUseEventListeners: canUseDOM && !!(window.addEventListener || window.attachEvent), + + canUseViewport: canUseDOM && !!window.screen, + + isInWorker: !canUseDOM // For now, this is true - might change in the future. + +}; + +var ExecutionEnvironment_1 = ExecutionEnvironment; + +var contentKey = null; + +/** + * Gets the key used to access text content on a DOM node. + * + * @return {?string} Key used to access text content. + * @internal + */ +function getTextContentAccessor() { + if (!contentKey && ExecutionEnvironment_1.canUseDOM) { + // Prefer textContent to innerText because many browsers support both but + // SVG <text> elements don't support innerText even when <div> does. + contentKey = 'textContent' in document.documentElement ? 'textContent' : 'innerText'; + } + return contentKey; +} + +/** + * This helper object stores information about text content of a target node, + * allowing comparison of content before and after a given event. + * + * Identify the node where selection currently begins, then observe + * both its text content and its current position in the DOM. Since the + * browser may natively replace the target node during composition, we can + * use its position to find its replacement. + * + * + */ +var compositionState = { + _root: null, + _startText: null, + _fallbackText: null +}; + +function initialize(nativeEventTarget) { + compositionState._root = nativeEventTarget; + compositionState._startText = getText(); + return true; +} + +function reset() { + compositionState._root = null; + compositionState._startText = null; + compositionState._fallbackText = null; +} + +function getData() { + if (compositionState._fallbackText) { + return compositionState._fallbackText; + } + + var start; + var startValue = compositionState._startText; + var startLength = startValue.length; + var end; + var endValue = getText(); + var endLength = endValue.length; + + for (start = 0; start < startLength; start++) { + if (startValue[start] !== endValue[start]) { + break; + } + } + + var minEnd = startLength - start; + for (end = 1; end <= minEnd; end++) { + if (startValue[startLength - end] !== endValue[endLength - end]) { + break; + } + } + + var sliceTail = end > 1 ? 1 - end : undefined; + compositionState._fallbackText = endValue.slice(start, sliceTail); + return compositionState._fallbackText; +} + +function getText() { + if ('value' in compositionState._root) { + return compositionState._root.value; + } + return compositionState._root[getTextContentAccessor()]; +} + +var ReactInternals = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; + +var _assign = ReactInternals.assign; + +/* eslint valid-typeof: 0 */ + +var didWarnForAddedNewProperty = false; +var isProxySupported = typeof Proxy === 'function'; +var EVENT_POOL_SIZE = 10; + +var shouldBeReleasedProperties = ['dispatchConfig', '_targetInst', 'nativeEvent', 'isDefaultPrevented', 'isPropagationStopped', '_dispatchListeners', '_dispatchInstances']; + +/** + * @interface Event + * @see http://www.w3.org/TR/DOM-Level-3-Events/ + */ +var EventInterface = { + type: null, + target: null, + // currentTarget is set when dispatching; no use in copying it here + currentTarget: emptyFunction_1.thatReturnsNull, + eventPhase: null, + bubbles: null, + cancelable: null, + timeStamp: function (event) { + return event.timeStamp || Date.now(); + }, + defaultPrevented: null, + isTrusted: null +}; + +/** + * Synthetic events are dispatched by event plugins, typically in response to a + * top-level event delegation handler. + * + * These systems should generally use pooling to reduce the frequency of garbage + * collection. The system should check `isPersistent` to determine whether the + * event should be released into the pool after being dispatched. Users that + * need a persisted event should invoke `persist`. + * + * Synthetic events (and subclasses) implement the DOM Level 3 Events API by + * normalizing browser quirks. Subclasses do not necessarily have to implement a + * DOM interface; custom application-specific events can also subclass this. + * + * @param {object} dispatchConfig Configuration used to dispatch this event. + * @param {*} targetInst Marker identifying the event target. + * @param {object} nativeEvent Native browser event. + * @param {DOMEventTarget} nativeEventTarget Target node. + */ +function SyntheticEvent(dispatchConfig, targetInst, nativeEvent, nativeEventTarget) { + { + // these have a getter/setter for warnings + delete this.nativeEvent; + delete this.preventDefault; + delete this.stopPropagation; + } + + this.dispatchConfig = dispatchConfig; + this._targetInst = targetInst; + this.nativeEvent = nativeEvent; + + var Interface = this.constructor.Interface; + for (var propName in Interface) { + if (!Interface.hasOwnProperty(propName)) { + continue; + } + { + delete this[propName]; // this has a getter/setter for warnings + } + var normalize = Interface[propName]; + if (normalize) { + this[propName] = normalize(nativeEvent); + } else { + if (propName === 'target') { + this.target = nativeEventTarget; + } else { + this[propName] = nativeEvent[propName]; + } + } + } + + var defaultPrevented = nativeEvent.defaultPrevented != null ? nativeEvent.defaultPrevented : nativeEvent.returnValue === false; + if (defaultPrevented) { + this.isDefaultPrevented = emptyFunction_1.thatReturnsTrue; + } else { + this.isDefaultPrevented = emptyFunction_1.thatReturnsFalse; + } + this.isPropagationStopped = emptyFunction_1.thatReturnsFalse; + return this; +} + +_assign(SyntheticEvent.prototype, { + preventDefault: function () { + this.defaultPrevented = true; + var event = this.nativeEvent; + if (!event) { + return; + } + + if (event.preventDefault) { + event.preventDefault(); + } else if (typeof event.returnValue !== 'unknown') { + event.returnValue = false; + } + this.isDefaultPrevented = emptyFunction_1.thatReturnsTrue; }, - get: function (key) { - return key._reactInternalFiber; + stopPropagation: function () { + var event = this.nativeEvent; + if (!event) { + return; + } + + if (event.stopPropagation) { + event.stopPropagation(); + } else if (typeof event.cancelBubble !== 'unknown') { + // The ChangeEventPlugin registers a "propertychange" event for + // IE. This event does not support bubbling or cancelling, and + // any references to cancelBubble throw "Member not found". A + // typeof check of "unknown" circumvents this issue (and is also + // IE specific). + event.cancelBubble = true; + } + + this.isPropagationStopped = emptyFunction_1.thatReturnsTrue; }, - has: function (key) { - return key._reactInternalFiber !== undefined; + /** + * We release all dispatched `SyntheticEvent`s after each event loop, adding + * them back into the pool. This allows a way to hold onto a reference that + * won't be added back into the pool. + */ + persist: function () { + this.isPersistent = emptyFunction_1.thatReturnsTrue; }, - set: function (key, value) { - key._reactInternalFiber = value; + /** + * Checks if this event should be released back into the pool. + * + * @return {boolean} True if this should not be released, false otherwise. + */ + isPersistent: emptyFunction_1.thatReturnsFalse, + + /** + * `PooledClass` looks for `destructor` on each instance it releases. + */ + destructor: function () { + var Interface = this.constructor.Interface; + for (var propName in Interface) { + { + Object.defineProperty(this, propName, getPooledWarningPropertyDefinition(propName, Interface[propName])); + } + } + for (var i = 0; i < shouldBeReleasedProperties.length; i++) { + this[shouldBeReleasedProperties[i]] = null; + } + { + Object.defineProperty(this, 'nativeEvent', getPooledWarningPropertyDefinition('nativeEvent', null)); + Object.defineProperty(this, 'preventDefault', getPooledWarningPropertyDefinition('preventDefault', emptyFunction_1)); + Object.defineProperty(this, 'stopPropagation', getPooledWarningPropertyDefinition('stopPropagation', emptyFunction_1)); + } } -}; +}); -var ReactInstanceMap_1 = ReactInstanceMap; +SyntheticEvent.Interface = EventInterface; -var ReactInternals$1 = require$$0.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; +/** + * Helper to reduce boilerplate when creating subclasses. + * + * @param {function} Class + * @param {?object} Interface + */ +SyntheticEvent.augmentClass = function (Class, Interface) { + var Super = this; -var ReactGlobalSharedState = { - ReactCurrentOwner: ReactInternals$1.ReactCurrentOwner + var E = function () {}; + E.prototype = Super.prototype; + var prototype = new E(); + + _assign(prototype, Class.prototype); + Class.prototype = prototype; + Class.prototype.constructor = Class; + + Class.Interface = _assign({}, Super.Interface, Interface); + Class.augmentClass = Super.augmentClass; + addEventPoolingTo(Class); }; +/** Proxying after everything set on SyntheticEvent + * to resolve Proxy issue on some WebKit browsers + * in which some Event properties are set to undefined (GH#10010) + */ { - assign(ReactGlobalSharedState, { - ReactComponentTreeHook: ReactInternals$1.ReactComponentTreeHook, - ReactDebugCurrentFrame: ReactInternals$1.ReactDebugCurrentFrame - }); + if (isProxySupported) { + /*eslint-disable no-func-assign */ + SyntheticEvent = new Proxy(SyntheticEvent, { + construct: function (target, args) { + return this.apply(target, Object.create(target.prototype), args); + }, + apply: function (constructor, that, args) { + return new Proxy(constructor.apply(that, args), { + set: function (target, prop, value) { + if (prop !== 'isPersistent' && !target.constructor.Interface.hasOwnProperty(prop) && shouldBeReleasedProperties.indexOf(prop) === -1) { + warning_1(didWarnForAddedNewProperty || target.isPersistent(), "This synthetic event is reused for performance reasons. If you're " + "seeing this, you're adding a new property in the synthetic event object. " + 'The property is never released. See ' + 'https://fb.me/react-event-pooling for more information.'); + didWarnForAddedNewProperty = true; + } + target[prop] = value; + return true; + } + }); + } + }); + /*eslint-enable no-func-assign */ + } } -var ReactGlobalSharedState_1 = ReactGlobalSharedState; +addEventPoolingTo(SyntheticEvent); /** - * Copyright (c) 2013-present, Facebook, Inc. + * Helper to nullify syntheticEvent instance properties when destructing * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. + * @param {String} propName + * @param {?object} getVal + * @return {object} defineProperty object + */ +function getPooledWarningPropertyDefinition(propName, getVal) { + var isFunction = typeof getVal === 'function'; + return { + configurable: true, + set: set, + get: get + }; + + function set(val) { + var action = isFunction ? 'setting the method' : 'setting the property'; + warn(action, 'This is effectively a no-op'); + return val; + } + + function get() { + var action = isFunction ? 'accessing the method' : 'accessing the property'; + var result = isFunction ? 'This is a no-op function' : 'This is set to null'; + warn(action, result); + return getVal; + } + + function warn(action, result) { + var warningCondition = false; + warning_1(warningCondition, "This synthetic event is reused for performance reasons. If you're seeing this, " + "you're %s `%s` on a released/nullified synthetic event. %s. " + 'If you must keep the original synthetic event around, use event.persist(). ' + 'See https://fb.me/react-event-pooling for more information.', action, propName, result); + } +} + +function getPooledEvent(dispatchConfig, targetInst, nativeEvent, nativeInst) { + var EventConstructor = this; + if (EventConstructor.eventPool.length) { + var instance = EventConstructor.eventPool.pop(); + EventConstructor.call(instance, dispatchConfig, targetInst, nativeEvent, nativeInst); + return instance; + } + return new EventConstructor(dispatchConfig, targetInst, nativeEvent, nativeInst); +} + +function releasePooledEvent(event) { + var EventConstructor = this; + !(event instanceof EventConstructor) ? invariant_1(false, 'Trying to release an event instance into a pool of a different type.') : void 0; + event.destructor(); + if (EventConstructor.eventPool.length < EVENT_POOL_SIZE) { + EventConstructor.eventPool.push(event); + } +} + +function addEventPoolingTo(EventConstructor) { + EventConstructor.eventPool = []; + EventConstructor.getPooled = getPooledEvent; + EventConstructor.release = releasePooledEvent; +} + +var SyntheticEvent$1 = SyntheticEvent; + +/** + * @interface Event + * @see http://www.w3.org/TR/DOM-Level-3-Events/#events-compositionevents + */ +var CompositionEventInterface = { + data: 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 SyntheticCompositionEvent(dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget) { + return SyntheticEvent$1.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget); +} + +SyntheticEvent$1.augmentClass(SyntheticCompositionEvent, CompositionEventInterface); + +/** + * @interface Event + * @see http://www.w3.org/TR/2013/WD-DOM-Level-3-Events-20131105 + * /#events-inputevents + */ +var InputEventInterface = { + data: 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 SyntheticInputEvent(dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget) { + return SyntheticEvent$1.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget); +} + +SyntheticEvent$1.augmentClass(SyntheticInputEvent, InputEventInterface); + +var END_KEYCODES = [9, 13, 27, 32]; // Tab, Return, Esc, Space +var START_KEYCODE = 229; + +var canUseCompositionEvent = ExecutionEnvironment_1.canUseDOM && 'CompositionEvent' in window; + +var documentMode = null; +if (ExecutionEnvironment_1.canUseDOM && 'documentMode' in document) { + documentMode = document.documentMode; +} + +// Webkit offers a very useful `textInput` event that can be used to +// directly represent `beforeInput`. The IE `textinput` event is not as +// useful, so we don't use it. +var canUseTextInputEvent = ExecutionEnvironment_1.canUseDOM && 'TextEvent' in window && !documentMode && !isPresto(); + +// In IE9+, we have access to composition events, but the data supplied +// by the native compositionend event may be incorrect. Japanese ideographic +// spaces, for instance (\u3000) are not recorded correctly. +var useFallbackCompositionData = ExecutionEnvironment_1.canUseDOM && (!canUseCompositionEvent || documentMode && documentMode > 8 && documentMode <= 11); + +/** + * Opera <= 12 includes TextEvent in window, but does not fire + * text input events. Rely on keypress instead. + */ +function isPresto() { + var opera = window.opera; + return typeof opera === 'object' && typeof opera.version === 'function' && parseInt(opera.version(), 10) <= 12; +} + +var SPACEBAR_CODE = 32; +var SPACEBAR_CHAR = String.fromCharCode(SPACEBAR_CODE); + +// Events and their corresponding property names. +var eventTypes = { + beforeInput: { + phasedRegistrationNames: { + bubbled: 'onBeforeInput', + captured: 'onBeforeInputCapture' + }, + dependencies: ['topCompositionEnd', 'topKeyPress', 'topTextInput', 'topPaste'] + }, + compositionEnd: { + phasedRegistrationNames: { + bubbled: 'onCompositionEnd', + captured: 'onCompositionEndCapture' + }, + dependencies: ['topBlur', 'topCompositionEnd', 'topKeyDown', 'topKeyPress', 'topKeyUp', 'topMouseDown'] + }, + compositionStart: { + phasedRegistrationNames: { + bubbled: 'onCompositionStart', + captured: 'onCompositionStartCapture' + }, + dependencies: ['topBlur', 'topCompositionStart', 'topKeyDown', 'topKeyPress', 'topKeyUp', 'topMouseDown'] + }, + compositionUpdate: { + phasedRegistrationNames: { + bubbled: 'onCompositionUpdate', + captured: 'onCompositionUpdateCapture' + }, + dependencies: ['topBlur', 'topCompositionUpdate', 'topKeyDown', 'topKeyPress', 'topKeyUp', 'topMouseDown'] + } +}; + +// Track whether we've ever handled a keypress on the space key. +var hasSpaceKeypress = false; + +/** + * Return whether a native keypress event is assumed to be a command. + * This is required because Firefox fires `keypress` events for key commands + * (cut, copy, select-all, etc.) even though no character is inserted. + */ +function isKeypressCommand(nativeEvent) { + return (nativeEvent.ctrlKey || nativeEvent.altKey || nativeEvent.metaKey) && + // ctrlKey && altKey is equivalent to AltGr, and is not a command. + !(nativeEvent.ctrlKey && nativeEvent.altKey); +} + +/** + * Translate native top level events into event types. * - * @providesModule getComponentName - * + * @param {string} topLevelType + * @return {object} */ +function getCompositionEventType(topLevelType) { + switch (topLevelType) { + case 'topCompositionStart': + return eventTypes.compositionStart; + case 'topCompositionEnd': + return eventTypes.compositionEnd; + case 'topCompositionUpdate': + return eventTypes.compositionUpdate; + } +} -function getComponentName(instanceOrFiber) { - if (typeof instanceOrFiber.getName === 'function') { - // Stack reconciler - var instance = instanceOrFiber; - return instance.getName(); +/** + * Does our fallback best-guess model think this event signifies that + * composition has begun? + * + * @param {string} topLevelType + * @param {object} nativeEvent + * @return {boolean} + */ +function isFallbackCompositionStart(topLevelType, nativeEvent) { + return topLevelType === 'topKeyDown' && nativeEvent.keyCode === START_KEYCODE; +} + +/** + * Does our fallback mode think that this event is the end of composition? + * + * @param {string} topLevelType + * @param {object} nativeEvent + * @return {boolean} + */ +function isFallbackCompositionEnd(topLevelType, nativeEvent) { + switch (topLevelType) { + case 'topKeyUp': + // Command keys insert or clear IME input. + return END_KEYCODES.indexOf(nativeEvent.keyCode) !== -1; + case 'topKeyDown': + // Expect IME keyCode on each keydown. If we get any other + // code we must have exited earlier. + return nativeEvent.keyCode !== START_KEYCODE; + case 'topKeyPress': + case 'topMouseDown': + case 'topBlur': + // Events are not possible without cancelling IME. + return true; + default: + return false; } - if (typeof instanceOrFiber.tag === 'number') { - // Fiber reconciler - var fiber = instanceOrFiber; - var type = fiber.type; +} - if (typeof type === 'string') { - return type; - } - if (typeof type === 'function') { - return type.displayName || type.name; - } +/** + * Google Input Tools provides composition data via a CustomEvent, + * with the `data` property populated in the `detail` object. If this + * is available on the event object, use it. If not, this is a plain + * composition event and we have nothing special to extract. + * + * @param {object} nativeEvent + * @return {?string} + */ +function getDataFromCustomEvent(nativeEvent) { + var detail = nativeEvent.detail; + if (typeof detail === 'object' && 'data' in detail) { + return detail.data; } return null; } -var getComponentName_1 = getComponentName; +// Track the current IME composition status, if any. +var isComposing = false; /** - * 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. + * @return {?object} A SyntheticCompositionEvent. */ +function extractCompositionEvent(topLevelType, targetInst, nativeEvent, nativeEventTarget) { + var eventType; + var fallbackData; -var warning$2 = emptyFunction_1; - -{ - var printWarning = function printWarning(format) { - for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { - args[_key - 1] = arguments[_key]; + if (canUseCompositionEvent) { + eventType = getCompositionEventType(topLevelType); + } else if (!isComposing) { + if (isFallbackCompositionStart(topLevelType, nativeEvent)) { + eventType = eventTypes.compositionStart; } + } else if (isFallbackCompositionEnd(topLevelType, nativeEvent)) { + eventType = eventTypes.compositionEnd; + } - var argIndex = 0; - var message = 'Warning: ' + format.replace(/%s/g, function () { - return args[argIndex++]; - }); - if (typeof console !== 'undefined') { - console.error(message); + if (!eventType) { + return null; + } + + if (useFallbackCompositionData) { + // The current composition is stored statically and must not be + // overwritten while composition continues. + if (!isComposing && eventType === eventTypes.compositionStart) { + isComposing = initialize(nativeEventTarget); + } else if (eventType === eventTypes.compositionEnd) { + if (isComposing) { + fallbackData = getData(); + } } - 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) {} - }; + } - warning$2 = function warning(condition, format) { - if (format === undefined) { - throw new Error('`warning(condition, format, ...args)` requires a warning ' + 'message argument'); + var event = SyntheticCompositionEvent.getPooled(eventType, targetInst, nativeEvent, nativeEventTarget); + + if (fallbackData) { + // Inject data generated from fallback path into the synthetic event. + // This matches the property of native CompositionEventInterface. + event.data = fallbackData; + } else { + var customData = getDataFromCustomEvent(nativeEvent); + if (customData !== null) { + event.data = customData; } + } - if (format.indexOf('Failed Composite propType: ') === 0) { - return; // Ignore CompositeComponent proptype check. + accumulateTwoPhaseDispatches(event); + return event; +} + +/** + * @param {TopLevelTypes} topLevelType Record from `BrowserEventConstants`. + * @param {object} nativeEvent Native browser event. + * @return {?string} The string corresponding to this `beforeInput` event. + */ +function getNativeBeforeInputChars(topLevelType, nativeEvent) { + switch (topLevelType) { + case 'topCompositionEnd': + return getDataFromCustomEvent(nativeEvent); + case 'topKeyPress': + /** + * If native `textInput` events are available, our goal is to make + * use of them. However, there is a special case: the spacebar key. + * In Webkit, preventing default on a spacebar `textInput` event + * cancels character insertion, but it *also* causes the browser + * to fall back to its default spacebar behavior of scrolling the + * page. + * + * Tracking at: + * https://code.google.com/p/chromium/issues/detail?id=355103 + * + * To avoid this issue, use the keypress event as if no `textInput` + * event is available. + */ + var which = nativeEvent.which; + if (which !== SPACEBAR_CODE) { + return null; + } + + hasSpaceKeypress = true; + return SPACEBAR_CHAR; + + case 'topTextInput': + // Record the characters to be added to the DOM. + var chars = nativeEvent.data; + + // If it's a spacebar character, assume that we have already handled + // it at the keypress level and bail immediately. Android Chrome + // doesn't give us keycodes, so we need to blacklist it. + if (chars === SPACEBAR_CHAR && hasSpaceKeypress) { + return null; + } + + return chars; + + default: + // For other native event types, do nothing. + return null; + } +} + +/** + * For browsers that do not provide the `textInput` event, extract the + * appropriate string to use for SyntheticInputEvent. + * + * @param {string} topLevelType Record from `BrowserEventConstants`. + * @param {object} nativeEvent Native browser event. + * @return {?string} The fallback string for this `beforeInput` event. + */ +function getFallbackBeforeInputChars(topLevelType, nativeEvent) { + // If we are currently composing (IME) and using a fallback to do so, + // try to extract the composed characters from the fallback object. + // If composition event is available, we extract a string only at + // compositionevent, otherwise extract it at fallback events. + if (isComposing) { + if (topLevelType === 'topCompositionEnd' || !canUseCompositionEvent && isFallbackCompositionEnd(topLevelType, nativeEvent)) { + var chars = getData(); + reset(); + isComposing = false; + return chars; } + return null; + } - if (!condition) { - for (var _len2 = arguments.length, args = Array(_len2 > 2 ? _len2 - 2 : 0), _key2 = 2; _key2 < _len2; _key2++) { - args[_key2 - 2] = arguments[_key2]; + switch (topLevelType) { + case 'topPaste': + // If a paste event occurs after a keypress, throw out the input + // chars. Paste events should not lead to BeforeInput events. + return null; + case 'topKeyPress': + /** + * As of v27, Firefox may fire keypress events even when no character + * will be inserted. A few possibilities: + * + * - `which` is `0`. Arrow keys, Esc key, etc. + * + * - `which` is the pressed key code, but no char is available. + * Ex: 'AltGr + d` in Polish. There is no modified character for + * this key combination and no character is inserted into the + * document, but FF fires the keypress for char code `100` anyway. + * No `input` event will occur. + * + * - `which` is the pressed key code, but a command combination is + * being used. Ex: `Cmd+C`. No character is inserted, and no + * `input` event will occur. + */ + if (!isKeypressCommand(nativeEvent)) { + // IE fires the `keypress` event when a user types an emoji via + // Touch keyboard of Windows. In such a case, the `char` property + // holds an emoji character like `\uD83D\uDE0A`. Because its length + // is 2, the property `which` does not represent an emoji correctly. + // In such a case, we directly return the `char` property instead of + // using `which`. + if (nativeEvent.char && nativeEvent.char.length > 1) { + return nativeEvent.char; + } else if (nativeEvent.which) { + return String.fromCharCode(nativeEvent.which); + } } + return null; + case 'topCompositionEnd': + return useFallbackCompositionData ? null : nativeEvent.data; + default: + return null; + } +} - printWarning.apply(undefined, [format].concat(args)); +/** + * Extract a SyntheticInputEvent for `beforeInput`, based on either native + * `textInput` or fallback behavior. + * + * @return {?object} A SyntheticInputEvent. + */ +function extractBeforeInputEvent(topLevelType, targetInst, nativeEvent, nativeEventTarget) { + var chars; + + if (canUseTextInputEvent) { + chars = getNativeBeforeInputChars(topLevelType, nativeEvent); + } else { + chars = getFallbackBeforeInputChars(topLevelType, nativeEvent); + } + + // If no characters are being inserted, no BeforeInput event should + // be fired. + if (!chars) { + return null; + } + + var event = SyntheticInputEvent.getPooled(eventTypes.beforeInput, targetInst, nativeEvent, nativeEventTarget); + + event.data = chars; + accumulateTwoPhaseDispatches(event); + return event; +} + +/** + * Create an `onBeforeInput` event to match + * http://www.w3.org/TR/2013/WD-DOM-Level-3-Events-20131105/#events-inputevents. + * + * This event plugin is based on the native `textInput` event + * available in Chrome, Safari, Opera, and IE. This event fires after + * `onKeyPress` and `onCompositionEnd`, but before `onInput`. + * + * `beforeInput` is spec'd but not implemented in any browsers, and + * the `input` event does not provide any useful information about what has + * actually been added, contrary to the spec. Thus, `textInput` is the best + * available event to identify the characters that have actually been inserted + * into the target node. + * + * This plugin is also responsible for emitting `composition` events, thus + * allowing us to share composition fallback code for both `beforeInput` and + * `composition` event types. + */ +var BeforeInputEventPlugin = { + eventTypes: eventTypes, + + extractEvents: function (topLevelType, targetInst, nativeEvent, nativeEventTarget) { + return [extractCompositionEvent(topLevelType, targetInst, nativeEvent, nativeEventTarget), extractBeforeInputEvent(topLevelType, targetInst, nativeEvent, nativeEventTarget)]; + } +}; + +// Use to restore controlled state after a change event has fired. + +var fiberHostComponent = null; + +var ReactControlledComponentInjection = { + injectFiberControlledHostComponent: function (hostComponentImpl) { + // The fiber implementation doesn't use dynamic dispatch so we need to + // inject the implementation. + fiberHostComponent = hostComponentImpl; + } +}; + +var restoreTarget = null; +var restoreQueue = null; + +function restoreStateOfTarget(target) { + // We perform this translation at the end of the event loop so that we + // always receive the correct fiber here + var internalInstance = getInstanceFromNode(target); + if (!internalInstance) { + // Unmounted + return; + } + !(fiberHostComponent && typeof fiberHostComponent.restoreControlledState === 'function') ? invariant_1(false, 'Fiber needs to be injected to handle a fiber target for controlled events. This error is likely caused by a bug in React. Please file an issue.') : void 0; + var props = getFiberCurrentPropsFromNode(internalInstance.stateNode); + fiberHostComponent.restoreControlledState(internalInstance.stateNode, internalInstance.type, props); +} + +var injection$3 = ReactControlledComponentInjection; + +function enqueueStateRestore(target) { + if (restoreTarget) { + if (restoreQueue) { + restoreQueue.push(target); + } else { + restoreQueue = [target]; + } + } else { + restoreTarget = target; + } +} + +function restoreStateIfNeeded() { + if (!restoreTarget) { + return; + } + var target = restoreTarget; + var queuedTargets = restoreQueue; + restoreTarget = null; + restoreQueue = null; + + restoreStateOfTarget(target); + if (queuedTargets) { + for (var i = 0; i < queuedTargets.length; i++) { + restoreStateOfTarget(queuedTargets[i]); + } + } +} + +var ReactControlledComponent = Object.freeze({ + injection: injection$3, + enqueueStateRestore: enqueueStateRestore, + restoreStateIfNeeded: restoreStateIfNeeded +}); + +// Used as a way to call batchedUpdates when we don't have a reference to +// the renderer. Such as when we're dispatching events or if third party +// libraries need to call batchedUpdates. Eventually, this API will go away when +// everything is batched by default. We'll then have a similar API to opt-out of +// scheduled work and instead do synchronous work. + +// Defaults +var fiberBatchedUpdates = function (fn, bookkeeping) { + return fn(bookkeeping); +}; + +var isNestingBatched = false; +function batchedUpdates(fn, bookkeeping) { + if (isNestingBatched) { + // If we are currently inside another batch, we need to wait until it + // fully completes before restoring state. Therefore, we add the target to + // a queue of work. + return fiberBatchedUpdates(fn, bookkeeping); + } + isNestingBatched = true; + try { + return fiberBatchedUpdates(fn, bookkeeping); + } finally { + // Here we wait until all updates have propagated, which is important + // when using controlled components within layers: + // https://github.com/facebook/react/issues/1698 + // Then we restore state of any controlled component. + isNestingBatched = false; + restoreStateIfNeeded(); + } +} + +var ReactGenericBatchingInjection = { + injectFiberBatchedUpdates: function (_batchedUpdates) { + fiberBatchedUpdates = _batchedUpdates; + } +}; + +var injection$4 = ReactGenericBatchingInjection; + +/** + * @see http://www.whatwg.org/specs/web-apps/current-work/multipage/the-input-element.html#input-type-attr-summary + */ +var supportedInputTypes = { + color: true, + date: true, + datetime: true, + 'datetime-local': true, + email: true, + month: true, + number: true, + password: true, + range: true, + search: true, + tel: true, + text: true, + time: true, + url: true, + week: true +}; + +function isTextInputElement(elem) { + var nodeName = elem && elem.nodeName && elem.nodeName.toLowerCase(); + + if (nodeName === 'input') { + return !!supportedInputTypes[elem.type]; + } + + if (nodeName === 'textarea') { + return true; + } + + return false; +} + +/** + * HTML nodeType values that represent the type of the node + */ + +var ELEMENT_NODE = 1; +var TEXT_NODE = 3; +var COMMENT_NODE = 8; +var DOCUMENT_NODE = 9; +var DOCUMENT_FRAGMENT_NODE = 11; + +/** + * Gets the target node from a native browser event by accounting for + * inconsistencies in browser DOM APIs. + * + * @param {object} nativeEvent Native browser event. + * @return {DOMEventTarget} Target node. + */ +function getEventTarget(nativeEvent) { + var target = nativeEvent.target || nativeEvent.srcElement || window; + + // Normalize SVG <use> element events #4963 + if (target.correspondingUseElement) { + target = target.correspondingUseElement; + } + + // Safari may fire events on text nodes (Node.TEXT_NODE is 3). + // @see http://www.quirksmode.org/js/events_properties.html + return target.nodeType === TEXT_NODE ? target.parentNode : target; +} + +var useHasFeature; +if (ExecutionEnvironment_1.canUseDOM) { + useHasFeature = document.implementation && document.implementation.hasFeature && + // always returns true in newer browsers as per the standard. + // @see http://dom.spec.whatwg.org/#dom-domimplementation-hasfeature + document.implementation.hasFeature('', '') !== true; +} + +/** + * Checks if an event is supported in the current execution environment. + * + * NOTE: This will not work correctly for non-generic events such as `change`, + * `reset`, `load`, `error`, and `select`. + * + * Borrows from Modernizr. + * + * @param {string} eventNameSuffix Event name, e.g. "click". + * @param {?boolean} capture Check if the capture phase is supported. + * @return {boolean} True if the event is supported. + * @internal + * @license Modernizr 3.0.0pre (Custom Build) | MIT + */ +function isEventSupported(eventNameSuffix, capture) { + if (!ExecutionEnvironment_1.canUseDOM || capture && !('addEventListener' in document)) { + return false; + } + + var eventName = 'on' + eventNameSuffix; + var isSupported = eventName in document; + + if (!isSupported) { + var element = document.createElement('div'); + element.setAttribute(eventName, 'return;'); + isSupported = typeof element[eventName] === 'function'; + } + + if (!isSupported && useHasFeature && eventNameSuffix === 'wheel') { + // This is the only way to test support for the `wheel` event in IE9+. + isSupported = document.implementation.hasFeature('Events.wheel', '3.0'); + } + + return isSupported; +} + +function isCheckable(elem) { + var type = elem.type; + var nodeName = elem.nodeName; + return nodeName && nodeName.toLowerCase() === 'input' && (type === 'checkbox' || type === 'radio'); +} + +function getTracker(node) { + return node._valueTracker; +} + +function detachTracker(node) { + node._valueTracker = null; +} + +function getValueFromNode(node) { + var value = ''; + if (!node) { + return value; + } + + if (isCheckable(node)) { + value = node.checked ? 'true' : 'false'; + } else { + value = node.value; + } + + return value; +} + +function trackValueOnNode(node) { + var valueField = isCheckable(node) ? 'checked' : 'value'; + var descriptor = Object.getOwnPropertyDescriptor(node.constructor.prototype, valueField); + + var currentValue = '' + node[valueField]; + + // if someone has already defined a value or Safari, then bail + // and don't track value will cause over reporting of changes, + // but it's better then a hard failure + // (needed for certain tests that spyOn input values and Safari) + if (node.hasOwnProperty(valueField) || typeof descriptor.get !== 'function' || typeof descriptor.set !== 'function') { + return; + } + + Object.defineProperty(node, valueField, { + enumerable: descriptor.enumerable, + configurable: true, + get: function () { + return descriptor.get.call(this); + }, + set: function (value) { + currentValue = '' + value; + descriptor.set.call(this, value); + } + }); + + var tracker = { + getValue: function () { + return currentValue; + }, + setValue: function (value) { + currentValue = '' + value; + }, + stopTracking: function () { + detachTracker(node); + delete node[valueField]; } }; + return tracker; +} + +function track(node) { + if (getTracker(node)) { + return; + } + + // TODO: Once it's just Fiber we can move this to node._wrapperState + node._valueTracker = trackValueOnNode(node); } -var warning_1 = warning$2; +function updateValueIfChanged(node) { + if (!node) { + return false; + } + var tracker = getTracker(node); + // if there is no tracker at this point it's unlikely + // that trying again will succeed + if (!tracker) { + return true; + } + + var lastValue = tracker.getValue(); + var nextValue = getValueFromNode(node); + if (nextValue !== lastValue) { + tracker.setValue(nextValue); + return true; + } + return false; +} + +var eventTypes$1 = { + change: { + phasedRegistrationNames: { + bubbled: 'onChange', + captured: 'onChangeCapture' + }, + dependencies: ['topBlur', 'topChange', 'topClick', 'topFocus', 'topInput', 'topKeyDown', 'topKeyUp', 'topSelectionChange'] + } +}; + +function createAndAccumulateChangeEvent(inst, nativeEvent, target) { + var event = SyntheticEvent$1.getPooled(eventTypes$1.change, inst, nativeEvent, target); + event.type = 'change'; + // Flag this event loop as needing state restore. + enqueueStateRestore(target); + accumulateTwoPhaseDispatches(event); + return event; +} /** - * Copyright (c) 2013-present, Facebook, Inc. + * For IE shims + */ +var activeElement = null; +var activeElementInst = null; + +/** + * SECTION: handle `change` event + */ +function shouldUseChangeEvent(elem) { + var nodeName = elem.nodeName && elem.nodeName.toLowerCase(); + return nodeName === 'select' || nodeName === 'input' && elem.type === 'file'; +} + +function manualDispatchChangeEvent(nativeEvent) { + var event = createAndAccumulateChangeEvent(activeElementInst, nativeEvent, getEventTarget(nativeEvent)); + + // If change and propertychange bubbled, we'd just bind to it like all the + // other events and have it go through ReactBrowserEventEmitter. Since it + // doesn't, we manually listen for the events and so we have to enqueue and + // process the abstract event manually. + // + // Batching is necessary here in order to ensure that all event handlers run + // before the next rerender (including event handlers attached to ancestor + // elements instead of directly on the input). Without this, controlled + // components don't work properly in conjunction with event bubbling because + // the component is rerendered and the value reverted before all the event + // handlers can run. See https://github.com/facebook/react/issues/708. + batchedUpdates(runEventInBatch, event); +} + +function runEventInBatch(event) { + enqueueEvents(event); + processEventQueue(false); +} + +function getInstIfValueChanged(targetInst) { + var targetNode = getNodeFromInstance$1(targetInst); + if (updateValueIfChanged(targetNode)) { + return targetInst; + } +} + +function getTargetInstForChangeEvent(topLevelType, targetInst) { + if (topLevelType === 'topChange') { + return targetInst; + } +} + +/** + * SECTION: handle `input` event + */ +var isInputEventSupported = false; +if (ExecutionEnvironment_1.canUseDOM) { + // IE9 claims to support the input event but fails to trigger it when + // deleting text, so we ignore its input events. + isInputEventSupported = isEventSupported('input') && (!document.documentMode || document.documentMode > 9); +} + +/** + * (For IE <=9) Starts tracking propertychange events on the passed-in element + * and override the value property so that we can distinguish user events from + * value changes in JS. + */ +function startWatchingForValueChange(target, targetInst) { + activeElement = target; + activeElementInst = targetInst; + activeElement.attachEvent('onpropertychange', handlePropertyChange); +} + +/** + * (For IE <=9) Removes the event listeners from the currently-tracked element, + * if any exists. + */ +function stopWatchingForValueChange() { + if (!activeElement) { + return; + } + activeElement.detachEvent('onpropertychange', handlePropertyChange); + activeElement = null; + activeElementInst = null; +} + +/** + * (For IE <=9) Handles a propertychange event, sending a `change` event if + * the value of the active element has changed. + */ +function handlePropertyChange(nativeEvent) { + if (nativeEvent.propertyName !== 'value') { + return; + } + if (getInstIfValueChanged(activeElementInst)) { + manualDispatchChangeEvent(nativeEvent); + } +} + +function handleEventsForInputEventPolyfill(topLevelType, target, targetInst) { + if (topLevelType === 'topFocus') { + // In IE9, propertychange fires for most input events but is buggy and + // doesn't fire when text is deleted, but conveniently, selectionchange + // appears to fire in all of the remaining cases so we catch those and + // forward the event if the value has changed + // In either case, we don't want to call the event handler if the value + // is changed from JS so we redefine a setter for `.value` that updates + // our activeElementValue variable, allowing us to ignore those changes + // + // stopWatching() should be a noop here but we call it just in case we + // missed a blur event somehow. + stopWatchingForValueChange(); + startWatchingForValueChange(target, targetInst); + } else if (topLevelType === 'topBlur') { + stopWatchingForValueChange(); + } +} + +// For IE8 and IE9. +function getTargetInstForInputEventPolyfill(topLevelType, targetInst) { + if (topLevelType === 'topSelectionChange' || topLevelType === 'topKeyUp' || topLevelType === 'topKeyDown') { + // On the selectionchange event, the target is just document which isn't + // helpful for us so just check activeElement instead. + // + // 99% of the time, keydown and keyup aren't necessary. IE8 fails to fire + // propertychange on the first input event after setting `value` from a + // script and fires only keydown, keypress, keyup. Catching keyup usually + // gets it and catching keydown lets us fire an event for the first + // keystroke if user does a key repeat (it'll be a little delayed: right + // before the second keystroke). Other input methods (e.g., paste) seem to + // fire selectionchange normally. + return getInstIfValueChanged(activeElementInst); + } +} + +/** + * SECTION: handle `click` event + */ +function shouldUseClickEvent(elem) { + // Use the `click` event to detect changes to checkbox and radio inputs. + // This approach works across all browsers, whereas `change` does not fire + // until `blur` in IE8. + var nodeName = elem.nodeName; + return nodeName && nodeName.toLowerCase() === 'input' && (elem.type === 'checkbox' || elem.type === 'radio'); +} + +function getTargetInstForClickEvent(topLevelType, targetInst) { + if (topLevelType === 'topClick') { + return getInstIfValueChanged(targetInst); + } +} + +function getTargetInstForInputOrChangeEvent(topLevelType, targetInst) { + if (topLevelType === 'topInput' || topLevelType === 'topChange') { + return getInstIfValueChanged(targetInst); + } +} + +function handleControlledInputBlur(inst, node) { + // TODO: In IE, inst is occasionally null. Why? + if (inst == null) { + return; + } + + // Fiber and ReactDOM keep wrapper state in separate places + var state = inst._wrapperState || node._wrapperState; + + if (!state || !state.controlled || node.type !== 'number') { + return; + } + + // If controlled, assign the value attribute to the current value on blur + var value = '' + node.value; + if (node.getAttribute('value') !== value) { + node.setAttribute('value', value); + } +} + +/** + * This plugin creates an `onChange` event that normalizes change events + * across form elements. This event fires at a time when it's possible to + * change the element's value without seeing a flicker. * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. + * Supported elements are: + * - input (see `isTextInputElement`) + * - textarea + * - select + */ +var ChangeEventPlugin = { + eventTypes: eventTypes$1, + + _isInputEventSupported: isInputEventSupported, + + extractEvents: function (topLevelType, targetInst, nativeEvent, nativeEventTarget) { + var targetNode = targetInst ? getNodeFromInstance$1(targetInst) : window; + + var getTargetInstFunc, handleEventFunc; + if (shouldUseChangeEvent(targetNode)) { + getTargetInstFunc = getTargetInstForChangeEvent; + } else if (isTextInputElement(targetNode)) { + if (isInputEventSupported) { + getTargetInstFunc = getTargetInstForInputOrChangeEvent; + } else { + getTargetInstFunc = getTargetInstForInputEventPolyfill; + handleEventFunc = handleEventsForInputEventPolyfill; + } + } else if (shouldUseClickEvent(targetNode)) { + getTargetInstFunc = getTargetInstForClickEvent; + } + + if (getTargetInstFunc) { + var inst = getTargetInstFunc(topLevelType, targetInst); + if (inst) { + var event = createAndAccumulateChangeEvent(inst, nativeEvent, nativeEventTarget); + return event; + } + } + + if (handleEventFunc) { + handleEventFunc(topLevelType, targetNode, targetInst); + } + + // When blurring, set the value attribute for number inputs + if (topLevelType === 'topBlur') { + handleControlledInputBlur(targetInst, targetNode); + } + } +}; + +/** + * Module that is injectable into `EventPluginHub`, that specifies a + * deterministic ordering of `EventPlugin`s. A convenient way to reason about + * plugins, without having to package every one of them. This is better than + * having plugins be ordered in the same order that they are injected because + * that ordering would be influenced by the packaging order. + * `ResponderEventPlugin` must occur before `SimpleEventPlugin` so that + * preventing default on events is convenient in `SimpleEventPlugin` handlers. + */ +var DOMEventPluginOrder = ['ResponderEventPlugin', 'SimpleEventPlugin', 'TapEventPlugin', 'EnterLeaveEventPlugin', 'ChangeEventPlugin', 'SelectEventPlugin', 'BeforeInputEventPlugin']; + +/** + * @interface UIEvent + * @see http://www.w3.org/TR/DOM-Level-3-Events/ + */ +var UIEventInterface = { + view: null, + detail: 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 SyntheticUIEvent(dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget) { + return SyntheticEvent$1.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget); +} + +SyntheticEvent$1.augmentClass(SyntheticUIEvent, UIEventInterface); + +/** + * Translation from modifier key to the associated property in the event. + * @see http://www.w3.org/TR/DOM-Level-3-Events/#keys-Modifiers + */ + +var modifierKeyToProp = { + Alt: 'altKey', + Control: 'ctrlKey', + Meta: 'metaKey', + Shift: 'shiftKey' +}; + +// IE8 does not implement getModifierState so we simply map it to the only +// modifier keys exposed by the event itself, does not support Lock-keys. +// Currently, all major browsers except Chrome seems to support Lock-keys. +function modifierStateGetter(keyArg) { + var syntheticEvent = this; + var nativeEvent = syntheticEvent.nativeEvent; + if (nativeEvent.getModifierState) { + return nativeEvent.getModifierState(keyArg); + } + var keyProp = modifierKeyToProp[keyArg]; + return keyProp ? !!nativeEvent[keyProp] : false; +} + +function getEventModifierState(nativeEvent) { + return modifierStateGetter; +} + +/** + * @interface MouseEvent + * @see http://www.w3.org/TR/DOM-Level-3-Events/ + */ +var MouseEventInterface = { + screenX: null, + screenY: null, + clientX: null, + clientY: null, + pageX: null, + pageY: null, + ctrlKey: null, + shiftKey: null, + altKey: null, + metaKey: null, + getModifierState: getEventModifierState, + button: null, + buttons: null, + relatedTarget: function (event) { + return event.relatedTarget || (event.fromElement === event.srcElement ? event.toElement : event.fromElement); + } +}; + +/** + * @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 SyntheticMouseEvent(dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget) { + return SyntheticUIEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget); +} + +SyntheticUIEvent.augmentClass(SyntheticMouseEvent, MouseEventInterface); + +var eventTypes$2 = { + mouseEnter: { + registrationName: 'onMouseEnter', + dependencies: ['topMouseOut', 'topMouseOver'] + }, + mouseLeave: { + registrationName: 'onMouseLeave', + dependencies: ['topMouseOut', 'topMouseOver'] + } +}; + +var EnterLeaveEventPlugin = { + eventTypes: eventTypes$2, + + /** + * For almost every interaction we care about, there will be both a top-level + * `mouseover` and `mouseout` event that occurs. Only use `mouseout` so that + * we do not extract duplicate events. However, moving the mouse into the + * browser from outside will not fire a `mouseout` event. In this case, we use + * the `mouseover` top-level event. + */ + extractEvents: function (topLevelType, targetInst, nativeEvent, nativeEventTarget) { + if (topLevelType === 'topMouseOver' && (nativeEvent.relatedTarget || nativeEvent.fromElement)) { + return null; + } + if (topLevelType !== 'topMouseOut' && topLevelType !== 'topMouseOver') { + // Must not be a mouse in or mouse out - ignoring. + return null; + } + + var win; + if (nativeEventTarget.window === nativeEventTarget) { + // `nativeEventTarget` is probably a window object. + win = nativeEventTarget; + } else { + // TODO: Figure out why `ownerDocument` is sometimes undefined in IE8. + var doc = nativeEventTarget.ownerDocument; + if (doc) { + win = doc.defaultView || doc.parentWindow; + } else { + win = window; + } + } + + var from; + var to; + if (topLevelType === 'topMouseOut') { + from = targetInst; + var related = nativeEvent.relatedTarget || nativeEvent.toElement; + to = related ? getClosestInstanceFromNode(related) : null; + } else { + // Moving to a node from outside the window. + from = null; + to = targetInst; + } + + if (from === to) { + // Nothing pertains to our managed components. + return null; + } + + var fromNode = from == null ? win : getNodeFromInstance$1(from); + var toNode = to == null ? win : getNodeFromInstance$1(to); + + var leave = SyntheticMouseEvent.getPooled(eventTypes$2.mouseLeave, from, nativeEvent, nativeEventTarget); + leave.type = 'mouseleave'; + leave.target = fromNode; + leave.relatedTarget = toNode; + + var enter = SyntheticMouseEvent.getPooled(eventTypes$2.mouseEnter, to, nativeEvent, nativeEventTarget); + enter.type = 'mouseenter'; + enter.target = toNode; + enter.relatedTarget = fromNode; + + accumulateEnterLeaveDispatches(leave, enter, from, to); + + return [leave, enter]; + } +}; + +/** + * `ReactInstanceMap` maintains a mapping from a public facing stateful + * instance (key) and the internal representation (value). This allows public + * methods to accept the user facing instance as an argument and map them back + * to internal methods. * - * @providesModule ReactTypeOfSideEffect - * + * Note that this module is currently shared and assumed to be stateless. + * If this becomes an actual Map, that will break. */ -var ReactTypeOfSideEffect = { - // Don't change these two values: - NoEffect: 0, // 0b00000000 - PerformedWork: 1, // 0b00000001 - // You can change the rest (and add more). - Placement: 2, // 0b00000010 - Update: 4, // 0b00000100 - PlacementAndUpdate: 6, // 0b00000110 - Deletion: 8, // 0b00001000 - ContentReset: 16, // 0b00010000 - Callback: 32, // 0b00100000 - Err: 64, // 0b01000000 - Ref: 128 }; +/** + * This API should be called `delete` but we'd have to make sure to always + * transform these to strings for IE support. When this transform is fully + * supported we can rename it. + */ -var ReactCurrentOwner = ReactGlobalSharedState_1.ReactCurrentOwner; +function get(key) { + return key._reactInternalFiber; +} +function has(key) { + return key._reactInternalFiber !== undefined; +} +function set(key, value) { + key._reactInternalFiber = value; +} -{ - var warning$1 = warning_1; +var ReactInternals$1 = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; + +var ReactCurrentOwner = ReactInternals$1.ReactCurrentOwner; +var ReactDebugCurrentFrame = ReactInternals$1.ReactDebugCurrentFrame; + +function getComponentName(fiber) { + var type = fiber.type; + + if (typeof type === 'string') { + return type; + } + if (typeof type === 'function') { + return type.displayName || type.name; + } + return null; } -var ClassComponent = ReactTypeOfWork.ClassComponent; -var HostComponent$1 = ReactTypeOfWork.HostComponent; -var HostRoot$1 = ReactTypeOfWork.HostRoot; -var HostPortal = ReactTypeOfWork.HostPortal; -var HostText$1 = ReactTypeOfWork.HostText; +// Don't change these two values: +var NoEffect = 0; // 0b00000000 +var PerformedWork = 1; // 0b00000001 -var NoEffect = ReactTypeOfSideEffect.NoEffect; -var Placement = ReactTypeOfSideEffect.Placement; +// You can change the rest (and add more). +var Placement = 2; // 0b00000010 +var Update = 4; // 0b00000100 +var PlacementAndUpdate = 6; // 0b00000110 +var Deletion = 8; // 0b00001000 +var ContentReset = 16; // 0b00010000 +var Callback = 32; // 0b00100000 +var Err = 64; // 0b01000000 +var Ref = 128; // 0b10000000 var MOUNTING = 1; var MOUNTED = 2; @@ -1168,7 +3232,7 @@ function isFiberMountedImpl(fiber) { node = node['return']; } } - if (node.tag === HostRoot$1) { + if (node.tag === HostRoot) { // TODO: Check if this was a nested HostRoot when used with // renderContainerIntoSubtree. return MOUNTED; @@ -1177,27 +3241,28 @@ function isFiberMountedImpl(fiber) { // that has been unmounted. return UNMOUNTED; } -var isFiberMounted = function (fiber) { + +function isFiberMounted(fiber) { return isFiberMountedImpl(fiber) === MOUNTED; -}; +} -var isMounted = function (component) { +function isMounted(component) { { var owner = ReactCurrentOwner.current; if (owner !== null && owner.tag === ClassComponent) { var ownerFiber = owner; var instance = ownerFiber.stateNode; - warning$1(instance._warnedAboutRefsInRender, '%s is accessing isMounted inside its render() function. ' + 'render() should be a pure function of props and state. It should ' + 'never access something that requires stale data from the previous ' + 'render, such as refs. Move this logic to componentDidMount and ' + 'componentDidUpdate instead.', getComponentName_1(ownerFiber) || 'A component'); + warning_1(instance._warnedAboutRefsInRender, '%s is accessing isMounted inside its render() function. ' + 'render() should be a pure function of props and state. It should ' + 'never access something that requires stale data from the previous ' + 'render, such as refs. Move this logic to componentDidMount and ' + 'componentDidUpdate instead.', getComponentName(ownerFiber) || 'A component'); instance._warnedAboutRefsInRender = true; } } - var fiber = ReactInstanceMap_1.get(component); + var fiber = get(component); if (!fiber) { return false; } return isFiberMountedImpl(fiber) === MOUNTED; -}; +} function assertIsMounted(fiber) { !(isFiberMountedImpl(fiber) === MOUNTED) ? invariant_1(false, 'Unable to find node on an unmounted component.') : void 0; @@ -1306,7 +3371,7 @@ function findCurrentFiberUsingSlowPath(fiber) { } // If the root is not a host container, we're in a disconnected tree. I.e. // unmounted. - !(a.tag === HostRoot$1) ? invariant_1(false, 'Unable to find node on an unmounted component.') : void 0; + !(a.tag === HostRoot) ? invariant_1(false, 'Unable to find node on an unmounted component.') : void 0; if (a.stateNode.current === a) { // We've determined that A is the current branch. return fiber; @@ -1314,9 +3379,8 @@ function findCurrentFiberUsingSlowPath(fiber) { // Otherwise B has to be current branch. return alternate; } -var findCurrentFiberUsingSlowPath_1 = findCurrentFiberUsingSlowPath; -var findCurrentHostFiber = function (parent) { +function findCurrentHostFiber(parent) { var currentParent = findCurrentFiberUsingSlowPath(parent); if (!currentParent) { return null; @@ -1325,7 +3389,7 @@ var findCurrentHostFiber = function (parent) { // Next we'll drill down this component to find the first HostComponent/Text. var node = currentParent; while (true) { - if (node.tag === HostComponent$1 || node.tag === HostText$1) { + if (node.tag === HostComponent || node.tag === HostText) { return node; } else if (node.child) { node.child['return'] = node; @@ -1347,9 +3411,9 @@ var findCurrentHostFiber = function (parent) { // Flow needs the return null here, but ESLint complains about it. // eslint-disable-next-line no-unreachable return null; -}; +} -var findCurrentHostFiberWithNoPortals = function (parent) { +function findCurrentHostFiberWithNoPortals(parent) { var currentParent = findCurrentFiberUsingSlowPath(parent); if (!currentParent) { return null; @@ -1358,7 +3422,7 @@ var findCurrentHostFiberWithNoPortals = function (parent) { // Next we'll drill down this component to find the first HostComponent/Text. var node = currentParent; while (true) { - if (node.tag === HostComponent$1 || node.tag === HostText$1) { + if (node.tag === HostComponent || node.tag === HostText) { return node; } else if (node.child && node.tag !== HostPortal) { node.child['return'] = node; @@ -1380,570 +3444,80 @@ var findCurrentHostFiberWithNoPortals = function (parent) { // Flow needs the return null here, but ESLint complains about it. // eslint-disable-next-line no-unreachable return null; -}; - -var ReactFiberTreeReflection = { - isFiberMounted: isFiberMounted, - isMounted: isMounted, - findCurrentFiberUsingSlowPath: findCurrentFiberUsingSlowPath_1, - findCurrentHostFiber: findCurrentHostFiber, - findCurrentHostFiberWithNoPortals: findCurrentHostFiberWithNoPortals -}; - -var ReactErrorUtils = { - // Used by Fiber to simulate a try-catch. - _caughtError: null, - _hasCaughtError: false, +} - // Used by event system to capture/rethrow the first error. - _rethrowError: null, - _hasRethrowError: false, +/** + * Copyright (c) 2013-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @typechecks + */ - injection: { - injectErrorUtils: function (injectedErrorUtils) { - !(typeof injectedErrorUtils.invokeGuardedCallback === 'function') ? invariant_1(false, 'Injected invokeGuardedCallback() must be a function.') : void 0; - invokeGuardedCallback = injectedErrorUtils.invokeGuardedCallback; - } - }, - /** - * Call a function while guarding against errors that happens within it. - * Returns an error if it throws, otherwise null. - * - * In production, this is implemented using a try-catch. The reason we don't - * use a try-catch directly is so that we can swap out a different - * implementation in DEV mode. - * - * @param {String} name of the guard to use for logging or debugging - * @param {Function} func The function to invoke - * @param {*} context The context to use when calling the function - * @param {...*} args Arguments for function - */ - invokeGuardedCallback: function (name, func, context, a, b, c, d, e, f) { - invokeGuardedCallback.apply(ReactErrorUtils, arguments); - }, +/** + * Upstream version of event listener. Does not take into account specific + * nature of platform. + */ +var EventListener = { /** - * Same as invokeGuardedCallback, but instead of returning an error, it stores - * it in a global so it can be rethrown by `rethrowCaughtError` later. - * TODO: See if _caughtError and _rethrowError can be unified. + * Listen to DOM events during the bubble phase. * - * @param {String} name of the guard to use for logging or debugging - * @param {Function} func The function to invoke - * @param {*} context The context to use when calling the function - * @param {...*} args Arguments for function + * @param {DOMEventTarget} target DOM element to register listener on. + * @param {string} eventType Event type, e.g. 'click' or 'mouseover'. + * @param {function} callback Callback function. + * @return {object} Object with a `remove` method. */ - invokeGuardedCallbackAndCatchFirstError: function (name, func, context, a, b, c, d, e, f) { - ReactErrorUtils.invokeGuardedCallback.apply(this, arguments); - if (ReactErrorUtils.hasCaughtError()) { - var error = ReactErrorUtils.clearCaughtError(); - if (!ReactErrorUtils._hasRethrowError) { - ReactErrorUtils._hasRethrowError = true; - ReactErrorUtils._rethrowError = error; - } + listen: function listen(target, eventType, callback) { + if (target.addEventListener) { + target.addEventListener(eventType, callback, false); + return { + remove: function remove() { + target.removeEventListener(eventType, callback, false); + } + }; + } else if (target.attachEvent) { + target.attachEvent('on' + eventType, callback); + return { + remove: function remove() { + target.detachEvent('on' + eventType, callback); + } + }; } }, /** - * During execution of guarded functions we will capture the first error which - * we will rethrow to be handled by the top level error handler. + * Listen to DOM events during the capture phase. + * + * @param {DOMEventTarget} target DOM element to register listener on. + * @param {string} eventType Event type, e.g. 'click' or 'mouseover'. + * @param {function} callback Callback function. + * @return {object} Object with a `remove` method. */ - rethrowCaughtError: function () { - return rethrowCaughtError.apply(ReactErrorUtils, arguments); - }, - - hasCaughtError: function () { - return ReactErrorUtils._hasCaughtError; - }, - - clearCaughtError: function () { - if (ReactErrorUtils._hasCaughtError) { - var error = ReactErrorUtils._caughtError; - ReactErrorUtils._caughtError = null; - ReactErrorUtils._hasCaughtError = false; - return error; - } else { - invariant_1(false, 'clearCaughtError was called but no error was captured. This error is likely caused by a bug in React. Please file an issue.'); - } - } -}; - -var invokeGuardedCallback = function (name, func, context, a, b, c, d, e, f) { - ReactErrorUtils._hasCaughtError = false; - ReactErrorUtils._caughtError = null; - var funcArgs = Array.prototype.slice.call(arguments, 3); - try { - func.apply(context, funcArgs); - } catch (error) { - ReactErrorUtils._caughtError = error; - ReactErrorUtils._hasCaughtError = true; - } -}; - -{ - // In DEV mode, we swap out invokeGuardedCallback for a special version - // that plays more nicely with the browser's DevTools. The idea is to preserve - // "Pause on exceptions" behavior. Because React wraps all user-provided - // functions in invokeGuardedCallback, and the production version of - // invokeGuardedCallback uses a try-catch, all user exceptions are treated - // like caught exceptions, and the DevTools won't pause unless the developer - // takes the extra step of enabling pause on caught exceptions. This is - // untintuitive, though, because even though React has caught the error, from - // the developer's perspective, the error is uncaught. - // - // To preserve the expected "Pause on exceptions" behavior, we don't use a - // try-catch in DEV. Instead, we synchronously dispatch a fake event to a fake - // DOM node, and call the user-provided callback from inside an event handler - // for that fake event. If the callback throws, the error is "captured" using - // a global event handler. But because the error happens in a different - // event loop context, it does not interrupt the normal program flow. - // Effectively, this gives us try-catch behavior without actually using - // try-catch. Neat! - - // Check that the browser supports the APIs we need to implement our special - // DEV version of invokeGuardedCallback - if (typeof window !== 'undefined' && typeof window.dispatchEvent === 'function' && typeof document !== 'undefined' && typeof document.createEvent === 'function') { - var fakeNode = document.createElement('react'); - - var invokeGuardedCallbackDev = function (name, func, context, a, b, c, d, e, f) { - // Keeps track of whether the user-provided callback threw an error. We - // set this to true at the beginning, then set it to false right after - // calling the function. If the function errors, `didError` will never be - // set to false. This strategy works even if the browser is flaky and - // fails to call our global error handler, because it doesn't rely on - // the error event at all. - var didError = true; - - // Create an event handler for our fake event. We will synchronously - // dispatch our fake event using `dispatchEvent`. Inside the handler, we - // call the user-provided callback. - var funcArgs = Array.prototype.slice.call(arguments, 3); - function callCallback() { - // We immediately remove the callback from event listeners so that - // nested `invokeGuardedCallback` calls do not clash. Otherwise, a - // nested call would trigger the fake event handlers of any call higher - // in the stack. - fakeNode.removeEventListener(evtType, callCallback, false); - func.apply(context, funcArgs); - didError = false; - } - - // Create a global error event handler. We use this to capture the value - // that was thrown. It's possible that this error handler will fire more - // than once; for example, if non-React code also calls `dispatchEvent` - // and a handler for that event throws. We should be resilient to most of - // those cases. Even if our error event handler fires more than once, the - // last error event is always used. If the callback actually does error, - // we know that the last error event is the correct one, because it's not - // possible for anything else to have happened in between our callback - // erroring and the code that follows the `dispatchEvent` call below. If - // the callback doesn't error, but the error event was fired, we know to - // ignore it because `didError` will be false, as described above. - var error = void 0; - // Use this to track whether the error event is ever called. - var didSetError = false; - var isCrossOriginError = false; - - function onError(event) { - error = event.error; - didSetError = true; - if (error === null && event.colno === 0 && event.lineno === 0) { - isCrossOriginError = true; - } - } - - // Create a fake event type. - var evtType = 'react-' + (name ? name : 'invokeguardedcallback'); - - // Attach our event handlers - window.addEventListener('error', onError); - fakeNode.addEventListener(evtType, callCallback, false); - - // Synchronously dispatch our fake event. If the user-provided function - // errors, it will trigger our global error handler. - var evt = document.createEvent('Event'); - evt.initEvent(evtType, false, false); - fakeNode.dispatchEvent(evt); - - if (didError) { - if (!didSetError) { - // The callback errored, but the error event never fired. - error = new Error('An error was thrown inside one of your components, but React ' + "doesn't know what it was. This is likely due to browser " + 'flakiness. React does its best to preserve the "Pause on ' + 'exceptions" behavior of the DevTools, which requires some ' + "DEV-mode only tricks. It's possible that these don't work in " + 'your browser. Try triggering the error in production mode, ' + 'or switching to a modern browser. If you suspect that this is ' + 'actually an issue with React, please file an issue.'); - } else if (isCrossOriginError) { - error = new Error("A cross-origin error was thrown. React doesn't have access to " + 'the actual error object in development. ' + 'See https://fb.me/react-crossorigin-error for more information.'); + capture: function capture(target, eventType, callback) { + if (target.addEventListener) { + target.addEventListener(eventType, callback, true); + return { + remove: function remove() { + target.removeEventListener(eventType, callback, true); } - ReactErrorUtils._hasCaughtError = true; - ReactErrorUtils._caughtError = error; - } else { - ReactErrorUtils._hasCaughtError = false; - ReactErrorUtils._caughtError = null; - } - - // Remove our event listeners - window.removeEventListener('error', onError); - }; - - invokeGuardedCallback = invokeGuardedCallbackDev; - } -} - -var rethrowCaughtError = function () { - if (ReactErrorUtils._hasRethrowError) { - var error = ReactErrorUtils._rethrowError; - ReactErrorUtils._rethrowError = null; - ReactErrorUtils._hasRethrowError = false; - throw error; - } -}; - -var ReactErrorUtils_1 = ReactErrorUtils; - -{ - var warning$3 = warning_1; -} - -/** - * Injected dependencies: - */ - -/** - * - `ComponentTree`: [required] Module that can convert between React instances - * and actual node references. - */ -var ComponentTree; -var injection = { - injectComponentTree: function (Injected) { - ComponentTree = Injected; - { - warning$3(Injected && Injected.getNodeFromInstance && Injected.getInstanceFromNode, 'EventPluginUtils.injection.injectComponentTree(...): Injected ' + 'module is missing getNodeFromInstance or getInstanceFromNode.'); - } - } -}; - -function isEndish(topLevelType) { - return topLevelType === 'topMouseUp' || topLevelType === 'topTouchEnd' || topLevelType === 'topTouchCancel'; -} - -function isMoveish(topLevelType) { - return topLevelType === 'topMouseMove' || topLevelType === 'topTouchMove'; -} -function isStartish(topLevelType) { - return topLevelType === 'topMouseDown' || topLevelType === 'topTouchStart'; -} - -var validateEventDispatches; -{ - validateEventDispatches = function (event) { - var dispatchListeners = event._dispatchListeners; - var dispatchInstances = event._dispatchInstances; - - var listenersIsArr = Array.isArray(dispatchListeners); - var listenersLen = listenersIsArr ? dispatchListeners.length : dispatchListeners ? 1 : 0; - - var instancesIsArr = Array.isArray(dispatchInstances); - var instancesLen = instancesIsArr ? dispatchInstances.length : dispatchInstances ? 1 : 0; - - warning$3(instancesIsArr === listenersIsArr && instancesLen === listenersLen, 'EventPluginUtils: Invalid `event`.'); - }; -} - -/** - * Dispatch the event to the listener. - * @param {SyntheticEvent} event SyntheticEvent to handle - * @param {boolean} simulated If the event is simulated (changes exn behavior) - * @param {function} listener Application-level callback - * @param {*} inst Internal component instance - */ -function executeDispatch(event, simulated, listener, inst) { - var type = event.type || 'unknown-event'; - event.currentTarget = EventPluginUtils.getNodeFromInstance(inst); - ReactErrorUtils_1.invokeGuardedCallbackAndCatchFirstError(type, listener, undefined, event); - event.currentTarget = null; -} - -/** - * Standard/simple iteration through an event's collected dispatches. - */ -function executeDispatchesInOrder(event, simulated) { - var dispatchListeners = event._dispatchListeners; - var dispatchInstances = event._dispatchInstances; - { - validateEventDispatches(event); - } - if (Array.isArray(dispatchListeners)) { - for (var i = 0; i < dispatchListeners.length; i++) { - if (event.isPropagationStopped()) { - break; - } - // Listeners and Instances are two parallel arrays that are always in sync. - executeDispatch(event, simulated, dispatchListeners[i], dispatchInstances[i]); - } - } else if (dispatchListeners) { - executeDispatch(event, simulated, dispatchListeners, dispatchInstances); - } - event._dispatchListeners = null; - event._dispatchInstances = null; -} - -/** - * Standard/simple iteration through an event's collected dispatches, but stops - * at the first dispatch execution returning true, and returns that id. - * - * @return {?string} id of the first dispatch execution who's listener returns - * true, or null if no listener returned true. - */ -function executeDispatchesInOrderStopAtTrueImpl(event) { - var dispatchListeners = event._dispatchListeners; - var dispatchInstances = event._dispatchInstances; - { - validateEventDispatches(event); - } - if (Array.isArray(dispatchListeners)) { - for (var i = 0; i < dispatchListeners.length; i++) { - if (event.isPropagationStopped()) { - break; - } - // Listeners and Instances are two parallel arrays that are always in sync. - if (dispatchListeners[i](event, dispatchInstances[i])) { - return dispatchInstances[i]; - } - } - } else if (dispatchListeners) { - if (dispatchListeners(event, dispatchInstances)) { - return dispatchInstances; - } - } - return null; -} - -/** - * @see executeDispatchesInOrderStopAtTrueImpl - */ -function executeDispatchesInOrderStopAtTrue(event) { - var ret = executeDispatchesInOrderStopAtTrueImpl(event); - event._dispatchInstances = null; - event._dispatchListeners = null; - return ret; -} - -/** - * Execution of a "direct" dispatch - there must be at most one dispatch - * accumulated on the event or it is considered an error. It doesn't really make - * sense for an event with multiple dispatches (bubbled) to keep track of the - * return values at each dispatch execution, but it does tend to make sense when - * dealing with "direct" dispatches. - * - * @return {*} The return value of executing the single dispatch. - */ -function executeDirectDispatch(event) { - { - validateEventDispatches(event); - } - var dispatchListener = event._dispatchListeners; - var dispatchInstance = event._dispatchInstances; - !!Array.isArray(dispatchListener) ? invariant_1(false, 'executeDirectDispatch(...): Invalid `event`.') : void 0; - event.currentTarget = dispatchListener ? EventPluginUtils.getNodeFromInstance(dispatchInstance) : null; - var res = dispatchListener ? dispatchListener(event) : null; - event.currentTarget = null; - event._dispatchListeners = null; - event._dispatchInstances = null; - return res; -} - -/** - * @param {SyntheticEvent} event - * @return {boolean} True iff number of dispatches accumulated is greater than 0. - */ -function hasDispatches(event) { - return !!event._dispatchListeners; -} - -/** - * General utilities that are useful in creating custom Event Plugins. - */ -var EventPluginUtils = { - isEndish: isEndish, - isMoveish: isMoveish, - isStartish: isStartish, - - executeDirectDispatch: executeDirectDispatch, - executeDispatchesInOrder: executeDispatchesInOrder, - executeDispatchesInOrderStopAtTrue: executeDispatchesInOrderStopAtTrue, - hasDispatches: hasDispatches, - - getFiberCurrentPropsFromNode: function (node) { - return ComponentTree.getFiberCurrentPropsFromNode(node); - }, - getInstanceFromNode: function (node) { - return ComponentTree.getInstanceFromNode(node); - }, - getNodeFromInstance: function (node) { - return ComponentTree.getNodeFromInstance(node); - }, - - injection: injection -}; - -var EventPluginUtils_1 = EventPluginUtils; - -// Use to restore controlled state after a change event has fired. - -var fiberHostComponent = null; - -var ReactControlledComponentInjection = { - injectFiberControlledHostComponent: function (hostComponentImpl) { - // The fiber implementation doesn't use dynamic dispatch so we need to - // inject the implementation. - fiberHostComponent = hostComponentImpl; - } -}; - -var restoreTarget = null; -var restoreQueue = null; - -function restoreStateOfTarget(target) { - // We perform this translation at the end of the event loop so that we - // always receive the correct fiber here - var internalInstance = EventPluginUtils_1.getInstanceFromNode(target); - if (!internalInstance) { - // Unmounted - return; - } - if (typeof internalInstance.tag === 'number') { - !(fiberHostComponent && typeof fiberHostComponent.restoreControlledState === 'function') ? invariant_1(false, 'Fiber needs to be injected to handle a fiber target for controlled events. This error is likely caused by a bug in React. Please file an issue.') : void 0; - var props = EventPluginUtils_1.getFiberCurrentPropsFromNode(internalInstance.stateNode); - fiberHostComponent.restoreControlledState(internalInstance.stateNode, internalInstance.type, props); - return; - } - !(typeof internalInstance.restoreControlledState === 'function') ? invariant_1(false, 'The internal instance must be a React host component. This error is likely caused by a bug in React. Please file an issue.') : void 0; - // If it is not a Fiber, we can just use dynamic dispatch. - internalInstance.restoreControlledState(); -} - -var ReactControlledComponent = { - injection: ReactControlledComponentInjection, - - enqueueStateRestore: function (target) { - if (restoreTarget) { - if (restoreQueue) { - restoreQueue.push(target); - } else { - restoreQueue = [target]; - } + }; } else { - restoreTarget = target; - } - }, - restoreStateIfNeeded: function () { - if (!restoreTarget) { - return; - } - var target = restoreTarget; - var queuedTargets = restoreQueue; - restoreTarget = null; - restoreQueue = null; - - restoreStateOfTarget(target); - if (queuedTargets) { - for (var i = 0; i < queuedTargets.length; i++) { - restoreStateOfTarget(queuedTargets[i]); + { + console.error('Attempted to listen to events during the capture phase on a ' + 'browser that does not support the capture phase. Your application ' + 'will not receive some events.'); } + return { + remove: emptyFunction_1 + }; } - } -}; - -var ReactControlledComponent_1 = ReactControlledComponent; - -// Used as a way to call batchedUpdates when we don't know if we're in a Fiber -// or Stack context. Such as when we're dispatching events or if third party -// libraries need to call batchedUpdates. Eventually, this API will go away when -// everything is batched by default. We'll then have a similar API to opt-out of -// scheduled work and instead do synchronous work. - -// Defaults -var stackBatchedUpdates = function (fn, a, b, c, d, e) { - return fn(a, b, c, d, e); -}; -var fiberBatchedUpdates = function (fn, bookkeeping) { - return fn(bookkeeping); -}; - -function performFiberBatchedUpdates(fn, bookkeeping) { - // If we have Fiber loaded, we need to wrap this in a batching call so that - // Fiber can apply its default priority for this call. - return fiberBatchedUpdates(fn, bookkeeping); -} -function batchedUpdates(fn, bookkeeping) { - // We first perform work with the stack batching strategy, by passing our - // indirection to it. - return stackBatchedUpdates(performFiberBatchedUpdates, fn, bookkeeping); -} - -var isNestingBatched = false; -function batchedUpdatesWithControlledComponents(fn, bookkeeping) { - if (isNestingBatched) { - // If we are currently inside another batch, we need to wait until it - // fully completes before restoring state. Therefore, we add the target to - // a queue of work. - return batchedUpdates(fn, bookkeeping); - } - isNestingBatched = true; - try { - return batchedUpdates(fn, bookkeeping); - } finally { - // Here we wait until all updates have propagated, which is important - // when using controlled components within layers: - // https://github.com/facebook/react/issues/1698 - // Then we restore state of any controlled component. - isNestingBatched = false; - ReactControlledComponent_1.restoreStateIfNeeded(); - } -} - -var ReactGenericBatchingInjection = { - injectStackBatchedUpdates: function (_batchedUpdates) { - stackBatchedUpdates = _batchedUpdates; }, - injectFiberBatchedUpdates: function (_batchedUpdates) { - fiberBatchedUpdates = _batchedUpdates; - } -}; -var ReactGenericBatching = { - batchedUpdates: batchedUpdatesWithControlledComponents, - injection: ReactGenericBatchingInjection + registerDefault: function registerDefault() {} }; -var ReactGenericBatching_1 = ReactGenericBatching; - -var TEXT_NODE$1 = HTMLNodeType_1.TEXT_NODE; - -/** - * Gets the target node from a native browser event by accounting for - * inconsistencies in browser DOM APIs. - * - * @param {object} nativeEvent Native browser event. - * @return {DOMEventTarget} Target node. - */ - - -function getEventTarget(nativeEvent) { - var target = nativeEvent.target || nativeEvent.srcElement || window; - - // Normalize SVG <use> element events #4963 - if (target.correspondingUseElement) { - target = target.correspondingUseElement; - } - - // Safari may fire events on text nodes (Node.TEXT_NODE is 3). - // @see http://www.quirksmode.org/js/events_properties.html - return target.nodeType === TEXT_NODE$1 ? target.parentNode : target; -} - -var getEventTarget_1 = getEventTarget; - -var HostRoot = ReactTypeOfWork.HostRoot; - +var EventListener_1 = EventListener; var CALLBACK_BOOKKEEPING_POOL_SIZE = 10; var callbackBookkeepingPool = []; @@ -1957,22 +3531,14 @@ function findRootContainerNode(inst) { // TODO: It may be a good idea to cache this to prevent unnecessary DOM // traversal, but caching is difficult to do correctly without using a // mutation observer to listen for all DOM changes. - if (typeof inst.tag === 'number') { - while (inst['return']) { - inst = inst['return']; - } - if (inst.tag !== HostRoot) { - // This can happen if we're in a detached tree. - return null; - } - return inst.stateNode.containerInfo; - } else { - while (inst._hostParent) { - inst = inst._hostParent; - } - var rootNode = ReactDOMComponentTree_1.getNodeFromInstance(inst); - return rootNode.parentNode; + while (inst['return']) { + inst = inst['return']; + } + if (inst.tag !== HostRoot) { + // This can happen if we're in a detached tree. + return null; } + return inst.stateNode.containerInfo; } // Used to store ancestor hierarchy in top level callback @@ -2020,423 +3586,101 @@ function handleTopLevelImpl(bookKeeping) { break; } bookKeeping.ancestors.push(ancestor); - ancestor = ReactDOMComponentTree_1.getClosestInstanceFromNode(root); + ancestor = getClosestInstanceFromNode(root); } while (ancestor); for (var i = 0; i < bookKeeping.ancestors.length; i++) { targetInst = bookKeeping.ancestors[i]; - ReactDOMEventListener._handleTopLevel(bookKeeping.topLevelType, targetInst, bookKeeping.nativeEvent, getEventTarget_1(bookKeeping.nativeEvent)); + _handleTopLevel(bookKeeping.topLevelType, targetInst, bookKeeping.nativeEvent, getEventTarget(bookKeeping.nativeEvent)); } } -var ReactDOMEventListener = { - _enabled: true, - _handleTopLevel: null, - - setHandleTopLevel: function (handleTopLevel) { - ReactDOMEventListener._handleTopLevel = handleTopLevel; - }, - - setEnabled: function (enabled) { - ReactDOMEventListener._enabled = !!enabled; - }, - - isEnabled: function () { - return ReactDOMEventListener._enabled; - }, - - /** - * Traps top-level events by using event bubbling. - * - * @param {string} topLevelType Record from `BrowserEventConstants`. - * @param {string} handlerBaseName Event name (e.g. "click"). - * @param {object} element Element on which to attach listener. - * @return {?object} An object with a remove function which will forcefully - * remove the listener. - * @internal - */ - trapBubbledEvent: function (topLevelType, handlerBaseName, element) { - if (!element) { - return null; - } - return EventListener_1.listen(element, handlerBaseName, ReactDOMEventListener.dispatchEvent.bind(null, topLevelType)); - }, - - /** - * Traps a top-level event by using event capturing. - * - * @param {string} topLevelType Record from `BrowserEventConstants`. - * @param {string} handlerBaseName Event name (e.g. "click"). - * @param {object} element Element on which to attach listener. - * @return {?object} An object with a remove function which will forcefully - * remove the listener. - * @internal - */ - trapCapturedEvent: function (topLevelType, handlerBaseName, element) { - if (!element) { - return null; - } - return EventListener_1.capture(element, handlerBaseName, ReactDOMEventListener.dispatchEvent.bind(null, topLevelType)); - }, - - dispatchEvent: function (topLevelType, nativeEvent) { - if (!ReactDOMEventListener._enabled) { - return; - } - - var nativeEventTarget = getEventTarget_1(nativeEvent); - var targetInst = ReactDOMComponentTree_1.getClosestInstanceFromNode(nativeEventTarget); - if (targetInst !== null && typeof targetInst.tag === 'number' && !ReactFiberTreeReflection.isFiberMounted(targetInst)) { - // If we get an event (ex: img onload) before committing that - // component's mount, ignore it for now (that is, treat it as if it was an - // event on a non-React tree). We might also consider queueing events and - // dispatching them after the mount. - targetInst = null; - } - - var bookKeeping = getTopLevelCallbackBookKeeping(topLevelType, nativeEvent, targetInst); - - try { - // Event queue being processed in the same cycle allows - // `preventDefault`. - ReactGenericBatching_1.batchedUpdates(handleTopLevelImpl, bookKeeping); - } finally { - releaseTopLevelCallbackBookKeeping(bookKeeping); - } - } -}; - -var ReactDOMEventListener_1 = ReactDOMEventListener; - -/** - * Accumulates items that must not be null or undefined into the first one. This - * is used to conserve memory by avoiding array allocations, and thus sacrifices - * API cleanness. Since `current` can be null before being passed in and not - * null after this function, make sure to assign it back to `current`: - * - * `a = accumulateInto(a, b);` - * - * This API should be sparingly used. Try `accumulate` for something cleaner. - * - * @return {*|array<*>} An accumulation of items. - */ - -function accumulateInto(current, next) { - !(next != null) ? invariant_1(false, 'accumulateInto(...): Accumulated items must not be null or undefined.') : void 0; - - if (current == null) { - return next; - } - - // Both are not empty. Warning: Never call x.concat(y) when you are not - // certain that x is an Array (x could be a string with concat method). - if (Array.isArray(current)) { - if (Array.isArray(next)) { - current.push.apply(current, next); - return current; - } - current.push(next); - return current; - } - - if (Array.isArray(next)) { - // A bit too dangerous to mutate `next`. - return [current].concat(next); - } +// TODO: can we stop exporting these? +var _enabled = true; +var _handleTopLevel = void 0; - return [current, next]; +function setHandleTopLevel(handleTopLevel) { + _handleTopLevel = handleTopLevel; } -var accumulateInto_1 = accumulateInto; - -/** - * Copyright (c) 2013-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @providesModule forEachAccumulated - * - */ - -/** - * @param {array} arr an "accumulation" of items which is either an Array or - * a single item. Useful when paired with the `accumulate` module. This is a - * simple utility that allows us to reason about a collection of items, but - * handling the case when there is exactly one item (and we do not need to - * allocate an array). - * @param {function} cb Callback invoked with each element or a collection. - * @param {?} [scope] Scope used as `this` in a callback. - */ - -function forEachAccumulated(arr, cb, scope) { - if (Array.isArray(arr)) { - arr.forEach(cb, scope); - } else if (arr) { - cb.call(scope, arr); - } +function setEnabled(enabled) { + _enabled = !!enabled; } -var forEachAccumulated_1 = forEachAccumulated; - -/** - * Internal queue of events that have accumulated their dispatches and are - * waiting to have their dispatches executed. - */ -var eventQueue = null; +function isEnabled() { + return _enabled; +} /** - * Dispatches an event and releases it back into the pool, unless persistent. + * Traps top-level events by using event bubbling. * - * @param {?object} event Synthetic event to be dispatched. - * @param {boolean} simulated If the event is simulated (changes exn behavior) - * @private + * @param {string} topLevelType Record from `BrowserEventConstants`. + * @param {string} handlerBaseName Event name (e.g. "click"). + * @param {object} element Element on which to attach listener. + * @return {?object} An object with a remove function which will forcefully + * remove the listener. + * @internal */ -var executeDispatchesAndRelease = function (event, simulated) { - if (event) { - EventPluginUtils_1.executeDispatchesInOrder(event, simulated); - - if (!event.isPersistent()) { - event.constructor.release(event); - } - } -}; -var executeDispatchesAndReleaseSimulated = function (e) { - return executeDispatchesAndRelease(e, true); -}; -var executeDispatchesAndReleaseTopLevel = function (e) { - return executeDispatchesAndRelease(e, false); -}; - -function isInteractive(tag) { - return tag === 'button' || tag === 'input' || tag === 'select' || tag === 'textarea'; -} - -function shouldPreventMouseEvent(name, type, props) { - switch (name) { - case 'onClick': - case 'onClickCapture': - case 'onDoubleClick': - case 'onDoubleClickCapture': - case 'onMouseDown': - case 'onMouseDownCapture': - case 'onMouseMove': - case 'onMouseMoveCapture': - case 'onMouseUp': - case 'onMouseUpCapture': - return !!(props.disabled && isInteractive(type)); - default: - return false; +function trapBubbledEvent(topLevelType, handlerBaseName, element) { + if (!element) { + return null; } + return EventListener_1.listen(element, handlerBaseName, dispatchEvent.bind(null, topLevelType)); } /** - * This is a unified interface for event plugins to be installed and configured. - * - * Event plugins can implement the following properties: - * - * `extractEvents` {function(string, DOMEventTarget, string, object): *} - * Required. When a top-level event is fired, this method is expected to - * extract synthetic events that will in turn be queued and dispatched. - * - * `eventTypes` {object} - * Optional, plugins that fire events must publish a mapping of registration - * names that are used to register listeners. Values of this mapping must - * be objects that contain `registrationName` or `phasedRegistrationNames`. - * - * `executeDispatch` {function(object, function, string)} - * Optional, allows plugins to override how an event gets dispatched. By - * default, the listener is simply invoked. + * Traps a top-level event by using event capturing. * - * Each plugin that is injected into `EventsPluginHub` is immediately operable. - * - * @public + * @param {string} topLevelType Record from `BrowserEventConstants`. + * @param {string} handlerBaseName Event name (e.g. "click"). + * @param {object} element Element on which to attach listener. + * @return {?object} An object with a remove function which will forcefully + * remove the listener. + * @internal */ -var EventPluginHub = { - /** - * Methods for injecting dependencies. - */ - injection: { - /** - * @param {array} InjectedEventPluginOrder - * @public - */ - injectEventPluginOrder: EventPluginRegistry_1.injectEventPluginOrder, - - /** - * @param {object} injectedNamesToPlugins Map from names to plugin modules. - */ - injectEventPluginsByName: EventPluginRegistry_1.injectEventPluginsByName - }, - - /** - * @param {object} inst The instance, which is the source of events. - * @param {string} registrationName Name of listener (e.g. `onClick`). - * @return {?function} The stored callback. - */ - getListener: function (inst, registrationName) { - var listener; - - // TODO: shouldPreventMouseEvent is DOM-specific and definitely should not - // live here; needs to be moved to a better place soon - if (typeof inst.tag === 'number') { - var stateNode = inst.stateNode; - if (!stateNode) { - // Work in progress (ex: onload events in incremental mode). - return null; - } - var props = EventPluginUtils_1.getFiberCurrentPropsFromNode(stateNode); - if (!props) { - // Work in progress. - return null; - } - listener = props[registrationName]; - if (shouldPreventMouseEvent(registrationName, inst.type, props)) { - return null; - } - } else { - var currentElement = inst._currentElement; - if (typeof currentElement === 'string' || typeof currentElement === 'number') { - // Text node, let it bubble through. - return null; - } - if (!inst._rootNodeID) { - // If the instance is already unmounted, we have no listeners. - return null; - } - var _props = currentElement.props; - listener = _props[registrationName]; - if (shouldPreventMouseEvent(registrationName, currentElement.type, _props)) { - return null; - } - } - - !(!listener || typeof listener === 'function') ? invariant_1(false, 'Expected `%s` listener to be a function, instead got a value of `%s` type.', registrationName, typeof listener) : void 0; - return listener; - }, - - /** - * Allows registered plugins an opportunity to extract events from top-level - * native browser events. - * - * @return {*} An accumulation of synthetic events. - * @internal - */ - extractEvents: function (topLevelType, targetInst, nativeEvent, nativeEventTarget) { - var events; - var plugins = EventPluginRegistry_1.plugins; - for (var i = 0; i < plugins.length; i++) { - // Not every plugin in the ordering may be loaded at runtime. - var possiblePlugin = plugins[i]; - if (possiblePlugin) { - var extractedEvents = possiblePlugin.extractEvents(topLevelType, targetInst, nativeEvent, nativeEventTarget); - if (extractedEvents) { - events = accumulateInto_1(events, extractedEvents); - } - } - } - return events; - }, - - /** - * Enqueues a synthetic event that should be dispatched when - * `processEventQueue` is invoked. - * - * @param {*} events An accumulation of synthetic events. - * @internal - */ - enqueueEvents: function (events) { - if (events) { - eventQueue = accumulateInto_1(eventQueue, events); - } - }, - - /** - * Dispatches all synthetic events on the event queue. - * - * @internal - */ - processEventQueue: function (simulated) { - // Set `eventQueue` to null before processing it so that we can tell if more - // events get enqueued while processing. - var processingEventQueue = eventQueue; - eventQueue = null; - if (simulated) { - forEachAccumulated_1(processingEventQueue, executeDispatchesAndReleaseSimulated); - } else { - forEachAccumulated_1(processingEventQueue, executeDispatchesAndReleaseTopLevel); - } - !!eventQueue ? invariant_1(false, 'processEventQueue(): Additional events were enqueued while processing an event queue. Support for this has not yet been implemented.') : void 0; - // This would be a good time to rethrow if any of the event handlers threw. - ReactErrorUtils_1.rethrowCaughtError(); +function trapCapturedEvent(topLevelType, handlerBaseName, element) { + if (!element) { + return null; } -}; - -var EventPluginHub_1 = EventPluginHub; - -function runEventQueueInBatch(events) { - EventPluginHub_1.enqueueEvents(events); - EventPluginHub_1.processEventQueue(false); + return EventListener_1.capture(element, handlerBaseName, dispatchEvent.bind(null, topLevelType)); } -var ReactEventEmitterMixin = { - /** - * Streams a fired top-level event to `EventPluginHub` where plugins have the - * opportunity to create `ReactEvent`s to be dispatched. - */ - handleTopLevel: function (topLevelType, targetInst, nativeEvent, nativeEventTarget) { - var events = EventPluginHub_1.extractEvents(topLevelType, targetInst, nativeEvent, nativeEventTarget); - runEventQueueInBatch(events); +function dispatchEvent(topLevelType, nativeEvent) { + if (!_enabled) { + return; } -}; - -var ReactEventEmitterMixin_1 = ReactEventEmitterMixin; - -var useHasFeature; -if (ExecutionEnvironment_1.canUseDOM) { - useHasFeature = document.implementation && document.implementation.hasFeature && - // always returns true in newer browsers as per the standard. - // @see http://dom.spec.whatwg.org/#dom-domimplementation-hasfeature - document.implementation.hasFeature('', '') !== true; -} -/** - * Checks if an event is supported in the current execution environment. - * - * NOTE: This will not work correctly for non-generic events such as `change`, - * `reset`, `load`, `error`, and `select`. - * - * Borrows from Modernizr. - * - * @param {string} eventNameSuffix Event name, e.g. "click". - * @param {?boolean} capture Check if the capture phase is supported. - * @return {boolean} True if the event is supported. - * @internal - * @license Modernizr 3.0.0pre (Custom Build) | MIT - */ -function isEventSupported(eventNameSuffix, capture) { - if (!ExecutionEnvironment_1.canUseDOM || capture && !('addEventListener' in document)) { - return false; + var nativeEventTarget = getEventTarget(nativeEvent); + var targetInst = getClosestInstanceFromNode(nativeEventTarget); + if (targetInst !== null && typeof targetInst.tag === 'number' && !isFiberMounted(targetInst)) { + // If we get an event (ex: img onload) before committing that + // component's mount, ignore it for now (that is, treat it as if it was an + // event on a non-React tree). We might also consider queueing events and + // dispatching them after the mount. + targetInst = null; } - var eventName = 'on' + eventNameSuffix; - var isSupported = eventName in document; - - if (!isSupported) { - var element = document.createElement('div'); - element.setAttribute(eventName, 'return;'); - isSupported = typeof element[eventName] === 'function'; - } + var bookKeeping = getTopLevelCallbackBookKeeping(topLevelType, nativeEvent, targetInst); - if (!isSupported && useHasFeature && eventNameSuffix === 'wheel') { - // This is the only way to test support for the `wheel` event in IE9+. - isSupported = document.implementation.hasFeature('Events.wheel', '3.0'); + try { + // Event queue being processed in the same cycle allows + // `preventDefault`. + batchedUpdates(handleTopLevelImpl, bookKeeping); + } finally { + releaseTopLevelCallbackBookKeeping(bookKeeping); } - - return isSupported; } -var isEventSupported_1 = isEventSupported; +var ReactDOMEventListener = Object.freeze({ + get _enabled () { return _enabled; }, + get _handleTopLevel () { return _handleTopLevel; }, + setHandleTopLevel: setHandleTopLevel, + setEnabled: setEnabled, + isEnabled: isEnabled, + trapBubbledEvent: trapBubbledEvent, + trapCapturedEvent: trapCapturedEvent, + dispatchEvent: dispatchEvent +}); /** * Generate a mapping of standard vendor prefixes using the defined style property and event name. @@ -2523,8 +3767,6 @@ function getVendorPrefixedEventName(eventName) { return ''; } -var getVendorPrefixedEventName_1 = getVendorPrefixedEventName; - /** * Types of raw signals from the browser caught at the top level. * @@ -2534,9 +3776,9 @@ var getVendorPrefixedEventName_1 = getVendorPrefixedEventName; */ var topLevelTypes$1 = { topAbort: 'abort', - topAnimationEnd: getVendorPrefixedEventName_1('animationend') || 'animationend', - topAnimationIteration: getVendorPrefixedEventName_1('animationiteration') || 'animationiteration', - topAnimationStart: getVendorPrefixedEventName_1('animationstart') || 'animationstart', + topAnimationEnd: getVendorPrefixedEventName('animationend') || 'animationend', + topAnimationIteration: getVendorPrefixedEventName('animationiteration') || 'animationiteration', + topAnimationStart: getVendorPrefixedEventName('animationstart') || 'animationstart', topBlur: 'blur', topCancel: 'cancel', topCanPlay: 'canplay', @@ -2597,7 +3839,7 @@ var topLevelTypes$1 = { topTouchEnd: 'touchend', topTouchMove: 'touchmove', topTouchStart: 'touchstart', - topTransitionEnd: getVendorPrefixedEventName_1('transitionend') || 'transitionend', + topTransitionEnd: getVendorPrefixedEventName('transitionend') || 'transitionend', topVolumeChange: 'volumechange', topWaiting: 'waiting', topWheel: 'wheel' @@ -2607,9 +3849,21 @@ var BrowserEventConstants = { topLevelTypes: topLevelTypes$1 }; -var BrowserEventConstants_1 = BrowserEventConstants; +function runEventQueueInBatch(events) { + enqueueEvents(events); + processEventQueue(false); +} + +/** + * Streams a fired top-level event to `EventPluginHub` where plugins have the + * opportunity to create `ReactEvent`s to be dispatched. + */ +function handleTopLevel(topLevelType, targetInst, nativeEvent, nativeEventTarget) { + var events = extractEvents(topLevelType, targetInst, nativeEvent, nativeEventTarget); + runEventQueueInBatch(events); +} -var topLevelTypes = BrowserEventConstants_1.topLevelTypes; +var topLevelTypes = BrowserEventConstants.topLevelTypes; /** * Summary of `ReactBrowserEventEmitter` event handling: @@ -2685,114 +3939,74 @@ function getListeningForDocument(mountAt) { return alreadyListeningTo[mountAt[topListenersIDKey]]; } -var ReactBrowserEventEmitter = assign({}, ReactEventEmitterMixin_1, { - /** - * Sets whether or not any created callbacks should be enabled. - * - * @param {boolean} enabled True if callbacks should be enabled. - */ - setEnabled: function (enabled) { - if (ReactDOMEventListener_1) { - ReactDOMEventListener_1.setEnabled(enabled); - } - }, +/** + * 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]; - /** - * @return {boolean} True if callbacks are enabled. - */ - isEnabled: function () { - return !!(ReactDOMEventListener_1 && ReactDOMEventListener_1.isEnabled()); - }, + 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); - /** - * 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 - */ - listenTo: function (registrationName, contentDocumentHandle) { - var mountAt = contentDocumentHandle; - var isListening = getListeningForDocument(mountAt); - var dependencies = EventPluginRegistry_1.registrationNameDependencies[registrationName]; - - for (var i = 0; i < dependencies.length; i++) { - var dependency = dependencies[i]; - if (!(isListening.hasOwnProperty(dependency) && isListening[dependency])) { - if (dependency === 'topWheel') { - if (isEventSupported_1('wheel')) { - ReactDOMEventListener_1.trapBubbledEvent('topWheel', 'wheel', mountAt); - } else if (isEventSupported_1('mousewheel')) { - ReactDOMEventListener_1.trapBubbledEvent('topWheel', 'mousewheel', mountAt); - } else { - // Firefox needs to capture a different mouse scroll event. - // @see http://www.quirksmode.org/dom/events/tests/scroll.html - ReactDOMEventListener_1.trapBubbledEvent('topWheel', 'DOMMouseScroll', mountAt); - } - } else if (dependency === 'topScroll') { - ReactDOMEventListener_1.trapCapturedEvent('topScroll', 'scroll', mountAt); - } else if (dependency === 'topFocus' || dependency === 'topBlur') { - ReactDOMEventListener_1.trapCapturedEvent('topFocus', 'focus', mountAt); - ReactDOMEventListener_1.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_1('cancel', true)) { - ReactDOMEventListener_1.trapCapturedEvent('topCancel', 'cancel', mountAt); - } - isListening.topCancel = true; - } else if (dependency === 'topClose') { - if (isEventSupported_1('close', true)) { - ReactDOMEventListener_1.trapCapturedEvent('topClose', 'close', mountAt); - } - isListening.topClose = true; - } else if (topLevelTypes.hasOwnProperty(dependency)) { - ReactDOMEventListener_1.trapBubbledEvent(dependency, topLevelTypes[dependency], 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[dependency] = true; + 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); } - } - }, - isListeningToAllDependencies: function (registrationName, mountAt) { - var isListening = getListeningForDocument(mountAt); - var dependencies = EventPluginRegistry_1.registrationNameDependencies[registrationName]; - for (var i = 0; i < dependencies.length; i++) { - var dependency = dependencies[i]; - if (!(isListening.hasOwnProperty(dependency) && isListening[dependency])) { - return false; - } + isListening[dependency] = true; } - return true; - }, - - trapBubbledEvent: function (topLevelType, handlerBaseName, handle) { - return ReactDOMEventListener_1.trapBubbledEvent(topLevelType, handlerBaseName, handle); - }, - - trapCapturedEvent: function (topLevelType, handlerBaseName, handle) { - return ReactDOMEventListener_1.trapCapturedEvent(topLevelType, handlerBaseName, handle); } -}); +} -var ReactBrowserEventEmitter_1 = ReactBrowserEventEmitter; +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; +} /** * Copyright (c) 2013-present, Facebook, Inc. @@ -2800,15 +4014,34 @@ var ReactBrowserEventEmitter_1 = ReactBrowserEventEmitter; * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule ReactDOMFeatureFlags + * @typechecks */ -var ReactDOMFeatureFlags = { - fiberAsyncScheduling: false, - useFiber: true -}; +/* eslint-disable fb-www/typeof-undefined */ + +/** + * Same as document.activeElement but wraps in a try-catch block. In IE it is + * not safe to call document.activeElement if there is nothing focused. + * + * The activeElement will be null only if the document or document body is not + * yet defined. + * + * @param {?DOMDocument} doc Defaults to current document. + * @return {?DOMElement} + */ +function getActiveElement(doc) /*?DOMElement*/{ + doc = doc || (typeof document !== 'undefined' ? document : undefined); + if (typeof doc === 'undefined') { + return null; + } + try { + return doc.activeElement || doc.body; + } catch (e) { + return doc.body; + } +} -var ReactDOMFeatureFlags_1 = ReactDOMFeatureFlags; +var getActiveElement_1 = getActiveElement; /** * Copyright (c) 2013-present, Facebook, Inc. @@ -2816,187 +4049,65 @@ var ReactDOMFeatureFlags_1 = ReactDOMFeatureFlags; * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule CSSProperty + * @typechecks + * */ -/** - * CSS properties which accept numbers but are not in units of "px". - */ +/*eslint-disable no-self-compare */ -var isUnitlessNumber = { - animationIterationCount: true, - borderImageOutset: true, - borderImageSlice: true, - borderImageWidth: true, - boxFlex: true, - boxFlexGroup: true, - boxOrdinalGroup: true, - columnCount: true, - columns: true, - flex: true, - flexGrow: true, - flexPositive: true, - flexShrink: true, - flexNegative: true, - flexOrder: true, - gridRow: true, - gridRowEnd: true, - gridRowSpan: true, - gridRowStart: true, - gridColumn: true, - gridColumnEnd: true, - gridColumnSpan: true, - gridColumnStart: true, - fontWeight: true, - lineClamp: true, - lineHeight: true, - opacity: true, - order: true, - orphans: true, - tabSize: true, - widows: true, - zIndex: true, - zoom: true, - // SVG-related properties - fillOpacity: true, - floodOpacity: true, - stopOpacity: true, - strokeDasharray: true, - strokeDashoffset: true, - strokeMiterlimit: true, - strokeOpacity: true, - strokeWidth: true -}; -/** - * @param {string} prefix vendor-specific prefix, eg: Webkit - * @param {string} key style name, eg: transitionDuration - * @return {string} style name prefixed with `prefix`, properly camelCased, eg: - * WebkitTransitionDuration - */ -function prefixKey(prefix, key) { - return prefix + key.charAt(0).toUpperCase() + key.substring(1); -} +var hasOwnProperty = Object.prototype.hasOwnProperty; /** - * Support style names that may come passed in prefixed by adding permutations - * of vendor prefixes. + * inlined Object.is polyfill to avoid requiring consumers ship their own + * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is */ -var prefixes = ['Webkit', 'ms', 'Moz', 'O']; - -// Using Object.keys here, or else the vanilla for-in loop makes IE8 go into an -// infinite loop, because it iterates over the newly added props too. -Object.keys(isUnitlessNumber).forEach(function (prop) { - prefixes.forEach(function (prefix) { - isUnitlessNumber[prefixKey(prefix, prop)] = isUnitlessNumber[prop]; - }); -}); +function is(x, y) { + // SameValue algorithm + if (x === y) { + // Steps 1-5, 7-10 + // Steps 6.b-6.e: +0 != -0 + // Added the nonzero y check to make Flow happy, but it is redundant + return x !== 0 || y !== 0 || 1 / x === 1 / y; + } else { + // Step 6.a: NaN == NaN + return x !== x && y !== y; + } +} /** - * Most style properties can be unset by doing .style[prop] = '' but IE8 - * doesn't like doing that with shorthand properties so for the properties that - * IE8 breaks on, which are listed here, we instead unset each of the - * individual properties. See http://bugs.jquery.com/ticket/12385. - * The 4-value 'clock' properties like margin, padding, border-width seem to - * behave without any problems. Curiously, list-style works too without any - * special prodding. + * Performs equality by iterating through keys on an object and returning false + * when any key has values which are not strictly equal between the arguments. + * Returns true when the values of all keys are strictly equal. */ -var shorthandPropertyExpansions = { - background: { - backgroundAttachment: true, - backgroundColor: true, - backgroundImage: true, - backgroundPositionX: true, - backgroundPositionY: true, - backgroundRepeat: true - }, - backgroundPosition: { - backgroundPositionX: true, - backgroundPositionY: true - }, - border: { - borderWidth: true, - borderStyle: true, - borderColor: true - }, - borderBottom: { - borderBottomWidth: true, - borderBottomStyle: true, - borderBottomColor: true - }, - borderLeft: { - borderLeftWidth: true, - borderLeftStyle: true, - borderLeftColor: true - }, - borderRight: { - borderRightWidth: true, - borderRightStyle: true, - borderRightColor: true - }, - borderTop: { - borderTopWidth: true, - borderTopStyle: true, - borderTopColor: true - }, - font: { - fontStyle: true, - fontVariant: true, - fontWeight: true, - fontSize: true, - lineHeight: true, - fontFamily: true - }, - outline: { - outlineWidth: true, - outlineStyle: true, - outlineColor: true +function shallowEqual(objA, objB) { + if (is(objA, objB)) { + return true; } -}; - -var CSSProperty = { - isUnitlessNumber: isUnitlessNumber, - shorthandPropertyExpansions: shorthandPropertyExpansions -}; -var CSSProperty_1 = CSSProperty; - -var isUnitlessNumber$1 = CSSProperty_1.isUnitlessNumber; + if (typeof objA !== 'object' || objA === null || typeof objB !== 'object' || objB === null) { + return false; + } -/** - * Convert a value into the proper css writable value. The style name `name` - * should be logical (no hyphens), as specified - * in `CSSProperty.isUnitlessNumber`. - * - * @param {string} name CSS property name such as `topMargin`. - * @param {*} value CSS property value such as `10px`. - * @return {string} Normalized style value with dimensions applied. - */ -function dangerousStyleValue(name, value, isCustomProperty) { - // Note that we've removed escapeTextForBrowser() calls here since the - // whole string will be escaped when the attribute is injected into - // the markup. If you provide unsafe user data here they can inject - // arbitrary CSS which may be problematic (I couldn't repro this): - // https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet - // http://www.thespanner.co.uk/2007/11/26/ultimate-xss-css-injection/ - // This is not an XSS hole but instead a potential CSS injection issue - // which has lead to a greater discussion about how we're going to - // trust URLs moving forward. See #2115901 + var keysA = Object.keys(objA); + var keysB = Object.keys(objB); - var isEmpty = value == null || typeof value === 'boolean' || value === ''; - if (isEmpty) { - return ''; + if (keysA.length !== keysB.length) { + return false; } - if (!isCustomProperty && typeof value === 'number' && value !== 0 && !(isUnitlessNumber$1.hasOwnProperty(name) && isUnitlessNumber$1[name])) { - return value + 'px'; // Presumes implicit 'px' suffix for unitless numbers + // Test for A's keys different from B. + for (var i = 0; i < keysA.length; i++) { + if (!hasOwnProperty.call(objB, keysA[i]) || !is(objA[keysA[i]], objB[keysA[i]])) { + return false; + } } - return ('' + value).trim(); + return true; } -var dangerousStyleValue_1 = dangerousStyleValue; +var shallowEqual_1 = shallowEqual; /** * Copyright (c) 2013-present, Facebook, Inc. @@ -3007,49 +4118,17 @@ var dangerousStyleValue_1 = dangerousStyleValue; * @typechecks */ -var _uppercasePattern = /([A-Z])/g; - /** - * Hyphenates a camelcased string, for example: - * - * > hyphenate('backgroundColor') - * < "background-color" - * - * For CSS style names, use `hyphenateStyleName` instead which works properly - * with all vendor prefixes, including `ms`. - * - * @param {string} string - * @return {string} - */ -function hyphenate(string) { - return string.replace(_uppercasePattern, '-$1').toLowerCase(); -} - -var hyphenate_1 = hyphenate; - -var msPattern = /^ms-/; - -/** - * Hyphenates a camelcased CSS property name, for example: - * - * > hyphenateStyleName('backgroundColor') - * < "background-color" - * > hyphenateStyleName('MozTransition') - * < "-moz-transition" - * > hyphenateStyleName('msTransition') - * < "-ms-transition" - * - * As Modernizr suggests (http://modernizr.com/docs/#prefixed), an `ms` prefix - * is converted to `-ms-`. - * - * @param {string} string - * @return {string} + * @param {*} object The object to check. + * @return {boolean} Whether or not the object is a DOM node. */ -function hyphenateStyleName$1(string) { - return hyphenate_1(string).replace(msPattern, '-ms-'); +function isNode(object) { + var doc = object ? object.ownerDocument || object : document; + var defaultView = doc.defaultView || window; + return !!(object && (typeof defaultView.Node === 'function' ? object instanceof defaultView.Node : typeof object === 'object' && typeof object.nodeType === 'number' && typeof object.nodeName === 'string')); } -var hyphenateStyleName_1 = hyphenateStyleName$1; +var isNode_1 = isNode; /** * Copyright (c) 2013-present, Facebook, Inc. @@ -3060,439 +4139,53 @@ var hyphenateStyleName_1 = hyphenateStyleName$1; * @typechecks */ -var _hyphenPattern = /-(.)/g; -/** - * Camelcases a hyphenated string, for example: - * - * > camelize('background-color') - * < "backgroundColor" - * - * @param {string} string - * @return {string} - */ -function camelize(string) { - return string.replace(_hyphenPattern, function (_, character) { - return character.toUpperCase(); - }); -} - -var camelize_1 = camelize; - -var msPattern$1 = /^-ms-/; /** - * Camelcases a hyphenated CSS property name, for example: - * - * > camelizeStyleName('background-color') - * < "backgroundColor" - * > camelizeStyleName('-moz-transition') - * < "MozTransition" - * > camelizeStyleName('-ms-transition') - * < "msTransition" - * - * As Andi Smith suggests - * (http://www.andismith.com/blog/2012/02/modernizr-prefixed/), an `-ms` prefix - * is converted to lowercase `ms`. - * - * @param {string} string - * @return {string} + * @param {*} object The object to check. + * @return {boolean} Whether or not the object is a DOM text node. */ -function camelizeStyleName$1(string) { - return camelize_1(string.replace(msPattern$1, 'ms-')); +function isTextNode(object) { + return isNode_1(object) && object.nodeType == 3; } -var camelizeStyleName_1 = camelizeStyleName$1; +var isTextNode_1 = isTextNode; /** - * Copyright (c) 2016-present, Facebook, Inc. + * Copyright (c) 2013-present, Facebook, Inc. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * * - * @providesModule describeComponentFrame */ -var describeComponentFrame = function (name, source, ownerName) { - return '\n in ' + (name || 'Unknown') + (source ? ' (at ' + source.fileName.replace(/^.*[\\\/]/, '') + ':' + source.lineNumber + ')' : ownerName ? ' (created by ' + ownerName + ')' : ''); -}; - -var IndeterminateComponent = ReactTypeOfWork.IndeterminateComponent; -var FunctionalComponent = ReactTypeOfWork.FunctionalComponent; -var ClassComponent$1 = ReactTypeOfWork.ClassComponent; -var HostComponent$2 = ReactTypeOfWork.HostComponent; - - -function describeFiber(fiber) { - switch (fiber.tag) { - case IndeterminateComponent: - case FunctionalComponent: - case ClassComponent$1: - case HostComponent$2: - var owner = fiber._debugOwner; - var source = fiber._debugSource; - var name = getComponentName_1(fiber); - var ownerName = null; - if (owner) { - ownerName = getComponentName_1(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$1(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; -} - -var ReactFiberComponentTreeHook = { - getStackAddendumByWorkInProgressFiber: getStackAddendumByWorkInProgressFiber$1 -}; - -var ReactDebugCurrentFrame = ReactGlobalSharedState_1.ReactDebugCurrentFrame; - -{ - var getComponentName$3 = getComponentName_1; - - var _require2$2 = ReactFiberComponentTreeHook, - getStackAddendumByWorkInProgressFiber = _require2$2.getStackAddendumByWorkInProgressFiber; -} - -function getCurrentFiberOwnerName$2() { - { - var fiber = ReactDebugCurrentFiber.current; - if (fiber === null) { - return null; - } - if (fiber._debugOwner != null) { - return getComponentName$3(fiber._debugOwner); - } - } - return null; -} - -function getCurrentFiberStackAddendum$1() { - { - 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, phase) { - ReactDebugCurrentFrame.getCurrentStack = getCurrentFiberStackAddendum$1; - ReactDebugCurrentFiber.current = fiber; - ReactDebugCurrentFiber.phase = phase; -} - -var ReactDebugCurrentFiber = { - current: null, - phase: null, - resetCurrentFiber: resetCurrentFiber, - setCurrentFiber: setCurrentFiber, - getCurrentFiberOwnerName: getCurrentFiberOwnerName$2, - getCurrentFiberStackAddendum: getCurrentFiberStackAddendum$1 -}; - -var ReactDebugCurrentFiber_1 = ReactDebugCurrentFiber; - -var warnValidStyle$1 = emptyFunction_1; - -{ - var camelizeStyleName = camelizeStyleName_1; - var getComponentName$2 = getComponentName_1; - var warning$5 = warning_1; - - var _require$3 = ReactDebugCurrentFiber_1, - getCurrentFiberOwnerName$1 = _require$3.getCurrentFiberOwnerName; - - // 'msTransform' is correct, but the other prefixes should be capitalized - - - var badVendoredStyleNamePattern = /^(?:webkit|moz|o)[A-Z]/; - - // style values shouldn't contain a semicolon - var badStyleValueWithSemicolonPattern = /;\s*$/; - - var warnedStyleNames = {}; - var warnedStyleValues = {}; - var warnedForNaNValue = false; - var warnedForInfinityValue = false; - - var warnHyphenatedStyleName = function (name, owner) { - if (warnedStyleNames.hasOwnProperty(name) && warnedStyleNames[name]) { - return; - } - - warnedStyleNames[name] = true; - warning$5(false, 'Unsupported style property %s. Did you mean %s?%s', name, camelizeStyleName(name), checkRenderMessage(owner)); - }; - - var warnBadVendoredStyleName = function (name, owner) { - if (warnedStyleNames.hasOwnProperty(name) && warnedStyleNames[name]) { - return; - } - - warnedStyleNames[name] = true; - warning$5(false, 'Unsupported vendor-prefixed style property %s. Did you mean %s?%s', name, name.charAt(0).toUpperCase() + name.slice(1), checkRenderMessage(owner)); - }; - - var warnStyleValueWithSemicolon = function (name, value, owner) { - if (warnedStyleValues.hasOwnProperty(value) && warnedStyleValues[value]) { - return; - } - - warnedStyleValues[value] = true; - warning$5(false, "Style property values shouldn't contain a semicolon.%s " + 'Try "%s: %s" instead.', checkRenderMessage(owner), name, value.replace(badStyleValueWithSemicolonPattern, '')); - }; - - var warnStyleValueIsNaN = function (name, value, owner) { - if (warnedForNaNValue) { - return; - } - - warnedForNaNValue = true; - warning$5(false, '`NaN` is an invalid value for the `%s` css style property.%s', name, checkRenderMessage(owner)); - }; - - var warnStyleValueIsInfinity = function (name, value, owner) { - if (warnedForInfinityValue) { - return; - } - - warnedForInfinityValue = true; - warning$5(false, '`Infinity` is an invalid value for the `%s` css style property.%s', name, checkRenderMessage(owner)); - }; - - var checkRenderMessage = function (owner) { - var ownerName; - if (owner != null) { - // Stack passes the owner manually all the way to CSSPropertyOperations. - ownerName = getComponentName$2(owner); - } else { - // Fiber doesn't pass it but uses ReactDebugCurrentFiber to track it. - // It is only enabled in development and tracks host components too. - ownerName = getCurrentFiberOwnerName$1(); - // TODO: also report the stack. - } - if (ownerName) { - return '\n\nCheck the render method of `' + ownerName + '`.'; - } - return ''; - }; - - warnValidStyle$1 = function (name, value, component) { - var owner; - if (component) { - // TODO: this only works with Stack. Seems like we need to add unit tests? - owner = component._currentElement._owner; - } - if (name.indexOf('-') > -1) { - warnHyphenatedStyleName(name, owner); - } else if (badVendoredStyleNamePattern.test(name)) { - warnBadVendoredStyleName(name, owner); - } else if (badStyleValueWithSemicolonPattern.test(value)) { - warnStyleValueWithSemicolon(name, value, owner); - } - - if (typeof value === 'number') { - if (isNaN(value)) { - warnStyleValueIsNaN(name, value, owner); - } else if (!isFinite(value)) { - warnStyleValueIsInfinity(name, value, owner); - } - } - }; -} - -var warnValidStyle_1 = warnValidStyle$1; - -{ - var hyphenateStyleName = hyphenateStyleName_1; - var warnValidStyle = warnValidStyle_1; -} - -var hasShorthandPropertyBug = false; -if (ExecutionEnvironment_1.canUseDOM) { - var tempStyle = document.createElement('div').style; - try { - // IE8 throws "Invalid argument." if resetting shorthand style properties. - tempStyle.font = ''; - } catch (e) { - hasShorthandPropertyBug = true; - } -} +/*eslint-disable no-bitwise */ /** - * Operations for dealing with CSS properties. + * Checks if a given DOM node contains or is another DOM node. */ -var CSSPropertyOperations = { - /** - * This creates a string that is expected to be equivalent to the style - * attribute generated by server-side rendering. It by-passes warnings and - * security checks so it's not safe to use this value for anything other than - * comparison. It is only used in DEV for SSR validation. - */ - createDangerousStringForStyles: function (styles) { - { - var serialized = ''; - var delimiter = ''; - for (var styleName in styles) { - if (!styles.hasOwnProperty(styleName)) { - continue; - } - var styleValue = styles[styleName]; - if (styleValue != null) { - var isCustomProperty = styleName.indexOf('--') === 0; - serialized += delimiter + hyphenateStyleName(styleName) + ':'; - serialized += dangerousStyleValue_1(styleName, styleValue, isCustomProperty); - - delimiter = ';'; - } - } - return serialized || null; - } - }, - - /** - * Sets the value for multiple styles on a node. If a value is specified as - * '' (empty string), the corresponding style property will be unset. - * - * @param {DOMElement} node - * @param {object} styles - * @param {ReactDOMComponent} component - */ - setValueForStyles: function (node, styles, component) { - var style = node.style; - for (var styleName in styles) { - if (!styles.hasOwnProperty(styleName)) { - continue; - } - var isCustomProperty = styleName.indexOf('--') === 0; - { - if (!isCustomProperty) { - warnValidStyle(styleName, styles[styleName], component); - } - } - var styleValue = dangerousStyleValue_1(styleName, styles[styleName], isCustomProperty); - if (styleName === 'float') { - styleName = 'cssFloat'; - } - if (isCustomProperty) { - style.setProperty(styleName, styleValue); - } else if (styleValue) { - style[styleName] = styleValue; - } else { - var expansion = hasShorthandPropertyBug && CSSProperty_1.shorthandPropertyExpansions[styleName]; - if (expansion) { - // Shorthand property that IE8 won't like unsetting, so unset each - // component to placate it - for (var individualStyleName in expansion) { - style[individualStyleName] = ''; - } - } else { - style[styleName] = ''; - } - } - } +function containsNode(outerNode, innerNode) { + if (!outerNode || !innerNode) { + return false; + } else if (outerNode === innerNode) { + return true; + } else if (isTextNode_1(outerNode)) { + return false; + } else if (isTextNode_1(innerNode)) { + return containsNode(outerNode, innerNode.parentNode); + } else if ('contains' in outerNode) { + return outerNode.contains(innerNode); + } else if (outerNode.compareDocumentPosition) { + return !!(outerNode.compareDocumentPosition(innerNode) & 16); + } else { + return false; } -}; - -var CSSPropertyOperations_1 = CSSPropertyOperations; - -var ReactInvalidSetStateWarningHook = {}; - -{ - var warning$8 = warning_1; - var processingChildContext = false; - - var warnInvalidSetState = function () { - warning$8(!processingChildContext, 'setState(...): Cannot call setState() inside getChildContext()'); - }; - - ReactInvalidSetStateWarningHook = { - onBeginProcessingChildContext: function () { - processingChildContext = true; - }, - onEndProcessingChildContext: function () { - processingChildContext = false; - }, - onSetState: function () { - warnInvalidSetState(); - } - }; } -var ReactInvalidSetStateWarningHook_1 = ReactInvalidSetStateWarningHook; - -/** - * Copyright (c) 2016-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @providesModule ReactHostOperationHistoryHook - * - */ - -// Trust the developer to only use this with a true check -var ReactHostOperationHistoryHook = null; - -{ - var history = []; - - ReactHostOperationHistoryHook = { - onHostOperation: function (operation) { - history.push(operation); - }, - clearHistory: function () { - if (ReactHostOperationHistoryHook._preventClearing) { - // Should only be used for tests. - return; - } - - history = []; - }, - getHistory: function () { - return history; - } - }; -} - -var ReactHostOperationHistoryHook_1 = ReactHostOperationHistoryHook; - -var performance$1; - -if (ExecutionEnvironment_1.canUseDOM) { - performance$1 = window.performance || window.msPerformance || window.webkitPerformance; -} - -var performance_1 = performance$1 || {}; +var containsNode_1 = containsNode; /** * Copyright (c) 2013-present, Facebook, Inc. @@ -3500,5222 +4193,1688 @@ var performance_1 = performance$1 || {}; * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @typechecks */ -var performanceNow; - /** - * Detect if we can use `window.performance.now()` and gracefully fallback to - * `Date.now()` if it doesn't exist. We need to support Firefox < 15 for now - * because of Facebook's testing infrastructure. + * @param {DOMElement} node input/textarea to focus */ -if (performance_1.now) { - performanceNow = function performanceNow() { - return performance_1.now(); - }; -} else { - performanceNow = function performanceNow() { - return Date.now(); - }; -} - -var performanceNow_1 = performanceNow; - -var ReactComponentTreeHook = ReactGlobalSharedState_1.ReactComponentTreeHook; - - -{ - var warning$7 = warning_1; -} - -// Trust the developer to only use this with a true check -var ReactDebugTool$1 = null; - -{ - var hooks = []; - var didHookThrowForEvent = {}; - - var callHook = function (event, fn, context, arg1, arg2, arg3, arg4, arg5) { - try { - fn.call(context, arg1, arg2, arg3, arg4, arg5); - } catch (e) { - warning$7(didHookThrowForEvent[event], 'Exception thrown by hook while handling %s: %s', event, e + '\n' + e.stack); - didHookThrowForEvent[event] = true; - } - }; - - var emitEvent = function (event, arg1, arg2, arg3, arg4, arg5) { - for (var i = 0; i < hooks.length; i++) { - var hook = hooks[i]; - var fn = hook[event]; - if (fn) { - callHook(event, fn, hook, arg1, arg2, arg3, arg4, arg5); - } - } - }; - - var isProfiling = false; - var flushHistory = []; - var lifeCycleTimerStack = []; - var currentFlushNesting = 0; - var currentFlushMeasurements = []; - var currentFlushStartTime = 0; - var currentTimerDebugID = null; - var currentTimerStartTime = 0; - var currentTimerNestedFlushDuration = 0; - var currentTimerType = null; - - var lifeCycleTimerHasWarned = false; - - var clearHistory = function () { - ReactComponentTreeHook.purgeUnmountedComponents(); - ReactHostOperationHistoryHook_1.clearHistory(); - }; - - var getTreeSnapshot = function (registeredIDs) { - return registeredIDs.reduce(function (tree, id) { - var ownerID = ReactComponentTreeHook.getOwnerID(id); - var parentID = ReactComponentTreeHook.getParentID(id); - tree[id] = { - displayName: ReactComponentTreeHook.getDisplayName(id), - text: ReactComponentTreeHook.getText(id), - updateCount: ReactComponentTreeHook.getUpdateCount(id), - childIDs: ReactComponentTreeHook.getChildIDs(id), - // Text nodes don't have owners but this is close enough. - ownerID: ownerID || parentID && ReactComponentTreeHook.getOwnerID(parentID) || 0, - parentID: parentID - }; - return tree; - }, {}); - }; - - var resetMeasurements = function () { - var previousStartTime = currentFlushStartTime; - var previousMeasurements = currentFlushMeasurements; - var previousOperations = ReactHostOperationHistoryHook_1.getHistory(); - - if (currentFlushNesting === 0) { - currentFlushStartTime = 0; - currentFlushMeasurements = []; - clearHistory(); - return; - } - - if (previousMeasurements.length || previousOperations.length) { - var registeredIDs = ReactComponentTreeHook.getRegisteredIDs(); - flushHistory.push({ - duration: performanceNow_1() - previousStartTime, - measurements: previousMeasurements || [], - operations: previousOperations || [], - treeSnapshot: getTreeSnapshot(registeredIDs) - }); - } - - clearHistory(); - currentFlushStartTime = performanceNow_1(); - currentFlushMeasurements = []; - }; - - var checkDebugID = function (debugID) { - var allowRoot = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; - - if (allowRoot && debugID === 0) { - return; - } - if (!debugID) { - warning$7(false, 'ReactDebugTool: debugID may not be empty.'); - } - }; - - var beginLifeCycleTimer = function (debugID, timerType) { - if (currentFlushNesting === 0) { - return; - } - if (currentTimerType && !lifeCycleTimerHasWarned) { - warning$7(false, 'There is an internal error in the React performance measurement code.' + '\n\nDid not expect %s timer to start while %s timer is still in ' + 'progress for %s instance.', timerType, currentTimerType || 'no', debugID === currentTimerDebugID ? 'the same' : 'another'); - lifeCycleTimerHasWarned = true; - } - currentTimerStartTime = performanceNow_1(); - currentTimerNestedFlushDuration = 0; - currentTimerDebugID = debugID; - currentTimerType = timerType; - }; - - var endLifeCycleTimer = function (debugID, timerType) { - if (currentFlushNesting === 0) { - return; - } - if (currentTimerType !== timerType && !lifeCycleTimerHasWarned) { - warning$7(false, 'There is an internal error in the React performance measurement code. ' + 'We did not expect %s timer to stop while %s timer is still in ' + 'progress for %s instance. Please report this as a bug in React.', timerType, currentTimerType || 'no', debugID === currentTimerDebugID ? 'the same' : 'another'); - lifeCycleTimerHasWarned = true; - } - if (isProfiling) { - currentFlushMeasurements.push({ - timerType: timerType, - instanceID: debugID, - duration: performanceNow_1() - currentTimerStartTime - currentTimerNestedFlushDuration - }); - } - currentTimerStartTime = 0; - currentTimerNestedFlushDuration = 0; - currentTimerDebugID = null; - currentTimerType = null; - }; - - var pauseCurrentLifeCycleTimer = function () { - var currentTimer = { - startTime: currentTimerStartTime, - nestedFlushStartTime: performanceNow_1(), - debugID: currentTimerDebugID, - timerType: currentTimerType - }; - lifeCycleTimerStack.push(currentTimer); - currentTimerStartTime = 0; - currentTimerNestedFlushDuration = 0; - currentTimerDebugID = null; - currentTimerType = null; - }; - - var resumeCurrentLifeCycleTimer = function () { - var _lifeCycleTimerStack$ = lifeCycleTimerStack.pop(), - startTime = _lifeCycleTimerStack$.startTime, - nestedFlushStartTime = _lifeCycleTimerStack$.nestedFlushStartTime, - debugID = _lifeCycleTimerStack$.debugID, - timerType = _lifeCycleTimerStack$.timerType; - - var nestedFlushDuration = performanceNow_1() - nestedFlushStartTime; - currentTimerStartTime = startTime; - currentTimerNestedFlushDuration += nestedFlushDuration; - currentTimerDebugID = debugID; - currentTimerType = timerType; - }; - - var lastMarkTimeStamp = 0; - var canUsePerformanceMeasure = typeof performance !== 'undefined' && typeof performance.mark === 'function' && typeof performance.clearMarks === 'function' && typeof performance.measure === 'function' && typeof performance.clearMeasures === 'function'; - - var shouldMark = function (debugID) { - if (!isProfiling || !canUsePerformanceMeasure) { - return false; - } - var element = ReactComponentTreeHook.getElement(debugID); - if (element == null || typeof element !== 'object') { - return false; - } - var isHostElement = typeof element.type === 'string'; - if (isHostElement) { - return false; - } - return true; - }; - - var markBegin = function (debugID, markType) { - if (!shouldMark(debugID)) { - return; - } - - var markName = debugID + '::' + markType; - lastMarkTimeStamp = performanceNow_1(); - performance.mark(markName); - }; - - var markEnd = function (debugID, markType) { - if (!shouldMark(debugID)) { - return; - } - - var markName = debugID + '::' + markType; - var displayName = ReactComponentTreeHook.getDisplayName(debugID) || 'Unknown'; - - // Chrome has an issue of dropping markers recorded too fast: - // https://bugs.chromium.org/p/chromium/issues/detail?id=640652 - // To work around this, we will not report very small measurements. - // I determined the magic number by tweaking it back and forth. - // 0.05ms was enough to prevent the issue, but I set it to 0.1ms to be safe. - // When the bug is fixed, we can `measure()` unconditionally if we want to. - var timeStamp = performanceNow_1(); - if (timeStamp - lastMarkTimeStamp > 0.1) { - var measurementName = displayName + ' [' + markType + ']'; - performance.measure(measurementName, markName); - } - - performance.clearMarks(markName); - if (measurementName) { - performance.clearMeasures(measurementName); - } - }; - - ReactDebugTool$1 = { - addHook: function (hook) { - hooks.push(hook); - }, - removeHook: function (hook) { - for (var i = 0; i < hooks.length; i++) { - if (hooks[i] === hook) { - hooks.splice(i, 1); - i--; - } - } - }, - isProfiling: function () { - return isProfiling; - }, - beginProfiling: function () { - if (isProfiling) { - return; - } - - isProfiling = true; - flushHistory.length = 0; - resetMeasurements(); - ReactDebugTool$1.addHook(ReactHostOperationHistoryHook_1); - }, - endProfiling: function () { - if (!isProfiling) { - return; - } - - isProfiling = false; - resetMeasurements(); - ReactDebugTool$1.removeHook(ReactHostOperationHistoryHook_1); - }, - getFlushHistory: function () { - return flushHistory; - }, - onBeginFlush: function () { - currentFlushNesting++; - resetMeasurements(); - pauseCurrentLifeCycleTimer(); - emitEvent('onBeginFlush'); - }, - onEndFlush: function () { - resetMeasurements(); - currentFlushNesting--; - resumeCurrentLifeCycleTimer(); - emitEvent('onEndFlush'); - }, - onBeginLifeCycleTimer: function (debugID, timerType) { - checkDebugID(debugID); - emitEvent('onBeginLifeCycleTimer', debugID, timerType); - markBegin(debugID, timerType); - beginLifeCycleTimer(debugID, timerType); - }, - onEndLifeCycleTimer: function (debugID, timerType) { - checkDebugID(debugID); - endLifeCycleTimer(debugID, timerType); - markEnd(debugID, timerType); - emitEvent('onEndLifeCycleTimer', debugID, timerType); - }, - onBeginProcessingChildContext: function () { - emitEvent('onBeginProcessingChildContext'); - }, - onEndProcessingChildContext: function () { - emitEvent('onEndProcessingChildContext'); - }, - onHostOperation: function (operation) { - checkDebugID(operation.instanceID); - emitEvent('onHostOperation', operation); - }, - onSetState: function () { - emitEvent('onSetState'); - }, - onSetChildren: function (debugID, childDebugIDs) { - checkDebugID(debugID); - childDebugIDs.forEach(checkDebugID); - emitEvent('onSetChildren', debugID, childDebugIDs); - }, - onBeforeMountComponent: function (debugID, element, parentDebugID) { - checkDebugID(debugID); - checkDebugID(parentDebugID, true); - emitEvent('onBeforeMountComponent', debugID, element, parentDebugID); - markBegin(debugID, 'mount'); - }, - onMountComponent: function (debugID) { - checkDebugID(debugID); - markEnd(debugID, 'mount'); - emitEvent('onMountComponent', debugID); - }, - onBeforeUpdateComponent: function (debugID, element) { - checkDebugID(debugID); - emitEvent('onBeforeUpdateComponent', debugID, element); - markBegin(debugID, 'update'); - }, - onUpdateComponent: function (debugID) { - checkDebugID(debugID); - markEnd(debugID, 'update'); - emitEvent('onUpdateComponent', debugID); - }, - onBeforeUnmountComponent: function (debugID) { - checkDebugID(debugID); - emitEvent('onBeforeUnmountComponent', debugID); - markBegin(debugID, 'unmount'); - }, - onUnmountComponent: function (debugID) { - checkDebugID(debugID); - markEnd(debugID, 'unmount'); - emitEvent('onUnmountComponent', debugID); - }, - onTestEvent: function () { - emitEvent('onTestEvent'); - } - }; - - ReactDebugTool$1.addHook(ReactInvalidSetStateWarningHook_1); - ReactDebugTool$1.addHook(ReactComponentTreeHook); - var url = ExecutionEnvironment_1.canUseDOM && window.location.href || ''; - if (/[?&]react_perf\b/.test(url)) { - ReactDebugTool$1.beginProfiling(); - } -} - -var ReactDebugTool_1 = ReactDebugTool$1; - -// Trust the developer to only use ReactInstrumentation with a true check - -var debugTool = null; - -{ - var ReactDebugTool = ReactDebugTool_1; - debugTool = ReactDebugTool; -} - -var ReactInstrumentation = { debugTool: debugTool }; - -{ - var warning$6 = warning_1; -} - -// isAttributeNameSafe() is currently duplicated in DOMMarkupOperations. -// TODO: Find a better place for this. -var VALID_ATTRIBUTE_NAME_REGEX = new RegExp('^[' + DOMProperty_1.ATTRIBUTE_NAME_START_CHAR + '][' + DOMProperty_1.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$6(false, 'Invalid attribute name: `%s`', attributeName); - } - return false; +function focusNode(node) { + // IE8 can throw "Can't move focus to the control because it is invisible, + // not enabled, or of a type that does not accept the focus." for all kinds of + // reasons that are too expensive and fragile to test. + try { + node.focus(); + } catch (e) {} } -// 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; -} +var focusNode_1 = focusNode; /** - * Operations for dealing with DOM properties. + * Given any node return the first leaf node without children. + * + * @param {DOMElement|DOMTextNode} node + * @return {DOMElement|DOMTextNode} */ -var DOMPropertyOperations = { - setAttributeForID: function (node, id) { - node.setAttribute(DOMProperty_1.ID_ATTRIBUTE_NAME, id); - }, - - setAttributeForRoot: function (node) { - node.setAttribute(DOMProperty_1.ROOT_ATTRIBUTE_NAME, ''); - }, - - /** - * 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. - */ - getValueForProperty: function (node, name, expected) { - { - var propertyInfo = DOMProperty_1.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. - */ - getValueForAttribute: function (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 - */ - setValueForProperty: function (node, name, value) { - var propertyInfo = DOMProperty_1.getPropertyInfo(name); - - if (propertyInfo && DOMProperty_1.shouldSetAttribute(name, value)) { - var mutationMethod = propertyInfo.mutationMethod; - if (mutationMethod) { - mutationMethod(node, value); - } else if (shouldIgnoreValue(propertyInfo, value)) { - DOMPropertyOperations.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 { - DOMPropertyOperations.setValueForAttribute(node, name, DOMProperty_1.shouldSetAttribute(name, value) ? value : null); - return; - } - - { - var payload = {}; - payload[name] = value; - ReactInstrumentation.debugTool.onHostOperation({ - instanceID: ReactDOMComponentTree_1.getInstanceFromNode(node)._debugID, - type: 'update attribute', - payload: payload - }); - } - }, - - setValueForAttribute: function (node, name, value) { - if (!isAttributeNameSafe(name)) { - return; - } - if (value == null) { - node.removeAttribute(name); - } else { - node.setAttribute(name, '' + value); - } - - { - var payload = {}; - payload[name] = value; - ReactInstrumentation.debugTool.onHostOperation({ - instanceID: ReactDOMComponentTree_1.getInstanceFromNode(node)._debugID, - type: 'update attribute', - payload: payload - }); - } - }, - - /** - * Deletes an attributes from a node. - * - * @param {DOMElement} node - * @param {string} name - */ - deleteValueForAttribute: function (node, name) { - node.removeAttribute(name); - { - ReactInstrumentation.debugTool.onHostOperation({ - instanceID: ReactDOMComponentTree_1.getInstanceFromNode(node)._debugID, - type: 'remove attribute', - payload: name - }); - } - }, - - /** - * Deletes the value for a property on a node. - * - * @param {DOMElement} node - * @param {string} name - */ - deleteValueForProperty: function (node, name) { - var propertyInfo = DOMProperty_1.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); - } - - { - ReactInstrumentation.debugTool.onHostOperation({ - instanceID: ReactDOMComponentTree_1.getInstanceFromNode(node)._debugID, - type: 'remove attribute', - payload: name - }); - } +function getLeafNode(node) { + while (node && node.firstChild) { + node = node.firstChild; } -}; - -var DOMPropertyOperations_1 = DOMPropertyOperations; - -function createCommonjsModule(fn, module) { - return module = { exports: {} }, fn(module, module.exports), module.exports; + return node; } /** - * Copyright (c) 2013-present, Facebook, Inc. + * Get the next sibling within a container. This will walk up the + * DOM if a node's siblings have been exhausted. * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. + * @param {DOMElement|DOMTextNode} node + * @return {?DOMElement|DOMTextNode} */ - -var ReactPropTypesSecret$1 = 'SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED'; - -var ReactPropTypesSecret_1 = ReactPropTypesSecret$1; - -{ - var invariant$2 = invariant_1; - var warning$11 = warning_1; - var ReactPropTypesSecret$2 = ReactPropTypesSecret_1; - var loggedTypeFailures$1 = {}; +function getSiblingNode(node) { + while (node) { + if (node.nextSibling) { + return node.nextSibling; + } + node = node.parentNode; + } } /** - * Assert that the values match with the type specs. - * Error messages are memorized and will only be shown once. + * Get object describing the nodes which contain characters at offset. * - * @param {object} typeSpecs Map of name to a ReactPropType - * @param {object} values Runtime values that need to be type-checked - * @param {string} location e.g. "prop", "context", "child context" - * @param {string} componentName Name of the component for error messages. - * @param {?Function} getStack Returns the component stack. - * @private + * @param {DOMElement|DOMTextNode} root + * @param {number} offset + * @return {?object} */ -function checkPropTypes(typeSpecs, values, location, componentName, getStack) { - { - for (var typeSpecName in typeSpecs) { - if (typeSpecs.hasOwnProperty(typeSpecName)) { - var error; - // Prop type validation may throw. In case they do, we don't want to - // fail the render phase where it didn't fail before. So we log it. - // After these have been cleaned up, we'll let them throw. - try { - // This is intentionally an invariant that gets caught. It's the same - // behavior as without this statement except with a better message. - invariant$2(typeof typeSpecs[typeSpecName] === 'function', '%s: %s type `%s` is invalid; it must be a function, usually from ' + 'the `prop-types` package, but received `%s`.', componentName || 'React class', location, typeSpecName, typeof typeSpecs[typeSpecName]); - error = typeSpecs[typeSpecName](values, typeSpecName, componentName, location, null, ReactPropTypesSecret$2); - } catch (ex) { - error = ex; - } - warning$11(!error || error instanceof Error, '%s: type specification of %s `%s` is invalid; the type checker ' + 'function must return `null` or an `Error` but returned a %s. ' + 'You may have forgotten to pass an argument to the type checker ' + 'creator (arrayOf, instanceOf, objectOf, oneOf, oneOfType, and ' + 'shape all require an argument).', componentName || 'React class', location, typeSpecName, typeof error); - if (error instanceof Error && !(error.message in loggedTypeFailures$1)) { - // Only monitor this failure once because there tends to be a lot of the - // same error. - loggedTypeFailures$1[error.message] = true; +function getNodeForCharacterOffset(root, offset) { + var node = getLeafNode(root); + var nodeStart = 0; + var nodeEnd = 0; - var stack = getStack ? getStack() : ''; + while (node) { + if (node.nodeType === TEXT_NODE) { + nodeEnd = nodeStart + node.textContent.length; - warning$11(false, 'Failed %s type: %s%s', location, error.message, stack != null ? stack : ''); - } + if (nodeStart <= offset && nodeEnd >= offset) { + return { + node: node, + offset: offset - nodeStart + }; } - } - } -} - -var checkPropTypes_1 = checkPropTypes; - -var factoryWithTypeCheckers = function(isValidElement, throwOnDirectAccess) { - /* global Symbol */ - var ITERATOR_SYMBOL = typeof Symbol === 'function' && Symbol.iterator; - var FAUX_ITERATOR_SYMBOL = '@@iterator'; // Before Symbol spec. - - /** - * Returns the iterator method function contained on the iterable object. - * - * Be sure to invoke the function with the iterable as context: - * - * var iteratorFn = getIteratorFn(myIterable); - * if (iteratorFn) { - * var iterator = iteratorFn.call(myIterable); - * ... - * } - * - * @param {?object} maybeIterable - * @return {?function} - */ - function getIteratorFn(maybeIterable) { - var iteratorFn = maybeIterable && (ITERATOR_SYMBOL && maybeIterable[ITERATOR_SYMBOL] || maybeIterable[FAUX_ITERATOR_SYMBOL]); - if (typeof iteratorFn === 'function') { - return iteratorFn; - } - } - - /** - * Collection of methods that allow declaration and validation of props that are - * supplied to React components. Example usage: - * - * var Props = require('ReactPropTypes'); - * var MyArticle = React.createClass({ - * propTypes: { - * // An optional string prop named "description". - * description: Props.string, - * - * // A required enum prop named "category". - * category: Props.oneOf(['News','Photos']).isRequired, - * - * // A prop named "dialog" that requires an instance of Dialog. - * dialog: Props.instanceOf(Dialog).isRequired - * }, - * render: function() { ... } - * }); - * - * A more formal specification of how these methods are used: - * - * type := array|bool|func|object|number|string|oneOf([...])|instanceOf(...) - * decl := ReactPropTypes.{type}(.isRequired)? - * - * Each and every declaration produces a function with the same signature. This - * allows the creation of custom validation functions. For example: - * - * var MyLink = React.createClass({ - * propTypes: { - * // An optional string or URI prop named "href". - * href: function(props, propName, componentName) { - * var propValue = props[propName]; - * if (propValue != null && typeof propValue !== 'string' && - * !(propValue instanceof URI)) { - * return new Error( - * 'Expected a string or an URI for ' + propName + ' in ' + - * componentName - * ); - * } - * } - * }, - * render: function() {...} - * }); - * - * @internal - */ - - var ANONYMOUS = '<<anonymous>>'; - - // Important! - // Keep this list in sync with production version in `./factoryWithThrowingShims.js`. - var ReactPropTypes = { - array: createPrimitiveTypeChecker('array'), - bool: createPrimitiveTypeChecker('boolean'), - func: createPrimitiveTypeChecker('function'), - number: createPrimitiveTypeChecker('number'), - object: createPrimitiveTypeChecker('object'), - string: createPrimitiveTypeChecker('string'), - symbol: createPrimitiveTypeChecker('symbol'), - - any: createAnyTypeChecker(), - arrayOf: createArrayOfTypeChecker, - element: createElementTypeChecker(), - instanceOf: createInstanceTypeChecker, - node: createNodeChecker(), - objectOf: createObjectOfTypeChecker, - oneOf: createEnumTypeChecker, - oneOfType: createUnionTypeChecker, - shape: createShapeTypeChecker, - exact: createStrictShapeTypeChecker, - }; - - /** - * inlined Object.is polyfill to avoid requiring consumers ship their own - * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is - */ - /*eslint-disable no-self-compare*/ - function is(x, y) { - // SameValue algorithm - if (x === y) { - // Steps 1-5, 7-10 - // Steps 6.b-6.e: +0 != -0 - return x !== 0 || 1 / x === 1 / y; - } else { - // Step 6.a: NaN == NaN - return x !== x && y !== y; - } - } - /*eslint-enable no-self-compare*/ - /** - * We use an Error-like object for backward compatibility as people may call - * PropTypes directly and inspect their output. However, we don't use real - * Errors anymore. We don't inspect their stack anyway, and creating them - * is prohibitively expensive if they are created too often, such as what - * happens in oneOfType() for any type before the one that matched. - */ - function PropTypeError(message) { - this.message = message; - this.stack = ''; - } - // Make `instanceof Error` still work for returned errors. - PropTypeError.prototype = Error.prototype; - - function createChainableTypeChecker(validate) { - { - var manualPropTypeCallCache = {}; - var manualPropTypeWarningCount = 0; - } - function checkType(isRequired, props, propName, componentName, location, propFullName, secret) { - componentName = componentName || ANONYMOUS; - propFullName = propFullName || propName; - - if (secret !== ReactPropTypesSecret_1) { - if (throwOnDirectAccess) { - // New behavior only for users of `prop-types` package - invariant_1( - false, - 'Calling PropTypes validators directly is not supported by the `prop-types` package. ' + - 'Use `PropTypes.checkPropTypes()` to call them. ' + - 'Read more at http://fb.me/use-check-prop-types' - ); - } else if ('development' !== 'production' && typeof console !== 'undefined') { - // Old behavior for people using React.PropTypes - var cacheKey = componentName + ':' + propName; - if ( - !manualPropTypeCallCache[cacheKey] && - // Avoid spamming the console because they are often not actionable except for lib authors - manualPropTypeWarningCount < 3 - ) { - warning_1( - false, - 'You are manually calling a React.PropTypes validation ' + - 'function for the `%s` prop on `%s`. This is deprecated ' + - 'and will throw in the standalone `prop-types` package. ' + - 'You may be seeing this warning due to a third-party PropTypes ' + - 'library. See https://fb.me/react-warning-dont-call-proptypes ' + 'for details.', - propFullName, - componentName - ); - manualPropTypeCallCache[cacheKey] = true; - manualPropTypeWarningCount++; - } - } - } - if (props[propName] == null) { - if (isRequired) { - if (props[propName] === null) { - return new PropTypeError('The ' + location + ' `' + propFullName + '` is marked as required ' + ('in `' + componentName + '`, but its value is `null`.')); - } - return new PropTypeError('The ' + location + ' `' + propFullName + '` is marked as required in ' + ('`' + componentName + '`, but its value is `undefined`.')); - } - return null; - } else { - return validate(props, propName, componentName, location, propFullName); - } + nodeStart = nodeEnd; } - var chainedCheckType = checkType.bind(null, false); - chainedCheckType.isRequired = checkType.bind(null, true); - - return chainedCheckType; + node = getLeafNode(getSiblingNode(node)); } +} - function createPrimitiveTypeChecker(expectedType) { - function validate(props, propName, componentName, location, propFullName, secret) { - var propValue = props[propName]; - var propType = getPropType(propValue); - if (propType !== expectedType) { - // `propValue` being instance of, say, date/regexp, pass the 'object' - // check, but we can offer a more precise error message here rather than - // 'of type `object`'. - var preciseType = getPreciseType(propValue); - - return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type ' + ('`' + preciseType + '` supplied to `' + componentName + '`, expected ') + ('`' + expectedType + '`.')); - } - return null; - } - return createChainableTypeChecker(validate); - } +/** + * @param {DOMElement} outerNode + * @return {?object} + */ +function getOffsets(outerNode) { + var selection = window.getSelection && window.getSelection(); - function createAnyTypeChecker() { - return createChainableTypeChecker(emptyFunction_1.thatReturnsNull); + if (!selection || selection.rangeCount === 0) { + return null; } - function createArrayOfTypeChecker(typeChecker) { - function validate(props, propName, componentName, location, propFullName) { - if (typeof typeChecker !== 'function') { - return new PropTypeError('Property `' + propFullName + '` of component `' + componentName + '` has invalid PropType notation inside arrayOf.'); - } - var propValue = props[propName]; - if (!Array.isArray(propValue)) { - var propType = getPropType(propValue); - return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type ' + ('`' + propType + '` supplied to `' + componentName + '`, expected an array.')); - } - for (var i = 0; i < propValue.length; i++) { - var error = typeChecker(propValue, i, componentName, location, propFullName + '[' + i + ']', ReactPropTypesSecret_1); - if (error instanceof Error) { - return error; - } - } - return null; - } - return createChainableTypeChecker(validate); - } + var anchorNode = selection.anchorNode, + anchorOffset = selection.anchorOffset, + focusNode = selection.focusNode, + focusOffset = selection.focusOffset; - function createElementTypeChecker() { - function validate(props, propName, componentName, location, propFullName) { - var propValue = props[propName]; - if (!isValidElement(propValue)) { - var propType = getPropType(propValue); - return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type ' + ('`' + propType + '` supplied to `' + componentName + '`, expected a single ReactElement.')); - } - return null; - } - return createChainableTypeChecker(validate); - } + // In Firefox, anchorNode and focusNode can be "anonymous divs", e.g. the + // up/down buttons on an <input type="number">. 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 - function createInstanceTypeChecker(expectedClass) { - function validate(props, propName, componentName, location, propFullName) { - if (!(props[propName] instanceof expectedClass)) { - var expectedClassName = expectedClass.name || ANONYMOUS; - var actualClassName = getClassName(props[propName]); - return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type ' + ('`' + actualClassName + '` supplied to `' + componentName + '`, expected ') + ('instance of `' + expectedClassName + '`.')); - } - return null; - } - return createChainableTypeChecker(validate); + try { + /* eslint-disable no-unused-expressions */ + anchorNode.nodeType; + focusNode.nodeType; + /* eslint-enable no-unused-expressions */ + } catch (e) { + return null; } - function createEnumTypeChecker(expectedValues) { - if (!Array.isArray(expectedValues)) { - warning_1(false, 'Invalid argument supplied to oneOf, expected an instance of array.'); - return emptyFunction_1.thatReturnsNull; - } + return getModernOffsetsFromPoints(outerNode, anchorNode, anchorOffset, focusNode, focusOffset); +} - function validate(props, propName, componentName, location, propFullName) { - var propValue = props[propName]; - for (var i = 0; i < expectedValues.length; i++) { - if (is(propValue, expectedValues[i])) { - return null; - } - } +/** + * 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, focusOffset) { + var length = 0; + var start = -1; + var end = -1; + var indexWithinAnchor = 0; + var indexWithinFocus = 0; + var node = outerNode; + var parentNode = null; - var valuesString = JSON.stringify(expectedValues); - return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of value `' + propValue + '` ' + ('supplied to `' + componentName + '`, expected one of ' + valuesString + '.')); - } - return createChainableTypeChecker(validate); - } + outer: while (true) { + var next = null; - function createObjectOfTypeChecker(typeChecker) { - function validate(props, propName, componentName, location, propFullName) { - if (typeof typeChecker !== 'function') { - return new PropTypeError('Property `' + propFullName + '` of component `' + componentName + '` has invalid PropType notation inside objectOf.'); + while (true) { + if (node === anchorNode && (anchorOffset === 0 || node.nodeType === TEXT_NODE)) { + start = length + anchorOffset; } - var propValue = props[propName]; - var propType = getPropType(propValue); - if (propType !== 'object') { - return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type ' + ('`' + propType + '` supplied to `' + componentName + '`, expected an object.')); + if (node === focusNode && (focusOffset === 0 || node.nodeType === TEXT_NODE)) { + end = length + focusOffset; } - for (var key in propValue) { - if (propValue.hasOwnProperty(key)) { - var error = typeChecker(propValue, key, componentName, location, propFullName + '.' + key, ReactPropTypesSecret_1); - if (error instanceof Error) { - return error; - } - } - } - return null; - } - return createChainableTypeChecker(validate); - } - - function createUnionTypeChecker(arrayOfTypeCheckers) { - if (!Array.isArray(arrayOfTypeCheckers)) { - warning_1(false, 'Invalid argument supplied to oneOfType, expected an instance of array.'); - return emptyFunction_1.thatReturnsNull; - } - for (var i = 0; i < arrayOfTypeCheckers.length; i++) { - var checker = arrayOfTypeCheckers[i]; - if (typeof checker !== 'function') { - warning_1( - false, - 'Invalid argument supplied to oneOfType. Expected an array of check functions, but ' + - 'received %s at index %s.', - getPostfixForTypeWarning(checker), - i - ); - return emptyFunction_1.thatReturnsNull; + if (node.nodeType === TEXT_NODE) { + length += node.nodeValue.length; } - } - function validate(props, propName, componentName, location, propFullName) { - for (var i = 0; i < arrayOfTypeCheckers.length; i++) { - var checker = arrayOfTypeCheckers[i]; - if (checker(props, propName, componentName, location, propFullName, ReactPropTypesSecret_1) == null) { - return null; - } + if ((next = node.firstChild) === null) { + break; } - - return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` supplied to ' + ('`' + componentName + '`.')); + // Moving from `node` to its first child `next`. + parentNode = node; + node = next; } - return createChainableTypeChecker(validate); - } - function createNodeChecker() { - function validate(props, propName, componentName, location, propFullName) { - if (!isNode(props[propName])) { - return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` supplied to ' + ('`' + componentName + '`, expected a ReactNode.')); + 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; } - return null; - } - return createChainableTypeChecker(validate); - } - - function createShapeTypeChecker(shapeTypes) { - function validate(props, propName, componentName, location, propFullName) { - var propValue = props[propName]; - var propType = getPropType(propValue); - if (propType !== 'object') { - return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type `' + propType + '` ' + ('supplied to `' + componentName + '`, expected `object`.')); + if (parentNode === anchorNode && ++indexWithinAnchor === anchorOffset) { + start = length; } - for (var key in shapeTypes) { - var checker = shapeTypes[key]; - if (!checker) { - continue; - } - var error = checker(propValue, key, componentName, location, propFullName + '.' + key, ReactPropTypesSecret_1); - if (error) { - return error; - } + if (parentNode === focusNode && ++indexWithinFocus === focusOffset) { + end = length; } - return null; - } - return createChainableTypeChecker(validate); - } - - function createStrictShapeTypeChecker(shapeTypes) { - function validate(props, propName, componentName, location, propFullName) { - var propValue = props[propName]; - var propType = getPropType(propValue); - if (propType !== 'object') { - return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type `' + propType + '` ' + ('supplied to `' + componentName + '`, expected `object`.')); - } - // We need to check all keys in case some are required but missing from - // props. - var allKeys = assign({}, props[propName], shapeTypes); - for (var key in allKeys) { - var checker = shapeTypes[key]; - if (!checker) { - return new PropTypeError( - 'Invalid ' + location + ' `' + propFullName + '` key `' + key + '` supplied to `' + componentName + '`.' + - '\nBad object: ' + JSON.stringify(props[propName], null, ' ') + - '\nValid keys: ' + JSON.stringify(Object.keys(shapeTypes), null, ' ') - ); - } - var error = checker(propValue, key, componentName, location, propFullName + '.' + key, ReactPropTypesSecret_1); - if (error) { - return error; - } + if ((next = node.nextSibling) !== null) { + break; } - return null; + node = parentNode; + parentNode = node.parentNode; } - return createChainableTypeChecker(validate); + // Moving from `node` to its next sibling `next`. + node = next; } - function isNode(propValue) { - switch (typeof propValue) { - case 'number': - case 'string': - case 'undefined': - return true; - case 'boolean': - return !propValue; - case 'object': - if (Array.isArray(propValue)) { - return propValue.every(isNode); - } - if (propValue === null || isValidElement(propValue)) { - return true; - } - - var iteratorFn = getIteratorFn(propValue); - if (iteratorFn) { - var iterator = iteratorFn.call(propValue); - var step; - if (iteratorFn !== propValue.entries) { - while (!(step = iterator.next()).done) { - if (!isNode(step.value)) { - return false; - } - } - } else { - // Iterator will provide entry [k,v] tuples rather than values. - while (!(step = iterator.next()).done) { - var entry = step.value; - if (entry) { - if (!isNode(entry[1])) { - return false; - } - } - } - } - } else { - return false; - } - - return true; - default: - return false; - } + 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; } - function isSymbol(propType, propValue) { - // Native Symbol. - if (propType === 'symbol') { - return true; - } - - // 19.4.3.5 Symbol.prototype[@@toStringTag] === 'Symbol' - if (propValue['@@toStringTag'] === 'Symbol') { - return true; - } - - // Fallback for non-spec compliant Symbols which are polyfilled. - if (typeof Symbol === 'function' && propValue instanceof Symbol) { - return true; - } + return { + start: start, + end: end + }; +} - return false; +/** + * 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; } - // Equivalent of `typeof` but with special handling for array and regexp. - function getPropType(propValue) { - var propType = typeof propValue; - if (Array.isArray(propValue)) { - return 'array'; - } - if (propValue instanceof RegExp) { - // Old webkits (at least until Android 4.0) return 'function' rather than - // 'object' for typeof a RegExp. We'll normalize this here so that /bla/ - // passes PropTypes.object. - return 'object'; - } - if (isSymbol(propType, propValue)) { - return 'symbol'; - } - return propType; - } + 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); - // This handles more types than `getPropType`. Only used for error messages. - // See `createPrimitiveTypeChecker`. - function getPreciseType(propValue) { - if (typeof propValue === 'undefined' || propValue === null) { - return '' + propValue; - } - var propType = getPropType(propValue); - if (propType === 'object') { - if (propValue instanceof Date) { - return 'date'; - } else if (propValue instanceof RegExp) { - return 'regexp'; - } - } - return propType; + // 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; } - // Returns a string that is postfixed to a warning about an invalid type. - // For example, "undefined" or "of type array" - function getPostfixForTypeWarning(value) { - var type = getPreciseType(value); - switch (type) { - case 'array': - case 'object': - return 'an ' + type; - case 'boolean': - case 'date': - case 'regexp': - return 'a ' + type; - default: - return type; + 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(); - // Returns class name of the object, if any. - function getClassName(propValue) { - if (!propValue.constructor || !propValue.constructor.name) { - return ANONYMOUS; + if (start > end) { + selection.addRange(range); + selection.extend(endMarker.node, endMarker.offset); + } else { + range.setEnd(endMarker.node, endMarker.offset); + selection.addRange(range); } - return propValue.constructor.name; } +} - ReactPropTypes.checkPropTypes = checkPropTypes_1; - ReactPropTypes.PropTypes = ReactPropTypes; - - return ReactPropTypes; -}; +function isInDocument(node) { + return containsNode_1(document.documentElement, node); +} -var index = createCommonjsModule(function (module) { /** - * Copyright (c) 2013-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. + * @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. */ -{ - var REACT_ELEMENT_TYPE = (typeof Symbol === 'function' && - Symbol.for && - Symbol.for('react.element')) || - 0xeac7; - - var isValidElement = function(object) { - return typeof object === 'object' && - object !== null && - object.$$typeof === REACT_ELEMENT_TYPE; - }; - - // By explicitly using `prop-types` you are opting into new development behavior. - // http://fb.me/prop-types-in-prod - var throwOnDirectAccess = true; - module.exports = factoryWithTypeCheckers(isValidElement, throwOnDirectAccess); +function hasSelectionCapabilities(elem) { + var nodeName = elem && elem.nodeName && elem.nodeName.toLowerCase(); + return nodeName && (nodeName === 'input' && elem.type === 'text' || nodeName === 'textarea' || elem.contentEditable === 'true'); } -}); -var ReactControlledValuePropTypes = { - checkPropTypes: null -}; - -{ - var warning$10 = warning_1; - var emptyFunction$2 = emptyFunction_1; - var PropTypes = index; - var ReactPropTypesSecret = 'SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED'; - - ReactControlledValuePropTypes.checkPropTypes = emptyFunction$2; - 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`.'); - }, - onChange: PropTypes.func - }; - - var loggedTypeFailures = {}; - - /** - * 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) { - for (var propName in propTypes) { - if (propTypes.hasOwnProperty(propName)) { - var error = propTypes[propName](props, propName, tagName, 'prop', null, ReactPropTypesSecret); - } - if (error instanceof Error && !(error.message in loggedTypeFailures)) { - // Only monitor this failure once because there tends to be a lot of the - // same error. - loggedTypeFailures[error.message] = true; - - warning$10(false, 'Failed form propType: %s%s', error.message, getStack()); - } - } +function getSelectionInformation() { + var focusedElem = getActiveElement_1(); + return { + focusedElem: focusedElem, + selectionRange: hasSelectionCapabilities(focusedElem) ? getSelection$1(focusedElem) : null }; } -var ReactControlledValuePropTypes_1 = ReactControlledValuePropTypes; - -var getCurrentFiberOwnerName$3 = ReactDebugCurrentFiber_1.getCurrentFiberOwnerName; - -{ - var _require2$3 = ReactDebugCurrentFiber_1, - getCurrentFiberStackAddendum$2 = _require2$3.getCurrentFiberStackAddendum; - - var warning$9 = warning_1; -} - - - -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 <input> 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 + * @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. */ -var ReactDOMInput = { - getHostProps: function (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; - }, - - initWrapperState: function (element, props) { - { - ReactControlledValuePropTypes_1.checkPropTypes('input', props, getCurrentFiberStackAddendum$2); - - if (props.checked !== undefined && props.defaultChecked !== undefined && !didWarnCheckedDefaultChecked) { - warning$9(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$3() || 'A component', props.type); - didWarnCheckedDefaultChecked = true; - } - if (props.value !== undefined && props.defaultValue !== undefined && !didWarnValueDefaultValue) { - warning$9(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$3() || '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) - }; - }, - - updateWrapper: function (element, props) { - var node = element; - { - var controlled = isControlled(props); - - if (!node._wrapperState.controlled && controlled && !didWarnUncontrolledToControlled) { - warning$9(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$2()); - didWarnUncontrolledToControlled = true; - } - if (node._wrapperState.controlled && !controlled && !didWarnControlledToUncontrolled) { - warning$9(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$2()); - didWarnControlledToUncontrolled = true; - } +function restoreSelection(priorSelectionInformation) { + var curFocusedElem = getActiveElement_1(); + var priorFocusedElem = priorSelectionInformation.focusedElem; + var priorSelectionRange = priorSelectionInformation.selectionRange; + if (curFocusedElem !== priorFocusedElem && isInDocument(priorFocusedElem)) { + if (hasSelectionCapabilities(priorFocusedElem)) { + setSelection(priorFocusedElem, priorSelectionRange); } - var checked = props.checked; - if (checked != null) { - DOMPropertyOperations_1.setValueForProperty(node, 'checked', checked || false); - } - - 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 <x> 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; + // 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 + }); } } - }, - - postMountWrapper: function (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. + focusNode_1(priorFocusedElem); - 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; - } - }, - - restoreControlledState: function (element, props) { - var node = element; - ReactDOMInput.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 = ReactDOMComponentTree_1.getFiberCurrentPropsFromNode(otherNode); - !otherProps ? invariant_1(false, 'ReactDOMInput: Mixing React and non-React radio inputs with the same `name` is not supported.') : void 0; - // 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. - ReactDOMInput.updateWrapper(otherNode, otherProps); + for (var i = 0; i < ancestors.length; i++) { + var info = ancestors[i]; + info.element.scrollLeft = info.left; + info.element.scrollTop = info.top; } } } -var ReactDOMFiberInput = ReactDOMInput; - -{ - var warning$12 = warning_1; -} - -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. - require$$0.Children.forEach(children, function (child) { - if (child == null) { - return; - } - if (typeof child === 'string' || typeof child === 'number') { - content += child; - } - }); - - return content; -} - /** - * Implements an <option> host component that warns when `selected` is set. + * @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} */ -var ReactDOMOption = { - validateProps: function (element, props) { - // TODO (yungsters): Remove support for `selected` in <option>. - { - warning$12(props.selected == null, 'Use the `defaultValue` or `value` props on <select> instead of ' + 'setting `selected` on <option>.'); - } - }, - - postMountWrapper: function (element, props) { - // value="" should make a value attribute (#6219) - if (props.value != null) { - element.setAttribute('value', props.value); - } - }, - - getHostProps: function (element, props) { - var hostProps = assign({ children: undefined }, props); - - var content = flattenChildren(props.children); - - if (content) { - hostProps.children = content; - } +function getSelection$1(input) { + var selection = void 0; - return hostProps; + 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); } -}; - -var ReactDOMFiberOption = ReactDOMOption; - -var getCurrentFiberOwnerName$4 = ReactDebugCurrentFiber_1.getCurrentFiberOwnerName; - -{ - var didWarnValueDefaultValue$1 = false; - var warning$13 = warning_1; - - var _require2$4 = ReactDebugCurrentFiber_1, - getCurrentFiberStackAddendum$3 = _require2$4.getCurrentFiberStackAddendum; -} -function getDeclarationErrorAddendum() { - var ownerName = getCurrentFiberOwnerName$4(); - if (ownerName) { - return '\n\nCheck the render method of `' + ownerName + '`.'; - } - return ''; + return selection || { start: 0, end: 0 }; } -var valuePropNames = ['value', 'defaultValue']; - /** - * Validation function for `value` and `defaultValue`. + * @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 checkSelectPropTypes(props) { - ReactControlledValuePropTypes_1.checkPropTypes('select', props, getCurrentFiberStackAddendum$3); +function setSelection(input, offsets) { + var start = offsets.start, + end = offsets.end; - for (var i = 0; i < valuePropNames.length; i++) { - var propName = valuePropNames[i]; - if (props[propName] == null) { - continue; - } - var isArray = Array.isArray(props[propName]); - if (props.multiple && !isArray) { - warning$13(false, 'The `%s` prop supplied to <select> must be an array if ' + '`multiple` is true.%s', propName, getDeclarationErrorAddendum()); - } else if (!props.multiple && isArray) { - warning$13(false, 'The `%s` prop supplied to <select> must be a scalar ' + 'value if `multiple` is false.%s', propName, getDeclarationErrorAddendum()); - } + if (end === undefined) { + end = start; } -} -function updateOptions(node, multiple, propValue) { - var options = node.options; - - if (multiple) { - var selectedValues = propValue; - var selectedValue = {}; - for (var i = 0; i < selectedValues.length; i++) { - // Prefix to avoid chaos with special keys. - selectedValue['$' + selectedValues[i]] = true; - } - for (var _i = 0; _i < options.length; _i++) { - var selected = selectedValue.hasOwnProperty('$' + options[_i].value); - if (options[_i].selected !== selected) { - options[_i].selected = selected; - } - } + if ('selectionStart' in input) { + input.selectionStart = start; + input.selectionEnd = Math.min(end, input.value.length); } else { - // Do not set `select.value` as exact behavior isn't consistent across all - // browsers for all cases. - var _selectedValue = '' + propValue; - var defaultSelected = null; - for (var _i2 = 0; _i2 < options.length; _i2++) { - if (options[_i2].value === _selectedValue) { - options[_i2].selected = true; - return; - } - if (defaultSelected === null && !options[_i2].disabled) { - defaultSelected = options[_i2]; - } - } - if (defaultSelected !== null) { - defaultSelected.selected = true; - } + setOffsets(input, offsets); } } -/** - * Implements a <select> host component that allows optionally setting the - * props `value` and `defaultValue`. If `multiple` is false, the prop must be a - * stringable. If `multiple` is true, the prop must be an array of stringables. - * - * If `value` is not supplied (or null/undefined), user actions that change the - * selected option will trigger updates to the rendered options. - * - * If it is supplied (and not null/undefined), the rendered options will not - * update in response to user actions. Instead, the `value` prop must change in - * order for the rendered options to update. - * - * If `defaultValue` is provided, any options with the supplied values will be - * selected. - */ -var ReactDOMSelect = { - getHostProps: function (element, props) { - return assign({}, props, { - value: undefined - }); - }, - - initWrapperState: function (element, props) { - var node = element; - { - checkSelectPropTypes(props); - } - - var value = props.value; - node._wrapperState = { - initialValue: value != null ? value : props.defaultValue, - wasMultiple: !!props.multiple - }; - - { - if (props.value !== undefined && props.defaultValue !== undefined && !didWarnValueDefaultValue$1) { - warning$13(false, 'Select 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 select ' + 'element and remove one of these props. More info: ' + 'https://fb.me/react-controlled-components'); - didWarnValueDefaultValue$1 = true; - } - } - }, - - postMountWrapper: function (element, props) { - var node = element; - node.multiple = !!props.multiple; - var value = props.value; - if (value != null) { - updateOptions(node, !!props.multiple, value); - } else if (props.defaultValue != null) { - updateOptions(node, !!props.multiple, props.defaultValue); - } - }, - - postUpdateWrapper: function (element, props) { - var node = element; - // After the initial mount, we control selected-ness manually so don't pass - // this value down - node._wrapperState.initialValue = undefined; - - var wasMultiple = node._wrapperState.wasMultiple; - node._wrapperState.wasMultiple = !!props.multiple; - - var value = props.value; - if (value != null) { - updateOptions(node, !!props.multiple, value); - } else if (wasMultiple !== !!props.multiple) { - // For simplicity, reapply `defaultValue` if `multiple` is toggled. - if (props.defaultValue != null) { - updateOptions(node, !!props.multiple, props.defaultValue); - } else { - // Revert the select back to its default unselected state. - updateOptions(node, !!props.multiple, props.multiple ? [] : ''); - } - } - }, - - restoreControlledState: function (element, props) { - var node = element; - var value = props.value; +var skipSelectionChangeEvent = ExecutionEnvironment_1.canUseDOM && 'documentMode' in document && document.documentMode <= 11; - if (value != null) { - updateOptions(node, !!props.multiple, value); - } +var eventTypes$3 = { + select: { + phasedRegistrationNames: { + bubbled: 'onSelect', + captured: 'onSelectCapture' + }, + dependencies: ['topBlur', 'topContextMenu', 'topFocus', 'topKeyDown', 'topKeyUp', 'topMouseDown', 'topMouseUp', 'topSelectionChange'] } }; -var ReactDOMFiberSelect = ReactDOMSelect; - -{ - var warning$14 = warning_1; - - var _require$4 = ReactDebugCurrentFiber_1, - getCurrentFiberStackAddendum$4 = _require$4.getCurrentFiberStackAddendum; -} - -var didWarnValDefaultVal = false; +var activeElement$1 = null; +var activeElementInst$1 = null; +var lastSelection = null; +var mouseDown = false; /** - * Implements a <textarea> host component that allows setting `value`, and - * `defaultValue`. This differs from the traditional DOM API because value is - * usually set as PCDATA children. - * - * If `value` is not supplied (or null/undefined), user actions that affect the - * value will trigger updates to the element. + * Get an object which is a unique representation of the current selection. * - * If `value` is supplied (and not null/undefined), the rendered element will - * not trigger updates to the element. Instead, the `value` prop must change in - * order for the rendered element to be updated. + * The return value will not be consistent across nodes or browsers, but + * two identical selections on the same node will return identical objects. * - * The rendered element will be initialized with an empty value, the prop - * `defaultValue` if specified, or the children content (deprecated). + * @param {DOMElement} node + * @return {object} */ -var ReactDOMTextarea = { - getHostProps: function (element, props) { - var node = element; - !(props.dangerouslySetInnerHTML == null) ? invariant_1(false, '`dangerouslySetInnerHTML` does not make sense on <textarea>.') : void 0; - - // Always set children to the same thing. In IE9, the selection range will - // get reset if `textContent` is mutated. We could add a check in setTextContent - // to only set the value if/when the value differs from the node value (which would - // completely solve this IE9 bug), but Sebastian+Sophie seemed to like this - // solution. The value can be a boolean or object so that's why it's forced - // to be a string. - var hostProps = assign({}, props, { - value: undefined, - defaultValue: undefined, - children: '' + node._wrapperState.initialValue - }); - - return hostProps; - }, - - initWrapperState: function (element, props) { - var node = element; - { - ReactControlledValuePropTypes_1.checkPropTypes('textarea', props, getCurrentFiberStackAddendum$4); - if (props.value !== undefined && props.defaultValue !== undefined && !didWarnValDefaultVal) { - warning$14(false, 'Textarea 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 textarea ' + 'and remove one of these props. More info: ' + 'https://fb.me/react-controlled-components'); - didWarnValDefaultVal = true; - } - } - - var value = props.value; - var initialValue = value; - - // Only bother fetching default value if we're going to use it - if (value == null) { - var defaultValue = props.defaultValue; - // TODO (yungsters): Remove support for children content in <textarea>. - var children = props.children; - if (children != null) { - { - warning$14(false, 'Use the `defaultValue` or `value` props instead of setting ' + 'children on <textarea>.'); - } - !(defaultValue == null) ? invariant_1(false, 'If you supply `defaultValue` on a <textarea>, do not pass children.') : void 0; - if (Array.isArray(children)) { - !(children.length <= 1) ? invariant_1(false, '<textarea> can only have at most one child.') : void 0; - children = children[0]; - } - - defaultValue = '' + children; - } - if (defaultValue == null) { - defaultValue = ''; - } - initialValue = defaultValue; - } - - node._wrapperState = { - initialValue: '' + initialValue +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 }; - }, - - updateWrapper: function (element, props) { - var node = element; - var value = props.value; - if (value != null) { - // Cast `value` to a string to ensure the value is set correctly. While - // browsers typically do this as necessary, jsdom doesn't. - var newValue = '' + value; - - // To avoid side effects (such as losing text selection), only set value if changed - if (newValue !== node.value) { - node.value = newValue; - } - if (props.defaultValue == null) { - node.defaultValue = newValue; - } - } - if (props.defaultValue != null) { - node.defaultValue = props.defaultValue; - } - }, - - postMountWrapper: function (element, props) { - var node = element; - // This is in postMount because we need access to the DOM node, which is not - // available until after the component has mounted. - var textContent = node.textContent; - - // Only set node.value if textContent is equal to the expected - // initial value. In IE10/IE11 there is a bug where the placeholder attribute - // will populate textContent as well. - // https://developer.microsoft.com/microsoft-edge/platform/issues/101525/ - if (textContent === node._wrapperState.initialValue) { - node.value = textContent; - } - }, - - restoreControlledState: function (element, props) { - // DOM component is still mounted; update - ReactDOMTextarea.updateWrapper(element, props); } -}; - -var ReactDOMFiberTextarea = ReactDOMTextarea; +} /** - * Copyright (c) 2013-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. + * Poll selection to see whether it's changed. * - * @providesModule omittedCloseTags + * @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_1()) { + return null; + } -// For HTML, certain tags should omit their close tag. We keep a whitelist for -// those special-case tags. - -var omittedCloseTags = { - area: true, - base: true, - br: true, - col: true, - embed: true, - hr: true, - img: true, - input: true, - keygen: true, - link: true, - meta: true, - param: true, - source: true, - track: true, - wbr: true -}; - -var omittedCloseTags_1 = omittedCloseTags; - -// For HTML, certain tags cannot have children. This has the same purpose as -// `omittedCloseTags` except that `menuitem` should still have its closing tag. - -var voidElementTags = assign({ - menuitem: true -}, omittedCloseTags_1); + // Only fire when selection has actually changed. + var currentSelection = getSelection(activeElement$1); + if (!lastSelection || !shallowEqual_1(lastSelection, currentSelection)) { + lastSelection = currentSelection; -var voidElementTags_1 = voidElementTags; + var syntheticEvent = SyntheticEvent$1.getPooled(eventTypes$3.select, activeElementInst$1, nativeEvent, nativeEventTarget); -{ - var warning$15 = warning_1; -} + syntheticEvent.type = 'select'; + syntheticEvent.target = activeElement$1; -var HTML$1 = '__html'; + accumulateTwoPhaseDispatches(syntheticEvent); -function getDeclarationErrorAddendum$1(getCurrentOwnerName) { - { - var ownerName = getCurrentOwnerName(); - if (ownerName) { - // TODO: also report the stack. - return '\n\nThis DOM node was rendered by `' + ownerName + '`.'; - } + return syntheticEvent; } - return ''; -} -function assertValidProps(tag, props, getCurrentOwnerName) { - if (!props) { - return; - } - // Note the use of `==` which checks for null or undefined. - if (voidElementTags_1[tag]) { - !(props.children == null && props.dangerouslySetInnerHTML == null) ? invariant_1(false, '%s is a void element tag and must neither have `children` nor use `dangerouslySetInnerHTML`.%s', tag, getDeclarationErrorAddendum$1(getCurrentOwnerName)) : void 0; - } - if (props.dangerouslySetInnerHTML != null) { - !(props.children == null) ? invariant_1(false, 'Can only set one of `children` or `props.dangerouslySetInnerHTML`.') : void 0; - !(typeof props.dangerouslySetInnerHTML === 'object' && HTML$1 in props.dangerouslySetInnerHTML) ? invariant_1(false, '`props.dangerouslySetInnerHTML` must be in the form `{__html: ...}`. Please visit https://fb.me/react-invariant-dangerously-set-inner-html for more information.') : void 0; - } - { - warning$15(props.suppressContentEditableWarning || !props.contentEditable || props.children == null, 'A component is `contentEditable` and contains `children` managed by ' + 'React. It is now your responsibility to guarantee that none of ' + 'those nodes are unexpectedly modified or duplicated. This is ' + 'probably not intentional.'); - } - !(props.style == null || typeof props.style === 'object') ? invariant_1(false, 'The `style` prop expects a mapping from style properties to values, not a string. For example, style={{marginRight: spacing + \'em\'}} when using JSX.%s', getDeclarationErrorAddendum$1(getCurrentOwnerName)) : void 0; + return null; } -var assertValidProps_1 = assertValidProps; - /** - * Copyright (c) 2013-present, Facebook, Inc. + * This plugin creates an `onSelect` event that normalizes select events + * across form elements. * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. + * Supported elements are: + * - input (see `isTextInputElement`) + * - textarea + * - contentEditable * - * @providesModule inputValueTracking - * + * 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, -function isCheckable(elem) { - var type = elem.type; - var nodeName = elem.nodeName; - return nodeName && nodeName.toLowerCase() === 'input' && (type === 'checkbox' || type === 'radio'); -} - -function getTracker(node) { - return node._valueTracker; -} - -function detachTracker(node) { - node._valueTracker = null; -} - -function getValueFromNode(node) { - var value = ''; - if (!node) { - return value; - } - - if (isCheckable(node)) { - value = node.checked ? 'true' : 'false'; - } else { - value = node.value; - } - - return value; -} - -function trackValueOnNode(node) { - var valueField = isCheckable(node) ? 'checked' : 'value'; - var descriptor = Object.getOwnPropertyDescriptor(node.constructor.prototype, valueField); - - var currentValue = '' + node[valueField]; - - // if someone has already defined a value or Safari, then bail - // and don't track value will cause over reporting of changes, - // but it's better then a hard failure - // (needed for certain tests that spyOn input values and Safari) - if (node.hasOwnProperty(valueField) || typeof descriptor.get !== 'function' || typeof descriptor.set !== 'function') { - return; - } - - Object.defineProperty(node, valueField, { - enumerable: descriptor.enumerable, - configurable: true, - get: function () { - return descriptor.get.call(this); - }, - set: function (value) { - currentValue = '' + value; - descriptor.set.call(this, value); - } - }); - - var tracker = { - getValue: function () { - return currentValue; - }, - setValue: function (value) { - currentValue = '' + value; - }, - stopTracking: function () { - detachTracker(node); - delete node[valueField]; - } - }; - return tracker; -} - -var inputValueTracking = { - // exposed for testing - _getTrackerFromNode: getTracker, - - track: function (node) { - if (getTracker(node)) { - return; + 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; } - // TODO: Once it's just Fiber we can move this to node._wrapperState - node._valueTracker = trackValueOnNode(node); - }, - updateValueIfChanged: function (node) { - if (!node) { - return false; - } + var targetNode = targetInst ? getNodeFromInstance$1(targetInst) : window; - var tracker = getTracker(node); - // if there is no tracker at this point it's unlikely - // that trying again will succeed - if (!tracker) { - return true; + 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); } - var lastValue = tracker.getValue(); - var nextValue = getValueFromNode(node); - if (nextValue !== lastValue) { - tracker.setValue(nextValue); - return true; - } - return false; - }, - stopTracking: function (node) { - var tracker = getTracker(node); - if (tracker) { - tracker.stopTracking(); - } + return null; } }; -var inputValueTracking_1 = inputValueTracking; - /** - * Copyright (c) 2013-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @providesModule isCustomComponent - * + * @interface Event + * @see http://www.w3.org/TR/css3-animations/#AnimationEvent-interface + * @see https://developer.mozilla.org/en-US/docs/Web/API/AnimationEvent */ - -function isCustomComponent(tagName, props) { - if (tagName.indexOf('-') === -1) { - return typeof props.is === 'string'; - } - switch (tagName) { - // These are reserved SVG and MathML elements. - // We don't mind this whitelist too much because we expect it to never grow. - // The alternative is to track the namespace in a few places which is convoluted. - // https://w3c.github.io/webcomponents/spec/custom/#custom-elements-core-concepts - case 'annotation-xml': - case 'color-profile': - case 'font-face': - case 'font-face-src': - case 'font-face-uri': - case 'font-face-format': - case 'font-face-name': - case 'missing-glyph': - return false; - default: - return true; - } -} - -var isCustomComponent_1 = isCustomComponent; +var AnimationEventInterface = { + animationName: null, + elapsedTime: null, + pseudoElement: null +}; /** - * Copyright (c) 2013-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @providesModule createMicrosoftUnsafeLocalFunction + * @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); +} -/* globals MSApp */ +SyntheticEvent$1.augmentClass(SyntheticAnimationEvent, AnimationEventInterface); /** - * Create a function which has 'unsafe' privileges (required by windows8 apps) + * @interface Event + * @see http://www.w3.org/TR/clipboard-apis/ */ - -var createMicrosoftUnsafeLocalFunction = function (func) { - if (typeof MSApp !== 'undefined' && MSApp.execUnsafeLocalFunction) { - return function (arg0, arg1, arg2, arg3) { - MSApp.execUnsafeLocalFunction(function () { - return func(arg0, arg1, arg2, arg3); - }); - }; - } else { - return func; +var ClipboardEventInterface = { + clipboardData: function (event) { + return 'clipboardData' in event ? event.clipboardData : window.clipboardData; } }; -var createMicrosoftUnsafeLocalFunction_1 = createMicrosoftUnsafeLocalFunction; - -var Namespaces$1 = DOMNamespaces.Namespaces; - - -// SVG temp container for IE lacking innerHTML -var reusableSVGContainer; - /** - * Set the innerHTML property of a node - * - * @param {DOMElement} node - * @param {string} html - * @internal + * @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} */ -var setInnerHTML = createMicrosoftUnsafeLocalFunction_1(function (node, html) { - // IE does not have innerHTML for SVG nodes, so instead we inject the - // new markup in a temp node and then move the child nodes across into - // the target node - if (node.namespaceURI === Namespaces$1.svg && !('innerHTML' in node)) { - reusableSVGContainer = reusableSVGContainer || document.createElement('div'); - reusableSVGContainer.innerHTML = '<svg>' + html + '</svg>'; - var svgNode = reusableSVGContainer.firstChild; - while (svgNode.firstChild) { - node.appendChild(svgNode.firstChild); - } - } else { - node.innerHTML = html; - } -}); +function SyntheticClipboardEvent(dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget) { + return SyntheticEvent$1.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget); +} -var setInnerHTML_1 = setInnerHTML; +SyntheticEvent$1.augmentClass(SyntheticClipboardEvent, ClipboardEventInterface); /** - * Copyright (c) 2016-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * Based on the escape-html library, which is used under the MIT License below: - * - * Copyright (c) 2012-2013 TJ Holowaychuk - * Copyright (c) 2015 Andreas Lubbe - * Copyright (c) 2015 Tiancheng "Timothy" Gu - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * 'Software'), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - * @providesModule escapeTextContentForBrowser + * @interface FocusEvent + * @see http://www.w3.org/TR/DOM-Level-3-Events/ */ +var FocusEventInterface = { + relatedTarget: null +}; -// code copied and modified from escape-html /** - * Module variables. - * @private + * @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); +} -var matchHtmlRegExp = /["'&<>]/; +SyntheticUIEvent.augmentClass(SyntheticFocusEvent, FocusEventInterface); /** - * Escape special characters in the given string of html. + * `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 {string} string The string to escape for inserting into HTML - * @return {string} - * @public + * @param {object} nativeEvent Native browser event. + * @return {number} Normalized `charCode` property. */ +function getEventCharCode(nativeEvent) { + var charCode; + var keyCode = nativeEvent.keyCode; -function escapeHtml(string) { - var str = '' + string; - var match = matchHtmlRegExp.exec(str); - - if (!match) { - return str; - } - - var escape; - var html = ''; - var index = 0; - var lastIndex = 0; - - for (index = match.index; index < str.length; index++) { - switch (str.charCodeAt(index)) { - case 34: - // " - escape = '"'; - break; - case 38: - // & - escape = '&'; - break; - case 39: - // ' - escape = '''; // modified from escape-html; used to be ''' - break; - case 60: - // < - escape = '<'; - break; - case 62: - // > - escape = '>'; - break; - default: - continue; - } + if ('charCode' in nativeEvent) { + charCode = nativeEvent.charCode; - if (lastIndex !== index) { - html += str.substring(lastIndex, index); + // 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; + } - lastIndex = index + 1; - html += escape; + // 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 lastIndex !== index ? html + str.substring(lastIndex, index) : html; + return 0; } -// end code copied and modified from escape-html /** - * Escapes text to prevent scripting attacks. - * - * @param {*} text Text value to escape. - * @return {string} An escaped string. + * Normalization of deprecated HTML5 `key` values + * @see https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent#Key_names */ -function escapeTextContentForBrowser(text) { - if (typeof text === 'boolean' || typeof text === 'number') { - // this shortcircuit helps perf for types that we know will never have - // special characters, especially given that this function is used often - // for numeric dom ids. - return '' + text; - } - return escapeHtml(text); -} - -var escapeTextContentForBrowser_1 = escapeTextContentForBrowser; - -var TEXT_NODE$2 = HTMLNodeType_1.TEXT_NODE; +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' +}; /** - * Set the textContent property of a node, ensuring that whitespace is preserved - * even in IE8. innerText is a poor substitute for textContent and, among many - * issues, inserts <br> instead of the literal newline chars. innerHTML behaves - * as it should. - * - * @param {DOMElement} node - * @param {string} text - * @internal + * 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 setTextContent = function (node, text) { - if (text) { - var firstChild = node.firstChild; - - if (firstChild && firstChild === node.lastChild && firstChild.nodeType === TEXT_NODE$2) { - firstChild.nodeValue = text; - return; - } - } - node.textContent = text; +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' }; -if (ExecutionEnvironment_1.canUseDOM) { - if (!('textContent' in document.documentElement)) { - setTextContent = function (node, text) { - if (node.nodeType === TEXT_NODE$2) { - node.nodeValue = text; - return; - } - setInnerHTML_1(node, escapeTextContentForBrowser_1(text)); - }; - } -} - -var setTextContent_1 = setTextContent; - /** - * Copyright (c) 2013-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @providesModule validAriaProperties + * @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. -var ariaProperties = { - 'aria-current': 0, // state - 'aria-details': 0, - 'aria-disabled': 0, // state - 'aria-hidden': 0, // state - 'aria-invalid': 0, // state - 'aria-keyshortcuts': 0, - 'aria-label': 0, - 'aria-roledescription': 0, - // Widget Attributes - 'aria-autocomplete': 0, - 'aria-checked': 0, - 'aria-expanded': 0, - 'aria-haspopup': 0, - 'aria-level': 0, - 'aria-modal': 0, - 'aria-multiline': 0, - 'aria-multiselectable': 0, - 'aria-orientation': 0, - 'aria-placeholder': 0, - 'aria-pressed': 0, - 'aria-readonly': 0, - 'aria-required': 0, - 'aria-selected': 0, - 'aria-sort': 0, - 'aria-valuemax': 0, - 'aria-valuemin': 0, - 'aria-valuenow': 0, - 'aria-valuetext': 0, - // Live Region Attributes - 'aria-atomic': 0, - 'aria-busy': 0, - 'aria-live': 0, - 'aria-relevant': 0, - // Drag-and-Drop Attributes - 'aria-dropeffect': 0, - 'aria-grabbed': 0, - // Relationship Attributes - 'aria-activedescendant': 0, - 'aria-colcount': 0, - 'aria-colindex': 0, - 'aria-colspan': 0, - 'aria-controls': 0, - 'aria-describedby': 0, - 'aria-errormessage': 0, - 'aria-flowto': 0, - 'aria-labelledby': 0, - 'aria-owns': 0, - 'aria-posinset': 0, - 'aria-rowcount': 0, - 'aria-rowindex': 0, - 'aria-rowspan': 0, - 'aria-setsize': 0 -}; - -var validAriaProperties$1 = ariaProperties; - -var warnedProperties = {}; -var rARIA = new RegExp('^(aria)-[' + DOMProperty_1.ATTRIBUTE_NAME_CHAR + ']*$'); -var rARIACamel = new RegExp('^(aria)[A-Z][' + DOMProperty_1.ATTRIBUTE_NAME_CHAR + ']*$'); - -var hasOwnProperty = Object.prototype.hasOwnProperty; - -{ - var warning$16 = warning_1; - - var _require$5 = ReactGlobalSharedState_1, - ReactComponentTreeHook$1 = _require$5.ReactComponentTreeHook, - ReactDebugCurrentFrame$1 = _require$5.ReactDebugCurrentFrame; - - var getStackAddendumByID = ReactComponentTreeHook$1.getStackAddendumByID; - - - var validAriaProperties = validAriaProperties$1; -} - -function getStackAddendum(debugID) { - if (debugID != null) { - // This can only happen on Stack - return getStackAddendumByID(debugID); - } else { - // This can only happen on Fiber / Server - var stack = ReactDebugCurrentFrame$1.getStackAddendum(); - return stack != null ? stack : ''; - } -} - -function validateProperty(tagName, name, debugID) { - if (hasOwnProperty.call(warnedProperties, name) && warnedProperties[name]) { - return true; - } - - if (rARIACamel.test(name)) { - var ariaName = 'aria-' + name.slice(4).toLowerCase(); - var correctName = validAriaProperties.hasOwnProperty(ariaName) ? ariaName : null; - - // If this is an aria-* attribute, but is not listed in the known DOM - // DOM properties, then it is an invalid aria-* attribute. - if (correctName == null) { - warning$16(false, 'Invalid ARIA attribute `%s`. ARIA attributes follow the pattern aria-* and must be lowercase.%s', name, getStackAddendum(debugID)); - warnedProperties[name] = true; - return true; - } - // aria-* attributes should be lowercase; suggest the lowercase version. - if (name !== correctName) { - warning$16(false, 'Invalid ARIA attribute `%s`. Did you mean `%s`?%s', name, correctName, getStackAddendum(debugID)); - warnedProperties[name] = true; - return true; - } - } - - if (rARIA.test(name)) { - var lowerCasedName = name.toLowerCase(); - var standardName = validAriaProperties.hasOwnProperty(lowerCasedName) ? lowerCasedName : null; - - // If this is an aria-* attribute, but is not listed in the known DOM - // DOM properties, then it is an invalid aria-* attribute. - if (standardName == null) { - warnedProperties[name] = true; - return false; - } - // aria-* attributes should be lowercase; suggest the lowercase version. - if (name !== standardName) { - warning$16(false, 'Unknown ARIA attribute `%s`. Did you mean `%s`?%s', name, standardName, getStackAddendum(debugID)); - warnedProperties[name] = true; - return true; + // 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; } } - return true; -} - -function warnInvalidARIAProps(type, props, debugID) { - var invalidProps = []; + // Browser does not implement `key`, polyfill as much of it as we can. + if (nativeEvent.type === 'keypress') { + var charCode = getEventCharCode(nativeEvent); - for (var key in props) { - var isValid = validateProperty(type, key, debugID); - if (!isValid) { - invalidProps.push(key); - } + // 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); } - - var unknownPropString = invalidProps.map(function (prop) { - return '`' + prop + '`'; - }).join(', '); - - if (invalidProps.length === 1) { - warning$16(false, 'Invalid aria prop %s on <%s> tag. ' + 'For details, see https://fb.me/invalid-aria-prop%s', unknownPropString, type, getStackAddendum(debugID)); - } else if (invalidProps.length > 1) { - warning$16(false, 'Invalid aria props %s on <%s> tag. ' + 'For details, see https://fb.me/invalid-aria-prop%s', unknownPropString, type, getStackAddendum(debugID)); + 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 ''; } -function validateProperties(type, props, debugID /* Stack only */) { - if (isCustomComponent_1(type, props)) { - return; - } - warnInvalidARIAProps(type, props, debugID); -} +/** + * @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. -var ReactDOMInvalidARIAHook$1 = { - // Fiber - validateProperties: validateProperties, - // Stack - onBeforeMountComponent: function (debugID, element) { - if (true && element != null && typeof element.type === 'string') { - validateProperties(element.type, element.props, debugID); + // 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; }, - onBeforeUpdateComponent: function (debugID, element) { - if (true && element != null && typeof element.type === 'string') { - validateProperties(element.type, element.props, debugID); - } - } -}; - -var ReactDOMInvalidARIAHook_1 = ReactDOMInvalidARIAHook$1; - -{ - var warning$17 = warning_1; - - var _require$6 = ReactGlobalSharedState_1, - ReactComponentTreeHook$2 = _require$6.ReactComponentTreeHook, - ReactDebugCurrentFrame$2 = _require$6.ReactDebugCurrentFrame; - - var getStackAddendumByID$1 = ReactComponentTreeHook$2.getStackAddendumByID; -} - -var didWarnValueNull = false; - -function getStackAddendum$1(debugID) { - if (debugID != null) { - // This can only happen on Stack - return getStackAddendumByID$1(debugID); - } else { - // This can only happen on Fiber / Server - var stack = ReactDebugCurrentFrame$2.getStackAddendum(); - return stack != null ? stack : ''; - } -} - -function validateProperties$1(type, props, debugID /* Stack only */) { - if (type !== 'input' && type !== 'textarea' && type !== 'select') { - return; - } - if (props != null && props.value === null && !didWarnValueNull) { - warning$17(false, '`value` prop on `%s` should not be null. ' + 'Consider using the empty string to clear the component or `undefined` ' + 'for uncontrolled components.%s', type, getStackAddendum$1(debugID)); - - didWarnValueNull = true; - } -} + keyCode: function (event) { + // `keyCode` is the result of a KeyDown/Up event and represents the value of + // physical keyboard key. -var ReactDOMNullInputValuePropHook$1 = { - // Fiber - validateProperties: validateProperties$1, - // Stack - onBeforeMountComponent: function (debugID, element) { - if (true && element != null && typeof element.type === 'string') { - validateProperties$1(element.type, element.props, debugID); + // 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; }, - onBeforeUpdateComponent: function (debugID, element) { - if (true && element != null && typeof element.type === 'string') { - validateProperties$1(element.type, element.props, debugID); + 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; } }; -var ReactDOMNullInputValuePropHook_1 = ReactDOMNullInputValuePropHook$1; - /** - * Copyright (c) 2013-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @providesModule possibleStandardNames + * @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} */ - -// When adding attributes to the HTML or SVG whitelist, be sure to -// also add them to this module to ensure casing and incorrect name -// warnings. -var possibleStandardNames$1 = { - // HTML - accept: 'accept', - acceptcharset: 'acceptCharset', - 'accept-charset': 'acceptCharset', - accesskey: 'accessKey', - action: 'action', - allowfullscreen: 'allowFullScreen', - allowtransparency: 'allowTransparency', - alt: 'alt', - as: 'as', - async: 'async', - autocapitalize: 'autoCapitalize', - autocomplete: 'autoComplete', - autocorrect: 'autoCorrect', - autofocus: 'autoFocus', - autoplay: 'autoPlay', - autosave: 'autoSave', - capture: 'capture', - cellpadding: 'cellPadding', - cellspacing: 'cellSpacing', - challenge: 'challenge', - charset: 'charSet', - checked: 'checked', - children: 'children', - cite: 'cite', - 'class': 'className', - classid: 'classID', - classname: 'className', - cols: 'cols', - colspan: 'colSpan', - content: 'content', - contenteditable: 'contentEditable', - contextmenu: 'contextMenu', - controls: 'controls', - controlslist: 'controlsList', - coords: 'coords', - crossorigin: 'crossOrigin', - dangerouslysetinnerhtml: 'dangerouslySetInnerHTML', - data: 'data', - datetime: 'dateTime', - 'default': 'default', - defaultchecked: 'defaultChecked', - defaultvalue: 'defaultValue', - defer: 'defer', - dir: 'dir', - disabled: 'disabled', - download: 'download', - draggable: 'draggable', - enctype: 'encType', - 'for': 'htmlFor', - form: 'form', - formmethod: 'formMethod', - formaction: 'formAction', - formenctype: 'formEncType', - formnovalidate: 'formNoValidate', - formtarget: 'formTarget', - frameborder: 'frameBorder', - headers: 'headers', - height: 'height', - hidden: 'hidden', - high: 'high', - href: 'href', - hreflang: 'hrefLang', - htmlfor: 'htmlFor', - httpequiv: 'httpEquiv', - 'http-equiv': 'httpEquiv', - icon: 'icon', - id: 'id', - innerhtml: 'innerHTML', - inputmode: 'inputMode', - integrity: 'integrity', - is: 'is', - itemid: 'itemID', - itemprop: 'itemProp', - itemref: 'itemRef', - itemscope: 'itemScope', - itemtype: 'itemType', - keyparams: 'keyParams', - keytype: 'keyType', - kind: 'kind', - label: 'label', - lang: 'lang', - list: 'list', - loop: 'loop', - low: 'low', - manifest: 'manifest', - marginwidth: 'marginWidth', - marginheight: 'marginHeight', - max: 'max', - maxlength: 'maxLength', - media: 'media', - mediagroup: 'mediaGroup', - method: 'method', - min: 'min', - minlength: 'minLength', - multiple: 'multiple', - muted: 'muted', - name: 'name', - nonce: 'nonce', - novalidate: 'noValidate', - open: 'open', - optimum: 'optimum', - pattern: 'pattern', - placeholder: 'placeholder', - playsinline: 'playsInline', - poster: 'poster', - preload: 'preload', - profile: 'profile', - radiogroup: 'radioGroup', - readonly: 'readOnly', - referrerpolicy: 'referrerPolicy', - rel: 'rel', - required: 'required', - reversed: 'reversed', - role: 'role', - rows: 'rows', - rowspan: 'rowSpan', - sandbox: 'sandbox', - scope: 'scope', - scoped: 'scoped', - scrolling: 'scrolling', - seamless: 'seamless', - selected: 'selected', - shape: 'shape', - size: 'size', - sizes: 'sizes', - span: 'span', - spellcheck: 'spellCheck', - src: 'src', - srcdoc: 'srcDoc', - srclang: 'srcLang', - srcset: 'srcSet', - start: 'start', - step: 'step', - style: 'style', - summary: 'summary', - tabindex: 'tabIndex', - target: 'target', - title: 'title', - type: 'type', - usemap: 'useMap', - value: 'value', - width: 'width', - wmode: 'wmode', - wrap: 'wrap', - - // SVG - about: 'about', - accentheight: 'accentHeight', - 'accent-height': 'accentHeight', - accumulate: 'accumulate', - additive: 'additive', - alignmentbaseline: 'alignmentBaseline', - 'alignment-baseline': 'alignmentBaseline', - allowreorder: 'allowReorder', - alphabetic: 'alphabetic', - amplitude: 'amplitude', - arabicform: 'arabicForm', - 'arabic-form': 'arabicForm', - ascent: 'ascent', - attributename: 'attributeName', - attributetype: 'attributeType', - autoreverse: 'autoReverse', - azimuth: 'azimuth', - basefrequency: 'baseFrequency', - baselineshift: 'baselineShift', - 'baseline-shift': 'baselineShift', - baseprofile: 'baseProfile', - bbox: 'bbox', - begin: 'begin', - bias: 'bias', - by: 'by', - calcmode: 'calcMode', - capheight: 'capHeight', - 'cap-height': 'capHeight', - clip: 'clip', - clippath: 'clipPath', - 'clip-path': 'clipPath', - clippathunits: 'clipPathUnits', - cliprule: 'clipRule', - 'clip-rule': 'clipRule', - color: 'color', - colorinterpolation: 'colorInterpolation', - 'color-interpolation': 'colorInterpolation', - colorinterpolationfilters: 'colorInterpolationFilters', - 'color-interpolation-filters': 'colorInterpolationFilters', - colorprofile: 'colorProfile', - 'color-profile': 'colorProfile', - colorrendering: 'colorRendering', - 'color-rendering': 'colorRendering', - contentscripttype: 'contentScriptType', - contentstyletype: 'contentStyleType', - cursor: 'cursor', - cx: 'cx', - cy: 'cy', - d: 'd', - datatype: 'datatype', - decelerate: 'decelerate', - descent: 'descent', - diffuseconstant: 'diffuseConstant', - direction: 'direction', - display: 'display', - divisor: 'divisor', - dominantbaseline: 'dominantBaseline', - 'dominant-baseline': 'dominantBaseline', - dur: 'dur', - dx: 'dx', - dy: 'dy', - edgemode: 'edgeMode', - elevation: 'elevation', - enablebackground: 'enableBackground', - 'enable-background': 'enableBackground', - end: 'end', - exponent: 'exponent', - externalresourcesrequired: 'externalResourcesRequired', - fill: 'fill', - fillopacity: 'fillOpacity', - 'fill-opacity': 'fillOpacity', - fillrule: 'fillRule', - 'fill-rule': 'fillRule', - filter: 'filter', - filterres: 'filterRes', - filterunits: 'filterUnits', - floodopacity: 'floodOpacity', - 'flood-opacity': 'floodOpacity', - floodcolor: 'floodColor', - 'flood-color': 'floodColor', - focusable: 'focusable', - fontfamily: 'fontFamily', - 'font-family': 'fontFamily', - fontsize: 'fontSize', - 'font-size': 'fontSize', - fontsizeadjust: 'fontSizeAdjust', - 'font-size-adjust': 'fontSizeAdjust', - fontstretch: 'fontStretch', - 'font-stretch': 'fontStretch', - fontstyle: 'fontStyle', - 'font-style': 'fontStyle', - fontvariant: 'fontVariant', - 'font-variant': 'fontVariant', - fontweight: 'fontWeight', - 'font-weight': 'fontWeight', - format: 'format', - from: 'from', - fx: 'fx', - fy: 'fy', - g1: 'g1', - g2: 'g2', - glyphname: 'glyphName', - 'glyph-name': 'glyphName', - glyphorientationhorizontal: 'glyphOrientationHorizontal', - 'glyph-orientation-horizontal': 'glyphOrientationHorizontal', - glyphorientationvertical: 'glyphOrientationVertical', - 'glyph-orientation-vertical': 'glyphOrientationVertical', - glyphref: 'glyphRef', - gradienttransform: 'gradientTransform', - gradientunits: 'gradientUnits', - hanging: 'hanging', - horizadvx: 'horizAdvX', - 'horiz-adv-x': 'horizAdvX', - horizoriginx: 'horizOriginX', - 'horiz-origin-x': 'horizOriginX', - ideographic: 'ideographic', - imagerendering: 'imageRendering', - 'image-rendering': 'imageRendering', - in2: 'in2', - 'in': 'in', - inlist: 'inlist', - intercept: 'intercept', - k1: 'k1', - k2: 'k2', - k3: 'k3', - k4: 'k4', - k: 'k', - kernelmatrix: 'kernelMatrix', - kernelunitlength: 'kernelUnitLength', - kerning: 'kerning', - keypoints: 'keyPoints', - keysplines: 'keySplines', - keytimes: 'keyTimes', - lengthadjust: 'lengthAdjust', - letterspacing: 'letterSpacing', - 'letter-spacing': 'letterSpacing', - lightingcolor: 'lightingColor', - 'lighting-color': 'lightingColor', - limitingconeangle: 'limitingConeAngle', - local: 'local', - markerend: 'markerEnd', - 'marker-end': 'markerEnd', - markerheight: 'markerHeight', - markermid: 'markerMid', - 'marker-mid': 'markerMid', - markerstart: 'markerStart', - 'marker-start': 'markerStart', - markerunits: 'markerUnits', - markerwidth: 'markerWidth', - mask: 'mask', - maskcontentunits: 'maskContentUnits', - maskunits: 'maskUnits', - mathematical: 'mathematical', - mode: 'mode', - numoctaves: 'numOctaves', - offset: 'offset', - opacity: 'opacity', - operator: 'operator', - order: 'order', - orient: 'orient', - orientation: 'orientation', - origin: 'origin', - overflow: 'overflow', - overlineposition: 'overlinePosition', - 'overline-position': 'overlinePosition', - overlinethickness: 'overlineThickness', - 'overline-thickness': 'overlineThickness', - paintorder: 'paintOrder', - 'paint-order': 'paintOrder', - panose1: 'panose1', - 'panose-1': 'panose1', - pathlength: 'pathLength', - patterncontentunits: 'patternContentUnits', - patterntransform: 'patternTransform', - patternunits: 'patternUnits', - pointerevents: 'pointerEvents', - 'pointer-events': 'pointerEvents', - points: 'points', - pointsatx: 'pointsAtX', - pointsaty: 'pointsAtY', - pointsatz: 'pointsAtZ', - prefix: 'prefix', - preservealpha: 'preserveAlpha', - preserveaspectratio: 'preserveAspectRatio', - primitiveunits: 'primitiveUnits', - property: 'property', - r: 'r', - radius: 'radius', - refx: 'refX', - refy: 'refY', - renderingintent: 'renderingIntent', - 'rendering-intent': 'renderingIntent', - repeatcount: 'repeatCount', - repeatdur: 'repeatDur', - requiredextensions: 'requiredExtensions', - requiredfeatures: 'requiredFeatures', - resource: 'resource', - restart: 'restart', - result: 'result', - results: 'results', - rotate: 'rotate', - rx: 'rx', - ry: 'ry', - scale: 'scale', - security: 'security', - seed: 'seed', - shaperendering: 'shapeRendering', - 'shape-rendering': 'shapeRendering', - slope: 'slope', - spacing: 'spacing', - specularconstant: 'specularConstant', - specularexponent: 'specularExponent', - speed: 'speed', - spreadmethod: 'spreadMethod', - startoffset: 'startOffset', - stddeviation: 'stdDeviation', - stemh: 'stemh', - stemv: 'stemv', - stitchtiles: 'stitchTiles', - stopcolor: 'stopColor', - 'stop-color': 'stopColor', - stopopacity: 'stopOpacity', - 'stop-opacity': 'stopOpacity', - strikethroughposition: 'strikethroughPosition', - 'strikethrough-position': 'strikethroughPosition', - strikethroughthickness: 'strikethroughThickness', - 'strikethrough-thickness': 'strikethroughThickness', - string: 'string', - stroke: 'stroke', - strokedasharray: 'strokeDasharray', - 'stroke-dasharray': 'strokeDasharray', - strokedashoffset: 'strokeDashoffset', - 'stroke-dashoffset': 'strokeDashoffset', - strokelinecap: 'strokeLinecap', - 'stroke-linecap': 'strokeLinecap', - strokelinejoin: 'strokeLinejoin', - 'stroke-linejoin': 'strokeLinejoin', - strokemiterlimit: 'strokeMiterlimit', - 'stroke-miterlimit': 'strokeMiterlimit', - strokewidth: 'strokeWidth', - 'stroke-width': 'strokeWidth', - strokeopacity: 'strokeOpacity', - 'stroke-opacity': 'strokeOpacity', - suppresscontenteditablewarning: 'suppressContentEditableWarning', - surfacescale: 'surfaceScale', - systemlanguage: 'systemLanguage', - tablevalues: 'tableValues', - targetx: 'targetX', - targety: 'targetY', - textanchor: 'textAnchor', - 'text-anchor': 'textAnchor', - textdecoration: 'textDecoration', - 'text-decoration': 'textDecoration', - textlength: 'textLength', - textrendering: 'textRendering', - 'text-rendering': 'textRendering', - to: 'to', - transform: 'transform', - 'typeof': 'typeof', - u1: 'u1', - u2: 'u2', - underlineposition: 'underlinePosition', - 'underline-position': 'underlinePosition', - underlinethickness: 'underlineThickness', - 'underline-thickness': 'underlineThickness', - unicode: 'unicode', - unicodebidi: 'unicodeBidi', - 'unicode-bidi': 'unicodeBidi', - unicoderange: 'unicodeRange', - 'unicode-range': 'unicodeRange', - unitsperem: 'unitsPerEm', - 'units-per-em': 'unitsPerEm', - unselectable: 'unselectable', - valphabetic: 'vAlphabetic', - 'v-alphabetic': 'vAlphabetic', - values: 'values', - vectoreffect: 'vectorEffect', - 'vector-effect': 'vectorEffect', - version: 'version', - vertadvy: 'vertAdvY', - 'vert-adv-y': 'vertAdvY', - vertoriginx: 'vertOriginX', - 'vert-origin-x': 'vertOriginX', - vertoriginy: 'vertOriginY', - 'vert-origin-y': 'vertOriginY', - vhanging: 'vHanging', - 'v-hanging': 'vHanging', - videographic: 'vIdeographic', - 'v-ideographic': 'vIdeographic', - viewbox: 'viewBox', - viewtarget: 'viewTarget', - visibility: 'visibility', - vmathematical: 'vMathematical', - 'v-mathematical': 'vMathematical', - vocab: 'vocab', - widths: 'widths', - wordspacing: 'wordSpacing', - 'word-spacing': 'wordSpacing', - writingmode: 'writingMode', - 'writing-mode': 'writingMode', - x1: 'x1', - x2: 'x2', - x: 'x', - xchannelselector: 'xChannelSelector', - xheight: 'xHeight', - 'x-height': 'xHeight', - xlinkactuate: 'xlinkActuate', - 'xlink:actuate': 'xlinkActuate', - xlinkarcrole: 'xlinkArcrole', - 'xlink:arcrole': 'xlinkArcrole', - xlinkhref: 'xlinkHref', - 'xlink:href': 'xlinkHref', - xlinkrole: 'xlinkRole', - 'xlink:role': 'xlinkRole', - xlinkshow: 'xlinkShow', - 'xlink:show': 'xlinkShow', - xlinktitle: 'xlinkTitle', - 'xlink:title': 'xlinkTitle', - xlinktype: 'xlinkType', - 'xlink:type': 'xlinkType', - xmlbase: 'xmlBase', - 'xml:base': 'xmlBase', - xmllang: 'xmlLang', - 'xml:lang': 'xmlLang', - xmlns: 'xmlns', - 'xml:space': 'xmlSpace', - xmlnsxlink: 'xmlnsXlink', - 'xmlns:xlink': 'xmlnsXlink', - xmlspace: 'xmlSpace', - y1: 'y1', - y2: 'y2', - y: 'y', - ychannelselector: 'yChannelSelector', - z: 'z', - zoomandpan: 'zoomAndPan' -}; - -var possibleStandardNames_1 = possibleStandardNames$1; - -{ - var warning$18 = warning_1; - - var _require$7 = ReactGlobalSharedState_1, - ReactComponentTreeHook$3 = _require$7.ReactComponentTreeHook, - ReactDebugCurrentFrame$3 = _require$7.ReactDebugCurrentFrame; - - var getStackAddendumByID$2 = ReactComponentTreeHook$3.getStackAddendumByID; -} - -function getStackAddendum$2(debugID) { - if (debugID != null) { - // This can only happen on Stack - return getStackAddendumByID$2(debugID); - } else { - // This can only happen on Fiber / Server - var stack = ReactDebugCurrentFrame$3.getStackAddendum(); - return stack != null ? stack : ''; - } -} - -{ - var warnedProperties$1 = {}; - var hasOwnProperty$1 = Object.prototype.hasOwnProperty; - var EVENT_NAME_REGEX = /^on[A-Z]/; - var rARIA$1 = new RegExp('^(aria)-[' + DOMProperty_1.ATTRIBUTE_NAME_CHAR + ']*$'); - var rARIACamel$1 = new RegExp('^(aria)[A-Z][' + DOMProperty_1.ATTRIBUTE_NAME_CHAR + ']*$'); - var possibleStandardNames = possibleStandardNames_1; - - var validateProperty$1 = function (tagName, name, value, debugID) { - if (hasOwnProperty$1.call(warnedProperties$1, name) && warnedProperties$1[name]) { - return true; - } - - if (EventPluginRegistry_1.registrationNameModules.hasOwnProperty(name)) { - return true; - } - - if (EventPluginRegistry_1.plugins.length === 0 && EVENT_NAME_REGEX.test(name)) { - // If no event plugins have been injected, we might be in a server environment. - // Don't check events in this case. - return true; - } - - var lowerCasedName = name.toLowerCase(); - var registrationName = EventPluginRegistry_1.possibleRegistrationNames.hasOwnProperty(lowerCasedName) ? EventPluginRegistry_1.possibleRegistrationNames[lowerCasedName] : null; - - if (registrationName != null) { - warning$18(false, 'Invalid event handler property `%s`. Did you mean `%s`?%s', name, registrationName, getStackAddendum$2(debugID)); - warnedProperties$1[name] = true; - return true; - } - - if (lowerCasedName.indexOf('on') === 0) { - warning$18(false, 'Unknown event handler property `%s`. It will be ignored.%s', name, getStackAddendum$2(debugID)); - warnedProperties$1[name] = true; - return true; - } - - // Let the ARIA attribute hook validate ARIA attributes - if (rARIA$1.test(name) || rARIACamel$1.test(name)) { - return true; - } - - if (lowerCasedName === 'onfocusin' || lowerCasedName === 'onfocusout') { - warning$18(false, 'React uses onFocus and onBlur instead of onFocusIn and onFocusOut. ' + 'All React events are normalized to bubble, so onFocusIn and onFocusOut ' + 'are not needed/supported by React.'); - warnedProperties$1[name] = true; - return true; - } - - if (lowerCasedName === 'innerhtml') { - warning$18(false, 'Directly setting property `innerHTML` is not permitted. ' + 'For more information, lookup documentation on `dangerouslySetInnerHTML`.'); - warnedProperties$1[name] = true; - return true; - } - - if (lowerCasedName === 'aria') { - warning$18(false, 'The `aria` attribute is reserved for future use in React. ' + 'Pass individual `aria-` attributes instead.'); - warnedProperties$1[name] = true; - return true; - } - - if (lowerCasedName === 'is' && value !== null && value !== undefined && typeof value !== 'string') { - warning$18(false, 'Received a `%s` for string attribute `is`. If this is expected, cast ' + 'the value to a string.%s', typeof value, getStackAddendum$2(debugID)); - warnedProperties$1[name] = true; - return true; - } - - if (typeof value === 'number' && isNaN(value)) { - warning$18(false, 'Received NaN for numeric attribute `%s`. If this is expected, cast ' + 'the value to a string.%s', name, getStackAddendum$2(debugID)); - warnedProperties$1[name] = true; - return true; - } - - var isReserved = DOMProperty_1.isReservedProp(name); - - // Known attributes should match the casing specified in the property config. - if (possibleStandardNames.hasOwnProperty(lowerCasedName)) { - var standardName = possibleStandardNames[lowerCasedName]; - if (standardName !== name) { - warning$18(false, 'Invalid DOM property `%s`. Did you mean `%s`?%s', name, standardName, getStackAddendum$2(debugID)); - warnedProperties$1[name] = true; - return true; - } - } else if (!isReserved && name !== lowerCasedName) { - // Unknown attributes should have lowercase casing since that's how they - // will be cased anyway with server rendering. - warning$18(false, 'React does not recognize the `%s` prop on a DOM element. If you ' + 'intentionally want it to appear in the DOM as a custom ' + 'attribute, spell it as lowercase `%s` instead. ' + 'If you accidentally passed it from a parent component, remove ' + 'it from the DOM element.%s', name, lowerCasedName, getStackAddendum$2(debugID)); - warnedProperties$1[name] = true; - return true; - } - - if (typeof value === 'boolean') { - warning$18(DOMProperty_1.shouldAttributeAcceptBooleanValue(name), 'Received `%s` for non-boolean attribute `%s`. If this is expected, cast ' + 'the value to a string.%s', value, name, getStackAddendum$2(debugID)); - warnedProperties$1[name] = true; - return true; - } - - // Now that we've validated casing, do not validate - // data types for reserved props - if (isReserved) { - return true; - } - - // Warn when a known attribute is a bad type - if (!DOMProperty_1.shouldSetAttribute(name, value)) { - warnedProperties$1[name] = true; - return false; - } - - return true; - }; +function SyntheticKeyboardEvent(dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget) { + return SyntheticUIEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget); } -var warnUnknownProperties = function (type, props, debugID) { - var unknownProps = []; - for (var key in props) { - var isValid = validateProperty$1(type, key, props[key], debugID); - if (!isValid) { - unknownProps.push(key); - } - } +SyntheticUIEvent.augmentClass(SyntheticKeyboardEvent, KeyboardEventInterface); - var unknownPropString = unknownProps.map(function (prop) { - return '`' + prop + '`'; - }).join(', '); - if (unknownProps.length === 1) { - warning$18(false, 'Invalid value for prop %s on <%s> tag. Either remove it from the element, ' + 'or pass a string or number value to keep it in the DOM. ' + 'For details, see https://fb.me/react-attribute-behavior%s', unknownPropString, type, getStackAddendum$2(debugID)); - } else if (unknownProps.length > 1) { - warning$18(false, 'Invalid values for props %s on <%s> tag. Either remove them from the element, ' + 'or pass a string or number value to keep them in the DOM. ' + 'For details, see https://fb.me/react-attribute-behavior%s', unknownPropString, type, getStackAddendum$2(debugID)); - } -}; - -function validateProperties$2(type, props, debugID /* Stack only */) { - if (isCustomComponent_1(type, props)) { - return; - } - warnUnknownProperties(type, props, debugID); -} - -var ReactDOMUnknownPropertyHook$1 = { - // Fiber - validateProperties: validateProperties$2, - // Stack - onBeforeMountComponent: function (debugID, element) { - if (true && element != null && typeof element.type === 'string') { - validateProperties$2(element.type, element.props, debugID); - } - }, - onBeforeUpdateComponent: function (debugID, element) { - if (true && element != null && typeof element.type === 'string') { - validateProperties$2(element.type, element.props, debugID); - } - } +/** + * @interface DragEvent + * @see http://www.w3.org/TR/DOM-Level-3-Events/ + */ +var DragEventInterface = { + dataTransfer: null }; -var ReactDOMUnknownPropertyHook_1 = ReactDOMUnknownPropertyHook$1; - -var getCurrentFiberOwnerName = ReactDebugCurrentFiber_1.getCurrentFiberOwnerName; - -var DOCUMENT_NODE$1 = HTMLNodeType_1.DOCUMENT_NODE; -var DOCUMENT_FRAGMENT_NODE$1 = HTMLNodeType_1.DOCUMENT_FRAGMENT_NODE; - - - - - - - - -{ - var warning$4 = warning_1; - - var _require3$1 = ReactDebugCurrentFiber_1, - getCurrentFiberStackAddendum = _require3$1.getCurrentFiberStackAddendum; - - var ReactDOMInvalidARIAHook = ReactDOMInvalidARIAHook_1; - var ReactDOMNullInputValuePropHook = ReactDOMNullInputValuePropHook_1; - var ReactDOMUnknownPropertyHook = ReactDOMUnknownPropertyHook_1; - var validateARIAProperties = ReactDOMInvalidARIAHook.validateProperties; - var validateInputProperties = ReactDOMNullInputValuePropHook.validateProperties; - var validateUnknownProperties = ReactDOMUnknownPropertyHook.validateProperties; +/** + * @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); } -var didWarnInvalidHydration = false; -var didWarnShadyDOM = false; +SyntheticMouseEvent.augmentClass(SyntheticDragEvent, DragEventInterface); -var listenTo = ReactBrowserEventEmitter_1.listenTo; -var registrationNameModules = EventPluginRegistry_1.registrationNameModules; - -var DANGEROUSLY_SET_INNER_HTML = 'dangerouslySetInnerHTML'; -var SUPPRESS_CONTENT_EDITABLE_WARNING = 'suppressContentEditableWarning'; -var CHILDREN = 'children'; -var STYLE = 'style'; -var HTML = '__html'; - -var HTML_NAMESPACE$1 = DOMNamespaces.Namespaces.html; -var getIntrinsicNamespace$1 = DOMNamespaces.getIntrinsicNamespace; - - -{ - var warnedUnknownTags = { - // Chrome is the only major browser not shipping <time>. But as of July - // 2017 it intends to ship it due to widespread usage. We intentionally - // *don't* warn for <time> even if it's unrecognized by Chrome because - // it soon will be, and many apps have been using it anyway. - time: true - }; - - var validatePropertiesInDevelopment = function (type, props) { - validateARIAProperties(type, props); - validateInputProperties(type, props); - validateUnknownProperties(type, props); - }; - - var warnForTextDifference = function (serverText, clientText) { - if (didWarnInvalidHydration) { - return; - } - didWarnInvalidHydration = true; - warning$4(false, 'Text content did not match. Server: "%s" Client: "%s"', serverText, clientText); - }; - - var warnForPropDifference = function (propName, serverValue, clientValue) { - if (didWarnInvalidHydration) { - return; - } - didWarnInvalidHydration = true; - warning$4(false, 'Prop `%s` did not match. Server: %s Client: %s', propName, JSON.stringify(serverValue), JSON.stringify(clientValue)); - }; - - var warnForExtraAttributes = function (attributeNames) { - if (didWarnInvalidHydration) { - return; - } - didWarnInvalidHydration = true; - var names = []; - attributeNames.forEach(function (name) { - names.push(name); - }); - warning$4(false, 'Extra attributes from the server: %s', names); - }; - - var warnForInvalidEventListener = function (registrationName, listener) { - warning$4(false, 'Expected `%s` listener to be a function, instead got a value of `%s` type.%s', registrationName, typeof listener, getCurrentFiberStackAddendum()); - }; - - var testDocument; - // Parse the HTML and read it back to normalize the HTML string so that it - // can be used for comparison. - var normalizeHTML = function (parent, html) { - if (!testDocument) { - testDocument = document.implementation.createHTMLDocument(); - } - var testElement = parent.namespaceURI === HTML_NAMESPACE$1 ? testDocument.createElement(parent.tagName) : testDocument.createElementNS(parent.namespaceURI, parent.tagName); - testElement.innerHTML = html; - return testElement.innerHTML; - }; -} +/** + * @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 +}; -function ensureListeningTo(rootContainerElement, registrationName) { - var isDocumentOrFragment = rootContainerElement.nodeType === DOCUMENT_NODE$1 || rootContainerElement.nodeType === DOCUMENT_FRAGMENT_NODE$1; - var doc = isDocumentOrFragment ? rootContainerElement : rootContainerElement.ownerDocument; - listenTo(registrationName, doc); +/** + * @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); } -function getOwnerDocumentFromRootContainer(rootContainerElement) { - return rootContainerElement.nodeType === DOCUMENT_NODE$1 ? rootContainerElement : rootContainerElement.ownerDocument; -} +SyntheticUIEvent.augmentClass(SyntheticTouchEvent, TouchEventInterface); -// There are so many media events, it makes sense to just -// maintain a list rather than create a `trapBubbledEvent` for each -var mediaEvents = { - topAbort: 'abort', - topCanPlay: 'canplay', - topCanPlayThrough: 'canplaythrough', - topDurationChange: 'durationchange', - topEmptied: 'emptied', - topEncrypted: 'encrypted', - topEnded: 'ended', - topError: 'error', - topLoadedData: 'loadeddata', - topLoadedMetadata: 'loadedmetadata', - topLoadStart: 'loadstart', - topPause: 'pause', - topPlay: 'play', - topPlaying: 'playing', - topProgress: 'progress', - topRateChange: 'ratechange', - topSeeked: 'seeked', - topSeeking: 'seeking', - topStalled: 'stalled', - topSuspend: 'suspend', - topTimeUpdate: 'timeupdate', - topVolumeChange: 'volumechange', - topWaiting: 'waiting' +/** + * @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 }; -function trapClickOnNonInteractiveElement(node) { - // Mobile Safari does not fire properly bubble click events on - // non-interactive elements, which means delegated click listeners do not - // fire. The workaround for this bug involves attaching an empty click - // listener on the target node. - // http://www.quirksmode.org/blog/archives/2010/09/click_event_del.html - // Just set it using the onclick property so that we don't have to manage any - // bookkeeping for it. Not sure if we need to clear it when the listener is - // removed. - // TODO: Only do this for the relevant Safaris maybe? - node.onclick = emptyFunction_1; -} - -function setInitialDOMProperties(domElement, rootContainerElement, nextProps, isCustomComponentTag) { - for (var propKey in nextProps) { - if (!nextProps.hasOwnProperty(propKey)) { - continue; - } - var nextProp = nextProps[propKey]; - if (propKey === STYLE) { - { - if (nextProp) { - // Freeze the next style object so that we can assume it won't be - // mutated. We have already warned for this in the past. - Object.freeze(nextProp); - } - } - // Relies on `updateStylesByID` not mutating `styleUpdates`. - CSSPropertyOperations_1.setValueForStyles(domElement, nextProp); - } else if (propKey === DANGEROUSLY_SET_INNER_HTML) { - var nextHtml = nextProp ? nextProp[HTML] : undefined; - if (nextHtml != null) { - setInnerHTML_1(domElement, nextHtml); - } - } else if (propKey === CHILDREN) { - if (typeof nextProp === 'string') { - setTextContent_1(domElement, nextProp); - } else if (typeof nextProp === 'number') { - setTextContent_1(domElement, '' + nextProp); - } - } else if (propKey === SUPPRESS_CONTENT_EDITABLE_WARNING) { - // Noop - } else if (registrationNameModules.hasOwnProperty(propKey)) { - if (nextProp != null) { - if (true && typeof nextProp !== 'function') { - warnForInvalidEventListener(propKey, nextProp); - } - ensureListeningTo(rootContainerElement, propKey); - } - } else if (isCustomComponentTag) { - DOMPropertyOperations_1.setValueForAttribute(domElement, propKey, nextProp); - } else if (nextProp != null) { - // If we're updating to null or undefined, we should remove the property - // from the DOM node instead of inadvertently setting to a string. This - // brings us in line with the same behavior we have on initial render. - DOMPropertyOperations_1.setValueForProperty(domElement, propKey, nextProp); - } - } -} - -function updateDOMProperties(domElement, updatePayload, wasCustomComponentTag, isCustomComponentTag) { - // TODO: Handle wasCustomComponentTag - for (var i = 0; i < updatePayload.length; i += 2) { - var propKey = updatePayload[i]; - var propValue = updatePayload[i + 1]; - if (propKey === STYLE) { - CSSPropertyOperations_1.setValueForStyles(domElement, propValue); - } else if (propKey === DANGEROUSLY_SET_INNER_HTML) { - setInnerHTML_1(domElement, propValue); - } else if (propKey === CHILDREN) { - setTextContent_1(domElement, propValue); - } else if (isCustomComponentTag) { - if (propValue != null) { - DOMPropertyOperations_1.setValueForAttribute(domElement, propKey, propValue); - } else { - DOMPropertyOperations_1.deleteValueForAttribute(domElement, propKey); - } - } else if (propValue != null) { - DOMPropertyOperations_1.setValueForProperty(domElement, propKey, propValue); - } else { - // If we're updating to null or undefined, we should remove the property - // from the DOM node instead of inadvertently setting to a string. This - // brings us in line with the same behavior we have on initial render. - DOMPropertyOperations_1.deleteValueForProperty(domElement, propKey); - } - } +/** + * @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); } -var ReactDOMFiberComponent = { - createElement: function (type, props, rootContainerElement, parentNamespace) { - // We create tags in the namespace of their parent container, except HTML - var ownerDocument = getOwnerDocumentFromRootContainer(rootContainerElement); - var domElement; - var namespaceURI = parentNamespace; - if (namespaceURI === HTML_NAMESPACE$1) { - namespaceURI = getIntrinsicNamespace$1(type); - } - if (namespaceURI === HTML_NAMESPACE$1) { - { - var isCustomComponentTag = isCustomComponent_1(type, props); - // Should this check be gated by parent namespace? Not sure we want to - // allow <SVG> or <mATH>. - warning$4(isCustomComponentTag || type === type.toLowerCase(), '<%s /> is using uppercase HTML. Always use lowercase HTML tags ' + 'in React.', type); - } - - if (type === 'script') { - // Create the script via .innerHTML so its "parser-inserted" flag is - // set to true and it does not execute - var div = ownerDocument.createElement('div'); - div.innerHTML = '<script><' + '/script>'; // eslint-disable-line - // This is guaranteed to yield a script element. - var firstChild = div.firstChild; - domElement = div.removeChild(firstChild); - } else if (typeof props.is === 'string') { - // $FlowIssue `createElement` should be updated for Web Components - domElement = ownerDocument.createElement(type, { is: props.is }); - } else { - // Separate else branch instead of using `props.is || undefined` above because of a Firefox bug. - // See discussion in https://github.com/facebook/react/pull/6896 - // and discussion in https://bugzilla.mozilla.org/show_bug.cgi?id=1276240 - domElement = ownerDocument.createElement(type); - } - } else { - domElement = ownerDocument.createElementNS(namespaceURI, type); - } - - { - if (namespaceURI === HTML_NAMESPACE$1) { - if (!isCustomComponentTag && Object.prototype.toString.call(domElement) === '[object HTMLUnknownElement]' && !Object.prototype.hasOwnProperty.call(warnedUnknownTags, type)) { - warnedUnknownTags[type] = true; - warning$4(false, 'The tag <%s> is unrecognized in this browser. ' + 'If you meant to render a React component, start its name with ' + 'an uppercase letter.', type); - } - } - } +SyntheticEvent$1.augmentClass(SyntheticTransitionEvent, TransitionEventInterface); - return domElement; +/** + * @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; }, - createTextNode: function (text, rootContainerElement) { - return getOwnerDocumentFromRootContainer(rootContainerElement).createTextNode(text); + 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; }, - setInitialProperties: function (domElement, tag, rawProps, rootContainerElement) { - var isCustomComponentTag = isCustomComponent_1(tag, rawProps); - { - validatePropertiesInDevelopment(tag, rawProps); - if (isCustomComponentTag && !didWarnShadyDOM && domElement.shadyRoot) { - warning$4(false, '%s is using shady DOM. Using shady DOM with React can ' + 'cause things to break subtly.', getCurrentFiberOwnerName() || 'A component'); - didWarnShadyDOM = true; - } - } - - // TODO: Make sure that we check isMounted before firing any of these events. - var props; - switch (tag) { - case 'iframe': - case 'object': - ReactBrowserEventEmitter_1.trapBubbledEvent('topLoad', 'load', domElement); - props = rawProps; - break; - case 'video': - case 'audio': - // Create listener for each media event - for (var event in mediaEvents) { - if (mediaEvents.hasOwnProperty(event)) { - ReactBrowserEventEmitter_1.trapBubbledEvent(event, mediaEvents[event], domElement); - } - } - props = rawProps; - break; - case 'source': - ReactBrowserEventEmitter_1.trapBubbledEvent('topError', 'error', domElement); - props = rawProps; - break; - case 'img': - case 'image': - ReactBrowserEventEmitter_1.trapBubbledEvent('topError', 'error', domElement); - ReactBrowserEventEmitter_1.trapBubbledEvent('topLoad', 'load', domElement); - props = rawProps; - break; - case 'form': - ReactBrowserEventEmitter_1.trapBubbledEvent('topReset', 'reset', domElement); - ReactBrowserEventEmitter_1.trapBubbledEvent('topSubmit', 'submit', domElement); - props = rawProps; - break; - case 'details': - ReactBrowserEventEmitter_1.trapBubbledEvent('topToggle', 'toggle', domElement); - props = rawProps; - break; - case 'input': - ReactDOMFiberInput.initWrapperState(domElement, rawProps); - props = ReactDOMFiberInput.getHostProps(domElement, rawProps); - ReactBrowserEventEmitter_1.trapBubbledEvent('topInvalid', 'invalid', domElement); - // For controlled components we always need to ensure we're listening - // to onChange. Even if there is no listener. - ensureListeningTo(rootContainerElement, 'onChange'); - break; - case 'option': - ReactDOMFiberOption.validateProps(domElement, rawProps); - props = ReactDOMFiberOption.getHostProps(domElement, rawProps); - break; - case 'select': - ReactDOMFiberSelect.initWrapperState(domElement, rawProps); - props = ReactDOMFiberSelect.getHostProps(domElement, rawProps); - ReactBrowserEventEmitter_1.trapBubbledEvent('topInvalid', 'invalid', domElement); - // For controlled components we always need to ensure we're listening - // to onChange. Even if there is no listener. - ensureListeningTo(rootContainerElement, 'onChange'); - break; - case 'textarea': - ReactDOMFiberTextarea.initWrapperState(domElement, rawProps); - props = ReactDOMFiberTextarea.getHostProps(domElement, rawProps); - ReactBrowserEventEmitter_1.trapBubbledEvent('topInvalid', 'invalid', domElement); - // For controlled components we always need to ensure we're listening - // to onChange. Even if there is no listener. - ensureListeningTo(rootContainerElement, 'onChange'); - break; - default: - props = rawProps; - } - - assertValidProps_1(tag, props, getCurrentFiberOwnerName); + deltaZ: null, - setInitialDOMProperties(domElement, rootContainerElement, props, isCustomComponentTag); + // 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 +}; - switch (tag) { - case 'input': - // TODO: Make sure we check if this is still unmounted or do any clean - // up necessary since we never stop tracking anymore. - inputValueTracking_1.track(domElement); - ReactDOMFiberInput.postMountWrapper(domElement, rawProps); - break; - case 'textarea': - // TODO: Make sure we check if this is still unmounted or do any clean - // up necessary since we never stop tracking anymore. - inputValueTracking_1.track(domElement); - ReactDOMFiberTextarea.postMountWrapper(domElement, rawProps); - break; - case 'option': - ReactDOMFiberOption.postMountWrapper(domElement, rawProps); - break; - case 'select': - ReactDOMFiberSelect.postMountWrapper(domElement, rawProps); - break; - default: - if (typeof props.onClick === 'function') { - // TODO: This cast may not be sound for SVG, MathML or custom elements. - trapClickOnNonInteractiveElement(domElement); - } - break; - } - }, +/** + * @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); - // Calculate the diff between the two objects. - diffProperties: function (domElement, tag, lastRawProps, nextRawProps, rootContainerElement) { - { - validatePropertiesInDevelopment(tag, nextRawProps); - } +/** + * 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 updatePayload = null; + var type = { + phasedRegistrationNames: { + bubbled: onEvent, + captured: onEvent + 'Capture' + }, + dependencies: [topEvent] + }; + eventTypes$4[event] = type; + topLevelEventsToDispatchConfig[topEvent] = type; +}); - var lastProps; - var nextProps; - switch (tag) { - case 'input': - lastProps = ReactDOMFiberInput.getHostProps(domElement, lastRawProps); - nextProps = ReactDOMFiberInput.getHostProps(domElement, nextRawProps); - updatePayload = []; - break; - case 'option': - lastProps = ReactDOMFiberOption.getHostProps(domElement, lastRawProps); - nextProps = ReactDOMFiberOption.getHostProps(domElement, nextRawProps); - updatePayload = []; - break; - case 'select': - lastProps = ReactDOMFiberSelect.getHostProps(domElement, lastRawProps); - nextProps = ReactDOMFiberSelect.getHostProps(domElement, nextRawProps); - updatePayload = []; - break; - case 'textarea': - lastProps = ReactDOMFiberTextarea.getHostProps(domElement, lastRawProps); - nextProps = ReactDOMFiberTextarea.getHostProps(domElement, nextRawProps); - updatePayload = []; - break; - default: - lastProps = lastRawProps; - nextProps = nextRawProps; - if (typeof lastProps.onClick !== 'function' && typeof nextProps.onClick === 'function') { - // TODO: This cast may not be sound for SVG, MathML or custom elements. - trapClickOnNonInteractiveElement(domElement); - } - break; - } +// 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']; - assertValidProps_1(tag, nextProps, getCurrentFiberOwnerName); +var SimpleEventPlugin = { + eventTypes: eventTypes$4, - var propKey; - var styleName; - var styleUpdates = null; - for (propKey in lastProps) { - if (nextProps.hasOwnProperty(propKey) || !lastProps.hasOwnProperty(propKey) || lastProps[propKey] == null) { - continue; - } - if (propKey === STYLE) { - var lastStyle = lastProps[propKey]; - for (styleName in lastStyle) { - if (lastStyle.hasOwnProperty(styleName)) { - if (!styleUpdates) { - styleUpdates = {}; - } - styleUpdates[styleName] = ''; - } - } - } else if (propKey === DANGEROUSLY_SET_INNER_HTML || propKey === CHILDREN) { - // Noop. This is handled by the clear text mechanism. - } else if (propKey === SUPPRESS_CONTENT_EDITABLE_WARNING) { - // Noop - } else if (registrationNameModules.hasOwnProperty(propKey)) { - // This is a special case. If any listener updates we need to ensure - // that the "current" fiber pointer gets updated so we need a commit - // to update this element. - if (!updatePayload) { - updatePayload = []; - } - } else { - // For all other deleted properties we add it to the queue. We use - // the whitelist in the commit phase instead. - (updatePayload = updatePayload || []).push(propKey, null); - } + extractEvents: function (topLevelType, targetInst, nativeEvent, nativeEventTarget) { + var dispatchConfig = topLevelEventsToDispatchConfig[topLevelType]; + if (!dispatchConfig) { + return null; } - for (propKey in nextProps) { - var nextProp = nextProps[propKey]; - var lastProp = lastProps != null ? lastProps[propKey] : undefined; - if (!nextProps.hasOwnProperty(propKey) || nextProp === lastProp || nextProp == null && lastProp == null) { - continue; - } - if (propKey === STYLE) { - { - if (nextProp) { - // Freeze the next style object so that we can assume it won't be - // mutated. We have already warned for this in the past. - Object.freeze(nextProp); - } - } - if (lastProp) { - // Unset styles on `lastProp` but not on `nextProp`. - for (styleName in lastProp) { - if (lastProp.hasOwnProperty(styleName) && (!nextProp || !nextProp.hasOwnProperty(styleName))) { - if (!styleUpdates) { - styleUpdates = {}; - } - styleUpdates[styleName] = ''; - } - } - // Update styles that changed since `lastProp`. - for (styleName in nextProp) { - if (nextProp.hasOwnProperty(styleName) && lastProp[styleName] !== nextProp[styleName]) { - if (!styleUpdates) { - styleUpdates = {}; - } - styleUpdates[styleName] = nextProp[styleName]; - } - } - } else { - // Relies on `updateStylesByID` not mutating `styleUpdates`. - if (!styleUpdates) { - if (!updatePayload) { - updatePayload = []; - } - updatePayload.push(propKey, styleUpdates); - } - styleUpdates = nextProp; - } - } else if (propKey === DANGEROUSLY_SET_INNER_HTML) { - var nextHtml = nextProp ? nextProp[HTML] : undefined; - var lastHtml = lastProp ? lastProp[HTML] : undefined; - if (nextHtml != null) { - if (lastHtml !== nextHtml) { - (updatePayload = updatePayload || []).push(propKey, '' + nextHtml); - } - } else { - // TODO: It might be too late to clear this if we have children - // inserted already. - } - } else if (propKey === CHILDREN) { - if (lastProp !== nextProp && (typeof nextProp === 'string' || typeof nextProp === 'number')) { - (updatePayload = updatePayload || []).push(propKey, '' + nextProp); - } - } else if (propKey === SUPPRESS_CONTENT_EDITABLE_WARNING) { - // Noop - } else if (registrationNameModules.hasOwnProperty(propKey)) { - if (nextProp != null) { - // We eagerly listen to this even though we haven't committed yet. - if (true && typeof nextProp !== 'function') { - warnForInvalidEventListener(propKey, nextProp); - } - ensureListeningTo(rootContainerElement, propKey); - } - if (!updatePayload && lastProp !== nextProp) { - // This is a special case. If any listener updates we need to ensure - // that the "current" props pointer gets updated so we need a commit - // to update this element. - updatePayload = []; + 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; } - } else { - // For any other property we always add it to the queue and then we - // filter it out using the whitelist during the commit. - (updatePayload = updatePayload || []).push(propKey, nextProp); - } - } - if (styleUpdates) { - (updatePayload = updatePayload || []).push(STYLE, styleUpdates); - } - return updatePayload; - }, - - - // Apply the diff. - updateProperties: function (domElement, updatePayload, tag, lastRawProps, nextRawProps) { - var wasCustomComponentTag = isCustomComponent_1(tag, lastRawProps); - var isCustomComponentTag = isCustomComponent_1(tag, nextRawProps); - // Apply the diff. - updateDOMProperties(domElement, updatePayload, wasCustomComponentTag, isCustomComponentTag); - - // TODO: Ensure that an update gets scheduled if any of the special props - // changed. - switch (tag) { - case 'input': - // Update the wrapper around inputs *after* updating props. This has to - // happen after `updateDOMProperties`. Otherwise HTML5 input validations - // raise warnings and prevent the new value from being assigned. - ReactDOMFiberInput.updateWrapper(domElement, nextRawProps); - - // We also check that we haven't missed a value update, such as a - // Radio group shifting the checked value to another named radio input. - inputValueTracking_1.updateValueIfChanged(domElement); - break; - case 'textarea': - ReactDOMFiberTextarea.updateWrapper(domElement, nextRawProps); - break; - case 'select': - // <select> value update needs to occur after <option> children - // reconciliation - ReactDOMFiberSelect.postUpdateWrapper(domElement, nextRawProps); + /* falls through */ + case 'topKeyDown': + case 'topKeyUp': + EventConstructor = SyntheticKeyboardEvent; break; - } - }, - diffHydratedProperties: function (domElement, tag, rawProps, parentNamespace, rootContainerElement) { - { - var isCustomComponentTag = isCustomComponent_1(tag, rawProps); - validatePropertiesInDevelopment(tag, rawProps); - if (isCustomComponentTag && !didWarnShadyDOM && domElement.shadyRoot) { - warning$4(false, '%s is using shady DOM. Using shady DOM with React can ' + 'cause things to break subtly.', getCurrentFiberOwnerName() || 'A component'); - didWarnShadyDOM = true; - } - } - - // TODO: Make sure that we check isMounted before firing any of these events. - switch (tag) { - case 'iframe': - case 'object': - ReactBrowserEventEmitter_1.trapBubbledEvent('topLoad', 'load', domElement); + case 'topBlur': + case 'topFocus': + EventConstructor = SyntheticFocusEvent; break; - case 'video': - case 'audio': - // Create listener for each media event - for (var event in mediaEvents) { - if (mediaEvents.hasOwnProperty(event)) { - ReactBrowserEventEmitter_1.trapBubbledEvent(event, mediaEvents[event], domElement); - } + 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 'source': - ReactBrowserEventEmitter_1.trapBubbledEvent('topError', 'error', domElement); - break; - case 'img': - case 'image': - ReactBrowserEventEmitter_1.trapBubbledEvent('topError', 'error', domElement); - ReactBrowserEventEmitter_1.trapBubbledEvent('topLoad', 'load', domElement); - break; - case 'form': - ReactBrowserEventEmitter_1.trapBubbledEvent('topReset', 'reset', domElement); - ReactBrowserEventEmitter_1.trapBubbledEvent('topSubmit', 'submit', domElement); - break; - case 'details': - ReactBrowserEventEmitter_1.trapBubbledEvent('topToggle', 'toggle', domElement); - break; - case 'input': - ReactDOMFiberInput.initWrapperState(domElement, rawProps); - ReactBrowserEventEmitter_1.trapBubbledEvent('topInvalid', 'invalid', domElement); - // For controlled components we always need to ensure we're listening - // to onChange. Even if there is no listener. - ensureListeningTo(rootContainerElement, 'onChange'); + case 'topDrag': + case 'topDragEnd': + case 'topDragEnter': + case 'topDragExit': + case 'topDragLeave': + case 'topDragOver': + case 'topDragStart': + case 'topDrop': + EventConstructor = SyntheticDragEvent; break; - case 'option': - ReactDOMFiberOption.validateProps(domElement, rawProps); + case 'topTouchCancel': + case 'topTouchEnd': + case 'topTouchMove': + case 'topTouchStart': + EventConstructor = SyntheticTouchEvent; break; - case 'select': - ReactDOMFiberSelect.initWrapperState(domElement, rawProps); - ReactBrowserEventEmitter_1.trapBubbledEvent('topInvalid', 'invalid', domElement); - // For controlled components we always need to ensure we're listening - // to onChange. Even if there is no listener. - ensureListeningTo(rootContainerElement, 'onChange'); + case 'topAnimationEnd': + case 'topAnimationIteration': + case 'topAnimationStart': + EventConstructor = SyntheticAnimationEvent; break; - case 'textarea': - ReactDOMFiberTextarea.initWrapperState(domElement, rawProps); - ReactBrowserEventEmitter_1.trapBubbledEvent('topInvalid', 'invalid', domElement); - // For controlled components we always need to ensure we're listening - // to onChange. Even if there is no listener. - ensureListeningTo(rootContainerElement, 'onChange'); + case 'topTransitionEnd': + EventConstructor = SyntheticTransitionEvent; break; - } - - assertValidProps_1(tag, rawProps, getCurrentFiberOwnerName); - - { - var extraAttributeNames = new Set(); - var attributes = domElement.attributes; - for (var i = 0; i < attributes.length; i++) { - var name = attributes[i].name.toLowerCase(); - switch (name) { - // Built-in SSR attribute is whitelisted - case 'data-reactroot': - break; - // Controlled attributes are not validated - // TODO: Only ignore them on controlled tags. - case 'value': - break; - case 'checked': - break; - case 'selected': - break; - default: - // Intentionally use the original name. - // See discussion in https://github.com/facebook/react/pull/10676. - extraAttributeNames.add(attributes[i].name); - } - } - } - - var updatePayload = null; - for (var propKey in rawProps) { - if (!rawProps.hasOwnProperty(propKey)) { - continue; - } - var nextProp = rawProps[propKey]; - if (propKey === CHILDREN) { - // For text content children we compare against textContent. This - // might match additional HTML that is hidden when we read it using - // textContent. E.g. "foo" will match "f<span>oo</span>" but that still - // satisfies our requirement. Our requirement is not to produce perfect - // HTML and attributes. Ideally we should preserve structure but it's - // ok not to if the visible content is still enough to indicate what - // even listeners these nodes might be wired up to. - // TODO: Warn if there is more than a single textNode as a child. - // TODO: Should we use domElement.firstChild.nodeValue to compare? - if (typeof nextProp === 'string') { - if (domElement.textContent !== nextProp) { - { - warnForTextDifference(domElement.textContent, nextProp); - } - updatePayload = [CHILDREN, nextProp]; - } - } else if (typeof nextProp === 'number') { - if (domElement.textContent !== '' + nextProp) { - { - warnForTextDifference(domElement.textContent, nextProp); - } - updatePayload = [CHILDREN, '' + nextProp]; - } - } - } else if (registrationNameModules.hasOwnProperty(propKey)) { - if (nextProp != null) { - if (true && typeof nextProp !== 'function') { - warnForInvalidEventListener(propKey, nextProp); - } - ensureListeningTo(rootContainerElement, propKey); - } - } else { - // Validate that the properties correspond to their expected values. - var serverValue; - var propertyInfo; - if (propKey === SUPPRESS_CONTENT_EDITABLE_WARNING || - // Controlled attributes are not validated - // TODO: Only ignore them on controlled tags. - propKey === 'value' || propKey === 'checked' || propKey === 'selected') { - // Noop - } else if (propKey === DANGEROUSLY_SET_INNER_HTML) { - var rawHtml = nextProp ? nextProp[HTML] || '' : ''; - var serverHTML = domElement.innerHTML; - var expectedHTML = normalizeHTML(domElement, rawHtml); - if (expectedHTML !== serverHTML) { - warnForPropDifference(propKey, serverHTML, expectedHTML); - } - } else if (propKey === STYLE) { - // $FlowFixMe - Should be inferred as not undefined. - extraAttributeNames['delete'](propKey); - var expectedStyle = CSSPropertyOperations_1.createDangerousStringForStyles(nextProp); - serverValue = domElement.getAttribute('style'); - if (expectedStyle !== serverValue) { - warnForPropDifference(propKey, serverValue, expectedStyle); - } - } else if (isCustomComponentTag) { - // $FlowFixMe - Should be inferred as not undefined. - extraAttributeNames['delete'](propKey.toLowerCase()); - serverValue = DOMPropertyOperations_1.getValueForAttribute(domElement, propKey, nextProp); - - if (nextProp !== serverValue) { - warnForPropDifference(propKey, serverValue, nextProp); - } - } else if (DOMProperty_1.shouldSetAttribute(propKey, nextProp)) { - if (propertyInfo = DOMProperty_1.getPropertyInfo(propKey)) { - // $FlowFixMe - Should be inferred as not undefined. - extraAttributeNames['delete'](propertyInfo.attributeName); - serverValue = DOMPropertyOperations_1.getValueForProperty(domElement, propKey, nextProp); - } else { - var ownNamespace = parentNamespace; - if (ownNamespace === HTML_NAMESPACE$1) { - ownNamespace = getIntrinsicNamespace$1(tag); - } - if (ownNamespace === HTML_NAMESPACE$1) { - // $FlowFixMe - Should be inferred as not undefined. - extraAttributeNames['delete'](propKey.toLowerCase()); - } else { - // $FlowFixMe - Should be inferred as not undefined. - extraAttributeNames['delete'](propKey); - } - serverValue = DOMPropertyOperations_1.getValueForAttribute(domElement, propKey, nextProp); - } - - if (nextProp !== serverValue) { - warnForPropDifference(propKey, serverValue, nextProp); - } - } - } - } - - { - // $FlowFixMe - Should be inferred as not undefined. - if (extraAttributeNames.size > 0) { - // $FlowFixMe - Should be inferred as not undefined. - warnForExtraAttributes(extraAttributeNames); - } - } - - switch (tag) { - case 'input': - // TODO: Make sure we check if this is still unmounted or do any clean - // up necessary since we never stop tracking anymore. - inputValueTracking_1.track(domElement); - ReactDOMFiberInput.postMountWrapper(domElement, rawProps); + case 'topScroll': + EventConstructor = SyntheticUIEvent; break; - case 'textarea': - // TODO: Make sure we check if this is still unmounted or do any clean - // up necessary since we never stop tracking anymore. - inputValueTracking_1.track(domElement); - ReactDOMFiberTextarea.postMountWrapper(domElement, rawProps); + case 'topWheel': + EventConstructor = SyntheticWheelEvent; break; - case 'select': - case 'option': - // For input and textarea we current always set the value property at - // post mount to force it to diverge from attributes. However, for - // option and select we don't quite do the same thing and select - // is not resilient to the DOM state changing so we don't do that here. - // TODO: Consider not doing this for input and textarea. + case 'topCopy': + case 'topCut': + case 'topPaste': + EventConstructor = SyntheticClipboardEvent; break; default: - if (typeof rawProps.onClick === 'function') { - // TODO: This cast may not be sound for SVG, MathML or custom elements. - trapClickOnNonInteractiveElement(domElement); + { + if (knownHTMLTopLevelTypes.indexOf(topLevelType) === -1) { + warning_1(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; } - - return updatePayload; - }, - diffHydratedText: function (textNode, text) { - var isDifferent = textNode.nodeValue !== text; - { - if (isDifferent) { - warnForTextDifference(textNode.nodeValue, text); - } - } - return isDifferent; - }, - warnForDeletedHydratableElement: function (parentNode, child) { - { - if (didWarnInvalidHydration) { - return; - } - didWarnInvalidHydration = true; - warning$4(false, 'Did not expect server HTML to contain a <%s> in <%s>.', child.nodeName.toLowerCase(), parentNode.nodeName.toLowerCase()); - } - }, - warnForDeletedHydratableText: function (parentNode, child) { - { - if (didWarnInvalidHydration) { - return; - } - didWarnInvalidHydration = true; - warning$4(false, 'Did not expect server HTML to contain the text node "%s" in <%s>.', child.nodeValue, parentNode.nodeName.toLowerCase()); - } - }, - warnForInsertedHydratedElement: function (parentNode, tag, props) { - { - if (didWarnInvalidHydration) { - return; - } - didWarnInvalidHydration = true; - warning$4(false, 'Expected server HTML to contain a matching <%s> in <%s>.', tag, parentNode.nodeName.toLowerCase()); - } - }, - warnForInsertedHydratedText: function (parentNode, text) { - { - if (text === '') { - // We expect to insert empty text nodes since they're not represented in - // the HTML. - // TODO: Remove this special case if we can just avoid inserting empty - // text nodes. - return; - } - if (didWarnInvalidHydration) { - return; - } - didWarnInvalidHydration = true; - warning$4(false, 'Expected server HTML to contain a matching text node for "%s" in <%s>.', text, parentNode.nodeName.toLowerCase()); - } - }, - restoreControlledState: function (domElement, tag, props) { - switch (tag) { - case 'input': - ReactDOMFiberInput.restoreControlledState(domElement, props); - return; - case 'textarea': - ReactDOMFiberTextarea.restoreControlledState(domElement, props); - return; - case 'select': - ReactDOMFiberSelect.restoreControlledState(domElement, props); - return; - } + var event = EventConstructor.getPooled(dispatchConfig, targetInst, nativeEvent, nativeEventTarget); + accumulateTwoPhaseDispatches(event); + return event; } }; -var ReactDOMFiberComponent_1 = ReactDOMFiberComponent; - -// This is a built-in polyfill for requestIdleCallback. It works by scheduling -// 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. - - +setHandleTopLevel(handleTopLevel); -{ - var warning$19 = warning_1; +/** + * Inject modules for resolving DOM hierarchy and plugin ordering. + */ +injection$1.injectEventPluginOrder(DOMEventPluginOrder); +injection$2.injectComponentTree(ReactDOMComponentTree); - if (ExecutionEnvironment_1.canUseDOM && typeof requestAnimationFrame !== 'function') { - warning$19(false, 'React depends on requestAnimationFrame. Make sure that you load a ' + 'polyfill in older browsers. http://fb.me/react-polyfills'); - } -} +/** + * 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 +}); -// TODO: There's no way to cancel, because Fiber doesn't atm. -var rIC = void 0; +var enableAsyncSubtreeAPI = true; +var enableAsyncSchedulingByDefaultInReactDOM = false; +// Exports ReactDOM.createRoot +var enableCreateRoot = false; +var enableUserTimingAPI = true; -if (!ExecutionEnvironment_1.canUseDOM) { - rIC = function (frameCallback) { - setTimeout(function () { - frameCallback({ - timeRemaining: function () { - return Infinity; - } - }); - }); - return 0; - }; -} else if (typeof requestIdleCallback !== 'function') { - // Polyfill requestIdleCallback. +// 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; - var scheduledRAFCallback = null; - var scheduledRICCallback = null; +// Helps identify side effects in begin-phase lifecycle hooks and setState reducers: +var debugRenderPhaseSideEffects = false; - var isIdleScheduled = false; - var isAnimationFrameScheduled = false; +// Only used in www builds. - 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; +/** + * Copyright (c) 2013-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + */ - var frameDeadlineObject = { - timeRemaining: typeof performance === 'object' && typeof performance.now === 'function' ? 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. - return frameDeadline - performance.now(); - } : function () { - // As a fallback we use Date.now. - return frameDeadline - Date.now(); - } - }; - // 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 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, '*'); - } - var callback = scheduledRAFCallback; - scheduledRAFCallback = null; - if (callback !== null) { - callback(rafTime); - } - }; +var emptyObject = {}; - rIC = function (callback) { - // This assumes that we only schedule one callback at a time because that's - // how Fiber uses it. - scheduledRICCallback = callback; - 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; - }; -} else { - rIC = requestIdleCallback; +{ + Object.freeze(emptyObject); } -var rIC_1 = rIC; - -var ReactDOMFrameScheduling = { - rIC: rIC_1 -}; +var emptyObject_1 = emptyObject; /** * Copyright (c) 2013-present, Facebook, Inc. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. - * - * @providesModule ReactFeatureFlags - * */ -var ReactFeatureFlags = { - enableAsyncSubtreeAPI: true -}; -var ReactFeatureFlags_1 = ReactFeatureFlags; + +var ReactPropTypesSecret$1 = 'SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED'; + +var ReactPropTypesSecret_1 = ReactPropTypesSecret$1; /** * Copyright (c) 2013-present, Facebook, Inc. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. - * - * @providesModule ReactPriorityLevel - * */ -var ReactPriorityLevel = { - NoWork: 0, // No work is pending. - SynchronousPriority: 1, // For controlled text inputs. Synchronous side-effects. - TaskPriority: 2, // Completes at the end of the current tick. - HighPriority: 3, // Interaction that needs to complete pretty soon to feel responsive. - LowPriority: 4, // Data fetching, or result from updating stores. - OffscreenPriority: 5 }; - -var CallbackEffect = ReactTypeOfSideEffect.Callback; - -var NoWork = ReactPriorityLevel.NoWork; -var SynchronousPriority = ReactPriorityLevel.SynchronousPriority; -var TaskPriority = ReactPriorityLevel.TaskPriority; - -var ClassComponent$2 = ReactTypeOfWork.ClassComponent; -var HostRoot$2 = ReactTypeOfWork.HostRoot; { - var warning$21 = warning_1; + var invariant$2 = invariant_1; + var warning$2 = warning_1; + var ReactPropTypesSecret = ReactPropTypesSecret_1; + var loggedTypeFailures = {}; } -// Callbacks are not validated until invocation +/** + * Assert that the values match with the type specs. + * Error messages are memorized and will only be shown once. + * + * @param {object} typeSpecs Map of name to a ReactPropType + * @param {object} values Runtime values that need to be type-checked + * @param {string} location e.g. "prop", "context", "child context" + * @param {string} componentName Name of the component for error messages. + * @param {?Function} getStack Returns the component stack. + * @private + */ +function checkPropTypes(typeSpecs, values, location, componentName, getStack) { + { + for (var typeSpecName in typeSpecs) { + if (typeSpecs.hasOwnProperty(typeSpecName)) { + var error; + // Prop type validation may throw. In case they do, we don't want to + // fail the render phase where it didn't fail before. So we log it. + // After these have been cleaned up, we'll let them throw. + try { + // This is intentionally an invariant that gets caught. It's the same + // behavior as without this statement except with a better message. + invariant$2(typeof typeSpecs[typeSpecName] === 'function', '%s: %s type `%s` is invalid; it must be a function, usually from ' + 'the `prop-types` package, but received `%s`.', componentName || 'React class', location, typeSpecName, typeof typeSpecs[typeSpecName]); + error = typeSpecs[typeSpecName](values, typeSpecName, componentName, location, null, ReactPropTypesSecret); + } catch (ex) { + error = ex; + } + warning$2(!error || error instanceof Error, '%s: type specification of %s `%s` is invalid; the type checker ' + 'function must return `null` or an `Error` but returned a %s. ' + 'You may have forgotten to pass an argument to the type checker ' + 'creator (arrayOf, instanceOf, objectOf, oneOf, oneOfType, and ' + 'shape all require an argument).', componentName || 'React class', location, typeSpecName, typeof error); + if (error instanceof Error && !(error.message in loggedTypeFailures)) { + // Only monitor this failure once because there tends to be a lot of the + // same error. + loggedTypeFailures[error.message] = true; + var stack = getStack ? getStack() : ''; -// 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. + warning$2(false, 'Failed %s type: %s%s', location, error.message, stack != null ? stack : ''); + } + } + } + } +} +var checkPropTypes_1 = checkPropTypes; -var _queue1 = void 0; -var _queue2 = void 0; +var valueStack = []; -function comparePriority(a, b) { - // When comparing update priorities, treat sync and Task work as equal. - // TODO: Could we avoid the need for this by always coercing sync priority - // to Task when scheduling an update? - if ((a === TaskPriority || a === SynchronousPriority) && (b === TaskPriority || b === SynchronousPriority)) { - return 0; - } - if (a === NoWork && b !== NoWork) { - return -255; - } - if (a !== NoWork && b === NoWork) { - return 255; - } - return a - b; +{ + var fiberStack = []; } -function createUpdateQueue() { - var queue = { - first: null, - last: null, - hasForceUpdate: false, - callbackList: null - }; - { - queue.isProcessing = false; - } - return queue; -} +var index = -1; -function cloneUpdate(update) { +function createCursor(defaultValue) { return { - priorityLevel: update.priorityLevel, - partialState: update.partialState, - callback: update.callback, - isReplace: update.isReplace, - isForced: update.isForced, - isTopLevelUnmount: update.isTopLevelUnmount, - next: null + current: defaultValue }; } -function insertUpdateIntoQueue(queue, update, insertAfter, insertBefore) { - if (insertAfter !== null) { - insertAfter.next = update; - } else { - // This is the first item in the queue. - update.next = queue.first; - queue.first = update; - } - if (insertBefore !== null) { - update.next = insertBefore; - } else { - // This is the last item in the queue. - queue.last = update; - } -} -// Returns the update after which the incoming update should be inserted into -// the queue, or null if it should be inserted at beginning. -function findInsertionPosition(queue, update) { - var priorityLevel = update.priorityLevel; - var insertAfter = null; - var insertBefore = null; - if (queue.last !== null && comparePriority(queue.last.priorityLevel, priorityLevel) <= 0) { - // Fast path for the common case where the update should be inserted at - // the end of the queue. - insertAfter = queue.last; - } else { - insertBefore = queue.first; - while (insertBefore !== null && comparePriority(insertBefore.priorityLevel, priorityLevel) <= 0) { - insertAfter = insertBefore; - insertBefore = insertBefore.next; +function pop(cursor, fiber) { + if (index < 0) { + { + warning_1(false, 'Unexpected pop.'); } - } - return insertAfter; -} - -function ensureUpdateQueues(fiber) { - var alternateFiber = fiber.alternate; - - var queue1 = fiber.updateQueue; - if (queue1 === null) { - queue1 = fiber.updateQueue = createUpdateQueue(); + return; } - var queue2 = void 0; - if (alternateFiber !== null) { - queue2 = alternateFiber.updateQueue; - if (queue2 === null) { - queue2 = alternateFiber.updateQueue = createUpdateQueue(); + { + if (fiber !== fiberStack[index]) { + warning_1(false, 'Unexpected Fiber popped.'); } - } else { - queue2 = null; } - _queue1 = queue1; - // Return null if there is no alternate queue, or if its queue is the same. - _queue2 = queue2 !== queue1 ? queue2 : null; -} + cursor.current = valueStack[index]; -// The work-in-progress queue is a subset of the current queue (if it exists). -// We need to insert the incoming update into both lists. However, it's possible -// that the correct position in one list will be different from the position in -// the other. Consider the following case: -// -// Current: 3-5-6 -// Work-in-progress: 6 -// -// Then we receive an update with priority 4 and insert it into each list: -// -// Current: 3-4-5-6 -// Work-in-progress: 4-6 -// -// In the current queue, the new update's `next` pointer points to the update -// with priority 5. But in the work-in-progress queue, the pointer points to the -// update with priority 6. Because these two queues share the same persistent -// data structure, this won't do. (This can only happen when the incoming update -// has higher priority than all the updates in the work-in-progress queue.) -// -// To solve this, in the case where the incoming update needs to be inserted -// into two different positions, we'll make a clone of the update and insert -// each copy into a separate queue. This forks the list while maintaining a -// persistent structure, because the update that is added to the work-in-progress -// is always added to the front of the list. -// -// However, if incoming update is inserted into the same position of both lists, -// we shouldn't make a copy. -// -// If the update is cloned, it returns the cloned update. -function insertUpdate(fiber, update) { - // We'll have at least one and at most two distinct update queues. - ensureUpdateQueues(fiber); - var queue1 = _queue1; - var queue2 = _queue2; + valueStack[index] = null; - // Warn if an update is scheduled from inside an updater function. { - if (queue1.isProcessing || queue2 !== null && queue2.isProcessing) { - warning$21(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.'); - } + fiberStack[index] = null; } - // Find the insertion position in the first queue. - var insertAfter1 = findInsertionPosition(queue1, update); - var insertBefore1 = insertAfter1 !== null ? insertAfter1.next : queue1.first; + index--; +} - if (queue2 === null) { - // If there's no alternate queue, there's nothing else to do but insert. - insertUpdateIntoQueue(queue1, update, insertAfter1, insertBefore1); - return null; +function push(cursor, value, fiber) { + index++; + + valueStack[index] = cursor.current; + + { + fiberStack[index] = fiber; } - // If there is an alternate queue, find the insertion position. - var insertAfter2 = findInsertionPosition(queue2, update); - var insertBefore2 = insertAfter2 !== null ? insertAfter2.next : queue2.first; + cursor.current = value; +} - // Now we can insert into the first queue. This must come after finding both - // insertion positions because it mutates the list. - insertUpdateIntoQueue(queue1, update, insertAfter1, insertBefore1); +function reset$1() { + while (index > -1) { + valueStack[index] = null; - // See if the insertion positions are equal. Be careful to only compare - // non-null values. - if (insertBefore1 === insertBefore2 && insertBefore1 !== null || insertAfter1 === insertAfter2 && insertAfter1 !== null) { - // The insertion positions are the same, so when we inserted into the first - // queue, it also inserted into the alternate. All we need to do is update - // the alternate queue's `first` and `last` pointers, in case they - // have changed. - if (insertAfter2 === null) { - queue2.first = update; - } - if (insertBefore2 === null) { - queue2.last = null; + { + fiberStack[index] = null; } - return null; - } else { - // The insertion positions are different, so we need to clone the update and - // insert the clone into the alternate queue. - var update2 = cloneUpdate(update); - insertUpdateIntoQueue(queue2, update2, insertAfter2, insertBefore2); - return update2; - } -} - -function addUpdate(fiber, partialState, callback, priorityLevel) { - var update = { - priorityLevel: priorityLevel, - partialState: partialState, - callback: callback, - isReplace: false, - isForced: false, - isTopLevelUnmount: false, - next: null - }; - insertUpdate(fiber, update); -} -var addUpdate_1 = addUpdate; - -function addReplaceUpdate(fiber, state, callback, priorityLevel) { - var update = { - priorityLevel: priorityLevel, - partialState: state, - callback: callback, - isReplace: true, - isForced: false, - isTopLevelUnmount: false, - next: null - }; - insertUpdate(fiber, update); -} -var addReplaceUpdate_1 = addReplaceUpdate; - -function addForceUpdate(fiber, callback, priorityLevel) { - var update = { - priorityLevel: priorityLevel, - partialState: null, - callback: callback, - isReplace: false, - isForced: true, - isTopLevelUnmount: false, - next: null - }; - insertUpdate(fiber, update); -} -var addForceUpdate_1 = addForceUpdate; -function getUpdatePriority(fiber) { - var updateQueue = fiber.updateQueue; - if (updateQueue === null) { - return NoWork; - } - if (fiber.tag !== ClassComponent$2 && fiber.tag !== HostRoot$2) { - return NoWork; + index--; } - return updateQueue.first !== null ? updateQueue.first.priorityLevel : NoWork; } -var getUpdatePriority_1 = getUpdatePriority; - -function addTopLevelUpdate$1(fiber, partialState, callback, priorityLevel) { - var isTopLevelUnmount = partialState.element === null; - var update = { - priorityLevel: priorityLevel, - partialState: partialState, - callback: callback, - isReplace: false, - isForced: false, - isTopLevelUnmount: isTopLevelUnmount, - next: null - }; - var update2 = insertUpdate(fiber, update); - - if (isTopLevelUnmount) { - // TODO: Redesign the top-level mount/update/unmount API to avoid this - // special case. - var queue1 = _queue1; - var queue2 = _queue2; +var describeComponentFrame = function (name, source, ownerName) { + return '\n in ' + (name || 'Unknown') + (source ? ' (at ' + source.fileName.replace(/^.*[\\\/]/, '') + ':' + source.lineNumber + ')' : ownerName ? ' (created by ' + ownerName + ')' : ''); +}; - // Drop all updates that are lower-priority, so that the tree is not - // remounted. We need to do this for both queues. - if (queue1 !== null && update.next !== null) { - update.next = null; - queue1.last = update; - } - if (queue2 !== null && update2 !== null && update2.next !== null) { - update2.next = null; - queue2.last = update; - } +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 ''; } } -var addTopLevelUpdate_1 = addTopLevelUpdate$1; -function getStateFromUpdate(update, instance, prevState, props) { - var partialState = update.partialState; - if (typeof partialState === 'function') { - var updateFn = partialState; - return updateFn.call(instance, prevState, props); - } else { - return partialState; - } +// 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 beginUpdateQueue(current, workInProgress, queue, instance, prevState, props, priorityLevel) { - 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 = { - first: currentQueue.first, - last: currentQueue.last, - // These fields are no longer valid because they were already committed. - // Reset them. - callbackList: null, - hasForceUpdate: false - }; - } - +function getCurrentFiberOwnerName() { { - // Set this flag so we can warn if setState is called inside the update - // function of another setState. - queue.isProcessing = true; - } - - // Calculate these using the the existing values as a base. - var callbackList = queue.callbackList; - var hasForceUpdate = queue.hasForceUpdate; - - // Applies updates with matching priority to the previous state to create - // a new state object. - var state = prevState; - var dontMutatePrevState = true; - var update = queue.first; - while (update !== null && comparePriority(update.priorityLevel, priorityLevel) <= 0) { - // Remove each update from the queue right before it is processed. That way - // if setState is called from inside an updater function, the new update - // will be inserted in the correct position. - queue.first = update.next; - if (queue.first === null) { - queue.last = null; - } - - 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) { - state = assign({}, state, _partialState); - } else { - state = assign(state, _partialState); - } - dontMutatePrevState = false; - } - } - if (update.isForced) { - hasForceUpdate = true; + var fiber = ReactDebugCurrentFiber.current; + if (fiber === null) { + return null; } - // Second condition ignores top-level unmount callbacks if they are not the - // last update in the queue, since a subsequent update will cause a remount. - if (update.callback !== null && !(update.isTopLevelUnmount && update.next !== null)) { - callbackList = callbackList !== null ? callbackList : []; - callbackList.push(update.callback); - workInProgress.effectTag |= CallbackEffect; + var owner = fiber._debugOwner; + if (owner !== null && typeof owner !== 'undefined') { + return getComponentName(owner); } - update = update.next; - } - - queue.callbackList = callbackList; - queue.hasForceUpdate = hasForceUpdate; - - if (queue.first === null && callbackList === null && !hasForceUpdate) { - // The queue is empty and there are no callbacks. We can reset it. - workInProgress.updateQueue = null; - } - - { - // No longer processing. - queue.isProcessing = false; } - - return state; + return null; } -var beginUpdateQueue_1 = beginUpdateQueue; -function commitCallbacks(finishedWork, 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 _callback = callbackList[i]; - !(typeof _callback === 'function') ? invariant_1(false, 'Invalid argument passed as callback. Expected a function. Instead received: %s', _callback) : void 0; - _callback.call(context); +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; } -var commitCallbacks_1 = commitCallbacks; -var ReactFiberUpdateQueue = { - addUpdate: addUpdate_1, - addReplaceUpdate: addReplaceUpdate_1, - addForceUpdate: addForceUpdate_1, - getUpdatePriority: getUpdatePriority_1, - addTopLevelUpdate: addTopLevelUpdate_1, - beginUpdateQueue: beginUpdateQueue_1, - commitCallbacks: commitCallbacks_1 -}; - -/** - * Copyright (c) 2013-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - */ - -var emptyObject = {}; - -{ - Object.freeze(emptyObject); +function resetCurrentFiber() { + ReactDebugCurrentFrame.getCurrentStack = null; + ReactDebugCurrentFiber.current = null; + ReactDebugCurrentFiber.phase = null; } -var emptyObject_1 = emptyObject; - -{ - var warning$23 = warning_1; +function setCurrentFiber(fiber) { + ReactDebugCurrentFrame.getCurrentStack = getCurrentFiberStackAddendum; + ReactDebugCurrentFiber.current = fiber; + ReactDebugCurrentFiber.phase = null; } -var valueStack = []; - -{ - var fiberStack = []; +function setCurrentPhase(phase) { + ReactDebugCurrentFiber.phase = phase; } -var index$2 = -1; +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) { + var prefix = warning ? warningEmoji + ' ' : reactEmoji + ' '; + var suffix = warning ? ' Warning: ' + warning : ''; + 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) { + var formattedMarkName = formatMarkName(markName); + var formattedLabel = formatLabel(label, warning); + 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. -var createCursor$1 = function (defaultValue) { - return { - current: defaultValue - }; + // Clear marks immediately to avoid growing buffer. + performance.clearMarks(formattedMarkName); + performance.clearMeasures(formattedLabel); }; -var isEmpty = function () { - return index$2 === -1; +var getFiberMarkName = function (label, debugID) { + return label + ' (#' + debugID + ')'; }; -var pop$1 = function (cursor, fiber) { - if (index$2 < 0) { - { - warning$23(false, 'Unexpected pop.'); - } - return; - } - - { - if (fiber !== fiberStack[index$2]) { - warning$23(false, 'Unexpected Fiber popped.'); - } +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; } +}; - cursor.current = valueStack[index$2]; - - valueStack[index$2] = null; +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); - { - fiberStack[index$2] = null; + 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); - index$2--; + var markName = getFiberMarkName(label, debugID); + beginMark(markName); + return true; }; -var push$1 = function (cursor, value, fiber) { - index$2++; +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); +}; - valueStack[index$2] = cursor.current; +var endFiberMark = function (fiber, phase, warning) { + 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); +}; - { - fiberStack[index$2] = fiber; +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; } - - cursor.current = value; }; -var reset = function () { - while (index$2 > -1) { - valueStack[index$2] = null; +var clearPendingPhaseMeasurement = function () { + if (currentPhase !== null && currentPhaseFiber !== null) { + clearFiberMark(currentPhaseFiber, currentPhase); + } + currentPhaseFiber = null; + currentPhase = null; + hasScheduledUpdateInCurrentPhase = false; +}; - { - fiberStack[index$2] = null; +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); } - - index$2--; + fiber = fiber['return']; } }; -var ReactFiberStack = { - createCursor: createCursor$1, - isEmpty: isEmpty, - pop: pop$1, - push: push$1, - reset: reset +var resumeTimersRecursively = function (fiber) { + if (fiber['return'] !== null) { + resumeTimersRecursively(fiber['return']); + } + if (fiber._debugIsCurrentlyTiming) { + beginFiberMark(fiber, null); + } }; -// Trust the developer to only use this with a true check -/** - * Copyright (c) 2013-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @providesModule ReactDebugFiberPerf - * - */ - -var ReactDebugFiberPerf = null; - -{ - var _require$8 = ReactTypeOfWork, - HostRoot$4 = _require$8.HostRoot, - HostComponent$4 = _require$8.HostComponent, - HostText$2 = _require$8.HostText, - HostPortal$1 = _require$8.HostPortal, - YieldComponent = _require$8.YieldComponent, - Fragment = _require$8.Fragment; - - var getComponentName$5 = getComponentName_1; - - // 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; - // 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) { - var prefix = warning ? warningEmoji + ' ' : reactEmoji + ' '; - var suffix = warning ? ' Warning: ' + warning : ''; - return '' + prefix + label + suffix; - }; - - var beginMark = function (markName) { - performance.mark(formatMarkName(markName)); - }; - - var clearMark = function (markName) { - performance.clearMarks(formatMarkName(markName)); - }; +var resumeTimers = function () { + // Resumes all measurements that were active during the last deferred loop. + if (currentFiber !== null) { + resumeTimersRecursively(currentFiber); + } +}; - var endMark = function (label, markName, warning) { - var formattedMarkName = formatMarkName(markName); - var formattedLabel = formatLabel(label, warning); - 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); - }; +function recordEffect() { + if (enableUserTimingAPI) { + effectCountInCurrentCommit++; + } +} - var getFiberMarkName = function (label, debugID) { - return label + ' (#' + debugID + ')'; - }; +function recordScheduleUpdate() { + if (enableUserTimingAPI) { + if (isCommitting) { + hasScheduledUpdateInCurrentCommit = true; + } + if (currentPhase !== null && currentPhase !== 'componentWillMount' && currentPhase !== 'componentWillReceiveProps') { + hasScheduledUpdateInCurrentPhase = true; + } + } +} - 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; +function startRequestCallbackTimer() { + if (enableUserTimingAPI) { + if (supportsUserTiming && !isWaitingForCallback) { + isWaitingForCallback = true; + beginMark('(Waiting for async callback...)'); } - }; + } +} - var beginFiberMark = function (fiber, phase) { - var componentName = getComponentName$5(fiber) || 'Unknown'; - var debugID = fiber._debugID; - var isMounted = fiber.alternate !== null; - var label = getFiberLabel(componentName, isMounted, phase); +function stopRequestCallbackTimer(didExpire) { + if (enableUserTimingAPI) { + if (supportsUserTiming) { + isWaitingForCallback = false; + var warning = didExpire ? 'React was blocked by main thread' : null; + endMark('(Waiting for async callback...)', '(Waiting for async callback...)', warning); + } + } +} - 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; +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; } - labelsInCurrentCommit.add(label); + fiber._debugIsCurrentlyTiming = true; + } +} - var markName = getFiberMarkName(label, debugID); - beginMark(markName); - return 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); + } +} - var clearFiberMark = function (fiber, phase) { - var componentName = getComponentName$5(fiber) || 'Unknown'; - var debugID = fiber._debugID; - var isMounted = fiber.alternate !== null; - var label = getFiberLabel(componentName, isMounted, phase); - var markName = getFiberMarkName(label, debugID); - clearMark(markName); - }; +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); + } +} - var endFiberMark = function (fiber, phase, warning) { - var componentName = getComponentName$5(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); - }; +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 = 'An error was thrown inside this error boundary'; + endFiberMark(fiber, null, warning); + } +} - 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$4: - case HostComponent$4: - case HostText$2: - case HostPortal$1: - case YieldComponent: - case Fragment: - return true; - default: - return false; +function startPhaseTimer(fiber, phase) { + if (enableUserTimingAPI) { + if (!supportsUserTiming) { + return; } - }; + clearPendingPhaseMeasurement(); + if (!beginFiberMark(fiber, phase)) { + return; + } + currentPhaseFiber = fiber; + currentPhase = phase; + } +} - var clearPendingPhaseMeasurement = function () { +function stopPhaseTimer() { + if (enableUserTimingAPI) { + if (!supportsUserTiming) { + return; + } if (currentPhase !== null && currentPhaseFiber !== null) { - clearFiberMark(currentPhaseFiber, currentPhase); + var warning = hasScheduledUpdateInCurrentPhase ? 'Scheduled a cascading update' : null; + endFiberMark(currentPhaseFiber, currentPhase, warning); } - currentPhaseFiber = null; currentPhase = null; - hasScheduledUpdateInCurrentPhase = false; - }; + currentPhaseFiber = null; + } +} - 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']; +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(); + } +} - var resumeTimersRecursively = function (fiber) { - if (fiber['return'] !== null) { - resumeTimersRecursively(fiber['return']); +function stopWorkLoopTimer(interruptedBy) { + if (enableUserTimingAPI) { + if (!supportsUserTiming) { + return; } - if (fiber._debugIsCurrentlyTiming) { - beginFiberMark(fiber, null); + var warning = null; + if (interruptedBy !== null) { + if (interruptedBy.tag === HostRoot) { + warning = 'A top-level update interrupted the previous render'; + } else { + var componentName = getComponentName(interruptedBy) || 'Unknown'; + warning = 'An update to ' + componentName + ' interrupted the previous render'; + } + } else if (commitCountInCurrentWorkLoop > 1) { + warning = 'There were cascading updates'; } - }; + commitCountInCurrentWorkLoop = 0; + // Pause any measurements until the next loop. + pauseTimers(); + endMark('(React Tree Reconciliation)', '(React Tree Reconciliation)', warning); + } +} - var resumeTimers = function () { - // Resumes all measurements that were active during the last deferred loop. - if (currentFiber !== null) { - resumeTimersRecursively(currentFiber); +function startCommitTimer() { + if (enableUserTimingAPI) { + if (!supportsUserTiming) { + return; } - }; - - ReactDebugFiberPerf = { - recordEffect: function () { - effectCountInCurrentCommit++; - }, - recordScheduleUpdate: function () { - if (isCommitting) { - hasScheduledUpdateInCurrentCommit = true; - } - if (currentPhase !== null && currentPhase !== 'componentWillMount' && currentPhase !== 'componentWillReceiveProps') { - hasScheduledUpdateInCurrentPhase = true; - } - }, - startWorkTimer: function (fiber) { - 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; - }, - cancelWorkTimer: function (fiber) { - 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); - }, - stopWorkTimer: function (fiber) { - 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); - }, - stopFailedWorkTimer: function (fiber) { - 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 = 'An error was thrown inside this error boundary'; - endFiberMark(fiber, null, warning); - }, - startPhaseTimer: function (fiber, phase) { - if (!supportsUserTiming) { - return; - } - clearPendingPhaseMeasurement(); - if (!beginFiberMark(fiber, phase)) { - return; - } - currentPhaseFiber = fiber; - currentPhase = phase; - }, - stopPhaseTimer: function () { - if (!supportsUserTiming) { - return; - } - if (currentPhase !== null && currentPhaseFiber !== null) { - var warning = hasScheduledUpdateInCurrentPhase ? 'Scheduled a cascading update' : null; - endFiberMark(currentPhaseFiber, currentPhase, warning); - } - currentPhase = null; - currentPhaseFiber = null; - }, - startWorkLoopTimer: function () { - 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(); - }, - stopWorkLoopTimer: function () { - if (!supportsUserTiming) { - return; - } - var warning = commitCountInCurrentWorkLoop > 1 ? 'There were cascading updates' : null; - commitCountInCurrentWorkLoop = 0; - // Pause any measurements until the next loop. - pauseTimers(); - endMark('(React Tree Reconciliation)', '(React Tree Reconciliation)', warning); - }, - startCommitTimer: function () { - if (!supportsUserTiming) { - return; - } - isCommitting = true; - hasScheduledUpdateInCurrentCommit = false; - labelsInCurrentCommit.clear(); - beginMark('(Committing Changes)'); - }, - stopCommitTimer: function () { - if (!supportsUserTiming) { - return; - } + isCommitting = true; + hasScheduledUpdateInCurrentCommit = false; + labelsInCurrentCommit.clear(); + beginMark('(Committing Changes)'); + } +} - var warning = null; - if (hasScheduledUpdateInCurrentCommit) { - warning = 'Lifecycle hook scheduled a cascading update'; - } else if (commitCountInCurrentWorkLoop > 0) { - warning = 'Caused by a cascading update in earlier commit'; - } - hasScheduledUpdateInCurrentCommit = false; - commitCountInCurrentWorkLoop++; - isCommitting = false; - labelsInCurrentCommit.clear(); +function stopCommitTimer() { + if (enableUserTimingAPI) { + if (!supportsUserTiming) { + return; + } - endMark('(Committing Changes)', '(Committing Changes)', warning); - }, - startCommitHostEffectsTimer: function () { - if (!supportsUserTiming) { - return; - } - effectCountInCurrentCommit = 0; - beginMark('(Committing Host Effects)'); - }, - stopCommitHostEffectsTimer: function () { - if (!supportsUserTiming) { - return; - } - var count = effectCountInCurrentCommit; - effectCountInCurrentCommit = 0; - endMark('(Committing Host Effects: ' + count + ' Total)', '(Committing Host Effects)', null); - }, - startCommitLifeCyclesTimer: function () { - if (!supportsUserTiming) { - return; - } - effectCountInCurrentCommit = 0; - beginMark('(Calling Lifecycle Methods)'); - }, - stopCommitLifeCyclesTimer: function () { - if (!supportsUserTiming) { - return; - } - var count = effectCountInCurrentCommit; - effectCountInCurrentCommit = 0; - endMark('(Calling Lifecycle Methods: ' + count + ' Total)', '(Calling Lifecycle Methods)', null); + var warning = null; + if (hasScheduledUpdateInCurrentCommit) { + warning = 'Lifecycle hook scheduled a cascading update'; + } else if (commitCountInCurrentWorkLoop > 0) { + warning = 'Caused by a cascading update in earlier commit'; } - }; + hasScheduledUpdateInCurrentCommit = false; + commitCountInCurrentWorkLoop++; + isCommitting = false; + labelsInCurrentCommit.clear(); + + endMark('(Committing Changes)', '(Committing Changes)', warning); + } } -var ReactDebugFiberPerf_1 = ReactDebugFiberPerf; +function startCommitHostEffectsTimer() { + if (enableUserTimingAPI) { + if (!supportsUserTiming) { + return; + } + effectCountInCurrentCommit = 0; + beginMark('(Committing Host Effects)'); + } +} -var isFiberMounted$1 = ReactFiberTreeReflection.isFiberMounted; +function stopCommitHostEffectsTimer() { + if (enableUserTimingAPI) { + if (!supportsUserTiming) { + return; + } + var count = effectCountInCurrentCommit; + effectCountInCurrentCommit = 0; + endMark('(Committing Host Effects: ' + count + ' Total)', '(Committing Host Effects)', null); + } +} -var ClassComponent$3 = ReactTypeOfWork.ClassComponent; -var HostRoot$3 = ReactTypeOfWork.HostRoot; +function startCommitLifeCyclesTimer() { + if (enableUserTimingAPI) { + if (!supportsUserTiming) { + return; + } + effectCountInCurrentCommit = 0; + beginMark('(Calling Lifecycle Methods)'); + } +} -var createCursor = ReactFiberStack.createCursor; -var pop = ReactFiberStack.pop; -var push = ReactFiberStack.push; +function stopCommitLifeCyclesTimer() { + if (enableUserTimingAPI) { + if (!supportsUserTiming) { + return; + } + var count = effectCountInCurrentCommit; + effectCountInCurrentCommit = 0; + endMark('(Calling Lifecycle Methods: ' + count + ' Total)', '(Calling Lifecycle Methods)', null); + } +} { - var warning$22 = warning_1; - var checkPropTypes$1 = checkPropTypes_1; - var ReactDebugCurrentFiber$2 = ReactDebugCurrentFiber_1; - - var _require4 = ReactDebugFiberPerf_1, - startPhaseTimer = _require4.startPhaseTimer, - stopPhaseTimer = _require4.stopPhaseTimer; - var warnedAboutMissingGetChildContext = {}; } @@ -8729,7 +5888,7 @@ var didPerformWorkStackCursor = createCursor(false); var previousContext = emptyObject_1; function getUnmaskedContext(workInProgress) { - var hasOwnContext = isContextProvider$1(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 @@ -8739,16 +5898,14 @@ function getUnmaskedContext(workInProgress) { } return contextStackCursor.current; } -var getUnmaskedContext_1 = getUnmaskedContext; function cacheContext(workInProgress, unmaskedContext, maskedContext) { var instance = workInProgress.stateNode; instance.__reactInternalMemoizedUnmaskedChildContext = unmaskedContext; instance.__reactInternalMemoizedMaskedChildContext = maskedContext; } -var cacheContext_1 = cacheContext; -var getMaskedContext = function (workInProgress, unmaskedContext) { +function getMaskedContext(workInProgress, unmaskedContext) { var type = workInProgress.type; var contextTypes = type.contextTypes; if (!contextTypes) { @@ -8769,10 +5926,8 @@ var getMaskedContext = function (workInProgress, unmaskedContext) { } { - var name = getComponentName_1(workInProgress) || 'Unknown'; - ReactDebugCurrentFiber$2.setCurrentFiber(workInProgress, null); - checkPropTypes$1(contextTypes, context, 'context', name, ReactDebugCurrentFiber$2.getCurrentFiberStackAddendum); - ReactDebugCurrentFiber$2.resetCurrentFiber(); + var name = getComponentName(workInProgress) || 'Unknown'; + checkPropTypes_1(contextTypes, context, 'context', name, ReactDebugCurrentFiber.getCurrentFiberStackAddendum); } // Cache unmasked context so we can avoid recreating masked context unless necessary. @@ -8782,45 +5937,42 @@ var getMaskedContext = function (workInProgress, unmaskedContext) { } return context; -}; +} -var hasContextChanged = function () { +function hasContextChanged() { return didPerformWorkStackCursor.current; -}; +} function isContextConsumer(fiber) { - return fiber.tag === ClassComponent$3 && fiber.type.contextTypes != null; + return fiber.tag === ClassComponent && fiber.type.contextTypes != null; } -var isContextConsumer_1 = isContextConsumer; -function isContextProvider$1(fiber) { - return fiber.tag === ClassComponent$3 && fiber.type.childContextTypes != null; +function isContextProvider(fiber) { + return fiber.tag === ClassComponent && fiber.type.childContextTypes != null; } -var isContextProvider_1 = isContextProvider$1; function popContextProvider(fiber) { - if (!isContextProvider$1(fiber)) { + if (!isContextProvider(fiber)) { return; } pop(didPerformWorkStackCursor, fiber); pop(contextStackCursor, fiber); } -var popContextProvider_1 = popContextProvider; -var popTopLevelContextObject = function (fiber) { +function popTopLevelContextObject(fiber) { pop(didPerformWorkStackCursor, fiber); pop(contextStackCursor, fiber); -}; +} -var pushTopLevelContextObject = function (fiber, context, didChange) { +function pushTopLevelContextObject(fiber, context, didChange) { !(contextStackCursor.cursor == null) ? invariant_1(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$1(fiber, parentContext, isReconciling) { +function processChildContext(fiber, parentContext) { var instance = fiber.stateNode; var childContextTypes = fiber.type.childContextTypes; @@ -8828,11 +5980,11 @@ function processChildContext$1(fiber, parentContext, isReconciling) { // It has only been added in Fiber to match the (unintentional) behavior in Stack. if (typeof instance.getChildContext !== 'function') { { - var componentName = getComponentName_1(fiber) || 'Unknown'; + var componentName = getComponentName(fiber) || 'Unknown'; if (!warnedAboutMissingGetChildContext[componentName]) { warnedAboutMissingGetChildContext[componentName] = true; - warning$22(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); + warning_1(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; @@ -8840,34 +5992,33 @@ function processChildContext$1(fiber, parentContext, isReconciling) { var childContext = void 0; { - ReactDebugCurrentFiber$2.setCurrentFiber(fiber, 'getChildContext'); - startPhaseTimer(fiber, 'getChildContext'); - childContext = instance.getChildContext(); - stopPhaseTimer(); - ReactDebugCurrentFiber$2.resetCurrentFiber(); + ReactDebugCurrentFiber.setCurrentPhase('getChildContext'); + } + startPhaseTimer(fiber, 'getChildContext'); + childContext = instance.getChildContext(); + stopPhaseTimer(); + { + ReactDebugCurrentFiber.setCurrentPhase(null); } for (var contextKey in childContext) { - !(contextKey in childContextTypes) ? invariant_1(false, '%s.getChildContext(): key "%s" is not defined in childContextTypes.', getComponentName_1(fiber) || 'Unknown', contextKey) : void 0; + !(contextKey in childContextTypes) ? invariant_1(false, '%s.getChildContext(): key "%s" is not defined in childContextTypes.', getComponentName(fiber) || 'Unknown', contextKey) : void 0; } { - var name = getComponentName_1(fiber) || 'Unknown'; - // We can only provide accurate element stacks if we pass work-in-progress tree - // during the begin or complete phase. However currently this function is also - // called from unstable_renderSubtree legacy implementation. In this case it unsafe to - // assume anything about the given fiber. We won't pass it down if we aren't sure. - // TODO: remove this hack when we delete unstable_renderSubtree in Fiber. - var workInProgress = isReconciling ? fiber : null; - ReactDebugCurrentFiber$2.setCurrentFiber(workInProgress, null); - checkPropTypes$1(childContextTypes, childContext, 'child context', name, ReactDebugCurrentFiber$2.getCurrentFiberStackAddendum); - ReactDebugCurrentFiber$2.resetCurrentFiber(); + var name = getComponentName(fiber) || 'Unknown'; + checkPropTypes_1(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); + return _assign({}, parentContext, childContext); } -var processChildContext_1 = processChildContext$1; -var pushContextProvider = function (workInProgress) { - if (!isContextProvider$1(workInProgress)) { +function pushContextProvider(workInProgress) { + if (!isContextProvider(workInProgress)) { return false; } @@ -8878,15 +6029,15 @@ var pushContextProvider = function (workInProgress) { var memoizedMergedChildContext = instance && instance.__reactInternalMemoizedMergedChildContext || emptyObject_1; // Remember the parent context so we can merge with it later. - // Inherit the parent's did-perform-work value to avoid inadvertantly blocking updates. + // 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; -}; +} -var invalidateContextProvider = function (workInProgress, didChange) { +function invalidateContextProvider(workInProgress, didChange) { var instance = workInProgress.stateNode; !instance ? invariant_1(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; @@ -8894,7 +6045,7 @@ var invalidateContextProvider = function (workInProgress, 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$1(workInProgress, previousContext, true); + var mergedContext = processChildContext(workInProgress, previousContext); instance.__reactInternalMemoizedMergedChildContext = mergedContext; // Replace the old (or empty) context with the new one. @@ -8908,22 +6059,22 @@ var invalidateContextProvider = function (workInProgress, didChange) { pop(didPerformWorkStackCursor, workInProgress); push(didPerformWorkStackCursor, didChange, workInProgress); } -}; +} -var resetContext = function () { +function resetContext() { previousContext = emptyObject_1; contextStackCursor.current = emptyObject_1; didPerformWorkStackCursor.current = false; -}; +} -var findCurrentUnmaskedContext$1 = function (fiber) { +function findCurrentUnmaskedContext(fiber) { // Currently this is only used with renderSubtreeIntoContainer; not sure if it // makes sense elsewhere - !(isFiberMounted$1(fiber) && fiber.tag === ClassComponent$3) ? invariant_1(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; + !(isFiberMounted(fiber) && fiber.tag === ClassComponent) ? invariant_1(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$3) { - if (isContextProvider$1(node)) { + while (node.tag !== HostRoot) { + if (isContextProvider(node)) { return node.stateNode.__reactInternalMemoizedMergedChildContext; } var parent = node['return']; @@ -8931,66 +6082,43 @@ var findCurrentUnmaskedContext$1 = function (fiber) { node = parent; } return node.stateNode.context; -}; - -var ReactFiberContext = { - getUnmaskedContext: getUnmaskedContext_1, - cacheContext: cacheContext_1, - getMaskedContext: getMaskedContext, - hasContextChanged: hasContextChanged, - isContextConsumer: isContextConsumer_1, - isContextProvider: isContextProvider_1, - popContextProvider: popContextProvider_1, - popTopLevelContextObject: popTopLevelContextObject, - pushTopLevelContextObject: pushTopLevelContextObject, - processChildContext: processChildContext_1, - pushContextProvider: pushContextProvider, - invalidateContextProvider: invalidateContextProvider, - resetContext: resetContext, - findCurrentUnmaskedContext: findCurrentUnmaskedContext$1 -}; +} -/** - * Copyright (c) 2013-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @providesModule ReactTypeOfInternalContext - * - */ +var NoWork = 0; // TODO: Use an opaque type once ESLint et al support the syntax -var ReactTypeOfInternalContext = { - NoContext: 0, - AsyncUpdates: 1 -}; +var Sync = 1; +var Never = 2147483647; // Max int32: Math.pow(2, 31) - 1 -var IndeterminateComponent$1 = ReactTypeOfWork.IndeterminateComponent; -var ClassComponent$4 = ReactTypeOfWork.ClassComponent; -var HostRoot$5 = ReactTypeOfWork.HostRoot; -var HostComponent$5 = ReactTypeOfWork.HostComponent; -var HostText$3 = ReactTypeOfWork.HostText; -var HostPortal$2 = ReactTypeOfWork.HostPortal; -var CoroutineComponent = ReactTypeOfWork.CoroutineComponent; -var YieldComponent$1 = ReactTypeOfWork.YieldComponent; -var Fragment$1 = ReactTypeOfWork.Fragment; +var UNIT_SIZE = 10; +var MAGIC_NUMBER_OFFSET = 2; -var NoWork$1 = ReactPriorityLevel.NoWork; +// 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; +} -var NoContext = ReactTypeOfInternalContext.NoContext; +function expirationTimeToMs(expirationTime) { + return (expirationTime - MAGIC_NUMBER_OFFSET) * UNIT_SIZE; +} -var NoEffect$1 = ReactTypeOfSideEffect.NoEffect; +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 getComponentName$6 = getComponentName_1; var hasBadMapPolyfill = false; try { var nonExtensibleObject = Object.preventExtensions({}); /* eslint-disable no-new */ - new Map([[nonExtensibleObject, null]]); - new Set([nonExtensibleObject]); + /* eslint-enable no-new */ } catch (e) { // TODO: Consider warning about bad polyfills @@ -9029,13 +6157,13 @@ function FiberNode(tag, key, internalContextTag) { this.internalContextTag = internalContextTag; // Effects - this.effectTag = NoEffect$1; + this.effectTag = NoEffect; this.nextEffect = null; this.firstEffect = null; this.lastEffect = null; - this.pendingWorkPriority = NoWork$1; + this.expirationTime = NoWork; this.alternate = null; @@ -9073,7 +6201,7 @@ function shouldConstruct(Component) { } // This is used to create an alternate fiber to do work on. -var createWorkInProgress = function (current, renderPriority) { +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 @@ -9097,7 +6225,7 @@ var createWorkInProgress = function (current, renderPriority) { } else { // We already have an alternate. // Reset the effect tag. - workInProgress.effectTag = NoEffect$1; + workInProgress.effectTag = NoEffect; // The effect list is no longer valid. workInProgress.nextEffect = null; @@ -9105,71 +6233,45 @@ var createWorkInProgress = function (current, renderPriority) { workInProgress.lastEffect = null; } - workInProgress.pendingWorkPriority = renderPriority; + workInProgress.expirationTime = expirationTime; + workInProgress.pendingProps = pendingProps; workInProgress.child = current.child; workInProgress.memoizedProps = current.memoizedProps; workInProgress.memoizedState = current.memoizedState; workInProgress.updateQueue = current.updateQueue; - // pendingProps is set by the parent during reconciliation. - // TODO: Pass this as an argument. - // These will be overridden during the parent's reconciliation workInProgress.sibling = current.sibling; workInProgress.index = current.index; workInProgress.ref = current.ref; return workInProgress; -}; +} -var createHostRootFiber$1 = function () { - var fiber = createFiber(HostRoot$5, null, NoContext); +function createHostRootFiber() { + var fiber = createFiber(HostRoot, null, NoContext); return fiber; -}; +} -var createFiberFromElement = function (element, internalContextTag, priorityLevel) { +function createFiberFromElement(element, internalContextTag, expirationTime) { var owner = null; { owner = element._owner; } - var fiber = createFiberFromElementType(element.type, element.key, internalContextTag, owner); - fiber.pendingProps = element.props; - fiber.pendingWorkPriority = priorityLevel; - - { - fiber._debugSource = element._source; - fiber._debugOwner = element._owner; - } - - return fiber; -}; - -var createFiberFromFragment = function (elements, internalContextTag, priorityLevel) { - // TODO: Consider supporting keyed fragments. Technically, we accidentally - // support that in the existing React. - var fiber = createFiber(Fragment$1, null, internalContextTag); - fiber.pendingProps = elements; - fiber.pendingWorkPriority = priorityLevel; - return fiber; -}; - -var createFiberFromText = function (content, internalContextTag, priorityLevel) { - var fiber = createFiber(HostText$3, null, internalContextTag); - fiber.pendingProps = content; - fiber.pendingWorkPriority = priorityLevel; - return fiber; -}; - -function createFiberFromElementType(type, key, internalContextTag, debugOwner) { var fiber = void 0; + var type = element.type, + key = element.key; + if (typeof type === 'function') { - fiber = shouldConstruct(type) ? createFiber(ClassComponent$4, key, internalContextTag) : createFiber(IndeterminateComponent$1, key, internalContextTag); + 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$5, key, internalContextTag); + 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. @@ -9178,309 +6280,941 @@ function createFiberFromElementType(type, key, internalContextTag, debugOwner) { // 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."; + 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 = debugOwner ? getComponentName$6(debugOwner) : null; + var ownerName = owner ? getComponentName(owner) : null; if (ownerName) { info += '\n\nCheck the render method of `' + ownerName + '`.'; } } invariant_1(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; } -var createFiberFromElementType_1 = createFiberFromElementType; +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; +} -var createFiberFromHostInstanceForDeletion = function () { - var fiber = createFiber(HostComponent$5, null, NoContext); +function createFiberFromHostInstanceForDeletion() { + var fiber = createFiber(HostComponent, null, NoContext); fiber.type = 'DELETED'; return fiber; -}; +} -var createFiberFromCoroutine = function (coroutine, internalContextTag, priorityLevel) { - var fiber = createFiber(CoroutineComponent, coroutine.key, internalContextTag); - fiber.type = coroutine.handler; - fiber.pendingProps = coroutine; - fiber.pendingWorkPriority = priorityLevel; +function createFiberFromCall(call, internalContextTag, expirationTime) { + var fiber = createFiber(CallComponent, call.key, internalContextTag); + fiber.type = call.handler; + fiber.pendingProps = call; + fiber.expirationTime = expirationTime; return fiber; -}; +} -var createFiberFromYield = function (yieldNode, internalContextTag, priorityLevel) { - var fiber = createFiber(YieldComponent$1, null, internalContextTag); +function createFiberFromReturn(returnNode, internalContextTag, expirationTime) { + var fiber = createFiber(ReturnComponent, null, internalContextTag); + fiber.expirationTime = expirationTime; return fiber; -}; +} -var createFiberFromPortal = function (portal, internalContextTag, priorityLevel) { - var fiber = createFiber(HostPortal$2, portal.key, internalContextTag); +function createFiberFromPortal(portal, internalContextTag, expirationTime) { + var fiber = createFiber(HostPortal, portal.key, internalContextTag); fiber.pendingProps = portal.children || []; - fiber.pendingWorkPriority = priorityLevel; + fiber.expirationTime = expirationTime; fiber.stateNode = { containerInfo: portal.containerInfo, + pendingChildren: null, // Used by persistent updates implementation: portal.implementation }; return fiber; -}; - -var largerPriority = function (p1, p2) { - return p1 !== NoWork$1 && (p2 === NoWork$1 || p2 > p1) ? p1 : p2; -}; - -var ReactFiber = { - createWorkInProgress: createWorkInProgress, - createHostRootFiber: createHostRootFiber$1, - createFiberFromElement: createFiberFromElement, - createFiberFromFragment: createFiberFromFragment, - createFiberFromText: createFiberFromText, - createFiberFromElementType: createFiberFromElementType_1, - createFiberFromHostInstanceForDeletion: createFiberFromHostInstanceForDeletion, - createFiberFromCoroutine: createFiberFromCoroutine, - createFiberFromYield: createFiberFromYield, - createFiberFromPortal: createFiberFromPortal, - largerPriority: largerPriority -}; - -var createHostRootFiber = ReactFiber.createHostRootFiber; +} -var createFiberRoot$1 = function (containerInfo) { +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, - isScheduled: false, - nextScheduledRoot: null, + pendingChildren: null, + remainingExpirationTime: NoWork, + isReadyForCommit: false, + finishedWork: null, context: null, - pendingContext: null + pendingContext: null, + hydrate: hydrate, + nextScheduledRoot: null }; uninitializedFiber.stateNode = root; return root; -}; +} -var ReactFiberRoot = { - createFiberRoot: createFiberRoot$1 -}; +var onCommitFiberRoot = null; +var onCommitFiberUnmount = null; +var hasLoggedError = false; -var defaultShowDialog = function (capturedError) { +function catchErrors(fn) { + return function (arg) { + try { + return fn(arg); + } catch (err) { + if (true && !hasLoggedError) { + hasLoggedError = true; + warning_1(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_1(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_1(false, 'React DevTools encountered an error: %s.', err); + } + } + // DevTools exists return true; -}; +} -var showDialog = defaultShowDialog; +function onCommitRoot(root) { + if (typeof onCommitFiberRoot === 'function') { + onCommitFiberRoot(root); + } +} -function logCapturedError$1(capturedError) { - var logError = showDialog(capturedError); +function onCommitUnmount(fiber) { + if (typeof onCommitFiberUnmount === 'function') { + onCommitFiberUnmount(fiber); + } +} - // Allow injected showDialog() to prevent default console.error logging. - // This enables renderers like ReactNative to better manage redbox behavior. - if (logError === false) { +{ + 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_1(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; } - var error = capturedError.error; + // 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 + }; + } + { - var componentName = capturedError.componentName, - componentStack = capturedError.componentStack, - errorBoundaryName = capturedError.errorBoundaryName, - errorBoundaryFound = capturedError.errorBoundaryFound, - willRetry = capturedError.willRetry; + // 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; - var componentNameMessage = componentName ? 'The above error occurred in the <' + componentName + '> component:' : 'The above error occurred in one of your React components:'; + // 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; + } - 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.'; + // 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 { - errorBoundaryMessage = 'Consider adding an error boundary to your tree to customize error handling behavior.\n' + 'You can learn more about error boundaries at https://fb.me/react-error-boundaries.'; + _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; + } } - var combinedMessage = '' + componentNameMessage + componentStack + '\n\n' + ('' + errorBoundaryMessage); + 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; + } - // 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); + 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; } -var injection$1 = { - /** - * Display custom dialog for lifecycle errors. - * Return false to prevent default behavior of logging to console.error. - */ - injectDialog: function (fn) { - !(showDialog === defaultShowDialog) ? invariant_1(false, 'The custom dialog was already injected.') : void 0; - !(typeof fn === 'function') ? invariant_1(false, 'Injected showDialog() must be a function.') : void 0; - showDialog = fn; +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_1(false, 'Invalid argument passed as callback. Expected a function. Instead received: %s', _callback) : void 0; + _callback.call(context); + } +} -var logCapturedError_1 = logCapturedError$1; +var fakeInternalInstance = {}; +var isArray = Array.isArray; -var ReactFiberErrorLogger = { - injection: injection$1, - logCapturedError: logCapturedError_1 -}; +{ + var didWarnAboutStateAssignmentForComponent = {}; -/** - * Copyright (c) 2014-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @providesModule ReactCoroutine - * - */ + var warnOnInvalidCallback = function (callback, callerName) { + warning_1(callback === null || typeof callback === 'function', '%s(...): Expected the last optional `callback` argument to be a ' + 'function. Instead received: %s.', callerName, callback); + }; -// The Symbol used to tag the special React types. If there is no native Symbol -// nor polyfill, then a plain number is used for performance. -var REACT_COROUTINE_TYPE$1; -var REACT_YIELD_TYPE$1; -if (typeof Symbol === 'function' && Symbol['for']) { - REACT_COROUTINE_TYPE$1 = Symbol['for']('react.coroutine'); - REACT_YIELD_TYPE$1 = Symbol['for']('react.yield'); -} else { - REACT_COROUTINE_TYPE$1 = 0xeac8; - REACT_YIELD_TYPE$1 = 0xeac9; + // 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_1(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 createCoroutine = function (children, handler, props) { - var key = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null; - - var coroutine = { - // This tag allow us to uniquely identify this as a React Coroutine - $$typeof: REACT_COROUTINE_TYPE$1, - key: key == null ? null : '' + key, - children: children, - handler: handler, - props: props +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); + } }; - { - // TODO: Add _store property for marking this as validated. - if (Object.freeze) { - Object.freeze(coroutine.props); - Object.freeze(coroutine); + 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_1(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_1(oldProps, newProps) || !shallowEqual_1(oldState, newState); } + + return true; } - return coroutine; -}; + function checkClassInstance(workInProgress) { + var instance = workInProgress.stateNode; + var type = workInProgress.type; + { + var name = getComponentName(workInProgress); + var renderPresent = instance.render; -var createYield = function (value) { - var yieldNode = { - // This tag allow us to uniquely identify this as a React Yield - $$typeof: REACT_YIELD_TYPE$1, - value: value - }; + if (!renderPresent) { + if (type.prototype && typeof type.prototype.render === 'function') { + warning_1(false, '%s(...): No `render` method found on the returned component ' + 'instance: did you accidentally return an object from the constructor?', name); + } else { + warning_1(false, '%s(...): No `render` method found on the returned component ' + 'instance: you may have forgotten to define `render`.', name); + } + } - { - // TODO: Add _store property for marking this as validated. - if (Object.freeze) { - Object.freeze(yieldNode); + var noGetInitialStateOnES6 = !instance.getInitialState || instance.getInitialState.isReactClassApproved || instance.state; + warning_1(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_1(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_1(noInstancePropTypes, 'propTypes was defined as an instance property on %s. Use a static ' + 'property to define propTypes instead.', name); + var noInstanceContextTypes = !instance.contextTypes; + warning_1(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_1(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_1(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_1(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_1(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_1(noComponentWillRecieveProps, '%s has a method called ' + 'componentWillRecieveProps(). Did you mean componentWillReceiveProps()?', name); + var hasMutatedProps = instance.props !== workInProgress.pendingProps; + warning_1(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_1(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_1(false, '%s.state: must be set to an object or null', getComponentName(workInProgress)); + } + if (typeof instance.getChildContext === 'function') { + warning_1(typeof workInProgress.type.childContextTypes === 'object', '%s.getChildContext(): childContextTypes must be defined in order to ' + 'use getChildContext().', getComponentName(workInProgress)); } } - return yieldNode; -}; + function resetInputPointers(workInProgress, instance) { + instance.props = workInProgress.memoizedProps; + instance.state = workInProgress.memoizedState; + } -/** - * Verifies the object is a coroutine object. - */ -var isCoroutine = function (object) { - return typeof object === 'object' && object !== null && object.$$typeof === REACT_COROUTINE_TYPE$1; -}; + 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; + } + } -/** - * Verifies the object is a yield object. - */ -var isYield = function (object) { - return typeof object === 'object' && object !== null && object.$$typeof === REACT_YIELD_TYPE$1; -}; + function constructClassInstance(workInProgress, props) { + var ctor = workInProgress.type; + var unmaskedContext = getUnmaskedContext(workInProgress); + var needsContext = isContextConsumer(workInProgress); + var context = needsContext ? getMaskedContext(workInProgress, unmaskedContext) : emptyObject_1; + var instance = new ctor(props, context); + adoptClassInstance(workInProgress, instance); -var REACT_YIELD_TYPE_1 = REACT_YIELD_TYPE$1; -var REACT_COROUTINE_TYPE_1 = REACT_COROUTINE_TYPE$1; + // 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); + } -var ReactCoroutine = { - createCoroutine: createCoroutine, - createYield: createYield, - isCoroutine: isCoroutine, - isYield: isYield, - REACT_YIELD_TYPE: REACT_YIELD_TYPE_1, - REACT_COROUTINE_TYPE: REACT_COROUTINE_TYPE_1 -}; + return instance; + } -/** - * Copyright (c) 2014-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @providesModule ReactPortal - * - */ + function callComponentWillMount(workInProgress, instance) { + startPhaseTimer(workInProgress, 'componentWillMount'); + var oldState = instance.state; + instance.componentWillMount(); + stopPhaseTimer(); -// The Symbol used to tag the special React types. If there is no native Symbol -// nor polyfill, then a plain number is used for performance. -var REACT_PORTAL_TYPE$1 = typeof Symbol === 'function' && Symbol['for'] && Symbol['for']('react.portal') || 0xeaca; + // Simulate an async bailout/interruption by invoking lifecycle twice. + if (debugRenderPhaseSideEffects) { + instance.componentWillMount(); + } -var createPortal$1 = function (children, containerInfo, -// TODO: figure out the API for cross-renderer implementation. -implementation) { - var key = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null; + if (oldState !== instance.state) { + { + warning_1(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); + } + } - return { - // This tag allow us to uniquely identify this as a React Portal - $$typeof: REACT_PORTAL_TYPE$1, - key: key == null ? null : '' + key, - children: children, - containerInfo: containerInfo, - implementation: implementation - }; -}; + function callComponentWillReceiveProps(workInProgress, instance, newProps, newContext) { + startPhaseTimer(workInProgress, 'componentWillReceiveProps'); + var oldState = instance.state; + instance.componentWillReceiveProps(newProps, newContext); + stopPhaseTimer(); -/** - * Verifies the object is a portal object. - */ -var isPortal = function (object) { - return typeof object === 'object' && object !== null && object.$$typeof === REACT_PORTAL_TYPE$1; -}; + // 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_1(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); + } + } -var REACT_PORTAL_TYPE_1 = REACT_PORTAL_TYPE$1; + // Invokes the mount life-cycles on a previously never rendered instance. + function mountClassInstance(workInProgress, renderExpirationTime) { + var current = workInProgress.alternate; -var ReactPortal = { - createPortal: createPortal$1, - isPortal: isPortal, - REACT_PORTAL_TYPE: REACT_PORTAL_TYPE_1 -}; + { + checkClassInstance(workInProgress); + } + + var instance = workInProgress.stateNode; + var state = instance.state || null; + + var props = workInProgress.pendingProps; + !props ? invariant_1(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_1; + 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; + // } -var REACT_COROUTINE_TYPE = ReactCoroutine.REACT_COROUTINE_TYPE; -var REACT_YIELD_TYPE = ReactCoroutine.REACT_YIELD_TYPE; + // // Update the input pointers now so that they are correct when we call + // // componentWillMount + // instance.props = newProps; + // instance.state = newState; + // instance.context = newContext; -var REACT_PORTAL_TYPE = ReactPortal.REACT_PORTAL_TYPE; + // 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_1(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); + } -{ - var _require3$4 = ReactDebugCurrentFiber_1, - getCurrentFiberStackAddendum$5 = _require3$4.getCurrentFiberStackAddendum; + // 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; + } - var warning$26 = warning_1; + 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 @@ -9488,6 +7222,7 @@ var REACT_PORTAL_TYPE = ReactPortal.REACT_PORTAL_TYPE; * updates. */ var ownerHasKeyUseWarning = {}; + var ownerHasFunctionTypeWarning = {}; var warnForMissingKey = function (child) { if (child === null || typeof child !== 'object') { @@ -9499,55 +7234,17 @@ var REACT_PORTAL_TYPE = ReactPortal.REACT_PORTAL_TYPE; !(typeof child._store === 'object') ? invariant_1(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$5() || ''); + 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$26(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$5()); + warning_1(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 createWorkInProgress$2 = ReactFiber.createWorkInProgress; -var createFiberFromElement$1 = ReactFiber.createFiberFromElement; -var createFiberFromFragment$1 = ReactFiber.createFiberFromFragment; -var createFiberFromText$1 = ReactFiber.createFiberFromText; -var createFiberFromCoroutine$1 = ReactFiber.createFiberFromCoroutine; -var createFiberFromYield$1 = ReactFiber.createFiberFromYield; -var createFiberFromPortal$1 = ReactFiber.createFiberFromPortal; - - -var isArray = Array.isArray; - -var FunctionalComponent$2 = ReactTypeOfWork.FunctionalComponent; -var ClassComponent$7 = ReactTypeOfWork.ClassComponent; -var HostText$5 = ReactTypeOfWork.HostText; -var HostPortal$5 = ReactTypeOfWork.HostPortal; -var CoroutineComponent$2 = ReactTypeOfWork.CoroutineComponent; -var YieldComponent$3 = ReactTypeOfWork.YieldComponent; -var Fragment$3 = ReactTypeOfWork.Fragment; -var NoEffect$2 = ReactTypeOfSideEffect.NoEffect; -var Placement$3 = ReactTypeOfSideEffect.Placement; -var Deletion$1 = ReactTypeOfSideEffect.Deletion; - - -var ITERATOR_SYMBOL = typeof Symbol === 'function' && Symbol.iterator; -var FAUX_ITERATOR_SYMBOL = '@@iterator'; // Before Symbol spec. -// The Symbol used to tag the ReactElement type. If there is no native Symbol -// nor polyfill, then a plain number is used for performance. -var REACT_ELEMENT_TYPE = typeof Symbol === 'function' && Symbol['for'] && Symbol['for']('react.element') || 0xeac7; - -function getIteratorFn(maybeIterable) { - if (maybeIterable === null || typeof maybeIterable === 'undefined') { - return null; - } - var iteratorFn = ITERATOR_SYMBOL && maybeIterable[ITERATOR_SYMBOL] || maybeIterable[FAUX_ITERATOR_SYMBOL]; - if (typeof iteratorFn === 'function') { - return iteratorFn; - } - return null; -} +var isArray$1 = Array.isArray; function coerceRef(current, element) { var mixedRef = element.ref; @@ -9556,14 +7253,9 @@ function coerceRef(current, element) { var owner = element._owner; var inst = void 0; if (owner) { - if (typeof owner.tag === 'number') { - var ownerFiber = owner; - !(ownerFiber.tag === ClassComponent$7) ? invariant_1(false, 'Stateless function components cannot have refs.') : void 0; - inst = ownerFiber.stateNode; - } else { - // Stack - inst = owner.getPublicInstance(); - } + var ownerFiber = owner; + !(ownerFiber.tag === ClassComponent) ? invariant_1(false, 'Stateless function components cannot have refs.') : void 0; + inst = ownerFiber.stateNode; } !inst ? invariant_1(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; @@ -9593,35 +7285,33 @@ 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$5() || ''); + addendum = ' If you meant to render a collection of children, use an array ' + 'instead.' + (getCurrentFiberStackAddendum$1() || ''); } invariant_1(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() { - warning$26(false, 'Functions are not valid as a React child. This may happen if ' + 'you return a Component instead of <Component /> from render. ' + 'Or maybe you meant to call this function rather than return it.%s', getCurrentFiberStackAddendum$5() || ''); + var currentComponentErrorInfo = 'Functions are not valid as a React child. This may happen if ' + 'you return a Component instead of <Component /> from render. ' + 'Or maybe you meant to call this function rather than return it.' + (getCurrentFiberStackAddendum$1() || ''); + + if (ownerHasFunctionTypeWarning[currentComponentErrorInfo]) { + return; + } + ownerHasFunctionTypeWarning[currentComponentErrorInfo] = true; + + warning_1(false, 'Functions are not valid as a React child. This may happen if ' + 'you return a Component instead of <Component /> 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(shouldClone, shouldTrackSideEffects) { +function ChildReconciler(shouldTrackSideEffects) { function deleteChild(returnFiber, childToDelete) { if (!shouldTrackSideEffects) { // Noop. return; } - if (!shouldClone) { - // When we're reconciling in place we have a work in progress copy. We - // actually want the current copy. If there is no current copy, then we - // don't need to track deletion side-effects. - if (childToDelete.alternate === null) { - return; - } - childToDelete = childToDelete.alternate; - } // 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 @@ -9635,7 +7325,7 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) { returnFiber.firstEffect = returnFiber.lastEffect = childToDelete; } childToDelete.nextEffect = null; - childToDelete.effectTag = Deletion$1; + childToDelete.effectTag = Deletion; } function deleteRemainingChildren(returnFiber, currentFirstChild) { @@ -9671,24 +7361,13 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) { return existingChildren; } - function useFiber(fiber, priority) { + 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. - if (shouldClone) { - var clone = createWorkInProgress$2(fiber, priority); - clone.index = 0; - clone.sibling = null; - return clone; - } else { - // We override the pending priority even if it is higher, because if - // we're reconciling at a lower priority that means that this was - // down-prioritized. - fiber.pendingWorkPriority = priority; - fiber.effectTag = NoEffect$2; - fiber.index = 0; - fiber.sibling = null; - return fiber; - } + var clone = createWorkInProgress(fiber, pendingProps, expirationTime); + clone.index = 0; + clone.sibling = null; + return clone; } function placeChild(newFiber, lastPlacedIndex, newIndex) { @@ -9702,7 +7381,7 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) { var oldIndex = current.index; if (oldIndex < lastPlacedIndex) { // This is a move. - newFiber.effectTag = Placement$3; + newFiber.effectTag = Placement; return lastPlacedIndex; } else { // This item can stay in place. @@ -9710,7 +7389,7 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) { } } else { // This is an insertion. - newFiber.effectTag = Placement$3; + newFiber.effectTag = Placement; return lastPlacedIndex; } } @@ -9719,115 +7398,110 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) { // 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$3; + newFiber.effectTag = Placement; } return newFiber; } - function updateTextNode(returnFiber, current, textContent, priority) { - if (current === null || current.tag !== HostText$5) { + function updateTextNode(returnFiber, current, textContent, expirationTime) { + if (current === null || current.tag !== HostText) { // Insert - var created = createFiberFromText$1(textContent, returnFiber.internalContextTag, priority); + var created = createFiberFromText(textContent, returnFiber.internalContextTag, expirationTime); created['return'] = returnFiber; return created; } else { // Update - var existing = useFiber(current, priority); - existing.pendingProps = textContent; + var existing = useFiber(current, textContent, expirationTime); existing['return'] = returnFiber; return existing; } } - function updateElement(returnFiber, current, element, priority) { - if (current === null || current.type !== element.type) { - // Insert - var created = createFiberFromElement$1(element, returnFiber.internalContextTag, priority); - created.ref = coerceRef(current, element); - created['return'] = returnFiber; - return created; - } else { + function updateElement(returnFiber, current, element, expirationTime) { + if (current !== null && current.type === element.type) { // Move based on index - var existing = useFiber(current, priority); + var existing = useFiber(current, element.props, expirationTime); existing.ref = coerceRef(current, element); - existing.pendingProps = element.props; 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 updateCoroutine(returnFiber, current, coroutine, priority) { + function updateCall(returnFiber, current, call, expirationTime) { // TODO: Should this also compare handler to determine whether to reuse? - if (current === null || current.tag !== CoroutineComponent$2) { + if (current === null || current.tag !== CallComponent) { // Insert - var created = createFiberFromCoroutine$1(coroutine, returnFiber.internalContextTag, priority); + var created = createFiberFromCall(call, returnFiber.internalContextTag, expirationTime); created['return'] = returnFiber; return created; } else { // Move based on index - var existing = useFiber(current, priority); - existing.pendingProps = coroutine; + var existing = useFiber(current, call, expirationTime); existing['return'] = returnFiber; return existing; } } - function updateYield(returnFiber, current, yieldNode, priority) { - if (current === null || current.tag !== YieldComponent$3) { + function updateReturn(returnFiber, current, returnNode, expirationTime) { + if (current === null || current.tag !== ReturnComponent) { // Insert - var created = createFiberFromYield$1(yieldNode, returnFiber.internalContextTag, priority); - created.type = yieldNode.value; + 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, priority); - existing.type = yieldNode.value; + var existing = useFiber(current, null, expirationTime); + existing.type = returnNode.value; existing['return'] = returnFiber; return existing; } } - function updatePortal(returnFiber, current, portal, priority) { - if (current === null || current.tag !== HostPortal$5 || current.stateNode.containerInfo !== portal.containerInfo || current.stateNode.implementation !== portal.implementation) { + 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$1(portal, returnFiber.internalContextTag, priority); + var created = createFiberFromPortal(portal, returnFiber.internalContextTag, expirationTime); created['return'] = returnFiber; return created; } else { // Update - var existing = useFiber(current, priority); - existing.pendingProps = portal.children || []; + var existing = useFiber(current, portal.children || [], expirationTime); existing['return'] = returnFiber; return existing; } } - function updateFragment(returnFiber, current, fragment, priority) { - if (current === null || current.tag !== Fragment$3) { + function updateFragment(returnFiber, current, fragment, expirationTime, key) { + if (current === null || current.tag !== Fragment) { // Insert - var created = createFiberFromFragment$1(fragment, returnFiber.internalContextTag, priority); + var created = createFiberFromFragment(fragment, returnFiber.internalContextTag, expirationTime, key); created['return'] = returnFiber; return created; } else { // Update - var existing = useFiber(current, priority); - existing.pendingProps = fragment; + var existing = useFiber(current, fragment, expirationTime); existing['return'] = returnFiber; return existing; } } - function createChild(returnFiber, newChild, priority) { + function createChild(returnFiber, newChild, expirationTime) { if (typeof newChild === 'string' || typeof newChild === 'number') { - // Text nodes doesn't have keys. If the previous node is implicitly keyed + // 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$1('' + newChild, returnFiber.internalContextTag, priority); + var created = createFiberFromText('' + newChild, returnFiber.internalContextTag, expirationTime); created['return'] = returnFiber; return created; } @@ -9836,39 +7510,45 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) { switch (newChild.$$typeof) { case REACT_ELEMENT_TYPE: { - var _created = createFiberFromElement$1(newChild, returnFiber.internalContextTag, priority); - _created.ref = coerceRef(null, newChild); - _created['return'] = returnFiber; - return _created; - } - - case REACT_COROUTINE_TYPE: - { - var _created2 = createFiberFromCoroutine$1(newChild, returnFiber.internalContextTag, priority); - _created2['return'] = returnFiber; - return _created2; + 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_YIELD_TYPE: + case REACT_CALL_TYPE: { - var _created3 = createFiberFromYield$1(newChild, returnFiber.internalContextTag, priority); - _created3.type = newChild.value; + var _created3 = createFiberFromCall(newChild, returnFiber.internalContextTag, expirationTime); _created3['return'] = returnFiber; return _created3; } - case REACT_PORTAL_TYPE: + case REACT_RETURN_TYPE: { - var _created4 = createFiberFromPortal$1(newChild, returnFiber.internalContextTag, priority); + 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(newChild) || getIteratorFn(newChild)) { - var _created5 = createFiberFromFragment$1(newChild, returnFiber.internalContextTag, priority); - _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); @@ -9883,19 +7563,19 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) { return null; } - function updateSlot(returnFiber, oldFiber, newChild, priority) { + 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 doesn't have keys. If the previous node is implicitly keyed + // 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, priority); + return updateTextNode(returnFiber, oldFiber, '' + newChild, expirationTime); } if (typeof newChild === 'object' && newChild !== null) { @@ -9903,28 +7583,31 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) { case REACT_ELEMENT_TYPE: { if (newChild.key === key) { - return updateElement(returnFiber, oldFiber, newChild, priority); + 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_COROUTINE_TYPE: + case REACT_CALL_TYPE: { if (newChild.key === key) { - return updateCoroutine(returnFiber, oldFiber, newChild, priority); + return updateCall(returnFiber, oldFiber, newChild, expirationTime); } else { return null; } } - case REACT_YIELD_TYPE: + case REACT_RETURN_TYPE: { - // Yields doesn't have keys. If the previous node is implicitly keyed + // 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 updateYield(returnFiber, oldFiber, newChild, priority); + return updateReturn(returnFiber, oldFiber, newChild, expirationTime); } else { return null; } @@ -9933,20 +7616,19 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) { case REACT_PORTAL_TYPE: { if (newChild.key === key) { - return updatePortal(returnFiber, oldFiber, newChild, priority); + return updatePortal(returnFiber, oldFiber, newChild, expirationTime); } else { return null; } } } - if (isArray(newChild) || getIteratorFn(newChild)) { - // Fragments doesn't have keys so if the previous key is implicit we can - // update it. + if (isArray$1(newChild) || getIteratorFn(newChild)) { if (key !== null) { return null; } - return updateFragment(returnFiber, oldFiber, newChild, priority); + + return updateFragment(returnFiber, oldFiber, newChild, expirationTime, null); } throwOnInvalidObjectType(returnFiber, newChild); @@ -9961,12 +7643,12 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) { return null; } - function updateFromMap(existingChildren, returnFiber, newIdx, newChild, priority) { + function updateFromMap(existingChildren, returnFiber, newIdx, newChild, expirationTime) { if (typeof newChild === 'string' || typeof newChild === 'number') { - // Text nodes doesn't have keys, so we neither have to check the old nor + // 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, priority); + return updateTextNode(returnFiber, matchedFiber, '' + newChild, expirationTime); } if (typeof newChild === 'object' && newChild !== null) { @@ -9974,33 +7656,36 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) { case REACT_ELEMENT_TYPE: { var _matchedFiber = existingChildren.get(newChild.key === null ? newIdx : newChild.key) || null; - return updateElement(returnFiber, _matchedFiber, newChild, priority); + if (newChild.type === REACT_FRAGMENT_TYPE) { + return updateFragment(returnFiber, _matchedFiber, newChild.props.children, expirationTime, newChild.key); + } + return updateElement(returnFiber, _matchedFiber, newChild, expirationTime); } - case REACT_COROUTINE_TYPE: + case REACT_CALL_TYPE: { var _matchedFiber2 = existingChildren.get(newChild.key === null ? newIdx : newChild.key) || null; - return updateCoroutine(returnFiber, _matchedFiber2, newChild, priority); + return updateCall(returnFiber, _matchedFiber2, newChild, expirationTime); } - case REACT_YIELD_TYPE: + case REACT_RETURN_TYPE: { - // Yields doesn't have keys, so we neither have to check the old nor - // new node for the key. If both are yields, they match. + // 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 updateYield(returnFiber, _matchedFiber3, newChild, priority); + 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, priority); + return updatePortal(returnFiber, _matchedFiber4, newChild, expirationTime); } } - if (isArray(newChild) || getIteratorFn(newChild)) { + if (isArray$1(newChild) || getIteratorFn(newChild)) { var _matchedFiber5 = existingChildren.get(newIdx) || null; - return updateFragment(returnFiber, _matchedFiber5, newChild, priority); + return updateFragment(returnFiber, _matchedFiber5, newChild, expirationTime, null); } throwOnInvalidObjectType(returnFiber, newChild); @@ -10025,7 +7710,7 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) { } switch (child.$$typeof) { case REACT_ELEMENT_TYPE: - case REACT_COROUTINE_TYPE: + case REACT_CALL_TYPE: case REACT_PORTAL_TYPE: warnForMissingKey(child); var key = child.key; @@ -10041,7 +7726,7 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) { knownKeys.add(key); break; } - warning$26(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$5()); + warning_1(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; @@ -10050,7 +7735,7 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) { return knownKeys; } - function reconcileChildrenArray(returnFiber, currentFirstChild, newChildren, priority) { + 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 @@ -10093,7 +7778,7 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) { } else { nextOldFiber = oldFiber.sibling; } - var newFiber = updateSlot(returnFiber, oldFiber, newChildren[newIdx], priority); + 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 @@ -10136,7 +7821,7 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) { // 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], priority); + var _newFiber = createChild(returnFiber, newChildren[newIdx], expirationTime); if (!_newFiber) { continue; } @@ -10157,7 +7842,7 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) { // 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], priority); + var _newFiber2 = updateFromMap(existingChildren, returnFiber, newIdx, newChildren[newIdx], expirationTime); if (_newFiber2) { if (shouldTrackSideEffects) { if (_newFiber2.alternate !== null) { @@ -10189,7 +7874,7 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) { return resultingFirstChild; } - function reconcileChildrenIterator(returnFiber, currentFirstChild, newChildrenIterable, priority) { + function reconcileChildrenIterator(returnFiber, currentFirstChild, newChildrenIterable, expirationTime) { // This is the same implementation as reconcileChildrenArray(), // but using the iterator instead. @@ -10201,7 +7886,7 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) { if (typeof newChildrenIterable.entries === 'function') { var possibleMap = newChildrenIterable; if (possibleMap.entries === iteratorFn) { - warning$26(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$5()); + warning_1(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; } } @@ -10238,7 +7923,7 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) { } else { nextOldFiber = oldFiber.sibling; } - var newFiber = updateSlot(returnFiber, oldFiber, step.value, priority); + 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 @@ -10281,7 +7966,7 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) { // 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, priority); + var _newFiber3 = createChild(returnFiber, step.value, expirationTime); if (_newFiber3 === null) { continue; } @@ -10302,7 +7987,7 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) { // 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, priority); + var _newFiber4 = updateFromMap(existingChildren, returnFiber, newIdx, step.value, expirationTime); if (_newFiber4 !== null) { if (shouldTrackSideEffects) { if (_newFiber4.alternate !== null) { @@ -10334,38 +8019,36 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) { return resultingFirstChild; } - function reconcileSingleTextNode(returnFiber, currentFirstChild, textContent, priority) { + 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$5) { + 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, priority); - existing.pendingProps = textContent; + 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$1(textContent, returnFiber.internalContextTag, priority); + var created = createFiberFromText(textContent, returnFiber.internalContextTag, expirationTime); created['return'] = returnFiber; return created; } - function reconcileSingleElement(returnFiber, currentFirstChild, element, priority) { + 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.type === element.type) { + if (child.tag === Fragment ? element.type === REACT_FRAGMENT_TYPE : child.type === element.type) { deleteRemainingChildren(returnFiber, child.sibling); - var existing = useFiber(child, priority); + var existing = useFiber(child, element.type === REACT_FRAGMENT_TYPE ? element.props.children : element.props, expirationTime); existing.ref = coerceRef(child, element); - existing.pendingProps = element.props; existing['return'] = returnFiber; { existing._debugSource = element._source; @@ -10382,23 +8065,28 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) { child = child.sibling; } - var created = createFiberFromElement$1(element, returnFiber.internalContextTag, priority); - created.ref = coerceRef(currentFirstChild, element); - created['return'] = returnFiber; - return created; + 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 reconcileSingleCoroutine(returnFiber, currentFirstChild, coroutine, priority) { - var key = coroutine.key; + 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 === CoroutineComponent$2) { + if (child.tag === CallComponent) { deleteRemainingChildren(returnFiber, child.sibling); - var existing = useFiber(child, priority); - existing.pendingProps = coroutine; + var existing = useFiber(child, call, expirationTime); existing['return'] = returnFiber; return existing; } else { @@ -10411,19 +8099,19 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) { child = child.sibling; } - var created = createFiberFromCoroutine$1(coroutine, returnFiber.internalContextTag, priority); + var created = createFiberFromCall(call, returnFiber.internalContextTag, expirationTime); created['return'] = returnFiber; return created; } - function reconcileSingleYield(returnFiber, currentFirstChild, yieldNode, priority) { + 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 === YieldComponent$3) { + if (child.tag === ReturnComponent) { deleteRemainingChildren(returnFiber, child.sibling); - var existing = useFiber(child, priority); - existing.type = yieldNode.value; + var existing = useFiber(child, null, expirationTime); + existing.type = returnNode.value; existing['return'] = returnFiber; return existing; } else { @@ -10431,23 +8119,22 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) { } } - var created = createFiberFromYield$1(yieldNode, returnFiber.internalContextTag, priority); - created.type = yieldNode.value; + var created = createFiberFromReturn(returnNode, returnFiber.internalContextTag, expirationTime); + created.type = returnNode.value; created['return'] = returnFiber; return created; } - function reconcileSinglePortal(returnFiber, currentFirstChild, portal, priority) { + 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$5 && child.stateNode.containerInfo === portal.containerInfo && child.stateNode.implementation === portal.implementation) { + if (child.tag === HostPortal && child.stateNode.containerInfo === portal.containerInfo && child.stateNode.implementation === portal.implementation) { deleteRemainingChildren(returnFiber, child.sibling); - var existing = useFiber(child, priority); - existing.pendingProps = portal.children || []; + var existing = useFiber(child, portal.children || [], expirationTime); existing['return'] = returnFiber; return existing; } else { @@ -10460,7 +8147,7 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) { child = child.sibling; } - var created = createFiberFromPortal$1(portal, returnFiber.internalContextTag, priority); + var created = createFiberFromPortal(portal, returnFiber.internalContextTag, expirationTime); created['return'] = returnFiber; return created; } @@ -10468,42 +8155,46 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) { // 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, priority) { + 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) { - // Support only the subset of return types that Stack supports. Treat - // everything else as empty, but log a warning. switch (newChild.$$typeof) { case REACT_ELEMENT_TYPE: - return placeSingleChild(reconcileSingleElement(returnFiber, currentFirstChild, newChild, priority)); - - case REACT_COROUTINE_TYPE: - return placeSingleChild(reconcileSingleCoroutine(returnFiber, currentFirstChild, newChild, priority)); - - case REACT_YIELD_TYPE: - return placeSingleChild(reconcileSingleYield(returnFiber, currentFirstChild, newChild, priority)); + 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, priority)); + return placeSingleChild(reconcileSinglePortal(returnFiber, currentFirstChild, newChild, expirationTime)); } } if (typeof newChild === 'string' || typeof newChild === 'number') { - return placeSingleChild(reconcileSingleTextNode(returnFiber, currentFirstChild, '' + newChild, priority)); + return placeSingleChild(reconcileSingleTextNode(returnFiber, currentFirstChild, '' + newChild, expirationTime)); } - if (isArray(newChild)) { - return reconcileChildrenArray(returnFiber, currentFirstChild, newChild, priority); + if (isArray$1(newChild)) { + return reconcileChildrenArray(returnFiber, currentFirstChild, newChild, expirationTime); } if (getIteratorFn(newChild)) { - return reconcileChildrenIterator(returnFiber, currentFirstChild, newChild, priority); + return reconcileChildrenIterator(returnFiber, currentFirstChild, newChild, expirationTime); } if (isObject) { @@ -10520,7 +8211,7 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) { // component, throw an error. If Fiber return types are disabled, // we already threw above. switch (returnFiber.tag) { - case ClassComponent$7: + case ClassComponent: { { var instance = returnFiber.stateNode; @@ -10533,7 +8224,7 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) { // Intentionally fall through to the next case, which handles both // functions and classes // eslint-disable-next-lined no-fallthrough - case FunctionalComponent$2: + case FunctionalComponent: { var Component = returnFiber.type; invariant_1(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'); @@ -10548,13 +8239,10 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) { return reconcileChildFibers; } -var reconcileChildFibers$1 = ChildReconciler(true, true); +var reconcileChildFibers = ChildReconciler(true); +var mountChildFibers = ChildReconciler(false); -var reconcileChildFibersInPlace$1 = ChildReconciler(false, true); - -var mountChildFibersInPlace$1 = ChildReconciler(false, false); - -var cloneChildFibers$1 = function (current, workInProgress) { +function cloneChildFibers(current, workInProgress) { !(current === null || workInProgress.child === current.child) ? invariant_1(false, 'Resuming work not yet implemented.') : void 0; if (workInProgress.child === null) { @@ -10562,613 +8250,23 @@ var cloneChildFibers$1 = function (current, workInProgress) { } var currentChild = workInProgress.child; - var newChild = createWorkInProgress$2(currentChild, currentChild.pendingWorkPriority); - // TODO: Pass this as an argument, since it's easy to forget. - newChild.pendingProps = currentChild.pendingProps; + 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$2(currentChild, currentChild.pendingWorkPriority); - newChild.pendingProps = currentChild.pendingProps; + newChild = newChild.sibling = createWorkInProgress(currentChild, currentChild.pendingProps, currentChild.expirationTime); newChild['return'] = workInProgress; } newChild.sibling = null; -}; - -var ReactChildFiber = { - reconcileChildFibers: reconcileChildFibers$1, - reconcileChildFibersInPlace: reconcileChildFibersInPlace$1, - mountChildFibersInPlace: mountChildFibersInPlace$1, - cloneChildFibers: cloneChildFibers$1 -}; - -/** - * Copyright (c) 2013-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @typechecks - * - */ - -/*eslint-disable no-self-compare */ - -var hasOwnProperty$2 = Object.prototype.hasOwnProperty; - -/** - * inlined Object.is polyfill to avoid requiring consumers ship their own - * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is - */ -function is(x, y) { - // SameValue algorithm - if (x === y) { - // Steps 1-5, 7-10 - // Steps 6.b-6.e: +0 != -0 - // Added the nonzero y check to make Flow happy, but it is redundant - return x !== 0 || y !== 0 || 1 / x === 1 / y; - } else { - // Step 6.a: NaN == NaN - return x !== x && y !== y; - } } -/** - * Performs equality by iterating through keys on an object and returning false - * when any key has values which are not strictly equal between the arguments. - * Returns true when the values of all keys are strictly equal. - */ -function shallowEqual(objA, objB) { - if (is(objA, objB)) { - return true; - } - - if (typeof objA !== 'object' || objA === null || typeof objB !== 'object' || objB === null) { - return false; - } - - var keysA = Object.keys(objA); - var keysB = Object.keys(objB); - - if (keysA.length !== keysB.length) { - return false; - } - - // Test for A's keys different from B. - for (var i = 0; i < keysA.length; i++) { - if (!hasOwnProperty$2.call(objB, keysA[i]) || !is(objA[keysA[i]], objB[keysA[i]])) { - return false; - } - } - - return true; -} - -var shallowEqual_1 = shallowEqual; - -var Update$1 = ReactTypeOfSideEffect.Update; - - - -var AsyncUpdates$1 = ReactTypeOfInternalContext.AsyncUpdates; - -var cacheContext$1 = ReactFiberContext.cacheContext; -var getMaskedContext$2 = ReactFiberContext.getMaskedContext; -var getUnmaskedContext$2 = ReactFiberContext.getUnmaskedContext; -var isContextConsumer$1 = ReactFiberContext.isContextConsumer; - -var addUpdate$1 = ReactFiberUpdateQueue.addUpdate; -var addReplaceUpdate$1 = ReactFiberUpdateQueue.addReplaceUpdate; -var addForceUpdate$1 = ReactFiberUpdateQueue.addForceUpdate; -var beginUpdateQueue$2 = ReactFiberUpdateQueue.beginUpdateQueue; - -var _require5 = ReactFiberContext; -var hasContextChanged$2 = _require5.hasContextChanged; - -var isMounted$1 = ReactFiberTreeReflection.isMounted; - - - - - - - -var fakeInternalInstance = {}; -var isArray$1 = Array.isArray; - { - var _require7$1 = ReactDebugFiberPerf_1, - startPhaseTimer$1 = _require7$1.startPhaseTimer, - stopPhaseTimer$1 = _require7$1.stopPhaseTimer; - - var warning$27 = warning_1; - var warnOnInvalidCallback = function (callback, callerName) { - warning$27(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_1(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 (scheduleUpdate, getPriorityContext, memoizeProps, memoizeState) { - // Class component state updater - var updater = { - isMounted: isMounted$1, - enqueueSetState: function (instance, partialState, callback) { - var fiber = ReactInstanceMap_1.get(instance); - var priorityLevel = getPriorityContext(fiber, false); - callback = callback === undefined ? null : callback; - { - warnOnInvalidCallback(callback, 'setState'); - } - addUpdate$1(fiber, partialState, callback, priorityLevel); - scheduleUpdate(fiber, priorityLevel); - }, - enqueueReplaceState: function (instance, state, callback) { - var fiber = ReactInstanceMap_1.get(instance); - var priorityLevel = getPriorityContext(fiber, false); - callback = callback === undefined ? null : callback; - { - warnOnInvalidCallback(callback, 'replaceState'); - } - addReplaceUpdate$1(fiber, state, callback, priorityLevel); - scheduleUpdate(fiber, priorityLevel); - }, - enqueueForceUpdate: function (instance, callback) { - var fiber = ReactInstanceMap_1.get(instance); - var priorityLevel = getPriorityContext(fiber, false); - callback = callback === undefined ? null : callback; - { - warnOnInvalidCallback(callback, 'forceUpdate'); - } - addForceUpdate$1(fiber, callback, priorityLevel); - scheduleUpdate(fiber, priorityLevel); - } - }; - - 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$1(workInProgress, 'shouldComponentUpdate'); - } - var shouldUpdate = instance.shouldComponentUpdate(newProps, newState, newContext); - { - stopPhaseTimer$1(); - } - - { - warning$27(shouldUpdate !== undefined, '%s.shouldComponentUpdate(): Returned undefined instead of a ' + 'boolean value. Make sure to return true or false.', getComponentName_1(workInProgress) || 'Unknown'); - } - - return shouldUpdate; - } - - if (type.prototype && type.prototype.isPureReactComponent) { - return !shallowEqual_1(oldProps, newProps) || !shallowEqual_1(oldState, newState); - } - - return true; - } - - function checkClassInstance(workInProgress) { - var instance = workInProgress.stateNode; - var type = workInProgress.type; - { - var name = getComponentName_1(workInProgress); - var renderPresent = instance.render; - warning$27(renderPresent, '%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$27(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$27(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$27(noInstancePropTypes, 'propTypes was defined as an instance property on %s. Use a static ' + 'property to define propTypes instead.', name); - var noInstanceContextTypes = !instance.contextTypes; - warning$27(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$27(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$27(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_1(workInProgress) || 'A pure component'); - } - var noComponentDidUnmount = typeof instance.componentDidUnmount !== 'function'; - warning$27(noComponentDidUnmount, '%s has a method called ' + 'componentDidUnmount(). But there is no such lifecycle method. ' + 'Did you mean componentWillUnmount()?', name); - var noComponentWillRecieveProps = typeof instance.componentWillRecieveProps !== 'function'; - warning$27(noComponentWillRecieveProps, '%s has a method called ' + 'componentWillRecieveProps(). Did you mean componentWillReceiveProps()?', name); - var hasMutatedProps = instance.props !== workInProgress.pendingProps; - warning$27(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$27(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$1(state))) { - invariant_1(false, '%s.state: must be set to an object or null', getComponentName_1(workInProgress)); - } - if (typeof instance.getChildContext === 'function') { - !(typeof workInProgress.type.childContextTypes === 'object') ? invariant_1(false, '%s.getChildContext(): childContextTypes must be defined in order to use getChildContext().', getComponentName_1(workInProgress)) : void 0; - } - } - - 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 - ReactInstanceMap_1.set(instance, workInProgress); - { - instance._reactInternalInstance = fakeInternalInstance; - } - } - - function constructClassInstance(workInProgress, props) { - var ctor = workInProgress.type; - var unmaskedContext = getUnmaskedContext$2(workInProgress); - var needsContext = isContextConsumer$1(workInProgress); - var context = needsContext ? getMaskedContext$2(workInProgress, unmaskedContext) : emptyObject_1; - 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$1(workInProgress, unmaskedContext, context); - } - - return instance; - } - - function callComponentWillMount(workInProgress, instance) { - { - startPhaseTimer$1(workInProgress, 'componentWillMount'); - } - var oldState = instance.state; - instance.componentWillMount(); - { - stopPhaseTimer$1(); - } - - if (oldState !== instance.state) { - { - warning$27(false, '%s.componentWillMount(): Assigning directly to this.state is ' + "deprecated (except inside a component's " + 'constructor). Use setState instead.', getComponentName_1(workInProgress)); - } - updater.enqueueReplaceState(instance, instance.state, null); - } - } - - function callComponentWillReceiveProps(workInProgress, instance, newProps, newContext) { - { - startPhaseTimer$1(workInProgress, 'componentWillReceiveProps'); - } - var oldState = instance.state; - instance.componentWillReceiveProps(newProps, newContext); - { - stopPhaseTimer$1(); - } - - if (instance.state !== oldState) { - { - warning$27(false, '%s.componentWillReceiveProps(): Assigning directly to ' + "this.state is deprecated (except inside a component's " + 'constructor). Use setState instead.', getComponentName_1(workInProgress)); - } - updater.enqueueReplaceState(instance, instance.state, null); - } - } - - // Invokes the mount life-cycles on a previously never rendered instance. - function mountClassInstance(workInProgress, priorityLevel) { - var current = workInProgress.alternate; - - { - checkClassInstance(workInProgress); - } - - var instance = workInProgress.stateNode; - var state = instance.state || null; - - var props = workInProgress.pendingProps; - !props ? invariant_1(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$2(workInProgress); - - instance.props = props; - instance.state = state; - instance.refs = emptyObject_1; - instance.context = getMaskedContext$2(workInProgress, unmaskedContext); - - if (ReactFeatureFlags_1.enableAsyncSubtreeAPI && workInProgress.type != null && workInProgress.type.prototype != null && workInProgress.type.prototype.unstable_isAsyncReactComponent === true) { - workInProgress.internalContextTag |= AsyncUpdates$1; - } - - 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 = beginUpdateQueue$2(current, workInProgress, updateQueue, instance, state, props, priorityLevel); - } - } - if (typeof instance.componentDidMount === 'function') { - workInProgress.effectTag |= Update$1; - } - } - - // 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 = beginUpdateQueue( - // 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 = beginUpdateQueue( - // 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, priorityLevel) { - 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_1(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$2(workInProgress); - var newContext = getMaskedContext$2(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 = beginUpdateQueue$2(current, workInProgress, workInProgress.updateQueue, instance, oldState, newProps, priorityLevel); - } else { - newState = oldState; - } - - if (oldProps === newProps && oldState === newState && !hasContextChanged$2() && !(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$1; - } - } - return false; - } - - var shouldUpdate = checkShouldComponentUpdate(workInProgress, oldProps, newProps, oldState, newState, newContext); - - if (shouldUpdate) { - if (typeof instance.componentWillUpdate === 'function') { - { - startPhaseTimer$1(workInProgress, 'componentWillUpdate'); - } - instance.componentWillUpdate(newProps, newState, newContext); - { - stopPhaseTimer$1(); - } - } - if (typeof instance.componentDidUpdate === 'function') { - workInProgress.effectTag |= Update$1; - } - } 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$1; - } - } - - // 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 - }; -}; - -var mountChildFibersInPlace = ReactChildFiber.mountChildFibersInPlace; -var reconcileChildFibers = ReactChildFiber.reconcileChildFibers; -var reconcileChildFibersInPlace = ReactChildFiber.reconcileChildFibersInPlace; -var cloneChildFibers = ReactChildFiber.cloneChildFibers; - -var beginUpdateQueue$1 = ReactFiberUpdateQueue.beginUpdateQueue; - - - -var getMaskedContext$1 = ReactFiberContext.getMaskedContext; -var getUnmaskedContext$1 = ReactFiberContext.getUnmaskedContext; -var hasContextChanged$1 = ReactFiberContext.hasContextChanged; -var pushContextProvider$1 = ReactFiberContext.pushContextProvider; -var pushTopLevelContextObject$1 = ReactFiberContext.pushTopLevelContextObject; -var invalidateContextProvider$1 = ReactFiberContext.invalidateContextProvider; - -var IndeterminateComponent$2 = ReactTypeOfWork.IndeterminateComponent; -var FunctionalComponent$1 = ReactTypeOfWork.FunctionalComponent; -var ClassComponent$6 = ReactTypeOfWork.ClassComponent; -var HostRoot$7 = ReactTypeOfWork.HostRoot; -var HostComponent$7 = ReactTypeOfWork.HostComponent; -var HostText$4 = ReactTypeOfWork.HostText; -var HostPortal$4 = ReactTypeOfWork.HostPortal; -var CoroutineComponent$1 = ReactTypeOfWork.CoroutineComponent; -var CoroutineHandlerPhase = ReactTypeOfWork.CoroutineHandlerPhase; -var YieldComponent$2 = ReactTypeOfWork.YieldComponent; -var Fragment$2 = ReactTypeOfWork.Fragment; - -var NoWork$3 = ReactPriorityLevel.NoWork; -var OffscreenPriority$1 = ReactPriorityLevel.OffscreenPriority; - -var PerformedWork$1 = ReactTypeOfSideEffect.PerformedWork; -var Placement$2 = ReactTypeOfSideEffect.Placement; -var ContentReset$1 = ReactTypeOfSideEffect.ContentReset; -var Err$1 = ReactTypeOfSideEffect.Err; -var Ref$1 = ReactTypeOfSideEffect.Ref; - - - -var ReactCurrentOwner$2 = ReactGlobalSharedState_1.ReactCurrentOwner; - - - -{ - var ReactDebugCurrentFiber$4 = ReactDebugCurrentFiber_1; - - var _require7 = ReactDebugFiberPerf_1, - cancelWorkTimer = _require7.cancelWorkTimer; - - var warning$25 = warning_1; - var warnedAboutStatelessRefs = {}; } -var ReactFiberBeginWork = function (config, hostContext, hydrationContext, scheduleUpdate, getPriorityContext) { +var ReactFiberBeginWork = function (config, hostContext, hydrationContext, scheduleWork, computeExpirationForFiber) { var shouldSetTextContent = config.shouldSetTextContent, useSyncScheduling = config.useSyncScheduling, shouldDeprioritizeSubtree = config.shouldDeprioritizeSubtree; @@ -11178,43 +8276,40 @@ var ReactFiberBeginWork = function (config, hostContext, hydrationContext, sched resetHydrationState = hydrationContext.resetHydrationState, tryToClaimNextHydratableInstance = hydrationContext.tryToClaimNextHydratableInstance; - var _ReactFiberClassCompo = ReactFiberClassComponent(scheduleUpdate, getPriorityContext, memoizeProps, memoizeState), + 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) { - var priorityLevel = workInProgress.pendingWorkPriority; - reconcileChildrenAtPriority(current, workInProgress, nextChildren, priorityLevel); + reconcileChildrenAtExpirationTime(current, workInProgress, nextChildren, workInProgress.expirationTime); } - function reconcileChildrenAtPriority(current, workInProgress, nextChildren, priorityLevel) { + 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 = mountChildFibersInPlace(workInProgress, workInProgress.child, nextChildren, priorityLevel); - } else if (current.child === workInProgress.child) { + 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, workInProgress.child, nextChildren, priorityLevel); - } else { - // If, on the other hand, it is already using a clone, that means we've - // already begun some work on this tree and we can continue where we left - // off by reconciling against the existing children. - workInProgress.child = reconcileChildFibersInPlace(workInProgress, workInProgress.child, nextChildren, priorityLevel); + workInProgress.child = reconcileChildFibers(workInProgress, current.child, nextChildren, renderExpirationTime); } } function updateFragment(current, workInProgress) { var nextChildren = workInProgress.pendingProps; - if (hasContextChanged$1()) { + 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) { @@ -11232,7 +8327,7 @@ var ReactFiberBeginWork = function (config, hostContext, hydrationContext, sched var ref = workInProgress.ref; if (ref !== null && (!current || current.ref !== ref)) { // Schedule a Ref effect - workInProgress.effectTag |= Ref$1; + workInProgress.effectTag |= Ref; } } @@ -11241,7 +8336,7 @@ var ReactFiberBeginWork = function (config, hostContext, hydrationContext, sched var nextProps = workInProgress.pendingProps; var memoizedProps = workInProgress.memoizedProps; - if (hasContextChanged$1()) { + 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) { @@ -11255,44 +8350,44 @@ var ReactFiberBeginWork = function (config, hostContext, hydrationContext, sched // It used to be here. } - var unmaskedContext = getUnmaskedContext$1(workInProgress); - var context = getMaskedContext$1(workInProgress, unmaskedContext); + var unmaskedContext = getUnmaskedContext(workInProgress); + var context = getMaskedContext(workInProgress, unmaskedContext); var nextChildren; { - ReactCurrentOwner$2.current = workInProgress; - ReactDebugCurrentFiber$4.setCurrentFiber(workInProgress, 'render'); + ReactCurrentOwner.current = workInProgress; + ReactDebugCurrentFiber.setCurrentPhase('render'); nextChildren = fn(nextProps, context); - ReactDebugCurrentFiber$4.setCurrentFiber(workInProgress, null); + ReactDebugCurrentFiber.setCurrentPhase(null); } // React DevTools reads this flag. - workInProgress.effectTag |= PerformedWork$1; + workInProgress.effectTag |= PerformedWork; reconcileChildren(current, workInProgress, nextChildren); memoizeProps(workInProgress, nextProps); return workInProgress.child; } - function updateClassComponent(current, workInProgress, priorityLevel) { + 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$1(workInProgress); + 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, priorityLevel); + mountClassInstance(workInProgress, renderExpirationTime); shouldUpdate = true; } else { invariant_1(false, 'Resuming work not yet implemented.'); // In a resume, we'll already have an instance we can reuse. - // shouldUpdate = resumeMountClassInstance(workInProgress, priorityLevel); + // shouldUpdate = resumeMountClassInstance(workInProgress, renderExpirationTime); } } else { - shouldUpdate = updateClassInstance(current, workInProgress, priorityLevel); + shouldUpdate = updateClassInstance(current, workInProgress, renderExpirationTime); } return finishClassComponent(current, workInProgress, shouldUpdate, hasContext); } @@ -11304,7 +8399,7 @@ var ReactFiberBeginWork = function (config, hostContext, hydrationContext, sched if (!shouldUpdate) { // Context providers should defer to sCU for rendering if (hasContext) { - invalidateContextProvider$1(workInProgress, false); + invalidateContextProvider(workInProgress, false); } return bailoutOnAlreadyFinishedWork(current, workInProgress); @@ -11313,15 +8408,18 @@ var ReactFiberBeginWork = function (config, hostContext, hydrationContext, sched var instance = workInProgress.stateNode; // Rerender - ReactCurrentOwner$2.current = workInProgress; + ReactCurrentOwner.current = workInProgress; var nextChildren = void 0; { - ReactDebugCurrentFiber$4.setCurrentFiber(workInProgress, 'render'); + ReactDebugCurrentFiber.setCurrentPhase('render'); nextChildren = instance.render(); - ReactDebugCurrentFiber$4.setCurrentFiber(workInProgress, null); + if (debugRenderPhaseSideEffects) { + instance.render(); + } + ReactDebugCurrentFiber.setCurrentPhase(null); } // React DevTools reads this flag. - workInProgress.effectTag |= PerformedWork$1; + 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. @@ -11330,7 +8428,7 @@ var ReactFiberBeginWork = function (config, hostContext, hydrationContext, sched // The context might have changed so we need to recalculate it. if (hasContext) { - invalidateContextProvider$1(workInProgress, true); + invalidateContextProvider(workInProgress, true); } return workInProgress.child; @@ -11339,28 +8437,29 @@ var ReactFiberBeginWork = function (config, hostContext, hydrationContext, sched function pushHostRootContext(workInProgress) { var root = workInProgress.stateNode; if (root.pendingContext) { - pushTopLevelContextObject$1(workInProgress, root.pendingContext, root.pendingContext !== root.context); + pushTopLevelContextObject(workInProgress, root.pendingContext, root.pendingContext !== root.context); } else if (root.context) { // Should always be set - pushTopLevelContextObject$1(workInProgress, root.context, false); + pushTopLevelContextObject(workInProgress, root.context, false); } pushHostContainer(workInProgress, root.containerInfo); } - function updateHostRoot(current, workInProgress, priorityLevel) { + function updateHostRoot(current, workInProgress, renderExpirationTime) { pushHostRootContext(workInProgress); var updateQueue = workInProgress.updateQueue; if (updateQueue !== null) { var prevState = workInProgress.memoizedState; - var state = beginUpdateQueue$1(current, workInProgress, updateQueue, null, prevState, null, priorityLevel); + 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 matching this priority. + // no work that expires at this time. resetHydrationState(); return bailoutOnAlreadyFinishedWork(current, workInProgress); } var element = state.element; - if ((current === null || current.child === null) && enterHydrationState(workInProgress)) { + 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 @@ -11370,12 +8469,12 @@ var ReactFiberBeginWork = function (config, hostContext, hydrationContext, sched // 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$2; + 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 = mountChildFibersInPlace(workInProgress, workInProgress.child, element, priorityLevel); + workInProgress.child = mountChildFibers(workInProgress, null, element, renderExpirationTime); } else { // Otherwise reset hydration state in case we aborted and resumed another // root. @@ -11390,7 +8489,7 @@ var ReactFiberBeginWork = function (config, hostContext, hydrationContext, sched return bailoutOnAlreadyFinishedWork(current, workInProgress); } - function updateHostComponent(current, workInProgress, renderPriority) { + function updateHostComponent(current, workInProgress, renderExpirationTime) { pushHostContext(workInProgress); if (current === null) { @@ -11406,7 +8505,7 @@ var ReactFiberBeginWork = function (config, hostContext, hydrationContext, sched } var prevProps = current !== null ? current.memoizedProps : null; - if (hasContextChanged$1()) { + 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) { @@ -11425,16 +8524,16 @@ var ReactFiberBeginWork = function (config, hostContext, hydrationContext, sched } 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$1; + workInProgress.effectTag |= ContentReset; } markRef(current, workInProgress); // Check the host config to see if the children are offscreen/hidden. - if (renderPriority !== OffscreenPriority$1 && !useSyncScheduling && shouldDeprioritizeSubtree(type, nextProps)) { + if (renderExpirationTime !== Never && !useSyncScheduling && shouldDeprioritizeSubtree(type, nextProps)) { // Down-prioritize the children. - workInProgress.pendingWorkPriority = OffscreenPriority$1; - // Bailout and come back to this fiber later at OffscreenPriority. + workInProgress.expirationTime = Never; + // Bailout and come back to this fiber later. return null; } @@ -11457,45 +8556,49 @@ var ReactFiberBeginWork = function (config, hostContext, hydrationContext, sched return null; } - function mountIndeterminateComponent(current, workInProgress, priorityLevel) { + function mountIndeterminateComponent(current, workInProgress, renderExpirationTime) { !(current === null) ? invariant_1(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$1(workInProgress); - var context = getMaskedContext$1(workInProgress, unmaskedContext); + var unmaskedContext = getUnmaskedContext(workInProgress); + var context = getMaskedContext(workInProgress, unmaskedContext); var value; { - ReactCurrentOwner$2.current = workInProgress; + if (fn.prototype && typeof fn.prototype.render === 'function') { + var componentName = getComponentName(workInProgress); + warning_1(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$1; + 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$6; + 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$1(workInProgress); + var hasContext = pushContextProvider(workInProgress); adoptClassInstance(workInProgress, value); - mountClassInstance(workInProgress, priorityLevel); + mountClassInstance(workInProgress, renderExpirationTime); return finishClassComponent(current, workInProgress, true, hasContext); } else { // Proceed under the assumption that this is a functional component - workInProgress.tag = FunctionalComponent$1; + workInProgress.tag = FunctionalComponent; { var Component = workInProgress.type; if (Component) { - warning$25(!Component.childContextTypes, '%s(...): childContextTypes cannot be defined on a functional component.', Component.displayName || Component.name || 'Component'); + warning_1(!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$4.getCurrentFiberOwnerName(); + var ownerName = ReactDebugCurrentFiber.getCurrentFiberOwnerName(); if (ownerName) { info += '\n\nCheck the render method of `' + ownerName + '`.'; } @@ -11507,7 +8610,7 @@ var ReactFiberBeginWork = function (config, hostContext, hydrationContext, sched } if (!warnedAboutStatelessRefs[warningKey]) { warnedAboutStatelessRefs[warningKey] = true; - warning$25(false, 'Stateless function components cannot be given refs. ' + 'Attempts to access this ref will fail.%s%s', info, ReactDebugCurrentFiber$4.getCurrentFiberStackAddendum()); + warning_1(false, 'Stateless function components cannot be given refs. ' + 'Attempts to access this ref will fail.%s%s', info, ReactDebugCurrentFiber.getCurrentFiberStackAddendum()); } } } @@ -11517,46 +8620,42 @@ var ReactFiberBeginWork = function (config, hostContext, hydrationContext, sched } } - function updateCoroutineComponent(current, workInProgress) { - var nextCoroutine = workInProgress.pendingProps; - if (hasContextChanged$1()) { + 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 (nextCoroutine === null) { - nextCoroutine = current && current.memoizedProps; - !(nextCoroutine !== null) ? invariant_1(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; + if (nextCall === null) { + nextCall = current && current.memoizedProps; + !(nextCall !== null) ? invariant_1(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 (nextCoroutine === null || workInProgress.memoizedProps === nextCoroutine) { - nextCoroutine = workInProgress.memoizedProps; + } 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 = nextCoroutine.children; - var priorityLevel = workInProgress.pendingWorkPriority; + var nextChildren = nextCall.children; - // The following is a fork of reconcileChildrenAtPriority but using + // The following is a fork of reconcileChildrenAtExpirationTime but using // stateNode to store the child. if (current === null) { - workInProgress.stateNode = mountChildFibersInPlace(workInProgress, workInProgress.stateNode, nextChildren, priorityLevel); - } else if (current.child === workInProgress.child) { - workInProgress.stateNode = reconcileChildFibers(workInProgress, workInProgress.stateNode, nextChildren, priorityLevel); + workInProgress.stateNode = mountChildFibers(workInProgress, workInProgress.stateNode, nextChildren, renderExpirationTime); } else { - workInProgress.stateNode = reconcileChildFibersInPlace(workInProgress, workInProgress.stateNode, nextChildren, priorityLevel); + workInProgress.stateNode = reconcileChildFibers(workInProgress, workInProgress.stateNode, nextChildren, renderExpirationTime); } - memoizeProps(workInProgress, nextCoroutine); + 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) { + function updatePortalComponent(current, workInProgress, renderExpirationTime) { pushHostContainer(workInProgress, workInProgress.stateNode.containerInfo); - var priorityLevel = workInProgress.pendingWorkPriority; var nextChildren = workInProgress.pendingProps; - if (hasContextChanged$1()) { + 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) { @@ -11573,7 +8672,7 @@ var ReactFiberBeginWork = function (config, hostContext, hydrationContext, sched // 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 = reconcileChildFibersInPlace(workInProgress, workInProgress.child, nextChildren, priorityLevel); + workInProgress.child = reconcileChildFibers(workInProgress, null, nextChildren, renderExpirationTime); memoizeProps(workInProgress, nextChildren); } else { reconcileChildren(current, workInProgress, nextChildren); @@ -11602,9 +8701,7 @@ var ReactFiberBeginWork = function (config, hostContext, hydrationContext, sched */ function bailoutOnAlreadyFinishedWork(current, workInProgress) { - { - cancelWorkTimer(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 @@ -11625,20 +8722,18 @@ var ReactFiberBeginWork = function (config, hostContext, hydrationContext, sched } function bailoutOnLowPriority(current, workInProgress) { - { - cancelWorkTimer(workInProgress); - } + cancelWorkTimer(workInProgress); // TODO: Handle HostComponent tags here as well and call pushHostContext()? // See PR 8590 discussion for context switch (workInProgress.tag) { - case HostRoot$7: + case HostRoot: pushHostRootContext(workInProgress); break; - case ClassComponent$6: - pushContextProvider$1(workInProgress); + case ClassComponent: + pushContextProvider(workInProgress); break; - case HostPortal$4: + case HostPortal: pushHostContainer(workInProgress, workInProgress.stateNode.containerInfo); break; } @@ -11655,57 +8750,53 @@ var ReactFiberBeginWork = function (config, hostContext, hydrationContext, sched function memoizeState(workInProgress, nextState) { workInProgress.memoizedState = nextState; // Don't reset the updateQueue, in case there are pending updates. Resetting - // is handled by beginUpdateQueue. + // is handled by processUpdateQueue. } - function beginWork(current, workInProgress, priorityLevel) { - if (workInProgress.pendingWorkPriority === NoWork$3 || workInProgress.pendingWorkPriority > priorityLevel) { + function beginWork(current, workInProgress, renderExpirationTime) { + if (workInProgress.expirationTime === NoWork || workInProgress.expirationTime > renderExpirationTime) { return bailoutOnLowPriority(current, workInProgress); } - { - ReactDebugCurrentFiber$4.setCurrentFiber(workInProgress, null); - } - switch (workInProgress.tag) { - case IndeterminateComponent$2: - return mountIndeterminateComponent(current, workInProgress, priorityLevel); - case FunctionalComponent$1: + case IndeterminateComponent: + return mountIndeterminateComponent(current, workInProgress, renderExpirationTime); + case FunctionalComponent: return updateFunctionalComponent(current, workInProgress); - case ClassComponent$6: - return updateClassComponent(current, workInProgress, priorityLevel); - case HostRoot$7: - return updateHostRoot(current, workInProgress, priorityLevel); - case HostComponent$7: - return updateHostComponent(current, workInProgress, priorityLevel); - case HostText$4: + 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 CoroutineHandlerPhase: + case CallHandlerPhase: // This is a restart. Reset the tag to the initial phase. - workInProgress.tag = CoroutineComponent$1; + workInProgress.tag = CallComponent; // Intentionally fall through since this is now the same. - case CoroutineComponent$1: - return updateCoroutineComponent(current, workInProgress); - case YieldComponent$2: - // A yield component is just a placeholder, we can just run through the + 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$4: - return updatePortalComponent(current, workInProgress); - case Fragment$2: + case HostPortal: + return updatePortalComponent(current, workInProgress, renderExpirationTime); + case Fragment: return updateFragment(current, workInProgress); default: invariant_1(false, 'Unknown unit of work tag. This error is likely caused by a bug in React. Please file an issue.'); } } - function beginFailedWork(current, workInProgress, priorityLevel) { + function beginFailedWork(current, workInProgress, renderExpirationTime) { // Push context providers here to avoid a push/pop context mismatch. switch (workInProgress.tag) { - case ClassComponent$6: - pushContextProvider$1(workInProgress); + case ClassComponent: + pushContextProvider(workInProgress); break; - case HostRoot$7: + case HostRoot: pushHostRootContext(workInProgress); break; default: @@ -11713,7 +8804,7 @@ var ReactFiberBeginWork = function (config, hostContext, hydrationContext, sched } // Add an error effect so we can handle the error during the commit phase - workInProgress.effectTag |= Err$1; + 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 @@ -11726,7 +8817,7 @@ var ReactFiberBeginWork = function (config, hostContext, hydrationContext, sched workInProgress.child = current.child; } - if (workInProgress.pendingWorkPriority === NoWork$3 || workInProgress.pendingWorkPriority > priorityLevel) { + if (workInProgress.expirationTime === NoWork || workInProgress.expirationTime > renderExpirationTime) { return bailoutOnLowPriority(current, workInProgress); } @@ -11737,9 +8828,9 @@ var ReactFiberBeginWork = function (config, hostContext, hydrationContext, sched // Unmount the current children as if the component rendered null var nextChildren = null; - reconcileChildrenAtPriority(current, workInProgress, nextChildren, priorityLevel); + reconcileChildrenAtExpirationTime(current, workInProgress, nextChildren, renderExpirationTime); - if (workInProgress.tag === ClassComponent$6) { + if (workInProgress.tag === ClassComponent) { var instance = workInProgress.stateNode; workInProgress.memoizedProps = instance.props; workInProgress.memoizedState = instance.state; @@ -11754,43 +8845,14 @@ var ReactFiberBeginWork = function (config, hostContext, hydrationContext, sched }; }; -var reconcileChildFibers$2 = ReactChildFiber.reconcileChildFibers; - -var popContextProvider$2 = ReactFiberContext.popContextProvider; -var popTopLevelContextObject$1 = ReactFiberContext.popTopLevelContextObject; - - - - -var IndeterminateComponent$3 = ReactTypeOfWork.IndeterminateComponent; -var FunctionalComponent$3 = ReactTypeOfWork.FunctionalComponent; -var ClassComponent$8 = ReactTypeOfWork.ClassComponent; -var HostRoot$8 = ReactTypeOfWork.HostRoot; -var HostComponent$8 = ReactTypeOfWork.HostComponent; -var HostText$6 = ReactTypeOfWork.HostText; -var HostPortal$6 = ReactTypeOfWork.HostPortal; -var CoroutineComponent$3 = ReactTypeOfWork.CoroutineComponent; -var CoroutineHandlerPhase$1 = ReactTypeOfWork.CoroutineHandlerPhase; -var YieldComponent$4 = ReactTypeOfWork.YieldComponent; -var Fragment$4 = ReactTypeOfWork.Fragment; -var Placement$4 = ReactTypeOfSideEffect.Placement; -var Ref$2 = ReactTypeOfSideEffect.Ref; -var Update$2 = ReactTypeOfSideEffect.Update; -var OffscreenPriority$2 = ReactPriorityLevel.OffscreenPriority; - - -{ - var ReactDebugCurrentFiber$5 = ReactDebugCurrentFiber_1; -} - - - var ReactFiberCompleteWork = function (config, hostContext, hydrationContext) { var createInstance = config.createInstance, createTextInstance = config.createTextInstance, appendInitialChild = config.appendInitialChild, finalizeInitialChildren = config.finalizeInitialChildren, - prepareUpdate = config.prepareUpdate; + prepareUpdate = config.prepareUpdate, + mutation = config.mutation, + persistence = config.persistence; var getRootHostContainer = hostContext.getRootHostContainer, popHostContext = hostContext.popHostContext, getHostContext = hostContext.getHostContext, @@ -11803,23 +8865,23 @@ var ReactFiberCompleteWork = function (config, hostContext, hydrationContext) { function markUpdate(workInProgress) { // Tag the fiber with an update effect. This turns a Placement into // an UpdateAndPlacement. - workInProgress.effectTag |= Update$2; + workInProgress.effectTag |= Update; } function markRef(workInProgress) { - workInProgress.effectTag |= Ref$2; + workInProgress.effectTag |= Ref; } - function appendAllYields(yields, workInProgress) { + function appendAllReturns(returns, workInProgress) { var node = workInProgress.stateNode; if (node) { node['return'] = workInProgress; } while (node !== null) { - if (node.tag === HostComponent$8 || node.tag === HostText$6 || node.tag === HostPortal$6) { - invariant_1(false, 'A coroutine cannot have host component children.'); - } else if (node.tag === YieldComponent$4) { - yields.push(node.type); + if (node.tag === HostComponent || node.tag === HostText || node.tag === HostPortal) { + invariant_1(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; @@ -11836,31 +8898,29 @@ var ReactFiberCompleteWork = function (config, hostContext, hydrationContext) { } } - function moveCoroutineToHandlerPhase(current, workInProgress) { - var coroutine = workInProgress.memoizedProps; - !coroutine ? invariant_1(false, 'Should be resolved by now. This error is likely caused by a bug in React. Please file an issue.') : void 0; + function moveCallToHandlerPhase(current, workInProgress, renderExpirationTime) { + var call = workInProgress.memoizedProps; + !call ? invariant_1(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 coroutine has completed. Now we need to do the second. - // TODO: It would be nice to have a multi stage coroutine represented by a + // 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 = CoroutineHandlerPhase$1; + workInProgress.tag = CallHandlerPhase; - // Build up the yields. + // Build up the returns. // TODO: Compare this to a generator or opaque helpers like Children. - var yields = []; - appendAllYields(yields, workInProgress); - var fn = coroutine.handler; - var props = coroutine.props; - var nextChildren = fn(props, yields); + 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; - // Inherit the priority of the returnFiber. - var priority = workInProgress.pendingWorkPriority; - workInProgress.child = reconcileChildFibers$2(workInProgress, currentFirstChild, nextChildren, priority); + workInProgress.child = reconcileChildFibers(workInProgress, currentFirstChild, nextChildren, renderExpirationTime); return workInProgress.child; } @@ -11869,13 +8929,14 @@ var ReactFiberCompleteWork = function (config, hostContext, hydrationContext) { // children to find all the terminal nodes. var node = workInProgress.child; while (node !== null) { - if (node.tag === HostComponent$8 || node.tag === HostText$6) { + if (node.tag === HostComponent || node.tag === HostText) { appendInitialChild(parent, node.stateNode); - } else if (node.tag === HostPortal$6) { + } 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; } @@ -11888,37 +8949,176 @@ var ReactFiberCompleteWork = function (config, hostContext, hydrationContext) { } node = node['return']; } + node.sibling['return'] = node['return']; node = node.sibling; } } - function completeWork(current, workInProgress, renderPriority) { - { - ReactDebugCurrentFiber$5.setCurrentFiber(workInProgress, null); + 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_1(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_1(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_1(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.pendingWorkPriority !== OffscreenPriority$2 || renderPriority === OffscreenPriority$2) { + } 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$3: + case FunctionalComponent: return null; - case ClassComponent$8: + case ClassComponent: { // We are leaving this subtree, so pop context if any. - popContextProvider$2(workInProgress); + popContextProvider(workInProgress); return null; } - case HostRoot$8: + case HostRoot: { popHostContainer(workInProgress); - popTopLevelContextObject$1(workInProgress); + popTopLevelContextObject(workInProgress); var fiberRoot = workInProgress.stateNode; if (fiberRoot.pendingContext) { fiberRoot.context = fiberRoot.pendingContext; @@ -11931,11 +9131,12 @@ var ReactFiberCompleteWork = function (config, hostContext, hydrationContext) { popHydrationState(workInProgress); // This resets the hacky state to fix isMounted before committing. // TODO: Delete this when we delete isMounted and findDOMNode. - workInProgress.effectTag &= ~Placement$4; + workInProgress.effectTag &= ~Placement; } + updateHostContainer(workInProgress); return null; } - case HostComponent$8: + case HostComponent: { popHostContext(workInProgress); var rootContainerInstance = getRootHostContainer(); @@ -11952,13 +9153,8 @@ var ReactFiberCompleteWork = function (config, hostContext, hydrationContext) { var currentHostContext = getHostContext(); var updatePayload = prepareUpdate(instance, type, oldProps, newProps, rootContainerInstance, currentHostContext); - // 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. - if (updatePayload) { - markUpdate(workInProgress); - } + updateHostComponent(current, workInProgress, updatePayload, type, oldProps, newProps, rootContainerInstance); + if (current.ref !== workInProgress.ref) { markRef(workInProgress); } @@ -11976,7 +9172,7 @@ var ReactFiberCompleteWork = function (config, hostContext, hydrationContext) { // bottom->up. Top->down is faster in IE11. var wasHydrated = popHydrationState(workInProgress); if (wasHydrated) { - // TOOD: Move this and createInstance step into the beginPhase + // 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 @@ -12004,16 +9200,14 @@ var ReactFiberCompleteWork = function (config, hostContext, hydrationContext) { } return null; } - case HostText$6: + 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. - if (oldText !== newText) { - markUpdate(workInProgress); - } + updateHostText(current, workInProgress, oldText, newText); } else { if (typeof newText !== 'string') { !(workInProgress.stateNode !== null) ? invariant_1(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; @@ -12033,24 +9227,23 @@ var ReactFiberCompleteWork = function (config, hostContext, hydrationContext) { } return null; } - case CoroutineComponent$3: - return moveCoroutineToHandlerPhase(current, workInProgress); - case CoroutineHandlerPhase$1: - // Reset the tag to now be a first phase coroutine. - workInProgress.tag = CoroutineComponent$3; + 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 YieldComponent$4: + case ReturnComponent: // Does nothing. return null; - case Fragment$4: + case Fragment: return null; - case HostPortal$6: - // TODO: Only mark this as an update if we have any pending callbacks. - markUpdate(workInProgress); + case HostPortal: popHostContainer(workInProgress); + updateHostContainer(workInProgress); return null; // Error cases - case IndeterminateComponent$3: + case IndeterminateComponent: invariant_1(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: @@ -12063,137 +9256,29 @@ var ReactFiberCompleteWork = function (config, hostContext, hydrationContext) { }; }; -{ - var warning$28 = warning_1; -} - -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$28(false, 'React DevTools encountered an error: %s', err); - } - } - }; -} - -function injectInternals$1(internals) { - if (typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ === 'undefined') { - // No DevTools - return false; - } - var hook = __REACT_DEVTOOLS_GLOBAL_HOOK__; - if (!hook.supportsFiber) { - { - warning$28(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$28(false, 'React DevTools encountered an error: %s.', err); - } - } - // DevTools exists - return true; -} - -function onCommitRoot$1(root) { - if (typeof onCommitFiberRoot === 'function') { - onCommitFiberRoot(root); - } -} - -function onCommitUnmount$1(fiber) { - if (typeof onCommitFiberUnmount === 'function') { - onCommitFiberUnmount(fiber); - } -} - -var injectInternals_1 = injectInternals$1; -var onCommitRoot_1 = onCommitRoot$1; -var onCommitUnmount_1 = onCommitUnmount$1; - -var ReactFiberDevToolsHook = { - injectInternals: injectInternals_1, - onCommitRoot: onCommitRoot_1, - onCommitUnmount: onCommitUnmount_1 -}; - -var ClassComponent$9 = ReactTypeOfWork.ClassComponent; -var HostRoot$9 = ReactTypeOfWork.HostRoot; -var HostComponent$9 = ReactTypeOfWork.HostComponent; -var HostText$7 = ReactTypeOfWork.HostText; -var HostPortal$7 = ReactTypeOfWork.HostPortal; -var CoroutineComponent$4 = ReactTypeOfWork.CoroutineComponent; +var invokeGuardedCallback$2 = ReactErrorUtils.invokeGuardedCallback; +var hasCaughtError$1 = ReactErrorUtils.hasCaughtError; +var clearCaughtError$1 = ReactErrorUtils.clearCaughtError; -var commitCallbacks$1 = ReactFiberUpdateQueue.commitCallbacks; - -var onCommitUnmount = ReactFiberDevToolsHook.onCommitUnmount; - -var invokeGuardedCallback$2 = ReactErrorUtils_1.invokeGuardedCallback; -var hasCaughtError$1 = ReactErrorUtils_1.hasCaughtError; -var clearCaughtError$1 = ReactErrorUtils_1.clearCaughtError; - -var Placement$5 = ReactTypeOfSideEffect.Placement; -var Update$3 = ReactTypeOfSideEffect.Update; -var Callback$1 = ReactTypeOfSideEffect.Callback; -var ContentReset$2 = ReactTypeOfSideEffect.ContentReset; - - - -{ - var _require5$1 = ReactDebugFiberPerf_1, - startPhaseTimer$2 = _require5$1.startPhaseTimer, - stopPhaseTimer$2 = _require5$1.stopPhaseTimer; -} var ReactFiberCommitWork = function (config, captureError) { - var commitMount = config.commitMount, - commitUpdate = config.commitUpdate, - resetTextContent = config.resetTextContent, - commitTextUpdate = config.commitTextUpdate, - appendChild = config.appendChild, - appendChildToContainer = config.appendChildToContainer, - insertBefore = config.insertBefore, - insertInContainerBefore = config.insertInContainerBefore, - removeChild = config.removeChild, - removeChildFromContainer = config.removeChildFromContainer, - getPublicInstance = config.getPublicInstance; + var getPublicInstance = config.getPublicInstance, + mutation = config.mutation, + persistence = config.persistence; - { - var callComponentWillUnmountWithTimerInDev = function (current, instance) { - startPhaseTimer$2(current, 'componentWillUnmount'); - instance.props = current.memoizedProps; - instance.state = current.memoizedState; - instance.componentWillUnmount(); - stopPhaseTimer$2(); - }; - } + 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, callComponentWillUnmountWithTimerInDev, null, current, instance); + invokeGuardedCallback$2(null, callComponentWillUnmountWithTimer, null, current, instance); if (hasCaughtError$1()) { var unmountError = clearCaughtError$1(); captureError(current, unmountError); @@ -12214,6 +9299,269 @@ var ReactFiberCommitWork = function (config, captureError) { } } + 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_1(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_1(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_1(false, 'Persistent reconciler is disabled.'); + } else { + invariant_1(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) { @@ -12226,7 +9574,7 @@ var ReactFiberCommitWork = function (config, captureError) { } function isHostParent(fiber) { - return fiber.tag === HostComponent$9 || fiber.tag === HostRoot$9 || fiber.tag === HostPortal$7; + return fiber.tag === HostComponent || fiber.tag === HostRoot || fiber.tag === HostPortal; } function getHostSibling(fiber) { @@ -12246,16 +9594,16 @@ var ReactFiberCommitWork = function (config, captureError) { } node.sibling['return'] = node['return']; node = node.sibling; - while (node.tag !== HostComponent$9 && node.tag !== HostText$7) { + 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$5) { + 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$7) { + if (node.child === null || node.tag === HostPortal) { continue siblings; } else { node.child['return'] = node; @@ -12263,7 +9611,7 @@ var ReactFiberCommitWork = function (config, captureError) { } } // Check if this host node is stable or about to be placed. - if (!(node.effectTag & Placement$5)) { + if (!(node.effectTag & Placement)) { // Found it! return node.stateNode; } @@ -12276,26 +9624,26 @@ var ReactFiberCommitWork = function (config, captureError) { var parent = void 0; var isContainer = void 0; switch (parentFiber.tag) { - case HostComponent$9: + case HostComponent: parent = parentFiber.stateNode; isContainer = false; break; - case HostRoot$9: + case HostRoot: parent = parentFiber.stateNode.containerInfo; isContainer = true; break; - case HostPortal$7: + case HostPortal: parent = parentFiber.stateNode.containerInfo; isContainer = true; break; default: invariant_1(false, 'Invalid host parent fiber. This error is likely caused by a bug in React. Please file an issue.'); } - if (parentFiber.effectTag & ContentReset$2) { + 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$2; + parentFiber.effectTag &= ~ContentReset; } var before = getHostSibling(finishedWork); @@ -12303,7 +9651,7 @@ var ReactFiberCommitWork = function (config, captureError) { // children to find all the terminal nodes. var node = finishedWork; while (true) { - if (node.tag === HostComponent$9 || node.tag === HostText$7) { + if (node.tag === HostComponent || node.tag === HostText) { if (before) { if (isContainer) { insertInContainerBefore(parent, node.stateNode, before); @@ -12317,7 +9665,7 @@ var ReactFiberCommitWork = function (config, captureError) { appendChild(parent, node.stateNode); } } - } else if (node.tag === HostPortal$7) { + } 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. @@ -12340,35 +9688,6 @@ var ReactFiberCommitWork = function (config, captureError) { } } - 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 && node.tag !== HostPortal$7) { - 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 unmountHostComponents(current) { // We only have the top Fiber that was inserted but we need recurse down its var node = current; @@ -12385,15 +9704,15 @@ var ReactFiberCommitWork = function (config, captureError) { findParent: while (true) { !(parent !== null) ? invariant_1(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$9: + case HostComponent: currentParent = parent.stateNode; currentParentIsContainer = false; break findParent; - case HostRoot$9: + case HostRoot: currentParent = parent.stateNode.containerInfo; currentParentIsContainer = true; break findParent; - case HostPortal$7: + case HostPortal: currentParent = parent.stateNode.containerInfo; currentParentIsContainer = true; break findParent; @@ -12403,7 +9722,7 @@ var ReactFiberCommitWork = function (config, captureError) { currentParentIsValid = true; } - if (node.tag === HostComponent$9 || node.tag === HostText$7) { + 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. @@ -12413,7 +9732,7 @@ var ReactFiberCommitWork = function (config, captureError) { removeChild(currentParent, node.stateNode); } // Don't visit children because we already visited them. - } else if (node.tag === HostPortal$7) { + } 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; @@ -12440,7 +9759,7 @@ var ReactFiberCommitWork = function (config, captureError) { return; } node = node['return']; - if (node.tag === HostPortal$7) { + 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; @@ -12455,66 +9774,16 @@ var ReactFiberCommitWork = function (config, captureError) { // Recursively delete all host nodes from the parent. // Detach refs and call componentWillUnmount() on the whole subtree. unmountHostComponents(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; - } - } - - // 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$9: - { - safelyDetachRef(current); - var instance = current.stateNode; - if (typeof instance.componentWillUnmount === 'function') { - safelyCallComponentWillUnmount(current, instance); - } - return; - } - case HostComponent$9: - { - safelyDetachRef(current); - return; - } - case CoroutineComponent$4: - { - commitNestedUnmounts(current.stateNode); - return; - } - case HostPortal$7: - { - // TODO: this is recursive. - // We are also not using this parent because - // the portal will get pushed immediately. - unmountHostComponents(current); - return; - } - } + detachFiber(current); } function commitWork(current, finishedWork) { switch (finishedWork.tag) { - case ClassComponent$9: + case ClassComponent: { return; } - case HostComponent$9: + case HostComponent: { var instance = finishedWork.stateNode; if (instance != null) { @@ -12534,7 +9803,7 @@ var ReactFiberCommitWork = function (config, captureError) { } return; } - case HostText$7: + case HostText: { !(finishedWork.stateNode !== null) ? invariant_1(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; @@ -12546,89 +9815,8 @@ var ReactFiberCommitWork = function (config, captureError) { commitTextUpdate(textInstance, oldText, newText); return; } - case HostRoot$9: - { - return; - } - case HostPortal$7: - { - return; - } - default: - { - invariant_1(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 commitLifeCycles(current, finishedWork) { - switch (finishedWork.tag) { - case ClassComponent$9: - { - var instance = finishedWork.stateNode; - if (finishedWork.effectTag & Update$3) { - if (current === null) { - { - startPhaseTimer$2(finishedWork, 'componentDidMount'); - } - instance.props = finishedWork.memoizedProps; - instance.state = finishedWork.memoizedState; - instance.componentDidMount(); - { - stopPhaseTimer$2(); - } - } else { - var prevProps = current.memoizedProps; - var prevState = current.memoizedState; - { - startPhaseTimer$2(finishedWork, 'componentDidUpdate'); - } - instance.props = finishedWork.memoizedProps; - instance.state = finishedWork.memoizedState; - instance.componentDidUpdate(prevProps, prevState); - { - stopPhaseTimer$2(); - } - } - } - if (finishedWork.effectTag & Callback$1 && finishedWork.updateQueue !== null) { - commitCallbacks$1(finishedWork, finishedWork.updateQueue, instance); - } - return; - } - case HostRoot$9: - { - var updateQueue = finishedWork.updateQueue; - if (updateQueue !== null) { - var _instance = finishedWork.child && finishedWork.child.stateNode; - commitCallbacks$1(finishedWork, updateQueue, _instance); - } - return; - } - case HostComponent$9: - { - 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$3) { - var type = finishedWork.type; - var props = finishedWork.memoizedProps; - commitMount(_instance2, type, props, finishedWork); - } - - return; - } - case HostText$7: + case HostRoot: { - // We have no life-cycles associated with text. - return; - } - case HostPortal$7: - { - // We have no life-cycles associated with portals. return; } default: @@ -12638,43 +9826,25 @@ var ReactFiberCommitWork = function (config, captureError) { } } - function commitAttachRef(finishedWork) { - var ref = finishedWork.ref; - if (ref !== null) { - var instance = finishedWork.stateNode; - switch (finishedWork.tag) { - case HostComponent$9: - ref(getPublicInstance(instance)); - break; - default: - ref(instance); - } - } + function commitResetTextContent(current) { + resetTextContent(current.stateNode); } - function commitDetachRef(current) { - var currentRef = current.ref; - if (currentRef !== null) { - currentRef(null); - } + if (enableMutatingReconciler) { + return { + commitResetTextContent: commitResetTextContent, + commitPlacement: commitPlacement, + commitDeletion: commitDeletion, + commitWork: commitWork, + commitLifeCycles: commitLifeCycles, + commitAttachRef: commitAttachRef, + commitDetachRef: commitDetachRef + }; + } else { + invariant_1(false, 'Mutating reconciler is disabled.'); } - - return { - commitPlacement: commitPlacement, - commitDeletion: commitDeletion, - commitWork: commitWork, - commitLifeCycles: commitLifeCycles, - commitAttachRef: commitAttachRef, - commitDetachRef: commitDetachRef - }; }; -var createCursor$2 = ReactFiberStack.createCursor; -var pop$2 = ReactFiberStack.pop; -var push$2 = ReactFiberStack.push; - - - var NO_CONTEXT = {}; var ReactFiberHostContext = function (config) { @@ -12682,9 +9852,9 @@ var ReactFiberHostContext = function (config) { getRootHostContext = config.getRootHostContext; - var contextStackCursor = createCursor$2(NO_CONTEXT); - var contextFiberStackCursor = createCursor$2(NO_CONTEXT); - var rootInstanceStackCursor = createCursor$2(NO_CONTEXT); + var contextStackCursor = createCursor(NO_CONTEXT); + var contextFiberStackCursor = createCursor(NO_CONTEXT); + var rootInstanceStackCursor = createCursor(NO_CONTEXT); function requiredContext(c) { !(c !== NO_CONTEXT) ? invariant_1(false, 'Expected host context to exist. This error is likely caused by a bug in React. Please file an issue.') : void 0; @@ -12699,20 +9869,20 @@ var ReactFiberHostContext = function (config) { function pushHostContainer(fiber, nextRootInstance) { // Push current root instance onto the stack; // This allows us to reset root when portals are popped. - push$2(rootInstanceStackCursor, nextRootInstance, fiber); + 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$2(contextFiberStackCursor, fiber, fiber); - push$2(contextStackCursor, nextRootContext, fiber); + push(contextFiberStackCursor, fiber, fiber); + push(contextStackCursor, nextRootContext, fiber); } function popHostContainer(fiber) { - pop$2(contextStackCursor, fiber); - pop$2(contextFiberStackCursor, fiber); - pop$2(rootInstanceStackCursor, fiber); + pop(contextStackCursor, fiber); + pop(contextFiberStackCursor, fiber); + pop(rootInstanceStackCursor, fiber); } function getHostContext() { @@ -12732,8 +9902,8 @@ var ReactFiberHostContext = function (config) { // Track the context and the Fiber that provided it. // This enables us to pop only Fibers that provide unique contexts. - push$2(contextFiberStackCursor, fiber, fiber); - push$2(contextStackCursor, nextContext, fiber); + push(contextFiberStackCursor, fiber, fiber); + push(contextStackCursor, nextContext, fiber); } function popHostContext(fiber) { @@ -12743,8 +9913,8 @@ var ReactFiberHostContext = function (config) { return; } - pop$2(contextStackCursor, fiber); - pop$2(contextFiberStackCursor, fiber); + pop(contextStackCursor, fiber); + pop(contextFiberStackCursor, fiber); } function resetHostContainer() { @@ -12763,30 +9933,13 @@ var ReactFiberHostContext = function (config) { }; }; -var HostComponent$10 = ReactTypeOfWork.HostComponent; -var HostText$8 = ReactTypeOfWork.HostText; -var HostRoot$10 = ReactTypeOfWork.HostRoot; - -var Deletion$2 = ReactTypeOfSideEffect.Deletion; -var Placement$6 = ReactTypeOfSideEffect.Placement; - -var createFiberFromHostInstanceForDeletion$1 = ReactFiber.createFiberFromHostInstanceForDeletion; - var ReactFiberHydrationContext = function (config) { var shouldSetTextContent = config.shouldSetTextContent, - canHydrateInstance = config.canHydrateInstance, - canHydrateTextInstance = config.canHydrateTextInstance, - getNextHydratableSibling = config.getNextHydratableSibling, - getFirstHydratableChild = config.getFirstHydratableChild, - hydrateInstance = config.hydrateInstance, - hydrateTextInstance = config.hydrateTextInstance, - didNotHydrateInstance = config.didNotHydrateInstance, - didNotFindHydratableInstance = config.didNotFindHydratableInstance, - didNotFindHydratableTextInstance = config.didNotFindHydratableTextInstance; + hydration = config.hydration; // If this doesn't have hydration mode. - if (!(canHydrateInstance && canHydrateTextInstance && getNextHydratableSibling && getFirstHydratableChild && hydrateInstance && hydrateTextInstance && didNotHydrateInstance && didNotFindHydratableInstance && didNotFindHydratableTextInstance)) { + if (!hydration) { return { enterHydrationState: function () { return false; @@ -12805,8 +9958,24 @@ var ReactFiberHydrationContext = function (config) { }; } + 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; @@ -12822,19 +9991,19 @@ var ReactFiberHydrationContext = function (config) { function deleteHydratableInstance(returnFiber, instance) { { switch (returnFiber.tag) { - case HostRoot$10: - didNotHydrateInstance(returnFiber.stateNode.containerInfo, instance); + case HostRoot: + didNotHydrateContainerInstance(returnFiber.stateNode.containerInfo, instance); break; - case HostComponent$10: - didNotHydrateInstance(returnFiber.stateNode, instance); + case HostComponent: + didNotHydrateInstance(returnFiber.type, returnFiber.memoizedProps, returnFiber.stateNode, instance); break; } } - var childToDelete = createFiberFromHostInstanceForDeletion$1(); + var childToDelete = createFiberFromHostInstanceForDeletion(); childToDelete.stateNode = instance; childToDelete['return'] = returnFiber; - childToDelete.effectTag = Deletion$2; + childToDelete.effectTag = Deletion; // This might seem like it belongs on progressedFirstDeletion. However, // these children are not part of the reconciliation list of children. @@ -12850,49 +10019,71 @@ var ReactFiberHydrationContext = function (config) { } function insertNonHydratedInstance(returnFiber, fiber) { - fiber.effectTag |= Placement$6; + fiber.effectTag |= Placement; { - var parentInstance; switch (returnFiber.tag) { - // TODO: Currently we don't warn for insertions into the root because - // we always insert into the root in the non-hydrating case. We just - // delete the existing content. Reenable this once we have a better - // strategy for determining if we're hydrating or not. - // case HostRoot: - // parentInstance = returnFiber.stateNode.containerInfo; - // break; - case HostComponent$10: - parentInstance = returnFiber.stateNode; - break; + 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; } - switch (fiber.tag) { - case HostComponent$10: - var type = fiber.type; - var props = fiber.pendingProps; - didNotFindHydratableInstance(parentInstance, type, props); - break; - case HostText$8: - var text = fiber.pendingProps; - didNotFindHydratableTextInstance(parentInstance, text); - break; - } } } - function canHydrate(fiber, nextInstance) { + function tryHydrate(fiber, nextInstance) { switch (fiber.tag) { - case HostComponent$10: + case HostComponent: { var type = fiber.type; var props = fiber.pendingProps; - return canHydrateInstance(nextInstance, type, props); + var instance = canHydrateInstance(nextInstance, type, props); + if (instance !== null) { + fiber.stateNode = instance; + return true; + } + return false; } - case HostText$8: + case HostText: { var text = fiber.pendingProps; - return canHydrateTextInstance(nextInstance, text); + var textInstance = canHydrateTextInstance(nextInstance, text); + if (textInstance !== null) { + fiber.stateNode = textInstance; + return true; + } + return false; } default: return false; @@ -12911,12 +10102,12 @@ var ReactFiberHydrationContext = function (config) { hydrationParentFiber = fiber; return; } - if (!canHydrate(fiber, nextInstance)) { + 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 || !canHydrate(fiber, nextInstance)) { + if (!nextInstance || !tryHydrate(fiber, nextInstance)) { // Nothing to hydrate. Make it an insertion. insertNonHydratedInstance(hydrationParentFiber, fiber); isHydrating = false; @@ -12929,7 +10120,6 @@ var ReactFiberHydrationContext = function (config) { // fiber associated with it. deleteHydratableInstance(hydrationParentFiber, nextHydratableInstance); } - fiber.stateNode = nextInstance; hydrationParentFiber = fiber; nextHydratableInstance = getFirstHydratableChild(nextInstance); } @@ -12949,13 +10139,39 @@ var ReactFiberHydrationContext = function (config) { function prepareToHydrateHostTextInstance(fiber) { var textInstance = fiber.stateNode; - var shouldUpdate = hydrateTextInstance(textInstance, fiber.memoizedProps, fiber); + 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$10 && parent.tag !== HostRoot$10) { + while (parent !== null && parent.tag !== HostComponent && parent.tag !== HostRoot) { parent = parent['return']; } hydrationParentFiber = parent; @@ -12983,7 +10199,7 @@ var ReactFiberHydrationContext = function (config) { // other nodes in them. We also ignore components with pure text content in // side of them. // TODO: Better heuristic. - if (fiber.tag !== HostComponent$10 || type !== 'head' && type !== 'body' && !shouldSetTextContent(type, fiber.memoizedProps)) { + if (fiber.tag !== HostComponent || type !== 'head' && type !== 'body' && !shouldSetTextContent(type, fiber.memoizedProps)) { var nextInstance = nextHydratableInstance; while (nextInstance) { deleteHydratableInstance(fiber, nextInstance); @@ -13012,124 +10228,107 @@ var ReactFiberHydrationContext = function (config) { }; }; -/** - * Copyright (c) 2013-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @providesModule ReactFiberInstrumentation - * - */ - // 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$2 = { +var ReactFiberInstrumentation = { debugTool: null }; -var ReactFiberInstrumentation_1 = ReactFiberInstrumentation$2; - -var popContextProvider$1 = ReactFiberContext.popContextProvider; - -var reset$1 = ReactFiberStack.reset; - -var getStackAddendumByWorkInProgressFiber$2 = ReactFiberComponentTreeHook.getStackAddendumByWorkInProgressFiber; - -var logCapturedError = ReactFiberErrorLogger.logCapturedError; - -var invokeGuardedCallback$1 = ReactErrorUtils_1.invokeGuardedCallback; -var hasCaughtError = ReactErrorUtils_1.hasCaughtError; -var clearCaughtError = ReactErrorUtils_1.clearCaughtError; - - - - - - - -var ReactCurrentOwner$1 = ReactGlobalSharedState_1.ReactCurrentOwner; +var ReactFiberInstrumentation_1 = ReactFiberInstrumentation; +var defaultShowDialog = function (capturedError) { + return true; +}; +var showDialog = defaultShowDialog; -var createWorkInProgress$1 = ReactFiber.createWorkInProgress; -var largerPriority$1 = ReactFiber.largerPriority; +function logCapturedError(capturedError) { + var logError = showDialog(capturedError); -var onCommitRoot = ReactFiberDevToolsHook.onCommitRoot; + // Allow injected showDialog() to prevent default console.error logging. + // This enables renderers like ReactNative to better manage redbox behavior. + if (logError === false) { + return; + } -var NoWork$2 = ReactPriorityLevel.NoWork; -var SynchronousPriority$1 = ReactPriorityLevel.SynchronousPriority; -var TaskPriority$1 = ReactPriorityLevel.TaskPriority; -var HighPriority = ReactPriorityLevel.HighPriority; -var LowPriority = ReactPriorityLevel.LowPriority; -var OffscreenPriority = ReactPriorityLevel.OffscreenPriority; + var error = capturedError.error; + var suppressLogging = error && error.suppressReactErrorLogging; + if (suppressLogging) { + return; + } -var AsyncUpdates = ReactTypeOfInternalContext.AsyncUpdates; + { + var componentName = capturedError.componentName, + componentStack = capturedError.componentStack, + errorBoundaryName = capturedError.errorBoundaryName, + errorBoundaryFound = capturedError.errorBoundaryFound, + willRetry = capturedError.willRetry; -var PerformedWork = ReactTypeOfSideEffect.PerformedWork; -var Placement$1 = ReactTypeOfSideEffect.Placement; -var Update = ReactTypeOfSideEffect.Update; -var PlacementAndUpdate = ReactTypeOfSideEffect.PlacementAndUpdate; -var Deletion = ReactTypeOfSideEffect.Deletion; -var ContentReset = ReactTypeOfSideEffect.ContentReset; -var Callback = ReactTypeOfSideEffect.Callback; -var Err = ReactTypeOfSideEffect.Err; -var Ref = ReactTypeOfSideEffect.Ref; -var HostRoot$6 = ReactTypeOfWork.HostRoot; -var HostComponent$6 = ReactTypeOfWork.HostComponent; -var HostPortal$3 = ReactTypeOfWork.HostPortal; -var ClassComponent$5 = ReactTypeOfWork.ClassComponent; + var componentNameMessage = componentName ? 'The above error occurred in the <' + componentName + '> component:' : 'The above error occurred in one of your React components:'; -var getUpdatePriority$1 = ReactFiberUpdateQueue.getUpdatePriority; + 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); -var _require14 = ReactFiberContext; -var resetContext$1 = _require14.resetContext; + // 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 warning$24 = warning_1; - var ReactFiberInstrumentation$1 = ReactFiberInstrumentation_1; - var ReactDebugCurrentFiber$3 = ReactDebugCurrentFiber_1; - - var _require15 = ReactDebugFiberPerf_1, - recordEffect = _require15.recordEffect, - recordScheduleUpdate = _require15.recordScheduleUpdate, - startWorkTimer = _require15.startWorkTimer, - stopWorkTimer = _require15.stopWorkTimer, - stopFailedWorkTimer = _require15.stopFailedWorkTimer, - startWorkLoopTimer = _require15.startWorkLoopTimer, - stopWorkLoopTimer = _require15.stopWorkLoopTimer, - startCommitTimer = _require15.startCommitTimer, - stopCommitTimer = _require15.stopCommitTimer, - startCommitHostEffectsTimer = _require15.startCommitHostEffectsTimer, - stopCommitHostEffectsTimer = _require15.stopCommitHostEffectsTimer, - startCommitLifeCyclesTimer = _require15.startCommitLifeCyclesTimer, - stopCommitLifeCyclesTimer = _require15.stopCommitLifeCyclesTimer; - - var warnAboutUpdateOnUnmounted = function (instance) { - var ctor = instance.constructor; - warning$24(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.', ctor && (ctor.displayName || ctor.name) || 'ReactClass'); + var didWarnAboutStateTransition = false; + var didWarnSetStateChildContext = false; + var didWarnStateUpdateForUnmountedComponent = {}; + + var warnAboutUpdateOnUnmounted = function (fiber) { + var componentName = getComponentName(fiber) || 'ReactClass'; + if (didWarnStateUpdateForUnmountedComponent[componentName]) { + return; + } + warning_1(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$3.phase) { + switch (ReactDebugCurrentFiber.phase) { case 'getChildContext': - warning$24(false, 'setState(...): Cannot call setState() inside getChildContext()'); + if (didWarnSetStateChildContext) { + return; + } + warning_1(false, 'setState(...): Cannot call setState() inside getChildContext()'); + didWarnSetStateChildContext = true; break; case 'render': - warning$24(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`.'); + if (didWarnAboutStateTransition) { + return; + } + warning_1(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 timeHeuristicForUnitOfWork = 1; - var ReactFiberScheduler = function (config) { var hostContext = ReactFiberHostContext(config); var hydrationContext = ReactFiberHydrationContext(config); @@ -13137,7 +10336,7 @@ var ReactFiberScheduler = function (config) { popHostContext = hostContext.popHostContext, resetHostContainer = hostContext.resetHostContainer; - var _ReactFiberBeginWork = ReactFiberBeginWork(config, hostContext, hydrationContext, scheduleUpdate, getPriorityContext), + var _ReactFiberBeginWork = ReactFiberBeginWork(config, hostContext, hydrationContext, scheduleWork, computeExpirationForFiber), beginWork = _ReactFiberBeginWork.beginWork, beginFailedWork = _ReactFiberBeginWork.beginFailedWork; @@ -13145,6 +10344,7 @@ var ReactFiberScheduler = function (config) { completeWork = _ReactFiberCompleteWo.completeWork; var _ReactFiberCommitWork = ReactFiberCommitWork(config, captureError), + commitResetTextContent = _ReactFiberCommitWork.commitResetTextContent, commitPlacement = _ReactFiberCommitWork.commitPlacement, commitDeletion = _ReactFiberCommitWork.commitDeletion, commitWork = _ReactFiberCommitWork.commitWork, @@ -13152,47 +10352,34 @@ var ReactFiberScheduler = function (config) { commitAttachRef = _ReactFiberCommitWork.commitAttachRef, commitDetachRef = _ReactFiberCommitWork.commitDetachRef; - var scheduleDeferredCallback = config.scheduleDeferredCallback, + var now = config.now, + scheduleDeferredCallback = config.scheduleDeferredCallback, + cancelDeferredCallback = config.cancelDeferredCallback, useSyncScheduling = config.useSyncScheduling, prepareForCommit = config.prepareForCommit, resetAfterCommit = config.resetAfterCommit; - // The priority level to use when scheduling an update. We use NoWork to - // represent the default priority. - // TODO: Should we change this to an array instead of using the call stack? - // Might be less confusing. + // Represents the current time in ms. - var priorityContext = NoWork$2; + var startTime = now(); + var mostRecentCurrentTime = msToExpirationTime(0); - // Keeps track of whether we're currently in a work loop. - var isPerformingWork = false; + // 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; - // Keeps track of whether the current deadline has expired. - var deadlineHasExpired = false; - - // Keeps track of whether we should should batch sync updates. - var isBatchingUpdates = false; - - // This is needed for the weird case where the initial mount is synchronous - // even inside batchedUpdates :( - var isUnbatchingUpdates = false; + var isWorking = false; // The next work in progress fiber that we're currently working on. var nextUnitOfWork = null; - var nextPriorityLevel = NoWork$2; + 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; - var pendingCommit = null; - - // Linked list of roots with scheduled work on them. - var nextScheduledRoot = null; - var lastScheduledRoot = null; - - // Keep track of which host environment callbacks are scheduled. - var isCallbackScheduled = false; - // 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; @@ -13209,88 +10396,27 @@ var ReactFiberScheduler = function (config) { var isCommitting = false; var isUnmounting = false; - // Use these to prevent an infinite loop of nested updates - var NESTED_UPDATE_LIMIT = 1000; - var nestedUpdateCount = 0; - var nextRenderedTree = null; + // Used for performance tracking. + var interruptedBy = null; function resetContextStack() { // Reset the stack reset$1(); // Reset the cursors - resetContext$1(); + resetContext(); resetHostContainer(); } - // resetNextUnitOfWork mutates the current priority context. It is reset after - // after the workLoop exits, so never call resetNextUnitOfWork from outside - // the work loop. - function resetNextUnitOfWork() { - // Clear out roots with no more work on them, or if they have uncaught errors - while (nextScheduledRoot !== null && nextScheduledRoot.current.pendingWorkPriority === NoWork$2) { - // Unschedule this root. - nextScheduledRoot.isScheduled = false; - // Read the next pointer now. - // We need to clear it in case this root gets scheduled again later. - var next = nextScheduledRoot.nextScheduledRoot; - nextScheduledRoot.nextScheduledRoot = null; - // Exit if we cleared all the roots and there's no work to do. - if (nextScheduledRoot === lastScheduledRoot) { - nextScheduledRoot = null; - lastScheduledRoot = null; - nextPriorityLevel = NoWork$2; - return null; - } - // Continue with the next root. - // If there's no work on it, it will get unscheduled too. - nextScheduledRoot = next; - } - - var root = nextScheduledRoot; - var highestPriorityRoot = null; - var highestPriorityLevel = NoWork$2; - while (root !== null) { - if (root.current.pendingWorkPriority !== NoWork$2 && (highestPriorityLevel === NoWork$2 || highestPriorityLevel > root.current.pendingWorkPriority)) { - highestPriorityLevel = root.current.pendingWorkPriority; - highestPriorityRoot = root; - } - // We didn't find anything to do in this root, so let's try the next one. - root = root.nextScheduledRoot; - } - if (highestPriorityRoot !== null) { - nextPriorityLevel = highestPriorityLevel; - // Before we start any new work, let's make sure that we have a fresh - // stack to work from. - // TODO: This call is buried a bit too deep. It would be nice to have - // a single point which happens right before any new work and - // unfortunately this is it. - resetContextStack(); - - nextUnitOfWork = createWorkInProgress$1(highestPriorityRoot.current, highestPriorityLevel); - if (highestPriorityRoot !== nextRenderedTree) { - // We've switched trees. Reset the nested update counter. - nestedUpdateCount = 0; - nextRenderedTree = highestPriorityRoot; - } - return; - } - - nextPriorityLevel = NoWork$2; - nextUnitOfWork = null; - nextRenderedTree = null; - return; - } - function commitAllHostEffects() { while (nextEffect !== null) { { - ReactDebugCurrentFiber$3.setCurrentFiber(nextEffect, null); - recordEffect(); + ReactDebugCurrentFiber.setCurrentFiber(nextEffect); } + recordEffect(); var effectTag = nextEffect.effectTag; if (effectTag & ContentReset) { - config.resetTextContent(nextEffect.stateNode); + commitResetTextContent(nextEffect); } if (effectTag & Ref) { @@ -13306,7 +10432,7 @@ var ReactFiberScheduler = function (config) { // effect tag and switch on that value. var primaryEffectTag = effectTag & ~(Callback | Err | ContentReset | Ref | PerformedWork); switch (primaryEffectTag) { - case Placement$1: + case Placement: { commitPlacement(nextEffect); // Clear the "placement" from effect tag so that we know that this is inserted, before @@ -13314,7 +10440,7 @@ var ReactFiberScheduler = function (config) { // 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$1; + nextEffect.effectTag &= ~Placement; break; } case PlacementAndUpdate: @@ -13323,7 +10449,7 @@ var ReactFiberScheduler = function (config) { 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$1; + nextEffect.effectTag &= ~Placement; // Update var _current = nextEffect.alternate; @@ -13348,7 +10474,7 @@ var ReactFiberScheduler = function (config) { } { - ReactDebugCurrentFiber$3.resetCurrentFiber(); + ReactDebugCurrentFiber.resetCurrentFiber(); } } @@ -13356,26 +10482,19 @@ var ReactFiberScheduler = function (config) { while (nextEffect !== null) { var effectTag = nextEffect.effectTag; - // Use Task priority for lifecycle updates if (effectTag & (Update | Callback)) { - { - recordEffect(); - } + recordEffect(); var current = nextEffect.alternate; commitLifeCycles(current, nextEffect); } if (effectTag & Ref) { - { - recordEffect(); - } + recordEffect(); commitAttachRef(nextEffect); } if (effectTag & Err) { - { - recordEffect(); - } + recordEffect(); commitErrorHandling(nextEffect); } @@ -13391,28 +10510,21 @@ var ReactFiberScheduler = function (config) { } } - function commitAllWork(finishedWork) { + 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(); - } + startCommitTimer(); - pendingCommit = null; var root = finishedWork.stateNode; !(root.current !== finishedWork) ? invariant_1(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; - - if (nextPriorityLevel === SynchronousPriority$1 || nextPriorityLevel === TaskPriority$1) { - // Keep track of the number of iterations to prevent an infinite - // update loop. - nestedUpdateCount++; - } + root.isReadyForCommit = false; // Reset this to null before calling lifecycles - ReactCurrentOwner$1.current = null; + ReactCurrentOwner.current = null; var firstEffect = void 0; if (finishedWork.effectTag > PerformedWork) { @@ -13437,9 +10549,7 @@ var ReactFiberScheduler = function (config) { // The first pass performs all the host insertions, updates, deletions and // ref unmounts. nextEffect = firstEffect; - { - startCommitHostEffectsTimer(); - } + startCommitHostEffectsTimer(); while (nextEffect !== null) { var didError = false; var _error = void 0; @@ -13459,9 +10569,7 @@ var ReactFiberScheduler = function (config) { } } } - { - stopCommitHostEffectsTimer(); - } + stopCommitHostEffectsTimer(); resetAfterCommit(); @@ -13476,9 +10584,7 @@ var ReactFiberScheduler = function (config) { // and deletions in the entire tree have already been invoked. // This pass also triggers any renderer-specific initial effects. nextEffect = firstEffect; - { - startCommitLifeCyclesTimer(); - } + startCommitLifeCyclesTimer(); while (nextEffect !== null) { var _didError = false; var _error2 = void 0; @@ -13499,15 +10605,14 @@ var ReactFiberScheduler = function (config) { } isCommitting = false; - { - stopCommitLifeCyclesTimer(); - stopCommitTimer(); - } + isWorking = false; + stopCommitLifeCyclesTimer(); + stopCommitTimer(); if (typeof onCommitRoot === 'function') { onCommitRoot(finishedWork.stateNode); } - if (true && ReactFiberInstrumentation$1.debugTool) { - ReactFiberInstrumentation$1.debugTool.onCommitWork(finishedWork); + if (true && ReactFiberInstrumentation_1.debugTool) { + ReactFiberInstrumentation_1.debugTool.onCommitWork(finishedWork); } // If we caught any errors during this commit, schedule their boundaries @@ -13517,29 +10622,43 @@ var ReactFiberScheduler = function (config) { commitPhaseBoundaries = null; } - // This tree is done. Reset the unit of work pointer to the next highest - // priority root. If there's no more work left, the pointer is set to null. - resetNextUnitOfWork(); + 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 resetWorkPriority(workInProgress, renderPriority) { - if (workInProgress.pendingWorkPriority !== NoWork$2 && workInProgress.pendingWorkPriority > renderPriority) { - // This was a down-prioritization. Don't bubble priority from children. + 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 update priority. - var newPriority = getUpdatePriority$1(workInProgress); + // Check for pending updates. + var newExpirationTime = getUpdateExpirationTime(workInProgress); - // TODO: Coroutines need to visit stateNode + // TODO: Calls need to visit stateNode + // Bubble up the earliest expiration time. var child = workInProgress.child; while (child !== null) { - // Ensure that remaining work priority bubbles up. - newPriority = largerPriority$1(newPriority, child.pendingWorkPriority); + if (child.expirationTime !== NoWork && (newExpirationTime === NoWork || newExpirationTime > child.expirationTime)) { + newExpirationTime = child.expirationTime; + } child = child.sibling; } - workInProgress.pendingWorkPriority = newPriority; + workInProgress.expirationTime = newExpirationTime; } function completeUnitOfWork(workInProgress) { @@ -13549,19 +10668,23 @@ var ReactFiberScheduler = function (config) { // means that we don't need an additional field on the work in // progress. var current = workInProgress.alternate; - var next = completeWork(current, workInProgress, nextPriorityLevel); + { + ReactDebugCurrentFiber.setCurrentFiber(workInProgress); + } + var next = completeWork(current, workInProgress, nextRenderExpirationTime); + { + ReactDebugCurrentFiber.resetCurrentFiber(); + } var returnFiber = workInProgress['return']; var siblingFiber = workInProgress.sibling; - resetWorkPriority(workInProgress, nextPriorityLevel); + resetExpirationTime(workInProgress, nextRenderExpirationTime); if (next !== null) { - { - stopWorkTimer(workInProgress); - } - if (true && ReactFiberInstrumentation$1.debugTool) { - ReactFiberInstrumentation$1.debugTool.onCompleteWork(workInProgress); + 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. @@ -13601,11 +10724,9 @@ var ReactFiberScheduler = function (config) { } } - { - stopWorkTimer(workInProgress); - } - if (true && ReactFiberInstrumentation$1.debugTool) { - ReactFiberInstrumentation$1.debugTool.onCompleteWork(workInProgress); + stopWorkTimer(workInProgress); + if (true && ReactFiberInstrumentation_1.debugTool) { + ReactFiberInstrumentation_1.debugTool.onCompleteWork(workInProgress); } if (siblingFiber !== null) { @@ -13616,10 +10737,9 @@ var ReactFiberScheduler = function (config) { workInProgress = returnFiber; continue; } else { - // We've reached the root. Mark the root as pending commit. Depending - // on how much time we have left, we'll either commit it now or in - // the next frame. - pendingCommit = workInProgress; + // We've reached the root. + var root = workInProgress.stateNode; + root.isReadyForCommit = true; return null; } } @@ -13638,12 +10758,17 @@ var ReactFiberScheduler = function (config) { var current = workInProgress.alternate; // See if beginning this work spawns more work. + startWorkTimer(workInProgress); + { + ReactDebugCurrentFiber.setCurrentFiber(workInProgress); + } + + var next = beginWork(current, workInProgress, nextRenderExpirationTime); { - startWorkTimer(workInProgress); + ReactDebugCurrentFiber.resetCurrentFiber(); } - var next = beginWork(current, workInProgress, nextPriorityLevel); - if (true && ReactFiberInstrumentation$1.debugTool) { - ReactFiberInstrumentation$1.debugTool.onBeginWork(workInProgress); + if (true && ReactFiberInstrumentation_1.debugTool) { + ReactFiberInstrumentation_1.debugTool.onBeginWork(workInProgress); } if (next === null) { @@ -13651,10 +10776,7 @@ var ReactFiberScheduler = function (config) { next = completeUnitOfWork(workInProgress); } - ReactCurrentOwner$1.current = null; - { - ReactDebugCurrentFiber$3.resetCurrentFiber(); - } + ReactCurrentOwner.current = null; return next; } @@ -13667,12 +10789,16 @@ var ReactFiberScheduler = function (config) { var current = workInProgress.alternate; // See if beginning this work spawns more work. + startWorkTimer(workInProgress); + { + ReactDebugCurrentFiber.setCurrentFiber(workInProgress); + } + var next = beginFailedWork(current, workInProgress, nextRenderExpirationTime); { - startWorkTimer(workInProgress); + ReactDebugCurrentFiber.resetCurrentFiber(); } - var next = beginFailedWork(current, workInProgress, nextPriorityLevel); - if (true && ReactFiberInstrumentation$1.debugTool) { - ReactFiberInstrumentation$1.debugTool.onBeginWork(workInProgress); + if (true && ReactFiberInstrumentation_1.debugTool) { + ReactFiberInstrumentation_1.debugTool.onBeginWork(workInProgress); } if (next === null) { @@ -13680,29 +10806,44 @@ var ReactFiberScheduler = function (config) { next = completeUnitOfWork(workInProgress); } - ReactCurrentOwner$1.current = null; - { - ReactDebugCurrentFiber$3.resetCurrentFiber(); - } + ReactCurrentOwner.current = null; return next; } - function performDeferredWork(deadline) { - performWork(OffscreenPriority, deadline); + 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 handleCommitPhaseErrors() { - // This is a special work loop for handling commit phase errors. It's - // similar to the syncrhonous work loop, but does an additional check on - // each fiber to see if it's an error boundary with an unhandled error. If - // so, it uses a forked version of performUnitOfWork that unmounts the - // failed subtree. - // - // The loop stops once the children have unmounted and error lifecycles are - // called. Then we return to the regular flow. + function slowWorkLoopThatChecksForFailedWork(expirationTime) { + if (nextRenderExpirationTime === NoWork || nextRenderExpirationTime > expirationTime) { + return; + } - if (capturedErrors !== null && capturedErrors.size > 0 && nextPriorityLevel === TaskPriority$1) { + if (nextRenderExpirationTime <= mostRecentCurrentTime) { + // Flush all expired work. while (nextUnitOfWork !== null) { if (hasCapturedError(nextUnitOfWork)) { // Use a forked version of performUnitOfWork @@ -13710,133 +10851,21 @@ var ReactFiberScheduler = function (config) { } else { nextUnitOfWork = performUnitOfWork(nextUnitOfWork); } - if (nextUnitOfWork === null) { - !(pendingCommit !== null) ? invariant_1(false, 'Should have a pending commit. This error is likely caused by a bug in React. Please file an issue.') : void 0; - // We just completed a root. Commit it now. - priorityContext = TaskPriority$1; - commitAllWork(pendingCommit); - priorityContext = nextPriorityLevel; - - if (capturedErrors === null || capturedErrors.size === 0 || nextPriorityLevel !== TaskPriority$1) { - // There are no more unhandled errors. We can exit this special - // work loop. If there's still additional work, we'll perform it - // using one of the normal work loops. - break; - } - // The commit phase produced additional errors. Continue working. - } } - } - } - - function workLoop(minPriorityLevel, deadline) { - if (pendingCommit !== null) { - priorityContext = TaskPriority$1; - commitAllWork(pendingCommit); - handleCommitPhaseErrors(); - } else if (nextUnitOfWork === null) { - resetNextUnitOfWork(); - } - - if (nextPriorityLevel === NoWork$2 || nextPriorityLevel > minPriorityLevel) { - return; - } - - // During the render phase, updates should have the same priority at which - // we're rendering. - priorityContext = nextPriorityLevel; - - loop: do { - if (nextPriorityLevel <= TaskPriority$1) { - // Flush all synchronous and task work. - while (nextUnitOfWork !== null) { + } 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); - if (nextUnitOfWork === null) { - !(pendingCommit !== null) ? invariant_1(false, 'Should have a pending commit. This error is likely caused by a bug in React. Please file an issue.') : void 0; - // We just completed a root. Commit it now. - priorityContext = TaskPriority$1; - commitAllWork(pendingCommit); - priorityContext = nextPriorityLevel; - // Clear any errors that were scheduled during the commit phase. - handleCommitPhaseErrors(); - // The priority level may have changed. Check again. - if (nextPriorityLevel === NoWork$2 || nextPriorityLevel > minPriorityLevel || nextPriorityLevel > TaskPriority$1) { - // The priority level does not match. - break; - } - } - } - } else if (deadline !== null) { - // Flush asynchronous work until the deadline expires. - while (nextUnitOfWork !== null && !deadlineHasExpired) { - if (deadline.timeRemaining() > timeHeuristicForUnitOfWork) { - nextUnitOfWork = performUnitOfWork(nextUnitOfWork); - // In a deferred work batch, iff nextUnitOfWork returns null, we just - // completed a root and a pendingCommit exists. Logically, we could - // omit either of the checks in the following condition, but we need - // both to satisfy Flow. - if (nextUnitOfWork === null) { - !(pendingCommit !== null) ? invariant_1(false, 'Should have a pending commit. This error is likely caused by a bug in React. Please file an issue.') : void 0; - // We just completed a root. If we have time, commit it now. - // Otherwise, we'll commit it in the next frame. - if (deadline.timeRemaining() > timeHeuristicForUnitOfWork) { - priorityContext = TaskPriority$1; - commitAllWork(pendingCommit); - priorityContext = nextPriorityLevel; - // Clear any errors that were scheduled during the commit phase. - handleCommitPhaseErrors(); - // The priority level may have changed. Check again. - if (nextPriorityLevel === NoWork$2 || nextPriorityLevel > minPriorityLevel || nextPriorityLevel < HighPriority) { - // The priority level does not match. - break; - } - } else { - deadlineHasExpired = true; - } - } - } else { - deadlineHasExpired = true; - } } } - - // There might be work left. Depending on the priority, we should - // either perform it now or schedule a callback to perform it later. - switch (nextPriorityLevel) { - case SynchronousPriority$1: - case TaskPriority$1: - // We have remaining synchronous or task work. Keep performing it, - // regardless of whether we're inside a callback. - if (nextPriorityLevel <= minPriorityLevel) { - continue loop; - } - break loop; - case HighPriority: - case LowPriority: - case OffscreenPriority: - // We have remaining async work. - if (deadline === null) { - // We're not inside a callback. Exit and perform the work during - // the next callback. - break loop; - } - // We are inside a callback. - if (!deadlineHasExpired && nextPriorityLevel <= minPriorityLevel) { - // We still have time. Keep working. - continue loop; - } - // We've run out of time. Exit. - break loop; - case NoWork$2: - // No work left. We can exit. - break loop; - default: - invariant_1(false, 'Switch statement should be exhuastive. This error is likely caused by a bug in React. Please file an issue.'); - } - } while (true); + } } - function performWorkCatchBlock(failedWork, boundary, minPriorityLevel, deadline) { + 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. @@ -13850,25 +10879,33 @@ var ReactFiberScheduler = function (config) { nextUnitOfWork = performFailedUnitOfWork(boundary); // Continue working. - workLoop(minPriorityLevel, deadline); + workLoop(expirationTime); } - function performWork(minPriorityLevel, deadline) { - { - startWorkLoopTimer(); - } + function renderRoot(root, expirationTime) { + !!isWorking ? invariant_1(false, 'renderRoot was called recursively. This error is likely caused by a bug in React. Please file an issue.') : void 0; + isWorking = true; - !!isPerformingWork ? invariant_1(false, 'performWork was called recursively. This error is likely caused by a bug in React. Please file an issue.') : void 0; - isPerformingWork = 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; - // The priority context changes during the render phase. We'll need to - // reset it at the end. - var previousPriorityContext = priorityContext; + // 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, minPriorityLevel, deadline); + invokeGuardedCallback$1(null, workLoop, null, expirationTime); if (hasCaughtError()) { didError = true; error = clearCaughtError(); @@ -13905,7 +10942,7 @@ var ReactFiberScheduler = function (config) { didError = false; error = null; { - invokeGuardedCallback$1(null, performWorkCatchBlock, null, failedWork, boundary, minPriorityLevel, deadline); + invokeGuardedCallback$1(null, renderRootCatchBlock, null, root, failedWork, boundary, expirationTime); if (hasCaughtError()) { didError = true; error = clearCaughtError(); @@ -13916,47 +10953,28 @@ var ReactFiberScheduler = function (config) { break; } - // Reset the priority context to its previous value. - priorityContext = previousPriorityContext; - - // If we're inside a callback, set this to false, since we just flushed it. - if (deadline !== null) { - isCallbackScheduled = false; - } - // If there's remaining async work, make sure we schedule another callback. - if (nextPriorityLevel > TaskPriority$1 && !isCallbackScheduled) { - scheduleDeferredCallback(performDeferredWork); - isCallbackScheduled = true; - } - - var errorToThrow = firstUncaughtError; + var uncaughtError = firstUncaughtError; // We're done performing work. Time to clean up. - isPerformingWork = false; - deadlineHasExpired = false; + stopWorkLoopTimer(interruptedBy); + interruptedBy = null; + isWorking = false; didFatal = false; firstUncaughtError = null; - capturedErrors = null; - failedBoundaries = null; - nextRenderedTree = null; - nestedUpdateCount = 0; - { - stopWorkLoopTimer(); + if (uncaughtError !== null) { + onUncaughtError(uncaughtError); } - // It's safe to throw any unhandled errors. - if (errorToThrow !== null) { - throw errorToThrow; - } + 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$1.current = null; + ReactCurrentOwner.current = null; { - ReactDebugCurrentFiber$3.resetCurrentFiber(); + ReactDebugCurrentFiber.resetCurrentFiber(); } // Search for the nearest error boundary. @@ -13970,7 +10988,7 @@ var ReactFiberScheduler = function (config) { // 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$6) { + if (failedWork.tag === HostRoot) { boundary = failedWork; if (isFailedBoundary(failedWork)) { @@ -13982,17 +11000,17 @@ var ReactFiberScheduler = function (config) { } else { var node = failedWork['return']; while (node !== null && boundary === null) { - if (node.tag === ClassComponent$5) { + if (node.tag === ClassComponent) { var instance = node.stateNode; if (typeof instance.componentDidCatch === 'function') { errorBoundaryFound = true; - errorBoundaryName = getComponentName_1(node); + errorBoundaryName = getComponentName(node); // Found an error boundary! boundary = node; willRetry = true; } - } else if (node.tag === HostRoot$6) { + } else if (node.tag === HostRoot) { // Treat the root like a no-op error boundary boundary = node; } @@ -14037,8 +11055,8 @@ var ReactFiberScheduler = function (config) { // 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$2(failedWork); - var _componentName = getComponentName_1(failedWork); + 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 @@ -14065,7 +11083,10 @@ var ReactFiberScheduler = function (config) { } catch (e) { // Prevent cycle if logCapturedError() throws. // A cycle may still occur if logCapturedError renders a component that throws. - console.error(e); + var suppressLogging = e && e.suppressReactErrorLogging; + if (!suppressLogging) { + console.error(e); + } } // If we're in the commit phase, defer scheduling an update on the @@ -14119,7 +11140,7 @@ var ReactFiberScheduler = function (config) { !(capturedError != null) ? invariant_1(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$5: + case ClassComponent: var instance = effectfulFiber.stateNode; var info = { @@ -14130,11 +11151,8 @@ var ReactFiberScheduler = function (config) { // an update to itself instance.componentDidCatch(capturedError.error, info); return; - case HostRoot$6: + case HostRoot: if (firstUncaughtError === null) { - // If this is the host container, we treat it as a no-op error - // boundary. We'll throw the first uncaught error once it's safe to - // do so, at the end of the batch. firstUncaughtError = capturedError.error; } return; @@ -14147,23 +11165,21 @@ var ReactFiberScheduler = function (config) { var node = from; while (node !== null) { switch (node.tag) { - case ClassComponent$5: - popContextProvider$1(node); + case ClassComponent: + popContextProvider(node); break; - case HostComponent$6: + case HostComponent: popHostContext(node); break; - case HostRoot$6: + case HostRoot: popHostContainer(node); break; - case HostPortal$3: + case HostPortal: popHostContainer(node); break; } if (node === to || node.alternate === to) { - { - stopFailedWorkTimer(node); - } + stopFailedWorkTimer(node); break; } else { stopWorkTimer(node); @@ -14172,105 +11188,95 @@ var ReactFiberScheduler = function (config) { } } - function scheduleRoot(root, priorityLevel) { - if (priorityLevel === NoWork$2) { - 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); + } - if (!root.isScheduled) { - root.isScheduled = true; - if (lastScheduledRoot) { - // Schedule ourselves to the end. - lastScheduledRoot.nextScheduledRoot = root; - lastScheduledRoot = root; + 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 { - // We're the only work scheduled. - nextScheduledRoot = root; - lastScheduledRoot = root; + // 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 scheduleUpdate(fiber, priorityLevel) { - return scheduleUpdateImpl(fiber, priorityLevel, false); + function scheduleWork(fiber, expirationTime) { + return scheduleWorkImpl(fiber, expirationTime, false); } - function scheduleUpdateImpl(fiber, priorityLevel, isErrorRecovery) { - { - recordScheduleUpdate(); - } - - if (nestedUpdateCount > NESTED_UPDATE_LIMIT) { - didFatal = true; - invariant_1(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.'); - } - - if (!isPerformingWork && priorityLevel <= nextPriorityLevel) { - // We must reset the current unit of work pointer so that we restart the - // search from the root during the next tick, in case there is now higher - // priority work somewhere earlier than before. + 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$5) { + if (!isErrorRecovery && fiber.tag === ClassComponent) { var instance = fiber.stateNode; warnAboutInvalidUpdates(instance); } } var node = fiber; - var shouldContinue = true; - while (node !== null && shouldContinue) { - // Walk the parent path to the root and update each node's priority. Once - // we reach a node whose priority matches (and whose alternate's priority - // matches) we can exit safely knowing that the rest of the path is correct. - shouldContinue = false; - if (node.pendingWorkPriority === NoWork$2 || node.pendingWorkPriority > priorityLevel) { - // Priority did not match. Update and keep going. - shouldContinue = true; - node.pendingWorkPriority = priorityLevel; + 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.pendingWorkPriority === NoWork$2 || node.alternate.pendingWorkPriority > priorityLevel) { - // Priority did not match. Update and keep going. - shouldContinue = true; - node.alternate.pendingWorkPriority = priorityLevel; + if (node.alternate.expirationTime === NoWork || node.alternate.expirationTime > expirationTime) { + node.alternate.expirationTime = expirationTime; } } if (node['return'] === null) { - if (node.tag === HostRoot$6) { + if (node.tag === HostRoot) { var root = node.stateNode; - scheduleRoot(root, priorityLevel); - if (!isPerformingWork) { - switch (priorityLevel) { - case SynchronousPriority$1: - // Perform this update now. - if (isUnbatchingUpdates) { - // We're inside unbatchedUpdates, which is inside either - // batchedUpdates or a lifecycle. We should only flush - // synchronous work, not task work. - performWork(SynchronousPriority$1, null); - } else { - // Flush both synchronous and task work. - performWork(TaskPriority$1, null); - } - break; - case TaskPriority$1: - !isBatchingUpdates ? invariant_1(false, 'Task updates can only be scheduled as a nested update or inside batchedUpdates.') : void 0; - break; - default: - // Schedule a callback to perform the work later. - if (!isCallbackScheduled) { - scheduleDeferredCallback(performDeferredWork); - isCallbackScheduled = true; - } - } - } + + checkRootNeedsClearing(root, fiber, expirationTime); + requestWork(root, expirationTime); + checkRootNeedsClearing(root, fiber, expirationTime); } else { { - if (!isErrorRecovery && fiber.tag === ClassComponent$5) { - warnAboutUpdateOnUnmounted(fiber.stateNode); + if (!isErrorRecovery && fiber.tag === ClassComponent) { + warnAboutUpdateOnUnmounted(fiber); } } return; @@ -14280,28 +11286,337 @@ var ReactFiberScheduler = function (config) { } } - function getPriorityContext(fiber, forceAsync) { - var priorityLevel = priorityContext; - if (priorityLevel === NoWork$2) { - if (!useSyncScheduling || fiber.internalContextTag & AsyncUpdates || forceAsync) { - priorityLevel = LowPriority; + 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_1(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 { - priorityLevel = SynchronousPriority$1; + 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 we're in a batch, or if we're already performing work, downgrade sync - // priority to task priority - if (priorityLevel === SynchronousPriority$1 && (isPerformingWork || isBatchingUpdates)) { - return TaskPriority$1; + 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); } - return priorityLevel; } - function scheduleErrorRecovery(fiber) { - scheduleUpdateImpl(fiber, TaskPriority$1, true); + 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_1(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_1(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_1(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; @@ -14309,57 +11624,44 @@ var ReactFiberScheduler = function (config) { return fn(a); } finally { isBatchingUpdates = previousIsBatchingUpdates; - // If we're not already inside a batch, we need to flush any task work - // that was created by the user-provided function. - if (!isPerformingWork && !isBatchingUpdates) { - performWork(TaskPriority$1, null); + if (!isBatchingUpdates && !isRendering) { + performWork(Sync, null); } } } + // TODO: Batching should be implemented at the renderer level, not inside + // the reconciler. function unbatchedUpdates(fn) { - var previousIsUnbatchingUpdates = isUnbatchingUpdates; - var previousIsBatchingUpdates = isBatchingUpdates; - // This is only true if we're nested inside batchedUpdates. - isUnbatchingUpdates = isBatchingUpdates; - isBatchingUpdates = false; - try { - return fn(); - } finally { - isBatchingUpdates = previousIsBatchingUpdates; - isUnbatchingUpdates = previousIsUnbatchingUpdates; + if (isBatchingUpdates && !isUnbatchingUpdates) { + isUnbatchingUpdates = true; + try { + return fn(); + } finally { + isUnbatchingUpdates = false; + } } + return fn(); } - function flushSync(batch) { + // TODO: Batching should be implemented at the renderer level, not within + // the reconciler. + function flushSync(fn) { var previousIsBatchingUpdates = isBatchingUpdates; - var previousPriorityContext = priorityContext; isBatchingUpdates = true; - priorityContext = SynchronousPriority$1; try { - return batch(); + return syncUpdates(fn); } finally { isBatchingUpdates = previousIsBatchingUpdates; - priorityContext = previousPriorityContext; - - !!isPerformingWork ? invariant_1(false, 'flushSync was called from inside a lifecycle method. It cannot be called when React is already rendering.') : void 0; - performWork(TaskPriority$1, null); - } - } - - function deferredUpdates(fn) { - var previousPriorityContext = priorityContext; - priorityContext = LowPriority; - try { - return fn(); - } finally { - priorityContext = previousPriorityContext; + !!isRendering ? invariant_1(false, 'flushSync was called from inside a lifecycle method. It cannot be called when React is already rendering.') : void 0; + performWork(Sync, null); } } return { - scheduleUpdate: scheduleUpdate, - getPriorityContext: getPriorityContext, + computeAsyncExpiration: computeAsyncExpiration, + computeExpirationForFiber: computeExpirationForFiber, + scheduleWork: scheduleWork, batchedUpdates: batchedUpdates, unbatchedUpdates: unbatchedUpdates, flushSync: flushSync, @@ -14367,79 +11669,31 @@ var ReactFiberScheduler = function (config) { }; }; -/** - * Copyright (c) 2013-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @providesModule getContextForSubtree - * - */ - - - - +{ + var didWarnAboutNestedUpdates = false; +} +// 0 is PROD, 1 is DEV. +// Might add PROFILE later. -var getContextFiber = function (arg) { - invariant_1(false, 'Missing injection for fiber getContextForSubtree'); -}; function getContextForSubtree(parentComponent) { if (!parentComponent) { return emptyObject_1; } - var instance = ReactInstanceMap_1.get(parentComponent); - if (typeof instance.tag === 'number') { - return getContextFiber(instance); - } else { - return instance._processChildContext(instance._context); - } -} - -getContextForSubtree._injectFiber = function (fn) { - getContextFiber = fn; -}; - -var getContextForSubtree_1 = getContextForSubtree; - -var addTopLevelUpdate = ReactFiberUpdateQueue.addTopLevelUpdate; - -var findCurrentUnmaskedContext = ReactFiberContext.findCurrentUnmaskedContext; -var isContextProvider = ReactFiberContext.isContextProvider; -var processChildContext = ReactFiberContext.processChildContext; - -var createFiberRoot = ReactFiberRoot.createFiberRoot; - - - -var HostComponent$3 = ReactTypeOfWork.HostComponent; - -{ - var warning$20 = warning_1; - var ReactFiberInstrumentation = ReactFiberInstrumentation_1; - var ReactDebugCurrentFiber$1 = ReactDebugCurrentFiber_1; - var getComponentName$4 = getComponentName_1; -} - -var findCurrentHostFiber$1 = ReactFiberTreeReflection.findCurrentHostFiber; -var findCurrentHostFiberWithNoPortals$1 = ReactFiberTreeReflection.findCurrentHostFiberWithNoPortals; - - - -getContextForSubtree_1._injectFiber(function (fiber) { + var fiber = get(parentComponent); var parentContext = findCurrentUnmaskedContext(fiber); - return isContextProvider(fiber) ? processChildContext(fiber, parentContext, false) : parentContext; -}); + return isContextProvider(fiber) ? processChildContext(fiber, parentContext) : parentContext; +} -var ReactFiberReconciler = function (config) { +var ReactFiberReconciler$1 = function (config) { var getPublicInstance = config.getPublicInstance; var _ReactFiberScheduler = ReactFiberScheduler(config), - scheduleUpdate = _ReactFiberScheduler.scheduleUpdate, - getPriorityContext = _ReactFiberScheduler.getPriorityContext, + computeAsyncExpiration = _ReactFiberScheduler.computeAsyncExpiration, + computeExpirationForFiber = _ReactFiberScheduler.computeExpirationForFiber, + scheduleWork = _ReactFiberScheduler.scheduleWork, batchedUpdates = _ReactFiberScheduler.batchedUpdates, unbatchedUpdates = _ReactFiberScheduler.unbatchedUpdates, flushSync = _ReactFiberScheduler.flushSync, @@ -14447,46 +11701,69 @@ var ReactFiberReconciler = function (config) { function scheduleTopLevelUpdate(current, element, callback) { { - if (ReactDebugCurrentFiber$1.phase === 'render' && ReactDebugCurrentFiber$1.current !== null) { - warning$20(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$4(ReactDebugCurrentFiber$1.current) || 'Unknown'); + if (ReactDebugCurrentFiber.phase === 'render' && ReactDebugCurrentFiber.current !== null && !didWarnAboutNestedUpdates) { + didWarnAboutNestedUpdates = true; + warning_1(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'); } } - // 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. - var forceAsync = ReactFeatureFlags_1.enableAsyncSubtreeAPI && element != null && element.type != null && element.type.prototype != null && element.type.prototype.unstable_isAsyncReactComponent === true; - var priorityLevel = getPriorityContext(current, forceAsync); - var nextState = { element: element }; callback = callback === undefined ? null : callback; { - warning$20(callback === null || typeof callback === 'function', 'render(...): Expected the last optional `callback` argument to be a ' + 'function. Instead received: %s.', callback); + warning_1(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); } - addTopLevelUpdate(current, nextState, callback, priorityLevel); - scheduleUpdate(current, priorityLevel); + + 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) { - return createFiberRoot(containerInfo); + 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.debugTool) { + if (ReactFiberInstrumentation_1.debugTool) { if (current.alternate === null) { - ReactFiberInstrumentation.debugTool.onMountContainer(container); + ReactFiberInstrumentation_1.debugTool.onMountContainer(container); } else if (element === null) { - ReactFiberInstrumentation.debugTool.onUnmountContainer(container); + ReactFiberInstrumentation_1.debugTool.onUnmountContainer(container); } else { - ReactFiberInstrumentation.debugTool.onUpdateContainer(container); + ReactFiberInstrumentation_1.debugTool.onUpdateContainer(container); } } } - var context = getContextForSubtree_1(parentComponent); + var context = getContextForSubtree(parentComponent); if (container.context === null) { container.context = context; } else { @@ -14511,592 +11788,253 @@ var ReactFiberReconciler = function (config) { return null; } switch (containerFiber.child.tag) { - case HostComponent$3: + case HostComponent: return getPublicInstance(containerFiber.child.stateNode); default: return containerFiber.child.stateNode; } }, - findHostInstance: function (fiber) { - var hostFiber = findCurrentHostFiber$1(fiber); - if (hostFiber === null) { - return null; - } - return hostFiber.stateNode; - }, + + + findHostInstance: findHostInstance, + findHostInstanceWithNoPortals: function (fiber) { - var hostFiber = findCurrentHostFiberWithNoPortals$1(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 TEXT_NODE$3 = HTMLNodeType_1.TEXT_NODE; - -/** - * 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$3) { - nodeEnd = nodeStart + node.textContent.length; - - if (nodeStart <= offset && nodeEnd >= offset) { - return { - node: node, - offset: offset - nodeStart - }; - } - - nodeStart = nodeEnd; - } - - node = getLeafNode(getSiblingNode(node)); - } -} - -var getNodeForCharacterOffset_1 = getNodeForCharacterOffset; - -var contentKey = null; - -/** - * Gets the key used to access text content on a DOM node. - * - * @return {?string} Key used to access text content. - * @internal - */ -function getTextContentAccessor() { - if (!contentKey && ExecutionEnvironment_1.canUseDOM) { - // Prefer textContent to innerText because many browsers support both but - // SVG <text> elements don't support innerText even when <div> does. - contentKey = 'textContent' in document.documentElement ? 'textContent' : 'innerText'; - } - return contentKey; -} - -var getTextContentAccessor_1 = getTextContentAccessor; - -/** - * While `isCollapsed` is available on the Selection object and `collapsed` - * is available on the Range object, IE11 sometimes gets them wrong. - * If the anchor/focus nodes and offsets are the same, the range is collapsed. - */ -function isCollapsed(anchorNode, anchorOffset, focusNode, focusOffset) { - return anchorNode === focusNode && anchorOffset === focusOffset; -} - -/** - * @param {DOMElement} node - * @return {?object} - */ -function getModernOffsets(node) { - var selection = window.getSelection && window.getSelection(); - - if (!selection || selection.rangeCount === 0) { - return null; - } - - var anchorNode = selection.anchorNode; - var anchorOffset = selection.anchorOffset; - var focusNode = selection.focusNode; - var focusOffset = selection.focusOffset; - - var currentRange = selection.getRangeAt(0); - - // In Firefox, range.startContainer and range.endContainer can be "anonymous - // divs", e.g. the up/down buttons on an <input type="number">. 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 */ - currentRange.startContainer.nodeType; - currentRange.endContainer.nodeType; - /* eslint-enable no-unused-expressions */ - } catch (e) { - return null; - } +var ReactFiberReconciler$2 = Object.freeze({ + default: ReactFiberReconciler$1 +}); - // If the node and offset values are the same, the selection is collapsed. - // `Selection.isCollapsed` is available natively, but IE sometimes gets - // this value wrong. - var isSelectionCollapsed = isCollapsed(selection.anchorNode, selection.anchorOffset, selection.focusNode, selection.focusOffset); +var ReactFiberReconciler$3 = ( ReactFiberReconciler$2 && ReactFiberReconciler$1 ) || ReactFiberReconciler$2; - var rangeLength = isSelectionCollapsed ? 0 : currentRange.toString().length; +// TODO: bundle Flow types with the package. - var tempRange = currentRange.cloneRange(); - tempRange.selectNodeContents(node); - tempRange.setEnd(currentRange.startContainer, currentRange.startOffset); - var isTempRangeCollapsed = isCollapsed(tempRange.startContainer, tempRange.startOffset, tempRange.endContainer, tempRange.endOffset); - var start = isTempRangeCollapsed ? 0 : tempRange.toString().length; - var end = start + rangeLength; +// 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; - // Detect whether the selection is backward. - var detectionRange = document.createRange(); - detectionRange.setStart(anchorNode, anchorOffset); - detectionRange.setEnd(focusNode, focusOffset); - var isBackward = detectionRange.collapsed; +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 { - start: isBackward ? end : start, - end: isBackward ? start : end + // 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 }; } -/** - * 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 setModernOffsets(node, offsets) { - if (!window.getSelection) { - return; - } +// TODO: this is special because it gets imported during build. - var selection = window.getSelection(); - var length = node[getTextContentAccessor_1()].length; - var start = Math.min(offsets.start, length); - var end = offsets.end === undefined ? start : Math.min(offsets.end, length); +var ReactVersion = '16.2.0'; - // 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_1(node, start); - var endMarker = getNodeForCharacterOffset_1(node, end); - - if (startMarker && endMarker) { - var range = document.createRange(); - range.setStart(startMarker.node, startMarker.offset); - selection.removeAllRanges(); +// 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 (start > end) { - selection.addRange(range); - selection.extend(endMarker.node, endMarker.offset); - } else { - range.setEnd(endMarker.node, endMarker.offset); - selection.addRange(range); - } +{ + if (ExecutionEnvironment_1.canUseDOM && typeof requestAnimationFrame !== 'function') { + warning_1(false, 'React depends on requestAnimationFrame. Make sure that you load a ' + 'polyfill in older browsers. http://fb.me/react-polyfills'); } } -var ReactDOMSelection = { - /** - * @param {DOMElement} node - */ - getOffsets: getModernOffsets, - - /** - * @param {DOMElement|DOMTextNode} node - * @param {object} offsets - */ - setOffsets: setModernOffsets -}; - -var ReactDOMSelection_1 = ReactDOMSelection; - -/** - * Copyright (c) 2013-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @typechecks - */ - -/** - * @param {*} object The object to check. - * @return {boolean} Whether or not the object is a DOM node. - */ -function isNode(object) { - var doc = object ? object.ownerDocument || object : document; - var defaultView = doc.defaultView || window; - return !!(object && (typeof defaultView.Node === 'function' ? object instanceof defaultView.Node : typeof object === 'object' && typeof object.nodeType === 'number' && typeof object.nodeName === 'string')); -} - -var isNode_1 = isNode; +var hasNativePerformanceNow = typeof performance === 'object' && typeof performance.now === 'function'; -/** - * Copyright (c) 2013-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @typechecks - */ - - - -/** - * @param {*} object The object to check. - * @return {boolean} Whether or not the object is a DOM text node. - */ -function isTextNode(object) { - return isNode_1(object) && object.nodeType == 3; +var now = void 0; +if (hasNativePerformanceNow) { + now = function () { + return performance.now(); + }; +} else { + now = function () { + return Date.now(); + }; } -var isTextNode_1 = isTextNode; +// TODO: There's no way to cancel, because Fiber doesn't atm. +var rIC = void 0; +var cIC = void 0; -/** - * Copyright (c) 2013-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * - */ +if (!ExecutionEnvironment_1.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; -/*eslint-disable no-bitwise */ + 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; -/** - * Checks if a given DOM node contains or is another DOM node. - */ -function containsNode(outerNode, innerNode) { - if (!outerNode || !innerNode) { - return false; - } else if (outerNode === innerNode) { - return true; - } else if (isTextNode_1(outerNode)) { - return false; - } else if (isTextNode_1(innerNode)) { - return containsNode(outerNode, innerNode.parentNode); - } else if ('contains' in outerNode) { - return outerNode.contains(innerNode); - } else if (outerNode.compareDocumentPosition) { - return !!(outerNode.compareDocumentPosition(innerNode) & 16); + 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 { - return false; - } -} - -var containsNode_1 = containsNode; - -/** - * Copyright (c) 2013-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - */ - -/** - * @param {DOMElement} node input/textarea to focus - */ - -function focusNode(node) { - // IE8 can throw "Can't move focus to the control because it is invisible, - // not enabled, or of a type that does not accept the focus." for all kinds of - // reasons that are too expensive and fragile to test. - try { - node.focus(); - } catch (e) {} -} - -var focusNode_1 = focusNode; - -/** - * Copyright (c) 2013-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @typechecks - */ - -/* eslint-disable fb-www/typeof-undefined */ - -/** - * Same as document.activeElement but wraps in a try-catch block. In IE it is - * not safe to call document.activeElement if there is nothing focused. - * - * The activeElement will be null only if the document or document body is not - * yet defined. - * - * @param {?DOMDocument} doc Defaults to current document. - * @return {?DOMElement} - */ -function getActiveElement(doc) /*?DOMElement*/{ - doc = doc || (typeof document !== 'undefined' ? document : undefined); - if (typeof doc === 'undefined') { - return null; - } - try { - return doc.activeElement || doc.body; - } catch (e) { - return doc.body; + frameDeadlineObject = { + didTimeout: false, + timeRemaining: function () { + // Fallback to Date.now() + var remaining = frameDeadline - Date.now(); + return remaining > 0 ? remaining : 0; + } + }; } -} - -var getActiveElement_1 = getActiveElement; - -var ELEMENT_NODE$2 = HTMLNodeType_1.ELEMENT_NODE; - - - - - -function isInDocument(node) { - return containsNode_1(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. - */ -var ReactInputSelection = { - hasSelectionCapabilities: function (elem) { - var nodeName = elem && elem.nodeName && elem.nodeName.toLowerCase(); - return nodeName && (nodeName === 'input' && elem.type === 'text' || nodeName === 'textarea' || elem.contentEditable === 'true'); - }, + // 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; + } - getSelectionInformation: function () { - var focusedElem = getActiveElement_1(); - return { - focusedElem: focusedElem, - selectionRange: ReactInputSelection.hasSelectionCapabilities(focusedElem) ? ReactInputSelection.getSelection(focusedElem) : null - }; - }, + isIdleScheduled = false; - /** - * @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. - */ - restoreSelection: function (priorSelectionInformation) { - var curFocusedElem = getActiveElement_1(); - var priorFocusedElem = priorSelectionInformation.focusedElem; - var priorSelectionRange = priorSelectionInformation.selectionRange; - if (curFocusedElem !== priorFocusedElem && isInDocument(priorFocusedElem)) { - if (ReactInputSelection.hasSelectionCapabilities(priorFocusedElem)) { - ReactInputSelection.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$2) { - ancestors.push({ - element: ancestor, - left: ancestor.scrollLeft, - top: ancestor.scrollTop - }); + 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; } - - focusNode_1(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} - */ - getSelection: function (input) { - var selection; - - 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 = ReactDOMSelection_1.getOffsets(input); + // There's still time left in this idle period. + frameDeadlineObject.didTimeout = false; } - 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* - */ - setSelection: function (input, offsets) { - var start = offsets.start; - var end = offsets.end; - if (end === undefined) { - end = start; + 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); - if ('selectionStart' in input) { - input.selectionStart = start; - input.selectionEnd = Math.min(end, input.value.length); + 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 { - ReactDOMSelection_1.setOffsets(input, offsets); + previousFrameTime = nextFrameTime; } - } -}; - -var ReactInputSelection_1 = ReactInputSelection; - -/** - * Copyright (c) 2013-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @providesModule ReactVersion - */ - -var ReactVersion = '16.0.0'; - -/** - * Copyright (c) 2013-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @providesModule findDOMNode - * - */ - - - -var ELEMENT_NODE$3 = HTMLNodeType_1.ELEMENT_NODE; - -var ReactCurrentOwner$3 = ReactGlobalSharedState_1.ReactCurrentOwner; - - - - -{ - var warning$29 = warning_1; -} - -var findFiber = function (arg) { - invariant_1(false, 'Missing injection for fiber findDOMNode'); -}; -var findStack = function (arg) { - invariant_1(false, 'Missing injection for stack findDOMNode'); -}; - -var findDOMNode = function (componentOrElement) { - { - var owner = ReactCurrentOwner$3.current; - if (owner !== null) { - var isFiber = typeof owner.tag === 'number'; - var warnedAboutRefsInRender = isFiber ? owner.stateNode._warnedAboutRefsInRender : owner._warnedAboutRefsInRender; - warning$29(warnedAboutRefsInRender, '%s is accessing findDOMNode inside its render(). ' + 'render() should be a pure function of props and state. It should ' + 'never access something that requires stale data from the previous ' + 'render, such as refs. Move this logic to componentDidMount and ' + 'componentDidUpdate instead.', getComponentName_1(owner) || 'A component'); - if (isFiber) { - owner.stateNode._warnedAboutRefsInRender = true; - } else { - owner._warnedAboutRefsInRender = true; - } + frameDeadline = rafTime + activeFrameTime; + if (!isIdleScheduled) { + isIdleScheduled = true; + window.postMessage(messageKey, '*'); } - } - if (componentOrElement == null) { - return null; - } - if (componentOrElement.nodeType === ELEMENT_NODE$3) { - return componentOrElement; - } + }; - var inst = ReactInstanceMap_1.get(componentOrElement); - if (inst) { - if (typeof inst.tag === 'number') { - return findFiber(inst); - } else { - return findStack(inst); + 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 (typeof componentOrElement.render === 'function') { - invariant_1(false, 'Unable to find node on an unmounted component.'); - } else { - invariant_1(false, 'Element appears to be neither ReactComponent nor DOMNode. Keys: %s', Object.keys(componentOrElement)); - } -}; - -findDOMNode._injectFiber = function (fn) { - findFiber = fn; -}; -findDOMNode._injectStack = function (fn) { - findStack = fn; -}; - -var findDOMNode_1 = findDOMNode; + 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; + }; -/** - * Copyright (c) 2014-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @providesModule lowPriorityWarning - */ + cIC = function () { + scheduledRICCallback = null; + isIdleScheduled = false; + timeoutTime = -1; + }; +} else { + rIC = window.requestIdleCallback; + cIC = window.cancelIdleCallback; +} /** * Forked from fbjs/warning: @@ -15112,7 +12050,7 @@ var findDOMNode_1 = findDOMNode; * same logic and follow the same code paths. */ -var lowPriorityWarning$1 = function () {}; +var lowPriorityWarning = function () {}; { var printWarning$1 = function (format) { @@ -15135,7 +12073,7 @@ var lowPriorityWarning$1 = function () {}; } catch (x) {} }; - lowPriorityWarning$1 = function (condition, format) { + lowPriorityWarning = function (condition, format) { if (format === undefined) { throw new Error('`warning(condition, format, ...args)` requires a warning ' + 'message argument'); } @@ -15149,1398 +12087,1141 @@ var lowPriorityWarning$1 = function () {}; }; } -var lowPriorityWarning_1 = lowPriorityWarning$1; - -var validateDOMNesting$1 = emptyFunction_1; +var lowPriorityWarning$1 = lowPriorityWarning; -{ - var warning$30 = warning_1; - - var _require$13 = ReactDebugCurrentFiber_1, - getCurrentFiberStackAddendum$6 = _require$13.getCurrentFiberStackAddendum; - - // This validation code was written based on the HTML5 parsing spec: - // https://html.spec.whatwg.org/multipage/syntax.html#has-an-element-in-scope - // - // Note: this does not catch all invalid nesting, nor does it try to (as it's - // not clear what practical benefit doing so provides); instead, we warn only - // for cases where the parser will give a parse tree differing from what React - // intended. For example, <b><div></div></b> is invalid but we don't warn - // because it still parses correctly; we do warn for other cases like nested - // <p> tags where the beginning of the second element implicitly closes the - // first, causing a confusing mess. - - // https://html.spec.whatwg.org/multipage/syntax.html#special +// 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_1(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; +} - var specialTags = ['address', 'applet', 'area', 'article', 'aside', 'base', 'basefont', 'bgsound', 'blockquote', 'body', 'br', 'button', 'caption', 'center', 'col', 'colgroup', 'dd', 'details', 'dir', 'div', 'dl', 'dt', 'embed', 'fieldset', 'figcaption', 'figure', 'footer', 'form', 'frame', 'frameset', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'head', 'header', 'hgroup', 'hr', 'html', 'iframe', 'img', 'input', 'isindex', 'li', 'link', 'listing', 'main', 'marquee', 'menu', 'menuitem', 'meta', 'nav', 'noembed', 'noframes', 'noscript', 'object', 'ol', 'p', 'param', 'plaintext', 'pre', 'script', 'section', 'select', 'source', 'style', 'summary', 'table', 'tbody', 'td', 'template', 'textarea', 'tfoot', 'th', 'thead', 'title', 'tr', 'track', 'ul', 'wbr', 'xmp']; +/** + * Operations for dealing with DOM properties. + */ - // https://html.spec.whatwg.org/multipage/syntax.html#has-an-element-in-scope - var inScopeTags = ['applet', 'caption', 'html', 'table', 'td', 'th', 'marquee', 'object', 'template', - // https://html.spec.whatwg.org/multipage/syntax.html#html-integration-point - // TODO: Distinguish by namespace here -- for <title>, including it here - // errs on the side of fewer warnings - 'foreignObject', 'desc', 'title']; - // https://html.spec.whatwg.org/multipage/syntax.html#has-an-element-in-button-scope - var buttonScopeTags = inScopeTags.concat(['button']); - // https://html.spec.whatwg.org/multipage/syntax.html#generate-implied-end-tags - var impliedEndTags = ['dd', 'dt', 'li', 'option', 'optgroup', 'p', 'rp', 'rt']; - var emptyAncestorInfo = { - current: null, +/** + * 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; - formTag: null, - aTagInScope: null, - buttonTagInScope: null, - nobrTagInScope: null, - pTagInButtonScope: null, + var stringValue = null; - listItemTagAutoclosing: null, - dlItemTagAutoclosing: 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); + } - var updatedAncestorInfo$1 = function (oldInfo, tag, instance) { - var ancestorInfo = assign({}, oldInfo || emptyAncestorInfo); - var info = { tag: tag, instance: instance }; + if (shouldIgnoreValue(propertyInfo, expected)) { + return stringValue === null ? expected : stringValue; + } else if (stringValue === '' + expected) { + return expected; + } else { + return stringValue; + } + } + } + } +} - if (inScopeTags.indexOf(tag) !== -1) { - ancestorInfo.aTagInScope = null; - ancestorInfo.buttonTagInScope = null; - ancestorInfo.nobrTagInScope = null; +/** + * 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 (buttonScopeTags.indexOf(tag) !== -1) { - ancestorInfo.pTagInButtonScope = null; + if (!node.hasAttribute(name)) { + return expected === undefined ? undefined : null; + } + var value = node.getAttribute(name); + if (value === '' + expected) { + return expected; } + return value; + } +} - // See rules for 'li', 'dd', 'dt' start tags in - // https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-inbody - if (specialTags.indexOf(tag) !== -1 && tag !== 'address' && tag !== 'div' && tag !== 'p') { - ancestorInfo.listItemTagAutoclosing = null; - ancestorInfo.dlItemTagAutoclosing = null; +/** + * 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; + } - ancestorInfo.current = info; + { + + } +} - if (tag === 'form') { - ancestorInfo.formTag = info; - } - if (tag === 'a') { - ancestorInfo.aTagInScope = info; - } - if (tag === 'button') { - ancestorInfo.buttonTagInScope = info; - } - if (tag === 'nobr') { - ancestorInfo.nobrTagInScope = info; - } - if (tag === 'p') { - ancestorInfo.pTagInButtonScope = info; - } - if (tag === 'li') { - ancestorInfo.listItemTagAutoclosing = info; - } - if (tag === 'dd' || tag === 'dt') { - ancestorInfo.dlItemTagAutoclosing = info; - } +function setValueForAttribute(node, name, value) { + if (!isAttributeNameSafe(name)) { + return; + } + if (value == null) { + node.removeAttribute(name); + } else { + node.setAttribute(name, '' + value); + } - return ancestorInfo; - }; + { + + } +} - /** - * Returns whether - */ - var isTagValidWithParent = function (tag, parentTag) { - // First, let's check if we're in an unusual parsing mode... - switch (parentTag) { - // https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-inselect - case 'select': - return tag === 'option' || tag === 'optgroup' || tag === '#text'; - case 'optgroup': - return tag === 'option' || tag === '#text'; - // Strictly speaking, seeing an <option> doesn't mean we're in a <select> - // but - case 'option': - return tag === '#text'; - // https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-intd - // https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-incaption - // No special behavior since these rules fall back to "in body" mode for - // all except special table nodes which cause bad parsing behavior anyway. +/** + * Deletes an attributes from a node. + * + * @param {DOMElement} node + * @param {string} name + */ +function deleteValueForAttribute(node, name) { + node.removeAttribute(name); +} - // https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-intr - case 'tr': - return tag === 'th' || tag === 'td' || tag === 'style' || tag === 'script' || tag === 'template'; - // https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-intbody - case 'tbody': - case 'thead': - case 'tfoot': - return tag === 'tr' || tag === 'style' || tag === 'script' || tag === 'template'; - // https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-incolgroup - case 'colgroup': - return tag === 'col' || tag === 'template'; - // https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-intable - case 'table': - return tag === 'caption' || tag === 'colgroup' || tag === 'tbody' || tag === 'tfoot' || tag === 'thead' || tag === 'style' || tag === 'script' || tag === 'template'; - // https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-inhead - case 'head': - return tag === 'base' || tag === 'basefont' || tag === 'bgsound' || tag === 'link' || tag === 'meta' || tag === 'title' || tag === 'noscript' || tag === 'noframes' || tag === 'style' || tag === 'script' || tag === 'template'; - // https://html.spec.whatwg.org/multipage/semantics.html#the-html-element - case 'html': - return tag === 'head' || tag === 'body'; - case '#document': - return tag === 'html'; +/** + * 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); + } +} - // Probably in the "in body" parsing mode, so we outlaw only tag combos - // where the parsing rules cause implicit opens or closes to be added. - // https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-inbody - switch (tag) { - case 'h1': - case 'h2': - case 'h3': - case 'h4': - case 'h5': - case 'h6': - return parentTag !== 'h1' && parentTag !== 'h2' && parentTag !== 'h3' && parentTag !== 'h4' && parentTag !== 'h5' && parentTag !== 'h6'; +var ReactControlledValuePropTypes = { + checkPropTypes: null +}; - case 'rp': - case 'rt': - return impliedEndTags.indexOf(parentTag) === -1; +{ + var hasReadOnlyValue = { + button: true, + checkbox: true, + image: true, + hidden: true, + radio: true, + reset: true, + submit: true + }; - case 'body': - case 'caption': - case 'col': - case 'colgroup': - case 'frame': - case 'head': - case 'html': - case 'tbody': - case 'td': - case 'tfoot': - case 'th': - case 'thead': - case 'tr': - // These tags are only valid with a few parents that have special child - // parsing rules -- if we're down here, then none of those matched and - // so we allow it only if we don't know what the parent is, as all other - // cases are invalid. - return parentTag == null; + 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`.'); } - - return true; }; /** - * Returns whether + * Provide a linked `value` attribute for controlled forms. You should not use + * this outside of the ReactDOM controlled form components. */ - var findInvalidAncestorForTag = function (tag, ancestorInfo) { - switch (tag) { - case 'address': - case 'article': - case 'aside': - case 'blockquote': - case 'center': - case 'details': - case 'dialog': - case 'dir': - case 'div': - case 'dl': - case 'fieldset': - case 'figcaption': - case 'figure': - case 'footer': - case 'header': - case 'hgroup': - case 'main': - case 'menu': - case 'nav': - case 'ol': - case 'p': - case 'section': - case 'summary': - case 'ul': - case 'pre': - case 'listing': - case 'table': - case 'hr': - case 'xmp': - case 'h1': - case 'h2': - case 'h3': - case 'h4': - case 'h5': - case 'h6': - return ancestorInfo.pTagInButtonScope; + ReactControlledValuePropTypes.checkPropTypes = function (tagName, props, getStack) { + checkPropTypes_1(propTypes, props, 'prop', tagName, getStack); + }; +} - case 'form': - return ancestorInfo.formTag || ancestorInfo.pTagInButtonScope; +// TODO: direct imports like some-package/src/* are bad. Fix me. +var getCurrentFiberOwnerName$2 = ReactDebugCurrentFiber.getCurrentFiberOwnerName; +var getCurrentFiberStackAddendum$3 = ReactDebugCurrentFiber.getCurrentFiberStackAddendum; - case 'li': - return ancestorInfo.listItemTagAutoclosing; +var didWarnValueDefaultValue = false; +var didWarnCheckedDefaultChecked = false; +var didWarnControlledToUncontrolled = false; +var didWarnUncontrolledToControlled = false; - case 'dd': - case 'dt': - return ancestorInfo.dlItemTagAutoclosing; +function isControlled(props) { + var usesChecked = props.type === 'checkbox' || props.type === 'radio'; + return usesChecked ? props.checked != null : props.value != null; +} - case 'button': - return ancestorInfo.buttonTagInScope; +/** + * Implements an <input> 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 + */ - case 'a': - // Spec says something about storing a list of markers, but it sounds - // equivalent to this check. - return ancestorInfo.aTagInScope; +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 + }); - case 'nobr': - return ancestorInfo.nobrTagInScope; - } + return hostProps; +} - return null; - }; +function initWrapperState(element, props) { + { + ReactControlledValuePropTypes.checkPropTypes('input', props, getCurrentFiberStackAddendum$3); - /** - * Given a ReactCompositeComponent instance, return a list of its recursive - * owners, starting at the root and ending with the instance itself. - */ - var findOwnerStack = function (instance) { - if (!instance) { - return []; + if (props.checked !== undefined && props.defaultChecked !== undefined && !didWarnCheckedDefaultChecked) { + warning_1(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; } - - var stack = []; - do { - stack.push(instance); - } while (instance = instance._currentElement._owner); - stack.reverse(); - return stack; - }; - - var getOwnerInfo = function (childInstance, childTag, ancestorInstance, ancestorTag, isParent) { - var childOwner = childInstance && childInstance._currentElement._owner; - var ancestorOwner = ancestorInstance && ancestorInstance._currentElement._owner; - - var childOwners = findOwnerStack(childOwner); - var ancestorOwners = findOwnerStack(ancestorOwner); - - var minStackLen = Math.min(childOwners.length, ancestorOwners.length); - var i; - - var deepestCommon = -1; - for (i = 0; i < minStackLen; i++) { - if (childOwners[i] === ancestorOwners[i]) { - deepestCommon = i; - } else { - break; - } + if (props.value !== undefined && props.defaultValue !== undefined && !didWarnValueDefaultValue) { + warning_1(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 UNKNOWN = '(unknown)'; - var childOwnerNames = childOwners.slice(deepestCommon + 1).map(function (inst) { - return getComponentName_1(inst) || UNKNOWN; - }); - var ancestorOwnerNames = ancestorOwners.slice(deepestCommon + 1).map(function (inst) { - return getComponentName_1(inst) || UNKNOWN; - }); - var ownerInfo = [].concat( - // If the parent and child instances have a common owner ancestor, start - // with that -- otherwise we just start with the parent's owners. - deepestCommon !== -1 ? getComponentName_1(childOwners[deepestCommon]) || UNKNOWN : [], ancestorOwnerNames, ancestorTag, - // If we're warning about an invalid (non-parent) ancestry, add '...' - isParent ? [] : ['...'], childOwnerNames, childTag).join(' > '); - - return ownerInfo; + 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) }; +} - var didWarn = {}; +function updateChecked(element, props) { + var node = element; + var checked = props.checked; + if (checked != null) { + setValueForProperty(node, 'checked', checked); + } +} - validateDOMNesting$1 = function (childTag, childText, childInstance, ancestorInfo) { - ancestorInfo = ancestorInfo || emptyAncestorInfo; - var parentInfo = ancestorInfo.current; - var parentTag = parentInfo && parentInfo.tag; +function updateWrapper(element, props) { + var node = element; + { + var controlled = isControlled(props); - if (childText != null) { - warning$30(childTag == null, 'validateDOMNesting: when childText is passed, childTag should be null'); - childTag = '#text'; + if (!node._wrapperState.controlled && controlled && !didWarnUncontrolledToControlled) { + warning_1(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; } - - var invalidParent = isTagValidWithParent(childTag, parentTag) ? null : parentInfo; - var invalidAncestor = invalidParent ? null : findInvalidAncestorForTag(childTag, ancestorInfo); - var invalidParentOrAncestor = invalidParent || invalidAncestor; - if (!invalidParentOrAncestor) { - return; + if (node._wrapperState.controlled && !controlled && !didWarnControlledToUncontrolled) { + warning_1(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; } + } - var ancestorInstance = invalidParentOrAncestor.instance; - var ancestorTag = invalidParentOrAncestor.tag; - var addendum; - - if (childInstance != null) { - addendum = ' See ' + getOwnerInfo(childInstance, childTag, ancestorInstance, ancestorTag, !!invalidParent) + '.'; - } else { - addendum = getCurrentFiberStackAddendum$6(); - } + updateChecked(element, props); - var warnKey = !!invalidParent + '|' + childTag + '|' + ancestorTag + '|' + addendum; - if (didWarn[warnKey]) { - return; - } - didWarn[warnKey] = true; + 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; - var tagDisplayName = childTag; - var whitespaceInfo = ''; - if (childTag === '#text') { - if (/\S/.test(childText)) { - tagDisplayName = 'Text nodes'; - } else { - tagDisplayName = 'Whitespace text nodes'; - whitespaceInfo = " Make sure you don't have any extra whitespace between tags on " + 'each line of your source code.'; + 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 { - tagDisplayName = '<' + childTag + '>'; + } 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; } - - if (invalidParent) { - var info = ''; - if (ancestorTag === 'table' && childTag === 'tr') { - info += ' Add a <tbody> to your code to match the DOM tree generated by ' + 'the browser.'; + } 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 <x> 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; } - warning$30(false, 'validateDOMNesting(...): %s cannot appear as a child of <%s>.%s%s%s', tagDisplayName, ancestorTag, whitespaceInfo, info, addendum); - } else { - warning$30(false, 'validateDOMNesting(...): %s cannot appear as a descendant of ' + '<%s>.%s', tagDisplayName, ancestorTag, addendum); } - }; - - validateDOMNesting$1.updatedAncestorInfo = updatedAncestorInfo$1; - - // For testing - validateDOMNesting$1.isTagValidInContext = function (tag, ancestorInfo) { - ancestorInfo = ancestorInfo || emptyAncestorInfo; - var parentInfo = ancestorInfo.current; - var parentTag = parentInfo && parentInfo.tag; - return isTagValidWithParent(tag, parentTag) && !findInvalidAncestorForTag(tag, ancestorInfo); - }; + if (props.checked == null && props.defaultChecked != null) { + node.defaultChecked = !!props.defaultChecked; + } + } } -var validateDOMNesting_1 = validateDOMNesting$1; +function postMountWrapper(element, props) { + var node = element; -var HostComponent$11 = ReactTypeOfWork.HostComponent; + // 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. -function getParent(inst) { - if (inst._hostParent !== undefined) { - return inst._hostParent; - } - if (typeof inst.tag === 'number') { - do { - inst = inst['return']; - // TODO: If this is a HostRoot we might want to bail out. - // That is depending on if we want nested subtrees (layers) to bubble - // events to their parent. We could also go through parentNode on the - // host node but that wouldn't work for React Native and doesn't let us - // do the portal feature. - } while (inst && inst.tag !== HostComponent$11); - if (inst) { - return inst; - } + 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; } - return null; -} -/** - * Return the lowest common ancestor of A and B, or null if they are in - * different trees. - */ -function getLowestCommonAncestor(instA, instB) { - var depthA = 0; - for (var tempA = instA; tempA; tempA = getParent(tempA)) { - depthA++; + // 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 = ''; } - var depthB = 0; - for (var tempB = instB; tempB; tempB = getParent(tempB)) { - depthB++; + node.defaultChecked = !node.defaultChecked; + node.defaultChecked = !node.defaultChecked; + if (name !== '') { + node.name = name; } +} - // If A is deeper, crawl up. - while (depthA - depthB > 0) { - instA = getParent(instA); - depthA--; - } +function restoreControlledState$1(element, props) { + var node = element; + updateWrapper(node, props); + updateNamedCousins(node, props); +} - // If B is deeper, crawl up. - while (depthB - depthA > 0) { - instB = getParent(instB); - depthB--; - } +function updateNamedCousins(rootNode, props) { + var name = props.name; + if (props.type === 'radio' && name != null) { + var queryRoot = rootNode; - // Walk in lockstep until we find a match. - var depth = depthA; - while (depth--) { - if (instA === instB || instA === instB.alternate) { - return instA; + while (queryRoot.parentNode) { + queryRoot = queryRoot.parentNode; } - instA = getParent(instA); - instB = getParent(instB); - } - return null; -} -/** - * Return if A is an ancestor of B. - */ -function isAncestor(instA, instB) { - while (instB) { - if (instA === instB || instA === instB.alternate) { - return true; - } - instB = getParent(instB); - } - return false; -} + // 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"]'); -/** - * Return the parent instance of the passed-in instance. - */ -function getParentInstance(inst) { - return getParent(inst); -} + 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_1(false, 'ReactDOMInput: Mixing React and non-React radio inputs with the same `name` is not supported.') : void 0; -/** - * Simulates the traversal of a two-phase, capture/bubble event dispatch. - */ -function traverseTwoPhase(inst, fn, arg) { - var path = []; - while (inst) { - path.push(inst); - inst = getParent(inst); - } - var i; - for (i = path.length; i-- > 0;) { - fn(path[i], 'captured', arg); - } - for (i = 0; i < path.length; i++) { - fn(path[i], 'bubbled', arg); - } -} + // 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); -/** - * Traverses the ID hierarchy and invokes the supplied `cb` on any IDs that - * should would receive a `mouseEnter` or `mouseLeave` event. - * - * Does not invoke the callback on the nearest common ancestor because nothing - * "entered" or "left" that element. - */ -function traverseEnterLeave(from, to, fn, argFrom, argTo) { - var common = from && to ? getLowestCommonAncestor(from, to) : null; - var pathFrom = []; - while (from && from !== common) { - pathFrom.push(from); - from = getParent(from); - } - var pathTo = []; - while (to && to !== common) { - pathTo.push(to); - to = getParent(to); - } - var i; - for (i = 0; i < pathFrom.length; i++) { - fn(pathFrom[i], 'bubbled', argFrom); - } - for (i = pathTo.length; i-- > 0;) { - fn(pathTo[i], 'captured', argTo); + // 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); + } } } -var ReactTreeTraversal = { - isAncestor: isAncestor, - getLowestCommonAncestor: getLowestCommonAncestor, - getParentInstance: getParentInstance, - traverseTwoPhase: traverseTwoPhase, - traverseEnterLeave: traverseEnterLeave -}; +function flattenChildren(children) { + var content = ''; -var getListener = EventPluginHub_1.getListener; + // 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; + } + }); -{ - var warning$31 = warning_1; + return content; } /** - * Some event types have a notion of different registration names for different - * "phases" of propagation. This finds listeners by a given phase. + * Implements an <option> host component that warns when `selected` is set. */ -function listenerAtPhase(inst, event, propagationPhase) { - var registrationName = event.dispatchConfig.phasedRegistrationNames[propagationPhase]; - return getListener(inst, registrationName); -} -/** - * Tags a `SyntheticEvent` with dispatched listeners. Creating this function - * here, allows us to not have to bind or create functions for each event. - * Mutating the event's members allows us to not have to create a wrapping - * "dispatch" object that pairs the event with the listener. - */ -function accumulateDirectionalDispatches(inst, phase, event) { +function validateProps(element, props) { + // TODO (yungsters): Remove support for `selected` in <option>. { - warning$31(inst, 'Dispatching inst must not be null'); - } - var listener = listenerAtPhase(inst, event, phase); - if (listener) { - event._dispatchListeners = accumulateInto_1(event._dispatchListeners, listener); - event._dispatchInstances = accumulateInto_1(event._dispatchInstances, inst); + warning_1(props.selected == null, 'Use the `defaultValue` or `value` props on <select> instead of ' + 'setting `selected` on <option>.'); } } -/** - * Collect dispatches (must be entirely collected before dispatching - see unit - * tests). Lazily allocate the array to conserve memory. We must loop through - * each event and perform the traversal for each one. We cannot perform a - * single traversal for the entire collection of events because each event may - * have a different target. - */ -function accumulateTwoPhaseDispatchesSingle(event) { - if (event && event.dispatchConfig.phasedRegistrationNames) { - ReactTreeTraversal.traverseTwoPhase(event._targetInst, accumulateDirectionalDispatches, event); +function postMountWrapper$1(element, props) { + // value="" should make a value attribute (#6219) + if (props.value != null) { + element.setAttribute('value', props.value); } } -/** - * Same as `accumulateTwoPhaseDispatchesSingle`, but skips over the targetID. - */ -function accumulateTwoPhaseDispatchesSingleSkipTarget(event) { - if (event && event.dispatchConfig.phasedRegistrationNames) { - var targetInst = event._targetInst; - var parentInst = targetInst ? ReactTreeTraversal.getParentInstance(targetInst) : null; - ReactTreeTraversal.traverseTwoPhase(parentInst, accumulateDirectionalDispatches, event); - } -} +function getHostProps$1(element, props) { + var hostProps = _assign({ children: undefined }, props); + var content = flattenChildren(props.children); -/** - * Accumulates without regard to direction, does not look for phased - * registration names. Same as `accumulateDirectDispatchesSingle` but without - * requiring that the `dispatchMarker` be the same as the dispatched ID. - */ -function accumulateDispatches(inst, ignoredDirection, event) { - if (inst && event && event.dispatchConfig.registrationName) { - var registrationName = event.dispatchConfig.registrationName; - var listener = getListener(inst, registrationName); - if (listener) { - event._dispatchListeners = accumulateInto_1(event._dispatchListeners, listener); - event._dispatchInstances = accumulateInto_1(event._dispatchInstances, inst); - } + if (content) { + hostProps.children = content; } -} -/** - * Accumulates dispatches on an `SyntheticEvent`, but only for the - * `dispatchMarker`. - * @param {SyntheticEvent} event - */ -function accumulateDirectDispatchesSingle(event) { - if (event && event.dispatchConfig.registrationName) { - accumulateDispatches(event._targetInst, null, event); - } + return hostProps; } -function accumulateTwoPhaseDispatches(events) { - forEachAccumulated_1(events, accumulateTwoPhaseDispatchesSingle); -} +// TODO: direct imports like some-package/src/* are bad. Fix me. +var getCurrentFiberOwnerName$3 = ReactDebugCurrentFiber.getCurrentFiberOwnerName; +var getCurrentFiberStackAddendum$4 = ReactDebugCurrentFiber.getCurrentFiberStackAddendum; -function accumulateTwoPhaseDispatchesSkipTarget(events) { - forEachAccumulated_1(events, accumulateTwoPhaseDispatchesSingleSkipTarget); -} -function accumulateEnterLeaveDispatches(leave, enter, from, to) { - ReactTreeTraversal.traverseEnterLeave(from, to, accumulateDispatches, leave, enter); +{ + var didWarnValueDefaultValue$1 = false; } -function accumulateDirectDispatches(events) { - forEachAccumulated_1(events, accumulateDirectDispatchesSingle); +function getDeclarationErrorAddendum() { + var ownerName = getCurrentFiberOwnerName$3(); + if (ownerName) { + return '\n\nCheck the render method of `' + ownerName + '`.'; + } + return ''; } -/** - * A small set of propagation patterns, each of which will accept a small amount - * of information, and generate a set of "dispatch ready event objects" - which - * are sets of events that have already been annotated with a set of dispatched - * listener functions/ids. The API is designed this way to discourage these - * propagation strategies from actually executing the dispatches, since we - * always want to collect the entire set of dispatches before executing even a - * single one. - * - * @constructor EventPropagators - */ -var EventPropagators = { - accumulateTwoPhaseDispatches: accumulateTwoPhaseDispatches, - accumulateTwoPhaseDispatchesSkipTarget: accumulateTwoPhaseDispatchesSkipTarget, - accumulateDirectDispatches: accumulateDirectDispatches, - accumulateEnterLeaveDispatches: accumulateEnterLeaveDispatches -}; - -var EventPropagators_1 = EventPropagators; +var valuePropNames = ['value', 'defaultValue']; /** - * This helper object stores information about text content of a target node, - * allowing comparison of content before and after a given event. - * - * Identify the node where selection currently begins, then observe - * both its text content and its current position in the DOM. Since the - * browser may natively replace the target node during composition, we can - * use its position to find its replacement. - * - * + * Validation function for `value` and `defaultValue`. */ -var compositionState = { - _root: null, - _startText: null, - _fallbackText: null -}; +function checkSelectPropTypes(props) { + ReactControlledValuePropTypes.checkPropTypes('select', props, getCurrentFiberStackAddendum$4); -var FallbackCompositionState = { - initialize: function (nativeEventTarget) { - compositionState._root = nativeEventTarget; - compositionState._startText = FallbackCompositionState.getText(); - return true; - }, - reset: function () { - compositionState._root = null; - compositionState._startText = null; - compositionState._fallbackText = null; - }, - getData: function () { - if (compositionState._fallbackText) { - return compositionState._fallbackText; + for (var i = 0; i < valuePropNames.length; i++) { + var propName = valuePropNames[i]; + if (props[propName] == null) { + continue; } + var isArray = Array.isArray(props[propName]); + if (props.multiple && !isArray) { + warning_1(false, 'The `%s` prop supplied to <select> must be an array if ' + '`multiple` is true.%s', propName, getDeclarationErrorAddendum()); + } else if (!props.multiple && isArray) { + warning_1(false, 'The `%s` prop supplied to <select> must be a scalar ' + 'value if `multiple` is false.%s', propName, getDeclarationErrorAddendum()); + } + } +} - var start; - var startValue = compositionState._startText; - var startLength = startValue.length; - var end; - var endValue = FallbackCompositionState.getText(); - var endLength = endValue.length; +function updateOptions(node, multiple, propValue, setDefaultSelected) { + var options = node.options; - for (start = 0; start < startLength; start++) { - if (startValue[start] !== endValue[start]) { - break; + if (multiple) { + var selectedValues = propValue; + var selectedValue = {}; + for (var i = 0; i < selectedValues.length; i++) { + // Prefix to avoid chaos with special keys. + selectedValue['$' + selectedValues[i]] = true; + } + for (var _i = 0; _i < options.length; _i++) { + var selected = selectedValue.hasOwnProperty('$' + options[_i].value); + if (options[_i].selected !== selected) { + options[_i].selected = selected; + } + if (selected && setDefaultSelected) { + options[_i].defaultSelected = true; } } - - var minEnd = startLength - start; - for (end = 1; end <= minEnd; end++) { - if (startValue[startLength - end] !== endValue[endLength - end]) { - break; + } else { + // Do not set `select.value` as exact behavior isn't consistent across all + // browsers for all cases. + var _selectedValue = '' + propValue; + var defaultSelected = null; + for (var _i2 = 0; _i2 < options.length; _i2++) { + if (options[_i2].value === _selectedValue) { + options[_i2].selected = true; + if (setDefaultSelected) { + options[_i2].defaultSelected = true; + } + return; + } + if (defaultSelected === null && !options[_i2].disabled) { + defaultSelected = options[_i2]; } } - - var sliceTail = end > 1 ? 1 - end : undefined; - compositionState._fallbackText = endValue.slice(start, sliceTail); - return compositionState._fallbackText; - }, - getText: function () { - if ('value' in compositionState._root) { - return compositionState._root.value; + if (defaultSelected !== null) { + defaultSelected.selected = true; } - return compositionState._root[getTextContentAccessor_1()]; } -}; - -var FallbackCompositionState_1 = FallbackCompositionState; - -var didWarnForAddedNewProperty = false; -var isProxySupported = typeof Proxy === 'function'; -var EVENT_POOL_SIZE = 10; - -{ - var warning$32 = warning_1; } -var shouldBeReleasedProperties = ['dispatchConfig', '_targetInst', 'nativeEvent', 'isDefaultPrevented', 'isPropagationStopped', '_dispatchListeners', '_dispatchInstances']; - /** - * @interface Event - * @see http://www.w3.org/TR/DOM-Level-3-Events/ - */ -var EventInterface = { - type: null, - target: null, - // currentTarget is set when dispatching; no use in copying it here - currentTarget: emptyFunction_1.thatReturnsNull, - eventPhase: null, - bubbles: null, - cancelable: null, - timeStamp: function (event) { - return event.timeStamp || Date.now(); - }, - defaultPrevented: null, - isTrusted: null -}; - -/** - * Synthetic events are dispatched by event plugins, typically in response to a - * top-level event delegation handler. + * Implements a <select> host component that allows optionally setting the + * props `value` and `defaultValue`. If `multiple` is false, the prop must be a + * stringable. If `multiple` is true, the prop must be an array of stringables. * - * These systems should generally use pooling to reduce the frequency of garbage - * collection. The system should check `isPersistent` to determine whether the - * event should be released into the pool after being dispatched. Users that - * need a persisted event should invoke `persist`. + * If `value` is not supplied (or null/undefined), user actions that change the + * selected option will trigger updates to the rendered options. * - * Synthetic events (and subclasses) implement the DOM Level 3 Events API by - * normalizing browser quirks. Subclasses do not necessarily have to implement a - * DOM interface; custom application-specific events can also subclass this. + * If it is supplied (and not null/undefined), the rendered options will not + * update in response to user actions. Instead, the `value` prop must change in + * order for the rendered options to update. * - * @param {object} dispatchConfig Configuration used to dispatch this event. - * @param {*} targetInst Marker identifying the event target. - * @param {object} nativeEvent Native browser event. - * @param {DOMEventTarget} nativeEventTarget Target node. + * If `defaultValue` is provided, any options with the supplied values will be + * selected. */ -function SyntheticEvent(dispatchConfig, targetInst, nativeEvent, nativeEventTarget) { + +function getHostProps$2(element, props) { + return _assign({}, props, { + value: undefined + }); +} + +function initWrapperState$1(element, props) { + var node = element; { - // these have a getter/setter for warnings - delete this.nativeEvent; - delete this.preventDefault; - delete this.stopPropagation; + checkSelectPropTypes(props); } - this.dispatchConfig = dispatchConfig; - this._targetInst = targetInst; - this.nativeEvent = nativeEvent; + var value = props.value; + node._wrapperState = { + initialValue: value != null ? value : props.defaultValue, + wasMultiple: !!props.multiple + }; - var Interface = this.constructor.Interface; - for (var propName in Interface) { - if (!Interface.hasOwnProperty(propName)) { - continue; - } - { - delete this[propName]; // this has a getter/setter for warnings - } - var normalize = Interface[propName]; - if (normalize) { - this[propName] = normalize(nativeEvent); - } else { - if (propName === 'target') { - this.target = nativeEventTarget; - } else { - this[propName] = nativeEvent[propName]; - } + { + if (props.value !== undefined && props.defaultValue !== undefined && !didWarnValueDefaultValue$1) { + warning_1(false, 'Select 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 select ' + 'element and remove one of these props. More info: ' + 'https://fb.me/react-controlled-components'); + didWarnValueDefaultValue$1 = true; } } +} - var defaultPrevented = nativeEvent.defaultPrevented != null ? nativeEvent.defaultPrevented : nativeEvent.returnValue === false; - if (defaultPrevented) { - this.isDefaultPrevented = emptyFunction_1.thatReturnsTrue; - } else { - this.isDefaultPrevented = emptyFunction_1.thatReturnsFalse; +function postMountWrapper$2(element, props) { + var node = element; + node.multiple = !!props.multiple; + var value = props.value; + if (value != null) { + updateOptions(node, !!props.multiple, value, false); + } else if (props.defaultValue != null) { + updateOptions(node, !!props.multiple, props.defaultValue, true); } - this.isPropagationStopped = emptyFunction_1.thatReturnsFalse; - return this; } -assign(SyntheticEvent.prototype, { - preventDefault: function () { - this.defaultPrevented = true; - var event = this.nativeEvent; - if (!event) { - return; - } +function postUpdateWrapper(element, props) { + var node = element; + // After the initial mount, we control selected-ness manually so don't pass + // this value down + node._wrapperState.initialValue = undefined; - if (event.preventDefault) { - event.preventDefault(); - } else if (typeof event.returnValue !== 'unknown') { - event.returnValue = false; - } - this.isDefaultPrevented = emptyFunction_1.thatReturnsTrue; - }, + var wasMultiple = node._wrapperState.wasMultiple; + node._wrapperState.wasMultiple = !!props.multiple; - stopPropagation: function () { - var event = this.nativeEvent; - if (!event) { - return; - } - - if (event.stopPropagation) { - event.stopPropagation(); - } else if (typeof event.cancelBubble !== 'unknown') { - // The ChangeEventPlugin registers a "propertychange" event for - // IE. This event does not support bubbling or cancelling, and - // any references to cancelBubble throw "Member not found". A - // typeof check of "unknown" circumvents this issue (and is also - // IE specific). - event.cancelBubble = true; + var value = props.value; + if (value != null) { + updateOptions(node, !!props.multiple, value, false); + } else if (wasMultiple !== !!props.multiple) { + // For simplicity, reapply `defaultValue` if `multiple` is toggled. + if (props.defaultValue != null) { + updateOptions(node, !!props.multiple, props.defaultValue, true); + } else { + // Revert the select back to its default unselected state. + updateOptions(node, !!props.multiple, props.multiple ? [] : '', false); } + } +} - this.isPropagationStopped = emptyFunction_1.thatReturnsTrue; - }, - - /** - * We release all dispatched `SyntheticEvent`s after each event loop, adding - * them back into the pool. This allows a way to hold onto a reference that - * won't be added back into the pool. - */ - persist: function () { - this.isPersistent = emptyFunction_1.thatReturnsTrue; - }, - - /** - * Checks if this event should be released back into the pool. - * - * @return {boolean} True if this should not be released, false otherwise. - */ - isPersistent: emptyFunction_1.thatReturnsFalse, +function restoreControlledState$2(element, props) { + var node = element; + var value = props.value; - /** - * `PooledClass` looks for `destructor` on each instance it releases. - */ - destructor: function () { - var Interface = this.constructor.Interface; - for (var propName in Interface) { - { - Object.defineProperty(this, propName, getPooledWarningPropertyDefinition(propName, Interface[propName])); - } - } - for (var i = 0; i < shouldBeReleasedProperties.length; i++) { - this[shouldBeReleasedProperties[i]] = null; - } - { - Object.defineProperty(this, 'nativeEvent', getPooledWarningPropertyDefinition('nativeEvent', null)); - Object.defineProperty(this, 'preventDefault', getPooledWarningPropertyDefinition('preventDefault', emptyFunction_1)); - Object.defineProperty(this, 'stopPropagation', getPooledWarningPropertyDefinition('stopPropagation', emptyFunction_1)); - } + if (value != null) { + updateOptions(node, !!props.multiple, value, false); } -}); +} -SyntheticEvent.Interface = EventInterface; +// TODO: direct imports like some-package/src/* are bad. Fix me. +var getCurrentFiberStackAddendum$5 = ReactDebugCurrentFiber.getCurrentFiberStackAddendum; + +var didWarnValDefaultVal = false; /** - * Helper to reduce boilerplate when creating subclasses. + * Implements a <textarea> host component that allows setting `value`, and + * `defaultValue`. This differs from the traditional DOM API because value is + * usually set as PCDATA children. * - * @param {function} Class - * @param {?object} Interface + * If `value` is not supplied (or null/undefined), user actions that affect the + * value will trigger updates to the element. + * + * If `value` is supplied (and not null/undefined), the rendered element will + * not trigger updates to the element. Instead, the `value` prop must change in + * order for the rendered element to be updated. + * + * The rendered element will be initialized with an empty value, the prop + * `defaultValue` if specified, or the children content (deprecated). */ -SyntheticEvent.augmentClass = function (Class, Interface) { - var Super = this; - var E = function () {}; - E.prototype = Super.prototype; - var prototype = new E(); - - assign(prototype, Class.prototype); - Class.prototype = prototype; - Class.prototype.constructor = Class; +function getHostProps$3(element, props) { + var node = element; + !(props.dangerouslySetInnerHTML == null) ? invariant_1(false, '`dangerouslySetInnerHTML` does not make sense on <textarea>.') : void 0; + + // Always set children to the same thing. In IE9, the selection range will + // get reset if `textContent` is mutated. We could add a check in setTextContent + // to only set the value if/when the value differs from the node value (which would + // completely solve this IE9 bug), but Sebastian+Sophie seemed to like this + // solution. The value can be a boolean or object so that's why it's forced + // to be a string. + var hostProps = _assign({}, props, { + value: undefined, + defaultValue: undefined, + children: '' + node._wrapperState.initialValue + }); - Class.Interface = assign({}, Super.Interface, Interface); - Class.augmentClass = Super.augmentClass; - addEventPoolingTo(Class); -}; + return hostProps; +} -/** Proxying after everything set on SyntheticEvent - * to resolve Proxy issue on some WebKit browsers - * in which some Event properties are set to undefined (GH#10010) - */ -{ - if (isProxySupported) { - /*eslint-disable no-func-assign */ - SyntheticEvent = new Proxy(SyntheticEvent, { - construct: function (target, args) { - return this.apply(target, Object.create(target.prototype), args); - }, - apply: function (constructor, that, args) { - return new Proxy(constructor.apply(that, args), { - set: function (target, prop, value) { - if (prop !== 'isPersistent' && !target.constructor.Interface.hasOwnProperty(prop) && shouldBeReleasedProperties.indexOf(prop) === -1) { - warning$32(didWarnForAddedNewProperty || target.isPersistent(), "This synthetic event is reused for performance reasons. If you're " + "seeing this, you're adding a new property in the synthetic event object. " + 'The property is never released. See ' + 'https://fb.me/react-event-pooling for more information.'); - didWarnForAddedNewProperty = true; - } - target[prop] = value; - return true; - } - }); - } - }); - /*eslint-enable no-func-assign */ +function initWrapperState$2(element, props) { + var node = element; + { + ReactControlledValuePropTypes.checkPropTypes('textarea', props, getCurrentFiberStackAddendum$5); + if (props.value !== undefined && props.defaultValue !== undefined && !didWarnValDefaultVal) { + warning_1(false, 'Textarea 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 textarea ' + 'and remove one of these props. More info: ' + 'https://fb.me/react-controlled-components'); + didWarnValDefaultVal = true; + } } -} -addEventPoolingTo(SyntheticEvent); + var initialValue = props.value; -var SyntheticEvent_1 = SyntheticEvent; + // Only bother fetching default value if we're going to use it + if (initialValue == null) { + var defaultValue = props.defaultValue; + // TODO (yungsters): Remove support for children content in <textarea>. + var children = props.children; + if (children != null) { + { + warning_1(false, 'Use the `defaultValue` or `value` props instead of setting ' + 'children on <textarea>.'); + } + !(defaultValue == null) ? invariant_1(false, 'If you supply `defaultValue` on a <textarea>, do not pass children.') : void 0; + if (Array.isArray(children)) { + !(children.length <= 1) ? invariant_1(false, '<textarea> can only have at most one child.') : void 0; + children = children[0]; + } -/** - * Helper to nullify syntheticEvent instance properties when destructing - * - * @param {String} propName - * @param {?object} getVal - * @return {object} defineProperty object - */ -function getPooledWarningPropertyDefinition(propName, getVal) { - var isFunction = typeof getVal === 'function'; - return { - configurable: true, - set: set, - get: get + defaultValue = '' + children; + } + if (defaultValue == null) { + defaultValue = ''; + } + initialValue = defaultValue; + } + + node._wrapperState = { + initialValue: '' + initialValue }; +} - function set(val) { - var action = isFunction ? 'setting the method' : 'setting the property'; - warn(action, 'This is effectively a no-op'); - return val; - } +function updateWrapper$1(element, props) { + var node = element; + var value = props.value; + if (value != null) { + // Cast `value` to a string to ensure the value is set correctly. While + // browsers typically do this as necessary, jsdom doesn't. + var newValue = '' + value; - function get() { - var action = isFunction ? 'accessing the method' : 'accessing the property'; - var result = isFunction ? 'This is a no-op function' : 'This is set to null'; - warn(action, result); - return getVal; + // To avoid side effects (such as losing text selection), only set value if changed + if (newValue !== node.value) { + node.value = newValue; + } + if (props.defaultValue == null) { + node.defaultValue = newValue; + } } - - function warn(action, result) { - var warningCondition = false; - warning$32(warningCondition, "This synthetic event is reused for performance reasons. If you're seeing this, " + "you're %s `%s` on a released/nullified synthetic event. %s. " + 'If you must keep the original synthetic event around, use event.persist(). ' + 'See https://fb.me/react-event-pooling for more information.', action, propName, result); + if (props.defaultValue != null) { + node.defaultValue = props.defaultValue; } } -function getPooledEvent(dispatchConfig, targetInst, nativeEvent, nativeInst) { - var EventConstructor = this; - if (EventConstructor.eventPool.length) { - var instance = EventConstructor.eventPool.pop(); - EventConstructor.call(instance, dispatchConfig, targetInst, nativeEvent, nativeInst); - return instance; - } - return new EventConstructor(dispatchConfig, targetInst, nativeEvent, nativeInst); -} +function postMountWrapper$3(element, props) { + var node = element; + // This is in postMount because we need access to the DOM node, which is not + // available until after the component has mounted. + var textContent = node.textContent; -function releasePooledEvent(event) { - var EventConstructor = this; - !(event instanceof EventConstructor) ? invariant_1(false, 'Trying to release an event instance into a pool of a different type.') : void 0; - event.destructor(); - if (EventConstructor.eventPool.length < EVENT_POOL_SIZE) { - EventConstructor.eventPool.push(event); + // Only set node.value if textContent is equal to the expected + // initial value. In IE10/IE11 there is a bug where the placeholder attribute + // will populate textContent as well. + // https://developer.microsoft.com/microsoft-edge/platform/issues/101525/ + if (textContent === node._wrapperState.initialValue) { + node.value = textContent; } } -function addEventPoolingTo(EventConstructor) { - EventConstructor.eventPool = []; - EventConstructor.getPooled = getPooledEvent; - EventConstructor.release = releasePooledEvent; +function restoreControlledState$3(element, props) { + // DOM component is still mounted; update + updateWrapper$1(element, props); } -/** - * @interface Event - * @see http://www.w3.org/TR/DOM-Level-3-Events/#events-compositionevents - */ -var CompositionEventInterface = { - data: 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 SyntheticCompositionEvent(dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget) { - return SyntheticEvent_1.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget); -} - -SyntheticEvent_1.augmentClass(SyntheticCompositionEvent, CompositionEventInterface); - -var SyntheticCompositionEvent_1 = SyntheticCompositionEvent; +var HTML_NAMESPACE$1 = 'http://www.w3.org/1999/xhtml'; +var MATH_NAMESPACE = 'http://www.w3.org/1998/Math/MathML'; +var SVG_NAMESPACE = 'http://www.w3.org/2000/svg'; -/** - * @interface Event - * @see http://www.w3.org/TR/2013/WD-DOM-Level-3-Events-20131105 - * /#events-inputevents - */ -var InputEventInterface = { - data: null +var Namespaces = { + html: HTML_NAMESPACE$1, + mathml: MATH_NAMESPACE, + svg: SVG_NAMESPACE }; -/** - * @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 SyntheticInputEvent(dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget) { - return SyntheticEvent_1.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget); +// Assumes there is no parent namespace. +function getIntrinsicNamespace(type) { + switch (type) { + case 'svg': + return SVG_NAMESPACE; + case 'math': + return MATH_NAMESPACE; + default: + return HTML_NAMESPACE$1; + } } -SyntheticEvent_1.augmentClass(SyntheticInputEvent, InputEventInterface); - -var SyntheticInputEvent_1 = SyntheticInputEvent; - -var END_KEYCODES = [9, 13, 27, 32]; // Tab, Return, Esc, Space -var START_KEYCODE = 229; - -var canUseCompositionEvent = ExecutionEnvironment_1.canUseDOM && 'CompositionEvent' in window; - -var documentMode = null; -if (ExecutionEnvironment_1.canUseDOM && 'documentMode' in document) { - documentMode = document.documentMode; +function getChildNamespace(parentNamespace, type) { + if (parentNamespace == null || parentNamespace === HTML_NAMESPACE$1) { + // No (or default) parent namespace: potential entry point. + return getIntrinsicNamespace(type); + } + if (parentNamespace === SVG_NAMESPACE && type === 'foreignObject') { + // We're leaving SVG. + return HTML_NAMESPACE$1; + } + // By default, pass namespace below. + return parentNamespace; } -// Webkit offers a very useful `textInput` event that can be used to -// directly represent `beforeInput`. The IE `textinput` event is not as -// useful, so we don't use it. -var canUseTextInputEvent = ExecutionEnvironment_1.canUseDOM && 'TextEvent' in window && !documentMode && !isPresto(); - -// In IE9+, we have access to composition events, but the data supplied -// by the native compositionend event may be incorrect. Japanese ideographic -// spaces, for instance (\u3000) are not recorded correctly. -var useFallbackCompositionData = ExecutionEnvironment_1.canUseDOM && (!canUseCompositionEvent || documentMode && documentMode > 8 && documentMode <= 11); +/* globals MSApp */ /** - * Opera <= 12 includes TextEvent in window, but does not fire - * text input events. Rely on keypress instead. + * Create a function which has 'unsafe' privileges (required by windows8 apps) */ -function isPresto() { - var opera = window.opera; - return typeof opera === 'object' && typeof opera.version === 'function' && parseInt(opera.version(), 10) <= 12; -} - -var SPACEBAR_CODE = 32; -var SPACEBAR_CHAR = String.fromCharCode(SPACEBAR_CODE); - -// Events and their corresponding property names. -var eventTypes = { - beforeInput: { - phasedRegistrationNames: { - bubbled: 'onBeforeInput', - captured: 'onBeforeInputCapture' - }, - dependencies: ['topCompositionEnd', 'topKeyPress', 'topTextInput', 'topPaste'] - }, - compositionEnd: { - phasedRegistrationNames: { - bubbled: 'onCompositionEnd', - captured: 'onCompositionEndCapture' - }, - dependencies: ['topBlur', 'topCompositionEnd', 'topKeyDown', 'topKeyPress', 'topKeyUp', 'topMouseDown'] - }, - compositionStart: { - phasedRegistrationNames: { - bubbled: 'onCompositionStart', - captured: 'onCompositionStartCapture' - }, - dependencies: ['topBlur', 'topCompositionStart', 'topKeyDown', 'topKeyPress', 'topKeyUp', 'topMouseDown'] - }, - compositionUpdate: { - phasedRegistrationNames: { - bubbled: 'onCompositionUpdate', - captured: 'onCompositionUpdateCapture' - }, - dependencies: ['topBlur', 'topCompositionUpdate', 'topKeyDown', 'topKeyPress', 'topKeyUp', 'topMouseDown'] +var createMicrosoftUnsafeLocalFunction = function (func) { + if (typeof MSApp !== 'undefined' && MSApp.execUnsafeLocalFunction) { + return function (arg0, arg1, arg2, arg3) { + MSApp.execUnsafeLocalFunction(function () { + return func(arg0, arg1, arg2, arg3); + }); + }; + } else { + return func; } }; -// Track whether we've ever handled a keypress on the space key. -var hasSpaceKeypress = false; +// SVG temp container for IE lacking innerHTML +var reusableSVGContainer = void 0; /** - * Return whether a native keypress event is assumed to be a command. - * This is required because Firefox fires `keypress` events for key commands - * (cut, copy, select-all, etc.) even though no character is inserted. + * Set the innerHTML property of a node + * + * @param {DOMElement} node + * @param {string} html + * @internal */ -function isKeypressCommand(nativeEvent) { - return (nativeEvent.ctrlKey || nativeEvent.altKey || nativeEvent.metaKey) && - // ctrlKey && altKey is equivalent to AltGr, and is not a command. - !(nativeEvent.ctrlKey && nativeEvent.altKey); -} +var setInnerHTML = createMicrosoftUnsafeLocalFunction(function (node, html) { + // IE does not have innerHTML for SVG nodes, so instead we inject the + // new markup in a temp node and then move the child nodes across into + // the target node + + if (node.namespaceURI === Namespaces.svg && !('innerHTML' in node)) { + reusableSVGContainer = reusableSVGContainer || document.createElement('div'); + reusableSVGContainer.innerHTML = '<svg>' + html + '</svg>'; + var svgNode = reusableSVGContainer.firstChild; + while (node.firstChild) { + node.removeChild(node.firstChild); + } + while (svgNode.firstChild) { + node.appendChild(svgNode.firstChild); + } + } else { + node.innerHTML = html; + } +}); /** - * Translate native top level events into event types. + * Set the textContent property of a node, ensuring that whitespace is preserved + * even in IE8. innerText is a poor substitute for textContent and, among many + * issues, inserts <br> instead of the literal newline chars. innerHTML behaves + * as it should. * - * @param {string} topLevelType - * @return {object} + * @param {DOMElement} node + * @param {string} text + * @internal */ -function getCompositionEventType(topLevelType) { - switch (topLevelType) { - case 'topCompositionStart': - return eventTypes.compositionStart; - case 'topCompositionEnd': - return eventTypes.compositionEnd; - case 'topCompositionUpdate': - return eventTypes.compositionUpdate; +var setTextContent = function (node, text) { + if (text) { + var firstChild = node.firstChild; + + if (firstChild && firstChild === node.lastChild && firstChild.nodeType === TEXT_NODE) { + firstChild.nodeValue = text; + return; + } } -} + node.textContent = text; +}; /** - * Does our fallback best-guess model think this event signifies that - * composition has begun? - * - * @param {string} topLevelType - * @param {object} nativeEvent - * @return {boolean} + * CSS properties which accept numbers but are not in units of "px". */ -function isFallbackCompositionStart(topLevelType, nativeEvent) { - return topLevelType === 'topKeyDown' && nativeEvent.keyCode === START_KEYCODE; -} +var isUnitlessNumber = { + animationIterationCount: true, + borderImageOutset: true, + borderImageSlice: true, + borderImageWidth: true, + boxFlex: true, + boxFlexGroup: true, + boxOrdinalGroup: true, + columnCount: true, + columns: true, + flex: true, + flexGrow: true, + flexPositive: true, + flexShrink: true, + flexNegative: true, + flexOrder: true, + gridRow: true, + gridRowEnd: true, + gridRowSpan: true, + gridRowStart: true, + gridColumn: true, + gridColumnEnd: true, + gridColumnSpan: true, + gridColumnStart: true, + fontWeight: true, + lineClamp: true, + lineHeight: true, + opacity: true, + order: true, + orphans: true, + tabSize: true, + widows: true, + zIndex: true, + zoom: true, + + // SVG-related properties + fillOpacity: true, + floodOpacity: true, + stopOpacity: true, + strokeDasharray: true, + strokeDashoffset: true, + strokeMiterlimit: true, + strokeOpacity: true, + strokeWidth: true +}; /** - * Does our fallback mode think that this event is the end of composition? - * - * @param {string} topLevelType - * @param {object} nativeEvent - * @return {boolean} + * @param {string} prefix vendor-specific prefix, eg: Webkit + * @param {string} key style name, eg: transitionDuration + * @return {string} style name prefixed with `prefix`, properly camelCased, eg: + * WebkitTransitionDuration */ -function isFallbackCompositionEnd(topLevelType, nativeEvent) { - switch (topLevelType) { - case 'topKeyUp': - // Command keys insert or clear IME input. - return END_KEYCODES.indexOf(nativeEvent.keyCode) !== -1; - case 'topKeyDown': - // Expect IME keyCode on each keydown. If we get any other - // code we must have exited earlier. - return nativeEvent.keyCode !== START_KEYCODE; - case 'topKeyPress': - case 'topMouseDown': - case 'topBlur': - // Events are not possible without cancelling IME. - return true; - default: - return false; - } +function prefixKey(prefix, key) { + return prefix + key.charAt(0).toUpperCase() + key.substring(1); } /** - * Google Input Tools provides composition data via a CustomEvent, - * with the `data` property populated in the `detail` object. If this - * is available on the event object, use it. If not, this is a plain - * composition event and we have nothing special to extract. - * - * @param {object} nativeEvent - * @return {?string} + * Support style names that may come passed in prefixed by adding permutations + * of vendor prefixes. */ -function getDataFromCustomEvent(nativeEvent) { - var detail = nativeEvent.detail; - if (typeof detail === 'object' && 'data' in detail) { - return detail.data; - } - return null; -} +var prefixes = ['Webkit', 'ms', 'Moz', 'O']; -// Track the current IME composition status, if any. -var isComposing = false; +// Using Object.keys here, or else the vanilla for-in loop makes IE8 go into an +// infinite loop, because it iterates over the newly added props too. +Object.keys(isUnitlessNumber).forEach(function (prop) { + prefixes.forEach(function (prefix) { + isUnitlessNumber[prefixKey(prefix, prop)] = isUnitlessNumber[prop]; + }); +}); /** - * @return {?object} A SyntheticCompositionEvent. + * Convert a value into the proper css writable value. The style name `name` + * should be logical (no hyphens), as specified + * in `CSSProperty.isUnitlessNumber`. + * + * @param {string} name CSS property name such as `topMargin`. + * @param {*} value CSS property value such as `10px`. + * @return {string} Normalized style value with dimensions applied. */ -function extractCompositionEvent(topLevelType, targetInst, nativeEvent, nativeEventTarget) { - var eventType; - var fallbackData; +function dangerousStyleValue(name, value, isCustomProperty) { + // Note that we've removed escapeTextForBrowser() calls here since the + // whole string will be escaped when the attribute is injected into + // the markup. If you provide unsafe user data here they can inject + // arbitrary CSS which may be problematic (I couldn't repro this): + // https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet + // http://www.thespanner.co.uk/2007/11/26/ultimate-xss-css-injection/ + // This is not an XSS hole but instead a potential CSS injection issue + // which has lead to a greater discussion about how we're going to + // trust URLs moving forward. See #2115901 - if (canUseCompositionEvent) { - eventType = getCompositionEventType(topLevelType); - } else if (!isComposing) { - if (isFallbackCompositionStart(topLevelType, nativeEvent)) { - eventType = eventTypes.compositionStart; - } - } else if (isFallbackCompositionEnd(topLevelType, nativeEvent)) { - eventType = eventTypes.compositionEnd; + var isEmpty = value == null || typeof value === 'boolean' || value === ''; + if (isEmpty) { + return ''; } - if (!eventType) { - return null; + if (!isCustomProperty && typeof value === 'number' && value !== 0 && !(isUnitlessNumber.hasOwnProperty(name) && isUnitlessNumber[name])) { + return value + 'px'; // Presumes implicit 'px' suffix for unitless numbers } - if (useFallbackCompositionData) { - // The current composition is stored statically and must not be - // overwritten while composition continues. - if (!isComposing && eventType === eventTypes.compositionStart) { - isComposing = FallbackCompositionState_1.initialize(nativeEventTarget); - } else if (eventType === eventTypes.compositionEnd) { - if (isComposing) { - fallbackData = FallbackCompositionState_1.getData(); - } - } - } + return ('' + value).trim(); +} - var event = SyntheticCompositionEvent_1.getPooled(eventType, targetInst, nativeEvent, nativeEventTarget); +/** + * Copyright (c) 2013-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @typechecks + */ - if (fallbackData) { - // Inject data generated from fallback path into the synthetic event. - // This matches the property of native CompositionEventInterface. - event.data = fallbackData; - } else { - var customData = getDataFromCustomEvent(nativeEvent); - if (customData !== null) { - event.data = customData; - } - } +var _uppercasePattern = /([A-Z])/g; - EventPropagators_1.accumulateTwoPhaseDispatches(event); - return event; +/** + * Hyphenates a camelcased string, for example: + * + * > hyphenate('backgroundColor') + * < "background-color" + * + * For CSS style names, use `hyphenateStyleName` instead which works properly + * with all vendor prefixes, including `ms`. + * + * @param {string} string + * @return {string} + */ +function hyphenate(string) { + return string.replace(_uppercasePattern, '-$1').toLowerCase(); } +var hyphenate_1 = hyphenate; + /** - * @param {TopLevelTypes} topLevelType Record from `BrowserEventConstants`. - * @param {object} nativeEvent Native browser event. - * @return {?string} The string corresponding to this `beforeInput` event. + * Copyright (c) 2013-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @typechecks */ -function getNativeBeforeInputChars(topLevelType, nativeEvent) { - switch (topLevelType) { - case 'topCompositionEnd': - return getDataFromCustomEvent(nativeEvent); - case 'topKeyPress': - /** - * If native `textInput` events are available, our goal is to make - * use of them. However, there is a special case: the spacebar key. - * In Webkit, preventing default on a spacebar `textInput` event - * cancels character insertion, but it *also* causes the browser - * to fall back to its default spacebar behavior of scrolling the - * page. - * - * Tracking at: - * https://code.google.com/p/chromium/issues/detail?id=355103 - * - * To avoid this issue, use the keypress event as if no `textInput` - * event is available. - */ - var which = nativeEvent.which; - if (which !== SPACEBAR_CODE) { - return null; - } - hasSpaceKeypress = true; - return SPACEBAR_CHAR; - case 'topTextInput': - // Record the characters to be added to the DOM. - var chars = nativeEvent.data; - // If it's a spacebar character, assume that we have already handled - // it at the keypress level and bail immediately. Android Chrome - // doesn't give us keycodes, so we need to blacklist it. - if (chars === SPACEBAR_CHAR && hasSpaceKeypress) { - return null; - } - return chars; - default: - // For other native event types, do nothing. - return null; - } -} +var msPattern = /^ms-/; /** - * For browsers that do not provide the `textInput` event, extract the - * appropriate string to use for SyntheticInputEvent. + * Hyphenates a camelcased CSS property name, for example: * - * @param {string} topLevelType Record from `BrowserEventConstants`. - * @param {object} nativeEvent Native browser event. - * @return {?string} The fallback string for this `beforeInput` event. + * > hyphenateStyleName('backgroundColor') + * < "background-color" + * > hyphenateStyleName('MozTransition') + * < "-moz-transition" + * > hyphenateStyleName('msTransition') + * < "-ms-transition" + * + * As Modernizr suggests (http://modernizr.com/docs/#prefixed), an `ms` prefix + * is converted to `-ms-`. + * + * @param {string} string + * @return {string} */ -function getFallbackBeforeInputChars(topLevelType, nativeEvent) { - // If we are currently composing (IME) and using a fallback to do so, - // try to extract the composed characters from the fallback object. - // If composition event is available, we extract a string only at - // compositionevent, otherwise extract it at fallback events. - if (isComposing) { - if (topLevelType === 'topCompositionEnd' || !canUseCompositionEvent && isFallbackCompositionEnd(topLevelType, nativeEvent)) { - var chars = FallbackCompositionState_1.getData(); - FallbackCompositionState_1.reset(); - isComposing = false; - return chars; - } - return null; - } - - switch (topLevelType) { - case 'topPaste': - // If a paste event occurs after a keypress, throw out the input - // chars. Paste events should not lead to BeforeInput events. - return null; - case 'topKeyPress': - /** - * As of v27, Firefox may fire keypress events even when no character - * will be inserted. A few possibilities: - * - * - `which` is `0`. Arrow keys, Esc key, etc. - * - * - `which` is the pressed key code, but no char is available. - * Ex: 'AltGr + d` in Polish. There is no modified character for - * this key combination and no character is inserted into the - * document, but FF fires the keypress for char code `100` anyway. - * No `input` event will occur. - * - * - `which` is the pressed key code, but a command combination is - * being used. Ex: `Cmd+C`. No character is inserted, and no - * `input` event will occur. - */ - if (!isKeypressCommand(nativeEvent)) { - // IE fires the `keypress` event when a user types an emoji via - // Touch keyboard of Windows. In such a case, the `char` property - // holds an emoji character like `\uD83D\uDE0A`. Because its length - // is 2, the property `which` does not represent an emoji correctly. - // In such a case, we directly return the `char` property instead of - // using `which`. - if (nativeEvent.char && nativeEvent.char.length > 1) { - return nativeEvent.char; - } else if (nativeEvent.which) { - return String.fromCharCode(nativeEvent.which); - } - } - return null; - case 'topCompositionEnd': - return useFallbackCompositionData ? null : nativeEvent.data; - default: - return null; - } +function hyphenateStyleName(string) { + return hyphenate_1(string).replace(msPattern, '-ms-'); } +var hyphenateStyleName_1 = hyphenateStyleName; + /** - * Extract a SyntheticInputEvent for `beforeInput`, based on either native - * `textInput` or fallback behavior. + * Copyright (c) 2013-present, Facebook, Inc. * - * @return {?object} A SyntheticInputEvent. + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @typechecks */ -function extractBeforeInputEvent(topLevelType, targetInst, nativeEvent, nativeEventTarget) { - var chars; - - if (canUseTextInputEvent) { - chars = getNativeBeforeInputChars(topLevelType, nativeEvent); - } else { - chars = getFallbackBeforeInputChars(topLevelType, nativeEvent); - } - - // If no characters are being inserted, no BeforeInput event should - // be fired. - if (!chars) { - return null; - } - var event = SyntheticInputEvent_1.getPooled(eventTypes.beforeInput, targetInst, nativeEvent, nativeEventTarget); - - event.data = chars; - EventPropagators_1.accumulateTwoPhaseDispatches(event); - return event; -} +var _hyphenPattern = /-(.)/g; /** - * Create an `onBeforeInput` event to match - * http://www.w3.org/TR/2013/WD-DOM-Level-3-Events-20131105/#events-inputevents. - * - * This event plugin is based on the native `textInput` event - * available in Chrome, Safari, Opera, and IE. This event fires after - * `onKeyPress` and `onCompositionEnd`, but before `onInput`. + * Camelcases a hyphenated string, for example: * - * `beforeInput` is spec'd but not implemented in any browsers, and - * the `input` event does not provide any useful information about what has - * actually been added, contrary to the spec. Thus, `textInput` is the best - * available event to identify the characters that have actually been inserted - * into the target node. + * > camelize('background-color') + * < "backgroundColor" * - * This plugin is also responsible for emitting `composition` events, thus - * allowing us to share composition fallback code for both `beforeInput` and - * `composition` event types. + * @param {string} string + * @return {string} */ -var BeforeInputEventPlugin = { - eventTypes: eventTypes, - - extractEvents: function (topLevelType, targetInst, nativeEvent, nativeEventTarget) { - return [extractCompositionEvent(topLevelType, targetInst, nativeEvent, nativeEventTarget), extractBeforeInputEvent(topLevelType, targetInst, nativeEvent, nativeEventTarget)]; - } -}; +function camelize(string) { + return string.replace(_hyphenPattern, function (_, character) { + return character.toUpperCase(); + }); +} -var BeforeInputEventPlugin_1 = BeforeInputEventPlugin; +var camelize_1 = camelize; /** * Copyright (c) 2013-present, Facebook, Inc. @@ -16548,1469 +13229,2318 @@ var BeforeInputEventPlugin_1 = BeforeInputEventPlugin; * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule isTextInputElement - * + * @typechecks */ + + + + +var msPattern$1 = /^-ms-/; + /** - * @see http://www.whatwg.org/specs/web-apps/current-work/multipage/the-input-element.html#input-type-attr-summary + * Camelcases a hyphenated CSS property name, for example: + * + * > camelizeStyleName('background-color') + * < "backgroundColor" + * > camelizeStyleName('-moz-transition') + * < "MozTransition" + * > camelizeStyleName('-ms-transition') + * < "msTransition" + * + * As Andi Smith suggests + * (http://www.andismith.com/blog/2012/02/modernizr-prefixed/), an `-ms` prefix + * is converted to lowercase `ms`. + * + * @param {string} string + * @return {string} */ +function camelizeStyleName(string) { + return camelize_1(string.replace(msPattern$1, 'ms-')); +} -var supportedInputTypes = { - color: true, - date: true, - datetime: true, - 'datetime-local': true, - email: true, - month: true, - number: true, - password: true, - range: true, - search: true, - tel: true, - text: true, - time: true, - url: true, - week: true -}; +var camelizeStyleName_1 = camelizeStyleName; -function isTextInputElement(elem) { - var nodeName = elem && elem.nodeName && elem.nodeName.toLowerCase(); +var warnValidStyle = emptyFunction_1; - if (nodeName === 'input') { - return !!supportedInputTypes[elem.type]; - } +{ + // 'msTransform' is correct, but the other prefixes should be capitalized + var badVendoredStyleNamePattern = /^(?:webkit|moz|o)[A-Z]/; - if (nodeName === 'textarea') { - return true; - } + // style values shouldn't contain a semicolon + var badStyleValueWithSemicolonPattern = /;\s*$/; - return false; -} + var warnedStyleNames = {}; + var warnedStyleValues = {}; + var warnedForNaNValue = false; + var warnedForInfinityValue = false; -var isTextInputElement_1 = isTextInputElement; + var warnHyphenatedStyleName = function (name, getStack) { + if (warnedStyleNames.hasOwnProperty(name) && warnedStyleNames[name]) { + return; + } -var eventTypes$1 = { - change: { - phasedRegistrationNames: { - bubbled: 'onChange', - captured: 'onChangeCapture' - }, - dependencies: ['topBlur', 'topChange', 'topClick', 'topFocus', 'topInput', 'topKeyDown', 'topKeyUp', 'topSelectionChange'] - } -}; + warnedStyleNames[name] = true; + warning_1(false, 'Unsupported style property %s. Did you mean %s?%s', name, camelizeStyleName_1(name), getStack()); + }; -function createAndAccumulateChangeEvent(inst, nativeEvent, target) { - var event = SyntheticEvent_1.getPooled(eventTypes$1.change, inst, nativeEvent, target); - event.type = 'change'; - // Flag this event loop as needing state restore. - ReactControlledComponent_1.enqueueStateRestore(target); - EventPropagators_1.accumulateTwoPhaseDispatches(event); - return event; -} -/** - * For IE shims - */ -var activeElement = null; -var activeElementInst = null; + var warnBadVendoredStyleName = function (name, getStack) { + if (warnedStyleNames.hasOwnProperty(name) && warnedStyleNames[name]) { + return; + } -/** - * SECTION: handle `change` event - */ -function shouldUseChangeEvent(elem) { - var nodeName = elem.nodeName && elem.nodeName.toLowerCase(); - return nodeName === 'select' || nodeName === 'input' && elem.type === 'file'; -} + warnedStyleNames[name] = true; + warning_1(false, 'Unsupported vendor-prefixed style property %s. Did you mean %s?%s', name, name.charAt(0).toUpperCase() + name.slice(1), getStack()); + }; -function manualDispatchChangeEvent(nativeEvent) { - var event = createAndAccumulateChangeEvent(activeElementInst, nativeEvent, getEventTarget_1(nativeEvent)); + var warnStyleValueWithSemicolon = function (name, value, getStack) { + if (warnedStyleValues.hasOwnProperty(value) && warnedStyleValues[value]) { + return; + } - // If change and propertychange bubbled, we'd just bind to it like all the - // other events and have it go through ReactBrowserEventEmitter. Since it - // doesn't, we manually listen for the events and so we have to enqueue and - // process the abstract event manually. - // - // Batching is necessary here in order to ensure that all event handlers run - // before the next rerender (including event handlers attached to ancestor - // elements instead of directly on the input). Without this, controlled - // components don't work properly in conjunction with event bubbling because - // the component is rerendered and the value reverted before all the event - // handlers can run. See https://github.com/facebook/react/issues/708. - ReactGenericBatching_1.batchedUpdates(runEventInBatch, event); -} + warnedStyleValues[value] = true; + warning_1(false, "Style property values shouldn't contain a semicolon. " + 'Try "%s: %s" instead.%s', name, value.replace(badStyleValueWithSemicolonPattern, ''), getStack()); + }; -function runEventInBatch(event) { - EventPluginHub_1.enqueueEvents(event); - EventPluginHub_1.processEventQueue(false); -} + var warnStyleValueIsNaN = function (name, value, getStack) { + if (warnedForNaNValue) { + return; + } -function getInstIfValueChanged(targetInst) { - var targetNode = ReactDOMComponentTree_1.getNodeFromInstance(targetInst); - if (inputValueTracking_1.updateValueIfChanged(targetNode)) { - return targetInst; - } -} + warnedForNaNValue = true; + warning_1(false, '`NaN` is an invalid value for the `%s` css style property.%s', name, getStack()); + }; -function getTargetInstForChangeEvent(topLevelType, targetInst) { - if (topLevelType === 'topChange') { - return targetInst; - } + var warnStyleValueIsInfinity = function (name, value, getStack) { + if (warnedForInfinityValue) { + return; + } + + warnedForInfinityValue = true; + warning_1(false, '`Infinity` is an invalid value for the `%s` css style property.%s', name, getStack()); + }; + + warnValidStyle = function (name, value, getStack) { + if (name.indexOf('-') > -1) { + warnHyphenatedStyleName(name, getStack); + } else if (badVendoredStyleNamePattern.test(name)) { + warnBadVendoredStyleName(name, getStack); + } else if (badStyleValueWithSemicolonPattern.test(value)) { + warnStyleValueWithSemicolon(name, value, getStack); + } + + if (typeof value === 'number') { + if (isNaN(value)) { + warnStyleValueIsNaN(name, value, getStack); + } else if (!isFinite(value)) { + warnStyleValueIsInfinity(name, value, getStack); + } + } + }; } +var warnValidStyle$1 = warnValidStyle; + /** - * SECTION: handle `input` event + * Operations for dealing with CSS properties. */ -var isInputEventSupported = false; -if (ExecutionEnvironment_1.canUseDOM) { - // IE9 claims to support the input event but fails to trigger it when - // deleting text, so we ignore its input events. - isInputEventSupported = isEventSupported_1('input') && (!document.documentMode || document.documentMode > 9); -} /** - * (For IE <=9) Starts tracking propertychange events on the passed-in element - * and override the value property so that we can distinguish user events from - * value changes in JS. + * This creates a string that is expected to be equivalent to the style + * attribute generated by server-side rendering. It by-passes warnings and + * security checks so it's not safe to use this value for anything other than + * comparison. It is only used in DEV for SSR validation. */ -function startWatchingForValueChange(target, targetInst) { - activeElement = target; - activeElementInst = targetInst; - activeElement.attachEvent('onpropertychange', handlePropertyChange); +function createDangerousStringForStyles(styles) { + { + var serialized = ''; + var delimiter = ''; + for (var styleName in styles) { + if (!styles.hasOwnProperty(styleName)) { + continue; + } + var styleValue = styles[styleName]; + if (styleValue != null) { + var isCustomProperty = styleName.indexOf('--') === 0; + serialized += delimiter + hyphenateStyleName_1(styleName) + ':'; + serialized += dangerousStyleValue(styleName, styleValue, isCustomProperty); + + delimiter = ';'; + } + } + return serialized || null; + } } /** - * (For IE <=9) Removes the event listeners from the currently-tracked element, - * if any exists. + * Sets the value for multiple styles on a node. If a value is specified as + * '' (empty string), the corresponding style property will be unset. + * + * @param {DOMElement} node + * @param {object} styles */ -function stopWatchingForValueChange() { - if (!activeElement) { - return; +function setValueForStyles(node, styles, getStack) { + var style = node.style; + for (var styleName in styles) { + if (!styles.hasOwnProperty(styleName)) { + continue; + } + var isCustomProperty = styleName.indexOf('--') === 0; + { + if (!isCustomProperty) { + warnValidStyle$1(styleName, styles[styleName], getStack); + } + } + var styleValue = dangerousStyleValue(styleName, styles[styleName], isCustomProperty); + if (styleName === 'float') { + styleName = 'cssFloat'; + } + if (isCustomProperty) { + style.setProperty(styleName, styleValue); + } else { + style[styleName] = styleValue; + } } - activeElement.detachEvent('onpropertychange', handlePropertyChange); - activeElement = null; - activeElementInst = null; } -/** - * (For IE <=9) Handles a propertychange event, sending a `change` event if - * the value of the active element has changed. - */ -function handlePropertyChange(nativeEvent) { - if (nativeEvent.propertyName !== 'value') { +// For HTML, certain tags should omit their close tag. We keep a whitelist for +// those special-case tags. + +var omittedCloseTags = { + area: true, + base: true, + br: true, + col: true, + embed: true, + hr: true, + img: true, + input: true, + keygen: true, + link: true, + meta: true, + param: true, + source: true, + track: true, + wbr: true +}; + +// For HTML, certain tags cannot have children. This has the same purpose as +// `omittedCloseTags` except that `menuitem` should still have its closing tag. + +var voidElementTags = _assign({ + menuitem: true +}, omittedCloseTags); + +var HTML$1 = '__html'; + +function assertValidProps(tag, props, getStack) { + if (!props) { return; } - if (getInstIfValueChanged(activeElementInst)) { - manualDispatchChangeEvent(nativeEvent); + // Note the use of `==` which checks for null or undefined. + if (voidElementTags[tag]) { + !(props.children == null && props.dangerouslySetInnerHTML == null) ? invariant_1(false, '%s is a void element tag and must neither have `children` nor use `dangerouslySetInnerHTML`.%s', tag, getStack()) : void 0; } -} - -function handleEventsForInputEventPolyfill(topLevelType, target, targetInst) { - if (topLevelType === 'topFocus') { - // In IE9, propertychange fires for most input events but is buggy and - // doesn't fire when text is deleted, but conveniently, selectionchange - // appears to fire in all of the remaining cases so we catch those and - // forward the event if the value has changed - // In either case, we don't want to call the event handler if the value - // is changed from JS so we redefine a setter for `.value` that updates - // our activeElementValue variable, allowing us to ignore those changes - // - // stopWatching() should be a noop here but we call it just in case we - // missed a blur event somehow. - stopWatchingForValueChange(); - startWatchingForValueChange(target, targetInst); - } else if (topLevelType === 'topBlur') { - stopWatchingForValueChange(); + if (props.dangerouslySetInnerHTML != null) { + !(props.children == null) ? invariant_1(false, 'Can only set one of `children` or `props.dangerouslySetInnerHTML`.') : void 0; + !(typeof props.dangerouslySetInnerHTML === 'object' && HTML$1 in props.dangerouslySetInnerHTML) ? invariant_1(false, '`props.dangerouslySetInnerHTML` must be in the form `{__html: ...}`. Please visit https://fb.me/react-invariant-dangerously-set-inner-html for more information.') : void 0; + } + { + warning_1(props.suppressContentEditableWarning || !props.contentEditable || props.children == null, 'A component is `contentEditable` and contains `children` managed by ' + 'React. It is now your responsibility to guarantee that none of ' + 'those nodes are unexpectedly modified or duplicated. This is ' + 'probably not intentional.%s', getStack()); } + !(props.style == null || typeof props.style === 'object') ? invariant_1(false, 'The `style` prop expects a mapping from style properties to values, not a string. For example, style={{marginRight: spacing + \'em\'}} when using JSX.%s', getStack()) : void 0; } -// For IE8 and IE9. -function getTargetInstForInputEventPolyfill(topLevelType, targetInst) { - if (topLevelType === 'topSelectionChange' || topLevelType === 'topKeyUp' || topLevelType === 'topKeyDown') { - // On the selectionchange event, the target is just document which isn't - // helpful for us so just check activeElement instead. - // - // 99% of the time, keydown and keyup aren't necessary. IE8 fails to fire - // propertychange on the first input event after setting `value` from a - // script and fires only keydown, keypress, keyup. Catching keyup usually - // gets it and catching keydown lets us fire an event for the first - // keystroke if user does a key repeat (it'll be a little delayed: right - // before the second keystroke). Other input methods (e.g., paste) seem to - // fire selectionchange normally. - return getInstIfValueChanged(activeElementInst); +function isCustomComponent(tagName, props) { + if (tagName.indexOf('-') === -1) { + return typeof props.is === 'string'; + } + switch (tagName) { + // These are reserved SVG and MathML elements. + // We don't mind this whitelist too much because we expect it to never grow. + // The alternative is to track the namespace in a few places which is convoluted. + // https://w3c.github.io/webcomponents/spec/custom/#custom-elements-core-concepts + case 'annotation-xml': + case 'color-profile': + case 'font-face': + case 'font-face-src': + case 'font-face-uri': + case 'font-face-format': + case 'font-face-name': + case 'missing-glyph': + return false; + default: + return true; } } -/** - * SECTION: handle `click` event - */ -function shouldUseClickEvent(elem) { - // Use the `click` event to detect changes to checkbox and radio inputs. - // This approach works across all browsers, whereas `change` does not fire - // until `blur` in IE8. - var nodeName = elem.nodeName; - return nodeName && nodeName.toLowerCase() === 'input' && (elem.type === 'checkbox' || elem.type === 'radio'); +var ariaProperties = { + 'aria-current': 0, // state + 'aria-details': 0, + 'aria-disabled': 0, // state + 'aria-hidden': 0, // state + 'aria-invalid': 0, // state + 'aria-keyshortcuts': 0, + 'aria-label': 0, + 'aria-roledescription': 0, + // Widget Attributes + 'aria-autocomplete': 0, + 'aria-checked': 0, + 'aria-expanded': 0, + 'aria-haspopup': 0, + 'aria-level': 0, + 'aria-modal': 0, + 'aria-multiline': 0, + 'aria-multiselectable': 0, + 'aria-orientation': 0, + 'aria-placeholder': 0, + 'aria-pressed': 0, + 'aria-readonly': 0, + 'aria-required': 0, + 'aria-selected': 0, + 'aria-sort': 0, + 'aria-valuemax': 0, + 'aria-valuemin': 0, + 'aria-valuenow': 0, + 'aria-valuetext': 0, + // Live Region Attributes + 'aria-atomic': 0, + 'aria-busy': 0, + 'aria-live': 0, + 'aria-relevant': 0, + // Drag-and-Drop Attributes + 'aria-dropeffect': 0, + 'aria-grabbed': 0, + // Relationship Attributes + 'aria-activedescendant': 0, + 'aria-colcount': 0, + 'aria-colindex': 0, + 'aria-colspan': 0, + 'aria-controls': 0, + 'aria-describedby': 0, + 'aria-errormessage': 0, + 'aria-flowto': 0, + 'aria-labelledby': 0, + 'aria-owns': 0, + 'aria-posinset': 0, + 'aria-rowcount': 0, + 'aria-rowindex': 0, + 'aria-rowspan': 0, + 'aria-setsize': 0 +}; + +var warnedProperties = {}; +var rARIA = new RegExp('^(aria)-[' + ATTRIBUTE_NAME_CHAR + ']*$'); +var rARIACamel = new RegExp('^(aria)[A-Z][' + ATTRIBUTE_NAME_CHAR + ']*$'); + +var hasOwnProperty$1 = Object.prototype.hasOwnProperty; + +function getStackAddendum() { + var stack = ReactDebugCurrentFrame.getStackAddendum(); + return stack != null ? stack : ''; } -function getTargetInstForClickEvent(topLevelType, targetInst) { - if (topLevelType === 'topClick') { - return getInstIfValueChanged(targetInst); +function validateProperty(tagName, name) { + if (hasOwnProperty$1.call(warnedProperties, name) && warnedProperties[name]) { + return true; + } + + if (rARIACamel.test(name)) { + var ariaName = 'aria-' + name.slice(4).toLowerCase(); + var correctName = ariaProperties.hasOwnProperty(ariaName) ? ariaName : null; + + // If this is an aria-* attribute, but is not listed in the known DOM + // DOM properties, then it is an invalid aria-* attribute. + if (correctName == null) { + warning_1(false, 'Invalid ARIA attribute `%s`. ARIA attributes follow the pattern aria-* and must be lowercase.%s', name, getStackAddendum()); + warnedProperties[name] = true; + return true; + } + // aria-* attributes should be lowercase; suggest the lowercase version. + if (name !== correctName) { + warning_1(false, 'Invalid ARIA attribute `%s`. Did you mean `%s`?%s', name, correctName, getStackAddendum()); + warnedProperties[name] = true; + return true; + } } + + if (rARIA.test(name)) { + var lowerCasedName = name.toLowerCase(); + var standardName = ariaProperties.hasOwnProperty(lowerCasedName) ? lowerCasedName : null; + + // If this is an aria-* attribute, but is not listed in the known DOM + // DOM properties, then it is an invalid aria-* attribute. + if (standardName == null) { + warnedProperties[name] = true; + return false; + } + // aria-* attributes should be lowercase; suggest the lowercase version. + if (name !== standardName) { + warning_1(false, 'Unknown ARIA attribute `%s`. Did you mean `%s`?%s', name, standardName, getStackAddendum()); + warnedProperties[name] = true; + return true; + } + } + + return true; } -function getTargetInstForInputOrChangeEvent(topLevelType, targetInst) { - if (topLevelType === 'topInput' || topLevelType === 'topChange') { - return getInstIfValueChanged(targetInst); +function warnInvalidARIAProps(type, props) { + var invalidProps = []; + + for (var key in props) { + var isValid = validateProperty(type, key); + if (!isValid) { + invalidProps.push(key); + } + } + + var unknownPropString = invalidProps.map(function (prop) { + return '`' + prop + '`'; + }).join(', '); + + if (invalidProps.length === 1) { + warning_1(false, 'Invalid aria prop %s on <%s> tag. ' + 'For details, see https://fb.me/invalid-aria-prop%s', unknownPropString, type, getStackAddendum()); + } else if (invalidProps.length > 1) { + warning_1(false, 'Invalid aria props %s on <%s> tag. ' + 'For details, see https://fb.me/invalid-aria-prop%s', unknownPropString, type, getStackAddendum()); } } -function handleControlledInputBlur(inst, node) { - // TODO: In IE, inst is occasionally null. Why? - if (inst == null) { +function validateProperties(type, props) { + if (isCustomComponent(type, props)) { return; } + warnInvalidARIAProps(type, props); +} - // Fiber and ReactDOM keep wrapper state in separate places - var state = inst._wrapperState || node._wrapperState; +var didWarnValueNull = false; - if (!state || !state.controlled || node.type !== 'number') { +function getStackAddendum$1() { + var stack = ReactDebugCurrentFrame.getStackAddendum(); + return stack != null ? stack : ''; +} + +function validateProperties$1(type, props) { + if (type !== 'input' && type !== 'textarea' && type !== 'select') { return; } - // If controlled, assign the value attribute to the current value on blur - var value = '' + node.value; - if (node.getAttribute('value') !== value) { - node.setAttribute('value', value); + if (props != null && props.value === null && !didWarnValueNull) { + didWarnValueNull = true; + if (type === 'select' && props.multiple) { + warning_1(false, '`value` prop on `%s` should not be null. ' + 'Consider using an empty array when `multiple` is set to `true` ' + 'to clear the component or `undefined` for uncontrolled components.%s', type, getStackAddendum$1()); + } else { + warning_1(false, '`value` prop on `%s` should not be null. ' + 'Consider using an empty string to clear the component or `undefined` ' + 'for uncontrolled components.%s', type, getStackAddendum$1()); + } } } -/** - * This plugin creates an `onChange` event that normalizes change events - * across form elements. This event fires at a time when it's possible to - * change the element's value without seeing a flicker. - * - * Supported elements are: - * - input (see `isTextInputElement`) - * - textarea - * - select - */ -var ChangeEventPlugin = { - eventTypes: eventTypes$1, +// When adding attributes to the HTML or SVG whitelist, be sure to +// also add them to this module to ensure casing and incorrect name +// warnings. +var possibleStandardNames = { + // HTML + accept: 'accept', + acceptcharset: 'acceptCharset', + 'accept-charset': 'acceptCharset', + accesskey: 'accessKey', + action: 'action', + allowfullscreen: 'allowFullScreen', + alt: 'alt', + as: 'as', + async: 'async', + autocapitalize: 'autoCapitalize', + autocomplete: 'autoComplete', + autocorrect: 'autoCorrect', + autofocus: 'autoFocus', + autoplay: 'autoPlay', + autosave: 'autoSave', + capture: 'capture', + cellpadding: 'cellPadding', + cellspacing: 'cellSpacing', + challenge: 'challenge', + charset: 'charSet', + checked: 'checked', + children: 'children', + cite: 'cite', + 'class': 'className', + classid: 'classID', + classname: 'className', + cols: 'cols', + colspan: 'colSpan', + content: 'content', + contenteditable: 'contentEditable', + contextmenu: 'contextMenu', + controls: 'controls', + controlslist: 'controlsList', + coords: 'coords', + crossorigin: 'crossOrigin', + dangerouslysetinnerhtml: 'dangerouslySetInnerHTML', + data: 'data', + datetime: 'dateTime', + 'default': 'default', + defaultchecked: 'defaultChecked', + defaultvalue: 'defaultValue', + defer: 'defer', + dir: 'dir', + disabled: 'disabled', + download: 'download', + draggable: 'draggable', + enctype: 'encType', + 'for': 'htmlFor', + form: 'form', + formmethod: 'formMethod', + formaction: 'formAction', + formenctype: 'formEncType', + formnovalidate: 'formNoValidate', + formtarget: 'formTarget', + frameborder: 'frameBorder', + headers: 'headers', + height: 'height', + hidden: 'hidden', + high: 'high', + href: 'href', + hreflang: 'hrefLang', + htmlfor: 'htmlFor', + httpequiv: 'httpEquiv', + 'http-equiv': 'httpEquiv', + icon: 'icon', + id: 'id', + innerhtml: 'innerHTML', + inputmode: 'inputMode', + integrity: 'integrity', + is: 'is', + itemid: 'itemID', + itemprop: 'itemProp', + itemref: 'itemRef', + itemscope: 'itemScope', + itemtype: 'itemType', + keyparams: 'keyParams', + keytype: 'keyType', + kind: 'kind', + label: 'label', + lang: 'lang', + list: 'list', + loop: 'loop', + low: 'low', + manifest: 'manifest', + marginwidth: 'marginWidth', + marginheight: 'marginHeight', + max: 'max', + maxlength: 'maxLength', + media: 'media', + mediagroup: 'mediaGroup', + method: 'method', + min: 'min', + minlength: 'minLength', + multiple: 'multiple', + muted: 'muted', + name: 'name', + nonce: 'nonce', + novalidate: 'noValidate', + open: 'open', + optimum: 'optimum', + pattern: 'pattern', + placeholder: 'placeholder', + playsinline: 'playsInline', + poster: 'poster', + preload: 'preload', + profile: 'profile', + radiogroup: 'radioGroup', + readonly: 'readOnly', + referrerpolicy: 'referrerPolicy', + rel: 'rel', + required: 'required', + reversed: 'reversed', + role: 'role', + rows: 'rows', + rowspan: 'rowSpan', + sandbox: 'sandbox', + scope: 'scope', + scoped: 'scoped', + scrolling: 'scrolling', + seamless: 'seamless', + selected: 'selected', + shape: 'shape', + size: 'size', + sizes: 'sizes', + span: 'span', + spellcheck: 'spellCheck', + src: 'src', + srcdoc: 'srcDoc', + srclang: 'srcLang', + srcset: 'srcSet', + start: 'start', + step: 'step', + style: 'style', + summary: 'summary', + tabindex: 'tabIndex', + target: 'target', + title: 'title', + type: 'type', + usemap: 'useMap', + value: 'value', + width: 'width', + wmode: 'wmode', + wrap: 'wrap', - _isInputEventSupported: isInputEventSupported, + // SVG + about: 'about', + accentheight: 'accentHeight', + 'accent-height': 'accentHeight', + accumulate: 'accumulate', + additive: 'additive', + alignmentbaseline: 'alignmentBaseline', + 'alignment-baseline': 'alignmentBaseline', + allowreorder: 'allowReorder', + alphabetic: 'alphabetic', + amplitude: 'amplitude', + arabicform: 'arabicForm', + 'arabic-form': 'arabicForm', + ascent: 'ascent', + attributename: 'attributeName', + attributetype: 'attributeType', + autoreverse: 'autoReverse', + azimuth: 'azimuth', + basefrequency: 'baseFrequency', + baselineshift: 'baselineShift', + 'baseline-shift': 'baselineShift', + baseprofile: 'baseProfile', + bbox: 'bbox', + begin: 'begin', + bias: 'bias', + by: 'by', + calcmode: 'calcMode', + capheight: 'capHeight', + 'cap-height': 'capHeight', + clip: 'clip', + clippath: 'clipPath', + 'clip-path': 'clipPath', + clippathunits: 'clipPathUnits', + cliprule: 'clipRule', + 'clip-rule': 'clipRule', + color: 'color', + colorinterpolation: 'colorInterpolation', + 'color-interpolation': 'colorInterpolation', + colorinterpolationfilters: 'colorInterpolationFilters', + 'color-interpolation-filters': 'colorInterpolationFilters', + colorprofile: 'colorProfile', + 'color-profile': 'colorProfile', + colorrendering: 'colorRendering', + 'color-rendering': 'colorRendering', + contentscripttype: 'contentScriptType', + contentstyletype: 'contentStyleType', + cursor: 'cursor', + cx: 'cx', + cy: 'cy', + d: 'd', + datatype: 'datatype', + decelerate: 'decelerate', + descent: 'descent', + diffuseconstant: 'diffuseConstant', + direction: 'direction', + display: 'display', + divisor: 'divisor', + dominantbaseline: 'dominantBaseline', + 'dominant-baseline': 'dominantBaseline', + dur: 'dur', + dx: 'dx', + dy: 'dy', + edgemode: 'edgeMode', + elevation: 'elevation', + enablebackground: 'enableBackground', + 'enable-background': 'enableBackground', + end: 'end', + exponent: 'exponent', + externalresourcesrequired: 'externalResourcesRequired', + fill: 'fill', + fillopacity: 'fillOpacity', + 'fill-opacity': 'fillOpacity', + fillrule: 'fillRule', + 'fill-rule': 'fillRule', + filter: 'filter', + filterres: 'filterRes', + filterunits: 'filterUnits', + floodopacity: 'floodOpacity', + 'flood-opacity': 'floodOpacity', + floodcolor: 'floodColor', + 'flood-color': 'floodColor', + focusable: 'focusable', + fontfamily: 'fontFamily', + 'font-family': 'fontFamily', + fontsize: 'fontSize', + 'font-size': 'fontSize', + fontsizeadjust: 'fontSizeAdjust', + 'font-size-adjust': 'fontSizeAdjust', + fontstretch: 'fontStretch', + 'font-stretch': 'fontStretch', + fontstyle: 'fontStyle', + 'font-style': 'fontStyle', + fontvariant: 'fontVariant', + 'font-variant': 'fontVariant', + fontweight: 'fontWeight', + 'font-weight': 'fontWeight', + format: 'format', + from: 'from', + fx: 'fx', + fy: 'fy', + g1: 'g1', + g2: 'g2', + glyphname: 'glyphName', + 'glyph-name': 'glyphName', + glyphorientationhorizontal: 'glyphOrientationHorizontal', + 'glyph-orientation-horizontal': 'glyphOrientationHorizontal', + glyphorientationvertical: 'glyphOrientationVertical', + 'glyph-orientation-vertical': 'glyphOrientationVertical', + glyphref: 'glyphRef', + gradienttransform: 'gradientTransform', + gradientunits: 'gradientUnits', + hanging: 'hanging', + horizadvx: 'horizAdvX', + 'horiz-adv-x': 'horizAdvX', + horizoriginx: 'horizOriginX', + 'horiz-origin-x': 'horizOriginX', + ideographic: 'ideographic', + imagerendering: 'imageRendering', + 'image-rendering': 'imageRendering', + in2: 'in2', + 'in': 'in', + inlist: 'inlist', + intercept: 'intercept', + k1: 'k1', + k2: 'k2', + k3: 'k3', + k4: 'k4', + k: 'k', + kernelmatrix: 'kernelMatrix', + kernelunitlength: 'kernelUnitLength', + kerning: 'kerning', + keypoints: 'keyPoints', + keysplines: 'keySplines', + keytimes: 'keyTimes', + lengthadjust: 'lengthAdjust', + letterspacing: 'letterSpacing', + 'letter-spacing': 'letterSpacing', + lightingcolor: 'lightingColor', + 'lighting-color': 'lightingColor', + limitingconeangle: 'limitingConeAngle', + local: 'local', + markerend: 'markerEnd', + 'marker-end': 'markerEnd', + markerheight: 'markerHeight', + markermid: 'markerMid', + 'marker-mid': 'markerMid', + markerstart: 'markerStart', + 'marker-start': 'markerStart', + markerunits: 'markerUnits', + markerwidth: 'markerWidth', + mask: 'mask', + maskcontentunits: 'maskContentUnits', + maskunits: 'maskUnits', + mathematical: 'mathematical', + mode: 'mode', + numoctaves: 'numOctaves', + offset: 'offset', + opacity: 'opacity', + operator: 'operator', + order: 'order', + orient: 'orient', + orientation: 'orientation', + origin: 'origin', + overflow: 'overflow', + overlineposition: 'overlinePosition', + 'overline-position': 'overlinePosition', + overlinethickness: 'overlineThickness', + 'overline-thickness': 'overlineThickness', + paintorder: 'paintOrder', + 'paint-order': 'paintOrder', + panose1: 'panose1', + 'panose-1': 'panose1', + pathlength: 'pathLength', + patterncontentunits: 'patternContentUnits', + patterntransform: 'patternTransform', + patternunits: 'patternUnits', + pointerevents: 'pointerEvents', + 'pointer-events': 'pointerEvents', + points: 'points', + pointsatx: 'pointsAtX', + pointsaty: 'pointsAtY', + pointsatz: 'pointsAtZ', + prefix: 'prefix', + preservealpha: 'preserveAlpha', + preserveaspectratio: 'preserveAspectRatio', + primitiveunits: 'primitiveUnits', + property: 'property', + r: 'r', + radius: 'radius', + refx: 'refX', + refy: 'refY', + renderingintent: 'renderingIntent', + 'rendering-intent': 'renderingIntent', + repeatcount: 'repeatCount', + repeatdur: 'repeatDur', + requiredextensions: 'requiredExtensions', + requiredfeatures: 'requiredFeatures', + resource: 'resource', + restart: 'restart', + result: 'result', + results: 'results', + rotate: 'rotate', + rx: 'rx', + ry: 'ry', + scale: 'scale', + security: 'security', + seed: 'seed', + shaperendering: 'shapeRendering', + 'shape-rendering': 'shapeRendering', + slope: 'slope', + spacing: 'spacing', + specularconstant: 'specularConstant', + specularexponent: 'specularExponent', + speed: 'speed', + spreadmethod: 'spreadMethod', + startoffset: 'startOffset', + stddeviation: 'stdDeviation', + stemh: 'stemh', + stemv: 'stemv', + stitchtiles: 'stitchTiles', + stopcolor: 'stopColor', + 'stop-color': 'stopColor', + stopopacity: 'stopOpacity', + 'stop-opacity': 'stopOpacity', + strikethroughposition: 'strikethroughPosition', + 'strikethrough-position': 'strikethroughPosition', + strikethroughthickness: 'strikethroughThickness', + 'strikethrough-thickness': 'strikethroughThickness', + string: 'string', + stroke: 'stroke', + strokedasharray: 'strokeDasharray', + 'stroke-dasharray': 'strokeDasharray', + strokedashoffset: 'strokeDashoffset', + 'stroke-dashoffset': 'strokeDashoffset', + strokelinecap: 'strokeLinecap', + 'stroke-linecap': 'strokeLinecap', + strokelinejoin: 'strokeLinejoin', + 'stroke-linejoin': 'strokeLinejoin', + strokemiterlimit: 'strokeMiterlimit', + 'stroke-miterlimit': 'strokeMiterlimit', + strokewidth: 'strokeWidth', + 'stroke-width': 'strokeWidth', + strokeopacity: 'strokeOpacity', + 'stroke-opacity': 'strokeOpacity', + suppresscontenteditablewarning: 'suppressContentEditableWarning', + suppresshydrationwarning: 'suppressHydrationWarning', + surfacescale: 'surfaceScale', + systemlanguage: 'systemLanguage', + tablevalues: 'tableValues', + targetx: 'targetX', + targety: 'targetY', + textanchor: 'textAnchor', + 'text-anchor': 'textAnchor', + textdecoration: 'textDecoration', + 'text-decoration': 'textDecoration', + textlength: 'textLength', + textrendering: 'textRendering', + 'text-rendering': 'textRendering', + to: 'to', + transform: 'transform', + 'typeof': 'typeof', + u1: 'u1', + u2: 'u2', + underlineposition: 'underlinePosition', + 'underline-position': 'underlinePosition', + underlinethickness: 'underlineThickness', + 'underline-thickness': 'underlineThickness', + unicode: 'unicode', + unicodebidi: 'unicodeBidi', + 'unicode-bidi': 'unicodeBidi', + unicoderange: 'unicodeRange', + 'unicode-range': 'unicodeRange', + unitsperem: 'unitsPerEm', + 'units-per-em': 'unitsPerEm', + unselectable: 'unselectable', + valphabetic: 'vAlphabetic', + 'v-alphabetic': 'vAlphabetic', + values: 'values', + vectoreffect: 'vectorEffect', + 'vector-effect': 'vectorEffect', + version: 'version', + vertadvy: 'vertAdvY', + 'vert-adv-y': 'vertAdvY', + vertoriginx: 'vertOriginX', + 'vert-origin-x': 'vertOriginX', + vertoriginy: 'vertOriginY', + 'vert-origin-y': 'vertOriginY', + vhanging: 'vHanging', + 'v-hanging': 'vHanging', + videographic: 'vIdeographic', + 'v-ideographic': 'vIdeographic', + viewbox: 'viewBox', + viewtarget: 'viewTarget', + visibility: 'visibility', + vmathematical: 'vMathematical', + 'v-mathematical': 'vMathematical', + vocab: 'vocab', + widths: 'widths', + wordspacing: 'wordSpacing', + 'word-spacing': 'wordSpacing', + writingmode: 'writingMode', + 'writing-mode': 'writingMode', + x1: 'x1', + x2: 'x2', + x: 'x', + xchannelselector: 'xChannelSelector', + xheight: 'xHeight', + 'x-height': 'xHeight', + xlinkactuate: 'xlinkActuate', + 'xlink:actuate': 'xlinkActuate', + xlinkarcrole: 'xlinkArcrole', + 'xlink:arcrole': 'xlinkArcrole', + xlinkhref: 'xlinkHref', + 'xlink:href': 'xlinkHref', + xlinkrole: 'xlinkRole', + 'xlink:role': 'xlinkRole', + xlinkshow: 'xlinkShow', + 'xlink:show': 'xlinkShow', + xlinktitle: 'xlinkTitle', + 'xlink:title': 'xlinkTitle', + xlinktype: 'xlinkType', + 'xlink:type': 'xlinkType', + xmlbase: 'xmlBase', + 'xml:base': 'xmlBase', + xmllang: 'xmlLang', + 'xml:lang': 'xmlLang', + xmlns: 'xmlns', + 'xml:space': 'xmlSpace', + xmlnsxlink: 'xmlnsXlink', + 'xmlns:xlink': 'xmlnsXlink', + xmlspace: 'xmlSpace', + y1: 'y1', + y2: 'y2', + y: 'y', + ychannelselector: 'yChannelSelector', + z: 'z', + zoomandpan: 'zoomAndPan' +}; - extractEvents: function (topLevelType, targetInst, nativeEvent, nativeEventTarget) { - var targetNode = targetInst ? ReactDOMComponentTree_1.getNodeFromInstance(targetInst) : window; +function getStackAddendum$2() { + var stack = ReactDebugCurrentFrame.getStackAddendum(); + return stack != null ? stack : ''; +} - var getTargetInstFunc, handleEventFunc; - if (shouldUseChangeEvent(targetNode)) { - getTargetInstFunc = getTargetInstForChangeEvent; - } else if (isTextInputElement_1(targetNode)) { - if (isInputEventSupported) { - getTargetInstFunc = getTargetInstForInputOrChangeEvent; - } else { - getTargetInstFunc = getTargetInstForInputEventPolyfill; - handleEventFunc = handleEventsForInputEventPolyfill; - } - } else if (shouldUseClickEvent(targetNode)) { - getTargetInstFunc = getTargetInstForClickEvent; +{ + var warnedProperties$1 = {}; + var hasOwnProperty$2 = Object.prototype.hasOwnProperty; + var EVENT_NAME_REGEX = /^on./; + var INVALID_EVENT_NAME_REGEX = /^on[^A-Z]/; + var rARIA$1 = new RegExp('^(aria)-[' + ATTRIBUTE_NAME_CHAR + ']*$'); + var rARIACamel$1 = new RegExp('^(aria)[A-Z][' + ATTRIBUTE_NAME_CHAR + ']*$'); + + var validateProperty$1 = function (tagName, name, value, canUseEventSystem) { + if (hasOwnProperty$2.call(warnedProperties$1, name) && warnedProperties$1[name]) { + return true; } - if (getTargetInstFunc) { - var inst = getTargetInstFunc(topLevelType, targetInst); - if (inst) { - var event = createAndAccumulateChangeEvent(inst, nativeEvent, nativeEventTarget); - return event; + var lowerCasedName = name.toLowerCase(); + if (lowerCasedName === 'onfocusin' || lowerCasedName === 'onfocusout') { + warning_1(false, 'React uses onFocus and onBlur instead of onFocusIn and onFocusOut. ' + 'All React events are normalized to bubble, so onFocusIn and onFocusOut ' + 'are not needed/supported by React.'); + warnedProperties$1[name] = true; + return true; + } + + // We can't rely on the event system being injected on the server. + if (canUseEventSystem) { + if (registrationNameModules.hasOwnProperty(name)) { + return true; + } + var registrationName = possibleRegistrationNames.hasOwnProperty(lowerCasedName) ? possibleRegistrationNames[lowerCasedName] : null; + if (registrationName != null) { + warning_1(false, 'Invalid event handler property `%s`. Did you mean `%s`?%s', name, registrationName, getStackAddendum$2()); + warnedProperties$1[name] = true; + return true; + } + if (EVENT_NAME_REGEX.test(name)) { + warning_1(false, 'Unknown event handler property `%s`. It will be ignored.%s', name, getStackAddendum$2()); + warnedProperties$1[name] = true; + return true; } + } else if (EVENT_NAME_REGEX.test(name)) { + // If no event plugins have been injected, we are in a server environment. + // So we can't tell if the event name is correct for sure, but we can filter + // out known bad ones like `onclick`. We can't suggest a specific replacement though. + if (INVALID_EVENT_NAME_REGEX.test(name)) { + warning_1(false, 'Invalid event handler property `%s`. ' + 'React events use the camelCase naming convention, for example `onClick`.%s', name, getStackAddendum$2()); + } + warnedProperties$1[name] = true; + return true; } - if (handleEventFunc) { - handleEventFunc(topLevelType, targetNode, targetInst); + // Let the ARIA attribute hook validate ARIA attributes + if (rARIA$1.test(name) || rARIACamel$1.test(name)) { + return true; } - // When blurring, set the value attribute for number inputs - if (topLevelType === 'topBlur') { - handleControlledInputBlur(targetInst, targetNode); + if (lowerCasedName === 'innerhtml') { + warning_1(false, 'Directly setting property `innerHTML` is not permitted. ' + 'For more information, lookup documentation on `dangerouslySetInnerHTML`.'); + warnedProperties$1[name] = true; + return true; } - } -}; -var ChangeEventPlugin_1 = ChangeEventPlugin; + if (lowerCasedName === 'aria') { + warning_1(false, 'The `aria` attribute is reserved for future use in React. ' + 'Pass individual `aria-` attributes instead.'); + warnedProperties$1[name] = true; + return true; + } -/** - * Copyright (c) 2013-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @providesModule DOMEventPluginOrder - */ + if (lowerCasedName === 'is' && value !== null && value !== undefined && typeof value !== 'string') { + warning_1(false, 'Received a `%s` for a string attribute `is`. If this is expected, cast ' + 'the value to a string.%s', typeof value, getStackAddendum$2()); + warnedProperties$1[name] = true; + return true; + } -/** - * Module that is injectable into `EventPluginHub`, that specifies a - * deterministic ordering of `EventPlugin`s. A convenient way to reason about - * plugins, without having to package every one of them. This is better than - * having plugins be ordered in the same order that they are injected because - * that ordering would be influenced by the packaging order. - * `ResponderEventPlugin` must occur before `SimpleEventPlugin` so that - * preventing default on events is convenient in `SimpleEventPlugin` handlers. - */ + if (typeof value === 'number' && isNaN(value)) { + warning_1(false, 'Received NaN for the `%s` attribute. If this is expected, cast ' + 'the value to a string.%s', name, getStackAddendum$2()); + warnedProperties$1[name] = true; + return true; + } -var DOMEventPluginOrder = ['ResponderEventPlugin', 'SimpleEventPlugin', 'TapEventPlugin', 'EnterLeaveEventPlugin', 'ChangeEventPlugin', 'SelectEventPlugin', 'BeforeInputEventPlugin']; + var isReserved = isReservedProp(name); -var DOMEventPluginOrder_1 = DOMEventPluginOrder; + // Known attributes should match the casing specified in the property config. + if (possibleStandardNames.hasOwnProperty(lowerCasedName)) { + var standardName = possibleStandardNames[lowerCasedName]; + if (standardName !== name) { + warning_1(false, 'Invalid DOM property `%s`. Did you mean `%s`?%s', name, standardName, getStackAddendum$2()); + warnedProperties$1[name] = true; + return true; + } + } else if (!isReserved && name !== lowerCasedName) { + // Unknown attributes should have lowercase casing since that's how they + // will be cased anyway with server rendering. + warning_1(false, 'React does not recognize the `%s` prop on a DOM element. If you ' + 'intentionally want it to appear in the DOM as a custom ' + 'attribute, spell it as lowercase `%s` instead. ' + 'If you accidentally passed it from a parent component, remove ' + 'it from the DOM element.%s', name, lowerCasedName, getStackAddendum$2()); + warnedProperties$1[name] = true; + return true; + } -/** - * @interface UIEvent - * @see http://www.w3.org/TR/DOM-Level-3-Events/ - */ -var UIEventInterface = { - view: function (event) { - if (event.view) { - return event.view; + if (typeof value === 'boolean' && !shouldAttributeAcceptBooleanValue(name)) { + if (value) { + warning_1(false, 'Received `%s` for a non-boolean attribute `%s`.\n\n' + 'If you want to write it to the DOM, pass a string instead: ' + '%s="%s" or %s={value.toString()}.%s', value, name, name, value, name, getStackAddendum$2()); + } else { + warning_1(false, 'Received `%s` for a non-boolean attribute `%s`.\n\n' + 'If you want to write it to the DOM, pass a string instead: ' + '%s="%s" or %s={value.toString()}.\n\n' + 'If you used to conditionally omit it with %s={condition && value}, ' + 'pass %s={condition ? value : undefined} instead.%s', value, name, name, value, name, name, name, getStackAddendum$2()); + } + warnedProperties$1[name] = true; + return true; } - var target = getEventTarget_1(event); - if (target.window === target) { - // target is a window object - return target; + // Now that we've validated casing, do not validate + // data types for reserved props + if (isReserved) { + return true; } - var doc = target.ownerDocument; - // TODO: Figure out why `ownerDocument` is sometimes undefined in IE8. - if (doc) { - return doc.defaultView || doc.parentWindow; - } else { - return window; + // Warn when a known attribute is a bad type + if (!shouldSetAttribute(name, value)) { + warnedProperties$1[name] = true; + return false; } - }, - detail: function (event) { - return event.detail || 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 {SyntheticEvent} - */ -function SyntheticUIEvent(dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget) { - return SyntheticEvent_1.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget); + return true; + }; } -SyntheticEvent_1.augmentClass(SyntheticUIEvent, UIEventInterface); - -var SyntheticUIEvent_1 = SyntheticUIEvent; - -/** - * Copyright (c) 2013-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @providesModule getEventModifierState - */ - -/** - * Translation from modifier key to the associated property in the event. - * @see http://www.w3.org/TR/DOM-Level-3-Events/#keys-Modifiers - */ +var warnUnknownProperties = function (type, props, canUseEventSystem) { + var unknownProps = []; + for (var key in props) { + var isValid = validateProperty$1(type, key, props[key], canUseEventSystem); + if (!isValid) { + unknownProps.push(key); + } + } -var modifierKeyToProp = { - Alt: 'altKey', - Control: 'ctrlKey', - Meta: 'metaKey', - Shift: 'shiftKey' + var unknownPropString = unknownProps.map(function (prop) { + return '`' + prop + '`'; + }).join(', '); + if (unknownProps.length === 1) { + warning_1(false, 'Invalid value for prop %s on <%s> tag. Either remove it from the element, ' + 'or pass a string or number value to keep it in the DOM. ' + 'For details, see https://fb.me/react-attribute-behavior%s', unknownPropString, type, getStackAddendum$2()); + } else if (unknownProps.length > 1) { + warning_1(false, 'Invalid values for props %s on <%s> tag. Either remove them from the element, ' + 'or pass a string or number value to keep them in the DOM. ' + 'For details, see https://fb.me/react-attribute-behavior%s', unknownPropString, type, getStackAddendum$2()); + } }; -// IE8 does not implement getModifierState so we simply map it to the only -// modifier keys exposed by the event itself, does not support Lock-keys. -// Currently, all major browsers except Chrome seems to support Lock-keys. -function modifierStateGetter(keyArg) { - var syntheticEvent = this; - var nativeEvent = syntheticEvent.nativeEvent; - if (nativeEvent.getModifierState) { - return nativeEvent.getModifierState(keyArg); +function validateProperties$2(type, props, canUseEventSystem) { + if (isCustomComponent(type, props)) { + return; } - var keyProp = modifierKeyToProp[keyArg]; - return keyProp ? !!nativeEvent[keyProp] : false; + warnUnknownProperties(type, props, canUseEventSystem); } -function getEventModifierState(nativeEvent) { - return modifierStateGetter; -} +// TODO: direct imports like some-package/src/* are bad. Fix me. +var getCurrentFiberOwnerName$1 = ReactDebugCurrentFiber.getCurrentFiberOwnerName; +var getCurrentFiberStackAddendum$2 = ReactDebugCurrentFiber.getCurrentFiberStackAddendum; -var getEventModifierState_1 = getEventModifierState; +var didWarnInvalidHydration = false; +var didWarnShadyDOM = false; -/** - * @interface MouseEvent - * @see http://www.w3.org/TR/DOM-Level-3-Events/ - */ -var MouseEventInterface = { - screenX: null, - screenY: null, - clientX: null, - clientY: null, - pageX: null, - pageY: null, - ctrlKey: null, - shiftKey: null, - altKey: null, - metaKey: null, - getModifierState: getEventModifierState_1, - button: null, - buttons: null, - relatedTarget: function (event) { - return event.relatedTarget || (event.fromElement === event.srcElement ? event.toElement : event.fromElement); - } -}; +var DANGEROUSLY_SET_INNER_HTML = 'dangerouslySetInnerHTML'; +var SUPPRESS_CONTENT_EDITABLE_WARNING = 'suppressContentEditableWarning'; +var SUPPRESS_HYDRATION_WARNING$1 = 'suppressHydrationWarning'; +var AUTOFOCUS = 'autoFocus'; +var CHILDREN = 'children'; +var STYLE = 'style'; +var HTML = '__html'; -/** - * @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 SyntheticMouseEvent(dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget) { - return SyntheticUIEvent_1.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget); -} +var HTML_NAMESPACE = Namespaces.html; -SyntheticUIEvent_1.augmentClass(SyntheticMouseEvent, MouseEventInterface); -var SyntheticMouseEvent_1 = SyntheticMouseEvent; +var getStack = emptyFunction_1.thatReturns(''); -var eventTypes$2 = { - mouseEnter: { - registrationName: 'onMouseEnter', - dependencies: ['topMouseOut', 'topMouseOver'] - }, - mouseLeave: { - registrationName: 'onMouseLeave', - dependencies: ['topMouseOut', 'topMouseOver'] - } -}; +{ + getStack = getCurrentFiberStackAddendum$2; -var EnterLeaveEventPlugin = { - eventTypes: eventTypes$2, + var warnedUnknownTags = { + // Chrome is the only major browser not shipping <time>. But as of July + // 2017 it intends to ship it due to widespread usage. We intentionally + // *don't* warn for <time> even if it's unrecognized by Chrome because + // it soon will be, and many apps have been using it anyway. + time: true, + // There are working polyfills for <dialog>. Let people use it. + dialog: true + }; - /** - * For almost every interaction we care about, there will be both a top-level - * `mouseover` and `mouseout` event that occurs. Only use `mouseout` so that - * we do not extract duplicate events. However, moving the mouse into the - * browser from outside will not fire a `mouseout` event. In this case, we use - * the `mouseover` top-level event. - */ - extractEvents: function (topLevelType, targetInst, nativeEvent, nativeEventTarget) { - if (topLevelType === 'topMouseOver' && (nativeEvent.relatedTarget || nativeEvent.fromElement)) { - return null; + var validatePropertiesInDevelopment = function (type, props) { + validateProperties(type, props); + validateProperties$1(type, props); + validateProperties$2(type, props, /* canUseEventSystem */true); + }; + + // HTML parsing normalizes CR and CRLF to LF. + // It also can turn \u0000 into \uFFFD inside attributes. + // https://www.w3.org/TR/html5/single-page.html#preprocessing-the-input-stream + // If we have a mismatch, it might be caused by that. + // We will still patch up in this case but not fire the warning. + var NORMALIZE_NEWLINES_REGEX = /\r\n?/g; + var NORMALIZE_NULL_AND_REPLACEMENT_REGEX = /\u0000|\uFFFD/g; + + var normalizeMarkupForTextOrAttribute = function (markup) { + var markupString = typeof markup === 'string' ? markup : '' + markup; + return markupString.replace(NORMALIZE_NEWLINES_REGEX, '\n').replace(NORMALIZE_NULL_AND_REPLACEMENT_REGEX, ''); + }; + + var warnForTextDifference = function (serverText, clientText) { + if (didWarnInvalidHydration) { + return; } - if (topLevelType !== 'topMouseOut' && topLevelType !== 'topMouseOver') { - // Must not be a mouse in or mouse out - ignoring. - return null; + var normalizedClientText = normalizeMarkupForTextOrAttribute(clientText); + var normalizedServerText = normalizeMarkupForTextOrAttribute(serverText); + if (normalizedServerText === normalizedClientText) { + return; } + didWarnInvalidHydration = true; + warning_1(false, 'Text content did not match. Server: "%s" Client: "%s"', normalizedServerText, normalizedClientText); + }; - var win; - if (nativeEventTarget.window === nativeEventTarget) { - // `nativeEventTarget` is probably a window object. - win = nativeEventTarget; - } else { - // TODO: Figure out why `ownerDocument` is sometimes undefined in IE8. - var doc = nativeEventTarget.ownerDocument; - if (doc) { - win = doc.defaultView || doc.parentWindow; - } else { - win = window; - } + var warnForPropDifference = function (propName, serverValue, clientValue) { + if (didWarnInvalidHydration) { + return; } - - var from; - var to; - if (topLevelType === 'topMouseOut') { - from = targetInst; - var related = nativeEvent.relatedTarget || nativeEvent.toElement; - to = related ? ReactDOMComponentTree_1.getClosestInstanceFromNode(related) : null; - } else { - // Moving to a node from outside the window. - from = null; - to = targetInst; + var normalizedClientValue = normalizeMarkupForTextOrAttribute(clientValue); + var normalizedServerValue = normalizeMarkupForTextOrAttribute(serverValue); + if (normalizedServerValue === normalizedClientValue) { + return; } + didWarnInvalidHydration = true; + warning_1(false, 'Prop `%s` did not match. Server: %s Client: %s', propName, JSON.stringify(normalizedServerValue), JSON.stringify(normalizedClientValue)); + }; - if (from === to) { - // Nothing pertains to our managed components. - return null; + var warnForExtraAttributes = function (attributeNames) { + if (didWarnInvalidHydration) { + return; } + didWarnInvalidHydration = true; + var names = []; + attributeNames.forEach(function (name) { + names.push(name); + }); + warning_1(false, 'Extra attributes from the server: %s', names); + }; - var fromNode = from == null ? win : ReactDOMComponentTree_1.getNodeFromInstance(from); - var toNode = to == null ? win : ReactDOMComponentTree_1.getNodeFromInstance(to); + var warnForInvalidEventListener = function (registrationName, listener) { + if (listener === false) { + warning_1(false, 'Expected `%s` listener to be a function, instead got `false`.\n\n' + 'If you used to conditionally omit it with %s={condition && value}, ' + 'pass %s={condition ? value : undefined} instead.%s', registrationName, registrationName, registrationName, getCurrentFiberStackAddendum$2()); + } else { + warning_1(false, 'Expected `%s` listener to be a function, instead got a value of `%s` type.%s', registrationName, typeof listener, getCurrentFiberStackAddendum$2()); + } + }; - var leave = SyntheticMouseEvent_1.getPooled(eventTypes$2.mouseLeave, from, nativeEvent, nativeEventTarget); - leave.type = 'mouseleave'; - leave.target = fromNode; - leave.relatedTarget = toNode; + // Parse the HTML and read it back to normalize the HTML string so that it + // can be used for comparison. + var normalizeHTML = function (parent, html) { + // We could have created a separate document here to avoid + // re-initializing custom elements if they exist. But this breaks + // how <noscript> is being handled. So we use the same document. + // See the discussion in https://github.com/facebook/react/pull/11157. + var testElement = parent.namespaceURI === HTML_NAMESPACE ? parent.ownerDocument.createElement(parent.tagName) : parent.ownerDocument.createElementNS(parent.namespaceURI, parent.tagName); + testElement.innerHTML = html; + return testElement.innerHTML; + }; +} - var enter = SyntheticMouseEvent_1.getPooled(eventTypes$2.mouseEnter, to, nativeEvent, nativeEventTarget); - enter.type = 'mouseenter'; - enter.target = toNode; - enter.relatedTarget = fromNode; +function ensureListeningTo(rootContainerElement, registrationName) { + var isDocumentOrFragment = rootContainerElement.nodeType === DOCUMENT_NODE || rootContainerElement.nodeType === DOCUMENT_FRAGMENT_NODE; + var doc = isDocumentOrFragment ? rootContainerElement : rootContainerElement.ownerDocument; + listenTo(registrationName, doc); +} - EventPropagators_1.accumulateEnterLeaveDispatches(leave, enter, from, to); +function getOwnerDocumentFromRootContainer(rootContainerElement) { + return rootContainerElement.nodeType === DOCUMENT_NODE ? rootContainerElement : rootContainerElement.ownerDocument; +} - return [leave, enter]; - } +// There are so many media events, it makes sense to just +// maintain a list rather than create a `trapBubbledEvent` for each +var mediaEvents = { + topAbort: 'abort', + topCanPlay: 'canplay', + topCanPlayThrough: 'canplaythrough', + topDurationChange: 'durationchange', + topEmptied: 'emptied', + topEncrypted: 'encrypted', + topEnded: 'ended', + topError: 'error', + topLoadedData: 'loadeddata', + topLoadedMetadata: 'loadedmetadata', + topLoadStart: 'loadstart', + topPause: 'pause', + topPlay: 'play', + topPlaying: 'playing', + topProgress: 'progress', + topRateChange: 'ratechange', + topSeeked: 'seeked', + topSeeking: 'seeking', + topStalled: 'stalled', + topSuspend: 'suspend', + topTimeUpdate: 'timeupdate', + topVolumeChange: 'volumechange', + topWaiting: 'waiting' }; -var EnterLeaveEventPlugin_1 = EnterLeaveEventPlugin; +function trapClickOnNonInteractiveElement(node) { + // Mobile Safari does not fire properly bubble click events on + // non-interactive elements, which means delegated click listeners do not + // fire. The workaround for this bug involves attaching an empty click + // listener on the target node. + // http://www.quirksmode.org/blog/archives/2010/09/click_event_del.html + // Just set it using the onclick property so that we don't have to manage any + // bookkeeping for it. Not sure if we need to clear it when the listener is + // removed. + // TODO: Only do this for the relevant Safaris maybe? + node.onclick = emptyFunction_1; +} -var DOCUMENT_NODE$2 = HTMLNodeType_1.DOCUMENT_NODE; +function setInitialDOMProperties(tag, domElement, rootContainerElement, nextProps, isCustomComponentTag) { + for (var propKey in nextProps) { + if (!nextProps.hasOwnProperty(propKey)) { + continue; + } + var nextProp = nextProps[propKey]; + if (propKey === STYLE) { + { + if (nextProp) { + // Freeze the next style object so that we can assume it won't be + // mutated. We have already warned for this in the past. + Object.freeze(nextProp); + } + } + // Relies on `updateStylesByID` not mutating `styleUpdates`. + setValueForStyles(domElement, nextProp, getStack); + } else if (propKey === DANGEROUSLY_SET_INNER_HTML) { + var nextHtml = nextProp ? nextProp[HTML] : undefined; + if (nextHtml != null) { + setInnerHTML(domElement, nextHtml); + } + } else if (propKey === CHILDREN) { + if (typeof nextProp === 'string') { + // Avoid setting initial textContent when the text is empty. In IE11 setting + // textContent on a <textarea> will cause the placeholder to not + // show within the <textarea> until it has been focused and blurred again. + // https://github.com/facebook/react/issues/6731#issuecomment-254874553 + var canSetTextContent = tag !== 'textarea' || nextProp !== ''; + if (canSetTextContent) { + setTextContent(domElement, nextProp); + } + } else if (typeof nextProp === 'number') { + setTextContent(domElement, '' + nextProp); + } + } else if (propKey === SUPPRESS_CONTENT_EDITABLE_WARNING || propKey === SUPPRESS_HYDRATION_WARNING$1) { + // Noop + } else if (propKey === AUTOFOCUS) { + // We polyfill it separately on the client during commit. + // We blacklist it here rather than in the property list because we emit it in SSR. + } else if (registrationNameModules.hasOwnProperty(propKey)) { + if (nextProp != null) { + if (true && typeof nextProp !== 'function') { + warnForInvalidEventListener(propKey, nextProp); + } + ensureListeningTo(rootContainerElement, propKey); + } + } else if (isCustomComponentTag) { + setValueForAttribute(domElement, propKey, nextProp); + } else if (nextProp != null) { + // If we're updating to null or undefined, we should remove the property + // from the DOM node instead of inadvertently setting to a string. This + // brings us in line with the same behavior we have on initial render. + setValueForProperty(domElement, propKey, nextProp); + } + } +} +function updateDOMProperties(domElement, updatePayload, wasCustomComponentTag, isCustomComponentTag) { + // TODO: Handle wasCustomComponentTag + for (var i = 0; i < updatePayload.length; i += 2) { + var propKey = updatePayload[i]; + var propValue = updatePayload[i + 1]; + if (propKey === STYLE) { + setValueForStyles(domElement, propValue, getStack); + } else if (propKey === DANGEROUSLY_SET_INNER_HTML) { + setInnerHTML(domElement, propValue); + } else if (propKey === CHILDREN) { + setTextContent(domElement, propValue); + } else if (isCustomComponentTag) { + if (propValue != null) { + setValueForAttribute(domElement, propKey, propValue); + } else { + deleteValueForAttribute(domElement, propKey); + } + } else if (propValue != null) { + setValueForProperty(domElement, propKey, propValue); + } else { + // If we're updating to null or undefined, we should remove the property + // from the DOM node instead of inadvertently setting to a string. This + // brings us in line with the same behavior we have on initial render. + deleteValueForProperty(domElement, propKey); + } + } +} +function createElement$1(type, props, rootContainerElement, parentNamespace) { + // We create tags in the namespace of their parent container, except HTML + var ownerDocument = getOwnerDocumentFromRootContainer(rootContainerElement); + var domElement; + var namespaceURI = parentNamespace; + if (namespaceURI === HTML_NAMESPACE) { + namespaceURI = getIntrinsicNamespace(type); + } + if (namespaceURI === HTML_NAMESPACE) { + { + var isCustomComponentTag = isCustomComponent(type, props); + // Should this check be gated by parent namespace? Not sure we want to + // allow <SVG> or <mATH>. + warning_1(isCustomComponentTag || type === type.toLowerCase(), '<%s /> is using uppercase HTML. Always use lowercase HTML tags ' + 'in React.', type); + } + + if (type === 'script') { + // Create the script via .innerHTML so its "parser-inserted" flag is + // set to true and it does not execute + var div = ownerDocument.createElement('div'); + div.innerHTML = '<script><' + '/script>'; // eslint-disable-line + // This is guaranteed to yield a script element. + var firstChild = div.firstChild; + domElement = div.removeChild(firstChild); + } else if (typeof props.is === 'string') { + // $FlowIssue `createElement` should be updated for Web Components + domElement = ownerDocument.createElement(type, { is: props.is }); + } else { + // Separate else branch instead of using `props.is || undefined` above because of a Firefox bug. + // See discussion in https://github.com/facebook/react/pull/6896 + // and discussion in https://bugzilla.mozilla.org/show_bug.cgi?id=1276240 + domElement = ownerDocument.createElement(type); + } + } else { + domElement = ownerDocument.createElementNS(namespaceURI, type); + } + { + if (namespaceURI === HTML_NAMESPACE) { + if (!isCustomComponentTag && Object.prototype.toString.call(domElement) === '[object HTMLUnknownElement]' && !Object.prototype.hasOwnProperty.call(warnedUnknownTags, type)) { + warnedUnknownTags[type] = true; + warning_1(false, 'The tag <%s> is unrecognized in this browser. ' + 'If you meant to render a React component, start its name with ' + 'an uppercase letter.', type); + } + } + } + return domElement; +} -var skipSelectionChangeEvent = ExecutionEnvironment_1.canUseDOM && 'documentMode' in document && document.documentMode <= 11; +function createTextNode$1(text, rootContainerElement) { + return getOwnerDocumentFromRootContainer(rootContainerElement).createTextNode(text); +} -var eventTypes$3 = { - select: { - phasedRegistrationNames: { - bubbled: 'onSelect', - captured: 'onSelectCapture' - }, - dependencies: ['topBlur', 'topContextMenu', 'topFocus', 'topKeyDown', 'topKeyUp', 'topMouseDown', 'topMouseUp', 'topSelectionChange'] +function setInitialProperties$1(domElement, tag, rawProps, rootContainerElement) { + var isCustomComponentTag = isCustomComponent(tag, rawProps); + { + validatePropertiesInDevelopment(tag, rawProps); + if (isCustomComponentTag && !didWarnShadyDOM && domElement.shadyRoot) { + warning_1(false, '%s is using shady DOM. Using shady DOM with React can ' + 'cause things to break subtly.', getCurrentFiberOwnerName$1() || 'A component'); + didWarnShadyDOM = true; + } } -}; -var activeElement$1 = null; -var activeElementInst$1 = null; -var lastSelection = null; -var mouseDown = false; + // TODO: Make sure that we check isMounted before firing any of these events. + var props; + switch (tag) { + case 'iframe': + case 'object': + trapBubbledEvent('topLoad', 'load', domElement); + props = rawProps; + break; + case 'video': + case 'audio': + // Create listener for each media event + for (var event in mediaEvents) { + if (mediaEvents.hasOwnProperty(event)) { + trapBubbledEvent(event, mediaEvents[event], domElement); + } + } + props = rawProps; + break; + case 'source': + trapBubbledEvent('topError', 'error', domElement); + props = rawProps; + break; + case 'img': + case 'image': + trapBubbledEvent('topError', 'error', domElement); + trapBubbledEvent('topLoad', 'load', domElement); + props = rawProps; + break; + case 'form': + trapBubbledEvent('topReset', 'reset', domElement); + trapBubbledEvent('topSubmit', 'submit', domElement); + props = rawProps; + break; + case 'details': + trapBubbledEvent('topToggle', 'toggle', domElement); + props = rawProps; + break; + case 'input': + initWrapperState(domElement, rawProps); + props = getHostProps(domElement, rawProps); + trapBubbledEvent('topInvalid', 'invalid', domElement); + // For controlled components we always need to ensure we're listening + // to onChange. Even if there is no listener. + ensureListeningTo(rootContainerElement, 'onChange'); + break; + case 'option': + validateProps(domElement, rawProps); + props = getHostProps$1(domElement, rawProps); + break; + case 'select': + initWrapperState$1(domElement, rawProps); + props = getHostProps$2(domElement, rawProps); + trapBubbledEvent('topInvalid', 'invalid', domElement); + // For controlled components we always need to ensure we're listening + // to onChange. Even if there is no listener. + ensureListeningTo(rootContainerElement, 'onChange'); + break; + case 'textarea': + initWrapperState$2(domElement, rawProps); + props = getHostProps$3(domElement, rawProps); + trapBubbledEvent('topInvalid', 'invalid', domElement); + // For controlled components we always need to ensure we're listening + // to onChange. Even if there is no listener. + ensureListeningTo(rootContainerElement, 'onChange'); + break; + default: + props = rawProps; + } -// Track whether all listeners exists for this plugin. If none exist, we do -// not extract events. See #3639. -var isListeningToAllDependencies = ReactBrowserEventEmitter_1.isListeningToAllDependencies; + assertValidProps(tag, props, getStack); -/** - * 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 && ReactInputSelection_1.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 - }; + setInitialDOMProperties(tag, domElement, rootContainerElement, props, isCustomComponentTag); + + switch (tag) { + case 'input': + // TODO: Make sure we check if this is still unmounted or do any clean + // up necessary since we never stop tracking anymore. + track(domElement); + postMountWrapper(domElement, rawProps); + break; + case 'textarea': + // TODO: Make sure we check if this is still unmounted or do any clean + // up necessary since we never stop tracking anymore. + track(domElement); + postMountWrapper$3(domElement, rawProps); + break; + case 'option': + postMountWrapper$1(domElement, rawProps); + break; + case 'select': + postMountWrapper$2(domElement, rawProps); + break; + default: + if (typeof props.onClick === 'function') { + // TODO: This cast may not be sound for SVG, MathML or custom elements. + trapClickOnNonInteractiveElement(domElement); + } + break; } } -/** - * 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_1()) { - return null; +// Calculate the diff between the two objects. +function diffProperties$1(domElement, tag, lastRawProps, nextRawProps, rootContainerElement) { + { + validatePropertiesInDevelopment(tag, nextRawProps); } - // Only fire when selection has actually changed. - var currentSelection = getSelection(activeElement$1); - if (!lastSelection || !shallowEqual_1(lastSelection, currentSelection)) { - lastSelection = currentSelection; - - var syntheticEvent = SyntheticEvent_1.getPooled(eventTypes$3.select, activeElementInst$1, nativeEvent, nativeEventTarget); - - syntheticEvent.type = 'select'; - syntheticEvent.target = activeElement$1; + var updatePayload = null; - EventPropagators_1.accumulateTwoPhaseDispatches(syntheticEvent); - - return syntheticEvent; + var lastProps; + var nextProps; + switch (tag) { + case 'input': + lastProps = getHostProps(domElement, lastRawProps); + nextProps = getHostProps(domElement, nextRawProps); + updatePayload = []; + break; + case 'option': + lastProps = getHostProps$1(domElement, lastRawProps); + nextProps = getHostProps$1(domElement, nextRawProps); + updatePayload = []; + break; + case 'select': + lastProps = getHostProps$2(domElement, lastRawProps); + nextProps = getHostProps$2(domElement, nextRawProps); + updatePayload = []; + break; + case 'textarea': + lastProps = getHostProps$3(domElement, lastRawProps); + nextProps = getHostProps$3(domElement, nextRawProps); + updatePayload = []; + break; + default: + lastProps = lastRawProps; + nextProps = nextRawProps; + if (typeof lastProps.onClick !== 'function' && typeof nextProps.onClick === 'function') { + // TODO: This cast may not be sound for SVG, MathML or custom elements. + trapClickOnNonInteractiveElement(domElement); + } + break; } - 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, + assertValidProps(tag, nextProps, getStack); - extractEvents: function (topLevelType, targetInst, nativeEvent, nativeEventTarget) { - var doc = nativeEventTarget.window === nativeEventTarget ? nativeEventTarget.document : nativeEventTarget.nodeType === DOCUMENT_NODE$2 ? nativeEventTarget : nativeEventTarget.ownerDocument; - if (!doc || !isListeningToAllDependencies('onSelect', doc)) { - return null; + var propKey; + var styleName; + var styleUpdates = null; + for (propKey in lastProps) { + if (nextProps.hasOwnProperty(propKey) || !lastProps.hasOwnProperty(propKey) || lastProps[propKey] == null) { + continue; } - - var targetNode = targetInst ? ReactDOMComponentTree_1.getNodeFromInstance(targetInst) : window; - - switch (topLevelType) { - // Track the input node that has focus. - case 'topFocus': - if (isTextInputElement_1(targetNode) || targetNode.contentEditable === 'true') { - activeElement$1 = targetNode; - activeElementInst$1 = targetInst; - lastSelection = null; + if (propKey === STYLE) { + var lastStyle = lastProps[propKey]; + for (styleName in lastStyle) { + if (lastStyle.hasOwnProperty(styleName)) { + if (!styleUpdates) { + styleUpdates = {}; + } + styleUpdates[styleName] = ''; } - 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; + } + } else if (propKey === DANGEROUSLY_SET_INNER_HTML || propKey === CHILDREN) { + // Noop. This is handled by the clear text mechanism. + } else if (propKey === SUPPRESS_CONTENT_EDITABLE_WARNING || propKey === SUPPRESS_HYDRATION_WARNING$1) { + // Noop + } else if (propKey === AUTOFOCUS) { + // Noop. It doesn't work on updates anyway. + } else if (registrationNameModules.hasOwnProperty(propKey)) { + // This is a special case. If any listener updates we need to ensure + // that the "current" fiber pointer gets updated so we need a commit + // to update this element. + if (!updatePayload) { + updatePayload = []; + } + } else { + // For all other deleted properties we add it to the queue. We use + // the whitelist in the commit phase instead. + (updatePayload = updatePayload || []).push(propKey, null); + } + } + for (propKey in nextProps) { + var nextProp = nextProps[propKey]; + var lastProp = lastProps != null ? lastProps[propKey] : undefined; + if (!nextProps.hasOwnProperty(propKey) || nextProp === lastProp || nextProp == null && lastProp == null) { + continue; + } + if (propKey === STYLE) { + { + if (nextProp) { + // Freeze the next style object so that we can assume it won't be + // mutated. We have already warned for this in the past. + Object.freeze(nextProp); } - // falls through - case 'topKeyDown': - case 'topKeyUp': - return constructSelectEvent(nativeEvent, nativeEventTarget); + } + if (lastProp) { + // Unset styles on `lastProp` but not on `nextProp`. + for (styleName in lastProp) { + if (lastProp.hasOwnProperty(styleName) && (!nextProp || !nextProp.hasOwnProperty(styleName))) { + if (!styleUpdates) { + styleUpdates = {}; + } + styleUpdates[styleName] = ''; + } + } + // Update styles that changed since `lastProp`. + for (styleName in nextProp) { + if (nextProp.hasOwnProperty(styleName) && lastProp[styleName] !== nextProp[styleName]) { + if (!styleUpdates) { + styleUpdates = {}; + } + styleUpdates[styleName] = nextProp[styleName]; + } + } + } else { + // Relies on `updateStylesByID` not mutating `styleUpdates`. + if (!styleUpdates) { + if (!updatePayload) { + updatePayload = []; + } + updatePayload.push(propKey, styleUpdates); + } + styleUpdates = nextProp; + } + } else if (propKey === DANGEROUSLY_SET_INNER_HTML) { + var nextHtml = nextProp ? nextProp[HTML] : undefined; + var lastHtml = lastProp ? lastProp[HTML] : undefined; + if (nextHtml != null) { + if (lastHtml !== nextHtml) { + (updatePayload = updatePayload || []).push(propKey, '' + nextHtml); + } + } else { + // TODO: It might be too late to clear this if we have children + // inserted already. + } + } else if (propKey === CHILDREN) { + if (lastProp !== nextProp && (typeof nextProp === 'string' || typeof nextProp === 'number')) { + (updatePayload = updatePayload || []).push(propKey, '' + nextProp); + } + } else if (propKey === SUPPRESS_CONTENT_EDITABLE_WARNING || propKey === SUPPRESS_HYDRATION_WARNING$1) { + // Noop + } else if (registrationNameModules.hasOwnProperty(propKey)) { + if (nextProp != null) { + // We eagerly listen to this even though we haven't committed yet. + if (true && typeof nextProp !== 'function') { + warnForInvalidEventListener(propKey, nextProp); + } + ensureListeningTo(rootContainerElement, propKey); + } + if (!updatePayload && lastProp !== nextProp) { + // This is a special case. If any listener updates we need to ensure + // that the "current" props pointer gets updated so we need a commit + // to update this element. + updatePayload = []; + } + } else { + // For any other property we always add it to the queue and then we + // filter it out using the whitelist during the commit. + (updatePayload = updatePayload || []).push(propKey, nextProp); } - - return null; } -}; - -var SelectEventPlugin_1 = SelectEventPlugin; - -/** - * @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); + if (styleUpdates) { + (updatePayload = updatePayload || []).push(STYLE, styleUpdates); + } + return updatePayload; } -SyntheticEvent_1.augmentClass(SyntheticAnimationEvent, AnimationEventInterface); +// Apply the diff. +function updateProperties$1(domElement, updatePayload, tag, lastRawProps, nextRawProps) { + // Update checked *before* name. + // In the middle of an update, it is possible to have multiple checked. + // When a checked radio tries to change name, browser makes another radio's checked false. + if (tag === 'input' && nextRawProps.type === 'radio' && nextRawProps.name != null) { + updateChecked(domElement, nextRawProps); + } -var SyntheticAnimationEvent_1 = SyntheticAnimationEvent; + var wasCustomComponentTag = isCustomComponent(tag, lastRawProps); + var isCustomComponentTag = isCustomComponent(tag, nextRawProps); + // Apply the diff. + updateDOMProperties(domElement, updatePayload, wasCustomComponentTag, isCustomComponentTag); -/** - * @interface Event - * @see http://www.w3.org/TR/clipboard-apis/ - */ -var ClipboardEventInterface = { - clipboardData: function (event) { - return 'clipboardData' in event ? event.clipboardData : window.clipboardData; + // TODO: Ensure that an update gets scheduled if any of the special props + // changed. + switch (tag) { + case 'input': + // Update the wrapper around inputs *after* updating props. This has to + // happen after `updateDOMProperties`. Otherwise HTML5 input validations + // raise warnings and prevent the new value from being assigned. + updateWrapper(domElement, nextRawProps); + break; + case 'textarea': + updateWrapper$1(domElement, nextRawProps); + break; + case 'select': + // <select> value update needs to occur after <option> children + // reconciliation + postUpdateWrapper(domElement, nextRawProps); + break; } -}; - -/** - * @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 SyntheticClipboardEvent(dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget) { - return SyntheticEvent_1.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget); } -SyntheticEvent_1.augmentClass(SyntheticClipboardEvent, ClipboardEventInterface); - -var SyntheticClipboardEvent_1 = SyntheticClipboardEvent; - -/** - * @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_1.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget); -} +function diffHydratedProperties$1(domElement, tag, rawProps, parentNamespace, rootContainerElement) { + { + var suppressHydrationWarning = rawProps[SUPPRESS_HYDRATION_WARNING$1] === true; + var isCustomComponentTag = isCustomComponent(tag, rawProps); + validatePropertiesInDevelopment(tag, rawProps); + if (isCustomComponentTag && !didWarnShadyDOM && domElement.shadyRoot) { + warning_1(false, '%s is using shady DOM. Using shady DOM with React can ' + 'cause things to break subtly.', getCurrentFiberOwnerName$1() || 'A component'); + didWarnShadyDOM = true; + } + } -SyntheticUIEvent_1.augmentClass(SyntheticFocusEvent, FocusEventInterface); + // TODO: Make sure that we check isMounted before firing any of these events. + switch (tag) { + case 'iframe': + case 'object': + trapBubbledEvent('topLoad', 'load', domElement); + break; + case 'video': + case 'audio': + // Create listener for each media event + for (var event in mediaEvents) { + if (mediaEvents.hasOwnProperty(event)) { + trapBubbledEvent(event, mediaEvents[event], domElement); + } + } + break; + case 'source': + trapBubbledEvent('topError', 'error', domElement); + break; + case 'img': + case 'image': + trapBubbledEvent('topError', 'error', domElement); + trapBubbledEvent('topLoad', 'load', domElement); + break; + case 'form': + trapBubbledEvent('topReset', 'reset', domElement); + trapBubbledEvent('topSubmit', 'submit', domElement); + break; + case 'details': + trapBubbledEvent('topToggle', 'toggle', domElement); + break; + case 'input': + initWrapperState(domElement, rawProps); + trapBubbledEvent('topInvalid', 'invalid', domElement); + // For controlled components we always need to ensure we're listening + // to onChange. Even if there is no listener. + ensureListeningTo(rootContainerElement, 'onChange'); + break; + case 'option': + validateProps(domElement, rawProps); + break; + case 'select': + initWrapperState$1(domElement, rawProps); + trapBubbledEvent('topInvalid', 'invalid', domElement); + // For controlled components we always need to ensure we're listening + // to onChange. Even if there is no listener. + ensureListeningTo(rootContainerElement, 'onChange'); + break; + case 'textarea': + initWrapperState$2(domElement, rawProps); + trapBubbledEvent('topInvalid', 'invalid', domElement); + // For controlled components we always need to ensure we're listening + // to onChange. Even if there is no listener. + ensureListeningTo(rootContainerElement, 'onChange'); + break; + } -var SyntheticFocusEvent_1 = SyntheticFocusEvent; + assertValidProps(tag, rawProps, getStack); -/** - * Copyright (c) 2013-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @providesModule getEventCharCode - */ + { + var extraAttributeNames = new Set(); + var attributes = domElement.attributes; + for (var i = 0; i < attributes.length; i++) { + var name = attributes[i].name.toLowerCase(); + switch (name) { + // Built-in SSR attribute is whitelisted + case 'data-reactroot': + break; + // Controlled attributes are not validated + // TODO: Only ignore them on controlled tags. + case 'value': + break; + case 'checked': + break; + case 'selected': + break; + default: + // Intentionally use the original name. + // See discussion in https://github.com/facebook/react/pull/10676. + extraAttributeNames.add(attributes[i].name); + } + } + } -/** - * `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. - */ + var updatePayload = null; + for (var propKey in rawProps) { + if (!rawProps.hasOwnProperty(propKey)) { + continue; + } + var nextProp = rawProps[propKey]; + if (propKey === CHILDREN) { + // For text content children we compare against textContent. This + // might match additional HTML that is hidden when we read it using + // textContent. E.g. "foo" will match "f<span>oo</span>" but that still + // satisfies our requirement. Our requirement is not to produce perfect + // HTML and attributes. Ideally we should preserve structure but it's + // ok not to if the visible content is still enough to indicate what + // even listeners these nodes might be wired up to. + // TODO: Warn if there is more than a single textNode as a child. + // TODO: Should we use domElement.firstChild.nodeValue to compare? + if (typeof nextProp === 'string') { + if (domElement.textContent !== nextProp) { + if (true && !suppressHydrationWarning) { + warnForTextDifference(domElement.textContent, nextProp); + } + updatePayload = [CHILDREN, nextProp]; + } + } else if (typeof nextProp === 'number') { + if (domElement.textContent !== '' + nextProp) { + if (true && !suppressHydrationWarning) { + warnForTextDifference(domElement.textContent, nextProp); + } + updatePayload = [CHILDREN, '' + nextProp]; + } + } + } else if (registrationNameModules.hasOwnProperty(propKey)) { + if (nextProp != null) { + if (true && typeof nextProp !== 'function') { + warnForInvalidEventListener(propKey, nextProp); + } + ensureListeningTo(rootContainerElement, propKey); + } + } else { + // Validate that the properties correspond to their expected values. + var serverValue; + var propertyInfo; + if (suppressHydrationWarning) { + // Don't bother comparing. We're ignoring all these warnings. + } else if (propKey === SUPPRESS_CONTENT_EDITABLE_WARNING || propKey === SUPPRESS_HYDRATION_WARNING$1 || + // Controlled attributes are not validated + // TODO: Only ignore them on controlled tags. + propKey === 'value' || propKey === 'checked' || propKey === 'selected') { + // Noop + } else if (propKey === DANGEROUSLY_SET_INNER_HTML) { + var rawHtml = nextProp ? nextProp[HTML] || '' : ''; + var serverHTML = domElement.innerHTML; + var expectedHTML = normalizeHTML(domElement, rawHtml); + if (expectedHTML !== serverHTML) { + warnForPropDifference(propKey, serverHTML, expectedHTML); + } + } else if (propKey === STYLE) { + // $FlowFixMe - Should be inferred as not undefined. + extraAttributeNames['delete'](propKey); + var expectedStyle = createDangerousStringForStyles(nextProp); + serverValue = domElement.getAttribute('style'); + if (expectedStyle !== serverValue) { + warnForPropDifference(propKey, serverValue, expectedStyle); + } + } else if (isCustomComponentTag) { + // $FlowFixMe - Should be inferred as not undefined. + extraAttributeNames['delete'](propKey.toLowerCase()); + serverValue = getValueForAttribute(domElement, propKey, nextProp); -function getEventCharCode(nativeEvent) { - var charCode; - var keyCode = nativeEvent.keyCode; + if (nextProp !== serverValue) { + warnForPropDifference(propKey, serverValue, nextProp); + } + } else if (shouldSetAttribute(propKey, nextProp)) { + if (propertyInfo = getPropertyInfo(propKey)) { + // $FlowFixMe - Should be inferred as not undefined. + extraAttributeNames['delete'](propertyInfo.attributeName); + serverValue = getValueForProperty(domElement, propKey, nextProp); + } else { + var ownNamespace = parentNamespace; + if (ownNamespace === HTML_NAMESPACE) { + ownNamespace = getIntrinsicNamespace(tag); + } + if (ownNamespace === HTML_NAMESPACE) { + // $FlowFixMe - Should be inferred as not undefined. + extraAttributeNames['delete'](propKey.toLowerCase()); + } else { + // $FlowFixMe - Should be inferred as not undefined. + extraAttributeNames['delete'](propKey); + } + serverValue = getValueForAttribute(domElement, propKey, nextProp); + } - if ('charCode' in nativeEvent) { - charCode = nativeEvent.charCode; + if (nextProp !== serverValue) { + warnForPropDifference(propKey, serverValue, nextProp); + } + } + } + } - // FF does not set `charCode` for the Enter-key, check against `keyCode`. - if (charCode === 0 && keyCode === 13) { - charCode = 13; + { + // $FlowFixMe - Should be inferred as not undefined. + if (extraAttributeNames.size > 0 && !suppressHydrationWarning) { + // $FlowFixMe - Should be inferred as not undefined. + warnForExtraAttributes(extraAttributeNames); } - } 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; + switch (tag) { + case 'input': + // TODO: Make sure we check if this is still unmounted or do any clean + // up necessary since we never stop tracking anymore. + track(domElement); + postMountWrapper(domElement, rawProps); + break; + case 'textarea': + // TODO: Make sure we check if this is still unmounted or do any clean + // up necessary since we never stop tracking anymore. + track(domElement); + postMountWrapper$3(domElement, rawProps); + break; + case 'select': + case 'option': + // For input and textarea we current always set the value property at + // post mount to force it to diverge from attributes. However, for + // option and select we don't quite do the same thing and select + // is not resilient to the DOM state changing so we don't do that here. + // TODO: Consider not doing this for input and textarea. + break; + default: + if (typeof rawProps.onClick === 'function') { + // TODO: This cast may not be sound for SVG, MathML or custom elements. + trapClickOnNonInteractiveElement(domElement); + } + break; } - return 0; + return updatePayload; } -var getEventCharCode_1 = getEventCharCode; - -/** - * 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' -}; +function diffHydratedText$1(textNode, text) { + var isDifferent = textNode.nodeValue !== text; + return isDifferent; +} -/** - * @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. +function warnForUnmatchedText$1(textNode, text) { + { + warnForTextDifference(textNode.nodeValue, text); + } +} - // 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; +function warnForDeletedHydratableElement$1(parentNode, child) { + { + if (didWarnInvalidHydration) { + return; } + didWarnInvalidHydration = true; + warning_1(false, 'Did not expect server HTML to contain a <%s> in <%s>.', child.nodeName.toLowerCase(), parentNode.nodeName.toLowerCase()); } +} - // Browser does not implement `key`, polyfill as much of it as we can. - if (nativeEvent.type === 'keypress') { - var charCode = getEventCharCode_1(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'; +function warnForDeletedHydratableText$1(parentNode, child) { + { + if (didWarnInvalidHydration) { + return; + } + didWarnInvalidHydration = true; + warning_1(false, 'Did not expect server HTML to contain the text node "%s" in <%s>.', child.nodeValue, parentNode.nodeName.toLowerCase()); } - return ''; } -var getEventKey_1 = getEventKey; - -/** - * @interface KeyboardEvent - * @see http://www.w3.org/TR/DOM-Level-3-Events/ - */ -var KeyboardEventInterface = { - key: getEventKey_1, - location: null, - ctrlKey: null, - shiftKey: null, - altKey: null, - metaKey: null, - repeat: null, - locale: null, - getModifierState: getEventModifierState_1, - // 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_1(event); +function warnForInsertedHydratedElement$1(parentNode, tag, props) { + { + if (didWarnInvalidHydration) { + return; } - return 0; - }, - keyCode: function (event) { - // `keyCode` is the result of a KeyDown/Up event and represents the value of - // physical keyboard key. + didWarnInvalidHydration = true; + warning_1(false, 'Expected server HTML to contain a matching <%s> in <%s>.', tag, parentNode.nodeName.toLowerCase()); + } +} - // 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_1(event); +function warnForInsertedHydratedText$1(parentNode, text) { + { + if (text === '') { + // We expect to insert empty text nodes since they're not represented in + // the HTML. + // TODO: Remove this special case if we can just avoid inserting empty + // text nodes. + return; } - if (event.type === 'keydown' || event.type === 'keyup') { - return event.keyCode; + if (didWarnInvalidHydration) { + return; } - return 0; + didWarnInvalidHydration = true; + warning_1(false, 'Expected server HTML to contain a matching text node for "%s" in <%s>.', text, parentNode.nodeName.toLowerCase()); } -}; - -/** - * @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_1.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget); } -SyntheticUIEvent_1.augmentClass(SyntheticKeyboardEvent, KeyboardEventInterface); - -var SyntheticKeyboardEvent_1 = SyntheticKeyboardEvent; - -/** - * @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 {SyntheticUIEvent} - */ -function SyntheticDragEvent(dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget) { - return SyntheticMouseEvent_1.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget); +function restoreControlledState(domElement, tag, props) { + switch (tag) { + case 'input': + restoreControlledState$1(domElement, props); + return; + case 'textarea': + restoreControlledState$3(domElement, props); + return; + case 'select': + restoreControlledState$2(domElement, props); + return; + } } -SyntheticMouseEvent_1.augmentClass(SyntheticDragEvent, DragEventInterface); - -var SyntheticDragEvent_1 = SyntheticDragEvent; - -/** - * @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_1 -}; +var ReactDOMFiberComponent = Object.freeze({ + createElement: createElement$1, + createTextNode: createTextNode$1, + setInitialProperties: setInitialProperties$1, + diffProperties: diffProperties$1, + updateProperties: updateProperties$1, + diffHydratedProperties: diffHydratedProperties$1, + diffHydratedText: diffHydratedText$1, + warnForUnmatchedText: warnForUnmatchedText$1, + warnForDeletedHydratableElement: warnForDeletedHydratableElement$1, + warnForDeletedHydratableText: warnForDeletedHydratableText$1, + warnForInsertedHydratedElement: warnForInsertedHydratedElement$1, + warnForInsertedHydratedText: warnForInsertedHydratedText$1, + restoreControlledState: restoreControlledState +}); -/** - * @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_1.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget); -} +// TODO: direct imports like some-package/src/* are bad. Fix me. +var getCurrentFiberStackAddendum$6 = ReactDebugCurrentFiber.getCurrentFiberStackAddendum; -SyntheticUIEvent_1.augmentClass(SyntheticTouchEvent, TouchEventInterface); +var validateDOMNesting = emptyFunction_1; -var SyntheticTouchEvent_1 = SyntheticTouchEvent; +{ + // This validation code was written based on the HTML5 parsing spec: + // https://html.spec.whatwg.org/multipage/syntax.html#has-an-element-in-scope + // + // Note: this does not catch all invalid nesting, nor does it try to (as it's + // not clear what practical benefit doing so provides); instead, we warn only + // for cases where the parser will give a parse tree differing from what React + // intended. For example, <b><div></div></b> is invalid but we don't warn + // because it still parses correctly; we do warn for other cases like nested + // <p> tags where the beginning of the second element implicitly closes the + // first, causing a confusing mess. -/** - * @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 -}; + // https://html.spec.whatwg.org/multipage/syntax.html#special + var specialTags = ['address', 'applet', 'area', 'article', 'aside', 'base', 'basefont', 'bgsound', 'blockquote', 'body', 'br', 'button', 'caption', 'center', 'col', 'colgroup', 'dd', 'details', 'dir', 'div', 'dl', 'dt', 'embed', 'fieldset', 'figcaption', 'figure', 'footer', 'form', 'frame', 'frameset', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'head', 'header', 'hgroup', 'hr', 'html', 'iframe', 'img', 'input', 'isindex', 'li', 'link', 'listing', 'main', 'marquee', 'menu', 'menuitem', 'meta', 'nav', 'noembed', 'noframes', 'noscript', 'object', 'ol', 'p', 'param', 'plaintext', 'pre', 'script', 'section', 'select', 'source', 'style', 'summary', 'table', 'tbody', 'td', 'template', 'textarea', 'tfoot', 'th', 'thead', 'title', 'tr', 'track', 'ul', 'wbr', 'xmp']; -/** - * @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); -} + // https://html.spec.whatwg.org/multipage/syntax.html#has-an-element-in-scope + var inScopeTags = ['applet', 'caption', 'html', 'table', 'td', 'th', 'marquee', 'object', 'template', -SyntheticEvent_1.augmentClass(SyntheticTransitionEvent, TransitionEventInterface); + // https://html.spec.whatwg.org/multipage/syntax.html#html-integration-point + // TODO: Distinguish by namespace here -- for <title>, including it here + // errs on the side of fewer warnings + 'foreignObject', 'desc', 'title']; -var SyntheticTransitionEvent_1 = SyntheticTransitionEvent; + // https://html.spec.whatwg.org/multipage/syntax.html#has-an-element-in-button-scope + var buttonScopeTags = inScopeTags.concat(['button']); -/** - * @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, + // https://html.spec.whatwg.org/multipage/syntax.html#generate-implied-end-tags + var impliedEndTags = ['dd', 'dt', 'li', 'option', 'optgroup', 'p', 'rp', 'rt']; - // 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 -}; + var emptyAncestorInfo = { + current: 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_1.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget); -} + formTag: null, + aTagInScope: null, + buttonTagInScope: null, + nobrTagInScope: null, + pTagInButtonScope: null, -SyntheticMouseEvent_1.augmentClass(SyntheticWheelEvent, WheelEventInterface); + listItemTagAutoclosing: null, + dlItemTagAutoclosing: null + }; -var SyntheticWheelEvent_1 = SyntheticWheelEvent; + var updatedAncestorInfo$1 = function (oldInfo, tag, instance) { + var ancestorInfo = _assign({}, oldInfo || emptyAncestorInfo); + var info = { tag: tag, instance: instance }; -/** - * 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; + if (inScopeTags.indexOf(tag) !== -1) { + ancestorInfo.aTagInScope = null; + ancestorInfo.buttonTagInScope = null; + ancestorInfo.nobrTagInScope = null; + } + if (buttonScopeTags.indexOf(tag) !== -1) { + ancestorInfo.pTagInButtonScope = null; + } - var type = { - phasedRegistrationNames: { - bubbled: onEvent, - captured: onEvent + 'Capture' - }, - dependencies: [topEvent] - }; - eventTypes$4[event] = type; - topLevelEventsToDispatchConfig[topEvent] = type; -}); + // See rules for 'li', 'dd', 'dt' start tags in + // https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-inbody + if (specialTags.indexOf(tag) !== -1 && tag !== 'address' && tag !== 'div' && tag !== 'p') { + ancestorInfo.listItemTagAutoclosing = null; + ancestorInfo.dlItemTagAutoclosing = null; + } -var SimpleEventPlugin = { - eventTypes: eventTypes$4, + ancestorInfo.current = info; - extractEvents: function (topLevelType, targetInst, nativeEvent, nativeEventTarget) { - var dispatchConfig = topLevelEventsToDispatchConfig[topLevelType]; - if (!dispatchConfig) { - return null; + if (tag === 'form') { + ancestorInfo.formTag = info; } - var EventConstructor; - switch (topLevelType) { - case 'topAbort': - case 'topCancel': - case 'topCanPlay': - case 'topCanPlayThrough': - case 'topClose': - case 'topDurationChange': - case 'topEmptied': - case 'topEncrypted': - case 'topEnded': - case 'topError': - case 'topInput': - case 'topInvalid': - case 'topLoad': - case 'topLoadedData': - case 'topLoadedMetadata': - case 'topLoadStart': - case 'topPause': - case 'topPlay': - case 'topPlaying': - case 'topProgress': - case 'topRateChange': - case 'topReset': - case 'topSeeked': - case 'topSeeking': - case 'topStalled': - case 'topSubmit': - case 'topSuspend': - case 'topTimeUpdate': - case 'topToggle': - case 'topVolumeChange': - case 'topWaiting': - // HTML Events - // @see http://www.w3.org/TR/html5/index.html#events-0 - EventConstructor = SyntheticEvent_1; - break; - 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_1(nativeEvent) === 0) { - return null; - } - /* falls through */ - case 'topKeyDown': - case 'topKeyUp': - EventConstructor = SyntheticKeyboardEvent_1; - break; - case 'topBlur': - case 'topFocus': - EventConstructor = SyntheticFocusEvent_1; - 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_1; - break; - case 'topDrag': - case 'topDragEnd': - case 'topDragEnter': - case 'topDragExit': - case 'topDragLeave': - case 'topDragOver': - case 'topDragStart': - case 'topDrop': - EventConstructor = SyntheticDragEvent_1; - break; - case 'topTouchCancel': - case 'topTouchEnd': - case 'topTouchMove': - case 'topTouchStart': - EventConstructor = SyntheticTouchEvent_1; - break; - case 'topAnimationEnd': - case 'topAnimationIteration': - case 'topAnimationStart': - EventConstructor = SyntheticAnimationEvent_1; - break; - case 'topTransitionEnd': - EventConstructor = SyntheticTransitionEvent_1; - break; - case 'topScroll': - EventConstructor = SyntheticUIEvent_1; - break; - case 'topWheel': - EventConstructor = SyntheticWheelEvent_1; - break; - case 'topCopy': - case 'topCut': - case 'topPaste': - EventConstructor = SyntheticClipboardEvent_1; - break; + if (tag === 'a') { + ancestorInfo.aTagInScope = info; + } + if (tag === 'button') { + ancestorInfo.buttonTagInScope = info; + } + if (tag === 'nobr') { + ancestorInfo.nobrTagInScope = info; + } + if (tag === 'p') { + ancestorInfo.pTagInButtonScope = info; + } + if (tag === 'li') { + ancestorInfo.listItemTagAutoclosing = info; + } + if (tag === 'dd' || tag === 'dt') { + ancestorInfo.dlItemTagAutoclosing = info; } - !EventConstructor ? invariant_1(false, 'SimpleEventPlugin: Unhandled event type, `%s`.', topLevelType) : void 0; - var event = EventConstructor.getPooled(dispatchConfig, targetInst, nativeEvent, nativeEventTarget); - EventPropagators_1.accumulateTwoPhaseDispatches(event); - return event; - } -}; - -var SimpleEventPlugin_1 = SimpleEventPlugin; -ReactDOMEventListener_1.setHandleTopLevel(ReactBrowserEventEmitter_1.handleTopLevel); + return ancestorInfo; + }; -/** - * Inject modules for resolving DOM hierarchy and plugin ordering. - */ -EventPluginHub_1.injection.injectEventPluginOrder(DOMEventPluginOrder_1); -EventPluginUtils_1.injection.injectComponentTree(ReactDOMComponentTree_1); + /** + * Returns whether + */ + var isTagValidWithParent = function (tag, parentTag) { + // First, let's check if we're in an unusual parsing mode... + switch (parentTag) { + // https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-inselect + case 'select': + return tag === 'option' || tag === 'optgroup' || tag === '#text'; + case 'optgroup': + return tag === 'option' || tag === '#text'; + // Strictly speaking, seeing an <option> doesn't mean we're in a <select> + // but + case 'option': + return tag === '#text'; + // https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-intd + // https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-incaption + // No special behavior since these rules fall back to "in body" mode for + // all except special table nodes which cause bad parsing behavior anyway. -/** - * Some important event plugins included by default (without having to require - * them). - */ -EventPluginHub_1.injection.injectEventPluginsByName({ - SimpleEventPlugin: SimpleEventPlugin_1, - EnterLeaveEventPlugin: EnterLeaveEventPlugin_1, - ChangeEventPlugin: ChangeEventPlugin_1, - SelectEventPlugin: SelectEventPlugin_1, - BeforeInputEventPlugin: BeforeInputEventPlugin_1 -}); + // https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-intr + case 'tr': + return tag === 'th' || tag === 'td' || tag === 'style' || tag === 'script' || tag === 'template'; + // https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-intbody + case 'tbody': + case 'thead': + case 'tfoot': + return tag === 'tr' || tag === 'style' || tag === 'script' || tag === 'template'; + // https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-incolgroup + case 'colgroup': + return tag === 'col' || tag === 'template'; + // https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-intable + case 'table': + return tag === 'caption' || tag === 'colgroup' || tag === 'tbody' || tag === 'tfoot' || tag === 'thead' || tag === 'style' || tag === 'script' || tag === 'template'; + // https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-inhead + case 'head': + return tag === 'base' || tag === 'basefont' || tag === 'bgsound' || tag === 'link' || tag === 'meta' || tag === 'title' || tag === 'noscript' || tag === 'noframes' || tag === 'style' || tag === 'script' || tag === 'template'; + // https://html.spec.whatwg.org/multipage/semantics.html#the-html-element + case 'html': + return tag === 'head' || tag === 'body'; + case '#document': + return tag === 'html'; + } -var MUST_USE_PROPERTY = DOMProperty_1.injection.MUST_USE_PROPERTY; -var HAS_BOOLEAN_VALUE = DOMProperty_1.injection.HAS_BOOLEAN_VALUE; -var HAS_NUMERIC_VALUE = DOMProperty_1.injection.HAS_NUMERIC_VALUE; -var HAS_POSITIVE_NUMERIC_VALUE = DOMProperty_1.injection.HAS_POSITIVE_NUMERIC_VALUE; -var HAS_OVERLOADED_BOOLEAN_VALUE = DOMProperty_1.injection.HAS_OVERLOADED_BOOLEAN_VALUE; -var HAS_STRING_BOOLEAN_VALUE = DOMProperty_1.injection.HAS_STRING_BOOLEAN_VALUE; + // Probably in the "in body" parsing mode, so we outlaw only tag combos + // where the parsing rules cause implicit opens or closes to be added. + // https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-inbody + switch (tag) { + case 'h1': + case 'h2': + case 'h3': + case 'h4': + case 'h5': + case 'h6': + return parentTag !== 'h1' && parentTag !== 'h2' && parentTag !== 'h3' && parentTag !== 'h4' && parentTag !== 'h5' && parentTag !== 'h6'; -var HTMLDOMPropertyConfig = { - // When adding attributes to this list, be sure to also add them to - // the `possibleStandardNames` module to ensure casing and incorrect - // name warnings. - Properties: { - allowFullScreen: HAS_BOOLEAN_VALUE, - // IE only true/false iFrame attribute - // https://msdn.microsoft.com/en-us/library/ms533072(v=vs.85).aspx - allowTransparency: HAS_STRING_BOOLEAN_VALUE, - // specifies target context for links with `preload` type - async: HAS_BOOLEAN_VALUE, - // autoFocus is polyfilled/normalized by AutoFocusUtils - // autoFocus: HAS_BOOLEAN_VALUE, - autoPlay: HAS_BOOLEAN_VALUE, - capture: HAS_BOOLEAN_VALUE, - checked: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE, - cols: HAS_POSITIVE_NUMERIC_VALUE, - contentEditable: HAS_STRING_BOOLEAN_VALUE, - controls: HAS_BOOLEAN_VALUE, - 'default': HAS_BOOLEAN_VALUE, - defer: HAS_BOOLEAN_VALUE, - disabled: HAS_BOOLEAN_VALUE, - download: HAS_OVERLOADED_BOOLEAN_VALUE, - draggable: HAS_STRING_BOOLEAN_VALUE, - formNoValidate: HAS_BOOLEAN_VALUE, - hidden: HAS_BOOLEAN_VALUE, - loop: HAS_BOOLEAN_VALUE, - // Caution; `option.selected` is not updated if `select.multiple` is - // disabled with `removeAttribute`. - multiple: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE, - muted: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE, - noValidate: HAS_BOOLEAN_VALUE, - open: HAS_BOOLEAN_VALUE, - playsInline: HAS_BOOLEAN_VALUE, - readOnly: HAS_BOOLEAN_VALUE, - required: HAS_BOOLEAN_VALUE, - reversed: HAS_BOOLEAN_VALUE, - rows: HAS_POSITIVE_NUMERIC_VALUE, - rowSpan: HAS_NUMERIC_VALUE, - scoped: HAS_BOOLEAN_VALUE, - seamless: HAS_BOOLEAN_VALUE, - selected: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE, - size: HAS_POSITIVE_NUMERIC_VALUE, - start: HAS_NUMERIC_VALUE, - // support for projecting regular DOM Elements via V1 named slots ( shadow dom ) - span: HAS_POSITIVE_NUMERIC_VALUE, - spellCheck: HAS_STRING_BOOLEAN_VALUE, - // Style must be explicitly set in the attribute list. React components - // expect a style object - style: 0, - // itemScope is for for Microdata support. - // See http://schema.org/docs/gs.html - itemScope: HAS_BOOLEAN_VALUE, - // These attributes must stay in the white-list because they have - // different attribute names (see DOMAttributeNames below) - acceptCharset: 0, - className: 0, - htmlFor: 0, - httpEquiv: 0, - // Attributes with mutation methods must be specified in the whitelist - // Set the string boolean flag to allow the behavior - value: HAS_STRING_BOOLEAN_VALUE - }, - DOMAttributeNames: { - acceptCharset: 'accept-charset', - className: 'class', - htmlFor: 'for', - httpEquiv: 'http-equiv' - }, - DOMMutationMethods: { - value: function (node, value) { - if (value == null) { - return node.removeAttribute('value'); - } + case 'rp': + case 'rt': + return impliedEndTags.indexOf(parentTag) === -1; - // Number inputs get special treatment due to some edge cases in - // Chrome. Let everything else assign the value attribute as normal. - // https://github.com/facebook/react/issues/7253#issuecomment-236074326 - if (node.type !== 'number' || node.hasAttribute('value') === false) { - node.setAttribute('value', '' + value); - } else if (node.validity && !node.validity.badInput && node.ownerDocument.activeElement !== node) { - // Don't assign an attribute if validation reports bad - // input. Chrome will clear the value. Additionally, don't - // operate on inputs that have focus, otherwise Chrome might - // strip off trailing decimal places and cause the user's - // cursor position to jump to the beginning of the input. - // - // In ReactDOMInput, we have an onBlur event that will trigger - // this function again when focus is lost. - node.setAttribute('value', '' + value); - } + case 'body': + case 'caption': + case 'col': + case 'colgroup': + case 'frame': + case 'head': + case 'html': + case 'tbody': + case 'td': + case 'tfoot': + case 'th': + case 'thead': + case 'tr': + // These tags are only valid with a few parents that have special child + // parsing rules -- if we're down here, then none of those matched and + // so we allow it only if we don't know what the parent is, as all other + // cases are invalid. + return parentTag == null; } - } -}; -var HTMLDOMPropertyConfig_1 = HTMLDOMPropertyConfig; + return true; + }; -var HAS_STRING_BOOLEAN_VALUE$1 = DOMProperty_1.injection.HAS_STRING_BOOLEAN_VALUE; + /** + * Returns whether + */ + var findInvalidAncestorForTag = function (tag, ancestorInfo) { + switch (tag) { + case 'address': + case 'article': + case 'aside': + case 'blockquote': + case 'center': + case 'details': + case 'dialog': + case 'dir': + case 'div': + case 'dl': + case 'fieldset': + case 'figcaption': + case 'figure': + case 'footer': + case 'header': + case 'hgroup': + case 'main': + case 'menu': + case 'nav': + case 'ol': + case 'p': + case 'section': + case 'summary': + case 'ul': + case 'pre': + case 'listing': + case 'table': + case 'hr': + case 'xmp': + case 'h1': + case 'h2': + case 'h3': + case 'h4': + case 'h5': + case 'h6': + return ancestorInfo.pTagInButtonScope; + case 'form': + return ancestorInfo.formTag || ancestorInfo.pTagInButtonScope; -var NS = { - xlink: 'http://www.w3.org/1999/xlink', - xml: 'http://www.w3.org/XML/1998/namespace' -}; + case 'li': + return ancestorInfo.listItemTagAutoclosing; -/** - * This is a list of all SVG attributes that need special casing, - * namespacing, or boolean value assignment. - * - * When adding attributes to this list, be sure to also add them to - * the `possibleStandardNames` module to ensure casing and incorrect - * name warnings. - * - * SVG Attributes List: - * https://www.w3.org/TR/SVG/attindex.html - * SMIL Spec: - * https://www.w3.org/TR/smil - */ -var ATTRS = ['accent-height', 'alignment-baseline', 'arabic-form', 'baseline-shift', 'cap-height', 'clip-path', 'clip-rule', 'color-interpolation', 'color-interpolation-filters', 'color-profile', 'color-rendering', 'dominant-baseline', 'enable-background', 'fill-opacity', 'fill-rule', 'flood-color', 'flood-opacity', 'font-family', 'font-size', 'font-size-adjust', 'font-stretch', 'font-style', 'font-variant', 'font-weight', 'glyph-name', 'glyph-orientation-horizontal', 'glyph-orientation-vertical', 'horiz-adv-x', 'horiz-origin-x', 'image-rendering', 'letter-spacing', 'lighting-color', 'marker-end', 'marker-mid', 'marker-start', 'overline-position', 'overline-thickness', 'paint-order', 'panose-1', 'pointer-events', 'rendering-intent', 'shape-rendering', 'stop-color', 'stop-opacity', 'strikethrough-position', 'strikethrough-thickness', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'text-anchor', 'text-decoration', 'text-rendering', 'underline-position', 'underline-thickness', 'unicode-bidi', 'unicode-range', 'units-per-em', 'v-alphabetic', 'v-hanging', 'v-ideographic', 'v-mathematical', 'vector-effect', 'vert-adv-y', 'vert-origin-x', 'vert-origin-y', 'word-spacing', 'writing-mode', 'x-height', 'xlink:actuate', 'xlink:arcrole', 'xlink:href', 'xlink:role', 'xlink:show', 'xlink:title', 'xlink:type', 'xml:base', 'xmlns:xlink', 'xml:lang', 'xml:space']; + case 'dd': + case 'dt': + return ancestorInfo.dlItemTagAutoclosing; -var SVGDOMPropertyConfig = { - Properties: { - autoReverse: HAS_STRING_BOOLEAN_VALUE$1, - externalResourcesRequired: HAS_STRING_BOOLEAN_VALUE$1, - preserveAlpha: HAS_STRING_BOOLEAN_VALUE$1 - }, - DOMAttributeNames: { - autoReverse: 'autoReverse', - externalResourcesRequired: 'externalResourcesRequired', - preserveAlpha: 'preserveAlpha' - }, - DOMAttributeNamespaces: { - xlinkActuate: NS.xlink, - xlinkArcrole: NS.xlink, - xlinkHref: NS.xlink, - xlinkRole: NS.xlink, - xlinkShow: NS.xlink, - xlinkTitle: NS.xlink, - xlinkType: NS.xlink, - xmlBase: NS.xml, - xmlLang: NS.xml, - xmlSpace: NS.xml - } -}; + case 'button': + return ancestorInfo.buttonTagInScope; -var CAMELIZE = /[\-\:]([a-z])/g; -var capitalize = function (token) { - return token[1].toUpperCase(); -}; + case 'a': + // Spec says something about storing a list of markers, but it sounds + // equivalent to this check. + return ancestorInfo.aTagInScope; -ATTRS.forEach(function (original) { - var reactName = original.replace(CAMELIZE, capitalize); + case 'nobr': + return ancestorInfo.nobrTagInScope; + } - SVGDOMPropertyConfig.Properties[reactName] = 0; - SVGDOMPropertyConfig.DOMAttributeNames[reactName] = original; -}); + return null; + }; -var SVGDOMPropertyConfig_1 = SVGDOMPropertyConfig; + var didWarn = {}; -DOMProperty_1.injection.injectDOMPropertyConfig(HTMLDOMPropertyConfig_1); -DOMProperty_1.injection.injectDOMPropertyConfig(SVGDOMPropertyConfig_1); + validateDOMNesting = function (childTag, childText, ancestorInfo) { + ancestorInfo = ancestorInfo || emptyAncestorInfo; + var parentInfo = ancestorInfo.current; + var parentTag = parentInfo && parentInfo.tag; -var injectInternals = ReactFiberDevToolsHook.injectInternals; + if (childText != null) { + warning_1(childTag == null, 'validateDOMNesting: when childText is passed, childTag should be null'); + childTag = '#text'; + } -var ELEMENT_NODE = HTMLNodeType_1.ELEMENT_NODE; -var TEXT_NODE = HTMLNodeType_1.TEXT_NODE; -var COMMENT_NODE = HTMLNodeType_1.COMMENT_NODE; -var DOCUMENT_NODE = HTMLNodeType_1.DOCUMENT_NODE; -var DOCUMENT_FRAGMENT_NODE = HTMLNodeType_1.DOCUMENT_FRAGMENT_NODE; + var invalidParent = isTagValidWithParent(childTag, parentTag) ? null : parentInfo; + var invalidAncestor = invalidParent ? null : findInvalidAncestorForTag(childTag, ancestorInfo); + var invalidParentOrAncestor = invalidParent || invalidAncestor; + if (!invalidParentOrAncestor) { + return; + } -var ROOT_ATTRIBUTE_NAME = DOMProperty_1.ROOT_ATTRIBUTE_NAME; + var ancestorTag = invalidParentOrAncestor.tag; + var addendum = getCurrentFiberStackAddendum$6(); + + var warnKey = !!invalidParent + '|' + childTag + '|' + ancestorTag + '|' + addendum; + if (didWarn[warnKey]) { + return; + } + didWarn[warnKey] = true; + var tagDisplayName = childTag; + var whitespaceInfo = ''; + if (childTag === '#text') { + if (/\S/.test(childText)) { + tagDisplayName = 'Text nodes'; + } else { + tagDisplayName = 'Whitespace text nodes'; + whitespaceInfo = " Make sure you don't have any extra whitespace between tags on " + 'each line of your source code.'; + } + } else { + tagDisplayName = '<' + childTag + '>'; + } + if (invalidParent) { + var info = ''; + if (ancestorTag === 'table' && childTag === 'tr') { + info += ' Add a <tbody> to your code to match the DOM tree generated by ' + 'the browser.'; + } + warning_1(false, 'validateDOMNesting(...): %s cannot appear as a child of <%s>.%s%s%s', tagDisplayName, ancestorTag, whitespaceInfo, info, addendum); + } else { + warning_1(false, 'validateDOMNesting(...): %s cannot appear as a descendant of ' + '<%s>.%s', tagDisplayName, ancestorTag, addendum); + } + }; + // TODO: turn this into a named export + validateDOMNesting.updatedAncestorInfo = updatedAncestorInfo$1; -var getChildNamespace = DOMNamespaces.getChildNamespace; -var createElement = ReactDOMFiberComponent_1.createElement; -var createTextNode = ReactDOMFiberComponent_1.createTextNode; -var setInitialProperties = ReactDOMFiberComponent_1.setInitialProperties; -var diffProperties = ReactDOMFiberComponent_1.diffProperties; -var updateProperties = ReactDOMFiberComponent_1.updateProperties; -var diffHydratedProperties = ReactDOMFiberComponent_1.diffHydratedProperties; -var diffHydratedText = ReactDOMFiberComponent_1.diffHydratedText; -var warnForDeletedHydratableElement = ReactDOMFiberComponent_1.warnForDeletedHydratableElement; -var warnForDeletedHydratableText = ReactDOMFiberComponent_1.warnForDeletedHydratableText; -var warnForInsertedHydratedElement = ReactDOMFiberComponent_1.warnForInsertedHydratedElement; -var warnForInsertedHydratedText = ReactDOMFiberComponent_1.warnForInsertedHydratedText; -var precacheFiberNode = ReactDOMComponentTree_1.precacheFiberNode; -var updateFiberProps = ReactDOMComponentTree_1.updateFiberProps; + // For testing + validateDOMNesting.isTagValidInContext = function (tag, ancestorInfo) { + ancestorInfo = ancestorInfo || emptyAncestorInfo; + var parentInfo = ancestorInfo.current; + var parentTag = parentInfo && parentInfo.tag; + return isTagValidWithParent(tag, parentTag) && !findInvalidAncestorForTag(tag, ancestorInfo); + }; +} +var validateDOMNesting$1 = validateDOMNesting; -{ - var lowPriorityWarning = lowPriorityWarning_1; - var warning = warning_1; - var validateDOMNesting = validateDOMNesting_1; - var updatedAncestorInfo = validateDOMNesting.updatedAncestorInfo; +// TODO: direct imports like some-package/src/* are bad. Fix me. +var createElement = createElement$1; +var createTextNode = createTextNode$1; +var setInitialProperties = setInitialProperties$1; +var diffProperties = diffProperties$1; +var updateProperties = updateProperties$1; +var diffHydratedProperties = diffHydratedProperties$1; +var diffHydratedText = diffHydratedText$1; +var warnForUnmatchedText = warnForUnmatchedText$1; +var warnForDeletedHydratableElement = warnForDeletedHydratableElement$1; +var warnForDeletedHydratableText = warnForDeletedHydratableText$1; +var warnForInsertedHydratedElement = warnForInsertedHydratedElement$1; +var warnForInsertedHydratedText = warnForInsertedHydratedText$1; +var updatedAncestorInfo = validateDOMNesting$1.updatedAncestorInfo; +var precacheFiberNode = precacheFiberNode$1; +var updateFiberProps = updateFiberProps$1; +{ + var SUPPRESS_HYDRATION_WARNING = 'suppressHydrationWarning'; if (typeof Map !== 'function' || Map.prototype == null || typeof Map.prototype.forEach !== 'function' || typeof Set !== 'function' || Set.prototype == null || typeof Set.prototype.clear !== 'function' || typeof Set.prototype.forEach !== 'function') { - warning(false, 'React depends on Map and Set built-in types. Make sure that you load a ' + 'polyfill in older browsers. http://fb.me/react-polyfills'); + warning_1(false, 'React depends on Map and Set built-in types. Make sure that you load a ' + 'polyfill in older browsers. http://fb.me/react-polyfills'); } } - - -ReactControlledComponent_1.injection.injectFiberControlledHostComponent(ReactDOMFiberComponent_1); -findDOMNode_1._injectFiber(function (fiber) { - return DOMRenderer.findHostInstance(fiber); -}); +injection$3.injectFiberControlledHostComponent(ReactDOMFiberComponent); var eventsEnabled = null; var selectionInformation = null; @@ -18054,19 +15584,28 @@ function shouldAutoFocusHostComponent(type, props) { return false; } -var DOMRenderer = ReactFiberReconciler({ +var DOMRenderer = reactReconciler({ getRootHostContext: function (rootContainerInstance) { var type = void 0; var namespace = void 0; - if (rootContainerInstance.nodeType === DOCUMENT_NODE) { - type = '#document'; - var root = rootContainerInstance.documentElement; - namespace = root ? root.namespaceURI : getChildNamespace(null, ''); - } else { - var container = rootContainerInstance.nodeType === COMMENT_NODE ? rootContainerInstance.parentNode : rootContainerInstance; - var ownNamespace = container.namespaceURI || null; - type = container.tagName; - namespace = getChildNamespace(ownNamespace, type); + var nodeType = rootContainerInstance.nodeType; + switch (nodeType) { + case DOCUMENT_NODE: + case DOCUMENT_FRAGMENT_NODE: + { + type = nodeType === DOCUMENT_NODE ? '#document' : '#fragment'; + var root = rootContainerInstance.documentElement; + namespace = root ? root.namespaceURI : getChildNamespace(null, ''); + break; + } + default: + { + var container = nodeType === COMMENT_NODE ? rootContainerInstance.parentNode : rootContainerInstance; + var ownNamespace = container.namespaceURI || null; + type = container.tagName; + namespace = getChildNamespace(ownNamespace, type); + break; + } } { var validatedTag = type.toLowerCase(); @@ -18089,14 +15628,14 @@ var DOMRenderer = ReactFiberReconciler({ return instance; }, prepareForCommit: function () { - eventsEnabled = ReactBrowserEventEmitter_1.isEnabled(); - selectionInformation = ReactInputSelection_1.getSelectionInformation(); - ReactBrowserEventEmitter_1.setEnabled(false); + eventsEnabled = isEnabled(); + selectionInformation = getSelectionInformation(); + setEnabled(false); }, resetAfterCommit: function () { - ReactInputSelection_1.restoreSelection(selectionInformation); + restoreSelection(selectionInformation); selectionInformation = null; - ReactBrowserEventEmitter_1.setEnabled(eventsEnabled); + setEnabled(eventsEnabled); eventsEnabled = null; }, createInstance: function (type, props, rootContainerInstance, hostContext, internalInstanceHandle) { @@ -18104,11 +15643,11 @@ var DOMRenderer = ReactFiberReconciler({ { // TODO: take namespace into account when validating. var hostContextDev = hostContext; - validateDOMNesting(type, null, null, hostContextDev.ancestorInfo); + validateDOMNesting$1(type, null, hostContextDev.ancestorInfo); if (typeof props.children === 'string' || typeof props.children === 'number') { var string = '' + props.children; var ownAncestorInfo = updatedAncestorInfo(hostContextDev.ancestorInfo, type, null); - validateDOMNesting(null, string, null, ownAncestorInfo); + validateDOMNesting$1(null, string, ownAncestorInfo); } parentNamespace = hostContextDev.namespace; } @@ -18130,135 +15669,184 @@ var DOMRenderer = ReactFiberReconciler({ if (typeof newProps.children !== typeof oldProps.children && (typeof newProps.children === 'string' || typeof newProps.children === 'number')) { var string = '' + newProps.children; var ownAncestorInfo = updatedAncestorInfo(hostContextDev.ancestorInfo, type, null); - validateDOMNesting(null, string, null, ownAncestorInfo); + validateDOMNesting$1(null, string, ownAncestorInfo); } } return diffProperties(domElement, type, oldProps, newProps, rootContainerInstance); }, - commitMount: function (domElement, type, newProps, internalInstanceHandle) { - domElement.focus(); - }, - commitUpdate: function (domElement, updatePayload, type, oldProps, newProps, internalInstanceHandle) { - // Update the props handle so that we know which props are the ones with - // with current event handlers. - updateFiberProps(domElement, newProps); - // Apply the diff to the DOM node. - updateProperties(domElement, updatePayload, type, oldProps, newProps); - }, shouldSetTextContent: function (type, props) { return type === 'textarea' || typeof props.children === 'string' || typeof props.children === 'number' || typeof props.dangerouslySetInnerHTML === 'object' && props.dangerouslySetInnerHTML !== null && typeof props.dangerouslySetInnerHTML.__html === 'string'; }, - resetTextContent: function (domElement) { - domElement.textContent = ''; - }, shouldDeprioritizeSubtree: function (type, props) { return !!props.hidden; }, createTextInstance: function (text, rootContainerInstance, hostContext, internalInstanceHandle) { { var hostContextDev = hostContext; - validateDOMNesting(null, text, null, hostContextDev.ancestorInfo); + validateDOMNesting$1(null, text, hostContextDev.ancestorInfo); } var textNode = createTextNode(text, rootContainerInstance); precacheFiberNode(internalInstanceHandle, textNode); return textNode; }, - commitTextUpdate: function (textInstance, oldText, newText) { - textInstance.nodeValue = newText; - }, - appendChild: function (parentInstance, child) { - parentInstance.appendChild(child); - }, - appendChildToContainer: function (container, child) { - if (container.nodeType === COMMENT_NODE) { - container.parentNode.insertBefore(child, container); - } else { - container.appendChild(child); - } - }, - insertBefore: function (parentInstance, child, beforeChild) { - parentInstance.insertBefore(child, beforeChild); - }, - insertInContainerBefore: function (container, child, beforeChild) { - if (container.nodeType === COMMENT_NODE) { - container.parentNode.insertBefore(child, beforeChild); - } else { - container.insertBefore(child, beforeChild); - } - }, - removeChild: function (parentInstance, child) { - parentInstance.removeChild(child); - }, - removeChildFromContainer: function (container, child) { - if (container.nodeType === COMMENT_NODE) { - container.parentNode.removeChild(child); - } else { - container.removeChild(child); - } - }, - canHydrateInstance: function (instance, type, props) { - return instance.nodeType === ELEMENT_NODE && type === instance.nodeName.toLowerCase(); - }, - canHydrateTextInstance: function (instance, text) { - if (text === '') { - // Empty strings are not parsed by HTML so there won't be a correct match here. - return false; - } - return instance.nodeType === TEXT_NODE; - }, - getNextHydratableSibling: function (instance) { - var node = instance.nextSibling; - // Skip non-hydratable nodes. - while (node && node.nodeType !== ELEMENT_NODE && node.nodeType !== TEXT_NODE) { - node = node.nextSibling; - } - return node; - }, - getFirstHydratableChild: function (parentInstance) { - var next = parentInstance.firstChild; - // Skip non-hydratable nodes. - while (next && next.nodeType !== ELEMENT_NODE && next.nodeType !== TEXT_NODE) { - next = next.nextSibling; - } - return next; - }, - hydrateInstance: function (instance, type, props, rootContainerInstance, hostContext, internalInstanceHandle) { - precacheFiberNode(internalInstanceHandle, instance); - // TODO: Possibly defer this until the commit phase where all the events - // get attached. - updateFiberProps(instance, props); - var parentNamespace = void 0; - { - var hostContextDev = hostContext; - parentNamespace = hostContextDev.namespace; + + + now: now, + + mutation: { + commitMount: function (domElement, type, newProps, internalInstanceHandle) { + domElement.focus(); + }, + commitUpdate: function (domElement, updatePayload, type, oldProps, newProps, internalInstanceHandle) { + // Update the props handle so that we know which props are the ones with + // with current event handlers. + updateFiberProps(domElement, newProps); + // Apply the diff to the DOM node. + updateProperties(domElement, updatePayload, type, oldProps, newProps); + }, + resetTextContent: function (domElement) { + domElement.textContent = ''; + }, + commitTextUpdate: function (textInstance, oldText, newText) { + textInstance.nodeValue = newText; + }, + appendChild: function (parentInstance, child) { + parentInstance.appendChild(child); + }, + appendChildToContainer: function (container, child) { + if (container.nodeType === COMMENT_NODE) { + container.parentNode.insertBefore(child, container); + } else { + container.appendChild(child); + } + }, + insertBefore: function (parentInstance, child, beforeChild) { + parentInstance.insertBefore(child, beforeChild); + }, + insertInContainerBefore: function (container, child, beforeChild) { + if (container.nodeType === COMMENT_NODE) { + container.parentNode.insertBefore(child, beforeChild); + } else { + container.insertBefore(child, beforeChild); + } + }, + removeChild: function (parentInstance, child) { + parentInstance.removeChild(child); + }, + removeChildFromContainer: function (container, child) { + if (container.nodeType === COMMENT_NODE) { + container.parentNode.removeChild(child); + } else { + container.removeChild(child); + } } - return diffHydratedProperties(instance, type, props, parentNamespace, rootContainerInstance); - }, - hydrateTextInstance: function (textInstance, text, internalInstanceHandle) { - precacheFiberNode(internalInstanceHandle, textInstance); - return diffHydratedText(textInstance, text); }, - didNotHydrateInstance: function (parentInstance, instance) { - if (instance.nodeType === 1) { - warnForDeletedHydratableElement(parentInstance, instance); - } else { - warnForDeletedHydratableText(parentInstance, instance); + + hydration: { + canHydrateInstance: function (instance, type, props) { + if (instance.nodeType !== ELEMENT_NODE || type.toLowerCase() !== instance.nodeName.toLowerCase()) { + return null; + } + // This has now been refined to an element node. + return instance; + }, + canHydrateTextInstance: function (instance, text) { + if (text === '' || instance.nodeType !== TEXT_NODE) { + // Empty strings are not parsed by HTML so there won't be a correct match here. + return null; + } + // This has now been refined to a text node. + return instance; + }, + getNextHydratableSibling: function (instance) { + var node = instance.nextSibling; + // Skip non-hydratable nodes. + while (node && node.nodeType !== ELEMENT_NODE && node.nodeType !== TEXT_NODE) { + node = node.nextSibling; + } + return node; + }, + getFirstHydratableChild: function (parentInstance) { + var next = parentInstance.firstChild; + // Skip non-hydratable nodes. + while (next && next.nodeType !== ELEMENT_NODE && next.nodeType !== TEXT_NODE) { + next = next.nextSibling; + } + return next; + }, + hydrateInstance: function (instance, type, props, rootContainerInstance, hostContext, internalInstanceHandle) { + precacheFiberNode(internalInstanceHandle, instance); + // TODO: Possibly defer this until the commit phase where all the events + // get attached. + updateFiberProps(instance, props); + var parentNamespace = void 0; + { + var hostContextDev = hostContext; + parentNamespace = hostContextDev.namespace; + } + return diffHydratedProperties(instance, type, props, parentNamespace, rootContainerInstance); + }, + hydrateTextInstance: function (textInstance, text, internalInstanceHandle) { + precacheFiberNode(internalInstanceHandle, textInstance); + return diffHydratedText(textInstance, text); + }, + didNotMatchHydratedContainerTextInstance: function (parentContainer, textInstance, text) { + { + warnForUnmatchedText(textInstance, text); + } + }, + didNotMatchHydratedTextInstance: function (parentType, parentProps, parentInstance, textInstance, text) { + if (true && parentProps[SUPPRESS_HYDRATION_WARNING] !== true) { + warnForUnmatchedText(textInstance, text); + } + }, + didNotHydrateContainerInstance: function (parentContainer, instance) { + { + if (instance.nodeType === 1) { + warnForDeletedHydratableElement(parentContainer, instance); + } else { + warnForDeletedHydratableText(parentContainer, instance); + } + } + }, + didNotHydrateInstance: function (parentType, parentProps, parentInstance, instance) { + if (true && parentProps[SUPPRESS_HYDRATION_WARNING] !== true) { + if (instance.nodeType === 1) { + warnForDeletedHydratableElement(parentInstance, instance); + } else { + warnForDeletedHydratableText(parentInstance, instance); + } + } + }, + didNotFindHydratableContainerInstance: function (parentContainer, type, props) { + { + warnForInsertedHydratedElement(parentContainer, type, props); + } + }, + didNotFindHydratableContainerTextInstance: function (parentContainer, text) { + { + warnForInsertedHydratedText(parentContainer, text); + } + }, + didNotFindHydratableInstance: function (parentType, parentProps, parentInstance, type, props) { + if (true && parentProps[SUPPRESS_HYDRATION_WARNING] !== true) { + warnForInsertedHydratedElement(parentInstance, type, props); + } + }, + didNotFindHydratableTextInstance: function (parentType, parentProps, parentInstance, text) { + if (true && parentProps[SUPPRESS_HYDRATION_WARNING] !== true) { + warnForInsertedHydratedText(parentInstance, text); + } } }, - didNotFindHydratableInstance: function (parentInstance, type, props) { - warnForInsertedHydratedElement(parentInstance, type, props); - }, - didNotFindHydratableTextInstance: function (parentInstance, text) { - warnForInsertedHydratedText(parentInstance, text); - }, - - scheduleDeferredCallback: ReactDOMFrameScheduling.rIC, + scheduleDeferredCallback: rIC, + cancelDeferredCallback: cIC, - useSyncScheduling: !ReactDOMFeatureFlags_1.fiberAsyncScheduling + useSyncScheduling: !enableAsyncSchedulingByDefaultInReactDOM }); -ReactGenericBatching_1.injection.injectFiberBatchedUpdates(DOMRenderer.batchedUpdates); +injection$4.injectFiberBatchedUpdates(DOMRenderer.batchedUpdates); var warnedAboutHydrateAPI = false; @@ -18269,17 +15857,17 @@ function renderSubtreeIntoContainer(parentComponent, children, container, forceH if (container._reactRootContainer && container.nodeType !== COMMENT_NODE) { var hostInstance = DOMRenderer.findHostInstanceWithNoPortals(container._reactRootContainer.current); if (hostInstance) { - warning(hostInstance.parentNode === container, 'render(...): It looks like the React-rendered content of this ' + 'container was removed without using React. This is not ' + 'supported and will cause errors. Instead, call ' + 'ReactDOM.unmountComponentAtNode to empty a container.'); + warning_1(hostInstance.parentNode === container, 'render(...): It looks like the React-rendered content of this ' + 'container was removed without using React. This is not ' + 'supported and will cause errors. Instead, call ' + 'ReactDOM.unmountComponentAtNode to empty a container.'); } } var isRootRenderedBySomeReact = !!container._reactRootContainer; var rootEl = getReactRootElementInContainer(container); - var hasNonRootReactChild = !!(rootEl && ReactDOMComponentTree_1.getInstanceFromNode(rootEl)); + var hasNonRootReactChild = !!(rootEl && getInstanceFromNode$1(rootEl)); - warning(!hasNonRootReactChild || isRootRenderedBySomeReact, 'render(...): Replacing React-rendered children with a new root ' + 'component. If you intended to update the children of this node, ' + 'you should instead have the existing children update their state ' + 'and render the new components instead of calling ReactDOM.render.'); + warning_1(!hasNonRootReactChild || isRootRenderedBySomeReact, 'render(...): Replacing React-rendered children with a new root ' + 'component. If you intended to update the children of this node, ' + 'you should instead have the existing children update their state ' + 'and render the new components instead of calling ReactDOM.render.'); - warning(container.nodeType !== ELEMENT_NODE || !container.tagName || container.tagName.toUpperCase() !== 'BODY', 'render(): Rendering components directly into document.body is ' + 'discouraged, since its children are often manipulated by third-party ' + 'scripts and browser extensions. This may lead to subtle ' + 'reconciliation issues. Try rendering into a container element created ' + 'for your app.'); + warning_1(container.nodeType !== ELEMENT_NODE || !container.tagName || container.tagName.toUpperCase() !== 'BODY', 'render(): Rendering components directly into document.body is ' + 'discouraged, since its children are often manipulated by third-party ' + 'scripts and browser extensions. This may lead to subtle ' + 'reconciliation issues. Try rendering into a container element created ' + 'for your app.'); } var root = container._reactRootContainer; @@ -18293,7 +15881,7 @@ function renderSubtreeIntoContainer(parentComponent, children, container, forceH { if (!warned && rootSibling.nodeType === ELEMENT_NODE && rootSibling.hasAttribute(ROOT_ATTRIBUTE_NAME)) { warned = true; - warning(false, 'render(): Target node has markup rendered by React, but there ' + 'are unrelated nodes as well. This is most commonly caused by ' + 'white-space inserted around server-rendered markup.'); + warning_1(false, 'render(): Target node has markup rendered by React, but there ' + 'are unrelated nodes as well. This is most commonly caused by ' + 'white-space inserted around server-rendered markup.'); } } container.removeChild(rootSibling); @@ -18302,10 +15890,10 @@ function renderSubtreeIntoContainer(parentComponent, children, container, forceH { if (shouldHydrate && !forceHydrate && !warnedAboutHydrateAPI) { warnedAboutHydrateAPI = true; - lowPriorityWarning(false, 'render(): Calling ReactDOM.render() to hydrate server-rendered markup ' + 'will stop working in React v17. Replace the ReactDOM.render() call ' + 'with ReactDOM.hydrate() if you want React to attach to the server HTML.'); + lowPriorityWarning$1(false, 'render(): Calling ReactDOM.render() to hydrate server-rendered markup ' + 'will stop working in React v17. Replace the ReactDOM.render() call ' + 'with ReactDOM.hydrate() if you want React to attach to the server HTML.'); } } - var newRoot = DOMRenderer.createContainer(container); + var newRoot = DOMRenderer.createContainer(container, shouldHydrate); root = container._reactRootContainer = newRoot; // Initial mount should not be batched. DOMRenderer.unbatchedUpdates(function () { @@ -18322,12 +15910,52 @@ function createPortal(children, container) { !isValidContainer(container) ? invariant_1(false, 'Target container is not a DOM element.') : void 0; // TODO: pass ReactDOM portal implementation as third argument - return ReactPortal.createPortal(children, container, null, key); + return createPortal$1(children, container, null, key); } -var ReactDOMFiber = { +function ReactRoot(container, hydrate) { + var root = DOMRenderer.createContainer(container, hydrate); + this._reactRootContainer = root; +} +ReactRoot.prototype.render = function (children, callback) { + var root = this._reactRootContainer; + DOMRenderer.updateContainer(children, root, null, callback); +}; +ReactRoot.prototype.unmount = function (callback) { + var root = this._reactRootContainer; + DOMRenderer.updateContainer(null, root, null, callback); +}; + +var ReactDOM = { createPortal: createPortal, + findDOMNode: function (componentOrElement) { + { + var owner = ReactCurrentOwner.current; + if (owner !== null) { + var warnedAboutRefsInRender = owner.stateNode._warnedAboutRefsInRender; + warning_1(warnedAboutRefsInRender, '%s is accessing findDOMNode inside its render(). ' + 'render() should be a pure function of props and state. It should ' + 'never access something that requires stale data from the previous ' + 'render, such as refs. Move this logic to componentDidMount and ' + 'componentDidUpdate instead.', getComponentName(owner) || 'A component'); + owner.stateNode._warnedAboutRefsInRender = true; + } + } + if (componentOrElement == null) { + return null; + } + if (componentOrElement.nodeType === ELEMENT_NODE) { + return componentOrElement; + } + + var inst = get(componentOrElement); + if (inst) { + return DOMRenderer.findHostInstance(inst); + } + + if (typeof componentOrElement.render === 'function') { + invariant_1(false, 'Unable to find node on an unmounted component.'); + } else { + invariant_1(false, 'Element appears to be neither ReactComponent nor DOMNode. Keys: %s', Object.keys(componentOrElement)); + } + }, hydrate: function (element, container, callback) { // TODO: throw or warn if we couldn't hydrate? return renderSubtreeIntoContainer(null, element, container, true, callback); @@ -18336,7 +15964,7 @@ var ReactDOMFiber = { return renderSubtreeIntoContainer(null, element, container, false, callback); }, unstable_renderSubtreeIntoContainer: function (parentComponent, element, containerNode, callback) { - !(parentComponent != null && ReactInstanceMap_1.has(parentComponent)) ? invariant_1(false, 'parentComponent must be a valid React Component') : void 0; + !(parentComponent != null && has(parentComponent)) ? invariant_1(false, 'parentComponent must be a valid React Component') : void 0; return renderSubtreeIntoContainer(parentComponent, element, containerNode, false, callback); }, unmountComponentAtNode: function (container) { @@ -18345,8 +15973,8 @@ var ReactDOMFiber = { if (container._reactRootContainer) { { var rootEl = getReactRootElementInContainer(container); - var renderedByDifferentReact = rootEl && !ReactDOMComponentTree_1.getInstanceFromNode(rootEl); - warning(!renderedByDifferentReact, "unmountComponentAtNode(): The node you're attempting to unmount " + 'was rendered by another copy of React.'); + var renderedByDifferentReact = rootEl && !getInstanceFromNode$1(rootEl); + warning_1(!renderedByDifferentReact, "unmountComponentAtNode(): The node you're attempting to unmount " + 'was rendered by another copy of React.'); } // Unmount should not be batched. @@ -18361,12 +15989,12 @@ var ReactDOMFiber = { } else { { var _rootEl = getReactRootElementInContainer(container); - var hasNonRootReactChild = !!(_rootEl && ReactDOMComponentTree_1.getInstanceFromNode(_rootEl)); + var hasNonRootReactChild = !!(_rootEl && getInstanceFromNode$1(_rootEl)); // Check if the container itself is a React root node. var isContainerReactRoot = container.nodeType === 1 && isValidContainer(container.parentNode) && !!container.parentNode._reactRootContainer; - warning(!hasNonRootReactChild, "unmountComponentAtNode(): The node you're attempting to unmount " + 'was rendered by React and is not a top-level container. %s', isContainerReactRoot ? 'You may have accidentally passed in a React root node instead ' + 'of its container.' : 'Instead, have the parent component update its state and ' + 'rerender in order to remove this component.'); + warning_1(!hasNonRootReactChild, "unmountComponentAtNode(): The node you're attempting to unmount " + 'was rendered by React and is not a top-level container. %s', isContainerReactRoot ? 'You may have accidentally passed in a React root node instead ' + 'of its container.' : 'Instead, have the parent component update its state and ' + 'rerender in order to remove this component.'); } return false; @@ -18374,13 +16002,11 @@ var ReactDOMFiber = { }, - findDOMNode: findDOMNode_1, - // Temporary alias since we already shipped React 16 RC with it. // TODO: remove in React 17. unstable_createPortal: createPortal, - unstable_batchedUpdates: ReactGenericBatching_1.batchedUpdates, + unstable_batchedUpdates: batchedUpdates, unstable_deferredUpdates: DOMRenderer.deferredUpdates, @@ -18388,20 +16014,25 @@ var ReactDOMFiber = { __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: { // For TapEventPlugin which is popular in open source - EventPluginHub: EventPluginHub_1, + EventPluginHub: EventPluginHub, // Used by test-utils - EventPluginRegistry: EventPluginRegistry_1, - EventPropagators: EventPropagators_1, - ReactControlledComponent: ReactControlledComponent_1, - ReactDOMComponentTree: ReactDOMComponentTree_1, - ReactDOMEventListener: ReactDOMEventListener_1 + EventPluginRegistry: EventPluginRegistry, + EventPropagators: EventPropagators, + ReactControlledComponent: ReactControlledComponent, + ReactDOMComponentTree: ReactDOMComponentTree, + ReactDOMEventListener: ReactDOMEventListener } }; -var foundDevTools = injectInternals({ - findFiberByHostInstance: ReactDOMComponentTree_1.getClosestInstanceFromNode, - findHostInstanceByFiber: DOMRenderer.findHostInstance, - // This is an enum because we may add more (e.g. profiler build) +if (enableCreateRoot) { + ReactDOM.createRoot = function createRoot(container, options) { + var hydrate = options != null && options.hydrate === true; + return new ReactRoot(container, hydrate); + }; +} + +var foundDevTools = DOMRenderer.injectIntoDevTools({ + findFiberByHostInstance: getClosestInstanceFromNode, bundleType: 1, version: ReactVersion, rendererPackageName: 'react-dom' @@ -18420,8 +16051,18 @@ var foundDevTools = injectInternals({ } } -var ReactDOMFiberEntry = ReactDOMFiber; -return ReactDOMFiberEntry; + +var ReactDOM$2 = Object.freeze({ + default: ReactDOM +}); + +var ReactDOM$3 = ( ReactDOM$2 && ReactDOM ) || ReactDOM$2; + +// TODO: decide on the top-level export form. +// This is hacky but makes it work with both Rollup and Jest. +var reactDom = ReactDOM$3['default'] ? ReactDOM$3['default'] : ReactDOM$3; + +return reactDom; }))); |