/** * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * * @noflow * @nolint * @preventMunge * @preserve-invariant-messages */ 'use strict'; if (__DEV__) { (function() { "use strict"; var Scheduler = require("scheduler"); var React = require("react"); var assign = Object.assign; var debugRenderPhaseSideEffectsForStrictMode = false; var enableSchedulingProfiler = false; var enableProfilerTimer = false; var disableCommentsAsDOMContainers = true; var enableSuspenseCallback = true; var enableClientRenderFallbackOnTextMismatch = true; var createRootStrictEffectsByDefault = false; var enableLazyContextPropagation = false; var enableLegacyHidden = false; var enableCustomElementPropertySupport = false; // This refers to a WWW module. var warningWWW = require("warning"); function warn(format) { { { for ( var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++ ) { args[_key - 1] = arguments[_key]; } printWarning("warn", format, args); } } } function error(format) { { { for ( var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++ ) { args[_key2 - 1] = arguments[_key2]; } printWarning("error", format, args); } } } function printWarning(level, format, args) { { var React = require("react"); var ReactSharedInternals = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; // Defensive in case this is fired before React is initialized. if (ReactSharedInternals != null) { var ReactDebugCurrentFrame = ReactSharedInternals.ReactDebugCurrentFrame; var stack = ReactDebugCurrentFrame.getStackAddendum(); if (stack !== "") { format += "%s"; args.push(stack); } } // TODO: don't ignore level and pass it down somewhere too. args.unshift(format); args.unshift(false); warningWWW.apply(null, args); } } /** * `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. * * Note that this module is currently shared and assumed to be stateless. * If this becomes an actual Map, that will break. */ function get(key) { return key._reactInternals; } function has(key) { return key._reactInternals !== undefined; } function set(key, value) { key._reactInternals = value; } var ReactSharedInternals = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; var FunctionComponent = 0; var ClassComponent = 1; var IndeterminateComponent = 2; // Before we know whether it is function or class 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 Fragment = 7; var Mode = 8; var ContextConsumer = 9; var ContextProvider = 10; var ForwardRef = 11; var Profiler = 12; var SuspenseComponent = 13; var MemoComponent = 14; var SimpleMemoComponent = 15; var LazyComponent = 16; var IncompleteClassComponent = 17; var DehydratedFragment = 18; var SuspenseListComponent = 19; var ScopeComponent = 21; var OffscreenComponent = 22; var LegacyHiddenComponent = 23; var CacheComponent = 24; var TracingMarkerComponent = 25; var HostResource = 26; var HostSingleton = 27; // ATTENTION // When adding new symbols to this file, // Please consider also adding to 'react-devtools-shared/src/backend/ReactSymbols' // The Symbol used to tag the ReactElement-like types. var REACT_ELEMENT_TYPE = Symbol.for("react.element"); var REACT_PORTAL_TYPE = Symbol.for("react.portal"); var REACT_FRAGMENT_TYPE = Symbol.for("react.fragment"); var REACT_STRICT_MODE_TYPE = Symbol.for("react.strict_mode"); var REACT_PROFILER_TYPE = Symbol.for("react.profiler"); var REACT_PROVIDER_TYPE = Symbol.for("react.provider"); var REACT_CONTEXT_TYPE = Symbol.for("react.context"); var REACT_SERVER_CONTEXT_TYPE = Symbol.for("react.server_context"); var REACT_FORWARD_REF_TYPE = Symbol.for("react.forward_ref"); var REACT_SUSPENSE_TYPE = Symbol.for("react.suspense"); var REACT_SUSPENSE_LIST_TYPE = Symbol.for("react.suspense_list"); var REACT_MEMO_TYPE = Symbol.for("react.memo"); var REACT_LAZY_TYPE = Symbol.for("react.lazy"); var REACT_SCOPE_TYPE = Symbol.for("react.scope"); var REACT_DEBUG_TRACING_MODE_TYPE = Symbol.for("react.debug_trace_mode"); var REACT_OFFSCREEN_TYPE = Symbol.for("react.offscreen"); var REACT_LEGACY_HIDDEN_TYPE = Symbol.for("react.legacy_hidden"); var REACT_CACHE_TYPE = Symbol.for("react.cache"); var REACT_TRACING_MARKER_TYPE = Symbol.for("react.tracing_marker"); var REACT_SERVER_CONTEXT_DEFAULT_VALUE_NOT_LOADED = Symbol.for( "react.default_value" ); var MAYBE_ITERATOR_SYMBOL = Symbol.iterator; var FAUX_ITERATOR_SYMBOL = "@@iterator"; function getIteratorFn(maybeIterable) { if (maybeIterable === null || typeof maybeIterable !== "object") { return null; } var maybeIterator = (MAYBE_ITERATOR_SYMBOL && maybeIterable[MAYBE_ITERATOR_SYMBOL]) || maybeIterable[FAUX_ITERATOR_SYMBOL]; if (typeof maybeIterator === "function") { return maybeIterator; } return null; } function getWrappedName(outerType, innerType, wrapperName) { var displayName = outerType.displayName; if (displayName) { return displayName; } var functionName = innerType.displayName || innerType.name || ""; return functionName !== "" ? wrapperName + "(" + functionName + ")" : wrapperName; } // Keep in sync with react-reconciler/getComponentNameFromFiber function getContextName(type) { return type.displayName || "Context"; } // Note that the reconciler package should generally prefer to use getComponentNameFromFiber() instead. function getComponentNameFromType(type) { if (type == null) { // Host root, text node or just invalid type. return null; } { if (typeof type.tag === "number") { error( "Received an unexpected object in getComponentNameFromType(). " + "This is likely a bug in React. Please file an issue." ); } } if (typeof type === "function") { return type.displayName || type.name || null; } if (typeof type === "string") { return type; } switch (type) { case REACT_FRAGMENT_TYPE: return "Fragment"; case REACT_PORTAL_TYPE: return "Portal"; case REACT_PROFILER_TYPE: return "Profiler"; case REACT_STRICT_MODE_TYPE: return "StrictMode"; case REACT_SUSPENSE_TYPE: return "Suspense"; case REACT_SUSPENSE_LIST_TYPE: return "SuspenseList"; case REACT_CACHE_TYPE: { return "Cache"; } } if (typeof type === "object") { switch (type.$$typeof) { case REACT_CONTEXT_TYPE: var context = type; return getContextName(context) + ".Consumer"; case REACT_PROVIDER_TYPE: var provider = type; return getContextName(provider._context) + ".Provider"; case REACT_FORWARD_REF_TYPE: return getWrappedName(type, type.render, "ForwardRef"); case REACT_MEMO_TYPE: var outerName = type.displayName || null; if (outerName !== null) { return outerName; } return getComponentNameFromType(type.type) || "Memo"; case REACT_LAZY_TYPE: { var lazyComponent = type; var payload = lazyComponent._payload; var init = lazyComponent._init; try { return getComponentNameFromType(init(payload)); } catch (x) { return null; } } case REACT_SERVER_CONTEXT_TYPE: { var context2 = type; return (context2.displayName || context2._globalName) + ".Provider"; } // eslint-disable-next-line no-fallthrough } } return null; } function getWrappedName$1(outerType, innerType, wrapperName) { var functionName = innerType.displayName || innerType.name || ""; return ( outerType.displayName || (functionName !== "" ? wrapperName + "(" + functionName + ")" : wrapperName) ); } // Keep in sync with shared/getComponentNameFromType function getContextName$1(type) { return type.displayName || "Context"; } function getComponentNameFromFiber(fiber) { var tag = fiber.tag, type = fiber.type; switch (tag) { case CacheComponent: return "Cache"; case ContextConsumer: var context = type; return getContextName$1(context) + ".Consumer"; case ContextProvider: var provider = type; return getContextName$1(provider._context) + ".Provider"; case DehydratedFragment: return "DehydratedFragment"; case ForwardRef: return getWrappedName$1(type, type.render, "ForwardRef"); case Fragment: return "Fragment"; case HostResource: case HostSingleton: case HostComponent: // Host component type is the display name (e.g. "div", "View") return type; case HostPortal: return "Portal"; case HostRoot: return "Root"; case HostText: return "Text"; case LazyComponent: // Name comes from the type in this case; we don't have a tag. return getComponentNameFromType(type); case Mode: if (type === REACT_STRICT_MODE_TYPE) { // Don't be less specific than shared/getComponentNameFromType return "StrictMode"; } return "Mode"; case OffscreenComponent: return "Offscreen"; case Profiler: return "Profiler"; case ScopeComponent: return "Scope"; case SuspenseComponent: return "Suspense"; case SuspenseListComponent: return "SuspenseList"; case TracingMarkerComponent: return "TracingMarker"; // The display name for this tags come from the user-provided type: case ClassComponent: case FunctionComponent: case IncompleteClassComponent: case IndeterminateComponent: case MemoComponent: case SimpleMemoComponent: if (typeof type === "function") { return type.displayName || type.name || null; } if (typeof type === "string") { return type; } break; } return null; } var NoFlags = /* */ 0; var PerformedWork = /* */ 1; var Placement = /* */ 2; var DidCapture = /* */ 128; var Hydrating = /* */ 4096; // You can change the rest (and add more). var Update = /* */ 4; /* Skipped value: 0b000000000000000000000001000; */ var ChildDeletion = /* */ 16; var ContentReset = /* */ 32; var Callback = /* */ 64; /* Used by DidCapture: 0b000000000000000000010000000; */ var ForceClientRender = /* */ 256; var Ref = /* */ 512; var Snapshot = /* */ 1024; var Passive = /* */ 2048; /* Used by Hydrating: 0b000000000000001000000000000; */ var Visibility = /* */ 8192; var StoreConsistency = /* */ 16384; var LifecycleEffectMask = Passive | Update | Callback | Ref | Snapshot | StoreConsistency; // Union of all commit flags (flags with the lifetime of a particular commit) var HostEffectMask = /* */ 16383; // These are not really side effects, but we still reuse this field. var Incomplete = /* */ 32768; var ShouldCapture = /* */ 65536; var ForceUpdateForLegacySuspense = /* */ 131072; var Forked = /* */ 1048576; // Static tags describe aspects of a fiber that are not specific to a render, // e.g. a fiber uses a passive effect (even if there are no updates on this particular render). // This enables us to defer more work in the unmount case, // since we can defer traversing the tree during layout to look for Passive effects, // and instead rely on the static flag as a signal that there may be cleanup work. var RefStatic = /* */ 2097152; var LayoutStatic = /* */ 4194304; var PassiveStatic = /* */ 8388608; // Flag used to identify newly inserted fibers. It isn't reset after commit unlike `Placement`. var PlacementDEV = /* */ 16777216; var MountLayoutDev = /* */ 33554432; var MountPassiveDev = /* */ 67108864; // Groups of flags that are used in the commit phase to skip over trees that // don't contain effects, by checking subtreeFlags. var BeforeMutationMask = // TODO: Remove Update flag from before mutation phase by re-landing Visibility // flag logic (see #20043) Update | Snapshot | // createEventHandle needs to visit deleted and hidden trees to // fire beforeblur // TODO: Only need to visit Deletions during BeforeMutation phase if an // element is focused. (ChildDeletion | Visibility); var MutationMask = Placement | Update | ChildDeletion | ContentReset | Ref | Hydrating | Visibility; var LayoutMask = Update | Callback | Ref | Visibility; // TODO: Split into PassiveMountMask and PassiveUnmountMask var PassiveMask = Passive | Visibility | ChildDeletion; // Union of tags that don't get reset on clones. // This allows certain concepts to persist without recalculating them, // e.g. whether a subtree contains passive effects or portals. var StaticMask = LayoutStatic | PassiveStatic | RefStatic; var ReactCurrentOwner = ReactSharedInternals.ReactCurrentOwner; function getNearestMountedFiber(fiber) { var node = fiber; var nearestMounted = fiber; if (!fiber.alternate) { // If there is no alternate, this might be a new tree that isn't inserted // yet. If it is, then it will have a pending insertion effect on it. var nextNode = node; do { node = nextNode; if ((node.flags & (Placement | Hydrating)) !== NoFlags) { // This is an insertion or in-progress hydration. The nearest possible // mounted fiber is the parent but we need to continue to figure out // if that one is still mounted. nearestMounted = node.return; } // $FlowFixMe[incompatible-type] we bail out when we get a null nextNode = node.return; } while (nextNode); } else { while (node.return) { node = node.return; } } if (node.tag === HostRoot) { // TODO: Check if this was a nested HostRoot when used with // renderContainerIntoSubtree. return nearestMounted; } // If we didn't hit the root, that means that we're in an disconnected tree // that has been unmounted. return null; } function getSuspenseInstanceFromFiber(fiber) { if (fiber.tag === SuspenseComponent) { var suspenseState = fiber.memoizedState; if (suspenseState === null) { var current = fiber.alternate; if (current !== null) { suspenseState = current.memoizedState; } } if (suspenseState !== null) { return suspenseState.dehydrated; } } return null; } function getContainerFromFiber(fiber) { return fiber.tag === HostRoot ? fiber.stateNode.containerInfo : null; } function isFiberMounted(fiber) { return getNearestMountedFiber(fiber) === fiber; } function isMounted(component) { { var owner = ReactCurrentOwner.current; if (owner !== null && owner.tag === ClassComponent) { var ownerFiber = owner; var instance = ownerFiber.stateNode; if (!instance._warnedAboutRefsInRender) { error( "%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.", getComponentNameFromFiber(ownerFiber) || "A component" ); } instance._warnedAboutRefsInRender = true; } } var fiber = get(component); if (!fiber) { return false; } return getNearestMountedFiber(fiber) === fiber; } function assertIsMounted(fiber) { if (getNearestMountedFiber(fiber) !== fiber) { throw new Error("Unable to find node on an unmounted component."); } } function findCurrentFiberUsingSlowPath(fiber) { var alternate = fiber.alternate; if (!alternate) { // If there is no alternate, then we only need to check if it is mounted. var nearestMounted = getNearestMountedFiber(fiber); if (nearestMounted === null) { throw new Error("Unable to find node on an unmounted component."); } if (nearestMounted !== fiber) { return null; } return fiber; } // If we have two possible branches, we'll walk backwards up to the root // to see what path the root points to. On the way we may hit one of the // special cases and we'll deal with them. var a = fiber; var b = alternate; while (true) { var parentA = a.return; if (parentA === null) { // We're at the root. break; } var parentB = parentA.alternate; if (parentB === null) { // There is no alternate. This is an unusual case. Currently, it only // happens when a Suspense component is hidden. An extra fragment fiber // is inserted in between the Suspense fiber and its children. Skip // over this extra fragment fiber and proceed to the next parent. var nextParent = parentA.return; if (nextParent !== null) { a = b = nextParent; continue; } // If there's no parent, we're at the root. break; } // If both copies of the parent fiber point to the same child, we can // assume that the child is current. This happens when we bailout on low // priority: the bailed out fiber's child reuses the current child. if (parentA.child === parentB.child) { var child = parentA.child; while (child) { if (child === a) { // We've determined that A is the current branch. assertIsMounted(parentA); return fiber; } if (child === b) { // We've determined that B is the current branch. assertIsMounted(parentA); return alternate; } child = child.sibling; } // We should never have an alternate for any mounting node. So the only // way this could possibly happen is if this was unmounted, if at all. throw new Error("Unable to find node on an unmounted component."); } if (a.return !== b.return) { // The return pointer of A and the return pointer of B point to different // fibers. We assume that return pointers never criss-cross, so A must // belong to the child set of A.return, and B must belong to the child // set of B.return. a = parentA; b = parentB; } else { // The return pointers point to the same fiber. We'll have to use the // default, slow path: scan the child sets of each parent alternate to see // which child belongs to which set. // // Search parent A's child set var didFindChild = false; var _child = parentA.child; while (_child) { if (_child === a) { didFindChild = true; a = parentA; b = parentB; break; } if (_child === b) { didFindChild = true; b = parentA; a = parentB; break; } _child = _child.sibling; } if (!didFindChild) { // Search parent B's child set _child = parentB.child; while (_child) { if (_child === a) { didFindChild = true; a = parentB; b = parentA; break; } if (_child === b) { didFindChild = true; b = parentB; a = parentA; break; } _child = _child.sibling; } if (!didFindChild) { throw new Error( "Child was not found in either parent set. This indicates a bug " + "in React related to the return pointer. Please file an issue." ); } } } if (a.alternate !== b) { throw new Error( "Return fibers should always be each others' alternates. " + "This error is likely caused by a bug in React. Please file an issue." ); } } // If the root is not a host container, we're in a disconnected tree. I.e. // unmounted. if (a.tag !== HostRoot) { throw new Error("Unable to find node on an unmounted component."); } if (a.stateNode.current === a) { // We've determined that A is the current branch. return fiber; } // Otherwise B has to be current branch. return alternate; } function findCurrentHostFiber(parent) { var currentParent = findCurrentFiberUsingSlowPath(parent); return currentParent !== null ? findCurrentHostFiberImpl(currentParent) : null; } function findCurrentHostFiberImpl(node) { // Next we'll drill down this component to find the first HostComponent/Text. var tag = node.tag; if ( tag === HostComponent || tag === HostResource || tag === HostSingleton || tag === HostText ) { return node; } var child = node.child; while (child !== null) { var match = findCurrentHostFiberImpl(child); if (match !== null) { return match; } child = child.sibling; } return null; } function findCurrentHostFiberWithNoPortals(parent) { var currentParent = findCurrentFiberUsingSlowPath(parent); return currentParent !== null ? findCurrentHostFiberWithNoPortalsImpl(currentParent) : null; } function findCurrentHostFiberWithNoPortalsImpl(node) { // Next we'll drill down this component to find the first HostComponent/Text. var tag = node.tag; if ( tag === HostComponent || tag === HostResource || tag === HostSingleton || tag === HostText ) { return node; } var child = node.child; while (child !== null) { if (child.tag !== HostPortal) { var match = findCurrentHostFiberWithNoPortalsImpl(child); if (match !== null) { return match; } } child = child.sibling; } return null; } function isFiberSuspenseAndTimedOut(fiber) { var memoizedState = fiber.memoizedState; return ( fiber.tag === SuspenseComponent && memoizedState !== null && memoizedState.dehydrated === null ); } function doesFiberContain(parentFiber, childFiber) { var node = childFiber; var parentFiberAlternate = parentFiber.alternate; while (node !== null) { if (node === parentFiber || node === parentFiberAlternate) { return true; } node = node.return; } return false; } // This exists to avoid circular dependency between ReactDOMEventReplaying // and DOMPluginEventSystem. var currentReplayingEvent = null; function setReplayingEvent(event) { { if (currentReplayingEvent !== null) { error( "Expected currently replaying event to be null. This error " + "is likely caused by a bug in React. Please file an issue." ); } } currentReplayingEvent = event; } function resetReplayingEvent() { { if (currentReplayingEvent === null) { error( "Expected currently replaying event to not be null. This error " + "is likely caused by a bug in React. Please file an issue." ); } } currentReplayingEvent = null; } function isReplayingEvent(event) { return event === currentReplayingEvent; } var allNativeEvents = new Set(); { allNativeEvents.add("beforeblur"); allNativeEvents.add("afterblur"); } /** * Mapping from registration name to event name */ var registrationNameDependencies = {}; /** * 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 function registerTwoPhaseEvent(registrationName, dependencies) { registerDirectEvent(registrationName, dependencies); registerDirectEvent(registrationName + "Capture", dependencies); } function registerDirectEvent(registrationName, dependencies) { { if (registrationNameDependencies[registrationName]) { error( "EventRegistry: More than one plugin attempted to publish the same " + "registration name, `%s`.", registrationName ); } } registrationNameDependencies[registrationName] = dependencies; { var lowerCasedName = registrationName.toLowerCase(); possibleRegistrationNames[lowerCasedName] = registrationName; if (registrationName === "onDoubleClick") { possibleRegistrationNames.ondblclick = registrationName; } } for (var i = 0; i < dependencies.length; i++) { allNativeEvents.add(dependencies[i]); } } var IS_EVENT_HANDLE_NON_MANAGED_NODE = 1; var IS_NON_DELEGATED = 1 << 1; var IS_CAPTURE_PHASE = 1 << 2; var IS_LEGACY_FB_SUPPORT_MODE = 1 << 4; var SHOULD_NOT_DEFER_CLICK_FOR_FB_SUPPORT_MODE = IS_LEGACY_FB_SUPPORT_MODE | IS_CAPTURE_PHASE; // We do not want to defer if the event system has already been // set to LEGACY_FB_SUPPORT. LEGACY_FB_SUPPORT only gets set when // we call willDeferLaterForLegacyFBSupport, thus not bailing out // will result in endless cycles like an infinite loop. // We also don't want to defer during event replaying. var SHOULD_NOT_PROCESS_POLYFILL_EVENT_PLUGINS = IS_EVENT_HANDLE_NON_MANAGED_NODE | IS_NON_DELEGATED | IS_CAPTURE_PHASE; /** * 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_TYPE_NODE = 10; 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) { // Fallback to nativeEvent.srcElement for IE9 // https://github.com/facebook/react/issues/12506 var target = nativeEvent.target || nativeEvent.srcElement || window; // Normalize SVG 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; } // Below code forked from dom-accessibility-api var tagToRoleMappings = { ARTICLE: "article", ASIDE: "complementary", BODY: "document", BUTTON: "button", DATALIST: "listbox", DD: "definition", DETAILS: "group", DIALOG: "dialog", DT: "term", FIELDSET: "group", FIGURE: "figure", // WARNING: Only with an accessible name FORM: "form", FOOTER: "contentinfo", H1: "heading", H2: "heading", H3: "heading", H4: "heading", H5: "heading", H6: "heading", HEADER: "banner", HR: "separator", LEGEND: "legend", LI: "listitem", MATH: "math", MAIN: "main", MENU: "list", NAV: "navigation", OL: "list", OPTGROUP: "group", // WARNING: Only in certain context OPTION: "option", OUTPUT: "status", PROGRESS: "progressbar", // WARNING: Only with an accessible name SECTION: "region", SUMMARY: "button", TABLE: "table", TBODY: "rowgroup", TEXTAREA: "textbox", TFOOT: "rowgroup", // WARNING: Only in certain context TD: "cell", TH: "columnheader", THEAD: "rowgroup", TR: "row", UL: "list" }; function getImplicitRole(element) { var mappedByTag = tagToRoleMappings[element.tagName]; if (mappedByTag !== undefined) { return mappedByTag; } switch (element.tagName) { case "A": case "AREA": case "LINK": if (element.hasAttribute("href")) { return "link"; } break; case "IMG": if ((element.getAttribute("alt") || "").length > 0) { return "img"; } break; case "INPUT": { var type = element.type; switch (type) { case "button": case "image": case "reset": case "submit": return "button"; case "checkbox": case "radio": return type; case "range": return "slider"; case "email": case "tel": case "text": case "url": if (element.hasAttribute("list")) { return "combobox"; } return "textbox"; case "search": if (element.hasAttribute("list")) { return "combobox"; } return "searchbox"; default: return null; } } case "SELECT": if (element.hasAttribute("multiple") || element.size > 1) { return "listbox"; } return "combobox"; } return null; } function getExplicitRoles(element) { var role = element.getAttribute("role"); if (role) { return role.trim().split(" "); } return null; } // https://w3c.github.io/html-aria/#document-conformance-requirements-for-use-of-aria-attributes-in-html function hasRole(element, role) { var explicitRoles = getExplicitRoles(element); if (explicitRoles !== null && explicitRoles.indexOf(role) >= 0) { return true; } return role === getImplicitRole(element); } var canUseDOM = !!( typeof window !== "undefined" && typeof window.document !== "undefined" && typeof window.document.createElement !== "undefined" ); // $FlowFixMe[method-unbinding] var hasOwnProperty = Object.prototype.hasOwnProperty; /* * The `'' + value` pattern (used in perf-sensitive code) throws for Symbol * and Temporal.* types. See https://github.com/facebook/react/pull/22064. * * The functions in this module will throw an easier-to-understand, * easier-to-debug exception with a clear errors message message explaining the * problem. (Instead of a confusing exception thrown inside the implementation * of the `value` object). */ // $FlowFixMe only called in DEV, so void return is not possible. function typeName(value) { { // toStringTag is needed for namespaced types like Temporal.Instant var hasToStringTag = typeof Symbol === "function" && Symbol.toStringTag; var type = (hasToStringTag && value[Symbol.toStringTag]) || value.constructor.name || "Object"; // $FlowFixMe return type; } } // $FlowFixMe only called in DEV, so void return is not possible. function willCoercionThrow(value) { { try { testStringCoercion(value); return false; } catch (e) { return true; } } } function testStringCoercion(value) { // If you ended up here by following an exception call stack, here's what's // happened: you supplied an object or symbol value to React (as a prop, key, // DOM attribute, CSS property, string ref, etc.) and when React tried to // coerce it to a string using `'' + value`, an exception was thrown. // // The most common types that will cause this exception are `Symbol` instances // and Temporal objects like `Temporal.Instant`. But any object that has a // `valueOf` or `[Symbol.toPrimitive]` method that throws will also cause this // exception. (Library authors do this to prevent users from using built-in // numeric operators like `+` or comparison operators like `>=` because custom // methods are needed to perform accurate arithmetic or comparison.) // // To fix the problem, coerce this object or symbol value to a string before // passing it to React. The most reliable way is usually `String(value)`. // // To find which value is throwing, check the browser or debugger console. // Before this exception was thrown, there should be `console.error` output // that shows the type (Symbol, Temporal.PlainDate, etc.) that caused the // problem and how that type was used: key, atrribute, input value prop, etc. // In most cases, this console output also shows the component and its // ancestor components where the exception happened. // // eslint-disable-next-line react-internal/safe-string-coercion return "" + value; } function checkAttributeStringCoercion(value, attributeName) { { if (willCoercionThrow(value)) { error( "The provided `%s` attribute is an unsupported type %s." + " This value must be coerced to a string before before using it here.", attributeName, typeName(value) ); return testStringCoercion(value); // throw (to help callers find troubleshooting comments) } } } function checkKeyStringCoercion(value) { { if (willCoercionThrow(value)) { error( "The provided key is an unsupported type %s." + " This value must be coerced to a string before before using it here.", typeName(value) ); return testStringCoercion(value); // throw (to help callers find troubleshooting comments) } } } function checkPropStringCoercion(value, propName) { { if (willCoercionThrow(value)) { error( "The provided `%s` prop is an unsupported type %s." + " This value must be coerced to a string before before using it here.", propName, typeName(value) ); return testStringCoercion(value); // throw (to help callers find troubleshooting comments) } } } function checkCSSPropertyStringCoercion(value, propName) { { if (willCoercionThrow(value)) { error( "The provided `%s` CSS property is an unsupported type %s." + " This value must be coerced to a string before before using it here.", propName, typeName(value) ); return testStringCoercion(value); // throw (to help callers find troubleshooting comments) } } } function checkHtmlStringCoercion(value) { { if (willCoercionThrow(value)) { error( "The provided HTML markup uses a value of unsupported type %s." + " This value must be coerced to a string before before using it here.", typeName(value) ); return testStringCoercion(value); // throw (to help callers find troubleshooting comments) } } } function checkFormFieldValueStringCoercion(value) { { if (willCoercionThrow(value)) { error( "Form field values (value, checked, defaultValue, or defaultChecked props)" + " must be strings, not %s." + " This value must be coerced to a string before before using it here.", typeName(value) ); return testStringCoercion(value); // throw (to help callers find troubleshooting comments) } } } // It is handled by React separately and shouldn't be written to the DOM. var RESERVED = 0; // A simple string attribute. // Attributes that aren't in the filter are presumed to have this type. var STRING = 1; // A string attribute that accepts booleans in React. In HTML, these are called // "enumerated" attributes with "true" and "false" as possible values. // When true, it should be set to a "true" string. // When false, it should be set to a "false" string. var BOOLEANISH_STRING = 2; // A real boolean attribute. // When true, it should be present (set either to an empty string or its name). // When false, it should be omitted. var BOOLEAN = 3; // An attribute that can be used as a flag as well as with a value. // When true, it should be present (set either to an empty string or its name). // When false, it should be omitted. // For any other value, should be present with that value. var OVERLOADED_BOOLEAN = 4; // An attribute that must be numeric or parse as a numeric. // When falsy, it should be removed. var NUMERIC = 5; // An attribute that must be positive numeric or parse as a positive numeric. // When falsy, it should be removed. var POSITIVE_NUMERIC = 6; /* 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 VALID_ATTRIBUTE_NAME_REGEX = new RegExp( "^[" + ATTRIBUTE_NAME_START_CHAR + "][" + ATTRIBUTE_NAME_CHAR + "]*$" ); var illegalAttributeNameCache = {}; var validatedAttributeNameCache = {}; function isAttributeNameSafe(attributeName) { if (hasOwnProperty.call(validatedAttributeNameCache, attributeName)) { return true; } if (hasOwnProperty.call(illegalAttributeNameCache, attributeName)) { return false; } if (VALID_ATTRIBUTE_NAME_REGEX.test(attributeName)) { validatedAttributeNameCache[attributeName] = true; return true; } illegalAttributeNameCache[attributeName] = true; { error("Invalid attribute name: `%s`", attributeName); } return false; } function shouldIgnoreAttribute(name, propertyInfo, isCustomComponentTag) { if (propertyInfo !== null) { return propertyInfo.type === RESERVED; } if (isCustomComponentTag) { return false; } if ( name.length > 2 && (name[0] === "o" || name[0] === "O") && (name[1] === "n" || name[1] === "N") ) { return true; } return false; } function shouldRemoveAttributeWithWarning( name, value, propertyInfo, isCustomComponentTag ) { if (propertyInfo !== null && propertyInfo.type === RESERVED) { return false; } switch (typeof value) { case "function": case "symbol": // eslint-disable-line return true; case "boolean": { if (isCustomComponentTag) { return false; } if (propertyInfo !== null) { return !propertyInfo.acceptsBooleans; } else { var prefix = name.toLowerCase().slice(0, 5); return prefix !== "data-" && prefix !== "aria-"; } } default: return false; } } function shouldRemoveAttribute( name, value, propertyInfo, isCustomComponentTag ) { if (value === null || typeof value === "undefined") { return true; } if ( shouldRemoveAttributeWithWarning( name, value, propertyInfo, isCustomComponentTag ) ) { return true; } if (isCustomComponentTag) { return false; } if (propertyInfo !== null) { switch (propertyInfo.type) { case BOOLEAN: return !value; case OVERLOADED_BOOLEAN: return value === false; case NUMERIC: return isNaN(value); case POSITIVE_NUMERIC: return isNaN(value) || value < 1; } } return false; } function getPropertyInfo(name) { return properties.hasOwnProperty(name) ? properties[name] : null; } // $FlowFixMe[missing-this-annot] function PropertyInfoRecord( name, type, mustUseProperty, attributeName, attributeNamespace, sanitizeURL, removeEmptyString ) { this.acceptsBooleans = type === BOOLEANISH_STRING || type === BOOLEAN || type === OVERLOADED_BOOLEAN; this.attributeName = attributeName; this.attributeNamespace = attributeNamespace; this.mustUseProperty = mustUseProperty; this.propertyName = name; this.type = type; this.sanitizeURL = sanitizeURL; this.removeEmptyString = removeEmptyString; } // When adding attributes to this list, be sure to also add them to // the `possibleStandardNames` module to ensure casing and incorrect // name warnings. var properties = {}; // These props are reserved by React. They shouldn't be written to the DOM. var reservedProps = [ "children", "dangerouslySetInnerHTML", // TODO: This prevents the assignment of defaultValue to regular // elements (not just inputs). Now that ReactDOMInput assigns to the // defaultValue property -- do we need this? "defaultValue", "defaultChecked", "innerHTML", "suppressContentEditableWarning", "suppressHydrationWarning", "style" ]; reservedProps.forEach(function(name) { // $FlowFixMe[invalid-constructor] Flow no longer supports calling new on functions properties[name] = new PropertyInfoRecord( name, RESERVED, false, // mustUseProperty name, // attributeName null, // attributeNamespace false, // sanitizeURL false ); }); // A few React string attributes have a different name. // This is a mapping from React prop names to the attribute names. [ ["acceptCharset", "accept-charset"], ["className", "class"], ["htmlFor", "for"], ["httpEquiv", "http-equiv"] ].forEach(function(_ref) { var name = _ref[0], attributeName = _ref[1]; // $FlowFixMe[invalid-constructor] Flow no longer supports calling new on functions properties[name] = new PropertyInfoRecord( name, STRING, false, // mustUseProperty attributeName, // attributeName null, // attributeNamespace false, // sanitizeURL false ); }); // These are "enumerated" HTML attributes that accept "true" and "false". // In React, we let users pass `true` and `false` even though technically // these aren't boolean attributes (they are coerced to strings). ["contentEditable", "draggable", "spellCheck", "value"].forEach(function(name) { // $FlowFixMe[invalid-constructor] Flow no longer supports calling new on functions properties[name] = new PropertyInfoRecord( name, BOOLEANISH_STRING, false, // mustUseProperty name.toLowerCase(), // attributeName null, // attributeNamespace false, // sanitizeURL false ); }); // These are "enumerated" SVG attributes that accept "true" and "false". // In React, we let users pass `true` and `false` even though technically // these aren't boolean attributes (they are coerced to strings). // Since these are SVG attributes, their attribute names are case-sensitive. [ "autoReverse", "externalResourcesRequired", "focusable", "preserveAlpha" ].forEach(function(name) { // $FlowFixMe[invalid-constructor] Flow no longer supports calling new on functions properties[name] = new PropertyInfoRecord( name, BOOLEANISH_STRING, false, // mustUseProperty name, // attributeName null, // attributeNamespace false, // sanitizeURL false ); }); // These are HTML boolean attributes. [ "allowFullScreen", "async", // 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", "autoPlay", "controls", "default", "defer", "disabled", "disablePictureInPicture", "disableRemotePlayback", "formNoValidate", "hidden", "loop", "noModule", "noValidate", "open", "playsInline", "readOnly", "required", "reversed", "scoped", "seamless", // Microdata "itemScope" ].forEach(function(name) { // $FlowFixMe[invalid-constructor] Flow no longer supports calling new on functions properties[name] = new PropertyInfoRecord( name, BOOLEAN, false, // mustUseProperty name.toLowerCase(), // attributeName null, // attributeNamespace false, // sanitizeURL false ); }); // These are the few React props that we set as DOM properties // rather than attributes. These are all booleans. [ "checked", // Note: `option.selected` is not updated if `select.multiple` is // disabled with `removeAttribute`. We have special logic for handling this. "multiple", "muted", "selected" // NOTE: if you add a camelCased prop to this list, // you'll need to set attributeName to name.toLowerCase() // instead in the assignment below. ].forEach(function(name) { // $FlowFixMe[invalid-constructor] Flow no longer supports calling new on functions properties[name] = new PropertyInfoRecord( name, BOOLEAN, true, // mustUseProperty name, // attributeName null, // attributeNamespace false, // sanitizeURL false ); }); // These are HTML attributes that are "overloaded booleans": they behave like // booleans, but can also accept a string value. [ "capture", "download" // NOTE: if you add a camelCased prop to this list, // you'll need to set attributeName to name.toLowerCase() // instead in the assignment below. ].forEach(function(name) { // $FlowFixMe[invalid-constructor] Flow no longer supports calling new on functions properties[name] = new PropertyInfoRecord( name, OVERLOADED_BOOLEAN, false, // mustUseProperty name, // attributeName null, // attributeNamespace false, // sanitizeURL false ); }); // These are HTML attributes that must be positive numbers. [ "cols", "rows", "size", "span" // NOTE: if you add a camelCased prop to this list, // you'll need to set attributeName to name.toLowerCase() // instead in the assignment below. ].forEach(function(name) { // $FlowFixMe[invalid-constructor] Flow no longer supports calling new on functions properties[name] = new PropertyInfoRecord( name, POSITIVE_NUMERIC, false, // mustUseProperty name, // attributeName null, // attributeNamespace false, // sanitizeURL false ); }); // These are HTML attributes that must be numbers. ["rowSpan", "start"].forEach(function(name) { // $FlowFixMe[invalid-constructor] Flow no longer supports calling new on functions properties[name] = new PropertyInfoRecord( name, NUMERIC, false, // mustUseProperty name.toLowerCase(), // attributeName null, // attributeNamespace false, // sanitizeURL false ); }); var CAMELIZE = /[\-\:]([a-z])/g; var capitalize = function(token) { return token[1].toUpperCase(); }; // This is a list of all SVG attributes that need special casing, namespacing, // or boolean value assignment. Regular attributes that just accept strings // and have the same names are omitted, just like in the HTML attribute filter. // Some of these attributes can be hard to find. This list was created by // scraping the MDN documentation. [ "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", "xmlns:xlink", "x-height" // NOTE: if you add a camelCased prop to this list, // you'll need to set attributeName to name.toLowerCase() // instead in the assignment below. ].forEach(function(attributeName) { var name = attributeName.replace(CAMELIZE, capitalize); // $FlowFixMe[invalid-constructor] Flow no longer supports calling new on functions properties[name] = new PropertyInfoRecord( name, STRING, false, // mustUseProperty attributeName, null, // attributeNamespace false, // sanitizeURL false ); }); // String SVG attributes with the xlink namespace. [ "xlink:actuate", "xlink:arcrole", "xlink:role", "xlink:show", "xlink:title", "xlink:type" // NOTE: if you add a camelCased prop to this list, // you'll need to set attributeName to name.toLowerCase() // instead in the assignment below. ].forEach(function(attributeName) { var name = attributeName.replace(CAMELIZE, capitalize); // $FlowFixMe[invalid-constructor] Flow no longer supports calling new on functions properties[name] = new PropertyInfoRecord( name, STRING, false, // mustUseProperty attributeName, "http://www.w3.org/1999/xlink", false, // sanitizeURL false ); }); // String SVG attributes with the xml namespace. [ "xml:base", "xml:lang", "xml:space" // NOTE: if you add a camelCased prop to this list, // you'll need to set attributeName to name.toLowerCase() // instead in the assignment below. ].forEach(function(attributeName) { var name = attributeName.replace(CAMELIZE, capitalize); // $FlowFixMe[invalid-constructor] Flow no longer supports calling new on functions properties[name] = new PropertyInfoRecord( name, STRING, false, // mustUseProperty attributeName, "http://www.w3.org/XML/1998/namespace", false, // sanitizeURL false ); }); // These attribute exists both in HTML and SVG. // The attribute name is case-sensitive in SVG so we can't just use // the React name like we do for attributes that exist only in HTML. ["tabIndex", "crossOrigin"].forEach(function(attributeName) { // $FlowFixMe[invalid-constructor] Flow no longer supports calling new on functions properties[attributeName] = new PropertyInfoRecord( attributeName, STRING, false, // mustUseProperty attributeName.toLowerCase(), // attributeName null, // attributeNamespace false, // sanitizeURL false ); }); // These attributes accept URLs. These must not allow javascript: URLS. // These will also need to accept Trusted Types object in the future. var xlinkHref = "xlinkHref"; // $FlowFixMe[invalid-constructor] Flow no longer supports calling new on functions properties[xlinkHref] = new PropertyInfoRecord( "xlinkHref", STRING, false, // mustUseProperty "xlink:href", "http://www.w3.org/1999/xlink", true, // sanitizeURL false ); ["src", "href", "action", "formAction"].forEach(function(attributeName) { // $FlowFixMe[invalid-constructor] Flow no longer supports calling new on functions properties[attributeName] = new PropertyInfoRecord( attributeName, STRING, false, // mustUseProperty attributeName.toLowerCase(), // attributeName null, // attributeNamespace true, // sanitizeURL true ); }); // and any newline or tab are filtered out as if they're not part of the URL. // https://url.spec.whatwg.org/#url-parsing // Tab or newline are defined as \r\n\t: // https://infra.spec.whatwg.org/#ascii-tab-or-newline // A C0 control is a code point in the range \u0000 NULL to \u001F // INFORMATION SEPARATOR ONE, inclusive: // https://infra.spec.whatwg.org/#c0-control-or-space /* eslint-disable max-len */ var isJavaScriptProtocol = /^[\u0000-\u001F ]*j[\r\n\t]*a[\r\n\t]*v[\r\n\t]*a[\r\n\t]*s[\r\n\t]*c[\r\n\t]*r[\r\n\t]*i[\r\n\t]*p[\r\n\t]*t[\r\n\t]*\:/i; function sanitizeURL(url) { { if (isJavaScriptProtocol.test(url)) { throw new Error( "React has blocked a javascript: URL as a security precaution." ); } } } /** * 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, propertyInfo) { { if (propertyInfo.mustUseProperty) { var propertyName = propertyInfo.propertyName; return node[propertyName]; } else { // This check protects multiple uses of `expected`, which is why the // react-internal/safe-string-coercion rule is disabled in several spots // below. { checkAttributeStringCoercion(expected, name); } var attributeName = propertyInfo.attributeName; var stringValue = null; if (propertyInfo.type === OVERLOADED_BOOLEAN) { if (node.hasAttribute(attributeName)) { var value = node.getAttribute(attributeName); if (value === "") { return true; } if (shouldRemoveAttribute(name, expected, propertyInfo, false)) { return value; } // eslint-disable-next-line react-internal/safe-string-coercion if (value === "" + expected) { return expected; } return value; } } else if (node.hasAttribute(attributeName)) { if (shouldRemoveAttribute(name, expected, propertyInfo, false)) { // We had an attribute but shouldn't have had one, so read it // for the error message. return node.getAttribute(attributeName); } if (propertyInfo.type === BOOLEAN) { // 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 (shouldRemoveAttribute(name, expected, propertyInfo, false)) { return stringValue === null ? expected : stringValue; // eslint-disable-next-line react-internal/safe-string-coercion } else if (stringValue === "" + expected) { return expected; } else { return stringValue; } } } } /** * Get the value for a attribute on a node. Only used in DEV for SSR validation. * The third argument is used as a hint of what the expected value is. Some * attributes have multiple equivalent values. */ function getValueForAttribute(node, name, expected, isCustomComponentTag) { { if (!isAttributeNameSafe(name)) { return; } if (!node.hasAttribute(name)) { return expected === undefined ? undefined : null; } var value = node.getAttribute(name); { checkAttributeStringCoercion(expected, name); } if (value === "" + expected) { return expected; } return value; } } /** * Sets the value for a property on a node. * * @param {DOMElement} node * @param {string} name * @param {*} value */ function setValueForProperty(node, name, value, isCustomComponentTag) { var propertyInfo = getPropertyInfo(name); if (shouldIgnoreAttribute(name, propertyInfo, isCustomComponentTag)) { return; } if (shouldRemoveAttribute(name, value, propertyInfo, isCustomComponentTag)) { value = null; } if (isCustomComponentTag || propertyInfo === null) { if (isAttributeNameSafe(name)) { var _attributeName = name; if (value === null) { node.removeAttribute(_attributeName); } else { { checkAttributeStringCoercion(value, name); } node.setAttribute(_attributeName, "" + value); } } return; } var mustUseProperty = propertyInfo.mustUseProperty; if (mustUseProperty) { var propertyName = propertyInfo.propertyName; if (value === null) { var type = propertyInfo.type; node[propertyName] = type === BOOLEAN ? false : ""; } else { // Contrary to `setAttribute`, object properties are properly // `toString`ed by IE8/9. node[propertyName] = value; } return; } // The rest are treated as attributes with special cases. var attributeName = propertyInfo.attributeName, attributeNamespace = propertyInfo.attributeNamespace; if (value === null) { node.removeAttribute(attributeName); } else { var _type = propertyInfo.type; var attributeValue; if (_type === BOOLEAN || (_type === OVERLOADED_BOOLEAN && value === true)) { // If attribute type is boolean, we know for sure it won't be an execution sink // and we won't require Trusted Type here. attributeValue = ""; } else { // `setAttribute` with objects becomes only `[object]` in IE8/9, // ('' + value) makes it output the correct toString()-value. { { checkAttributeStringCoercion(value, attributeName); } attributeValue = "" + value; } if (propertyInfo.sanitizeURL) { sanitizeURL(attributeValue.toString()); } } if (attributeNamespace) { node.setAttributeNS(attributeNamespace, attributeName, attributeValue); } else { node.setAttribute(attributeName, attributeValue); } } } // Helpers to patch console.logs to avoid logging during side-effect free // replaying on render function. This currently only patches the object // lazily which won't cover if the log function was extracted eagerly. // We could also eagerly patch the method. var disabledDepth = 0; var prevLog; var prevInfo; var prevWarn; var prevError; var prevGroup; var prevGroupCollapsed; var prevGroupEnd; function disabledLog() {} disabledLog.__reactDisabledLog = true; function disableLogs() { { if (disabledDepth === 0) { /* eslint-disable react-internal/no-production-logging */ prevLog = console.log; prevInfo = console.info; prevWarn = console.warn; prevError = console.error; prevGroup = console.group; prevGroupCollapsed = console.groupCollapsed; prevGroupEnd = console.groupEnd; // https://github.com/facebook/react/issues/19099 var props = { configurable: true, enumerable: true, value: disabledLog, writable: true }; // $FlowFixMe Flow thinks console is immutable. Object.defineProperties(console, { info: props, log: props, warn: props, error: props, group: props, groupCollapsed: props, groupEnd: props }); /* eslint-enable react-internal/no-production-logging */ } disabledDepth++; } } function reenableLogs() { { disabledDepth--; if (disabledDepth === 0) { /* eslint-disable react-internal/no-production-logging */ var props = { configurable: true, enumerable: true, writable: true }; // $FlowFixMe Flow thinks console is immutable. Object.defineProperties(console, { log: assign({}, props, { value: prevLog }), info: assign({}, props, { value: prevInfo }), warn: assign({}, props, { value: prevWarn }), error: assign({}, props, { value: prevError }), group: assign({}, props, { value: prevGroup }), groupCollapsed: assign({}, props, { value: prevGroupCollapsed }), groupEnd: assign({}, props, { value: prevGroupEnd }) }); /* eslint-enable react-internal/no-production-logging */ } if (disabledDepth < 0) { error( "disabledDepth fell below zero. " + "This is a bug in React. Please file an issue." ); } } } var ReactCurrentDispatcher = ReactSharedInternals.ReactCurrentDispatcher; var prefix; function describeBuiltInComponentFrame(name, source, ownerFn) { { if (prefix === undefined) { // Extract the VM specific prefix used by each line. try { throw Error(); } catch (x) { var match = x.stack.trim().match(/\n( *(at )?)/); prefix = (match && match[1]) || ""; } } // We use the prefix to ensure our stacks line up with native stack frames. return "\n" + prefix + name; } } var reentry = false; var componentFrameCache; { var PossiblyWeakMap = typeof WeakMap === "function" ? WeakMap : Map; componentFrameCache = new PossiblyWeakMap(); } function describeNativeComponentFrame(fn, construct) { // If something asked for a stack inside a fake render, it should get ignored. if (!fn || reentry) { return ""; } { var frame = componentFrameCache.get(fn); if (frame !== undefined) { return frame; } } var control; reentry = true; var previousPrepareStackTrace = Error.prepareStackTrace; // $FlowFixMe It does accept undefined. Error.prepareStackTrace = undefined; var previousDispatcher; { previousDispatcher = ReactCurrentDispatcher.current; // Set the dispatcher in DEV because this might be call in the render function // for warnings. ReactCurrentDispatcher.current = null; disableLogs(); } try { // This should throw. if (construct) { // Something should be setting the props in the constructor. var Fake = function() { throw Error(); }; // $FlowFixMe Object.defineProperty(Fake.prototype, "props", { set: function() { // We use a throwing setter instead of frozen or non-writable props // because that won't throw in a non-strict mode function. throw Error(); } }); if (typeof Reflect === "object" && Reflect.construct) { // We construct a different control for this case to include any extra // frames added by the construct call. try { Reflect.construct(Fake, []); } catch (x) { control = x; } Reflect.construct(fn, [], Fake); } else { try { Fake.call(); } catch (x) { control = x; } // $FlowFixMe[prop-missing] found when upgrading Flow fn.call(Fake.prototype); } } else { try { throw Error(); } catch (x) { control = x; } // TODO(luna): This will currently only throw if the function component // tries to access React/ReactDOM/props. We should probably make this throw // in simple components too fn(); } } catch (sample) { // This is inlined manually because closure doesn't do it for us. if (sample && control && typeof sample.stack === "string") { // This extracts the first frame from the sample that isn't also in the control. // Skipping one frame that we assume is the frame that calls the two. var sampleLines = sample.stack.split("\n"); var controlLines = control.stack.split("\n"); var s = sampleLines.length - 1; var c = controlLines.length - 1; while (s >= 1 && c >= 0 && sampleLines[s] !== controlLines[c]) { // We expect at least one stack frame to be shared. // Typically this will be the root most one. However, stack frames may be // cut off due to maximum stack limits. In this case, one maybe cut off // earlier than the other. We assume that the sample is longer or the same // and there for cut off earlier. So we should find the root most frame in // the sample somewhere in the control. c--; } for (; s >= 1 && c >= 0; s--, c--) { // Next we find the first one that isn't the same which should be the // frame that called our sample function and the control. if (sampleLines[s] !== controlLines[c]) { // In V8, the first line is describing the message but other VMs don't. // If we're about to return the first line, and the control is also on the same // line, that's a pretty good indicator that our sample threw at same line as // the control. I.e. before we entered the sample frame. So we ignore this result. // This can happen if you passed a class to function component, or non-function. if (s !== 1 || c !== 1) { do { s--; c--; // We may still have similar intermediate frames from the construct call. // The next one that isn't the same should be our match though. if (c < 0 || sampleLines[s] !== controlLines[c]) { // V8 adds a "new" prefix for native classes. Let's remove it to make it prettier. var _frame = "\n" + sampleLines[s].replace(" at new ", " at "); // If our component frame is labeled "" // but we have a user-provided "displayName" // splice it in to make the stack more readable. if (fn.displayName && _frame.includes("")) { _frame = _frame.replace("", fn.displayName); } { if (typeof fn === "function") { componentFrameCache.set(fn, _frame); } } // Return the line we found. return _frame; } } while (s >= 1 && c >= 0); } break; } } } } finally { reentry = false; { ReactCurrentDispatcher.current = previousDispatcher; reenableLogs(); } Error.prepareStackTrace = previousPrepareStackTrace; } // Fallback to just using the name if we couldn't make it throw. var name = fn ? fn.displayName || fn.name : ""; var syntheticFrame = name ? describeBuiltInComponentFrame(name) : ""; { if (typeof fn === "function") { componentFrameCache.set(fn, syntheticFrame); } } return syntheticFrame; } function describeClassComponentFrame(ctor, source, ownerFn) { { return describeNativeComponentFrame(ctor, true); } } function describeFunctionComponentFrame(fn, source, ownerFn) { { return describeNativeComponentFrame(fn, false); } } function shouldConstruct(Component) { var prototype = Component.prototype; return !!(prototype && prototype.isReactComponent); } function describeUnknownElementTypeFrameInDEV(type, source, ownerFn) { if (type == null) { return ""; } if (typeof type === "function") { { return describeNativeComponentFrame(type, shouldConstruct(type)); } } if (typeof type === "string") { return describeBuiltInComponentFrame(type); } switch (type) { case REACT_SUSPENSE_TYPE: return describeBuiltInComponentFrame("Suspense"); case REACT_SUSPENSE_LIST_TYPE: return describeBuiltInComponentFrame("SuspenseList"); } if (typeof type === "object") { switch (type.$$typeof) { case REACT_FORWARD_REF_TYPE: return describeFunctionComponentFrame(type.render); case REACT_MEMO_TYPE: // Memo may contain any component type so we recursively resolve it. return describeUnknownElementTypeFrameInDEV(type.type, source, ownerFn); case REACT_LAZY_TYPE: { var lazyComponent = type; var payload = lazyComponent._payload; var init = lazyComponent._init; try { // Lazy may contain any component type so we recursively resolve it. return describeUnknownElementTypeFrameInDEV( init(payload), source, ownerFn ); } catch (x) {} } } } return ""; } function describeFiber(fiber) { var owner = fiber._debugOwner ? fiber._debugOwner.type : null; var source = fiber._debugSource; switch (fiber.tag) { case HostResource: case HostSingleton: case HostComponent: return describeBuiltInComponentFrame(fiber.type); case LazyComponent: return describeBuiltInComponentFrame("Lazy"); case SuspenseComponent: return describeBuiltInComponentFrame("Suspense"); case SuspenseListComponent: return describeBuiltInComponentFrame("SuspenseList"); case FunctionComponent: case IndeterminateComponent: case SimpleMemoComponent: return describeFunctionComponentFrame(fiber.type); case ForwardRef: return describeFunctionComponentFrame(fiber.type.render); case ClassComponent: return describeClassComponentFrame(fiber.type); default: return ""; } } function getStackByFiberInDevAndProd(workInProgress) { try { var info = ""; var node = workInProgress; do { info += describeFiber(node); // $FlowFixMe[incompatible-type] we bail out when we get a null node = node.return; } while (node); return info; } catch (x) { return "\nError generating stack: " + x.message + "\n" + x.stack; } } var ReactDebugCurrentFrame = ReactSharedInternals.ReactDebugCurrentFrame; var current = null; var isRendering = false; function getCurrentFiberOwnerNameInDevOrNull() { { if (current === null) { return null; } var owner = current._debugOwner; if (owner !== null && typeof owner !== "undefined") { return getComponentNameFromFiber(owner); } } return null; } function getCurrentFiberStackInDev() { { if (current === null) { return ""; } // Safe because if current fiber exists, we are reconciling, // and it is guaranteed to be the work-in-progress version. return getStackByFiberInDevAndProd(current); } } function resetCurrentFiber() { { ReactDebugCurrentFrame.getCurrentStack = null; current = null; isRendering = false; } } function setCurrentFiber(fiber) { { ReactDebugCurrentFrame.getCurrentStack = fiber === null ? null : getCurrentFiberStackInDev; current = fiber; isRendering = false; } } function getCurrentFiber() { { return current; } } function setIsRendering(rendering) { { isRendering = rendering; } } // around this limitation, we use an opaque type that can only be obtained by // passing the value through getToStringValue first. function toString(value) { // The coercion safety check is performed in getToStringValue(). // eslint-disable-next-line react-internal/safe-string-coercion return "" + value; } function getToStringValue(value) { switch (typeof value) { case "boolean": case "number": case "string": case "undefined": return value; case "object": { checkFormFieldValueStringCoercion(value); } return value; default: // function, symbol are assigned as empty strings return ""; } } var hasReadOnlyValue = { button: true, checkbox: true, image: true, hidden: true, radio: true, reset: true, submit: true }; function checkControlledValueProps(tagName, props) { { if ( !( hasReadOnlyValue[props.type] || props.onChange || props.onInput || props.readOnly || props.disabled || props.value == null ) ) { 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`." ); } if ( !( props.onChange || props.readOnly || props.disabled || props.checked == null ) ) { 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`." ); } } } 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 ); { checkFormFieldValueStringCoercion(node[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 === "undefined" || typeof descriptor.get !== "function" || typeof descriptor.set !== "function" ) { return; } var get = descriptor.get, set = descriptor.set; Object.defineProperty(node, valueField, { configurable: true, // $FlowFixMe[missing-this-annot] get: function() { return get.call(this); }, // $FlowFixMe[missing-local-annot] // $FlowFixMe[missing-this-annot] set: function(value) { { checkFormFieldValueStringCoercion(value); } currentValue = "" + value; set.call(this, value); } }); // We could've passed this the first time // but it triggers a bug in IE11 and Edge 14/15. // Calling defineProperty() again should be equivalent. // https://github.com/facebook/react/issues/11768 Object.defineProperty(node, valueField, { enumerable: descriptor.enumerable }); var tracker = { getValue: function() { return currentValue; }, setValue: function(value) { { checkFormFieldValueStringCoercion(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); } 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; } function getActiveElement(doc) { 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 didWarnValueDefaultValue = false; var didWarnCheckedDefaultChecked = false; var didWarnControlledToUncontrolled = false; var didWarnUncontrolledToControlled = false; function isControlled(props) { var usesChecked = props.type === "checkbox" || props.type === "radio"; return usesChecked ? props.checked != null : props.value != null; } /** * Implements an host component that allows setting these optional * props: `checked`, `value`, `defaultChecked`, and `defaultValue`. * * If `checked` or `value` are not supplied (or null/undefined), user actions * that affect the checked state or value will trigger updates to the element. * * If they are supplied (and not null/undefined), the rendered element will not * trigger updates to the element. Instead, the props must change in order for * the rendered element to be updated. * * The rendered element will be initialized as unchecked (or `defaultChecked`) * with an empty value (or `defaultValue`). * * See http://www.w3.org/TR/2012/WD-html5-20121025/the-input-element.html */ function getHostProps(element, props) { var node = element; var checked = props.checked; var hostProps = assign({}, props, { defaultChecked: undefined, defaultValue: undefined, value: undefined, checked: checked != null ? checked : node._wrapperState.initialChecked }); return hostProps; } function initWrapperState(element, props) { { checkControlledValueProps("input", props); if ( props.checked !== undefined && props.defaultChecked !== undefined && !didWarnCheckedDefaultChecked ) { error( "%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://reactjs.org/link/controlled-components", getCurrentFiberOwnerNameInDevOrNull() || "A component", props.type ); didWarnCheckedDefaultChecked = true; } if ( props.value !== undefined && props.defaultValue !== undefined && !didWarnValueDefaultValue ) { error( "%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://reactjs.org/link/controlled-components", getCurrentFiberOwnerNameInDevOrNull() || "A component", props.type ); didWarnValueDefaultValue = true; } } var node = element; var defaultValue = props.defaultValue == null ? "" : props.defaultValue; node._wrapperState = { initialChecked: props.checked != null ? props.checked : props.defaultChecked, initialValue: getToStringValue( props.value != null ? props.value : defaultValue ), controlled: isControlled(props) }; } function updateChecked(element, props) { var node = element; var checked = props.checked; if (checked != null) { setValueForProperty(node, "checked", checked, false); } } function updateWrapper(element, props) { var node = element; { var controlled = isControlled(props); if ( !node._wrapperState.controlled && controlled && !didWarnUncontrolledToControlled ) { error( "A component is changing an uncontrolled input to be controlled. " + "This is likely caused by the value changing from undefined to " + "a defined value, which should not happen. " + "Decide between using a controlled or uncontrolled input " + "element for the lifetime of the component. More info: https://reactjs.org/link/controlled-components" ); didWarnUncontrolledToControlled = true; } if ( node._wrapperState.controlled && !controlled && !didWarnControlledToUncontrolled ) { error( "A component is changing a controlled input to be uncontrolled. " + "This is likely caused by the value changing from a defined to " + "undefined, which should not happen. " + "Decide between using a controlled or uncontrolled input " + "element for the lifetime of the component. More info: https://reactjs.org/link/controlled-components" ); didWarnControlledToUncontrolled = true; } } updateChecked(element, props); var value = getToStringValue(props.value); var type = props.type; if (value != null) { if (type === "number") { if ( // $FlowFixMe[incompatible-type] (value === 0 && node.value === "") || // We explicitly want to coerce to number here if possible. // eslint-disable-next-line node.value != value ) { node.value = toString(value); } } else if (node.value !== toString(value)) { node.value = toString(value); } } else if (type === "submit" || type === "reset") { // Submit/reset inputs need the attribute removed completely to avoid // blank-text buttons. node.removeAttribute("value"); return; } { // When syncing the value attribute, the value comes from a cascade of // properties: // 1. The value React property // 2. The defaultValue React property // 3. Otherwise there should be no change if (props.hasOwnProperty("value")) { setDefaultValue(node, props.type, value); } else if (props.hasOwnProperty("defaultValue")) { setDefaultValue(node, props.type, getToStringValue(props.defaultValue)); } } { // When syncing the checked attribute, it only changes when it needs // to be removed, such as transitioning from a checkbox into a text input if (props.checked == null && props.defaultChecked != null) { node.defaultChecked = !!props.defaultChecked; } } } function postMountWrapper(element, props, isHydrating) { var node = element; // Do not assign value if it is already set. This prevents user text input // from being lost during SSR hydration. if (props.hasOwnProperty("value") || props.hasOwnProperty("defaultValue")) { var type = props.type; var isButton = type === "submit" || type === "reset"; // Avoid setting value attribute on submit/reset inputs as it overrides the // default value provided by the browser. See: #12872 if (isButton && (props.value === undefined || props.value === null)) { return; } var initialValue = toString(node._wrapperState.initialValue); // Do not assign value if it is already set. This prevents user text input // from being lost during SSR hydration. if (!isHydrating) { { // When syncing the value attribute, the value property should use // the wrapperState._initialValue property. This uses: // // 1. The value React property when present // 2. The defaultValue React property when present // 3. An empty string if (initialValue !== node.value) { node.value = initialValue; } } } { // Otherwise, the value attribute is synchronized to the property, // so we assign defaultValue to the same thing as the value property // assignment step above. node.defaultValue = initialValue; } } // 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 = ""; } { // When syncing the checked attribute, both the checked property and // attribute are assigned at the same time using defaultChecked. This uses: // // 1. The checked React property when present // 2. The defaultChecked React property when present // 3. Otherwise, false node.defaultChecked = !node.defaultChecked; node.defaultChecked = !!node._wrapperState.initialChecked; } if (name !== "") { node.name = name; } } function restoreControlledState(element, props) { var node = element; updateWrapper(node, props); updateNamedCousins(node, props); } function updateNamedCousins(rootNode, props) { var name = props.name; if (props.type === "radio" && name != null) { var queryRoot = rootNode; while (queryRoot.parentNode) { queryRoot = queryRoot.parentNode; } // If `rootNode.form` was non-null, then we could try `form.elements`, // but that sometimes behaves strangely in IE8. We could also try using // `form.getElementsByName`, but that will only return direct children // and won't include inputs that use the HTML5 `form=` attribute. Since // the input might not even be in a form. It might not even be in the // document. Let's just use the local `querySelectorAll` to ensure we don't // miss anything. { checkAttributeStringCoercion(name, "name"); } var group = queryRoot.querySelectorAll( "input[name=" + JSON.stringify("" + name) + '][type="radio"]' ); for (var i = 0; i < group.length; i++) { var otherNode = group[i]; if (otherNode === rootNode || otherNode.form !== rootNode.form) { continue; } // This will throw if radio buttons rendered by different copies of React // and the same name are rendered into the same form (same as #1939). // That's probably okay; we don't support it just as we don't support // mixing React radio buttons with non-React ones. var otherProps = getFiberCurrentPropsFromNode(otherNode); if (!otherProps) { throw new Error( "ReactDOMInput: Mixing React and non-React radio inputs with the " + "same `name` is not supported." ); } // We need update the tracked value on the named cousin since the value // was changed but the input saw no event or value set updateValueIfChanged(otherNode); // If this is a controlled radio button group, forcing the input that // was previously checked to update will cause it to be come re-checked // as appropriate. updateWrapper(otherNode, otherProps); } } } // In Chrome, assigning defaultValue to certain input types triggers input validation. // For number inputs, the display value loses trailing decimal points. For email inputs, // Chrome raises "The specified value is not a valid email address". // // Here we check to see if the defaultValue has actually changed, avoiding these problems // when the user is inputting text // // https://github.com/facebook/react/issues/7253 function setDefaultValue(node, type, value) { if ( // Focused number inputs synchronize on blur. See ChangeEventPlugin.js type !== "number" || getActiveElement(node.ownerDocument) !== node ) { if (value == null) { node.defaultValue = toString(node._wrapperState.initialValue); } else if (node.defaultValue !== toString(value)) { node.defaultValue = toString(value); } } } var didWarnSelectedSetOnOption = false; var didWarnInvalidChild = false; var didWarnInvalidInnerHTML = false; /** * Implements an