react-dom.js (906293B)
1 /** @license React v16.13.1 2 * react-dom.development.js 3 * 4 * Copyright (c) Facebook, Inc. and its affiliates. 5 * 6 * This source code is licensed under the MIT license found in the 7 * LICENSE file in the root directory of this source tree. 8 */ 9 10 'use strict'; 11 12 (function (global, factory) { 13 typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('react')) : 14 typeof define === 'function' && define.amd ? define(['exports', 'react'], factory) : 15 (global = global || self, factory(global.ReactDOM = {}, global.React)); 16 }(this, (function (exports, React) { 'use strict'; 17 18 var ReactSharedInternals = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; // Prevent newer renderers from RTE when used with older react package versions. 19 // Current owner and dispatcher used to share the same ref, 20 // but PR #14548 split them out to better support the react-debug-tools package. 21 22 if (!ReactSharedInternals.hasOwnProperty('ReactCurrentDispatcher')) { 23 ReactSharedInternals.ReactCurrentDispatcher = { 24 current: null 25 }; 26 } 27 28 if (!ReactSharedInternals.hasOwnProperty('ReactCurrentBatchConfig')) { 29 ReactSharedInternals.ReactCurrentBatchConfig = { 30 suspense: null 31 }; 32 } 33 34 // by calls to these methods by a Babel plugin. 35 // 36 // In PROD (or in packages without access to React internals), 37 // they are left as they are instead. 38 39 function warn(format) { 40 { 41 for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { 42 args[_key - 1] = arguments[_key]; 43 } 44 45 printWarning('warn', format, args); 46 } 47 } 48 function error(format) { 49 { 50 for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) { 51 args[_key2 - 1] = arguments[_key2]; 52 } 53 54 printWarning('error', format, args); 55 } 56 } 57 58 function printWarning(level, format, args) { 59 // When changing this logic, you might want to also 60 // update consoleWithStackDev.www.js as well. 61 { 62 var hasExistingStack = args.length > 0 && typeof args[args.length - 1] === 'string' && args[args.length - 1].indexOf('\n in') === 0; 63 64 if (!hasExistingStack) { 65 var ReactDebugCurrentFrame = ReactSharedInternals.ReactDebugCurrentFrame; 66 var stack = ReactDebugCurrentFrame.getStackAddendum(); 67 68 if (stack !== '') { 69 format += '%s'; 70 args = args.concat([stack]); 71 } 72 } 73 74 var argsWithFormat = args.map(function (item) { 75 return '' + item; 76 }); // Careful: RN currently depends on this prefix 77 78 argsWithFormat.unshift('Warning: ' + format); // We intentionally don't use spread (or .apply) directly because it 79 // breaks IE9: https://github.com/facebook/react/issues/13610 80 // eslint-disable-next-line react-internal/no-production-logging 81 82 Function.prototype.apply.call(console[level], console, argsWithFormat); 83 84 try { 85 // --- Welcome to debugging React --- 86 // This error was thrown as a convenience so that you can use this stack 87 // to find the callsite that caused this warning to fire. 88 var argIndex = 0; 89 var message = 'Warning: ' + format.replace(/%s/g, function () { 90 return args[argIndex++]; 91 }); 92 throw new Error(message); 93 } catch (x) {} 94 } 95 } 96 97 if (!React) { 98 { 99 throw Error( "ReactDOM was loaded before React. Make sure you load the React package before loading ReactDOM." ); 100 } 101 } 102 103 var invokeGuardedCallbackImpl = function (name, func, context, a, b, c, d, e, f) { 104 var funcArgs = Array.prototype.slice.call(arguments, 3); 105 106 try { 107 func.apply(context, funcArgs); 108 } catch (error) { 109 this.onError(error); 110 } 111 }; 112 113 { 114 // In DEV mode, we swap out invokeGuardedCallback for a special version 115 // that plays more nicely with the browser's DevTools. The idea is to preserve 116 // "Pause on exceptions" behavior. Because React wraps all user-provided 117 // functions in invokeGuardedCallback, and the production version of 118 // invokeGuardedCallback uses a try-catch, all user exceptions are treated 119 // like caught exceptions, and the DevTools won't pause unless the developer 120 // takes the extra step of enabling pause on caught exceptions. This is 121 // unintuitive, though, because even though React has caught the error, from 122 // the developer's perspective, the error is uncaught. 123 // 124 // To preserve the expected "Pause on exceptions" behavior, we don't use a 125 // try-catch in DEV. Instead, we synchronously dispatch a fake event to a fake 126 // DOM node, and call the user-provided callback from inside an event handler 127 // for that fake event. If the callback throws, the error is "captured" using 128 // a global event handler. But because the error happens in a different 129 // event loop context, it does not interrupt the normal program flow. 130 // Effectively, this gives us try-catch behavior without actually using 131 // try-catch. Neat! 132 // Check that the browser supports the APIs we need to implement our special 133 // DEV version of invokeGuardedCallback 134 if (typeof window !== 'undefined' && typeof window.dispatchEvent === 'function' && typeof document !== 'undefined' && typeof document.createEvent === 'function') { 135 var fakeNode = document.createElement('react'); 136 137 var invokeGuardedCallbackDev = function (name, func, context, a, b, c, d, e, f) { 138 // If document doesn't exist we know for sure we will crash in this method 139 // when we call document.createEvent(). However this can cause confusing 140 // errors: https://github.com/facebookincubator/create-react-app/issues/3482 141 // So we preemptively throw with a better message instead. 142 if (!(typeof document !== 'undefined')) { 143 { 144 throw Error( "The `document` global was defined when React was initialized, but is not defined anymore. This can happen in a test environment if a component schedules an update from an asynchronous callback, but the test has already finished running. To solve this, you can either unmount the component at the end of your test (and ensure that any asynchronous operations get canceled in `componentWillUnmount`), or you can change the test itself to be asynchronous." ); 145 } 146 } 147 148 var evt = document.createEvent('Event'); // Keeps track of whether the user-provided callback threw an error. We 149 // set this to true at the beginning, then set it to false right after 150 // calling the function. If the function errors, `didError` will never be 151 // set to false. This strategy works even if the browser is flaky and 152 // fails to call our global error handler, because it doesn't rely on 153 // the error event at all. 154 155 var didError = true; // Keeps track of the value of window.event so that we can reset it 156 // during the callback to let user code access window.event in the 157 // browsers that support it. 158 159 var windowEvent = window.event; // Keeps track of the descriptor of window.event to restore it after event 160 // dispatching: https://github.com/facebook/react/issues/13688 161 162 var windowEventDescriptor = Object.getOwnPropertyDescriptor(window, 'event'); // Create an event handler for our fake event. We will synchronously 163 // dispatch our fake event using `dispatchEvent`. Inside the handler, we 164 // call the user-provided callback. 165 166 var funcArgs = Array.prototype.slice.call(arguments, 3); 167 168 function callCallback() { 169 // We immediately remove the callback from event listeners so that 170 // nested `invokeGuardedCallback` calls do not clash. Otherwise, a 171 // nested call would trigger the fake event handlers of any call higher 172 // in the stack. 173 fakeNode.removeEventListener(evtType, callCallback, false); // We check for window.hasOwnProperty('event') to prevent the 174 // window.event assignment in both IE <= 10 as they throw an error 175 // "Member not found" in strict mode, and in Firefox which does not 176 // support window.event. 177 178 if (typeof window.event !== 'undefined' && window.hasOwnProperty('event')) { 179 window.event = windowEvent; 180 } 181 182 func.apply(context, funcArgs); 183 didError = false; 184 } // Create a global error event handler. We use this to capture the value 185 // that was thrown. It's possible that this error handler will fire more 186 // than once; for example, if non-React code also calls `dispatchEvent` 187 // and a handler for that event throws. We should be resilient to most of 188 // those cases. Even if our error event handler fires more than once, the 189 // last error event is always used. If the callback actually does error, 190 // we know that the last error event is the correct one, because it's not 191 // possible for anything else to have happened in between our callback 192 // erroring and the code that follows the `dispatchEvent` call below. If 193 // the callback doesn't error, but the error event was fired, we know to 194 // ignore it because `didError` will be false, as described above. 195 196 197 var error; // Use this to track whether the error event is ever called. 198 199 var didSetError = false; 200 var isCrossOriginError = false; 201 202 function handleWindowError(event) { 203 error = event.error; 204 didSetError = true; 205 206 if (error === null && event.colno === 0 && event.lineno === 0) { 207 isCrossOriginError = true; 208 } 209 210 if (event.defaultPrevented) { 211 // Some other error handler has prevented default. 212 // Browsers silence the error report if this happens. 213 // We'll remember this to later decide whether to log it or not. 214 if (error != null && typeof error === 'object') { 215 try { 216 error._suppressLogging = true; 217 } catch (inner) {// Ignore. 218 } 219 } 220 } 221 } // Create a fake event type. 222 223 224 var evtType = "react-" + (name ? name : 'invokeguardedcallback'); // Attach our event handlers 225 226 window.addEventListener('error', handleWindowError); 227 fakeNode.addEventListener(evtType, callCallback, false); // Synchronously dispatch our fake event. If the user-provided function 228 // errors, it will trigger our global error handler. 229 230 evt.initEvent(evtType, false, false); 231 fakeNode.dispatchEvent(evt); 232 233 if (windowEventDescriptor) { 234 Object.defineProperty(window, 'event', windowEventDescriptor); 235 } 236 237 if (didError) { 238 if (!didSetError) { 239 // The callback errored, but the error event never fired. 240 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.'); 241 } else if (isCrossOriginError) { 242 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.'); 243 } 244 245 this.onError(error); 246 } // Remove our event listeners 247 248 249 window.removeEventListener('error', handleWindowError); 250 }; 251 252 invokeGuardedCallbackImpl = invokeGuardedCallbackDev; 253 } 254 } 255 256 var invokeGuardedCallbackImpl$1 = invokeGuardedCallbackImpl; 257 258 var hasError = false; 259 var caughtError = null; // Used by event system to capture/rethrow the first error. 260 261 var hasRethrowError = false; 262 var rethrowError = null; 263 var reporter = { 264 onError: function (error) { 265 hasError = true; 266 caughtError = error; 267 } 268 }; 269 /** 270 * Call a function while guarding against errors that happens within it. 271 * Returns an error if it throws, otherwise null. 272 * 273 * In production, this is implemented using a try-catch. The reason we don't 274 * use a try-catch directly is so that we can swap out a different 275 * implementation in DEV mode. 276 * 277 * @param {String} name of the guard to use for logging or debugging 278 * @param {Function} func The function to invoke 279 * @param {*} context The context to use when calling the function 280 * @param {...*} args Arguments for function 281 */ 282 283 function invokeGuardedCallback(name, func, context, a, b, c, d, e, f) { 284 hasError = false; 285 caughtError = null; 286 invokeGuardedCallbackImpl$1.apply(reporter, arguments); 287 } 288 /** 289 * Same as invokeGuardedCallback, but instead of returning an error, it stores 290 * it in a global so it can be rethrown by `rethrowCaughtError` later. 291 * TODO: See if caughtError and rethrowError can be unified. 292 * 293 * @param {String} name of the guard to use for logging or debugging 294 * @param {Function} func The function to invoke 295 * @param {*} context The context to use when calling the function 296 * @param {...*} args Arguments for function 297 */ 298 299 function invokeGuardedCallbackAndCatchFirstError(name, func, context, a, b, c, d, e, f) { 300 invokeGuardedCallback.apply(this, arguments); 301 302 if (hasError) { 303 var error = clearCaughtError(); 304 305 if (!hasRethrowError) { 306 hasRethrowError = true; 307 rethrowError = error; 308 } 309 } 310 } 311 /** 312 * During execution of guarded functions we will capture the first error which 313 * we will rethrow to be handled by the top level error handler. 314 */ 315 316 function rethrowCaughtError() { 317 if (hasRethrowError) { 318 var error = rethrowError; 319 hasRethrowError = false; 320 rethrowError = null; 321 throw error; 322 } 323 } 324 function hasCaughtError() { 325 return hasError; 326 } 327 function clearCaughtError() { 328 if (hasError) { 329 var error = caughtError; 330 hasError = false; 331 caughtError = null; 332 return error; 333 } else { 334 { 335 { 336 throw Error( "clearCaughtError was called but no error was captured. This error is likely caused by a bug in React. Please file an issue." ); 337 } 338 } 339 } 340 } 341 342 var getFiberCurrentPropsFromNode = null; 343 var getInstanceFromNode = null; 344 var getNodeFromInstance = null; 345 function setComponentTree(getFiberCurrentPropsFromNodeImpl, getInstanceFromNodeImpl, getNodeFromInstanceImpl) { 346 getFiberCurrentPropsFromNode = getFiberCurrentPropsFromNodeImpl; 347 getInstanceFromNode = getInstanceFromNodeImpl; 348 getNodeFromInstance = getNodeFromInstanceImpl; 349 350 { 351 if (!getNodeFromInstance || !getInstanceFromNode) { 352 error('EventPluginUtils.setComponentTree(...): Injected ' + 'module is missing getNodeFromInstance or getInstanceFromNode.'); 353 } 354 } 355 } 356 var validateEventDispatches; 357 358 { 359 validateEventDispatches = function (event) { 360 var dispatchListeners = event._dispatchListeners; 361 var dispatchInstances = event._dispatchInstances; 362 var listenersIsArr = Array.isArray(dispatchListeners); 363 var listenersLen = listenersIsArr ? dispatchListeners.length : dispatchListeners ? 1 : 0; 364 var instancesIsArr = Array.isArray(dispatchInstances); 365 var instancesLen = instancesIsArr ? dispatchInstances.length : dispatchInstances ? 1 : 0; 366 367 if (instancesIsArr !== listenersIsArr || instancesLen !== listenersLen) { 368 error('EventPluginUtils: Invalid `event`.'); 369 } 370 }; 371 } 372 /** 373 * Dispatch the event to the listener. 374 * @param {SyntheticEvent} event SyntheticEvent to handle 375 * @param {function} listener Application-level callback 376 * @param {*} inst Internal component instance 377 */ 378 379 380 function executeDispatch(event, listener, inst) { 381 var type = event.type || 'unknown-event'; 382 event.currentTarget = getNodeFromInstance(inst); 383 invokeGuardedCallbackAndCatchFirstError(type, listener, undefined, event); 384 event.currentTarget = null; 385 } 386 /** 387 * Standard/simple iteration through an event's collected dispatches. 388 */ 389 390 function executeDispatchesInOrder(event) { 391 var dispatchListeners = event._dispatchListeners; 392 var dispatchInstances = event._dispatchInstances; 393 394 { 395 validateEventDispatches(event); 396 } 397 398 if (Array.isArray(dispatchListeners)) { 399 for (var i = 0; i < dispatchListeners.length; i++) { 400 if (event.isPropagationStopped()) { 401 break; 402 } // Listeners and Instances are two parallel arrays that are always in sync. 403 404 405 executeDispatch(event, dispatchListeners[i], dispatchInstances[i]); 406 } 407 } else if (dispatchListeners) { 408 executeDispatch(event, dispatchListeners, dispatchInstances); 409 } 410 411 event._dispatchListeners = null; 412 event._dispatchInstances = null; 413 } 414 415 var FunctionComponent = 0; 416 var ClassComponent = 1; 417 var IndeterminateComponent = 2; // Before we know whether it is function or class 418 419 var HostRoot = 3; // Root of a host tree. Could be nested inside another node. 420 421 var HostPortal = 4; // A subtree. Could be an entry point to a different renderer. 422 423 var HostComponent = 5; 424 var HostText = 6; 425 var Fragment = 7; 426 var Mode = 8; 427 var ContextConsumer = 9; 428 var ContextProvider = 10; 429 var ForwardRef = 11; 430 var Profiler = 12; 431 var SuspenseComponent = 13; 432 var MemoComponent = 14; 433 var SimpleMemoComponent = 15; 434 var LazyComponent = 16; 435 var IncompleteClassComponent = 17; 436 var DehydratedFragment = 18; 437 var SuspenseListComponent = 19; 438 var FundamentalComponent = 20; 439 var ScopeComponent = 21; 440 var Block = 22; 441 442 /** 443 * Injectable ordering of event plugins. 444 */ 445 var eventPluginOrder = null; 446 /** 447 * Injectable mapping from names to event plugin modules. 448 */ 449 450 var namesToPlugins = {}; 451 /** 452 * Recomputes the plugin list using the injected plugins and plugin ordering. 453 * 454 * @private 455 */ 456 457 function recomputePluginOrdering() { 458 if (!eventPluginOrder) { 459 // Wait until an `eventPluginOrder` is injected. 460 return; 461 } 462 463 for (var pluginName in namesToPlugins) { 464 var pluginModule = namesToPlugins[pluginName]; 465 var pluginIndex = eventPluginOrder.indexOf(pluginName); 466 467 if (!(pluginIndex > -1)) { 468 { 469 throw Error( "EventPluginRegistry: Cannot inject event plugins that do not exist in the plugin ordering, `" + pluginName + "`." ); 470 } 471 } 472 473 if (plugins[pluginIndex]) { 474 continue; 475 } 476 477 if (!pluginModule.extractEvents) { 478 { 479 throw Error( "EventPluginRegistry: Event plugins must implement an `extractEvents` method, but `" + pluginName + "` does not." ); 480 } 481 } 482 483 plugins[pluginIndex] = pluginModule; 484 var publishedEvents = pluginModule.eventTypes; 485 486 for (var eventName in publishedEvents) { 487 if (!publishEventForPlugin(publishedEvents[eventName], pluginModule, eventName)) { 488 { 489 throw Error( "EventPluginRegistry: Failed to publish event `" + eventName + "` for plugin `" + pluginName + "`." ); 490 } 491 } 492 } 493 } 494 } 495 /** 496 * Publishes an event so that it can be dispatched by the supplied plugin. 497 * 498 * @param {object} dispatchConfig Dispatch configuration for the event. 499 * @param {object} PluginModule Plugin publishing the event. 500 * @return {boolean} True if the event was successfully published. 501 * @private 502 */ 503 504 505 function publishEventForPlugin(dispatchConfig, pluginModule, eventName) { 506 if (!!eventNameDispatchConfigs.hasOwnProperty(eventName)) { 507 { 508 throw Error( "EventPluginRegistry: More than one plugin attempted to publish the same event name, `" + eventName + "`." ); 509 } 510 } 511 512 eventNameDispatchConfigs[eventName] = dispatchConfig; 513 var phasedRegistrationNames = dispatchConfig.phasedRegistrationNames; 514 515 if (phasedRegistrationNames) { 516 for (var phaseName in phasedRegistrationNames) { 517 if (phasedRegistrationNames.hasOwnProperty(phaseName)) { 518 var phasedRegistrationName = phasedRegistrationNames[phaseName]; 519 publishRegistrationName(phasedRegistrationName, pluginModule, eventName); 520 } 521 } 522 523 return true; 524 } else if (dispatchConfig.registrationName) { 525 publishRegistrationName(dispatchConfig.registrationName, pluginModule, eventName); 526 return true; 527 } 528 529 return false; 530 } 531 /** 532 * Publishes a registration name that is used to identify dispatched events. 533 * 534 * @param {string} registrationName Registration name to add. 535 * @param {object} PluginModule Plugin publishing the event. 536 * @private 537 */ 538 539 540 function publishRegistrationName(registrationName, pluginModule, eventName) { 541 if (!!registrationNameModules[registrationName]) { 542 { 543 throw Error( "EventPluginRegistry: More than one plugin attempted to publish the same registration name, `" + registrationName + "`." ); 544 } 545 } 546 547 registrationNameModules[registrationName] = pluginModule; 548 registrationNameDependencies[registrationName] = pluginModule.eventTypes[eventName].dependencies; 549 550 { 551 var lowerCasedName = registrationName.toLowerCase(); 552 possibleRegistrationNames[lowerCasedName] = registrationName; 553 554 if (registrationName === 'onDoubleClick') { 555 possibleRegistrationNames.ondblclick = registrationName; 556 } 557 } 558 } 559 /** 560 * Registers plugins so that they can extract and dispatch events. 561 */ 562 563 /** 564 * Ordered list of injected plugins. 565 */ 566 567 568 var plugins = []; 569 /** 570 * Mapping from event name to dispatch config 571 */ 572 573 var eventNameDispatchConfigs = {}; 574 /** 575 * Mapping from registration name to plugin module 576 */ 577 578 var registrationNameModules = {}; 579 /** 580 * Mapping from registration name to event name 581 */ 582 583 var registrationNameDependencies = {}; 584 /** 585 * Mapping from lowercase registration names to the properly cased version, 586 * used to warn in the case of missing event handlers. Available 587 * only in true. 588 * @type {Object} 589 */ 590 591 var possibleRegistrationNames = {} ; // Trust the developer to only use possibleRegistrationNames in true 592 593 /** 594 * Injects an ordering of plugins (by plugin name). This allows the ordering 595 * to be decoupled from injection of the actual plugins so that ordering is 596 * always deterministic regardless of packaging, on-the-fly injection, etc. 597 * 598 * @param {array} InjectedEventPluginOrder 599 * @internal 600 */ 601 602 function injectEventPluginOrder(injectedEventPluginOrder) { 603 if (!!eventPluginOrder) { 604 { 605 throw Error( "EventPluginRegistry: Cannot inject event plugin ordering more than once. You are likely trying to load more than one copy of React." ); 606 } 607 } // Clone the ordering so it cannot be dynamically mutated. 608 609 610 eventPluginOrder = Array.prototype.slice.call(injectedEventPluginOrder); 611 recomputePluginOrdering(); 612 } 613 /** 614 * Injects plugins to be used by plugin event system. The plugin names must be 615 * in the ordering injected by `injectEventPluginOrder`. 616 * 617 * Plugins can be injected as part of page initialization or on-the-fly. 618 * 619 * @param {object} injectedNamesToPlugins Map from names to plugin modules. 620 * @internal 621 */ 622 623 function injectEventPluginsByName(injectedNamesToPlugins) { 624 var isOrderingDirty = false; 625 626 for (var pluginName in injectedNamesToPlugins) { 627 if (!injectedNamesToPlugins.hasOwnProperty(pluginName)) { 628 continue; 629 } 630 631 var pluginModule = injectedNamesToPlugins[pluginName]; 632 633 if (!namesToPlugins.hasOwnProperty(pluginName) || namesToPlugins[pluginName] !== pluginModule) { 634 if (!!namesToPlugins[pluginName]) { 635 { 636 throw Error( "EventPluginRegistry: Cannot inject two different event plugins using the same name, `" + pluginName + "`." ); 637 } 638 } 639 640 namesToPlugins[pluginName] = pluginModule; 641 isOrderingDirty = true; 642 } 643 } 644 645 if (isOrderingDirty) { 646 recomputePluginOrdering(); 647 } 648 } 649 650 var canUseDOM = !!(typeof window !== 'undefined' && typeof window.document !== 'undefined' && typeof window.document.createElement !== 'undefined'); 651 652 var ReactInternals = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; 653 var _assign = ReactInternals.assign; 654 655 var PLUGIN_EVENT_SYSTEM = 1; 656 var IS_REPLAYED = 1 << 5; 657 var IS_FIRST_ANCESTOR = 1 << 6; 658 659 var restoreImpl = null; 660 var restoreTarget = null; 661 var restoreQueue = null; 662 663 function restoreStateOfTarget(target) { 664 // We perform this translation at the end of the event loop so that we 665 // always receive the correct fiber here 666 var internalInstance = getInstanceFromNode(target); 667 668 if (!internalInstance) { 669 // Unmounted 670 return; 671 } 672 673 if (!(typeof restoreImpl === 'function')) { 674 { 675 throw Error( "setRestoreImplementation() needs to be called to handle a target for controlled events. This error is likely caused by a bug in React. Please file an issue." ); 676 } 677 } 678 679 var stateNode = internalInstance.stateNode; // Guard against Fiber being unmounted. 680 681 if (stateNode) { 682 var _props = getFiberCurrentPropsFromNode(stateNode); 683 684 restoreImpl(internalInstance.stateNode, internalInstance.type, _props); 685 } 686 } 687 688 function setRestoreImplementation(impl) { 689 restoreImpl = impl; 690 } 691 function enqueueStateRestore(target) { 692 if (restoreTarget) { 693 if (restoreQueue) { 694 restoreQueue.push(target); 695 } else { 696 restoreQueue = [target]; 697 } 698 } else { 699 restoreTarget = target; 700 } 701 } 702 function needsStateRestore() { 703 return restoreTarget !== null || restoreQueue !== null; 704 } 705 function restoreStateIfNeeded() { 706 if (!restoreTarget) { 707 return; 708 } 709 710 var target = restoreTarget; 711 var queuedTargets = restoreQueue; 712 restoreTarget = null; 713 restoreQueue = null; 714 restoreStateOfTarget(target); 715 716 if (queuedTargets) { 717 for (var i = 0; i < queuedTargets.length; i++) { 718 restoreStateOfTarget(queuedTargets[i]); 719 } 720 } 721 } 722 723 var enableProfilerTimer = true; // Trace which interactions trigger each commit. 724 725 var enableDeprecatedFlareAPI = false; // Experimental Host Component support. 726 727 var enableFundamentalAPI = false; // Experimental Scope support. 728 var warnAboutStringRefs = false; 729 730 // the renderer. Such as when we're dispatching events or if third party 731 // libraries need to call batchedUpdates. Eventually, this API will go away when 732 // everything is batched by default. We'll then have a similar API to opt-out of 733 // scheduled work and instead do synchronous work. 734 // Defaults 735 736 var batchedUpdatesImpl = function (fn, bookkeeping) { 737 return fn(bookkeeping); 738 }; 739 740 var discreteUpdatesImpl = function (fn, a, b, c, d) { 741 return fn(a, b, c, d); 742 }; 743 744 var flushDiscreteUpdatesImpl = function () {}; 745 746 var batchedEventUpdatesImpl = batchedUpdatesImpl; 747 var isInsideEventHandler = false; 748 var isBatchingEventUpdates = false; 749 750 function finishEventHandler() { 751 // Here we wait until all updates have propagated, which is important 752 // when using controlled components within layers: 753 // https://github.com/facebook/react/issues/1698 754 // Then we restore state of any controlled component. 755 var controlledComponentsHavePendingUpdates = needsStateRestore(); 756 757 if (controlledComponentsHavePendingUpdates) { 758 // If a controlled event was fired, we may need to restore the state of 759 // the DOM node back to the controlled value. This is necessary when React 760 // bails out of the update without touching the DOM. 761 flushDiscreteUpdatesImpl(); 762 restoreStateIfNeeded(); 763 } 764 } 765 766 function batchedUpdates(fn, bookkeeping) { 767 if (isInsideEventHandler) { 768 // If we are currently inside another batch, we need to wait until it 769 // fully completes before restoring state. 770 return fn(bookkeeping); 771 } 772 773 isInsideEventHandler = true; 774 775 try { 776 return batchedUpdatesImpl(fn, bookkeeping); 777 } finally { 778 isInsideEventHandler = false; 779 finishEventHandler(); 780 } 781 } 782 function batchedEventUpdates(fn, a, b) { 783 if (isBatchingEventUpdates) { 784 // If we are currently inside another batch, we need to wait until it 785 // fully completes before restoring state. 786 return fn(a, b); 787 } 788 789 isBatchingEventUpdates = true; 790 791 try { 792 return batchedEventUpdatesImpl(fn, a, b); 793 } finally { 794 isBatchingEventUpdates = false; 795 finishEventHandler(); 796 } 797 } // This is for the React Flare event system 798 function discreteUpdates(fn, a, b, c, d) { 799 var prevIsInsideEventHandler = isInsideEventHandler; 800 isInsideEventHandler = true; 801 802 try { 803 return discreteUpdatesImpl(fn, a, b, c, d); 804 } finally { 805 isInsideEventHandler = prevIsInsideEventHandler; 806 807 if (!isInsideEventHandler) { 808 finishEventHandler(); 809 } 810 } 811 } 812 function flushDiscreteUpdatesIfNeeded(timeStamp) { 813 // event.timeStamp isn't overly reliable due to inconsistencies in 814 // how different browsers have historically provided the time stamp. 815 // Some browsers provide high-resolution time stamps for all events, 816 // some provide low-resolution time stamps for all events. FF < 52 817 // even mixes both time stamps together. Some browsers even report 818 // negative time stamps or time stamps that are 0 (iOS9) in some cases. 819 // Given we are only comparing two time stamps with equality (!==), 820 // we are safe from the resolution differences. If the time stamp is 0 821 // we bail-out of preventing the flush, which can affect semantics, 822 // such as if an earlier flush removes or adds event listeners that 823 // are fired in the subsequent flush. However, this is the same 824 // behaviour as we had before this change, so the risks are low. 825 if (!isInsideEventHandler && (!enableDeprecatedFlareAPI )) { 826 flushDiscreteUpdatesImpl(); 827 } 828 } 829 function setBatchingImplementation(_batchedUpdatesImpl, _discreteUpdatesImpl, _flushDiscreteUpdatesImpl, _batchedEventUpdatesImpl) { 830 batchedUpdatesImpl = _batchedUpdatesImpl; 831 discreteUpdatesImpl = _discreteUpdatesImpl; 832 flushDiscreteUpdatesImpl = _flushDiscreteUpdatesImpl; 833 batchedEventUpdatesImpl = _batchedEventUpdatesImpl; 834 } 835 836 var DiscreteEvent = 0; 837 var UserBlockingEvent = 1; 838 var ContinuousEvent = 2; 839 840 var ReactInternals$1 = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; 841 var _ReactInternals$Sched = ReactInternals$1.Scheduler, 842 unstable_cancelCallback = _ReactInternals$Sched.unstable_cancelCallback, 843 unstable_now = _ReactInternals$Sched.unstable_now, 844 unstable_scheduleCallback = _ReactInternals$Sched.unstable_scheduleCallback, 845 unstable_shouldYield = _ReactInternals$Sched.unstable_shouldYield, 846 unstable_requestPaint = _ReactInternals$Sched.unstable_requestPaint, 847 unstable_getFirstCallbackNode = _ReactInternals$Sched.unstable_getFirstCallbackNode, 848 unstable_runWithPriority = _ReactInternals$Sched.unstable_runWithPriority, 849 unstable_next = _ReactInternals$Sched.unstable_next, 850 unstable_continueExecution = _ReactInternals$Sched.unstable_continueExecution, 851 unstable_pauseExecution = _ReactInternals$Sched.unstable_pauseExecution, 852 unstable_getCurrentPriorityLevel = _ReactInternals$Sched.unstable_getCurrentPriorityLevel, 853 unstable_ImmediatePriority = _ReactInternals$Sched.unstable_ImmediatePriority, 854 unstable_UserBlockingPriority = _ReactInternals$Sched.unstable_UserBlockingPriority, 855 unstable_NormalPriority = _ReactInternals$Sched.unstable_NormalPriority, 856 unstable_LowPriority = _ReactInternals$Sched.unstable_LowPriority, 857 unstable_IdlePriority = _ReactInternals$Sched.unstable_IdlePriority, 858 unstable_forceFrameRate = _ReactInternals$Sched.unstable_forceFrameRate, 859 unstable_flushAllWithoutAsserting = _ReactInternals$Sched.unstable_flushAllWithoutAsserting; 860 861 // A reserved attribute. 862 // It is handled by React separately and shouldn't be written to the DOM. 863 var RESERVED = 0; // A simple string attribute. 864 // Attributes that aren't in the whitelist are presumed to have this type. 865 866 var STRING = 1; // A string attribute that accepts booleans in React. In HTML, these are called 867 // "enumerated" attributes with "true" and "false" as possible values. 868 // When true, it should be set to a "true" string. 869 // When false, it should be set to a "false" string. 870 871 var BOOLEANISH_STRING = 2; // A real boolean attribute. 872 // When true, it should be present (set either to an empty string or its name). 873 // When false, it should be omitted. 874 875 var BOOLEAN = 3; // An attribute that can be used as a flag as well as with a value. 876 // When true, it should be present (set either to an empty string or its name). 877 // When false, it should be omitted. 878 // For any other value, should be present with that value. 879 880 var OVERLOADED_BOOLEAN = 4; // An attribute that must be numeric or parse as a numeric. 881 // When falsy, it should be removed. 882 883 var NUMERIC = 5; // An attribute that must be positive numeric or parse as a positive numeric. 884 // When falsy, it should be removed. 885 886 var POSITIVE_NUMERIC = 6; 887 888 /* eslint-disable max-len */ 889 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"; 890 /* eslint-enable max-len */ 891 892 var ATTRIBUTE_NAME_CHAR = ATTRIBUTE_NAME_START_CHAR + "\\-.0-9\\u00B7\\u0300-\\u036F\\u203F-\\u2040"; 893 var ROOT_ATTRIBUTE_NAME = 'data-reactroot'; 894 var VALID_ATTRIBUTE_NAME_REGEX = new RegExp('^[' + ATTRIBUTE_NAME_START_CHAR + '][' + ATTRIBUTE_NAME_CHAR + ']*$'); 895 var hasOwnProperty = Object.prototype.hasOwnProperty; 896 var illegalAttributeNameCache = {}; 897 var validatedAttributeNameCache = {}; 898 function isAttributeNameSafe(attributeName) { 899 if (hasOwnProperty.call(validatedAttributeNameCache, attributeName)) { 900 return true; 901 } 902 903 if (hasOwnProperty.call(illegalAttributeNameCache, attributeName)) { 904 return false; 905 } 906 907 if (VALID_ATTRIBUTE_NAME_REGEX.test(attributeName)) { 908 validatedAttributeNameCache[attributeName] = true; 909 return true; 910 } 911 912 illegalAttributeNameCache[attributeName] = true; 913 914 { 915 error('Invalid attribute name: `%s`', attributeName); 916 } 917 918 return false; 919 } 920 function shouldIgnoreAttribute(name, propertyInfo, isCustomComponentTag) { 921 if (propertyInfo !== null) { 922 return propertyInfo.type === RESERVED; 923 } 924 925 if (isCustomComponentTag) { 926 return false; 927 } 928 929 if (name.length > 2 && (name[0] === 'o' || name[0] === 'O') && (name[1] === 'n' || name[1] === 'N')) { 930 return true; 931 } 932 933 return false; 934 } 935 function shouldRemoveAttributeWithWarning(name, value, propertyInfo, isCustomComponentTag) { 936 if (propertyInfo !== null && propertyInfo.type === RESERVED) { 937 return false; 938 } 939 940 switch (typeof value) { 941 case 'function': // $FlowIssue symbol is perfectly valid here 942 943 case 'symbol': 944 // eslint-disable-line 945 return true; 946 947 case 'boolean': 948 { 949 if (isCustomComponentTag) { 950 return false; 951 } 952 953 if (propertyInfo !== null) { 954 return !propertyInfo.acceptsBooleans; 955 } else { 956 var prefix = name.toLowerCase().slice(0, 5); 957 return prefix !== 'data-' && prefix !== 'aria-'; 958 } 959 } 960 961 default: 962 return false; 963 } 964 } 965 function shouldRemoveAttribute(name, value, propertyInfo, isCustomComponentTag) { 966 if (value === null || typeof value === 'undefined') { 967 return true; 968 } 969 970 if (shouldRemoveAttributeWithWarning(name, value, propertyInfo, isCustomComponentTag)) { 971 return true; 972 } 973 974 if (isCustomComponentTag) { 975 return false; 976 } 977 978 if (propertyInfo !== null) { 979 switch (propertyInfo.type) { 980 case BOOLEAN: 981 return !value; 982 983 case OVERLOADED_BOOLEAN: 984 return value === false; 985 986 case NUMERIC: 987 return isNaN(value); 988 989 case POSITIVE_NUMERIC: 990 return isNaN(value) || value < 1; 991 } 992 } 993 994 return false; 995 } 996 function getPropertyInfo(name) { 997 return properties.hasOwnProperty(name) ? properties[name] : null; 998 } 999 1000 function PropertyInfoRecord(name, type, mustUseProperty, attributeName, attributeNamespace, sanitizeURL) { 1001 this.acceptsBooleans = type === BOOLEANISH_STRING || type === BOOLEAN || type === OVERLOADED_BOOLEAN; 1002 this.attributeName = attributeName; 1003 this.attributeNamespace = attributeNamespace; 1004 this.mustUseProperty = mustUseProperty; 1005 this.propertyName = name; 1006 this.type = type; 1007 this.sanitizeURL = sanitizeURL; 1008 } // When adding attributes to this list, be sure to also add them to 1009 // the `possibleStandardNames` module to ensure casing and incorrect 1010 // name warnings. 1011 1012 1013 var properties = {}; // These props are reserved by React. They shouldn't be written to the DOM. 1014 1015 var reservedProps = ['children', 'dangerouslySetInnerHTML', // TODO: This prevents the assignment of defaultValue to regular 1016 // elements (not just inputs). Now that ReactDOMInput assigns to the 1017 // defaultValue property -- do we need this? 1018 'defaultValue', 'defaultChecked', 'innerHTML', 'suppressContentEditableWarning', 'suppressHydrationWarning', 'style']; 1019 1020 reservedProps.forEach(function (name) { 1021 properties[name] = new PropertyInfoRecord(name, RESERVED, false, // mustUseProperty 1022 name, // attributeName 1023 null, // attributeNamespace 1024 false); 1025 }); // A few React string attributes have a different name. 1026 // This is a mapping from React prop names to the attribute names. 1027 1028 [['acceptCharset', 'accept-charset'], ['className', 'class'], ['htmlFor', 'for'], ['httpEquiv', 'http-equiv']].forEach(function (_ref) { 1029 var name = _ref[0], 1030 attributeName = _ref[1]; 1031 properties[name] = new PropertyInfoRecord(name, STRING, false, // mustUseProperty 1032 attributeName, // attributeName 1033 null, // attributeNamespace 1034 false); 1035 }); // These are "enumerated" HTML attributes that accept "true" and "false". 1036 // In React, we let users pass `true` and `false` even though technically 1037 // these aren't boolean attributes (they are coerced to strings). 1038 1039 ['contentEditable', 'draggable', 'spellCheck', 'value'].forEach(function (name) { 1040 properties[name] = new PropertyInfoRecord(name, BOOLEANISH_STRING, false, // mustUseProperty 1041 name.toLowerCase(), // attributeName 1042 null, // attributeNamespace 1043 false); 1044 }); // These are "enumerated" SVG attributes that accept "true" and "false". 1045 // In React, we let users pass `true` and `false` even though technically 1046 // these aren't boolean attributes (they are coerced to strings). 1047 // Since these are SVG attributes, their attribute names are case-sensitive. 1048 1049 ['autoReverse', 'externalResourcesRequired', 'focusable', 'preserveAlpha'].forEach(function (name) { 1050 properties[name] = new PropertyInfoRecord(name, BOOLEANISH_STRING, false, // mustUseProperty 1051 name, // attributeName 1052 null, // attributeNamespace 1053 false); 1054 }); // These are HTML boolean attributes. 1055 1056 ['allowFullScreen', 'async', // Note: there is a special case that prevents it from being written to the DOM 1057 // on the client side because the browsers are inconsistent. Instead we call focus(). 1058 'autoFocus', 'autoPlay', 'controls', 'default', 'defer', 'disabled', 'disablePictureInPicture', 'formNoValidate', 'hidden', 'loop', 'noModule', 'noValidate', 'open', 'playsInline', 'readOnly', 'required', 'reversed', 'scoped', 'seamless', // Microdata 1059 'itemScope'].forEach(function (name) { 1060 properties[name] = new PropertyInfoRecord(name, BOOLEAN, false, // mustUseProperty 1061 name.toLowerCase(), // attributeName 1062 null, // attributeNamespace 1063 false); 1064 }); // These are the few React props that we set as DOM properties 1065 // rather than attributes. These are all booleans. 1066 1067 ['checked', // Note: `option.selected` is not updated if `select.multiple` is 1068 // disabled with `removeAttribute`. We have special logic for handling this. 1069 'multiple', 'muted', 'selected' // NOTE: if you add a camelCased prop to this list, 1070 // you'll need to set attributeName to name.toLowerCase() 1071 // instead in the assignment below. 1072 ].forEach(function (name) { 1073 properties[name] = new PropertyInfoRecord(name, BOOLEAN, true, // mustUseProperty 1074 name, // attributeName 1075 null, // attributeNamespace 1076 false); 1077 }); // These are HTML attributes that are "overloaded booleans": they behave like 1078 // booleans, but can also accept a string value. 1079 1080 ['capture', 'download' // NOTE: if you add a camelCased prop to this list, 1081 // you'll need to set attributeName to name.toLowerCase() 1082 // instead in the assignment below. 1083 ].forEach(function (name) { 1084 properties[name] = new PropertyInfoRecord(name, OVERLOADED_BOOLEAN, false, // mustUseProperty 1085 name, // attributeName 1086 null, // attributeNamespace 1087 false); 1088 }); // These are HTML attributes that must be positive numbers. 1089 1090 ['cols', 'rows', 'size', 'span' // NOTE: if you add a camelCased prop to this list, 1091 // you'll need to set attributeName to name.toLowerCase() 1092 // instead in the assignment below. 1093 ].forEach(function (name) { 1094 properties[name] = new PropertyInfoRecord(name, POSITIVE_NUMERIC, false, // mustUseProperty 1095 name, // attributeName 1096 null, // attributeNamespace 1097 false); 1098 }); // These are HTML attributes that must be numbers. 1099 1100 ['rowSpan', 'start'].forEach(function (name) { 1101 properties[name] = new PropertyInfoRecord(name, NUMERIC, false, // mustUseProperty 1102 name.toLowerCase(), // attributeName 1103 null, // attributeNamespace 1104 false); 1105 }); 1106 var CAMELIZE = /[\-\:]([a-z])/g; 1107 1108 var capitalize = function (token) { 1109 return token[1].toUpperCase(); 1110 }; // This is a list of all SVG attributes that need special casing, namespacing, 1111 // or boolean value assignment. Regular attributes that just accept strings 1112 // and have the same names are omitted, just like in the HTML whitelist. 1113 // Some of these attributes can be hard to find. This list was created by 1114 // scraping the MDN documentation. 1115 1116 1117 ['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, 1118 // you'll need to set attributeName to name.toLowerCase() 1119 // instead in the assignment below. 1120 ].forEach(function (attributeName) { 1121 var name = attributeName.replace(CAMELIZE, capitalize); 1122 properties[name] = new PropertyInfoRecord(name, STRING, false, // mustUseProperty 1123 attributeName, null, // attributeNamespace 1124 false); 1125 }); // String SVG attributes with the xlink namespace. 1126 1127 ['xlink:actuate', 'xlink:arcrole', 'xlink:role', 'xlink:show', 'xlink:title', 'xlink:type' // NOTE: if you add a camelCased prop to this list, 1128 // you'll need to set attributeName to name.toLowerCase() 1129 // instead in the assignment below. 1130 ].forEach(function (attributeName) { 1131 var name = attributeName.replace(CAMELIZE, capitalize); 1132 properties[name] = new PropertyInfoRecord(name, STRING, false, // mustUseProperty 1133 attributeName, 'http://www.w3.org/1999/xlink', false); 1134 }); // String SVG attributes with the xml namespace. 1135 1136 ['xml:base', 'xml:lang', 'xml:space' // NOTE: if you add a camelCased prop to this list, 1137 // you'll need to set attributeName to name.toLowerCase() 1138 // instead in the assignment below. 1139 ].forEach(function (attributeName) { 1140 var name = attributeName.replace(CAMELIZE, capitalize); 1141 properties[name] = new PropertyInfoRecord(name, STRING, false, // mustUseProperty 1142 attributeName, 'http://www.w3.org/XML/1998/namespace', false); 1143 }); // These attribute exists both in HTML and SVG. 1144 // The attribute name is case-sensitive in SVG so we can't just use 1145 // the React name like we do for attributes that exist only in HTML. 1146 1147 ['tabIndex', 'crossOrigin'].forEach(function (attributeName) { 1148 properties[attributeName] = new PropertyInfoRecord(attributeName, STRING, false, // mustUseProperty 1149 attributeName.toLowerCase(), // attributeName 1150 null, // attributeNamespace 1151 false); 1152 }); // These attributes accept URLs. These must not allow javascript: URLS. 1153 // These will also need to accept Trusted Types object in the future. 1154 1155 var xlinkHref = 'xlinkHref'; 1156 properties[xlinkHref] = new PropertyInfoRecord('xlinkHref', STRING, false, // mustUseProperty 1157 'xlink:href', 'http://www.w3.org/1999/xlink', true); 1158 ['src', 'href', 'action', 'formAction'].forEach(function (attributeName) { 1159 properties[attributeName] = new PropertyInfoRecord(attributeName, STRING, false, // mustUseProperty 1160 attributeName.toLowerCase(), // attributeName 1161 null, // attributeNamespace 1162 true); 1163 }); 1164 1165 var ReactDebugCurrentFrame = null; 1166 1167 { 1168 ReactDebugCurrentFrame = ReactSharedInternals.ReactDebugCurrentFrame; 1169 } // A javascript: URL can contain leading C0 control or \u0020 SPACE, 1170 // and any newline or tab are filtered out as if they're not part of the URL. 1171 // https://url.spec.whatwg.org/#url-parsing 1172 // Tab or newline are defined as \r\n\t: 1173 // https://infra.spec.whatwg.org/#ascii-tab-or-newline 1174 // A C0 control is a code point in the range \u0000 NULL to \u001F 1175 // INFORMATION SEPARATOR ONE, inclusive: 1176 // https://infra.spec.whatwg.org/#c0-control-or-space 1177 1178 /* eslint-disable max-len */ 1179 1180 1181 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; 1182 var didWarn = false; 1183 1184 function sanitizeURL(url) { 1185 { 1186 if (!didWarn && isJavaScriptProtocol.test(url)) { 1187 didWarn = true; 1188 1189 error('A future version of React will block javascript: URLs as a security precaution. ' + 'Use event handlers instead if you can. If you need to generate unsafe HTML try ' + 'using dangerouslySetInnerHTML instead. React was passed %s.', JSON.stringify(url)); 1190 } 1191 } 1192 } 1193 1194 /** 1195 * Get the value for a property on a node. Only used in DEV for SSR validation. 1196 * The "expected" argument is used as a hint of what the expected value is. 1197 * Some properties have multiple equivalent values. 1198 */ 1199 function getValueForProperty(node, name, expected, propertyInfo) { 1200 { 1201 if (propertyInfo.mustUseProperty) { 1202 var propertyName = propertyInfo.propertyName; 1203 return node[propertyName]; 1204 } else { 1205 if ( propertyInfo.sanitizeURL) { 1206 // If we haven't fully disabled javascript: URLs, and if 1207 // the hydration is successful of a javascript: URL, we 1208 // still want to warn on the client. 1209 sanitizeURL('' + expected); 1210 } 1211 1212 var attributeName = propertyInfo.attributeName; 1213 var stringValue = null; 1214 1215 if (propertyInfo.type === OVERLOADED_BOOLEAN) { 1216 if (node.hasAttribute(attributeName)) { 1217 var value = node.getAttribute(attributeName); 1218 1219 if (value === '') { 1220 return true; 1221 } 1222 1223 if (shouldRemoveAttribute(name, expected, propertyInfo, false)) { 1224 return value; 1225 } 1226 1227 if (value === '' + expected) { 1228 return expected; 1229 } 1230 1231 return value; 1232 } 1233 } else if (node.hasAttribute(attributeName)) { 1234 if (shouldRemoveAttribute(name, expected, propertyInfo, false)) { 1235 // We had an attribute but shouldn't have had one, so read it 1236 // for the error message. 1237 return node.getAttribute(attributeName); 1238 } 1239 1240 if (propertyInfo.type === BOOLEAN) { 1241 // If this was a boolean, it doesn't matter what the value is 1242 // the fact that we have it is the same as the expected. 1243 return expected; 1244 } // Even if this property uses a namespace we use getAttribute 1245 // because we assume its namespaced name is the same as our config. 1246 // To use getAttributeNS we need the local name which we don't have 1247 // in our config atm. 1248 1249 1250 stringValue = node.getAttribute(attributeName); 1251 } 1252 1253 if (shouldRemoveAttribute(name, expected, propertyInfo, false)) { 1254 return stringValue === null ? expected : stringValue; 1255 } else if (stringValue === '' + expected) { 1256 return expected; 1257 } else { 1258 return stringValue; 1259 } 1260 } 1261 } 1262 } 1263 /** 1264 * Get the value for a attribute on a node. Only used in DEV for SSR validation. 1265 * The third argument is used as a hint of what the expected value is. Some 1266 * attributes have multiple equivalent values. 1267 */ 1268 1269 function getValueForAttribute(node, name, expected) { 1270 { 1271 if (!isAttributeNameSafe(name)) { 1272 return; 1273 } 1274 1275 if (!node.hasAttribute(name)) { 1276 return expected === undefined ? undefined : null; 1277 } 1278 1279 var value = node.getAttribute(name); 1280 1281 if (value === '' + expected) { 1282 return expected; 1283 } 1284 1285 return value; 1286 } 1287 } 1288 /** 1289 * Sets the value for a property on a node. 1290 * 1291 * @param {DOMElement} node 1292 * @param {string} name 1293 * @param {*} value 1294 */ 1295 1296 function setValueForProperty(node, name, value, isCustomComponentTag) { 1297 var propertyInfo = getPropertyInfo(name); 1298 1299 if (shouldIgnoreAttribute(name, propertyInfo, isCustomComponentTag)) { 1300 return; 1301 } 1302 1303 if (shouldRemoveAttribute(name, value, propertyInfo, isCustomComponentTag)) { 1304 value = null; 1305 } // If the prop isn't in the special list, treat it as a simple attribute. 1306 1307 1308 if (isCustomComponentTag || propertyInfo === null) { 1309 if (isAttributeNameSafe(name)) { 1310 var _attributeName = name; 1311 1312 if (value === null) { 1313 node.removeAttribute(_attributeName); 1314 } else { 1315 node.setAttribute(_attributeName, '' + value); 1316 } 1317 } 1318 1319 return; 1320 } 1321 1322 var mustUseProperty = propertyInfo.mustUseProperty; 1323 1324 if (mustUseProperty) { 1325 var propertyName = propertyInfo.propertyName; 1326 1327 if (value === null) { 1328 var type = propertyInfo.type; 1329 node[propertyName] = type === BOOLEAN ? false : ''; 1330 } else { 1331 // Contrary to `setAttribute`, object properties are properly 1332 // `toString`ed by IE8/9. 1333 node[propertyName] = value; 1334 } 1335 1336 return; 1337 } // The rest are treated as attributes with special cases. 1338 1339 1340 var attributeName = propertyInfo.attributeName, 1341 attributeNamespace = propertyInfo.attributeNamespace; 1342 1343 if (value === null) { 1344 node.removeAttribute(attributeName); 1345 } else { 1346 var _type = propertyInfo.type; 1347 var attributeValue; 1348 1349 if (_type === BOOLEAN || _type === OVERLOADED_BOOLEAN && value === true) { 1350 // If attribute type is boolean, we know for sure it won't be an execution sink 1351 // and we won't require Trusted Type here. 1352 attributeValue = ''; 1353 } else { 1354 // `setAttribute` with objects becomes only `[object]` in IE8/9, 1355 // ('' + value) makes it output the correct toString()-value. 1356 { 1357 attributeValue = '' + value; 1358 } 1359 1360 if (propertyInfo.sanitizeURL) { 1361 sanitizeURL(attributeValue.toString()); 1362 } 1363 } 1364 1365 if (attributeNamespace) { 1366 node.setAttributeNS(attributeNamespace, attributeName, attributeValue); 1367 } else { 1368 node.setAttribute(attributeName, attributeValue); 1369 } 1370 } 1371 } 1372 1373 var BEFORE_SLASH_RE = /^(.*)[\\\/]/; 1374 function describeComponentFrame (name, source, ownerName) { 1375 var sourceInfo = ''; 1376 1377 if (source) { 1378 var path = source.fileName; 1379 var fileName = path.replace(BEFORE_SLASH_RE, ''); 1380 1381 { 1382 // In DEV, include code for a common special case: 1383 // prefer "folder/index.js" instead of just "index.js". 1384 if (/^index\./.test(fileName)) { 1385 var match = path.match(BEFORE_SLASH_RE); 1386 1387 if (match) { 1388 var pathBeforeSlash = match[1]; 1389 1390 if (pathBeforeSlash) { 1391 var folderName = pathBeforeSlash.replace(BEFORE_SLASH_RE, ''); 1392 fileName = folderName + '/' + fileName; 1393 } 1394 } 1395 } 1396 } 1397 1398 sourceInfo = ' (at ' + fileName + ':' + source.lineNumber + ')'; 1399 } else if (ownerName) { 1400 sourceInfo = ' (created by ' + ownerName + ')'; 1401 } 1402 1403 return '\n in ' + (name || 'Unknown') + sourceInfo; 1404 } 1405 1406 // The Symbol used to tag the ReactElement-like types. If there is no native Symbol 1407 // nor polyfill, then a plain number is used for performance. 1408 var hasSymbol = typeof Symbol === 'function' && Symbol.for; 1409 var REACT_ELEMENT_TYPE = hasSymbol ? Symbol.for('react.element') : 0xeac7; 1410 var REACT_PORTAL_TYPE = hasSymbol ? Symbol.for('react.portal') : 0xeaca; 1411 var REACT_FRAGMENT_TYPE = hasSymbol ? Symbol.for('react.fragment') : 0xeacb; 1412 var REACT_STRICT_MODE_TYPE = hasSymbol ? Symbol.for('react.strict_mode') : 0xeacc; 1413 var REACT_PROFILER_TYPE = hasSymbol ? Symbol.for('react.profiler') : 0xead2; 1414 var REACT_PROVIDER_TYPE = hasSymbol ? Symbol.for('react.provider') : 0xeacd; 1415 var REACT_CONTEXT_TYPE = hasSymbol ? Symbol.for('react.context') : 0xeace; // TODO: We don't use AsyncMode or ConcurrentMode anymore. They were temporary 1416 var REACT_CONCURRENT_MODE_TYPE = hasSymbol ? Symbol.for('react.concurrent_mode') : 0xeacf; 1417 var REACT_FORWARD_REF_TYPE = hasSymbol ? Symbol.for('react.forward_ref') : 0xead0; 1418 var REACT_SUSPENSE_TYPE = hasSymbol ? Symbol.for('react.suspense') : 0xead1; 1419 var REACT_SUSPENSE_LIST_TYPE = hasSymbol ? Symbol.for('react.suspense_list') : 0xead8; 1420 var REACT_MEMO_TYPE = hasSymbol ? Symbol.for('react.memo') : 0xead3; 1421 var REACT_LAZY_TYPE = hasSymbol ? Symbol.for('react.lazy') : 0xead4; 1422 var REACT_BLOCK_TYPE = hasSymbol ? Symbol.for('react.block') : 0xead9; 1423 var MAYBE_ITERATOR_SYMBOL = typeof Symbol === 'function' && Symbol.iterator; 1424 var FAUX_ITERATOR_SYMBOL = '@@iterator'; 1425 function getIteratorFn(maybeIterable) { 1426 if (maybeIterable === null || typeof maybeIterable !== 'object') { 1427 return null; 1428 } 1429 1430 var maybeIterator = MAYBE_ITERATOR_SYMBOL && maybeIterable[MAYBE_ITERATOR_SYMBOL] || maybeIterable[FAUX_ITERATOR_SYMBOL]; 1431 1432 if (typeof maybeIterator === 'function') { 1433 return maybeIterator; 1434 } 1435 1436 return null; 1437 } 1438 1439 var Uninitialized = -1; 1440 var Pending = 0; 1441 var Resolved = 1; 1442 var Rejected = 2; 1443 function refineResolvedLazyComponent(lazyComponent) { 1444 return lazyComponent._status === Resolved ? lazyComponent._result : null; 1445 } 1446 function initializeLazyComponentType(lazyComponent) { 1447 if (lazyComponent._status === Uninitialized) { 1448 lazyComponent._status = Pending; 1449 var ctor = lazyComponent._ctor; 1450 var thenable = ctor(); 1451 lazyComponent._result = thenable; 1452 thenable.then(function (moduleObject) { 1453 if (lazyComponent._status === Pending) { 1454 var defaultExport = moduleObject.default; 1455 1456 { 1457 if (defaultExport === undefined) { 1458 error('lazy: Expected the result of a dynamic import() call. ' + 'Instead received: %s\n\nYour code should look like: \n ' + "const MyComponent = lazy(() => import('./MyComponent'))", moduleObject); 1459 } 1460 } 1461 1462 lazyComponent._status = Resolved; 1463 lazyComponent._result = defaultExport; 1464 } 1465 }, function (error) { 1466 if (lazyComponent._status === Pending) { 1467 lazyComponent._status = Rejected; 1468 lazyComponent._result = error; 1469 } 1470 }); 1471 } 1472 } 1473 1474 function getWrappedName(outerType, innerType, wrapperName) { 1475 var functionName = innerType.displayName || innerType.name || ''; 1476 return outerType.displayName || (functionName !== '' ? wrapperName + "(" + functionName + ")" : wrapperName); 1477 } 1478 1479 function getComponentName(type) { 1480 if (type == null) { 1481 // Host root, text node or just invalid type. 1482 return null; 1483 } 1484 1485 { 1486 if (typeof type.tag === 'number') { 1487 error('Received an unexpected object in getComponentName(). ' + 'This is likely a bug in React. Please file an issue.'); 1488 } 1489 } 1490 1491 if (typeof type === 'function') { 1492 return type.displayName || type.name || null; 1493 } 1494 1495 if (typeof type === 'string') { 1496 return type; 1497 } 1498 1499 switch (type) { 1500 case REACT_FRAGMENT_TYPE: 1501 return 'Fragment'; 1502 1503 case REACT_PORTAL_TYPE: 1504 return 'Portal'; 1505 1506 case REACT_PROFILER_TYPE: 1507 return "Profiler"; 1508 1509 case REACT_STRICT_MODE_TYPE: 1510 return 'StrictMode'; 1511 1512 case REACT_SUSPENSE_TYPE: 1513 return 'Suspense'; 1514 1515 case REACT_SUSPENSE_LIST_TYPE: 1516 return 'SuspenseList'; 1517 } 1518 1519 if (typeof type === 'object') { 1520 switch (type.$$typeof) { 1521 case REACT_CONTEXT_TYPE: 1522 return 'Context.Consumer'; 1523 1524 case REACT_PROVIDER_TYPE: 1525 return 'Context.Provider'; 1526 1527 case REACT_FORWARD_REF_TYPE: 1528 return getWrappedName(type, type.render, 'ForwardRef'); 1529 1530 case REACT_MEMO_TYPE: 1531 return getComponentName(type.type); 1532 1533 case REACT_BLOCK_TYPE: 1534 return getComponentName(type.render); 1535 1536 case REACT_LAZY_TYPE: 1537 { 1538 var thenable = type; 1539 var resolvedThenable = refineResolvedLazyComponent(thenable); 1540 1541 if (resolvedThenable) { 1542 return getComponentName(resolvedThenable); 1543 } 1544 1545 break; 1546 } 1547 } 1548 } 1549 1550 return null; 1551 } 1552 1553 var ReactDebugCurrentFrame$1 = ReactSharedInternals.ReactDebugCurrentFrame; 1554 1555 function describeFiber(fiber) { 1556 switch (fiber.tag) { 1557 case HostRoot: 1558 case HostPortal: 1559 case HostText: 1560 case Fragment: 1561 case ContextProvider: 1562 case ContextConsumer: 1563 return ''; 1564 1565 default: 1566 var owner = fiber._debugOwner; 1567 var source = fiber._debugSource; 1568 var name = getComponentName(fiber.type); 1569 var ownerName = null; 1570 1571 if (owner) { 1572 ownerName = getComponentName(owner.type); 1573 } 1574 1575 return describeComponentFrame(name, source, ownerName); 1576 } 1577 } 1578 1579 function getStackByFiberInDevAndProd(workInProgress) { 1580 var info = ''; 1581 var node = workInProgress; 1582 1583 do { 1584 info += describeFiber(node); 1585 node = node.return; 1586 } while (node); 1587 1588 return info; 1589 } 1590 var current = null; 1591 var isRendering = false; 1592 function getCurrentFiberOwnerNameInDevOrNull() { 1593 { 1594 if (current === null) { 1595 return null; 1596 } 1597 1598 var owner = current._debugOwner; 1599 1600 if (owner !== null && typeof owner !== 'undefined') { 1601 return getComponentName(owner.type); 1602 } 1603 } 1604 1605 return null; 1606 } 1607 function getCurrentFiberStackInDev() { 1608 { 1609 if (current === null) { 1610 return ''; 1611 } // Safe because if current fiber exists, we are reconciling, 1612 // and it is guaranteed to be the work-in-progress version. 1613 1614 1615 return getStackByFiberInDevAndProd(current); 1616 } 1617 } 1618 function resetCurrentFiber() { 1619 { 1620 ReactDebugCurrentFrame$1.getCurrentStack = null; 1621 current = null; 1622 isRendering = false; 1623 } 1624 } 1625 function setCurrentFiber(fiber) { 1626 { 1627 ReactDebugCurrentFrame$1.getCurrentStack = getCurrentFiberStackInDev; 1628 current = fiber; 1629 isRendering = false; 1630 } 1631 } 1632 function setIsRendering(rendering) { 1633 { 1634 isRendering = rendering; 1635 } 1636 } 1637 1638 // Flow does not allow string concatenation of most non-string types. To work 1639 // around this limitation, we use an opaque type that can only be obtained by 1640 // passing the value through getToStringValue first. 1641 function toString(value) { 1642 return '' + value; 1643 } 1644 function getToStringValue(value) { 1645 switch (typeof value) { 1646 case 'boolean': 1647 case 'number': 1648 case 'object': 1649 case 'string': 1650 case 'undefined': 1651 return value; 1652 1653 default: 1654 // function, symbol are assigned as empty strings 1655 return ''; 1656 } 1657 } 1658 1659 /** 1660 * Copyright (c) 2013-present, Facebook, Inc. 1661 * 1662 * This source code is licensed under the MIT license found in the 1663 * LICENSE file in the root directory of this source tree. 1664 */ 1665 1666 var ReactPropTypesSecret = 'SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED'; 1667 1668 var ReactPropTypesSecret_1 = ReactPropTypesSecret; 1669 1670 var printWarning$1 = function() {}; 1671 1672 { 1673 var ReactPropTypesSecret$1 = ReactPropTypesSecret_1; 1674 var loggedTypeFailures = {}; 1675 var has = Function.call.bind(Object.prototype.hasOwnProperty); 1676 1677 printWarning$1 = function(text) { 1678 var message = 'Warning: ' + text; 1679 if (typeof console !== 'undefined') { 1680 console.error(message); 1681 } 1682 try { 1683 // --- Welcome to debugging React --- 1684 // This error was thrown as a convenience so that you can use this stack 1685 // to find the callsite that caused this warning to fire. 1686 throw new Error(message); 1687 } catch (x) {} 1688 }; 1689 } 1690 1691 /** 1692 * Assert that the values match with the type specs. 1693 * Error messages are memorized and will only be shown once. 1694 * 1695 * @param {object} typeSpecs Map of name to a ReactPropType 1696 * @param {object} values Runtime values that need to be type-checked 1697 * @param {string} location e.g. "prop", "context", "child context" 1698 * @param {string} componentName Name of the component for error messages. 1699 * @param {?Function} getStack Returns the component stack. 1700 * @private 1701 */ 1702 function checkPropTypes(typeSpecs, values, location, componentName, getStack) { 1703 { 1704 for (var typeSpecName in typeSpecs) { 1705 if (has(typeSpecs, typeSpecName)) { 1706 var error; 1707 // Prop type validation may throw. In case they do, we don't want to 1708 // fail the render phase where it didn't fail before. So we log it. 1709 // After these have been cleaned up, we'll let them throw. 1710 try { 1711 // This is intentionally an invariant that gets caught. It's the same 1712 // behavior as without this statement except with a better message. 1713 if (typeof typeSpecs[typeSpecName] !== 'function') { 1714 var err = Error( 1715 (componentName || 'React class') + ': ' + location + ' type `' + typeSpecName + '` is invalid; ' + 1716 'it must be a function, usually from the `prop-types` package, but received `' + typeof typeSpecs[typeSpecName] + '`.' 1717 ); 1718 err.name = 'Invariant Violation'; 1719 throw err; 1720 } 1721 error = typeSpecs[typeSpecName](values, typeSpecName, componentName, location, null, ReactPropTypesSecret$1); 1722 } catch (ex) { 1723 error = ex; 1724 } 1725 if (error && !(error instanceof Error)) { 1726 printWarning$1( 1727 (componentName || 'React class') + ': type specification of ' + 1728 location + ' `' + typeSpecName + '` is invalid; the type checker ' + 1729 'function must return `null` or an `Error` but returned a ' + typeof error + '. ' + 1730 'You may have forgotten to pass an argument to the type checker ' + 1731 'creator (arrayOf, instanceOf, objectOf, oneOf, oneOfType, and ' + 1732 'shape all require an argument).' 1733 ); 1734 } 1735 if (error instanceof Error && !(error.message in loggedTypeFailures)) { 1736 // Only monitor this failure once because there tends to be a lot of the 1737 // same error. 1738 loggedTypeFailures[error.message] = true; 1739 1740 var stack = getStack ? getStack() : ''; 1741 1742 printWarning$1( 1743 'Failed ' + location + ' type: ' + error.message + (stack != null ? stack : '') 1744 ); 1745 } 1746 } 1747 } 1748 } 1749 } 1750 1751 /** 1752 * Resets warning cache when testing. 1753 * 1754 * @private 1755 */ 1756 checkPropTypes.resetWarningCache = function() { 1757 { 1758 loggedTypeFailures = {}; 1759 } 1760 }; 1761 1762 var checkPropTypes_1 = checkPropTypes; 1763 1764 var ReactDebugCurrentFrame$2 = null; 1765 var ReactControlledValuePropTypes = { 1766 checkPropTypes: null 1767 }; 1768 1769 { 1770 ReactDebugCurrentFrame$2 = ReactSharedInternals.ReactDebugCurrentFrame; 1771 var hasReadOnlyValue = { 1772 button: true, 1773 checkbox: true, 1774 image: true, 1775 hidden: true, 1776 radio: true, 1777 reset: true, 1778 submit: true 1779 }; 1780 var propTypes = { 1781 value: function (props, propName, componentName) { 1782 if (hasReadOnlyValue[props.type] || props.onChange || props.readOnly || props.disabled || props[propName] == null || enableDeprecatedFlareAPI ) { 1783 return null; 1784 } 1785 1786 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`.'); 1787 }, 1788 checked: function (props, propName, componentName) { 1789 if (props.onChange || props.readOnly || props.disabled || props[propName] == null || enableDeprecatedFlareAPI ) { 1790 return null; 1791 } 1792 1793 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`.'); 1794 } 1795 }; 1796 /** 1797 * Provide a linked `value` attribute for controlled forms. You should not use 1798 * this outside of the ReactDOM controlled form components. 1799 */ 1800 1801 ReactControlledValuePropTypes.checkPropTypes = function (tagName, props) { 1802 checkPropTypes_1(propTypes, props, 'prop', tagName, ReactDebugCurrentFrame$2.getStackAddendum); 1803 }; 1804 } 1805 1806 function isCheckable(elem) { 1807 var type = elem.type; 1808 var nodeName = elem.nodeName; 1809 return nodeName && nodeName.toLowerCase() === 'input' && (type === 'checkbox' || type === 'radio'); 1810 } 1811 1812 function getTracker(node) { 1813 return node._valueTracker; 1814 } 1815 1816 function detachTracker(node) { 1817 node._valueTracker = null; 1818 } 1819 1820 function getValueFromNode(node) { 1821 var value = ''; 1822 1823 if (!node) { 1824 return value; 1825 } 1826 1827 if (isCheckable(node)) { 1828 value = node.checked ? 'true' : 'false'; 1829 } else { 1830 value = node.value; 1831 } 1832 1833 return value; 1834 } 1835 1836 function trackValueOnNode(node) { 1837 var valueField = isCheckable(node) ? 'checked' : 'value'; 1838 var descriptor = Object.getOwnPropertyDescriptor(node.constructor.prototype, valueField); 1839 var currentValue = '' + node[valueField]; // if someone has already defined a value or Safari, then bail 1840 // and don't track value will cause over reporting of changes, 1841 // but it's better then a hard failure 1842 // (needed for certain tests that spyOn input values and Safari) 1843 1844 if (node.hasOwnProperty(valueField) || typeof descriptor === 'undefined' || typeof descriptor.get !== 'function' || typeof descriptor.set !== 'function') { 1845 return; 1846 } 1847 1848 var get = descriptor.get, 1849 set = descriptor.set; 1850 Object.defineProperty(node, valueField, { 1851 configurable: true, 1852 get: function () { 1853 return get.call(this); 1854 }, 1855 set: function (value) { 1856 currentValue = '' + value; 1857 set.call(this, value); 1858 } 1859 }); // We could've passed this the first time 1860 // but it triggers a bug in IE11 and Edge 14/15. 1861 // Calling defineProperty() again should be equivalent. 1862 // https://github.com/facebook/react/issues/11768 1863 1864 Object.defineProperty(node, valueField, { 1865 enumerable: descriptor.enumerable 1866 }); 1867 var tracker = { 1868 getValue: function () { 1869 return currentValue; 1870 }, 1871 setValue: function (value) { 1872 currentValue = '' + value; 1873 }, 1874 stopTracking: function () { 1875 detachTracker(node); 1876 delete node[valueField]; 1877 } 1878 }; 1879 return tracker; 1880 } 1881 1882 function track(node) { 1883 if (getTracker(node)) { 1884 return; 1885 } // TODO: Once it's just Fiber we can move this to node._wrapperState 1886 1887 1888 node._valueTracker = trackValueOnNode(node); 1889 } 1890 function updateValueIfChanged(node) { 1891 if (!node) { 1892 return false; 1893 } 1894 1895 var tracker = getTracker(node); // if there is no tracker at this point it's unlikely 1896 // that trying again will succeed 1897 1898 if (!tracker) { 1899 return true; 1900 } 1901 1902 var lastValue = tracker.getValue(); 1903 var nextValue = getValueFromNode(node); 1904 1905 if (nextValue !== lastValue) { 1906 tracker.setValue(nextValue); 1907 return true; 1908 } 1909 1910 return false; 1911 } 1912 1913 var didWarnValueDefaultValue = false; 1914 var didWarnCheckedDefaultChecked = false; 1915 var didWarnControlledToUncontrolled = false; 1916 var didWarnUncontrolledToControlled = false; 1917 1918 function isControlled(props) { 1919 var usesChecked = props.type === 'checkbox' || props.type === 'radio'; 1920 return usesChecked ? props.checked != null : props.value != null; 1921 } 1922 /** 1923 * Implements an <input> host component that allows setting these optional 1924 * props: `checked`, `value`, `defaultChecked`, and `defaultValue`. 1925 * 1926 * If `checked` or `value` are not supplied (or null/undefined), user actions 1927 * that affect the checked state or value will trigger updates to the element. 1928 * 1929 * If they are supplied (and not null/undefined), the rendered element will not 1930 * trigger updates to the element. Instead, the props must change in order for 1931 * the rendered element to be updated. 1932 * 1933 * The rendered element will be initialized as unchecked (or `defaultChecked`) 1934 * with an empty value (or `defaultValue`). 1935 * 1936 * See http://www.w3.org/TR/2012/WD-html5-20121025/the-input-element.html 1937 */ 1938 1939 1940 function getHostProps(element, props) { 1941 var node = element; 1942 var checked = props.checked; 1943 1944 var hostProps = _assign({}, props, { 1945 defaultChecked: undefined, 1946 defaultValue: undefined, 1947 value: undefined, 1948 checked: checked != null ? checked : node._wrapperState.initialChecked 1949 }); 1950 1951 return hostProps; 1952 } 1953 function initWrapperState(element, props) { 1954 { 1955 ReactControlledValuePropTypes.checkPropTypes('input', props); 1956 1957 if (props.checked !== undefined && props.defaultChecked !== undefined && !didWarnCheckedDefaultChecked) { 1958 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://fb.me/react-controlled-components', getCurrentFiberOwnerNameInDevOrNull() || 'A component', props.type); 1959 1960 didWarnCheckedDefaultChecked = true; 1961 } 1962 1963 if (props.value !== undefined && props.defaultValue !== undefined && !didWarnValueDefaultValue) { 1964 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://fb.me/react-controlled-components', getCurrentFiberOwnerNameInDevOrNull() || 'A component', props.type); 1965 1966 didWarnValueDefaultValue = true; 1967 } 1968 } 1969 1970 var node = element; 1971 var defaultValue = props.defaultValue == null ? '' : props.defaultValue; 1972 node._wrapperState = { 1973 initialChecked: props.checked != null ? props.checked : props.defaultChecked, 1974 initialValue: getToStringValue(props.value != null ? props.value : defaultValue), 1975 controlled: isControlled(props) 1976 }; 1977 } 1978 function updateChecked(element, props) { 1979 var node = element; 1980 var checked = props.checked; 1981 1982 if (checked != null) { 1983 setValueForProperty(node, 'checked', checked, false); 1984 } 1985 } 1986 function updateWrapper(element, props) { 1987 var node = element; 1988 1989 { 1990 var controlled = isControlled(props); 1991 1992 if (!node._wrapperState.controlled && controlled && !didWarnUncontrolledToControlled) { 1993 error('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', props.type); 1994 1995 didWarnUncontrolledToControlled = true; 1996 } 1997 1998 if (node._wrapperState.controlled && !controlled && !didWarnControlledToUncontrolled) { 1999 error('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', props.type); 2000 2001 didWarnControlledToUncontrolled = true; 2002 } 2003 } 2004 2005 updateChecked(element, props); 2006 var value = getToStringValue(props.value); 2007 var type = props.type; 2008 2009 if (value != null) { 2010 if (type === 'number') { 2011 if (value === 0 && node.value === '' || // We explicitly want to coerce to number here if possible. 2012 // eslint-disable-next-line 2013 node.value != value) { 2014 node.value = toString(value); 2015 } 2016 } else if (node.value !== toString(value)) { 2017 node.value = toString(value); 2018 } 2019 } else if (type === 'submit' || type === 'reset') { 2020 // Submit/reset inputs need the attribute removed completely to avoid 2021 // blank-text buttons. 2022 node.removeAttribute('value'); 2023 return; 2024 } 2025 2026 { 2027 // When syncing the value attribute, the value comes from a cascade of 2028 // properties: 2029 // 1. The value React property 2030 // 2. The defaultValue React property 2031 // 3. Otherwise there should be no change 2032 if (props.hasOwnProperty('value')) { 2033 setDefaultValue(node, props.type, value); 2034 } else if (props.hasOwnProperty('defaultValue')) { 2035 setDefaultValue(node, props.type, getToStringValue(props.defaultValue)); 2036 } 2037 } 2038 2039 { 2040 // When syncing the checked attribute, it only changes when it needs 2041 // to be removed, such as transitioning from a checkbox into a text input 2042 if (props.checked == null && props.defaultChecked != null) { 2043 node.defaultChecked = !!props.defaultChecked; 2044 } 2045 } 2046 } 2047 function postMountWrapper(element, props, isHydrating) { 2048 var node = element; // Do not assign value if it is already set. This prevents user text input 2049 // from being lost during SSR hydration. 2050 2051 if (props.hasOwnProperty('value') || props.hasOwnProperty('defaultValue')) { 2052 var type = props.type; 2053 var isButton = type === 'submit' || type === 'reset'; // Avoid setting value attribute on submit/reset inputs as it overrides the 2054 // default value provided by the browser. See: #12872 2055 2056 if (isButton && (props.value === undefined || props.value === null)) { 2057 return; 2058 } 2059 2060 var initialValue = toString(node._wrapperState.initialValue); // Do not assign value if it is already set. This prevents user text input 2061 // from being lost during SSR hydration. 2062 2063 if (!isHydrating) { 2064 { 2065 // When syncing the value attribute, the value property should use 2066 // the wrapperState._initialValue property. This uses: 2067 // 2068 // 1. The value React property when present 2069 // 2. The defaultValue React property when present 2070 // 3. An empty string 2071 if (initialValue !== node.value) { 2072 node.value = initialValue; 2073 } 2074 } 2075 } 2076 2077 { 2078 // Otherwise, the value attribute is synchronized to the property, 2079 // so we assign defaultValue to the same thing as the value property 2080 // assignment step above. 2081 node.defaultValue = initialValue; 2082 } 2083 } // Normally, we'd just do `node.checked = node.checked` upon initial mount, less this bug 2084 // this is needed to work around a chrome bug where setting defaultChecked 2085 // will sometimes influence the value of checked (even after detachment). 2086 // Reference: https://bugs.chromium.org/p/chromium/issues/detail?id=608416 2087 // We need to temporarily unset name to avoid disrupting radio button groups. 2088 2089 2090 var name = node.name; 2091 2092 if (name !== '') { 2093 node.name = ''; 2094 } 2095 2096 { 2097 // When syncing the checked attribute, both the checked property and 2098 // attribute are assigned at the same time using defaultChecked. This uses: 2099 // 2100 // 1. The checked React property when present 2101 // 2. The defaultChecked React property when present 2102 // 3. Otherwise, false 2103 node.defaultChecked = !node.defaultChecked; 2104 node.defaultChecked = !!node._wrapperState.initialChecked; 2105 } 2106 2107 if (name !== '') { 2108 node.name = name; 2109 } 2110 } 2111 function restoreControlledState(element, props) { 2112 var node = element; 2113 updateWrapper(node, props); 2114 updateNamedCousins(node, props); 2115 } 2116 2117 function updateNamedCousins(rootNode, props) { 2118 var name = props.name; 2119 2120 if (props.type === 'radio' && name != null) { 2121 var queryRoot = rootNode; 2122 2123 while (queryRoot.parentNode) { 2124 queryRoot = queryRoot.parentNode; 2125 } // If `rootNode.form` was non-null, then we could try `form.elements`, 2126 // but that sometimes behaves strangely in IE8. We could also try using 2127 // `form.getElementsByName`, but that will only return direct children 2128 // and won't include inputs that use the HTML5 `form=` attribute. Since 2129 // the input might not even be in a form. It might not even be in the 2130 // document. Let's just use the local `querySelectorAll` to ensure we don't 2131 // miss anything. 2132 2133 2134 var group = queryRoot.querySelectorAll('input[name=' + JSON.stringify('' + name) + '][type="radio"]'); 2135 2136 for (var i = 0; i < group.length; i++) { 2137 var otherNode = group[i]; 2138 2139 if (otherNode === rootNode || otherNode.form !== rootNode.form) { 2140 continue; 2141 } // This will throw if radio buttons rendered by different copies of React 2142 // and the same name are rendered into the same form (same as #1939). 2143 // That's probably okay; we don't support it just as we don't support 2144 // mixing React radio buttons with non-React ones. 2145 2146 2147 var otherProps = getFiberCurrentPropsFromNode$1(otherNode); 2148 2149 if (!otherProps) { 2150 { 2151 throw Error( "ReactDOMInput: Mixing React and non-React radio inputs with the same `name` is not supported." ); 2152 } 2153 } // We need update the tracked value on the named cousin since the value 2154 // was changed but the input saw no event or value set 2155 2156 2157 updateValueIfChanged(otherNode); // If this is a controlled radio button group, forcing the input that 2158 // was previously checked to update will cause it to be come re-checked 2159 // as appropriate. 2160 2161 updateWrapper(otherNode, otherProps); 2162 } 2163 } 2164 } // In Chrome, assigning defaultValue to certain input types triggers input validation. 2165 // For number inputs, the display value loses trailing decimal points. For email inputs, 2166 // Chrome raises "The specified value <x> is not a valid email address". 2167 // 2168 // Here we check to see if the defaultValue has actually changed, avoiding these problems 2169 // when the user is inputting text 2170 // 2171 // https://github.com/facebook/react/issues/7253 2172 2173 2174 function setDefaultValue(node, type, value) { 2175 if ( // Focused number inputs synchronize on blur. See ChangeEventPlugin.js 2176 type !== 'number' || node.ownerDocument.activeElement !== node) { 2177 if (value == null) { 2178 node.defaultValue = toString(node._wrapperState.initialValue); 2179 } else if (node.defaultValue !== toString(value)) { 2180 node.defaultValue = toString(value); 2181 } 2182 } 2183 } 2184 2185 var didWarnSelectedSetOnOption = false; 2186 var didWarnInvalidChild = false; 2187 2188 function flattenChildren(children) { 2189 var content = ''; // Flatten children. We'll warn if they are invalid 2190 // during validateProps() which runs for hydration too. 2191 // Note that this would throw on non-element objects. 2192 // Elements are stringified (which is normally irrelevant 2193 // but matters for <fbt>). 2194 2195 React.Children.forEach(children, function (child) { 2196 if (child == null) { 2197 return; 2198 } 2199 2200 content += child; // Note: we don't warn about invalid children here. 2201 // Instead, this is done separately below so that 2202 // it happens during the hydration codepath too. 2203 }); 2204 return content; 2205 } 2206 /** 2207 * Implements an <option> host component that warns when `selected` is set. 2208 */ 2209 2210 2211 function validateProps(element, props) { 2212 { 2213 // This mirrors the codepath above, but runs for hydration too. 2214 // Warn about invalid children here so that client and hydration are consistent. 2215 // TODO: this seems like it could cause a DEV-only throw for hydration 2216 // if children contains a non-element object. We should try to avoid that. 2217 if (typeof props.children === 'object' && props.children !== null) { 2218 React.Children.forEach(props.children, function (child) { 2219 if (child == null) { 2220 return; 2221 } 2222 2223 if (typeof child === 'string' || typeof child === 'number') { 2224 return; 2225 } 2226 2227 if (typeof child.type !== 'string') { 2228 return; 2229 } 2230 2231 if (!didWarnInvalidChild) { 2232 didWarnInvalidChild = true; 2233 2234 error('Only strings and numbers are supported as <option> children.'); 2235 } 2236 }); 2237 } // TODO: Remove support for `selected` in <option>. 2238 2239 2240 if (props.selected != null && !didWarnSelectedSetOnOption) { 2241 error('Use the `defaultValue` or `value` props on <select> instead of ' + 'setting `selected` on <option>.'); 2242 2243 didWarnSelectedSetOnOption = true; 2244 } 2245 } 2246 } 2247 function postMountWrapper$1(element, props) { 2248 // value="" should make a value attribute (#6219) 2249 if (props.value != null) { 2250 element.setAttribute('value', toString(getToStringValue(props.value))); 2251 } 2252 } 2253 function getHostProps$1(element, props) { 2254 var hostProps = _assign({ 2255 children: undefined 2256 }, props); 2257 2258 var content = flattenChildren(props.children); 2259 2260 if (content) { 2261 hostProps.children = content; 2262 } 2263 2264 return hostProps; 2265 } 2266 2267 var didWarnValueDefaultValue$1; 2268 2269 { 2270 didWarnValueDefaultValue$1 = false; 2271 } 2272 2273 function getDeclarationErrorAddendum() { 2274 var ownerName = getCurrentFiberOwnerNameInDevOrNull(); 2275 2276 if (ownerName) { 2277 return '\n\nCheck the render method of `' + ownerName + '`.'; 2278 } 2279 2280 return ''; 2281 } 2282 2283 var valuePropNames = ['value', 'defaultValue']; 2284 /** 2285 * Validation function for `value` and `defaultValue`. 2286 */ 2287 2288 function checkSelectPropTypes(props) { 2289 { 2290 ReactControlledValuePropTypes.checkPropTypes('select', props); 2291 2292 for (var i = 0; i < valuePropNames.length; i++) { 2293 var propName = valuePropNames[i]; 2294 2295 if (props[propName] == null) { 2296 continue; 2297 } 2298 2299 var isArray = Array.isArray(props[propName]); 2300 2301 if (props.multiple && !isArray) { 2302 error('The `%s` prop supplied to <select> must be an array if ' + '`multiple` is true.%s', propName, getDeclarationErrorAddendum()); 2303 } else if (!props.multiple && isArray) { 2304 error('The `%s` prop supplied to <select> must be a scalar ' + 'value if `multiple` is false.%s', propName, getDeclarationErrorAddendum()); 2305 } 2306 } 2307 } 2308 } 2309 2310 function updateOptions(node, multiple, propValue, setDefaultSelected) { 2311 var options = node.options; 2312 2313 if (multiple) { 2314 var selectedValues = propValue; 2315 var selectedValue = {}; 2316 2317 for (var i = 0; i < selectedValues.length; i++) { 2318 // Prefix to avoid chaos with special keys. 2319 selectedValue['$' + selectedValues[i]] = true; 2320 } 2321 2322 for (var _i = 0; _i < options.length; _i++) { 2323 var selected = selectedValue.hasOwnProperty('$' + options[_i].value); 2324 2325 if (options[_i].selected !== selected) { 2326 options[_i].selected = selected; 2327 } 2328 2329 if (selected && setDefaultSelected) { 2330 options[_i].defaultSelected = true; 2331 } 2332 } 2333 } else { 2334 // Do not set `select.value` as exact behavior isn't consistent across all 2335 // browsers for all cases. 2336 var _selectedValue = toString(getToStringValue(propValue)); 2337 2338 var defaultSelected = null; 2339 2340 for (var _i2 = 0; _i2 < options.length; _i2++) { 2341 if (options[_i2].value === _selectedValue) { 2342 options[_i2].selected = true; 2343 2344 if (setDefaultSelected) { 2345 options[_i2].defaultSelected = true; 2346 } 2347 2348 return; 2349 } 2350 2351 if (defaultSelected === null && !options[_i2].disabled) { 2352 defaultSelected = options[_i2]; 2353 } 2354 } 2355 2356 if (defaultSelected !== null) { 2357 defaultSelected.selected = true; 2358 } 2359 } 2360 } 2361 /** 2362 * Implements a <select> host component that allows optionally setting the 2363 * props `value` and `defaultValue`. If `multiple` is false, the prop must be a 2364 * stringable. If `multiple` is true, the prop must be an array of stringables. 2365 * 2366 * If `value` is not supplied (or null/undefined), user actions that change the 2367 * selected option will trigger updates to the rendered options. 2368 * 2369 * If it is supplied (and not null/undefined), the rendered options will not 2370 * update in response to user actions. Instead, the `value` prop must change in 2371 * order for the rendered options to update. 2372 * 2373 * If `defaultValue` is provided, any options with the supplied values will be 2374 * selected. 2375 */ 2376 2377 2378 function getHostProps$2(element, props) { 2379 return _assign({}, props, { 2380 value: undefined 2381 }); 2382 } 2383 function initWrapperState$1(element, props) { 2384 var node = element; 2385 2386 { 2387 checkSelectPropTypes(props); 2388 } 2389 2390 node._wrapperState = { 2391 wasMultiple: !!props.multiple 2392 }; 2393 2394 { 2395 if (props.value !== undefined && props.defaultValue !== undefined && !didWarnValueDefaultValue$1) { 2396 error('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'); 2397 2398 didWarnValueDefaultValue$1 = true; 2399 } 2400 } 2401 } 2402 function postMountWrapper$2(element, props) { 2403 var node = element; 2404 node.multiple = !!props.multiple; 2405 var value = props.value; 2406 2407 if (value != null) { 2408 updateOptions(node, !!props.multiple, value, false); 2409 } else if (props.defaultValue != null) { 2410 updateOptions(node, !!props.multiple, props.defaultValue, true); 2411 } 2412 } 2413 function postUpdateWrapper(element, props) { 2414 var node = element; 2415 var wasMultiple = node._wrapperState.wasMultiple; 2416 node._wrapperState.wasMultiple = !!props.multiple; 2417 var value = props.value; 2418 2419 if (value != null) { 2420 updateOptions(node, !!props.multiple, value, false); 2421 } else if (wasMultiple !== !!props.multiple) { 2422 // For simplicity, reapply `defaultValue` if `multiple` is toggled. 2423 if (props.defaultValue != null) { 2424 updateOptions(node, !!props.multiple, props.defaultValue, true); 2425 } else { 2426 // Revert the select back to its default unselected state. 2427 updateOptions(node, !!props.multiple, props.multiple ? [] : '', false); 2428 } 2429 } 2430 } 2431 function restoreControlledState$1(element, props) { 2432 var node = element; 2433 var value = props.value; 2434 2435 if (value != null) { 2436 updateOptions(node, !!props.multiple, value, false); 2437 } 2438 } 2439 2440 var didWarnValDefaultVal = false; 2441 2442 /** 2443 * Implements a <textarea> host component that allows setting `value`, and 2444 * `defaultValue`. This differs from the traditional DOM API because value is 2445 * usually set as PCDATA children. 2446 * 2447 * If `value` is not supplied (or null/undefined), user actions that affect the 2448 * value will trigger updates to the element. 2449 * 2450 * If `value` is supplied (and not null/undefined), the rendered element will 2451 * not trigger updates to the element. Instead, the `value` prop must change in 2452 * order for the rendered element to be updated. 2453 * 2454 * The rendered element will be initialized with an empty value, the prop 2455 * `defaultValue` if specified, or the children content (deprecated). 2456 */ 2457 function getHostProps$3(element, props) { 2458 var node = element; 2459 2460 if (!(props.dangerouslySetInnerHTML == null)) { 2461 { 2462 throw Error( "`dangerouslySetInnerHTML` does not make sense on <textarea>." ); 2463 } 2464 } // Always set children to the same thing. In IE9, the selection range will 2465 // get reset if `textContent` is mutated. We could add a check in setTextContent 2466 // to only set the value if/when the value differs from the node value (which would 2467 // completely solve this IE9 bug), but Sebastian+Sophie seemed to like this 2468 // solution. The value can be a boolean or object so that's why it's forced 2469 // to be a string. 2470 2471 2472 var hostProps = _assign({}, props, { 2473 value: undefined, 2474 defaultValue: undefined, 2475 children: toString(node._wrapperState.initialValue) 2476 }); 2477 2478 return hostProps; 2479 } 2480 function initWrapperState$2(element, props) { 2481 var node = element; 2482 2483 { 2484 ReactControlledValuePropTypes.checkPropTypes('textarea', props); 2485 2486 if (props.value !== undefined && props.defaultValue !== undefined && !didWarnValDefaultVal) { 2487 error('%s contains a textarea with both value and defaultValue props. ' + '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', getCurrentFiberOwnerNameInDevOrNull() || 'A component'); 2488 2489 didWarnValDefaultVal = true; 2490 } 2491 } 2492 2493 var initialValue = props.value; // Only bother fetching default value if we're going to use it 2494 2495 if (initialValue == null) { 2496 var children = props.children, 2497 defaultValue = props.defaultValue; 2498 2499 if (children != null) { 2500 { 2501 error('Use the `defaultValue` or `value` props instead of setting ' + 'children on <textarea>.'); 2502 } 2503 2504 { 2505 if (!(defaultValue == null)) { 2506 { 2507 throw Error( "If you supply `defaultValue` on a <textarea>, do not pass children." ); 2508 } 2509 } 2510 2511 if (Array.isArray(children)) { 2512 if (!(children.length <= 1)) { 2513 { 2514 throw Error( "<textarea> can only have at most one child." ); 2515 } 2516 } 2517 2518 children = children[0]; 2519 } 2520 2521 defaultValue = children; 2522 } 2523 } 2524 2525 if (defaultValue == null) { 2526 defaultValue = ''; 2527 } 2528 2529 initialValue = defaultValue; 2530 } 2531 2532 node._wrapperState = { 2533 initialValue: getToStringValue(initialValue) 2534 }; 2535 } 2536 function updateWrapper$1(element, props) { 2537 var node = element; 2538 var value = getToStringValue(props.value); 2539 var defaultValue = getToStringValue(props.defaultValue); 2540 2541 if (value != null) { 2542 // Cast `value` to a string to ensure the value is set correctly. While 2543 // browsers typically do this as necessary, jsdom doesn't. 2544 var newValue = toString(value); // To avoid side effects (such as losing text selection), only set value if changed 2545 2546 if (newValue !== node.value) { 2547 node.value = newValue; 2548 } 2549 2550 if (props.defaultValue == null && node.defaultValue !== newValue) { 2551 node.defaultValue = newValue; 2552 } 2553 } 2554 2555 if (defaultValue != null) { 2556 node.defaultValue = toString(defaultValue); 2557 } 2558 } 2559 function postMountWrapper$3(element, props) { 2560 var node = element; // This is in postMount because we need access to the DOM node, which is not 2561 // available until after the component has mounted. 2562 2563 var textContent = node.textContent; // Only set node.value if textContent is equal to the expected 2564 // initial value. In IE10/IE11 there is a bug where the placeholder attribute 2565 // will populate textContent as well. 2566 // https://developer.microsoft.com/microsoft-edge/platform/issues/101525/ 2567 2568 if (textContent === node._wrapperState.initialValue) { 2569 if (textContent !== '' && textContent !== null) { 2570 node.value = textContent; 2571 } 2572 } 2573 } 2574 function restoreControlledState$2(element, props) { 2575 // DOM component is still mounted; update 2576 updateWrapper$1(element, props); 2577 } 2578 2579 var HTML_NAMESPACE = 'http://www.w3.org/1999/xhtml'; 2580 var MATH_NAMESPACE = 'http://www.w3.org/1998/Math/MathML'; 2581 var SVG_NAMESPACE = 'http://www.w3.org/2000/svg'; 2582 var Namespaces = { 2583 html: HTML_NAMESPACE, 2584 mathml: MATH_NAMESPACE, 2585 svg: SVG_NAMESPACE 2586 }; // Assumes there is no parent namespace. 2587 2588 function getIntrinsicNamespace(type) { 2589 switch (type) { 2590 case 'svg': 2591 return SVG_NAMESPACE; 2592 2593 case 'math': 2594 return MATH_NAMESPACE; 2595 2596 default: 2597 return HTML_NAMESPACE; 2598 } 2599 } 2600 function getChildNamespace(parentNamespace, type) { 2601 if (parentNamespace == null || parentNamespace === HTML_NAMESPACE) { 2602 // No (or default) parent namespace: potential entry point. 2603 return getIntrinsicNamespace(type); 2604 } 2605 2606 if (parentNamespace === SVG_NAMESPACE && type === 'foreignObject') { 2607 // We're leaving SVG. 2608 return HTML_NAMESPACE; 2609 } // By default, pass namespace below. 2610 2611 2612 return parentNamespace; 2613 } 2614 2615 /* globals MSApp */ 2616 2617 /** 2618 * Create a function which has 'unsafe' privileges (required by windows8 apps) 2619 */ 2620 var createMicrosoftUnsafeLocalFunction = function (func) { 2621 if (typeof MSApp !== 'undefined' && MSApp.execUnsafeLocalFunction) { 2622 return function (arg0, arg1, arg2, arg3) { 2623 MSApp.execUnsafeLocalFunction(function () { 2624 return func(arg0, arg1, arg2, arg3); 2625 }); 2626 }; 2627 } else { 2628 return func; 2629 } 2630 }; 2631 2632 var reusableSVGContainer; 2633 /** 2634 * Set the innerHTML property of a node 2635 * 2636 * @param {DOMElement} node 2637 * @param {string} html 2638 * @internal 2639 */ 2640 2641 var setInnerHTML = createMicrosoftUnsafeLocalFunction(function (node, html) { 2642 if (node.namespaceURI === Namespaces.svg) { 2643 2644 if (!('innerHTML' in node)) { 2645 // IE does not have innerHTML for SVG nodes, so instead we inject the 2646 // new markup in a temp node and then move the child nodes across into 2647 // the target node 2648 reusableSVGContainer = reusableSVGContainer || document.createElement('div'); 2649 reusableSVGContainer.innerHTML = '<svg>' + html.valueOf().toString() + '</svg>'; 2650 var svgNode = reusableSVGContainer.firstChild; 2651 2652 while (node.firstChild) { 2653 node.removeChild(node.firstChild); 2654 } 2655 2656 while (svgNode.firstChild) { 2657 node.appendChild(svgNode.firstChild); 2658 } 2659 2660 return; 2661 } 2662 } 2663 2664 node.innerHTML = html; 2665 }); 2666 2667 /** 2668 * HTML nodeType values that represent the type of the node 2669 */ 2670 var ELEMENT_NODE = 1; 2671 var TEXT_NODE = 3; 2672 var COMMENT_NODE = 8; 2673 var DOCUMENT_NODE = 9; 2674 var DOCUMENT_FRAGMENT_NODE = 11; 2675 2676 /** 2677 * Set the textContent property of a node. For text updates, it's faster 2678 * to set the `nodeValue` of the Text node directly instead of using 2679 * `.textContent` which will remove the existing node and create a new one. 2680 * 2681 * @param {DOMElement} node 2682 * @param {string} text 2683 * @internal 2684 */ 2685 2686 var setTextContent = function (node, text) { 2687 if (text) { 2688 var firstChild = node.firstChild; 2689 2690 if (firstChild && firstChild === node.lastChild && firstChild.nodeType === TEXT_NODE) { 2691 firstChild.nodeValue = text; 2692 return; 2693 } 2694 } 2695 2696 node.textContent = text; 2697 }; 2698 2699 // Do not use the below two methods directly! 2700 // Instead use constants exported from DOMTopLevelEventTypes in ReactDOM. 2701 // (It is the only module that is allowed to access these methods.) 2702 function unsafeCastStringToDOMTopLevelType(topLevelType) { 2703 return topLevelType; 2704 } 2705 function unsafeCastDOMTopLevelTypeToString(topLevelType) { 2706 return topLevelType; 2707 } 2708 2709 /** 2710 * Generate a mapping of standard vendor prefixes using the defined style property and event name. 2711 * 2712 * @param {string} styleProp 2713 * @param {string} eventName 2714 * @returns {object} 2715 */ 2716 2717 function makePrefixMap(styleProp, eventName) { 2718 var prefixes = {}; 2719 prefixes[styleProp.toLowerCase()] = eventName.toLowerCase(); 2720 prefixes['Webkit' + styleProp] = 'webkit' + eventName; 2721 prefixes['Moz' + styleProp] = 'moz' + eventName; 2722 return prefixes; 2723 } 2724 /** 2725 * A list of event names to a configurable list of vendor prefixes. 2726 */ 2727 2728 2729 var vendorPrefixes = { 2730 animationend: makePrefixMap('Animation', 'AnimationEnd'), 2731 animationiteration: makePrefixMap('Animation', 'AnimationIteration'), 2732 animationstart: makePrefixMap('Animation', 'AnimationStart'), 2733 transitionend: makePrefixMap('Transition', 'TransitionEnd') 2734 }; 2735 /** 2736 * Event names that have already been detected and prefixed (if applicable). 2737 */ 2738 2739 var prefixedEventNames = {}; 2740 /** 2741 * Element to check for prefixes on. 2742 */ 2743 2744 var style = {}; 2745 /** 2746 * Bootstrap if a DOM exists. 2747 */ 2748 2749 if (canUseDOM) { 2750 style = document.createElement('div').style; // On some platforms, in particular some releases of Android 4.x, 2751 // the un-prefixed "animation" and "transition" properties are defined on the 2752 // style object but the events that fire will still be prefixed, so we need 2753 // to check if the un-prefixed events are usable, and if not remove them from the map. 2754 2755 if (!('AnimationEvent' in window)) { 2756 delete vendorPrefixes.animationend.animation; 2757 delete vendorPrefixes.animationiteration.animation; 2758 delete vendorPrefixes.animationstart.animation; 2759 } // Same as above 2760 2761 2762 if (!('TransitionEvent' in window)) { 2763 delete vendorPrefixes.transitionend.transition; 2764 } 2765 } 2766 /** 2767 * Attempts to determine the correct vendor prefixed event name. 2768 * 2769 * @param {string} eventName 2770 * @returns {string} 2771 */ 2772 2773 2774 function getVendorPrefixedEventName(eventName) { 2775 if (prefixedEventNames[eventName]) { 2776 return prefixedEventNames[eventName]; 2777 } else if (!vendorPrefixes[eventName]) { 2778 return eventName; 2779 } 2780 2781 var prefixMap = vendorPrefixes[eventName]; 2782 2783 for (var styleProp in prefixMap) { 2784 if (prefixMap.hasOwnProperty(styleProp) && styleProp in style) { 2785 return prefixedEventNames[eventName] = prefixMap[styleProp]; 2786 } 2787 } 2788 2789 return eventName; 2790 } 2791 2792 /** 2793 * To identify top level events in ReactDOM, we use constants defined by this 2794 * module. This is the only module that uses the unsafe* methods to express 2795 * that the constants actually correspond to the browser event names. This lets 2796 * us save some bundle size by avoiding a top level type -> event name map. 2797 * The rest of ReactDOM code should import top level types from this file. 2798 */ 2799 2800 var TOP_ABORT = unsafeCastStringToDOMTopLevelType('abort'); 2801 var TOP_ANIMATION_END = unsafeCastStringToDOMTopLevelType(getVendorPrefixedEventName('animationend')); 2802 var TOP_ANIMATION_ITERATION = unsafeCastStringToDOMTopLevelType(getVendorPrefixedEventName('animationiteration')); 2803 var TOP_ANIMATION_START = unsafeCastStringToDOMTopLevelType(getVendorPrefixedEventName('animationstart')); 2804 var TOP_BLUR = unsafeCastStringToDOMTopLevelType('blur'); 2805 var TOP_CAN_PLAY = unsafeCastStringToDOMTopLevelType('canplay'); 2806 var TOP_CAN_PLAY_THROUGH = unsafeCastStringToDOMTopLevelType('canplaythrough'); 2807 var TOP_CANCEL = unsafeCastStringToDOMTopLevelType('cancel'); 2808 var TOP_CHANGE = unsafeCastStringToDOMTopLevelType('change'); 2809 var TOP_CLICK = unsafeCastStringToDOMTopLevelType('click'); 2810 var TOP_CLOSE = unsafeCastStringToDOMTopLevelType('close'); 2811 var TOP_COMPOSITION_END = unsafeCastStringToDOMTopLevelType('compositionend'); 2812 var TOP_COMPOSITION_START = unsafeCastStringToDOMTopLevelType('compositionstart'); 2813 var TOP_COMPOSITION_UPDATE = unsafeCastStringToDOMTopLevelType('compositionupdate'); 2814 var TOP_CONTEXT_MENU = unsafeCastStringToDOMTopLevelType('contextmenu'); 2815 var TOP_COPY = unsafeCastStringToDOMTopLevelType('copy'); 2816 var TOP_CUT = unsafeCastStringToDOMTopLevelType('cut'); 2817 var TOP_DOUBLE_CLICK = unsafeCastStringToDOMTopLevelType('dblclick'); 2818 var TOP_AUX_CLICK = unsafeCastStringToDOMTopLevelType('auxclick'); 2819 var TOP_DRAG = unsafeCastStringToDOMTopLevelType('drag'); 2820 var TOP_DRAG_END = unsafeCastStringToDOMTopLevelType('dragend'); 2821 var TOP_DRAG_ENTER = unsafeCastStringToDOMTopLevelType('dragenter'); 2822 var TOP_DRAG_EXIT = unsafeCastStringToDOMTopLevelType('dragexit'); 2823 var TOP_DRAG_LEAVE = unsafeCastStringToDOMTopLevelType('dragleave'); 2824 var TOP_DRAG_OVER = unsafeCastStringToDOMTopLevelType('dragover'); 2825 var TOP_DRAG_START = unsafeCastStringToDOMTopLevelType('dragstart'); 2826 var TOP_DROP = unsafeCastStringToDOMTopLevelType('drop'); 2827 var TOP_DURATION_CHANGE = unsafeCastStringToDOMTopLevelType('durationchange'); 2828 var TOP_EMPTIED = unsafeCastStringToDOMTopLevelType('emptied'); 2829 var TOP_ENCRYPTED = unsafeCastStringToDOMTopLevelType('encrypted'); 2830 var TOP_ENDED = unsafeCastStringToDOMTopLevelType('ended'); 2831 var TOP_ERROR = unsafeCastStringToDOMTopLevelType('error'); 2832 var TOP_FOCUS = unsafeCastStringToDOMTopLevelType('focus'); 2833 var TOP_GOT_POINTER_CAPTURE = unsafeCastStringToDOMTopLevelType('gotpointercapture'); 2834 var TOP_INPUT = unsafeCastStringToDOMTopLevelType('input'); 2835 var TOP_INVALID = unsafeCastStringToDOMTopLevelType('invalid'); 2836 var TOP_KEY_DOWN = unsafeCastStringToDOMTopLevelType('keydown'); 2837 var TOP_KEY_PRESS = unsafeCastStringToDOMTopLevelType('keypress'); 2838 var TOP_KEY_UP = unsafeCastStringToDOMTopLevelType('keyup'); 2839 var TOP_LOAD = unsafeCastStringToDOMTopLevelType('load'); 2840 var TOP_LOAD_START = unsafeCastStringToDOMTopLevelType('loadstart'); 2841 var TOP_LOADED_DATA = unsafeCastStringToDOMTopLevelType('loadeddata'); 2842 var TOP_LOADED_METADATA = unsafeCastStringToDOMTopLevelType('loadedmetadata'); 2843 var TOP_LOST_POINTER_CAPTURE = unsafeCastStringToDOMTopLevelType('lostpointercapture'); 2844 var TOP_MOUSE_DOWN = unsafeCastStringToDOMTopLevelType('mousedown'); 2845 var TOP_MOUSE_MOVE = unsafeCastStringToDOMTopLevelType('mousemove'); 2846 var TOP_MOUSE_OUT = unsafeCastStringToDOMTopLevelType('mouseout'); 2847 var TOP_MOUSE_OVER = unsafeCastStringToDOMTopLevelType('mouseover'); 2848 var TOP_MOUSE_UP = unsafeCastStringToDOMTopLevelType('mouseup'); 2849 var TOP_PASTE = unsafeCastStringToDOMTopLevelType('paste'); 2850 var TOP_PAUSE = unsafeCastStringToDOMTopLevelType('pause'); 2851 var TOP_PLAY = unsafeCastStringToDOMTopLevelType('play'); 2852 var TOP_PLAYING = unsafeCastStringToDOMTopLevelType('playing'); 2853 var TOP_POINTER_CANCEL = unsafeCastStringToDOMTopLevelType('pointercancel'); 2854 var TOP_POINTER_DOWN = unsafeCastStringToDOMTopLevelType('pointerdown'); 2855 var TOP_POINTER_MOVE = unsafeCastStringToDOMTopLevelType('pointermove'); 2856 var TOP_POINTER_OUT = unsafeCastStringToDOMTopLevelType('pointerout'); 2857 var TOP_POINTER_OVER = unsafeCastStringToDOMTopLevelType('pointerover'); 2858 var TOP_POINTER_UP = unsafeCastStringToDOMTopLevelType('pointerup'); 2859 var TOP_PROGRESS = unsafeCastStringToDOMTopLevelType('progress'); 2860 var TOP_RATE_CHANGE = unsafeCastStringToDOMTopLevelType('ratechange'); 2861 var TOP_RESET = unsafeCastStringToDOMTopLevelType('reset'); 2862 var TOP_SCROLL = unsafeCastStringToDOMTopLevelType('scroll'); 2863 var TOP_SEEKED = unsafeCastStringToDOMTopLevelType('seeked'); 2864 var TOP_SEEKING = unsafeCastStringToDOMTopLevelType('seeking'); 2865 var TOP_SELECTION_CHANGE = unsafeCastStringToDOMTopLevelType('selectionchange'); 2866 var TOP_STALLED = unsafeCastStringToDOMTopLevelType('stalled'); 2867 var TOP_SUBMIT = unsafeCastStringToDOMTopLevelType('submit'); 2868 var TOP_SUSPEND = unsafeCastStringToDOMTopLevelType('suspend'); 2869 var TOP_TEXT_INPUT = unsafeCastStringToDOMTopLevelType('textInput'); 2870 var TOP_TIME_UPDATE = unsafeCastStringToDOMTopLevelType('timeupdate'); 2871 var TOP_TOGGLE = unsafeCastStringToDOMTopLevelType('toggle'); 2872 var TOP_TOUCH_CANCEL = unsafeCastStringToDOMTopLevelType('touchcancel'); 2873 var TOP_TOUCH_END = unsafeCastStringToDOMTopLevelType('touchend'); 2874 var TOP_TOUCH_MOVE = unsafeCastStringToDOMTopLevelType('touchmove'); 2875 var TOP_TOUCH_START = unsafeCastStringToDOMTopLevelType('touchstart'); 2876 var TOP_TRANSITION_END = unsafeCastStringToDOMTopLevelType(getVendorPrefixedEventName('transitionend')); 2877 var TOP_VOLUME_CHANGE = unsafeCastStringToDOMTopLevelType('volumechange'); 2878 var TOP_WAITING = unsafeCastStringToDOMTopLevelType('waiting'); 2879 var TOP_WHEEL = unsafeCastStringToDOMTopLevelType('wheel'); // List of events that need to be individually attached to media elements. 2880 // Note that events in this list will *not* be listened to at the top level 2881 // unless they're explicitly whitelisted in `ReactBrowserEventEmitter.listenTo`. 2882 2883 var mediaEventTypes = [TOP_ABORT, TOP_CAN_PLAY, TOP_CAN_PLAY_THROUGH, TOP_DURATION_CHANGE, TOP_EMPTIED, TOP_ENCRYPTED, TOP_ENDED, TOP_ERROR, TOP_LOADED_DATA, TOP_LOADED_METADATA, TOP_LOAD_START, TOP_PAUSE, TOP_PLAY, TOP_PLAYING, TOP_PROGRESS, TOP_RATE_CHANGE, TOP_SEEKED, TOP_SEEKING, TOP_STALLED, TOP_SUSPEND, TOP_TIME_UPDATE, TOP_VOLUME_CHANGE, TOP_WAITING]; 2884 function getRawEventName(topLevelType) { 2885 return unsafeCastDOMTopLevelTypeToString(topLevelType); 2886 } 2887 2888 var PossiblyWeakMap = typeof WeakMap === 'function' ? WeakMap : Map; // prettier-ignore 2889 2890 var elementListenerMap = new PossiblyWeakMap(); 2891 function getListenerMapForElement(element) { 2892 var listenerMap = elementListenerMap.get(element); 2893 2894 if (listenerMap === undefined) { 2895 listenerMap = new Map(); 2896 elementListenerMap.set(element, listenerMap); 2897 } 2898 2899 return listenerMap; 2900 } 2901 2902 /** 2903 * `ReactInstanceMap` maintains a mapping from a public facing stateful 2904 * instance (key) and the internal representation (value). This allows public 2905 * methods to accept the user facing instance as an argument and map them back 2906 * to internal methods. 2907 * 2908 * Note that this module is currently shared and assumed to be stateless. 2909 * If this becomes an actual Map, that will break. 2910 */ 2911 function get(key) { 2912 return key._reactInternalFiber; 2913 } 2914 function has$1(key) { 2915 return key._reactInternalFiber !== undefined; 2916 } 2917 function set(key, value) { 2918 key._reactInternalFiber = value; 2919 } 2920 2921 // Don't change these two values. They're used by React Dev Tools. 2922 var NoEffect = 2923 /* */ 2924 0; 2925 var PerformedWork = 2926 /* */ 2927 1; // You can change the rest (and add more). 2928 2929 var Placement = 2930 /* */ 2931 2; 2932 var Update = 2933 /* */ 2934 4; 2935 var PlacementAndUpdate = 2936 /* */ 2937 6; 2938 var Deletion = 2939 /* */ 2940 8; 2941 var ContentReset = 2942 /* */ 2943 16; 2944 var Callback = 2945 /* */ 2946 32; 2947 var DidCapture = 2948 /* */ 2949 64; 2950 var Ref = 2951 /* */ 2952 128; 2953 var Snapshot = 2954 /* */ 2955 256; 2956 var Passive = 2957 /* */ 2958 512; 2959 var Hydrating = 2960 /* */ 2961 1024; 2962 var HydratingAndUpdate = 2963 /* */ 2964 1028; // Passive & Update & Callback & Ref & Snapshot 2965 2966 var LifecycleEffectMask = 2967 /* */ 2968 932; // Union of all host effects 2969 2970 var HostEffectMask = 2971 /* */ 2972 2047; 2973 var Incomplete = 2974 /* */ 2975 2048; 2976 var ShouldCapture = 2977 /* */ 2978 4096; 2979 2980 var ReactCurrentOwner = ReactSharedInternals.ReactCurrentOwner; 2981 function getNearestMountedFiber(fiber) { 2982 var node = fiber; 2983 var nearestMounted = fiber; 2984 2985 if (!fiber.alternate) { 2986 // If there is no alternate, this might be a new tree that isn't inserted 2987 // yet. If it is, then it will have a pending insertion effect on it. 2988 var nextNode = node; 2989 2990 do { 2991 node = nextNode; 2992 2993 if ((node.effectTag & (Placement | Hydrating)) !== NoEffect) { 2994 // This is an insertion or in-progress hydration. The nearest possible 2995 // mounted fiber is the parent but we need to continue to figure out 2996 // if that one is still mounted. 2997 nearestMounted = node.return; 2998 } 2999 3000 nextNode = node.return; 3001 } while (nextNode); 3002 } else { 3003 while (node.return) { 3004 node = node.return; 3005 } 3006 } 3007 3008 if (node.tag === HostRoot) { 3009 // TODO: Check if this was a nested HostRoot when used with 3010 // renderContainerIntoSubtree. 3011 return nearestMounted; 3012 } // If we didn't hit the root, that means that we're in an disconnected tree 3013 // that has been unmounted. 3014 3015 3016 return null; 3017 } 3018 function getSuspenseInstanceFromFiber(fiber) { 3019 if (fiber.tag === SuspenseComponent) { 3020 var suspenseState = fiber.memoizedState; 3021 3022 if (suspenseState === null) { 3023 var current = fiber.alternate; 3024 3025 if (current !== null) { 3026 suspenseState = current.memoizedState; 3027 } 3028 } 3029 3030 if (suspenseState !== null) { 3031 return suspenseState.dehydrated; 3032 } 3033 } 3034 3035 return null; 3036 } 3037 function getContainerFromFiber(fiber) { 3038 return fiber.tag === HostRoot ? fiber.stateNode.containerInfo : null; 3039 } 3040 function isFiberMounted(fiber) { 3041 return getNearestMountedFiber(fiber) === fiber; 3042 } 3043 function isMounted(component) { 3044 { 3045 var owner = ReactCurrentOwner.current; 3046 3047 if (owner !== null && owner.tag === ClassComponent) { 3048 var ownerFiber = owner; 3049 var instance = ownerFiber.stateNode; 3050 3051 if (!instance._warnedAboutRefsInRender) { 3052 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.', getComponentName(ownerFiber.type) || 'A component'); 3053 } 3054 3055 instance._warnedAboutRefsInRender = true; 3056 } 3057 } 3058 3059 var fiber = get(component); 3060 3061 if (!fiber) { 3062 return false; 3063 } 3064 3065 return getNearestMountedFiber(fiber) === fiber; 3066 } 3067 3068 function assertIsMounted(fiber) { 3069 if (!(getNearestMountedFiber(fiber) === fiber)) { 3070 { 3071 throw Error( "Unable to find node on an unmounted component." ); 3072 } 3073 } 3074 } 3075 3076 function findCurrentFiberUsingSlowPath(fiber) { 3077 var alternate = fiber.alternate; 3078 3079 if (!alternate) { 3080 // If there is no alternate, then we only need to check if it is mounted. 3081 var nearestMounted = getNearestMountedFiber(fiber); 3082 3083 if (!(nearestMounted !== null)) { 3084 { 3085 throw Error( "Unable to find node on an unmounted component." ); 3086 } 3087 } 3088 3089 if (nearestMounted !== fiber) { 3090 return null; 3091 } 3092 3093 return fiber; 3094 } // If we have two possible branches, we'll walk backwards up to the root 3095 // to see what path the root points to. On the way we may hit one of the 3096 // special cases and we'll deal with them. 3097 3098 3099 var a = fiber; 3100 var b = alternate; 3101 3102 while (true) { 3103 var parentA = a.return; 3104 3105 if (parentA === null) { 3106 // We're at the root. 3107 break; 3108 } 3109 3110 var parentB = parentA.alternate; 3111 3112 if (parentB === null) { 3113 // There is no alternate. This is an unusual case. Currently, it only 3114 // happens when a Suspense component is hidden. An extra fragment fiber 3115 // is inserted in between the Suspense fiber and its children. Skip 3116 // over this extra fragment fiber and proceed to the next parent. 3117 var nextParent = parentA.return; 3118 3119 if (nextParent !== null) { 3120 a = b = nextParent; 3121 continue; 3122 } // If there's no parent, we're at the root. 3123 3124 3125 break; 3126 } // If both copies of the parent fiber point to the same child, we can 3127 // assume that the child is current. This happens when we bailout on low 3128 // priority: the bailed out fiber's child reuses the current child. 3129 3130 3131 if (parentA.child === parentB.child) { 3132 var child = parentA.child; 3133 3134 while (child) { 3135 if (child === a) { 3136 // We've determined that A is the current branch. 3137 assertIsMounted(parentA); 3138 return fiber; 3139 } 3140 3141 if (child === b) { 3142 // We've determined that B is the current branch. 3143 assertIsMounted(parentA); 3144 return alternate; 3145 } 3146 3147 child = child.sibling; 3148 } // We should never have an alternate for any mounting node. So the only 3149 // way this could possibly happen is if this was unmounted, if at all. 3150 3151 3152 { 3153 { 3154 throw Error( "Unable to find node on an unmounted component." ); 3155 } 3156 } 3157 } 3158 3159 if (a.return !== b.return) { 3160 // The return pointer of A and the return pointer of B point to different 3161 // fibers. We assume that return pointers never criss-cross, so A must 3162 // belong to the child set of A.return, and B must belong to the child 3163 // set of B.return. 3164 a = parentA; 3165 b = parentB; 3166 } else { 3167 // The return pointers point to the same fiber. We'll have to use the 3168 // default, slow path: scan the child sets of each parent alternate to see 3169 // which child belongs to which set. 3170 // 3171 // Search parent A's child set 3172 var didFindChild = false; 3173 var _child = parentA.child; 3174 3175 while (_child) { 3176 if (_child === a) { 3177 didFindChild = true; 3178 a = parentA; 3179 b = parentB; 3180 break; 3181 } 3182 3183 if (_child === b) { 3184 didFindChild = true; 3185 b = parentA; 3186 a = parentB; 3187 break; 3188 } 3189 3190 _child = _child.sibling; 3191 } 3192 3193 if (!didFindChild) { 3194 // Search parent B's child set 3195 _child = parentB.child; 3196 3197 while (_child) { 3198 if (_child === a) { 3199 didFindChild = true; 3200 a = parentB; 3201 b = parentA; 3202 break; 3203 } 3204 3205 if (_child === b) { 3206 didFindChild = true; 3207 b = parentB; 3208 a = parentA; 3209 break; 3210 } 3211 3212 _child = _child.sibling; 3213 } 3214 3215 if (!didFindChild) { 3216 { 3217 throw Error( "Child was not found in either parent set. This indicates a bug in React related to the return pointer. Please file an issue." ); 3218 } 3219 } 3220 } 3221 } 3222 3223 if (!(a.alternate === b)) { 3224 { 3225 throw Error( "Return fibers should always be each others' alternates. This error is likely caused by a bug in React. Please file an issue." ); 3226 } 3227 } 3228 } // If the root is not a host container, we're in a disconnected tree. I.e. 3229 // unmounted. 3230 3231 3232 if (!(a.tag === HostRoot)) { 3233 { 3234 throw Error( "Unable to find node on an unmounted component." ); 3235 } 3236 } 3237 3238 if (a.stateNode.current === a) { 3239 // We've determined that A is the current branch. 3240 return fiber; 3241 } // Otherwise B has to be current branch. 3242 3243 3244 return alternate; 3245 } 3246 function findCurrentHostFiber(parent) { 3247 var currentParent = findCurrentFiberUsingSlowPath(parent); 3248 3249 if (!currentParent) { 3250 return null; 3251 } // Next we'll drill down this component to find the first HostComponent/Text. 3252 3253 3254 var node = currentParent; 3255 3256 while (true) { 3257 if (node.tag === HostComponent || node.tag === HostText) { 3258 return node; 3259 } else if (node.child) { 3260 node.child.return = node; 3261 node = node.child; 3262 continue; 3263 } 3264 3265 if (node === currentParent) { 3266 return null; 3267 } 3268 3269 while (!node.sibling) { 3270 if (!node.return || node.return === currentParent) { 3271 return null; 3272 } 3273 3274 node = node.return; 3275 } 3276 3277 node.sibling.return = node.return; 3278 node = node.sibling; 3279 } // Flow needs the return null here, but ESLint complains about it. 3280 // eslint-disable-next-line no-unreachable 3281 3282 3283 return null; 3284 } 3285 function findCurrentHostFiberWithNoPortals(parent) { 3286 var currentParent = findCurrentFiberUsingSlowPath(parent); 3287 3288 if (!currentParent) { 3289 return null; 3290 } // Next we'll drill down this component to find the first HostComponent/Text. 3291 3292 3293 var node = currentParent; 3294 3295 while (true) { 3296 if (node.tag === HostComponent || node.tag === HostText || enableFundamentalAPI ) { 3297 return node; 3298 } else if (node.child && node.tag !== HostPortal) { 3299 node.child.return = node; 3300 node = node.child; 3301 continue; 3302 } 3303 3304 if (node === currentParent) { 3305 return null; 3306 } 3307 3308 while (!node.sibling) { 3309 if (!node.return || node.return === currentParent) { 3310 return null; 3311 } 3312 3313 node = node.return; 3314 } 3315 3316 node.sibling.return = node.return; 3317 node = node.sibling; 3318 } // Flow needs the return null here, but ESLint complains about it. 3319 // eslint-disable-next-line no-unreachable 3320 3321 3322 return null; 3323 } 3324 3325 /** 3326 * Accumulates items that must not be null or undefined into the first one. This 3327 * is used to conserve memory by avoiding array allocations, and thus sacrifices 3328 * API cleanness. Since `current` can be null before being passed in and not 3329 * null after this function, make sure to assign it back to `current`: 3330 * 3331 * `a = accumulateInto(a, b);` 3332 * 3333 * This API should be sparingly used. Try `accumulate` for something cleaner. 3334 * 3335 * @return {*|array<*>} An accumulation of items. 3336 */ 3337 3338 function accumulateInto(current, next) { 3339 if (!(next != null)) { 3340 { 3341 throw Error( "accumulateInto(...): Accumulated items must not be null or undefined." ); 3342 } 3343 } 3344 3345 if (current == null) { 3346 return next; 3347 } // Both are not empty. Warning: Never call x.concat(y) when you are not 3348 // certain that x is an Array (x could be a string with concat method). 3349 3350 3351 if (Array.isArray(current)) { 3352 if (Array.isArray(next)) { 3353 current.push.apply(current, next); 3354 return current; 3355 } 3356 3357 current.push(next); 3358 return current; 3359 } 3360 3361 if (Array.isArray(next)) { 3362 // A bit too dangerous to mutate `next`. 3363 return [current].concat(next); 3364 } 3365 3366 return [current, next]; 3367 } 3368 3369 /** 3370 * @param {array} arr an "accumulation" of items which is either an Array or 3371 * a single item. Useful when paired with the `accumulate` module. This is a 3372 * simple utility that allows us to reason about a collection of items, but 3373 * handling the case when there is exactly one item (and we do not need to 3374 * allocate an array). 3375 * @param {function} cb Callback invoked with each element or a collection. 3376 * @param {?} [scope] Scope used as `this` in a callback. 3377 */ 3378 function forEachAccumulated(arr, cb, scope) { 3379 if (Array.isArray(arr)) { 3380 arr.forEach(cb, scope); 3381 } else if (arr) { 3382 cb.call(scope, arr); 3383 } 3384 } 3385 3386 /** 3387 * Internal queue of events that have accumulated their dispatches and are 3388 * waiting to have their dispatches executed. 3389 */ 3390 3391 var eventQueue = null; 3392 /** 3393 * Dispatches an event and releases it back into the pool, unless persistent. 3394 * 3395 * @param {?object} event Synthetic event to be dispatched. 3396 * @private 3397 */ 3398 3399 var executeDispatchesAndRelease = function (event) { 3400 if (event) { 3401 executeDispatchesInOrder(event); 3402 3403 if (!event.isPersistent()) { 3404 event.constructor.release(event); 3405 } 3406 } 3407 }; 3408 3409 var executeDispatchesAndReleaseTopLevel = function (e) { 3410 return executeDispatchesAndRelease(e); 3411 }; 3412 3413 function runEventsInBatch(events) { 3414 if (events !== null) { 3415 eventQueue = accumulateInto(eventQueue, events); 3416 } // Set `eventQueue` to null before processing it so that we can tell if more 3417 // events get enqueued while processing. 3418 3419 3420 var processingEventQueue = eventQueue; 3421 eventQueue = null; 3422 3423 if (!processingEventQueue) { 3424 return; 3425 } 3426 3427 forEachAccumulated(processingEventQueue, executeDispatchesAndReleaseTopLevel); 3428 3429 if (!!eventQueue) { 3430 { 3431 throw Error( "processEventQueue(): Additional events were enqueued while processing an event queue. Support for this has not yet been implemented." ); 3432 } 3433 } // This would be a good time to rethrow if any of the event handlers threw. 3434 3435 3436 rethrowCaughtError(); 3437 } 3438 3439 /** 3440 * Gets the target node from a native browser event by accounting for 3441 * inconsistencies in browser DOM APIs. 3442 * 3443 * @param {object} nativeEvent Native browser event. 3444 * @return {DOMEventTarget} Target node. 3445 */ 3446 3447 function getEventTarget(nativeEvent) { 3448 // Fallback to nativeEvent.srcElement for IE9 3449 // https://github.com/facebook/react/issues/12506 3450 var target = nativeEvent.target || nativeEvent.srcElement || window; // Normalize SVG <use> element events #4963 3451 3452 if (target.correspondingUseElement) { 3453 target = target.correspondingUseElement; 3454 } // Safari may fire events on text nodes (Node.TEXT_NODE is 3). 3455 // @see http://www.quirksmode.org/js/events_properties.html 3456 3457 3458 return target.nodeType === TEXT_NODE ? target.parentNode : target; 3459 } 3460 3461 /** 3462 * Checks if an event is supported in the current execution environment. 3463 * 3464 * NOTE: This will not work correctly for non-generic events such as `change`, 3465 * `reset`, `load`, `error`, and `select`. 3466 * 3467 * Borrows from Modernizr. 3468 * 3469 * @param {string} eventNameSuffix Event name, e.g. "click". 3470 * @return {boolean} True if the event is supported. 3471 * @internal 3472 * @license Modernizr 3.0.0pre (Custom Build) | MIT 3473 */ 3474 3475 function isEventSupported(eventNameSuffix) { 3476 if (!canUseDOM) { 3477 return false; 3478 } 3479 3480 var eventName = 'on' + eventNameSuffix; 3481 var isSupported = eventName in document; 3482 3483 if (!isSupported) { 3484 var element = document.createElement('div'); 3485 element.setAttribute(eventName, 'return;'); 3486 isSupported = typeof element[eventName] === 'function'; 3487 } 3488 3489 return isSupported; 3490 } 3491 3492 /** 3493 * Summary of `DOMEventPluginSystem` event handling: 3494 * 3495 * - Top-level delegation is used to trap most native browser events. This 3496 * may only occur in the main thread and is the responsibility of 3497 * ReactDOMEventListener, which is injected and can therefore support 3498 * pluggable event sources. This is the only work that occurs in the main 3499 * thread. 3500 * 3501 * - We normalize and de-duplicate events to account for browser quirks. This 3502 * may be done in the worker thread. 3503 * 3504 * - Forward these native events (with the associated top-level type used to 3505 * trap it) to `EventPluginRegistry`, which in turn will ask plugins if they want 3506 * to extract any synthetic events. 3507 * 3508 * - The `EventPluginRegistry` will then process each event by annotating them with 3509 * "dispatches", a sequence of listeners and IDs that care about that event. 3510 * 3511 * - The `EventPluginRegistry` then dispatches the events. 3512 * 3513 * Overview of React and the event system: 3514 * 3515 * +------------+ . 3516 * | DOM | . 3517 * +------------+ . 3518 * | . 3519 * v . 3520 * +------------+ . 3521 * | ReactEvent | . 3522 * | Listener | . 3523 * +------------+ . +-----------+ 3524 * | . +--------+|SimpleEvent| 3525 * | . | |Plugin | 3526 * +-----|------+ . v +-----------+ 3527 * | | | . +--------------+ +------------+ 3528 * | +-----------.--->|PluginRegistry| | Event | 3529 * | | . | | +-----------+ | Propagators| 3530 * | ReactEvent | . | | |TapEvent | |------------| 3531 * | Emitter | . | |<---+|Plugin | |other plugin| 3532 * | | . | | +-----------+ | utilities | 3533 * | +-----------.--->| | +------------+ 3534 * | | | . +--------------+ 3535 * +-----|------+ . ^ +-----------+ 3536 * | . | |Enter/Leave| 3537 * + . +-------+|Plugin | 3538 * +-------------+ . +-----------+ 3539 * | application | . 3540 * |-------------| . 3541 * | | . 3542 * | | . 3543 * +-------------+ . 3544 * . 3545 * React Core . General Purpose Event Plugin System 3546 */ 3547 3548 var CALLBACK_BOOKKEEPING_POOL_SIZE = 10; 3549 var callbackBookkeepingPool = []; 3550 3551 function releaseTopLevelCallbackBookKeeping(instance) { 3552 instance.topLevelType = null; 3553 instance.nativeEvent = null; 3554 instance.targetInst = null; 3555 instance.ancestors.length = 0; 3556 3557 if (callbackBookkeepingPool.length < CALLBACK_BOOKKEEPING_POOL_SIZE) { 3558 callbackBookkeepingPool.push(instance); 3559 } 3560 } // Used to store ancestor hierarchy in top level callback 3561 3562 3563 function getTopLevelCallbackBookKeeping(topLevelType, nativeEvent, targetInst, eventSystemFlags) { 3564 if (callbackBookkeepingPool.length) { 3565 var instance = callbackBookkeepingPool.pop(); 3566 instance.topLevelType = topLevelType; 3567 instance.eventSystemFlags = eventSystemFlags; 3568 instance.nativeEvent = nativeEvent; 3569 instance.targetInst = targetInst; 3570 return instance; 3571 } 3572 3573 return { 3574 topLevelType: topLevelType, 3575 eventSystemFlags: eventSystemFlags, 3576 nativeEvent: nativeEvent, 3577 targetInst: targetInst, 3578 ancestors: [] 3579 }; 3580 } 3581 /** 3582 * Find the deepest React component completely containing the root of the 3583 * passed-in instance (for use when entire React trees are nested within each 3584 * other). If React trees are not nested, returns null. 3585 */ 3586 3587 3588 function findRootContainerNode(inst) { 3589 if (inst.tag === HostRoot) { 3590 return inst.stateNode.containerInfo; 3591 } // TODO: It may be a good idea to cache this to prevent unnecessary DOM 3592 // traversal, but caching is difficult to do correctly without using a 3593 // mutation observer to listen for all DOM changes. 3594 3595 3596 while (inst.return) { 3597 inst = inst.return; 3598 } 3599 3600 if (inst.tag !== HostRoot) { 3601 // This can happen if we're in a detached tree. 3602 return null; 3603 } 3604 3605 return inst.stateNode.containerInfo; 3606 } 3607 /** 3608 * Allows registered plugins an opportunity to extract events from top-level 3609 * native browser events. 3610 * 3611 * @return {*} An accumulation of synthetic events. 3612 * @internal 3613 */ 3614 3615 3616 function extractPluginEvents(topLevelType, targetInst, nativeEvent, nativeEventTarget, eventSystemFlags) { 3617 var events = null; 3618 3619 for (var i = 0; i < plugins.length; i++) { 3620 // Not every plugin in the ordering may be loaded at runtime. 3621 var possiblePlugin = plugins[i]; 3622 3623 if (possiblePlugin) { 3624 var extractedEvents = possiblePlugin.extractEvents(topLevelType, targetInst, nativeEvent, nativeEventTarget, eventSystemFlags); 3625 3626 if (extractedEvents) { 3627 events = accumulateInto(events, extractedEvents); 3628 } 3629 } 3630 } 3631 3632 return events; 3633 } 3634 3635 function runExtractedPluginEventsInBatch(topLevelType, targetInst, nativeEvent, nativeEventTarget, eventSystemFlags) { 3636 var events = extractPluginEvents(topLevelType, targetInst, nativeEvent, nativeEventTarget, eventSystemFlags); 3637 runEventsInBatch(events); 3638 } 3639 3640 function handleTopLevel(bookKeeping) { 3641 var targetInst = bookKeeping.targetInst; // Loop through the hierarchy, in case there's any nested components. 3642 // It's important that we build the array of ancestors before calling any 3643 // event handlers, because event handlers can modify the DOM, leading to 3644 // inconsistencies with ReactMount's node cache. See #1105. 3645 3646 var ancestor = targetInst; 3647 3648 do { 3649 if (!ancestor) { 3650 var ancestors = bookKeeping.ancestors; 3651 ancestors.push(ancestor); 3652 break; 3653 } 3654 3655 var root = findRootContainerNode(ancestor); 3656 3657 if (!root) { 3658 break; 3659 } 3660 3661 var tag = ancestor.tag; 3662 3663 if (tag === HostComponent || tag === HostText) { 3664 bookKeeping.ancestors.push(ancestor); 3665 } 3666 3667 ancestor = getClosestInstanceFromNode(root); 3668 } while (ancestor); 3669 3670 for (var i = 0; i < bookKeeping.ancestors.length; i++) { 3671 targetInst = bookKeeping.ancestors[i]; 3672 var eventTarget = getEventTarget(bookKeeping.nativeEvent); 3673 var topLevelType = bookKeeping.topLevelType; 3674 var nativeEvent = bookKeeping.nativeEvent; 3675 var eventSystemFlags = bookKeeping.eventSystemFlags; // If this is the first ancestor, we mark it on the system flags 3676 3677 if (i === 0) { 3678 eventSystemFlags |= IS_FIRST_ANCESTOR; 3679 } 3680 3681 runExtractedPluginEventsInBatch(topLevelType, targetInst, nativeEvent, eventTarget, eventSystemFlags); 3682 } 3683 } 3684 3685 function dispatchEventForLegacyPluginEventSystem(topLevelType, eventSystemFlags, nativeEvent, targetInst) { 3686 var bookKeeping = getTopLevelCallbackBookKeeping(topLevelType, nativeEvent, targetInst, eventSystemFlags); 3687 3688 try { 3689 // Event queue being processed in the same cycle allows 3690 // `preventDefault`. 3691 batchedEventUpdates(handleTopLevel, bookKeeping); 3692 } finally { 3693 releaseTopLevelCallbackBookKeeping(bookKeeping); 3694 } 3695 } 3696 /** 3697 * We listen for bubbled touch events on the document object. 3698 * 3699 * Firefox v8.01 (and possibly others) exhibited strange behavior when 3700 * mounting `onmousemove` events at some node that was not the document 3701 * element. The symptoms were that if your mouse is not moving over something 3702 * contained within that mount point (for example on the background) the 3703 * top-level listeners for `onmousemove` won't be called. However, if you 3704 * register the `mousemove` on the document object, then it will of course 3705 * catch all `mousemove`s. This along with iOS quirks, justifies restricting 3706 * top-level listeners to the document object only, at least for these 3707 * movement types of events and possibly all events. 3708 * 3709 * @see http://www.quirksmode.org/blog/archives/2010/09/click_event_del.html 3710 * 3711 * Also, `keyup`/`keypress`/`keydown` do not bubble to the window on IE, but 3712 * they bubble to document. 3713 * 3714 * @param {string} registrationName Name of listener (e.g. `onClick`). 3715 * @param {object} mountAt Container where to mount the listener 3716 */ 3717 3718 function legacyListenToEvent(registrationName, mountAt) { 3719 var listenerMap = getListenerMapForElement(mountAt); 3720 var dependencies = registrationNameDependencies[registrationName]; 3721 3722 for (var i = 0; i < dependencies.length; i++) { 3723 var dependency = dependencies[i]; 3724 legacyListenToTopLevelEvent(dependency, mountAt, listenerMap); 3725 } 3726 } 3727 function legacyListenToTopLevelEvent(topLevelType, mountAt, listenerMap) { 3728 if (!listenerMap.has(topLevelType)) { 3729 switch (topLevelType) { 3730 case TOP_SCROLL: 3731 trapCapturedEvent(TOP_SCROLL, mountAt); 3732 break; 3733 3734 case TOP_FOCUS: 3735 case TOP_BLUR: 3736 trapCapturedEvent(TOP_FOCUS, mountAt); 3737 trapCapturedEvent(TOP_BLUR, mountAt); // We set the flag for a single dependency later in this function, 3738 // but this ensures we mark both as attached rather than just one. 3739 3740 listenerMap.set(TOP_BLUR, null); 3741 listenerMap.set(TOP_FOCUS, null); 3742 break; 3743 3744 case TOP_CANCEL: 3745 case TOP_CLOSE: 3746 if (isEventSupported(getRawEventName(topLevelType))) { 3747 trapCapturedEvent(topLevelType, mountAt); 3748 } 3749 3750 break; 3751 3752 case TOP_INVALID: 3753 case TOP_SUBMIT: 3754 case TOP_RESET: 3755 // We listen to them on the target DOM elements. 3756 // Some of them bubble so we don't want them to fire twice. 3757 break; 3758 3759 default: 3760 // By default, listen on the top level to all non-media events. 3761 // Media events don't bubble so adding the listener wouldn't do anything. 3762 var isMediaEvent = mediaEventTypes.indexOf(topLevelType) !== -1; 3763 3764 if (!isMediaEvent) { 3765 trapBubbledEvent(topLevelType, mountAt); 3766 } 3767 3768 break; 3769 } 3770 3771 listenerMap.set(topLevelType, null); 3772 } 3773 } 3774 function isListeningToAllDependencies(registrationName, mountAt) { 3775 var listenerMap = getListenerMapForElement(mountAt); 3776 var dependencies = registrationNameDependencies[registrationName]; 3777 3778 for (var i = 0; i < dependencies.length; i++) { 3779 var dependency = dependencies[i]; 3780 3781 if (!listenerMap.has(dependency)) { 3782 return false; 3783 } 3784 } 3785 3786 return true; 3787 } 3788 3789 var attemptUserBlockingHydration; 3790 function setAttemptUserBlockingHydration(fn) { 3791 attemptUserBlockingHydration = fn; 3792 } 3793 var attemptContinuousHydration; 3794 function setAttemptContinuousHydration(fn) { 3795 attemptContinuousHydration = fn; 3796 } 3797 var attemptHydrationAtCurrentPriority; 3798 function setAttemptHydrationAtCurrentPriority(fn) { 3799 attemptHydrationAtCurrentPriority = fn; 3800 } // TODO: Upgrade this definition once we're on a newer version of Flow that 3801 var hasScheduledReplayAttempt = false; // The queue of discrete events to be replayed. 3802 3803 var queuedDiscreteEvents = []; // Indicates if any continuous event targets are non-null for early bailout. 3804 // if the last target was dehydrated. 3805 3806 var queuedFocus = null; 3807 var queuedDrag = null; 3808 var queuedMouse = null; // For pointer events there can be one latest event per pointerId. 3809 3810 var queuedPointers = new Map(); 3811 var queuedPointerCaptures = new Map(); // We could consider replaying selectionchange and touchmoves too. 3812 3813 var queuedExplicitHydrationTargets = []; 3814 function hasQueuedDiscreteEvents() { 3815 return queuedDiscreteEvents.length > 0; 3816 } 3817 var discreteReplayableEvents = [TOP_MOUSE_DOWN, TOP_MOUSE_UP, TOP_TOUCH_CANCEL, TOP_TOUCH_END, TOP_TOUCH_START, TOP_AUX_CLICK, TOP_DOUBLE_CLICK, TOP_POINTER_CANCEL, TOP_POINTER_DOWN, TOP_POINTER_UP, TOP_DRAG_END, TOP_DRAG_START, TOP_DROP, TOP_COMPOSITION_END, TOP_COMPOSITION_START, TOP_KEY_DOWN, TOP_KEY_PRESS, TOP_KEY_UP, TOP_INPUT, TOP_TEXT_INPUT, TOP_CLOSE, TOP_CANCEL, TOP_COPY, TOP_CUT, TOP_PASTE, TOP_CLICK, TOP_CHANGE, TOP_CONTEXT_MENU, TOP_RESET, TOP_SUBMIT]; 3818 var continuousReplayableEvents = [TOP_FOCUS, TOP_BLUR, TOP_DRAG_ENTER, TOP_DRAG_LEAVE, TOP_MOUSE_OVER, TOP_MOUSE_OUT, TOP_POINTER_OVER, TOP_POINTER_OUT, TOP_GOT_POINTER_CAPTURE, TOP_LOST_POINTER_CAPTURE]; 3819 function isReplayableDiscreteEvent(eventType) { 3820 return discreteReplayableEvents.indexOf(eventType) > -1; 3821 } 3822 3823 function trapReplayableEventForDocument(topLevelType, document, listenerMap) { 3824 legacyListenToTopLevelEvent(topLevelType, document, listenerMap); 3825 } 3826 3827 function eagerlyTrapReplayableEvents(container, document) { 3828 var listenerMapForDoc = getListenerMapForElement(document); // Discrete 3829 3830 discreteReplayableEvents.forEach(function (topLevelType) { 3831 trapReplayableEventForDocument(topLevelType, document, listenerMapForDoc); 3832 }); // Continuous 3833 3834 continuousReplayableEvents.forEach(function (topLevelType) { 3835 trapReplayableEventForDocument(topLevelType, document, listenerMapForDoc); 3836 }); 3837 } 3838 3839 function createQueuedReplayableEvent(blockedOn, topLevelType, eventSystemFlags, container, nativeEvent) { 3840 return { 3841 blockedOn: blockedOn, 3842 topLevelType: topLevelType, 3843 eventSystemFlags: eventSystemFlags | IS_REPLAYED, 3844 nativeEvent: nativeEvent, 3845 container: container 3846 }; 3847 } 3848 3849 function queueDiscreteEvent(blockedOn, topLevelType, eventSystemFlags, container, nativeEvent) { 3850 var queuedEvent = createQueuedReplayableEvent(blockedOn, topLevelType, eventSystemFlags, container, nativeEvent); 3851 queuedDiscreteEvents.push(queuedEvent); 3852 } // Resets the replaying for this type of continuous event to no event. 3853 3854 function clearIfContinuousEvent(topLevelType, nativeEvent) { 3855 switch (topLevelType) { 3856 case TOP_FOCUS: 3857 case TOP_BLUR: 3858 queuedFocus = null; 3859 break; 3860 3861 case TOP_DRAG_ENTER: 3862 case TOP_DRAG_LEAVE: 3863 queuedDrag = null; 3864 break; 3865 3866 case TOP_MOUSE_OVER: 3867 case TOP_MOUSE_OUT: 3868 queuedMouse = null; 3869 break; 3870 3871 case TOP_POINTER_OVER: 3872 case TOP_POINTER_OUT: 3873 { 3874 var pointerId = nativeEvent.pointerId; 3875 queuedPointers.delete(pointerId); 3876 break; 3877 } 3878 3879 case TOP_GOT_POINTER_CAPTURE: 3880 case TOP_LOST_POINTER_CAPTURE: 3881 { 3882 var _pointerId = nativeEvent.pointerId; 3883 queuedPointerCaptures.delete(_pointerId); 3884 break; 3885 } 3886 } 3887 } 3888 3889 function accumulateOrCreateContinuousQueuedReplayableEvent(existingQueuedEvent, blockedOn, topLevelType, eventSystemFlags, container, nativeEvent) { 3890 if (existingQueuedEvent === null || existingQueuedEvent.nativeEvent !== nativeEvent) { 3891 var queuedEvent = createQueuedReplayableEvent(blockedOn, topLevelType, eventSystemFlags, container, nativeEvent); 3892 3893 if (blockedOn !== null) { 3894 var _fiber2 = getInstanceFromNode$1(blockedOn); 3895 3896 if (_fiber2 !== null) { 3897 // Attempt to increase the priority of this target. 3898 attemptContinuousHydration(_fiber2); 3899 } 3900 } 3901 3902 return queuedEvent; 3903 } // If we have already queued this exact event, then it's because 3904 // the different event systems have different DOM event listeners. 3905 // We can accumulate the flags and store a single event to be 3906 // replayed. 3907 3908 3909 existingQueuedEvent.eventSystemFlags |= eventSystemFlags; 3910 return existingQueuedEvent; 3911 } 3912 3913 function queueIfContinuousEvent(blockedOn, topLevelType, eventSystemFlags, container, nativeEvent) { 3914 // These set relatedTarget to null because the replayed event will be treated as if we 3915 // moved from outside the window (no target) onto the target once it hydrates. 3916 // Instead of mutating we could clone the event. 3917 switch (topLevelType) { 3918 case TOP_FOCUS: 3919 { 3920 var focusEvent = nativeEvent; 3921 queuedFocus = accumulateOrCreateContinuousQueuedReplayableEvent(queuedFocus, blockedOn, topLevelType, eventSystemFlags, container, focusEvent); 3922 return true; 3923 } 3924 3925 case TOP_DRAG_ENTER: 3926 { 3927 var dragEvent = nativeEvent; 3928 queuedDrag = accumulateOrCreateContinuousQueuedReplayableEvent(queuedDrag, blockedOn, topLevelType, eventSystemFlags, container, dragEvent); 3929 return true; 3930 } 3931 3932 case TOP_MOUSE_OVER: 3933 { 3934 var mouseEvent = nativeEvent; 3935 queuedMouse = accumulateOrCreateContinuousQueuedReplayableEvent(queuedMouse, blockedOn, topLevelType, eventSystemFlags, container, mouseEvent); 3936 return true; 3937 } 3938 3939 case TOP_POINTER_OVER: 3940 { 3941 var pointerEvent = nativeEvent; 3942 var pointerId = pointerEvent.pointerId; 3943 queuedPointers.set(pointerId, accumulateOrCreateContinuousQueuedReplayableEvent(queuedPointers.get(pointerId) || null, blockedOn, topLevelType, eventSystemFlags, container, pointerEvent)); 3944 return true; 3945 } 3946 3947 case TOP_GOT_POINTER_CAPTURE: 3948 { 3949 var _pointerEvent = nativeEvent; 3950 var _pointerId2 = _pointerEvent.pointerId; 3951 queuedPointerCaptures.set(_pointerId2, accumulateOrCreateContinuousQueuedReplayableEvent(queuedPointerCaptures.get(_pointerId2) || null, blockedOn, topLevelType, eventSystemFlags, container, _pointerEvent)); 3952 return true; 3953 } 3954 } 3955 3956 return false; 3957 } // Check if this target is unblocked. Returns true if it's unblocked. 3958 3959 function attemptExplicitHydrationTarget(queuedTarget) { 3960 // TODO: This function shares a lot of logic with attemptToDispatchEvent. 3961 // Try to unify them. It's a bit tricky since it would require two return 3962 // values. 3963 var targetInst = getClosestInstanceFromNode(queuedTarget.target); 3964 3965 if (targetInst !== null) { 3966 var nearestMounted = getNearestMountedFiber(targetInst); 3967 3968 if (nearestMounted !== null) { 3969 var tag = nearestMounted.tag; 3970 3971 if (tag === SuspenseComponent) { 3972 var instance = getSuspenseInstanceFromFiber(nearestMounted); 3973 3974 if (instance !== null) { 3975 // We're blocked on hydrating this boundary. 3976 // Increase its priority. 3977 queuedTarget.blockedOn = instance; 3978 unstable_runWithPriority(queuedTarget.priority, function () { 3979 attemptHydrationAtCurrentPriority(nearestMounted); 3980 }); 3981 return; 3982 } 3983 } else if (tag === HostRoot) { 3984 var root = nearestMounted.stateNode; 3985 3986 if (root.hydrate) { 3987 queuedTarget.blockedOn = getContainerFromFiber(nearestMounted); // We don't currently have a way to increase the priority of 3988 // a root other than sync. 3989 3990 return; 3991 } 3992 } 3993 } 3994 } 3995 3996 queuedTarget.blockedOn = null; 3997 } 3998 3999 function attemptReplayContinuousQueuedEvent(queuedEvent) { 4000 if (queuedEvent.blockedOn !== null) { 4001 return false; 4002 } 4003 4004 var nextBlockedOn = attemptToDispatchEvent(queuedEvent.topLevelType, queuedEvent.eventSystemFlags, queuedEvent.container, queuedEvent.nativeEvent); 4005 4006 if (nextBlockedOn !== null) { 4007 // We're still blocked. Try again later. 4008 var _fiber3 = getInstanceFromNode$1(nextBlockedOn); 4009 4010 if (_fiber3 !== null) { 4011 attemptContinuousHydration(_fiber3); 4012 } 4013 4014 queuedEvent.blockedOn = nextBlockedOn; 4015 return false; 4016 } 4017 4018 return true; 4019 } 4020 4021 function attemptReplayContinuousQueuedEventInMap(queuedEvent, key, map) { 4022 if (attemptReplayContinuousQueuedEvent(queuedEvent)) { 4023 map.delete(key); 4024 } 4025 } 4026 4027 function replayUnblockedEvents() { 4028 hasScheduledReplayAttempt = false; // First replay discrete events. 4029 4030 while (queuedDiscreteEvents.length > 0) { 4031 var nextDiscreteEvent = queuedDiscreteEvents[0]; 4032 4033 if (nextDiscreteEvent.blockedOn !== null) { 4034 // We're still blocked. 4035 // Increase the priority of this boundary to unblock 4036 // the next discrete event. 4037 var _fiber4 = getInstanceFromNode$1(nextDiscreteEvent.blockedOn); 4038 4039 if (_fiber4 !== null) { 4040 attemptUserBlockingHydration(_fiber4); 4041 } 4042 4043 break; 4044 } 4045 4046 var nextBlockedOn = attemptToDispatchEvent(nextDiscreteEvent.topLevelType, nextDiscreteEvent.eventSystemFlags, nextDiscreteEvent.container, nextDiscreteEvent.nativeEvent); 4047 4048 if (nextBlockedOn !== null) { 4049 // We're still blocked. Try again later. 4050 nextDiscreteEvent.blockedOn = nextBlockedOn; 4051 } else { 4052 // We've successfully replayed the first event. Let's try the next one. 4053 queuedDiscreteEvents.shift(); 4054 } 4055 } // Next replay any continuous events. 4056 4057 4058 if (queuedFocus !== null && attemptReplayContinuousQueuedEvent(queuedFocus)) { 4059 queuedFocus = null; 4060 } 4061 4062 if (queuedDrag !== null && attemptReplayContinuousQueuedEvent(queuedDrag)) { 4063 queuedDrag = null; 4064 } 4065 4066 if (queuedMouse !== null && attemptReplayContinuousQueuedEvent(queuedMouse)) { 4067 queuedMouse = null; 4068 } 4069 4070 queuedPointers.forEach(attemptReplayContinuousQueuedEventInMap); 4071 queuedPointerCaptures.forEach(attemptReplayContinuousQueuedEventInMap); 4072 } 4073 4074 function scheduleCallbackIfUnblocked(queuedEvent, unblocked) { 4075 if (queuedEvent.blockedOn === unblocked) { 4076 queuedEvent.blockedOn = null; 4077 4078 if (!hasScheduledReplayAttempt) { 4079 hasScheduledReplayAttempt = true; // Schedule a callback to attempt replaying as many events as are 4080 // now unblocked. This first might not actually be unblocked yet. 4081 // We could check it early to avoid scheduling an unnecessary callback. 4082 4083 unstable_scheduleCallback(unstable_NormalPriority, replayUnblockedEvents); 4084 } 4085 } 4086 } 4087 4088 function retryIfBlockedOn(unblocked) { 4089 // Mark anything that was blocked on this as no longer blocked 4090 // and eligible for a replay. 4091 if (queuedDiscreteEvents.length > 0) { 4092 scheduleCallbackIfUnblocked(queuedDiscreteEvents[0], unblocked); // This is a exponential search for each boundary that commits. I think it's 4093 // worth it because we expect very few discrete events to queue up and once 4094 // we are actually fully unblocked it will be fast to replay them. 4095 4096 for (var i = 1; i < queuedDiscreteEvents.length; i++) { 4097 var queuedEvent = queuedDiscreteEvents[i]; 4098 4099 if (queuedEvent.blockedOn === unblocked) { 4100 queuedEvent.blockedOn = null; 4101 } 4102 } 4103 } 4104 4105 if (queuedFocus !== null) { 4106 scheduleCallbackIfUnblocked(queuedFocus, unblocked); 4107 } 4108 4109 if (queuedDrag !== null) { 4110 scheduleCallbackIfUnblocked(queuedDrag, unblocked); 4111 } 4112 4113 if (queuedMouse !== null) { 4114 scheduleCallbackIfUnblocked(queuedMouse, unblocked); 4115 } 4116 4117 var unblock = function (queuedEvent) { 4118 return scheduleCallbackIfUnblocked(queuedEvent, unblocked); 4119 }; 4120 4121 queuedPointers.forEach(unblock); 4122 queuedPointerCaptures.forEach(unblock); 4123 4124 for (var _i = 0; _i < queuedExplicitHydrationTargets.length; _i++) { 4125 var queuedTarget = queuedExplicitHydrationTargets[_i]; 4126 4127 if (queuedTarget.blockedOn === unblocked) { 4128 queuedTarget.blockedOn = null; 4129 } 4130 } 4131 4132 while (queuedExplicitHydrationTargets.length > 0) { 4133 var nextExplicitTarget = queuedExplicitHydrationTargets[0]; 4134 4135 if (nextExplicitTarget.blockedOn !== null) { 4136 // We're still blocked. 4137 break; 4138 } else { 4139 attemptExplicitHydrationTarget(nextExplicitTarget); 4140 4141 if (nextExplicitTarget.blockedOn === null) { 4142 // We're unblocked. 4143 queuedExplicitHydrationTargets.shift(); 4144 } 4145 } 4146 } 4147 } 4148 4149 function addEventBubbleListener(element, eventType, listener) { 4150 element.addEventListener(eventType, listener, false); 4151 } 4152 function addEventCaptureListener(element, eventType, listener) { 4153 element.addEventListener(eventType, listener, true); 4154 } 4155 4156 // do it in two places, which duplicates logic 4157 // and increases the bundle size, we do it all 4158 // here once. If we remove or refactor the 4159 // SimpleEventPlugin, we should also remove or 4160 // update the below line. 4161 4162 var simpleEventPluginEventTypes = {}; 4163 var topLevelEventsToDispatchConfig = new Map(); 4164 var eventPriorities = new Map(); // We store most of the events in this module in pairs of two strings so we can re-use 4165 // the code required to apply the same logic for event prioritization and that of the 4166 // SimpleEventPlugin. This complicates things slightly, but the aim is to reduce code 4167 // duplication (for which there would be quite a bit). For the events that are not needed 4168 // for the SimpleEventPlugin (otherDiscreteEvents) we process them separately as an 4169 // array of top level events. 4170 // Lastly, we ignore prettier so we can keep the formatting sane. 4171 // prettier-ignore 4172 4173 var discreteEventPairsForSimpleEventPlugin = [TOP_BLUR, 'blur', TOP_CANCEL, 'cancel', TOP_CLICK, 'click', TOP_CLOSE, 'close', TOP_CONTEXT_MENU, 'contextMenu', TOP_COPY, 'copy', TOP_CUT, 'cut', TOP_AUX_CLICK, 'auxClick', TOP_DOUBLE_CLICK, 'doubleClick', TOP_DRAG_END, 'dragEnd', TOP_DRAG_START, 'dragStart', TOP_DROP, 'drop', TOP_FOCUS, 'focus', TOP_INPUT, 'input', TOP_INVALID, 'invalid', TOP_KEY_DOWN, 'keyDown', TOP_KEY_PRESS, 'keyPress', TOP_KEY_UP, 'keyUp', TOP_MOUSE_DOWN, 'mouseDown', TOP_MOUSE_UP, 'mouseUp', TOP_PASTE, 'paste', TOP_PAUSE, 'pause', TOP_PLAY, 'play', TOP_POINTER_CANCEL, 'pointerCancel', TOP_POINTER_DOWN, 'pointerDown', TOP_POINTER_UP, 'pointerUp', TOP_RATE_CHANGE, 'rateChange', TOP_RESET, 'reset', TOP_SEEKED, 'seeked', TOP_SUBMIT, 'submit', TOP_TOUCH_CANCEL, 'touchCancel', TOP_TOUCH_END, 'touchEnd', TOP_TOUCH_START, 'touchStart', TOP_VOLUME_CHANGE, 'volumeChange']; 4174 var otherDiscreteEvents = [TOP_CHANGE, TOP_SELECTION_CHANGE, TOP_TEXT_INPUT, TOP_COMPOSITION_START, TOP_COMPOSITION_END, TOP_COMPOSITION_UPDATE]; // prettier-ignore 4175 4176 var userBlockingPairsForSimpleEventPlugin = [TOP_DRAG, 'drag', TOP_DRAG_ENTER, 'dragEnter', TOP_DRAG_EXIT, 'dragExit', TOP_DRAG_LEAVE, 'dragLeave', TOP_DRAG_OVER, 'dragOver', TOP_MOUSE_MOVE, 'mouseMove', TOP_MOUSE_OUT, 'mouseOut', TOP_MOUSE_OVER, 'mouseOver', TOP_POINTER_MOVE, 'pointerMove', TOP_POINTER_OUT, 'pointerOut', TOP_POINTER_OVER, 'pointerOver', TOP_SCROLL, 'scroll', TOP_TOGGLE, 'toggle', TOP_TOUCH_MOVE, 'touchMove', TOP_WHEEL, 'wheel']; // prettier-ignore 4177 4178 var continuousPairsForSimpleEventPlugin = [TOP_ABORT, 'abort', TOP_ANIMATION_END, 'animationEnd', TOP_ANIMATION_ITERATION, 'animationIteration', TOP_ANIMATION_START, 'animationStart', TOP_CAN_PLAY, 'canPlay', TOP_CAN_PLAY_THROUGH, 'canPlayThrough', TOP_DURATION_CHANGE, 'durationChange', TOP_EMPTIED, 'emptied', TOP_ENCRYPTED, 'encrypted', TOP_ENDED, 'ended', TOP_ERROR, 'error', TOP_GOT_POINTER_CAPTURE, 'gotPointerCapture', TOP_LOAD, 'load', TOP_LOADED_DATA, 'loadedData', TOP_LOADED_METADATA, 'loadedMetadata', TOP_LOAD_START, 'loadStart', TOP_LOST_POINTER_CAPTURE, 'lostPointerCapture', TOP_PLAYING, 'playing', TOP_PROGRESS, 'progress', TOP_SEEKING, 'seeking', TOP_STALLED, 'stalled', TOP_SUSPEND, 'suspend', TOP_TIME_UPDATE, 'timeUpdate', TOP_TRANSITION_END, 'transitionEnd', TOP_WAITING, 'waiting']; 4179 /** 4180 * Turns 4181 * ['abort', ...] 4182 * into 4183 * eventTypes = { 4184 * 'abort': { 4185 * phasedRegistrationNames: { 4186 * bubbled: 'onAbort', 4187 * captured: 'onAbortCapture', 4188 * }, 4189 * dependencies: [TOP_ABORT], 4190 * }, 4191 * ... 4192 * }; 4193 * topLevelEventsToDispatchConfig = new Map([ 4194 * [TOP_ABORT, { sameConfig }], 4195 * ]); 4196 */ 4197 4198 function processSimpleEventPluginPairsByPriority(eventTypes, priority) { 4199 // As the event types are in pairs of two, we need to iterate 4200 // through in twos. The events are in pairs of two to save code 4201 // and improve init perf of processing this array, as it will 4202 // result in far fewer object allocations and property accesses 4203 // if we only use three arrays to process all the categories of 4204 // instead of tuples. 4205 for (var i = 0; i < eventTypes.length; i += 2) { 4206 var topEvent = eventTypes[i]; 4207 var event = eventTypes[i + 1]; 4208 var capitalizedEvent = event[0].toUpperCase() + event.slice(1); 4209 var onEvent = 'on' + capitalizedEvent; 4210 var config = { 4211 phasedRegistrationNames: { 4212 bubbled: onEvent, 4213 captured: onEvent + 'Capture' 4214 }, 4215 dependencies: [topEvent], 4216 eventPriority: priority 4217 }; 4218 eventPriorities.set(topEvent, priority); 4219 topLevelEventsToDispatchConfig.set(topEvent, config); 4220 simpleEventPluginEventTypes[event] = config; 4221 } 4222 } 4223 4224 function processTopEventPairsByPriority(eventTypes, priority) { 4225 for (var i = 0; i < eventTypes.length; i++) { 4226 eventPriorities.set(eventTypes[i], priority); 4227 } 4228 } // SimpleEventPlugin 4229 4230 4231 processSimpleEventPluginPairsByPriority(discreteEventPairsForSimpleEventPlugin, DiscreteEvent); 4232 processSimpleEventPluginPairsByPriority(userBlockingPairsForSimpleEventPlugin, UserBlockingEvent); 4233 processSimpleEventPluginPairsByPriority(continuousPairsForSimpleEventPlugin, ContinuousEvent); // Not used by SimpleEventPlugin 4234 4235 processTopEventPairsByPriority(otherDiscreteEvents, DiscreteEvent); 4236 function getEventPriorityForPluginSystem(topLevelType) { 4237 var priority = eventPriorities.get(topLevelType); // Default to a ContinuousEvent. Note: we might 4238 // want to warn if we can't detect the priority 4239 // for the event. 4240 4241 return priority === undefined ? ContinuousEvent : priority; 4242 } 4243 4244 // Intentionally not named imports because Rollup would use dynamic dispatch for 4245 var UserBlockingPriority = unstable_UserBlockingPriority, 4246 runWithPriority = unstable_runWithPriority; // TODO: can we stop exporting these? 4247 4248 var _enabled = true; 4249 function setEnabled(enabled) { 4250 _enabled = !!enabled; 4251 } 4252 function isEnabled() { 4253 return _enabled; 4254 } 4255 function trapBubbledEvent(topLevelType, element) { 4256 trapEventForPluginEventSystem(element, topLevelType, false); 4257 } 4258 function trapCapturedEvent(topLevelType, element) { 4259 trapEventForPluginEventSystem(element, topLevelType, true); 4260 } 4261 4262 function trapEventForPluginEventSystem(container, topLevelType, capture) { 4263 var listener; 4264 4265 switch (getEventPriorityForPluginSystem(topLevelType)) { 4266 case DiscreteEvent: 4267 listener = dispatchDiscreteEvent.bind(null, topLevelType, PLUGIN_EVENT_SYSTEM, container); 4268 break; 4269 4270 case UserBlockingEvent: 4271 listener = dispatchUserBlockingUpdate.bind(null, topLevelType, PLUGIN_EVENT_SYSTEM, container); 4272 break; 4273 4274 case ContinuousEvent: 4275 default: 4276 listener = dispatchEvent.bind(null, topLevelType, PLUGIN_EVENT_SYSTEM, container); 4277 break; 4278 } 4279 4280 var rawEventName = getRawEventName(topLevelType); 4281 4282 if (capture) { 4283 addEventCaptureListener(container, rawEventName, listener); 4284 } else { 4285 addEventBubbleListener(container, rawEventName, listener); 4286 } 4287 } 4288 4289 function dispatchDiscreteEvent(topLevelType, eventSystemFlags, container, nativeEvent) { 4290 flushDiscreteUpdatesIfNeeded(nativeEvent.timeStamp); 4291 discreteUpdates(dispatchEvent, topLevelType, eventSystemFlags, container, nativeEvent); 4292 } 4293 4294 function dispatchUserBlockingUpdate(topLevelType, eventSystemFlags, container, nativeEvent) { 4295 runWithPriority(UserBlockingPriority, dispatchEvent.bind(null, topLevelType, eventSystemFlags, container, nativeEvent)); 4296 } 4297 4298 function dispatchEvent(topLevelType, eventSystemFlags, container, nativeEvent) { 4299 if (!_enabled) { 4300 return; 4301 } 4302 4303 if (hasQueuedDiscreteEvents() && isReplayableDiscreteEvent(topLevelType)) { 4304 // If we already have a queue of discrete events, and this is another discrete 4305 // event, then we can't dispatch it regardless of its target, since they 4306 // need to dispatch in order. 4307 queueDiscreteEvent(null, // Flags that we're not actually blocked on anything as far as we know. 4308 topLevelType, eventSystemFlags, container, nativeEvent); 4309 return; 4310 } 4311 4312 var blockedOn = attemptToDispatchEvent(topLevelType, eventSystemFlags, container, nativeEvent); 4313 4314 if (blockedOn === null) { 4315 // We successfully dispatched this event. 4316 clearIfContinuousEvent(topLevelType, nativeEvent); 4317 return; 4318 } 4319 4320 if (isReplayableDiscreteEvent(topLevelType)) { 4321 // This this to be replayed later once the target is available. 4322 queueDiscreteEvent(blockedOn, topLevelType, eventSystemFlags, container, nativeEvent); 4323 return; 4324 } 4325 4326 if (queueIfContinuousEvent(blockedOn, topLevelType, eventSystemFlags, container, nativeEvent)) { 4327 return; 4328 } // We need to clear only if we didn't queue because 4329 // queueing is accummulative. 4330 4331 4332 clearIfContinuousEvent(topLevelType, nativeEvent); // This is not replayable so we'll invoke it but without a target, 4333 // in case the event system needs to trace it. 4334 4335 { 4336 dispatchEventForLegacyPluginEventSystem(topLevelType, eventSystemFlags, nativeEvent, null); 4337 } 4338 } // Attempt dispatching an event. Returns a SuspenseInstance or Container if it's blocked. 4339 4340 function attemptToDispatchEvent(topLevelType, eventSystemFlags, container, nativeEvent) { 4341 // TODO: Warn if _enabled is false. 4342 var nativeEventTarget = getEventTarget(nativeEvent); 4343 var targetInst = getClosestInstanceFromNode(nativeEventTarget); 4344 4345 if (targetInst !== null) { 4346 var nearestMounted = getNearestMountedFiber(targetInst); 4347 4348 if (nearestMounted === null) { 4349 // This tree has been unmounted already. Dispatch without a target. 4350 targetInst = null; 4351 } else { 4352 var tag = nearestMounted.tag; 4353 4354 if (tag === SuspenseComponent) { 4355 var instance = getSuspenseInstanceFromFiber(nearestMounted); 4356 4357 if (instance !== null) { 4358 // Queue the event to be replayed later. Abort dispatching since we 4359 // don't want this event dispatched twice through the event system. 4360 // TODO: If this is the first discrete event in the queue. Schedule an increased 4361 // priority for this boundary. 4362 return instance; 4363 } // This shouldn't happen, something went wrong but to avoid blocking 4364 // the whole system, dispatch the event without a target. 4365 // TODO: Warn. 4366 4367 4368 targetInst = null; 4369 } else if (tag === HostRoot) { 4370 var root = nearestMounted.stateNode; 4371 4372 if (root.hydrate) { 4373 // If this happens during a replay something went wrong and it might block 4374 // the whole system. 4375 return getContainerFromFiber(nearestMounted); 4376 } 4377 4378 targetInst = null; 4379 } else if (nearestMounted !== targetInst) { 4380 // If we get an event (ex: img onload) before committing that 4381 // component's mount, ignore it for now (that is, treat it as if it was an 4382 // event on a non-React tree). We might also consider queueing events and 4383 // dispatching them after the mount. 4384 targetInst = null; 4385 } 4386 } 4387 } 4388 4389 { 4390 dispatchEventForLegacyPluginEventSystem(topLevelType, eventSystemFlags, nativeEvent, targetInst); 4391 } // We're not blocked on anything. 4392 4393 4394 return null; 4395 } 4396 4397 // List derived from Gecko source code: 4398 // https://github.com/mozilla/gecko-dev/blob/4e638efc71/layout/style/test/property_database.js 4399 var shorthandToLonghand = { 4400 animation: ['animationDelay', 'animationDirection', 'animationDuration', 'animationFillMode', 'animationIterationCount', 'animationName', 'animationPlayState', 'animationTimingFunction'], 4401 background: ['backgroundAttachment', 'backgroundClip', 'backgroundColor', 'backgroundImage', 'backgroundOrigin', 'backgroundPositionX', 'backgroundPositionY', 'backgroundRepeat', 'backgroundSize'], 4402 backgroundPosition: ['backgroundPositionX', 'backgroundPositionY'], 4403 border: ['borderBottomColor', 'borderBottomStyle', 'borderBottomWidth', 'borderImageOutset', 'borderImageRepeat', 'borderImageSlice', 'borderImageSource', 'borderImageWidth', 'borderLeftColor', 'borderLeftStyle', 'borderLeftWidth', 'borderRightColor', 'borderRightStyle', 'borderRightWidth', 'borderTopColor', 'borderTopStyle', 'borderTopWidth'], 4404 borderBlockEnd: ['borderBlockEndColor', 'borderBlockEndStyle', 'borderBlockEndWidth'], 4405 borderBlockStart: ['borderBlockStartColor', 'borderBlockStartStyle', 'borderBlockStartWidth'], 4406 borderBottom: ['borderBottomColor', 'borderBottomStyle', 'borderBottomWidth'], 4407 borderColor: ['borderBottomColor', 'borderLeftColor', 'borderRightColor', 'borderTopColor'], 4408 borderImage: ['borderImageOutset', 'borderImageRepeat', 'borderImageSlice', 'borderImageSource', 'borderImageWidth'], 4409 borderInlineEnd: ['borderInlineEndColor', 'borderInlineEndStyle', 'borderInlineEndWidth'], 4410 borderInlineStart: ['borderInlineStartColor', 'borderInlineStartStyle', 'borderInlineStartWidth'], 4411 borderLeft: ['borderLeftColor', 'borderLeftStyle', 'borderLeftWidth'], 4412 borderRadius: ['borderBottomLeftRadius', 'borderBottomRightRadius', 'borderTopLeftRadius', 'borderTopRightRadius'], 4413 borderRight: ['borderRightColor', 'borderRightStyle', 'borderRightWidth'], 4414 borderStyle: ['borderBottomStyle', 'borderLeftStyle', 'borderRightStyle', 'borderTopStyle'], 4415 borderTop: ['borderTopColor', 'borderTopStyle', 'borderTopWidth'], 4416 borderWidth: ['borderBottomWidth', 'borderLeftWidth', 'borderRightWidth', 'borderTopWidth'], 4417 columnRule: ['columnRuleColor', 'columnRuleStyle', 'columnRuleWidth'], 4418 columns: ['columnCount', 'columnWidth'], 4419 flex: ['flexBasis', 'flexGrow', 'flexShrink'], 4420 flexFlow: ['flexDirection', 'flexWrap'], 4421 font: ['fontFamily', 'fontFeatureSettings', 'fontKerning', 'fontLanguageOverride', 'fontSize', 'fontSizeAdjust', 'fontStretch', 'fontStyle', 'fontVariant', 'fontVariantAlternates', 'fontVariantCaps', 'fontVariantEastAsian', 'fontVariantLigatures', 'fontVariantNumeric', 'fontVariantPosition', 'fontWeight', 'lineHeight'], 4422 fontVariant: ['fontVariantAlternates', 'fontVariantCaps', 'fontVariantEastAsian', 'fontVariantLigatures', 'fontVariantNumeric', 'fontVariantPosition'], 4423 gap: ['columnGap', 'rowGap'], 4424 grid: ['gridAutoColumns', 'gridAutoFlow', 'gridAutoRows', 'gridTemplateAreas', 'gridTemplateColumns', 'gridTemplateRows'], 4425 gridArea: ['gridColumnEnd', 'gridColumnStart', 'gridRowEnd', 'gridRowStart'], 4426 gridColumn: ['gridColumnEnd', 'gridColumnStart'], 4427 gridColumnGap: ['columnGap'], 4428 gridGap: ['columnGap', 'rowGap'], 4429 gridRow: ['gridRowEnd', 'gridRowStart'], 4430 gridRowGap: ['rowGap'], 4431 gridTemplate: ['gridTemplateAreas', 'gridTemplateColumns', 'gridTemplateRows'], 4432 listStyle: ['listStyleImage', 'listStylePosition', 'listStyleType'], 4433 margin: ['marginBottom', 'marginLeft', 'marginRight', 'marginTop'], 4434 marker: ['markerEnd', 'markerMid', 'markerStart'], 4435 mask: ['maskClip', 'maskComposite', 'maskImage', 'maskMode', 'maskOrigin', 'maskPositionX', 'maskPositionY', 'maskRepeat', 'maskSize'], 4436 maskPosition: ['maskPositionX', 'maskPositionY'], 4437 outline: ['outlineColor', 'outlineStyle', 'outlineWidth'], 4438 overflow: ['overflowX', 'overflowY'], 4439 padding: ['paddingBottom', 'paddingLeft', 'paddingRight', 'paddingTop'], 4440 placeContent: ['alignContent', 'justifyContent'], 4441 placeItems: ['alignItems', 'justifyItems'], 4442 placeSelf: ['alignSelf', 'justifySelf'], 4443 textDecoration: ['textDecorationColor', 'textDecorationLine', 'textDecorationStyle'], 4444 textEmphasis: ['textEmphasisColor', 'textEmphasisStyle'], 4445 transition: ['transitionDelay', 'transitionDuration', 'transitionProperty', 'transitionTimingFunction'], 4446 wordWrap: ['overflowWrap'] 4447 }; 4448 4449 /** 4450 * CSS properties which accept numbers but are not in units of "px". 4451 */ 4452 var isUnitlessNumber = { 4453 animationIterationCount: true, 4454 borderImageOutset: true, 4455 borderImageSlice: true, 4456 borderImageWidth: true, 4457 boxFlex: true, 4458 boxFlexGroup: true, 4459 boxOrdinalGroup: true, 4460 columnCount: true, 4461 columns: true, 4462 flex: true, 4463 flexGrow: true, 4464 flexPositive: true, 4465 flexShrink: true, 4466 flexNegative: true, 4467 flexOrder: true, 4468 gridArea: true, 4469 gridRow: true, 4470 gridRowEnd: true, 4471 gridRowSpan: true, 4472 gridRowStart: true, 4473 gridColumn: true, 4474 gridColumnEnd: true, 4475 gridColumnSpan: true, 4476 gridColumnStart: true, 4477 fontWeight: true, 4478 lineClamp: true, 4479 lineHeight: true, 4480 opacity: true, 4481 order: true, 4482 orphans: true, 4483 tabSize: true, 4484 widows: true, 4485 zIndex: true, 4486 zoom: true, 4487 // SVG-related properties 4488 fillOpacity: true, 4489 floodOpacity: true, 4490 stopOpacity: true, 4491 strokeDasharray: true, 4492 strokeDashoffset: true, 4493 strokeMiterlimit: true, 4494 strokeOpacity: true, 4495 strokeWidth: true 4496 }; 4497 /** 4498 * @param {string} prefix vendor-specific prefix, eg: Webkit 4499 * @param {string} key style name, eg: transitionDuration 4500 * @return {string} style name prefixed with `prefix`, properly camelCased, eg: 4501 * WebkitTransitionDuration 4502 */ 4503 4504 function prefixKey(prefix, key) { 4505 return prefix + key.charAt(0).toUpperCase() + key.substring(1); 4506 } 4507 /** 4508 * Support style names that may come passed in prefixed by adding permutations 4509 * of vendor prefixes. 4510 */ 4511 4512 4513 var prefixes = ['Webkit', 'ms', 'Moz', 'O']; // Using Object.keys here, or else the vanilla for-in loop makes IE8 go into an 4514 // infinite loop, because it iterates over the newly added props too. 4515 4516 Object.keys(isUnitlessNumber).forEach(function (prop) { 4517 prefixes.forEach(function (prefix) { 4518 isUnitlessNumber[prefixKey(prefix, prop)] = isUnitlessNumber[prop]; 4519 }); 4520 }); 4521 4522 /** 4523 * Convert a value into the proper css writable value. The style name `name` 4524 * should be logical (no hyphens), as specified 4525 * in `CSSProperty.isUnitlessNumber`. 4526 * 4527 * @param {string} name CSS property name such as `topMargin`. 4528 * @param {*} value CSS property value such as `10px`. 4529 * @return {string} Normalized style value with dimensions applied. 4530 */ 4531 4532 function dangerousStyleValue(name, value, isCustomProperty) { 4533 // Note that we've removed escapeTextForBrowser() calls here since the 4534 // whole string will be escaped when the attribute is injected into 4535 // the markup. If you provide unsafe user data here they can inject 4536 // arbitrary CSS which may be problematic (I couldn't repro this): 4537 // https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet 4538 // http://www.thespanner.co.uk/2007/11/26/ultimate-xss-css-injection/ 4539 // This is not an XSS hole but instead a potential CSS injection issue 4540 // which has lead to a greater discussion about how we're going to 4541 // trust URLs moving forward. See #2115901 4542 var isEmpty = value == null || typeof value === 'boolean' || value === ''; 4543 4544 if (isEmpty) { 4545 return ''; 4546 } 4547 4548 if (!isCustomProperty && typeof value === 'number' && value !== 0 && !(isUnitlessNumber.hasOwnProperty(name) && isUnitlessNumber[name])) { 4549 return value + 'px'; // Presumes implicit 'px' suffix for unitless numbers 4550 } 4551 4552 return ('' + value).trim(); 4553 } 4554 4555 var uppercasePattern = /([A-Z])/g; 4556 var msPattern = /^ms-/; 4557 /** 4558 * Hyphenates a camelcased CSS property name, for example: 4559 * 4560 * > hyphenateStyleName('backgroundColor') 4561 * < "background-color" 4562 * > hyphenateStyleName('MozTransition') 4563 * < "-moz-transition" 4564 * > hyphenateStyleName('msTransition') 4565 * < "-ms-transition" 4566 * 4567 * As Modernizr suggests (http://modernizr.com/docs/#prefixed), an `ms` prefix 4568 * is converted to `-ms-`. 4569 */ 4570 4571 function hyphenateStyleName(name) { 4572 return name.replace(uppercasePattern, '-$1').toLowerCase().replace(msPattern, '-ms-'); 4573 } 4574 4575 var warnValidStyle = function () {}; 4576 4577 { 4578 // 'msTransform' is correct, but the other prefixes should be capitalized 4579 var badVendoredStyleNamePattern = /^(?:webkit|moz|o)[A-Z]/; 4580 var msPattern$1 = /^-ms-/; 4581 var hyphenPattern = /-(.)/g; // style values shouldn't contain a semicolon 4582 4583 var badStyleValueWithSemicolonPattern = /;\s*$/; 4584 var warnedStyleNames = {}; 4585 var warnedStyleValues = {}; 4586 var warnedForNaNValue = false; 4587 var warnedForInfinityValue = false; 4588 4589 var camelize = function (string) { 4590 return string.replace(hyphenPattern, function (_, character) { 4591 return character.toUpperCase(); 4592 }); 4593 }; 4594 4595 var warnHyphenatedStyleName = function (name) { 4596 if (warnedStyleNames.hasOwnProperty(name) && warnedStyleNames[name]) { 4597 return; 4598 } 4599 4600 warnedStyleNames[name] = true; 4601 4602 error('Unsupported style property %s. Did you mean %s?', name, // As Andi Smith suggests 4603 // (http://www.andismith.com/blog/2012/02/modernizr-prefixed/), an `-ms` prefix 4604 // is converted to lowercase `ms`. 4605 camelize(name.replace(msPattern$1, 'ms-'))); 4606 }; 4607 4608 var warnBadVendoredStyleName = function (name) { 4609 if (warnedStyleNames.hasOwnProperty(name) && warnedStyleNames[name]) { 4610 return; 4611 } 4612 4613 warnedStyleNames[name] = true; 4614 4615 error('Unsupported vendor-prefixed style property %s. Did you mean %s?', name, name.charAt(0).toUpperCase() + name.slice(1)); 4616 }; 4617 4618 var warnStyleValueWithSemicolon = function (name, value) { 4619 if (warnedStyleValues.hasOwnProperty(value) && warnedStyleValues[value]) { 4620 return; 4621 } 4622 4623 warnedStyleValues[value] = true; 4624 4625 error("Style property values shouldn't contain a semicolon. " + 'Try "%s: %s" instead.', name, value.replace(badStyleValueWithSemicolonPattern, '')); 4626 }; 4627 4628 var warnStyleValueIsNaN = function (name, value) { 4629 if (warnedForNaNValue) { 4630 return; 4631 } 4632 4633 warnedForNaNValue = true; 4634 4635 error('`NaN` is an invalid value for the `%s` css style property.', name); 4636 }; 4637 4638 var warnStyleValueIsInfinity = function (name, value) { 4639 if (warnedForInfinityValue) { 4640 return; 4641 } 4642 4643 warnedForInfinityValue = true; 4644 4645 error('`Infinity` is an invalid value for the `%s` css style property.', name); 4646 }; 4647 4648 warnValidStyle = function (name, value) { 4649 if (name.indexOf('-') > -1) { 4650 warnHyphenatedStyleName(name); 4651 } else if (badVendoredStyleNamePattern.test(name)) { 4652 warnBadVendoredStyleName(name); 4653 } else if (badStyleValueWithSemicolonPattern.test(value)) { 4654 warnStyleValueWithSemicolon(name, value); 4655 } 4656 4657 if (typeof value === 'number') { 4658 if (isNaN(value)) { 4659 warnStyleValueIsNaN(name, value); 4660 } else if (!isFinite(value)) { 4661 warnStyleValueIsInfinity(name, value); 4662 } 4663 } 4664 }; 4665 } 4666 4667 var warnValidStyle$1 = warnValidStyle; 4668 4669 /** 4670 * Operations for dealing with CSS properties. 4671 */ 4672 4673 /** 4674 * This creates a string that is expected to be equivalent to the style 4675 * attribute generated by server-side rendering. It by-passes warnings and 4676 * security checks so it's not safe to use this value for anything other than 4677 * comparison. It is only used in DEV for SSR validation. 4678 */ 4679 4680 function createDangerousStringForStyles(styles) { 4681 { 4682 var serialized = ''; 4683 var delimiter = ''; 4684 4685 for (var styleName in styles) { 4686 if (!styles.hasOwnProperty(styleName)) { 4687 continue; 4688 } 4689 4690 var styleValue = styles[styleName]; 4691 4692 if (styleValue != null) { 4693 var isCustomProperty = styleName.indexOf('--') === 0; 4694 serialized += delimiter + (isCustomProperty ? styleName : hyphenateStyleName(styleName)) + ':'; 4695 serialized += dangerousStyleValue(styleName, styleValue, isCustomProperty); 4696 delimiter = ';'; 4697 } 4698 } 4699 4700 return serialized || null; 4701 } 4702 } 4703 /** 4704 * Sets the value for multiple styles on a node. If a value is specified as 4705 * '' (empty string), the corresponding style property will be unset. 4706 * 4707 * @param {DOMElement} node 4708 * @param {object} styles 4709 */ 4710 4711 function setValueForStyles(node, styles) { 4712 var style = node.style; 4713 4714 for (var styleName in styles) { 4715 if (!styles.hasOwnProperty(styleName)) { 4716 continue; 4717 } 4718 4719 var isCustomProperty = styleName.indexOf('--') === 0; 4720 4721 { 4722 if (!isCustomProperty) { 4723 warnValidStyle$1(styleName, styles[styleName]); 4724 } 4725 } 4726 4727 var styleValue = dangerousStyleValue(styleName, styles[styleName], isCustomProperty); 4728 4729 if (styleName === 'float') { 4730 styleName = 'cssFloat'; 4731 } 4732 4733 if (isCustomProperty) { 4734 style.setProperty(styleName, styleValue); 4735 } else { 4736 style[styleName] = styleValue; 4737 } 4738 } 4739 } 4740 4741 function isValueEmpty(value) { 4742 return value == null || typeof value === 'boolean' || value === ''; 4743 } 4744 /** 4745 * Given {color: 'red', overflow: 'hidden'} returns { 4746 * color: 'color', 4747 * overflowX: 'overflow', 4748 * overflowY: 'overflow', 4749 * }. This can be read as "the overflowY property was set by the overflow 4750 * shorthand". That is, the values are the property that each was derived from. 4751 */ 4752 4753 4754 function expandShorthandMap(styles) { 4755 var expanded = {}; 4756 4757 for (var key in styles) { 4758 var longhands = shorthandToLonghand[key] || [key]; 4759 4760 for (var i = 0; i < longhands.length; i++) { 4761 expanded[longhands[i]] = key; 4762 } 4763 } 4764 4765 return expanded; 4766 } 4767 /** 4768 * When mixing shorthand and longhand property names, we warn during updates if 4769 * we expect an incorrect result to occur. In particular, we warn for: 4770 * 4771 * Updating a shorthand property (longhand gets overwritten): 4772 * {font: 'foo', fontVariant: 'bar'} -> {font: 'baz', fontVariant: 'bar'} 4773 * becomes .style.font = 'baz' 4774 * Removing a shorthand property (longhand gets lost too): 4775 * {font: 'foo', fontVariant: 'bar'} -> {fontVariant: 'bar'} 4776 * becomes .style.font = '' 4777 * Removing a longhand property (should revert to shorthand; doesn't): 4778 * {font: 'foo', fontVariant: 'bar'} -> {font: 'foo'} 4779 * becomes .style.fontVariant = '' 4780 */ 4781 4782 4783 function validateShorthandPropertyCollisionInDev(styleUpdates, nextStyles) { 4784 { 4785 4786 if (!nextStyles) { 4787 return; 4788 } 4789 4790 var expandedUpdates = expandShorthandMap(styleUpdates); 4791 var expandedStyles = expandShorthandMap(nextStyles); 4792 var warnedAbout = {}; 4793 4794 for (var key in expandedUpdates) { 4795 var originalKey = expandedUpdates[key]; 4796 var correctOriginalKey = expandedStyles[key]; 4797 4798 if (correctOriginalKey && originalKey !== correctOriginalKey) { 4799 var warningKey = originalKey + ',' + correctOriginalKey; 4800 4801 if (warnedAbout[warningKey]) { 4802 continue; 4803 } 4804 4805 warnedAbout[warningKey] = true; 4806 4807 error('%s a style property during rerender (%s) when a ' + 'conflicting property is set (%s) can lead to styling bugs. To ' + "avoid this, don't mix shorthand and non-shorthand properties " + 'for the same value; instead, replace the shorthand with ' + 'separate values.', isValueEmpty(styleUpdates[originalKey]) ? 'Removing' : 'Updating', originalKey, correctOriginalKey); 4808 } 4809 } 4810 } 4811 } 4812 4813 // For HTML, certain tags should omit their close tag. We keep a whitelist for 4814 // those special-case tags. 4815 var omittedCloseTags = { 4816 area: true, 4817 base: true, 4818 br: true, 4819 col: true, 4820 embed: true, 4821 hr: true, 4822 img: true, 4823 input: true, 4824 keygen: true, 4825 link: true, 4826 meta: true, 4827 param: true, 4828 source: true, 4829 track: true, 4830 wbr: true // NOTE: menuitem's close tag should be omitted, but that causes problems. 4831 4832 }; 4833 4834 // `omittedCloseTags` except that `menuitem` should still have its closing tag. 4835 4836 var voidElementTags = _assign({ 4837 menuitem: true 4838 }, omittedCloseTags); 4839 4840 var HTML = '__html'; 4841 var ReactDebugCurrentFrame$3 = null; 4842 4843 { 4844 ReactDebugCurrentFrame$3 = ReactSharedInternals.ReactDebugCurrentFrame; 4845 } 4846 4847 function assertValidProps(tag, props) { 4848 if (!props) { 4849 return; 4850 } // Note the use of `==` which checks for null or undefined. 4851 4852 4853 if (voidElementTags[tag]) { 4854 if (!(props.children == null && props.dangerouslySetInnerHTML == null)) { 4855 { 4856 throw Error( tag + " is a void element tag and must neither have `children` nor use `dangerouslySetInnerHTML`." + ( ReactDebugCurrentFrame$3.getStackAddendum() ) ); 4857 } 4858 } 4859 } 4860 4861 if (props.dangerouslySetInnerHTML != null) { 4862 if (!(props.children == null)) { 4863 { 4864 throw Error( "Can only set one of `children` or `props.dangerouslySetInnerHTML`." ); 4865 } 4866 } 4867 4868 if (!(typeof props.dangerouslySetInnerHTML === 'object' && HTML in props.dangerouslySetInnerHTML)) { 4869 { 4870 throw Error( "`props.dangerouslySetInnerHTML` must be in the form `{__html: ...}`. Please visit https://fb.me/react-invariant-dangerously-set-inner-html for more information." ); 4871 } 4872 } 4873 } 4874 4875 { 4876 if (!props.suppressContentEditableWarning && props.contentEditable && props.children != null) { 4877 error('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.'); 4878 } 4879 } 4880 4881 if (!(props.style == null || typeof props.style === 'object')) { 4882 { 4883 throw Error( "The `style` prop expects a mapping from style properties to values, not a string. For example, style={{marginRight: spacing + 'em'}} when using JSX." + ( ReactDebugCurrentFrame$3.getStackAddendum() ) ); 4884 } 4885 } 4886 } 4887 4888 function isCustomComponent(tagName, props) { 4889 if (tagName.indexOf('-') === -1) { 4890 return typeof props.is === 'string'; 4891 } 4892 4893 switch (tagName) { 4894 // These are reserved SVG and MathML elements. 4895 // We don't mind this whitelist too much because we expect it to never grow. 4896 // The alternative is to track the namespace in a few places which is convoluted. 4897 // https://w3c.github.io/webcomponents/spec/custom/#custom-elements-core-concepts 4898 case 'annotation-xml': 4899 case 'color-profile': 4900 case 'font-face': 4901 case 'font-face-src': 4902 case 'font-face-uri': 4903 case 'font-face-format': 4904 case 'font-face-name': 4905 case 'missing-glyph': 4906 return false; 4907 4908 default: 4909 return true; 4910 } 4911 } 4912 4913 // When adding attributes to the HTML or SVG whitelist, be sure to 4914 // also add them to this module to ensure casing and incorrect name 4915 // warnings. 4916 var possibleStandardNames = { 4917 // HTML 4918 accept: 'accept', 4919 acceptcharset: 'acceptCharset', 4920 'accept-charset': 'acceptCharset', 4921 accesskey: 'accessKey', 4922 action: 'action', 4923 allowfullscreen: 'allowFullScreen', 4924 alt: 'alt', 4925 as: 'as', 4926 async: 'async', 4927 autocapitalize: 'autoCapitalize', 4928 autocomplete: 'autoComplete', 4929 autocorrect: 'autoCorrect', 4930 autofocus: 'autoFocus', 4931 autoplay: 'autoPlay', 4932 autosave: 'autoSave', 4933 capture: 'capture', 4934 cellpadding: 'cellPadding', 4935 cellspacing: 'cellSpacing', 4936 challenge: 'challenge', 4937 charset: 'charSet', 4938 checked: 'checked', 4939 children: 'children', 4940 cite: 'cite', 4941 class: 'className', 4942 classid: 'classID', 4943 classname: 'className', 4944 cols: 'cols', 4945 colspan: 'colSpan', 4946 content: 'content', 4947 contenteditable: 'contentEditable', 4948 contextmenu: 'contextMenu', 4949 controls: 'controls', 4950 controlslist: 'controlsList', 4951 coords: 'coords', 4952 crossorigin: 'crossOrigin', 4953 dangerouslysetinnerhtml: 'dangerouslySetInnerHTML', 4954 data: 'data', 4955 datetime: 'dateTime', 4956 default: 'default', 4957 defaultchecked: 'defaultChecked', 4958 defaultvalue: 'defaultValue', 4959 defer: 'defer', 4960 dir: 'dir', 4961 disabled: 'disabled', 4962 disablepictureinpicture: 'disablePictureInPicture', 4963 download: 'download', 4964 draggable: 'draggable', 4965 enctype: 'encType', 4966 for: 'htmlFor', 4967 form: 'form', 4968 formmethod: 'formMethod', 4969 formaction: 'formAction', 4970 formenctype: 'formEncType', 4971 formnovalidate: 'formNoValidate', 4972 formtarget: 'formTarget', 4973 frameborder: 'frameBorder', 4974 headers: 'headers', 4975 height: 'height', 4976 hidden: 'hidden', 4977 high: 'high', 4978 href: 'href', 4979 hreflang: 'hrefLang', 4980 htmlfor: 'htmlFor', 4981 httpequiv: 'httpEquiv', 4982 'http-equiv': 'httpEquiv', 4983 icon: 'icon', 4984 id: 'id', 4985 innerhtml: 'innerHTML', 4986 inputmode: 'inputMode', 4987 integrity: 'integrity', 4988 is: 'is', 4989 itemid: 'itemID', 4990 itemprop: 'itemProp', 4991 itemref: 'itemRef', 4992 itemscope: 'itemScope', 4993 itemtype: 'itemType', 4994 keyparams: 'keyParams', 4995 keytype: 'keyType', 4996 kind: 'kind', 4997 label: 'label', 4998 lang: 'lang', 4999 list: 'list', 5000 loop: 'loop', 5001 low: 'low', 5002 manifest: 'manifest', 5003 marginwidth: 'marginWidth', 5004 marginheight: 'marginHeight', 5005 max: 'max', 5006 maxlength: 'maxLength', 5007 media: 'media', 5008 mediagroup: 'mediaGroup', 5009 method: 'method', 5010 min: 'min', 5011 minlength: 'minLength', 5012 multiple: 'multiple', 5013 muted: 'muted', 5014 name: 'name', 5015 nomodule: 'noModule', 5016 nonce: 'nonce', 5017 novalidate: 'noValidate', 5018 open: 'open', 5019 optimum: 'optimum', 5020 pattern: 'pattern', 5021 placeholder: 'placeholder', 5022 playsinline: 'playsInline', 5023 poster: 'poster', 5024 preload: 'preload', 5025 profile: 'profile', 5026 radiogroup: 'radioGroup', 5027 readonly: 'readOnly', 5028 referrerpolicy: 'referrerPolicy', 5029 rel: 'rel', 5030 required: 'required', 5031 reversed: 'reversed', 5032 role: 'role', 5033 rows: 'rows', 5034 rowspan: 'rowSpan', 5035 sandbox: 'sandbox', 5036 scope: 'scope', 5037 scoped: 'scoped', 5038 scrolling: 'scrolling', 5039 seamless: 'seamless', 5040 selected: 'selected', 5041 shape: 'shape', 5042 size: 'size', 5043 sizes: 'sizes', 5044 span: 'span', 5045 spellcheck: 'spellCheck', 5046 src: 'src', 5047 srcdoc: 'srcDoc', 5048 srclang: 'srcLang', 5049 srcset: 'srcSet', 5050 start: 'start', 5051 step: 'step', 5052 style: 'style', 5053 summary: 'summary', 5054 tabindex: 'tabIndex', 5055 target: 'target', 5056 title: 'title', 5057 type: 'type', 5058 usemap: 'useMap', 5059 value: 'value', 5060 width: 'width', 5061 wmode: 'wmode', 5062 wrap: 'wrap', 5063 // SVG 5064 about: 'about', 5065 accentheight: 'accentHeight', 5066 'accent-height': 'accentHeight', 5067 accumulate: 'accumulate', 5068 additive: 'additive', 5069 alignmentbaseline: 'alignmentBaseline', 5070 'alignment-baseline': 'alignmentBaseline', 5071 allowreorder: 'allowReorder', 5072 alphabetic: 'alphabetic', 5073 amplitude: 'amplitude', 5074 arabicform: 'arabicForm', 5075 'arabic-form': 'arabicForm', 5076 ascent: 'ascent', 5077 attributename: 'attributeName', 5078 attributetype: 'attributeType', 5079 autoreverse: 'autoReverse', 5080 azimuth: 'azimuth', 5081 basefrequency: 'baseFrequency', 5082 baselineshift: 'baselineShift', 5083 'baseline-shift': 'baselineShift', 5084 baseprofile: 'baseProfile', 5085 bbox: 'bbox', 5086 begin: 'begin', 5087 bias: 'bias', 5088 by: 'by', 5089 calcmode: 'calcMode', 5090 capheight: 'capHeight', 5091 'cap-height': 'capHeight', 5092 clip: 'clip', 5093 clippath: 'clipPath', 5094 'clip-path': 'clipPath', 5095 clippathunits: 'clipPathUnits', 5096 cliprule: 'clipRule', 5097 'clip-rule': 'clipRule', 5098 color: 'color', 5099 colorinterpolation: 'colorInterpolation', 5100 'color-interpolation': 'colorInterpolation', 5101 colorinterpolationfilters: 'colorInterpolationFilters', 5102 'color-interpolation-filters': 'colorInterpolationFilters', 5103 colorprofile: 'colorProfile', 5104 'color-profile': 'colorProfile', 5105 colorrendering: 'colorRendering', 5106 'color-rendering': 'colorRendering', 5107 contentscripttype: 'contentScriptType', 5108 contentstyletype: 'contentStyleType', 5109 cursor: 'cursor', 5110 cx: 'cx', 5111 cy: 'cy', 5112 d: 'd', 5113 datatype: 'datatype', 5114 decelerate: 'decelerate', 5115 descent: 'descent', 5116 diffuseconstant: 'diffuseConstant', 5117 direction: 'direction', 5118 display: 'display', 5119 divisor: 'divisor', 5120 dominantbaseline: 'dominantBaseline', 5121 'dominant-baseline': 'dominantBaseline', 5122 dur: 'dur', 5123 dx: 'dx', 5124 dy: 'dy', 5125 edgemode: 'edgeMode', 5126 elevation: 'elevation', 5127 enablebackground: 'enableBackground', 5128 'enable-background': 'enableBackground', 5129 end: 'end', 5130 exponent: 'exponent', 5131 externalresourcesrequired: 'externalResourcesRequired', 5132 fill: 'fill', 5133 fillopacity: 'fillOpacity', 5134 'fill-opacity': 'fillOpacity', 5135 fillrule: 'fillRule', 5136 'fill-rule': 'fillRule', 5137 filter: 'filter', 5138 filterres: 'filterRes', 5139 filterunits: 'filterUnits', 5140 floodopacity: 'floodOpacity', 5141 'flood-opacity': 'floodOpacity', 5142 floodcolor: 'floodColor', 5143 'flood-color': 'floodColor', 5144 focusable: 'focusable', 5145 fontfamily: 'fontFamily', 5146 'font-family': 'fontFamily', 5147 fontsize: 'fontSize', 5148 'font-size': 'fontSize', 5149 fontsizeadjust: 'fontSizeAdjust', 5150 'font-size-adjust': 'fontSizeAdjust', 5151 fontstretch: 'fontStretch', 5152 'font-stretch': 'fontStretch', 5153 fontstyle: 'fontStyle', 5154 'font-style': 'fontStyle', 5155 fontvariant: 'fontVariant', 5156 'font-variant': 'fontVariant', 5157 fontweight: 'fontWeight', 5158 'font-weight': 'fontWeight', 5159 format: 'format', 5160 from: 'from', 5161 fx: 'fx', 5162 fy: 'fy', 5163 g1: 'g1', 5164 g2: 'g2', 5165 glyphname: 'glyphName', 5166 'glyph-name': 'glyphName', 5167 glyphorientationhorizontal: 'glyphOrientationHorizontal', 5168 'glyph-orientation-horizontal': 'glyphOrientationHorizontal', 5169 glyphorientationvertical: 'glyphOrientationVertical', 5170 'glyph-orientation-vertical': 'glyphOrientationVertical', 5171 glyphref: 'glyphRef', 5172 gradienttransform: 'gradientTransform', 5173 gradientunits: 'gradientUnits', 5174 hanging: 'hanging', 5175 horizadvx: 'horizAdvX', 5176 'horiz-adv-x': 'horizAdvX', 5177 horizoriginx: 'horizOriginX', 5178 'horiz-origin-x': 'horizOriginX', 5179 ideographic: 'ideographic', 5180 imagerendering: 'imageRendering', 5181 'image-rendering': 'imageRendering', 5182 in2: 'in2', 5183 in: 'in', 5184 inlist: 'inlist', 5185 intercept: 'intercept', 5186 k1: 'k1', 5187 k2: 'k2', 5188 k3: 'k3', 5189 k4: 'k4', 5190 k: 'k', 5191 kernelmatrix: 'kernelMatrix', 5192 kernelunitlength: 'kernelUnitLength', 5193 kerning: 'kerning', 5194 keypoints: 'keyPoints', 5195 keysplines: 'keySplines', 5196 keytimes: 'keyTimes', 5197 lengthadjust: 'lengthAdjust', 5198 letterspacing: 'letterSpacing', 5199 'letter-spacing': 'letterSpacing', 5200 lightingcolor: 'lightingColor', 5201 'lighting-color': 'lightingColor', 5202 limitingconeangle: 'limitingConeAngle', 5203 local: 'local', 5204 markerend: 'markerEnd', 5205 'marker-end': 'markerEnd', 5206 markerheight: 'markerHeight', 5207 markermid: 'markerMid', 5208 'marker-mid': 'markerMid', 5209 markerstart: 'markerStart', 5210 'marker-start': 'markerStart', 5211 markerunits: 'markerUnits', 5212 markerwidth: 'markerWidth', 5213 mask: 'mask', 5214 maskcontentunits: 'maskContentUnits', 5215 maskunits: 'maskUnits', 5216 mathematical: 'mathematical', 5217 mode: 'mode', 5218 numoctaves: 'numOctaves', 5219 offset: 'offset', 5220 opacity: 'opacity', 5221 operator: 'operator', 5222 order: 'order', 5223 orient: 'orient', 5224 orientation: 'orientation', 5225 origin: 'origin', 5226 overflow: 'overflow', 5227 overlineposition: 'overlinePosition', 5228 'overline-position': 'overlinePosition', 5229 overlinethickness: 'overlineThickness', 5230 'overline-thickness': 'overlineThickness', 5231 paintorder: 'paintOrder', 5232 'paint-order': 'paintOrder', 5233 panose1: 'panose1', 5234 'panose-1': 'panose1', 5235 pathlength: 'pathLength', 5236 patterncontentunits: 'patternContentUnits', 5237 patterntransform: 'patternTransform', 5238 patternunits: 'patternUnits', 5239 pointerevents: 'pointerEvents', 5240 'pointer-events': 'pointerEvents', 5241 points: 'points', 5242 pointsatx: 'pointsAtX', 5243 pointsaty: 'pointsAtY', 5244 pointsatz: 'pointsAtZ', 5245 prefix: 'prefix', 5246 preservealpha: 'preserveAlpha', 5247 preserveaspectratio: 'preserveAspectRatio', 5248 primitiveunits: 'primitiveUnits', 5249 property: 'property', 5250 r: 'r', 5251 radius: 'radius', 5252 refx: 'refX', 5253 refy: 'refY', 5254 renderingintent: 'renderingIntent', 5255 'rendering-intent': 'renderingIntent', 5256 repeatcount: 'repeatCount', 5257 repeatdur: 'repeatDur', 5258 requiredextensions: 'requiredExtensions', 5259 requiredfeatures: 'requiredFeatures', 5260 resource: 'resource', 5261 restart: 'restart', 5262 result: 'result', 5263 results: 'results', 5264 rotate: 'rotate', 5265 rx: 'rx', 5266 ry: 'ry', 5267 scale: 'scale', 5268 security: 'security', 5269 seed: 'seed', 5270 shaperendering: 'shapeRendering', 5271 'shape-rendering': 'shapeRendering', 5272 slope: 'slope', 5273 spacing: 'spacing', 5274 specularconstant: 'specularConstant', 5275 specularexponent: 'specularExponent', 5276 speed: 'speed', 5277 spreadmethod: 'spreadMethod', 5278 startoffset: 'startOffset', 5279 stddeviation: 'stdDeviation', 5280 stemh: 'stemh', 5281 stemv: 'stemv', 5282 stitchtiles: 'stitchTiles', 5283 stopcolor: 'stopColor', 5284 'stop-color': 'stopColor', 5285 stopopacity: 'stopOpacity', 5286 'stop-opacity': 'stopOpacity', 5287 strikethroughposition: 'strikethroughPosition', 5288 'strikethrough-position': 'strikethroughPosition', 5289 strikethroughthickness: 'strikethroughThickness', 5290 'strikethrough-thickness': 'strikethroughThickness', 5291 string: 'string', 5292 stroke: 'stroke', 5293 strokedasharray: 'strokeDasharray', 5294 'stroke-dasharray': 'strokeDasharray', 5295 strokedashoffset: 'strokeDashoffset', 5296 'stroke-dashoffset': 'strokeDashoffset', 5297 strokelinecap: 'strokeLinecap', 5298 'stroke-linecap': 'strokeLinecap', 5299 strokelinejoin: 'strokeLinejoin', 5300 'stroke-linejoin': 'strokeLinejoin', 5301 strokemiterlimit: 'strokeMiterlimit', 5302 'stroke-miterlimit': 'strokeMiterlimit', 5303 strokewidth: 'strokeWidth', 5304 'stroke-width': 'strokeWidth', 5305 strokeopacity: 'strokeOpacity', 5306 'stroke-opacity': 'strokeOpacity', 5307 suppresscontenteditablewarning: 'suppressContentEditableWarning', 5308 suppresshydrationwarning: 'suppressHydrationWarning', 5309 surfacescale: 'surfaceScale', 5310 systemlanguage: 'systemLanguage', 5311 tablevalues: 'tableValues', 5312 targetx: 'targetX', 5313 targety: 'targetY', 5314 textanchor: 'textAnchor', 5315 'text-anchor': 'textAnchor', 5316 textdecoration: 'textDecoration', 5317 'text-decoration': 'textDecoration', 5318 textlength: 'textLength', 5319 textrendering: 'textRendering', 5320 'text-rendering': 'textRendering', 5321 to: 'to', 5322 transform: 'transform', 5323 typeof: 'typeof', 5324 u1: 'u1', 5325 u2: 'u2', 5326 underlineposition: 'underlinePosition', 5327 'underline-position': 'underlinePosition', 5328 underlinethickness: 'underlineThickness', 5329 'underline-thickness': 'underlineThickness', 5330 unicode: 'unicode', 5331 unicodebidi: 'unicodeBidi', 5332 'unicode-bidi': 'unicodeBidi', 5333 unicoderange: 'unicodeRange', 5334 'unicode-range': 'unicodeRange', 5335 unitsperem: 'unitsPerEm', 5336 'units-per-em': 'unitsPerEm', 5337 unselectable: 'unselectable', 5338 valphabetic: 'vAlphabetic', 5339 'v-alphabetic': 'vAlphabetic', 5340 values: 'values', 5341 vectoreffect: 'vectorEffect', 5342 'vector-effect': 'vectorEffect', 5343 version: 'version', 5344 vertadvy: 'vertAdvY', 5345 'vert-adv-y': 'vertAdvY', 5346 vertoriginx: 'vertOriginX', 5347 'vert-origin-x': 'vertOriginX', 5348 vertoriginy: 'vertOriginY', 5349 'vert-origin-y': 'vertOriginY', 5350 vhanging: 'vHanging', 5351 'v-hanging': 'vHanging', 5352 videographic: 'vIdeographic', 5353 'v-ideographic': 'vIdeographic', 5354 viewbox: 'viewBox', 5355 viewtarget: 'viewTarget', 5356 visibility: 'visibility', 5357 vmathematical: 'vMathematical', 5358 'v-mathematical': 'vMathematical', 5359 vocab: 'vocab', 5360 widths: 'widths', 5361 wordspacing: 'wordSpacing', 5362 'word-spacing': 'wordSpacing', 5363 writingmode: 'writingMode', 5364 'writing-mode': 'writingMode', 5365 x1: 'x1', 5366 x2: 'x2', 5367 x: 'x', 5368 xchannelselector: 'xChannelSelector', 5369 xheight: 'xHeight', 5370 'x-height': 'xHeight', 5371 xlinkactuate: 'xlinkActuate', 5372 'xlink:actuate': 'xlinkActuate', 5373 xlinkarcrole: 'xlinkArcrole', 5374 'xlink:arcrole': 'xlinkArcrole', 5375 xlinkhref: 'xlinkHref', 5376 'xlink:href': 'xlinkHref', 5377 xlinkrole: 'xlinkRole', 5378 'xlink:role': 'xlinkRole', 5379 xlinkshow: 'xlinkShow', 5380 'xlink:show': 'xlinkShow', 5381 xlinktitle: 'xlinkTitle', 5382 'xlink:title': 'xlinkTitle', 5383 xlinktype: 'xlinkType', 5384 'xlink:type': 'xlinkType', 5385 xmlbase: 'xmlBase', 5386 'xml:base': 'xmlBase', 5387 xmllang: 'xmlLang', 5388 'xml:lang': 'xmlLang', 5389 xmlns: 'xmlns', 5390 'xml:space': 'xmlSpace', 5391 xmlnsxlink: 'xmlnsXlink', 5392 'xmlns:xlink': 'xmlnsXlink', 5393 xmlspace: 'xmlSpace', 5394 y1: 'y1', 5395 y2: 'y2', 5396 y: 'y', 5397 ychannelselector: 'yChannelSelector', 5398 z: 'z', 5399 zoomandpan: 'zoomAndPan' 5400 }; 5401 5402 var ariaProperties = { 5403 'aria-current': 0, 5404 // state 5405 'aria-details': 0, 5406 'aria-disabled': 0, 5407 // state 5408 'aria-hidden': 0, 5409 // state 5410 'aria-invalid': 0, 5411 // state 5412 'aria-keyshortcuts': 0, 5413 'aria-label': 0, 5414 'aria-roledescription': 0, 5415 // Widget Attributes 5416 'aria-autocomplete': 0, 5417 'aria-checked': 0, 5418 'aria-expanded': 0, 5419 'aria-haspopup': 0, 5420 'aria-level': 0, 5421 'aria-modal': 0, 5422 'aria-multiline': 0, 5423 'aria-multiselectable': 0, 5424 'aria-orientation': 0, 5425 'aria-placeholder': 0, 5426 'aria-pressed': 0, 5427 'aria-readonly': 0, 5428 'aria-required': 0, 5429 'aria-selected': 0, 5430 'aria-sort': 0, 5431 'aria-valuemax': 0, 5432 'aria-valuemin': 0, 5433 'aria-valuenow': 0, 5434 'aria-valuetext': 0, 5435 // Live Region Attributes 5436 'aria-atomic': 0, 5437 'aria-busy': 0, 5438 'aria-live': 0, 5439 'aria-relevant': 0, 5440 // Drag-and-Drop Attributes 5441 'aria-dropeffect': 0, 5442 'aria-grabbed': 0, 5443 // Relationship Attributes 5444 'aria-activedescendant': 0, 5445 'aria-colcount': 0, 5446 'aria-colindex': 0, 5447 'aria-colspan': 0, 5448 'aria-controls': 0, 5449 'aria-describedby': 0, 5450 'aria-errormessage': 0, 5451 'aria-flowto': 0, 5452 'aria-labelledby': 0, 5453 'aria-owns': 0, 5454 'aria-posinset': 0, 5455 'aria-rowcount': 0, 5456 'aria-rowindex': 0, 5457 'aria-rowspan': 0, 5458 'aria-setsize': 0 5459 }; 5460 5461 var warnedProperties = {}; 5462 var rARIA = new RegExp('^(aria)-[' + ATTRIBUTE_NAME_CHAR + ']*$'); 5463 var rARIACamel = new RegExp('^(aria)[A-Z][' + ATTRIBUTE_NAME_CHAR + ']*$'); 5464 var hasOwnProperty$1 = Object.prototype.hasOwnProperty; 5465 5466 function validateProperty(tagName, name) { 5467 { 5468 if (hasOwnProperty$1.call(warnedProperties, name) && warnedProperties[name]) { 5469 return true; 5470 } 5471 5472 if (rARIACamel.test(name)) { 5473 var ariaName = 'aria-' + name.slice(4).toLowerCase(); 5474 var correctName = ariaProperties.hasOwnProperty(ariaName) ? ariaName : null; // If this is an aria-* attribute, but is not listed in the known DOM 5475 // DOM properties, then it is an invalid aria-* attribute. 5476 5477 if (correctName == null) { 5478 error('Invalid ARIA attribute `%s`. ARIA attributes follow the pattern aria-* and must be lowercase.', name); 5479 5480 warnedProperties[name] = true; 5481 return true; 5482 } // aria-* attributes should be lowercase; suggest the lowercase version. 5483 5484 5485 if (name !== correctName) { 5486 error('Invalid ARIA attribute `%s`. Did you mean `%s`?', name, correctName); 5487 5488 warnedProperties[name] = true; 5489 return true; 5490 } 5491 } 5492 5493 if (rARIA.test(name)) { 5494 var lowerCasedName = name.toLowerCase(); 5495 var standardName = ariaProperties.hasOwnProperty(lowerCasedName) ? lowerCasedName : null; // If this is an aria-* attribute, but is not listed in the known DOM 5496 // DOM properties, then it is an invalid aria-* attribute. 5497 5498 if (standardName == null) { 5499 warnedProperties[name] = true; 5500 return false; 5501 } // aria-* attributes should be lowercase; suggest the lowercase version. 5502 5503 5504 if (name !== standardName) { 5505 error('Unknown ARIA attribute `%s`. Did you mean `%s`?', name, standardName); 5506 5507 warnedProperties[name] = true; 5508 return true; 5509 } 5510 } 5511 } 5512 5513 return true; 5514 } 5515 5516 function warnInvalidARIAProps(type, props) { 5517 { 5518 var invalidProps = []; 5519 5520 for (var key in props) { 5521 var isValid = validateProperty(type, key); 5522 5523 if (!isValid) { 5524 invalidProps.push(key); 5525 } 5526 } 5527 5528 var unknownPropString = invalidProps.map(function (prop) { 5529 return '`' + prop + '`'; 5530 }).join(', '); 5531 5532 if (invalidProps.length === 1) { 5533 error('Invalid aria prop %s on <%s> tag. ' + 'For details, see https://fb.me/invalid-aria-prop', unknownPropString, type); 5534 } else if (invalidProps.length > 1) { 5535 error('Invalid aria props %s on <%s> tag. ' + 'For details, see https://fb.me/invalid-aria-prop', unknownPropString, type); 5536 } 5537 } 5538 } 5539 5540 function validateProperties(type, props) { 5541 if (isCustomComponent(type, props)) { 5542 return; 5543 } 5544 5545 warnInvalidARIAProps(type, props); 5546 } 5547 5548 var didWarnValueNull = false; 5549 function validateProperties$1(type, props) { 5550 { 5551 if (type !== 'input' && type !== 'textarea' && type !== 'select') { 5552 return; 5553 } 5554 5555 if (props != null && props.value === null && !didWarnValueNull) { 5556 didWarnValueNull = true; 5557 5558 if (type === 'select' && props.multiple) { 5559 error('`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.', type); 5560 } else { 5561 error('`value` prop on `%s` should not be null. ' + 'Consider using an empty string to clear the component or `undefined` ' + 'for uncontrolled components.', type); 5562 } 5563 } 5564 } 5565 } 5566 5567 var validateProperty$1 = function () {}; 5568 5569 { 5570 var warnedProperties$1 = {}; 5571 var _hasOwnProperty = Object.prototype.hasOwnProperty; 5572 var EVENT_NAME_REGEX = /^on./; 5573 var INVALID_EVENT_NAME_REGEX = /^on[^A-Z]/; 5574 var rARIA$1 = new RegExp('^(aria)-[' + ATTRIBUTE_NAME_CHAR + ']*$'); 5575 var rARIACamel$1 = new RegExp('^(aria)[A-Z][' + ATTRIBUTE_NAME_CHAR + ']*$'); 5576 5577 validateProperty$1 = function (tagName, name, value, canUseEventSystem) { 5578 if (_hasOwnProperty.call(warnedProperties$1, name) && warnedProperties$1[name]) { 5579 return true; 5580 } 5581 5582 var lowerCasedName = name.toLowerCase(); 5583 5584 if (lowerCasedName === 'onfocusin' || lowerCasedName === 'onfocusout') { 5585 error('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.'); 5586 5587 warnedProperties$1[name] = true; 5588 return true; 5589 } // We can't rely on the event system being injected on the server. 5590 5591 5592 if (canUseEventSystem) { 5593 if (registrationNameModules.hasOwnProperty(name)) { 5594 return true; 5595 } 5596 5597 var registrationName = possibleRegistrationNames.hasOwnProperty(lowerCasedName) ? possibleRegistrationNames[lowerCasedName] : null; 5598 5599 if (registrationName != null) { 5600 error('Invalid event handler property `%s`. Did you mean `%s`?', name, registrationName); 5601 5602 warnedProperties$1[name] = true; 5603 return true; 5604 } 5605 5606 if (EVENT_NAME_REGEX.test(name)) { 5607 error('Unknown event handler property `%s`. It will be ignored.', name); 5608 5609 warnedProperties$1[name] = true; 5610 return true; 5611 } 5612 } else if (EVENT_NAME_REGEX.test(name)) { 5613 // If no event plugins have been injected, we are in a server environment. 5614 // So we can't tell if the event name is correct for sure, but we can filter 5615 // out known bad ones like `onclick`. We can't suggest a specific replacement though. 5616 if (INVALID_EVENT_NAME_REGEX.test(name)) { 5617 error('Invalid event handler property `%s`. ' + 'React events use the camelCase naming convention, for example `onClick`.', name); 5618 } 5619 5620 warnedProperties$1[name] = true; 5621 return true; 5622 } // Let the ARIA attribute hook validate ARIA attributes 5623 5624 5625 if (rARIA$1.test(name) || rARIACamel$1.test(name)) { 5626 return true; 5627 } 5628 5629 if (lowerCasedName === 'innerhtml') { 5630 error('Directly setting property `innerHTML` is not permitted. ' + 'For more information, lookup documentation on `dangerouslySetInnerHTML`.'); 5631 5632 warnedProperties$1[name] = true; 5633 return true; 5634 } 5635 5636 if (lowerCasedName === 'aria') { 5637 error('The `aria` attribute is reserved for future use in React. ' + 'Pass individual `aria-` attributes instead.'); 5638 5639 warnedProperties$1[name] = true; 5640 return true; 5641 } 5642 5643 if (lowerCasedName === 'is' && value !== null && value !== undefined && typeof value !== 'string') { 5644 error('Received a `%s` for a string attribute `is`. If this is expected, cast ' + 'the value to a string.', typeof value); 5645 5646 warnedProperties$1[name] = true; 5647 return true; 5648 } 5649 5650 if (typeof value === 'number' && isNaN(value)) { 5651 error('Received NaN for the `%s` attribute. If this is expected, cast ' + 'the value to a string.', name); 5652 5653 warnedProperties$1[name] = true; 5654 return true; 5655 } 5656 5657 var propertyInfo = getPropertyInfo(name); 5658 var isReserved = propertyInfo !== null && propertyInfo.type === RESERVED; // Known attributes should match the casing specified in the property config. 5659 5660 if (possibleStandardNames.hasOwnProperty(lowerCasedName)) { 5661 var standardName = possibleStandardNames[lowerCasedName]; 5662 5663 if (standardName !== name) { 5664 error('Invalid DOM property `%s`. Did you mean `%s`?', name, standardName); 5665 5666 warnedProperties$1[name] = true; 5667 return true; 5668 } 5669 } else if (!isReserved && name !== lowerCasedName) { 5670 // Unknown attributes should have lowercase casing since that's how they 5671 // will be cased anyway with server rendering. 5672 error('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.', name, lowerCasedName); 5673 5674 warnedProperties$1[name] = true; 5675 return true; 5676 } 5677 5678 if (typeof value === 'boolean' && shouldRemoveAttributeWithWarning(name, value, propertyInfo, false)) { 5679 if (value) { 5680 error('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()}.', value, name, name, value, name); 5681 } else { 5682 error('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.', value, name, name, value, name, name, name); 5683 } 5684 5685 warnedProperties$1[name] = true; 5686 return true; 5687 } // Now that we've validated casing, do not validate 5688 // data types for reserved props 5689 5690 5691 if (isReserved) { 5692 return true; 5693 } // Warn when a known attribute is a bad type 5694 5695 5696 if (shouldRemoveAttributeWithWarning(name, value, propertyInfo, false)) { 5697 warnedProperties$1[name] = true; 5698 return false; 5699 } // Warn when passing the strings 'false' or 'true' into a boolean prop 5700 5701 5702 if ((value === 'false' || value === 'true') && propertyInfo !== null && propertyInfo.type === BOOLEAN) { 5703 error('Received the string `%s` for the boolean attribute `%s`. ' + '%s ' + 'Did you mean %s={%s}?', value, name, value === 'false' ? 'The browser will interpret it as a truthy value.' : 'Although this works, it will not work as expected if you pass the string "false".', name, value); 5704 5705 warnedProperties$1[name] = true; 5706 return true; 5707 } 5708 5709 return true; 5710 }; 5711 } 5712 5713 var warnUnknownProperties = function (type, props, canUseEventSystem) { 5714 { 5715 var unknownProps = []; 5716 5717 for (var key in props) { 5718 var isValid = validateProperty$1(type, key, props[key], canUseEventSystem); 5719 5720 if (!isValid) { 5721 unknownProps.push(key); 5722 } 5723 } 5724 5725 var unknownPropString = unknownProps.map(function (prop) { 5726 return '`' + prop + '`'; 5727 }).join(', '); 5728 5729 if (unknownProps.length === 1) { 5730 error('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', unknownPropString, type); 5731 } else if (unknownProps.length > 1) { 5732 error('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', unknownPropString, type); 5733 } 5734 } 5735 }; 5736 5737 function validateProperties$2(type, props, canUseEventSystem) { 5738 if (isCustomComponent(type, props)) { 5739 return; 5740 } 5741 5742 warnUnknownProperties(type, props, canUseEventSystem); 5743 } 5744 5745 var didWarnInvalidHydration = false; 5746 var DANGEROUSLY_SET_INNER_HTML = 'dangerouslySetInnerHTML'; 5747 var SUPPRESS_CONTENT_EDITABLE_WARNING = 'suppressContentEditableWarning'; 5748 var SUPPRESS_HYDRATION_WARNING = 'suppressHydrationWarning'; 5749 var AUTOFOCUS = 'autoFocus'; 5750 var CHILDREN = 'children'; 5751 var STYLE = 'style'; 5752 var HTML$1 = '__html'; 5753 var HTML_NAMESPACE$1 = Namespaces.html; 5754 var warnedUnknownTags; 5755 var suppressHydrationWarning; 5756 var validatePropertiesInDevelopment; 5757 var warnForTextDifference; 5758 var warnForPropDifference; 5759 var warnForExtraAttributes; 5760 var warnForInvalidEventListener; 5761 var canDiffStyleForHydrationWarning; 5762 var normalizeMarkupForTextOrAttribute; 5763 var normalizeHTML; 5764 5765 { 5766 warnedUnknownTags = { 5767 // Chrome is the only major browser not shipping <time>. But as of July 5768 // 2017 it intends to ship it due to widespread usage. We intentionally 5769 // *don't* warn for <time> even if it's unrecognized by Chrome because 5770 // it soon will be, and many apps have been using it anyway. 5771 time: true, 5772 // There are working polyfills for <dialog>. Let people use it. 5773 dialog: true, 5774 // Electron ships a custom <webview> tag to display external web content in 5775 // an isolated frame and process. 5776 // This tag is not present in non Electron environments such as JSDom which 5777 // is often used for testing purposes. 5778 // @see https://electronjs.org/docs/api/webview-tag 5779 webview: true 5780 }; 5781 5782 validatePropertiesInDevelopment = function (type, props) { 5783 validateProperties(type, props); 5784 validateProperties$1(type, props); 5785 validateProperties$2(type, props, 5786 /* canUseEventSystem */ 5787 true); 5788 }; // IE 11 parses & normalizes the style attribute as opposed to other 5789 // browsers. It adds spaces and sorts the properties in some 5790 // non-alphabetical order. Handling that would require sorting CSS 5791 // properties in the client & server versions or applying 5792 // `expectedStyle` to a temporary DOM node to read its `style` attribute 5793 // normalized. Since it only affects IE, we're skipping style warnings 5794 // in that browser completely in favor of doing all that work. 5795 // See https://github.com/facebook/react/issues/11807 5796 5797 5798 canDiffStyleForHydrationWarning = canUseDOM && !document.documentMode; // HTML parsing normalizes CR and CRLF to LF. 5799 // It also can turn \u0000 into \uFFFD inside attributes. 5800 // https://www.w3.org/TR/html5/single-page.html#preprocessing-the-input-stream 5801 // If we have a mismatch, it might be caused by that. 5802 // We will still patch up in this case but not fire the warning. 5803 5804 var NORMALIZE_NEWLINES_REGEX = /\r\n?/g; 5805 var NORMALIZE_NULL_AND_REPLACEMENT_REGEX = /\u0000|\uFFFD/g; 5806 5807 normalizeMarkupForTextOrAttribute = function (markup) { 5808 var markupString = typeof markup === 'string' ? markup : '' + markup; 5809 return markupString.replace(NORMALIZE_NEWLINES_REGEX, '\n').replace(NORMALIZE_NULL_AND_REPLACEMENT_REGEX, ''); 5810 }; 5811 5812 warnForTextDifference = function (serverText, clientText) { 5813 if (didWarnInvalidHydration) { 5814 return; 5815 } 5816 5817 var normalizedClientText = normalizeMarkupForTextOrAttribute(clientText); 5818 var normalizedServerText = normalizeMarkupForTextOrAttribute(serverText); 5819 5820 if (normalizedServerText === normalizedClientText) { 5821 return; 5822 } 5823 5824 didWarnInvalidHydration = true; 5825 5826 error('Text content did not match. Server: "%s" Client: "%s"', normalizedServerText, normalizedClientText); 5827 }; 5828 5829 warnForPropDifference = function (propName, serverValue, clientValue) { 5830 if (didWarnInvalidHydration) { 5831 return; 5832 } 5833 5834 var normalizedClientValue = normalizeMarkupForTextOrAttribute(clientValue); 5835 var normalizedServerValue = normalizeMarkupForTextOrAttribute(serverValue); 5836 5837 if (normalizedServerValue === normalizedClientValue) { 5838 return; 5839 } 5840 5841 didWarnInvalidHydration = true; 5842 5843 error('Prop `%s` did not match. Server: %s Client: %s', propName, JSON.stringify(normalizedServerValue), JSON.stringify(normalizedClientValue)); 5844 }; 5845 5846 warnForExtraAttributes = function (attributeNames) { 5847 if (didWarnInvalidHydration) { 5848 return; 5849 } 5850 5851 didWarnInvalidHydration = true; 5852 var names = []; 5853 attributeNames.forEach(function (name) { 5854 names.push(name); 5855 }); 5856 5857 error('Extra attributes from the server: %s', names); 5858 }; 5859 5860 warnForInvalidEventListener = function (registrationName, listener) { 5861 if (listener === false) { 5862 error('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.', registrationName, registrationName, registrationName); 5863 } else { 5864 error('Expected `%s` listener to be a function, instead got a value of `%s` type.', registrationName, typeof listener); 5865 } 5866 }; // Parse the HTML and read it back to normalize the HTML string so that it 5867 // can be used for comparison. 5868 5869 5870 normalizeHTML = function (parent, html) { 5871 // We could have created a separate document here to avoid 5872 // re-initializing custom elements if they exist. But this breaks 5873 // how <noscript> is being handled. So we use the same document. 5874 // See the discussion in https://github.com/facebook/react/pull/11157. 5875 var testElement = parent.namespaceURI === HTML_NAMESPACE$1 ? parent.ownerDocument.createElement(parent.tagName) : parent.ownerDocument.createElementNS(parent.namespaceURI, parent.tagName); 5876 testElement.innerHTML = html; 5877 return testElement.innerHTML; 5878 }; 5879 } 5880 5881 function ensureListeningTo(rootContainerElement, registrationName) { 5882 var isDocumentOrFragment = rootContainerElement.nodeType === DOCUMENT_NODE || rootContainerElement.nodeType === DOCUMENT_FRAGMENT_NODE; 5883 var doc = isDocumentOrFragment ? rootContainerElement : rootContainerElement.ownerDocument; 5884 legacyListenToEvent(registrationName, doc); 5885 } 5886 5887 function getOwnerDocumentFromRootContainer(rootContainerElement) { 5888 return rootContainerElement.nodeType === DOCUMENT_NODE ? rootContainerElement : rootContainerElement.ownerDocument; 5889 } 5890 5891 function noop() {} 5892 5893 function trapClickOnNonInteractiveElement(node) { 5894 // Mobile Safari does not fire properly bubble click events on 5895 // non-interactive elements, which means delegated click listeners do not 5896 // fire. The workaround for this bug involves attaching an empty click 5897 // listener on the target node. 5898 // http://www.quirksmode.org/blog/archives/2010/09/click_event_del.html 5899 // Just set it using the onclick property so that we don't have to manage any 5900 // bookkeeping for it. Not sure if we need to clear it when the listener is 5901 // removed. 5902 // TODO: Only do this for the relevant Safaris maybe? 5903 node.onclick = noop; 5904 } 5905 5906 function setInitialDOMProperties(tag, domElement, rootContainerElement, nextProps, isCustomComponentTag) { 5907 for (var propKey in nextProps) { 5908 if (!nextProps.hasOwnProperty(propKey)) { 5909 continue; 5910 } 5911 5912 var nextProp = nextProps[propKey]; 5913 5914 if (propKey === STYLE) { 5915 { 5916 if (nextProp) { 5917 // Freeze the next style object so that we can assume it won't be 5918 // mutated. We have already warned for this in the past. 5919 Object.freeze(nextProp); 5920 } 5921 } // Relies on `updateStylesByID` not mutating `styleUpdates`. 5922 5923 5924 setValueForStyles(domElement, nextProp); 5925 } else if (propKey === DANGEROUSLY_SET_INNER_HTML) { 5926 var nextHtml = nextProp ? nextProp[HTML$1] : undefined; 5927 5928 if (nextHtml != null) { 5929 setInnerHTML(domElement, nextHtml); 5930 } 5931 } else if (propKey === CHILDREN) { 5932 if (typeof nextProp === 'string') { 5933 // Avoid setting initial textContent when the text is empty. In IE11 setting 5934 // textContent on a <textarea> will cause the placeholder to not 5935 // show within the <textarea> until it has been focused and blurred again. 5936 // https://github.com/facebook/react/issues/6731#issuecomment-254874553 5937 var canSetTextContent = tag !== 'textarea' || nextProp !== ''; 5938 5939 if (canSetTextContent) { 5940 setTextContent(domElement, nextProp); 5941 } 5942 } else if (typeof nextProp === 'number') { 5943 setTextContent(domElement, '' + nextProp); 5944 } 5945 } else if ( propKey === SUPPRESS_CONTENT_EDITABLE_WARNING || propKey === SUPPRESS_HYDRATION_WARNING) ; else if (propKey === AUTOFOCUS) ; else if (registrationNameModules.hasOwnProperty(propKey)) { 5946 if (nextProp != null) { 5947 if ( typeof nextProp !== 'function') { 5948 warnForInvalidEventListener(propKey, nextProp); 5949 } 5950 5951 ensureListeningTo(rootContainerElement, propKey); 5952 } 5953 } else if (nextProp != null) { 5954 setValueForProperty(domElement, propKey, nextProp, isCustomComponentTag); 5955 } 5956 } 5957 } 5958 5959 function updateDOMProperties(domElement, updatePayload, wasCustomComponentTag, isCustomComponentTag) { 5960 // TODO: Handle wasCustomComponentTag 5961 for (var i = 0; i < updatePayload.length; i += 2) { 5962 var propKey = updatePayload[i]; 5963 var propValue = updatePayload[i + 1]; 5964 5965 if (propKey === STYLE) { 5966 setValueForStyles(domElement, propValue); 5967 } else if (propKey === DANGEROUSLY_SET_INNER_HTML) { 5968 setInnerHTML(domElement, propValue); 5969 } else if (propKey === CHILDREN) { 5970 setTextContent(domElement, propValue); 5971 } else { 5972 setValueForProperty(domElement, propKey, propValue, isCustomComponentTag); 5973 } 5974 } 5975 } 5976 5977 function createElement(type, props, rootContainerElement, parentNamespace) { 5978 var isCustomComponentTag; // We create tags in the namespace of their parent container, except HTML 5979 // tags get no namespace. 5980 5981 var ownerDocument = getOwnerDocumentFromRootContainer(rootContainerElement); 5982 var domElement; 5983 var namespaceURI = parentNamespace; 5984 5985 if (namespaceURI === HTML_NAMESPACE$1) { 5986 namespaceURI = getIntrinsicNamespace(type); 5987 } 5988 5989 if (namespaceURI === HTML_NAMESPACE$1) { 5990 { 5991 isCustomComponentTag = isCustomComponent(type, props); // Should this check be gated by parent namespace? Not sure we want to 5992 // allow <SVG> or <mATH>. 5993 5994 if (!isCustomComponentTag && type !== type.toLowerCase()) { 5995 error('<%s /> is using incorrect casing. ' + 'Use PascalCase for React components, ' + 'or lowercase for HTML elements.', type); 5996 } 5997 } 5998 5999 if (type === 'script') { 6000 // Create the script via .innerHTML so its "parser-inserted" flag is 6001 // set to true and it does not execute 6002 var div = ownerDocument.createElement('div'); 6003 6004 div.innerHTML = '<script><' + '/script>'; // eslint-disable-line 6005 // This is guaranteed to yield a script element. 6006 6007 var firstChild = div.firstChild; 6008 domElement = div.removeChild(firstChild); 6009 } else if (typeof props.is === 'string') { 6010 // $FlowIssue `createElement` should be updated for Web Components 6011 domElement = ownerDocument.createElement(type, { 6012 is: props.is 6013 }); 6014 } else { 6015 // Separate else branch instead of using `props.is || undefined` above because of a Firefox bug. 6016 // See discussion in https://github.com/facebook/react/pull/6896 6017 // and discussion in https://bugzilla.mozilla.org/show_bug.cgi?id=1276240 6018 domElement = ownerDocument.createElement(type); // Normally attributes are assigned in `setInitialDOMProperties`, however the `multiple` and `size` 6019 // attributes on `select`s needs to be added before `option`s are inserted. 6020 // This prevents: 6021 // - a bug where the `select` does not scroll to the correct option because singular 6022 // `select` elements automatically pick the first item #13222 6023 // - a bug where the `select` set the first item as selected despite the `size` attribute #14239 6024 // See https://github.com/facebook/react/issues/13222 6025 // and https://github.com/facebook/react/issues/14239 6026 6027 if (type === 'select') { 6028 var node = domElement; 6029 6030 if (props.multiple) { 6031 node.multiple = true; 6032 } else if (props.size) { 6033 // Setting a size greater than 1 causes a select to behave like `multiple=true`, where 6034 // it is possible that no option is selected. 6035 // 6036 // This is only necessary when a select in "single selection mode". 6037 node.size = props.size; 6038 } 6039 } 6040 } 6041 } else { 6042 domElement = ownerDocument.createElementNS(namespaceURI, type); 6043 } 6044 6045 { 6046 if (namespaceURI === HTML_NAMESPACE$1) { 6047 if (!isCustomComponentTag && Object.prototype.toString.call(domElement) === '[object HTMLUnknownElement]' && !Object.prototype.hasOwnProperty.call(warnedUnknownTags, type)) { 6048 warnedUnknownTags[type] = true; 6049 6050 error('The tag <%s> is unrecognized in this browser. ' + 'If you meant to render a React component, start its name with ' + 'an uppercase letter.', type); 6051 } 6052 } 6053 } 6054 6055 return domElement; 6056 } 6057 function createTextNode(text, rootContainerElement) { 6058 return getOwnerDocumentFromRootContainer(rootContainerElement).createTextNode(text); 6059 } 6060 function setInitialProperties(domElement, tag, rawProps, rootContainerElement) { 6061 var isCustomComponentTag = isCustomComponent(tag, rawProps); 6062 6063 { 6064 validatePropertiesInDevelopment(tag, rawProps); 6065 } // TODO: Make sure that we check isMounted before firing any of these events. 6066 6067 6068 var props; 6069 6070 switch (tag) { 6071 case 'iframe': 6072 case 'object': 6073 case 'embed': 6074 trapBubbledEvent(TOP_LOAD, domElement); 6075 props = rawProps; 6076 break; 6077 6078 case 'video': 6079 case 'audio': 6080 // Create listener for each media event 6081 for (var i = 0; i < mediaEventTypes.length; i++) { 6082 trapBubbledEvent(mediaEventTypes[i], domElement); 6083 } 6084 6085 props = rawProps; 6086 break; 6087 6088 case 'source': 6089 trapBubbledEvent(TOP_ERROR, domElement); 6090 props = rawProps; 6091 break; 6092 6093 case 'img': 6094 case 'image': 6095 case 'link': 6096 trapBubbledEvent(TOP_ERROR, domElement); 6097 trapBubbledEvent(TOP_LOAD, domElement); 6098 props = rawProps; 6099 break; 6100 6101 case 'form': 6102 trapBubbledEvent(TOP_RESET, domElement); 6103 trapBubbledEvent(TOP_SUBMIT, domElement); 6104 props = rawProps; 6105 break; 6106 6107 case 'details': 6108 trapBubbledEvent(TOP_TOGGLE, domElement); 6109 props = rawProps; 6110 break; 6111 6112 case 'input': 6113 initWrapperState(domElement, rawProps); 6114 props = getHostProps(domElement, rawProps); 6115 trapBubbledEvent(TOP_INVALID, domElement); // For controlled components we always need to ensure we're listening 6116 // to onChange. Even if there is no listener. 6117 6118 ensureListeningTo(rootContainerElement, 'onChange'); 6119 break; 6120 6121 case 'option': 6122 validateProps(domElement, rawProps); 6123 props = getHostProps$1(domElement, rawProps); 6124 break; 6125 6126 case 'select': 6127 initWrapperState$1(domElement, rawProps); 6128 props = getHostProps$2(domElement, rawProps); 6129 trapBubbledEvent(TOP_INVALID, domElement); // For controlled components we always need to ensure we're listening 6130 // to onChange. Even if there is no listener. 6131 6132 ensureListeningTo(rootContainerElement, 'onChange'); 6133 break; 6134 6135 case 'textarea': 6136 initWrapperState$2(domElement, rawProps); 6137 props = getHostProps$3(domElement, rawProps); 6138 trapBubbledEvent(TOP_INVALID, domElement); // For controlled components we always need to ensure we're listening 6139 // to onChange. Even if there is no listener. 6140 6141 ensureListeningTo(rootContainerElement, 'onChange'); 6142 break; 6143 6144 default: 6145 props = rawProps; 6146 } 6147 6148 assertValidProps(tag, props); 6149 setInitialDOMProperties(tag, domElement, rootContainerElement, props, isCustomComponentTag); 6150 6151 switch (tag) { 6152 case 'input': 6153 // TODO: Make sure we check if this is still unmounted or do any clean 6154 // up necessary since we never stop tracking anymore. 6155 track(domElement); 6156 postMountWrapper(domElement, rawProps, false); 6157 break; 6158 6159 case 'textarea': 6160 // TODO: Make sure we check if this is still unmounted or do any clean 6161 // up necessary since we never stop tracking anymore. 6162 track(domElement); 6163 postMountWrapper$3(domElement); 6164 break; 6165 6166 case 'option': 6167 postMountWrapper$1(domElement, rawProps); 6168 break; 6169 6170 case 'select': 6171 postMountWrapper$2(domElement, rawProps); 6172 break; 6173 6174 default: 6175 if (typeof props.onClick === 'function') { 6176 // TODO: This cast may not be sound for SVG, MathML or custom elements. 6177 trapClickOnNonInteractiveElement(domElement); 6178 } 6179 6180 break; 6181 } 6182 } // Calculate the diff between the two objects. 6183 6184 function diffProperties(domElement, tag, lastRawProps, nextRawProps, rootContainerElement) { 6185 { 6186 validatePropertiesInDevelopment(tag, nextRawProps); 6187 } 6188 6189 var updatePayload = null; 6190 var lastProps; 6191 var nextProps; 6192 6193 switch (tag) { 6194 case 'input': 6195 lastProps = getHostProps(domElement, lastRawProps); 6196 nextProps = getHostProps(domElement, nextRawProps); 6197 updatePayload = []; 6198 break; 6199 6200 case 'option': 6201 lastProps = getHostProps$1(domElement, lastRawProps); 6202 nextProps = getHostProps$1(domElement, nextRawProps); 6203 updatePayload = []; 6204 break; 6205 6206 case 'select': 6207 lastProps = getHostProps$2(domElement, lastRawProps); 6208 nextProps = getHostProps$2(domElement, nextRawProps); 6209 updatePayload = []; 6210 break; 6211 6212 case 'textarea': 6213 lastProps = getHostProps$3(domElement, lastRawProps); 6214 nextProps = getHostProps$3(domElement, nextRawProps); 6215 updatePayload = []; 6216 break; 6217 6218 default: 6219 lastProps = lastRawProps; 6220 nextProps = nextRawProps; 6221 6222 if (typeof lastProps.onClick !== 'function' && typeof nextProps.onClick === 'function') { 6223 // TODO: This cast may not be sound for SVG, MathML or custom elements. 6224 trapClickOnNonInteractiveElement(domElement); 6225 } 6226 6227 break; 6228 } 6229 6230 assertValidProps(tag, nextProps); 6231 var propKey; 6232 var styleName; 6233 var styleUpdates = null; 6234 6235 for (propKey in lastProps) { 6236 if (nextProps.hasOwnProperty(propKey) || !lastProps.hasOwnProperty(propKey) || lastProps[propKey] == null) { 6237 continue; 6238 } 6239 6240 if (propKey === STYLE) { 6241 var lastStyle = lastProps[propKey]; 6242 6243 for (styleName in lastStyle) { 6244 if (lastStyle.hasOwnProperty(styleName)) { 6245 if (!styleUpdates) { 6246 styleUpdates = {}; 6247 } 6248 6249 styleUpdates[styleName] = ''; 6250 } 6251 } 6252 } else if (propKey === DANGEROUSLY_SET_INNER_HTML || propKey === CHILDREN) ; else if ( propKey === SUPPRESS_CONTENT_EDITABLE_WARNING || propKey === SUPPRESS_HYDRATION_WARNING) ; else if (propKey === AUTOFOCUS) ; else if (registrationNameModules.hasOwnProperty(propKey)) { 6253 // This is a special case. If any listener updates we need to ensure 6254 // that the "current" fiber pointer gets updated so we need a commit 6255 // to update this element. 6256 if (!updatePayload) { 6257 updatePayload = []; 6258 } 6259 } else { 6260 // For all other deleted properties we add it to the queue. We use 6261 // the whitelist in the commit phase instead. 6262 (updatePayload = updatePayload || []).push(propKey, null); 6263 } 6264 } 6265 6266 for (propKey in nextProps) { 6267 var nextProp = nextProps[propKey]; 6268 var lastProp = lastProps != null ? lastProps[propKey] : undefined; 6269 6270 if (!nextProps.hasOwnProperty(propKey) || nextProp === lastProp || nextProp == null && lastProp == null) { 6271 continue; 6272 } 6273 6274 if (propKey === STYLE) { 6275 { 6276 if (nextProp) { 6277 // Freeze the next style object so that we can assume it won't be 6278 // mutated. We have already warned for this in the past. 6279 Object.freeze(nextProp); 6280 } 6281 } 6282 6283 if (lastProp) { 6284 // Unset styles on `lastProp` but not on `nextProp`. 6285 for (styleName in lastProp) { 6286 if (lastProp.hasOwnProperty(styleName) && (!nextProp || !nextProp.hasOwnProperty(styleName))) { 6287 if (!styleUpdates) { 6288 styleUpdates = {}; 6289 } 6290 6291 styleUpdates[styleName] = ''; 6292 } 6293 } // Update styles that changed since `lastProp`. 6294 6295 6296 for (styleName in nextProp) { 6297 if (nextProp.hasOwnProperty(styleName) && lastProp[styleName] !== nextProp[styleName]) { 6298 if (!styleUpdates) { 6299 styleUpdates = {}; 6300 } 6301 6302 styleUpdates[styleName] = nextProp[styleName]; 6303 } 6304 } 6305 } else { 6306 // Relies on `updateStylesByID` not mutating `styleUpdates`. 6307 if (!styleUpdates) { 6308 if (!updatePayload) { 6309 updatePayload = []; 6310 } 6311 6312 updatePayload.push(propKey, styleUpdates); 6313 } 6314 6315 styleUpdates = nextProp; 6316 } 6317 } else if (propKey === DANGEROUSLY_SET_INNER_HTML) { 6318 var nextHtml = nextProp ? nextProp[HTML$1] : undefined; 6319 var lastHtml = lastProp ? lastProp[HTML$1] : undefined; 6320 6321 if (nextHtml != null) { 6322 if (lastHtml !== nextHtml) { 6323 (updatePayload = updatePayload || []).push(propKey, nextHtml); 6324 } 6325 } 6326 } else if (propKey === CHILDREN) { 6327 if (lastProp !== nextProp && (typeof nextProp === 'string' || typeof nextProp === 'number')) { 6328 (updatePayload = updatePayload || []).push(propKey, '' + nextProp); 6329 } 6330 } else if ( propKey === SUPPRESS_CONTENT_EDITABLE_WARNING || propKey === SUPPRESS_HYDRATION_WARNING) ; else if (registrationNameModules.hasOwnProperty(propKey)) { 6331 if (nextProp != null) { 6332 // We eagerly listen to this even though we haven't committed yet. 6333 if ( typeof nextProp !== 'function') { 6334 warnForInvalidEventListener(propKey, nextProp); 6335 } 6336 6337 ensureListeningTo(rootContainerElement, propKey); 6338 } 6339 6340 if (!updatePayload && lastProp !== nextProp) { 6341 // This is a special case. If any listener updates we need to ensure 6342 // that the "current" props pointer gets updated so we need a commit 6343 // to update this element. 6344 updatePayload = []; 6345 } 6346 } else { 6347 // For any other property we always add it to the queue and then we 6348 // filter it out using the whitelist during the commit. 6349 (updatePayload = updatePayload || []).push(propKey, nextProp); 6350 } 6351 } 6352 6353 if (styleUpdates) { 6354 { 6355 validateShorthandPropertyCollisionInDev(styleUpdates, nextProps[STYLE]); 6356 } 6357 6358 (updatePayload = updatePayload || []).push(STYLE, styleUpdates); 6359 } 6360 6361 return updatePayload; 6362 } // Apply the diff. 6363 6364 function updateProperties(domElement, updatePayload, tag, lastRawProps, nextRawProps) { 6365 // Update checked *before* name. 6366 // In the middle of an update, it is possible to have multiple checked. 6367 // When a checked radio tries to change name, browser makes another radio's checked false. 6368 if (tag === 'input' && nextRawProps.type === 'radio' && nextRawProps.name != null) { 6369 updateChecked(domElement, nextRawProps); 6370 } 6371 6372 var wasCustomComponentTag = isCustomComponent(tag, lastRawProps); 6373 var isCustomComponentTag = isCustomComponent(tag, nextRawProps); // Apply the diff. 6374 6375 updateDOMProperties(domElement, updatePayload, wasCustomComponentTag, isCustomComponentTag); // TODO: Ensure that an update gets scheduled if any of the special props 6376 // changed. 6377 6378 switch (tag) { 6379 case 'input': 6380 // Update the wrapper around inputs *after* updating props. This has to 6381 // happen after `updateDOMProperties`. Otherwise HTML5 input validations 6382 // raise warnings and prevent the new value from being assigned. 6383 updateWrapper(domElement, nextRawProps); 6384 break; 6385 6386 case 'textarea': 6387 updateWrapper$1(domElement, nextRawProps); 6388 break; 6389 6390 case 'select': 6391 // <select> value update needs to occur after <option> children 6392 // reconciliation 6393 postUpdateWrapper(domElement, nextRawProps); 6394 break; 6395 } 6396 } 6397 6398 function getPossibleStandardName(propName) { 6399 { 6400 var lowerCasedName = propName.toLowerCase(); 6401 6402 if (!possibleStandardNames.hasOwnProperty(lowerCasedName)) { 6403 return null; 6404 } 6405 6406 return possibleStandardNames[lowerCasedName] || null; 6407 } 6408 } 6409 6410 function diffHydratedProperties(domElement, tag, rawProps, parentNamespace, rootContainerElement) { 6411 var isCustomComponentTag; 6412 var extraAttributeNames; 6413 6414 { 6415 suppressHydrationWarning = rawProps[SUPPRESS_HYDRATION_WARNING] === true; 6416 isCustomComponentTag = isCustomComponent(tag, rawProps); 6417 validatePropertiesInDevelopment(tag, rawProps); 6418 } // TODO: Make sure that we check isMounted before firing any of these events. 6419 6420 6421 switch (tag) { 6422 case 'iframe': 6423 case 'object': 6424 case 'embed': 6425 trapBubbledEvent(TOP_LOAD, domElement); 6426 break; 6427 6428 case 'video': 6429 case 'audio': 6430 // Create listener for each media event 6431 for (var i = 0; i < mediaEventTypes.length; i++) { 6432 trapBubbledEvent(mediaEventTypes[i], domElement); 6433 } 6434 6435 break; 6436 6437 case 'source': 6438 trapBubbledEvent(TOP_ERROR, domElement); 6439 break; 6440 6441 case 'img': 6442 case 'image': 6443 case 'link': 6444 trapBubbledEvent(TOP_ERROR, domElement); 6445 trapBubbledEvent(TOP_LOAD, domElement); 6446 break; 6447 6448 case 'form': 6449 trapBubbledEvent(TOP_RESET, domElement); 6450 trapBubbledEvent(TOP_SUBMIT, domElement); 6451 break; 6452 6453 case 'details': 6454 trapBubbledEvent(TOP_TOGGLE, domElement); 6455 break; 6456 6457 case 'input': 6458 initWrapperState(domElement, rawProps); 6459 trapBubbledEvent(TOP_INVALID, domElement); // For controlled components we always need to ensure we're listening 6460 // to onChange. Even if there is no listener. 6461 6462 ensureListeningTo(rootContainerElement, 'onChange'); 6463 break; 6464 6465 case 'option': 6466 validateProps(domElement, rawProps); 6467 break; 6468 6469 case 'select': 6470 initWrapperState$1(domElement, rawProps); 6471 trapBubbledEvent(TOP_INVALID, domElement); // For controlled components we always need to ensure we're listening 6472 // to onChange. Even if there is no listener. 6473 6474 ensureListeningTo(rootContainerElement, 'onChange'); 6475 break; 6476 6477 case 'textarea': 6478 initWrapperState$2(domElement, rawProps); 6479 trapBubbledEvent(TOP_INVALID, domElement); // For controlled components we always need to ensure we're listening 6480 // to onChange. Even if there is no listener. 6481 6482 ensureListeningTo(rootContainerElement, 'onChange'); 6483 break; 6484 } 6485 6486 assertValidProps(tag, rawProps); 6487 6488 { 6489 extraAttributeNames = new Set(); 6490 var attributes = domElement.attributes; 6491 6492 for (var _i = 0; _i < attributes.length; _i++) { 6493 var name = attributes[_i].name.toLowerCase(); 6494 6495 switch (name) { 6496 // Built-in SSR attribute is whitelisted 6497 case 'data-reactroot': 6498 break; 6499 // Controlled attributes are not validated 6500 // TODO: Only ignore them on controlled tags. 6501 6502 case 'value': 6503 break; 6504 6505 case 'checked': 6506 break; 6507 6508 case 'selected': 6509 break; 6510 6511 default: 6512 // Intentionally use the original name. 6513 // See discussion in https://github.com/facebook/react/pull/10676. 6514 extraAttributeNames.add(attributes[_i].name); 6515 } 6516 } 6517 } 6518 6519 var updatePayload = null; 6520 6521 for (var propKey in rawProps) { 6522 if (!rawProps.hasOwnProperty(propKey)) { 6523 continue; 6524 } 6525 6526 var nextProp = rawProps[propKey]; 6527 6528 if (propKey === CHILDREN) { 6529 // For text content children we compare against textContent. This 6530 // might match additional HTML that is hidden when we read it using 6531 // textContent. E.g. "foo" will match "f<span>oo</span>" but that still 6532 // satisfies our requirement. Our requirement is not to produce perfect 6533 // HTML and attributes. Ideally we should preserve structure but it's 6534 // ok not to if the visible content is still enough to indicate what 6535 // even listeners these nodes might be wired up to. 6536 // TODO: Warn if there is more than a single textNode as a child. 6537 // TODO: Should we use domElement.firstChild.nodeValue to compare? 6538 if (typeof nextProp === 'string') { 6539 if (domElement.textContent !== nextProp) { 6540 if ( !suppressHydrationWarning) { 6541 warnForTextDifference(domElement.textContent, nextProp); 6542 } 6543 6544 updatePayload = [CHILDREN, nextProp]; 6545 } 6546 } else if (typeof nextProp === 'number') { 6547 if (domElement.textContent !== '' + nextProp) { 6548 if ( !suppressHydrationWarning) { 6549 warnForTextDifference(domElement.textContent, nextProp); 6550 } 6551 6552 updatePayload = [CHILDREN, '' + nextProp]; 6553 } 6554 } 6555 } else if (registrationNameModules.hasOwnProperty(propKey)) { 6556 if (nextProp != null) { 6557 if ( typeof nextProp !== 'function') { 6558 warnForInvalidEventListener(propKey, nextProp); 6559 } 6560 6561 ensureListeningTo(rootContainerElement, propKey); 6562 } 6563 } else if ( // Convince Flow we've calculated it (it's DEV-only in this method.) 6564 typeof isCustomComponentTag === 'boolean') { 6565 // Validate that the properties correspond to their expected values. 6566 var serverValue = void 0; 6567 var propertyInfo = getPropertyInfo(propKey); 6568 6569 if (suppressHydrationWarning) ; else if ( propKey === SUPPRESS_CONTENT_EDITABLE_WARNING || propKey === SUPPRESS_HYDRATION_WARNING || // Controlled attributes are not validated 6570 // TODO: Only ignore them on controlled tags. 6571 propKey === 'value' || propKey === 'checked' || propKey === 'selected') ; else if (propKey === DANGEROUSLY_SET_INNER_HTML) { 6572 var serverHTML = domElement.innerHTML; 6573 var nextHtml = nextProp ? nextProp[HTML$1] : undefined; 6574 var expectedHTML = normalizeHTML(domElement, nextHtml != null ? nextHtml : ''); 6575 6576 if (expectedHTML !== serverHTML) { 6577 warnForPropDifference(propKey, serverHTML, expectedHTML); 6578 } 6579 } else if (propKey === STYLE) { 6580 // $FlowFixMe - Should be inferred as not undefined. 6581 extraAttributeNames.delete(propKey); 6582 6583 if (canDiffStyleForHydrationWarning) { 6584 var expectedStyle = createDangerousStringForStyles(nextProp); 6585 serverValue = domElement.getAttribute('style'); 6586 6587 if (expectedStyle !== serverValue) { 6588 warnForPropDifference(propKey, serverValue, expectedStyle); 6589 } 6590 } 6591 } else if (isCustomComponentTag) { 6592 // $FlowFixMe - Should be inferred as not undefined. 6593 extraAttributeNames.delete(propKey.toLowerCase()); 6594 serverValue = getValueForAttribute(domElement, propKey, nextProp); 6595 6596 if (nextProp !== serverValue) { 6597 warnForPropDifference(propKey, serverValue, nextProp); 6598 } 6599 } else if (!shouldIgnoreAttribute(propKey, propertyInfo, isCustomComponentTag) && !shouldRemoveAttribute(propKey, nextProp, propertyInfo, isCustomComponentTag)) { 6600 var isMismatchDueToBadCasing = false; 6601 6602 if (propertyInfo !== null) { 6603 // $FlowFixMe - Should be inferred as not undefined. 6604 extraAttributeNames.delete(propertyInfo.attributeName); 6605 serverValue = getValueForProperty(domElement, propKey, nextProp, propertyInfo); 6606 } else { 6607 var ownNamespace = parentNamespace; 6608 6609 if (ownNamespace === HTML_NAMESPACE$1) { 6610 ownNamespace = getIntrinsicNamespace(tag); 6611 } 6612 6613 if (ownNamespace === HTML_NAMESPACE$1) { 6614 // $FlowFixMe - Should be inferred as not undefined. 6615 extraAttributeNames.delete(propKey.toLowerCase()); 6616 } else { 6617 var standardName = getPossibleStandardName(propKey); 6618 6619 if (standardName !== null && standardName !== propKey) { 6620 // If an SVG prop is supplied with bad casing, it will 6621 // be successfully parsed from HTML, but will produce a mismatch 6622 // (and would be incorrectly rendered on the client). 6623 // However, we already warn about bad casing elsewhere. 6624 // So we'll skip the misleading extra mismatch warning in this case. 6625 isMismatchDueToBadCasing = true; // $FlowFixMe - Should be inferred as not undefined. 6626 6627 extraAttributeNames.delete(standardName); 6628 } // $FlowFixMe - Should be inferred as not undefined. 6629 6630 6631 extraAttributeNames.delete(propKey); 6632 } 6633 6634 serverValue = getValueForAttribute(domElement, propKey, nextProp); 6635 } 6636 6637 if (nextProp !== serverValue && !isMismatchDueToBadCasing) { 6638 warnForPropDifference(propKey, serverValue, nextProp); 6639 } 6640 } 6641 } 6642 } 6643 6644 { 6645 // $FlowFixMe - Should be inferred as not undefined. 6646 if (extraAttributeNames.size > 0 && !suppressHydrationWarning) { 6647 // $FlowFixMe - Should be inferred as not undefined. 6648 warnForExtraAttributes(extraAttributeNames); 6649 } 6650 } 6651 6652 switch (tag) { 6653 case 'input': 6654 // TODO: Make sure we check if this is still unmounted or do any clean 6655 // up necessary since we never stop tracking anymore. 6656 track(domElement); 6657 postMountWrapper(domElement, rawProps, true); 6658 break; 6659 6660 case 'textarea': 6661 // TODO: Make sure we check if this is still unmounted or do any clean 6662 // up necessary since we never stop tracking anymore. 6663 track(domElement); 6664 postMountWrapper$3(domElement); 6665 break; 6666 6667 case 'select': 6668 case 'option': 6669 // For input and textarea we current always set the value property at 6670 // post mount to force it to diverge from attributes. However, for 6671 // option and select we don't quite do the same thing and select 6672 // is not resilient to the DOM state changing so we don't do that here. 6673 // TODO: Consider not doing this for input and textarea. 6674 break; 6675 6676 default: 6677 if (typeof rawProps.onClick === 'function') { 6678 // TODO: This cast may not be sound for SVG, MathML or custom elements. 6679 trapClickOnNonInteractiveElement(domElement); 6680 } 6681 6682 break; 6683 } 6684 6685 return updatePayload; 6686 } 6687 function diffHydratedText(textNode, text) { 6688 var isDifferent = textNode.nodeValue !== text; 6689 return isDifferent; 6690 } 6691 function warnForUnmatchedText(textNode, text) { 6692 { 6693 warnForTextDifference(textNode.nodeValue, text); 6694 } 6695 } 6696 function warnForDeletedHydratableElement(parentNode, child) { 6697 { 6698 if (didWarnInvalidHydration) { 6699 return; 6700 } 6701 6702 didWarnInvalidHydration = true; 6703 6704 error('Did not expect server HTML to contain a <%s> in <%s>.', child.nodeName.toLowerCase(), parentNode.nodeName.toLowerCase()); 6705 } 6706 } 6707 function warnForDeletedHydratableText(parentNode, child) { 6708 { 6709 if (didWarnInvalidHydration) { 6710 return; 6711 } 6712 6713 didWarnInvalidHydration = true; 6714 6715 error('Did not expect server HTML to contain the text node "%s" in <%s>.', child.nodeValue, parentNode.nodeName.toLowerCase()); 6716 } 6717 } 6718 function warnForInsertedHydratedElement(parentNode, tag, props) { 6719 { 6720 if (didWarnInvalidHydration) { 6721 return; 6722 } 6723 6724 didWarnInvalidHydration = true; 6725 6726 error('Expected server HTML to contain a matching <%s> in <%s>.', tag, parentNode.nodeName.toLowerCase()); 6727 } 6728 } 6729 function warnForInsertedHydratedText(parentNode, text) { 6730 { 6731 if (text === '') { 6732 // We expect to insert empty text nodes since they're not represented in 6733 // the HTML. 6734 // TODO: Remove this special case if we can just avoid inserting empty 6735 // text nodes. 6736 return; 6737 } 6738 6739 if (didWarnInvalidHydration) { 6740 return; 6741 } 6742 6743 didWarnInvalidHydration = true; 6744 6745 error('Expected server HTML to contain a matching text node for "%s" in <%s>.', text, parentNode.nodeName.toLowerCase()); 6746 } 6747 } 6748 function restoreControlledState$3(domElement, tag, props) { 6749 switch (tag) { 6750 case 'input': 6751 restoreControlledState(domElement, props); 6752 return; 6753 6754 case 'textarea': 6755 restoreControlledState$2(domElement, props); 6756 return; 6757 6758 case 'select': 6759 restoreControlledState$1(domElement, props); 6760 return; 6761 } 6762 } 6763 6764 function getActiveElement(doc) { 6765 doc = doc || (typeof document !== 'undefined' ? document : undefined); 6766 6767 if (typeof doc === 'undefined') { 6768 return null; 6769 } 6770 6771 try { 6772 return doc.activeElement || doc.body; 6773 } catch (e) { 6774 return doc.body; 6775 } 6776 } 6777 6778 /** 6779 * Given any node return the first leaf node without children. 6780 * 6781 * @param {DOMElement|DOMTextNode} node 6782 * @return {DOMElement|DOMTextNode} 6783 */ 6784 6785 function getLeafNode(node) { 6786 while (node && node.firstChild) { 6787 node = node.firstChild; 6788 } 6789 6790 return node; 6791 } 6792 /** 6793 * Get the next sibling within a container. This will walk up the 6794 * DOM if a node's siblings have been exhausted. 6795 * 6796 * @param {DOMElement|DOMTextNode} node 6797 * @return {?DOMElement|DOMTextNode} 6798 */ 6799 6800 6801 function getSiblingNode(node) { 6802 while (node) { 6803 if (node.nextSibling) { 6804 return node.nextSibling; 6805 } 6806 6807 node = node.parentNode; 6808 } 6809 } 6810 /** 6811 * Get object describing the nodes which contain characters at offset. 6812 * 6813 * @param {DOMElement|DOMTextNode} root 6814 * @param {number} offset 6815 * @return {?object} 6816 */ 6817 6818 6819 function getNodeForCharacterOffset(root, offset) { 6820 var node = getLeafNode(root); 6821 var nodeStart = 0; 6822 var nodeEnd = 0; 6823 6824 while (node) { 6825 if (node.nodeType === TEXT_NODE) { 6826 nodeEnd = nodeStart + node.textContent.length; 6827 6828 if (nodeStart <= offset && nodeEnd >= offset) { 6829 return { 6830 node: node, 6831 offset: offset - nodeStart 6832 }; 6833 } 6834 6835 nodeStart = nodeEnd; 6836 } 6837 6838 node = getLeafNode(getSiblingNode(node)); 6839 } 6840 } 6841 6842 /** 6843 * @param {DOMElement} outerNode 6844 * @return {?object} 6845 */ 6846 6847 function getOffsets(outerNode) { 6848 var ownerDocument = outerNode.ownerDocument; 6849 var win = ownerDocument && ownerDocument.defaultView || window; 6850 var selection = win.getSelection && win.getSelection(); 6851 6852 if (!selection || selection.rangeCount === 0) { 6853 return null; 6854 } 6855 6856 var anchorNode = selection.anchorNode, 6857 anchorOffset = selection.anchorOffset, 6858 focusNode = selection.focusNode, 6859 focusOffset = selection.focusOffset; // In Firefox, anchorNode and focusNode can be "anonymous divs", e.g. the 6860 // up/down buttons on an <input type="number">. Anonymous divs do not seem to 6861 // expose properties, triggering a "Permission denied error" if any of its 6862 // properties are accessed. The only seemingly possible way to avoid erroring 6863 // is to access a property that typically works for non-anonymous divs and 6864 // catch any error that may otherwise arise. See 6865 // https://bugzilla.mozilla.org/show_bug.cgi?id=208427 6866 6867 try { 6868 /* eslint-disable no-unused-expressions */ 6869 anchorNode.nodeType; 6870 focusNode.nodeType; 6871 /* eslint-enable no-unused-expressions */ 6872 } catch (e) { 6873 return null; 6874 } 6875 6876 return getModernOffsetsFromPoints(outerNode, anchorNode, anchorOffset, focusNode, focusOffset); 6877 } 6878 /** 6879 * Returns {start, end} where `start` is the character/codepoint index of 6880 * (anchorNode, anchorOffset) within the textContent of `outerNode`, and 6881 * `end` is the index of (focusNode, focusOffset). 6882 * 6883 * Returns null if you pass in garbage input but we should probably just crash. 6884 * 6885 * Exported only for testing. 6886 */ 6887 6888 function getModernOffsetsFromPoints(outerNode, anchorNode, anchorOffset, focusNode, focusOffset) { 6889 var length = 0; 6890 var start = -1; 6891 var end = -1; 6892 var indexWithinAnchor = 0; 6893 var indexWithinFocus = 0; 6894 var node = outerNode; 6895 var parentNode = null; 6896 6897 outer: while (true) { 6898 var next = null; 6899 6900 while (true) { 6901 if (node === anchorNode && (anchorOffset === 0 || node.nodeType === TEXT_NODE)) { 6902 start = length + anchorOffset; 6903 } 6904 6905 if (node === focusNode && (focusOffset === 0 || node.nodeType === TEXT_NODE)) { 6906 end = length + focusOffset; 6907 } 6908 6909 if (node.nodeType === TEXT_NODE) { 6910 length += node.nodeValue.length; 6911 } 6912 6913 if ((next = node.firstChild) === null) { 6914 break; 6915 } // Moving from `node` to its first child `next`. 6916 6917 6918 parentNode = node; 6919 node = next; 6920 } 6921 6922 while (true) { 6923 if (node === outerNode) { 6924 // If `outerNode` has children, this is always the second time visiting 6925 // it. If it has no children, this is still the first loop, and the only 6926 // valid selection is anchorNode and focusNode both equal to this node 6927 // and both offsets 0, in which case we will have handled above. 6928 break outer; 6929 } 6930 6931 if (parentNode === anchorNode && ++indexWithinAnchor === anchorOffset) { 6932 start = length; 6933 } 6934 6935 if (parentNode === focusNode && ++indexWithinFocus === focusOffset) { 6936 end = length; 6937 } 6938 6939 if ((next = node.nextSibling) !== null) { 6940 break; 6941 } 6942 6943 node = parentNode; 6944 parentNode = node.parentNode; 6945 } // Moving from `node` to its next sibling `next`. 6946 6947 6948 node = next; 6949 } 6950 6951 if (start === -1 || end === -1) { 6952 // This should never happen. (Would happen if the anchor/focus nodes aren't 6953 // actually inside the passed-in node.) 6954 return null; 6955 } 6956 6957 return { 6958 start: start, 6959 end: end 6960 }; 6961 } 6962 /** 6963 * In modern non-IE browsers, we can support both forward and backward 6964 * selections. 6965 * 6966 * Note: IE10+ supports the Selection object, but it does not support 6967 * the `extend` method, which means that even in modern IE, it's not possible 6968 * to programmatically create a backward selection. Thus, for all IE 6969 * versions, we use the old IE API to create our selections. 6970 * 6971 * @param {DOMElement|DOMTextNode} node 6972 * @param {object} offsets 6973 */ 6974 6975 function setOffsets(node, offsets) { 6976 var doc = node.ownerDocument || document; 6977 var win = doc && doc.defaultView || window; // Edge fails with "Object expected" in some scenarios. 6978 // (For instance: TinyMCE editor used in a list component that supports pasting to add more, 6979 // fails when pasting 100+ items) 6980 6981 if (!win.getSelection) { 6982 return; 6983 } 6984 6985 var selection = win.getSelection(); 6986 var length = node.textContent.length; 6987 var start = Math.min(offsets.start, length); 6988 var end = offsets.end === undefined ? start : Math.min(offsets.end, length); // IE 11 uses modern selection, but doesn't support the extend method. 6989 // Flip backward selections, so we can set with a single range. 6990 6991 if (!selection.extend && start > end) { 6992 var temp = end; 6993 end = start; 6994 start = temp; 6995 } 6996 6997 var startMarker = getNodeForCharacterOffset(node, start); 6998 var endMarker = getNodeForCharacterOffset(node, end); 6999 7000 if (startMarker && endMarker) { 7001 if (selection.rangeCount === 1 && selection.anchorNode === startMarker.node && selection.anchorOffset === startMarker.offset && selection.focusNode === endMarker.node && selection.focusOffset === endMarker.offset) { 7002 return; 7003 } 7004 7005 var range = doc.createRange(); 7006 range.setStart(startMarker.node, startMarker.offset); 7007 selection.removeAllRanges(); 7008 7009 if (start > end) { 7010 selection.addRange(range); 7011 selection.extend(endMarker.node, endMarker.offset); 7012 } else { 7013 range.setEnd(endMarker.node, endMarker.offset); 7014 selection.addRange(range); 7015 } 7016 } 7017 } 7018 7019 function isTextNode(node) { 7020 return node && node.nodeType === TEXT_NODE; 7021 } 7022 7023 function containsNode(outerNode, innerNode) { 7024 if (!outerNode || !innerNode) { 7025 return false; 7026 } else if (outerNode === innerNode) { 7027 return true; 7028 } else if (isTextNode(outerNode)) { 7029 return false; 7030 } else if (isTextNode(innerNode)) { 7031 return containsNode(outerNode, innerNode.parentNode); 7032 } else if ('contains' in outerNode) { 7033 return outerNode.contains(innerNode); 7034 } else if (outerNode.compareDocumentPosition) { 7035 return !!(outerNode.compareDocumentPosition(innerNode) & 16); 7036 } else { 7037 return false; 7038 } 7039 } 7040 7041 function isInDocument(node) { 7042 return node && node.ownerDocument && containsNode(node.ownerDocument.documentElement, node); 7043 } 7044 7045 function isSameOriginFrame(iframe) { 7046 try { 7047 // Accessing the contentDocument of a HTMLIframeElement can cause the browser 7048 // to throw, e.g. if it has a cross-origin src attribute. 7049 // Safari will show an error in the console when the access results in "Blocked a frame with origin". e.g: 7050 // iframe.contentDocument.defaultView; 7051 // A safety way is to access one of the cross origin properties: Window or Location 7052 // Which might result in "SecurityError" DOM Exception and it is compatible to Safari. 7053 // https://html.spec.whatwg.org/multipage/browsers.html#integration-with-idl 7054 return typeof iframe.contentWindow.location.href === 'string'; 7055 } catch (err) { 7056 return false; 7057 } 7058 } 7059 7060 function getActiveElementDeep() { 7061 var win = window; 7062 var element = getActiveElement(); 7063 7064 while (element instanceof win.HTMLIFrameElement) { 7065 if (isSameOriginFrame(element)) { 7066 win = element.contentWindow; 7067 } else { 7068 return element; 7069 } 7070 7071 element = getActiveElement(win.document); 7072 } 7073 7074 return element; 7075 } 7076 /** 7077 * @ReactInputSelection: React input selection module. Based on Selection.js, 7078 * but modified to be suitable for react and has a couple of bug fixes (doesn't 7079 * assume buttons have range selections allowed). 7080 * Input selection module for React. 7081 */ 7082 7083 /** 7084 * @hasSelectionCapabilities: we get the element types that support selection 7085 * from https://html.spec.whatwg.org/#do-not-apply, looking at `selectionStart` 7086 * and `selectionEnd` rows. 7087 */ 7088 7089 7090 function hasSelectionCapabilities(elem) { 7091 var nodeName = elem && elem.nodeName && elem.nodeName.toLowerCase(); 7092 return nodeName && (nodeName === 'input' && (elem.type === 'text' || elem.type === 'search' || elem.type === 'tel' || elem.type === 'url' || elem.type === 'password') || nodeName === 'textarea' || elem.contentEditable === 'true'); 7093 } 7094 function getSelectionInformation() { 7095 var focusedElem = getActiveElementDeep(); 7096 return { 7097 // Used by Flare 7098 activeElementDetached: null, 7099 focusedElem: focusedElem, 7100 selectionRange: hasSelectionCapabilities(focusedElem) ? getSelection(focusedElem) : null 7101 }; 7102 } 7103 /** 7104 * @restoreSelection: If any selection information was potentially lost, 7105 * restore it. This is useful when performing operations that could remove dom 7106 * nodes and place them back in, resulting in focus being lost. 7107 */ 7108 7109 function restoreSelection(priorSelectionInformation) { 7110 var curFocusedElem = getActiveElementDeep(); 7111 var priorFocusedElem = priorSelectionInformation.focusedElem; 7112 var priorSelectionRange = priorSelectionInformation.selectionRange; 7113 7114 if (curFocusedElem !== priorFocusedElem && isInDocument(priorFocusedElem)) { 7115 if (priorSelectionRange !== null && hasSelectionCapabilities(priorFocusedElem)) { 7116 setSelection(priorFocusedElem, priorSelectionRange); 7117 } // Focusing a node can change the scroll position, which is undesirable 7118 7119 7120 var ancestors = []; 7121 var ancestor = priorFocusedElem; 7122 7123 while (ancestor = ancestor.parentNode) { 7124 if (ancestor.nodeType === ELEMENT_NODE) { 7125 ancestors.push({ 7126 element: ancestor, 7127 left: ancestor.scrollLeft, 7128 top: ancestor.scrollTop 7129 }); 7130 } 7131 } 7132 7133 if (typeof priorFocusedElem.focus === 'function') { 7134 priorFocusedElem.focus(); 7135 } 7136 7137 for (var i = 0; i < ancestors.length; i++) { 7138 var info = ancestors[i]; 7139 info.element.scrollLeft = info.left; 7140 info.element.scrollTop = info.top; 7141 } 7142 } 7143 } 7144 /** 7145 * @getSelection: Gets the selection bounds of a focused textarea, input or 7146 * contentEditable node. 7147 * -@input: Look up selection bounds of this input 7148 * -@return {start: selectionStart, end: selectionEnd} 7149 */ 7150 7151 function getSelection(input) { 7152 var selection; 7153 7154 if ('selectionStart' in input) { 7155 // Modern browser with input or textarea. 7156 selection = { 7157 start: input.selectionStart, 7158 end: input.selectionEnd 7159 }; 7160 } else { 7161 // Content editable or old IE textarea. 7162 selection = getOffsets(input); 7163 } 7164 7165 return selection || { 7166 start: 0, 7167 end: 0 7168 }; 7169 } 7170 /** 7171 * @setSelection: Sets the selection bounds of a textarea or input and focuses 7172 * the input. 7173 * -@input Set selection bounds of this input or textarea 7174 * -@offsets Object of same form that is returned from get* 7175 */ 7176 7177 function setSelection(input, offsets) { 7178 var start = offsets.start, 7179 end = offsets.end; 7180 7181 if (end === undefined) { 7182 end = start; 7183 } 7184 7185 if ('selectionStart' in input) { 7186 input.selectionStart = start; 7187 input.selectionEnd = Math.min(end, input.value.length); 7188 } else { 7189 setOffsets(input, offsets); 7190 } 7191 } 7192 7193 var validateDOMNesting = function () {}; 7194 7195 var updatedAncestorInfo = function () {}; 7196 7197 { 7198 // This validation code was written based on the HTML5 parsing spec: 7199 // https://html.spec.whatwg.org/multipage/syntax.html#has-an-element-in-scope 7200 // 7201 // Note: this does not catch all invalid nesting, nor does it try to (as it's 7202 // not clear what practical benefit doing so provides); instead, we warn only 7203 // for cases where the parser will give a parse tree differing from what React 7204 // intended. For example, <b><div></div></b> is invalid but we don't warn 7205 // because it still parses correctly; we do warn for other cases like nested 7206 // <p> tags where the beginning of the second element implicitly closes the 7207 // first, causing a confusing mess. 7208 // https://html.spec.whatwg.org/multipage/syntax.html#special 7209 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']; // https://html.spec.whatwg.org/multipage/syntax.html#has-an-element-in-scope 7210 7211 var inScopeTags = ['applet', 'caption', 'html', 'table', 'td', 'th', 'marquee', 'object', 'template', // https://html.spec.whatwg.org/multipage/syntax.html#html-integration-point 7212 // TODO: Distinguish by namespace here -- for <title>, including it here 7213 // errs on the side of fewer warnings 7214 'foreignObject', 'desc', 'title']; // https://html.spec.whatwg.org/multipage/syntax.html#has-an-element-in-button-scope 7215 7216 var buttonScopeTags = inScopeTags.concat(['button']); // https://html.spec.whatwg.org/multipage/syntax.html#generate-implied-end-tags 7217 7218 var impliedEndTags = ['dd', 'dt', 'li', 'option', 'optgroup', 'p', 'rp', 'rt']; 7219 var emptyAncestorInfo = { 7220 current: null, 7221 formTag: null, 7222 aTagInScope: null, 7223 buttonTagInScope: null, 7224 nobrTagInScope: null, 7225 pTagInButtonScope: null, 7226 listItemTagAutoclosing: null, 7227 dlItemTagAutoclosing: null 7228 }; 7229 7230 updatedAncestorInfo = function (oldInfo, tag) { 7231 var ancestorInfo = _assign({}, oldInfo || emptyAncestorInfo); 7232 7233 var info = { 7234 tag: tag 7235 }; 7236 7237 if (inScopeTags.indexOf(tag) !== -1) { 7238 ancestorInfo.aTagInScope = null; 7239 ancestorInfo.buttonTagInScope = null; 7240 ancestorInfo.nobrTagInScope = null; 7241 } 7242 7243 if (buttonScopeTags.indexOf(tag) !== -1) { 7244 ancestorInfo.pTagInButtonScope = null; 7245 } // See rules for 'li', 'dd', 'dt' start tags in 7246 // https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-inbody 7247 7248 7249 if (specialTags.indexOf(tag) !== -1 && tag !== 'address' && tag !== 'div' && tag !== 'p') { 7250 ancestorInfo.listItemTagAutoclosing = null; 7251 ancestorInfo.dlItemTagAutoclosing = null; 7252 } 7253 7254 ancestorInfo.current = info; 7255 7256 if (tag === 'form') { 7257 ancestorInfo.formTag = info; 7258 } 7259 7260 if (tag === 'a') { 7261 ancestorInfo.aTagInScope = info; 7262 } 7263 7264 if (tag === 'button') { 7265 ancestorInfo.buttonTagInScope = info; 7266 } 7267 7268 if (tag === 'nobr') { 7269 ancestorInfo.nobrTagInScope = info; 7270 } 7271 7272 if (tag === 'p') { 7273 ancestorInfo.pTagInButtonScope = info; 7274 } 7275 7276 if (tag === 'li') { 7277 ancestorInfo.listItemTagAutoclosing = info; 7278 } 7279 7280 if (tag === 'dd' || tag === 'dt') { 7281 ancestorInfo.dlItemTagAutoclosing = info; 7282 } 7283 7284 return ancestorInfo; 7285 }; 7286 /** 7287 * Returns whether 7288 */ 7289 7290 7291 var isTagValidWithParent = function (tag, parentTag) { 7292 // First, let's check if we're in an unusual parsing mode... 7293 switch (parentTag) { 7294 // https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-inselect 7295 case 'select': 7296 return tag === 'option' || tag === 'optgroup' || tag === '#text'; 7297 7298 case 'optgroup': 7299 return tag === 'option' || tag === '#text'; 7300 // Strictly speaking, seeing an <option> doesn't mean we're in a <select> 7301 // but 7302 7303 case 'option': 7304 return tag === '#text'; 7305 // https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-intd 7306 // https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-incaption 7307 // No special behavior since these rules fall back to "in body" mode for 7308 // all except special table nodes which cause bad parsing behavior anyway. 7309 // https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-intr 7310 7311 case 'tr': 7312 return tag === 'th' || tag === 'td' || tag === 'style' || tag === 'script' || tag === 'template'; 7313 // https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-intbody 7314 7315 case 'tbody': 7316 case 'thead': 7317 case 'tfoot': 7318 return tag === 'tr' || tag === 'style' || tag === 'script' || tag === 'template'; 7319 // https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-incolgroup 7320 7321 case 'colgroup': 7322 return tag === 'col' || tag === 'template'; 7323 // https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-intable 7324 7325 case 'table': 7326 return tag === 'caption' || tag === 'colgroup' || tag === 'tbody' || tag === 'tfoot' || tag === 'thead' || tag === 'style' || tag === 'script' || tag === 'template'; 7327 // https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-inhead 7328 7329 case 'head': 7330 return tag === 'base' || tag === 'basefont' || tag === 'bgsound' || tag === 'link' || tag === 'meta' || tag === 'title' || tag === 'noscript' || tag === 'noframes' || tag === 'style' || tag === 'script' || tag === 'template'; 7331 // https://html.spec.whatwg.org/multipage/semantics.html#the-html-element 7332 7333 case 'html': 7334 return tag === 'head' || tag === 'body' || tag === 'frameset'; 7335 7336 case 'frameset': 7337 return tag === 'frame'; 7338 7339 case '#document': 7340 return tag === 'html'; 7341 } // Probably in the "in body" parsing mode, so we outlaw only tag combos 7342 // where the parsing rules cause implicit opens or closes to be added. 7343 // https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-inbody 7344 7345 7346 switch (tag) { 7347 case 'h1': 7348 case 'h2': 7349 case 'h3': 7350 case 'h4': 7351 case 'h5': 7352 case 'h6': 7353 return parentTag !== 'h1' && parentTag !== 'h2' && parentTag !== 'h3' && parentTag !== 'h4' && parentTag !== 'h5' && parentTag !== 'h6'; 7354 7355 case 'rp': 7356 case 'rt': 7357 return impliedEndTags.indexOf(parentTag) === -1; 7358 7359 case 'body': 7360 case 'caption': 7361 case 'col': 7362 case 'colgroup': 7363 case 'frameset': 7364 case 'frame': 7365 case 'head': 7366 case 'html': 7367 case 'tbody': 7368 case 'td': 7369 case 'tfoot': 7370 case 'th': 7371 case 'thead': 7372 case 'tr': 7373 // These tags are only valid with a few parents that have special child 7374 // parsing rules -- if we're down here, then none of those matched and 7375 // so we allow it only if we don't know what the parent is, as all other 7376 // cases are invalid. 7377 return parentTag == null; 7378 } 7379 7380 return true; 7381 }; 7382 /** 7383 * Returns whether 7384 */ 7385 7386 7387 var findInvalidAncestorForTag = function (tag, ancestorInfo) { 7388 switch (tag) { 7389 case 'address': 7390 case 'article': 7391 case 'aside': 7392 case 'blockquote': 7393 case 'center': 7394 case 'details': 7395 case 'dialog': 7396 case 'dir': 7397 case 'div': 7398 case 'dl': 7399 case 'fieldset': 7400 case 'figcaption': 7401 case 'figure': 7402 case 'footer': 7403 case 'header': 7404 case 'hgroup': 7405 case 'main': 7406 case 'menu': 7407 case 'nav': 7408 case 'ol': 7409 case 'p': 7410 case 'section': 7411 case 'summary': 7412 case 'ul': 7413 case 'pre': 7414 case 'listing': 7415 case 'table': 7416 case 'hr': 7417 case 'xmp': 7418 case 'h1': 7419 case 'h2': 7420 case 'h3': 7421 case 'h4': 7422 case 'h5': 7423 case 'h6': 7424 return ancestorInfo.pTagInButtonScope; 7425 7426 case 'form': 7427 return ancestorInfo.formTag || ancestorInfo.pTagInButtonScope; 7428 7429 case 'li': 7430 return ancestorInfo.listItemTagAutoclosing; 7431 7432 case 'dd': 7433 case 'dt': 7434 return ancestorInfo.dlItemTagAutoclosing; 7435 7436 case 'button': 7437 return ancestorInfo.buttonTagInScope; 7438 7439 case 'a': 7440 // Spec says something about storing a list of markers, but it sounds 7441 // equivalent to this check. 7442 return ancestorInfo.aTagInScope; 7443 7444 case 'nobr': 7445 return ancestorInfo.nobrTagInScope; 7446 } 7447 7448 return null; 7449 }; 7450 7451 var didWarn$1 = {}; 7452 7453 validateDOMNesting = function (childTag, childText, ancestorInfo) { 7454 ancestorInfo = ancestorInfo || emptyAncestorInfo; 7455 var parentInfo = ancestorInfo.current; 7456 var parentTag = parentInfo && parentInfo.tag; 7457 7458 if (childText != null) { 7459 if (childTag != null) { 7460 error('validateDOMNesting: when childText is passed, childTag should be null'); 7461 } 7462 7463 childTag = '#text'; 7464 } 7465 7466 var invalidParent = isTagValidWithParent(childTag, parentTag) ? null : parentInfo; 7467 var invalidAncestor = invalidParent ? null : findInvalidAncestorForTag(childTag, ancestorInfo); 7468 var invalidParentOrAncestor = invalidParent || invalidAncestor; 7469 7470 if (!invalidParentOrAncestor) { 7471 return; 7472 } 7473 7474 var ancestorTag = invalidParentOrAncestor.tag; 7475 var addendum = getCurrentFiberStackInDev(); 7476 var warnKey = !!invalidParent + '|' + childTag + '|' + ancestorTag + '|' + addendum; 7477 7478 if (didWarn$1[warnKey]) { 7479 return; 7480 } 7481 7482 didWarn$1[warnKey] = true; 7483 var tagDisplayName = childTag; 7484 var whitespaceInfo = ''; 7485 7486 if (childTag === '#text') { 7487 if (/\S/.test(childText)) { 7488 tagDisplayName = 'Text nodes'; 7489 } else { 7490 tagDisplayName = 'Whitespace text nodes'; 7491 whitespaceInfo = " Make sure you don't have any extra whitespace between tags on " + 'each line of your source code.'; 7492 } 7493 } else { 7494 tagDisplayName = '<' + childTag + '>'; 7495 } 7496 7497 if (invalidParent) { 7498 var info = ''; 7499 7500 if (ancestorTag === 'table' && childTag === 'tr') { 7501 info += ' Add a <tbody>, <thead> or <tfoot> to your code to match the DOM tree generated by ' + 'the browser.'; 7502 } 7503 7504 error('validateDOMNesting(...): %s cannot appear as a child of <%s>.%s%s', tagDisplayName, ancestorTag, whitespaceInfo, info); 7505 } else { 7506 error('validateDOMNesting(...): %s cannot appear as a descendant of ' + '<%s>.', tagDisplayName, ancestorTag); 7507 } 7508 }; 7509 } 7510 7511 var SUPPRESS_HYDRATION_WARNING$1; 7512 7513 { 7514 SUPPRESS_HYDRATION_WARNING$1 = 'suppressHydrationWarning'; 7515 } 7516 7517 var SUSPENSE_START_DATA = '$'; 7518 var SUSPENSE_END_DATA = '/$'; 7519 var SUSPENSE_PENDING_START_DATA = '$?'; 7520 var SUSPENSE_FALLBACK_START_DATA = '$!'; 7521 var STYLE$1 = 'style'; 7522 var eventsEnabled = null; 7523 var selectionInformation = null; 7524 7525 function shouldAutoFocusHostComponent(type, props) { 7526 switch (type) { 7527 case 'button': 7528 case 'input': 7529 case 'select': 7530 case 'textarea': 7531 return !!props.autoFocus; 7532 } 7533 7534 return false; 7535 } 7536 function getRootHostContext(rootContainerInstance) { 7537 var type; 7538 var namespace; 7539 var nodeType = rootContainerInstance.nodeType; 7540 7541 switch (nodeType) { 7542 case DOCUMENT_NODE: 7543 case DOCUMENT_FRAGMENT_NODE: 7544 { 7545 type = nodeType === DOCUMENT_NODE ? '#document' : '#fragment'; 7546 var root = rootContainerInstance.documentElement; 7547 namespace = root ? root.namespaceURI : getChildNamespace(null, ''); 7548 break; 7549 } 7550 7551 default: 7552 { 7553 var container = nodeType === COMMENT_NODE ? rootContainerInstance.parentNode : rootContainerInstance; 7554 var ownNamespace = container.namespaceURI || null; 7555 type = container.tagName; 7556 namespace = getChildNamespace(ownNamespace, type); 7557 break; 7558 } 7559 } 7560 7561 { 7562 var validatedTag = type.toLowerCase(); 7563 var ancestorInfo = updatedAncestorInfo(null, validatedTag); 7564 return { 7565 namespace: namespace, 7566 ancestorInfo: ancestorInfo 7567 }; 7568 } 7569 } 7570 function getChildHostContext(parentHostContext, type, rootContainerInstance) { 7571 { 7572 var parentHostContextDev = parentHostContext; 7573 var namespace = getChildNamespace(parentHostContextDev.namespace, type); 7574 var ancestorInfo = updatedAncestorInfo(parentHostContextDev.ancestorInfo, type); 7575 return { 7576 namespace: namespace, 7577 ancestorInfo: ancestorInfo 7578 }; 7579 } 7580 } 7581 function getPublicInstance(instance) { 7582 return instance; 7583 } 7584 function prepareForCommit(containerInfo) { 7585 eventsEnabled = isEnabled(); 7586 selectionInformation = getSelectionInformation(); 7587 setEnabled(false); 7588 } 7589 function resetAfterCommit(containerInfo) { 7590 restoreSelection(selectionInformation); 7591 setEnabled(eventsEnabled); 7592 eventsEnabled = null; 7593 7594 selectionInformation = null; 7595 } 7596 function createInstance(type, props, rootContainerInstance, hostContext, internalInstanceHandle) { 7597 var parentNamespace; 7598 7599 { 7600 // TODO: take namespace into account when validating. 7601 var hostContextDev = hostContext; 7602 validateDOMNesting(type, null, hostContextDev.ancestorInfo); 7603 7604 if (typeof props.children === 'string' || typeof props.children === 'number') { 7605 var string = '' + props.children; 7606 var ownAncestorInfo = updatedAncestorInfo(hostContextDev.ancestorInfo, type); 7607 validateDOMNesting(null, string, ownAncestorInfo); 7608 } 7609 7610 parentNamespace = hostContextDev.namespace; 7611 } 7612 7613 var domElement = createElement(type, props, rootContainerInstance, parentNamespace); 7614 precacheFiberNode(internalInstanceHandle, domElement); 7615 updateFiberProps(domElement, props); 7616 return domElement; 7617 } 7618 function appendInitialChild(parentInstance, child) { 7619 parentInstance.appendChild(child); 7620 } 7621 function finalizeInitialChildren(domElement, type, props, rootContainerInstance, hostContext) { 7622 setInitialProperties(domElement, type, props, rootContainerInstance); 7623 return shouldAutoFocusHostComponent(type, props); 7624 } 7625 function prepareUpdate(domElement, type, oldProps, newProps, rootContainerInstance, hostContext) { 7626 { 7627 var hostContextDev = hostContext; 7628 7629 if (typeof newProps.children !== typeof oldProps.children && (typeof newProps.children === 'string' || typeof newProps.children === 'number')) { 7630 var string = '' + newProps.children; 7631 var ownAncestorInfo = updatedAncestorInfo(hostContextDev.ancestorInfo, type); 7632 validateDOMNesting(null, string, ownAncestorInfo); 7633 } 7634 } 7635 7636 return diffProperties(domElement, type, oldProps, newProps, rootContainerInstance); 7637 } 7638 function shouldSetTextContent(type, props) { 7639 return type === 'textarea' || type === 'option' || type === 'noscript' || typeof props.children === 'string' || typeof props.children === 'number' || typeof props.dangerouslySetInnerHTML === 'object' && props.dangerouslySetInnerHTML !== null && props.dangerouslySetInnerHTML.__html != null; 7640 } 7641 function shouldDeprioritizeSubtree(type, props) { 7642 return !!props.hidden; 7643 } 7644 function createTextInstance(text, rootContainerInstance, hostContext, internalInstanceHandle) { 7645 { 7646 var hostContextDev = hostContext; 7647 validateDOMNesting(null, text, hostContextDev.ancestorInfo); 7648 } 7649 7650 var textNode = createTextNode(text, rootContainerInstance); 7651 precacheFiberNode(internalInstanceHandle, textNode); 7652 return textNode; 7653 } 7654 // if a component just imports ReactDOM (e.g. for findDOMNode). 7655 // Some environments might not have setTimeout or clearTimeout. 7656 7657 var scheduleTimeout = typeof setTimeout === 'function' ? setTimeout : undefined; 7658 var cancelTimeout = typeof clearTimeout === 'function' ? clearTimeout : undefined; 7659 var noTimeout = -1; // ------------------- 7660 function commitMount(domElement, type, newProps, internalInstanceHandle) { 7661 // Despite the naming that might imply otherwise, this method only 7662 // fires if there is an `Update` effect scheduled during mounting. 7663 // This happens if `finalizeInitialChildren` returns `true` (which it 7664 // does to implement the `autoFocus` attribute on the client). But 7665 // there are also other cases when this might happen (such as patching 7666 // up text content during hydration mismatch). So we'll check this again. 7667 if (shouldAutoFocusHostComponent(type, newProps)) { 7668 domElement.focus(); 7669 } 7670 } 7671 function commitUpdate(domElement, updatePayload, type, oldProps, newProps, internalInstanceHandle) { 7672 // Update the props handle so that we know which props are the ones with 7673 // with current event handlers. 7674 updateFiberProps(domElement, newProps); // Apply the diff to the DOM node. 7675 7676 updateProperties(domElement, updatePayload, type, oldProps, newProps); 7677 } 7678 function resetTextContent(domElement) { 7679 setTextContent(domElement, ''); 7680 } 7681 function commitTextUpdate(textInstance, oldText, newText) { 7682 textInstance.nodeValue = newText; 7683 } 7684 function appendChild(parentInstance, child) { 7685 parentInstance.appendChild(child); 7686 } 7687 function appendChildToContainer(container, child) { 7688 var parentNode; 7689 7690 if (container.nodeType === COMMENT_NODE) { 7691 parentNode = container.parentNode; 7692 parentNode.insertBefore(child, container); 7693 } else { 7694 parentNode = container; 7695 parentNode.appendChild(child); 7696 } // This container might be used for a portal. 7697 // If something inside a portal is clicked, that click should bubble 7698 // through the React tree. However, on Mobile Safari the click would 7699 // never bubble through the *DOM* tree unless an ancestor with onclick 7700 // event exists. So we wouldn't see it and dispatch it. 7701 // This is why we ensure that non React root containers have inline onclick 7702 // defined. 7703 // https://github.com/facebook/react/issues/11918 7704 7705 7706 var reactRootContainer = container._reactRootContainer; 7707 7708 if ((reactRootContainer === null || reactRootContainer === undefined) && parentNode.onclick === null) { 7709 // TODO: This cast may not be sound for SVG, MathML or custom elements. 7710 trapClickOnNonInteractiveElement(parentNode); 7711 } 7712 } 7713 function insertBefore(parentInstance, child, beforeChild) { 7714 parentInstance.insertBefore(child, beforeChild); 7715 } 7716 function insertInContainerBefore(container, child, beforeChild) { 7717 if (container.nodeType === COMMENT_NODE) { 7718 container.parentNode.insertBefore(child, beforeChild); 7719 } else { 7720 container.insertBefore(child, beforeChild); 7721 } 7722 } 7723 function removeChild(parentInstance, child) { 7724 parentInstance.removeChild(child); 7725 } 7726 function removeChildFromContainer(container, child) { 7727 if (container.nodeType === COMMENT_NODE) { 7728 container.parentNode.removeChild(child); 7729 } else { 7730 container.removeChild(child); 7731 } 7732 } 7733 7734 function hideInstance(instance) { 7735 // pass host context to this method? 7736 7737 7738 instance = instance; 7739 var style = instance.style; 7740 7741 if (typeof style.setProperty === 'function') { 7742 style.setProperty('display', 'none', 'important'); 7743 } else { 7744 style.display = 'none'; 7745 } 7746 } 7747 function hideTextInstance(textInstance) { 7748 textInstance.nodeValue = ''; 7749 } 7750 function unhideInstance(instance, props) { 7751 instance = instance; 7752 var styleProp = props[STYLE$1]; 7753 var display = styleProp !== undefined && styleProp !== null && styleProp.hasOwnProperty('display') ? styleProp.display : null; 7754 instance.style.display = dangerousStyleValue('display', display); 7755 } 7756 function unhideTextInstance(textInstance, text) { 7757 textInstance.nodeValue = text; 7758 } // ------------------- 7759 function canHydrateInstance(instance, type, props) { 7760 if (instance.nodeType !== ELEMENT_NODE || type.toLowerCase() !== instance.nodeName.toLowerCase()) { 7761 return null; 7762 } // This has now been refined to an element node. 7763 7764 7765 return instance; 7766 } 7767 function canHydrateTextInstance(instance, text) { 7768 if (text === '' || instance.nodeType !== TEXT_NODE) { 7769 // Empty strings are not parsed by HTML so there won't be a correct match here. 7770 return null; 7771 } // This has now been refined to a text node. 7772 7773 7774 return instance; 7775 } 7776 function isSuspenseInstancePending(instance) { 7777 return instance.data === SUSPENSE_PENDING_START_DATA; 7778 } 7779 function isSuspenseInstanceFallback(instance) { 7780 return instance.data === SUSPENSE_FALLBACK_START_DATA; 7781 } 7782 7783 function getNextHydratable(node) { 7784 // Skip non-hydratable nodes. 7785 for (; node != null; node = node.nextSibling) { 7786 var nodeType = node.nodeType; 7787 7788 if (nodeType === ELEMENT_NODE || nodeType === TEXT_NODE) { 7789 break; 7790 } 7791 } 7792 7793 return node; 7794 } 7795 7796 function getNextHydratableSibling(instance) { 7797 return getNextHydratable(instance.nextSibling); 7798 } 7799 function getFirstHydratableChild(parentInstance) { 7800 return getNextHydratable(parentInstance.firstChild); 7801 } 7802 function hydrateInstance(instance, type, props, rootContainerInstance, hostContext, internalInstanceHandle) { 7803 precacheFiberNode(internalInstanceHandle, instance); // TODO: Possibly defer this until the commit phase where all the events 7804 // get attached. 7805 7806 updateFiberProps(instance, props); 7807 var parentNamespace; 7808 7809 { 7810 var hostContextDev = hostContext; 7811 parentNamespace = hostContextDev.namespace; 7812 } 7813 7814 return diffHydratedProperties(instance, type, props, parentNamespace, rootContainerInstance); 7815 } 7816 function hydrateTextInstance(textInstance, text, internalInstanceHandle) { 7817 precacheFiberNode(internalInstanceHandle, textInstance); 7818 return diffHydratedText(textInstance, text); 7819 } 7820 function getNextHydratableInstanceAfterSuspenseInstance(suspenseInstance) { 7821 var node = suspenseInstance.nextSibling; // Skip past all nodes within this suspense boundary. 7822 // There might be nested nodes so we need to keep track of how 7823 // deep we are and only break out when we're back on top. 7824 7825 var depth = 0; 7826 7827 while (node) { 7828 if (node.nodeType === COMMENT_NODE) { 7829 var data = node.data; 7830 7831 if (data === SUSPENSE_END_DATA) { 7832 if (depth === 0) { 7833 return getNextHydratableSibling(node); 7834 } else { 7835 depth--; 7836 } 7837 } else if (data === SUSPENSE_START_DATA || data === SUSPENSE_FALLBACK_START_DATA || data === SUSPENSE_PENDING_START_DATA) { 7838 depth++; 7839 } 7840 } 7841 7842 node = node.nextSibling; 7843 } // TODO: Warn, we didn't find the end comment boundary. 7844 7845 7846 return null; 7847 } // Returns the SuspenseInstance if this node is a direct child of a 7848 // SuspenseInstance. I.e. if its previous sibling is a Comment with 7849 // SUSPENSE_x_START_DATA. Otherwise, null. 7850 7851 function getParentSuspenseInstance(targetInstance) { 7852 var node = targetInstance.previousSibling; // Skip past all nodes within this suspense boundary. 7853 // There might be nested nodes so we need to keep track of how 7854 // deep we are and only break out when we're back on top. 7855 7856 var depth = 0; 7857 7858 while (node) { 7859 if (node.nodeType === COMMENT_NODE) { 7860 var data = node.data; 7861 7862 if (data === SUSPENSE_START_DATA || data === SUSPENSE_FALLBACK_START_DATA || data === SUSPENSE_PENDING_START_DATA) { 7863 if (depth === 0) { 7864 return node; 7865 } else { 7866 depth--; 7867 } 7868 } else if (data === SUSPENSE_END_DATA) { 7869 depth++; 7870 } 7871 } 7872 7873 node = node.previousSibling; 7874 } 7875 7876 return null; 7877 } 7878 function commitHydratedContainer(container) { 7879 // Retry if any event replaying was blocked on this. 7880 retryIfBlockedOn(container); 7881 } 7882 function commitHydratedSuspenseInstance(suspenseInstance) { 7883 // Retry if any event replaying was blocked on this. 7884 retryIfBlockedOn(suspenseInstance); 7885 } 7886 function didNotMatchHydratedContainerTextInstance(parentContainer, textInstance, text) { 7887 { 7888 warnForUnmatchedText(textInstance, text); 7889 } 7890 } 7891 function didNotMatchHydratedTextInstance(parentType, parentProps, parentInstance, textInstance, text) { 7892 if ( parentProps[SUPPRESS_HYDRATION_WARNING$1] !== true) { 7893 warnForUnmatchedText(textInstance, text); 7894 } 7895 } 7896 function didNotHydrateContainerInstance(parentContainer, instance) { 7897 { 7898 if (instance.nodeType === ELEMENT_NODE) { 7899 warnForDeletedHydratableElement(parentContainer, instance); 7900 } else if (instance.nodeType === COMMENT_NODE) ; else { 7901 warnForDeletedHydratableText(parentContainer, instance); 7902 } 7903 } 7904 } 7905 function didNotHydrateInstance(parentType, parentProps, parentInstance, instance) { 7906 if ( parentProps[SUPPRESS_HYDRATION_WARNING$1] !== true) { 7907 if (instance.nodeType === ELEMENT_NODE) { 7908 warnForDeletedHydratableElement(parentInstance, instance); 7909 } else if (instance.nodeType === COMMENT_NODE) ; else { 7910 warnForDeletedHydratableText(parentInstance, instance); 7911 } 7912 } 7913 } 7914 function didNotFindHydratableContainerInstance(parentContainer, type, props) { 7915 { 7916 warnForInsertedHydratedElement(parentContainer, type); 7917 } 7918 } 7919 function didNotFindHydratableContainerTextInstance(parentContainer, text) { 7920 { 7921 warnForInsertedHydratedText(parentContainer, text); 7922 } 7923 } 7924 function didNotFindHydratableInstance(parentType, parentProps, parentInstance, type, props) { 7925 if ( parentProps[SUPPRESS_HYDRATION_WARNING$1] !== true) { 7926 warnForInsertedHydratedElement(parentInstance, type); 7927 } 7928 } 7929 function didNotFindHydratableTextInstance(parentType, parentProps, parentInstance, text) { 7930 if ( parentProps[SUPPRESS_HYDRATION_WARNING$1] !== true) { 7931 warnForInsertedHydratedText(parentInstance, text); 7932 } 7933 } 7934 function didNotFindHydratableSuspenseInstance(parentType, parentProps, parentInstance) { 7935 if ( parentProps[SUPPRESS_HYDRATION_WARNING$1] !== true) ; 7936 } 7937 7938 var randomKey = Math.random().toString(36).slice(2); 7939 var internalInstanceKey = '__reactInternalInstance$' + randomKey; 7940 var internalEventHandlersKey = '__reactEventHandlers$' + randomKey; 7941 var internalContainerInstanceKey = '__reactContainere$' + randomKey; 7942 function precacheFiberNode(hostInst, node) { 7943 node[internalInstanceKey] = hostInst; 7944 } 7945 function markContainerAsRoot(hostRoot, node) { 7946 node[internalContainerInstanceKey] = hostRoot; 7947 } 7948 function unmarkContainerAsRoot(node) { 7949 node[internalContainerInstanceKey] = null; 7950 } 7951 function isContainerMarkedAsRoot(node) { 7952 return !!node[internalContainerInstanceKey]; 7953 } // Given a DOM node, return the closest HostComponent or HostText fiber ancestor. 7954 // If the target node is part of a hydrated or not yet rendered subtree, then 7955 // this may also return a SuspenseComponent or HostRoot to indicate that. 7956 // Conceptually the HostRoot fiber is a child of the Container node. So if you 7957 // pass the Container node as the targetNode, you will not actually get the 7958 // HostRoot back. To get to the HostRoot, you need to pass a child of it. 7959 // The same thing applies to Suspense boundaries. 7960 7961 function getClosestInstanceFromNode(targetNode) { 7962 var targetInst = targetNode[internalInstanceKey]; 7963 7964 if (targetInst) { 7965 // Don't return HostRoot or SuspenseComponent here. 7966 return targetInst; 7967 } // If the direct event target isn't a React owned DOM node, we need to look 7968 // to see if one of its parents is a React owned DOM node. 7969 7970 7971 var parentNode = targetNode.parentNode; 7972 7973 while (parentNode) { 7974 // We'll check if this is a container root that could include 7975 // React nodes in the future. We need to check this first because 7976 // if we're a child of a dehydrated container, we need to first 7977 // find that inner container before moving on to finding the parent 7978 // instance. Note that we don't check this field on the targetNode 7979 // itself because the fibers are conceptually between the container 7980 // node and the first child. It isn't surrounding the container node. 7981 // If it's not a container, we check if it's an instance. 7982 targetInst = parentNode[internalContainerInstanceKey] || parentNode[internalInstanceKey]; 7983 7984 if (targetInst) { 7985 // Since this wasn't the direct target of the event, we might have 7986 // stepped past dehydrated DOM nodes to get here. However they could 7987 // also have been non-React nodes. We need to answer which one. 7988 // If we the instance doesn't have any children, then there can't be 7989 // a nested suspense boundary within it. So we can use this as a fast 7990 // bailout. Most of the time, when people add non-React children to 7991 // the tree, it is using a ref to a child-less DOM node. 7992 // Normally we'd only need to check one of the fibers because if it 7993 // has ever gone from having children to deleting them or vice versa 7994 // it would have deleted the dehydrated boundary nested inside already. 7995 // However, since the HostRoot starts out with an alternate it might 7996 // have one on the alternate so we need to check in case this was a 7997 // root. 7998 var alternate = targetInst.alternate; 7999 8000 if (targetInst.child !== null || alternate !== null && alternate.child !== null) { 8001 // Next we need to figure out if the node that skipped past is 8002 // nested within a dehydrated boundary and if so, which one. 8003 var suspenseInstance = getParentSuspenseInstance(targetNode); 8004 8005 while (suspenseInstance !== null) { 8006 // We found a suspense instance. That means that we haven't 8007 // hydrated it yet. Even though we leave the comments in the 8008 // DOM after hydrating, and there are boundaries in the DOM 8009 // that could already be hydrated, we wouldn't have found them 8010 // through this pass since if the target is hydrated it would 8011 // have had an internalInstanceKey on it. 8012 // Let's get the fiber associated with the SuspenseComponent 8013 // as the deepest instance. 8014 var targetSuspenseInst = suspenseInstance[internalInstanceKey]; 8015 8016 if (targetSuspenseInst) { 8017 return targetSuspenseInst; 8018 } // If we don't find a Fiber on the comment, it might be because 8019 // we haven't gotten to hydrate it yet. There might still be a 8020 // parent boundary that hasn't above this one so we need to find 8021 // the outer most that is known. 8022 8023 8024 suspenseInstance = getParentSuspenseInstance(suspenseInstance); // If we don't find one, then that should mean that the parent 8025 // host component also hasn't hydrated yet. We can return it 8026 // below since it will bail out on the isMounted check later. 8027 } 8028 } 8029 8030 return targetInst; 8031 } 8032 8033 targetNode = parentNode; 8034 parentNode = targetNode.parentNode; 8035 } 8036 8037 return null; 8038 } 8039 /** 8040 * Given a DOM node, return the ReactDOMComponent or ReactDOMTextComponent 8041 * instance, or null if the node was not rendered by this React. 8042 */ 8043 8044 function getInstanceFromNode$1(node) { 8045 var inst = node[internalInstanceKey] || node[internalContainerInstanceKey]; 8046 8047 if (inst) { 8048 if (inst.tag === HostComponent || inst.tag === HostText || inst.tag === SuspenseComponent || inst.tag === HostRoot) { 8049 return inst; 8050 } else { 8051 return null; 8052 } 8053 } 8054 8055 return null; 8056 } 8057 /** 8058 * Given a ReactDOMComponent or ReactDOMTextComponent, return the corresponding 8059 * DOM node. 8060 */ 8061 8062 function getNodeFromInstance$1(inst) { 8063 if (inst.tag === HostComponent || inst.tag === HostText) { 8064 // In Fiber this, is just the state node right now. We assume it will be 8065 // a host component or host text. 8066 return inst.stateNode; 8067 } // Without this first invariant, passing a non-DOM-component triggers the next 8068 // invariant for a missing parent, which is super confusing. 8069 8070 8071 { 8072 { 8073 throw Error( "getNodeFromInstance: Invalid argument." ); 8074 } 8075 } 8076 } 8077 function getFiberCurrentPropsFromNode$1(node) { 8078 return node[internalEventHandlersKey] || null; 8079 } 8080 function updateFiberProps(node, props) { 8081 node[internalEventHandlersKey] = props; 8082 } 8083 8084 function getParent(inst) { 8085 do { 8086 inst = inst.return; // TODO: If this is a HostRoot we might want to bail out. 8087 // That is depending on if we want nested subtrees (layers) to bubble 8088 // events to their parent. We could also go through parentNode on the 8089 // host node but that wouldn't work for React Native and doesn't let us 8090 // do the portal feature. 8091 } while (inst && inst.tag !== HostComponent); 8092 8093 if (inst) { 8094 return inst; 8095 } 8096 8097 return null; 8098 } 8099 /** 8100 * Return the lowest common ancestor of A and B, or null if they are in 8101 * different trees. 8102 */ 8103 8104 8105 function getLowestCommonAncestor(instA, instB) { 8106 var depthA = 0; 8107 8108 for (var tempA = instA; tempA; tempA = getParent(tempA)) { 8109 depthA++; 8110 } 8111 8112 var depthB = 0; 8113 8114 for (var tempB = instB; tempB; tempB = getParent(tempB)) { 8115 depthB++; 8116 } // If A is deeper, crawl up. 8117 8118 8119 while (depthA - depthB > 0) { 8120 instA = getParent(instA); 8121 depthA--; 8122 } // If B is deeper, crawl up. 8123 8124 8125 while (depthB - depthA > 0) { 8126 instB = getParent(instB); 8127 depthB--; 8128 } // Walk in lockstep until we find a match. 8129 8130 8131 var depth = depthA; 8132 8133 while (depth--) { 8134 if (instA === instB || instA === instB.alternate) { 8135 return instA; 8136 } 8137 8138 instA = getParent(instA); 8139 instB = getParent(instB); 8140 } 8141 8142 return null; 8143 } 8144 /** 8145 * Simulates the traversal of a two-phase, capture/bubble event dispatch. 8146 */ 8147 8148 function traverseTwoPhase(inst, fn, arg) { 8149 var path = []; 8150 8151 while (inst) { 8152 path.push(inst); 8153 inst = getParent(inst); 8154 } 8155 8156 var i; 8157 8158 for (i = path.length; i-- > 0;) { 8159 fn(path[i], 'captured', arg); 8160 } 8161 8162 for (i = 0; i < path.length; i++) { 8163 fn(path[i], 'bubbled', arg); 8164 } 8165 } 8166 /** 8167 * Traverses the ID hierarchy and invokes the supplied `cb` on any IDs that 8168 * should would receive a `mouseEnter` or `mouseLeave` event. 8169 * 8170 * Does not invoke the callback on the nearest common ancestor because nothing 8171 * "entered" or "left" that element. 8172 */ 8173 8174 function traverseEnterLeave(from, to, fn, argFrom, argTo) { 8175 var common = from && to ? getLowestCommonAncestor(from, to) : null; 8176 var pathFrom = []; 8177 8178 while (true) { 8179 if (!from) { 8180 break; 8181 } 8182 8183 if (from === common) { 8184 break; 8185 } 8186 8187 var alternate = from.alternate; 8188 8189 if (alternate !== null && alternate === common) { 8190 break; 8191 } 8192 8193 pathFrom.push(from); 8194 from = getParent(from); 8195 } 8196 8197 var pathTo = []; 8198 8199 while (true) { 8200 if (!to) { 8201 break; 8202 } 8203 8204 if (to === common) { 8205 break; 8206 } 8207 8208 var _alternate = to.alternate; 8209 8210 if (_alternate !== null && _alternate === common) { 8211 break; 8212 } 8213 8214 pathTo.push(to); 8215 to = getParent(to); 8216 } 8217 8218 for (var i = 0; i < pathFrom.length; i++) { 8219 fn(pathFrom[i], 'bubbled', argFrom); 8220 } 8221 8222 for (var _i = pathTo.length; _i-- > 0;) { 8223 fn(pathTo[_i], 'captured', argTo); 8224 } 8225 } 8226 8227 function isInteractive(tag) { 8228 return tag === 'button' || tag === 'input' || tag === 'select' || tag === 'textarea'; 8229 } 8230 8231 function shouldPreventMouseEvent(name, type, props) { 8232 switch (name) { 8233 case 'onClick': 8234 case 'onClickCapture': 8235 case 'onDoubleClick': 8236 case 'onDoubleClickCapture': 8237 case 'onMouseDown': 8238 case 'onMouseDownCapture': 8239 case 'onMouseMove': 8240 case 'onMouseMoveCapture': 8241 case 'onMouseUp': 8242 case 'onMouseUpCapture': 8243 case 'onMouseEnter': 8244 return !!(props.disabled && isInteractive(type)); 8245 8246 default: 8247 return false; 8248 } 8249 } 8250 /** 8251 * @param {object} inst The instance, which is the source of events. 8252 * @param {string} registrationName Name of listener (e.g. `onClick`). 8253 * @return {?function} The stored callback. 8254 */ 8255 8256 8257 function getListener(inst, registrationName) { 8258 var listener; // TODO: shouldPreventMouseEvent is DOM-specific and definitely should not 8259 // live here; needs to be moved to a better place soon 8260 8261 var stateNode = inst.stateNode; 8262 8263 if (!stateNode) { 8264 // Work in progress (ex: onload events in incremental mode). 8265 return null; 8266 } 8267 8268 var props = getFiberCurrentPropsFromNode(stateNode); 8269 8270 if (!props) { 8271 // Work in progress. 8272 return null; 8273 } 8274 8275 listener = props[registrationName]; 8276 8277 if (shouldPreventMouseEvent(registrationName, inst.type, props)) { 8278 return null; 8279 } 8280 8281 if (!(!listener || typeof listener === 'function')) { 8282 { 8283 throw Error( "Expected `" + registrationName + "` listener to be a function, instead got a value of `" + typeof listener + "` type." ); 8284 } 8285 } 8286 8287 return listener; 8288 } 8289 8290 /** 8291 * Some event types have a notion of different registration names for different 8292 * "phases" of propagation. This finds listeners by a given phase. 8293 */ 8294 function listenerAtPhase(inst, event, propagationPhase) { 8295 var registrationName = event.dispatchConfig.phasedRegistrationNames[propagationPhase]; 8296 return getListener(inst, registrationName); 8297 } 8298 /** 8299 * A small set of propagation patterns, each of which will accept a small amount 8300 * of information, and generate a set of "dispatch ready event objects" - which 8301 * are sets of events that have already been annotated with a set of dispatched 8302 * listener functions/ids. The API is designed this way to discourage these 8303 * propagation strategies from actually executing the dispatches, since we 8304 * always want to collect the entire set of dispatches before executing even a 8305 * single one. 8306 */ 8307 8308 /** 8309 * Tags a `SyntheticEvent` with dispatched listeners. Creating this function 8310 * here, allows us to not have to bind or create functions for each event. 8311 * Mutating the event's members allows us to not have to create a wrapping 8312 * "dispatch" object that pairs the event with the listener. 8313 */ 8314 8315 8316 function accumulateDirectionalDispatches(inst, phase, event) { 8317 { 8318 if (!inst) { 8319 error('Dispatching inst must not be null'); 8320 } 8321 } 8322 8323 var listener = listenerAtPhase(inst, event, phase); 8324 8325 if (listener) { 8326 event._dispatchListeners = accumulateInto(event._dispatchListeners, listener); 8327 event._dispatchInstances = accumulateInto(event._dispatchInstances, inst); 8328 } 8329 } 8330 /** 8331 * Collect dispatches (must be entirely collected before dispatching - see unit 8332 * tests). Lazily allocate the array to conserve memory. We must loop through 8333 * each event and perform the traversal for each one. We cannot perform a 8334 * single traversal for the entire collection of events because each event may 8335 * have a different target. 8336 */ 8337 8338 8339 function accumulateTwoPhaseDispatchesSingle(event) { 8340 if (event && event.dispatchConfig.phasedRegistrationNames) { 8341 traverseTwoPhase(event._targetInst, accumulateDirectionalDispatches, event); 8342 } 8343 } 8344 /** 8345 * Accumulates without regard to direction, does not look for phased 8346 * registration names. Same as `accumulateDirectDispatchesSingle` but without 8347 * requiring that the `dispatchMarker` be the same as the dispatched ID. 8348 */ 8349 8350 8351 function accumulateDispatches(inst, ignoredDirection, event) { 8352 if (inst && event && event.dispatchConfig.registrationName) { 8353 var registrationName = event.dispatchConfig.registrationName; 8354 var listener = getListener(inst, registrationName); 8355 8356 if (listener) { 8357 event._dispatchListeners = accumulateInto(event._dispatchListeners, listener); 8358 event._dispatchInstances = accumulateInto(event._dispatchInstances, inst); 8359 } 8360 } 8361 } 8362 /** 8363 * Accumulates dispatches on an `SyntheticEvent`, but only for the 8364 * `dispatchMarker`. 8365 * @param {SyntheticEvent} event 8366 */ 8367 8368 8369 function accumulateDirectDispatchesSingle(event) { 8370 if (event && event.dispatchConfig.registrationName) { 8371 accumulateDispatches(event._targetInst, null, event); 8372 } 8373 } 8374 8375 function accumulateTwoPhaseDispatches(events) { 8376 forEachAccumulated(events, accumulateTwoPhaseDispatchesSingle); 8377 } 8378 function accumulateEnterLeaveDispatches(leave, enter, from, to) { 8379 traverseEnterLeave(from, to, accumulateDispatches, leave, enter); 8380 } 8381 function accumulateDirectDispatches(events) { 8382 forEachAccumulated(events, accumulateDirectDispatchesSingle); 8383 } 8384 8385 /** 8386 * These variables store information about text content of a target node, 8387 * allowing comparison of content before and after a given event. 8388 * 8389 * Identify the node where selection currently begins, then observe 8390 * both its text content and its current position in the DOM. Since the 8391 * browser may natively replace the target node during composition, we can 8392 * use its position to find its replacement. 8393 * 8394 * 8395 */ 8396 var root = null; 8397 var startText = null; 8398 var fallbackText = null; 8399 function initialize(nativeEventTarget) { 8400 root = nativeEventTarget; 8401 startText = getText(); 8402 return true; 8403 } 8404 function reset() { 8405 root = null; 8406 startText = null; 8407 fallbackText = null; 8408 } 8409 function getData() { 8410 if (fallbackText) { 8411 return fallbackText; 8412 } 8413 8414 var start; 8415 var startValue = startText; 8416 var startLength = startValue.length; 8417 var end; 8418 var endValue = getText(); 8419 var endLength = endValue.length; 8420 8421 for (start = 0; start < startLength; start++) { 8422 if (startValue[start] !== endValue[start]) { 8423 break; 8424 } 8425 } 8426 8427 var minEnd = startLength - start; 8428 8429 for (end = 1; end <= minEnd; end++) { 8430 if (startValue[startLength - end] !== endValue[endLength - end]) { 8431 break; 8432 } 8433 } 8434 8435 var sliceTail = end > 1 ? 1 - end : undefined; 8436 fallbackText = endValue.slice(start, sliceTail); 8437 return fallbackText; 8438 } 8439 function getText() { 8440 if ('value' in root) { 8441 return root.value; 8442 } 8443 8444 return root.textContent; 8445 } 8446 8447 var EVENT_POOL_SIZE = 10; 8448 /** 8449 * @interface Event 8450 * @see http://www.w3.org/TR/DOM-Level-3-Events/ 8451 */ 8452 8453 var EventInterface = { 8454 type: null, 8455 target: null, 8456 // currentTarget is set when dispatching; no use in copying it here 8457 currentTarget: function () { 8458 return null; 8459 }, 8460 eventPhase: null, 8461 bubbles: null, 8462 cancelable: null, 8463 timeStamp: function (event) { 8464 return event.timeStamp || Date.now(); 8465 }, 8466 defaultPrevented: null, 8467 isTrusted: null 8468 }; 8469 8470 function functionThatReturnsTrue() { 8471 return true; 8472 } 8473 8474 function functionThatReturnsFalse() { 8475 return false; 8476 } 8477 /** 8478 * Synthetic events are dispatched by event plugins, typically in response to a 8479 * top-level event delegation handler. 8480 * 8481 * These systems should generally use pooling to reduce the frequency of garbage 8482 * collection. The system should check `isPersistent` to determine whether the 8483 * event should be released into the pool after being dispatched. Users that 8484 * need a persisted event should invoke `persist`. 8485 * 8486 * Synthetic events (and subclasses) implement the DOM Level 3 Events API by 8487 * normalizing browser quirks. Subclasses do not necessarily have to implement a 8488 * DOM interface; custom application-specific events can also subclass this. 8489 * 8490 * @param {object} dispatchConfig Configuration used to dispatch this event. 8491 * @param {*} targetInst Marker identifying the event target. 8492 * @param {object} nativeEvent Native browser event. 8493 * @param {DOMEventTarget} nativeEventTarget Target node. 8494 */ 8495 8496 8497 function SyntheticEvent(dispatchConfig, targetInst, nativeEvent, nativeEventTarget) { 8498 { 8499 // these have a getter/setter for warnings 8500 delete this.nativeEvent; 8501 delete this.preventDefault; 8502 delete this.stopPropagation; 8503 delete this.isDefaultPrevented; 8504 delete this.isPropagationStopped; 8505 } 8506 8507 this.dispatchConfig = dispatchConfig; 8508 this._targetInst = targetInst; 8509 this.nativeEvent = nativeEvent; 8510 var Interface = this.constructor.Interface; 8511 8512 for (var propName in Interface) { 8513 if (!Interface.hasOwnProperty(propName)) { 8514 continue; 8515 } 8516 8517 { 8518 delete this[propName]; // this has a getter/setter for warnings 8519 } 8520 8521 var normalize = Interface[propName]; 8522 8523 if (normalize) { 8524 this[propName] = normalize(nativeEvent); 8525 } else { 8526 if (propName === 'target') { 8527 this.target = nativeEventTarget; 8528 } else { 8529 this[propName] = nativeEvent[propName]; 8530 } 8531 } 8532 } 8533 8534 var defaultPrevented = nativeEvent.defaultPrevented != null ? nativeEvent.defaultPrevented : nativeEvent.returnValue === false; 8535 8536 if (defaultPrevented) { 8537 this.isDefaultPrevented = functionThatReturnsTrue; 8538 } else { 8539 this.isDefaultPrevented = functionThatReturnsFalse; 8540 } 8541 8542 this.isPropagationStopped = functionThatReturnsFalse; 8543 return this; 8544 } 8545 8546 _assign(SyntheticEvent.prototype, { 8547 preventDefault: function () { 8548 this.defaultPrevented = true; 8549 var event = this.nativeEvent; 8550 8551 if (!event) { 8552 return; 8553 } 8554 8555 if (event.preventDefault) { 8556 event.preventDefault(); 8557 } else if (typeof event.returnValue !== 'unknown') { 8558 event.returnValue = false; 8559 } 8560 8561 this.isDefaultPrevented = functionThatReturnsTrue; 8562 }, 8563 stopPropagation: function () { 8564 var event = this.nativeEvent; 8565 8566 if (!event) { 8567 return; 8568 } 8569 8570 if (event.stopPropagation) { 8571 event.stopPropagation(); 8572 } else if (typeof event.cancelBubble !== 'unknown') { 8573 // The ChangeEventPlugin registers a "propertychange" event for 8574 // IE. This event does not support bubbling or cancelling, and 8575 // any references to cancelBubble throw "Member not found". A 8576 // typeof check of "unknown" circumvents this issue (and is also 8577 // IE specific). 8578 event.cancelBubble = true; 8579 } 8580 8581 this.isPropagationStopped = functionThatReturnsTrue; 8582 }, 8583 8584 /** 8585 * We release all dispatched `SyntheticEvent`s after each event loop, adding 8586 * them back into the pool. This allows a way to hold onto a reference that 8587 * won't be added back into the pool. 8588 */ 8589 persist: function () { 8590 this.isPersistent = functionThatReturnsTrue; 8591 }, 8592 8593 /** 8594 * Checks if this event should be released back into the pool. 8595 * 8596 * @return {boolean} True if this should not be released, false otherwise. 8597 */ 8598 isPersistent: functionThatReturnsFalse, 8599 8600 /** 8601 * `PooledClass` looks for `destructor` on each instance it releases. 8602 */ 8603 destructor: function () { 8604 var Interface = this.constructor.Interface; 8605 8606 for (var propName in Interface) { 8607 { 8608 Object.defineProperty(this, propName, getPooledWarningPropertyDefinition(propName, Interface[propName])); 8609 } 8610 } 8611 8612 this.dispatchConfig = null; 8613 this._targetInst = null; 8614 this.nativeEvent = null; 8615 this.isDefaultPrevented = functionThatReturnsFalse; 8616 this.isPropagationStopped = functionThatReturnsFalse; 8617 this._dispatchListeners = null; 8618 this._dispatchInstances = null; 8619 8620 { 8621 Object.defineProperty(this, 'nativeEvent', getPooledWarningPropertyDefinition('nativeEvent', null)); 8622 Object.defineProperty(this, 'isDefaultPrevented', getPooledWarningPropertyDefinition('isDefaultPrevented', functionThatReturnsFalse)); 8623 Object.defineProperty(this, 'isPropagationStopped', getPooledWarningPropertyDefinition('isPropagationStopped', functionThatReturnsFalse)); 8624 Object.defineProperty(this, 'preventDefault', getPooledWarningPropertyDefinition('preventDefault', function () {})); 8625 Object.defineProperty(this, 'stopPropagation', getPooledWarningPropertyDefinition('stopPropagation', function () {})); 8626 } 8627 } 8628 }); 8629 8630 SyntheticEvent.Interface = EventInterface; 8631 /** 8632 * Helper to reduce boilerplate when creating subclasses. 8633 */ 8634 8635 SyntheticEvent.extend = function (Interface) { 8636 var Super = this; 8637 8638 var E = function () {}; 8639 8640 E.prototype = Super.prototype; 8641 var prototype = new E(); 8642 8643 function Class() { 8644 return Super.apply(this, arguments); 8645 } 8646 8647 _assign(prototype, Class.prototype); 8648 8649 Class.prototype = prototype; 8650 Class.prototype.constructor = Class; 8651 Class.Interface = _assign({}, Super.Interface, Interface); 8652 Class.extend = Super.extend; 8653 addEventPoolingTo(Class); 8654 return Class; 8655 }; 8656 8657 addEventPoolingTo(SyntheticEvent); 8658 /** 8659 * Helper to nullify syntheticEvent instance properties when destructing 8660 * 8661 * @param {String} propName 8662 * @param {?object} getVal 8663 * @return {object} defineProperty object 8664 */ 8665 8666 function getPooledWarningPropertyDefinition(propName, getVal) { 8667 var isFunction = typeof getVal === 'function'; 8668 return { 8669 configurable: true, 8670 set: set, 8671 get: get 8672 }; 8673 8674 function set(val) { 8675 var action = isFunction ? 'setting the method' : 'setting the property'; 8676 warn(action, 'This is effectively a no-op'); 8677 return val; 8678 } 8679 8680 function get() { 8681 var action = isFunction ? 'accessing the method' : 'accessing the property'; 8682 var result = isFunction ? 'This is a no-op function' : 'This is set to null'; 8683 warn(action, result); 8684 return getVal; 8685 } 8686 8687 function warn(action, result) { 8688 { 8689 error("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); 8690 } 8691 } 8692 } 8693 8694 function getPooledEvent(dispatchConfig, targetInst, nativeEvent, nativeInst) { 8695 var EventConstructor = this; 8696 8697 if (EventConstructor.eventPool.length) { 8698 var instance = EventConstructor.eventPool.pop(); 8699 EventConstructor.call(instance, dispatchConfig, targetInst, nativeEvent, nativeInst); 8700 return instance; 8701 } 8702 8703 return new EventConstructor(dispatchConfig, targetInst, nativeEvent, nativeInst); 8704 } 8705 8706 function releasePooledEvent(event) { 8707 var EventConstructor = this; 8708 8709 if (!(event instanceof EventConstructor)) { 8710 { 8711 throw Error( "Trying to release an event instance into a pool of a different type." ); 8712 } 8713 } 8714 8715 event.destructor(); 8716 8717 if (EventConstructor.eventPool.length < EVENT_POOL_SIZE) { 8718 EventConstructor.eventPool.push(event); 8719 } 8720 } 8721 8722 function addEventPoolingTo(EventConstructor) { 8723 EventConstructor.eventPool = []; 8724 EventConstructor.getPooled = getPooledEvent; 8725 EventConstructor.release = releasePooledEvent; 8726 } 8727 8728 /** 8729 * @interface Event 8730 * @see http://www.w3.org/TR/DOM-Level-3-Events/#events-compositionevents 8731 */ 8732 8733 var SyntheticCompositionEvent = SyntheticEvent.extend({ 8734 data: null 8735 }); 8736 8737 /** 8738 * @interface Event 8739 * @see http://www.w3.org/TR/2013/WD-DOM-Level-3-Events-20131105 8740 * /#events-inputevents 8741 */ 8742 8743 var SyntheticInputEvent = SyntheticEvent.extend({ 8744 data: null 8745 }); 8746 8747 var END_KEYCODES = [9, 13, 27, 32]; // Tab, Return, Esc, Space 8748 8749 var START_KEYCODE = 229; 8750 var canUseCompositionEvent = canUseDOM && 'CompositionEvent' in window; 8751 var documentMode = null; 8752 8753 if (canUseDOM && 'documentMode' in document) { 8754 documentMode = document.documentMode; 8755 } // Webkit offers a very useful `textInput` event that can be used to 8756 // directly represent `beforeInput`. The IE `textinput` event is not as 8757 // useful, so we don't use it. 8758 8759 8760 var canUseTextInputEvent = canUseDOM && 'TextEvent' in window && !documentMode; // In IE9+, we have access to composition events, but the data supplied 8761 // by the native compositionend event may be incorrect. Japanese ideographic 8762 // spaces, for instance (\u3000) are not recorded correctly. 8763 8764 var useFallbackCompositionData = canUseDOM && (!canUseCompositionEvent || documentMode && documentMode > 8 && documentMode <= 11); 8765 var SPACEBAR_CODE = 32; 8766 var SPACEBAR_CHAR = String.fromCharCode(SPACEBAR_CODE); // Events and their corresponding property names. 8767 8768 var eventTypes = { 8769 beforeInput: { 8770 phasedRegistrationNames: { 8771 bubbled: 'onBeforeInput', 8772 captured: 'onBeforeInputCapture' 8773 }, 8774 dependencies: [TOP_COMPOSITION_END, TOP_KEY_PRESS, TOP_TEXT_INPUT, TOP_PASTE] 8775 }, 8776 compositionEnd: { 8777 phasedRegistrationNames: { 8778 bubbled: 'onCompositionEnd', 8779 captured: 'onCompositionEndCapture' 8780 }, 8781 dependencies: [TOP_BLUR, TOP_COMPOSITION_END, TOP_KEY_DOWN, TOP_KEY_PRESS, TOP_KEY_UP, TOP_MOUSE_DOWN] 8782 }, 8783 compositionStart: { 8784 phasedRegistrationNames: { 8785 bubbled: 'onCompositionStart', 8786 captured: 'onCompositionStartCapture' 8787 }, 8788 dependencies: [TOP_BLUR, TOP_COMPOSITION_START, TOP_KEY_DOWN, TOP_KEY_PRESS, TOP_KEY_UP, TOP_MOUSE_DOWN] 8789 }, 8790 compositionUpdate: { 8791 phasedRegistrationNames: { 8792 bubbled: 'onCompositionUpdate', 8793 captured: 'onCompositionUpdateCapture' 8794 }, 8795 dependencies: [TOP_BLUR, TOP_COMPOSITION_UPDATE, TOP_KEY_DOWN, TOP_KEY_PRESS, TOP_KEY_UP, TOP_MOUSE_DOWN] 8796 } 8797 }; // Track whether we've ever handled a keypress on the space key. 8798 8799 var hasSpaceKeypress = false; 8800 /** 8801 * Return whether a native keypress event is assumed to be a command. 8802 * This is required because Firefox fires `keypress` events for key commands 8803 * (cut, copy, select-all, etc.) even though no character is inserted. 8804 */ 8805 8806 function isKeypressCommand(nativeEvent) { 8807 return (nativeEvent.ctrlKey || nativeEvent.altKey || nativeEvent.metaKey) && // ctrlKey && altKey is equivalent to AltGr, and is not a command. 8808 !(nativeEvent.ctrlKey && nativeEvent.altKey); 8809 } 8810 /** 8811 * Translate native top level events into event types. 8812 * 8813 * @param {string} topLevelType 8814 * @return {object} 8815 */ 8816 8817 8818 function getCompositionEventType(topLevelType) { 8819 switch (topLevelType) { 8820 case TOP_COMPOSITION_START: 8821 return eventTypes.compositionStart; 8822 8823 case TOP_COMPOSITION_END: 8824 return eventTypes.compositionEnd; 8825 8826 case TOP_COMPOSITION_UPDATE: 8827 return eventTypes.compositionUpdate; 8828 } 8829 } 8830 /** 8831 * Does our fallback best-guess model think this event signifies that 8832 * composition has begun? 8833 * 8834 * @param {string} topLevelType 8835 * @param {object} nativeEvent 8836 * @return {boolean} 8837 */ 8838 8839 8840 function isFallbackCompositionStart(topLevelType, nativeEvent) { 8841 return topLevelType === TOP_KEY_DOWN && nativeEvent.keyCode === START_KEYCODE; 8842 } 8843 /** 8844 * Does our fallback mode think that this event is the end of composition? 8845 * 8846 * @param {string} topLevelType 8847 * @param {object} nativeEvent 8848 * @return {boolean} 8849 */ 8850 8851 8852 function isFallbackCompositionEnd(topLevelType, nativeEvent) { 8853 switch (topLevelType) { 8854 case TOP_KEY_UP: 8855 // Command keys insert or clear IME input. 8856 return END_KEYCODES.indexOf(nativeEvent.keyCode) !== -1; 8857 8858 case TOP_KEY_DOWN: 8859 // Expect IME keyCode on each keydown. If we get any other 8860 // code we must have exited earlier. 8861 return nativeEvent.keyCode !== START_KEYCODE; 8862 8863 case TOP_KEY_PRESS: 8864 case TOP_MOUSE_DOWN: 8865 case TOP_BLUR: 8866 // Events are not possible without cancelling IME. 8867 return true; 8868 8869 default: 8870 return false; 8871 } 8872 } 8873 /** 8874 * Google Input Tools provides composition data via a CustomEvent, 8875 * with the `data` property populated in the `detail` object. If this 8876 * is available on the event object, use it. If not, this is a plain 8877 * composition event and we have nothing special to extract. 8878 * 8879 * @param {object} nativeEvent 8880 * @return {?string} 8881 */ 8882 8883 8884 function getDataFromCustomEvent(nativeEvent) { 8885 var detail = nativeEvent.detail; 8886 8887 if (typeof detail === 'object' && 'data' in detail) { 8888 return detail.data; 8889 } 8890 8891 return null; 8892 } 8893 /** 8894 * Check if a composition event was triggered by Korean IME. 8895 * Our fallback mode does not work well with IE's Korean IME, 8896 * so just use native composition events when Korean IME is used. 8897 * Although CompositionEvent.locale property is deprecated, 8898 * it is available in IE, where our fallback mode is enabled. 8899 * 8900 * @param {object} nativeEvent 8901 * @return {boolean} 8902 */ 8903 8904 8905 function isUsingKoreanIME(nativeEvent) { 8906 return nativeEvent.locale === 'ko'; 8907 } // Track the current IME composition status, if any. 8908 8909 8910 var isComposing = false; 8911 /** 8912 * @return {?object} A SyntheticCompositionEvent. 8913 */ 8914 8915 function extractCompositionEvent(topLevelType, targetInst, nativeEvent, nativeEventTarget) { 8916 var eventType; 8917 var fallbackData; 8918 8919 if (canUseCompositionEvent) { 8920 eventType = getCompositionEventType(topLevelType); 8921 } else if (!isComposing) { 8922 if (isFallbackCompositionStart(topLevelType, nativeEvent)) { 8923 eventType = eventTypes.compositionStart; 8924 } 8925 } else if (isFallbackCompositionEnd(topLevelType, nativeEvent)) { 8926 eventType = eventTypes.compositionEnd; 8927 } 8928 8929 if (!eventType) { 8930 return null; 8931 } 8932 8933 if (useFallbackCompositionData && !isUsingKoreanIME(nativeEvent)) { 8934 // The current composition is stored statically and must not be 8935 // overwritten while composition continues. 8936 if (!isComposing && eventType === eventTypes.compositionStart) { 8937 isComposing = initialize(nativeEventTarget); 8938 } else if (eventType === eventTypes.compositionEnd) { 8939 if (isComposing) { 8940 fallbackData = getData(); 8941 } 8942 } 8943 } 8944 8945 var event = SyntheticCompositionEvent.getPooled(eventType, targetInst, nativeEvent, nativeEventTarget); 8946 8947 if (fallbackData) { 8948 // Inject data generated from fallback path into the synthetic event. 8949 // This matches the property of native CompositionEventInterface. 8950 event.data = fallbackData; 8951 } else { 8952 var customData = getDataFromCustomEvent(nativeEvent); 8953 8954 if (customData !== null) { 8955 event.data = customData; 8956 } 8957 } 8958 8959 accumulateTwoPhaseDispatches(event); 8960 return event; 8961 } 8962 /** 8963 * @param {TopLevelType} topLevelType Number from `TopLevelType`. 8964 * @param {object} nativeEvent Native browser event. 8965 * @return {?string} The string corresponding to this `beforeInput` event. 8966 */ 8967 8968 8969 function getNativeBeforeInputChars(topLevelType, nativeEvent) { 8970 switch (topLevelType) { 8971 case TOP_COMPOSITION_END: 8972 return getDataFromCustomEvent(nativeEvent); 8973 8974 case TOP_KEY_PRESS: 8975 /** 8976 * If native `textInput` events are available, our goal is to make 8977 * use of them. However, there is a special case: the spacebar key. 8978 * In Webkit, preventing default on a spacebar `textInput` event 8979 * cancels character insertion, but it *also* causes the browser 8980 * to fall back to its default spacebar behavior of scrolling the 8981 * page. 8982 * 8983 * Tracking at: 8984 * https://code.google.com/p/chromium/issues/detail?id=355103 8985 * 8986 * To avoid this issue, use the keypress event as if no `textInput` 8987 * event is available. 8988 */ 8989 var which = nativeEvent.which; 8990 8991 if (which !== SPACEBAR_CODE) { 8992 return null; 8993 } 8994 8995 hasSpaceKeypress = true; 8996 return SPACEBAR_CHAR; 8997 8998 case TOP_TEXT_INPUT: 8999 // Record the characters to be added to the DOM. 9000 var chars = nativeEvent.data; // If it's a spacebar character, assume that we have already handled 9001 // it at the keypress level and bail immediately. Android Chrome 9002 // doesn't give us keycodes, so we need to ignore it. 9003 9004 if (chars === SPACEBAR_CHAR && hasSpaceKeypress) { 9005 return null; 9006 } 9007 9008 return chars; 9009 9010 default: 9011 // For other native event types, do nothing. 9012 return null; 9013 } 9014 } 9015 /** 9016 * For browsers that do not provide the `textInput` event, extract the 9017 * appropriate string to use for SyntheticInputEvent. 9018 * 9019 * @param {number} topLevelType Number from `TopLevelEventTypes`. 9020 * @param {object} nativeEvent Native browser event. 9021 * @return {?string} The fallback string for this `beforeInput` event. 9022 */ 9023 9024 9025 function getFallbackBeforeInputChars(topLevelType, nativeEvent) { 9026 // If we are currently composing (IME) and using a fallback to do so, 9027 // try to extract the composed characters from the fallback object. 9028 // If composition event is available, we extract a string only at 9029 // compositionevent, otherwise extract it at fallback events. 9030 if (isComposing) { 9031 if (topLevelType === TOP_COMPOSITION_END || !canUseCompositionEvent && isFallbackCompositionEnd(topLevelType, nativeEvent)) { 9032 var chars = getData(); 9033 reset(); 9034 isComposing = false; 9035 return chars; 9036 } 9037 9038 return null; 9039 } 9040 9041 switch (topLevelType) { 9042 case TOP_PASTE: 9043 // If a paste event occurs after a keypress, throw out the input 9044 // chars. Paste events should not lead to BeforeInput events. 9045 return null; 9046 9047 case TOP_KEY_PRESS: 9048 /** 9049 * As of v27, Firefox may fire keypress events even when no character 9050 * will be inserted. A few possibilities: 9051 * 9052 * - `which` is `0`. Arrow keys, Esc key, etc. 9053 * 9054 * - `which` is the pressed key code, but no char is available. 9055 * Ex: 'AltGr + d` in Polish. There is no modified character for 9056 * this key combination and no character is inserted into the 9057 * document, but FF fires the keypress for char code `100` anyway. 9058 * No `input` event will occur. 9059 * 9060 * - `which` is the pressed key code, but a command combination is 9061 * being used. Ex: `Cmd+C`. No character is inserted, and no 9062 * `input` event will occur. 9063 */ 9064 if (!isKeypressCommand(nativeEvent)) { 9065 // IE fires the `keypress` event when a user types an emoji via 9066 // Touch keyboard of Windows. In such a case, the `char` property 9067 // holds an emoji character like `\uD83D\uDE0A`. Because its length 9068 // is 2, the property `which` does not represent an emoji correctly. 9069 // In such a case, we directly return the `char` property instead of 9070 // using `which`. 9071 if (nativeEvent.char && nativeEvent.char.length > 1) { 9072 return nativeEvent.char; 9073 } else if (nativeEvent.which) { 9074 return String.fromCharCode(nativeEvent.which); 9075 } 9076 } 9077 9078 return null; 9079 9080 case TOP_COMPOSITION_END: 9081 return useFallbackCompositionData && !isUsingKoreanIME(nativeEvent) ? null : nativeEvent.data; 9082 9083 default: 9084 return null; 9085 } 9086 } 9087 /** 9088 * Extract a SyntheticInputEvent for `beforeInput`, based on either native 9089 * `textInput` or fallback behavior. 9090 * 9091 * @return {?object} A SyntheticInputEvent. 9092 */ 9093 9094 9095 function extractBeforeInputEvent(topLevelType, targetInst, nativeEvent, nativeEventTarget) { 9096 var chars; 9097 9098 if (canUseTextInputEvent) { 9099 chars = getNativeBeforeInputChars(topLevelType, nativeEvent); 9100 } else { 9101 chars = getFallbackBeforeInputChars(topLevelType, nativeEvent); 9102 } // If no characters are being inserted, no BeforeInput event should 9103 // be fired. 9104 9105 9106 if (!chars) { 9107 return null; 9108 } 9109 9110 var event = SyntheticInputEvent.getPooled(eventTypes.beforeInput, targetInst, nativeEvent, nativeEventTarget); 9111 event.data = chars; 9112 accumulateTwoPhaseDispatches(event); 9113 return event; 9114 } 9115 /** 9116 * Create an `onBeforeInput` event to match 9117 * http://www.w3.org/TR/2013/WD-DOM-Level-3-Events-20131105/#events-inputevents. 9118 * 9119 * This event plugin is based on the native `textInput` event 9120 * available in Chrome, Safari, Opera, and IE. This event fires after 9121 * `onKeyPress` and `onCompositionEnd`, but before `onInput`. 9122 * 9123 * `beforeInput` is spec'd but not implemented in any browsers, and 9124 * the `input` event does not provide any useful information about what has 9125 * actually been added, contrary to the spec. Thus, `textInput` is the best 9126 * available event to identify the characters that have actually been inserted 9127 * into the target node. 9128 * 9129 * This plugin is also responsible for emitting `composition` events, thus 9130 * allowing us to share composition fallback code for both `beforeInput` and 9131 * `composition` event types. 9132 */ 9133 9134 9135 var BeforeInputEventPlugin = { 9136 eventTypes: eventTypes, 9137 extractEvents: function (topLevelType, targetInst, nativeEvent, nativeEventTarget, eventSystemFlags) { 9138 var composition = extractCompositionEvent(topLevelType, targetInst, nativeEvent, nativeEventTarget); 9139 var beforeInput = extractBeforeInputEvent(topLevelType, targetInst, nativeEvent, nativeEventTarget); 9140 9141 if (composition === null) { 9142 return beforeInput; 9143 } 9144 9145 if (beforeInput === null) { 9146 return composition; 9147 } 9148 9149 return [composition, beforeInput]; 9150 } 9151 }; 9152 9153 /** 9154 * @see http://www.whatwg.org/specs/web-apps/current-work/multipage/the-input-element.html#input-type-attr-summary 9155 */ 9156 var supportedInputTypes = { 9157 color: true, 9158 date: true, 9159 datetime: true, 9160 'datetime-local': true, 9161 email: true, 9162 month: true, 9163 number: true, 9164 password: true, 9165 range: true, 9166 search: true, 9167 tel: true, 9168 text: true, 9169 time: true, 9170 url: true, 9171 week: true 9172 }; 9173 9174 function isTextInputElement(elem) { 9175 var nodeName = elem && elem.nodeName && elem.nodeName.toLowerCase(); 9176 9177 if (nodeName === 'input') { 9178 return !!supportedInputTypes[elem.type]; 9179 } 9180 9181 if (nodeName === 'textarea') { 9182 return true; 9183 } 9184 9185 return false; 9186 } 9187 9188 var eventTypes$1 = { 9189 change: { 9190 phasedRegistrationNames: { 9191 bubbled: 'onChange', 9192 captured: 'onChangeCapture' 9193 }, 9194 dependencies: [TOP_BLUR, TOP_CHANGE, TOP_CLICK, TOP_FOCUS, TOP_INPUT, TOP_KEY_DOWN, TOP_KEY_UP, TOP_SELECTION_CHANGE] 9195 } 9196 }; 9197 9198 function createAndAccumulateChangeEvent(inst, nativeEvent, target) { 9199 var event = SyntheticEvent.getPooled(eventTypes$1.change, inst, nativeEvent, target); 9200 event.type = 'change'; // Flag this event loop as needing state restore. 9201 9202 enqueueStateRestore(target); 9203 accumulateTwoPhaseDispatches(event); 9204 return event; 9205 } 9206 /** 9207 * For IE shims 9208 */ 9209 9210 9211 var activeElement = null; 9212 var activeElementInst = null; 9213 /** 9214 * SECTION: handle `change` event 9215 */ 9216 9217 function shouldUseChangeEvent(elem) { 9218 var nodeName = elem.nodeName && elem.nodeName.toLowerCase(); 9219 return nodeName === 'select' || nodeName === 'input' && elem.type === 'file'; 9220 } 9221 9222 function manualDispatchChangeEvent(nativeEvent) { 9223 var event = createAndAccumulateChangeEvent(activeElementInst, nativeEvent, getEventTarget(nativeEvent)); // If change and propertychange bubbled, we'd just bind to it like all the 9224 // other events and have it go through ReactBrowserEventEmitter. Since it 9225 // doesn't, we manually listen for the events and so we have to enqueue and 9226 // process the abstract event manually. 9227 // 9228 // Batching is necessary here in order to ensure that all event handlers run 9229 // before the next rerender (including event handlers attached to ancestor 9230 // elements instead of directly on the input). Without this, controlled 9231 // components don't work properly in conjunction with event bubbling because 9232 // the component is rerendered and the value reverted before all the event 9233 // handlers can run. See https://github.com/facebook/react/issues/708. 9234 9235 batchedUpdates(runEventInBatch, event); 9236 } 9237 9238 function runEventInBatch(event) { 9239 runEventsInBatch(event); 9240 } 9241 9242 function getInstIfValueChanged(targetInst) { 9243 var targetNode = getNodeFromInstance$1(targetInst); 9244 9245 if (updateValueIfChanged(targetNode)) { 9246 return targetInst; 9247 } 9248 } 9249 9250 function getTargetInstForChangeEvent(topLevelType, targetInst) { 9251 if (topLevelType === TOP_CHANGE) { 9252 return targetInst; 9253 } 9254 } 9255 /** 9256 * SECTION: handle `input` event 9257 */ 9258 9259 9260 var isInputEventSupported = false; 9261 9262 if (canUseDOM) { 9263 // IE9 claims to support the input event but fails to trigger it when 9264 // deleting text, so we ignore its input events. 9265 isInputEventSupported = isEventSupported('input') && (!document.documentMode || document.documentMode > 9); 9266 } 9267 /** 9268 * (For IE <=9) Starts tracking propertychange events on the passed-in element 9269 * and override the value property so that we can distinguish user events from 9270 * value changes in JS. 9271 */ 9272 9273 9274 function startWatchingForValueChange(target, targetInst) { 9275 activeElement = target; 9276 activeElementInst = targetInst; 9277 activeElement.attachEvent('onpropertychange', handlePropertyChange); 9278 } 9279 /** 9280 * (For IE <=9) Removes the event listeners from the currently-tracked element, 9281 * if any exists. 9282 */ 9283 9284 9285 function stopWatchingForValueChange() { 9286 if (!activeElement) { 9287 return; 9288 } 9289 9290 activeElement.detachEvent('onpropertychange', handlePropertyChange); 9291 activeElement = null; 9292 activeElementInst = null; 9293 } 9294 /** 9295 * (For IE <=9) Handles a propertychange event, sending a `change` event if 9296 * the value of the active element has changed. 9297 */ 9298 9299 9300 function handlePropertyChange(nativeEvent) { 9301 if (nativeEvent.propertyName !== 'value') { 9302 return; 9303 } 9304 9305 if (getInstIfValueChanged(activeElementInst)) { 9306 manualDispatchChangeEvent(nativeEvent); 9307 } 9308 } 9309 9310 function handleEventsForInputEventPolyfill(topLevelType, target, targetInst) { 9311 if (topLevelType === TOP_FOCUS) { 9312 // In IE9, propertychange fires for most input events but is buggy and 9313 // doesn't fire when text is deleted, but conveniently, selectionchange 9314 // appears to fire in all of the remaining cases so we catch those and 9315 // forward the event if the value has changed 9316 // In either case, we don't want to call the event handler if the value 9317 // is changed from JS so we redefine a setter for `.value` that updates 9318 // our activeElementValue variable, allowing us to ignore those changes 9319 // 9320 // stopWatching() should be a noop here but we call it just in case we 9321 // missed a blur event somehow. 9322 stopWatchingForValueChange(); 9323 startWatchingForValueChange(target, targetInst); 9324 } else if (topLevelType === TOP_BLUR) { 9325 stopWatchingForValueChange(); 9326 } 9327 } // For IE8 and IE9. 9328 9329 9330 function getTargetInstForInputEventPolyfill(topLevelType, targetInst) { 9331 if (topLevelType === TOP_SELECTION_CHANGE || topLevelType === TOP_KEY_UP || topLevelType === TOP_KEY_DOWN) { 9332 // On the selectionchange event, the target is just document which isn't 9333 // helpful for us so just check activeElement instead. 9334 // 9335 // 99% of the time, keydown and keyup aren't necessary. IE8 fails to fire 9336 // propertychange on the first input event after setting `value` from a 9337 // script and fires only keydown, keypress, keyup. Catching keyup usually 9338 // gets it and catching keydown lets us fire an event for the first 9339 // keystroke if user does a key repeat (it'll be a little delayed: right 9340 // before the second keystroke). Other input methods (e.g., paste) seem to 9341 // fire selectionchange normally. 9342 return getInstIfValueChanged(activeElementInst); 9343 } 9344 } 9345 /** 9346 * SECTION: handle `click` event 9347 */ 9348 9349 9350 function shouldUseClickEvent(elem) { 9351 // Use the `click` event to detect changes to checkbox and radio inputs. 9352 // This approach works across all browsers, whereas `change` does not fire 9353 // until `blur` in IE8. 9354 var nodeName = elem.nodeName; 9355 return nodeName && nodeName.toLowerCase() === 'input' && (elem.type === 'checkbox' || elem.type === 'radio'); 9356 } 9357 9358 function getTargetInstForClickEvent(topLevelType, targetInst) { 9359 if (topLevelType === TOP_CLICK) { 9360 return getInstIfValueChanged(targetInst); 9361 } 9362 } 9363 9364 function getTargetInstForInputOrChangeEvent(topLevelType, targetInst) { 9365 if (topLevelType === TOP_INPUT || topLevelType === TOP_CHANGE) { 9366 return getInstIfValueChanged(targetInst); 9367 } 9368 } 9369 9370 function handleControlledInputBlur(node) { 9371 var state = node._wrapperState; 9372 9373 if (!state || !state.controlled || node.type !== 'number') { 9374 return; 9375 } 9376 9377 { 9378 // If controlled, assign the value attribute to the current value on blur 9379 setDefaultValue(node, 'number', node.value); 9380 } 9381 } 9382 /** 9383 * This plugin creates an `onChange` event that normalizes change events 9384 * across form elements. This event fires at a time when it's possible to 9385 * change the element's value without seeing a flicker. 9386 * 9387 * Supported elements are: 9388 * - input (see `isTextInputElement`) 9389 * - textarea 9390 * - select 9391 */ 9392 9393 9394 var ChangeEventPlugin = { 9395 eventTypes: eventTypes$1, 9396 _isInputEventSupported: isInputEventSupported, 9397 extractEvents: function (topLevelType, targetInst, nativeEvent, nativeEventTarget, eventSystemFlags) { 9398 var targetNode = targetInst ? getNodeFromInstance$1(targetInst) : window; 9399 var getTargetInstFunc, handleEventFunc; 9400 9401 if (shouldUseChangeEvent(targetNode)) { 9402 getTargetInstFunc = getTargetInstForChangeEvent; 9403 } else if (isTextInputElement(targetNode)) { 9404 if (isInputEventSupported) { 9405 getTargetInstFunc = getTargetInstForInputOrChangeEvent; 9406 } else { 9407 getTargetInstFunc = getTargetInstForInputEventPolyfill; 9408 handleEventFunc = handleEventsForInputEventPolyfill; 9409 } 9410 } else if (shouldUseClickEvent(targetNode)) { 9411 getTargetInstFunc = getTargetInstForClickEvent; 9412 } 9413 9414 if (getTargetInstFunc) { 9415 var inst = getTargetInstFunc(topLevelType, targetInst); 9416 9417 if (inst) { 9418 var event = createAndAccumulateChangeEvent(inst, nativeEvent, nativeEventTarget); 9419 return event; 9420 } 9421 } 9422 9423 if (handleEventFunc) { 9424 handleEventFunc(topLevelType, targetNode, targetInst); 9425 } // When blurring, set the value attribute for number inputs 9426 9427 9428 if (topLevelType === TOP_BLUR) { 9429 handleControlledInputBlur(targetNode); 9430 } 9431 } 9432 }; 9433 9434 var SyntheticUIEvent = SyntheticEvent.extend({ 9435 view: null, 9436 detail: null 9437 }); 9438 9439 /** 9440 * Translation from modifier key to the associated property in the event. 9441 * @see http://www.w3.org/TR/DOM-Level-3-Events/#keys-Modifiers 9442 */ 9443 var modifierKeyToProp = { 9444 Alt: 'altKey', 9445 Control: 'ctrlKey', 9446 Meta: 'metaKey', 9447 Shift: 'shiftKey' 9448 }; // Older browsers (Safari <= 10, iOS Safari <= 10.2) do not support 9449 // getModifierState. If getModifierState is not supported, we map it to a set of 9450 // modifier keys exposed by the event. In this case, Lock-keys are not supported. 9451 9452 function modifierStateGetter(keyArg) { 9453 var syntheticEvent = this; 9454 var nativeEvent = syntheticEvent.nativeEvent; 9455 9456 if (nativeEvent.getModifierState) { 9457 return nativeEvent.getModifierState(keyArg); 9458 } 9459 9460 var keyProp = modifierKeyToProp[keyArg]; 9461 return keyProp ? !!nativeEvent[keyProp] : false; 9462 } 9463 9464 function getEventModifierState(nativeEvent) { 9465 return modifierStateGetter; 9466 } 9467 9468 var previousScreenX = 0; 9469 var previousScreenY = 0; // Use flags to signal movementX/Y has already been set 9470 9471 var isMovementXSet = false; 9472 var isMovementYSet = false; 9473 /** 9474 * @interface MouseEvent 9475 * @see http://www.w3.org/TR/DOM-Level-3-Events/ 9476 */ 9477 9478 var SyntheticMouseEvent = SyntheticUIEvent.extend({ 9479 screenX: null, 9480 screenY: null, 9481 clientX: null, 9482 clientY: null, 9483 pageX: null, 9484 pageY: null, 9485 ctrlKey: null, 9486 shiftKey: null, 9487 altKey: null, 9488 metaKey: null, 9489 getModifierState: getEventModifierState, 9490 button: null, 9491 buttons: null, 9492 relatedTarget: function (event) { 9493 return event.relatedTarget || (event.fromElement === event.srcElement ? event.toElement : event.fromElement); 9494 }, 9495 movementX: function (event) { 9496 if ('movementX' in event) { 9497 return event.movementX; 9498 } 9499 9500 var screenX = previousScreenX; 9501 previousScreenX = event.screenX; 9502 9503 if (!isMovementXSet) { 9504 isMovementXSet = true; 9505 return 0; 9506 } 9507 9508 return event.type === 'mousemove' ? event.screenX - screenX : 0; 9509 }, 9510 movementY: function (event) { 9511 if ('movementY' in event) { 9512 return event.movementY; 9513 } 9514 9515 var screenY = previousScreenY; 9516 previousScreenY = event.screenY; 9517 9518 if (!isMovementYSet) { 9519 isMovementYSet = true; 9520 return 0; 9521 } 9522 9523 return event.type === 'mousemove' ? event.screenY - screenY : 0; 9524 } 9525 }); 9526 9527 /** 9528 * @interface PointerEvent 9529 * @see http://www.w3.org/TR/pointerevents/ 9530 */ 9531 9532 var SyntheticPointerEvent = SyntheticMouseEvent.extend({ 9533 pointerId: null, 9534 width: null, 9535 height: null, 9536 pressure: null, 9537 tangentialPressure: null, 9538 tiltX: null, 9539 tiltY: null, 9540 twist: null, 9541 pointerType: null, 9542 isPrimary: null 9543 }); 9544 9545 var eventTypes$2 = { 9546 mouseEnter: { 9547 registrationName: 'onMouseEnter', 9548 dependencies: [TOP_MOUSE_OUT, TOP_MOUSE_OVER] 9549 }, 9550 mouseLeave: { 9551 registrationName: 'onMouseLeave', 9552 dependencies: [TOP_MOUSE_OUT, TOP_MOUSE_OVER] 9553 }, 9554 pointerEnter: { 9555 registrationName: 'onPointerEnter', 9556 dependencies: [TOP_POINTER_OUT, TOP_POINTER_OVER] 9557 }, 9558 pointerLeave: { 9559 registrationName: 'onPointerLeave', 9560 dependencies: [TOP_POINTER_OUT, TOP_POINTER_OVER] 9561 } 9562 }; 9563 var EnterLeaveEventPlugin = { 9564 eventTypes: eventTypes$2, 9565 9566 /** 9567 * For almost every interaction we care about, there will be both a top-level 9568 * `mouseover` and `mouseout` event that occurs. Only use `mouseout` so that 9569 * we do not extract duplicate events. However, moving the mouse into the 9570 * browser from outside will not fire a `mouseout` event. In this case, we use 9571 * the `mouseover` top-level event. 9572 */ 9573 extractEvents: function (topLevelType, targetInst, nativeEvent, nativeEventTarget, eventSystemFlags) { 9574 var isOverEvent = topLevelType === TOP_MOUSE_OVER || topLevelType === TOP_POINTER_OVER; 9575 var isOutEvent = topLevelType === TOP_MOUSE_OUT || topLevelType === TOP_POINTER_OUT; 9576 9577 if (isOverEvent && (eventSystemFlags & IS_REPLAYED) === 0 && (nativeEvent.relatedTarget || nativeEvent.fromElement)) { 9578 // If this is an over event with a target, then we've already dispatched 9579 // the event in the out event of the other target. If this is replayed, 9580 // then it's because we couldn't dispatch against this target previously 9581 // so we have to do it now instead. 9582 return null; 9583 } 9584 9585 if (!isOutEvent && !isOverEvent) { 9586 // Must not be a mouse or pointer in or out - ignoring. 9587 return null; 9588 } 9589 9590 var win; 9591 9592 if (nativeEventTarget.window === nativeEventTarget) { 9593 // `nativeEventTarget` is probably a window object. 9594 win = nativeEventTarget; 9595 } else { 9596 // TODO: Figure out why `ownerDocument` is sometimes undefined in IE8. 9597 var doc = nativeEventTarget.ownerDocument; 9598 9599 if (doc) { 9600 win = doc.defaultView || doc.parentWindow; 9601 } else { 9602 win = window; 9603 } 9604 } 9605 9606 var from; 9607 var to; 9608 9609 if (isOutEvent) { 9610 from = targetInst; 9611 var related = nativeEvent.relatedTarget || nativeEvent.toElement; 9612 to = related ? getClosestInstanceFromNode(related) : null; 9613 9614 if (to !== null) { 9615 var nearestMounted = getNearestMountedFiber(to); 9616 9617 if (to !== nearestMounted || to.tag !== HostComponent && to.tag !== HostText) { 9618 to = null; 9619 } 9620 } 9621 } else { 9622 // Moving to a node from outside the window. 9623 from = null; 9624 to = targetInst; 9625 } 9626 9627 if (from === to) { 9628 // Nothing pertains to our managed components. 9629 return null; 9630 } 9631 9632 var eventInterface, leaveEventType, enterEventType, eventTypePrefix; 9633 9634 if (topLevelType === TOP_MOUSE_OUT || topLevelType === TOP_MOUSE_OVER) { 9635 eventInterface = SyntheticMouseEvent; 9636 leaveEventType = eventTypes$2.mouseLeave; 9637 enterEventType = eventTypes$2.mouseEnter; 9638 eventTypePrefix = 'mouse'; 9639 } else if (topLevelType === TOP_POINTER_OUT || topLevelType === TOP_POINTER_OVER) { 9640 eventInterface = SyntheticPointerEvent; 9641 leaveEventType = eventTypes$2.pointerLeave; 9642 enterEventType = eventTypes$2.pointerEnter; 9643 eventTypePrefix = 'pointer'; 9644 } 9645 9646 var fromNode = from == null ? win : getNodeFromInstance$1(from); 9647 var toNode = to == null ? win : getNodeFromInstance$1(to); 9648 var leave = eventInterface.getPooled(leaveEventType, from, nativeEvent, nativeEventTarget); 9649 leave.type = eventTypePrefix + 'leave'; 9650 leave.target = fromNode; 9651 leave.relatedTarget = toNode; 9652 var enter = eventInterface.getPooled(enterEventType, to, nativeEvent, nativeEventTarget); 9653 enter.type = eventTypePrefix + 'enter'; 9654 enter.target = toNode; 9655 enter.relatedTarget = fromNode; 9656 accumulateEnterLeaveDispatches(leave, enter, from, to); // If we are not processing the first ancestor, then we 9657 // should not process the same nativeEvent again, as we 9658 // will have already processed it in the first ancestor. 9659 9660 if ((eventSystemFlags & IS_FIRST_ANCESTOR) === 0) { 9661 return [leave]; 9662 } 9663 9664 return [leave, enter]; 9665 } 9666 }; 9667 9668 /** 9669 * inlined Object.is polyfill to avoid requiring consumers ship their own 9670 * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is 9671 */ 9672 function is(x, y) { 9673 return x === y && (x !== 0 || 1 / x === 1 / y) || x !== x && y !== y // eslint-disable-line no-self-compare 9674 ; 9675 } 9676 9677 var objectIs = typeof Object.is === 'function' ? Object.is : is; 9678 9679 var hasOwnProperty$2 = Object.prototype.hasOwnProperty; 9680 /** 9681 * Performs equality by iterating through keys on an object and returning false 9682 * when any key has values which are not strictly equal between the arguments. 9683 * Returns true when the values of all keys are strictly equal. 9684 */ 9685 9686 function shallowEqual(objA, objB) { 9687 if (objectIs(objA, objB)) { 9688 return true; 9689 } 9690 9691 if (typeof objA !== 'object' || objA === null || typeof objB !== 'object' || objB === null) { 9692 return false; 9693 } 9694 9695 var keysA = Object.keys(objA); 9696 var keysB = Object.keys(objB); 9697 9698 if (keysA.length !== keysB.length) { 9699 return false; 9700 } // Test for A's keys different from B. 9701 9702 9703 for (var i = 0; i < keysA.length; i++) { 9704 if (!hasOwnProperty$2.call(objB, keysA[i]) || !objectIs(objA[keysA[i]], objB[keysA[i]])) { 9705 return false; 9706 } 9707 } 9708 9709 return true; 9710 } 9711 9712 var skipSelectionChangeEvent = canUseDOM && 'documentMode' in document && document.documentMode <= 11; 9713 var eventTypes$3 = { 9714 select: { 9715 phasedRegistrationNames: { 9716 bubbled: 'onSelect', 9717 captured: 'onSelectCapture' 9718 }, 9719 dependencies: [TOP_BLUR, TOP_CONTEXT_MENU, TOP_DRAG_END, TOP_FOCUS, TOP_KEY_DOWN, TOP_KEY_UP, TOP_MOUSE_DOWN, TOP_MOUSE_UP, TOP_SELECTION_CHANGE] 9720 } 9721 }; 9722 var activeElement$1 = null; 9723 var activeElementInst$1 = null; 9724 var lastSelection = null; 9725 var mouseDown = false; 9726 /** 9727 * Get an object which is a unique representation of the current selection. 9728 * 9729 * The return value will not be consistent across nodes or browsers, but 9730 * two identical selections on the same node will return identical objects. 9731 * 9732 * @param {DOMElement} node 9733 * @return {object} 9734 */ 9735 9736 function getSelection$1(node) { 9737 if ('selectionStart' in node && hasSelectionCapabilities(node)) { 9738 return { 9739 start: node.selectionStart, 9740 end: node.selectionEnd 9741 }; 9742 } else { 9743 var win = node.ownerDocument && node.ownerDocument.defaultView || window; 9744 var selection = win.getSelection(); 9745 return { 9746 anchorNode: selection.anchorNode, 9747 anchorOffset: selection.anchorOffset, 9748 focusNode: selection.focusNode, 9749 focusOffset: selection.focusOffset 9750 }; 9751 } 9752 } 9753 /** 9754 * Get document associated with the event target. 9755 * 9756 * @param {object} nativeEventTarget 9757 * @return {Document} 9758 */ 9759 9760 9761 function getEventTargetDocument(eventTarget) { 9762 return eventTarget.window === eventTarget ? eventTarget.document : eventTarget.nodeType === DOCUMENT_NODE ? eventTarget : eventTarget.ownerDocument; 9763 } 9764 /** 9765 * Poll selection to see whether it's changed. 9766 * 9767 * @param {object} nativeEvent 9768 * @param {object} nativeEventTarget 9769 * @return {?SyntheticEvent} 9770 */ 9771 9772 9773 function constructSelectEvent(nativeEvent, nativeEventTarget) { 9774 // Ensure we have the right element, and that the user is not dragging a 9775 // selection (this matches native `select` event behavior). In HTML5, select 9776 // fires only on input and textarea thus if there's no focused element we 9777 // won't dispatch. 9778 var doc = getEventTargetDocument(nativeEventTarget); 9779 9780 if (mouseDown || activeElement$1 == null || activeElement$1 !== getActiveElement(doc)) { 9781 return null; 9782 } // Only fire when selection has actually changed. 9783 9784 9785 var currentSelection = getSelection$1(activeElement$1); 9786 9787 if (!lastSelection || !shallowEqual(lastSelection, currentSelection)) { 9788 lastSelection = currentSelection; 9789 var syntheticEvent = SyntheticEvent.getPooled(eventTypes$3.select, activeElementInst$1, nativeEvent, nativeEventTarget); 9790 syntheticEvent.type = 'select'; 9791 syntheticEvent.target = activeElement$1; 9792 accumulateTwoPhaseDispatches(syntheticEvent); 9793 return syntheticEvent; 9794 } 9795 9796 return null; 9797 } 9798 /** 9799 * This plugin creates an `onSelect` event that normalizes select events 9800 * across form elements. 9801 * 9802 * Supported elements are: 9803 * - input (see `isTextInputElement`) 9804 * - textarea 9805 * - contentEditable 9806 * 9807 * This differs from native browser implementations in the following ways: 9808 * - Fires on contentEditable fields as well as inputs. 9809 * - Fires for collapsed selection. 9810 * - Fires after user input. 9811 */ 9812 9813 9814 var SelectEventPlugin = { 9815 eventTypes: eventTypes$3, 9816 extractEvents: function (topLevelType, targetInst, nativeEvent, nativeEventTarget, eventSystemFlags, container) { 9817 var containerOrDoc = container || getEventTargetDocument(nativeEventTarget); // Track whether all listeners exists for this plugin. If none exist, we do 9818 // not extract events. See #3639. 9819 9820 if (!containerOrDoc || !isListeningToAllDependencies('onSelect', containerOrDoc)) { 9821 return null; 9822 } 9823 9824 var targetNode = targetInst ? getNodeFromInstance$1(targetInst) : window; 9825 9826 switch (topLevelType) { 9827 // Track the input node that has focus. 9828 case TOP_FOCUS: 9829 if (isTextInputElement(targetNode) || targetNode.contentEditable === 'true') { 9830 activeElement$1 = targetNode; 9831 activeElementInst$1 = targetInst; 9832 lastSelection = null; 9833 } 9834 9835 break; 9836 9837 case TOP_BLUR: 9838 activeElement$1 = null; 9839 activeElementInst$1 = null; 9840 lastSelection = null; 9841 break; 9842 // Don't fire the event while the user is dragging. This matches the 9843 // semantics of the native select event. 9844 9845 case TOP_MOUSE_DOWN: 9846 mouseDown = true; 9847 break; 9848 9849 case TOP_CONTEXT_MENU: 9850 case TOP_MOUSE_UP: 9851 case TOP_DRAG_END: 9852 mouseDown = false; 9853 return constructSelectEvent(nativeEvent, nativeEventTarget); 9854 // Chrome and IE fire non-standard event when selection is changed (and 9855 // sometimes when it hasn't). IE's event fires out of order with respect 9856 // to key and input events on deletion, so we discard it. 9857 // 9858 // Firefox doesn't support selectionchange, so check selection status 9859 // after each key entry. The selection changes after keydown and before 9860 // keyup, but we check on keydown as well in the case of holding down a 9861 // key, when multiple keydown events are fired but only one keyup is. 9862 // This is also our approach for IE handling, for the reason above. 9863 9864 case TOP_SELECTION_CHANGE: 9865 if (skipSelectionChangeEvent) { 9866 break; 9867 } 9868 9869 // falls through 9870 9871 case TOP_KEY_DOWN: 9872 case TOP_KEY_UP: 9873 return constructSelectEvent(nativeEvent, nativeEventTarget); 9874 } 9875 9876 return null; 9877 } 9878 }; 9879 9880 /** 9881 * @interface Event 9882 * @see http://www.w3.org/TR/css3-animations/#AnimationEvent-interface 9883 * @see https://developer.mozilla.org/en-US/docs/Web/API/AnimationEvent 9884 */ 9885 9886 var SyntheticAnimationEvent = SyntheticEvent.extend({ 9887 animationName: null, 9888 elapsedTime: null, 9889 pseudoElement: null 9890 }); 9891 9892 /** 9893 * @interface Event 9894 * @see http://www.w3.org/TR/clipboard-apis/ 9895 */ 9896 9897 var SyntheticClipboardEvent = SyntheticEvent.extend({ 9898 clipboardData: function (event) { 9899 return 'clipboardData' in event ? event.clipboardData : window.clipboardData; 9900 } 9901 }); 9902 9903 /** 9904 * @interface FocusEvent 9905 * @see http://www.w3.org/TR/DOM-Level-3-Events/ 9906 */ 9907 9908 var SyntheticFocusEvent = SyntheticUIEvent.extend({ 9909 relatedTarget: null 9910 }); 9911 9912 /** 9913 * `charCode` represents the actual "character code" and is safe to use with 9914 * `String.fromCharCode`. As such, only keys that correspond to printable 9915 * characters produce a valid `charCode`, the only exception to this is Enter. 9916 * The Tab-key is considered non-printable and does not have a `charCode`, 9917 * presumably because it does not produce a tab-character in browsers. 9918 * 9919 * @param {object} nativeEvent Native browser event. 9920 * @return {number} Normalized `charCode` property. 9921 */ 9922 function getEventCharCode(nativeEvent) { 9923 var charCode; 9924 var keyCode = nativeEvent.keyCode; 9925 9926 if ('charCode' in nativeEvent) { 9927 charCode = nativeEvent.charCode; // FF does not set `charCode` for the Enter-key, check against `keyCode`. 9928 9929 if (charCode === 0 && keyCode === 13) { 9930 charCode = 13; 9931 } 9932 } else { 9933 // IE8 does not implement `charCode`, but `keyCode` has the correct value. 9934 charCode = keyCode; 9935 } // IE and Edge (on Windows) and Chrome / Safari (on Windows and Linux) 9936 // report Enter as charCode 10 when ctrl is pressed. 9937 9938 9939 if (charCode === 10) { 9940 charCode = 13; 9941 } // Some non-printable keys are reported in `charCode`/`keyCode`, discard them. 9942 // Must not discard the (non-)printable Enter-key. 9943 9944 9945 if (charCode >= 32 || charCode === 13) { 9946 return charCode; 9947 } 9948 9949 return 0; 9950 } 9951 9952 /** 9953 * Normalization of deprecated HTML5 `key` values 9954 * @see https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent#Key_names 9955 */ 9956 9957 var normalizeKey = { 9958 Esc: 'Escape', 9959 Spacebar: ' ', 9960 Left: 'ArrowLeft', 9961 Up: 'ArrowUp', 9962 Right: 'ArrowRight', 9963 Down: 'ArrowDown', 9964 Del: 'Delete', 9965 Win: 'OS', 9966 Menu: 'ContextMenu', 9967 Apps: 'ContextMenu', 9968 Scroll: 'ScrollLock', 9969 MozPrintableKey: 'Unidentified' 9970 }; 9971 /** 9972 * Translation from legacy `keyCode` to HTML5 `key` 9973 * Only special keys supported, all others depend on keyboard layout or browser 9974 * @see https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent#Key_names 9975 */ 9976 9977 var translateToKey = { 9978 '8': 'Backspace', 9979 '9': 'Tab', 9980 '12': 'Clear', 9981 '13': 'Enter', 9982 '16': 'Shift', 9983 '17': 'Control', 9984 '18': 'Alt', 9985 '19': 'Pause', 9986 '20': 'CapsLock', 9987 '27': 'Escape', 9988 '32': ' ', 9989 '33': 'PageUp', 9990 '34': 'PageDown', 9991 '35': 'End', 9992 '36': 'Home', 9993 '37': 'ArrowLeft', 9994 '38': 'ArrowUp', 9995 '39': 'ArrowRight', 9996 '40': 'ArrowDown', 9997 '45': 'Insert', 9998 '46': 'Delete', 9999 '112': 'F1', 10000 '113': 'F2', 10001 '114': 'F3', 10002 '115': 'F4', 10003 '116': 'F5', 10004 '117': 'F6', 10005 '118': 'F7', 10006 '119': 'F8', 10007 '120': 'F9', 10008 '121': 'F10', 10009 '122': 'F11', 10010 '123': 'F12', 10011 '144': 'NumLock', 10012 '145': 'ScrollLock', 10013 '224': 'Meta' 10014 }; 10015 /** 10016 * @param {object} nativeEvent Native browser event. 10017 * @return {string} Normalized `key` property. 10018 */ 10019 10020 function getEventKey(nativeEvent) { 10021 if (nativeEvent.key) { 10022 // Normalize inconsistent values reported by browsers due to 10023 // implementations of a working draft specification. 10024 // FireFox implements `key` but returns `MozPrintableKey` for all 10025 // printable characters (normalized to `Unidentified`), ignore it. 10026 var key = normalizeKey[nativeEvent.key] || nativeEvent.key; 10027 10028 if (key !== 'Unidentified') { 10029 return key; 10030 } 10031 } // Browser does not implement `key`, polyfill as much of it as we can. 10032 10033 10034 if (nativeEvent.type === 'keypress') { 10035 var charCode = getEventCharCode(nativeEvent); // The enter-key is technically both printable and non-printable and can 10036 // thus be captured by `keypress`, no other non-printable key should. 10037 10038 return charCode === 13 ? 'Enter' : String.fromCharCode(charCode); 10039 } 10040 10041 if (nativeEvent.type === 'keydown' || nativeEvent.type === 'keyup') { 10042 // While user keyboard layout determines the actual meaning of each 10043 // `keyCode` value, almost all function keys have a universal value. 10044 return translateToKey[nativeEvent.keyCode] || 'Unidentified'; 10045 } 10046 10047 return ''; 10048 } 10049 10050 /** 10051 * @interface KeyboardEvent 10052 * @see http://www.w3.org/TR/DOM-Level-3-Events/ 10053 */ 10054 10055 var SyntheticKeyboardEvent = SyntheticUIEvent.extend({ 10056 key: getEventKey, 10057 location: null, 10058 ctrlKey: null, 10059 shiftKey: null, 10060 altKey: null, 10061 metaKey: null, 10062 repeat: null, 10063 locale: null, 10064 getModifierState: getEventModifierState, 10065 // Legacy Interface 10066 charCode: function (event) { 10067 // `charCode` is the result of a KeyPress event and represents the value of 10068 // the actual printable character. 10069 // KeyPress is deprecated, but its replacement is not yet final and not 10070 // implemented in any major browser. Only KeyPress has charCode. 10071 if (event.type === 'keypress') { 10072 return getEventCharCode(event); 10073 } 10074 10075 return 0; 10076 }, 10077 keyCode: function (event) { 10078 // `keyCode` is the result of a KeyDown/Up event and represents the value of 10079 // physical keyboard key. 10080 // The actual meaning of the value depends on the users' keyboard layout 10081 // which cannot be detected. Assuming that it is a US keyboard layout 10082 // provides a surprisingly accurate mapping for US and European users. 10083 // Due to this, it is left to the user to implement at this time. 10084 if (event.type === 'keydown' || event.type === 'keyup') { 10085 return event.keyCode; 10086 } 10087 10088 return 0; 10089 }, 10090 which: function (event) { 10091 // `which` is an alias for either `keyCode` or `charCode` depending on the 10092 // type of the event. 10093 if (event.type === 'keypress') { 10094 return getEventCharCode(event); 10095 } 10096 10097 if (event.type === 'keydown' || event.type === 'keyup') { 10098 return event.keyCode; 10099 } 10100 10101 return 0; 10102 } 10103 }); 10104 10105 /** 10106 * @interface DragEvent 10107 * @see http://www.w3.org/TR/DOM-Level-3-Events/ 10108 */ 10109 10110 var SyntheticDragEvent = SyntheticMouseEvent.extend({ 10111 dataTransfer: null 10112 }); 10113 10114 /** 10115 * @interface TouchEvent 10116 * @see http://www.w3.org/TR/touch-events/ 10117 */ 10118 10119 var SyntheticTouchEvent = SyntheticUIEvent.extend({ 10120 touches: null, 10121 targetTouches: null, 10122 changedTouches: null, 10123 altKey: null, 10124 metaKey: null, 10125 ctrlKey: null, 10126 shiftKey: null, 10127 getModifierState: getEventModifierState 10128 }); 10129 10130 /** 10131 * @interface Event 10132 * @see http://www.w3.org/TR/2009/WD-css3-transitions-20090320/#transition-events- 10133 * @see https://developer.mozilla.org/en-US/docs/Web/API/TransitionEvent 10134 */ 10135 10136 var SyntheticTransitionEvent = SyntheticEvent.extend({ 10137 propertyName: null, 10138 elapsedTime: null, 10139 pseudoElement: null 10140 }); 10141 10142 /** 10143 * @interface WheelEvent 10144 * @see http://www.w3.org/TR/DOM-Level-3-Events/ 10145 */ 10146 10147 var SyntheticWheelEvent = SyntheticMouseEvent.extend({ 10148 deltaX: function (event) { 10149 return 'deltaX' in event ? event.deltaX : // Fallback to `wheelDeltaX` for Webkit and normalize (right is positive). 10150 'wheelDeltaX' in event ? -event.wheelDeltaX : 0; 10151 }, 10152 deltaY: function (event) { 10153 return 'deltaY' in event ? event.deltaY : // Fallback to `wheelDeltaY` for Webkit and normalize (down is positive). 10154 'wheelDeltaY' in event ? -event.wheelDeltaY : // Fallback to `wheelDelta` for IE<9 and normalize (down is positive). 10155 'wheelDelta' in event ? -event.wheelDelta : 0; 10156 }, 10157 deltaZ: null, 10158 // Browsers without "deltaMode" is reporting in raw wheel delta where one 10159 // notch on the scroll is always +/- 120, roughly equivalent to pixels. 10160 // A good approximation of DOM_DELTA_LINE (1) is 5% of viewport size or 10161 // ~40 pixels, for DOM_DELTA_SCREEN (2) it is 87.5% of viewport size. 10162 deltaMode: null 10163 }); 10164 10165 var knownHTMLTopLevelTypes = [TOP_ABORT, TOP_CANCEL, TOP_CAN_PLAY, TOP_CAN_PLAY_THROUGH, TOP_CLOSE, TOP_DURATION_CHANGE, TOP_EMPTIED, TOP_ENCRYPTED, TOP_ENDED, TOP_ERROR, TOP_INPUT, TOP_INVALID, TOP_LOAD, TOP_LOADED_DATA, TOP_LOADED_METADATA, TOP_LOAD_START, TOP_PAUSE, TOP_PLAY, TOP_PLAYING, TOP_PROGRESS, TOP_RATE_CHANGE, TOP_RESET, TOP_SEEKED, TOP_SEEKING, TOP_STALLED, TOP_SUBMIT, TOP_SUSPEND, TOP_TIME_UPDATE, TOP_TOGGLE, TOP_VOLUME_CHANGE, TOP_WAITING]; 10166 var SimpleEventPlugin = { 10167 // simpleEventPluginEventTypes gets populated from 10168 // the DOMEventProperties module. 10169 eventTypes: simpleEventPluginEventTypes, 10170 extractEvents: function (topLevelType, targetInst, nativeEvent, nativeEventTarget, eventSystemFlags) { 10171 var dispatchConfig = topLevelEventsToDispatchConfig.get(topLevelType); 10172 10173 if (!dispatchConfig) { 10174 return null; 10175 } 10176 10177 var EventConstructor; 10178 10179 switch (topLevelType) { 10180 case TOP_KEY_PRESS: 10181 // Firefox creates a keypress event for function keys too. This removes 10182 // the unwanted keypress events. Enter is however both printable and 10183 // non-printable. One would expect Tab to be as well (but it isn't). 10184 if (getEventCharCode(nativeEvent) === 0) { 10185 return null; 10186 } 10187 10188 /* falls through */ 10189 10190 case TOP_KEY_DOWN: 10191 case TOP_KEY_UP: 10192 EventConstructor = SyntheticKeyboardEvent; 10193 break; 10194 10195 case TOP_BLUR: 10196 case TOP_FOCUS: 10197 EventConstructor = SyntheticFocusEvent; 10198 break; 10199 10200 case TOP_CLICK: 10201 // Firefox creates a click event on right mouse clicks. This removes the 10202 // unwanted click events. 10203 if (nativeEvent.button === 2) { 10204 return null; 10205 } 10206 10207 /* falls through */ 10208 10209 case TOP_AUX_CLICK: 10210 case TOP_DOUBLE_CLICK: 10211 case TOP_MOUSE_DOWN: 10212 case TOP_MOUSE_MOVE: 10213 case TOP_MOUSE_UP: // TODO: Disabled elements should not respond to mouse events 10214 10215 /* falls through */ 10216 10217 case TOP_MOUSE_OUT: 10218 case TOP_MOUSE_OVER: 10219 case TOP_CONTEXT_MENU: 10220 EventConstructor = SyntheticMouseEvent; 10221 break; 10222 10223 case TOP_DRAG: 10224 case TOP_DRAG_END: 10225 case TOP_DRAG_ENTER: 10226 case TOP_DRAG_EXIT: 10227 case TOP_DRAG_LEAVE: 10228 case TOP_DRAG_OVER: 10229 case TOP_DRAG_START: 10230 case TOP_DROP: 10231 EventConstructor = SyntheticDragEvent; 10232 break; 10233 10234 case TOP_TOUCH_CANCEL: 10235 case TOP_TOUCH_END: 10236 case TOP_TOUCH_MOVE: 10237 case TOP_TOUCH_START: 10238 EventConstructor = SyntheticTouchEvent; 10239 break; 10240 10241 case TOP_ANIMATION_END: 10242 case TOP_ANIMATION_ITERATION: 10243 case TOP_ANIMATION_START: 10244 EventConstructor = SyntheticAnimationEvent; 10245 break; 10246 10247 case TOP_TRANSITION_END: 10248 EventConstructor = SyntheticTransitionEvent; 10249 break; 10250 10251 case TOP_SCROLL: 10252 EventConstructor = SyntheticUIEvent; 10253 break; 10254 10255 case TOP_WHEEL: 10256 EventConstructor = SyntheticWheelEvent; 10257 break; 10258 10259 case TOP_COPY: 10260 case TOP_CUT: 10261 case TOP_PASTE: 10262 EventConstructor = SyntheticClipboardEvent; 10263 break; 10264 10265 case TOP_GOT_POINTER_CAPTURE: 10266 case TOP_LOST_POINTER_CAPTURE: 10267 case TOP_POINTER_CANCEL: 10268 case TOP_POINTER_DOWN: 10269 case TOP_POINTER_MOVE: 10270 case TOP_POINTER_OUT: 10271 case TOP_POINTER_OVER: 10272 case TOP_POINTER_UP: 10273 EventConstructor = SyntheticPointerEvent; 10274 break; 10275 10276 default: 10277 { 10278 if (knownHTMLTopLevelTypes.indexOf(topLevelType) === -1) { 10279 error('SimpleEventPlugin: Unhandled event type, `%s`. This warning ' + 'is likely caused by a bug in React. Please file an issue.', topLevelType); 10280 } 10281 } // HTML Events 10282 // @see http://www.w3.org/TR/html5/index.html#events-0 10283 10284 10285 EventConstructor = SyntheticEvent; 10286 break; 10287 } 10288 10289 var event = EventConstructor.getPooled(dispatchConfig, targetInst, nativeEvent, nativeEventTarget); 10290 accumulateTwoPhaseDispatches(event); 10291 return event; 10292 } 10293 }; 10294 10295 /** 10296 * Specifies a deterministic ordering of `EventPlugin`s. A convenient way to 10297 * reason about plugins, without having to package every one of them. This 10298 * is better than having plugins be ordered in the same order that they 10299 * are injected because that ordering would be influenced by the packaging order. 10300 * `ResponderEventPlugin` must occur before `SimpleEventPlugin` so that 10301 * preventing default on events is convenient in `SimpleEventPlugin` handlers. 10302 */ 10303 10304 var DOMEventPluginOrder = ['ResponderEventPlugin', 'SimpleEventPlugin', 'EnterLeaveEventPlugin', 'ChangeEventPlugin', 'SelectEventPlugin', 'BeforeInputEventPlugin']; 10305 /** 10306 * Inject modules for resolving DOM hierarchy and plugin ordering. 10307 */ 10308 10309 injectEventPluginOrder(DOMEventPluginOrder); 10310 setComponentTree(getFiberCurrentPropsFromNode$1, getInstanceFromNode$1, getNodeFromInstance$1); 10311 /** 10312 * Some important event plugins included by default (without having to require 10313 * them). 10314 */ 10315 10316 injectEventPluginsByName({ 10317 SimpleEventPlugin: SimpleEventPlugin, 10318 EnterLeaveEventPlugin: EnterLeaveEventPlugin, 10319 ChangeEventPlugin: ChangeEventPlugin, 10320 SelectEventPlugin: SelectEventPlugin, 10321 BeforeInputEventPlugin: BeforeInputEventPlugin 10322 }); 10323 10324 // Prefix measurements so that it's possible to filter them. 10325 // Longer prefixes are hard to read in DevTools. 10326 var reactEmoji = "\u269B"; 10327 var warningEmoji = "\u26D4"; 10328 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. 10329 // TODO: this looks the same as nextUnitOfWork in scheduler. Can we unify them? 10330 10331 var currentFiber = null; // If we're in the middle of user code, which fiber and method is it? 10332 // Reusing `currentFiber` would be confusing for this because user code fiber 10333 // can change during commit phase too, but we don't need to unwind it (since 10334 // lifecycles in the commit phase don't resemble a tree). 10335 10336 var currentPhase = null; 10337 var currentPhaseFiber = null; // Did lifecycle hook schedule an update? This is often a performance problem, 10338 // so we will keep track of it, and include it in the report. 10339 // Track commits caused by cascading updates. 10340 10341 var isCommitting = false; 10342 var hasScheduledUpdateInCurrentCommit = false; 10343 var hasScheduledUpdateInCurrentPhase = false; 10344 var commitCountInCurrentWorkLoop = 0; 10345 var effectCountInCurrentCommit = 0; 10346 // to avoid stretch the commit phase with measurement overhead. 10347 10348 var labelsInCurrentCommit = new Set(); 10349 10350 var formatMarkName = function (markName) { 10351 return reactEmoji + " " + markName; 10352 }; 10353 10354 var formatLabel = function (label, warning) { 10355 var prefix = warning ? warningEmoji + " " : reactEmoji + " "; 10356 var suffix = warning ? " Warning: " + warning : ''; 10357 return "" + prefix + label + suffix; 10358 }; 10359 10360 var beginMark = function (markName) { 10361 performance.mark(formatMarkName(markName)); 10362 }; 10363 10364 var clearMark = function (markName) { 10365 performance.clearMarks(formatMarkName(markName)); 10366 }; 10367 10368 var endMark = function (label, markName, warning) { 10369 var formattedMarkName = formatMarkName(markName); 10370 var formattedLabel = formatLabel(label, warning); 10371 10372 try { 10373 performance.measure(formattedLabel, formattedMarkName); 10374 } catch (err) {} // If previous mark was missing for some reason, this will throw. 10375 // This could only happen if React crashed in an unexpected place earlier. 10376 // Don't pile on with more errors. 10377 // Clear marks immediately to avoid growing buffer. 10378 10379 10380 performance.clearMarks(formattedMarkName); 10381 performance.clearMeasures(formattedLabel); 10382 }; 10383 10384 var getFiberMarkName = function (label, debugID) { 10385 return label + " (#" + debugID + ")"; 10386 }; 10387 10388 var getFiberLabel = function (componentName, isMounted, phase) { 10389 if (phase === null) { 10390 // These are composite component total time measurements. 10391 return componentName + " [" + (isMounted ? 'update' : 'mount') + "]"; 10392 } else { 10393 // Composite component methods. 10394 return componentName + "." + phase; 10395 } 10396 }; 10397 10398 var beginFiberMark = function (fiber, phase) { 10399 var componentName = getComponentName(fiber.type) || 'Unknown'; 10400 var debugID = fiber._debugID; 10401 var isMounted = fiber.alternate !== null; 10402 var label = getFiberLabel(componentName, isMounted, phase); 10403 10404 if (isCommitting && labelsInCurrentCommit.has(label)) { 10405 // During the commit phase, we don't show duplicate labels because 10406 // there is a fixed overhead for every measurement, and we don't 10407 // want to stretch the commit phase beyond necessary. 10408 return false; 10409 } 10410 10411 labelsInCurrentCommit.add(label); 10412 var markName = getFiberMarkName(label, debugID); 10413 beginMark(markName); 10414 return true; 10415 }; 10416 10417 var clearFiberMark = function (fiber, phase) { 10418 var componentName = getComponentName(fiber.type) || 'Unknown'; 10419 var debugID = fiber._debugID; 10420 var isMounted = fiber.alternate !== null; 10421 var label = getFiberLabel(componentName, isMounted, phase); 10422 var markName = getFiberMarkName(label, debugID); 10423 clearMark(markName); 10424 }; 10425 10426 var endFiberMark = function (fiber, phase, warning) { 10427 var componentName = getComponentName(fiber.type) || 'Unknown'; 10428 var debugID = fiber._debugID; 10429 var isMounted = fiber.alternate !== null; 10430 var label = getFiberLabel(componentName, isMounted, phase); 10431 var markName = getFiberMarkName(label, debugID); 10432 endMark(label, markName, warning); 10433 }; 10434 10435 var shouldIgnoreFiber = function (fiber) { 10436 // Host components should be skipped in the timeline. 10437 // We could check typeof fiber.type, but does this work with RN? 10438 switch (fiber.tag) { 10439 case HostRoot: 10440 case HostComponent: 10441 case HostText: 10442 case HostPortal: 10443 case Fragment: 10444 case ContextProvider: 10445 case ContextConsumer: 10446 case Mode: 10447 return true; 10448 10449 default: 10450 return false; 10451 } 10452 }; 10453 10454 var clearPendingPhaseMeasurement = function () { 10455 if (currentPhase !== null && currentPhaseFiber !== null) { 10456 clearFiberMark(currentPhaseFiber, currentPhase); 10457 } 10458 10459 currentPhaseFiber = null; 10460 currentPhase = null; 10461 hasScheduledUpdateInCurrentPhase = false; 10462 }; 10463 10464 var pauseTimers = function () { 10465 // Stops all currently active measurements so that they can be resumed 10466 // if we continue in a later deferred loop from the same unit of work. 10467 var fiber = currentFiber; 10468 10469 while (fiber) { 10470 if (fiber._debugIsCurrentlyTiming) { 10471 endFiberMark(fiber, null, null); 10472 } 10473 10474 fiber = fiber.return; 10475 } 10476 }; 10477 10478 var resumeTimersRecursively = function (fiber) { 10479 if (fiber.return !== null) { 10480 resumeTimersRecursively(fiber.return); 10481 } 10482 10483 if (fiber._debugIsCurrentlyTiming) { 10484 beginFiberMark(fiber, null); 10485 } 10486 }; 10487 10488 var resumeTimers = function () { 10489 // Resumes all measurements that were active during the last deferred loop. 10490 if (currentFiber !== null) { 10491 resumeTimersRecursively(currentFiber); 10492 } 10493 }; 10494 10495 function recordEffect() { 10496 { 10497 effectCountInCurrentCommit++; 10498 } 10499 } 10500 function recordScheduleUpdate() { 10501 { 10502 if (isCommitting) { 10503 hasScheduledUpdateInCurrentCommit = true; 10504 } 10505 10506 if (currentPhase !== null && currentPhase !== 'componentWillMount' && currentPhase !== 'componentWillReceiveProps') { 10507 hasScheduledUpdateInCurrentPhase = true; 10508 } 10509 } 10510 } 10511 function startWorkTimer(fiber) { 10512 { 10513 if (!supportsUserTiming || shouldIgnoreFiber(fiber)) { 10514 return; 10515 } // If we pause, this is the fiber to unwind from. 10516 10517 10518 currentFiber = fiber; 10519 10520 if (!beginFiberMark(fiber, null)) { 10521 return; 10522 } 10523 10524 fiber._debugIsCurrentlyTiming = true; 10525 } 10526 } 10527 function cancelWorkTimer(fiber) { 10528 { 10529 if (!supportsUserTiming || shouldIgnoreFiber(fiber)) { 10530 return; 10531 } // Remember we shouldn't complete measurement for this fiber. 10532 // Otherwise flamechart will be deep even for small updates. 10533 10534 10535 fiber._debugIsCurrentlyTiming = false; 10536 clearFiberMark(fiber, null); 10537 } 10538 } 10539 function stopWorkTimer(fiber) { 10540 { 10541 if (!supportsUserTiming || shouldIgnoreFiber(fiber)) { 10542 return; 10543 } // If we pause, its parent is the fiber to unwind from. 10544 10545 10546 currentFiber = fiber.return; 10547 10548 if (!fiber._debugIsCurrentlyTiming) { 10549 return; 10550 } 10551 10552 fiber._debugIsCurrentlyTiming = false; 10553 endFiberMark(fiber, null, null); 10554 } 10555 } 10556 function stopFailedWorkTimer(fiber) { 10557 { 10558 if (!supportsUserTiming || shouldIgnoreFiber(fiber)) { 10559 return; 10560 } // If we pause, its parent is the fiber to unwind from. 10561 10562 10563 currentFiber = fiber.return; 10564 10565 if (!fiber._debugIsCurrentlyTiming) { 10566 return; 10567 } 10568 10569 fiber._debugIsCurrentlyTiming = false; 10570 var warning = fiber.tag === SuspenseComponent ? 'Rendering was suspended' : 'An error was thrown inside this error boundary'; 10571 endFiberMark(fiber, null, warning); 10572 } 10573 } 10574 function startPhaseTimer(fiber, phase) { 10575 { 10576 if (!supportsUserTiming) { 10577 return; 10578 } 10579 10580 clearPendingPhaseMeasurement(); 10581 10582 if (!beginFiberMark(fiber, phase)) { 10583 return; 10584 } 10585 10586 currentPhaseFiber = fiber; 10587 currentPhase = phase; 10588 } 10589 } 10590 function stopPhaseTimer() { 10591 { 10592 if (!supportsUserTiming) { 10593 return; 10594 } 10595 10596 if (currentPhase !== null && currentPhaseFiber !== null) { 10597 var warning = hasScheduledUpdateInCurrentPhase ? 'Scheduled a cascading update' : null; 10598 endFiberMark(currentPhaseFiber, currentPhase, warning); 10599 } 10600 10601 currentPhase = null; 10602 currentPhaseFiber = null; 10603 } 10604 } 10605 function startWorkLoopTimer(nextUnitOfWork) { 10606 { 10607 currentFiber = nextUnitOfWork; 10608 10609 if (!supportsUserTiming) { 10610 return; 10611 } 10612 10613 commitCountInCurrentWorkLoop = 0; // This is top level call. 10614 // Any other measurements are performed within. 10615 10616 beginMark('(React Tree Reconciliation)'); // Resume any measurements that were in progress during the last loop. 10617 10618 resumeTimers(); 10619 } 10620 } 10621 function stopWorkLoopTimer(interruptedBy, didCompleteRoot) { 10622 { 10623 if (!supportsUserTiming) { 10624 return; 10625 } 10626 10627 var warning = null; 10628 10629 if (interruptedBy !== null) { 10630 if (interruptedBy.tag === HostRoot) { 10631 warning = 'A top-level update interrupted the previous render'; 10632 } else { 10633 var componentName = getComponentName(interruptedBy.type) || 'Unknown'; 10634 warning = "An update to " + componentName + " interrupted the previous render"; 10635 } 10636 } else if (commitCountInCurrentWorkLoop > 1) { 10637 warning = 'There were cascading updates'; 10638 } 10639 10640 commitCountInCurrentWorkLoop = 0; 10641 var label = didCompleteRoot ? '(React Tree Reconciliation: Completed Root)' : '(React Tree Reconciliation: Yielded)'; // Pause any measurements until the next loop. 10642 10643 pauseTimers(); 10644 endMark(label, '(React Tree Reconciliation)', warning); 10645 } 10646 } 10647 function startCommitTimer() { 10648 { 10649 if (!supportsUserTiming) { 10650 return; 10651 } 10652 10653 isCommitting = true; 10654 hasScheduledUpdateInCurrentCommit = false; 10655 labelsInCurrentCommit.clear(); 10656 beginMark('(Committing Changes)'); 10657 } 10658 } 10659 function stopCommitTimer() { 10660 { 10661 if (!supportsUserTiming) { 10662 return; 10663 } 10664 10665 var warning = null; 10666 10667 if (hasScheduledUpdateInCurrentCommit) { 10668 warning = 'Lifecycle hook scheduled a cascading update'; 10669 } else if (commitCountInCurrentWorkLoop > 0) { 10670 warning = 'Caused by a cascading update in earlier commit'; 10671 } 10672 10673 hasScheduledUpdateInCurrentCommit = false; 10674 commitCountInCurrentWorkLoop++; 10675 isCommitting = false; 10676 labelsInCurrentCommit.clear(); 10677 endMark('(Committing Changes)', '(Committing Changes)', warning); 10678 } 10679 } 10680 function startCommitSnapshotEffectsTimer() { 10681 { 10682 if (!supportsUserTiming) { 10683 return; 10684 } 10685 10686 effectCountInCurrentCommit = 0; 10687 beginMark('(Committing Snapshot Effects)'); 10688 } 10689 } 10690 function stopCommitSnapshotEffectsTimer() { 10691 { 10692 if (!supportsUserTiming) { 10693 return; 10694 } 10695 10696 var count = effectCountInCurrentCommit; 10697 effectCountInCurrentCommit = 0; 10698 endMark("(Committing Snapshot Effects: " + count + " Total)", '(Committing Snapshot Effects)', null); 10699 } 10700 } 10701 function startCommitHostEffectsTimer() { 10702 { 10703 if (!supportsUserTiming) { 10704 return; 10705 } 10706 10707 effectCountInCurrentCommit = 0; 10708 beginMark('(Committing Host Effects)'); 10709 } 10710 } 10711 function stopCommitHostEffectsTimer() { 10712 { 10713 if (!supportsUserTiming) { 10714 return; 10715 } 10716 10717 var count = effectCountInCurrentCommit; 10718 effectCountInCurrentCommit = 0; 10719 endMark("(Committing Host Effects: " + count + " Total)", '(Committing Host Effects)', null); 10720 } 10721 } 10722 function startCommitLifeCyclesTimer() { 10723 { 10724 if (!supportsUserTiming) { 10725 return; 10726 } 10727 10728 effectCountInCurrentCommit = 0; 10729 beginMark('(Calling Lifecycle Methods)'); 10730 } 10731 } 10732 function stopCommitLifeCyclesTimer() { 10733 { 10734 if (!supportsUserTiming) { 10735 return; 10736 } 10737 10738 var count = effectCountInCurrentCommit; 10739 effectCountInCurrentCommit = 0; 10740 endMark("(Calling Lifecycle Methods: " + count + " Total)", '(Calling Lifecycle Methods)', null); 10741 } 10742 } 10743 10744 var valueStack = []; 10745 var fiberStack; 10746 10747 { 10748 fiberStack = []; 10749 } 10750 10751 var index = -1; 10752 10753 function createCursor(defaultValue) { 10754 return { 10755 current: defaultValue 10756 }; 10757 } 10758 10759 function pop(cursor, fiber) { 10760 if (index < 0) { 10761 { 10762 error('Unexpected pop.'); 10763 } 10764 10765 return; 10766 } 10767 10768 { 10769 if (fiber !== fiberStack[index]) { 10770 error('Unexpected Fiber popped.'); 10771 } 10772 } 10773 10774 cursor.current = valueStack[index]; 10775 valueStack[index] = null; 10776 10777 { 10778 fiberStack[index] = null; 10779 } 10780 10781 index--; 10782 } 10783 10784 function push(cursor, value, fiber) { 10785 index++; 10786 valueStack[index] = cursor.current; 10787 10788 { 10789 fiberStack[index] = fiber; 10790 } 10791 10792 cursor.current = value; 10793 } 10794 10795 var warnedAboutMissingGetChildContext; 10796 10797 { 10798 warnedAboutMissingGetChildContext = {}; 10799 } 10800 10801 var emptyContextObject = {}; 10802 10803 { 10804 Object.freeze(emptyContextObject); 10805 } // A cursor to the current merged context object on the stack. 10806 10807 10808 var contextStackCursor = createCursor(emptyContextObject); // A cursor to a boolean indicating whether the context has changed. 10809 10810 var didPerformWorkStackCursor = createCursor(false); // Keep track of the previous context object that was on the stack. 10811 // We use this to get access to the parent context after we have already 10812 // pushed the next context provider, and now need to merge their contexts. 10813 10814 var previousContext = emptyContextObject; 10815 10816 function getUnmaskedContext(workInProgress, Component, didPushOwnContextIfProvider) { 10817 { 10818 if (didPushOwnContextIfProvider && isContextProvider(Component)) { 10819 // If the fiber is a context provider itself, when we read its context 10820 // we may have already pushed its own child context on the stack. A context 10821 // provider should not "see" its own child context. Therefore we read the 10822 // previous (parent) context instead for a context provider. 10823 return previousContext; 10824 } 10825 10826 return contextStackCursor.current; 10827 } 10828 } 10829 10830 function cacheContext(workInProgress, unmaskedContext, maskedContext) { 10831 { 10832 var instance = workInProgress.stateNode; 10833 instance.__reactInternalMemoizedUnmaskedChildContext = unmaskedContext; 10834 instance.__reactInternalMemoizedMaskedChildContext = maskedContext; 10835 } 10836 } 10837 10838 function getMaskedContext(workInProgress, unmaskedContext) { 10839 { 10840 var type = workInProgress.type; 10841 var contextTypes = type.contextTypes; 10842 10843 if (!contextTypes) { 10844 return emptyContextObject; 10845 } // Avoid recreating masked context unless unmasked context has changed. 10846 // Failing to do this will result in unnecessary calls to componentWillReceiveProps. 10847 // This may trigger infinite loops if componentWillReceiveProps calls setState. 10848 10849 10850 var instance = workInProgress.stateNode; 10851 10852 if (instance && instance.__reactInternalMemoizedUnmaskedChildContext === unmaskedContext) { 10853 return instance.__reactInternalMemoizedMaskedChildContext; 10854 } 10855 10856 var context = {}; 10857 10858 for (var key in contextTypes) { 10859 context[key] = unmaskedContext[key]; 10860 } 10861 10862 { 10863 var name = getComponentName(type) || 'Unknown'; 10864 checkPropTypes_1(contextTypes, context, 'context', name, getCurrentFiberStackInDev); 10865 } // Cache unmasked context so we can avoid recreating masked context unless necessary. 10866 // Context is created before the class component is instantiated so check for instance. 10867 10868 10869 if (instance) { 10870 cacheContext(workInProgress, unmaskedContext, context); 10871 } 10872 10873 return context; 10874 } 10875 } 10876 10877 function hasContextChanged() { 10878 { 10879 return didPerformWorkStackCursor.current; 10880 } 10881 } 10882 10883 function isContextProvider(type) { 10884 { 10885 var childContextTypes = type.childContextTypes; 10886 return childContextTypes !== null && childContextTypes !== undefined; 10887 } 10888 } 10889 10890 function popContext(fiber) { 10891 { 10892 pop(didPerformWorkStackCursor, fiber); 10893 pop(contextStackCursor, fiber); 10894 } 10895 } 10896 10897 function popTopLevelContextObject(fiber) { 10898 { 10899 pop(didPerformWorkStackCursor, fiber); 10900 pop(contextStackCursor, fiber); 10901 } 10902 } 10903 10904 function pushTopLevelContextObject(fiber, context, didChange) { 10905 { 10906 if (!(contextStackCursor.current === emptyContextObject)) { 10907 { 10908 throw Error( "Unexpected context found on stack. This error is likely caused by a bug in React. Please file an issue." ); 10909 } 10910 } 10911 10912 push(contextStackCursor, context, fiber); 10913 push(didPerformWorkStackCursor, didChange, fiber); 10914 } 10915 } 10916 10917 function processChildContext(fiber, type, parentContext) { 10918 { 10919 var instance = fiber.stateNode; 10920 var childContextTypes = type.childContextTypes; // TODO (bvaughn) Replace this behavior with an invariant() in the future. 10921 // It has only been added in Fiber to match the (unintentional) behavior in Stack. 10922 10923 if (typeof instance.getChildContext !== 'function') { 10924 { 10925 var componentName = getComponentName(type) || 'Unknown'; 10926 10927 if (!warnedAboutMissingGetChildContext[componentName]) { 10928 warnedAboutMissingGetChildContext[componentName] = true; 10929 10930 error('%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); 10931 } 10932 } 10933 10934 return parentContext; 10935 } 10936 10937 var childContext; 10938 startPhaseTimer(fiber, 'getChildContext'); 10939 childContext = instance.getChildContext(); 10940 stopPhaseTimer(); 10941 10942 for (var contextKey in childContext) { 10943 if (!(contextKey in childContextTypes)) { 10944 { 10945 throw Error( (getComponentName(type) || 'Unknown') + ".getChildContext(): key \"" + contextKey + "\" is not defined in childContextTypes." ); 10946 } 10947 } 10948 } 10949 10950 { 10951 var name = getComponentName(type) || 'Unknown'; 10952 checkPropTypes_1(childContextTypes, childContext, 'child context', name, // In practice, there is one case in which we won't get a stack. It's when 10953 // somebody calls unstable_renderSubtreeIntoContainer() and we process 10954 // context from the parent component instance. The stack will be missing 10955 // because it's outside of the reconciliation, and so the pointer has not 10956 // been set. This is rare and doesn't matter. We'll also remove that API. 10957 getCurrentFiberStackInDev); 10958 } 10959 10960 return _assign({}, parentContext, {}, childContext); 10961 } 10962 } 10963 10964 function pushContextProvider(workInProgress) { 10965 { 10966 var instance = workInProgress.stateNode; // We push the context as early as possible to ensure stack integrity. 10967 // If the instance does not exist yet, we will push null at first, 10968 // and replace it on the stack later when invalidating the context. 10969 10970 var memoizedMergedChildContext = instance && instance.__reactInternalMemoizedMergedChildContext || emptyContextObject; // Remember the parent context so we can merge with it later. 10971 // Inherit the parent's did-perform-work value to avoid inadvertently blocking updates. 10972 10973 previousContext = contextStackCursor.current; 10974 push(contextStackCursor, memoizedMergedChildContext, workInProgress); 10975 push(didPerformWorkStackCursor, didPerformWorkStackCursor.current, workInProgress); 10976 return true; 10977 } 10978 } 10979 10980 function invalidateContextProvider(workInProgress, type, didChange) { 10981 { 10982 var instance = workInProgress.stateNode; 10983 10984 if (!instance) { 10985 { 10986 throw Error( "Expected to have an instance by this point. This error is likely caused by a bug in React. Please file an issue." ); 10987 } 10988 } 10989 10990 if (didChange) { 10991 // Merge parent and own context. 10992 // Skip this if we're not updating due to sCU. 10993 // This avoids unnecessarily recomputing memoized values. 10994 var mergedContext = processChildContext(workInProgress, type, previousContext); 10995 instance.__reactInternalMemoizedMergedChildContext = mergedContext; // Replace the old (or empty) context with the new one. 10996 // It is important to unwind the context in the reverse order. 10997 10998 pop(didPerformWorkStackCursor, workInProgress); 10999 pop(contextStackCursor, workInProgress); // Now push the new context and mark that it has changed. 11000 11001 push(contextStackCursor, mergedContext, workInProgress); 11002 push(didPerformWorkStackCursor, didChange, workInProgress); 11003 } else { 11004 pop(didPerformWorkStackCursor, workInProgress); 11005 push(didPerformWorkStackCursor, didChange, workInProgress); 11006 } 11007 } 11008 } 11009 11010 function findCurrentUnmaskedContext(fiber) { 11011 { 11012 // Currently this is only used with renderSubtreeIntoContainer; not sure if it 11013 // makes sense elsewhere 11014 if (!(isFiberMounted(fiber) && fiber.tag === ClassComponent)) { 11015 { 11016 throw Error( "Expected subtree parent to be a mounted class component. This error is likely caused by a bug in React. Please file an issue." ); 11017 } 11018 } 11019 11020 var node = fiber; 11021 11022 do { 11023 switch (node.tag) { 11024 case HostRoot: 11025 return node.stateNode.context; 11026 11027 case ClassComponent: 11028 { 11029 var Component = node.type; 11030 11031 if (isContextProvider(Component)) { 11032 return node.stateNode.__reactInternalMemoizedMergedChildContext; 11033 } 11034 11035 break; 11036 } 11037 } 11038 11039 node = node.return; 11040 } while (node !== null); 11041 11042 { 11043 { 11044 throw Error( "Found unexpected detached subtree parent. This error is likely caused by a bug in React. Please file an issue." ); 11045 } 11046 } 11047 } 11048 } 11049 11050 var LegacyRoot = 0; 11051 var BlockingRoot = 1; 11052 var ConcurrentRoot = 2; 11053 11054 var ReactInternals$2 = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; 11055 var _ReactInternals$Sched$1 = ReactInternals$2.SchedulerTracing, 11056 __interactionsRef = _ReactInternals$Sched$1.__interactionsRef, 11057 __subscriberRef = _ReactInternals$Sched$1.__subscriberRef, 11058 unstable_clear = _ReactInternals$Sched$1.unstable_clear, 11059 unstable_getCurrent = _ReactInternals$Sched$1.unstable_getCurrent, 11060 unstable_getThreadID = _ReactInternals$Sched$1.unstable_getThreadID, 11061 unstable_subscribe = _ReactInternals$Sched$1.unstable_subscribe, 11062 unstable_trace = _ReactInternals$Sched$1.unstable_trace, 11063 unstable_unsubscribe = _ReactInternals$Sched$1.unstable_unsubscribe, 11064 unstable_wrap = _ReactInternals$Sched$1.unstable_wrap; 11065 11066 var Scheduler_runWithPriority = unstable_runWithPriority, 11067 Scheduler_scheduleCallback = unstable_scheduleCallback, 11068 Scheduler_cancelCallback = unstable_cancelCallback, 11069 Scheduler_shouldYield = unstable_shouldYield, 11070 Scheduler_requestPaint = unstable_requestPaint, 11071 Scheduler_now = unstable_now, 11072 Scheduler_getCurrentPriorityLevel = unstable_getCurrentPriorityLevel, 11073 Scheduler_ImmediatePriority = unstable_ImmediatePriority, 11074 Scheduler_UserBlockingPriority = unstable_UserBlockingPriority, 11075 Scheduler_NormalPriority = unstable_NormalPriority, 11076 Scheduler_LowPriority = unstable_LowPriority, 11077 Scheduler_IdlePriority = unstable_IdlePriority; 11078 11079 { 11080 // Provide explicit error message when production+profiling bundle of e.g. 11081 // react-dom is used with production (non-profiling) bundle of 11082 // scheduler/tracing 11083 if (!(__interactionsRef != null && __interactionsRef.current != null)) { 11084 { 11085 throw Error( "It is not supported to run the profiling version of a renderer (for example, `react-dom/profiling`) without also replacing the `scheduler/tracing` module with `scheduler/tracing-profiling`. Your bundler might have a setting for aliasing both modules. Learn more at http://fb.me/react-profiling" ); 11086 } 11087 } 11088 } 11089 11090 var fakeCallbackNode = {}; // Except for NoPriority, these correspond to Scheduler priorities. We use 11091 // ascending numbers so we can compare them like numbers. They start at 90 to 11092 // avoid clashing with Scheduler's priorities. 11093 11094 var ImmediatePriority = 99; 11095 var UserBlockingPriority$1 = 98; 11096 var NormalPriority = 97; 11097 var LowPriority = 96; 11098 var IdlePriority = 95; // NoPriority is the absence of priority. Also React-only. 11099 11100 var NoPriority = 90; 11101 var shouldYield = Scheduler_shouldYield; 11102 var requestPaint = // Fall back gracefully if we're running an older version of Scheduler. 11103 Scheduler_requestPaint !== undefined ? Scheduler_requestPaint : function () {}; 11104 var syncQueue = null; 11105 var immediateQueueCallbackNode = null; 11106 var isFlushingSyncQueue = false; 11107 var initialTimeMs = Scheduler_now(); // If the initial timestamp is reasonably small, use Scheduler's `now` directly. 11108 // This will be the case for modern browsers that support `performance.now`. In 11109 // older browsers, Scheduler falls back to `Date.now`, which returns a Unix 11110 // timestamp. In that case, subtract the module initialization time to simulate 11111 // the behavior of performance.now and keep our times small enough to fit 11112 // within 32 bits. 11113 // TODO: Consider lifting this into Scheduler. 11114 11115 var now = initialTimeMs < 10000 ? Scheduler_now : function () { 11116 return Scheduler_now() - initialTimeMs; 11117 }; 11118 function getCurrentPriorityLevel() { 11119 switch (Scheduler_getCurrentPriorityLevel()) { 11120 case Scheduler_ImmediatePriority: 11121 return ImmediatePriority; 11122 11123 case Scheduler_UserBlockingPriority: 11124 return UserBlockingPriority$1; 11125 11126 case Scheduler_NormalPriority: 11127 return NormalPriority; 11128 11129 case Scheduler_LowPriority: 11130 return LowPriority; 11131 11132 case Scheduler_IdlePriority: 11133 return IdlePriority; 11134 11135 default: 11136 { 11137 { 11138 throw Error( "Unknown priority level." ); 11139 } 11140 } 11141 11142 } 11143 } 11144 11145 function reactPriorityToSchedulerPriority(reactPriorityLevel) { 11146 switch (reactPriorityLevel) { 11147 case ImmediatePriority: 11148 return Scheduler_ImmediatePriority; 11149 11150 case UserBlockingPriority$1: 11151 return Scheduler_UserBlockingPriority; 11152 11153 case NormalPriority: 11154 return Scheduler_NormalPriority; 11155 11156 case LowPriority: 11157 return Scheduler_LowPriority; 11158 11159 case IdlePriority: 11160 return Scheduler_IdlePriority; 11161 11162 default: 11163 { 11164 { 11165 throw Error( "Unknown priority level." ); 11166 } 11167 } 11168 11169 } 11170 } 11171 11172 function runWithPriority$1(reactPriorityLevel, fn) { 11173 var priorityLevel = reactPriorityToSchedulerPriority(reactPriorityLevel); 11174 return Scheduler_runWithPriority(priorityLevel, fn); 11175 } 11176 function scheduleCallback(reactPriorityLevel, callback, options) { 11177 var priorityLevel = reactPriorityToSchedulerPriority(reactPriorityLevel); 11178 return Scheduler_scheduleCallback(priorityLevel, callback, options); 11179 } 11180 function scheduleSyncCallback(callback) { 11181 // Push this callback into an internal queue. We'll flush these either in 11182 // the next tick, or earlier if something calls `flushSyncCallbackQueue`. 11183 if (syncQueue === null) { 11184 syncQueue = [callback]; // Flush the queue in the next tick, at the earliest. 11185 11186 immediateQueueCallbackNode = Scheduler_scheduleCallback(Scheduler_ImmediatePriority, flushSyncCallbackQueueImpl); 11187 } else { 11188 // Push onto existing queue. Don't need to schedule a callback because 11189 // we already scheduled one when we created the queue. 11190 syncQueue.push(callback); 11191 } 11192 11193 return fakeCallbackNode; 11194 } 11195 function cancelCallback(callbackNode) { 11196 if (callbackNode !== fakeCallbackNode) { 11197 Scheduler_cancelCallback(callbackNode); 11198 } 11199 } 11200 function flushSyncCallbackQueue() { 11201 if (immediateQueueCallbackNode !== null) { 11202 var node = immediateQueueCallbackNode; 11203 immediateQueueCallbackNode = null; 11204 Scheduler_cancelCallback(node); 11205 } 11206 11207 flushSyncCallbackQueueImpl(); 11208 } 11209 11210 function flushSyncCallbackQueueImpl() { 11211 if (!isFlushingSyncQueue && syncQueue !== null) { 11212 // Prevent re-entrancy. 11213 isFlushingSyncQueue = true; 11214 var i = 0; 11215 11216 try { 11217 var _isSync = true; 11218 var queue = syncQueue; 11219 runWithPriority$1(ImmediatePriority, function () { 11220 for (; i < queue.length; i++) { 11221 var callback = queue[i]; 11222 11223 do { 11224 callback = callback(_isSync); 11225 } while (callback !== null); 11226 } 11227 }); 11228 syncQueue = null; 11229 } catch (error) { 11230 // If something throws, leave the remaining callbacks on the queue. 11231 if (syncQueue !== null) { 11232 syncQueue = syncQueue.slice(i + 1); 11233 } // Resume flushing in the next tick 11234 11235 11236 Scheduler_scheduleCallback(Scheduler_ImmediatePriority, flushSyncCallbackQueue); 11237 throw error; 11238 } finally { 11239 isFlushingSyncQueue = false; 11240 } 11241 } 11242 } 11243 11244 var NoMode = 0; 11245 var StrictMode = 1; // TODO: Remove BlockingMode and ConcurrentMode by reading from the root 11246 // tag instead 11247 11248 var BlockingMode = 2; 11249 var ConcurrentMode = 4; 11250 var ProfileMode = 8; 11251 11252 // Max 31 bit integer. The max integer size in V8 for 32-bit systems. 11253 // Math.pow(2, 30) - 1 11254 // 0b111111111111111111111111111111 11255 var MAX_SIGNED_31_BIT_INT = 1073741823; 11256 11257 var NoWork = 0; // TODO: Think of a better name for Never. The key difference with Idle is that 11258 // Never work can be committed in an inconsistent state without tearing the UI. 11259 // The main example is offscreen content, like a hidden subtree. So one possible 11260 // name is Offscreen. However, it also includes dehydrated Suspense boundaries, 11261 // which are inconsistent in the sense that they haven't finished yet, but 11262 // aren't visibly inconsistent because the server rendered HTML matches what the 11263 // hydrated tree would look like. 11264 11265 var Never = 1; // Idle is slightly higher priority than Never. It must completely finish in 11266 // order to be consistent. 11267 11268 var Idle = 2; // Continuous Hydration is slightly higher than Idle and is used to increase 11269 // priority of hover targets. 11270 11271 var ContinuousHydration = 3; 11272 var Sync = MAX_SIGNED_31_BIT_INT; 11273 var Batched = Sync - 1; 11274 var UNIT_SIZE = 10; 11275 var MAGIC_NUMBER_OFFSET = Batched - 1; // 1 unit of expiration time represents 10ms. 11276 11277 function msToExpirationTime(ms) { 11278 // Always subtract from the offset so that we don't clash with the magic number for NoWork. 11279 return MAGIC_NUMBER_OFFSET - (ms / UNIT_SIZE | 0); 11280 } 11281 function expirationTimeToMs(expirationTime) { 11282 return (MAGIC_NUMBER_OFFSET - expirationTime) * UNIT_SIZE; 11283 } 11284 11285 function ceiling(num, precision) { 11286 return ((num / precision | 0) + 1) * precision; 11287 } 11288 11289 function computeExpirationBucket(currentTime, expirationInMs, bucketSizeMs) { 11290 return MAGIC_NUMBER_OFFSET - ceiling(MAGIC_NUMBER_OFFSET - currentTime + expirationInMs / UNIT_SIZE, bucketSizeMs / UNIT_SIZE); 11291 } // TODO: This corresponds to Scheduler's NormalPriority, not LowPriority. Update 11292 // the names to reflect. 11293 11294 11295 var LOW_PRIORITY_EXPIRATION = 5000; 11296 var LOW_PRIORITY_BATCH_SIZE = 250; 11297 function computeAsyncExpiration(currentTime) { 11298 return computeExpirationBucket(currentTime, LOW_PRIORITY_EXPIRATION, LOW_PRIORITY_BATCH_SIZE); 11299 } 11300 function computeSuspenseExpiration(currentTime, timeoutMs) { 11301 // TODO: Should we warn if timeoutMs is lower than the normal pri expiration time? 11302 return computeExpirationBucket(currentTime, timeoutMs, LOW_PRIORITY_BATCH_SIZE); 11303 } // We intentionally set a higher expiration time for interactive updates in 11304 // dev than in production. 11305 // 11306 // If the main thread is being blocked so long that you hit the expiration, 11307 // it's a problem that could be solved with better scheduling. 11308 // 11309 // People will be more likely to notice this and fix it with the long 11310 // expiration time in development. 11311 // 11312 // In production we opt for better UX at the risk of masking scheduling 11313 // problems, by expiring fast. 11314 11315 var HIGH_PRIORITY_EXPIRATION = 500 ; 11316 var HIGH_PRIORITY_BATCH_SIZE = 100; 11317 function computeInteractiveExpiration(currentTime) { 11318 return computeExpirationBucket(currentTime, HIGH_PRIORITY_EXPIRATION, HIGH_PRIORITY_BATCH_SIZE); 11319 } 11320 function inferPriorityFromExpirationTime(currentTime, expirationTime) { 11321 if (expirationTime === Sync) { 11322 return ImmediatePriority; 11323 } 11324 11325 if (expirationTime === Never || expirationTime === Idle) { 11326 return IdlePriority; 11327 } 11328 11329 var msUntil = expirationTimeToMs(expirationTime) - expirationTimeToMs(currentTime); 11330 11331 if (msUntil <= 0) { 11332 return ImmediatePriority; 11333 } 11334 11335 if (msUntil <= HIGH_PRIORITY_EXPIRATION + HIGH_PRIORITY_BATCH_SIZE) { 11336 return UserBlockingPriority$1; 11337 } 11338 11339 if (msUntil <= LOW_PRIORITY_EXPIRATION + LOW_PRIORITY_BATCH_SIZE) { 11340 return NormalPriority; 11341 } // TODO: Handle LowPriority 11342 // Assume anything lower has idle priority 11343 11344 11345 return IdlePriority; 11346 } 11347 11348 var ReactStrictModeWarnings = { 11349 recordUnsafeLifecycleWarnings: function (fiber, instance) {}, 11350 flushPendingUnsafeLifecycleWarnings: function () {}, 11351 recordLegacyContextWarning: function (fiber, instance) {}, 11352 flushLegacyContextWarning: function () {}, 11353 discardPendingWarnings: function () {} 11354 }; 11355 11356 { 11357 var findStrictRoot = function (fiber) { 11358 var maybeStrictRoot = null; 11359 var node = fiber; 11360 11361 while (node !== null) { 11362 if (node.mode & StrictMode) { 11363 maybeStrictRoot = node; 11364 } 11365 11366 node = node.return; 11367 } 11368 11369 return maybeStrictRoot; 11370 }; 11371 11372 var setToSortedString = function (set) { 11373 var array = []; 11374 set.forEach(function (value) { 11375 array.push(value); 11376 }); 11377 return array.sort().join(', '); 11378 }; 11379 11380 var pendingComponentWillMountWarnings = []; 11381 var pendingUNSAFE_ComponentWillMountWarnings = []; 11382 var pendingComponentWillReceivePropsWarnings = []; 11383 var pendingUNSAFE_ComponentWillReceivePropsWarnings = []; 11384 var pendingComponentWillUpdateWarnings = []; 11385 var pendingUNSAFE_ComponentWillUpdateWarnings = []; // Tracks components we have already warned about. 11386 11387 var didWarnAboutUnsafeLifecycles = new Set(); 11388 11389 ReactStrictModeWarnings.recordUnsafeLifecycleWarnings = function (fiber, instance) { 11390 // Dedup strategy: Warn once per component. 11391 if (didWarnAboutUnsafeLifecycles.has(fiber.type)) { 11392 return; 11393 } 11394 11395 if (typeof instance.componentWillMount === 'function' && // Don't warn about react-lifecycles-compat polyfilled components. 11396 instance.componentWillMount.__suppressDeprecationWarning !== true) { 11397 pendingComponentWillMountWarnings.push(fiber); 11398 } 11399 11400 if (fiber.mode & StrictMode && typeof instance.UNSAFE_componentWillMount === 'function') { 11401 pendingUNSAFE_ComponentWillMountWarnings.push(fiber); 11402 } 11403 11404 if (typeof instance.componentWillReceiveProps === 'function' && instance.componentWillReceiveProps.__suppressDeprecationWarning !== true) { 11405 pendingComponentWillReceivePropsWarnings.push(fiber); 11406 } 11407 11408 if (fiber.mode & StrictMode && typeof instance.UNSAFE_componentWillReceiveProps === 'function') { 11409 pendingUNSAFE_ComponentWillReceivePropsWarnings.push(fiber); 11410 } 11411 11412 if (typeof instance.componentWillUpdate === 'function' && instance.componentWillUpdate.__suppressDeprecationWarning !== true) { 11413 pendingComponentWillUpdateWarnings.push(fiber); 11414 } 11415 11416 if (fiber.mode & StrictMode && typeof instance.UNSAFE_componentWillUpdate === 'function') { 11417 pendingUNSAFE_ComponentWillUpdateWarnings.push(fiber); 11418 } 11419 }; 11420 11421 ReactStrictModeWarnings.flushPendingUnsafeLifecycleWarnings = function () { 11422 // We do an initial pass to gather component names 11423 var componentWillMountUniqueNames = new Set(); 11424 11425 if (pendingComponentWillMountWarnings.length > 0) { 11426 pendingComponentWillMountWarnings.forEach(function (fiber) { 11427 componentWillMountUniqueNames.add(getComponentName(fiber.type) || 'Component'); 11428 didWarnAboutUnsafeLifecycles.add(fiber.type); 11429 }); 11430 pendingComponentWillMountWarnings = []; 11431 } 11432 11433 var UNSAFE_componentWillMountUniqueNames = new Set(); 11434 11435 if (pendingUNSAFE_ComponentWillMountWarnings.length > 0) { 11436 pendingUNSAFE_ComponentWillMountWarnings.forEach(function (fiber) { 11437 UNSAFE_componentWillMountUniqueNames.add(getComponentName(fiber.type) || 'Component'); 11438 didWarnAboutUnsafeLifecycles.add(fiber.type); 11439 }); 11440 pendingUNSAFE_ComponentWillMountWarnings = []; 11441 } 11442 11443 var componentWillReceivePropsUniqueNames = new Set(); 11444 11445 if (pendingComponentWillReceivePropsWarnings.length > 0) { 11446 pendingComponentWillReceivePropsWarnings.forEach(function (fiber) { 11447 componentWillReceivePropsUniqueNames.add(getComponentName(fiber.type) || 'Component'); 11448 didWarnAboutUnsafeLifecycles.add(fiber.type); 11449 }); 11450 pendingComponentWillReceivePropsWarnings = []; 11451 } 11452 11453 var UNSAFE_componentWillReceivePropsUniqueNames = new Set(); 11454 11455 if (pendingUNSAFE_ComponentWillReceivePropsWarnings.length > 0) { 11456 pendingUNSAFE_ComponentWillReceivePropsWarnings.forEach(function (fiber) { 11457 UNSAFE_componentWillReceivePropsUniqueNames.add(getComponentName(fiber.type) || 'Component'); 11458 didWarnAboutUnsafeLifecycles.add(fiber.type); 11459 }); 11460 pendingUNSAFE_ComponentWillReceivePropsWarnings = []; 11461 } 11462 11463 var componentWillUpdateUniqueNames = new Set(); 11464 11465 if (pendingComponentWillUpdateWarnings.length > 0) { 11466 pendingComponentWillUpdateWarnings.forEach(function (fiber) { 11467 componentWillUpdateUniqueNames.add(getComponentName(fiber.type) || 'Component'); 11468 didWarnAboutUnsafeLifecycles.add(fiber.type); 11469 }); 11470 pendingComponentWillUpdateWarnings = []; 11471 } 11472 11473 var UNSAFE_componentWillUpdateUniqueNames = new Set(); 11474 11475 if (pendingUNSAFE_ComponentWillUpdateWarnings.length > 0) { 11476 pendingUNSAFE_ComponentWillUpdateWarnings.forEach(function (fiber) { 11477 UNSAFE_componentWillUpdateUniqueNames.add(getComponentName(fiber.type) || 'Component'); 11478 didWarnAboutUnsafeLifecycles.add(fiber.type); 11479 }); 11480 pendingUNSAFE_ComponentWillUpdateWarnings = []; 11481 } // Finally, we flush all the warnings 11482 // UNSAFE_ ones before the deprecated ones, since they'll be 'louder' 11483 11484 11485 if (UNSAFE_componentWillMountUniqueNames.size > 0) { 11486 var sortedNames = setToSortedString(UNSAFE_componentWillMountUniqueNames); 11487 11488 error('Using UNSAFE_componentWillMount in strict mode is not recommended and may indicate bugs in your code. ' + 'See https://fb.me/react-unsafe-component-lifecycles for details.\n\n' + '* Move code with side effects to componentDidMount, and set initial state in the constructor.\n' + '\nPlease update the following components: %s', sortedNames); 11489 } 11490 11491 if (UNSAFE_componentWillReceivePropsUniqueNames.size > 0) { 11492 var _sortedNames = setToSortedString(UNSAFE_componentWillReceivePropsUniqueNames); 11493 11494 error('Using UNSAFE_componentWillReceiveProps in strict mode is not recommended ' + 'and may indicate bugs in your code. ' + 'See https://fb.me/react-unsafe-component-lifecycles for details.\n\n' + '* Move data fetching code or side effects to componentDidUpdate.\n' + "* If you're updating state whenever props change, " + 'refactor your code to use memoization techniques or move it to ' + 'static getDerivedStateFromProps. Learn more at: https://fb.me/react-derived-state\n' + '\nPlease update the following components: %s', _sortedNames); 11495 } 11496 11497 if (UNSAFE_componentWillUpdateUniqueNames.size > 0) { 11498 var _sortedNames2 = setToSortedString(UNSAFE_componentWillUpdateUniqueNames); 11499 11500 error('Using UNSAFE_componentWillUpdate in strict mode is not recommended ' + 'and may indicate bugs in your code. ' + 'See https://fb.me/react-unsafe-component-lifecycles for details.\n\n' + '* Move data fetching code or side effects to componentDidUpdate.\n' + '\nPlease update the following components: %s', _sortedNames2); 11501 } 11502 11503 if (componentWillMountUniqueNames.size > 0) { 11504 var _sortedNames3 = setToSortedString(componentWillMountUniqueNames); 11505 11506 warn('componentWillMount has been renamed, and is not recommended for use. ' + 'See https://fb.me/react-unsafe-component-lifecycles for details.\n\n' + '* Move code with side effects to componentDidMount, and set initial state in the constructor.\n' + '* Rename componentWillMount to UNSAFE_componentWillMount to suppress ' + 'this warning in non-strict mode. In React 17.x, only the UNSAFE_ name will work. ' + 'To rename all deprecated lifecycles to their new names, you can run ' + '`npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n' + '\nPlease update the following components: %s', _sortedNames3); 11507 } 11508 11509 if (componentWillReceivePropsUniqueNames.size > 0) { 11510 var _sortedNames4 = setToSortedString(componentWillReceivePropsUniqueNames); 11511 11512 warn('componentWillReceiveProps has been renamed, and is not recommended for use. ' + 'See https://fb.me/react-unsafe-component-lifecycles for details.\n\n' + '* Move data fetching code or side effects to componentDidUpdate.\n' + "* If you're updating state whenever props change, refactor your " + 'code to use memoization techniques or move it to ' + 'static getDerivedStateFromProps. Learn more at: https://fb.me/react-derived-state\n' + '* Rename componentWillReceiveProps to UNSAFE_componentWillReceiveProps to suppress ' + 'this warning in non-strict mode. In React 17.x, only the UNSAFE_ name will work. ' + 'To rename all deprecated lifecycles to their new names, you can run ' + '`npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n' + '\nPlease update the following components: %s', _sortedNames4); 11513 } 11514 11515 if (componentWillUpdateUniqueNames.size > 0) { 11516 var _sortedNames5 = setToSortedString(componentWillUpdateUniqueNames); 11517 11518 warn('componentWillUpdate has been renamed, and is not recommended for use. ' + 'See https://fb.me/react-unsafe-component-lifecycles for details.\n\n' + '* Move data fetching code or side effects to componentDidUpdate.\n' + '* Rename componentWillUpdate to UNSAFE_componentWillUpdate to suppress ' + 'this warning in non-strict mode. In React 17.x, only the UNSAFE_ name will work. ' + 'To rename all deprecated lifecycles to their new names, you can run ' + '`npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n' + '\nPlease update the following components: %s', _sortedNames5); 11519 } 11520 }; 11521 11522 var pendingLegacyContextWarning = new Map(); // Tracks components we have already warned about. 11523 11524 var didWarnAboutLegacyContext = new Set(); 11525 11526 ReactStrictModeWarnings.recordLegacyContextWarning = function (fiber, instance) { 11527 var strictRoot = findStrictRoot(fiber); 11528 11529 if (strictRoot === null) { 11530 error('Expected to find a StrictMode component in a strict mode tree. ' + 'This error is likely caused by a bug in React. Please file an issue.'); 11531 11532 return; 11533 } // Dedup strategy: Warn once per component. 11534 11535 11536 if (didWarnAboutLegacyContext.has(fiber.type)) { 11537 return; 11538 } 11539 11540 var warningsForRoot = pendingLegacyContextWarning.get(strictRoot); 11541 11542 if (fiber.type.contextTypes != null || fiber.type.childContextTypes != null || instance !== null && typeof instance.getChildContext === 'function') { 11543 if (warningsForRoot === undefined) { 11544 warningsForRoot = []; 11545 pendingLegacyContextWarning.set(strictRoot, warningsForRoot); 11546 } 11547 11548 warningsForRoot.push(fiber); 11549 } 11550 }; 11551 11552 ReactStrictModeWarnings.flushLegacyContextWarning = function () { 11553 pendingLegacyContextWarning.forEach(function (fiberArray, strictRoot) { 11554 if (fiberArray.length === 0) { 11555 return; 11556 } 11557 11558 var firstFiber = fiberArray[0]; 11559 var uniqueNames = new Set(); 11560 fiberArray.forEach(function (fiber) { 11561 uniqueNames.add(getComponentName(fiber.type) || 'Component'); 11562 didWarnAboutLegacyContext.add(fiber.type); 11563 }); 11564 var sortedNames = setToSortedString(uniqueNames); 11565 var firstComponentStack = getStackByFiberInDevAndProd(firstFiber); 11566 11567 error('Legacy context API has been detected within a strict-mode tree.' + '\n\nThe old API will be supported in all 16.x releases, but applications ' + 'using it should migrate to the new version.' + '\n\nPlease update the following components: %s' + '\n\nLearn more about this warning here: https://fb.me/react-legacy-context' + '%s', sortedNames, firstComponentStack); 11568 }); 11569 }; 11570 11571 ReactStrictModeWarnings.discardPendingWarnings = function () { 11572 pendingComponentWillMountWarnings = []; 11573 pendingUNSAFE_ComponentWillMountWarnings = []; 11574 pendingComponentWillReceivePropsWarnings = []; 11575 pendingUNSAFE_ComponentWillReceivePropsWarnings = []; 11576 pendingComponentWillUpdateWarnings = []; 11577 pendingUNSAFE_ComponentWillUpdateWarnings = []; 11578 pendingLegacyContextWarning = new Map(); 11579 }; 11580 } 11581 11582 var resolveFamily = null; // $FlowFixMe Flow gets confused by a WeakSet feature check below. 11583 11584 var failedBoundaries = null; 11585 var setRefreshHandler = function (handler) { 11586 { 11587 resolveFamily = handler; 11588 } 11589 }; 11590 function resolveFunctionForHotReloading(type) { 11591 { 11592 if (resolveFamily === null) { 11593 // Hot reloading is disabled. 11594 return type; 11595 } 11596 11597 var family = resolveFamily(type); 11598 11599 if (family === undefined) { 11600 return type; 11601 } // Use the latest known implementation. 11602 11603 11604 return family.current; 11605 } 11606 } 11607 function resolveClassForHotReloading(type) { 11608 // No implementation differences. 11609 return resolveFunctionForHotReloading(type); 11610 } 11611 function resolveForwardRefForHotReloading(type) { 11612 { 11613 if (resolveFamily === null) { 11614 // Hot reloading is disabled. 11615 return type; 11616 } 11617 11618 var family = resolveFamily(type); 11619 11620 if (family === undefined) { 11621 // Check if we're dealing with a real forwardRef. Don't want to crash early. 11622 if (type !== null && type !== undefined && typeof type.render === 'function') { 11623 // ForwardRef is special because its resolved .type is an object, 11624 // but it's possible that we only have its inner render function in the map. 11625 // If that inner render function is different, we'll build a new forwardRef type. 11626 var currentRender = resolveFunctionForHotReloading(type.render); 11627 11628 if (type.render !== currentRender) { 11629 var syntheticType = { 11630 $$typeof: REACT_FORWARD_REF_TYPE, 11631 render: currentRender 11632 }; 11633 11634 if (type.displayName !== undefined) { 11635 syntheticType.displayName = type.displayName; 11636 } 11637 11638 return syntheticType; 11639 } 11640 } 11641 11642 return type; 11643 } // Use the latest known implementation. 11644 11645 11646 return family.current; 11647 } 11648 } 11649 function isCompatibleFamilyForHotReloading(fiber, element) { 11650 { 11651 if (resolveFamily === null) { 11652 // Hot reloading is disabled. 11653 return false; 11654 } 11655 11656 var prevType = fiber.elementType; 11657 var nextType = element.type; // If we got here, we know types aren't === equal. 11658 11659 var needsCompareFamilies = false; 11660 var $$typeofNextType = typeof nextType === 'object' && nextType !== null ? nextType.$$typeof : null; 11661 11662 switch (fiber.tag) { 11663 case ClassComponent: 11664 { 11665 if (typeof nextType === 'function') { 11666 needsCompareFamilies = true; 11667 } 11668 11669 break; 11670 } 11671 11672 case FunctionComponent: 11673 { 11674 if (typeof nextType === 'function') { 11675 needsCompareFamilies = true; 11676 } else if ($$typeofNextType === REACT_LAZY_TYPE) { 11677 // We don't know the inner type yet. 11678 // We're going to assume that the lazy inner type is stable, 11679 // and so it is sufficient to avoid reconciling it away. 11680 // We're not going to unwrap or actually use the new lazy type. 11681 needsCompareFamilies = true; 11682 } 11683 11684 break; 11685 } 11686 11687 case ForwardRef: 11688 { 11689 if ($$typeofNextType === REACT_FORWARD_REF_TYPE) { 11690 needsCompareFamilies = true; 11691 } else if ($$typeofNextType === REACT_LAZY_TYPE) { 11692 needsCompareFamilies = true; 11693 } 11694 11695 break; 11696 } 11697 11698 case MemoComponent: 11699 case SimpleMemoComponent: 11700 { 11701 if ($$typeofNextType === REACT_MEMO_TYPE) { 11702 // TODO: if it was but can no longer be simple, 11703 // we shouldn't set this. 11704 needsCompareFamilies = true; 11705 } else if ($$typeofNextType === REACT_LAZY_TYPE) { 11706 needsCompareFamilies = true; 11707 } 11708 11709 break; 11710 } 11711 11712 default: 11713 return false; 11714 } // Check if both types have a family and it's the same one. 11715 11716 11717 if (needsCompareFamilies) { 11718 // Note: memo() and forwardRef() we'll compare outer rather than inner type. 11719 // This means both of them need to be registered to preserve state. 11720 // If we unwrapped and compared the inner types for wrappers instead, 11721 // then we would risk falsely saying two separate memo(Foo) 11722 // calls are equivalent because they wrap the same Foo function. 11723 var prevFamily = resolveFamily(prevType); 11724 11725 if (prevFamily !== undefined && prevFamily === resolveFamily(nextType)) { 11726 return true; 11727 } 11728 } 11729 11730 return false; 11731 } 11732 } 11733 function markFailedErrorBoundaryForHotReloading(fiber) { 11734 { 11735 if (resolveFamily === null) { 11736 // Hot reloading is disabled. 11737 return; 11738 } 11739 11740 if (typeof WeakSet !== 'function') { 11741 return; 11742 } 11743 11744 if (failedBoundaries === null) { 11745 failedBoundaries = new WeakSet(); 11746 } 11747 11748 failedBoundaries.add(fiber); 11749 } 11750 } 11751 var scheduleRefresh = function (root, update) { 11752 { 11753 if (resolveFamily === null) { 11754 // Hot reloading is disabled. 11755 return; 11756 } 11757 11758 var staleFamilies = update.staleFamilies, 11759 updatedFamilies = update.updatedFamilies; 11760 flushPassiveEffects(); 11761 flushSync(function () { 11762 scheduleFibersWithFamiliesRecursively(root.current, updatedFamilies, staleFamilies); 11763 }); 11764 } 11765 }; 11766 var scheduleRoot = function (root, element) { 11767 { 11768 if (root.context !== emptyContextObject) { 11769 // Super edge case: root has a legacy _renderSubtree context 11770 // but we don't know the parentComponent so we can't pass it. 11771 // Just ignore. We'll delete this with _renderSubtree code path later. 11772 return; 11773 } 11774 11775 flushPassiveEffects(); 11776 syncUpdates(function () { 11777 updateContainer(element, root, null, null); 11778 }); 11779 } 11780 }; 11781 11782 function scheduleFibersWithFamiliesRecursively(fiber, updatedFamilies, staleFamilies) { 11783 { 11784 var alternate = fiber.alternate, 11785 child = fiber.child, 11786 sibling = fiber.sibling, 11787 tag = fiber.tag, 11788 type = fiber.type; 11789 var candidateType = null; 11790 11791 switch (tag) { 11792 case FunctionComponent: 11793 case SimpleMemoComponent: 11794 case ClassComponent: 11795 candidateType = type; 11796 break; 11797 11798 case ForwardRef: 11799 candidateType = type.render; 11800 break; 11801 } 11802 11803 if (resolveFamily === null) { 11804 throw new Error('Expected resolveFamily to be set during hot reload.'); 11805 } 11806 11807 var needsRender = false; 11808 var needsRemount = false; 11809 11810 if (candidateType !== null) { 11811 var family = resolveFamily(candidateType); 11812 11813 if (family !== undefined) { 11814 if (staleFamilies.has(family)) { 11815 needsRemount = true; 11816 } else if (updatedFamilies.has(family)) { 11817 if (tag === ClassComponent) { 11818 needsRemount = true; 11819 } else { 11820 needsRender = true; 11821 } 11822 } 11823 } 11824 } 11825 11826 if (failedBoundaries !== null) { 11827 if (failedBoundaries.has(fiber) || alternate !== null && failedBoundaries.has(alternate)) { 11828 needsRemount = true; 11829 } 11830 } 11831 11832 if (needsRemount) { 11833 fiber._debugNeedsRemount = true; 11834 } 11835 11836 if (needsRemount || needsRender) { 11837 scheduleWork(fiber, Sync); 11838 } 11839 11840 if (child !== null && !needsRemount) { 11841 scheduleFibersWithFamiliesRecursively(child, updatedFamilies, staleFamilies); 11842 } 11843 11844 if (sibling !== null) { 11845 scheduleFibersWithFamiliesRecursively(sibling, updatedFamilies, staleFamilies); 11846 } 11847 } 11848 } 11849 11850 var findHostInstancesForRefresh = function (root, families) { 11851 { 11852 var hostInstances = new Set(); 11853 var types = new Set(families.map(function (family) { 11854 return family.current; 11855 })); 11856 findHostInstancesForMatchingFibersRecursively(root.current, types, hostInstances); 11857 return hostInstances; 11858 } 11859 }; 11860 11861 function findHostInstancesForMatchingFibersRecursively(fiber, types, hostInstances) { 11862 { 11863 var child = fiber.child, 11864 sibling = fiber.sibling, 11865 tag = fiber.tag, 11866 type = fiber.type; 11867 var candidateType = null; 11868 11869 switch (tag) { 11870 case FunctionComponent: 11871 case SimpleMemoComponent: 11872 case ClassComponent: 11873 candidateType = type; 11874 break; 11875 11876 case ForwardRef: 11877 candidateType = type.render; 11878 break; 11879 } 11880 11881 var didMatch = false; 11882 11883 if (candidateType !== null) { 11884 if (types.has(candidateType)) { 11885 didMatch = true; 11886 } 11887 } 11888 11889 if (didMatch) { 11890 // We have a match. This only drills down to the closest host components. 11891 // There's no need to search deeper because for the purpose of giving 11892 // visual feedback, "flashing" outermost parent rectangles is sufficient. 11893 findHostInstancesForFiberShallowly(fiber, hostInstances); 11894 } else { 11895 // If there's no match, maybe there will be one further down in the child tree. 11896 if (child !== null) { 11897 findHostInstancesForMatchingFibersRecursively(child, types, hostInstances); 11898 } 11899 } 11900 11901 if (sibling !== null) { 11902 findHostInstancesForMatchingFibersRecursively(sibling, types, hostInstances); 11903 } 11904 } 11905 } 11906 11907 function findHostInstancesForFiberShallowly(fiber, hostInstances) { 11908 { 11909 var foundHostInstances = findChildHostInstancesForFiberShallowly(fiber, hostInstances); 11910 11911 if (foundHostInstances) { 11912 return; 11913 } // If we didn't find any host children, fallback to closest host parent. 11914 11915 11916 var node = fiber; 11917 11918 while (true) { 11919 switch (node.tag) { 11920 case HostComponent: 11921 hostInstances.add(node.stateNode); 11922 return; 11923 11924 case HostPortal: 11925 hostInstances.add(node.stateNode.containerInfo); 11926 return; 11927 11928 case HostRoot: 11929 hostInstances.add(node.stateNode.containerInfo); 11930 return; 11931 } 11932 11933 if (node.return === null) { 11934 throw new Error('Expected to reach root first.'); 11935 } 11936 11937 node = node.return; 11938 } 11939 } 11940 } 11941 11942 function findChildHostInstancesForFiberShallowly(fiber, hostInstances) { 11943 { 11944 var node = fiber; 11945 var foundHostInstances = false; 11946 11947 while (true) { 11948 if (node.tag === HostComponent) { 11949 // We got a match. 11950 foundHostInstances = true; 11951 hostInstances.add(node.stateNode); // There may still be more, so keep searching. 11952 } else if (node.child !== null) { 11953 node.child.return = node; 11954 node = node.child; 11955 continue; 11956 } 11957 11958 if (node === fiber) { 11959 return foundHostInstances; 11960 } 11961 11962 while (node.sibling === null) { 11963 if (node.return === null || node.return === fiber) { 11964 return foundHostInstances; 11965 } 11966 11967 node = node.return; 11968 } 11969 11970 node.sibling.return = node.return; 11971 node = node.sibling; 11972 } 11973 } 11974 11975 return false; 11976 } 11977 11978 function resolveDefaultProps(Component, baseProps) { 11979 if (Component && Component.defaultProps) { 11980 // Resolve default props. Taken from ReactElement 11981 var props = _assign({}, baseProps); 11982 11983 var defaultProps = Component.defaultProps; 11984 11985 for (var propName in defaultProps) { 11986 if (props[propName] === undefined) { 11987 props[propName] = defaultProps[propName]; 11988 } 11989 } 11990 11991 return props; 11992 } 11993 11994 return baseProps; 11995 } 11996 function readLazyComponentType(lazyComponent) { 11997 initializeLazyComponentType(lazyComponent); 11998 11999 if (lazyComponent._status !== Resolved) { 12000 throw lazyComponent._result; 12001 } 12002 12003 return lazyComponent._result; 12004 } 12005 12006 var valueCursor = createCursor(null); 12007 var rendererSigil; 12008 12009 { 12010 // Use this to detect multiple renderers using the same context 12011 rendererSigil = {}; 12012 } 12013 12014 var currentlyRenderingFiber = null; 12015 var lastContextDependency = null; 12016 var lastContextWithAllBitsObserved = null; 12017 var isDisallowedContextReadInDEV = false; 12018 function resetContextDependencies() { 12019 // This is called right before React yields execution, to ensure `readContext` 12020 // cannot be called outside the render phase. 12021 currentlyRenderingFiber = null; 12022 lastContextDependency = null; 12023 lastContextWithAllBitsObserved = null; 12024 12025 { 12026 isDisallowedContextReadInDEV = false; 12027 } 12028 } 12029 function enterDisallowedContextReadInDEV() { 12030 { 12031 isDisallowedContextReadInDEV = true; 12032 } 12033 } 12034 function exitDisallowedContextReadInDEV() { 12035 { 12036 isDisallowedContextReadInDEV = false; 12037 } 12038 } 12039 function pushProvider(providerFiber, nextValue) { 12040 var context = providerFiber.type._context; 12041 12042 { 12043 push(valueCursor, context._currentValue, providerFiber); 12044 context._currentValue = nextValue; 12045 12046 { 12047 if (context._currentRenderer !== undefined && context._currentRenderer !== null && context._currentRenderer !== rendererSigil) { 12048 error('Detected multiple renderers concurrently rendering the ' + 'same context provider. This is currently unsupported.'); 12049 } 12050 12051 context._currentRenderer = rendererSigil; 12052 } 12053 } 12054 } 12055 function popProvider(providerFiber) { 12056 var currentValue = valueCursor.current; 12057 pop(valueCursor, providerFiber); 12058 var context = providerFiber.type._context; 12059 12060 { 12061 context._currentValue = currentValue; 12062 } 12063 } 12064 function calculateChangedBits(context, newValue, oldValue) { 12065 if (objectIs(oldValue, newValue)) { 12066 // No change 12067 return 0; 12068 } else { 12069 var changedBits = typeof context._calculateChangedBits === 'function' ? context._calculateChangedBits(oldValue, newValue) : MAX_SIGNED_31_BIT_INT; 12070 12071 { 12072 if ((changedBits & MAX_SIGNED_31_BIT_INT) !== changedBits) { 12073 error('calculateChangedBits: Expected the return value to be a ' + '31-bit integer. Instead received: %s', changedBits); 12074 } 12075 } 12076 12077 return changedBits | 0; 12078 } 12079 } 12080 function scheduleWorkOnParentPath(parent, renderExpirationTime) { 12081 // Update the child expiration time of all the ancestors, including 12082 // the alternates. 12083 var node = parent; 12084 12085 while (node !== null) { 12086 var alternate = node.alternate; 12087 12088 if (node.childExpirationTime < renderExpirationTime) { 12089 node.childExpirationTime = renderExpirationTime; 12090 12091 if (alternate !== null && alternate.childExpirationTime < renderExpirationTime) { 12092 alternate.childExpirationTime = renderExpirationTime; 12093 } 12094 } else if (alternate !== null && alternate.childExpirationTime < renderExpirationTime) { 12095 alternate.childExpirationTime = renderExpirationTime; 12096 } else { 12097 // Neither alternate was updated, which means the rest of the 12098 // ancestor path already has sufficient priority. 12099 break; 12100 } 12101 12102 node = node.return; 12103 } 12104 } 12105 function propagateContextChange(workInProgress, context, changedBits, renderExpirationTime) { 12106 var fiber = workInProgress.child; 12107 12108 if (fiber !== null) { 12109 // Set the return pointer of the child to the work-in-progress fiber. 12110 fiber.return = workInProgress; 12111 } 12112 12113 while (fiber !== null) { 12114 var nextFiber = void 0; // Visit this fiber. 12115 12116 var list = fiber.dependencies; 12117 12118 if (list !== null) { 12119 nextFiber = fiber.child; 12120 var dependency = list.firstContext; 12121 12122 while (dependency !== null) { 12123 // Check if the context matches. 12124 if (dependency.context === context && (dependency.observedBits & changedBits) !== 0) { 12125 // Match! Schedule an update on this fiber. 12126 if (fiber.tag === ClassComponent) { 12127 // Schedule a force update on the work-in-progress. 12128 var update = createUpdate(renderExpirationTime, null); 12129 update.tag = ForceUpdate; // TODO: Because we don't have a work-in-progress, this will add the 12130 // update to the current fiber, too, which means it will persist even if 12131 // this render is thrown away. Since it's a race condition, not sure it's 12132 // worth fixing. 12133 12134 enqueueUpdate(fiber, update); 12135 } 12136 12137 if (fiber.expirationTime < renderExpirationTime) { 12138 fiber.expirationTime = renderExpirationTime; 12139 } 12140 12141 var alternate = fiber.alternate; 12142 12143 if (alternate !== null && alternate.expirationTime < renderExpirationTime) { 12144 alternate.expirationTime = renderExpirationTime; 12145 } 12146 12147 scheduleWorkOnParentPath(fiber.return, renderExpirationTime); // Mark the expiration time on the list, too. 12148 12149 if (list.expirationTime < renderExpirationTime) { 12150 list.expirationTime = renderExpirationTime; 12151 } // Since we already found a match, we can stop traversing the 12152 // dependency list. 12153 12154 12155 break; 12156 } 12157 12158 dependency = dependency.next; 12159 } 12160 } else if (fiber.tag === ContextProvider) { 12161 // Don't scan deeper if this is a matching provider 12162 nextFiber = fiber.type === workInProgress.type ? null : fiber.child; 12163 } else { 12164 // Traverse down. 12165 nextFiber = fiber.child; 12166 } 12167 12168 if (nextFiber !== null) { 12169 // Set the return pointer of the child to the work-in-progress fiber. 12170 nextFiber.return = fiber; 12171 } else { 12172 // No child. Traverse to next sibling. 12173 nextFiber = fiber; 12174 12175 while (nextFiber !== null) { 12176 if (nextFiber === workInProgress) { 12177 // We're back to the root of this subtree. Exit. 12178 nextFiber = null; 12179 break; 12180 } 12181 12182 var sibling = nextFiber.sibling; 12183 12184 if (sibling !== null) { 12185 // Set the return pointer of the sibling to the work-in-progress fiber. 12186 sibling.return = nextFiber.return; 12187 nextFiber = sibling; 12188 break; 12189 } // No more siblings. Traverse up. 12190 12191 12192 nextFiber = nextFiber.return; 12193 } 12194 } 12195 12196 fiber = nextFiber; 12197 } 12198 } 12199 function prepareToReadContext(workInProgress, renderExpirationTime) { 12200 currentlyRenderingFiber = workInProgress; 12201 lastContextDependency = null; 12202 lastContextWithAllBitsObserved = null; 12203 var dependencies = workInProgress.dependencies; 12204 12205 if (dependencies !== null) { 12206 var firstContext = dependencies.firstContext; 12207 12208 if (firstContext !== null) { 12209 if (dependencies.expirationTime >= renderExpirationTime) { 12210 // Context list has a pending update. Mark that this fiber performed work. 12211 markWorkInProgressReceivedUpdate(); 12212 } // Reset the work-in-progress list 12213 12214 12215 dependencies.firstContext = null; 12216 } 12217 } 12218 } 12219 function readContext(context, observedBits) { 12220 { 12221 // This warning would fire if you read context inside a Hook like useMemo. 12222 // Unlike the class check below, it's not enforced in production for perf. 12223 if (isDisallowedContextReadInDEV) { 12224 error('Context can only be read while React is rendering. ' + 'In classes, you can read it in the render method or getDerivedStateFromProps. ' + 'In function components, you can read it directly in the function body, but not ' + 'inside Hooks like useReducer() or useMemo().'); 12225 } 12226 } 12227 12228 if (lastContextWithAllBitsObserved === context) ; else if (observedBits === false || observedBits === 0) ; else { 12229 var resolvedObservedBits; // Avoid deopting on observable arguments or heterogeneous types. 12230 12231 if (typeof observedBits !== 'number' || observedBits === MAX_SIGNED_31_BIT_INT) { 12232 // Observe all updates. 12233 lastContextWithAllBitsObserved = context; 12234 resolvedObservedBits = MAX_SIGNED_31_BIT_INT; 12235 } else { 12236 resolvedObservedBits = observedBits; 12237 } 12238 12239 var contextItem = { 12240 context: context, 12241 observedBits: resolvedObservedBits, 12242 next: null 12243 }; 12244 12245 if (lastContextDependency === null) { 12246 if (!(currentlyRenderingFiber !== null)) { 12247 { 12248 throw Error( "Context can only be read while React is rendering. In classes, you can read it in the render method or getDerivedStateFromProps. In function components, you can read it directly in the function body, but not inside Hooks like useReducer() or useMemo()." ); 12249 } 12250 } // This is the first dependency for this component. Create a new list. 12251 12252 12253 lastContextDependency = contextItem; 12254 currentlyRenderingFiber.dependencies = { 12255 expirationTime: NoWork, 12256 firstContext: contextItem, 12257 responders: null 12258 }; 12259 } else { 12260 // Append a new context item. 12261 lastContextDependency = lastContextDependency.next = contextItem; 12262 } 12263 } 12264 12265 return context._currentValue ; 12266 } 12267 12268 var UpdateState = 0; 12269 var ReplaceState = 1; 12270 var ForceUpdate = 2; 12271 var CaptureUpdate = 3; // Global state that is reset at the beginning of calling `processUpdateQueue`. 12272 // It should only be read right after calling `processUpdateQueue`, via 12273 // `checkHasForceUpdateAfterProcessing`. 12274 12275 var hasForceUpdate = false; 12276 var didWarnUpdateInsideUpdate; 12277 var currentlyProcessingQueue; 12278 12279 { 12280 didWarnUpdateInsideUpdate = false; 12281 currentlyProcessingQueue = null; 12282 } 12283 12284 function initializeUpdateQueue(fiber) { 12285 var queue = { 12286 baseState: fiber.memoizedState, 12287 baseQueue: null, 12288 shared: { 12289 pending: null 12290 }, 12291 effects: null 12292 }; 12293 fiber.updateQueue = queue; 12294 } 12295 function cloneUpdateQueue(current, workInProgress) { 12296 // Clone the update queue from current. Unless it's already a clone. 12297 var queue = workInProgress.updateQueue; 12298 var currentQueue = current.updateQueue; 12299 12300 if (queue === currentQueue) { 12301 var clone = { 12302 baseState: currentQueue.baseState, 12303 baseQueue: currentQueue.baseQueue, 12304 shared: currentQueue.shared, 12305 effects: currentQueue.effects 12306 }; 12307 workInProgress.updateQueue = clone; 12308 } 12309 } 12310 function createUpdate(expirationTime, suspenseConfig) { 12311 var update = { 12312 expirationTime: expirationTime, 12313 suspenseConfig: suspenseConfig, 12314 tag: UpdateState, 12315 payload: null, 12316 callback: null, 12317 next: null 12318 }; 12319 update.next = update; 12320 12321 { 12322 update.priority = getCurrentPriorityLevel(); 12323 } 12324 12325 return update; 12326 } 12327 function enqueueUpdate(fiber, update) { 12328 var updateQueue = fiber.updateQueue; 12329 12330 if (updateQueue === null) { 12331 // Only occurs if the fiber has been unmounted. 12332 return; 12333 } 12334 12335 var sharedQueue = updateQueue.shared; 12336 var pending = sharedQueue.pending; 12337 12338 if (pending === null) { 12339 // This is the first update. Create a circular list. 12340 update.next = update; 12341 } else { 12342 update.next = pending.next; 12343 pending.next = update; 12344 } 12345 12346 sharedQueue.pending = update; 12347 12348 { 12349 if (currentlyProcessingQueue === sharedQueue && !didWarnUpdateInsideUpdate) { 12350 error('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.'); 12351 12352 didWarnUpdateInsideUpdate = true; 12353 } 12354 } 12355 } 12356 function enqueueCapturedUpdate(workInProgress, update) { 12357 var current = workInProgress.alternate; 12358 12359 if (current !== null) { 12360 // Ensure the work-in-progress queue is a clone 12361 cloneUpdateQueue(current, workInProgress); 12362 } // Captured updates go only on the work-in-progress queue. 12363 12364 12365 var queue = workInProgress.updateQueue; // Append the update to the end of the list. 12366 12367 var last = queue.baseQueue; 12368 12369 if (last === null) { 12370 queue.baseQueue = update.next = update; 12371 update.next = update; 12372 } else { 12373 update.next = last.next; 12374 last.next = update; 12375 } 12376 } 12377 12378 function getStateFromUpdate(workInProgress, queue, update, prevState, nextProps, instance) { 12379 switch (update.tag) { 12380 case ReplaceState: 12381 { 12382 var payload = update.payload; 12383 12384 if (typeof payload === 'function') { 12385 // Updater function 12386 { 12387 enterDisallowedContextReadInDEV(); 12388 12389 if ( workInProgress.mode & StrictMode) { 12390 payload.call(instance, prevState, nextProps); 12391 } 12392 } 12393 12394 var nextState = payload.call(instance, prevState, nextProps); 12395 12396 { 12397 exitDisallowedContextReadInDEV(); 12398 } 12399 12400 return nextState; 12401 } // State object 12402 12403 12404 return payload; 12405 } 12406 12407 case CaptureUpdate: 12408 { 12409 workInProgress.effectTag = workInProgress.effectTag & ~ShouldCapture | DidCapture; 12410 } 12411 // Intentional fallthrough 12412 12413 case UpdateState: 12414 { 12415 var _payload = update.payload; 12416 var partialState; 12417 12418 if (typeof _payload === 'function') { 12419 // Updater function 12420 { 12421 enterDisallowedContextReadInDEV(); 12422 12423 if ( workInProgress.mode & StrictMode) { 12424 _payload.call(instance, prevState, nextProps); 12425 } 12426 } 12427 12428 partialState = _payload.call(instance, prevState, nextProps); 12429 12430 { 12431 exitDisallowedContextReadInDEV(); 12432 } 12433 } else { 12434 // Partial state object 12435 partialState = _payload; 12436 } 12437 12438 if (partialState === null || partialState === undefined) { 12439 // Null and undefined are treated as no-ops. 12440 return prevState; 12441 } // Merge the partial state and the previous state. 12442 12443 12444 return _assign({}, prevState, partialState); 12445 } 12446 12447 case ForceUpdate: 12448 { 12449 hasForceUpdate = true; 12450 return prevState; 12451 } 12452 } 12453 12454 return prevState; 12455 } 12456 12457 function processUpdateQueue(workInProgress, props, instance, renderExpirationTime) { 12458 // This is always non-null on a ClassComponent or HostRoot 12459 var queue = workInProgress.updateQueue; 12460 hasForceUpdate = false; 12461 12462 { 12463 currentlyProcessingQueue = queue.shared; 12464 } // The last rebase update that is NOT part of the base state. 12465 12466 12467 var baseQueue = queue.baseQueue; // The last pending update that hasn't been processed yet. 12468 12469 var pendingQueue = queue.shared.pending; 12470 12471 if (pendingQueue !== null) { 12472 // We have new updates that haven't been processed yet. 12473 // We'll add them to the base queue. 12474 if (baseQueue !== null) { 12475 // Merge the pending queue and the base queue. 12476 var baseFirst = baseQueue.next; 12477 var pendingFirst = pendingQueue.next; 12478 baseQueue.next = pendingFirst; 12479 pendingQueue.next = baseFirst; 12480 } 12481 12482 baseQueue = pendingQueue; 12483 queue.shared.pending = null; // TODO: Pass `current` as argument 12484 12485 var current = workInProgress.alternate; 12486 12487 if (current !== null) { 12488 var currentQueue = current.updateQueue; 12489 12490 if (currentQueue !== null) { 12491 currentQueue.baseQueue = pendingQueue; 12492 } 12493 } 12494 } // These values may change as we process the queue. 12495 12496 12497 if (baseQueue !== null) { 12498 var first = baseQueue.next; // Iterate through the list of updates to compute the result. 12499 12500 var newState = queue.baseState; 12501 var newExpirationTime = NoWork; 12502 var newBaseState = null; 12503 var newBaseQueueFirst = null; 12504 var newBaseQueueLast = null; 12505 12506 if (first !== null) { 12507 var update = first; 12508 12509 do { 12510 var updateExpirationTime = update.expirationTime; 12511 12512 if (updateExpirationTime < renderExpirationTime) { 12513 // Priority is insufficient. Skip this update. If this is the first 12514 // skipped update, the previous update/state is the new base 12515 // update/state. 12516 var clone = { 12517 expirationTime: update.expirationTime, 12518 suspenseConfig: update.suspenseConfig, 12519 tag: update.tag, 12520 payload: update.payload, 12521 callback: update.callback, 12522 next: null 12523 }; 12524 12525 if (newBaseQueueLast === null) { 12526 newBaseQueueFirst = newBaseQueueLast = clone; 12527 newBaseState = newState; 12528 } else { 12529 newBaseQueueLast = newBaseQueueLast.next = clone; 12530 } // Update the remaining priority in the queue. 12531 12532 12533 if (updateExpirationTime > newExpirationTime) { 12534 newExpirationTime = updateExpirationTime; 12535 } 12536 } else { 12537 // This update does have sufficient priority. 12538 if (newBaseQueueLast !== null) { 12539 var _clone = { 12540 expirationTime: Sync, 12541 // This update is going to be committed so we never want uncommit it. 12542 suspenseConfig: update.suspenseConfig, 12543 tag: update.tag, 12544 payload: update.payload, 12545 callback: update.callback, 12546 next: null 12547 }; 12548 newBaseQueueLast = newBaseQueueLast.next = _clone; 12549 } // Mark the event time of this update as relevant to this render pass. 12550 // TODO: This should ideally use the true event time of this update rather than 12551 // its priority which is a derived and not reverseable value. 12552 // TODO: We should skip this update if it was already committed but currently 12553 // we have no way of detecting the difference between a committed and suspended 12554 // update here. 12555 12556 12557 markRenderEventTimeAndConfig(updateExpirationTime, update.suspenseConfig); // Process this update. 12558 12559 newState = getStateFromUpdate(workInProgress, queue, update, newState, props, instance); 12560 var callback = update.callback; 12561 12562 if (callback !== null) { 12563 workInProgress.effectTag |= Callback; 12564 var effects = queue.effects; 12565 12566 if (effects === null) { 12567 queue.effects = [update]; 12568 } else { 12569 effects.push(update); 12570 } 12571 } 12572 } 12573 12574 update = update.next; 12575 12576 if (update === null || update === first) { 12577 pendingQueue = queue.shared.pending; 12578 12579 if (pendingQueue === null) { 12580 break; 12581 } else { 12582 // An update was scheduled from inside a reducer. Add the new 12583 // pending updates to the end of the list and keep processing. 12584 update = baseQueue.next = pendingQueue.next; 12585 pendingQueue.next = first; 12586 queue.baseQueue = baseQueue = pendingQueue; 12587 queue.shared.pending = null; 12588 } 12589 } 12590 } while (true); 12591 } 12592 12593 if (newBaseQueueLast === null) { 12594 newBaseState = newState; 12595 } else { 12596 newBaseQueueLast.next = newBaseQueueFirst; 12597 } 12598 12599 queue.baseState = newBaseState; 12600 queue.baseQueue = newBaseQueueLast; // Set the remaining expiration time to be whatever is remaining in the queue. 12601 // This should be fine because the only two other things that contribute to 12602 // expiration time are props and context. We're already in the middle of the 12603 // begin phase by the time we start processing the queue, so we've already 12604 // dealt with the props. Context in components that specify 12605 // shouldComponentUpdate is tricky; but we'll have to account for 12606 // that regardless. 12607 12608 markUnprocessedUpdateTime(newExpirationTime); 12609 workInProgress.expirationTime = newExpirationTime; 12610 workInProgress.memoizedState = newState; 12611 } 12612 12613 { 12614 currentlyProcessingQueue = null; 12615 } 12616 } 12617 12618 function callCallback(callback, context) { 12619 if (!(typeof callback === 'function')) { 12620 { 12621 throw Error( "Invalid argument passed as callback. Expected a function. Instead received: " + callback ); 12622 } 12623 } 12624 12625 callback.call(context); 12626 } 12627 12628 function resetHasForceUpdateBeforeProcessing() { 12629 hasForceUpdate = false; 12630 } 12631 function checkHasForceUpdateAfterProcessing() { 12632 return hasForceUpdate; 12633 } 12634 function commitUpdateQueue(finishedWork, finishedQueue, instance) { 12635 // Commit the effects 12636 var effects = finishedQueue.effects; 12637 finishedQueue.effects = null; 12638 12639 if (effects !== null) { 12640 for (var i = 0; i < effects.length; i++) { 12641 var effect = effects[i]; 12642 var callback = effect.callback; 12643 12644 if (callback !== null) { 12645 effect.callback = null; 12646 callCallback(callback, instance); 12647 } 12648 } 12649 } 12650 } 12651 12652 var ReactCurrentBatchConfig = ReactSharedInternals.ReactCurrentBatchConfig; 12653 function requestCurrentSuspenseConfig() { 12654 return ReactCurrentBatchConfig.suspense; 12655 } 12656 12657 var fakeInternalInstance = {}; 12658 var isArray = Array.isArray; // React.Component uses a shared frozen object by default. 12659 // We'll use it to determine whether we need to initialize legacy refs. 12660 12661 var emptyRefsObject = new React.Component().refs; 12662 var didWarnAboutStateAssignmentForComponent; 12663 var didWarnAboutUninitializedState; 12664 var didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate; 12665 var didWarnAboutLegacyLifecyclesAndDerivedState; 12666 var didWarnAboutUndefinedDerivedState; 12667 var warnOnUndefinedDerivedState; 12668 var warnOnInvalidCallback; 12669 var didWarnAboutDirectlyAssigningPropsToState; 12670 var didWarnAboutContextTypeAndContextTypes; 12671 var didWarnAboutInvalidateContextType; 12672 12673 { 12674 didWarnAboutStateAssignmentForComponent = new Set(); 12675 didWarnAboutUninitializedState = new Set(); 12676 didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate = new Set(); 12677 didWarnAboutLegacyLifecyclesAndDerivedState = new Set(); 12678 didWarnAboutDirectlyAssigningPropsToState = new Set(); 12679 didWarnAboutUndefinedDerivedState = new Set(); 12680 didWarnAboutContextTypeAndContextTypes = new Set(); 12681 didWarnAboutInvalidateContextType = new Set(); 12682 var didWarnOnInvalidCallback = new Set(); 12683 12684 warnOnInvalidCallback = function (callback, callerName) { 12685 if (callback === null || typeof callback === 'function') { 12686 return; 12687 } 12688 12689 var key = callerName + "_" + callback; 12690 12691 if (!didWarnOnInvalidCallback.has(key)) { 12692 didWarnOnInvalidCallback.add(key); 12693 12694 error('%s(...): Expected the last optional `callback` argument to be a ' + 'function. Instead received: %s.', callerName, callback); 12695 } 12696 }; 12697 12698 warnOnUndefinedDerivedState = function (type, partialState) { 12699 if (partialState === undefined) { 12700 var componentName = getComponentName(type) || 'Component'; 12701 12702 if (!didWarnAboutUndefinedDerivedState.has(componentName)) { 12703 didWarnAboutUndefinedDerivedState.add(componentName); 12704 12705 error('%s.getDerivedStateFromProps(): A valid state object (or null) must be returned. ' + 'You have returned undefined.', componentName); 12706 } 12707 } 12708 }; // This is so gross but it's at least non-critical and can be removed if 12709 // it causes problems. This is meant to give a nicer error message for 12710 // ReactDOM15.unstable_renderSubtreeIntoContainer(reactDOM16Component, 12711 // ...)) which otherwise throws a "_processChildContext is not a function" 12712 // exception. 12713 12714 12715 Object.defineProperty(fakeInternalInstance, '_processChildContext', { 12716 enumerable: false, 12717 value: function () { 12718 { 12719 { 12720 throw Error( "_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)." ); 12721 } 12722 } 12723 } 12724 }); 12725 Object.freeze(fakeInternalInstance); 12726 } 12727 12728 function applyDerivedStateFromProps(workInProgress, ctor, getDerivedStateFromProps, nextProps) { 12729 var prevState = workInProgress.memoizedState; 12730 12731 { 12732 if ( workInProgress.mode & StrictMode) { 12733 // Invoke the function an extra time to help detect side-effects. 12734 getDerivedStateFromProps(nextProps, prevState); 12735 } 12736 } 12737 12738 var partialState = getDerivedStateFromProps(nextProps, prevState); 12739 12740 { 12741 warnOnUndefinedDerivedState(ctor, partialState); 12742 } // Merge the partial state and the previous state. 12743 12744 12745 var memoizedState = partialState === null || partialState === undefined ? prevState : _assign({}, prevState, partialState); 12746 workInProgress.memoizedState = memoizedState; // Once the update queue is empty, persist the derived state onto the 12747 // base state. 12748 12749 if (workInProgress.expirationTime === NoWork) { 12750 // Queue is always non-null for classes 12751 var updateQueue = workInProgress.updateQueue; 12752 updateQueue.baseState = memoizedState; 12753 } 12754 } 12755 var classComponentUpdater = { 12756 isMounted: isMounted, 12757 enqueueSetState: function (inst, payload, callback) { 12758 var fiber = get(inst); 12759 var currentTime = requestCurrentTimeForUpdate(); 12760 var suspenseConfig = requestCurrentSuspenseConfig(); 12761 var expirationTime = computeExpirationForFiber(currentTime, fiber, suspenseConfig); 12762 var update = createUpdate(expirationTime, suspenseConfig); 12763 update.payload = payload; 12764 12765 if (callback !== undefined && callback !== null) { 12766 { 12767 warnOnInvalidCallback(callback, 'setState'); 12768 } 12769 12770 update.callback = callback; 12771 } 12772 12773 enqueueUpdate(fiber, update); 12774 scheduleWork(fiber, expirationTime); 12775 }, 12776 enqueueReplaceState: function (inst, payload, callback) { 12777 var fiber = get(inst); 12778 var currentTime = requestCurrentTimeForUpdate(); 12779 var suspenseConfig = requestCurrentSuspenseConfig(); 12780 var expirationTime = computeExpirationForFiber(currentTime, fiber, suspenseConfig); 12781 var update = createUpdate(expirationTime, suspenseConfig); 12782 update.tag = ReplaceState; 12783 update.payload = payload; 12784 12785 if (callback !== undefined && callback !== null) { 12786 { 12787 warnOnInvalidCallback(callback, 'replaceState'); 12788 } 12789 12790 update.callback = callback; 12791 } 12792 12793 enqueueUpdate(fiber, update); 12794 scheduleWork(fiber, expirationTime); 12795 }, 12796 enqueueForceUpdate: function (inst, callback) { 12797 var fiber = get(inst); 12798 var currentTime = requestCurrentTimeForUpdate(); 12799 var suspenseConfig = requestCurrentSuspenseConfig(); 12800 var expirationTime = computeExpirationForFiber(currentTime, fiber, suspenseConfig); 12801 var update = createUpdate(expirationTime, suspenseConfig); 12802 update.tag = ForceUpdate; 12803 12804 if (callback !== undefined && callback !== null) { 12805 { 12806 warnOnInvalidCallback(callback, 'forceUpdate'); 12807 } 12808 12809 update.callback = callback; 12810 } 12811 12812 enqueueUpdate(fiber, update); 12813 scheduleWork(fiber, expirationTime); 12814 } 12815 }; 12816 12817 function checkShouldComponentUpdate(workInProgress, ctor, oldProps, newProps, oldState, newState, nextContext) { 12818 var instance = workInProgress.stateNode; 12819 12820 if (typeof instance.shouldComponentUpdate === 'function') { 12821 { 12822 if ( workInProgress.mode & StrictMode) { 12823 // Invoke the function an extra time to help detect side-effects. 12824 instance.shouldComponentUpdate(newProps, newState, nextContext); 12825 } 12826 } 12827 12828 startPhaseTimer(workInProgress, 'shouldComponentUpdate'); 12829 var shouldUpdate = instance.shouldComponentUpdate(newProps, newState, nextContext); 12830 stopPhaseTimer(); 12831 12832 { 12833 if (shouldUpdate === undefined) { 12834 error('%s.shouldComponentUpdate(): Returned undefined instead of a ' + 'boolean value. Make sure to return true or false.', getComponentName(ctor) || 'Component'); 12835 } 12836 } 12837 12838 return shouldUpdate; 12839 } 12840 12841 if (ctor.prototype && ctor.prototype.isPureReactComponent) { 12842 return !shallowEqual(oldProps, newProps) || !shallowEqual(oldState, newState); 12843 } 12844 12845 return true; 12846 } 12847 12848 function checkClassInstance(workInProgress, ctor, newProps) { 12849 var instance = workInProgress.stateNode; 12850 12851 { 12852 var name = getComponentName(ctor) || 'Component'; 12853 var renderPresent = instance.render; 12854 12855 if (!renderPresent) { 12856 if (ctor.prototype && typeof ctor.prototype.render === 'function') { 12857 error('%s(...): No `render` method found on the returned component ' + 'instance: did you accidentally return an object from the constructor?', name); 12858 } else { 12859 error('%s(...): No `render` method found on the returned component ' + 'instance: you may have forgotten to define `render`.', name); 12860 } 12861 } 12862 12863 if (instance.getInitialState && !instance.getInitialState.isReactClassApproved && !instance.state) { 12864 error('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); 12865 } 12866 12867 if (instance.getDefaultProps && !instance.getDefaultProps.isReactClassApproved) { 12868 error('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); 12869 } 12870 12871 if (instance.propTypes) { 12872 error('propTypes was defined as an instance property on %s. Use a static ' + 'property to define propTypes instead.', name); 12873 } 12874 12875 if (instance.contextType) { 12876 error('contextType was defined as an instance property on %s. Use a static ' + 'property to define contextType instead.', name); 12877 } 12878 12879 { 12880 if (instance.contextTypes) { 12881 error('contextTypes was defined as an instance property on %s. Use a static ' + 'property to define contextTypes instead.', name); 12882 } 12883 12884 if (ctor.contextType && ctor.contextTypes && !didWarnAboutContextTypeAndContextTypes.has(ctor)) { 12885 didWarnAboutContextTypeAndContextTypes.add(ctor); 12886 12887 error('%s declares both contextTypes and contextType static properties. ' + 'The legacy contextTypes property will be ignored.', name); 12888 } 12889 } 12890 12891 if (typeof instance.componentShouldUpdate === 'function') { 12892 error('%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); 12893 } 12894 12895 if (ctor.prototype && ctor.prototype.isPureReactComponent && typeof instance.shouldComponentUpdate !== 'undefined') { 12896 error('%s has a method called shouldComponentUpdate(). ' + 'shouldComponentUpdate should not be used when extending React.PureComponent. ' + 'Please extend React.Component if shouldComponentUpdate is used.', getComponentName(ctor) || 'A pure component'); 12897 } 12898 12899 if (typeof instance.componentDidUnmount === 'function') { 12900 error('%s has a method called ' + 'componentDidUnmount(). But there is no such lifecycle method. ' + 'Did you mean componentWillUnmount()?', name); 12901 } 12902 12903 if (typeof instance.componentDidReceiveProps === 'function') { 12904 error('%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); 12905 } 12906 12907 if (typeof instance.componentWillRecieveProps === 'function') { 12908 error('%s has a method called ' + 'componentWillRecieveProps(). Did you mean componentWillReceiveProps()?', name); 12909 } 12910 12911 if (typeof instance.UNSAFE_componentWillRecieveProps === 'function') { 12912 error('%s has a method called ' + 'UNSAFE_componentWillRecieveProps(). Did you mean UNSAFE_componentWillReceiveProps()?', name); 12913 } 12914 12915 var hasMutatedProps = instance.props !== newProps; 12916 12917 if (instance.props !== undefined && hasMutatedProps) { 12918 error('%s(...): When calling super() in `%s`, make sure to pass ' + "up the same props that your component's constructor was passed.", name, name); 12919 } 12920 12921 if (instance.defaultProps) { 12922 error('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); 12923 } 12924 12925 if (typeof instance.getSnapshotBeforeUpdate === 'function' && typeof instance.componentDidUpdate !== 'function' && !didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate.has(ctor)) { 12926 didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate.add(ctor); 12927 12928 error('%s: getSnapshotBeforeUpdate() should be used with componentDidUpdate(). ' + 'This component defines getSnapshotBeforeUpdate() only.', getComponentName(ctor)); 12929 } 12930 12931 if (typeof instance.getDerivedStateFromProps === 'function') { 12932 error('%s: getDerivedStateFromProps() is defined as an instance method ' + 'and will be ignored. Instead, declare it as a static method.', name); 12933 } 12934 12935 if (typeof instance.getDerivedStateFromError === 'function') { 12936 error('%s: getDerivedStateFromError() is defined as an instance method ' + 'and will be ignored. Instead, declare it as a static method.', name); 12937 } 12938 12939 if (typeof ctor.getSnapshotBeforeUpdate === 'function') { 12940 error('%s: getSnapshotBeforeUpdate() is defined as a static method ' + 'and will be ignored. Instead, declare it as an instance method.', name); 12941 } 12942 12943 var _state = instance.state; 12944 12945 if (_state && (typeof _state !== 'object' || isArray(_state))) { 12946 error('%s.state: must be set to an object or null', name); 12947 } 12948 12949 if (typeof instance.getChildContext === 'function' && typeof ctor.childContextTypes !== 'object') { 12950 error('%s.getChildContext(): childContextTypes must be defined in order to ' + 'use getChildContext().', name); 12951 } 12952 } 12953 } 12954 12955 function adoptClassInstance(workInProgress, instance) { 12956 instance.updater = classComponentUpdater; 12957 workInProgress.stateNode = instance; // The instance needs access to the fiber so that it can schedule updates 12958 12959 set(instance, workInProgress); 12960 12961 { 12962 instance._reactInternalInstance = fakeInternalInstance; 12963 } 12964 } 12965 12966 function constructClassInstance(workInProgress, ctor, props) { 12967 var isLegacyContextConsumer = false; 12968 var unmaskedContext = emptyContextObject; 12969 var context = emptyContextObject; 12970 var contextType = ctor.contextType; 12971 12972 { 12973 if ('contextType' in ctor) { 12974 var isValid = // Allow null for conditional declaration 12975 contextType === null || contextType !== undefined && contextType.$$typeof === REACT_CONTEXT_TYPE && contextType._context === undefined; // Not a <Context.Consumer> 12976 12977 if (!isValid && !didWarnAboutInvalidateContextType.has(ctor)) { 12978 didWarnAboutInvalidateContextType.add(ctor); 12979 var addendum = ''; 12980 12981 if (contextType === undefined) { 12982 addendum = ' However, it is set to undefined. ' + 'This can be caused by a typo or by mixing up named and default imports. ' + 'This can also happen due to a circular dependency, so ' + 'try moving the createContext() call to a separate file.'; 12983 } else if (typeof contextType !== 'object') { 12984 addendum = ' However, it is set to a ' + typeof contextType + '.'; 12985 } else if (contextType.$$typeof === REACT_PROVIDER_TYPE) { 12986 addendum = ' Did you accidentally pass the Context.Provider instead?'; 12987 } else if (contextType._context !== undefined) { 12988 // <Context.Consumer> 12989 addendum = ' Did you accidentally pass the Context.Consumer instead?'; 12990 } else { 12991 addendum = ' However, it is set to an object with keys {' + Object.keys(contextType).join(', ') + '}.'; 12992 } 12993 12994 error('%s defines an invalid contextType. ' + 'contextType should point to the Context object returned by React.createContext().%s', getComponentName(ctor) || 'Component', addendum); 12995 } 12996 } 12997 } 12998 12999 if (typeof contextType === 'object' && contextType !== null) { 13000 context = readContext(contextType); 13001 } else { 13002 unmaskedContext = getUnmaskedContext(workInProgress, ctor, true); 13003 var contextTypes = ctor.contextTypes; 13004 isLegacyContextConsumer = contextTypes !== null && contextTypes !== undefined; 13005 context = isLegacyContextConsumer ? getMaskedContext(workInProgress, unmaskedContext) : emptyContextObject; 13006 } // Instantiate twice to help detect side-effects. 13007 13008 13009 { 13010 if ( workInProgress.mode & StrictMode) { 13011 new ctor(props, context); // eslint-disable-line no-new 13012 } 13013 } 13014 13015 var instance = new ctor(props, context); 13016 var state = workInProgress.memoizedState = instance.state !== null && instance.state !== undefined ? instance.state : null; 13017 adoptClassInstance(workInProgress, instance); 13018 13019 { 13020 if (typeof ctor.getDerivedStateFromProps === 'function' && state === null) { 13021 var componentName = getComponentName(ctor) || 'Component'; 13022 13023 if (!didWarnAboutUninitializedState.has(componentName)) { 13024 didWarnAboutUninitializedState.add(componentName); 13025 13026 error('`%s` uses `getDerivedStateFromProps` but its initial state is ' + '%s. This is not recommended. Instead, define the initial state by ' + 'assigning an object to `this.state` in the constructor of `%s`. ' + 'This ensures that `getDerivedStateFromProps` arguments have a consistent shape.', componentName, instance.state === null ? 'null' : 'undefined', componentName); 13027 } 13028 } // If new component APIs are defined, "unsafe" lifecycles won't be called. 13029 // Warn about these lifecycles if they are present. 13030 // Don't warn about react-lifecycles-compat polyfilled methods though. 13031 13032 13033 if (typeof ctor.getDerivedStateFromProps === 'function' || typeof instance.getSnapshotBeforeUpdate === 'function') { 13034 var foundWillMountName = null; 13035 var foundWillReceivePropsName = null; 13036 var foundWillUpdateName = null; 13037 13038 if (typeof instance.componentWillMount === 'function' && instance.componentWillMount.__suppressDeprecationWarning !== true) { 13039 foundWillMountName = 'componentWillMount'; 13040 } else if (typeof instance.UNSAFE_componentWillMount === 'function') { 13041 foundWillMountName = 'UNSAFE_componentWillMount'; 13042 } 13043 13044 if (typeof instance.componentWillReceiveProps === 'function' && instance.componentWillReceiveProps.__suppressDeprecationWarning !== true) { 13045 foundWillReceivePropsName = 'componentWillReceiveProps'; 13046 } else if (typeof instance.UNSAFE_componentWillReceiveProps === 'function') { 13047 foundWillReceivePropsName = 'UNSAFE_componentWillReceiveProps'; 13048 } 13049 13050 if (typeof instance.componentWillUpdate === 'function' && instance.componentWillUpdate.__suppressDeprecationWarning !== true) { 13051 foundWillUpdateName = 'componentWillUpdate'; 13052 } else if (typeof instance.UNSAFE_componentWillUpdate === 'function') { 13053 foundWillUpdateName = 'UNSAFE_componentWillUpdate'; 13054 } 13055 13056 if (foundWillMountName !== null || foundWillReceivePropsName !== null || foundWillUpdateName !== null) { 13057 var _componentName = getComponentName(ctor) || 'Component'; 13058 13059 var newApiName = typeof ctor.getDerivedStateFromProps === 'function' ? 'getDerivedStateFromProps()' : 'getSnapshotBeforeUpdate()'; 13060 13061 if (!didWarnAboutLegacyLifecyclesAndDerivedState.has(_componentName)) { 13062 didWarnAboutLegacyLifecyclesAndDerivedState.add(_componentName); 13063 13064 error('Unsafe legacy lifecycles will not be called for components using new component APIs.\n\n' + '%s uses %s but also contains the following legacy lifecycles:%s%s%s\n\n' + 'The above lifecycles should be removed. Learn more about this warning here:\n' + 'https://fb.me/react-unsafe-component-lifecycles', _componentName, newApiName, foundWillMountName !== null ? "\n " + foundWillMountName : '', foundWillReceivePropsName !== null ? "\n " + foundWillReceivePropsName : '', foundWillUpdateName !== null ? "\n " + foundWillUpdateName : ''); 13065 } 13066 } 13067 } 13068 } // Cache unmasked context so we can avoid recreating masked context unless necessary. 13069 // ReactFiberContext usually updates this cache but can't for newly-created instances. 13070 13071 13072 if (isLegacyContextConsumer) { 13073 cacheContext(workInProgress, unmaskedContext, context); 13074 } 13075 13076 return instance; 13077 } 13078 13079 function callComponentWillMount(workInProgress, instance) { 13080 startPhaseTimer(workInProgress, 'componentWillMount'); 13081 var oldState = instance.state; 13082 13083 if (typeof instance.componentWillMount === 'function') { 13084 instance.componentWillMount(); 13085 } 13086 13087 if (typeof instance.UNSAFE_componentWillMount === 'function') { 13088 instance.UNSAFE_componentWillMount(); 13089 } 13090 13091 stopPhaseTimer(); 13092 13093 if (oldState !== instance.state) { 13094 { 13095 error('%s.componentWillMount(): Assigning directly to this.state is ' + "deprecated (except inside a component's " + 'constructor). Use setState instead.', getComponentName(workInProgress.type) || 'Component'); 13096 } 13097 13098 classComponentUpdater.enqueueReplaceState(instance, instance.state, null); 13099 } 13100 } 13101 13102 function callComponentWillReceiveProps(workInProgress, instance, newProps, nextContext) { 13103 var oldState = instance.state; 13104 startPhaseTimer(workInProgress, 'componentWillReceiveProps'); 13105 13106 if (typeof instance.componentWillReceiveProps === 'function') { 13107 instance.componentWillReceiveProps(newProps, nextContext); 13108 } 13109 13110 if (typeof instance.UNSAFE_componentWillReceiveProps === 'function') { 13111 instance.UNSAFE_componentWillReceiveProps(newProps, nextContext); 13112 } 13113 13114 stopPhaseTimer(); 13115 13116 if (instance.state !== oldState) { 13117 { 13118 var componentName = getComponentName(workInProgress.type) || 'Component'; 13119 13120 if (!didWarnAboutStateAssignmentForComponent.has(componentName)) { 13121 didWarnAboutStateAssignmentForComponent.add(componentName); 13122 13123 error('%s.componentWillReceiveProps(): Assigning directly to ' + "this.state is deprecated (except inside a component's " + 'constructor). Use setState instead.', componentName); 13124 } 13125 } 13126 13127 classComponentUpdater.enqueueReplaceState(instance, instance.state, null); 13128 } 13129 } // Invokes the mount life-cycles on a previously never rendered instance. 13130 13131 13132 function mountClassInstance(workInProgress, ctor, newProps, renderExpirationTime) { 13133 { 13134 checkClassInstance(workInProgress, ctor, newProps); 13135 } 13136 13137 var instance = workInProgress.stateNode; 13138 instance.props = newProps; 13139 instance.state = workInProgress.memoizedState; 13140 instance.refs = emptyRefsObject; 13141 initializeUpdateQueue(workInProgress); 13142 var contextType = ctor.contextType; 13143 13144 if (typeof contextType === 'object' && contextType !== null) { 13145 instance.context = readContext(contextType); 13146 } else { 13147 var unmaskedContext = getUnmaskedContext(workInProgress, ctor, true); 13148 instance.context = getMaskedContext(workInProgress, unmaskedContext); 13149 } 13150 13151 { 13152 if (instance.state === newProps) { 13153 var componentName = getComponentName(ctor) || 'Component'; 13154 13155 if (!didWarnAboutDirectlyAssigningPropsToState.has(componentName)) { 13156 didWarnAboutDirectlyAssigningPropsToState.add(componentName); 13157 13158 error('%s: It is not recommended to assign props directly to state ' + "because updates to props won't be reflected in state. " + 'In most cases, it is better to use props directly.', componentName); 13159 } 13160 } 13161 13162 if (workInProgress.mode & StrictMode) { 13163 ReactStrictModeWarnings.recordLegacyContextWarning(workInProgress, instance); 13164 } 13165 13166 { 13167 ReactStrictModeWarnings.recordUnsafeLifecycleWarnings(workInProgress, instance); 13168 } 13169 } 13170 13171 processUpdateQueue(workInProgress, newProps, instance, renderExpirationTime); 13172 instance.state = workInProgress.memoizedState; 13173 var getDerivedStateFromProps = ctor.getDerivedStateFromProps; 13174 13175 if (typeof getDerivedStateFromProps === 'function') { 13176 applyDerivedStateFromProps(workInProgress, ctor, getDerivedStateFromProps, newProps); 13177 instance.state = workInProgress.memoizedState; 13178 } // In order to support react-lifecycles-compat polyfilled components, 13179 // Unsafe lifecycles should not be invoked for components using the new APIs. 13180 13181 13182 if (typeof ctor.getDerivedStateFromProps !== 'function' && typeof instance.getSnapshotBeforeUpdate !== 'function' && (typeof instance.UNSAFE_componentWillMount === 'function' || typeof instance.componentWillMount === 'function')) { 13183 callComponentWillMount(workInProgress, instance); // If we had additional state updates during this life-cycle, let's 13184 // process them now. 13185 13186 processUpdateQueue(workInProgress, newProps, instance, renderExpirationTime); 13187 instance.state = workInProgress.memoizedState; 13188 } 13189 13190 if (typeof instance.componentDidMount === 'function') { 13191 workInProgress.effectTag |= Update; 13192 } 13193 } 13194 13195 function resumeMountClassInstance(workInProgress, ctor, newProps, renderExpirationTime) { 13196 var instance = workInProgress.stateNode; 13197 var oldProps = workInProgress.memoizedProps; 13198 instance.props = oldProps; 13199 var oldContext = instance.context; 13200 var contextType = ctor.contextType; 13201 var nextContext = emptyContextObject; 13202 13203 if (typeof contextType === 'object' && contextType !== null) { 13204 nextContext = readContext(contextType); 13205 } else { 13206 var nextLegacyUnmaskedContext = getUnmaskedContext(workInProgress, ctor, true); 13207 nextContext = getMaskedContext(workInProgress, nextLegacyUnmaskedContext); 13208 } 13209 13210 var getDerivedStateFromProps = ctor.getDerivedStateFromProps; 13211 var hasNewLifecycles = typeof getDerivedStateFromProps === 'function' || typeof instance.getSnapshotBeforeUpdate === 'function'; // Note: During these life-cycles, instance.props/instance.state are what 13212 // ever the previously attempted to render - not the "current". However, 13213 // during componentDidUpdate we pass the "current" props. 13214 // In order to support react-lifecycles-compat polyfilled components, 13215 // Unsafe lifecycles should not be invoked for components using the new APIs. 13216 13217 if (!hasNewLifecycles && (typeof instance.UNSAFE_componentWillReceiveProps === 'function' || typeof instance.componentWillReceiveProps === 'function')) { 13218 if (oldProps !== newProps || oldContext !== nextContext) { 13219 callComponentWillReceiveProps(workInProgress, instance, newProps, nextContext); 13220 } 13221 } 13222 13223 resetHasForceUpdateBeforeProcessing(); 13224 var oldState = workInProgress.memoizedState; 13225 var newState = instance.state = oldState; 13226 processUpdateQueue(workInProgress, newProps, instance, renderExpirationTime); 13227 newState = workInProgress.memoizedState; 13228 13229 if (oldProps === newProps && oldState === newState && !hasContextChanged() && !checkHasForceUpdateAfterProcessing()) { 13230 // If an update was already in progress, we should schedule an Update 13231 // effect even though we're bailing out, so that cWU/cDU are called. 13232 if (typeof instance.componentDidMount === 'function') { 13233 workInProgress.effectTag |= Update; 13234 } 13235 13236 return false; 13237 } 13238 13239 if (typeof getDerivedStateFromProps === 'function') { 13240 applyDerivedStateFromProps(workInProgress, ctor, getDerivedStateFromProps, newProps); 13241 newState = workInProgress.memoizedState; 13242 } 13243 13244 var shouldUpdate = checkHasForceUpdateAfterProcessing() || checkShouldComponentUpdate(workInProgress, ctor, oldProps, newProps, oldState, newState, nextContext); 13245 13246 if (shouldUpdate) { 13247 // In order to support react-lifecycles-compat polyfilled components, 13248 // Unsafe lifecycles should not be invoked for components using the new APIs. 13249 if (!hasNewLifecycles && (typeof instance.UNSAFE_componentWillMount === 'function' || typeof instance.componentWillMount === 'function')) { 13250 startPhaseTimer(workInProgress, 'componentWillMount'); 13251 13252 if (typeof instance.componentWillMount === 'function') { 13253 instance.componentWillMount(); 13254 } 13255 13256 if (typeof instance.UNSAFE_componentWillMount === 'function') { 13257 instance.UNSAFE_componentWillMount(); 13258 } 13259 13260 stopPhaseTimer(); 13261 } 13262 13263 if (typeof instance.componentDidMount === 'function') { 13264 workInProgress.effectTag |= Update; 13265 } 13266 } else { 13267 // If an update was already in progress, we should schedule an Update 13268 // effect even though we're bailing out, so that cWU/cDU are called. 13269 if (typeof instance.componentDidMount === 'function') { 13270 workInProgress.effectTag |= Update; 13271 } // If shouldComponentUpdate returned false, we should still update the 13272 // memoized state to indicate that this work can be reused. 13273 13274 13275 workInProgress.memoizedProps = newProps; 13276 workInProgress.memoizedState = newState; 13277 } // Update the existing instance's state, props, and context pointers even 13278 // if shouldComponentUpdate returns false. 13279 13280 13281 instance.props = newProps; 13282 instance.state = newState; 13283 instance.context = nextContext; 13284 return shouldUpdate; 13285 } // Invokes the update life-cycles and returns false if it shouldn't rerender. 13286 13287 13288 function updateClassInstance(current, workInProgress, ctor, newProps, renderExpirationTime) { 13289 var instance = workInProgress.stateNode; 13290 cloneUpdateQueue(current, workInProgress); 13291 var oldProps = workInProgress.memoizedProps; 13292 instance.props = workInProgress.type === workInProgress.elementType ? oldProps : resolveDefaultProps(workInProgress.type, oldProps); 13293 var oldContext = instance.context; 13294 var contextType = ctor.contextType; 13295 var nextContext = emptyContextObject; 13296 13297 if (typeof contextType === 'object' && contextType !== null) { 13298 nextContext = readContext(contextType); 13299 } else { 13300 var nextUnmaskedContext = getUnmaskedContext(workInProgress, ctor, true); 13301 nextContext = getMaskedContext(workInProgress, nextUnmaskedContext); 13302 } 13303 13304 var getDerivedStateFromProps = ctor.getDerivedStateFromProps; 13305 var hasNewLifecycles = typeof getDerivedStateFromProps === 'function' || typeof instance.getSnapshotBeforeUpdate === 'function'; // Note: During these life-cycles, instance.props/instance.state are what 13306 // ever the previously attempted to render - not the "current". However, 13307 // during componentDidUpdate we pass the "current" props. 13308 // In order to support react-lifecycles-compat polyfilled components, 13309 // Unsafe lifecycles should not be invoked for components using the new APIs. 13310 13311 if (!hasNewLifecycles && (typeof instance.UNSAFE_componentWillReceiveProps === 'function' || typeof instance.componentWillReceiveProps === 'function')) { 13312 if (oldProps !== newProps || oldContext !== nextContext) { 13313 callComponentWillReceiveProps(workInProgress, instance, newProps, nextContext); 13314 } 13315 } 13316 13317 resetHasForceUpdateBeforeProcessing(); 13318 var oldState = workInProgress.memoizedState; 13319 var newState = instance.state = oldState; 13320 processUpdateQueue(workInProgress, newProps, instance, renderExpirationTime); 13321 newState = workInProgress.memoizedState; 13322 13323 if (oldProps === newProps && oldState === newState && !hasContextChanged() && !checkHasForceUpdateAfterProcessing()) { 13324 // If an update was already in progress, we should schedule an Update 13325 // effect even though we're bailing out, so that cWU/cDU are called. 13326 if (typeof instance.componentDidUpdate === 'function') { 13327 if (oldProps !== current.memoizedProps || oldState !== current.memoizedState) { 13328 workInProgress.effectTag |= Update; 13329 } 13330 } 13331 13332 if (typeof instance.getSnapshotBeforeUpdate === 'function') { 13333 if (oldProps !== current.memoizedProps || oldState !== current.memoizedState) { 13334 workInProgress.effectTag |= Snapshot; 13335 } 13336 } 13337 13338 return false; 13339 } 13340 13341 if (typeof getDerivedStateFromProps === 'function') { 13342 applyDerivedStateFromProps(workInProgress, ctor, getDerivedStateFromProps, newProps); 13343 newState = workInProgress.memoizedState; 13344 } 13345 13346 var shouldUpdate = checkHasForceUpdateAfterProcessing() || checkShouldComponentUpdate(workInProgress, ctor, oldProps, newProps, oldState, newState, nextContext); 13347 13348 if (shouldUpdate) { 13349 // In order to support react-lifecycles-compat polyfilled components, 13350 // Unsafe lifecycles should not be invoked for components using the new APIs. 13351 if (!hasNewLifecycles && (typeof instance.UNSAFE_componentWillUpdate === 'function' || typeof instance.componentWillUpdate === 'function')) { 13352 startPhaseTimer(workInProgress, 'componentWillUpdate'); 13353 13354 if (typeof instance.componentWillUpdate === 'function') { 13355 instance.componentWillUpdate(newProps, newState, nextContext); 13356 } 13357 13358 if (typeof instance.UNSAFE_componentWillUpdate === 'function') { 13359 instance.UNSAFE_componentWillUpdate(newProps, newState, nextContext); 13360 } 13361 13362 stopPhaseTimer(); 13363 } 13364 13365 if (typeof instance.componentDidUpdate === 'function') { 13366 workInProgress.effectTag |= Update; 13367 } 13368 13369 if (typeof instance.getSnapshotBeforeUpdate === 'function') { 13370 workInProgress.effectTag |= Snapshot; 13371 } 13372 } else { 13373 // If an update was already in progress, we should schedule an Update 13374 // effect even though we're bailing out, so that cWU/cDU are called. 13375 if (typeof instance.componentDidUpdate === 'function') { 13376 if (oldProps !== current.memoizedProps || oldState !== current.memoizedState) { 13377 workInProgress.effectTag |= Update; 13378 } 13379 } 13380 13381 if (typeof instance.getSnapshotBeforeUpdate === 'function') { 13382 if (oldProps !== current.memoizedProps || oldState !== current.memoizedState) { 13383 workInProgress.effectTag |= Snapshot; 13384 } 13385 } // If shouldComponentUpdate returned false, we should still update the 13386 // memoized props/state to indicate that this work can be reused. 13387 13388 13389 workInProgress.memoizedProps = newProps; 13390 workInProgress.memoizedState = newState; 13391 } // Update the existing instance's state, props, and context pointers even 13392 // if shouldComponentUpdate returns false. 13393 13394 13395 instance.props = newProps; 13396 instance.state = newState; 13397 instance.context = nextContext; 13398 return shouldUpdate; 13399 } 13400 13401 var didWarnAboutMaps; 13402 var didWarnAboutGenerators; 13403 var didWarnAboutStringRefs; 13404 var ownerHasKeyUseWarning; 13405 var ownerHasFunctionTypeWarning; 13406 13407 var warnForMissingKey = function (child) {}; 13408 13409 { 13410 didWarnAboutMaps = false; 13411 didWarnAboutGenerators = false; 13412 didWarnAboutStringRefs = {}; 13413 /** 13414 * Warn if there's no key explicitly set on dynamic arrays of children or 13415 * object keys are not valid. This allows us to keep track of children between 13416 * updates. 13417 */ 13418 13419 ownerHasKeyUseWarning = {}; 13420 ownerHasFunctionTypeWarning = {}; 13421 13422 warnForMissingKey = function (child) { 13423 if (child === null || typeof child !== 'object') { 13424 return; 13425 } 13426 13427 if (!child._store || child._store.validated || child.key != null) { 13428 return; 13429 } 13430 13431 if (!(typeof child._store === 'object')) { 13432 { 13433 throw Error( "React Component in warnForMissingKey should have a _store. This error is likely caused by a bug in React. Please file an issue." ); 13434 } 13435 } 13436 13437 child._store.validated = true; 13438 var currentComponentErrorInfo = 'Each child in a list should have a unique ' + '"key" prop. See https://fb.me/react-warning-keys for ' + 'more information.' + getCurrentFiberStackInDev(); 13439 13440 if (ownerHasKeyUseWarning[currentComponentErrorInfo]) { 13441 return; 13442 } 13443 13444 ownerHasKeyUseWarning[currentComponentErrorInfo] = true; 13445 13446 error('Each child in a list should have a unique ' + '"key" prop. See https://fb.me/react-warning-keys for ' + 'more information.'); 13447 }; 13448 } 13449 13450 var isArray$1 = Array.isArray; 13451 13452 function coerceRef(returnFiber, current, element) { 13453 var mixedRef = element.ref; 13454 13455 if (mixedRef !== null && typeof mixedRef !== 'function' && typeof mixedRef !== 'object') { 13456 { 13457 // TODO: Clean this up once we turn on the string ref warning for 13458 // everyone, because the strict mode case will no longer be relevant 13459 if ((returnFiber.mode & StrictMode || warnAboutStringRefs) && // We warn in ReactElement.js if owner and self are equal for string refs 13460 // because these cannot be automatically converted to an arrow function 13461 // using a codemod. Therefore, we don't have to warn about string refs again. 13462 !(element._owner && element._self && element._owner.stateNode !== element._self)) { 13463 var componentName = getComponentName(returnFiber.type) || 'Component'; 13464 13465 if (!didWarnAboutStringRefs[componentName]) { 13466 { 13467 error('A string ref, "%s", has been found within a strict mode tree. ' + 'String refs are a source of potential bugs and should be avoided. ' + 'We recommend using useRef() or createRef() instead. ' + 'Learn more about using refs safely here: ' + 'https://fb.me/react-strict-mode-string-ref%s', mixedRef, getStackByFiberInDevAndProd(returnFiber)); 13468 } 13469 13470 didWarnAboutStringRefs[componentName] = true; 13471 } 13472 } 13473 } 13474 13475 if (element._owner) { 13476 var owner = element._owner; 13477 var inst; 13478 13479 if (owner) { 13480 var ownerFiber = owner; 13481 13482 if (!(ownerFiber.tag === ClassComponent)) { 13483 { 13484 throw Error( "Function components cannot have string refs. We recommend using useRef() instead. Learn more about using refs safely here: https://fb.me/react-strict-mode-string-ref" ); 13485 } 13486 } 13487 13488 inst = ownerFiber.stateNode; 13489 } 13490 13491 if (!inst) { 13492 { 13493 throw Error( "Missing owner for string ref " + mixedRef + ". This error is likely caused by a bug in React. Please file an issue." ); 13494 } 13495 } 13496 13497 var stringRef = '' + mixedRef; // Check if previous string ref matches new string ref 13498 13499 if (current !== null && current.ref !== null && typeof current.ref === 'function' && current.ref._stringRef === stringRef) { 13500 return current.ref; 13501 } 13502 13503 var ref = function (value) { 13504 var refs = inst.refs; 13505 13506 if (refs === emptyRefsObject) { 13507 // This is a lazy pooled frozen object, so we need to initialize. 13508 refs = inst.refs = {}; 13509 } 13510 13511 if (value === null) { 13512 delete refs[stringRef]; 13513 } else { 13514 refs[stringRef] = value; 13515 } 13516 }; 13517 13518 ref._stringRef = stringRef; 13519 return ref; 13520 } else { 13521 if (!(typeof mixedRef === 'string')) { 13522 { 13523 throw Error( "Expected ref to be a function, a string, an object returned by React.createRef(), or null." ); 13524 } 13525 } 13526 13527 if (!element._owner) { 13528 { 13529 throw Error( "Element ref was specified as a string (" + mixedRef + ") but no owner was set. This could happen for one of the following reasons:\n1. You may be adding a ref to a function component\n2. You may be adding a ref to a component that was not created inside a component's render method\n3. You have multiple copies of React loaded\nSee https://fb.me/react-refs-must-have-owner for more information." ); 13530 } 13531 } 13532 } 13533 } 13534 13535 return mixedRef; 13536 } 13537 13538 function throwOnInvalidObjectType(returnFiber, newChild) { 13539 if (returnFiber.type !== 'textarea') { 13540 var addendum = ''; 13541 13542 { 13543 addendum = ' If you meant to render a collection of children, use an array ' + 'instead.' + getCurrentFiberStackInDev(); 13544 } 13545 13546 { 13547 { 13548 throw Error( "Objects are not valid as a React child (found: " + (Object.prototype.toString.call(newChild) === '[object Object]' ? 'object with keys {' + Object.keys(newChild).join(', ') + '}' : newChild) + ")." + addendum ); 13549 } 13550 } 13551 } 13552 } 13553 13554 function warnOnFunctionType() { 13555 { 13556 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.' + getCurrentFiberStackInDev(); 13557 13558 if (ownerHasFunctionTypeWarning[currentComponentErrorInfo]) { 13559 return; 13560 } 13561 13562 ownerHasFunctionTypeWarning[currentComponentErrorInfo] = true; 13563 13564 error('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.'); 13565 } 13566 } // This wrapper function exists because I expect to clone the code in each path 13567 // to be able to optimize each path individually by branching early. This needs 13568 // a compiler or we can do it manually. Helpers that don't need this branching 13569 // live outside of this function. 13570 13571 13572 function ChildReconciler(shouldTrackSideEffects) { 13573 function deleteChild(returnFiber, childToDelete) { 13574 if (!shouldTrackSideEffects) { 13575 // Noop. 13576 return; 13577 } // Deletions are added in reversed order so we add it to the front. 13578 // At this point, the return fiber's effect list is empty except for 13579 // deletions, so we can just append the deletion to the list. The remaining 13580 // effects aren't added until the complete phase. Once we implement 13581 // resuming, this may not be true. 13582 13583 13584 var last = returnFiber.lastEffect; 13585 13586 if (last !== null) { 13587 last.nextEffect = childToDelete; 13588 returnFiber.lastEffect = childToDelete; 13589 } else { 13590 returnFiber.firstEffect = returnFiber.lastEffect = childToDelete; 13591 } 13592 13593 childToDelete.nextEffect = null; 13594 childToDelete.effectTag = Deletion; 13595 } 13596 13597 function deleteRemainingChildren(returnFiber, currentFirstChild) { 13598 if (!shouldTrackSideEffects) { 13599 // Noop. 13600 return null; 13601 } // TODO: For the shouldClone case, this could be micro-optimized a bit by 13602 // assuming that after the first child we've already added everything. 13603 13604 13605 var childToDelete = currentFirstChild; 13606 13607 while (childToDelete !== null) { 13608 deleteChild(returnFiber, childToDelete); 13609 childToDelete = childToDelete.sibling; 13610 } 13611 13612 return null; 13613 } 13614 13615 function mapRemainingChildren(returnFiber, currentFirstChild) { 13616 // Add the remaining children to a temporary map so that we can find them by 13617 // keys quickly. Implicit (null) keys get added to this set with their index 13618 // instead. 13619 var existingChildren = new Map(); 13620 var existingChild = currentFirstChild; 13621 13622 while (existingChild !== null) { 13623 if (existingChild.key !== null) { 13624 existingChildren.set(existingChild.key, existingChild); 13625 } else { 13626 existingChildren.set(existingChild.index, existingChild); 13627 } 13628 13629 existingChild = existingChild.sibling; 13630 } 13631 13632 return existingChildren; 13633 } 13634 13635 function useFiber(fiber, pendingProps) { 13636 // We currently set sibling to null and index to 0 here because it is easy 13637 // to forget to do before returning it. E.g. for the single child case. 13638 var clone = createWorkInProgress(fiber, pendingProps); 13639 clone.index = 0; 13640 clone.sibling = null; 13641 return clone; 13642 } 13643 13644 function placeChild(newFiber, lastPlacedIndex, newIndex) { 13645 newFiber.index = newIndex; 13646 13647 if (!shouldTrackSideEffects) { 13648 // Noop. 13649 return lastPlacedIndex; 13650 } 13651 13652 var current = newFiber.alternate; 13653 13654 if (current !== null) { 13655 var oldIndex = current.index; 13656 13657 if (oldIndex < lastPlacedIndex) { 13658 // This is a move. 13659 newFiber.effectTag = Placement; 13660 return lastPlacedIndex; 13661 } else { 13662 // This item can stay in place. 13663 return oldIndex; 13664 } 13665 } else { 13666 // This is an insertion. 13667 newFiber.effectTag = Placement; 13668 return lastPlacedIndex; 13669 } 13670 } 13671 13672 function placeSingleChild(newFiber) { 13673 // This is simpler for the single child case. We only need to do a 13674 // placement for inserting new children. 13675 if (shouldTrackSideEffects && newFiber.alternate === null) { 13676 newFiber.effectTag = Placement; 13677 } 13678 13679 return newFiber; 13680 } 13681 13682 function updateTextNode(returnFiber, current, textContent, expirationTime) { 13683 if (current === null || current.tag !== HostText) { 13684 // Insert 13685 var created = createFiberFromText(textContent, returnFiber.mode, expirationTime); 13686 created.return = returnFiber; 13687 return created; 13688 } else { 13689 // Update 13690 var existing = useFiber(current, textContent); 13691 existing.return = returnFiber; 13692 return existing; 13693 } 13694 } 13695 13696 function updateElement(returnFiber, current, element, expirationTime) { 13697 if (current !== null) { 13698 if (current.elementType === element.type || ( // Keep this check inline so it only runs on the false path: 13699 isCompatibleFamilyForHotReloading(current, element) )) { 13700 // Move based on index 13701 var existing = useFiber(current, element.props); 13702 existing.ref = coerceRef(returnFiber, current, element); 13703 existing.return = returnFiber; 13704 13705 { 13706 existing._debugSource = element._source; 13707 existing._debugOwner = element._owner; 13708 } 13709 13710 return existing; 13711 } 13712 } // Insert 13713 13714 13715 var created = createFiberFromElement(element, returnFiber.mode, expirationTime); 13716 created.ref = coerceRef(returnFiber, current, element); 13717 created.return = returnFiber; 13718 return created; 13719 } 13720 13721 function updatePortal(returnFiber, current, portal, expirationTime) { 13722 if (current === null || current.tag !== HostPortal || current.stateNode.containerInfo !== portal.containerInfo || current.stateNode.implementation !== portal.implementation) { 13723 // Insert 13724 var created = createFiberFromPortal(portal, returnFiber.mode, expirationTime); 13725 created.return = returnFiber; 13726 return created; 13727 } else { 13728 // Update 13729 var existing = useFiber(current, portal.children || []); 13730 existing.return = returnFiber; 13731 return existing; 13732 } 13733 } 13734 13735 function updateFragment(returnFiber, current, fragment, expirationTime, key) { 13736 if (current === null || current.tag !== Fragment) { 13737 // Insert 13738 var created = createFiberFromFragment(fragment, returnFiber.mode, expirationTime, key); 13739 created.return = returnFiber; 13740 return created; 13741 } else { 13742 // Update 13743 var existing = useFiber(current, fragment); 13744 existing.return = returnFiber; 13745 return existing; 13746 } 13747 } 13748 13749 function createChild(returnFiber, newChild, expirationTime) { 13750 if (typeof newChild === 'string' || typeof newChild === 'number') { 13751 // Text nodes don't have keys. If the previous node is implicitly keyed 13752 // we can continue to replace it without aborting even if it is not a text 13753 // node. 13754 var created = createFiberFromText('' + newChild, returnFiber.mode, expirationTime); 13755 created.return = returnFiber; 13756 return created; 13757 } 13758 13759 if (typeof newChild === 'object' && newChild !== null) { 13760 switch (newChild.$$typeof) { 13761 case REACT_ELEMENT_TYPE: 13762 { 13763 var _created = createFiberFromElement(newChild, returnFiber.mode, expirationTime); 13764 13765 _created.ref = coerceRef(returnFiber, null, newChild); 13766 _created.return = returnFiber; 13767 return _created; 13768 } 13769 13770 case REACT_PORTAL_TYPE: 13771 { 13772 var _created2 = createFiberFromPortal(newChild, returnFiber.mode, expirationTime); 13773 13774 _created2.return = returnFiber; 13775 return _created2; 13776 } 13777 } 13778 13779 if (isArray$1(newChild) || getIteratorFn(newChild)) { 13780 var _created3 = createFiberFromFragment(newChild, returnFiber.mode, expirationTime, null); 13781 13782 _created3.return = returnFiber; 13783 return _created3; 13784 } 13785 13786 throwOnInvalidObjectType(returnFiber, newChild); 13787 } 13788 13789 { 13790 if (typeof newChild === 'function') { 13791 warnOnFunctionType(); 13792 } 13793 } 13794 13795 return null; 13796 } 13797 13798 function updateSlot(returnFiber, oldFiber, newChild, expirationTime) { 13799 // Update the fiber if the keys match, otherwise return null. 13800 var key = oldFiber !== null ? oldFiber.key : null; 13801 13802 if (typeof newChild === 'string' || typeof newChild === 'number') { 13803 // Text nodes don't have keys. If the previous node is implicitly keyed 13804 // we can continue to replace it without aborting even if it is not a text 13805 // node. 13806 if (key !== null) { 13807 return null; 13808 } 13809 13810 return updateTextNode(returnFiber, oldFiber, '' + newChild, expirationTime); 13811 } 13812 13813 if (typeof newChild === 'object' && newChild !== null) { 13814 switch (newChild.$$typeof) { 13815 case REACT_ELEMENT_TYPE: 13816 { 13817 if (newChild.key === key) { 13818 if (newChild.type === REACT_FRAGMENT_TYPE) { 13819 return updateFragment(returnFiber, oldFiber, newChild.props.children, expirationTime, key); 13820 } 13821 13822 return updateElement(returnFiber, oldFiber, newChild, expirationTime); 13823 } else { 13824 return null; 13825 } 13826 } 13827 13828 case REACT_PORTAL_TYPE: 13829 { 13830 if (newChild.key === key) { 13831 return updatePortal(returnFiber, oldFiber, newChild, expirationTime); 13832 } else { 13833 return null; 13834 } 13835 } 13836 } 13837 13838 if (isArray$1(newChild) || getIteratorFn(newChild)) { 13839 if (key !== null) { 13840 return null; 13841 } 13842 13843 return updateFragment(returnFiber, oldFiber, newChild, expirationTime, null); 13844 } 13845 13846 throwOnInvalidObjectType(returnFiber, newChild); 13847 } 13848 13849 { 13850 if (typeof newChild === 'function') { 13851 warnOnFunctionType(); 13852 } 13853 } 13854 13855 return null; 13856 } 13857 13858 function updateFromMap(existingChildren, returnFiber, newIdx, newChild, expirationTime) { 13859 if (typeof newChild === 'string' || typeof newChild === 'number') { 13860 // Text nodes don't have keys, so we neither have to check the old nor 13861 // new node for the key. If both are text nodes, they match. 13862 var matchedFiber = existingChildren.get(newIdx) || null; 13863 return updateTextNode(returnFiber, matchedFiber, '' + newChild, expirationTime); 13864 } 13865 13866 if (typeof newChild === 'object' && newChild !== null) { 13867 switch (newChild.$$typeof) { 13868 case REACT_ELEMENT_TYPE: 13869 { 13870 var _matchedFiber = existingChildren.get(newChild.key === null ? newIdx : newChild.key) || null; 13871 13872 if (newChild.type === REACT_FRAGMENT_TYPE) { 13873 return updateFragment(returnFiber, _matchedFiber, newChild.props.children, expirationTime, newChild.key); 13874 } 13875 13876 return updateElement(returnFiber, _matchedFiber, newChild, expirationTime); 13877 } 13878 13879 case REACT_PORTAL_TYPE: 13880 { 13881 var _matchedFiber2 = existingChildren.get(newChild.key === null ? newIdx : newChild.key) || null; 13882 13883 return updatePortal(returnFiber, _matchedFiber2, newChild, expirationTime); 13884 } 13885 } 13886 13887 if (isArray$1(newChild) || getIteratorFn(newChild)) { 13888 var _matchedFiber3 = existingChildren.get(newIdx) || null; 13889 13890 return updateFragment(returnFiber, _matchedFiber3, newChild, expirationTime, null); 13891 } 13892 13893 throwOnInvalidObjectType(returnFiber, newChild); 13894 } 13895 13896 { 13897 if (typeof newChild === 'function') { 13898 warnOnFunctionType(); 13899 } 13900 } 13901 13902 return null; 13903 } 13904 /** 13905 * Warns if there is a duplicate or missing key 13906 */ 13907 13908 13909 function warnOnInvalidKey(child, knownKeys) { 13910 { 13911 if (typeof child !== 'object' || child === null) { 13912 return knownKeys; 13913 } 13914 13915 switch (child.$$typeof) { 13916 case REACT_ELEMENT_TYPE: 13917 case REACT_PORTAL_TYPE: 13918 warnForMissingKey(child); 13919 var key = child.key; 13920 13921 if (typeof key !== 'string') { 13922 break; 13923 } 13924 13925 if (knownKeys === null) { 13926 knownKeys = new Set(); 13927 knownKeys.add(key); 13928 break; 13929 } 13930 13931 if (!knownKeys.has(key)) { 13932 knownKeys.add(key); 13933 break; 13934 } 13935 13936 error('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.', key); 13937 13938 break; 13939 } 13940 } 13941 13942 return knownKeys; 13943 } 13944 13945 function reconcileChildrenArray(returnFiber, currentFirstChild, newChildren, expirationTime) { 13946 // This algorithm can't optimize by searching from both ends since we 13947 // don't have backpointers on fibers. I'm trying to see how far we can get 13948 // with that model. If it ends up not being worth the tradeoffs, we can 13949 // add it later. 13950 // Even with a two ended optimization, we'd want to optimize for the case 13951 // where there are few changes and brute force the comparison instead of 13952 // going for the Map. It'd like to explore hitting that path first in 13953 // forward-only mode and only go for the Map once we notice that we need 13954 // lots of look ahead. This doesn't handle reversal as well as two ended 13955 // search but that's unusual. Besides, for the two ended optimization to 13956 // work on Iterables, we'd need to copy the whole set. 13957 // In this first iteration, we'll just live with hitting the bad case 13958 // (adding everything to a Map) in for every insert/move. 13959 // If you change this code, also update reconcileChildrenIterator() which 13960 // uses the same algorithm. 13961 { 13962 // First, validate keys. 13963 var knownKeys = null; 13964 13965 for (var i = 0; i < newChildren.length; i++) { 13966 var child = newChildren[i]; 13967 knownKeys = warnOnInvalidKey(child, knownKeys); 13968 } 13969 } 13970 13971 var resultingFirstChild = null; 13972 var previousNewFiber = null; 13973 var oldFiber = currentFirstChild; 13974 var lastPlacedIndex = 0; 13975 var newIdx = 0; 13976 var nextOldFiber = null; 13977 13978 for (; oldFiber !== null && newIdx < newChildren.length; newIdx++) { 13979 if (oldFiber.index > newIdx) { 13980 nextOldFiber = oldFiber; 13981 oldFiber = null; 13982 } else { 13983 nextOldFiber = oldFiber.sibling; 13984 } 13985 13986 var newFiber = updateSlot(returnFiber, oldFiber, newChildren[newIdx], expirationTime); 13987 13988 if (newFiber === null) { 13989 // TODO: This breaks on empty slots like null children. That's 13990 // unfortunate because it triggers the slow path all the time. We need 13991 // a better way to communicate whether this was a miss or null, 13992 // boolean, undefined, etc. 13993 if (oldFiber === null) { 13994 oldFiber = nextOldFiber; 13995 } 13996 13997 break; 13998 } 13999 14000 if (shouldTrackSideEffects) { 14001 if (oldFiber && newFiber.alternate === null) { 14002 // We matched the slot, but we didn't reuse the existing fiber, so we 14003 // need to delete the existing child. 14004 deleteChild(returnFiber, oldFiber); 14005 } 14006 } 14007 14008 lastPlacedIndex = placeChild(newFiber, lastPlacedIndex, newIdx); 14009 14010 if (previousNewFiber === null) { 14011 // TODO: Move out of the loop. This only happens for the first run. 14012 resultingFirstChild = newFiber; 14013 } else { 14014 // TODO: Defer siblings if we're not at the right index for this slot. 14015 // I.e. if we had null values before, then we want to defer this 14016 // for each null value. However, we also don't want to call updateSlot 14017 // with the previous one. 14018 previousNewFiber.sibling = newFiber; 14019 } 14020 14021 previousNewFiber = newFiber; 14022 oldFiber = nextOldFiber; 14023 } 14024 14025 if (newIdx === newChildren.length) { 14026 // We've reached the end of the new children. We can delete the rest. 14027 deleteRemainingChildren(returnFiber, oldFiber); 14028 return resultingFirstChild; 14029 } 14030 14031 if (oldFiber === null) { 14032 // If we don't have any more existing children we can choose a fast path 14033 // since the rest will all be insertions. 14034 for (; newIdx < newChildren.length; newIdx++) { 14035 var _newFiber = createChild(returnFiber, newChildren[newIdx], expirationTime); 14036 14037 if (_newFiber === null) { 14038 continue; 14039 } 14040 14041 lastPlacedIndex = placeChild(_newFiber, lastPlacedIndex, newIdx); 14042 14043 if (previousNewFiber === null) { 14044 // TODO: Move out of the loop. This only happens for the first run. 14045 resultingFirstChild = _newFiber; 14046 } else { 14047 previousNewFiber.sibling = _newFiber; 14048 } 14049 14050 previousNewFiber = _newFiber; 14051 } 14052 14053 return resultingFirstChild; 14054 } // Add all children to a key map for quick lookups. 14055 14056 14057 var existingChildren = mapRemainingChildren(returnFiber, oldFiber); // Keep scanning and use the map to restore deleted items as moves. 14058 14059 for (; newIdx < newChildren.length; newIdx++) { 14060 var _newFiber2 = updateFromMap(existingChildren, returnFiber, newIdx, newChildren[newIdx], expirationTime); 14061 14062 if (_newFiber2 !== null) { 14063 if (shouldTrackSideEffects) { 14064 if (_newFiber2.alternate !== null) { 14065 // The new fiber is a work in progress, but if there exists a 14066 // current, that means that we reused the fiber. We need to delete 14067 // it from the child list so that we don't add it to the deletion 14068 // list. 14069 existingChildren.delete(_newFiber2.key === null ? newIdx : _newFiber2.key); 14070 } 14071 } 14072 14073 lastPlacedIndex = placeChild(_newFiber2, lastPlacedIndex, newIdx); 14074 14075 if (previousNewFiber === null) { 14076 resultingFirstChild = _newFiber2; 14077 } else { 14078 previousNewFiber.sibling = _newFiber2; 14079 } 14080 14081 previousNewFiber = _newFiber2; 14082 } 14083 } 14084 14085 if (shouldTrackSideEffects) { 14086 // Any existing children that weren't consumed above were deleted. We need 14087 // to add them to the deletion list. 14088 existingChildren.forEach(function (child) { 14089 return deleteChild(returnFiber, child); 14090 }); 14091 } 14092 14093 return resultingFirstChild; 14094 } 14095 14096 function reconcileChildrenIterator(returnFiber, currentFirstChild, newChildrenIterable, expirationTime) { 14097 // This is the same implementation as reconcileChildrenArray(), 14098 // but using the iterator instead. 14099 var iteratorFn = getIteratorFn(newChildrenIterable); 14100 14101 if (!(typeof iteratorFn === 'function')) { 14102 { 14103 throw Error( "An object is not an iterable. This error is likely caused by a bug in React. Please file an issue." ); 14104 } 14105 } 14106 14107 { 14108 // We don't support rendering Generators because it's a mutation. 14109 // See https://github.com/facebook/react/issues/12995 14110 if (typeof Symbol === 'function' && // $FlowFixMe Flow doesn't know about toStringTag 14111 newChildrenIterable[Symbol.toStringTag] === 'Generator') { 14112 if (!didWarnAboutGenerators) { 14113 error('Using Generators as children is unsupported and will likely yield ' + 'unexpected results because enumerating a generator mutates it. ' + 'You may convert it to an array with `Array.from()` or the ' + '`[...spread]` operator before rendering. Keep in mind ' + 'you might need to polyfill these features for older browsers.'); 14114 } 14115 14116 didWarnAboutGenerators = true; 14117 } // Warn about using Maps as children 14118 14119 14120 if (newChildrenIterable.entries === iteratorFn) { 14121 if (!didWarnAboutMaps) { 14122 error('Using Maps as children is unsupported and will likely yield ' + 'unexpected results. Convert it to a sequence/iterable of keyed ' + 'ReactElements instead.'); 14123 } 14124 14125 didWarnAboutMaps = true; 14126 } // First, validate keys. 14127 // We'll get a different iterator later for the main pass. 14128 14129 14130 var _newChildren = iteratorFn.call(newChildrenIterable); 14131 14132 if (_newChildren) { 14133 var knownKeys = null; 14134 14135 var _step = _newChildren.next(); 14136 14137 for (; !_step.done; _step = _newChildren.next()) { 14138 var child = _step.value; 14139 knownKeys = warnOnInvalidKey(child, knownKeys); 14140 } 14141 } 14142 } 14143 14144 var newChildren = iteratorFn.call(newChildrenIterable); 14145 14146 if (!(newChildren != null)) { 14147 { 14148 throw Error( "An iterable object provided no iterator." ); 14149 } 14150 } 14151 14152 var resultingFirstChild = null; 14153 var previousNewFiber = null; 14154 var oldFiber = currentFirstChild; 14155 var lastPlacedIndex = 0; 14156 var newIdx = 0; 14157 var nextOldFiber = null; 14158 var step = newChildren.next(); 14159 14160 for (; oldFiber !== null && !step.done; newIdx++, step = newChildren.next()) { 14161 if (oldFiber.index > newIdx) { 14162 nextOldFiber = oldFiber; 14163 oldFiber = null; 14164 } else { 14165 nextOldFiber = oldFiber.sibling; 14166 } 14167 14168 var newFiber = updateSlot(returnFiber, oldFiber, step.value, expirationTime); 14169 14170 if (newFiber === null) { 14171 // TODO: This breaks on empty slots like null children. That's 14172 // unfortunate because it triggers the slow path all the time. We need 14173 // a better way to communicate whether this was a miss or null, 14174 // boolean, undefined, etc. 14175 if (oldFiber === null) { 14176 oldFiber = nextOldFiber; 14177 } 14178 14179 break; 14180 } 14181 14182 if (shouldTrackSideEffects) { 14183 if (oldFiber && newFiber.alternate === null) { 14184 // We matched the slot, but we didn't reuse the existing fiber, so we 14185 // need to delete the existing child. 14186 deleteChild(returnFiber, oldFiber); 14187 } 14188 } 14189 14190 lastPlacedIndex = placeChild(newFiber, lastPlacedIndex, newIdx); 14191 14192 if (previousNewFiber === null) { 14193 // TODO: Move out of the loop. This only happens for the first run. 14194 resultingFirstChild = newFiber; 14195 } else { 14196 // TODO: Defer siblings if we're not at the right index for this slot. 14197 // I.e. if we had null values before, then we want to defer this 14198 // for each null value. However, we also don't want to call updateSlot 14199 // with the previous one. 14200 previousNewFiber.sibling = newFiber; 14201 } 14202 14203 previousNewFiber = newFiber; 14204 oldFiber = nextOldFiber; 14205 } 14206 14207 if (step.done) { 14208 // We've reached the end of the new children. We can delete the rest. 14209 deleteRemainingChildren(returnFiber, oldFiber); 14210 return resultingFirstChild; 14211 } 14212 14213 if (oldFiber === null) { 14214 // If we don't have any more existing children we can choose a fast path 14215 // since the rest will all be insertions. 14216 for (; !step.done; newIdx++, step = newChildren.next()) { 14217 var _newFiber3 = createChild(returnFiber, step.value, expirationTime); 14218 14219 if (_newFiber3 === null) { 14220 continue; 14221 } 14222 14223 lastPlacedIndex = placeChild(_newFiber3, lastPlacedIndex, newIdx); 14224 14225 if (previousNewFiber === null) { 14226 // TODO: Move out of the loop. This only happens for the first run. 14227 resultingFirstChild = _newFiber3; 14228 } else { 14229 previousNewFiber.sibling = _newFiber3; 14230 } 14231 14232 previousNewFiber = _newFiber3; 14233 } 14234 14235 return resultingFirstChild; 14236 } // Add all children to a key map for quick lookups. 14237 14238 14239 var existingChildren = mapRemainingChildren(returnFiber, oldFiber); // Keep scanning and use the map to restore deleted items as moves. 14240 14241 for (; !step.done; newIdx++, step = newChildren.next()) { 14242 var _newFiber4 = updateFromMap(existingChildren, returnFiber, newIdx, step.value, expirationTime); 14243 14244 if (_newFiber4 !== null) { 14245 if (shouldTrackSideEffects) { 14246 if (_newFiber4.alternate !== null) { 14247 // The new fiber is a work in progress, but if there exists a 14248 // current, that means that we reused the fiber. We need to delete 14249 // it from the child list so that we don't add it to the deletion 14250 // list. 14251 existingChildren.delete(_newFiber4.key === null ? newIdx : _newFiber4.key); 14252 } 14253 } 14254 14255 lastPlacedIndex = placeChild(_newFiber4, lastPlacedIndex, newIdx); 14256 14257 if (previousNewFiber === null) { 14258 resultingFirstChild = _newFiber4; 14259 } else { 14260 previousNewFiber.sibling = _newFiber4; 14261 } 14262 14263 previousNewFiber = _newFiber4; 14264 } 14265 } 14266 14267 if (shouldTrackSideEffects) { 14268 // Any existing children that weren't consumed above were deleted. We need 14269 // to add them to the deletion list. 14270 existingChildren.forEach(function (child) { 14271 return deleteChild(returnFiber, child); 14272 }); 14273 } 14274 14275 return resultingFirstChild; 14276 } 14277 14278 function reconcileSingleTextNode(returnFiber, currentFirstChild, textContent, expirationTime) { 14279 // There's no need to check for keys on text nodes since we don't have a 14280 // way to define them. 14281 if (currentFirstChild !== null && currentFirstChild.tag === HostText) { 14282 // We already have an existing node so let's just update it and delete 14283 // the rest. 14284 deleteRemainingChildren(returnFiber, currentFirstChild.sibling); 14285 var existing = useFiber(currentFirstChild, textContent); 14286 existing.return = returnFiber; 14287 return existing; 14288 } // The existing first child is not a text node so we need to create one 14289 // and delete the existing ones. 14290 14291 14292 deleteRemainingChildren(returnFiber, currentFirstChild); 14293 var created = createFiberFromText(textContent, returnFiber.mode, expirationTime); 14294 created.return = returnFiber; 14295 return created; 14296 } 14297 14298 function reconcileSingleElement(returnFiber, currentFirstChild, element, expirationTime) { 14299 var key = element.key; 14300 var child = currentFirstChild; 14301 14302 while (child !== null) { 14303 // TODO: If key === null and child.key === null, then this only applies to 14304 // the first item in the list. 14305 if (child.key === key) { 14306 switch (child.tag) { 14307 case Fragment: 14308 { 14309 if (element.type === REACT_FRAGMENT_TYPE) { 14310 deleteRemainingChildren(returnFiber, child.sibling); 14311 var existing = useFiber(child, element.props.children); 14312 existing.return = returnFiber; 14313 14314 { 14315 existing._debugSource = element._source; 14316 existing._debugOwner = element._owner; 14317 } 14318 14319 return existing; 14320 } 14321 14322 break; 14323 } 14324 14325 case Block: 14326 14327 // We intentionally fallthrough here if enableBlocksAPI is not on. 14328 // eslint-disable-next-lined no-fallthrough 14329 14330 default: 14331 { 14332 if (child.elementType === element.type || ( // Keep this check inline so it only runs on the false path: 14333 isCompatibleFamilyForHotReloading(child, element) )) { 14334 deleteRemainingChildren(returnFiber, child.sibling); 14335 14336 var _existing3 = useFiber(child, element.props); 14337 14338 _existing3.ref = coerceRef(returnFiber, child, element); 14339 _existing3.return = returnFiber; 14340 14341 { 14342 _existing3._debugSource = element._source; 14343 _existing3._debugOwner = element._owner; 14344 } 14345 14346 return _existing3; 14347 } 14348 14349 break; 14350 } 14351 } // Didn't match. 14352 14353 14354 deleteRemainingChildren(returnFiber, child); 14355 break; 14356 } else { 14357 deleteChild(returnFiber, child); 14358 } 14359 14360 child = child.sibling; 14361 } 14362 14363 if (element.type === REACT_FRAGMENT_TYPE) { 14364 var created = createFiberFromFragment(element.props.children, returnFiber.mode, expirationTime, element.key); 14365 created.return = returnFiber; 14366 return created; 14367 } else { 14368 var _created4 = createFiberFromElement(element, returnFiber.mode, expirationTime); 14369 14370 _created4.ref = coerceRef(returnFiber, currentFirstChild, element); 14371 _created4.return = returnFiber; 14372 return _created4; 14373 } 14374 } 14375 14376 function reconcileSinglePortal(returnFiber, currentFirstChild, portal, expirationTime) { 14377 var key = portal.key; 14378 var child = currentFirstChild; 14379 14380 while (child !== null) { 14381 // TODO: If key === null and child.key === null, then this only applies to 14382 // the first item in the list. 14383 if (child.key === key) { 14384 if (child.tag === HostPortal && child.stateNode.containerInfo === portal.containerInfo && child.stateNode.implementation === portal.implementation) { 14385 deleteRemainingChildren(returnFiber, child.sibling); 14386 var existing = useFiber(child, portal.children || []); 14387 existing.return = returnFiber; 14388 return existing; 14389 } else { 14390 deleteRemainingChildren(returnFiber, child); 14391 break; 14392 } 14393 } else { 14394 deleteChild(returnFiber, child); 14395 } 14396 14397 child = child.sibling; 14398 } 14399 14400 var created = createFiberFromPortal(portal, returnFiber.mode, expirationTime); 14401 created.return = returnFiber; 14402 return created; 14403 } // This API will tag the children with the side-effect of the reconciliation 14404 // itself. They will be added to the side-effect list as we pass through the 14405 // children and the parent. 14406 14407 14408 function reconcileChildFibers(returnFiber, currentFirstChild, newChild, expirationTime) { 14409 // This function is not recursive. 14410 // If the top level item is an array, we treat it as a set of children, 14411 // not as a fragment. Nested arrays on the other hand will be treated as 14412 // fragment nodes. Recursion happens at the normal flow. 14413 // Handle top level unkeyed fragments as if they were arrays. 14414 // This leads to an ambiguity between <>{[...]}</> and <>...</>. 14415 // We treat the ambiguous cases above the same. 14416 var isUnkeyedTopLevelFragment = typeof newChild === 'object' && newChild !== null && newChild.type === REACT_FRAGMENT_TYPE && newChild.key === null; 14417 14418 if (isUnkeyedTopLevelFragment) { 14419 newChild = newChild.props.children; 14420 } // Handle object types 14421 14422 14423 var isObject = typeof newChild === 'object' && newChild !== null; 14424 14425 if (isObject) { 14426 switch (newChild.$$typeof) { 14427 case REACT_ELEMENT_TYPE: 14428 return placeSingleChild(reconcileSingleElement(returnFiber, currentFirstChild, newChild, expirationTime)); 14429 14430 case REACT_PORTAL_TYPE: 14431 return placeSingleChild(reconcileSinglePortal(returnFiber, currentFirstChild, newChild, expirationTime)); 14432 } 14433 } 14434 14435 if (typeof newChild === 'string' || typeof newChild === 'number') { 14436 return placeSingleChild(reconcileSingleTextNode(returnFiber, currentFirstChild, '' + newChild, expirationTime)); 14437 } 14438 14439 if (isArray$1(newChild)) { 14440 return reconcileChildrenArray(returnFiber, currentFirstChild, newChild, expirationTime); 14441 } 14442 14443 if (getIteratorFn(newChild)) { 14444 return reconcileChildrenIterator(returnFiber, currentFirstChild, newChild, expirationTime); 14445 } 14446 14447 if (isObject) { 14448 throwOnInvalidObjectType(returnFiber, newChild); 14449 } 14450 14451 { 14452 if (typeof newChild === 'function') { 14453 warnOnFunctionType(); 14454 } 14455 } 14456 14457 if (typeof newChild === 'undefined' && !isUnkeyedTopLevelFragment) { 14458 // If the new child is undefined, and the return fiber is a composite 14459 // component, throw an error. If Fiber return types are disabled, 14460 // we already threw above. 14461 switch (returnFiber.tag) { 14462 case ClassComponent: 14463 { 14464 { 14465 var instance = returnFiber.stateNode; 14466 14467 if (instance.render._isMockFunction) { 14468 // We allow auto-mocks to proceed as if they're returning null. 14469 break; 14470 } 14471 } 14472 } 14473 // Intentionally fall through to the next case, which handles both 14474 // functions and classes 14475 // eslint-disable-next-lined no-fallthrough 14476 14477 case FunctionComponent: 14478 { 14479 var Component = returnFiber.type; 14480 14481 { 14482 { 14483 throw Error( (Component.displayName || Component.name || 'Component') + "(...): Nothing was returned from render. This usually means a return statement is missing. Or, to render nothing, return null." ); 14484 } 14485 } 14486 } 14487 } 14488 } // Remaining cases are all treated as empty. 14489 14490 14491 return deleteRemainingChildren(returnFiber, currentFirstChild); 14492 } 14493 14494 return reconcileChildFibers; 14495 } 14496 14497 var reconcileChildFibers = ChildReconciler(true); 14498 var mountChildFibers = ChildReconciler(false); 14499 function cloneChildFibers(current, workInProgress) { 14500 if (!(current === null || workInProgress.child === current.child)) { 14501 { 14502 throw Error( "Resuming work not yet implemented." ); 14503 } 14504 } 14505 14506 if (workInProgress.child === null) { 14507 return; 14508 } 14509 14510 var currentChild = workInProgress.child; 14511 var newChild = createWorkInProgress(currentChild, currentChild.pendingProps); 14512 workInProgress.child = newChild; 14513 newChild.return = workInProgress; 14514 14515 while (currentChild.sibling !== null) { 14516 currentChild = currentChild.sibling; 14517 newChild = newChild.sibling = createWorkInProgress(currentChild, currentChild.pendingProps); 14518 newChild.return = workInProgress; 14519 } 14520 14521 newChild.sibling = null; 14522 } // Reset a workInProgress child set to prepare it for a second pass. 14523 14524 function resetChildFibers(workInProgress, renderExpirationTime) { 14525 var child = workInProgress.child; 14526 14527 while (child !== null) { 14528 resetWorkInProgress(child, renderExpirationTime); 14529 child = child.sibling; 14530 } 14531 } 14532 14533 var NO_CONTEXT = {}; 14534 var contextStackCursor$1 = createCursor(NO_CONTEXT); 14535 var contextFiberStackCursor = createCursor(NO_CONTEXT); 14536 var rootInstanceStackCursor = createCursor(NO_CONTEXT); 14537 14538 function requiredContext(c) { 14539 if (!(c !== NO_CONTEXT)) { 14540 { 14541 throw Error( "Expected host context to exist. This error is likely caused by a bug in React. Please file an issue." ); 14542 } 14543 } 14544 14545 return c; 14546 } 14547 14548 function getRootHostContainer() { 14549 var rootInstance = requiredContext(rootInstanceStackCursor.current); 14550 return rootInstance; 14551 } 14552 14553 function pushHostContainer(fiber, nextRootInstance) { 14554 // Push current root instance onto the stack; 14555 // This allows us to reset root when portals are popped. 14556 push(rootInstanceStackCursor, nextRootInstance, fiber); // Track the context and the Fiber that provided it. 14557 // This enables us to pop only Fibers that provide unique contexts. 14558 14559 push(contextFiberStackCursor, fiber, fiber); // Finally, we need to push the host context to the stack. 14560 // However, we can't just call getRootHostContext() and push it because 14561 // we'd have a different number of entries on the stack depending on 14562 // whether getRootHostContext() throws somewhere in renderer code or not. 14563 // So we push an empty value first. This lets us safely unwind on errors. 14564 14565 push(contextStackCursor$1, NO_CONTEXT, fiber); 14566 var nextRootContext = getRootHostContext(nextRootInstance); // Now that we know this function doesn't throw, replace it. 14567 14568 pop(contextStackCursor$1, fiber); 14569 push(contextStackCursor$1, nextRootContext, fiber); 14570 } 14571 14572 function popHostContainer(fiber) { 14573 pop(contextStackCursor$1, fiber); 14574 pop(contextFiberStackCursor, fiber); 14575 pop(rootInstanceStackCursor, fiber); 14576 } 14577 14578 function getHostContext() { 14579 var context = requiredContext(contextStackCursor$1.current); 14580 return context; 14581 } 14582 14583 function pushHostContext(fiber) { 14584 var rootInstance = requiredContext(rootInstanceStackCursor.current); 14585 var context = requiredContext(contextStackCursor$1.current); 14586 var nextContext = getChildHostContext(context, fiber.type); // Don't push this Fiber's context unless it's unique. 14587 14588 if (context === nextContext) { 14589 return; 14590 } // Track the context and the Fiber that provided it. 14591 // This enables us to pop only Fibers that provide unique contexts. 14592 14593 14594 push(contextFiberStackCursor, fiber, fiber); 14595 push(contextStackCursor$1, nextContext, fiber); 14596 } 14597 14598 function popHostContext(fiber) { 14599 // Do not pop unless this Fiber provided the current context. 14600 // pushHostContext() only pushes Fibers that provide unique contexts. 14601 if (contextFiberStackCursor.current !== fiber) { 14602 return; 14603 } 14604 14605 pop(contextStackCursor$1, fiber); 14606 pop(contextFiberStackCursor, fiber); 14607 } 14608 14609 var DefaultSuspenseContext = 0; // The Suspense Context is split into two parts. The lower bits is 14610 // inherited deeply down the subtree. The upper bits only affect 14611 // this immediate suspense boundary and gets reset each new 14612 // boundary or suspense list. 14613 14614 var SubtreeSuspenseContextMask = 1; // Subtree Flags: 14615 // InvisibleParentSuspenseContext indicates that one of our parent Suspense 14616 // boundaries is not currently showing visible main content. 14617 // Either because it is already showing a fallback or is not mounted at all. 14618 // We can use this to determine if it is desirable to trigger a fallback at 14619 // the parent. If not, then we might need to trigger undesirable boundaries 14620 // and/or suspend the commit to avoid hiding the parent content. 14621 14622 var InvisibleParentSuspenseContext = 1; // Shallow Flags: 14623 // ForceSuspenseFallback can be used by SuspenseList to force newly added 14624 // items into their fallback state during one of the render passes. 14625 14626 var ForceSuspenseFallback = 2; 14627 var suspenseStackCursor = createCursor(DefaultSuspenseContext); 14628 function hasSuspenseContext(parentContext, flag) { 14629 return (parentContext & flag) !== 0; 14630 } 14631 function setDefaultShallowSuspenseContext(parentContext) { 14632 return parentContext & SubtreeSuspenseContextMask; 14633 } 14634 function setShallowSuspenseContext(parentContext, shallowContext) { 14635 return parentContext & SubtreeSuspenseContextMask | shallowContext; 14636 } 14637 function addSubtreeSuspenseContext(parentContext, subtreeContext) { 14638 return parentContext | subtreeContext; 14639 } 14640 function pushSuspenseContext(fiber, newContext) { 14641 push(suspenseStackCursor, newContext, fiber); 14642 } 14643 function popSuspenseContext(fiber) { 14644 pop(suspenseStackCursor, fiber); 14645 } 14646 14647 function shouldCaptureSuspense(workInProgress, hasInvisibleParent) { 14648 // If it was the primary children that just suspended, capture and render the 14649 // fallback. Otherwise, don't capture and bubble to the next boundary. 14650 var nextState = workInProgress.memoizedState; 14651 14652 if (nextState !== null) { 14653 if (nextState.dehydrated !== null) { 14654 // A dehydrated boundary always captures. 14655 return true; 14656 } 14657 14658 return false; 14659 } 14660 14661 var props = workInProgress.memoizedProps; // In order to capture, the Suspense component must have a fallback prop. 14662 14663 if (props.fallback === undefined) { 14664 return false; 14665 } // Regular boundaries always capture. 14666 14667 14668 if (props.unstable_avoidThisFallback !== true) { 14669 return true; 14670 } // If it's a boundary we should avoid, then we prefer to bubble up to the 14671 // parent boundary if it is currently invisible. 14672 14673 14674 if (hasInvisibleParent) { 14675 return false; 14676 } // If the parent is not able to handle it, we must handle it. 14677 14678 14679 return true; 14680 } 14681 function findFirstSuspended(row) { 14682 var node = row; 14683 14684 while (node !== null) { 14685 if (node.tag === SuspenseComponent) { 14686 var state = node.memoizedState; 14687 14688 if (state !== null) { 14689 var dehydrated = state.dehydrated; 14690 14691 if (dehydrated === null || isSuspenseInstancePending(dehydrated) || isSuspenseInstanceFallback(dehydrated)) { 14692 return node; 14693 } 14694 } 14695 } else if (node.tag === SuspenseListComponent && // revealOrder undefined can't be trusted because it don't 14696 // keep track of whether it suspended or not. 14697 node.memoizedProps.revealOrder !== undefined) { 14698 var didSuspend = (node.effectTag & DidCapture) !== NoEffect; 14699 14700 if (didSuspend) { 14701 return node; 14702 } 14703 } else if (node.child !== null) { 14704 node.child.return = node; 14705 node = node.child; 14706 continue; 14707 } 14708 14709 if (node === row) { 14710 return null; 14711 } 14712 14713 while (node.sibling === null) { 14714 if (node.return === null || node.return === row) { 14715 return null; 14716 } 14717 14718 node = node.return; 14719 } 14720 14721 node.sibling.return = node.return; 14722 node = node.sibling; 14723 } 14724 14725 return null; 14726 } 14727 14728 function createDeprecatedResponderListener(responder, props) { 14729 var eventResponderListener = { 14730 responder: responder, 14731 props: props 14732 }; 14733 14734 { 14735 Object.freeze(eventResponderListener); 14736 } 14737 14738 return eventResponderListener; 14739 } 14740 14741 var HasEffect = 14742 /* */ 14743 1; // Represents the phase in which the effect (not the clean-up) fires. 14744 14745 var Layout = 14746 /* */ 14747 2; 14748 var Passive$1 = 14749 /* */ 14750 4; 14751 14752 var ReactCurrentDispatcher = ReactSharedInternals.ReactCurrentDispatcher, 14753 ReactCurrentBatchConfig$1 = ReactSharedInternals.ReactCurrentBatchConfig; 14754 var didWarnAboutMismatchedHooksForComponent; 14755 14756 { 14757 didWarnAboutMismatchedHooksForComponent = new Set(); 14758 } 14759 14760 // These are set right before calling the component. 14761 var renderExpirationTime = NoWork; // The work-in-progress fiber. I've named it differently to distinguish it from 14762 // the work-in-progress hook. 14763 14764 var currentlyRenderingFiber$1 = null; // Hooks are stored as a linked list on the fiber's memoizedState field. The 14765 // current hook list is the list that belongs to the current fiber. The 14766 // work-in-progress hook list is a new list that will be added to the 14767 // work-in-progress fiber. 14768 14769 var currentHook = null; 14770 var workInProgressHook = null; // Whether an update was scheduled at any point during the render phase. This 14771 // does not get reset if we do another render pass; only when we're completely 14772 // finished evaluating this component. This is an optimization so we know 14773 // whether we need to clear render phase updates after a throw. 14774 14775 var didScheduleRenderPhaseUpdate = false; 14776 var RE_RENDER_LIMIT = 25; // In DEV, this is the name of the currently executing primitive hook 14777 14778 var currentHookNameInDev = null; // In DEV, this list ensures that hooks are called in the same order between renders. 14779 // The list stores the order of hooks used during the initial render (mount). 14780 // Subsequent renders (updates) reference this list. 14781 14782 var hookTypesDev = null; 14783 var hookTypesUpdateIndexDev = -1; // In DEV, this tracks whether currently rendering component needs to ignore 14784 // the dependencies for Hooks that need them (e.g. useEffect or useMemo). 14785 // When true, such Hooks will always be "remounted". Only used during hot reload. 14786 14787 var ignorePreviousDependencies = false; 14788 14789 function mountHookTypesDev() { 14790 { 14791 var hookName = currentHookNameInDev; 14792 14793 if (hookTypesDev === null) { 14794 hookTypesDev = [hookName]; 14795 } else { 14796 hookTypesDev.push(hookName); 14797 } 14798 } 14799 } 14800 14801 function updateHookTypesDev() { 14802 { 14803 var hookName = currentHookNameInDev; 14804 14805 if (hookTypesDev !== null) { 14806 hookTypesUpdateIndexDev++; 14807 14808 if (hookTypesDev[hookTypesUpdateIndexDev] !== hookName) { 14809 warnOnHookMismatchInDev(hookName); 14810 } 14811 } 14812 } 14813 } 14814 14815 function checkDepsAreArrayDev(deps) { 14816 { 14817 if (deps !== undefined && deps !== null && !Array.isArray(deps)) { 14818 // Verify deps, but only on mount to avoid extra checks. 14819 // It's unlikely their type would change as usually you define them inline. 14820 error('%s received a final argument that is not an array (instead, received `%s`). When ' + 'specified, the final argument must be an array.', currentHookNameInDev, typeof deps); 14821 } 14822 } 14823 } 14824 14825 function warnOnHookMismatchInDev(currentHookName) { 14826 { 14827 var componentName = getComponentName(currentlyRenderingFiber$1.type); 14828 14829 if (!didWarnAboutMismatchedHooksForComponent.has(componentName)) { 14830 didWarnAboutMismatchedHooksForComponent.add(componentName); 14831 14832 if (hookTypesDev !== null) { 14833 var table = ''; 14834 var secondColumnStart = 30; 14835 14836 for (var i = 0; i <= hookTypesUpdateIndexDev; i++) { 14837 var oldHookName = hookTypesDev[i]; 14838 var newHookName = i === hookTypesUpdateIndexDev ? currentHookName : oldHookName; 14839 var row = i + 1 + ". " + oldHookName; // Extra space so second column lines up 14840 // lol @ IE not supporting String#repeat 14841 14842 while (row.length < secondColumnStart) { 14843 row += ' '; 14844 } 14845 14846 row += newHookName + '\n'; 14847 table += row; 14848 } 14849 14850 error('React has detected a change in the order of Hooks called by %s. ' + 'This will lead to bugs and errors if not fixed. ' + 'For more information, read the Rules of Hooks: https://fb.me/rules-of-hooks\n\n' + ' Previous render Next render\n' + ' ------------------------------------------------------\n' + '%s' + ' ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n', componentName, table); 14851 } 14852 } 14853 } 14854 } 14855 14856 function throwInvalidHookError() { 14857 { 14858 { 14859 throw Error( "Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:\n1. You might have mismatching versions of React and the renderer (such as React DOM)\n2. You might be breaking the Rules of Hooks\n3. You might have more than one copy of React in the same app\nSee https://fb.me/react-invalid-hook-call for tips about how to debug and fix this problem." ); 14860 } 14861 } 14862 } 14863 14864 function areHookInputsEqual(nextDeps, prevDeps) { 14865 { 14866 if (ignorePreviousDependencies) { 14867 // Only true when this component is being hot reloaded. 14868 return false; 14869 } 14870 } 14871 14872 if (prevDeps === null) { 14873 { 14874 error('%s received a final argument during this render, but not during ' + 'the previous render. Even though the final argument is optional, ' + 'its type cannot change between renders.', currentHookNameInDev); 14875 } 14876 14877 return false; 14878 } 14879 14880 { 14881 // Don't bother comparing lengths in prod because these arrays should be 14882 // passed inline. 14883 if (nextDeps.length !== prevDeps.length) { 14884 error('The final argument passed to %s changed size between renders. The ' + 'order and size of this array must remain constant.\n\n' + 'Previous: %s\n' + 'Incoming: %s', currentHookNameInDev, "[" + prevDeps.join(', ') + "]", "[" + nextDeps.join(', ') + "]"); 14885 } 14886 } 14887 14888 for (var i = 0; i < prevDeps.length && i < nextDeps.length; i++) { 14889 if (objectIs(nextDeps[i], prevDeps[i])) { 14890 continue; 14891 } 14892 14893 return false; 14894 } 14895 14896 return true; 14897 } 14898 14899 function renderWithHooks(current, workInProgress, Component, props, secondArg, nextRenderExpirationTime) { 14900 renderExpirationTime = nextRenderExpirationTime; 14901 currentlyRenderingFiber$1 = workInProgress; 14902 14903 { 14904 hookTypesDev = current !== null ? current._debugHookTypes : null; 14905 hookTypesUpdateIndexDev = -1; // Used for hot reloading: 14906 14907 ignorePreviousDependencies = current !== null && current.type !== workInProgress.type; 14908 } 14909 14910 workInProgress.memoizedState = null; 14911 workInProgress.updateQueue = null; 14912 workInProgress.expirationTime = NoWork; // The following should have already been reset 14913 // currentHook = null; 14914 // workInProgressHook = null; 14915 // didScheduleRenderPhaseUpdate = false; 14916 // TODO Warn if no hooks are used at all during mount, then some are used during update. 14917 // Currently we will identify the update render as a mount because memoizedState === null. 14918 // This is tricky because it's valid for certain types of components (e.g. React.lazy) 14919 // Using memoizedState to differentiate between mount/update only works if at least one stateful hook is used. 14920 // Non-stateful hooks (e.g. context) don't get added to memoizedState, 14921 // so memoizedState would be null during updates and mounts. 14922 14923 { 14924 if (current !== null && current.memoizedState !== null) { 14925 ReactCurrentDispatcher.current = HooksDispatcherOnUpdateInDEV; 14926 } else if (hookTypesDev !== null) { 14927 // This dispatcher handles an edge case where a component is updating, 14928 // but no stateful hooks have been used. 14929 // We want to match the production code behavior (which will use HooksDispatcherOnMount), 14930 // but with the extra DEV validation to ensure hooks ordering hasn't changed. 14931 // This dispatcher does that. 14932 ReactCurrentDispatcher.current = HooksDispatcherOnMountWithHookTypesInDEV; 14933 } else { 14934 ReactCurrentDispatcher.current = HooksDispatcherOnMountInDEV; 14935 } 14936 } 14937 14938 var children = Component(props, secondArg); // Check if there was a render phase update 14939 14940 if (workInProgress.expirationTime === renderExpirationTime) { 14941 // Keep rendering in a loop for as long as render phase updates continue to 14942 // be scheduled. Use a counter to prevent infinite loops. 14943 var numberOfReRenders = 0; 14944 14945 do { 14946 workInProgress.expirationTime = NoWork; 14947 14948 if (!(numberOfReRenders < RE_RENDER_LIMIT)) { 14949 { 14950 throw Error( "Too many re-renders. React limits the number of renders to prevent an infinite loop." ); 14951 } 14952 } 14953 14954 numberOfReRenders += 1; 14955 14956 { 14957 // Even when hot reloading, allow dependencies to stabilize 14958 // after first render to prevent infinite render phase updates. 14959 ignorePreviousDependencies = false; 14960 } // Start over from the beginning of the list 14961 14962 14963 currentHook = null; 14964 workInProgressHook = null; 14965 workInProgress.updateQueue = null; 14966 14967 { 14968 // Also validate hook order for cascading updates. 14969 hookTypesUpdateIndexDev = -1; 14970 } 14971 14972 ReactCurrentDispatcher.current = HooksDispatcherOnRerenderInDEV ; 14973 children = Component(props, secondArg); 14974 } while (workInProgress.expirationTime === renderExpirationTime); 14975 } // We can assume the previous dispatcher is always this one, since we set it 14976 // at the beginning of the render phase and there's no re-entrancy. 14977 14978 14979 ReactCurrentDispatcher.current = ContextOnlyDispatcher; 14980 14981 { 14982 workInProgress._debugHookTypes = hookTypesDev; 14983 } // This check uses currentHook so that it works the same in DEV and prod bundles. 14984 // hookTypesDev could catch more cases (e.g. context) but only in DEV bundles. 14985 14986 14987 var didRenderTooFewHooks = currentHook !== null && currentHook.next !== null; 14988 renderExpirationTime = NoWork; 14989 currentlyRenderingFiber$1 = null; 14990 currentHook = null; 14991 workInProgressHook = null; 14992 14993 { 14994 currentHookNameInDev = null; 14995 hookTypesDev = null; 14996 hookTypesUpdateIndexDev = -1; 14997 } 14998 14999 didScheduleRenderPhaseUpdate = false; 15000 15001 if (!!didRenderTooFewHooks) { 15002 { 15003 throw Error( "Rendered fewer hooks than expected. This may be caused by an accidental early return statement." ); 15004 } 15005 } 15006 15007 return children; 15008 } 15009 function bailoutHooks(current, workInProgress, expirationTime) { 15010 workInProgress.updateQueue = current.updateQueue; 15011 workInProgress.effectTag &= ~(Passive | Update); 15012 15013 if (current.expirationTime <= expirationTime) { 15014 current.expirationTime = NoWork; 15015 } 15016 } 15017 function resetHooksAfterThrow() { 15018 // We can assume the previous dispatcher is always this one, since we set it 15019 // at the beginning of the render phase and there's no re-entrancy. 15020 ReactCurrentDispatcher.current = ContextOnlyDispatcher; 15021 15022 if (didScheduleRenderPhaseUpdate) { 15023 // There were render phase updates. These are only valid for this render 15024 // phase, which we are now aborting. Remove the updates from the queues so 15025 // they do not persist to the next render. Do not remove updates from hooks 15026 // that weren't processed. 15027 // 15028 // Only reset the updates from the queue if it has a clone. If it does 15029 // not have a clone, that means it wasn't processed, and the updates were 15030 // scheduled before we entered the render phase. 15031 var hook = currentlyRenderingFiber$1.memoizedState; 15032 15033 while (hook !== null) { 15034 var queue = hook.queue; 15035 15036 if (queue !== null) { 15037 queue.pending = null; 15038 } 15039 15040 hook = hook.next; 15041 } 15042 } 15043 15044 renderExpirationTime = NoWork; 15045 currentlyRenderingFiber$1 = null; 15046 currentHook = null; 15047 workInProgressHook = null; 15048 15049 { 15050 hookTypesDev = null; 15051 hookTypesUpdateIndexDev = -1; 15052 currentHookNameInDev = null; 15053 } 15054 15055 didScheduleRenderPhaseUpdate = false; 15056 } 15057 15058 function mountWorkInProgressHook() { 15059 var hook = { 15060 memoizedState: null, 15061 baseState: null, 15062 baseQueue: null, 15063 queue: null, 15064 next: null 15065 }; 15066 15067 if (workInProgressHook === null) { 15068 // This is the first hook in the list 15069 currentlyRenderingFiber$1.memoizedState = workInProgressHook = hook; 15070 } else { 15071 // Append to the end of the list 15072 workInProgressHook = workInProgressHook.next = hook; 15073 } 15074 15075 return workInProgressHook; 15076 } 15077 15078 function updateWorkInProgressHook() { 15079 // This function is used both for updates and for re-renders triggered by a 15080 // render phase update. It assumes there is either a current hook we can 15081 // clone, or a work-in-progress hook from a previous render pass that we can 15082 // use as a base. When we reach the end of the base list, we must switch to 15083 // the dispatcher used for mounts. 15084 var nextCurrentHook; 15085 15086 if (currentHook === null) { 15087 var current = currentlyRenderingFiber$1.alternate; 15088 15089 if (current !== null) { 15090 nextCurrentHook = current.memoizedState; 15091 } else { 15092 nextCurrentHook = null; 15093 } 15094 } else { 15095 nextCurrentHook = currentHook.next; 15096 } 15097 15098 var nextWorkInProgressHook; 15099 15100 if (workInProgressHook === null) { 15101 nextWorkInProgressHook = currentlyRenderingFiber$1.memoizedState; 15102 } else { 15103 nextWorkInProgressHook = workInProgressHook.next; 15104 } 15105 15106 if (nextWorkInProgressHook !== null) { 15107 // There's already a work-in-progress. Reuse it. 15108 workInProgressHook = nextWorkInProgressHook; 15109 nextWorkInProgressHook = workInProgressHook.next; 15110 currentHook = nextCurrentHook; 15111 } else { 15112 // Clone from the current hook. 15113 if (!(nextCurrentHook !== null)) { 15114 { 15115 throw Error( "Rendered more hooks than during the previous render." ); 15116 } 15117 } 15118 15119 currentHook = nextCurrentHook; 15120 var newHook = { 15121 memoizedState: currentHook.memoizedState, 15122 baseState: currentHook.baseState, 15123 baseQueue: currentHook.baseQueue, 15124 queue: currentHook.queue, 15125 next: null 15126 }; 15127 15128 if (workInProgressHook === null) { 15129 // This is the first hook in the list. 15130 currentlyRenderingFiber$1.memoizedState = workInProgressHook = newHook; 15131 } else { 15132 // Append to the end of the list. 15133 workInProgressHook = workInProgressHook.next = newHook; 15134 } 15135 } 15136 15137 return workInProgressHook; 15138 } 15139 15140 function createFunctionComponentUpdateQueue() { 15141 return { 15142 lastEffect: null 15143 }; 15144 } 15145 15146 function basicStateReducer(state, action) { 15147 // $FlowFixMe: Flow doesn't like mixed types 15148 return typeof action === 'function' ? action(state) : action; 15149 } 15150 15151 function mountReducer(reducer, initialArg, init) { 15152 var hook = mountWorkInProgressHook(); 15153 var initialState; 15154 15155 if (init !== undefined) { 15156 initialState = init(initialArg); 15157 } else { 15158 initialState = initialArg; 15159 } 15160 15161 hook.memoizedState = hook.baseState = initialState; 15162 var queue = hook.queue = { 15163 pending: null, 15164 dispatch: null, 15165 lastRenderedReducer: reducer, 15166 lastRenderedState: initialState 15167 }; 15168 var dispatch = queue.dispatch = dispatchAction.bind(null, currentlyRenderingFiber$1, queue); 15169 return [hook.memoizedState, dispatch]; 15170 } 15171 15172 function updateReducer(reducer, initialArg, init) { 15173 var hook = updateWorkInProgressHook(); 15174 var queue = hook.queue; 15175 15176 if (!(queue !== null)) { 15177 { 15178 throw Error( "Should have a queue. This is likely a bug in React. Please file an issue." ); 15179 } 15180 } 15181 15182 queue.lastRenderedReducer = reducer; 15183 var current = currentHook; // The last rebase update that is NOT part of the base state. 15184 15185 var baseQueue = current.baseQueue; // The last pending update that hasn't been processed yet. 15186 15187 var pendingQueue = queue.pending; 15188 15189 if (pendingQueue !== null) { 15190 // We have new updates that haven't been processed yet. 15191 // We'll add them to the base queue. 15192 if (baseQueue !== null) { 15193 // Merge the pending queue and the base queue. 15194 var baseFirst = baseQueue.next; 15195 var pendingFirst = pendingQueue.next; 15196 baseQueue.next = pendingFirst; 15197 pendingQueue.next = baseFirst; 15198 } 15199 15200 current.baseQueue = baseQueue = pendingQueue; 15201 queue.pending = null; 15202 } 15203 15204 if (baseQueue !== null) { 15205 // We have a queue to process. 15206 var first = baseQueue.next; 15207 var newState = current.baseState; 15208 var newBaseState = null; 15209 var newBaseQueueFirst = null; 15210 var newBaseQueueLast = null; 15211 var update = first; 15212 15213 do { 15214 var updateExpirationTime = update.expirationTime; 15215 15216 if (updateExpirationTime < renderExpirationTime) { 15217 // Priority is insufficient. Skip this update. If this is the first 15218 // skipped update, the previous update/state is the new base 15219 // update/state. 15220 var clone = { 15221 expirationTime: update.expirationTime, 15222 suspenseConfig: update.suspenseConfig, 15223 action: update.action, 15224 eagerReducer: update.eagerReducer, 15225 eagerState: update.eagerState, 15226 next: null 15227 }; 15228 15229 if (newBaseQueueLast === null) { 15230 newBaseQueueFirst = newBaseQueueLast = clone; 15231 newBaseState = newState; 15232 } else { 15233 newBaseQueueLast = newBaseQueueLast.next = clone; 15234 } // Update the remaining priority in the queue. 15235 15236 15237 if (updateExpirationTime > currentlyRenderingFiber$1.expirationTime) { 15238 currentlyRenderingFiber$1.expirationTime = updateExpirationTime; 15239 markUnprocessedUpdateTime(updateExpirationTime); 15240 } 15241 } else { 15242 // This update does have sufficient priority. 15243 if (newBaseQueueLast !== null) { 15244 var _clone = { 15245 expirationTime: Sync, 15246 // This update is going to be committed so we never want uncommit it. 15247 suspenseConfig: update.suspenseConfig, 15248 action: update.action, 15249 eagerReducer: update.eagerReducer, 15250 eagerState: update.eagerState, 15251 next: null 15252 }; 15253 newBaseQueueLast = newBaseQueueLast.next = _clone; 15254 } // Mark the event time of this update as relevant to this render pass. 15255 // TODO: This should ideally use the true event time of this update rather than 15256 // its priority which is a derived and not reverseable value. 15257 // TODO: We should skip this update if it was already committed but currently 15258 // we have no way of detecting the difference between a committed and suspended 15259 // update here. 15260 15261 15262 markRenderEventTimeAndConfig(updateExpirationTime, update.suspenseConfig); // Process this update. 15263 15264 if (update.eagerReducer === reducer) { 15265 // If this update was processed eagerly, and its reducer matches the 15266 // current reducer, we can use the eagerly computed state. 15267 newState = update.eagerState; 15268 } else { 15269 var action = update.action; 15270 newState = reducer(newState, action); 15271 } 15272 } 15273 15274 update = update.next; 15275 } while (update !== null && update !== first); 15276 15277 if (newBaseQueueLast === null) { 15278 newBaseState = newState; 15279 } else { 15280 newBaseQueueLast.next = newBaseQueueFirst; 15281 } // Mark that the fiber performed work, but only if the new state is 15282 // different from the current state. 15283 15284 15285 if (!objectIs(newState, hook.memoizedState)) { 15286 markWorkInProgressReceivedUpdate(); 15287 } 15288 15289 hook.memoizedState = newState; 15290 hook.baseState = newBaseState; 15291 hook.baseQueue = newBaseQueueLast; 15292 queue.lastRenderedState = newState; 15293 } 15294 15295 var dispatch = queue.dispatch; 15296 return [hook.memoizedState, dispatch]; 15297 } 15298 15299 function rerenderReducer(reducer, initialArg, init) { 15300 var hook = updateWorkInProgressHook(); 15301 var queue = hook.queue; 15302 15303 if (!(queue !== null)) { 15304 { 15305 throw Error( "Should have a queue. This is likely a bug in React. Please file an issue." ); 15306 } 15307 } 15308 15309 queue.lastRenderedReducer = reducer; // This is a re-render. Apply the new render phase updates to the previous 15310 // work-in-progress hook. 15311 15312 var dispatch = queue.dispatch; 15313 var lastRenderPhaseUpdate = queue.pending; 15314 var newState = hook.memoizedState; 15315 15316 if (lastRenderPhaseUpdate !== null) { 15317 // The queue doesn't persist past this render pass. 15318 queue.pending = null; 15319 var firstRenderPhaseUpdate = lastRenderPhaseUpdate.next; 15320 var update = firstRenderPhaseUpdate; 15321 15322 do { 15323 // Process this render phase update. We don't have to check the 15324 // priority because it will always be the same as the current 15325 // render's. 15326 var action = update.action; 15327 newState = reducer(newState, action); 15328 update = update.next; 15329 } while (update !== firstRenderPhaseUpdate); // Mark that the fiber performed work, but only if the new state is 15330 // different from the current state. 15331 15332 15333 if (!objectIs(newState, hook.memoizedState)) { 15334 markWorkInProgressReceivedUpdate(); 15335 } 15336 15337 hook.memoizedState = newState; // Don't persist the state accumulated from the render phase updates to 15338 // the base state unless the queue is empty. 15339 // TODO: Not sure if this is the desired semantics, but it's what we 15340 // do for gDSFP. I can't remember why. 15341 15342 if (hook.baseQueue === null) { 15343 hook.baseState = newState; 15344 } 15345 15346 queue.lastRenderedState = newState; 15347 } 15348 15349 return [newState, dispatch]; 15350 } 15351 15352 function mountState(initialState) { 15353 var hook = mountWorkInProgressHook(); 15354 15355 if (typeof initialState === 'function') { 15356 // $FlowFixMe: Flow doesn't like mixed types 15357 initialState = initialState(); 15358 } 15359 15360 hook.memoizedState = hook.baseState = initialState; 15361 var queue = hook.queue = { 15362 pending: null, 15363 dispatch: null, 15364 lastRenderedReducer: basicStateReducer, 15365 lastRenderedState: initialState 15366 }; 15367 var dispatch = queue.dispatch = dispatchAction.bind(null, currentlyRenderingFiber$1, queue); 15368 return [hook.memoizedState, dispatch]; 15369 } 15370 15371 function updateState(initialState) { 15372 return updateReducer(basicStateReducer); 15373 } 15374 15375 function rerenderState(initialState) { 15376 return rerenderReducer(basicStateReducer); 15377 } 15378 15379 function pushEffect(tag, create, destroy, deps) { 15380 var effect = { 15381 tag: tag, 15382 create: create, 15383 destroy: destroy, 15384 deps: deps, 15385 // Circular 15386 next: null 15387 }; 15388 var componentUpdateQueue = currentlyRenderingFiber$1.updateQueue; 15389 15390 if (componentUpdateQueue === null) { 15391 componentUpdateQueue = createFunctionComponentUpdateQueue(); 15392 currentlyRenderingFiber$1.updateQueue = componentUpdateQueue; 15393 componentUpdateQueue.lastEffect = effect.next = effect; 15394 } else { 15395 var lastEffect = componentUpdateQueue.lastEffect; 15396 15397 if (lastEffect === null) { 15398 componentUpdateQueue.lastEffect = effect.next = effect; 15399 } else { 15400 var firstEffect = lastEffect.next; 15401 lastEffect.next = effect; 15402 effect.next = firstEffect; 15403 componentUpdateQueue.lastEffect = effect; 15404 } 15405 } 15406 15407 return effect; 15408 } 15409 15410 function mountRef(initialValue) { 15411 var hook = mountWorkInProgressHook(); 15412 var ref = { 15413 current: initialValue 15414 }; 15415 15416 { 15417 Object.seal(ref); 15418 } 15419 15420 hook.memoizedState = ref; 15421 return ref; 15422 } 15423 15424 function updateRef(initialValue) { 15425 var hook = updateWorkInProgressHook(); 15426 return hook.memoizedState; 15427 } 15428 15429 function mountEffectImpl(fiberEffectTag, hookEffectTag, create, deps) { 15430 var hook = mountWorkInProgressHook(); 15431 var nextDeps = deps === undefined ? null : deps; 15432 currentlyRenderingFiber$1.effectTag |= fiberEffectTag; 15433 hook.memoizedState = pushEffect(HasEffect | hookEffectTag, create, undefined, nextDeps); 15434 } 15435 15436 function updateEffectImpl(fiberEffectTag, hookEffectTag, create, deps) { 15437 var hook = updateWorkInProgressHook(); 15438 var nextDeps = deps === undefined ? null : deps; 15439 var destroy = undefined; 15440 15441 if (currentHook !== null) { 15442 var prevEffect = currentHook.memoizedState; 15443 destroy = prevEffect.destroy; 15444 15445 if (nextDeps !== null) { 15446 var prevDeps = prevEffect.deps; 15447 15448 if (areHookInputsEqual(nextDeps, prevDeps)) { 15449 pushEffect(hookEffectTag, create, destroy, nextDeps); 15450 return; 15451 } 15452 } 15453 } 15454 15455 currentlyRenderingFiber$1.effectTag |= fiberEffectTag; 15456 hook.memoizedState = pushEffect(HasEffect | hookEffectTag, create, destroy, nextDeps); 15457 } 15458 15459 function mountEffect(create, deps) { 15460 { 15461 // $FlowExpectedError - jest isn't a global, and isn't recognized outside of tests 15462 if ('undefined' !== typeof jest) { 15463 warnIfNotCurrentlyActingEffectsInDEV(currentlyRenderingFiber$1); 15464 } 15465 } 15466 15467 return mountEffectImpl(Update | Passive, Passive$1, create, deps); 15468 } 15469 15470 function updateEffect(create, deps) { 15471 { 15472 // $FlowExpectedError - jest isn't a global, and isn't recognized outside of tests 15473 if ('undefined' !== typeof jest) { 15474 warnIfNotCurrentlyActingEffectsInDEV(currentlyRenderingFiber$1); 15475 } 15476 } 15477 15478 return updateEffectImpl(Update | Passive, Passive$1, create, deps); 15479 } 15480 15481 function mountLayoutEffect(create, deps) { 15482 return mountEffectImpl(Update, Layout, create, deps); 15483 } 15484 15485 function updateLayoutEffect(create, deps) { 15486 return updateEffectImpl(Update, Layout, create, deps); 15487 } 15488 15489 function imperativeHandleEffect(create, ref) { 15490 if (typeof ref === 'function') { 15491 var refCallback = ref; 15492 15493 var _inst = create(); 15494 15495 refCallback(_inst); 15496 return function () { 15497 refCallback(null); 15498 }; 15499 } else if (ref !== null && ref !== undefined) { 15500 var refObject = ref; 15501 15502 { 15503 if (!refObject.hasOwnProperty('current')) { 15504 error('Expected useImperativeHandle() first argument to either be a ' + 'ref callback or React.createRef() object. Instead received: %s.', 'an object with keys {' + Object.keys(refObject).join(', ') + '}'); 15505 } 15506 } 15507 15508 var _inst2 = create(); 15509 15510 refObject.current = _inst2; 15511 return function () { 15512 refObject.current = null; 15513 }; 15514 } 15515 } 15516 15517 function mountImperativeHandle(ref, create, deps) { 15518 { 15519 if (typeof create !== 'function') { 15520 error('Expected useImperativeHandle() second argument to be a function ' + 'that creates a handle. Instead received: %s.', create !== null ? typeof create : 'null'); 15521 } 15522 } // TODO: If deps are provided, should we skip comparing the ref itself? 15523 15524 15525 var effectDeps = deps !== null && deps !== undefined ? deps.concat([ref]) : null; 15526 return mountEffectImpl(Update, Layout, imperativeHandleEffect.bind(null, create, ref), effectDeps); 15527 } 15528 15529 function updateImperativeHandle(ref, create, deps) { 15530 { 15531 if (typeof create !== 'function') { 15532 error('Expected useImperativeHandle() second argument to be a function ' + 'that creates a handle. Instead received: %s.', create !== null ? typeof create : 'null'); 15533 } 15534 } // TODO: If deps are provided, should we skip comparing the ref itself? 15535 15536 15537 var effectDeps = deps !== null && deps !== undefined ? deps.concat([ref]) : null; 15538 return updateEffectImpl(Update, Layout, imperativeHandleEffect.bind(null, create, ref), effectDeps); 15539 } 15540 15541 function mountDebugValue(value, formatterFn) {// This hook is normally a no-op. 15542 // The react-debug-hooks package injects its own implementation 15543 // so that e.g. DevTools can display custom hook values. 15544 } 15545 15546 var updateDebugValue = mountDebugValue; 15547 15548 function mountCallback(callback, deps) { 15549 var hook = mountWorkInProgressHook(); 15550 var nextDeps = deps === undefined ? null : deps; 15551 hook.memoizedState = [callback, nextDeps]; 15552 return callback; 15553 } 15554 15555 function updateCallback(callback, deps) { 15556 var hook = updateWorkInProgressHook(); 15557 var nextDeps = deps === undefined ? null : deps; 15558 var prevState = hook.memoizedState; 15559 15560 if (prevState !== null) { 15561 if (nextDeps !== null) { 15562 var prevDeps = prevState[1]; 15563 15564 if (areHookInputsEqual(nextDeps, prevDeps)) { 15565 return prevState[0]; 15566 } 15567 } 15568 } 15569 15570 hook.memoizedState = [callback, nextDeps]; 15571 return callback; 15572 } 15573 15574 function mountMemo(nextCreate, deps) { 15575 var hook = mountWorkInProgressHook(); 15576 var nextDeps = deps === undefined ? null : deps; 15577 var nextValue = nextCreate(); 15578 hook.memoizedState = [nextValue, nextDeps]; 15579 return nextValue; 15580 } 15581 15582 function updateMemo(nextCreate, deps) { 15583 var hook = updateWorkInProgressHook(); 15584 var nextDeps = deps === undefined ? null : deps; 15585 var prevState = hook.memoizedState; 15586 15587 if (prevState !== null) { 15588 // Assume these are defined. If they're not, areHookInputsEqual will warn. 15589 if (nextDeps !== null) { 15590 var prevDeps = prevState[1]; 15591 15592 if (areHookInputsEqual(nextDeps, prevDeps)) { 15593 return prevState[0]; 15594 } 15595 } 15596 } 15597 15598 var nextValue = nextCreate(); 15599 hook.memoizedState = [nextValue, nextDeps]; 15600 return nextValue; 15601 } 15602 15603 function mountDeferredValue(value, config) { 15604 var _mountState = mountState(value), 15605 prevValue = _mountState[0], 15606 setValue = _mountState[1]; 15607 15608 mountEffect(function () { 15609 var previousConfig = ReactCurrentBatchConfig$1.suspense; 15610 ReactCurrentBatchConfig$1.suspense = config === undefined ? null : config; 15611 15612 try { 15613 setValue(value); 15614 } finally { 15615 ReactCurrentBatchConfig$1.suspense = previousConfig; 15616 } 15617 }, [value, config]); 15618 return prevValue; 15619 } 15620 15621 function updateDeferredValue(value, config) { 15622 var _updateState = updateState(), 15623 prevValue = _updateState[0], 15624 setValue = _updateState[1]; 15625 15626 updateEffect(function () { 15627 var previousConfig = ReactCurrentBatchConfig$1.suspense; 15628 ReactCurrentBatchConfig$1.suspense = config === undefined ? null : config; 15629 15630 try { 15631 setValue(value); 15632 } finally { 15633 ReactCurrentBatchConfig$1.suspense = previousConfig; 15634 } 15635 }, [value, config]); 15636 return prevValue; 15637 } 15638 15639 function rerenderDeferredValue(value, config) { 15640 var _rerenderState = rerenderState(), 15641 prevValue = _rerenderState[0], 15642 setValue = _rerenderState[1]; 15643 15644 updateEffect(function () { 15645 var previousConfig = ReactCurrentBatchConfig$1.suspense; 15646 ReactCurrentBatchConfig$1.suspense = config === undefined ? null : config; 15647 15648 try { 15649 setValue(value); 15650 } finally { 15651 ReactCurrentBatchConfig$1.suspense = previousConfig; 15652 } 15653 }, [value, config]); 15654 return prevValue; 15655 } 15656 15657 function startTransition(setPending, config, callback) { 15658 var priorityLevel = getCurrentPriorityLevel(); 15659 runWithPriority$1(priorityLevel < UserBlockingPriority$1 ? UserBlockingPriority$1 : priorityLevel, function () { 15660 setPending(true); 15661 }); 15662 runWithPriority$1(priorityLevel > NormalPriority ? NormalPriority : priorityLevel, function () { 15663 var previousConfig = ReactCurrentBatchConfig$1.suspense; 15664 ReactCurrentBatchConfig$1.suspense = config === undefined ? null : config; 15665 15666 try { 15667 setPending(false); 15668 callback(); 15669 } finally { 15670 ReactCurrentBatchConfig$1.suspense = previousConfig; 15671 } 15672 }); 15673 } 15674 15675 function mountTransition(config) { 15676 var _mountState2 = mountState(false), 15677 isPending = _mountState2[0], 15678 setPending = _mountState2[1]; 15679 15680 var start = mountCallback(startTransition.bind(null, setPending, config), [setPending, config]); 15681 return [start, isPending]; 15682 } 15683 15684 function updateTransition(config) { 15685 var _updateState2 = updateState(), 15686 isPending = _updateState2[0], 15687 setPending = _updateState2[1]; 15688 15689 var start = updateCallback(startTransition.bind(null, setPending, config), [setPending, config]); 15690 return [start, isPending]; 15691 } 15692 15693 function rerenderTransition(config) { 15694 var _rerenderState2 = rerenderState(), 15695 isPending = _rerenderState2[0], 15696 setPending = _rerenderState2[1]; 15697 15698 var start = updateCallback(startTransition.bind(null, setPending, config), [setPending, config]); 15699 return [start, isPending]; 15700 } 15701 15702 function dispatchAction(fiber, queue, action) { 15703 { 15704 if (typeof arguments[3] === 'function') { 15705 error("State updates from the useState() and useReducer() Hooks don't support the " + 'second callback argument. To execute a side effect after ' + 'rendering, declare it in the component body with useEffect().'); 15706 } 15707 } 15708 15709 var currentTime = requestCurrentTimeForUpdate(); 15710 var suspenseConfig = requestCurrentSuspenseConfig(); 15711 var expirationTime = computeExpirationForFiber(currentTime, fiber, suspenseConfig); 15712 var update = { 15713 expirationTime: expirationTime, 15714 suspenseConfig: suspenseConfig, 15715 action: action, 15716 eagerReducer: null, 15717 eagerState: null, 15718 next: null 15719 }; 15720 15721 { 15722 update.priority = getCurrentPriorityLevel(); 15723 } // Append the update to the end of the list. 15724 15725 15726 var pending = queue.pending; 15727 15728 if (pending === null) { 15729 // This is the first update. Create a circular list. 15730 update.next = update; 15731 } else { 15732 update.next = pending.next; 15733 pending.next = update; 15734 } 15735 15736 queue.pending = update; 15737 var alternate = fiber.alternate; 15738 15739 if (fiber === currentlyRenderingFiber$1 || alternate !== null && alternate === currentlyRenderingFiber$1) { 15740 // This is a render phase update. Stash it in a lazily-created map of 15741 // queue -> linked list of updates. After this render pass, we'll restart 15742 // and apply the stashed updates on top of the work-in-progress hook. 15743 didScheduleRenderPhaseUpdate = true; 15744 update.expirationTime = renderExpirationTime; 15745 currentlyRenderingFiber$1.expirationTime = renderExpirationTime; 15746 } else { 15747 if (fiber.expirationTime === NoWork && (alternate === null || alternate.expirationTime === NoWork)) { 15748 // The queue is currently empty, which means we can eagerly compute the 15749 // next state before entering the render phase. If the new state is the 15750 // same as the current state, we may be able to bail out entirely. 15751 var lastRenderedReducer = queue.lastRenderedReducer; 15752 15753 if (lastRenderedReducer !== null) { 15754 var prevDispatcher; 15755 15756 { 15757 prevDispatcher = ReactCurrentDispatcher.current; 15758 ReactCurrentDispatcher.current = InvalidNestedHooksDispatcherOnUpdateInDEV; 15759 } 15760 15761 try { 15762 var currentState = queue.lastRenderedState; 15763 var eagerState = lastRenderedReducer(currentState, action); // Stash the eagerly computed state, and the reducer used to compute 15764 // it, on the update object. If the reducer hasn't changed by the 15765 // time we enter the render phase, then the eager state can be used 15766 // without calling the reducer again. 15767 15768 update.eagerReducer = lastRenderedReducer; 15769 update.eagerState = eagerState; 15770 15771 if (objectIs(eagerState, currentState)) { 15772 // Fast path. We can bail out without scheduling React to re-render. 15773 // It's still possible that we'll need to rebase this update later, 15774 // if the component re-renders for a different reason and by that 15775 // time the reducer has changed. 15776 return; 15777 } 15778 } catch (error) {// Suppress the error. It will throw again in the render phase. 15779 } finally { 15780 { 15781 ReactCurrentDispatcher.current = prevDispatcher; 15782 } 15783 } 15784 } 15785 } 15786 15787 { 15788 // $FlowExpectedError - jest isn't a global, and isn't recognized outside of tests 15789 if ('undefined' !== typeof jest) { 15790 warnIfNotScopedWithMatchingAct(fiber); 15791 warnIfNotCurrentlyActingUpdatesInDev(fiber); 15792 } 15793 } 15794 15795 scheduleWork(fiber, expirationTime); 15796 } 15797 } 15798 15799 var ContextOnlyDispatcher = { 15800 readContext: readContext, 15801 useCallback: throwInvalidHookError, 15802 useContext: throwInvalidHookError, 15803 useEffect: throwInvalidHookError, 15804 useImperativeHandle: throwInvalidHookError, 15805 useLayoutEffect: throwInvalidHookError, 15806 useMemo: throwInvalidHookError, 15807 useReducer: throwInvalidHookError, 15808 useRef: throwInvalidHookError, 15809 useState: throwInvalidHookError, 15810 useDebugValue: throwInvalidHookError, 15811 useResponder: throwInvalidHookError, 15812 useDeferredValue: throwInvalidHookError, 15813 useTransition: throwInvalidHookError 15814 }; 15815 var HooksDispatcherOnMountInDEV = null; 15816 var HooksDispatcherOnMountWithHookTypesInDEV = null; 15817 var HooksDispatcherOnUpdateInDEV = null; 15818 var HooksDispatcherOnRerenderInDEV = null; 15819 var InvalidNestedHooksDispatcherOnMountInDEV = null; 15820 var InvalidNestedHooksDispatcherOnUpdateInDEV = null; 15821 var InvalidNestedHooksDispatcherOnRerenderInDEV = null; 15822 15823 { 15824 var warnInvalidContextAccess = function () { 15825 error('Context can only be read while React is rendering. ' + 'In classes, you can read it in the render method or getDerivedStateFromProps. ' + 'In function components, you can read it directly in the function body, but not ' + 'inside Hooks like useReducer() or useMemo().'); 15826 }; 15827 15828 var warnInvalidHookAccess = function () { 15829 error('Do not call Hooks inside useEffect(...), useMemo(...), or other built-in Hooks. ' + 'You can only call Hooks at the top level of your React function. ' + 'For more information, see ' + 'https://fb.me/rules-of-hooks'); 15830 }; 15831 15832 HooksDispatcherOnMountInDEV = { 15833 readContext: function (context, observedBits) { 15834 return readContext(context, observedBits); 15835 }, 15836 useCallback: function (callback, deps) { 15837 currentHookNameInDev = 'useCallback'; 15838 mountHookTypesDev(); 15839 checkDepsAreArrayDev(deps); 15840 return mountCallback(callback, deps); 15841 }, 15842 useContext: function (context, observedBits) { 15843 currentHookNameInDev = 'useContext'; 15844 mountHookTypesDev(); 15845 return readContext(context, observedBits); 15846 }, 15847 useEffect: function (create, deps) { 15848 currentHookNameInDev = 'useEffect'; 15849 mountHookTypesDev(); 15850 checkDepsAreArrayDev(deps); 15851 return mountEffect(create, deps); 15852 }, 15853 useImperativeHandle: function (ref, create, deps) { 15854 currentHookNameInDev = 'useImperativeHandle'; 15855 mountHookTypesDev(); 15856 checkDepsAreArrayDev(deps); 15857 return mountImperativeHandle(ref, create, deps); 15858 }, 15859 useLayoutEffect: function (create, deps) { 15860 currentHookNameInDev = 'useLayoutEffect'; 15861 mountHookTypesDev(); 15862 checkDepsAreArrayDev(deps); 15863 return mountLayoutEffect(create, deps); 15864 }, 15865 useMemo: function (create, deps) { 15866 currentHookNameInDev = 'useMemo'; 15867 mountHookTypesDev(); 15868 checkDepsAreArrayDev(deps); 15869 var prevDispatcher = ReactCurrentDispatcher.current; 15870 ReactCurrentDispatcher.current = InvalidNestedHooksDispatcherOnMountInDEV; 15871 15872 try { 15873 return mountMemo(create, deps); 15874 } finally { 15875 ReactCurrentDispatcher.current = prevDispatcher; 15876 } 15877 }, 15878 useReducer: function (reducer, initialArg, init) { 15879 currentHookNameInDev = 'useReducer'; 15880 mountHookTypesDev(); 15881 var prevDispatcher = ReactCurrentDispatcher.current; 15882 ReactCurrentDispatcher.current = InvalidNestedHooksDispatcherOnMountInDEV; 15883 15884 try { 15885 return mountReducer(reducer, initialArg, init); 15886 } finally { 15887 ReactCurrentDispatcher.current = prevDispatcher; 15888 } 15889 }, 15890 useRef: function (initialValue) { 15891 currentHookNameInDev = 'useRef'; 15892 mountHookTypesDev(); 15893 return mountRef(initialValue); 15894 }, 15895 useState: function (initialState) { 15896 currentHookNameInDev = 'useState'; 15897 mountHookTypesDev(); 15898 var prevDispatcher = ReactCurrentDispatcher.current; 15899 ReactCurrentDispatcher.current = InvalidNestedHooksDispatcherOnMountInDEV; 15900 15901 try { 15902 return mountState(initialState); 15903 } finally { 15904 ReactCurrentDispatcher.current = prevDispatcher; 15905 } 15906 }, 15907 useDebugValue: function (value, formatterFn) { 15908 currentHookNameInDev = 'useDebugValue'; 15909 mountHookTypesDev(); 15910 return mountDebugValue(); 15911 }, 15912 useResponder: function (responder, props) { 15913 currentHookNameInDev = 'useResponder'; 15914 mountHookTypesDev(); 15915 return createDeprecatedResponderListener(responder, props); 15916 }, 15917 useDeferredValue: function (value, config) { 15918 currentHookNameInDev = 'useDeferredValue'; 15919 mountHookTypesDev(); 15920 return mountDeferredValue(value, config); 15921 }, 15922 useTransition: function (config) { 15923 currentHookNameInDev = 'useTransition'; 15924 mountHookTypesDev(); 15925 return mountTransition(config); 15926 } 15927 }; 15928 HooksDispatcherOnMountWithHookTypesInDEV = { 15929 readContext: function (context, observedBits) { 15930 return readContext(context, observedBits); 15931 }, 15932 useCallback: function (callback, deps) { 15933 currentHookNameInDev = 'useCallback'; 15934 updateHookTypesDev(); 15935 return mountCallback(callback, deps); 15936 }, 15937 useContext: function (context, observedBits) { 15938 currentHookNameInDev = 'useContext'; 15939 updateHookTypesDev(); 15940 return readContext(context, observedBits); 15941 }, 15942 useEffect: function (create, deps) { 15943 currentHookNameInDev = 'useEffect'; 15944 updateHookTypesDev(); 15945 return mountEffect(create, deps); 15946 }, 15947 useImperativeHandle: function (ref, create, deps) { 15948 currentHookNameInDev = 'useImperativeHandle'; 15949 updateHookTypesDev(); 15950 return mountImperativeHandle(ref, create, deps); 15951 }, 15952 useLayoutEffect: function (create, deps) { 15953 currentHookNameInDev = 'useLayoutEffect'; 15954 updateHookTypesDev(); 15955 return mountLayoutEffect(create, deps); 15956 }, 15957 useMemo: function (create, deps) { 15958 currentHookNameInDev = 'useMemo'; 15959 updateHookTypesDev(); 15960 var prevDispatcher = ReactCurrentDispatcher.current; 15961 ReactCurrentDispatcher.current = InvalidNestedHooksDispatcherOnMountInDEV; 15962 15963 try { 15964 return mountMemo(create, deps); 15965 } finally { 15966 ReactCurrentDispatcher.current = prevDispatcher; 15967 } 15968 }, 15969 useReducer: function (reducer, initialArg, init) { 15970 currentHookNameInDev = 'useReducer'; 15971 updateHookTypesDev(); 15972 var prevDispatcher = ReactCurrentDispatcher.current; 15973 ReactCurrentDispatcher.current = InvalidNestedHooksDispatcherOnMountInDEV; 15974 15975 try { 15976 return mountReducer(reducer, initialArg, init); 15977 } finally { 15978 ReactCurrentDispatcher.current = prevDispatcher; 15979 } 15980 }, 15981 useRef: function (initialValue) { 15982 currentHookNameInDev = 'useRef'; 15983 updateHookTypesDev(); 15984 return mountRef(initialValue); 15985 }, 15986 useState: function (initialState) { 15987 currentHookNameInDev = 'useState'; 15988 updateHookTypesDev(); 15989 var prevDispatcher = ReactCurrentDispatcher.current; 15990 ReactCurrentDispatcher.current = InvalidNestedHooksDispatcherOnMountInDEV; 15991 15992 try { 15993 return mountState(initialState); 15994 } finally { 15995 ReactCurrentDispatcher.current = prevDispatcher; 15996 } 15997 }, 15998 useDebugValue: function (value, formatterFn) { 15999 currentHookNameInDev = 'useDebugValue'; 16000 updateHookTypesDev(); 16001 return mountDebugValue(); 16002 }, 16003 useResponder: function (responder, props) { 16004 currentHookNameInDev = 'useResponder'; 16005 updateHookTypesDev(); 16006 return createDeprecatedResponderListener(responder, props); 16007 }, 16008 useDeferredValue: function (value, config) { 16009 currentHookNameInDev = 'useDeferredValue'; 16010 updateHookTypesDev(); 16011 return mountDeferredValue(value, config); 16012 }, 16013 useTransition: function (config) { 16014 currentHookNameInDev = 'useTransition'; 16015 updateHookTypesDev(); 16016 return mountTransition(config); 16017 } 16018 }; 16019 HooksDispatcherOnUpdateInDEV = { 16020 readContext: function (context, observedBits) { 16021 return readContext(context, observedBits); 16022 }, 16023 useCallback: function (callback, deps) { 16024 currentHookNameInDev = 'useCallback'; 16025 updateHookTypesDev(); 16026 return updateCallback(callback, deps); 16027 }, 16028 useContext: function (context, observedBits) { 16029 currentHookNameInDev = 'useContext'; 16030 updateHookTypesDev(); 16031 return readContext(context, observedBits); 16032 }, 16033 useEffect: function (create, deps) { 16034 currentHookNameInDev = 'useEffect'; 16035 updateHookTypesDev(); 16036 return updateEffect(create, deps); 16037 }, 16038 useImperativeHandle: function (ref, create, deps) { 16039 currentHookNameInDev = 'useImperativeHandle'; 16040 updateHookTypesDev(); 16041 return updateImperativeHandle(ref, create, deps); 16042 }, 16043 useLayoutEffect: function (create, deps) { 16044 currentHookNameInDev = 'useLayoutEffect'; 16045 updateHookTypesDev(); 16046 return updateLayoutEffect(create, deps); 16047 }, 16048 useMemo: function (create, deps) { 16049 currentHookNameInDev = 'useMemo'; 16050 updateHookTypesDev(); 16051 var prevDispatcher = ReactCurrentDispatcher.current; 16052 ReactCurrentDispatcher.current = InvalidNestedHooksDispatcherOnUpdateInDEV; 16053 16054 try { 16055 return updateMemo(create, deps); 16056 } finally { 16057 ReactCurrentDispatcher.current = prevDispatcher; 16058 } 16059 }, 16060 useReducer: function (reducer, initialArg, init) { 16061 currentHookNameInDev = 'useReducer'; 16062 updateHookTypesDev(); 16063 var prevDispatcher = ReactCurrentDispatcher.current; 16064 ReactCurrentDispatcher.current = InvalidNestedHooksDispatcherOnUpdateInDEV; 16065 16066 try { 16067 return updateReducer(reducer, initialArg, init); 16068 } finally { 16069 ReactCurrentDispatcher.current = prevDispatcher; 16070 } 16071 }, 16072 useRef: function (initialValue) { 16073 currentHookNameInDev = 'useRef'; 16074 updateHookTypesDev(); 16075 return updateRef(); 16076 }, 16077 useState: function (initialState) { 16078 currentHookNameInDev = 'useState'; 16079 updateHookTypesDev(); 16080 var prevDispatcher = ReactCurrentDispatcher.current; 16081 ReactCurrentDispatcher.current = InvalidNestedHooksDispatcherOnUpdateInDEV; 16082 16083 try { 16084 return updateState(initialState); 16085 } finally { 16086 ReactCurrentDispatcher.current = prevDispatcher; 16087 } 16088 }, 16089 useDebugValue: function (value, formatterFn) { 16090 currentHookNameInDev = 'useDebugValue'; 16091 updateHookTypesDev(); 16092 return updateDebugValue(); 16093 }, 16094 useResponder: function (responder, props) { 16095 currentHookNameInDev = 'useResponder'; 16096 updateHookTypesDev(); 16097 return createDeprecatedResponderListener(responder, props); 16098 }, 16099 useDeferredValue: function (value, config) { 16100 currentHookNameInDev = 'useDeferredValue'; 16101 updateHookTypesDev(); 16102 return updateDeferredValue(value, config); 16103 }, 16104 useTransition: function (config) { 16105 currentHookNameInDev = 'useTransition'; 16106 updateHookTypesDev(); 16107 return updateTransition(config); 16108 } 16109 }; 16110 HooksDispatcherOnRerenderInDEV = { 16111 readContext: function (context, observedBits) { 16112 return readContext(context, observedBits); 16113 }, 16114 useCallback: function (callback, deps) { 16115 currentHookNameInDev = 'useCallback'; 16116 updateHookTypesDev(); 16117 return updateCallback(callback, deps); 16118 }, 16119 useContext: function (context, observedBits) { 16120 currentHookNameInDev = 'useContext'; 16121 updateHookTypesDev(); 16122 return readContext(context, observedBits); 16123 }, 16124 useEffect: function (create, deps) { 16125 currentHookNameInDev = 'useEffect'; 16126 updateHookTypesDev(); 16127 return updateEffect(create, deps); 16128 }, 16129 useImperativeHandle: function (ref, create, deps) { 16130 currentHookNameInDev = 'useImperativeHandle'; 16131 updateHookTypesDev(); 16132 return updateImperativeHandle(ref, create, deps); 16133 }, 16134 useLayoutEffect: function (create, deps) { 16135 currentHookNameInDev = 'useLayoutEffect'; 16136 updateHookTypesDev(); 16137 return updateLayoutEffect(create, deps); 16138 }, 16139 useMemo: function (create, deps) { 16140 currentHookNameInDev = 'useMemo'; 16141 updateHookTypesDev(); 16142 var prevDispatcher = ReactCurrentDispatcher.current; 16143 ReactCurrentDispatcher.current = InvalidNestedHooksDispatcherOnRerenderInDEV; 16144 16145 try { 16146 return updateMemo(create, deps); 16147 } finally { 16148 ReactCurrentDispatcher.current = prevDispatcher; 16149 } 16150 }, 16151 useReducer: function (reducer, initialArg, init) { 16152 currentHookNameInDev = 'useReducer'; 16153 updateHookTypesDev(); 16154 var prevDispatcher = ReactCurrentDispatcher.current; 16155 ReactCurrentDispatcher.current = InvalidNestedHooksDispatcherOnRerenderInDEV; 16156 16157 try { 16158 return rerenderReducer(reducer, initialArg, init); 16159 } finally { 16160 ReactCurrentDispatcher.current = prevDispatcher; 16161 } 16162 }, 16163 useRef: function (initialValue) { 16164 currentHookNameInDev = 'useRef'; 16165 updateHookTypesDev(); 16166 return updateRef(); 16167 }, 16168 useState: function (initialState) { 16169 currentHookNameInDev = 'useState'; 16170 updateHookTypesDev(); 16171 var prevDispatcher = ReactCurrentDispatcher.current; 16172 ReactCurrentDispatcher.current = InvalidNestedHooksDispatcherOnRerenderInDEV; 16173 16174 try { 16175 return rerenderState(initialState); 16176 } finally { 16177 ReactCurrentDispatcher.current = prevDispatcher; 16178 } 16179 }, 16180 useDebugValue: function (value, formatterFn) { 16181 currentHookNameInDev = 'useDebugValue'; 16182 updateHookTypesDev(); 16183 return updateDebugValue(); 16184 }, 16185 useResponder: function (responder, props) { 16186 currentHookNameInDev = 'useResponder'; 16187 updateHookTypesDev(); 16188 return createDeprecatedResponderListener(responder, props); 16189 }, 16190 useDeferredValue: function (value, config) { 16191 currentHookNameInDev = 'useDeferredValue'; 16192 updateHookTypesDev(); 16193 return rerenderDeferredValue(value, config); 16194 }, 16195 useTransition: function (config) { 16196 currentHookNameInDev = 'useTransition'; 16197 updateHookTypesDev(); 16198 return rerenderTransition(config); 16199 } 16200 }; 16201 InvalidNestedHooksDispatcherOnMountInDEV = { 16202 readContext: function (context, observedBits) { 16203 warnInvalidContextAccess(); 16204 return readContext(context, observedBits); 16205 }, 16206 useCallback: function (callback, deps) { 16207 currentHookNameInDev = 'useCallback'; 16208 warnInvalidHookAccess(); 16209 mountHookTypesDev(); 16210 return mountCallback(callback, deps); 16211 }, 16212 useContext: function (context, observedBits) { 16213 currentHookNameInDev = 'useContext'; 16214 warnInvalidHookAccess(); 16215 mountHookTypesDev(); 16216 return readContext(context, observedBits); 16217 }, 16218 useEffect: function (create, deps) { 16219 currentHookNameInDev = 'useEffect'; 16220 warnInvalidHookAccess(); 16221 mountHookTypesDev(); 16222 return mountEffect(create, deps); 16223 }, 16224 useImperativeHandle: function (ref, create, deps) { 16225 currentHookNameInDev = 'useImperativeHandle'; 16226 warnInvalidHookAccess(); 16227 mountHookTypesDev(); 16228 return mountImperativeHandle(ref, create, deps); 16229 }, 16230 useLayoutEffect: function (create, deps) { 16231 currentHookNameInDev = 'useLayoutEffect'; 16232 warnInvalidHookAccess(); 16233 mountHookTypesDev(); 16234 return mountLayoutEffect(create, deps); 16235 }, 16236 useMemo: function (create, deps) { 16237 currentHookNameInDev = 'useMemo'; 16238 warnInvalidHookAccess(); 16239 mountHookTypesDev(); 16240 var prevDispatcher = ReactCurrentDispatcher.current; 16241 ReactCurrentDispatcher.current = InvalidNestedHooksDispatcherOnMountInDEV; 16242 16243 try { 16244 return mountMemo(create, deps); 16245 } finally { 16246 ReactCurrentDispatcher.current = prevDispatcher; 16247 } 16248 }, 16249 useReducer: function (reducer, initialArg, init) { 16250 currentHookNameInDev = 'useReducer'; 16251 warnInvalidHookAccess(); 16252 mountHookTypesDev(); 16253 var prevDispatcher = ReactCurrentDispatcher.current; 16254 ReactCurrentDispatcher.current = InvalidNestedHooksDispatcherOnMountInDEV; 16255 16256 try { 16257 return mountReducer(reducer, initialArg, init); 16258 } finally { 16259 ReactCurrentDispatcher.current = prevDispatcher; 16260 } 16261 }, 16262 useRef: function (initialValue) { 16263 currentHookNameInDev = 'useRef'; 16264 warnInvalidHookAccess(); 16265 mountHookTypesDev(); 16266 return mountRef(initialValue); 16267 }, 16268 useState: function (initialState) { 16269 currentHookNameInDev = 'useState'; 16270 warnInvalidHookAccess(); 16271 mountHookTypesDev(); 16272 var prevDispatcher = ReactCurrentDispatcher.current; 16273 ReactCurrentDispatcher.current = InvalidNestedHooksDispatcherOnMountInDEV; 16274 16275 try { 16276 return mountState(initialState); 16277 } finally { 16278 ReactCurrentDispatcher.current = prevDispatcher; 16279 } 16280 }, 16281 useDebugValue: function (value, formatterFn) { 16282 currentHookNameInDev = 'useDebugValue'; 16283 warnInvalidHookAccess(); 16284 mountHookTypesDev(); 16285 return mountDebugValue(); 16286 }, 16287 useResponder: function (responder, props) { 16288 currentHookNameInDev = 'useResponder'; 16289 warnInvalidHookAccess(); 16290 mountHookTypesDev(); 16291 return createDeprecatedResponderListener(responder, props); 16292 }, 16293 useDeferredValue: function (value, config) { 16294 currentHookNameInDev = 'useDeferredValue'; 16295 warnInvalidHookAccess(); 16296 mountHookTypesDev(); 16297 return mountDeferredValue(value, config); 16298 }, 16299 useTransition: function (config) { 16300 currentHookNameInDev = 'useTransition'; 16301 warnInvalidHookAccess(); 16302 mountHookTypesDev(); 16303 return mountTransition(config); 16304 } 16305 }; 16306 InvalidNestedHooksDispatcherOnUpdateInDEV = { 16307 readContext: function (context, observedBits) { 16308 warnInvalidContextAccess(); 16309 return readContext(context, observedBits); 16310 }, 16311 useCallback: function (callback, deps) { 16312 currentHookNameInDev = 'useCallback'; 16313 warnInvalidHookAccess(); 16314 updateHookTypesDev(); 16315 return updateCallback(callback, deps); 16316 }, 16317 useContext: function (context, observedBits) { 16318 currentHookNameInDev = 'useContext'; 16319 warnInvalidHookAccess(); 16320 updateHookTypesDev(); 16321 return readContext(context, observedBits); 16322 }, 16323 useEffect: function (create, deps) { 16324 currentHookNameInDev = 'useEffect'; 16325 warnInvalidHookAccess(); 16326 updateHookTypesDev(); 16327 return updateEffect(create, deps); 16328 }, 16329 useImperativeHandle: function (ref, create, deps) { 16330 currentHookNameInDev = 'useImperativeHandle'; 16331 warnInvalidHookAccess(); 16332 updateHookTypesDev(); 16333 return updateImperativeHandle(ref, create, deps); 16334 }, 16335 useLayoutEffect: function (create, deps) { 16336 currentHookNameInDev = 'useLayoutEffect'; 16337 warnInvalidHookAccess(); 16338 updateHookTypesDev(); 16339 return updateLayoutEffect(create, deps); 16340 }, 16341 useMemo: function (create, deps) { 16342 currentHookNameInDev = 'useMemo'; 16343 warnInvalidHookAccess(); 16344 updateHookTypesDev(); 16345 var prevDispatcher = ReactCurrentDispatcher.current; 16346 ReactCurrentDispatcher.current = InvalidNestedHooksDispatcherOnUpdateInDEV; 16347 16348 try { 16349 return updateMemo(create, deps); 16350 } finally { 16351 ReactCurrentDispatcher.current = prevDispatcher; 16352 } 16353 }, 16354 useReducer: function (reducer, initialArg, init) { 16355 currentHookNameInDev = 'useReducer'; 16356 warnInvalidHookAccess(); 16357 updateHookTypesDev(); 16358 var prevDispatcher = ReactCurrentDispatcher.current; 16359 ReactCurrentDispatcher.current = InvalidNestedHooksDispatcherOnUpdateInDEV; 16360 16361 try { 16362 return updateReducer(reducer, initialArg, init); 16363 } finally { 16364 ReactCurrentDispatcher.current = prevDispatcher; 16365 } 16366 }, 16367 useRef: function (initialValue) { 16368 currentHookNameInDev = 'useRef'; 16369 warnInvalidHookAccess(); 16370 updateHookTypesDev(); 16371 return updateRef(); 16372 }, 16373 useState: function (initialState) { 16374 currentHookNameInDev = 'useState'; 16375 warnInvalidHookAccess(); 16376 updateHookTypesDev(); 16377 var prevDispatcher = ReactCurrentDispatcher.current; 16378 ReactCurrentDispatcher.current = InvalidNestedHooksDispatcherOnUpdateInDEV; 16379 16380 try { 16381 return updateState(initialState); 16382 } finally { 16383 ReactCurrentDispatcher.current = prevDispatcher; 16384 } 16385 }, 16386 useDebugValue: function (value, formatterFn) { 16387 currentHookNameInDev = 'useDebugValue'; 16388 warnInvalidHookAccess(); 16389 updateHookTypesDev(); 16390 return updateDebugValue(); 16391 }, 16392 useResponder: function (responder, props) { 16393 currentHookNameInDev = 'useResponder'; 16394 warnInvalidHookAccess(); 16395 updateHookTypesDev(); 16396 return createDeprecatedResponderListener(responder, props); 16397 }, 16398 useDeferredValue: function (value, config) { 16399 currentHookNameInDev = 'useDeferredValue'; 16400 warnInvalidHookAccess(); 16401 updateHookTypesDev(); 16402 return updateDeferredValue(value, config); 16403 }, 16404 useTransition: function (config) { 16405 currentHookNameInDev = 'useTransition'; 16406 warnInvalidHookAccess(); 16407 updateHookTypesDev(); 16408 return updateTransition(config); 16409 } 16410 }; 16411 InvalidNestedHooksDispatcherOnRerenderInDEV = { 16412 readContext: function (context, observedBits) { 16413 warnInvalidContextAccess(); 16414 return readContext(context, observedBits); 16415 }, 16416 useCallback: function (callback, deps) { 16417 currentHookNameInDev = 'useCallback'; 16418 warnInvalidHookAccess(); 16419 updateHookTypesDev(); 16420 return updateCallback(callback, deps); 16421 }, 16422 useContext: function (context, observedBits) { 16423 currentHookNameInDev = 'useContext'; 16424 warnInvalidHookAccess(); 16425 updateHookTypesDev(); 16426 return readContext(context, observedBits); 16427 }, 16428 useEffect: function (create, deps) { 16429 currentHookNameInDev = 'useEffect'; 16430 warnInvalidHookAccess(); 16431 updateHookTypesDev(); 16432 return updateEffect(create, deps); 16433 }, 16434 useImperativeHandle: function (ref, create, deps) { 16435 currentHookNameInDev = 'useImperativeHandle'; 16436 warnInvalidHookAccess(); 16437 updateHookTypesDev(); 16438 return updateImperativeHandle(ref, create, deps); 16439 }, 16440 useLayoutEffect: function (create, deps) { 16441 currentHookNameInDev = 'useLayoutEffect'; 16442 warnInvalidHookAccess(); 16443 updateHookTypesDev(); 16444 return updateLayoutEffect(create, deps); 16445 }, 16446 useMemo: function (create, deps) { 16447 currentHookNameInDev = 'useMemo'; 16448 warnInvalidHookAccess(); 16449 updateHookTypesDev(); 16450 var prevDispatcher = ReactCurrentDispatcher.current; 16451 ReactCurrentDispatcher.current = InvalidNestedHooksDispatcherOnUpdateInDEV; 16452 16453 try { 16454 return updateMemo(create, deps); 16455 } finally { 16456 ReactCurrentDispatcher.current = prevDispatcher; 16457 } 16458 }, 16459 useReducer: function (reducer, initialArg, init) { 16460 currentHookNameInDev = 'useReducer'; 16461 warnInvalidHookAccess(); 16462 updateHookTypesDev(); 16463 var prevDispatcher = ReactCurrentDispatcher.current; 16464 ReactCurrentDispatcher.current = InvalidNestedHooksDispatcherOnUpdateInDEV; 16465 16466 try { 16467 return rerenderReducer(reducer, initialArg, init); 16468 } finally { 16469 ReactCurrentDispatcher.current = prevDispatcher; 16470 } 16471 }, 16472 useRef: function (initialValue) { 16473 currentHookNameInDev = 'useRef'; 16474 warnInvalidHookAccess(); 16475 updateHookTypesDev(); 16476 return updateRef(); 16477 }, 16478 useState: function (initialState) { 16479 currentHookNameInDev = 'useState'; 16480 warnInvalidHookAccess(); 16481 updateHookTypesDev(); 16482 var prevDispatcher = ReactCurrentDispatcher.current; 16483 ReactCurrentDispatcher.current = InvalidNestedHooksDispatcherOnUpdateInDEV; 16484 16485 try { 16486 return rerenderState(initialState); 16487 } finally { 16488 ReactCurrentDispatcher.current = prevDispatcher; 16489 } 16490 }, 16491 useDebugValue: function (value, formatterFn) { 16492 currentHookNameInDev = 'useDebugValue'; 16493 warnInvalidHookAccess(); 16494 updateHookTypesDev(); 16495 return updateDebugValue(); 16496 }, 16497 useResponder: function (responder, props) { 16498 currentHookNameInDev = 'useResponder'; 16499 warnInvalidHookAccess(); 16500 updateHookTypesDev(); 16501 return createDeprecatedResponderListener(responder, props); 16502 }, 16503 useDeferredValue: function (value, config) { 16504 currentHookNameInDev = 'useDeferredValue'; 16505 warnInvalidHookAccess(); 16506 updateHookTypesDev(); 16507 return rerenderDeferredValue(value, config); 16508 }, 16509 useTransition: function (config) { 16510 currentHookNameInDev = 'useTransition'; 16511 warnInvalidHookAccess(); 16512 updateHookTypesDev(); 16513 return rerenderTransition(config); 16514 } 16515 }; 16516 } 16517 16518 var now$1 = unstable_now; 16519 var commitTime = 0; 16520 var profilerStartTime = -1; 16521 16522 function getCommitTime() { 16523 return commitTime; 16524 } 16525 16526 function recordCommitTime() { 16527 16528 commitTime = now$1(); 16529 } 16530 16531 function startProfilerTimer(fiber) { 16532 16533 profilerStartTime = now$1(); 16534 16535 if (fiber.actualStartTime < 0) { 16536 fiber.actualStartTime = now$1(); 16537 } 16538 } 16539 16540 function stopProfilerTimerIfRunning(fiber) { 16541 16542 profilerStartTime = -1; 16543 } 16544 16545 function stopProfilerTimerIfRunningAndRecordDelta(fiber, overrideBaseTime) { 16546 16547 if (profilerStartTime >= 0) { 16548 var elapsedTime = now$1() - profilerStartTime; 16549 fiber.actualDuration += elapsedTime; 16550 16551 if (overrideBaseTime) { 16552 fiber.selfBaseDuration = elapsedTime; 16553 } 16554 16555 profilerStartTime = -1; 16556 } 16557 } 16558 16559 // This may have been an insertion or a hydration. 16560 16561 var hydrationParentFiber = null; 16562 var nextHydratableInstance = null; 16563 var isHydrating = false; 16564 16565 function enterHydrationState(fiber) { 16566 16567 var parentInstance = fiber.stateNode.containerInfo; 16568 nextHydratableInstance = getFirstHydratableChild(parentInstance); 16569 hydrationParentFiber = fiber; 16570 isHydrating = true; 16571 return true; 16572 } 16573 16574 function deleteHydratableInstance(returnFiber, instance) { 16575 { 16576 switch (returnFiber.tag) { 16577 case HostRoot: 16578 didNotHydrateContainerInstance(returnFiber.stateNode.containerInfo, instance); 16579 break; 16580 16581 case HostComponent: 16582 didNotHydrateInstance(returnFiber.type, returnFiber.memoizedProps, returnFiber.stateNode, instance); 16583 break; 16584 } 16585 } 16586 16587 var childToDelete = createFiberFromHostInstanceForDeletion(); 16588 childToDelete.stateNode = instance; 16589 childToDelete.return = returnFiber; 16590 childToDelete.effectTag = Deletion; // This might seem like it belongs on progressedFirstDeletion. However, 16591 // these children are not part of the reconciliation list of children. 16592 // Even if we abort and rereconcile the children, that will try to hydrate 16593 // again and the nodes are still in the host tree so these will be 16594 // recreated. 16595 16596 if (returnFiber.lastEffect !== null) { 16597 returnFiber.lastEffect.nextEffect = childToDelete; 16598 returnFiber.lastEffect = childToDelete; 16599 } else { 16600 returnFiber.firstEffect = returnFiber.lastEffect = childToDelete; 16601 } 16602 } 16603 16604 function insertNonHydratedInstance(returnFiber, fiber) { 16605 fiber.effectTag = fiber.effectTag & ~Hydrating | Placement; 16606 16607 { 16608 switch (returnFiber.tag) { 16609 case HostRoot: 16610 { 16611 var parentContainer = returnFiber.stateNode.containerInfo; 16612 16613 switch (fiber.tag) { 16614 case HostComponent: 16615 var type = fiber.type; 16616 var props = fiber.pendingProps; 16617 didNotFindHydratableContainerInstance(parentContainer, type); 16618 break; 16619 16620 case HostText: 16621 var text = fiber.pendingProps; 16622 didNotFindHydratableContainerTextInstance(parentContainer, text); 16623 break; 16624 } 16625 16626 break; 16627 } 16628 16629 case HostComponent: 16630 { 16631 var parentType = returnFiber.type; 16632 var parentProps = returnFiber.memoizedProps; 16633 var parentInstance = returnFiber.stateNode; 16634 16635 switch (fiber.tag) { 16636 case HostComponent: 16637 var _type = fiber.type; 16638 var _props = fiber.pendingProps; 16639 didNotFindHydratableInstance(parentType, parentProps, parentInstance, _type); 16640 break; 16641 16642 case HostText: 16643 var _text = fiber.pendingProps; 16644 didNotFindHydratableTextInstance(parentType, parentProps, parentInstance, _text); 16645 break; 16646 16647 case SuspenseComponent: 16648 didNotFindHydratableSuspenseInstance(parentType, parentProps); 16649 break; 16650 } 16651 16652 break; 16653 } 16654 16655 default: 16656 return; 16657 } 16658 } 16659 } 16660 16661 function tryHydrate(fiber, nextInstance) { 16662 switch (fiber.tag) { 16663 case HostComponent: 16664 { 16665 var type = fiber.type; 16666 var props = fiber.pendingProps; 16667 var instance = canHydrateInstance(nextInstance, type); 16668 16669 if (instance !== null) { 16670 fiber.stateNode = instance; 16671 return true; 16672 } 16673 16674 return false; 16675 } 16676 16677 case HostText: 16678 { 16679 var text = fiber.pendingProps; 16680 var textInstance = canHydrateTextInstance(nextInstance, text); 16681 16682 if (textInstance !== null) { 16683 fiber.stateNode = textInstance; 16684 return true; 16685 } 16686 16687 return false; 16688 } 16689 16690 case SuspenseComponent: 16691 { 16692 16693 return false; 16694 } 16695 16696 default: 16697 return false; 16698 } 16699 } 16700 16701 function tryToClaimNextHydratableInstance(fiber) { 16702 if (!isHydrating) { 16703 return; 16704 } 16705 16706 var nextInstance = nextHydratableInstance; 16707 16708 if (!nextInstance) { 16709 // Nothing to hydrate. Make it an insertion. 16710 insertNonHydratedInstance(hydrationParentFiber, fiber); 16711 isHydrating = false; 16712 hydrationParentFiber = fiber; 16713 return; 16714 } 16715 16716 var firstAttemptedInstance = nextInstance; 16717 16718 if (!tryHydrate(fiber, nextInstance)) { 16719 // If we can't hydrate this instance let's try the next one. 16720 // We use this as a heuristic. It's based on intuition and not data so it 16721 // might be flawed or unnecessary. 16722 nextInstance = getNextHydratableSibling(firstAttemptedInstance); 16723 16724 if (!nextInstance || !tryHydrate(fiber, nextInstance)) { 16725 // Nothing to hydrate. Make it an insertion. 16726 insertNonHydratedInstance(hydrationParentFiber, fiber); 16727 isHydrating = false; 16728 hydrationParentFiber = fiber; 16729 return; 16730 } // We matched the next one, we'll now assume that the first one was 16731 // superfluous and we'll delete it. Since we can't eagerly delete it 16732 // we'll have to schedule a deletion. To do that, this node needs a dummy 16733 // fiber associated with it. 16734 16735 16736 deleteHydratableInstance(hydrationParentFiber, firstAttemptedInstance); 16737 } 16738 16739 hydrationParentFiber = fiber; 16740 nextHydratableInstance = getFirstHydratableChild(nextInstance); 16741 } 16742 16743 function prepareToHydrateHostInstance(fiber, rootContainerInstance, hostContext) { 16744 16745 var instance = fiber.stateNode; 16746 var updatePayload = hydrateInstance(instance, fiber.type, fiber.memoizedProps, rootContainerInstance, hostContext, fiber); // TODO: Type this specific to this type of component. 16747 16748 fiber.updateQueue = updatePayload; // If the update payload indicates that there is a change or if there 16749 // is a new ref we mark this as an update. 16750 16751 if (updatePayload !== null) { 16752 return true; 16753 } 16754 16755 return false; 16756 } 16757 16758 function prepareToHydrateHostTextInstance(fiber) { 16759 16760 var textInstance = fiber.stateNode; 16761 var textContent = fiber.memoizedProps; 16762 var shouldUpdate = hydrateTextInstance(textInstance, textContent, fiber); 16763 16764 { 16765 if (shouldUpdate) { 16766 // We assume that prepareToHydrateHostTextInstance is called in a context where the 16767 // hydration parent is the parent host component of this host text. 16768 var returnFiber = hydrationParentFiber; 16769 16770 if (returnFiber !== null) { 16771 switch (returnFiber.tag) { 16772 case HostRoot: 16773 { 16774 var parentContainer = returnFiber.stateNode.containerInfo; 16775 didNotMatchHydratedContainerTextInstance(parentContainer, textInstance, textContent); 16776 break; 16777 } 16778 16779 case HostComponent: 16780 { 16781 var parentType = returnFiber.type; 16782 var parentProps = returnFiber.memoizedProps; 16783 var parentInstance = returnFiber.stateNode; 16784 didNotMatchHydratedTextInstance(parentType, parentProps, parentInstance, textInstance, textContent); 16785 break; 16786 } 16787 } 16788 } 16789 } 16790 } 16791 16792 return shouldUpdate; 16793 } 16794 16795 function skipPastDehydratedSuspenseInstance(fiber) { 16796 16797 var suspenseState = fiber.memoizedState; 16798 var suspenseInstance = suspenseState !== null ? suspenseState.dehydrated : null; 16799 16800 if (!suspenseInstance) { 16801 { 16802 throw Error( "Expected to have a hydrated suspense instance. This error is likely caused by a bug in React. Please file an issue." ); 16803 } 16804 } 16805 16806 return getNextHydratableInstanceAfterSuspenseInstance(suspenseInstance); 16807 } 16808 16809 function popToNextHostParent(fiber) { 16810 var parent = fiber.return; 16811 16812 while (parent !== null && parent.tag !== HostComponent && parent.tag !== HostRoot && parent.tag !== SuspenseComponent) { 16813 parent = parent.return; 16814 } 16815 16816 hydrationParentFiber = parent; 16817 } 16818 16819 function popHydrationState(fiber) { 16820 16821 if (fiber !== hydrationParentFiber) { 16822 // We're deeper than the current hydration context, inside an inserted 16823 // tree. 16824 return false; 16825 } 16826 16827 if (!isHydrating) { 16828 // If we're not currently hydrating but we're in a hydration context, then 16829 // we were an insertion and now need to pop up reenter hydration of our 16830 // siblings. 16831 popToNextHostParent(fiber); 16832 isHydrating = true; 16833 return false; 16834 } 16835 16836 var type = fiber.type; // If we have any remaining hydratable nodes, we need to delete them now. 16837 // We only do this deeper than head and body since they tend to have random 16838 // other nodes in them. We also ignore components with pure text content in 16839 // side of them. 16840 // TODO: Better heuristic. 16841 16842 if (fiber.tag !== HostComponent || type !== 'head' && type !== 'body' && !shouldSetTextContent(type, fiber.memoizedProps)) { 16843 var nextInstance = nextHydratableInstance; 16844 16845 while (nextInstance) { 16846 deleteHydratableInstance(fiber, nextInstance); 16847 nextInstance = getNextHydratableSibling(nextInstance); 16848 } 16849 } 16850 16851 popToNextHostParent(fiber); 16852 16853 if (fiber.tag === SuspenseComponent) { 16854 nextHydratableInstance = skipPastDehydratedSuspenseInstance(fiber); 16855 } else { 16856 nextHydratableInstance = hydrationParentFiber ? getNextHydratableSibling(fiber.stateNode) : null; 16857 } 16858 16859 return true; 16860 } 16861 16862 function resetHydrationState() { 16863 16864 hydrationParentFiber = null; 16865 nextHydratableInstance = null; 16866 isHydrating = false; 16867 } 16868 16869 var ReactCurrentOwner$1 = ReactSharedInternals.ReactCurrentOwner; 16870 var didReceiveUpdate = false; 16871 var didWarnAboutBadClass; 16872 var didWarnAboutModulePatternComponent; 16873 var didWarnAboutContextTypeOnFunctionComponent; 16874 var didWarnAboutGetDerivedStateOnFunctionComponent; 16875 var didWarnAboutFunctionRefs; 16876 var didWarnAboutReassigningProps; 16877 var didWarnAboutRevealOrder; 16878 var didWarnAboutTailOptions; 16879 16880 { 16881 didWarnAboutBadClass = {}; 16882 didWarnAboutModulePatternComponent = {}; 16883 didWarnAboutContextTypeOnFunctionComponent = {}; 16884 didWarnAboutGetDerivedStateOnFunctionComponent = {}; 16885 didWarnAboutFunctionRefs = {}; 16886 didWarnAboutReassigningProps = false; 16887 didWarnAboutRevealOrder = {}; 16888 didWarnAboutTailOptions = {}; 16889 } 16890 16891 function reconcileChildren(current, workInProgress, nextChildren, renderExpirationTime) { 16892 if (current === null) { 16893 // If this is a fresh new component that hasn't been rendered yet, we 16894 // won't update its child set by applying minimal side-effects. Instead, 16895 // we will add them all to the child before it gets rendered. That means 16896 // we can optimize this reconciliation pass by not tracking side-effects. 16897 workInProgress.child = mountChildFibers(workInProgress, null, nextChildren, renderExpirationTime); 16898 } else { 16899 // If the current child is the same as the work in progress, it means that 16900 // we haven't yet started any work on these children. Therefore, we use 16901 // the clone algorithm to create a copy of all the current children. 16902 // If we had any progressed work already, that is invalid at this point so 16903 // let's throw it out. 16904 workInProgress.child = reconcileChildFibers(workInProgress, current.child, nextChildren, renderExpirationTime); 16905 } 16906 } 16907 16908 function forceUnmountCurrentAndReconcile(current, workInProgress, nextChildren, renderExpirationTime) { 16909 // This function is fork of reconcileChildren. It's used in cases where we 16910 // want to reconcile without matching against the existing set. This has the 16911 // effect of all current children being unmounted; even if the type and key 16912 // are the same, the old child is unmounted and a new child is created. 16913 // 16914 // To do this, we're going to go through the reconcile algorithm twice. In 16915 // the first pass, we schedule a deletion for all the current children by 16916 // passing null. 16917 workInProgress.child = reconcileChildFibers(workInProgress, current.child, null, renderExpirationTime); // In the second pass, we mount the new children. The trick here is that we 16918 // pass null in place of where we usually pass the current child set. This has 16919 // the effect of remounting all children regardless of whether their 16920 // identities match. 16921 16922 workInProgress.child = reconcileChildFibers(workInProgress, null, nextChildren, renderExpirationTime); 16923 } 16924 16925 function updateForwardRef(current, workInProgress, Component, nextProps, renderExpirationTime) { 16926 // TODO: current can be non-null here even if the component 16927 // hasn't yet mounted. This happens after the first render suspends. 16928 // We'll need to figure out if this is fine or can cause issues. 16929 { 16930 if (workInProgress.type !== workInProgress.elementType) { 16931 // Lazy component props can't be validated in createElement 16932 // because they're only guaranteed to be resolved here. 16933 var innerPropTypes = Component.propTypes; 16934 16935 if (innerPropTypes) { 16936 checkPropTypes_1(innerPropTypes, nextProps, // Resolved props 16937 'prop', getComponentName(Component), getCurrentFiberStackInDev); 16938 } 16939 } 16940 } 16941 16942 var render = Component.render; 16943 var ref = workInProgress.ref; // The rest is a fork of updateFunctionComponent 16944 16945 var nextChildren; 16946 prepareToReadContext(workInProgress, renderExpirationTime); 16947 16948 { 16949 ReactCurrentOwner$1.current = workInProgress; 16950 setIsRendering(true); 16951 nextChildren = renderWithHooks(current, workInProgress, render, nextProps, ref, renderExpirationTime); 16952 16953 if ( workInProgress.mode & StrictMode) { 16954 // Only double-render components with Hooks 16955 if (workInProgress.memoizedState !== null) { 16956 nextChildren = renderWithHooks(current, workInProgress, render, nextProps, ref, renderExpirationTime); 16957 } 16958 } 16959 16960 setIsRendering(false); 16961 } 16962 16963 if (current !== null && !didReceiveUpdate) { 16964 bailoutHooks(current, workInProgress, renderExpirationTime); 16965 return bailoutOnAlreadyFinishedWork(current, workInProgress, renderExpirationTime); 16966 } // React DevTools reads this flag. 16967 16968 16969 workInProgress.effectTag |= PerformedWork; 16970 reconcileChildren(current, workInProgress, nextChildren, renderExpirationTime); 16971 return workInProgress.child; 16972 } 16973 16974 function updateMemoComponent(current, workInProgress, Component, nextProps, updateExpirationTime, renderExpirationTime) { 16975 if (current === null) { 16976 var type = Component.type; 16977 16978 if (isSimpleFunctionComponent(type) && Component.compare === null && // SimpleMemoComponent codepath doesn't resolve outer props either. 16979 Component.defaultProps === undefined) { 16980 var resolvedType = type; 16981 16982 { 16983 resolvedType = resolveFunctionForHotReloading(type); 16984 } // If this is a plain function component without default props, 16985 // and with only the default shallow comparison, we upgrade it 16986 // to a SimpleMemoComponent to allow fast path updates. 16987 16988 16989 workInProgress.tag = SimpleMemoComponent; 16990 workInProgress.type = resolvedType; 16991 16992 { 16993 validateFunctionComponentInDev(workInProgress, type); 16994 } 16995 16996 return updateSimpleMemoComponent(current, workInProgress, resolvedType, nextProps, updateExpirationTime, renderExpirationTime); 16997 } 16998 16999 { 17000 var innerPropTypes = type.propTypes; 17001 17002 if (innerPropTypes) { 17003 // Inner memo component props aren't currently validated in createElement. 17004 // We could move it there, but we'd still need this for lazy code path. 17005 checkPropTypes_1(innerPropTypes, nextProps, // Resolved props 17006 'prop', getComponentName(type), getCurrentFiberStackInDev); 17007 } 17008 } 17009 17010 var child = createFiberFromTypeAndProps(Component.type, null, nextProps, null, workInProgress.mode, renderExpirationTime); 17011 child.ref = workInProgress.ref; 17012 child.return = workInProgress; 17013 workInProgress.child = child; 17014 return child; 17015 } 17016 17017 { 17018 var _type = Component.type; 17019 var _innerPropTypes = _type.propTypes; 17020 17021 if (_innerPropTypes) { 17022 // Inner memo component props aren't currently validated in createElement. 17023 // We could move it there, but we'd still need this for lazy code path. 17024 checkPropTypes_1(_innerPropTypes, nextProps, // Resolved props 17025 'prop', getComponentName(_type), getCurrentFiberStackInDev); 17026 } 17027 } 17028 17029 var currentChild = current.child; // This is always exactly one child 17030 17031 if (updateExpirationTime < renderExpirationTime) { 17032 // This will be the props with resolved defaultProps, 17033 // unlike current.memoizedProps which will be the unresolved ones. 17034 var prevProps = currentChild.memoizedProps; // Default to shallow comparison 17035 17036 var compare = Component.compare; 17037 compare = compare !== null ? compare : shallowEqual; 17038 17039 if (compare(prevProps, nextProps) && current.ref === workInProgress.ref) { 17040 return bailoutOnAlreadyFinishedWork(current, workInProgress, renderExpirationTime); 17041 } 17042 } // React DevTools reads this flag. 17043 17044 17045 workInProgress.effectTag |= PerformedWork; 17046 var newChild = createWorkInProgress(currentChild, nextProps); 17047 newChild.ref = workInProgress.ref; 17048 newChild.return = workInProgress; 17049 workInProgress.child = newChild; 17050 return newChild; 17051 } 17052 17053 function updateSimpleMemoComponent(current, workInProgress, Component, nextProps, updateExpirationTime, renderExpirationTime) { 17054 // TODO: current can be non-null here even if the component 17055 // hasn't yet mounted. This happens when the inner render suspends. 17056 // We'll need to figure out if this is fine or can cause issues. 17057 { 17058 if (workInProgress.type !== workInProgress.elementType) { 17059 // Lazy component props can't be validated in createElement 17060 // because they're only guaranteed to be resolved here. 17061 var outerMemoType = workInProgress.elementType; 17062 17063 if (outerMemoType.$$typeof === REACT_LAZY_TYPE) { 17064 // We warn when you define propTypes on lazy() 17065 // so let's just skip over it to find memo() outer wrapper. 17066 // Inner props for memo are validated later. 17067 outerMemoType = refineResolvedLazyComponent(outerMemoType); 17068 } 17069 17070 var outerPropTypes = outerMemoType && outerMemoType.propTypes; 17071 17072 if (outerPropTypes) { 17073 checkPropTypes_1(outerPropTypes, nextProps, // Resolved (SimpleMemoComponent has no defaultProps) 17074 'prop', getComponentName(outerMemoType), getCurrentFiberStackInDev); 17075 } // Inner propTypes will be validated in the function component path. 17076 17077 } 17078 } 17079 17080 if (current !== null) { 17081 var prevProps = current.memoizedProps; 17082 17083 if (shallowEqual(prevProps, nextProps) && current.ref === workInProgress.ref && ( // Prevent bailout if the implementation changed due to hot reload. 17084 workInProgress.type === current.type )) { 17085 didReceiveUpdate = false; 17086 17087 if (updateExpirationTime < renderExpirationTime) { 17088 // The pending update priority was cleared at the beginning of 17089 // beginWork. We're about to bail out, but there might be additional 17090 // updates at a lower priority. Usually, the priority level of the 17091 // remaining updates is accumlated during the evaluation of the 17092 // component (i.e. when processing the update queue). But since since 17093 // we're bailing out early *without* evaluating the component, we need 17094 // to account for it here, too. Reset to the value of the current fiber. 17095 // NOTE: This only applies to SimpleMemoComponent, not MemoComponent, 17096 // because a MemoComponent fiber does not have hooks or an update queue; 17097 // rather, it wraps around an inner component, which may or may not 17098 // contains hooks. 17099 // TODO: Move the reset at in beginWork out of the common path so that 17100 // this is no longer necessary. 17101 workInProgress.expirationTime = current.expirationTime; 17102 return bailoutOnAlreadyFinishedWork(current, workInProgress, renderExpirationTime); 17103 } 17104 } 17105 } 17106 17107 return updateFunctionComponent(current, workInProgress, Component, nextProps, renderExpirationTime); 17108 } 17109 17110 function updateFragment(current, workInProgress, renderExpirationTime) { 17111 var nextChildren = workInProgress.pendingProps; 17112 reconcileChildren(current, workInProgress, nextChildren, renderExpirationTime); 17113 return workInProgress.child; 17114 } 17115 17116 function updateMode(current, workInProgress, renderExpirationTime) { 17117 var nextChildren = workInProgress.pendingProps.children; 17118 reconcileChildren(current, workInProgress, nextChildren, renderExpirationTime); 17119 return workInProgress.child; 17120 } 17121 17122 function updateProfiler(current, workInProgress, renderExpirationTime) { 17123 { 17124 workInProgress.effectTag |= Update; 17125 } 17126 17127 var nextProps = workInProgress.pendingProps; 17128 var nextChildren = nextProps.children; 17129 reconcileChildren(current, workInProgress, nextChildren, renderExpirationTime); 17130 return workInProgress.child; 17131 } 17132 17133 function markRef(current, workInProgress) { 17134 var ref = workInProgress.ref; 17135 17136 if (current === null && ref !== null || current !== null && current.ref !== ref) { 17137 // Schedule a Ref effect 17138 workInProgress.effectTag |= Ref; 17139 } 17140 } 17141 17142 function updateFunctionComponent(current, workInProgress, Component, nextProps, renderExpirationTime) { 17143 { 17144 if (workInProgress.type !== workInProgress.elementType) { 17145 // Lazy component props can't be validated in createElement 17146 // because they're only guaranteed to be resolved here. 17147 var innerPropTypes = Component.propTypes; 17148 17149 if (innerPropTypes) { 17150 checkPropTypes_1(innerPropTypes, nextProps, // Resolved props 17151 'prop', getComponentName(Component), getCurrentFiberStackInDev); 17152 } 17153 } 17154 } 17155 17156 var context; 17157 17158 { 17159 var unmaskedContext = getUnmaskedContext(workInProgress, Component, true); 17160 context = getMaskedContext(workInProgress, unmaskedContext); 17161 } 17162 17163 var nextChildren; 17164 prepareToReadContext(workInProgress, renderExpirationTime); 17165 17166 { 17167 ReactCurrentOwner$1.current = workInProgress; 17168 setIsRendering(true); 17169 nextChildren = renderWithHooks(current, workInProgress, Component, nextProps, context, renderExpirationTime); 17170 17171 if ( workInProgress.mode & StrictMode) { 17172 // Only double-render components with Hooks 17173 if (workInProgress.memoizedState !== null) { 17174 nextChildren = renderWithHooks(current, workInProgress, Component, nextProps, context, renderExpirationTime); 17175 } 17176 } 17177 17178 setIsRendering(false); 17179 } 17180 17181 if (current !== null && !didReceiveUpdate) { 17182 bailoutHooks(current, workInProgress, renderExpirationTime); 17183 return bailoutOnAlreadyFinishedWork(current, workInProgress, renderExpirationTime); 17184 } // React DevTools reads this flag. 17185 17186 17187 workInProgress.effectTag |= PerformedWork; 17188 reconcileChildren(current, workInProgress, nextChildren, renderExpirationTime); 17189 return workInProgress.child; 17190 } 17191 17192 function updateClassComponent(current, workInProgress, Component, nextProps, renderExpirationTime) { 17193 { 17194 if (workInProgress.type !== workInProgress.elementType) { 17195 // Lazy component props can't be validated in createElement 17196 // because they're only guaranteed to be resolved here. 17197 var innerPropTypes = Component.propTypes; 17198 17199 if (innerPropTypes) { 17200 checkPropTypes_1(innerPropTypes, nextProps, // Resolved props 17201 'prop', getComponentName(Component), getCurrentFiberStackInDev); 17202 } 17203 } 17204 } // Push context providers early to prevent context stack mismatches. 17205 // During mounting we don't know the child context yet as the instance doesn't exist. 17206 // We will invalidate the child context in finishClassComponent() right after rendering. 17207 17208 17209 var hasContext; 17210 17211 if (isContextProvider(Component)) { 17212 hasContext = true; 17213 pushContextProvider(workInProgress); 17214 } else { 17215 hasContext = false; 17216 } 17217 17218 prepareToReadContext(workInProgress, renderExpirationTime); 17219 var instance = workInProgress.stateNode; 17220 var shouldUpdate; 17221 17222 if (instance === null) { 17223 if (current !== null) { 17224 // A class component without an instance only mounts if it suspended 17225 // inside a non-concurrent tree, in an inconsistent state. We want to 17226 // treat it like a new mount, even though an empty version of it already 17227 // committed. Disconnect the alternate pointers. 17228 current.alternate = null; 17229 workInProgress.alternate = null; // Since this is conceptually a new fiber, schedule a Placement effect 17230 17231 workInProgress.effectTag |= Placement; 17232 } // In the initial pass we might need to construct the instance. 17233 17234 17235 constructClassInstance(workInProgress, Component, nextProps); 17236 mountClassInstance(workInProgress, Component, nextProps, renderExpirationTime); 17237 shouldUpdate = true; 17238 } else if (current === null) { 17239 // In a resume, we'll already have an instance we can reuse. 17240 shouldUpdate = resumeMountClassInstance(workInProgress, Component, nextProps, renderExpirationTime); 17241 } else { 17242 shouldUpdate = updateClassInstance(current, workInProgress, Component, nextProps, renderExpirationTime); 17243 } 17244 17245 var nextUnitOfWork = finishClassComponent(current, workInProgress, Component, shouldUpdate, hasContext, renderExpirationTime); 17246 17247 { 17248 var inst = workInProgress.stateNode; 17249 17250 if (inst.props !== nextProps) { 17251 if (!didWarnAboutReassigningProps) { 17252 error('It looks like %s is reassigning its own `this.props` while rendering. ' + 'This is not supported and can lead to confusing bugs.', getComponentName(workInProgress.type) || 'a component'); 17253 } 17254 17255 didWarnAboutReassigningProps = true; 17256 } 17257 } 17258 17259 return nextUnitOfWork; 17260 } 17261 17262 function finishClassComponent(current, workInProgress, Component, shouldUpdate, hasContext, renderExpirationTime) { 17263 // Refs should update even if shouldComponentUpdate returns false 17264 markRef(current, workInProgress); 17265 var didCaptureError = (workInProgress.effectTag & DidCapture) !== NoEffect; 17266 17267 if (!shouldUpdate && !didCaptureError) { 17268 // Context providers should defer to sCU for rendering 17269 if (hasContext) { 17270 invalidateContextProvider(workInProgress, Component, false); 17271 } 17272 17273 return bailoutOnAlreadyFinishedWork(current, workInProgress, renderExpirationTime); 17274 } 17275 17276 var instance = workInProgress.stateNode; // Rerender 17277 17278 ReactCurrentOwner$1.current = workInProgress; 17279 var nextChildren; 17280 17281 if (didCaptureError && typeof Component.getDerivedStateFromError !== 'function') { 17282 // If we captured an error, but getDerivedStateFromError is not defined, 17283 // unmount all the children. componentDidCatch will schedule an update to 17284 // re-render a fallback. This is temporary until we migrate everyone to 17285 // the new API. 17286 // TODO: Warn in a future release. 17287 nextChildren = null; 17288 17289 { 17290 stopProfilerTimerIfRunning(); 17291 } 17292 } else { 17293 { 17294 setIsRendering(true); 17295 nextChildren = instance.render(); 17296 17297 if ( workInProgress.mode & StrictMode) { 17298 instance.render(); 17299 } 17300 17301 setIsRendering(false); 17302 } 17303 } // React DevTools reads this flag. 17304 17305 17306 workInProgress.effectTag |= PerformedWork; 17307 17308 if (current !== null && didCaptureError) { 17309 // If we're recovering from an error, reconcile without reusing any of 17310 // the existing children. Conceptually, the normal children and the children 17311 // that are shown on error are two different sets, so we shouldn't reuse 17312 // normal children even if their identities match. 17313 forceUnmountCurrentAndReconcile(current, workInProgress, nextChildren, renderExpirationTime); 17314 } else { 17315 reconcileChildren(current, workInProgress, nextChildren, renderExpirationTime); 17316 } // Memoize state using the values we just used to render. 17317 // TODO: Restructure so we never read values from the instance. 17318 17319 17320 workInProgress.memoizedState = instance.state; // The context might have changed so we need to recalculate it. 17321 17322 if (hasContext) { 17323 invalidateContextProvider(workInProgress, Component, true); 17324 } 17325 17326 return workInProgress.child; 17327 } 17328 17329 function pushHostRootContext(workInProgress) { 17330 var root = workInProgress.stateNode; 17331 17332 if (root.pendingContext) { 17333 pushTopLevelContextObject(workInProgress, root.pendingContext, root.pendingContext !== root.context); 17334 } else if (root.context) { 17335 // Should always be set 17336 pushTopLevelContextObject(workInProgress, root.context, false); 17337 } 17338 17339 pushHostContainer(workInProgress, root.containerInfo); 17340 } 17341 17342 function updateHostRoot(current, workInProgress, renderExpirationTime) { 17343 pushHostRootContext(workInProgress); 17344 var updateQueue = workInProgress.updateQueue; 17345 17346 if (!(current !== null && updateQueue !== null)) { 17347 { 17348 throw Error( "If the root does not have an updateQueue, we should have already bailed out. This error is likely caused by a bug in React. Please file an issue." ); 17349 } 17350 } 17351 17352 var nextProps = workInProgress.pendingProps; 17353 var prevState = workInProgress.memoizedState; 17354 var prevChildren = prevState !== null ? prevState.element : null; 17355 cloneUpdateQueue(current, workInProgress); 17356 processUpdateQueue(workInProgress, nextProps, null, renderExpirationTime); 17357 var nextState = workInProgress.memoizedState; // Caution: React DevTools currently depends on this property 17358 // being called "element". 17359 17360 var nextChildren = nextState.element; 17361 17362 if (nextChildren === prevChildren) { 17363 // If the state is the same as before, that's a bailout because we had 17364 // no work that expires at this time. 17365 resetHydrationState(); 17366 return bailoutOnAlreadyFinishedWork(current, workInProgress, renderExpirationTime); 17367 } 17368 17369 var root = workInProgress.stateNode; 17370 17371 if (root.hydrate && enterHydrationState(workInProgress)) { 17372 // If we don't have any current children this might be the first pass. 17373 // We always try to hydrate. If this isn't a hydration pass there won't 17374 // be any children to hydrate which is effectively the same thing as 17375 // not hydrating. 17376 var child = mountChildFibers(workInProgress, null, nextChildren, renderExpirationTime); 17377 workInProgress.child = child; 17378 var node = child; 17379 17380 while (node) { 17381 // Mark each child as hydrating. This is a fast path to know whether this 17382 // tree is part of a hydrating tree. This is used to determine if a child 17383 // node has fully mounted yet, and for scheduling event replaying. 17384 // Conceptually this is similar to Placement in that a new subtree is 17385 // inserted into the React tree here. It just happens to not need DOM 17386 // mutations because it already exists. 17387 node.effectTag = node.effectTag & ~Placement | Hydrating; 17388 node = node.sibling; 17389 } 17390 } else { 17391 // Otherwise reset hydration state in case we aborted and resumed another 17392 // root. 17393 reconcileChildren(current, workInProgress, nextChildren, renderExpirationTime); 17394 resetHydrationState(); 17395 } 17396 17397 return workInProgress.child; 17398 } 17399 17400 function updateHostComponent(current, workInProgress, renderExpirationTime) { 17401 pushHostContext(workInProgress); 17402 17403 if (current === null) { 17404 tryToClaimNextHydratableInstance(workInProgress); 17405 } 17406 17407 var type = workInProgress.type; 17408 var nextProps = workInProgress.pendingProps; 17409 var prevProps = current !== null ? current.memoizedProps : null; 17410 var nextChildren = nextProps.children; 17411 var isDirectTextChild = shouldSetTextContent(type, nextProps); 17412 17413 if (isDirectTextChild) { 17414 // We special case a direct text child of a host node. This is a common 17415 // case. We won't handle it as a reified child. We will instead handle 17416 // this in the host environment that also has access to this prop. That 17417 // avoids allocating another HostText fiber and traversing it. 17418 nextChildren = null; 17419 } else if (prevProps !== null && shouldSetTextContent(type, prevProps)) { 17420 // If we're switching from a direct text child to a normal child, or to 17421 // empty, we need to schedule the text content to be reset. 17422 workInProgress.effectTag |= ContentReset; 17423 } 17424 17425 markRef(current, workInProgress); // Check the host config to see if the children are offscreen/hidden. 17426 17427 if (workInProgress.mode & ConcurrentMode && renderExpirationTime !== Never && shouldDeprioritizeSubtree(type, nextProps)) { 17428 { 17429 markSpawnedWork(Never); 17430 } // Schedule this fiber to re-render at offscreen priority. Then bailout. 17431 17432 17433 workInProgress.expirationTime = workInProgress.childExpirationTime = Never; 17434 return null; 17435 } 17436 17437 reconcileChildren(current, workInProgress, nextChildren, renderExpirationTime); 17438 return workInProgress.child; 17439 } 17440 17441 function updateHostText(current, workInProgress) { 17442 if (current === null) { 17443 tryToClaimNextHydratableInstance(workInProgress); 17444 } // Nothing to do here. This is terminal. We'll do the completion step 17445 // immediately after. 17446 17447 17448 return null; 17449 } 17450 17451 function mountLazyComponent(_current, workInProgress, elementType, updateExpirationTime, renderExpirationTime) { 17452 if (_current !== null) { 17453 // A lazy component only mounts if it suspended inside a non- 17454 // concurrent tree, in an inconsistent state. We want to treat it like 17455 // a new mount, even though an empty version of it already committed. 17456 // Disconnect the alternate pointers. 17457 _current.alternate = null; 17458 workInProgress.alternate = null; // Since this is conceptually a new fiber, schedule a Placement effect 17459 17460 workInProgress.effectTag |= Placement; 17461 } 17462 17463 var props = workInProgress.pendingProps; // We can't start a User Timing measurement with correct label yet. 17464 // Cancel and resume right after we know the tag. 17465 17466 cancelWorkTimer(workInProgress); 17467 var Component = readLazyComponentType(elementType); // Store the unwrapped component in the type. 17468 17469 workInProgress.type = Component; 17470 var resolvedTag = workInProgress.tag = resolveLazyComponentTag(Component); 17471 startWorkTimer(workInProgress); 17472 var resolvedProps = resolveDefaultProps(Component, props); 17473 var child; 17474 17475 switch (resolvedTag) { 17476 case FunctionComponent: 17477 { 17478 { 17479 validateFunctionComponentInDev(workInProgress, Component); 17480 workInProgress.type = Component = resolveFunctionForHotReloading(Component); 17481 } 17482 17483 child = updateFunctionComponent(null, workInProgress, Component, resolvedProps, renderExpirationTime); 17484 return child; 17485 } 17486 17487 case ClassComponent: 17488 { 17489 { 17490 workInProgress.type = Component = resolveClassForHotReloading(Component); 17491 } 17492 17493 child = updateClassComponent(null, workInProgress, Component, resolvedProps, renderExpirationTime); 17494 return child; 17495 } 17496 17497 case ForwardRef: 17498 { 17499 { 17500 workInProgress.type = Component = resolveForwardRefForHotReloading(Component); 17501 } 17502 17503 child = updateForwardRef(null, workInProgress, Component, resolvedProps, renderExpirationTime); 17504 return child; 17505 } 17506 17507 case MemoComponent: 17508 { 17509 { 17510 if (workInProgress.type !== workInProgress.elementType) { 17511 var outerPropTypes = Component.propTypes; 17512 17513 if (outerPropTypes) { 17514 checkPropTypes_1(outerPropTypes, resolvedProps, // Resolved for outer only 17515 'prop', getComponentName(Component), getCurrentFiberStackInDev); 17516 } 17517 } 17518 } 17519 17520 child = updateMemoComponent(null, workInProgress, Component, resolveDefaultProps(Component.type, resolvedProps), // The inner type can have defaults too 17521 updateExpirationTime, renderExpirationTime); 17522 return child; 17523 } 17524 } 17525 17526 var hint = ''; 17527 17528 { 17529 if (Component !== null && typeof Component === 'object' && Component.$$typeof === REACT_LAZY_TYPE) { 17530 hint = ' Did you wrap a component in React.lazy() more than once?'; 17531 } 17532 } // This message intentionally doesn't mention ForwardRef or MemoComponent 17533 // because the fact that it's a separate type of work is an 17534 // implementation detail. 17535 17536 17537 { 17538 { 17539 throw Error( "Element type is invalid. Received a promise that resolves to: " + Component + ". Lazy element type must resolve to a class or function." + hint ); 17540 } 17541 } 17542 } 17543 17544 function mountIncompleteClassComponent(_current, workInProgress, Component, nextProps, renderExpirationTime) { 17545 if (_current !== null) { 17546 // An incomplete component only mounts if it suspended inside a non- 17547 // concurrent tree, in an inconsistent state. We want to treat it like 17548 // a new mount, even though an empty version of it already committed. 17549 // Disconnect the alternate pointers. 17550 _current.alternate = null; 17551 workInProgress.alternate = null; // Since this is conceptually a new fiber, schedule a Placement effect 17552 17553 workInProgress.effectTag |= Placement; 17554 } // Promote the fiber to a class and try rendering again. 17555 17556 17557 workInProgress.tag = ClassComponent; // The rest of this function is a fork of `updateClassComponent` 17558 // Push context providers early to prevent context stack mismatches. 17559 // During mounting we don't know the child context yet as the instance doesn't exist. 17560 // We will invalidate the child context in finishClassComponent() right after rendering. 17561 17562 var hasContext; 17563 17564 if (isContextProvider(Component)) { 17565 hasContext = true; 17566 pushContextProvider(workInProgress); 17567 } else { 17568 hasContext = false; 17569 } 17570 17571 prepareToReadContext(workInProgress, renderExpirationTime); 17572 constructClassInstance(workInProgress, Component, nextProps); 17573 mountClassInstance(workInProgress, Component, nextProps, renderExpirationTime); 17574 return finishClassComponent(null, workInProgress, Component, true, hasContext, renderExpirationTime); 17575 } 17576 17577 function mountIndeterminateComponent(_current, workInProgress, Component, renderExpirationTime) { 17578 if (_current !== null) { 17579 // An indeterminate component only mounts if it suspended inside a non- 17580 // concurrent tree, in an inconsistent state. We want to treat it like 17581 // a new mount, even though an empty version of it already committed. 17582 // Disconnect the alternate pointers. 17583 _current.alternate = null; 17584 workInProgress.alternate = null; // Since this is conceptually a new fiber, schedule a Placement effect 17585 17586 workInProgress.effectTag |= Placement; 17587 } 17588 17589 var props = workInProgress.pendingProps; 17590 var context; 17591 17592 { 17593 var unmaskedContext = getUnmaskedContext(workInProgress, Component, false); 17594 context = getMaskedContext(workInProgress, unmaskedContext); 17595 } 17596 17597 prepareToReadContext(workInProgress, renderExpirationTime); 17598 var value; 17599 17600 { 17601 if (Component.prototype && typeof Component.prototype.render === 'function') { 17602 var componentName = getComponentName(Component) || 'Unknown'; 17603 17604 if (!didWarnAboutBadClass[componentName]) { 17605 error("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); 17606 17607 didWarnAboutBadClass[componentName] = true; 17608 } 17609 } 17610 17611 if (workInProgress.mode & StrictMode) { 17612 ReactStrictModeWarnings.recordLegacyContextWarning(workInProgress, null); 17613 } 17614 17615 setIsRendering(true); 17616 ReactCurrentOwner$1.current = workInProgress; 17617 value = renderWithHooks(null, workInProgress, Component, props, context, renderExpirationTime); 17618 setIsRendering(false); 17619 } // React DevTools reads this flag. 17620 17621 17622 workInProgress.effectTag |= PerformedWork; 17623 17624 if (typeof value === 'object' && value !== null && typeof value.render === 'function' && value.$$typeof === undefined) { 17625 { 17626 var _componentName = getComponentName(Component) || 'Unknown'; 17627 17628 if (!didWarnAboutModulePatternComponent[_componentName]) { 17629 error('The <%s /> component appears to be a function component that returns a class instance. ' + 'Change %s to a class that extends React.Component instead. ' + "If you can't use a class try assigning the prototype on the function as a workaround. " + "`%s.prototype = React.Component.prototype`. Don't use an arrow function since it " + 'cannot be called with `new` by React.', _componentName, _componentName, _componentName); 17630 17631 didWarnAboutModulePatternComponent[_componentName] = true; 17632 } 17633 } // Proceed under the assumption that this is a class instance 17634 17635 17636 workInProgress.tag = ClassComponent; // Throw out any hooks that were used. 17637 17638 workInProgress.memoizedState = null; 17639 workInProgress.updateQueue = null; // Push context providers early to prevent context stack mismatches. 17640 // During mounting we don't know the child context yet as the instance doesn't exist. 17641 // We will invalidate the child context in finishClassComponent() right after rendering. 17642 17643 var hasContext = false; 17644 17645 if (isContextProvider(Component)) { 17646 hasContext = true; 17647 pushContextProvider(workInProgress); 17648 } else { 17649 hasContext = false; 17650 } 17651 17652 workInProgress.memoizedState = value.state !== null && value.state !== undefined ? value.state : null; 17653 initializeUpdateQueue(workInProgress); 17654 var getDerivedStateFromProps = Component.getDerivedStateFromProps; 17655 17656 if (typeof getDerivedStateFromProps === 'function') { 17657 applyDerivedStateFromProps(workInProgress, Component, getDerivedStateFromProps, props); 17658 } 17659 17660 adoptClassInstance(workInProgress, value); 17661 mountClassInstance(workInProgress, Component, props, renderExpirationTime); 17662 return finishClassComponent(null, workInProgress, Component, true, hasContext, renderExpirationTime); 17663 } else { 17664 // Proceed under the assumption that this is a function component 17665 workInProgress.tag = FunctionComponent; 17666 17667 { 17668 17669 if ( workInProgress.mode & StrictMode) { 17670 // Only double-render components with Hooks 17671 if (workInProgress.memoizedState !== null) { 17672 value = renderWithHooks(null, workInProgress, Component, props, context, renderExpirationTime); 17673 } 17674 } 17675 } 17676 17677 reconcileChildren(null, workInProgress, value, renderExpirationTime); 17678 17679 { 17680 validateFunctionComponentInDev(workInProgress, Component); 17681 } 17682 17683 return workInProgress.child; 17684 } 17685 } 17686 17687 function validateFunctionComponentInDev(workInProgress, Component) { 17688 { 17689 if (Component) { 17690 if (Component.childContextTypes) { 17691 error('%s(...): childContextTypes cannot be defined on a function component.', Component.displayName || Component.name || 'Component'); 17692 } 17693 } 17694 17695 if (workInProgress.ref !== null) { 17696 var info = ''; 17697 var ownerName = getCurrentFiberOwnerNameInDevOrNull(); 17698 17699 if (ownerName) { 17700 info += '\n\nCheck the render method of `' + ownerName + '`.'; 17701 } 17702 17703 var warningKey = ownerName || workInProgress._debugID || ''; 17704 var debugSource = workInProgress._debugSource; 17705 17706 if (debugSource) { 17707 warningKey = debugSource.fileName + ':' + debugSource.lineNumber; 17708 } 17709 17710 if (!didWarnAboutFunctionRefs[warningKey]) { 17711 didWarnAboutFunctionRefs[warningKey] = true; 17712 17713 error('Function components cannot be given refs. ' + 'Attempts to access this ref will fail. ' + 'Did you mean to use React.forwardRef()?%s', info); 17714 } 17715 } 17716 17717 if (typeof Component.getDerivedStateFromProps === 'function') { 17718 var _componentName2 = getComponentName(Component) || 'Unknown'; 17719 17720 if (!didWarnAboutGetDerivedStateOnFunctionComponent[_componentName2]) { 17721 error('%s: Function components do not support getDerivedStateFromProps.', _componentName2); 17722 17723 didWarnAboutGetDerivedStateOnFunctionComponent[_componentName2] = true; 17724 } 17725 } 17726 17727 if (typeof Component.contextType === 'object' && Component.contextType !== null) { 17728 var _componentName3 = getComponentName(Component) || 'Unknown'; 17729 17730 if (!didWarnAboutContextTypeOnFunctionComponent[_componentName3]) { 17731 error('%s: Function components do not support contextType.', _componentName3); 17732 17733 didWarnAboutContextTypeOnFunctionComponent[_componentName3] = true; 17734 } 17735 } 17736 } 17737 } 17738 17739 var SUSPENDED_MARKER = { 17740 dehydrated: null, 17741 retryTime: NoWork 17742 }; 17743 17744 function shouldRemainOnFallback(suspenseContext, current, workInProgress) { 17745 // If the context is telling us that we should show a fallback, and we're not 17746 // already showing content, then we should show the fallback instead. 17747 return hasSuspenseContext(suspenseContext, ForceSuspenseFallback) && (current === null || current.memoizedState !== null); 17748 } 17749 17750 function updateSuspenseComponent(current, workInProgress, renderExpirationTime) { 17751 var mode = workInProgress.mode; 17752 var nextProps = workInProgress.pendingProps; // This is used by DevTools to force a boundary to suspend. 17753 17754 { 17755 if (shouldSuspend(workInProgress)) { 17756 workInProgress.effectTag |= DidCapture; 17757 } 17758 } 17759 17760 var suspenseContext = suspenseStackCursor.current; 17761 var nextDidTimeout = false; 17762 var didSuspend = (workInProgress.effectTag & DidCapture) !== NoEffect; 17763 17764 if (didSuspend || shouldRemainOnFallback(suspenseContext, current)) { 17765 // Something in this boundary's subtree already suspended. Switch to 17766 // rendering the fallback children. 17767 nextDidTimeout = true; 17768 workInProgress.effectTag &= ~DidCapture; 17769 } else { 17770 // Attempting the main content 17771 if (current === null || current.memoizedState !== null) { 17772 // This is a new mount or this boundary is already showing a fallback state. 17773 // Mark this subtree context as having at least one invisible parent that could 17774 // handle the fallback state. 17775 // Boundaries without fallbacks or should be avoided are not considered since 17776 // they cannot handle preferred fallback states. 17777 if (nextProps.fallback !== undefined && nextProps.unstable_avoidThisFallback !== true) { 17778 suspenseContext = addSubtreeSuspenseContext(suspenseContext, InvisibleParentSuspenseContext); 17779 } 17780 } 17781 } 17782 17783 suspenseContext = setDefaultShallowSuspenseContext(suspenseContext); 17784 pushSuspenseContext(workInProgress, suspenseContext); // This next part is a bit confusing. If the children timeout, we switch to 17785 // showing the fallback children in place of the "primary" children. 17786 // However, we don't want to delete the primary children because then their 17787 // state will be lost (both the React state and the host state, e.g. 17788 // uncontrolled form inputs). Instead we keep them mounted and hide them. 17789 // Both the fallback children AND the primary children are rendered at the 17790 // same time. Once the primary children are un-suspended, we can delete 17791 // the fallback children — don't need to preserve their state. 17792 // 17793 // The two sets of children are siblings in the host environment, but 17794 // semantically, for purposes of reconciliation, they are two separate sets. 17795 // So we store them using two fragment fibers. 17796 // 17797 // However, we want to avoid allocating extra fibers for every placeholder. 17798 // They're only necessary when the children time out, because that's the 17799 // only time when both sets are mounted. 17800 // 17801 // So, the extra fragment fibers are only used if the children time out. 17802 // Otherwise, we render the primary children directly. This requires some 17803 // custom reconciliation logic to preserve the state of the primary 17804 // children. It's essentially a very basic form of re-parenting. 17805 17806 if (current === null) { 17807 // If we're currently hydrating, try to hydrate this boundary. 17808 // But only if this has a fallback. 17809 if (nextProps.fallback !== undefined) { 17810 tryToClaimNextHydratableInstance(workInProgress); // This could've been a dehydrated suspense component. 17811 } // This is the initial mount. This branch is pretty simple because there's 17812 // no previous state that needs to be preserved. 17813 17814 17815 if (nextDidTimeout) { 17816 // Mount separate fragments for primary and fallback children. 17817 var nextFallbackChildren = nextProps.fallback; 17818 var primaryChildFragment = createFiberFromFragment(null, mode, NoWork, null); 17819 primaryChildFragment.return = workInProgress; 17820 17821 if ((workInProgress.mode & BlockingMode) === NoMode) { 17822 // Outside of blocking mode, we commit the effects from the 17823 // partially completed, timed-out tree, too. 17824 var progressedState = workInProgress.memoizedState; 17825 var progressedPrimaryChild = progressedState !== null ? workInProgress.child.child : workInProgress.child; 17826 primaryChildFragment.child = progressedPrimaryChild; 17827 var progressedChild = progressedPrimaryChild; 17828 17829 while (progressedChild !== null) { 17830 progressedChild.return = primaryChildFragment; 17831 progressedChild = progressedChild.sibling; 17832 } 17833 } 17834 17835 var fallbackChildFragment = createFiberFromFragment(nextFallbackChildren, mode, renderExpirationTime, null); 17836 fallbackChildFragment.return = workInProgress; 17837 primaryChildFragment.sibling = fallbackChildFragment; // Skip the primary children, and continue working on the 17838 // fallback children. 17839 17840 workInProgress.memoizedState = SUSPENDED_MARKER; 17841 workInProgress.child = primaryChildFragment; 17842 return fallbackChildFragment; 17843 } else { 17844 // Mount the primary children without an intermediate fragment fiber. 17845 var nextPrimaryChildren = nextProps.children; 17846 workInProgress.memoizedState = null; 17847 return workInProgress.child = mountChildFibers(workInProgress, null, nextPrimaryChildren, renderExpirationTime); 17848 } 17849 } else { 17850 // This is an update. This branch is more complicated because we need to 17851 // ensure the state of the primary children is preserved. 17852 var prevState = current.memoizedState; 17853 17854 if (prevState !== null) { 17855 // wrapped in a fragment fiber. 17856 17857 17858 var currentPrimaryChildFragment = current.child; 17859 var currentFallbackChildFragment = currentPrimaryChildFragment.sibling; 17860 17861 if (nextDidTimeout) { 17862 // Still timed out. Reuse the current primary children by cloning 17863 // its fragment. We're going to skip over these entirely. 17864 var _nextFallbackChildren2 = nextProps.fallback; 17865 17866 var _primaryChildFragment2 = createWorkInProgress(currentPrimaryChildFragment, currentPrimaryChildFragment.pendingProps); 17867 17868 _primaryChildFragment2.return = workInProgress; 17869 17870 if ((workInProgress.mode & BlockingMode) === NoMode) { 17871 // Outside of blocking mode, we commit the effects from the 17872 // partially completed, timed-out tree, too. 17873 var _progressedState = workInProgress.memoizedState; 17874 17875 var _progressedPrimaryChild = _progressedState !== null ? workInProgress.child.child : workInProgress.child; 17876 17877 if (_progressedPrimaryChild !== currentPrimaryChildFragment.child) { 17878 _primaryChildFragment2.child = _progressedPrimaryChild; 17879 var _progressedChild2 = _progressedPrimaryChild; 17880 17881 while (_progressedChild2 !== null) { 17882 _progressedChild2.return = _primaryChildFragment2; 17883 _progressedChild2 = _progressedChild2.sibling; 17884 } 17885 } 17886 } // Because primaryChildFragment is a new fiber that we're inserting as the 17887 // parent of a new tree, we need to set its treeBaseDuration. 17888 17889 17890 if ( workInProgress.mode & ProfileMode) { 17891 // treeBaseDuration is the sum of all the child tree base durations. 17892 var _treeBaseDuration = 0; 17893 var _hiddenChild = _primaryChildFragment2.child; 17894 17895 while (_hiddenChild !== null) { 17896 _treeBaseDuration += _hiddenChild.treeBaseDuration; 17897 _hiddenChild = _hiddenChild.sibling; 17898 } 17899 17900 _primaryChildFragment2.treeBaseDuration = _treeBaseDuration; 17901 } // Clone the fallback child fragment, too. These we'll continue 17902 // working on. 17903 17904 17905 var _fallbackChildFragment2 = createWorkInProgress(currentFallbackChildFragment, _nextFallbackChildren2); 17906 17907 _fallbackChildFragment2.return = workInProgress; 17908 _primaryChildFragment2.sibling = _fallbackChildFragment2; 17909 _primaryChildFragment2.childExpirationTime = NoWork; // Skip the primary children, and continue working on the 17910 // fallback children. 17911 17912 workInProgress.memoizedState = SUSPENDED_MARKER; 17913 workInProgress.child = _primaryChildFragment2; 17914 return _fallbackChildFragment2; 17915 } else { 17916 // No longer suspended. Switch back to showing the primary children, 17917 // and remove the intermediate fragment fiber. 17918 var _nextPrimaryChildren = nextProps.children; 17919 var currentPrimaryChild = currentPrimaryChildFragment.child; 17920 var primaryChild = reconcileChildFibers(workInProgress, currentPrimaryChild, _nextPrimaryChildren, renderExpirationTime); // If this render doesn't suspend, we need to delete the fallback 17921 // children. Wait until the complete phase, after we've confirmed the 17922 // fallback is no longer needed. 17923 // TODO: Would it be better to store the fallback fragment on 17924 // the stateNode? 17925 // Continue rendering the children, like we normally do. 17926 17927 workInProgress.memoizedState = null; 17928 return workInProgress.child = primaryChild; 17929 } 17930 } else { 17931 // The current tree has not already timed out. That means the primary 17932 // children are not wrapped in a fragment fiber. 17933 var _currentPrimaryChild = current.child; 17934 17935 if (nextDidTimeout) { 17936 // Timed out. Wrap the children in a fragment fiber to keep them 17937 // separate from the fallback children. 17938 var _nextFallbackChildren3 = nextProps.fallback; 17939 17940 var _primaryChildFragment3 = createFiberFromFragment( // It shouldn't matter what the pending props are because we aren't 17941 // going to render this fragment. 17942 null, mode, NoWork, null); 17943 17944 _primaryChildFragment3.return = workInProgress; 17945 _primaryChildFragment3.child = _currentPrimaryChild; 17946 17947 if (_currentPrimaryChild !== null) { 17948 _currentPrimaryChild.return = _primaryChildFragment3; 17949 } // Even though we're creating a new fiber, there are no new children, 17950 // because we're reusing an already mounted tree. So we don't need to 17951 // schedule a placement. 17952 // primaryChildFragment.effectTag |= Placement; 17953 17954 17955 if ((workInProgress.mode & BlockingMode) === NoMode) { 17956 // Outside of blocking mode, we commit the effects from the 17957 // partially completed, timed-out tree, too. 17958 var _progressedState2 = workInProgress.memoizedState; 17959 17960 var _progressedPrimaryChild2 = _progressedState2 !== null ? workInProgress.child.child : workInProgress.child; 17961 17962 _primaryChildFragment3.child = _progressedPrimaryChild2; 17963 var _progressedChild3 = _progressedPrimaryChild2; 17964 17965 while (_progressedChild3 !== null) { 17966 _progressedChild3.return = _primaryChildFragment3; 17967 _progressedChild3 = _progressedChild3.sibling; 17968 } 17969 } // Because primaryChildFragment is a new fiber that we're inserting as the 17970 // parent of a new tree, we need to set its treeBaseDuration. 17971 17972 17973 if ( workInProgress.mode & ProfileMode) { 17974 // treeBaseDuration is the sum of all the child tree base durations. 17975 var _treeBaseDuration2 = 0; 17976 var _hiddenChild2 = _primaryChildFragment3.child; 17977 17978 while (_hiddenChild2 !== null) { 17979 _treeBaseDuration2 += _hiddenChild2.treeBaseDuration; 17980 _hiddenChild2 = _hiddenChild2.sibling; 17981 } 17982 17983 _primaryChildFragment3.treeBaseDuration = _treeBaseDuration2; 17984 } // Create a fragment from the fallback children, too. 17985 17986 17987 var _fallbackChildFragment3 = createFiberFromFragment(_nextFallbackChildren3, mode, renderExpirationTime, null); 17988 17989 _fallbackChildFragment3.return = workInProgress; 17990 _primaryChildFragment3.sibling = _fallbackChildFragment3; 17991 _fallbackChildFragment3.effectTag |= Placement; 17992 _primaryChildFragment3.childExpirationTime = NoWork; // Skip the primary children, and continue working on the 17993 // fallback children. 17994 17995 workInProgress.memoizedState = SUSPENDED_MARKER; 17996 workInProgress.child = _primaryChildFragment3; 17997 return _fallbackChildFragment3; 17998 } else { 17999 // Still haven't timed out. Continue rendering the children, like we 18000 // normally do. 18001 workInProgress.memoizedState = null; 18002 var _nextPrimaryChildren2 = nextProps.children; 18003 return workInProgress.child = reconcileChildFibers(workInProgress, _currentPrimaryChild, _nextPrimaryChildren2, renderExpirationTime); 18004 } 18005 } 18006 } 18007 } 18008 18009 function scheduleWorkOnFiber(fiber, renderExpirationTime) { 18010 if (fiber.expirationTime < renderExpirationTime) { 18011 fiber.expirationTime = renderExpirationTime; 18012 } 18013 18014 var alternate = fiber.alternate; 18015 18016 if (alternate !== null && alternate.expirationTime < renderExpirationTime) { 18017 alternate.expirationTime = renderExpirationTime; 18018 } 18019 18020 scheduleWorkOnParentPath(fiber.return, renderExpirationTime); 18021 } 18022 18023 function propagateSuspenseContextChange(workInProgress, firstChild, renderExpirationTime) { 18024 // Mark any Suspense boundaries with fallbacks as having work to do. 18025 // If they were previously forced into fallbacks, they may now be able 18026 // to unblock. 18027 var node = firstChild; 18028 18029 while (node !== null) { 18030 if (node.tag === SuspenseComponent) { 18031 var state = node.memoizedState; 18032 18033 if (state !== null) { 18034 scheduleWorkOnFiber(node, renderExpirationTime); 18035 } 18036 } else if (node.tag === SuspenseListComponent) { 18037 // If the tail is hidden there might not be an Suspense boundaries 18038 // to schedule work on. In this case we have to schedule it on the 18039 // list itself. 18040 // We don't have to traverse to the children of the list since 18041 // the list will propagate the change when it rerenders. 18042 scheduleWorkOnFiber(node, renderExpirationTime); 18043 } else if (node.child !== null) { 18044 node.child.return = node; 18045 node = node.child; 18046 continue; 18047 } 18048 18049 if (node === workInProgress) { 18050 return; 18051 } 18052 18053 while (node.sibling === null) { 18054 if (node.return === null || node.return === workInProgress) { 18055 return; 18056 } 18057 18058 node = node.return; 18059 } 18060 18061 node.sibling.return = node.return; 18062 node = node.sibling; 18063 } 18064 } 18065 18066 function findLastContentRow(firstChild) { 18067 // This is going to find the last row among these children that is already 18068 // showing content on the screen, as opposed to being in fallback state or 18069 // new. If a row has multiple Suspense boundaries, any of them being in the 18070 // fallback state, counts as the whole row being in a fallback state. 18071 // Note that the "rows" will be workInProgress, but any nested children 18072 // will still be current since we haven't rendered them yet. The mounted 18073 // order may not be the same as the new order. We use the new order. 18074 var row = firstChild; 18075 var lastContentRow = null; 18076 18077 while (row !== null) { 18078 var currentRow = row.alternate; // New rows can't be content rows. 18079 18080 if (currentRow !== null && findFirstSuspended(currentRow) === null) { 18081 lastContentRow = row; 18082 } 18083 18084 row = row.sibling; 18085 } 18086 18087 return lastContentRow; 18088 } 18089 18090 function validateRevealOrder(revealOrder) { 18091 { 18092 if (revealOrder !== undefined && revealOrder !== 'forwards' && revealOrder !== 'backwards' && revealOrder !== 'together' && !didWarnAboutRevealOrder[revealOrder]) { 18093 didWarnAboutRevealOrder[revealOrder] = true; 18094 18095 if (typeof revealOrder === 'string') { 18096 switch (revealOrder.toLowerCase()) { 18097 case 'together': 18098 case 'forwards': 18099 case 'backwards': 18100 { 18101 error('"%s" is not a valid value for revealOrder on <SuspenseList />. ' + 'Use lowercase "%s" instead.', revealOrder, revealOrder.toLowerCase()); 18102 18103 break; 18104 } 18105 18106 case 'forward': 18107 case 'backward': 18108 { 18109 error('"%s" is not a valid value for revealOrder on <SuspenseList />. ' + 'React uses the -s suffix in the spelling. Use "%ss" instead.', revealOrder, revealOrder.toLowerCase()); 18110 18111 break; 18112 } 18113 18114 default: 18115 error('"%s" is not a supported revealOrder on <SuspenseList />. ' + 'Did you mean "together", "forwards" or "backwards"?', revealOrder); 18116 18117 break; 18118 } 18119 } else { 18120 error('%s is not a supported value for revealOrder on <SuspenseList />. ' + 'Did you mean "together", "forwards" or "backwards"?', revealOrder); 18121 } 18122 } 18123 } 18124 } 18125 18126 function validateTailOptions(tailMode, revealOrder) { 18127 { 18128 if (tailMode !== undefined && !didWarnAboutTailOptions[tailMode]) { 18129 if (tailMode !== 'collapsed' && tailMode !== 'hidden') { 18130 didWarnAboutTailOptions[tailMode] = true; 18131 18132 error('"%s" is not a supported value for tail on <SuspenseList />. ' + 'Did you mean "collapsed" or "hidden"?', tailMode); 18133 } else if (revealOrder !== 'forwards' && revealOrder !== 'backwards') { 18134 didWarnAboutTailOptions[tailMode] = true; 18135 18136 error('<SuspenseList tail="%s" /> is only valid if revealOrder is ' + '"forwards" or "backwards". ' + 'Did you mean to specify revealOrder="forwards"?', tailMode); 18137 } 18138 } 18139 } 18140 } 18141 18142 function validateSuspenseListNestedChild(childSlot, index) { 18143 { 18144 var isArray = Array.isArray(childSlot); 18145 var isIterable = !isArray && typeof getIteratorFn(childSlot) === 'function'; 18146 18147 if (isArray || isIterable) { 18148 var type = isArray ? 'array' : 'iterable'; 18149 18150 error('A nested %s was passed to row #%s in <SuspenseList />. Wrap it in ' + 'an additional SuspenseList to configure its revealOrder: ' + '<SuspenseList revealOrder=...> ... ' + '<SuspenseList revealOrder=...>{%s}</SuspenseList> ... ' + '</SuspenseList>', type, index, type); 18151 18152 return false; 18153 } 18154 } 18155 18156 return true; 18157 } 18158 18159 function validateSuspenseListChildren(children, revealOrder) { 18160 { 18161 if ((revealOrder === 'forwards' || revealOrder === 'backwards') && children !== undefined && children !== null && children !== false) { 18162 if (Array.isArray(children)) { 18163 for (var i = 0; i < children.length; i++) { 18164 if (!validateSuspenseListNestedChild(children[i], i)) { 18165 return; 18166 } 18167 } 18168 } else { 18169 var iteratorFn = getIteratorFn(children); 18170 18171 if (typeof iteratorFn === 'function') { 18172 var childrenIterator = iteratorFn.call(children); 18173 18174 if (childrenIterator) { 18175 var step = childrenIterator.next(); 18176 var _i = 0; 18177 18178 for (; !step.done; step = childrenIterator.next()) { 18179 if (!validateSuspenseListNestedChild(step.value, _i)) { 18180 return; 18181 } 18182 18183 _i++; 18184 } 18185 } 18186 } else { 18187 error('A single row was passed to a <SuspenseList revealOrder="%s" />. ' + 'This is not useful since it needs multiple rows. ' + 'Did you mean to pass multiple children or an array?', revealOrder); 18188 } 18189 } 18190 } 18191 } 18192 } 18193 18194 function initSuspenseListRenderState(workInProgress, isBackwards, tail, lastContentRow, tailMode, lastEffectBeforeRendering) { 18195 var renderState = workInProgress.memoizedState; 18196 18197 if (renderState === null) { 18198 workInProgress.memoizedState = { 18199 isBackwards: isBackwards, 18200 rendering: null, 18201 renderingStartTime: 0, 18202 last: lastContentRow, 18203 tail: tail, 18204 tailExpiration: 0, 18205 tailMode: tailMode, 18206 lastEffect: lastEffectBeforeRendering 18207 }; 18208 } else { 18209 // We can reuse the existing object from previous renders. 18210 renderState.isBackwards = isBackwards; 18211 renderState.rendering = null; 18212 renderState.renderingStartTime = 0; 18213 renderState.last = lastContentRow; 18214 renderState.tail = tail; 18215 renderState.tailExpiration = 0; 18216 renderState.tailMode = tailMode; 18217 renderState.lastEffect = lastEffectBeforeRendering; 18218 } 18219 } // This can end up rendering this component multiple passes. 18220 // The first pass splits the children fibers into two sets. A head and tail. 18221 // We first render the head. If anything is in fallback state, we do another 18222 // pass through beginWork to rerender all children (including the tail) with 18223 // the force suspend context. If the first render didn't have anything in 18224 // in fallback state. Then we render each row in the tail one-by-one. 18225 // That happens in the completeWork phase without going back to beginWork. 18226 18227 18228 function updateSuspenseListComponent(current, workInProgress, renderExpirationTime) { 18229 var nextProps = workInProgress.pendingProps; 18230 var revealOrder = nextProps.revealOrder; 18231 var tailMode = nextProps.tail; 18232 var newChildren = nextProps.children; 18233 validateRevealOrder(revealOrder); 18234 validateTailOptions(tailMode, revealOrder); 18235 validateSuspenseListChildren(newChildren, revealOrder); 18236 reconcileChildren(current, workInProgress, newChildren, renderExpirationTime); 18237 var suspenseContext = suspenseStackCursor.current; 18238 var shouldForceFallback = hasSuspenseContext(suspenseContext, ForceSuspenseFallback); 18239 18240 if (shouldForceFallback) { 18241 suspenseContext = setShallowSuspenseContext(suspenseContext, ForceSuspenseFallback); 18242 workInProgress.effectTag |= DidCapture; 18243 } else { 18244 var didSuspendBefore = current !== null && (current.effectTag & DidCapture) !== NoEffect; 18245 18246 if (didSuspendBefore) { 18247 // If we previously forced a fallback, we need to schedule work 18248 // on any nested boundaries to let them know to try to render 18249 // again. This is the same as context updating. 18250 propagateSuspenseContextChange(workInProgress, workInProgress.child, renderExpirationTime); 18251 } 18252 18253 suspenseContext = setDefaultShallowSuspenseContext(suspenseContext); 18254 } 18255 18256 pushSuspenseContext(workInProgress, suspenseContext); 18257 18258 if ((workInProgress.mode & BlockingMode) === NoMode) { 18259 // Outside of blocking mode, SuspenseList doesn't work so we just 18260 // use make it a noop by treating it as the default revealOrder. 18261 workInProgress.memoizedState = null; 18262 } else { 18263 switch (revealOrder) { 18264 case 'forwards': 18265 { 18266 var lastContentRow = findLastContentRow(workInProgress.child); 18267 var tail; 18268 18269 if (lastContentRow === null) { 18270 // The whole list is part of the tail. 18271 // TODO: We could fast path by just rendering the tail now. 18272 tail = workInProgress.child; 18273 workInProgress.child = null; 18274 } else { 18275 // Disconnect the tail rows after the content row. 18276 // We're going to render them separately later. 18277 tail = lastContentRow.sibling; 18278 lastContentRow.sibling = null; 18279 } 18280 18281 initSuspenseListRenderState(workInProgress, false, // isBackwards 18282 tail, lastContentRow, tailMode, workInProgress.lastEffect); 18283 break; 18284 } 18285 18286 case 'backwards': 18287 { 18288 // We're going to find the first row that has existing content. 18289 // At the same time we're going to reverse the list of everything 18290 // we pass in the meantime. That's going to be our tail in reverse 18291 // order. 18292 var _tail = null; 18293 var row = workInProgress.child; 18294 workInProgress.child = null; 18295 18296 while (row !== null) { 18297 var currentRow = row.alternate; // New rows can't be content rows. 18298 18299 if (currentRow !== null && findFirstSuspended(currentRow) === null) { 18300 // This is the beginning of the main content. 18301 workInProgress.child = row; 18302 break; 18303 } 18304 18305 var nextRow = row.sibling; 18306 row.sibling = _tail; 18307 _tail = row; 18308 row = nextRow; 18309 } // TODO: If workInProgress.child is null, we can continue on the tail immediately. 18310 18311 18312 initSuspenseListRenderState(workInProgress, true, // isBackwards 18313 _tail, null, // last 18314 tailMode, workInProgress.lastEffect); 18315 break; 18316 } 18317 18318 case 'together': 18319 { 18320 initSuspenseListRenderState(workInProgress, false, // isBackwards 18321 null, // tail 18322 null, // last 18323 undefined, workInProgress.lastEffect); 18324 break; 18325 } 18326 18327 default: 18328 { 18329 // The default reveal order is the same as not having 18330 // a boundary. 18331 workInProgress.memoizedState = null; 18332 } 18333 } 18334 } 18335 18336 return workInProgress.child; 18337 } 18338 18339 function updatePortalComponent(current, workInProgress, renderExpirationTime) { 18340 pushHostContainer(workInProgress, workInProgress.stateNode.containerInfo); 18341 var nextChildren = workInProgress.pendingProps; 18342 18343 if (current === null) { 18344 // Portals are special because we don't append the children during mount 18345 // but at commit. Therefore we need to track insertions which the normal 18346 // flow doesn't do during mount. This doesn't happen at the root because 18347 // the root always starts with a "current" with a null child. 18348 // TODO: Consider unifying this with how the root works. 18349 workInProgress.child = reconcileChildFibers(workInProgress, null, nextChildren, renderExpirationTime); 18350 } else { 18351 reconcileChildren(current, workInProgress, nextChildren, renderExpirationTime); 18352 } 18353 18354 return workInProgress.child; 18355 } 18356 18357 function updateContextProvider(current, workInProgress, renderExpirationTime) { 18358 var providerType = workInProgress.type; 18359 var context = providerType._context; 18360 var newProps = workInProgress.pendingProps; 18361 var oldProps = workInProgress.memoizedProps; 18362 var newValue = newProps.value; 18363 18364 { 18365 var providerPropTypes = workInProgress.type.propTypes; 18366 18367 if (providerPropTypes) { 18368 checkPropTypes_1(providerPropTypes, newProps, 'prop', 'Context.Provider', getCurrentFiberStackInDev); 18369 } 18370 } 18371 18372 pushProvider(workInProgress, newValue); 18373 18374 if (oldProps !== null) { 18375 var oldValue = oldProps.value; 18376 var changedBits = calculateChangedBits(context, newValue, oldValue); 18377 18378 if (changedBits === 0) { 18379 // No change. Bailout early if children are the same. 18380 if (oldProps.children === newProps.children && !hasContextChanged()) { 18381 return bailoutOnAlreadyFinishedWork(current, workInProgress, renderExpirationTime); 18382 } 18383 } else { 18384 // The context value changed. Search for matching consumers and schedule 18385 // them to update. 18386 propagateContextChange(workInProgress, context, changedBits, renderExpirationTime); 18387 } 18388 } 18389 18390 var newChildren = newProps.children; 18391 reconcileChildren(current, workInProgress, newChildren, renderExpirationTime); 18392 return workInProgress.child; 18393 } 18394 18395 var hasWarnedAboutUsingContextAsConsumer = false; 18396 18397 function updateContextConsumer(current, workInProgress, renderExpirationTime) { 18398 var context = workInProgress.type; // The logic below for Context differs depending on PROD or DEV mode. In 18399 // DEV mode, we create a separate object for Context.Consumer that acts 18400 // like a proxy to Context. This proxy object adds unnecessary code in PROD 18401 // so we use the old behaviour (Context.Consumer references Context) to 18402 // reduce size and overhead. The separate object references context via 18403 // a property called "_context", which also gives us the ability to check 18404 // in DEV mode if this property exists or not and warn if it does not. 18405 18406 { 18407 if (context._context === undefined) { 18408 // This may be because it's a Context (rather than a Consumer). 18409 // Or it may be because it's older React where they're the same thing. 18410 // We only want to warn if we're sure it's a new React. 18411 if (context !== context.Consumer) { 18412 if (!hasWarnedAboutUsingContextAsConsumer) { 18413 hasWarnedAboutUsingContextAsConsumer = true; 18414 18415 error('Rendering <Context> directly is not supported and will be removed in ' + 'a future major release. Did you mean to render <Context.Consumer> instead?'); 18416 } 18417 } 18418 } else { 18419 context = context._context; 18420 } 18421 } 18422 18423 var newProps = workInProgress.pendingProps; 18424 var render = newProps.children; 18425 18426 { 18427 if (typeof render !== 'function') { 18428 error('A context consumer was rendered with multiple children, or a child ' + "that isn't a function. A context consumer expects a single child " + 'that is a function. If you did pass a function, make sure there ' + 'is no trailing or leading whitespace around it.'); 18429 } 18430 } 18431 18432 prepareToReadContext(workInProgress, renderExpirationTime); 18433 var newValue = readContext(context, newProps.unstable_observedBits); 18434 var newChildren; 18435 18436 { 18437 ReactCurrentOwner$1.current = workInProgress; 18438 setIsRendering(true); 18439 newChildren = render(newValue); 18440 setIsRendering(false); 18441 } // React DevTools reads this flag. 18442 18443 18444 workInProgress.effectTag |= PerformedWork; 18445 reconcileChildren(current, workInProgress, newChildren, renderExpirationTime); 18446 return workInProgress.child; 18447 } 18448 18449 function markWorkInProgressReceivedUpdate() { 18450 didReceiveUpdate = true; 18451 } 18452 18453 function bailoutOnAlreadyFinishedWork(current, workInProgress, renderExpirationTime) { 18454 cancelWorkTimer(workInProgress); 18455 18456 if (current !== null) { 18457 // Reuse previous dependencies 18458 workInProgress.dependencies = current.dependencies; 18459 } 18460 18461 { 18462 // Don't update "base" render times for bailouts. 18463 stopProfilerTimerIfRunning(); 18464 } 18465 18466 var updateExpirationTime = workInProgress.expirationTime; 18467 18468 if (updateExpirationTime !== NoWork) { 18469 markUnprocessedUpdateTime(updateExpirationTime); 18470 } // Check if the children have any pending work. 18471 18472 18473 var childExpirationTime = workInProgress.childExpirationTime; 18474 18475 if (childExpirationTime < renderExpirationTime) { 18476 // The children don't have any work either. We can skip them. 18477 // TODO: Once we add back resuming, we should check if the children are 18478 // a work-in-progress set. If so, we need to transfer their effects. 18479 return null; 18480 } else { 18481 // This fiber doesn't have work, but its subtree does. Clone the child 18482 // fibers and continue. 18483 cloneChildFibers(current, workInProgress); 18484 return workInProgress.child; 18485 } 18486 } 18487 18488 function remountFiber(current, oldWorkInProgress, newWorkInProgress) { 18489 { 18490 var returnFiber = oldWorkInProgress.return; 18491 18492 if (returnFiber === null) { 18493 throw new Error('Cannot swap the root fiber.'); 18494 } // Disconnect from the old current. 18495 // It will get deleted. 18496 18497 18498 current.alternate = null; 18499 oldWorkInProgress.alternate = null; // Connect to the new tree. 18500 18501 newWorkInProgress.index = oldWorkInProgress.index; 18502 newWorkInProgress.sibling = oldWorkInProgress.sibling; 18503 newWorkInProgress.return = oldWorkInProgress.return; 18504 newWorkInProgress.ref = oldWorkInProgress.ref; // Replace the child/sibling pointers above it. 18505 18506 if (oldWorkInProgress === returnFiber.child) { 18507 returnFiber.child = newWorkInProgress; 18508 } else { 18509 var prevSibling = returnFiber.child; 18510 18511 if (prevSibling === null) { 18512 throw new Error('Expected parent to have a child.'); 18513 } 18514 18515 while (prevSibling.sibling !== oldWorkInProgress) { 18516 prevSibling = prevSibling.sibling; 18517 18518 if (prevSibling === null) { 18519 throw new Error('Expected to find the previous sibling.'); 18520 } 18521 } 18522 18523 prevSibling.sibling = newWorkInProgress; 18524 } // Delete the old fiber and place the new one. 18525 // Since the old fiber is disconnected, we have to schedule it manually. 18526 18527 18528 var last = returnFiber.lastEffect; 18529 18530 if (last !== null) { 18531 last.nextEffect = current; 18532 returnFiber.lastEffect = current; 18533 } else { 18534 returnFiber.firstEffect = returnFiber.lastEffect = current; 18535 } 18536 18537 current.nextEffect = null; 18538 current.effectTag = Deletion; 18539 newWorkInProgress.effectTag |= Placement; // Restart work from the new fiber. 18540 18541 return newWorkInProgress; 18542 } 18543 } 18544 18545 function beginWork(current, workInProgress, renderExpirationTime) { 18546 var updateExpirationTime = workInProgress.expirationTime; 18547 18548 { 18549 if (workInProgress._debugNeedsRemount && current !== null) { 18550 // This will restart the begin phase with a new fiber. 18551 return remountFiber(current, workInProgress, createFiberFromTypeAndProps(workInProgress.type, workInProgress.key, workInProgress.pendingProps, workInProgress._debugOwner || null, workInProgress.mode, workInProgress.expirationTime)); 18552 } 18553 } 18554 18555 if (current !== null) { 18556 var oldProps = current.memoizedProps; 18557 var newProps = workInProgress.pendingProps; 18558 18559 if (oldProps !== newProps || hasContextChanged() || ( // Force a re-render if the implementation changed due to hot reload: 18560 workInProgress.type !== current.type )) { 18561 // If props or context changed, mark the fiber as having performed work. 18562 // This may be unset if the props are determined to be equal later (memo). 18563 didReceiveUpdate = true; 18564 } else if (updateExpirationTime < renderExpirationTime) { 18565 didReceiveUpdate = false; // This fiber does not have any pending work. Bailout without entering 18566 // the begin phase. There's still some bookkeeping we that needs to be done 18567 // in this optimized path, mostly pushing stuff onto the stack. 18568 18569 switch (workInProgress.tag) { 18570 case HostRoot: 18571 pushHostRootContext(workInProgress); 18572 resetHydrationState(); 18573 break; 18574 18575 case HostComponent: 18576 pushHostContext(workInProgress); 18577 18578 if (workInProgress.mode & ConcurrentMode && renderExpirationTime !== Never && shouldDeprioritizeSubtree(workInProgress.type, newProps)) { 18579 { 18580 markSpawnedWork(Never); 18581 } // Schedule this fiber to re-render at offscreen priority. Then bailout. 18582 18583 18584 workInProgress.expirationTime = workInProgress.childExpirationTime = Never; 18585 return null; 18586 } 18587 18588 break; 18589 18590 case ClassComponent: 18591 { 18592 var Component = workInProgress.type; 18593 18594 if (isContextProvider(Component)) { 18595 pushContextProvider(workInProgress); 18596 } 18597 18598 break; 18599 } 18600 18601 case HostPortal: 18602 pushHostContainer(workInProgress, workInProgress.stateNode.containerInfo); 18603 break; 18604 18605 case ContextProvider: 18606 { 18607 var newValue = workInProgress.memoizedProps.value; 18608 pushProvider(workInProgress, newValue); 18609 break; 18610 } 18611 18612 case Profiler: 18613 { 18614 // Profiler should only call onRender when one of its descendants actually rendered. 18615 var hasChildWork = workInProgress.childExpirationTime >= renderExpirationTime; 18616 18617 if (hasChildWork) { 18618 workInProgress.effectTag |= Update; 18619 } 18620 } 18621 18622 break; 18623 18624 case SuspenseComponent: 18625 { 18626 var state = workInProgress.memoizedState; 18627 18628 if (state !== null) { 18629 // whether to retry the primary children, or to skip over it and 18630 // go straight to the fallback. Check the priority of the primary 18631 // child fragment. 18632 18633 18634 var primaryChildFragment = workInProgress.child; 18635 var primaryChildExpirationTime = primaryChildFragment.childExpirationTime; 18636 18637 if (primaryChildExpirationTime !== NoWork && primaryChildExpirationTime >= renderExpirationTime) { 18638 // The primary children have pending work. Use the normal path 18639 // to attempt to render the primary children again. 18640 return updateSuspenseComponent(current, workInProgress, renderExpirationTime); 18641 } else { 18642 pushSuspenseContext(workInProgress, setDefaultShallowSuspenseContext(suspenseStackCursor.current)); // The primary children do not have pending work with sufficient 18643 // priority. Bailout. 18644 18645 var child = bailoutOnAlreadyFinishedWork(current, workInProgress, renderExpirationTime); 18646 18647 if (child !== null) { 18648 // The fallback children have pending work. Skip over the 18649 // primary children and work on the fallback. 18650 return child.sibling; 18651 } else { 18652 return null; 18653 } 18654 } 18655 } else { 18656 pushSuspenseContext(workInProgress, setDefaultShallowSuspenseContext(suspenseStackCursor.current)); 18657 } 18658 18659 break; 18660 } 18661 18662 case SuspenseListComponent: 18663 { 18664 var didSuspendBefore = (current.effectTag & DidCapture) !== NoEffect; 18665 18666 var _hasChildWork = workInProgress.childExpirationTime >= renderExpirationTime; 18667 18668 if (didSuspendBefore) { 18669 if (_hasChildWork) { 18670 // If something was in fallback state last time, and we have all the 18671 // same children then we're still in progressive loading state. 18672 // Something might get unblocked by state updates or retries in the 18673 // tree which will affect the tail. So we need to use the normal 18674 // path to compute the correct tail. 18675 return updateSuspenseListComponent(current, workInProgress, renderExpirationTime); 18676 } // If none of the children had any work, that means that none of 18677 // them got retried so they'll still be blocked in the same way 18678 // as before. We can fast bail out. 18679 18680 18681 workInProgress.effectTag |= DidCapture; 18682 } // If nothing suspended before and we're rendering the same children, 18683 // then the tail doesn't matter. Anything new that suspends will work 18684 // in the "together" mode, so we can continue from the state we had. 18685 18686 18687 var renderState = workInProgress.memoizedState; 18688 18689 if (renderState !== null) { 18690 // Reset to the "together" mode in case we've started a different 18691 // update in the past but didn't complete it. 18692 renderState.rendering = null; 18693 renderState.tail = null; 18694 } 18695 18696 pushSuspenseContext(workInProgress, suspenseStackCursor.current); 18697 18698 if (_hasChildWork) { 18699 break; 18700 } else { 18701 // If none of the children had any work, that means that none of 18702 // them got retried so they'll still be blocked in the same way 18703 // as before. We can fast bail out. 18704 return null; 18705 } 18706 } 18707 } 18708 18709 return bailoutOnAlreadyFinishedWork(current, workInProgress, renderExpirationTime); 18710 } else { 18711 // An update was scheduled on this fiber, but there are no new props 18712 // nor legacy context. Set this to false. If an update queue or context 18713 // consumer produces a changed value, it will set this to true. Otherwise, 18714 // the component will assume the children have not changed and bail out. 18715 didReceiveUpdate = false; 18716 } 18717 } else { 18718 didReceiveUpdate = false; 18719 } // Before entering the begin phase, clear pending update priority. 18720 // TODO: This assumes that we're about to evaluate the component and process 18721 // the update queue. However, there's an exception: SimpleMemoComponent 18722 // sometimes bails out later in the begin phase. This indicates that we should 18723 // move this assignment out of the common path and into each branch. 18724 18725 18726 workInProgress.expirationTime = NoWork; 18727 18728 switch (workInProgress.tag) { 18729 case IndeterminateComponent: 18730 { 18731 return mountIndeterminateComponent(current, workInProgress, workInProgress.type, renderExpirationTime); 18732 } 18733 18734 case LazyComponent: 18735 { 18736 var elementType = workInProgress.elementType; 18737 return mountLazyComponent(current, workInProgress, elementType, updateExpirationTime, renderExpirationTime); 18738 } 18739 18740 case FunctionComponent: 18741 { 18742 var _Component = workInProgress.type; 18743 var unresolvedProps = workInProgress.pendingProps; 18744 var resolvedProps = workInProgress.elementType === _Component ? unresolvedProps : resolveDefaultProps(_Component, unresolvedProps); 18745 return updateFunctionComponent(current, workInProgress, _Component, resolvedProps, renderExpirationTime); 18746 } 18747 18748 case ClassComponent: 18749 { 18750 var _Component2 = workInProgress.type; 18751 var _unresolvedProps = workInProgress.pendingProps; 18752 18753 var _resolvedProps = workInProgress.elementType === _Component2 ? _unresolvedProps : resolveDefaultProps(_Component2, _unresolvedProps); 18754 18755 return updateClassComponent(current, workInProgress, _Component2, _resolvedProps, renderExpirationTime); 18756 } 18757 18758 case HostRoot: 18759 return updateHostRoot(current, workInProgress, renderExpirationTime); 18760 18761 case HostComponent: 18762 return updateHostComponent(current, workInProgress, renderExpirationTime); 18763 18764 case HostText: 18765 return updateHostText(current, workInProgress); 18766 18767 case SuspenseComponent: 18768 return updateSuspenseComponent(current, workInProgress, renderExpirationTime); 18769 18770 case HostPortal: 18771 return updatePortalComponent(current, workInProgress, renderExpirationTime); 18772 18773 case ForwardRef: 18774 { 18775 var type = workInProgress.type; 18776 var _unresolvedProps2 = workInProgress.pendingProps; 18777 18778 var _resolvedProps2 = workInProgress.elementType === type ? _unresolvedProps2 : resolveDefaultProps(type, _unresolvedProps2); 18779 18780 return updateForwardRef(current, workInProgress, type, _resolvedProps2, renderExpirationTime); 18781 } 18782 18783 case Fragment: 18784 return updateFragment(current, workInProgress, renderExpirationTime); 18785 18786 case Mode: 18787 return updateMode(current, workInProgress, renderExpirationTime); 18788 18789 case Profiler: 18790 return updateProfiler(current, workInProgress, renderExpirationTime); 18791 18792 case ContextProvider: 18793 return updateContextProvider(current, workInProgress, renderExpirationTime); 18794 18795 case ContextConsumer: 18796 return updateContextConsumer(current, workInProgress, renderExpirationTime); 18797 18798 case MemoComponent: 18799 { 18800 var _type2 = workInProgress.type; 18801 var _unresolvedProps3 = workInProgress.pendingProps; // Resolve outer props first, then resolve inner props. 18802 18803 var _resolvedProps3 = resolveDefaultProps(_type2, _unresolvedProps3); 18804 18805 { 18806 if (workInProgress.type !== workInProgress.elementType) { 18807 var outerPropTypes = _type2.propTypes; 18808 18809 if (outerPropTypes) { 18810 checkPropTypes_1(outerPropTypes, _resolvedProps3, // Resolved for outer only 18811 'prop', getComponentName(_type2), getCurrentFiberStackInDev); 18812 } 18813 } 18814 } 18815 18816 _resolvedProps3 = resolveDefaultProps(_type2.type, _resolvedProps3); 18817 return updateMemoComponent(current, workInProgress, _type2, _resolvedProps3, updateExpirationTime, renderExpirationTime); 18818 } 18819 18820 case SimpleMemoComponent: 18821 { 18822 return updateSimpleMemoComponent(current, workInProgress, workInProgress.type, workInProgress.pendingProps, updateExpirationTime, renderExpirationTime); 18823 } 18824 18825 case IncompleteClassComponent: 18826 { 18827 var _Component3 = workInProgress.type; 18828 var _unresolvedProps4 = workInProgress.pendingProps; 18829 18830 var _resolvedProps4 = workInProgress.elementType === _Component3 ? _unresolvedProps4 : resolveDefaultProps(_Component3, _unresolvedProps4); 18831 18832 return mountIncompleteClassComponent(current, workInProgress, _Component3, _resolvedProps4, renderExpirationTime); 18833 } 18834 18835 case SuspenseListComponent: 18836 { 18837 return updateSuspenseListComponent(current, workInProgress, renderExpirationTime); 18838 } 18839 } 18840 18841 { 18842 { 18843 throw Error( "Unknown unit of work tag (" + workInProgress.tag + "). This error is likely caused by a bug in React. Please file an issue." ); 18844 } 18845 } 18846 } 18847 18848 function markUpdate(workInProgress) { 18849 // Tag the fiber with an update effect. This turns a Placement into 18850 // a PlacementAndUpdate. 18851 workInProgress.effectTag |= Update; 18852 } 18853 18854 function markRef$1(workInProgress) { 18855 workInProgress.effectTag |= Ref; 18856 } 18857 18858 var appendAllChildren; 18859 var updateHostContainer; 18860 var updateHostComponent$1; 18861 var updateHostText$1; 18862 18863 { 18864 // Mutation mode 18865 appendAllChildren = function (parent, workInProgress, needsVisibilityToggle, isHidden) { 18866 // We only have the top Fiber that was created but we need recurse down its 18867 // children to find all the terminal nodes. 18868 var node = workInProgress.child; 18869 18870 while (node !== null) { 18871 if (node.tag === HostComponent || node.tag === HostText) { 18872 appendInitialChild(parent, node.stateNode); 18873 } else if (node.tag === HostPortal) ; else if (node.child !== null) { 18874 node.child.return = node; 18875 node = node.child; 18876 continue; 18877 } 18878 18879 if (node === workInProgress) { 18880 return; 18881 } 18882 18883 while (node.sibling === null) { 18884 if (node.return === null || node.return === workInProgress) { 18885 return; 18886 } 18887 18888 node = node.return; 18889 } 18890 18891 node.sibling.return = node.return; 18892 node = node.sibling; 18893 } 18894 }; 18895 18896 updateHostContainer = function (workInProgress) {// Noop 18897 }; 18898 18899 updateHostComponent$1 = function (current, workInProgress, type, newProps, rootContainerInstance) { 18900 // If we have an alternate, that means this is an update and we need to 18901 // schedule a side-effect to do the updates. 18902 var oldProps = current.memoizedProps; 18903 18904 if (oldProps === newProps) { 18905 // In mutation mode, this is sufficient for a bailout because 18906 // we won't touch this node even if children changed. 18907 return; 18908 } // If we get updated because one of our children updated, we don't 18909 // have newProps so we'll have to reuse them. 18910 // TODO: Split the update API as separate for the props vs. children. 18911 // Even better would be if children weren't special cased at all tho. 18912 18913 18914 var instance = workInProgress.stateNode; 18915 var currentHostContext = getHostContext(); // TODO: Experiencing an error where oldProps is null. Suggests a host 18916 // component is hitting the resume path. Figure out why. Possibly 18917 // related to `hidden`. 18918 18919 var updatePayload = prepareUpdate(instance, type, oldProps, newProps, rootContainerInstance, currentHostContext); // TODO: Type this specific to this type of component. 18920 18921 workInProgress.updateQueue = updatePayload; // If the update payload indicates that there is a change or if there 18922 // is a new ref we mark this as an update. All the work is done in commitWork. 18923 18924 if (updatePayload) { 18925 markUpdate(workInProgress); 18926 } 18927 }; 18928 18929 updateHostText$1 = function (current, workInProgress, oldText, newText) { 18930 // If the text differs, mark it as an update. All the work in done in commitWork. 18931 if (oldText !== newText) { 18932 markUpdate(workInProgress); 18933 } 18934 }; 18935 } 18936 18937 function cutOffTailIfNeeded(renderState, hasRenderedATailFallback) { 18938 switch (renderState.tailMode) { 18939 case 'hidden': 18940 { 18941 // Any insertions at the end of the tail list after this point 18942 // should be invisible. If there are already mounted boundaries 18943 // anything before them are not considered for collapsing. 18944 // Therefore we need to go through the whole tail to find if 18945 // there are any. 18946 var tailNode = renderState.tail; 18947 var lastTailNode = null; 18948 18949 while (tailNode !== null) { 18950 if (tailNode.alternate !== null) { 18951 lastTailNode = tailNode; 18952 } 18953 18954 tailNode = tailNode.sibling; 18955 } // Next we're simply going to delete all insertions after the 18956 // last rendered item. 18957 18958 18959 if (lastTailNode === null) { 18960 // All remaining items in the tail are insertions. 18961 renderState.tail = null; 18962 } else { 18963 // Detach the insertion after the last node that was already 18964 // inserted. 18965 lastTailNode.sibling = null; 18966 } 18967 18968 break; 18969 } 18970 18971 case 'collapsed': 18972 { 18973 // Any insertions at the end of the tail list after this point 18974 // should be invisible. If there are already mounted boundaries 18975 // anything before them are not considered for collapsing. 18976 // Therefore we need to go through the whole tail to find if 18977 // there are any. 18978 var _tailNode = renderState.tail; 18979 var _lastTailNode = null; 18980 18981 while (_tailNode !== null) { 18982 if (_tailNode.alternate !== null) { 18983 _lastTailNode = _tailNode; 18984 } 18985 18986 _tailNode = _tailNode.sibling; 18987 } // Next we're simply going to delete all insertions after the 18988 // last rendered item. 18989 18990 18991 if (_lastTailNode === null) { 18992 // All remaining items in the tail are insertions. 18993 if (!hasRenderedATailFallback && renderState.tail !== null) { 18994 // We suspended during the head. We want to show at least one 18995 // row at the tail. So we'll keep on and cut off the rest. 18996 renderState.tail.sibling = null; 18997 } else { 18998 renderState.tail = null; 18999 } 19000 } else { 19001 // Detach the insertion after the last node that was already 19002 // inserted. 19003 _lastTailNode.sibling = null; 19004 } 19005 19006 break; 19007 } 19008 } 19009 } 19010 19011 function completeWork(current, workInProgress, renderExpirationTime) { 19012 var newProps = workInProgress.pendingProps; 19013 19014 switch (workInProgress.tag) { 19015 case IndeterminateComponent: 19016 case LazyComponent: 19017 case SimpleMemoComponent: 19018 case FunctionComponent: 19019 case ForwardRef: 19020 case Fragment: 19021 case Mode: 19022 case Profiler: 19023 case ContextConsumer: 19024 case MemoComponent: 19025 return null; 19026 19027 case ClassComponent: 19028 { 19029 var Component = workInProgress.type; 19030 19031 if (isContextProvider(Component)) { 19032 popContext(workInProgress); 19033 } 19034 19035 return null; 19036 } 19037 19038 case HostRoot: 19039 { 19040 popHostContainer(workInProgress); 19041 popTopLevelContextObject(workInProgress); 19042 var fiberRoot = workInProgress.stateNode; 19043 19044 if (fiberRoot.pendingContext) { 19045 fiberRoot.context = fiberRoot.pendingContext; 19046 fiberRoot.pendingContext = null; 19047 } 19048 19049 if (current === null || current.child === null) { 19050 // If we hydrated, pop so that we can delete any remaining children 19051 // that weren't hydrated. 19052 var wasHydrated = popHydrationState(workInProgress); 19053 19054 if (wasHydrated) { 19055 // If we hydrated, then we'll need to schedule an update for 19056 // the commit side-effects on the root. 19057 markUpdate(workInProgress); 19058 } 19059 } 19060 19061 updateHostContainer(workInProgress); 19062 return null; 19063 } 19064 19065 case HostComponent: 19066 { 19067 popHostContext(workInProgress); 19068 var rootContainerInstance = getRootHostContainer(); 19069 var type = workInProgress.type; 19070 19071 if (current !== null && workInProgress.stateNode != null) { 19072 updateHostComponent$1(current, workInProgress, type, newProps, rootContainerInstance); 19073 19074 if (current.ref !== workInProgress.ref) { 19075 markRef$1(workInProgress); 19076 } 19077 } else { 19078 if (!newProps) { 19079 if (!(workInProgress.stateNode !== null)) { 19080 { 19081 throw Error( "We must have new props for new mounts. This error is likely caused by a bug in React. Please file an issue." ); 19082 } 19083 } // This can happen when we abort work. 19084 19085 19086 return null; 19087 } 19088 19089 var currentHostContext = getHostContext(); // TODO: Move createInstance to beginWork and keep it on a context 19090 // "stack" as the parent. Then append children as we go in beginWork 19091 // or completeWork depending on whether we want to add them top->down or 19092 // bottom->up. Top->down is faster in IE11. 19093 19094 var _wasHydrated = popHydrationState(workInProgress); 19095 19096 if (_wasHydrated) { 19097 // TODO: Move this and createInstance step into the beginPhase 19098 // to consolidate. 19099 if (prepareToHydrateHostInstance(workInProgress, rootContainerInstance, currentHostContext)) { 19100 // If changes to the hydrated node need to be applied at the 19101 // commit-phase we mark this as such. 19102 markUpdate(workInProgress); 19103 } 19104 } else { 19105 var instance = createInstance(type, newProps, rootContainerInstance, currentHostContext, workInProgress); 19106 appendAllChildren(instance, workInProgress, false, false); // This needs to be set before we mount Flare event listeners 19107 19108 workInProgress.stateNode = instance; 19109 // (eg DOM renderer supports auto-focus for certain elements). 19110 // Make sure such renderers get scheduled for later work. 19111 19112 19113 if (finalizeInitialChildren(instance, type, newProps, rootContainerInstance)) { 19114 markUpdate(workInProgress); 19115 } 19116 } 19117 19118 if (workInProgress.ref !== null) { 19119 // If there is a ref on a host node we need to schedule a callback 19120 markRef$1(workInProgress); 19121 } 19122 } 19123 19124 return null; 19125 } 19126 19127 case HostText: 19128 { 19129 var newText = newProps; 19130 19131 if (current && workInProgress.stateNode != null) { 19132 var oldText = current.memoizedProps; // If we have an alternate, that means this is an update and we need 19133 // to schedule a side-effect to do the updates. 19134 19135 updateHostText$1(current, workInProgress, oldText, newText); 19136 } else { 19137 if (typeof newText !== 'string') { 19138 if (!(workInProgress.stateNode !== null)) { 19139 { 19140 throw Error( "We must have new props for new mounts. This error is likely caused by a bug in React. Please file an issue." ); 19141 } 19142 } // This can happen when we abort work. 19143 19144 } 19145 19146 var _rootContainerInstance = getRootHostContainer(); 19147 19148 var _currentHostContext = getHostContext(); 19149 19150 var _wasHydrated2 = popHydrationState(workInProgress); 19151 19152 if (_wasHydrated2) { 19153 if (prepareToHydrateHostTextInstance(workInProgress)) { 19154 markUpdate(workInProgress); 19155 } 19156 } else { 19157 workInProgress.stateNode = createTextInstance(newText, _rootContainerInstance, _currentHostContext, workInProgress); 19158 } 19159 } 19160 19161 return null; 19162 } 19163 19164 case SuspenseComponent: 19165 { 19166 popSuspenseContext(workInProgress); 19167 var nextState = workInProgress.memoizedState; 19168 19169 if ((workInProgress.effectTag & DidCapture) !== NoEffect) { 19170 // Something suspended. Re-render with the fallback children. 19171 workInProgress.expirationTime = renderExpirationTime; // Do not reset the effect list. 19172 19173 return workInProgress; 19174 } 19175 19176 var nextDidTimeout = nextState !== null; 19177 var prevDidTimeout = false; 19178 19179 if (current === null) { 19180 if (workInProgress.memoizedProps.fallback !== undefined) { 19181 popHydrationState(workInProgress); 19182 } 19183 } else { 19184 var prevState = current.memoizedState; 19185 prevDidTimeout = prevState !== null; 19186 19187 if (!nextDidTimeout && prevState !== null) { 19188 // We just switched from the fallback to the normal children. 19189 // Delete the fallback. 19190 // TODO: Would it be better to store the fallback fragment on 19191 // the stateNode during the begin phase? 19192 var currentFallbackChild = current.child.sibling; 19193 19194 if (currentFallbackChild !== null) { 19195 // Deletions go at the beginning of the return fiber's effect list 19196 var first = workInProgress.firstEffect; 19197 19198 if (first !== null) { 19199 workInProgress.firstEffect = currentFallbackChild; 19200 currentFallbackChild.nextEffect = first; 19201 } else { 19202 workInProgress.firstEffect = workInProgress.lastEffect = currentFallbackChild; 19203 currentFallbackChild.nextEffect = null; 19204 } 19205 19206 currentFallbackChild.effectTag = Deletion; 19207 } 19208 } 19209 } 19210 19211 if (nextDidTimeout && !prevDidTimeout) { 19212 // If this subtreee is running in blocking mode we can suspend, 19213 // otherwise we won't suspend. 19214 // TODO: This will still suspend a synchronous tree if anything 19215 // in the concurrent tree already suspended during this render. 19216 // This is a known bug. 19217 if ((workInProgress.mode & BlockingMode) !== NoMode) { 19218 // TODO: Move this back to throwException because this is too late 19219 // if this is a large tree which is common for initial loads. We 19220 // don't know if we should restart a render or not until we get 19221 // this marker, and this is too late. 19222 // If this render already had a ping or lower pri updates, 19223 // and this is the first time we know we're going to suspend we 19224 // should be able to immediately restart from within throwException. 19225 var hasInvisibleChildContext = current === null && workInProgress.memoizedProps.unstable_avoidThisFallback !== true; 19226 19227 if (hasInvisibleChildContext || hasSuspenseContext(suspenseStackCursor.current, InvisibleParentSuspenseContext)) { 19228 // If this was in an invisible tree or a new render, then showing 19229 // this boundary is ok. 19230 renderDidSuspend(); 19231 } else { 19232 // Otherwise, we're going to have to hide content so we should 19233 // suspend for longer if possible. 19234 renderDidSuspendDelayIfPossible(); 19235 } 19236 } 19237 } 19238 19239 { 19240 // TODO: Only schedule updates if these values are non equal, i.e. it changed. 19241 if (nextDidTimeout || prevDidTimeout) { 19242 // If this boundary just timed out, schedule an effect to attach a 19243 // retry listener to the promise. This flag is also used to hide the 19244 // primary children. In mutation mode, we also need the flag to 19245 // *unhide* children that were previously hidden, so check if this 19246 // is currently timed out, too. 19247 workInProgress.effectTag |= Update; 19248 } 19249 } 19250 19251 return null; 19252 } 19253 19254 case HostPortal: 19255 popHostContainer(workInProgress); 19256 updateHostContainer(workInProgress); 19257 return null; 19258 19259 case ContextProvider: 19260 // Pop provider fiber 19261 popProvider(workInProgress); 19262 return null; 19263 19264 case IncompleteClassComponent: 19265 { 19266 // Same as class component case. I put it down here so that the tags are 19267 // sequential to ensure this switch is compiled to a jump table. 19268 var _Component = workInProgress.type; 19269 19270 if (isContextProvider(_Component)) { 19271 popContext(workInProgress); 19272 } 19273 19274 return null; 19275 } 19276 19277 case SuspenseListComponent: 19278 { 19279 popSuspenseContext(workInProgress); 19280 var renderState = workInProgress.memoizedState; 19281 19282 if (renderState === null) { 19283 // We're running in the default, "independent" mode. 19284 // We don't do anything in this mode. 19285 return null; 19286 } 19287 19288 var didSuspendAlready = (workInProgress.effectTag & DidCapture) !== NoEffect; 19289 var renderedTail = renderState.rendering; 19290 19291 if (renderedTail === null) { 19292 // We just rendered the head. 19293 if (!didSuspendAlready) { 19294 // This is the first pass. We need to figure out if anything is still 19295 // suspended in the rendered set. 19296 // If new content unsuspended, but there's still some content that 19297 // didn't. Then we need to do a second pass that forces everything 19298 // to keep showing their fallbacks. 19299 // We might be suspended if something in this render pass suspended, or 19300 // something in the previous committed pass suspended. Otherwise, 19301 // there's no chance so we can skip the expensive call to 19302 // findFirstSuspended. 19303 var cannotBeSuspended = renderHasNotSuspendedYet() && (current === null || (current.effectTag & DidCapture) === NoEffect); 19304 19305 if (!cannotBeSuspended) { 19306 var row = workInProgress.child; 19307 19308 while (row !== null) { 19309 var suspended = findFirstSuspended(row); 19310 19311 if (suspended !== null) { 19312 didSuspendAlready = true; 19313 workInProgress.effectTag |= DidCapture; 19314 cutOffTailIfNeeded(renderState, false); // If this is a newly suspended tree, it might not get committed as 19315 // part of the second pass. In that case nothing will subscribe to 19316 // its thennables. Instead, we'll transfer its thennables to the 19317 // SuspenseList so that it can retry if they resolve. 19318 // There might be multiple of these in the list but since we're 19319 // going to wait for all of them anyway, it doesn't really matter 19320 // which ones gets to ping. In theory we could get clever and keep 19321 // track of how many dependencies remain but it gets tricky because 19322 // in the meantime, we can add/remove/change items and dependencies. 19323 // We might bail out of the loop before finding any but that 19324 // doesn't matter since that means that the other boundaries that 19325 // we did find already has their listeners attached. 19326 19327 var newThennables = suspended.updateQueue; 19328 19329 if (newThennables !== null) { 19330 workInProgress.updateQueue = newThennables; 19331 workInProgress.effectTag |= Update; 19332 } // Rerender the whole list, but this time, we'll force fallbacks 19333 // to stay in place. 19334 // Reset the effect list before doing the second pass since that's now invalid. 19335 19336 19337 if (renderState.lastEffect === null) { 19338 workInProgress.firstEffect = null; 19339 } 19340 19341 workInProgress.lastEffect = renderState.lastEffect; // Reset the child fibers to their original state. 19342 19343 resetChildFibers(workInProgress, renderExpirationTime); // Set up the Suspense Context to force suspense and immediately 19344 // rerender the children. 19345 19346 pushSuspenseContext(workInProgress, setShallowSuspenseContext(suspenseStackCursor.current, ForceSuspenseFallback)); 19347 return workInProgress.child; 19348 } 19349 19350 row = row.sibling; 19351 } 19352 } 19353 } else { 19354 cutOffTailIfNeeded(renderState, false); 19355 } // Next we're going to render the tail. 19356 19357 } else { 19358 // Append the rendered row to the child list. 19359 if (!didSuspendAlready) { 19360 var _suspended = findFirstSuspended(renderedTail); 19361 19362 if (_suspended !== null) { 19363 workInProgress.effectTag |= DidCapture; 19364 didSuspendAlready = true; // Ensure we transfer the update queue to the parent so that it doesn't 19365 // get lost if this row ends up dropped during a second pass. 19366 19367 var _newThennables = _suspended.updateQueue; 19368 19369 if (_newThennables !== null) { 19370 workInProgress.updateQueue = _newThennables; 19371 workInProgress.effectTag |= Update; 19372 } 19373 19374 cutOffTailIfNeeded(renderState, true); // This might have been modified. 19375 19376 if (renderState.tail === null && renderState.tailMode === 'hidden' && !renderedTail.alternate) { 19377 // We need to delete the row we just rendered. 19378 // Reset the effect list to what it was before we rendered this 19379 // child. The nested children have already appended themselves. 19380 var lastEffect = workInProgress.lastEffect = renderState.lastEffect; // Remove any effects that were appended after this point. 19381 19382 if (lastEffect !== null) { 19383 lastEffect.nextEffect = null; 19384 } // We're done. 19385 19386 19387 return null; 19388 } 19389 } else if ( // The time it took to render last row is greater than time until 19390 // the expiration. 19391 now() * 2 - renderState.renderingStartTime > renderState.tailExpiration && renderExpirationTime > Never) { 19392 // We have now passed our CPU deadline and we'll just give up further 19393 // attempts to render the main content and only render fallbacks. 19394 // The assumption is that this is usually faster. 19395 workInProgress.effectTag |= DidCapture; 19396 didSuspendAlready = true; 19397 cutOffTailIfNeeded(renderState, false); // Since nothing actually suspended, there will nothing to ping this 19398 // to get it started back up to attempt the next item. If we can show 19399 // them, then they really have the same priority as this render. 19400 // So we'll pick it back up the very next render pass once we've had 19401 // an opportunity to yield for paint. 19402 19403 var nextPriority = renderExpirationTime - 1; 19404 workInProgress.expirationTime = workInProgress.childExpirationTime = nextPriority; 19405 19406 { 19407 markSpawnedWork(nextPriority); 19408 } 19409 } 19410 } 19411 19412 if (renderState.isBackwards) { 19413 // The effect list of the backwards tail will have been added 19414 // to the end. This breaks the guarantee that life-cycles fire in 19415 // sibling order but that isn't a strong guarantee promised by React. 19416 // Especially since these might also just pop in during future commits. 19417 // Append to the beginning of the list. 19418 renderedTail.sibling = workInProgress.child; 19419 workInProgress.child = renderedTail; 19420 } else { 19421 var previousSibling = renderState.last; 19422 19423 if (previousSibling !== null) { 19424 previousSibling.sibling = renderedTail; 19425 } else { 19426 workInProgress.child = renderedTail; 19427 } 19428 19429 renderState.last = renderedTail; 19430 } 19431 } 19432 19433 if (renderState.tail !== null) { 19434 // We still have tail rows to render. 19435 if (renderState.tailExpiration === 0) { 19436 // Heuristic for how long we're willing to spend rendering rows 19437 // until we just give up and show what we have so far. 19438 var TAIL_EXPIRATION_TIMEOUT_MS = 500; 19439 renderState.tailExpiration = now() + TAIL_EXPIRATION_TIMEOUT_MS; // TODO: This is meant to mimic the train model or JND but this 19440 // is a per component value. It should really be since the start 19441 // of the total render or last commit. Consider using something like 19442 // globalMostRecentFallbackTime. That doesn't account for being 19443 // suspended for part of the time or when it's a new render. 19444 // It should probably use a global start time value instead. 19445 } // Pop a row. 19446 19447 19448 var next = renderState.tail; 19449 renderState.rendering = next; 19450 renderState.tail = next.sibling; 19451 renderState.lastEffect = workInProgress.lastEffect; 19452 renderState.renderingStartTime = now(); 19453 next.sibling = null; // Restore the context. 19454 // TODO: We can probably just avoid popping it instead and only 19455 // setting it the first time we go from not suspended to suspended. 19456 19457 var suspenseContext = suspenseStackCursor.current; 19458 19459 if (didSuspendAlready) { 19460 suspenseContext = setShallowSuspenseContext(suspenseContext, ForceSuspenseFallback); 19461 } else { 19462 suspenseContext = setDefaultShallowSuspenseContext(suspenseContext); 19463 } 19464 19465 pushSuspenseContext(workInProgress, suspenseContext); // Do a pass over the next row. 19466 19467 return next; 19468 } 19469 19470 return null; 19471 } 19472 } 19473 19474 { 19475 { 19476 throw Error( "Unknown unit of work tag (" + workInProgress.tag + "). This error is likely caused by a bug in React. Please file an issue." ); 19477 } 19478 } 19479 } 19480 19481 function unwindWork(workInProgress, renderExpirationTime) { 19482 switch (workInProgress.tag) { 19483 case ClassComponent: 19484 { 19485 var Component = workInProgress.type; 19486 19487 if (isContextProvider(Component)) { 19488 popContext(workInProgress); 19489 } 19490 19491 var effectTag = workInProgress.effectTag; 19492 19493 if (effectTag & ShouldCapture) { 19494 workInProgress.effectTag = effectTag & ~ShouldCapture | DidCapture; 19495 return workInProgress; 19496 } 19497 19498 return null; 19499 } 19500 19501 case HostRoot: 19502 { 19503 popHostContainer(workInProgress); 19504 popTopLevelContextObject(workInProgress); 19505 var _effectTag = workInProgress.effectTag; 19506 19507 if (!((_effectTag & DidCapture) === NoEffect)) { 19508 { 19509 throw Error( "The root failed to unmount after an error. This is likely a bug in React. Please file an issue." ); 19510 } 19511 } 19512 19513 workInProgress.effectTag = _effectTag & ~ShouldCapture | DidCapture; 19514 return workInProgress; 19515 } 19516 19517 case HostComponent: 19518 { 19519 // TODO: popHydrationState 19520 popHostContext(workInProgress); 19521 return null; 19522 } 19523 19524 case SuspenseComponent: 19525 { 19526 popSuspenseContext(workInProgress); 19527 19528 var _effectTag2 = workInProgress.effectTag; 19529 19530 if (_effectTag2 & ShouldCapture) { 19531 workInProgress.effectTag = _effectTag2 & ~ShouldCapture | DidCapture; // Captured a suspense effect. Re-render the boundary. 19532 19533 return workInProgress; 19534 } 19535 19536 return null; 19537 } 19538 19539 case SuspenseListComponent: 19540 { 19541 popSuspenseContext(workInProgress); // SuspenseList doesn't actually catch anything. It should've been 19542 // caught by a nested boundary. If not, it should bubble through. 19543 19544 return null; 19545 } 19546 19547 case HostPortal: 19548 popHostContainer(workInProgress); 19549 return null; 19550 19551 case ContextProvider: 19552 popProvider(workInProgress); 19553 return null; 19554 19555 default: 19556 return null; 19557 } 19558 } 19559 19560 function unwindInterruptedWork(interruptedWork) { 19561 switch (interruptedWork.tag) { 19562 case ClassComponent: 19563 { 19564 var childContextTypes = interruptedWork.type.childContextTypes; 19565 19566 if (childContextTypes !== null && childContextTypes !== undefined) { 19567 popContext(interruptedWork); 19568 } 19569 19570 break; 19571 } 19572 19573 case HostRoot: 19574 { 19575 popHostContainer(interruptedWork); 19576 popTopLevelContextObject(interruptedWork); 19577 break; 19578 } 19579 19580 case HostComponent: 19581 { 19582 popHostContext(interruptedWork); 19583 break; 19584 } 19585 19586 case HostPortal: 19587 popHostContainer(interruptedWork); 19588 break; 19589 19590 case SuspenseComponent: 19591 popSuspenseContext(interruptedWork); 19592 break; 19593 19594 case SuspenseListComponent: 19595 popSuspenseContext(interruptedWork); 19596 break; 19597 19598 case ContextProvider: 19599 popProvider(interruptedWork); 19600 break; 19601 } 19602 } 19603 19604 function createCapturedValue(value, source) { 19605 // If the value is an error, call this function immediately after it is thrown 19606 // so the stack is accurate. 19607 return { 19608 value: value, 19609 source: source, 19610 stack: getStackByFiberInDevAndProd(source) 19611 }; 19612 } 19613 19614 function logCapturedError(capturedError) { 19615 19616 var error = capturedError.error; 19617 19618 { 19619 var componentName = capturedError.componentName, 19620 componentStack = capturedError.componentStack, 19621 errorBoundaryName = capturedError.errorBoundaryName, 19622 errorBoundaryFound = capturedError.errorBoundaryFound, 19623 willRetry = capturedError.willRetry; // Browsers support silencing uncaught errors by calling 19624 // `preventDefault()` in window `error` handler. 19625 // We record this information as an expando on the error. 19626 19627 if (error != null && error._suppressLogging) { 19628 if (errorBoundaryFound && willRetry) { 19629 // The error is recoverable and was silenced. 19630 // Ignore it and don't print the stack addendum. 19631 // This is handy for testing error boundaries without noise. 19632 return; 19633 } // The error is fatal. Since the silencing might have 19634 // been accidental, we'll surface it anyway. 19635 // However, the browser would have silenced the original error 19636 // so we'll print it first, and then print the stack addendum. 19637 19638 19639 console['error'](error); // Don't transform to our wrapper 19640 // For a more detailed description of this block, see: 19641 // https://github.com/facebook/react/pull/13384 19642 } 19643 19644 var componentNameMessage = componentName ? "The above error occurred in the <" + componentName + "> component:" : 'The above error occurred in one of your React components:'; 19645 var errorBoundaryMessage; // errorBoundaryFound check is sufficient; errorBoundaryName check is to satisfy Flow. 19646 19647 if (errorBoundaryFound && errorBoundaryName) { 19648 if (willRetry) { 19649 errorBoundaryMessage = "React will try to recreate this component tree from scratch " + ("using the error boundary you provided, " + errorBoundaryName + "."); 19650 } else { 19651 errorBoundaryMessage = "This error was initially handled by the error boundary " + errorBoundaryName + ".\n" + "Recreating the tree from scratch failed so React will unmount the tree."; 19652 } 19653 } else { 19654 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.'; 19655 } 19656 19657 var combinedMessage = "" + componentNameMessage + componentStack + "\n\n" + ("" + errorBoundaryMessage); // In development, we provide our own message with just the component stack. 19658 // We don't include the original error message and JS stack because the browser 19659 // has already printed it. Even if the application swallows the error, it is still 19660 // displayed by the browser thanks to the DEV-only fake event trick in ReactErrorUtils. 19661 19662 console['error'](combinedMessage); // Don't transform to our wrapper 19663 } 19664 } 19665 19666 var didWarnAboutUndefinedSnapshotBeforeUpdate = null; 19667 19668 { 19669 didWarnAboutUndefinedSnapshotBeforeUpdate = new Set(); 19670 } 19671 19672 var PossiblyWeakSet = typeof WeakSet === 'function' ? WeakSet : Set; 19673 function logError(boundary, errorInfo) { 19674 var source = errorInfo.source; 19675 var stack = errorInfo.stack; 19676 19677 if (stack === null && source !== null) { 19678 stack = getStackByFiberInDevAndProd(source); 19679 } 19680 19681 var capturedError = { 19682 componentName: source !== null ? getComponentName(source.type) : null, 19683 componentStack: stack !== null ? stack : '', 19684 error: errorInfo.value, 19685 errorBoundary: null, 19686 errorBoundaryName: null, 19687 errorBoundaryFound: false, 19688 willRetry: false 19689 }; 19690 19691 if (boundary !== null && boundary.tag === ClassComponent) { 19692 capturedError.errorBoundary = boundary.stateNode; 19693 capturedError.errorBoundaryName = getComponentName(boundary.type); 19694 capturedError.errorBoundaryFound = true; 19695 capturedError.willRetry = true; 19696 } 19697 19698 try { 19699 logCapturedError(capturedError); 19700 } catch (e) { 19701 // This method must not throw, or React internal state will get messed up. 19702 // If console.error is overridden, or logCapturedError() shows a dialog that throws, 19703 // we want to report this error outside of the normal stack as a last resort. 19704 // https://github.com/facebook/react/issues/13188 19705 setTimeout(function () { 19706 throw e; 19707 }); 19708 } 19709 } 19710 19711 var callComponentWillUnmountWithTimer = function (current, instance) { 19712 startPhaseTimer(current, 'componentWillUnmount'); 19713 instance.props = current.memoizedProps; 19714 instance.state = current.memoizedState; 19715 instance.componentWillUnmount(); 19716 stopPhaseTimer(); 19717 }; // Capture errors so they don't interrupt unmounting. 19718 19719 19720 function safelyCallComponentWillUnmount(current, instance) { 19721 { 19722 invokeGuardedCallback(null, callComponentWillUnmountWithTimer, null, current, instance); 19723 19724 if (hasCaughtError()) { 19725 var unmountError = clearCaughtError(); 19726 captureCommitPhaseError(current, unmountError); 19727 } 19728 } 19729 } 19730 19731 function safelyDetachRef(current) { 19732 var ref = current.ref; 19733 19734 if (ref !== null) { 19735 if (typeof ref === 'function') { 19736 { 19737 invokeGuardedCallback(null, ref, null, null); 19738 19739 if (hasCaughtError()) { 19740 var refError = clearCaughtError(); 19741 captureCommitPhaseError(current, refError); 19742 } 19743 } 19744 } else { 19745 ref.current = null; 19746 } 19747 } 19748 } 19749 19750 function safelyCallDestroy(current, destroy) { 19751 { 19752 invokeGuardedCallback(null, destroy, null); 19753 19754 if (hasCaughtError()) { 19755 var error = clearCaughtError(); 19756 captureCommitPhaseError(current, error); 19757 } 19758 } 19759 } 19760 19761 function commitBeforeMutationLifeCycles(current, finishedWork) { 19762 switch (finishedWork.tag) { 19763 case FunctionComponent: 19764 case ForwardRef: 19765 case SimpleMemoComponent: 19766 case Block: 19767 { 19768 return; 19769 } 19770 19771 case ClassComponent: 19772 { 19773 if (finishedWork.effectTag & Snapshot) { 19774 if (current !== null) { 19775 var prevProps = current.memoizedProps; 19776 var prevState = current.memoizedState; 19777 startPhaseTimer(finishedWork, 'getSnapshotBeforeUpdate'); 19778 var instance = finishedWork.stateNode; // We could update instance props and state here, 19779 // but instead we rely on them being set during last render. 19780 // TODO: revisit this when we implement resuming. 19781 19782 { 19783 if (finishedWork.type === finishedWork.elementType && !didWarnAboutReassigningProps) { 19784 if (instance.props !== finishedWork.memoizedProps) { 19785 error('Expected %s props to match memoized props before ' + 'getSnapshotBeforeUpdate. ' + 'This might either be because of a bug in React, or because ' + 'a component reassigns its own `this.props`. ' + 'Please file an issue.', getComponentName(finishedWork.type) || 'instance'); 19786 } 19787 19788 if (instance.state !== finishedWork.memoizedState) { 19789 error('Expected %s state to match memoized state before ' + 'getSnapshotBeforeUpdate. ' + 'This might either be because of a bug in React, or because ' + 'a component reassigns its own `this.props`. ' + 'Please file an issue.', getComponentName(finishedWork.type) || 'instance'); 19790 } 19791 } 19792 } 19793 19794 var snapshot = instance.getSnapshotBeforeUpdate(finishedWork.elementType === finishedWork.type ? prevProps : resolveDefaultProps(finishedWork.type, prevProps), prevState); 19795 19796 { 19797 var didWarnSet = didWarnAboutUndefinedSnapshotBeforeUpdate; 19798 19799 if (snapshot === undefined && !didWarnSet.has(finishedWork.type)) { 19800 didWarnSet.add(finishedWork.type); 19801 19802 error('%s.getSnapshotBeforeUpdate(): A snapshot value (or null) ' + 'must be returned. You have returned undefined.', getComponentName(finishedWork.type)); 19803 } 19804 } 19805 19806 instance.__reactInternalSnapshotBeforeUpdate = snapshot; 19807 stopPhaseTimer(); 19808 } 19809 } 19810 19811 return; 19812 } 19813 19814 case HostRoot: 19815 case HostComponent: 19816 case HostText: 19817 case HostPortal: 19818 case IncompleteClassComponent: 19819 // Nothing to do for these component types 19820 return; 19821 } 19822 19823 { 19824 { 19825 throw Error( "This unit of work tag should not have side-effects. This error is likely caused by a bug in React. Please file an issue." ); 19826 } 19827 } 19828 } 19829 19830 function commitHookEffectListUnmount(tag, finishedWork) { 19831 var updateQueue = finishedWork.updateQueue; 19832 var lastEffect = updateQueue !== null ? updateQueue.lastEffect : null; 19833 19834 if (lastEffect !== null) { 19835 var firstEffect = lastEffect.next; 19836 var effect = firstEffect; 19837 19838 do { 19839 if ((effect.tag & tag) === tag) { 19840 // Unmount 19841 var destroy = effect.destroy; 19842 effect.destroy = undefined; 19843 19844 if (destroy !== undefined) { 19845 destroy(); 19846 } 19847 } 19848 19849 effect = effect.next; 19850 } while (effect !== firstEffect); 19851 } 19852 } 19853 19854 function commitHookEffectListMount(tag, finishedWork) { 19855 var updateQueue = finishedWork.updateQueue; 19856 var lastEffect = updateQueue !== null ? updateQueue.lastEffect : null; 19857 19858 if (lastEffect !== null) { 19859 var firstEffect = lastEffect.next; 19860 var effect = firstEffect; 19861 19862 do { 19863 if ((effect.tag & tag) === tag) { 19864 // Mount 19865 var create = effect.create; 19866 effect.destroy = create(); 19867 19868 { 19869 var destroy = effect.destroy; 19870 19871 if (destroy !== undefined && typeof destroy !== 'function') { 19872 var addendum = void 0; 19873 19874 if (destroy === null) { 19875 addendum = ' You returned null. If your effect does not require clean ' + 'up, return undefined (or nothing).'; 19876 } else if (typeof destroy.then === 'function') { 19877 addendum = '\n\nIt looks like you wrote useEffect(async () => ...) or returned a Promise. ' + 'Instead, write the async function inside your effect ' + 'and call it immediately:\n\n' + 'useEffect(() => {\n' + ' async function fetchData() {\n' + ' // You can await here\n' + ' const response = await MyAPI.getData(someId);\n' + ' // ...\n' + ' }\n' + ' fetchData();\n' + "}, [someId]); // Or [] if effect doesn't need props or state\n\n" + 'Learn more about data fetching with Hooks: https://fb.me/react-hooks-data-fetching'; 19878 } else { 19879 addendum = ' You returned: ' + destroy; 19880 } 19881 19882 error('An effect function must not return anything besides a function, ' + 'which is used for clean-up.%s%s', addendum, getStackByFiberInDevAndProd(finishedWork)); 19883 } 19884 } 19885 } 19886 19887 effect = effect.next; 19888 } while (effect !== firstEffect); 19889 } 19890 } 19891 19892 function commitPassiveHookEffects(finishedWork) { 19893 if ((finishedWork.effectTag & Passive) !== NoEffect) { 19894 switch (finishedWork.tag) { 19895 case FunctionComponent: 19896 case ForwardRef: 19897 case SimpleMemoComponent: 19898 case Block: 19899 { 19900 // TODO (#17945) We should call all passive destroy functions (for all fibers) 19901 // before calling any create functions. The current approach only serializes 19902 // these for a single fiber. 19903 commitHookEffectListUnmount(Passive$1 | HasEffect, finishedWork); 19904 commitHookEffectListMount(Passive$1 | HasEffect, finishedWork); 19905 break; 19906 } 19907 } 19908 } 19909 } 19910 19911 function commitLifeCycles(finishedRoot, current, finishedWork, committedExpirationTime) { 19912 switch (finishedWork.tag) { 19913 case FunctionComponent: 19914 case ForwardRef: 19915 case SimpleMemoComponent: 19916 case Block: 19917 { 19918 // At this point layout effects have already been destroyed (during mutation phase). 19919 // This is done to prevent sibling component effects from interfering with each other, 19920 // e.g. a destroy function in one component should never override a ref set 19921 // by a create function in another component during the same commit. 19922 commitHookEffectListMount(Layout | HasEffect, finishedWork); 19923 19924 return; 19925 } 19926 19927 case ClassComponent: 19928 { 19929 var instance = finishedWork.stateNode; 19930 19931 if (finishedWork.effectTag & Update) { 19932 if (current === null) { 19933 startPhaseTimer(finishedWork, 'componentDidMount'); // We could update instance props and state here, 19934 // but instead we rely on them being set during last render. 19935 // TODO: revisit this when we implement resuming. 19936 19937 { 19938 if (finishedWork.type === finishedWork.elementType && !didWarnAboutReassigningProps) { 19939 if (instance.props !== finishedWork.memoizedProps) { 19940 error('Expected %s props to match memoized props before ' + 'componentDidMount. ' + 'This might either be because of a bug in React, or because ' + 'a component reassigns its own `this.props`. ' + 'Please file an issue.', getComponentName(finishedWork.type) || 'instance'); 19941 } 19942 19943 if (instance.state !== finishedWork.memoizedState) { 19944 error('Expected %s state to match memoized state before ' + 'componentDidMount. ' + 'This might either be because of a bug in React, or because ' + 'a component reassigns its own `this.props`. ' + 'Please file an issue.', getComponentName(finishedWork.type) || 'instance'); 19945 } 19946 } 19947 } 19948 19949 instance.componentDidMount(); 19950 stopPhaseTimer(); 19951 } else { 19952 var prevProps = finishedWork.elementType === finishedWork.type ? current.memoizedProps : resolveDefaultProps(finishedWork.type, current.memoizedProps); 19953 var prevState = current.memoizedState; 19954 startPhaseTimer(finishedWork, 'componentDidUpdate'); // We could update instance props and state here, 19955 // but instead we rely on them being set during last render. 19956 // TODO: revisit this when we implement resuming. 19957 19958 { 19959 if (finishedWork.type === finishedWork.elementType && !didWarnAboutReassigningProps) { 19960 if (instance.props !== finishedWork.memoizedProps) { 19961 error('Expected %s props to match memoized props before ' + 'componentDidUpdate. ' + 'This might either be because of a bug in React, or because ' + 'a component reassigns its own `this.props`. ' + 'Please file an issue.', getComponentName(finishedWork.type) || 'instance'); 19962 } 19963 19964 if (instance.state !== finishedWork.memoizedState) { 19965 error('Expected %s state to match memoized state before ' + 'componentDidUpdate. ' + 'This might either be because of a bug in React, or because ' + 'a component reassigns its own `this.props`. ' + 'Please file an issue.', getComponentName(finishedWork.type) || 'instance'); 19966 } 19967 } 19968 } 19969 19970 instance.componentDidUpdate(prevProps, prevState, instance.__reactInternalSnapshotBeforeUpdate); 19971 stopPhaseTimer(); 19972 } 19973 } 19974 19975 var updateQueue = finishedWork.updateQueue; 19976 19977 if (updateQueue !== null) { 19978 { 19979 if (finishedWork.type === finishedWork.elementType && !didWarnAboutReassigningProps) { 19980 if (instance.props !== finishedWork.memoizedProps) { 19981 error('Expected %s props to match memoized props before ' + 'processing the update queue. ' + 'This might either be because of a bug in React, or because ' + 'a component reassigns its own `this.props`. ' + 'Please file an issue.', getComponentName(finishedWork.type) || 'instance'); 19982 } 19983 19984 if (instance.state !== finishedWork.memoizedState) { 19985 error('Expected %s state to match memoized state before ' + 'processing the update queue. ' + 'This might either be because of a bug in React, or because ' + 'a component reassigns its own `this.props`. ' + 'Please file an issue.', getComponentName(finishedWork.type) || 'instance'); 19986 } 19987 } 19988 } // We could update instance props and state here, 19989 // but instead we rely on them being set during last render. 19990 // TODO: revisit this when we implement resuming. 19991 19992 19993 commitUpdateQueue(finishedWork, updateQueue, instance); 19994 } 19995 19996 return; 19997 } 19998 19999 case HostRoot: 20000 { 20001 var _updateQueue = finishedWork.updateQueue; 20002 20003 if (_updateQueue !== null) { 20004 var _instance = null; 20005 20006 if (finishedWork.child !== null) { 20007 switch (finishedWork.child.tag) { 20008 case HostComponent: 20009 _instance = getPublicInstance(finishedWork.child.stateNode); 20010 break; 20011 20012 case ClassComponent: 20013 _instance = finishedWork.child.stateNode; 20014 break; 20015 } 20016 } 20017 20018 commitUpdateQueue(finishedWork, _updateQueue, _instance); 20019 } 20020 20021 return; 20022 } 20023 20024 case HostComponent: 20025 { 20026 var _instance2 = finishedWork.stateNode; // Renderers may schedule work to be done after host components are mounted 20027 // (eg DOM renderer may schedule auto-focus for inputs and form controls). 20028 // These effects should only be committed when components are first mounted, 20029 // aka when there is no current/alternate. 20030 20031 if (current === null && finishedWork.effectTag & Update) { 20032 var type = finishedWork.type; 20033 var props = finishedWork.memoizedProps; 20034 commitMount(_instance2, type, props); 20035 } 20036 20037 return; 20038 } 20039 20040 case HostText: 20041 { 20042 // We have no life-cycles associated with text. 20043 return; 20044 } 20045 20046 case HostPortal: 20047 { 20048 // We have no life-cycles associated with portals. 20049 return; 20050 } 20051 20052 case Profiler: 20053 { 20054 { 20055 var onRender = finishedWork.memoizedProps.onRender; 20056 20057 if (typeof onRender === 'function') { 20058 { 20059 onRender(finishedWork.memoizedProps.id, current === null ? 'mount' : 'update', finishedWork.actualDuration, finishedWork.treeBaseDuration, finishedWork.actualStartTime, getCommitTime(), finishedRoot.memoizedInteractions); 20060 } 20061 } 20062 } 20063 20064 return; 20065 } 20066 20067 case SuspenseComponent: 20068 { 20069 commitSuspenseHydrationCallbacks(finishedRoot, finishedWork); 20070 return; 20071 } 20072 20073 case SuspenseListComponent: 20074 case IncompleteClassComponent: 20075 case FundamentalComponent: 20076 case ScopeComponent: 20077 return; 20078 } 20079 20080 { 20081 { 20082 throw Error( "This unit of work tag should not have side-effects. This error is likely caused by a bug in React. Please file an issue." ); 20083 } 20084 } 20085 } 20086 20087 function hideOrUnhideAllChildren(finishedWork, isHidden) { 20088 { 20089 // We only have the top Fiber that was inserted but we need to recurse down its 20090 // children to find all the terminal nodes. 20091 var node = finishedWork; 20092 20093 while (true) { 20094 if (node.tag === HostComponent) { 20095 var instance = node.stateNode; 20096 20097 if (isHidden) { 20098 hideInstance(instance); 20099 } else { 20100 unhideInstance(node.stateNode, node.memoizedProps); 20101 } 20102 } else if (node.tag === HostText) { 20103 var _instance3 = node.stateNode; 20104 20105 if (isHidden) { 20106 hideTextInstance(_instance3); 20107 } else { 20108 unhideTextInstance(_instance3, node.memoizedProps); 20109 } 20110 } else if (node.tag === SuspenseComponent && node.memoizedState !== null && node.memoizedState.dehydrated === null) { 20111 // Found a nested Suspense component that timed out. Skip over the 20112 // primary child fragment, which should remain hidden. 20113 var fallbackChildFragment = node.child.sibling; 20114 fallbackChildFragment.return = node; 20115 node = fallbackChildFragment; 20116 continue; 20117 } else if (node.child !== null) { 20118 node.child.return = node; 20119 node = node.child; 20120 continue; 20121 } 20122 20123 if (node === finishedWork) { 20124 return; 20125 } 20126 20127 while (node.sibling === null) { 20128 if (node.return === null || node.return === finishedWork) { 20129 return; 20130 } 20131 20132 node = node.return; 20133 } 20134 20135 node.sibling.return = node.return; 20136 node = node.sibling; 20137 } 20138 } 20139 } 20140 20141 function commitAttachRef(finishedWork) { 20142 var ref = finishedWork.ref; 20143 20144 if (ref !== null) { 20145 var instance = finishedWork.stateNode; 20146 var instanceToUse; 20147 20148 switch (finishedWork.tag) { 20149 case HostComponent: 20150 instanceToUse = getPublicInstance(instance); 20151 break; 20152 20153 default: 20154 instanceToUse = instance; 20155 } // Moved outside to ensure DCE works with this flag 20156 20157 if (typeof ref === 'function') { 20158 ref(instanceToUse); 20159 } else { 20160 { 20161 if (!ref.hasOwnProperty('current')) { 20162 error('Unexpected ref object provided for %s. ' + 'Use either a ref-setter function or React.createRef().%s', getComponentName(finishedWork.type), getStackByFiberInDevAndProd(finishedWork)); 20163 } 20164 } 20165 20166 ref.current = instanceToUse; 20167 } 20168 } 20169 } 20170 20171 function commitDetachRef(current) { 20172 var currentRef = current.ref; 20173 20174 if (currentRef !== null) { 20175 if (typeof currentRef === 'function') { 20176 currentRef(null); 20177 } else { 20178 currentRef.current = null; 20179 } 20180 } 20181 } // User-originating errors (lifecycles and refs) should not interrupt 20182 // deletion, so don't let them throw. Host-originating errors should 20183 // interrupt deletion, so it's okay 20184 20185 20186 function commitUnmount(finishedRoot, current, renderPriorityLevel) { 20187 onCommitUnmount(current); 20188 20189 switch (current.tag) { 20190 case FunctionComponent: 20191 case ForwardRef: 20192 case MemoComponent: 20193 case SimpleMemoComponent: 20194 case Block: 20195 { 20196 var updateQueue = current.updateQueue; 20197 20198 if (updateQueue !== null) { 20199 var lastEffect = updateQueue.lastEffect; 20200 20201 if (lastEffect !== null) { 20202 var firstEffect = lastEffect.next; 20203 20204 { 20205 // When the owner fiber is deleted, the destroy function of a passive 20206 // effect hook is called during the synchronous commit phase. This is 20207 // a concession to implementation complexity. Calling it in the 20208 // passive effect phase (like they usually are, when dependencies 20209 // change during an update) would require either traversing the 20210 // children of the deleted fiber again, or including unmount effects 20211 // as part of the fiber effect list. 20212 // 20213 // Because this is during the sync commit phase, we need to change 20214 // the priority. 20215 // 20216 // TODO: Reconsider this implementation trade off. 20217 var priorityLevel = renderPriorityLevel > NormalPriority ? NormalPriority : renderPriorityLevel; 20218 runWithPriority$1(priorityLevel, function () { 20219 var effect = firstEffect; 20220 20221 do { 20222 var _destroy = effect.destroy; 20223 20224 if (_destroy !== undefined) { 20225 safelyCallDestroy(current, _destroy); 20226 } 20227 20228 effect = effect.next; 20229 } while (effect !== firstEffect); 20230 }); 20231 } 20232 } 20233 } 20234 20235 return; 20236 } 20237 20238 case ClassComponent: 20239 { 20240 safelyDetachRef(current); 20241 var instance = current.stateNode; 20242 20243 if (typeof instance.componentWillUnmount === 'function') { 20244 safelyCallComponentWillUnmount(current, instance); 20245 } 20246 20247 return; 20248 } 20249 20250 case HostComponent: 20251 { 20252 20253 safelyDetachRef(current); 20254 return; 20255 } 20256 20257 case HostPortal: 20258 { 20259 // TODO: this is recursive. 20260 // We are also not using this parent because 20261 // the portal will get pushed immediately. 20262 { 20263 unmountHostComponents(finishedRoot, current, renderPriorityLevel); 20264 } 20265 20266 return; 20267 } 20268 20269 case FundamentalComponent: 20270 { 20271 20272 return; 20273 } 20274 20275 case DehydratedFragment: 20276 { 20277 20278 return; 20279 } 20280 20281 case ScopeComponent: 20282 { 20283 20284 return; 20285 } 20286 } 20287 } 20288 20289 function commitNestedUnmounts(finishedRoot, root, renderPriorityLevel) { 20290 // While we're inside a removed host node we don't want to call 20291 // removeChild on the inner nodes because they're removed by the top 20292 // call anyway. We also want to call componentWillUnmount on all 20293 // composites before this host node is removed from the tree. Therefore 20294 // we do an inner loop while we're still inside the host node. 20295 var node = root; 20296 20297 while (true) { 20298 commitUnmount(finishedRoot, node, renderPriorityLevel); // Visit children because they may contain more composite or host nodes. 20299 // Skip portals because commitUnmount() currently visits them recursively. 20300 20301 if (node.child !== null && ( // If we use mutation we drill down into portals using commitUnmount above. 20302 // If we don't use mutation we drill down into portals here instead. 20303 node.tag !== HostPortal)) { 20304 node.child.return = node; 20305 node = node.child; 20306 continue; 20307 } 20308 20309 if (node === root) { 20310 return; 20311 } 20312 20313 while (node.sibling === null) { 20314 if (node.return === null || node.return === root) { 20315 return; 20316 } 20317 20318 node = node.return; 20319 } 20320 20321 node.sibling.return = node.return; 20322 node = node.sibling; 20323 } 20324 } 20325 20326 function detachFiber(current) { 20327 var alternate = current.alternate; // Cut off the return pointers to disconnect it from the tree. Ideally, we 20328 // should clear the child pointer of the parent alternate to let this 20329 // get GC:ed but we don't know which for sure which parent is the current 20330 // one so we'll settle for GC:ing the subtree of this child. This child 20331 // itself will be GC:ed when the parent updates the next time. 20332 20333 current.return = null; 20334 current.child = null; 20335 current.memoizedState = null; 20336 current.updateQueue = null; 20337 current.dependencies = null; 20338 current.alternate = null; 20339 current.firstEffect = null; 20340 current.lastEffect = null; 20341 current.pendingProps = null; 20342 current.memoizedProps = null; 20343 current.stateNode = null; 20344 20345 if (alternate !== null) { 20346 detachFiber(alternate); 20347 } 20348 } 20349 20350 function getHostParentFiber(fiber) { 20351 var parent = fiber.return; 20352 20353 while (parent !== null) { 20354 if (isHostParent(parent)) { 20355 return parent; 20356 } 20357 20358 parent = parent.return; 20359 } 20360 20361 { 20362 { 20363 throw Error( "Expected to find a host parent. This error is likely caused by a bug in React. Please file an issue." ); 20364 } 20365 } 20366 } 20367 20368 function isHostParent(fiber) { 20369 return fiber.tag === HostComponent || fiber.tag === HostRoot || fiber.tag === HostPortal; 20370 } 20371 20372 function getHostSibling(fiber) { 20373 // We're going to search forward into the tree until we find a sibling host 20374 // node. Unfortunately, if multiple insertions are done in a row we have to 20375 // search past them. This leads to exponential search for the next sibling. 20376 // TODO: Find a more efficient way to do this. 20377 var node = fiber; 20378 20379 siblings: while (true) { 20380 // If we didn't find anything, let's try the next sibling. 20381 while (node.sibling === null) { 20382 if (node.return === null || isHostParent(node.return)) { 20383 // If we pop out of the root or hit the parent the fiber we are the 20384 // last sibling. 20385 return null; 20386 } 20387 20388 node = node.return; 20389 } 20390 20391 node.sibling.return = node.return; 20392 node = node.sibling; 20393 20394 while (node.tag !== HostComponent && node.tag !== HostText && node.tag !== DehydratedFragment) { 20395 // If it is not host node and, we might have a host node inside it. 20396 // Try to search down until we find one. 20397 if (node.effectTag & Placement) { 20398 // If we don't have a child, try the siblings instead. 20399 continue siblings; 20400 } // If we don't have a child, try the siblings instead. 20401 // We also skip portals because they are not part of this host tree. 20402 20403 20404 if (node.child === null || node.tag === HostPortal) { 20405 continue siblings; 20406 } else { 20407 node.child.return = node; 20408 node = node.child; 20409 } 20410 } // Check if this host node is stable or about to be placed. 20411 20412 20413 if (!(node.effectTag & Placement)) { 20414 // Found it! 20415 return node.stateNode; 20416 } 20417 } 20418 } 20419 20420 function commitPlacement(finishedWork) { 20421 20422 20423 var parentFiber = getHostParentFiber(finishedWork); // Note: these two variables *must* always be updated together. 20424 20425 var parent; 20426 var isContainer; 20427 var parentStateNode = parentFiber.stateNode; 20428 20429 switch (parentFiber.tag) { 20430 case HostComponent: 20431 parent = parentStateNode; 20432 isContainer = false; 20433 break; 20434 20435 case HostRoot: 20436 parent = parentStateNode.containerInfo; 20437 isContainer = true; 20438 break; 20439 20440 case HostPortal: 20441 parent = parentStateNode.containerInfo; 20442 isContainer = true; 20443 break; 20444 20445 case FundamentalComponent: 20446 20447 // eslint-disable-next-line-no-fallthrough 20448 20449 default: 20450 { 20451 { 20452 throw Error( "Invalid host parent fiber. This error is likely caused by a bug in React. Please file an issue." ); 20453 } 20454 } 20455 20456 } 20457 20458 if (parentFiber.effectTag & ContentReset) { 20459 // Reset the text content of the parent before doing any insertions 20460 resetTextContent(parent); // Clear ContentReset from the effect tag 20461 20462 parentFiber.effectTag &= ~ContentReset; 20463 } 20464 20465 var before = getHostSibling(finishedWork); // We only have the top Fiber that was inserted but we need to recurse down its 20466 // children to find all the terminal nodes. 20467 20468 if (isContainer) { 20469 insertOrAppendPlacementNodeIntoContainer(finishedWork, before, parent); 20470 } else { 20471 insertOrAppendPlacementNode(finishedWork, before, parent); 20472 } 20473 } 20474 20475 function insertOrAppendPlacementNodeIntoContainer(node, before, parent) { 20476 var tag = node.tag; 20477 var isHost = tag === HostComponent || tag === HostText; 20478 20479 if (isHost || enableFundamentalAPI ) { 20480 var stateNode = isHost ? node.stateNode : node.stateNode.instance; 20481 20482 if (before) { 20483 insertInContainerBefore(parent, stateNode, before); 20484 } else { 20485 appendChildToContainer(parent, stateNode); 20486 } 20487 } else if (tag === HostPortal) ; else { 20488 var child = node.child; 20489 20490 if (child !== null) { 20491 insertOrAppendPlacementNodeIntoContainer(child, before, parent); 20492 var sibling = child.sibling; 20493 20494 while (sibling !== null) { 20495 insertOrAppendPlacementNodeIntoContainer(sibling, before, parent); 20496 sibling = sibling.sibling; 20497 } 20498 } 20499 } 20500 } 20501 20502 function insertOrAppendPlacementNode(node, before, parent) { 20503 var tag = node.tag; 20504 var isHost = tag === HostComponent || tag === HostText; 20505 20506 if (isHost || enableFundamentalAPI ) { 20507 var stateNode = isHost ? node.stateNode : node.stateNode.instance; 20508 20509 if (before) { 20510 insertBefore(parent, stateNode, before); 20511 } else { 20512 appendChild(parent, stateNode); 20513 } 20514 } else if (tag === HostPortal) ; else { 20515 var child = node.child; 20516 20517 if (child !== null) { 20518 insertOrAppendPlacementNode(child, before, parent); 20519 var sibling = child.sibling; 20520 20521 while (sibling !== null) { 20522 insertOrAppendPlacementNode(sibling, before, parent); 20523 sibling = sibling.sibling; 20524 } 20525 } 20526 } 20527 } 20528 20529 function unmountHostComponents(finishedRoot, current, renderPriorityLevel) { 20530 // We only have the top Fiber that was deleted but we need to recurse down its 20531 // children to find all the terminal nodes. 20532 var node = current; // Each iteration, currentParent is populated with node's host parent if not 20533 // currentParentIsValid. 20534 20535 var currentParentIsValid = false; // Note: these two variables *must* always be updated together. 20536 20537 var currentParent; 20538 var currentParentIsContainer; 20539 20540 while (true) { 20541 if (!currentParentIsValid) { 20542 var parent = node.return; 20543 20544 findParent: while (true) { 20545 if (!(parent !== null)) { 20546 { 20547 throw Error( "Expected to find a host parent. This error is likely caused by a bug in React. Please file an issue." ); 20548 } 20549 } 20550 20551 var parentStateNode = parent.stateNode; 20552 20553 switch (parent.tag) { 20554 case HostComponent: 20555 currentParent = parentStateNode; 20556 currentParentIsContainer = false; 20557 break findParent; 20558 20559 case HostRoot: 20560 currentParent = parentStateNode.containerInfo; 20561 currentParentIsContainer = true; 20562 break findParent; 20563 20564 case HostPortal: 20565 currentParent = parentStateNode.containerInfo; 20566 currentParentIsContainer = true; 20567 break findParent; 20568 20569 } 20570 20571 parent = parent.return; 20572 } 20573 20574 currentParentIsValid = true; 20575 } 20576 20577 if (node.tag === HostComponent || node.tag === HostText) { 20578 commitNestedUnmounts(finishedRoot, node, renderPriorityLevel); // After all the children have unmounted, it is now safe to remove the 20579 // node from the tree. 20580 20581 if (currentParentIsContainer) { 20582 removeChildFromContainer(currentParent, node.stateNode); 20583 } else { 20584 removeChild(currentParent, node.stateNode); 20585 } // Don't visit children because we already visited them. 20586 20587 } else if (node.tag === HostPortal) { 20588 if (node.child !== null) { 20589 // When we go into a portal, it becomes the parent to remove from. 20590 // We will reassign it back when we pop the portal on the way up. 20591 currentParent = node.stateNode.containerInfo; 20592 currentParentIsContainer = true; // Visit children because portals might contain host components. 20593 20594 node.child.return = node; 20595 node = node.child; 20596 continue; 20597 } 20598 } else { 20599 commitUnmount(finishedRoot, node, renderPriorityLevel); // Visit children because we may find more host components below. 20600 20601 if (node.child !== null) { 20602 node.child.return = node; 20603 node = node.child; 20604 continue; 20605 } 20606 } 20607 20608 if (node === current) { 20609 return; 20610 } 20611 20612 while (node.sibling === null) { 20613 if (node.return === null || node.return === current) { 20614 return; 20615 } 20616 20617 node = node.return; 20618 20619 if (node.tag === HostPortal) { 20620 // When we go out of the portal, we need to restore the parent. 20621 // Since we don't keep a stack of them, we will search for it. 20622 currentParentIsValid = false; 20623 } 20624 } 20625 20626 node.sibling.return = node.return; 20627 node = node.sibling; 20628 } 20629 } 20630 20631 function commitDeletion(finishedRoot, current, renderPriorityLevel) { 20632 { 20633 // Recursively delete all host nodes from the parent. 20634 // Detach refs and call componentWillUnmount() on the whole subtree. 20635 unmountHostComponents(finishedRoot, current, renderPriorityLevel); 20636 } 20637 20638 detachFiber(current); 20639 } 20640 20641 function commitWork(current, finishedWork) { 20642 20643 switch (finishedWork.tag) { 20644 case FunctionComponent: 20645 case ForwardRef: 20646 case MemoComponent: 20647 case SimpleMemoComponent: 20648 case Block: 20649 { 20650 // Layout effects are destroyed during the mutation phase so that all 20651 // destroy functions for all fibers are called before any create functions. 20652 // This prevents sibling component effects from interfering with each other, 20653 // e.g. a destroy function in one component should never override a ref set 20654 // by a create function in another component during the same commit. 20655 commitHookEffectListUnmount(Layout | HasEffect, finishedWork); 20656 return; 20657 } 20658 20659 case ClassComponent: 20660 { 20661 return; 20662 } 20663 20664 case HostComponent: 20665 { 20666 var instance = finishedWork.stateNode; 20667 20668 if (instance != null) { 20669 // Commit the work prepared earlier. 20670 var newProps = finishedWork.memoizedProps; // For hydration we reuse the update path but we treat the oldProps 20671 // as the newProps. The updatePayload will contain the real change in 20672 // this case. 20673 20674 var oldProps = current !== null ? current.memoizedProps : newProps; 20675 var type = finishedWork.type; // TODO: Type the updateQueue to be specific to host components. 20676 20677 var updatePayload = finishedWork.updateQueue; 20678 finishedWork.updateQueue = null; 20679 20680 if (updatePayload !== null) { 20681 commitUpdate(instance, updatePayload, type, oldProps, newProps); 20682 } 20683 } 20684 20685 return; 20686 } 20687 20688 case HostText: 20689 { 20690 if (!(finishedWork.stateNode !== null)) { 20691 { 20692 throw Error( "This should have a text node initialized. This error is likely caused by a bug in React. Please file an issue." ); 20693 } 20694 } 20695 20696 var textInstance = finishedWork.stateNode; 20697 var newText = finishedWork.memoizedProps; // For hydration we reuse the update path but we treat the oldProps 20698 // as the newProps. The updatePayload will contain the real change in 20699 // this case. 20700 20701 var oldText = current !== null ? current.memoizedProps : newText; 20702 commitTextUpdate(textInstance, oldText, newText); 20703 return; 20704 } 20705 20706 case HostRoot: 20707 { 20708 { 20709 var _root = finishedWork.stateNode; 20710 20711 if (_root.hydrate) { 20712 // We've just hydrated. No need to hydrate again. 20713 _root.hydrate = false; 20714 commitHydratedContainer(_root.containerInfo); 20715 } 20716 } 20717 20718 return; 20719 } 20720 20721 case Profiler: 20722 { 20723 return; 20724 } 20725 20726 case SuspenseComponent: 20727 { 20728 commitSuspenseComponent(finishedWork); 20729 attachSuspenseRetryListeners(finishedWork); 20730 return; 20731 } 20732 20733 case SuspenseListComponent: 20734 { 20735 attachSuspenseRetryListeners(finishedWork); 20736 return; 20737 } 20738 20739 case IncompleteClassComponent: 20740 { 20741 return; 20742 } 20743 } 20744 20745 { 20746 { 20747 throw Error( "This unit of work tag should not have side-effects. This error is likely caused by a bug in React. Please file an issue." ); 20748 } 20749 } 20750 } 20751 20752 function commitSuspenseComponent(finishedWork) { 20753 var newState = finishedWork.memoizedState; 20754 var newDidTimeout; 20755 var primaryChildParent = finishedWork; 20756 20757 if (newState === null) { 20758 newDidTimeout = false; 20759 } else { 20760 newDidTimeout = true; 20761 primaryChildParent = finishedWork.child; 20762 markCommitTimeOfFallback(); 20763 } 20764 20765 if ( primaryChildParent !== null) { 20766 hideOrUnhideAllChildren(primaryChildParent, newDidTimeout); 20767 } 20768 } 20769 20770 function commitSuspenseHydrationCallbacks(finishedRoot, finishedWork) { 20771 20772 var newState = finishedWork.memoizedState; 20773 20774 if (newState === null) { 20775 var current = finishedWork.alternate; 20776 20777 if (current !== null) { 20778 var prevState = current.memoizedState; 20779 20780 if (prevState !== null) { 20781 var suspenseInstance = prevState.dehydrated; 20782 20783 if (suspenseInstance !== null) { 20784 commitHydratedSuspenseInstance(suspenseInstance); 20785 } 20786 } 20787 } 20788 } 20789 } 20790 20791 function attachSuspenseRetryListeners(finishedWork) { 20792 // If this boundary just timed out, then it will have a set of thenables. 20793 // For each thenable, attach a listener so that when it resolves, React 20794 // attempts to re-render the boundary in the primary (pre-timeout) state. 20795 var thenables = finishedWork.updateQueue; 20796 20797 if (thenables !== null) { 20798 finishedWork.updateQueue = null; 20799 var retryCache = finishedWork.stateNode; 20800 20801 if (retryCache === null) { 20802 retryCache = finishedWork.stateNode = new PossiblyWeakSet(); 20803 } 20804 20805 thenables.forEach(function (thenable) { 20806 // Memoize using the boundary fiber to prevent redundant listeners. 20807 var retry = resolveRetryThenable.bind(null, finishedWork, thenable); 20808 20809 if (!retryCache.has(thenable)) { 20810 { 20811 if (thenable.__reactDoNotTraceInteractions !== true) { 20812 retry = unstable_wrap(retry); 20813 } 20814 } 20815 20816 retryCache.add(thenable); 20817 thenable.then(retry, retry); 20818 } 20819 }); 20820 } 20821 } 20822 20823 function commitResetTextContent(current) { 20824 20825 resetTextContent(current.stateNode); 20826 } 20827 20828 var PossiblyWeakMap$1 = typeof WeakMap === 'function' ? WeakMap : Map; 20829 20830 function createRootErrorUpdate(fiber, errorInfo, expirationTime) { 20831 var update = createUpdate(expirationTime, null); // Unmount the root by rendering null. 20832 20833 update.tag = CaptureUpdate; // Caution: React DevTools currently depends on this property 20834 // being called "element". 20835 20836 update.payload = { 20837 element: null 20838 }; 20839 var error = errorInfo.value; 20840 20841 update.callback = function () { 20842 onUncaughtError(error); 20843 logError(fiber, errorInfo); 20844 }; 20845 20846 return update; 20847 } 20848 20849 function createClassErrorUpdate(fiber, errorInfo, expirationTime) { 20850 var update = createUpdate(expirationTime, null); 20851 update.tag = CaptureUpdate; 20852 var getDerivedStateFromError = fiber.type.getDerivedStateFromError; 20853 20854 if (typeof getDerivedStateFromError === 'function') { 20855 var error$1 = errorInfo.value; 20856 20857 update.payload = function () { 20858 logError(fiber, errorInfo); 20859 return getDerivedStateFromError(error$1); 20860 }; 20861 } 20862 20863 var inst = fiber.stateNode; 20864 20865 if (inst !== null && typeof inst.componentDidCatch === 'function') { 20866 update.callback = function callback() { 20867 { 20868 markFailedErrorBoundaryForHotReloading(fiber); 20869 } 20870 20871 if (typeof getDerivedStateFromError !== 'function') { 20872 // To preserve the preexisting retry behavior of error boundaries, 20873 // we keep track of which ones already failed during this batch. 20874 // This gets reset before we yield back to the browser. 20875 // TODO: Warn in strict mode if getDerivedStateFromError is 20876 // not defined. 20877 markLegacyErrorBoundaryAsFailed(this); // Only log here if componentDidCatch is the only error boundary method defined 20878 20879 logError(fiber, errorInfo); 20880 } 20881 20882 var error$1 = errorInfo.value; 20883 var stack = errorInfo.stack; 20884 this.componentDidCatch(error$1, { 20885 componentStack: stack !== null ? stack : '' 20886 }); 20887 20888 { 20889 if (typeof getDerivedStateFromError !== 'function') { 20890 // If componentDidCatch is the only error boundary method defined, 20891 // then it needs to call setState to recover from errors. 20892 // If no state update is scheduled then the boundary will swallow the error. 20893 if (fiber.expirationTime !== Sync) { 20894 error('%s: Error boundaries should implement getDerivedStateFromError(). ' + 'In that method, return a state update to display an error message or fallback UI.', getComponentName(fiber.type) || 'Unknown'); 20895 } 20896 } 20897 } 20898 }; 20899 } else { 20900 update.callback = function () { 20901 markFailedErrorBoundaryForHotReloading(fiber); 20902 }; 20903 } 20904 20905 return update; 20906 } 20907 20908 function attachPingListener(root, renderExpirationTime, thenable) { 20909 // Attach a listener to the promise to "ping" the root and retry. But 20910 // only if one does not already exist for the current render expiration 20911 // time (which acts like a "thread ID" here). 20912 var pingCache = root.pingCache; 20913 var threadIDs; 20914 20915 if (pingCache === null) { 20916 pingCache = root.pingCache = new PossiblyWeakMap$1(); 20917 threadIDs = new Set(); 20918 pingCache.set(thenable, threadIDs); 20919 } else { 20920 threadIDs = pingCache.get(thenable); 20921 20922 if (threadIDs === undefined) { 20923 threadIDs = new Set(); 20924 pingCache.set(thenable, threadIDs); 20925 } 20926 } 20927 20928 if (!threadIDs.has(renderExpirationTime)) { 20929 // Memoize using the thread ID to prevent redundant listeners. 20930 threadIDs.add(renderExpirationTime); 20931 var ping = pingSuspendedRoot.bind(null, root, thenable, renderExpirationTime); 20932 thenable.then(ping, ping); 20933 } 20934 } 20935 20936 function throwException(root, returnFiber, sourceFiber, value, renderExpirationTime) { 20937 // The source fiber did not complete. 20938 sourceFiber.effectTag |= Incomplete; // Its effect list is no longer valid. 20939 20940 sourceFiber.firstEffect = sourceFiber.lastEffect = null; 20941 20942 if (value !== null && typeof value === 'object' && typeof value.then === 'function') { 20943 // This is a thenable. 20944 var thenable = value; 20945 20946 if ((sourceFiber.mode & BlockingMode) === NoMode) { 20947 // Reset the memoizedState to what it was before we attempted 20948 // to render it. 20949 var currentSource = sourceFiber.alternate; 20950 20951 if (currentSource) { 20952 sourceFiber.updateQueue = currentSource.updateQueue; 20953 sourceFiber.memoizedState = currentSource.memoizedState; 20954 sourceFiber.expirationTime = currentSource.expirationTime; 20955 } else { 20956 sourceFiber.updateQueue = null; 20957 sourceFiber.memoizedState = null; 20958 } 20959 } 20960 20961 var hasInvisibleParentBoundary = hasSuspenseContext(suspenseStackCursor.current, InvisibleParentSuspenseContext); // Schedule the nearest Suspense to re-render the timed out view. 20962 20963 var _workInProgress = returnFiber; 20964 20965 do { 20966 if (_workInProgress.tag === SuspenseComponent && shouldCaptureSuspense(_workInProgress, hasInvisibleParentBoundary)) { 20967 // Found the nearest boundary. 20968 // Stash the promise on the boundary fiber. If the boundary times out, we'll 20969 // attach another listener to flip the boundary back to its normal state. 20970 var thenables = _workInProgress.updateQueue; 20971 20972 if (thenables === null) { 20973 var updateQueue = new Set(); 20974 updateQueue.add(thenable); 20975 _workInProgress.updateQueue = updateQueue; 20976 } else { 20977 thenables.add(thenable); 20978 } // If the boundary is outside of blocking mode, we should *not* 20979 // suspend the commit. Pretend as if the suspended component rendered 20980 // null and keep rendering. In the commit phase, we'll schedule a 20981 // subsequent synchronous update to re-render the Suspense. 20982 // 20983 // Note: It doesn't matter whether the component that suspended was 20984 // inside a blocking mode tree. If the Suspense is outside of it, we 20985 // should *not* suspend the commit. 20986 20987 20988 if ((_workInProgress.mode & BlockingMode) === NoMode) { 20989 _workInProgress.effectTag |= DidCapture; // We're going to commit this fiber even though it didn't complete. 20990 // But we shouldn't call any lifecycle methods or callbacks. Remove 20991 // all lifecycle effect tags. 20992 20993 sourceFiber.effectTag &= ~(LifecycleEffectMask | Incomplete); 20994 20995 if (sourceFiber.tag === ClassComponent) { 20996 var currentSourceFiber = sourceFiber.alternate; 20997 20998 if (currentSourceFiber === null) { 20999 // This is a new mount. Change the tag so it's not mistaken for a 21000 // completed class component. For example, we should not call 21001 // componentWillUnmount if it is deleted. 21002 sourceFiber.tag = IncompleteClassComponent; 21003 } else { 21004 // When we try rendering again, we should not reuse the current fiber, 21005 // since it's known to be in an inconsistent state. Use a force update to 21006 // prevent a bail out. 21007 var update = createUpdate(Sync, null); 21008 update.tag = ForceUpdate; 21009 enqueueUpdate(sourceFiber, update); 21010 } 21011 } // The source fiber did not complete. Mark it with Sync priority to 21012 // indicate that it still has pending work. 21013 21014 21015 sourceFiber.expirationTime = Sync; // Exit without suspending. 21016 21017 return; 21018 } // Confirmed that the boundary is in a concurrent mode tree. Continue 21019 // with the normal suspend path. 21020 // 21021 // After this we'll use a set of heuristics to determine whether this 21022 // render pass will run to completion or restart or "suspend" the commit. 21023 // The actual logic for this is spread out in different places. 21024 // 21025 // This first principle is that if we're going to suspend when we complete 21026 // a root, then we should also restart if we get an update or ping that 21027 // might unsuspend it, and vice versa. The only reason to suspend is 21028 // because you think you might want to restart before committing. However, 21029 // it doesn't make sense to restart only while in the period we're suspended. 21030 // 21031 // Restarting too aggressively is also not good because it starves out any 21032 // intermediate loading state. So we use heuristics to determine when. 21033 // Suspense Heuristics 21034 // 21035 // If nothing threw a Promise or all the same fallbacks are already showing, 21036 // then don't suspend/restart. 21037 // 21038 // If this is an initial render of a new tree of Suspense boundaries and 21039 // those trigger a fallback, then don't suspend/restart. We want to ensure 21040 // that we can show the initial loading state as quickly as possible. 21041 // 21042 // If we hit a "Delayed" case, such as when we'd switch from content back into 21043 // a fallback, then we should always suspend/restart. SuspenseConfig applies to 21044 // this case. If none is defined, JND is used instead. 21045 // 21046 // If we're already showing a fallback and it gets "retried", allowing us to show 21047 // another level, but there's still an inner boundary that would show a fallback, 21048 // then we suspend/restart for 500ms since the last time we showed a fallback 21049 // anywhere in the tree. This effectively throttles progressive loading into a 21050 // consistent train of commits. This also gives us an opportunity to restart to 21051 // get to the completed state slightly earlier. 21052 // 21053 // If there's ambiguity due to batching it's resolved in preference of: 21054 // 1) "delayed", 2) "initial render", 3) "retry". 21055 // 21056 // We want to ensure that a "busy" state doesn't get force committed. We want to 21057 // ensure that new initial loading states can commit as soon as possible. 21058 21059 21060 attachPingListener(root, renderExpirationTime, thenable); 21061 _workInProgress.effectTag |= ShouldCapture; 21062 _workInProgress.expirationTime = renderExpirationTime; 21063 return; 21064 } // This boundary already captured during this render. Continue to the next 21065 // boundary. 21066 21067 21068 _workInProgress = _workInProgress.return; 21069 } while (_workInProgress !== null); // No boundary was found. Fallthrough to error mode. 21070 // TODO: Use invariant so the message is stripped in prod? 21071 21072 21073 value = new Error((getComponentName(sourceFiber.type) || 'A React component') + ' suspended while rendering, but no fallback UI was specified.\n' + '\n' + 'Add a <Suspense fallback=...> component higher in the tree to ' + 'provide a loading indicator or placeholder to display.' + getStackByFiberInDevAndProd(sourceFiber)); 21074 } // We didn't find a boundary that could handle this type of exception. Start 21075 // over and traverse parent path again, this time treating the exception 21076 // as an error. 21077 21078 21079 renderDidError(); 21080 value = createCapturedValue(value, sourceFiber); 21081 var workInProgress = returnFiber; 21082 21083 do { 21084 switch (workInProgress.tag) { 21085 case HostRoot: 21086 { 21087 var _errorInfo = value; 21088 workInProgress.effectTag |= ShouldCapture; 21089 workInProgress.expirationTime = renderExpirationTime; 21090 21091 var _update = createRootErrorUpdate(workInProgress, _errorInfo, renderExpirationTime); 21092 21093 enqueueCapturedUpdate(workInProgress, _update); 21094 return; 21095 } 21096 21097 case ClassComponent: 21098 // Capture and retry 21099 var errorInfo = value; 21100 var ctor = workInProgress.type; 21101 var instance = workInProgress.stateNode; 21102 21103 if ((workInProgress.effectTag & DidCapture) === NoEffect && (typeof ctor.getDerivedStateFromError === 'function' || instance !== null && typeof instance.componentDidCatch === 'function' && !isAlreadyFailedLegacyErrorBoundary(instance))) { 21104 workInProgress.effectTag |= ShouldCapture; 21105 workInProgress.expirationTime = renderExpirationTime; // Schedule the error boundary to re-render using updated state 21106 21107 var _update2 = createClassErrorUpdate(workInProgress, errorInfo, renderExpirationTime); 21108 21109 enqueueCapturedUpdate(workInProgress, _update2); 21110 return; 21111 } 21112 21113 break; 21114 } 21115 21116 workInProgress = workInProgress.return; 21117 } while (workInProgress !== null); 21118 } 21119 21120 var ceil = Math.ceil; 21121 var ReactCurrentDispatcher$1 = ReactSharedInternals.ReactCurrentDispatcher, 21122 ReactCurrentOwner$2 = ReactSharedInternals.ReactCurrentOwner, 21123 IsSomeRendererActing = ReactSharedInternals.IsSomeRendererActing; 21124 var NoContext = 21125 /* */ 21126 0; 21127 var BatchedContext = 21128 /* */ 21129 1; 21130 var EventContext = 21131 /* */ 21132 2; 21133 var DiscreteEventContext = 21134 /* */ 21135 4; 21136 var LegacyUnbatchedContext = 21137 /* */ 21138 8; 21139 var RenderContext = 21140 /* */ 21141 16; 21142 var CommitContext = 21143 /* */ 21144 32; 21145 var RootIncomplete = 0; 21146 var RootFatalErrored = 1; 21147 var RootErrored = 2; 21148 var RootSuspended = 3; 21149 var RootSuspendedWithDelay = 4; 21150 var RootCompleted = 5; 21151 // Describes where we are in the React execution stack 21152 var executionContext = NoContext; // The root we're working on 21153 21154 var workInProgressRoot = null; // The fiber we're working on 21155 21156 var workInProgress = null; // The expiration time we're rendering 21157 21158 var renderExpirationTime$1 = NoWork; // Whether to root completed, errored, suspended, etc. 21159 21160 var workInProgressRootExitStatus = RootIncomplete; // A fatal error, if one is thrown 21161 21162 var workInProgressRootFatalError = null; // Most recent event time among processed updates during this render. 21163 // This is conceptually a time stamp but expressed in terms of an ExpirationTime 21164 // because we deal mostly with expiration times in the hot path, so this avoids 21165 // the conversion happening in the hot path. 21166 21167 var workInProgressRootLatestProcessedExpirationTime = Sync; 21168 var workInProgressRootLatestSuspenseTimeout = Sync; 21169 var workInProgressRootCanSuspendUsingConfig = null; // The work left over by components that were visited during this render. Only 21170 // includes unprocessed updates, not work in bailed out children. 21171 21172 var workInProgressRootNextUnprocessedUpdateTime = NoWork; // If we're pinged while rendering we don't always restart immediately. 21173 // This flag determines if it might be worthwhile to restart if an opportunity 21174 // happens latere. 21175 21176 var workInProgressRootHasPendingPing = false; // The most recent time we committed a fallback. This lets us ensure a train 21177 // model where we don't commit new loading states in too quick succession. 21178 21179 var globalMostRecentFallbackTime = 0; 21180 var FALLBACK_THROTTLE_MS = 500; 21181 var nextEffect = null; 21182 var hasUncaughtError = false; 21183 var firstUncaughtError = null; 21184 var legacyErrorBoundariesThatAlreadyFailed = null; 21185 var rootDoesHavePassiveEffects = false; 21186 var rootWithPendingPassiveEffects = null; 21187 var pendingPassiveEffectsRenderPriority = NoPriority; 21188 var pendingPassiveEffectsExpirationTime = NoWork; 21189 var rootsWithPendingDiscreteUpdates = null; // Use these to prevent an infinite loop of nested updates 21190 21191 var NESTED_UPDATE_LIMIT = 50; 21192 var nestedUpdateCount = 0; 21193 var rootWithNestedUpdates = null; 21194 var NESTED_PASSIVE_UPDATE_LIMIT = 50; 21195 var nestedPassiveUpdateCount = 0; 21196 var interruptedBy = null; // Marks the need to reschedule pending interactions at these expiration times 21197 // during the commit phase. This enables them to be traced across components 21198 // that spawn new work during render. E.g. hidden boundaries, suspended SSR 21199 // hydration or SuspenseList. 21200 21201 var spawnedWorkDuringRender = null; // Expiration times are computed by adding to the current time (the start 21202 // time). However, if two updates are scheduled within the same event, we 21203 // should treat their start times as simultaneous, even if the actual clock 21204 // time has advanced between the first and second call. 21205 // In other words, because expiration times determine how updates are batched, 21206 // we want all updates of like priority that occur within the same event to 21207 // receive the same expiration time. Otherwise we get tearing. 21208 21209 var currentEventTime = NoWork; 21210 function requestCurrentTimeForUpdate() { 21211 if ((executionContext & (RenderContext | CommitContext)) !== NoContext) { 21212 // We're inside React, so it's fine to read the actual time. 21213 return msToExpirationTime(now()); 21214 } // We're not inside React, so we may be in the middle of a browser event. 21215 21216 21217 if (currentEventTime !== NoWork) { 21218 // Use the same start time for all updates until we enter React again. 21219 return currentEventTime; 21220 } // This is the first update since React yielded. Compute a new start time. 21221 21222 21223 currentEventTime = msToExpirationTime(now()); 21224 return currentEventTime; 21225 } 21226 function getCurrentTime() { 21227 return msToExpirationTime(now()); 21228 } 21229 function computeExpirationForFiber(currentTime, fiber, suspenseConfig) { 21230 var mode = fiber.mode; 21231 21232 if ((mode & BlockingMode) === NoMode) { 21233 return Sync; 21234 } 21235 21236 var priorityLevel = getCurrentPriorityLevel(); 21237 21238 if ((mode & ConcurrentMode) === NoMode) { 21239 return priorityLevel === ImmediatePriority ? Sync : Batched; 21240 } 21241 21242 if ((executionContext & RenderContext) !== NoContext) { 21243 // Use whatever time we're already rendering 21244 // TODO: Should there be a way to opt out, like with `runWithPriority`? 21245 return renderExpirationTime$1; 21246 } 21247 21248 var expirationTime; 21249 21250 if (suspenseConfig !== null) { 21251 // Compute an expiration time based on the Suspense timeout. 21252 expirationTime = computeSuspenseExpiration(currentTime, suspenseConfig.timeoutMs | 0 || LOW_PRIORITY_EXPIRATION); 21253 } else { 21254 // Compute an expiration time based on the Scheduler priority. 21255 switch (priorityLevel) { 21256 case ImmediatePriority: 21257 expirationTime = Sync; 21258 break; 21259 21260 case UserBlockingPriority$1: 21261 // TODO: Rename this to computeUserBlockingExpiration 21262 expirationTime = computeInteractiveExpiration(currentTime); 21263 break; 21264 21265 case NormalPriority: 21266 case LowPriority: 21267 // TODO: Handle LowPriority 21268 // TODO: Rename this to... something better. 21269 expirationTime = computeAsyncExpiration(currentTime); 21270 break; 21271 21272 case IdlePriority: 21273 expirationTime = Idle; 21274 break; 21275 21276 default: 21277 { 21278 { 21279 throw Error( "Expected a valid priority level" ); 21280 } 21281 } 21282 21283 } 21284 } // If we're in the middle of rendering a tree, do not update at the same 21285 // expiration time that is already rendering. 21286 // TODO: We shouldn't have to do this if the update is on a different root. 21287 // Refactor computeExpirationForFiber + scheduleUpdate so we have access to 21288 // the root when we check for this condition. 21289 21290 21291 if (workInProgressRoot !== null && expirationTime === renderExpirationTime$1) { 21292 // This is a trick to move this update into a separate batch 21293 expirationTime -= 1; 21294 } 21295 21296 return expirationTime; 21297 } 21298 function scheduleUpdateOnFiber(fiber, expirationTime) { 21299 checkForNestedUpdates(); 21300 warnAboutRenderPhaseUpdatesInDEV(fiber); 21301 var root = markUpdateTimeFromFiberToRoot(fiber, expirationTime); 21302 21303 if (root === null) { 21304 warnAboutUpdateOnUnmountedFiberInDEV(fiber); 21305 return; 21306 } 21307 21308 checkForInterruption(fiber, expirationTime); 21309 recordScheduleUpdate(); // TODO: computeExpirationForFiber also reads the priority. Pass the 21310 // priority as an argument to that function and this one. 21311 21312 var priorityLevel = getCurrentPriorityLevel(); 21313 21314 if (expirationTime === Sync) { 21315 if ( // Check if we're inside unbatchedUpdates 21316 (executionContext & LegacyUnbatchedContext) !== NoContext && // Check if we're not already rendering 21317 (executionContext & (RenderContext | CommitContext)) === NoContext) { 21318 // Register pending interactions on the root to avoid losing traced interaction data. 21319 schedulePendingInteractions(root, expirationTime); // This is a legacy edge case. The initial mount of a ReactDOM.render-ed 21320 // root inside of batchedUpdates should be synchronous, but layout updates 21321 // should be deferred until the end of the batch. 21322 21323 performSyncWorkOnRoot(root); 21324 } else { 21325 ensureRootIsScheduled(root); 21326 schedulePendingInteractions(root, expirationTime); 21327 21328 if (executionContext === NoContext) { 21329 // Flush the synchronous work now, unless we're already working or inside 21330 // a batch. This is intentionally inside scheduleUpdateOnFiber instead of 21331 // scheduleCallbackForFiber to preserve the ability to schedule a callback 21332 // without immediately flushing it. We only do this for user-initiated 21333 // updates, to preserve historical behavior of legacy mode. 21334 flushSyncCallbackQueue(); 21335 } 21336 } 21337 } else { 21338 ensureRootIsScheduled(root); 21339 schedulePendingInteractions(root, expirationTime); 21340 } 21341 21342 if ((executionContext & DiscreteEventContext) !== NoContext && ( // Only updates at user-blocking priority or greater are considered 21343 // discrete, even inside a discrete event. 21344 priorityLevel === UserBlockingPriority$1 || priorityLevel === ImmediatePriority)) { 21345 // This is the result of a discrete event. Track the lowest priority 21346 // discrete update per root so we can flush them early, if needed. 21347 if (rootsWithPendingDiscreteUpdates === null) { 21348 rootsWithPendingDiscreteUpdates = new Map([[root, expirationTime]]); 21349 } else { 21350 var lastDiscreteTime = rootsWithPendingDiscreteUpdates.get(root); 21351 21352 if (lastDiscreteTime === undefined || lastDiscreteTime > expirationTime) { 21353 rootsWithPendingDiscreteUpdates.set(root, expirationTime); 21354 } 21355 } 21356 } 21357 } 21358 var scheduleWork = scheduleUpdateOnFiber; // This is split into a separate function so we can mark a fiber with pending 21359 // work without treating it as a typical update that originates from an event; 21360 // e.g. retrying a Suspense boundary isn't an update, but it does schedule work 21361 // on a fiber. 21362 21363 function markUpdateTimeFromFiberToRoot(fiber, expirationTime) { 21364 // Update the source fiber's expiration time 21365 if (fiber.expirationTime < expirationTime) { 21366 fiber.expirationTime = expirationTime; 21367 } 21368 21369 var alternate = fiber.alternate; 21370 21371 if (alternate !== null && alternate.expirationTime < expirationTime) { 21372 alternate.expirationTime = expirationTime; 21373 } // Walk the parent path to the root and update the child expiration time. 21374 21375 21376 var node = fiber.return; 21377 var root = null; 21378 21379 if (node === null && fiber.tag === HostRoot) { 21380 root = fiber.stateNode; 21381 } else { 21382 while (node !== null) { 21383 alternate = node.alternate; 21384 21385 if (node.childExpirationTime < expirationTime) { 21386 node.childExpirationTime = expirationTime; 21387 21388 if (alternate !== null && alternate.childExpirationTime < expirationTime) { 21389 alternate.childExpirationTime = expirationTime; 21390 } 21391 } else if (alternate !== null && alternate.childExpirationTime < expirationTime) { 21392 alternate.childExpirationTime = expirationTime; 21393 } 21394 21395 if (node.return === null && node.tag === HostRoot) { 21396 root = node.stateNode; 21397 break; 21398 } 21399 21400 node = node.return; 21401 } 21402 } 21403 21404 if (root !== null) { 21405 if (workInProgressRoot === root) { 21406 // Received an update to a tree that's in the middle of rendering. Mark 21407 // that's unprocessed work on this root. 21408 markUnprocessedUpdateTime(expirationTime); 21409 21410 if (workInProgressRootExitStatus === RootSuspendedWithDelay) { 21411 // The root already suspended with a delay, which means this render 21412 // definitely won't finish. Since we have a new update, let's mark it as 21413 // suspended now, right before marking the incoming update. This has the 21414 // effect of interrupting the current render and switching to the update. 21415 // TODO: This happens to work when receiving an update during the render 21416 // phase, because of the trick inside computeExpirationForFiber to 21417 // subtract 1 from `renderExpirationTime` to move it into a 21418 // separate bucket. But we should probably model it with an exception, 21419 // using the same mechanism we use to force hydration of a subtree. 21420 // TODO: This does not account for low pri updates that were already 21421 // scheduled before the root started rendering. Need to track the next 21422 // pending expiration time (perhaps by backtracking the return path) and 21423 // then trigger a restart in the `renderDidSuspendDelayIfPossible` path. 21424 markRootSuspendedAtTime(root, renderExpirationTime$1); 21425 } 21426 } // Mark that the root has a pending update. 21427 21428 21429 markRootUpdatedAtTime(root, expirationTime); 21430 } 21431 21432 return root; 21433 } 21434 21435 function getNextRootExpirationTimeToWorkOn(root) { 21436 // Determines the next expiration time that the root should render, taking 21437 // into account levels that may be suspended, or levels that may have 21438 // received a ping. 21439 var lastExpiredTime = root.lastExpiredTime; 21440 21441 if (lastExpiredTime !== NoWork) { 21442 return lastExpiredTime; 21443 } // "Pending" refers to any update that hasn't committed yet, including if it 21444 // suspended. The "suspended" range is therefore a subset. 21445 21446 21447 var firstPendingTime = root.firstPendingTime; 21448 21449 if (!isRootSuspendedAtTime(root, firstPendingTime)) { 21450 // The highest priority pending time is not suspended. Let's work on that. 21451 return firstPendingTime; 21452 } // If the first pending time is suspended, check if there's a lower priority 21453 // pending level that we know about. Or check if we received a ping. Work 21454 // on whichever is higher priority. 21455 21456 21457 var lastPingedTime = root.lastPingedTime; 21458 var nextKnownPendingLevel = root.nextKnownPendingLevel; 21459 var nextLevel = lastPingedTime > nextKnownPendingLevel ? lastPingedTime : nextKnownPendingLevel; 21460 21461 if ( nextLevel <= Idle && firstPendingTime !== nextLevel) { 21462 // Don't work on Idle/Never priority unless everything else is committed. 21463 return NoWork; 21464 } 21465 21466 return nextLevel; 21467 } // Use this function to schedule a task for a root. There's only one task per 21468 // root; if a task was already scheduled, we'll check to make sure the 21469 // expiration time of the existing task is the same as the expiration time of 21470 // the next level that the root has work on. This function is called on every 21471 // update, and right before exiting a task. 21472 21473 21474 function ensureRootIsScheduled(root) { 21475 var lastExpiredTime = root.lastExpiredTime; 21476 21477 if (lastExpiredTime !== NoWork) { 21478 // Special case: Expired work should flush synchronously. 21479 root.callbackExpirationTime = Sync; 21480 root.callbackPriority = ImmediatePriority; 21481 root.callbackNode = scheduleSyncCallback(performSyncWorkOnRoot.bind(null, root)); 21482 return; 21483 } 21484 21485 var expirationTime = getNextRootExpirationTimeToWorkOn(root); 21486 var existingCallbackNode = root.callbackNode; 21487 21488 if (expirationTime === NoWork) { 21489 // There's nothing to work on. 21490 if (existingCallbackNode !== null) { 21491 root.callbackNode = null; 21492 root.callbackExpirationTime = NoWork; 21493 root.callbackPriority = NoPriority; 21494 } 21495 21496 return; 21497 } // TODO: If this is an update, we already read the current time. Pass the 21498 // time as an argument. 21499 21500 21501 var currentTime = requestCurrentTimeForUpdate(); 21502 var priorityLevel = inferPriorityFromExpirationTime(currentTime, expirationTime); // If there's an existing render task, confirm it has the correct priority and 21503 // expiration time. Otherwise, we'll cancel it and schedule a new one. 21504 21505 if (existingCallbackNode !== null) { 21506 var existingCallbackPriority = root.callbackPriority; 21507 var existingCallbackExpirationTime = root.callbackExpirationTime; 21508 21509 if ( // Callback must have the exact same expiration time. 21510 existingCallbackExpirationTime === expirationTime && // Callback must have greater or equal priority. 21511 existingCallbackPriority >= priorityLevel) { 21512 // Existing callback is sufficient. 21513 return; 21514 } // Need to schedule a new task. 21515 // TODO: Instead of scheduling a new task, we should be able to change the 21516 // priority of the existing one. 21517 21518 21519 cancelCallback(existingCallbackNode); 21520 } 21521 21522 root.callbackExpirationTime = expirationTime; 21523 root.callbackPriority = priorityLevel; 21524 var callbackNode; 21525 21526 if (expirationTime === Sync) { 21527 // Sync React callbacks are scheduled on a special internal queue 21528 callbackNode = scheduleSyncCallback(performSyncWorkOnRoot.bind(null, root)); 21529 } else { 21530 callbackNode = scheduleCallback(priorityLevel, performConcurrentWorkOnRoot.bind(null, root), // Compute a task timeout based on the expiration time. This also affects 21531 // ordering because tasks are processed in timeout order. 21532 { 21533 timeout: expirationTimeToMs(expirationTime) - now() 21534 }); 21535 } 21536 21537 root.callbackNode = callbackNode; 21538 } // This is the entry point for every concurrent task, i.e. anything that 21539 // goes through Scheduler. 21540 21541 21542 function performConcurrentWorkOnRoot(root, didTimeout) { 21543 // Since we know we're in a React event, we can clear the current 21544 // event time. The next update will compute a new event time. 21545 currentEventTime = NoWork; 21546 21547 if (didTimeout) { 21548 // The render task took too long to complete. Mark the current time as 21549 // expired to synchronously render all expired work in a single batch. 21550 var currentTime = requestCurrentTimeForUpdate(); 21551 markRootExpiredAtTime(root, currentTime); // This will schedule a synchronous callback. 21552 21553 ensureRootIsScheduled(root); 21554 return null; 21555 } // Determine the next expiration time to work on, using the fields stored 21556 // on the root. 21557 21558 21559 var expirationTime = getNextRootExpirationTimeToWorkOn(root); 21560 21561 if (expirationTime !== NoWork) { 21562 var originalCallbackNode = root.callbackNode; 21563 21564 if (!((executionContext & (RenderContext | CommitContext)) === NoContext)) { 21565 { 21566 throw Error( "Should not already be working." ); 21567 } 21568 } 21569 21570 flushPassiveEffects(); // If the root or expiration time have changed, throw out the existing stack 21571 // and prepare a fresh one. Otherwise we'll continue where we left off. 21572 21573 if (root !== workInProgressRoot || expirationTime !== renderExpirationTime$1) { 21574 prepareFreshStack(root, expirationTime); 21575 startWorkOnPendingInteractions(root, expirationTime); 21576 } // If we have a work-in-progress fiber, it means there's still work to do 21577 // in this root. 21578 21579 21580 if (workInProgress !== null) { 21581 var prevExecutionContext = executionContext; 21582 executionContext |= RenderContext; 21583 var prevDispatcher = pushDispatcher(); 21584 var prevInteractions = pushInteractions(root); 21585 startWorkLoopTimer(workInProgress); 21586 21587 do { 21588 try { 21589 workLoopConcurrent(); 21590 break; 21591 } catch (thrownValue) { 21592 handleError(root, thrownValue); 21593 } 21594 } while (true); 21595 21596 resetContextDependencies(); 21597 executionContext = prevExecutionContext; 21598 popDispatcher(prevDispatcher); 21599 21600 { 21601 popInteractions(prevInteractions); 21602 } 21603 21604 if (workInProgressRootExitStatus === RootFatalErrored) { 21605 var fatalError = workInProgressRootFatalError; 21606 stopInterruptedWorkLoopTimer(); 21607 prepareFreshStack(root, expirationTime); 21608 markRootSuspendedAtTime(root, expirationTime); 21609 ensureRootIsScheduled(root); 21610 throw fatalError; 21611 } 21612 21613 if (workInProgress !== null) { 21614 // There's still work left over. Exit without committing. 21615 stopInterruptedWorkLoopTimer(); 21616 } else { 21617 // We now have a consistent tree. The next step is either to commit it, 21618 // or, if something suspended, wait to commit it after a timeout. 21619 stopFinishedWorkLoopTimer(); 21620 var finishedWork = root.finishedWork = root.current.alternate; 21621 root.finishedExpirationTime = expirationTime; 21622 finishConcurrentRender(root, finishedWork, workInProgressRootExitStatus, expirationTime); 21623 } 21624 21625 ensureRootIsScheduled(root); 21626 21627 if (root.callbackNode === originalCallbackNode) { 21628 // The task node scheduled for this root is the same one that's 21629 // currently executed. Need to return a continuation. 21630 return performConcurrentWorkOnRoot.bind(null, root); 21631 } 21632 } 21633 } 21634 21635 return null; 21636 } 21637 21638 function finishConcurrentRender(root, finishedWork, exitStatus, expirationTime) { 21639 // Set this to null to indicate there's no in-progress render. 21640 workInProgressRoot = null; 21641 21642 switch (exitStatus) { 21643 case RootIncomplete: 21644 case RootFatalErrored: 21645 { 21646 { 21647 { 21648 throw Error( "Root did not complete. This is a bug in React." ); 21649 } 21650 } 21651 } 21652 // Flow knows about invariant, so it complains if I add a break 21653 // statement, but eslint doesn't know about invariant, so it complains 21654 // if I do. eslint-disable-next-line no-fallthrough 21655 21656 case RootErrored: 21657 { 21658 // If this was an async render, the error may have happened due to 21659 // a mutation in a concurrent event. Try rendering one more time, 21660 // synchronously, to see if the error goes away. If there are 21661 // lower priority updates, let's include those, too, in case they 21662 // fix the inconsistency. Render at Idle to include all updates. 21663 // If it was Idle or Never or some not-yet-invented time, render 21664 // at that time. 21665 markRootExpiredAtTime(root, expirationTime > Idle ? Idle : expirationTime); // We assume that this second render pass will be synchronous 21666 // and therefore not hit this path again. 21667 21668 break; 21669 } 21670 21671 case RootSuspended: 21672 { 21673 markRootSuspendedAtTime(root, expirationTime); 21674 var lastSuspendedTime = root.lastSuspendedTime; 21675 21676 if (expirationTime === lastSuspendedTime) { 21677 root.nextKnownPendingLevel = getRemainingExpirationTime(finishedWork); 21678 } // We have an acceptable loading state. We need to figure out if we 21679 // should immediately commit it or wait a bit. 21680 // If we have processed new updates during this render, we may now 21681 // have a new loading state ready. We want to ensure that we commit 21682 // that as soon as possible. 21683 21684 21685 var hasNotProcessedNewUpdates = workInProgressRootLatestProcessedExpirationTime === Sync; 21686 21687 if (hasNotProcessedNewUpdates && // do not delay if we're inside an act() scope 21688 !( IsThisRendererActing.current)) { 21689 // If we have not processed any new updates during this pass, then 21690 // this is either a retry of an existing fallback state or a 21691 // hidden tree. Hidden trees shouldn't be batched with other work 21692 // and after that's fixed it can only be a retry. We're going to 21693 // throttle committing retries so that we don't show too many 21694 // loading states too quickly. 21695 var msUntilTimeout = globalMostRecentFallbackTime + FALLBACK_THROTTLE_MS - now(); // Don't bother with a very short suspense time. 21696 21697 if (msUntilTimeout > 10) { 21698 if (workInProgressRootHasPendingPing) { 21699 var lastPingedTime = root.lastPingedTime; 21700 21701 if (lastPingedTime === NoWork || lastPingedTime >= expirationTime) { 21702 // This render was pinged but we didn't get to restart 21703 // earlier so try restarting now instead. 21704 root.lastPingedTime = expirationTime; 21705 prepareFreshStack(root, expirationTime); 21706 break; 21707 } 21708 } 21709 21710 var nextTime = getNextRootExpirationTimeToWorkOn(root); 21711 21712 if (nextTime !== NoWork && nextTime !== expirationTime) { 21713 // There's additional work on this root. 21714 break; 21715 } 21716 21717 if (lastSuspendedTime !== NoWork && lastSuspendedTime !== expirationTime) { 21718 // We should prefer to render the fallback of at the last 21719 // suspended level. Ping the last suspended level to try 21720 // rendering it again. 21721 root.lastPingedTime = lastSuspendedTime; 21722 break; 21723 } // The render is suspended, it hasn't timed out, and there's no 21724 // lower priority work to do. Instead of committing the fallback 21725 // immediately, wait for more data to arrive. 21726 21727 21728 root.timeoutHandle = scheduleTimeout(commitRoot.bind(null, root), msUntilTimeout); 21729 break; 21730 } 21731 } // The work expired. Commit immediately. 21732 21733 21734 commitRoot(root); 21735 break; 21736 } 21737 21738 case RootSuspendedWithDelay: 21739 { 21740 markRootSuspendedAtTime(root, expirationTime); 21741 var _lastSuspendedTime = root.lastSuspendedTime; 21742 21743 if (expirationTime === _lastSuspendedTime) { 21744 root.nextKnownPendingLevel = getRemainingExpirationTime(finishedWork); 21745 } 21746 21747 if ( // do not delay if we're inside an act() scope 21748 !( IsThisRendererActing.current)) { 21749 // We're suspended in a state that should be avoided. We'll try to 21750 // avoid committing it for as long as the timeouts let us. 21751 if (workInProgressRootHasPendingPing) { 21752 var _lastPingedTime = root.lastPingedTime; 21753 21754 if (_lastPingedTime === NoWork || _lastPingedTime >= expirationTime) { 21755 // This render was pinged but we didn't get to restart earlier 21756 // so try restarting now instead. 21757 root.lastPingedTime = expirationTime; 21758 prepareFreshStack(root, expirationTime); 21759 break; 21760 } 21761 } 21762 21763 var _nextTime = getNextRootExpirationTimeToWorkOn(root); 21764 21765 if (_nextTime !== NoWork && _nextTime !== expirationTime) { 21766 // There's additional work on this root. 21767 break; 21768 } 21769 21770 if (_lastSuspendedTime !== NoWork && _lastSuspendedTime !== expirationTime) { 21771 // We should prefer to render the fallback of at the last 21772 // suspended level. Ping the last suspended level to try 21773 // rendering it again. 21774 root.lastPingedTime = _lastSuspendedTime; 21775 break; 21776 } 21777 21778 var _msUntilTimeout; 21779 21780 if (workInProgressRootLatestSuspenseTimeout !== Sync) { 21781 // We have processed a suspense config whose expiration time we 21782 // can use as the timeout. 21783 _msUntilTimeout = expirationTimeToMs(workInProgressRootLatestSuspenseTimeout) - now(); 21784 } else if (workInProgressRootLatestProcessedExpirationTime === Sync) { 21785 // This should never normally happen because only new updates 21786 // cause delayed states, so we should have processed something. 21787 // However, this could also happen in an offscreen tree. 21788 _msUntilTimeout = 0; 21789 } else { 21790 // If we don't have a suspense config, we're going to use a 21791 // heuristic to determine how long we can suspend. 21792 var eventTimeMs = inferTimeFromExpirationTime(workInProgressRootLatestProcessedExpirationTime); 21793 var currentTimeMs = now(); 21794 var timeUntilExpirationMs = expirationTimeToMs(expirationTime) - currentTimeMs; 21795 var timeElapsed = currentTimeMs - eventTimeMs; 21796 21797 if (timeElapsed < 0) { 21798 // We get this wrong some time since we estimate the time. 21799 timeElapsed = 0; 21800 } 21801 21802 _msUntilTimeout = jnd(timeElapsed) - timeElapsed; // Clamp the timeout to the expiration time. TODO: Once the 21803 // event time is exact instead of inferred from expiration time 21804 // we don't need this. 21805 21806 if (timeUntilExpirationMs < _msUntilTimeout) { 21807 _msUntilTimeout = timeUntilExpirationMs; 21808 } 21809 } // Don't bother with a very short suspense time. 21810 21811 21812 if (_msUntilTimeout > 10) { 21813 // The render is suspended, it hasn't timed out, and there's no 21814 // lower priority work to do. Instead of committing the fallback 21815 // immediately, wait for more data to arrive. 21816 root.timeoutHandle = scheduleTimeout(commitRoot.bind(null, root), _msUntilTimeout); 21817 break; 21818 } 21819 } // The work expired. Commit immediately. 21820 21821 21822 commitRoot(root); 21823 break; 21824 } 21825 21826 case RootCompleted: 21827 { 21828 // The work completed. Ready to commit. 21829 if ( // do not delay if we're inside an act() scope 21830 !( IsThisRendererActing.current) && workInProgressRootLatestProcessedExpirationTime !== Sync && workInProgressRootCanSuspendUsingConfig !== null) { 21831 // If we have exceeded the minimum loading delay, which probably 21832 // means we have shown a spinner already, we might have to suspend 21833 // a bit longer to ensure that the spinner is shown for 21834 // enough time. 21835 var _msUntilTimeout2 = computeMsUntilSuspenseLoadingDelay(workInProgressRootLatestProcessedExpirationTime, expirationTime, workInProgressRootCanSuspendUsingConfig); 21836 21837 if (_msUntilTimeout2 > 10) { 21838 markRootSuspendedAtTime(root, expirationTime); 21839 root.timeoutHandle = scheduleTimeout(commitRoot.bind(null, root), _msUntilTimeout2); 21840 break; 21841 } 21842 } 21843 21844 commitRoot(root); 21845 break; 21846 } 21847 21848 default: 21849 { 21850 { 21851 { 21852 throw Error( "Unknown root exit status." ); 21853 } 21854 } 21855 } 21856 } 21857 } // This is the entry point for synchronous tasks that don't go 21858 // through Scheduler 21859 21860 21861 function performSyncWorkOnRoot(root) { 21862 // Check if there's expired work on this root. Otherwise, render at Sync. 21863 var lastExpiredTime = root.lastExpiredTime; 21864 var expirationTime = lastExpiredTime !== NoWork ? lastExpiredTime : Sync; 21865 21866 if (!((executionContext & (RenderContext | CommitContext)) === NoContext)) { 21867 { 21868 throw Error( "Should not already be working." ); 21869 } 21870 } 21871 21872 flushPassiveEffects(); // If the root or expiration time have changed, throw out the existing stack 21873 // and prepare a fresh one. Otherwise we'll continue where we left off. 21874 21875 if (root !== workInProgressRoot || expirationTime !== renderExpirationTime$1) { 21876 prepareFreshStack(root, expirationTime); 21877 startWorkOnPendingInteractions(root, expirationTime); 21878 } // If we have a work-in-progress fiber, it means there's still work to do 21879 // in this root. 21880 21881 21882 if (workInProgress !== null) { 21883 var prevExecutionContext = executionContext; 21884 executionContext |= RenderContext; 21885 var prevDispatcher = pushDispatcher(); 21886 var prevInteractions = pushInteractions(root); 21887 startWorkLoopTimer(workInProgress); 21888 21889 do { 21890 try { 21891 workLoopSync(); 21892 break; 21893 } catch (thrownValue) { 21894 handleError(root, thrownValue); 21895 } 21896 } while (true); 21897 21898 resetContextDependencies(); 21899 executionContext = prevExecutionContext; 21900 popDispatcher(prevDispatcher); 21901 21902 { 21903 popInteractions(prevInteractions); 21904 } 21905 21906 if (workInProgressRootExitStatus === RootFatalErrored) { 21907 var fatalError = workInProgressRootFatalError; 21908 stopInterruptedWorkLoopTimer(); 21909 prepareFreshStack(root, expirationTime); 21910 markRootSuspendedAtTime(root, expirationTime); 21911 ensureRootIsScheduled(root); 21912 throw fatalError; 21913 } 21914 21915 if (workInProgress !== null) { 21916 // This is a sync render, so we should have finished the whole tree. 21917 { 21918 { 21919 throw Error( "Cannot commit an incomplete root. This error is likely caused by a bug in React. Please file an issue." ); 21920 } 21921 } 21922 } else { 21923 // We now have a consistent tree. Because this is a sync render, we 21924 // will commit it even if something suspended. 21925 stopFinishedWorkLoopTimer(); 21926 root.finishedWork = root.current.alternate; 21927 root.finishedExpirationTime = expirationTime; 21928 finishSyncRender(root); 21929 } // Before exiting, make sure there's a callback scheduled for the next 21930 // pending level. 21931 21932 21933 ensureRootIsScheduled(root); 21934 } 21935 21936 return null; 21937 } 21938 21939 function finishSyncRender(root) { 21940 // Set this to null to indicate there's no in-progress render. 21941 workInProgressRoot = null; 21942 commitRoot(root); 21943 } 21944 function flushDiscreteUpdates() { 21945 // TODO: Should be able to flush inside batchedUpdates, but not inside `act`. 21946 // However, `act` uses `batchedUpdates`, so there's no way to distinguish 21947 // those two cases. Need to fix this before exposing flushDiscreteUpdates 21948 // as a public API. 21949 if ((executionContext & (BatchedContext | RenderContext | CommitContext)) !== NoContext) { 21950 { 21951 if ((executionContext & RenderContext) !== NoContext) { 21952 error('unstable_flushDiscreteUpdates: Cannot flush updates when React is ' + 'already rendering.'); 21953 } 21954 } // We're already rendering, so we can't synchronously flush pending work. 21955 // This is probably a nested event dispatch triggered by a lifecycle/effect, 21956 // like `el.focus()`. Exit. 21957 21958 21959 return; 21960 } 21961 21962 flushPendingDiscreteUpdates(); // If the discrete updates scheduled passive effects, flush them now so that 21963 // they fire before the next serial event. 21964 21965 flushPassiveEffects(); 21966 } 21967 function syncUpdates(fn, a, b, c) { 21968 return runWithPriority$1(ImmediatePriority, fn.bind(null, a, b, c)); 21969 } 21970 21971 function flushPendingDiscreteUpdates() { 21972 if (rootsWithPendingDiscreteUpdates !== null) { 21973 // For each root with pending discrete updates, schedule a callback to 21974 // immediately flush them. 21975 var roots = rootsWithPendingDiscreteUpdates; 21976 rootsWithPendingDiscreteUpdates = null; 21977 roots.forEach(function (expirationTime, root) { 21978 markRootExpiredAtTime(root, expirationTime); 21979 ensureRootIsScheduled(root); 21980 }); // Now flush the immediate queue. 21981 21982 flushSyncCallbackQueue(); 21983 } 21984 } 21985 21986 function batchedUpdates$1(fn, a) { 21987 var prevExecutionContext = executionContext; 21988 executionContext |= BatchedContext; 21989 21990 try { 21991 return fn(a); 21992 } finally { 21993 executionContext = prevExecutionContext; 21994 21995 if (executionContext === NoContext) { 21996 // Flush the immediate callbacks that were scheduled during this batch 21997 flushSyncCallbackQueue(); 21998 } 21999 } 22000 } 22001 function batchedEventUpdates$1(fn, a) { 22002 var prevExecutionContext = executionContext; 22003 executionContext |= EventContext; 22004 22005 try { 22006 return fn(a); 22007 } finally { 22008 executionContext = prevExecutionContext; 22009 22010 if (executionContext === NoContext) { 22011 // Flush the immediate callbacks that were scheduled during this batch 22012 flushSyncCallbackQueue(); 22013 } 22014 } 22015 } 22016 function discreteUpdates$1(fn, a, b, c, d) { 22017 var prevExecutionContext = executionContext; 22018 executionContext |= DiscreteEventContext; 22019 22020 try { 22021 // Should this 22022 return runWithPriority$1(UserBlockingPriority$1, fn.bind(null, a, b, c, d)); 22023 } finally { 22024 executionContext = prevExecutionContext; 22025 22026 if (executionContext === NoContext) { 22027 // Flush the immediate callbacks that were scheduled during this batch 22028 flushSyncCallbackQueue(); 22029 } 22030 } 22031 } 22032 function unbatchedUpdates(fn, a) { 22033 var prevExecutionContext = executionContext; 22034 executionContext &= ~BatchedContext; 22035 executionContext |= LegacyUnbatchedContext; 22036 22037 try { 22038 return fn(a); 22039 } finally { 22040 executionContext = prevExecutionContext; 22041 22042 if (executionContext === NoContext) { 22043 // Flush the immediate callbacks that were scheduled during this batch 22044 flushSyncCallbackQueue(); 22045 } 22046 } 22047 } 22048 function flushSync(fn, a) { 22049 if ((executionContext & (RenderContext | CommitContext)) !== NoContext) { 22050 { 22051 { 22052 throw Error( "flushSync was called from inside a lifecycle method. It cannot be called when React is already rendering." ); 22053 } 22054 } 22055 } 22056 22057 var prevExecutionContext = executionContext; 22058 executionContext |= BatchedContext; 22059 22060 try { 22061 return runWithPriority$1(ImmediatePriority, fn.bind(null, a)); 22062 } finally { 22063 executionContext = prevExecutionContext; // Flush the immediate callbacks that were scheduled during this batch. 22064 // Note that this will happen even if batchedUpdates is higher up 22065 // the stack. 22066 22067 flushSyncCallbackQueue(); 22068 } 22069 } 22070 22071 function prepareFreshStack(root, expirationTime) { 22072 root.finishedWork = null; 22073 root.finishedExpirationTime = NoWork; 22074 var timeoutHandle = root.timeoutHandle; 22075 22076 if (timeoutHandle !== noTimeout) { 22077 // The root previous suspended and scheduled a timeout to commit a fallback 22078 // state. Now that we have additional work, cancel the timeout. 22079 root.timeoutHandle = noTimeout; // $FlowFixMe Complains noTimeout is not a TimeoutID, despite the check above 22080 22081 cancelTimeout(timeoutHandle); 22082 } 22083 22084 if (workInProgress !== null) { 22085 var interruptedWork = workInProgress.return; 22086 22087 while (interruptedWork !== null) { 22088 unwindInterruptedWork(interruptedWork); 22089 interruptedWork = interruptedWork.return; 22090 } 22091 } 22092 22093 workInProgressRoot = root; 22094 workInProgress = createWorkInProgress(root.current, null); 22095 renderExpirationTime$1 = expirationTime; 22096 workInProgressRootExitStatus = RootIncomplete; 22097 workInProgressRootFatalError = null; 22098 workInProgressRootLatestProcessedExpirationTime = Sync; 22099 workInProgressRootLatestSuspenseTimeout = Sync; 22100 workInProgressRootCanSuspendUsingConfig = null; 22101 workInProgressRootNextUnprocessedUpdateTime = NoWork; 22102 workInProgressRootHasPendingPing = false; 22103 22104 { 22105 spawnedWorkDuringRender = null; 22106 } 22107 22108 { 22109 ReactStrictModeWarnings.discardPendingWarnings(); 22110 } 22111 } 22112 22113 function handleError(root, thrownValue) { 22114 do { 22115 try { 22116 // Reset module-level state that was set during the render phase. 22117 resetContextDependencies(); 22118 resetHooksAfterThrow(); 22119 resetCurrentFiber(); 22120 22121 if (workInProgress === null || workInProgress.return === null) { 22122 // Expected to be working on a non-root fiber. This is a fatal error 22123 // because there's no ancestor that can handle it; the root is 22124 // supposed to capture all errors that weren't caught by an error 22125 // boundary. 22126 workInProgressRootExitStatus = RootFatalErrored; 22127 workInProgressRootFatalError = thrownValue; // Set `workInProgress` to null. This represents advancing to the next 22128 // sibling, or the parent if there are no siblings. But since the root 22129 // has no siblings nor a parent, we set it to null. Usually this is 22130 // handled by `completeUnitOfWork` or `unwindWork`, but since we're 22131 // interntionally not calling those, we need set it here. 22132 // TODO: Consider calling `unwindWork` to pop the contexts. 22133 22134 workInProgress = null; 22135 return null; 22136 } 22137 22138 if (enableProfilerTimer && workInProgress.mode & ProfileMode) { 22139 // Record the time spent rendering before an error was thrown. This 22140 // avoids inaccurate Profiler durations in the case of a 22141 // suspended render. 22142 stopProfilerTimerIfRunningAndRecordDelta(workInProgress, true); 22143 } 22144 22145 throwException(root, workInProgress.return, workInProgress, thrownValue, renderExpirationTime$1); 22146 workInProgress = completeUnitOfWork(workInProgress); 22147 } catch (yetAnotherThrownValue) { 22148 // Something in the return path also threw. 22149 thrownValue = yetAnotherThrownValue; 22150 continue; 22151 } // Return to the normal work loop. 22152 22153 22154 return; 22155 } while (true); 22156 } 22157 22158 function pushDispatcher(root) { 22159 var prevDispatcher = ReactCurrentDispatcher$1.current; 22160 ReactCurrentDispatcher$1.current = ContextOnlyDispatcher; 22161 22162 if (prevDispatcher === null) { 22163 // The React isomorphic package does not include a default dispatcher. 22164 // Instead the first renderer will lazily attach one, in order to give 22165 // nicer error messages. 22166 return ContextOnlyDispatcher; 22167 } else { 22168 return prevDispatcher; 22169 } 22170 } 22171 22172 function popDispatcher(prevDispatcher) { 22173 ReactCurrentDispatcher$1.current = prevDispatcher; 22174 } 22175 22176 function pushInteractions(root) { 22177 { 22178 var prevInteractions = __interactionsRef.current; 22179 __interactionsRef.current = root.memoizedInteractions; 22180 return prevInteractions; 22181 } 22182 } 22183 22184 function popInteractions(prevInteractions) { 22185 { 22186 __interactionsRef.current = prevInteractions; 22187 } 22188 } 22189 22190 function markCommitTimeOfFallback() { 22191 globalMostRecentFallbackTime = now(); 22192 } 22193 function markRenderEventTimeAndConfig(expirationTime, suspenseConfig) { 22194 if (expirationTime < workInProgressRootLatestProcessedExpirationTime && expirationTime > Idle) { 22195 workInProgressRootLatestProcessedExpirationTime = expirationTime; 22196 } 22197 22198 if (suspenseConfig !== null) { 22199 if (expirationTime < workInProgressRootLatestSuspenseTimeout && expirationTime > Idle) { 22200 workInProgressRootLatestSuspenseTimeout = expirationTime; // Most of the time we only have one config and getting wrong is not bad. 22201 22202 workInProgressRootCanSuspendUsingConfig = suspenseConfig; 22203 } 22204 } 22205 } 22206 function markUnprocessedUpdateTime(expirationTime) { 22207 if (expirationTime > workInProgressRootNextUnprocessedUpdateTime) { 22208 workInProgressRootNextUnprocessedUpdateTime = expirationTime; 22209 } 22210 } 22211 function renderDidSuspend() { 22212 if (workInProgressRootExitStatus === RootIncomplete) { 22213 workInProgressRootExitStatus = RootSuspended; 22214 } 22215 } 22216 function renderDidSuspendDelayIfPossible() { 22217 if (workInProgressRootExitStatus === RootIncomplete || workInProgressRootExitStatus === RootSuspended) { 22218 workInProgressRootExitStatus = RootSuspendedWithDelay; 22219 } // Check if there's a lower priority update somewhere else in the tree. 22220 22221 22222 if (workInProgressRootNextUnprocessedUpdateTime !== NoWork && workInProgressRoot !== null) { 22223 // Mark the current render as suspended, and then mark that there's a 22224 // pending update. 22225 // TODO: This should immediately interrupt the current render, instead 22226 // of waiting until the next time we yield. 22227 markRootSuspendedAtTime(workInProgressRoot, renderExpirationTime$1); 22228 markRootUpdatedAtTime(workInProgressRoot, workInProgressRootNextUnprocessedUpdateTime); 22229 } 22230 } 22231 function renderDidError() { 22232 if (workInProgressRootExitStatus !== RootCompleted) { 22233 workInProgressRootExitStatus = RootErrored; 22234 } 22235 } // Called during render to determine if anything has suspended. 22236 // Returns false if we're not sure. 22237 22238 function renderHasNotSuspendedYet() { 22239 // If something errored or completed, we can't really be sure, 22240 // so those are false. 22241 return workInProgressRootExitStatus === RootIncomplete; 22242 } 22243 22244 function inferTimeFromExpirationTime(expirationTime) { 22245 // We don't know exactly when the update was scheduled, but we can infer an 22246 // approximate start time from the expiration time. 22247 var earliestExpirationTimeMs = expirationTimeToMs(expirationTime); 22248 return earliestExpirationTimeMs - LOW_PRIORITY_EXPIRATION; 22249 } 22250 22251 function inferTimeFromExpirationTimeWithSuspenseConfig(expirationTime, suspenseConfig) { 22252 // We don't know exactly when the update was scheduled, but we can infer an 22253 // approximate start time from the expiration time by subtracting the timeout 22254 // that was added to the event time. 22255 var earliestExpirationTimeMs = expirationTimeToMs(expirationTime); 22256 return earliestExpirationTimeMs - (suspenseConfig.timeoutMs | 0 || LOW_PRIORITY_EXPIRATION); 22257 } // The work loop is an extremely hot path. Tell Closure not to inline it. 22258 22259 /** @noinline */ 22260 22261 22262 function workLoopSync() { 22263 // Already timed out, so perform work without checking if we need to yield. 22264 while (workInProgress !== null) { 22265 workInProgress = performUnitOfWork(workInProgress); 22266 } 22267 } 22268 /** @noinline */ 22269 22270 22271 function workLoopConcurrent() { 22272 // Perform work until Scheduler asks us to yield 22273 while (workInProgress !== null && !shouldYield()) { 22274 workInProgress = performUnitOfWork(workInProgress); 22275 } 22276 } 22277 22278 function performUnitOfWork(unitOfWork) { 22279 // The current, flushed, state of this fiber is the alternate. Ideally 22280 // nothing should rely on this, but relying on it here means that we don't 22281 // need an additional field on the work in progress. 22282 var current = unitOfWork.alternate; 22283 startWorkTimer(unitOfWork); 22284 setCurrentFiber(unitOfWork); 22285 var next; 22286 22287 if ( (unitOfWork.mode & ProfileMode) !== NoMode) { 22288 startProfilerTimer(unitOfWork); 22289 next = beginWork$1(current, unitOfWork, renderExpirationTime$1); 22290 stopProfilerTimerIfRunningAndRecordDelta(unitOfWork, true); 22291 } else { 22292 next = beginWork$1(current, unitOfWork, renderExpirationTime$1); 22293 } 22294 22295 resetCurrentFiber(); 22296 unitOfWork.memoizedProps = unitOfWork.pendingProps; 22297 22298 if (next === null) { 22299 // If this doesn't spawn new work, complete the current work. 22300 next = completeUnitOfWork(unitOfWork); 22301 } 22302 22303 ReactCurrentOwner$2.current = null; 22304 return next; 22305 } 22306 22307 function completeUnitOfWork(unitOfWork) { 22308 // Attempt to complete the current unit of work, then move to the next 22309 // sibling. If there are no more siblings, return to the parent fiber. 22310 workInProgress = unitOfWork; 22311 22312 do { 22313 // The current, flushed, state of this fiber is the alternate. Ideally 22314 // nothing should rely on this, but relying on it here means that we don't 22315 // need an additional field on the work in progress. 22316 var current = workInProgress.alternate; 22317 var returnFiber = workInProgress.return; // Check if the work completed or if something threw. 22318 22319 if ((workInProgress.effectTag & Incomplete) === NoEffect) { 22320 setCurrentFiber(workInProgress); 22321 var next = void 0; 22322 22323 if ( (workInProgress.mode & ProfileMode) === NoMode) { 22324 next = completeWork(current, workInProgress, renderExpirationTime$1); 22325 } else { 22326 startProfilerTimer(workInProgress); 22327 next = completeWork(current, workInProgress, renderExpirationTime$1); // Update render duration assuming we didn't error. 22328 22329 stopProfilerTimerIfRunningAndRecordDelta(workInProgress, false); 22330 } 22331 22332 stopWorkTimer(workInProgress); 22333 resetCurrentFiber(); 22334 resetChildExpirationTime(workInProgress); 22335 22336 if (next !== null) { 22337 // Completing this fiber spawned new work. Work on that next. 22338 return next; 22339 } 22340 22341 if (returnFiber !== null && // Do not append effects to parents if a sibling failed to complete 22342 (returnFiber.effectTag & Incomplete) === NoEffect) { 22343 // Append all the effects of the subtree and this fiber onto the effect 22344 // list of the parent. The completion order of the children affects the 22345 // side-effect order. 22346 if (returnFiber.firstEffect === null) { 22347 returnFiber.firstEffect = workInProgress.firstEffect; 22348 } 22349 22350 if (workInProgress.lastEffect !== null) { 22351 if (returnFiber.lastEffect !== null) { 22352 returnFiber.lastEffect.nextEffect = workInProgress.firstEffect; 22353 } 22354 22355 returnFiber.lastEffect = workInProgress.lastEffect; 22356 } // If this fiber had side-effects, we append it AFTER the children's 22357 // side-effects. We can perform certain side-effects earlier if needed, 22358 // by doing multiple passes over the effect list. We don't want to 22359 // schedule our own side-effect on our own list because if end up 22360 // reusing children we'll schedule this effect onto itself since we're 22361 // at the end. 22362 22363 22364 var effectTag = workInProgress.effectTag; // Skip both NoWork and PerformedWork tags when creating the effect 22365 // list. PerformedWork effect is read by React DevTools but shouldn't be 22366 // committed. 22367 22368 if (effectTag > PerformedWork) { 22369 if (returnFiber.lastEffect !== null) { 22370 returnFiber.lastEffect.nextEffect = workInProgress; 22371 } else { 22372 returnFiber.firstEffect = workInProgress; 22373 } 22374 22375 returnFiber.lastEffect = workInProgress; 22376 } 22377 } 22378 } else { 22379 // This fiber did not complete because something threw. Pop values off 22380 // the stack without entering the complete phase. If this is a boundary, 22381 // capture values if possible. 22382 var _next = unwindWork(workInProgress); // Because this fiber did not complete, don't reset its expiration time. 22383 22384 22385 if ( (workInProgress.mode & ProfileMode) !== NoMode) { 22386 // Record the render duration for the fiber that errored. 22387 stopProfilerTimerIfRunningAndRecordDelta(workInProgress, false); // Include the time spent working on failed children before continuing. 22388 22389 var actualDuration = workInProgress.actualDuration; 22390 var child = workInProgress.child; 22391 22392 while (child !== null) { 22393 actualDuration += child.actualDuration; 22394 child = child.sibling; 22395 } 22396 22397 workInProgress.actualDuration = actualDuration; 22398 } 22399 22400 if (_next !== null) { 22401 // If completing this work spawned new work, do that next. We'll come 22402 // back here again. 22403 // Since we're restarting, remove anything that is not a host effect 22404 // from the effect tag. 22405 // TODO: The name stopFailedWorkTimer is misleading because Suspense 22406 // also captures and restarts. 22407 stopFailedWorkTimer(workInProgress); 22408 _next.effectTag &= HostEffectMask; 22409 return _next; 22410 } 22411 22412 stopWorkTimer(workInProgress); 22413 22414 if (returnFiber !== null) { 22415 // Mark the parent fiber as incomplete and clear its effect list. 22416 returnFiber.firstEffect = returnFiber.lastEffect = null; 22417 returnFiber.effectTag |= Incomplete; 22418 } 22419 } 22420 22421 var siblingFiber = workInProgress.sibling; 22422 22423 if (siblingFiber !== null) { 22424 // If there is more work to do in this returnFiber, do that next. 22425 return siblingFiber; 22426 } // Otherwise, return to the parent 22427 22428 22429 workInProgress = returnFiber; 22430 } while (workInProgress !== null); // We've reached the root. 22431 22432 22433 if (workInProgressRootExitStatus === RootIncomplete) { 22434 workInProgressRootExitStatus = RootCompleted; 22435 } 22436 22437 return null; 22438 } 22439 22440 function getRemainingExpirationTime(fiber) { 22441 var updateExpirationTime = fiber.expirationTime; 22442 var childExpirationTime = fiber.childExpirationTime; 22443 return updateExpirationTime > childExpirationTime ? updateExpirationTime : childExpirationTime; 22444 } 22445 22446 function resetChildExpirationTime(completedWork) { 22447 if (renderExpirationTime$1 !== Never && completedWork.childExpirationTime === Never) { 22448 // The children of this component are hidden. Don't bubble their 22449 // expiration times. 22450 return; 22451 } 22452 22453 var newChildExpirationTime = NoWork; // Bubble up the earliest expiration time. 22454 22455 if ( (completedWork.mode & ProfileMode) !== NoMode) { 22456 // In profiling mode, resetChildExpirationTime is also used to reset 22457 // profiler durations. 22458 var actualDuration = completedWork.actualDuration; 22459 var treeBaseDuration = completedWork.selfBaseDuration; // When a fiber is cloned, its actualDuration is reset to 0. This value will 22460 // only be updated if work is done on the fiber (i.e. it doesn't bailout). 22461 // When work is done, it should bubble to the parent's actualDuration. If 22462 // the fiber has not been cloned though, (meaning no work was done), then 22463 // this value will reflect the amount of time spent working on a previous 22464 // render. In that case it should not bubble. We determine whether it was 22465 // cloned by comparing the child pointer. 22466 22467 var shouldBubbleActualDurations = completedWork.alternate === null || completedWork.child !== completedWork.alternate.child; 22468 var child = completedWork.child; 22469 22470 while (child !== null) { 22471 var childUpdateExpirationTime = child.expirationTime; 22472 var childChildExpirationTime = child.childExpirationTime; 22473 22474 if (childUpdateExpirationTime > newChildExpirationTime) { 22475 newChildExpirationTime = childUpdateExpirationTime; 22476 } 22477 22478 if (childChildExpirationTime > newChildExpirationTime) { 22479 newChildExpirationTime = childChildExpirationTime; 22480 } 22481 22482 if (shouldBubbleActualDurations) { 22483 actualDuration += child.actualDuration; 22484 } 22485 22486 treeBaseDuration += child.treeBaseDuration; 22487 child = child.sibling; 22488 } 22489 22490 completedWork.actualDuration = actualDuration; 22491 completedWork.treeBaseDuration = treeBaseDuration; 22492 } else { 22493 var _child = completedWork.child; 22494 22495 while (_child !== null) { 22496 var _childUpdateExpirationTime = _child.expirationTime; 22497 var _childChildExpirationTime = _child.childExpirationTime; 22498 22499 if (_childUpdateExpirationTime > newChildExpirationTime) { 22500 newChildExpirationTime = _childUpdateExpirationTime; 22501 } 22502 22503 if (_childChildExpirationTime > newChildExpirationTime) { 22504 newChildExpirationTime = _childChildExpirationTime; 22505 } 22506 22507 _child = _child.sibling; 22508 } 22509 } 22510 22511 completedWork.childExpirationTime = newChildExpirationTime; 22512 } 22513 22514 function commitRoot(root) { 22515 var renderPriorityLevel = getCurrentPriorityLevel(); 22516 runWithPriority$1(ImmediatePriority, commitRootImpl.bind(null, root, renderPriorityLevel)); 22517 return null; 22518 } 22519 22520 function commitRootImpl(root, renderPriorityLevel) { 22521 do { 22522 // `flushPassiveEffects` will call `flushSyncUpdateQueue` at the end, which 22523 // means `flushPassiveEffects` will sometimes result in additional 22524 // passive effects. So we need to keep flushing in a loop until there are 22525 // no more pending effects. 22526 // TODO: Might be better if `flushPassiveEffects` did not automatically 22527 // flush synchronous work at the end, to avoid factoring hazards like this. 22528 flushPassiveEffects(); 22529 } while (rootWithPendingPassiveEffects !== null); 22530 22531 flushRenderPhaseStrictModeWarningsInDEV(); 22532 22533 if (!((executionContext & (RenderContext | CommitContext)) === NoContext)) { 22534 { 22535 throw Error( "Should not already be working." ); 22536 } 22537 } 22538 22539 var finishedWork = root.finishedWork; 22540 var expirationTime = root.finishedExpirationTime; 22541 22542 if (finishedWork === null) { 22543 return null; 22544 } 22545 22546 root.finishedWork = null; 22547 root.finishedExpirationTime = NoWork; 22548 22549 if (!(finishedWork !== root.current)) { 22550 { 22551 throw Error( "Cannot commit the same tree as before. This error is likely caused by a bug in React. Please file an issue." ); 22552 } 22553 } // commitRoot never returns a continuation; it always finishes synchronously. 22554 // So we can clear these now to allow a new callback to be scheduled. 22555 22556 22557 root.callbackNode = null; 22558 root.callbackExpirationTime = NoWork; 22559 root.callbackPriority = NoPriority; 22560 root.nextKnownPendingLevel = NoWork; 22561 startCommitTimer(); // Update the first and last pending times on this root. The new first 22562 // pending time is whatever is left on the root fiber. 22563 22564 var remainingExpirationTimeBeforeCommit = getRemainingExpirationTime(finishedWork); 22565 markRootFinishedAtTime(root, expirationTime, remainingExpirationTimeBeforeCommit); 22566 22567 if (root === workInProgressRoot) { 22568 // We can reset these now that they are finished. 22569 workInProgressRoot = null; 22570 workInProgress = null; 22571 renderExpirationTime$1 = NoWork; 22572 } // This indicates that the last root we worked on is not the same one that 22573 // we're committing now. This most commonly happens when a suspended root 22574 // times out. 22575 // Get the list of effects. 22576 22577 22578 var firstEffect; 22579 22580 if (finishedWork.effectTag > PerformedWork) { 22581 // A fiber's effect list consists only of its children, not itself. So if 22582 // the root has an effect, we need to add it to the end of the list. The 22583 // resulting list is the set that would belong to the root's parent, if it 22584 // had one; that is, all the effects in the tree including the root. 22585 if (finishedWork.lastEffect !== null) { 22586 finishedWork.lastEffect.nextEffect = finishedWork; 22587 firstEffect = finishedWork.firstEffect; 22588 } else { 22589 firstEffect = finishedWork; 22590 } 22591 } else { 22592 // There is no effect on the root. 22593 firstEffect = finishedWork.firstEffect; 22594 } 22595 22596 if (firstEffect !== null) { 22597 var prevExecutionContext = executionContext; 22598 executionContext |= CommitContext; 22599 var prevInteractions = pushInteractions(root); // Reset this to null before calling lifecycles 22600 22601 ReactCurrentOwner$2.current = null; // The commit phase is broken into several sub-phases. We do a separate pass 22602 // of the effect list for each phase: all mutation effects come before all 22603 // layout effects, and so on. 22604 // The first phase a "before mutation" phase. We use this phase to read the 22605 // state of the host tree right before we mutate it. This is where 22606 // getSnapshotBeforeUpdate is called. 22607 22608 startCommitSnapshotEffectsTimer(); 22609 prepareForCommit(root.containerInfo); 22610 nextEffect = firstEffect; 22611 22612 do { 22613 { 22614 invokeGuardedCallback(null, commitBeforeMutationEffects, null); 22615 22616 if (hasCaughtError()) { 22617 if (!(nextEffect !== null)) { 22618 { 22619 throw Error( "Should be working on an effect." ); 22620 } 22621 } 22622 22623 var error = clearCaughtError(); 22624 captureCommitPhaseError(nextEffect, error); 22625 nextEffect = nextEffect.nextEffect; 22626 } 22627 } 22628 } while (nextEffect !== null); 22629 22630 stopCommitSnapshotEffectsTimer(); 22631 22632 { 22633 // Mark the current commit time to be shared by all Profilers in this 22634 // batch. This enables them to be grouped later. 22635 recordCommitTime(); 22636 } // The next phase is the mutation phase, where we mutate the host tree. 22637 22638 22639 startCommitHostEffectsTimer(); 22640 nextEffect = firstEffect; 22641 22642 do { 22643 { 22644 invokeGuardedCallback(null, commitMutationEffects, null, root, renderPriorityLevel); 22645 22646 if (hasCaughtError()) { 22647 if (!(nextEffect !== null)) { 22648 { 22649 throw Error( "Should be working on an effect." ); 22650 } 22651 } 22652 22653 var _error = clearCaughtError(); 22654 22655 captureCommitPhaseError(nextEffect, _error); 22656 nextEffect = nextEffect.nextEffect; 22657 } 22658 } 22659 } while (nextEffect !== null); 22660 22661 stopCommitHostEffectsTimer(); 22662 resetAfterCommit(root.containerInfo); // The work-in-progress tree is now the current tree. This must come after 22663 // the mutation phase, so that the previous tree is still current during 22664 // componentWillUnmount, but before the layout phase, so that the finished 22665 // work is current during componentDidMount/Update. 22666 22667 root.current = finishedWork; // The next phase is the layout phase, where we call effects that read 22668 // the host tree after it's been mutated. The idiomatic use case for this is 22669 // layout, but class component lifecycles also fire here for legacy reasons. 22670 22671 startCommitLifeCyclesTimer(); 22672 nextEffect = firstEffect; 22673 22674 do { 22675 { 22676 invokeGuardedCallback(null, commitLayoutEffects, null, root, expirationTime); 22677 22678 if (hasCaughtError()) { 22679 if (!(nextEffect !== null)) { 22680 { 22681 throw Error( "Should be working on an effect." ); 22682 } 22683 } 22684 22685 var _error2 = clearCaughtError(); 22686 22687 captureCommitPhaseError(nextEffect, _error2); 22688 nextEffect = nextEffect.nextEffect; 22689 } 22690 } 22691 } while (nextEffect !== null); 22692 22693 stopCommitLifeCyclesTimer(); 22694 nextEffect = null; // Tell Scheduler to yield at the end of the frame, so the browser has an 22695 // opportunity to paint. 22696 22697 requestPaint(); 22698 22699 { 22700 popInteractions(prevInteractions); 22701 } 22702 22703 executionContext = prevExecutionContext; 22704 } else { 22705 // No effects. 22706 root.current = finishedWork; // Measure these anyway so the flamegraph explicitly shows that there were 22707 // no effects. 22708 // TODO: Maybe there's a better way to report this. 22709 22710 startCommitSnapshotEffectsTimer(); 22711 stopCommitSnapshotEffectsTimer(); 22712 22713 { 22714 recordCommitTime(); 22715 } 22716 22717 startCommitHostEffectsTimer(); 22718 stopCommitHostEffectsTimer(); 22719 startCommitLifeCyclesTimer(); 22720 stopCommitLifeCyclesTimer(); 22721 } 22722 22723 stopCommitTimer(); 22724 var rootDidHavePassiveEffects = rootDoesHavePassiveEffects; 22725 22726 if (rootDoesHavePassiveEffects) { 22727 // This commit has passive effects. Stash a reference to them. But don't 22728 // schedule a callback until after flushing layout work. 22729 rootDoesHavePassiveEffects = false; 22730 rootWithPendingPassiveEffects = root; 22731 pendingPassiveEffectsExpirationTime = expirationTime; 22732 pendingPassiveEffectsRenderPriority = renderPriorityLevel; 22733 } else { 22734 // We are done with the effect chain at this point so let's clear the 22735 // nextEffect pointers to assist with GC. If we have passive effects, we'll 22736 // clear this in flushPassiveEffects. 22737 nextEffect = firstEffect; 22738 22739 while (nextEffect !== null) { 22740 var nextNextEffect = nextEffect.nextEffect; 22741 nextEffect.nextEffect = null; 22742 nextEffect = nextNextEffect; 22743 } 22744 } // Check if there's remaining work on this root 22745 22746 22747 var remainingExpirationTime = root.firstPendingTime; 22748 22749 if (remainingExpirationTime !== NoWork) { 22750 { 22751 if (spawnedWorkDuringRender !== null) { 22752 var expirationTimes = spawnedWorkDuringRender; 22753 spawnedWorkDuringRender = null; 22754 22755 for (var i = 0; i < expirationTimes.length; i++) { 22756 scheduleInteractions(root, expirationTimes[i], root.memoizedInteractions); 22757 } 22758 } 22759 22760 schedulePendingInteractions(root, remainingExpirationTime); 22761 } 22762 } else { 22763 // If there's no remaining work, we can clear the set of already failed 22764 // error boundaries. 22765 legacyErrorBoundariesThatAlreadyFailed = null; 22766 } 22767 22768 { 22769 if (!rootDidHavePassiveEffects) { 22770 // If there are no passive effects, then we can complete the pending interactions. 22771 // Otherwise, we'll wait until after the passive effects are flushed. 22772 // Wait to do this until after remaining work has been scheduled, 22773 // so that we don't prematurely signal complete for interactions when there's e.g. hidden work. 22774 finishPendingInteractions(root, expirationTime); 22775 } 22776 } 22777 22778 if (remainingExpirationTime === Sync) { 22779 // Count the number of times the root synchronously re-renders without 22780 // finishing. If there are too many, it indicates an infinite update loop. 22781 if (root === rootWithNestedUpdates) { 22782 nestedUpdateCount++; 22783 } else { 22784 nestedUpdateCount = 0; 22785 rootWithNestedUpdates = root; 22786 } 22787 } else { 22788 nestedUpdateCount = 0; 22789 } 22790 22791 onCommitRoot(finishedWork.stateNode, expirationTime); // Always call this before exiting `commitRoot`, to ensure that any 22792 // additional work on this root is scheduled. 22793 22794 ensureRootIsScheduled(root); 22795 22796 if (hasUncaughtError) { 22797 hasUncaughtError = false; 22798 var _error3 = firstUncaughtError; 22799 firstUncaughtError = null; 22800 throw _error3; 22801 } 22802 22803 if ((executionContext & LegacyUnbatchedContext) !== NoContext) { 22804 // This is a legacy edge case. We just committed the initial mount of 22805 // a ReactDOM.render-ed root inside of batchedUpdates. The commit fired 22806 // synchronously, but layout updates should be deferred until the end 22807 // of the batch. 22808 return null; 22809 } // If layout work was scheduled, flush it now. 22810 22811 22812 flushSyncCallbackQueue(); 22813 return null; 22814 } 22815 22816 function commitBeforeMutationEffects() { 22817 while (nextEffect !== null) { 22818 var effectTag = nextEffect.effectTag; 22819 22820 if ((effectTag & Snapshot) !== NoEffect) { 22821 setCurrentFiber(nextEffect); 22822 recordEffect(); 22823 var current = nextEffect.alternate; 22824 commitBeforeMutationLifeCycles(current, nextEffect); 22825 resetCurrentFiber(); 22826 } 22827 22828 if ((effectTag & Passive) !== NoEffect) { 22829 // If there are passive effects, schedule a callback to flush at 22830 // the earliest opportunity. 22831 if (!rootDoesHavePassiveEffects) { 22832 rootDoesHavePassiveEffects = true; 22833 scheduleCallback(NormalPriority, function () { 22834 flushPassiveEffects(); 22835 return null; 22836 }); 22837 } 22838 } 22839 22840 nextEffect = nextEffect.nextEffect; 22841 } 22842 } 22843 22844 function commitMutationEffects(root, renderPriorityLevel) { 22845 // TODO: Should probably move the bulk of this function to commitWork. 22846 while (nextEffect !== null) { 22847 setCurrentFiber(nextEffect); 22848 var effectTag = nextEffect.effectTag; 22849 22850 if (effectTag & ContentReset) { 22851 commitResetTextContent(nextEffect); 22852 } 22853 22854 if (effectTag & Ref) { 22855 var current = nextEffect.alternate; 22856 22857 if (current !== null) { 22858 commitDetachRef(current); 22859 } 22860 } // The following switch statement is only concerned about placement, 22861 // updates, and deletions. To avoid needing to add a case for every possible 22862 // bitmap value, we remove the secondary effects from the effect tag and 22863 // switch on that value. 22864 22865 22866 var primaryEffectTag = effectTag & (Placement | Update | Deletion | Hydrating); 22867 22868 switch (primaryEffectTag) { 22869 case Placement: 22870 { 22871 commitPlacement(nextEffect); // Clear the "placement" from effect tag so that we know that this is 22872 // inserted, before any life-cycles like componentDidMount gets called. 22873 // TODO: findDOMNode doesn't rely on this any more but isMounted does 22874 // and isMounted is deprecated anyway so we should be able to kill this. 22875 22876 nextEffect.effectTag &= ~Placement; 22877 break; 22878 } 22879 22880 case PlacementAndUpdate: 22881 { 22882 // Placement 22883 commitPlacement(nextEffect); // Clear the "placement" from effect tag so that we know that this is 22884 // inserted, before any life-cycles like componentDidMount gets called. 22885 22886 nextEffect.effectTag &= ~Placement; // Update 22887 22888 var _current = nextEffect.alternate; 22889 commitWork(_current, nextEffect); 22890 break; 22891 } 22892 22893 case Hydrating: 22894 { 22895 nextEffect.effectTag &= ~Hydrating; 22896 break; 22897 } 22898 22899 case HydratingAndUpdate: 22900 { 22901 nextEffect.effectTag &= ~Hydrating; // Update 22902 22903 var _current2 = nextEffect.alternate; 22904 commitWork(_current2, nextEffect); 22905 break; 22906 } 22907 22908 case Update: 22909 { 22910 var _current3 = nextEffect.alternate; 22911 commitWork(_current3, nextEffect); 22912 break; 22913 } 22914 22915 case Deletion: 22916 { 22917 commitDeletion(root, nextEffect, renderPriorityLevel); 22918 break; 22919 } 22920 } // TODO: Only record a mutation effect if primaryEffectTag is non-zero. 22921 22922 22923 recordEffect(); 22924 resetCurrentFiber(); 22925 nextEffect = nextEffect.nextEffect; 22926 } 22927 } 22928 22929 function commitLayoutEffects(root, committedExpirationTime) { 22930 // TODO: Should probably move the bulk of this function to commitWork. 22931 while (nextEffect !== null) { 22932 setCurrentFiber(nextEffect); 22933 var effectTag = nextEffect.effectTag; 22934 22935 if (effectTag & (Update | Callback)) { 22936 recordEffect(); 22937 var current = nextEffect.alternate; 22938 commitLifeCycles(root, current, nextEffect); 22939 } 22940 22941 if (effectTag & Ref) { 22942 recordEffect(); 22943 commitAttachRef(nextEffect); 22944 } 22945 22946 resetCurrentFiber(); 22947 nextEffect = nextEffect.nextEffect; 22948 } 22949 } 22950 22951 function flushPassiveEffects() { 22952 if (pendingPassiveEffectsRenderPriority !== NoPriority) { 22953 var priorityLevel = pendingPassiveEffectsRenderPriority > NormalPriority ? NormalPriority : pendingPassiveEffectsRenderPriority; 22954 pendingPassiveEffectsRenderPriority = NoPriority; 22955 return runWithPriority$1(priorityLevel, flushPassiveEffectsImpl); 22956 } 22957 } 22958 22959 function flushPassiveEffectsImpl() { 22960 if (rootWithPendingPassiveEffects === null) { 22961 return false; 22962 } 22963 22964 var root = rootWithPendingPassiveEffects; 22965 var expirationTime = pendingPassiveEffectsExpirationTime; 22966 rootWithPendingPassiveEffects = null; 22967 pendingPassiveEffectsExpirationTime = NoWork; 22968 22969 if (!((executionContext & (RenderContext | CommitContext)) === NoContext)) { 22970 { 22971 throw Error( "Cannot flush passive effects while already rendering." ); 22972 } 22973 } 22974 22975 var prevExecutionContext = executionContext; 22976 executionContext |= CommitContext; 22977 var prevInteractions = pushInteractions(root); 22978 22979 { 22980 // Note: This currently assumes there are no passive effects on the root fiber 22981 // because the root is not part of its own effect list. 22982 // This could change in the future. 22983 var _effect2 = root.current.firstEffect; 22984 22985 while (_effect2 !== null) { 22986 { 22987 setCurrentFiber(_effect2); 22988 invokeGuardedCallback(null, commitPassiveHookEffects, null, _effect2); 22989 22990 if (hasCaughtError()) { 22991 if (!(_effect2 !== null)) { 22992 { 22993 throw Error( "Should be working on an effect." ); 22994 } 22995 } 22996 22997 var _error5 = clearCaughtError(); 22998 22999 captureCommitPhaseError(_effect2, _error5); 23000 } 23001 23002 resetCurrentFiber(); 23003 } 23004 23005 var nextNextEffect = _effect2.nextEffect; // Remove nextEffect pointer to assist GC 23006 23007 _effect2.nextEffect = null; 23008 _effect2 = nextNextEffect; 23009 } 23010 } 23011 23012 { 23013 popInteractions(prevInteractions); 23014 finishPendingInteractions(root, expirationTime); 23015 } 23016 23017 executionContext = prevExecutionContext; 23018 flushSyncCallbackQueue(); // If additional passive effects were scheduled, increment a counter. If this 23019 // exceeds the limit, we'll fire a warning. 23020 23021 nestedPassiveUpdateCount = rootWithPendingPassiveEffects === null ? 0 : nestedPassiveUpdateCount + 1; 23022 return true; 23023 } 23024 23025 function isAlreadyFailedLegacyErrorBoundary(instance) { 23026 return legacyErrorBoundariesThatAlreadyFailed !== null && legacyErrorBoundariesThatAlreadyFailed.has(instance); 23027 } 23028 function markLegacyErrorBoundaryAsFailed(instance) { 23029 if (legacyErrorBoundariesThatAlreadyFailed === null) { 23030 legacyErrorBoundariesThatAlreadyFailed = new Set([instance]); 23031 } else { 23032 legacyErrorBoundariesThatAlreadyFailed.add(instance); 23033 } 23034 } 23035 23036 function prepareToThrowUncaughtError(error) { 23037 if (!hasUncaughtError) { 23038 hasUncaughtError = true; 23039 firstUncaughtError = error; 23040 } 23041 } 23042 23043 var onUncaughtError = prepareToThrowUncaughtError; 23044 23045 function captureCommitPhaseErrorOnRoot(rootFiber, sourceFiber, error) { 23046 var errorInfo = createCapturedValue(error, sourceFiber); 23047 var update = createRootErrorUpdate(rootFiber, errorInfo, Sync); 23048 enqueueUpdate(rootFiber, update); 23049 var root = markUpdateTimeFromFiberToRoot(rootFiber, Sync); 23050 23051 if (root !== null) { 23052 ensureRootIsScheduled(root); 23053 schedulePendingInteractions(root, Sync); 23054 } 23055 } 23056 23057 function captureCommitPhaseError(sourceFiber, error) { 23058 if (sourceFiber.tag === HostRoot) { 23059 // Error was thrown at the root. There is no parent, so the root 23060 // itself should capture it. 23061 captureCommitPhaseErrorOnRoot(sourceFiber, sourceFiber, error); 23062 return; 23063 } 23064 23065 var fiber = sourceFiber.return; 23066 23067 while (fiber !== null) { 23068 if (fiber.tag === HostRoot) { 23069 captureCommitPhaseErrorOnRoot(fiber, sourceFiber, error); 23070 return; 23071 } else if (fiber.tag === ClassComponent) { 23072 var ctor = fiber.type; 23073 var instance = fiber.stateNode; 23074 23075 if (typeof ctor.getDerivedStateFromError === 'function' || typeof instance.componentDidCatch === 'function' && !isAlreadyFailedLegacyErrorBoundary(instance)) { 23076 var errorInfo = createCapturedValue(error, sourceFiber); 23077 var update = createClassErrorUpdate(fiber, errorInfo, // TODO: This is always sync 23078 Sync); 23079 enqueueUpdate(fiber, update); 23080 var root = markUpdateTimeFromFiberToRoot(fiber, Sync); 23081 23082 if (root !== null) { 23083 ensureRootIsScheduled(root); 23084 schedulePendingInteractions(root, Sync); 23085 } 23086 23087 return; 23088 } 23089 } 23090 23091 fiber = fiber.return; 23092 } 23093 } 23094 function pingSuspendedRoot(root, thenable, suspendedTime) { 23095 var pingCache = root.pingCache; 23096 23097 if (pingCache !== null) { 23098 // The thenable resolved, so we no longer need to memoize, because it will 23099 // never be thrown again. 23100 pingCache.delete(thenable); 23101 } 23102 23103 if (workInProgressRoot === root && renderExpirationTime$1 === suspendedTime) { 23104 // Received a ping at the same priority level at which we're currently 23105 // rendering. We might want to restart this render. This should mirror 23106 // the logic of whether or not a root suspends once it completes. 23107 // TODO: If we're rendering sync either due to Sync, Batched or expired, 23108 // we should probably never restart. 23109 // If we're suspended with delay, we'll always suspend so we can always 23110 // restart. If we're suspended without any updates, it might be a retry. 23111 // If it's early in the retry we can restart. We can't know for sure 23112 // whether we'll eventually process an update during this render pass, 23113 // but it's somewhat unlikely that we get to a ping before that, since 23114 // getting to the root most update is usually very fast. 23115 if (workInProgressRootExitStatus === RootSuspendedWithDelay || workInProgressRootExitStatus === RootSuspended && workInProgressRootLatestProcessedExpirationTime === Sync && now() - globalMostRecentFallbackTime < FALLBACK_THROTTLE_MS) { 23116 // Restart from the root. Don't need to schedule a ping because 23117 // we're already working on this tree. 23118 prepareFreshStack(root, renderExpirationTime$1); 23119 } else { 23120 // Even though we can't restart right now, we might get an 23121 // opportunity later. So we mark this render as having a ping. 23122 workInProgressRootHasPendingPing = true; 23123 } 23124 23125 return; 23126 } 23127 23128 if (!isRootSuspendedAtTime(root, suspendedTime)) { 23129 // The root is no longer suspended at this time. 23130 return; 23131 } 23132 23133 var lastPingedTime = root.lastPingedTime; 23134 23135 if (lastPingedTime !== NoWork && lastPingedTime < suspendedTime) { 23136 // There's already a lower priority ping scheduled. 23137 return; 23138 } // Mark the time at which this ping was scheduled. 23139 23140 23141 root.lastPingedTime = suspendedTime; 23142 23143 ensureRootIsScheduled(root); 23144 schedulePendingInteractions(root, suspendedTime); 23145 } 23146 23147 function retryTimedOutBoundary(boundaryFiber, retryTime) { 23148 // The boundary fiber (a Suspense component or SuspenseList component) 23149 // previously was rendered in its fallback state. One of the promises that 23150 // suspended it has resolved, which means at least part of the tree was 23151 // likely unblocked. Try rendering again, at a new expiration time. 23152 if (retryTime === NoWork) { 23153 var suspenseConfig = null; // Retries don't carry over the already committed update. 23154 23155 var currentTime = requestCurrentTimeForUpdate(); 23156 retryTime = computeExpirationForFiber(currentTime, boundaryFiber, suspenseConfig); 23157 } // TODO: Special case idle priority? 23158 23159 23160 var root = markUpdateTimeFromFiberToRoot(boundaryFiber, retryTime); 23161 23162 if (root !== null) { 23163 ensureRootIsScheduled(root); 23164 schedulePendingInteractions(root, retryTime); 23165 } 23166 } 23167 function resolveRetryThenable(boundaryFiber, thenable) { 23168 var retryTime = NoWork; // Default 23169 23170 var retryCache; 23171 23172 { 23173 retryCache = boundaryFiber.stateNode; 23174 } 23175 23176 if (retryCache !== null) { 23177 // The thenable resolved, so we no longer need to memoize, because it will 23178 // never be thrown again. 23179 retryCache.delete(thenable); 23180 } 23181 23182 retryTimedOutBoundary(boundaryFiber, retryTime); 23183 } // Computes the next Just Noticeable Difference (JND) boundary. 23184 // The theory is that a person can't tell the difference between small differences in time. 23185 // Therefore, if we wait a bit longer than necessary that won't translate to a noticeable 23186 // difference in the experience. However, waiting for longer might mean that we can avoid 23187 // showing an intermediate loading state. The longer we have already waited, the harder it 23188 // is to tell small differences in time. Therefore, the longer we've already waited, 23189 // the longer we can wait additionally. At some point we have to give up though. 23190 // We pick a train model where the next boundary commits at a consistent schedule. 23191 // These particular numbers are vague estimates. We expect to adjust them based on research. 23192 23193 function jnd(timeElapsed) { 23194 return timeElapsed < 120 ? 120 : timeElapsed < 480 ? 480 : timeElapsed < 1080 ? 1080 : timeElapsed < 1920 ? 1920 : timeElapsed < 3000 ? 3000 : timeElapsed < 4320 ? 4320 : ceil(timeElapsed / 1960) * 1960; 23195 } 23196 23197 function computeMsUntilSuspenseLoadingDelay(mostRecentEventTime, committedExpirationTime, suspenseConfig) { 23198 var busyMinDurationMs = suspenseConfig.busyMinDurationMs | 0; 23199 23200 if (busyMinDurationMs <= 0) { 23201 return 0; 23202 } 23203 23204 var busyDelayMs = suspenseConfig.busyDelayMs | 0; // Compute the time until this render pass would expire. 23205 23206 var currentTimeMs = now(); 23207 var eventTimeMs = inferTimeFromExpirationTimeWithSuspenseConfig(mostRecentEventTime, suspenseConfig); 23208 var timeElapsed = currentTimeMs - eventTimeMs; 23209 23210 if (timeElapsed <= busyDelayMs) { 23211 // If we haven't yet waited longer than the initial delay, we don't 23212 // have to wait any additional time. 23213 return 0; 23214 } 23215 23216 var msUntilTimeout = busyDelayMs + busyMinDurationMs - timeElapsed; // This is the value that is passed to `setTimeout`. 23217 23218 return msUntilTimeout; 23219 } 23220 23221 function checkForNestedUpdates() { 23222 if (nestedUpdateCount > NESTED_UPDATE_LIMIT) { 23223 nestedUpdateCount = 0; 23224 rootWithNestedUpdates = null; 23225 23226 { 23227 { 23228 throw Error( "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." ); 23229 } 23230 } 23231 } 23232 23233 { 23234 if (nestedPassiveUpdateCount > NESTED_PASSIVE_UPDATE_LIMIT) { 23235 nestedPassiveUpdateCount = 0; 23236 23237 error('Maximum update depth exceeded. This can happen when a component ' + "calls setState inside useEffect, but useEffect either doesn't " + 'have a dependency array, or one of the dependencies changes on ' + 'every render.'); 23238 } 23239 } 23240 } 23241 23242 function flushRenderPhaseStrictModeWarningsInDEV() { 23243 { 23244 ReactStrictModeWarnings.flushLegacyContextWarning(); 23245 23246 { 23247 ReactStrictModeWarnings.flushPendingUnsafeLifecycleWarnings(); 23248 } 23249 } 23250 } 23251 23252 function stopFinishedWorkLoopTimer() { 23253 var didCompleteRoot = true; 23254 stopWorkLoopTimer(interruptedBy, didCompleteRoot); 23255 interruptedBy = null; 23256 } 23257 23258 function stopInterruptedWorkLoopTimer() { 23259 // TODO: Track which fiber caused the interruption. 23260 var didCompleteRoot = false; 23261 stopWorkLoopTimer(interruptedBy, didCompleteRoot); 23262 interruptedBy = null; 23263 } 23264 23265 function checkForInterruption(fiberThatReceivedUpdate, updateExpirationTime) { 23266 if ( workInProgressRoot !== null && updateExpirationTime > renderExpirationTime$1) { 23267 interruptedBy = fiberThatReceivedUpdate; 23268 } 23269 } 23270 23271 var didWarnStateUpdateForUnmountedComponent = null; 23272 23273 function warnAboutUpdateOnUnmountedFiberInDEV(fiber) { 23274 { 23275 var tag = fiber.tag; 23276 23277 if (tag !== HostRoot && tag !== ClassComponent && tag !== FunctionComponent && tag !== ForwardRef && tag !== MemoComponent && tag !== SimpleMemoComponent && tag !== Block) { 23278 // Only warn for user-defined components, not internal ones like Suspense. 23279 return; 23280 } 23281 // the problematic code almost always lies inside that component. 23282 23283 23284 var componentName = getComponentName(fiber.type) || 'ReactComponent'; 23285 23286 if (didWarnStateUpdateForUnmountedComponent !== null) { 23287 if (didWarnStateUpdateForUnmountedComponent.has(componentName)) { 23288 return; 23289 } 23290 23291 didWarnStateUpdateForUnmountedComponent.add(componentName); 23292 } else { 23293 didWarnStateUpdateForUnmountedComponent = new Set([componentName]); 23294 } 23295 23296 error("Can't perform a React state update on an unmounted component. This " + 'is a no-op, but it indicates a memory leak in your application. To ' + 'fix, cancel all subscriptions and asynchronous tasks in %s.%s', tag === ClassComponent ? 'the componentWillUnmount method' : 'a useEffect cleanup function', getStackByFiberInDevAndProd(fiber)); 23297 } 23298 } 23299 23300 var beginWork$1; 23301 23302 { 23303 var dummyFiber = null; 23304 23305 beginWork$1 = function (current, unitOfWork, expirationTime) { 23306 // If a component throws an error, we replay it again in a synchronously 23307 // dispatched event, so that the debugger will treat it as an uncaught 23308 // error See ReactErrorUtils for more information. 23309 // Before entering the begin phase, copy the work-in-progress onto a dummy 23310 // fiber. If beginWork throws, we'll use this to reset the state. 23311 var originalWorkInProgressCopy = assignFiberPropertiesInDEV(dummyFiber, unitOfWork); 23312 23313 try { 23314 return beginWork(current, unitOfWork, expirationTime); 23315 } catch (originalError) { 23316 if (originalError !== null && typeof originalError === 'object' && typeof originalError.then === 'function') { 23317 // Don't replay promises. Treat everything else like an error. 23318 throw originalError; 23319 } // Keep this code in sync with handleError; any changes here must have 23320 // corresponding changes there. 23321 23322 23323 resetContextDependencies(); 23324 resetHooksAfterThrow(); // Don't reset current debug fiber, since we're about to work on the 23325 // same fiber again. 23326 // Unwind the failed stack frame 23327 23328 unwindInterruptedWork(unitOfWork); // Restore the original properties of the fiber. 23329 23330 assignFiberPropertiesInDEV(unitOfWork, originalWorkInProgressCopy); 23331 23332 if ( unitOfWork.mode & ProfileMode) { 23333 // Reset the profiler timer. 23334 startProfilerTimer(unitOfWork); 23335 } // Run beginWork again. 23336 23337 23338 invokeGuardedCallback(null, beginWork, null, current, unitOfWork, expirationTime); 23339 23340 if (hasCaughtError()) { 23341 var replayError = clearCaughtError(); // `invokeGuardedCallback` sometimes sets an expando `_suppressLogging`. 23342 // Rethrow this error instead of the original one. 23343 23344 throw replayError; 23345 } else { 23346 // This branch is reachable if the render phase is impure. 23347 throw originalError; 23348 } 23349 } 23350 }; 23351 } 23352 23353 var didWarnAboutUpdateInRender = false; 23354 var didWarnAboutUpdateInRenderForAnotherComponent; 23355 23356 { 23357 didWarnAboutUpdateInRenderForAnotherComponent = new Set(); 23358 } 23359 23360 function warnAboutRenderPhaseUpdatesInDEV(fiber) { 23361 { 23362 if (isRendering && (executionContext & RenderContext) !== NoContext) { 23363 switch (fiber.tag) { 23364 case FunctionComponent: 23365 case ForwardRef: 23366 case SimpleMemoComponent: 23367 { 23368 var renderingComponentName = workInProgress && getComponentName(workInProgress.type) || 'Unknown'; // Dedupe by the rendering component because it's the one that needs to be fixed. 23369 23370 var dedupeKey = renderingComponentName; 23371 23372 if (!didWarnAboutUpdateInRenderForAnotherComponent.has(dedupeKey)) { 23373 didWarnAboutUpdateInRenderForAnotherComponent.add(dedupeKey); 23374 var setStateComponentName = getComponentName(fiber.type) || 'Unknown'; 23375 23376 error('Cannot update a component (`%s`) while rendering a ' + 'different component (`%s`). To locate the bad setState() call inside `%s`, ' + 'follow the stack trace as described in https://fb.me/setstate-in-render', setStateComponentName, renderingComponentName, renderingComponentName); 23377 } 23378 23379 break; 23380 } 23381 23382 case ClassComponent: 23383 { 23384 if (!didWarnAboutUpdateInRender) { 23385 error('Cannot update during an existing state transition (such as ' + 'within `render`). Render methods should be a pure ' + 'function of props and state.'); 23386 23387 didWarnAboutUpdateInRender = true; 23388 } 23389 23390 break; 23391 } 23392 } 23393 } 23394 } 23395 } // a 'shared' variable that changes when act() opens/closes in tests. 23396 23397 23398 var IsThisRendererActing = { 23399 current: false 23400 }; 23401 function warnIfNotScopedWithMatchingAct(fiber) { 23402 { 23403 if ( IsSomeRendererActing.current === true && IsThisRendererActing.current !== true) { 23404 error("It looks like you're using the wrong act() around your test interactions.\n" + 'Be sure to use the matching version of act() corresponding to your renderer:\n\n' + '// for react-dom:\n' + "import {act} from 'react-dom/test-utils';\n" + '// ...\n' + 'act(() => ...);\n\n' + '// for react-test-renderer:\n' + "import TestRenderer from 'react-test-renderer';\n" + 'const {act} = TestRenderer;\n' + '// ...\n' + 'act(() => ...);' + '%s', getStackByFiberInDevAndProd(fiber)); 23405 } 23406 } 23407 } 23408 function warnIfNotCurrentlyActingEffectsInDEV(fiber) { 23409 { 23410 if ( (fiber.mode & StrictMode) !== NoMode && IsSomeRendererActing.current === false && IsThisRendererActing.current === false) { 23411 error('An update to %s ran an effect, but was not wrapped in act(...).\n\n' + 'When testing, code that causes React state updates should be ' + 'wrapped into act(...):\n\n' + 'act(() => {\n' + ' /* fire events that update state */\n' + '});\n' + '/* assert on the output */\n\n' + "This ensures that you're testing the behavior the user would see " + 'in the browser.' + ' Learn more at https://fb.me/react-wrap-tests-with-act' + '%s', getComponentName(fiber.type), getStackByFiberInDevAndProd(fiber)); 23412 } 23413 } 23414 } 23415 23416 function warnIfNotCurrentlyActingUpdatesInDEV(fiber) { 23417 { 23418 if ( executionContext === NoContext && IsSomeRendererActing.current === false && IsThisRendererActing.current === false) { 23419 error('An update to %s inside a test was not wrapped in act(...).\n\n' + 'When testing, code that causes React state updates should be ' + 'wrapped into act(...):\n\n' + 'act(() => {\n' + ' /* fire events that update state */\n' + '});\n' + '/* assert on the output */\n\n' + "This ensures that you're testing the behavior the user would see " + 'in the browser.' + ' Learn more at https://fb.me/react-wrap-tests-with-act' + '%s', getComponentName(fiber.type), getStackByFiberInDevAndProd(fiber)); 23420 } 23421 } 23422 } 23423 23424 var warnIfNotCurrentlyActingUpdatesInDev = warnIfNotCurrentlyActingUpdatesInDEV; // In tests, we want to enforce a mocked scheduler. 23425 23426 var didWarnAboutUnmockedScheduler = false; // TODO Before we release concurrent mode, revisit this and decide whether a mocked 23427 // scheduler is the actual recommendation. The alternative could be a testing build, 23428 // a new lib, or whatever; we dunno just yet. This message is for early adopters 23429 // to get their tests right. 23430 23431 function warnIfUnmockedScheduler(fiber) { 23432 { 23433 if (didWarnAboutUnmockedScheduler === false && unstable_flushAllWithoutAsserting === undefined) { 23434 if (fiber.mode & BlockingMode || fiber.mode & ConcurrentMode) { 23435 didWarnAboutUnmockedScheduler = true; 23436 23437 error('In Concurrent or Sync modes, the "scheduler" module needs to be mocked ' + 'to guarantee consistent behaviour across tests and browsers. ' + 'For example, with jest: \n' + "jest.mock('scheduler', () => require('scheduler/unstable_mock'));\n\n" + 'For more info, visit https://fb.me/react-mock-scheduler'); 23438 } 23439 } 23440 } 23441 } 23442 23443 function computeThreadID(root, expirationTime) { 23444 // Interaction threads are unique per root and expiration time. 23445 return expirationTime * 1000 + root.interactionThreadID; 23446 } 23447 23448 function markSpawnedWork(expirationTime) { 23449 23450 if (spawnedWorkDuringRender === null) { 23451 spawnedWorkDuringRender = [expirationTime]; 23452 } else { 23453 spawnedWorkDuringRender.push(expirationTime); 23454 } 23455 } 23456 23457 function scheduleInteractions(root, expirationTime, interactions) { 23458 23459 if (interactions.size > 0) { 23460 var pendingInteractionMap = root.pendingInteractionMap; 23461 var pendingInteractions = pendingInteractionMap.get(expirationTime); 23462 23463 if (pendingInteractions != null) { 23464 interactions.forEach(function (interaction) { 23465 if (!pendingInteractions.has(interaction)) { 23466 // Update the pending async work count for previously unscheduled interaction. 23467 interaction.__count++; 23468 } 23469 23470 pendingInteractions.add(interaction); 23471 }); 23472 } else { 23473 pendingInteractionMap.set(expirationTime, new Set(interactions)); // Update the pending async work count for the current interactions. 23474 23475 interactions.forEach(function (interaction) { 23476 interaction.__count++; 23477 }); 23478 } 23479 23480 var subscriber = __subscriberRef.current; 23481 23482 if (subscriber !== null) { 23483 var threadID = computeThreadID(root, expirationTime); 23484 subscriber.onWorkScheduled(interactions, threadID); 23485 } 23486 } 23487 } 23488 23489 function schedulePendingInteractions(root, expirationTime) { 23490 23491 scheduleInteractions(root, expirationTime, __interactionsRef.current); 23492 } 23493 23494 function startWorkOnPendingInteractions(root, expirationTime) { 23495 // we can accurately attribute time spent working on it, And so that cascading 23496 // work triggered during the render phase will be associated with it. 23497 23498 23499 var interactions = new Set(); 23500 root.pendingInteractionMap.forEach(function (scheduledInteractions, scheduledExpirationTime) { 23501 if (scheduledExpirationTime >= expirationTime) { 23502 scheduledInteractions.forEach(function (interaction) { 23503 return interactions.add(interaction); 23504 }); 23505 } 23506 }); // Store the current set of interactions on the FiberRoot for a few reasons: 23507 // We can re-use it in hot functions like performConcurrentWorkOnRoot() 23508 // without having to recalculate it. We will also use it in commitWork() to 23509 // pass to any Profiler onRender() hooks. This also provides DevTools with a 23510 // way to access it when the onCommitRoot() hook is called. 23511 23512 root.memoizedInteractions = interactions; 23513 23514 if (interactions.size > 0) { 23515 var subscriber = __subscriberRef.current; 23516 23517 if (subscriber !== null) { 23518 var threadID = computeThreadID(root, expirationTime); 23519 23520 try { 23521 subscriber.onWorkStarted(interactions, threadID); 23522 } catch (error) { 23523 // If the subscriber throws, rethrow it in a separate task 23524 scheduleCallback(ImmediatePriority, function () { 23525 throw error; 23526 }); 23527 } 23528 } 23529 } 23530 } 23531 23532 function finishPendingInteractions(root, committedExpirationTime) { 23533 23534 var earliestRemainingTimeAfterCommit = root.firstPendingTime; 23535 var subscriber; 23536 23537 try { 23538 subscriber = __subscriberRef.current; 23539 23540 if (subscriber !== null && root.memoizedInteractions.size > 0) { 23541 var threadID = computeThreadID(root, committedExpirationTime); 23542 subscriber.onWorkStopped(root.memoizedInteractions, threadID); 23543 } 23544 } catch (error) { 23545 // If the subscriber throws, rethrow it in a separate task 23546 scheduleCallback(ImmediatePriority, function () { 23547 throw error; 23548 }); 23549 } finally { 23550 // Clear completed interactions from the pending Map. 23551 // Unless the render was suspended or cascading work was scheduled, 23552 // In which case– leave pending interactions until the subsequent render. 23553 var pendingInteractionMap = root.pendingInteractionMap; 23554 pendingInteractionMap.forEach(function (scheduledInteractions, scheduledExpirationTime) { 23555 // Only decrement the pending interaction count if we're done. 23556 // If there's still work at the current priority, 23557 // That indicates that we are waiting for suspense data. 23558 if (scheduledExpirationTime > earliestRemainingTimeAfterCommit) { 23559 pendingInteractionMap.delete(scheduledExpirationTime); 23560 scheduledInteractions.forEach(function (interaction) { 23561 interaction.__count--; 23562 23563 if (subscriber !== null && interaction.__count === 0) { 23564 try { 23565 subscriber.onInteractionScheduledWorkCompleted(interaction); 23566 } catch (error) { 23567 // If the subscriber throws, rethrow it in a separate task 23568 scheduleCallback(ImmediatePriority, function () { 23569 throw error; 23570 }); 23571 } 23572 } 23573 }); 23574 } 23575 }); 23576 } 23577 } 23578 23579 var onScheduleFiberRoot = null; 23580 var onCommitFiberRoot = null; 23581 var onCommitFiberUnmount = null; 23582 var hasLoggedError = false; 23583 var isDevToolsPresent = typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ !== 'undefined'; 23584 function injectInternals(internals) { 23585 if (typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ === 'undefined') { 23586 // No DevTools 23587 return false; 23588 } 23589 23590 var hook = __REACT_DEVTOOLS_GLOBAL_HOOK__; 23591 23592 if (hook.isDisabled) { 23593 // This isn't a real property on the hook, but it can be set to opt out 23594 // of DevTools integration and associated warnings and logs. 23595 // https://github.com/facebook/react/issues/3877 23596 return true; 23597 } 23598 23599 if (!hook.supportsFiber) { 23600 { 23601 error('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'); 23602 } // DevTools exists, even though it doesn't support Fiber. 23603 23604 23605 return true; 23606 } 23607 23608 try { 23609 var rendererID = hook.inject(internals); // We have successfully injected, so now it is safe to set up hooks. 23610 23611 if (true) { 23612 // Only used by Fast Refresh 23613 if (typeof hook.onScheduleFiberRoot === 'function') { 23614 onScheduleFiberRoot = function (root, children) { 23615 try { 23616 hook.onScheduleFiberRoot(rendererID, root, children); 23617 } catch (err) { 23618 if (true && !hasLoggedError) { 23619 hasLoggedError = true; 23620 23621 error('React instrumentation encountered an error: %s', err); 23622 } 23623 } 23624 }; 23625 } 23626 } 23627 23628 onCommitFiberRoot = function (root, expirationTime) { 23629 try { 23630 var didError = (root.current.effectTag & DidCapture) === DidCapture; 23631 23632 if (enableProfilerTimer) { 23633 var currentTime = getCurrentTime(); 23634 var priorityLevel = inferPriorityFromExpirationTime(currentTime, expirationTime); 23635 hook.onCommitFiberRoot(rendererID, root, priorityLevel, didError); 23636 } else { 23637 hook.onCommitFiberRoot(rendererID, root, undefined, didError); 23638 } 23639 } catch (err) { 23640 if (true) { 23641 if (!hasLoggedError) { 23642 hasLoggedError = true; 23643 23644 error('React instrumentation encountered an error: %s', err); 23645 } 23646 } 23647 } 23648 }; 23649 23650 onCommitFiberUnmount = function (fiber) { 23651 try { 23652 hook.onCommitFiberUnmount(rendererID, fiber); 23653 } catch (err) { 23654 if (true) { 23655 if (!hasLoggedError) { 23656 hasLoggedError = true; 23657 23658 error('React instrumentation encountered an error: %s', err); 23659 } 23660 } 23661 } 23662 }; 23663 } catch (err) { 23664 // Catch all errors because it is unsafe to throw during initialization. 23665 { 23666 error('React instrumentation encountered an error: %s.', err); 23667 } 23668 } // DevTools exists 23669 23670 23671 return true; 23672 } 23673 function onScheduleRoot(root, children) { 23674 if (typeof onScheduleFiberRoot === 'function') { 23675 onScheduleFiberRoot(root, children); 23676 } 23677 } 23678 function onCommitRoot(root, expirationTime) { 23679 if (typeof onCommitFiberRoot === 'function') { 23680 onCommitFiberRoot(root, expirationTime); 23681 } 23682 } 23683 function onCommitUnmount(fiber) { 23684 if (typeof onCommitFiberUnmount === 'function') { 23685 onCommitFiberUnmount(fiber); 23686 } 23687 } 23688 23689 var hasBadMapPolyfill; 23690 23691 { 23692 hasBadMapPolyfill = false; 23693 23694 try { 23695 var nonExtensibleObject = Object.preventExtensions({}); 23696 var testMap = new Map([[nonExtensibleObject, null]]); 23697 var testSet = new Set([nonExtensibleObject]); // This is necessary for Rollup to not consider these unused. 23698 // https://github.com/rollup/rollup/issues/1771 23699 // TODO: we can remove these if Rollup fixes the bug. 23700 23701 testMap.set(0, 0); 23702 testSet.add(0); 23703 } catch (e) { 23704 // TODO: Consider warning about bad polyfills 23705 hasBadMapPolyfill = true; 23706 } 23707 } 23708 23709 var debugCounter = 1; 23710 23711 function FiberNode(tag, pendingProps, key, mode) { 23712 // Instance 23713 this.tag = tag; 23714 this.key = key; 23715 this.elementType = null; 23716 this.type = null; 23717 this.stateNode = null; // Fiber 23718 23719 this.return = null; 23720 this.child = null; 23721 this.sibling = null; 23722 this.index = 0; 23723 this.ref = null; 23724 this.pendingProps = pendingProps; 23725 this.memoizedProps = null; 23726 this.updateQueue = null; 23727 this.memoizedState = null; 23728 this.dependencies = null; 23729 this.mode = mode; // Effects 23730 23731 this.effectTag = NoEffect; 23732 this.nextEffect = null; 23733 this.firstEffect = null; 23734 this.lastEffect = null; 23735 this.expirationTime = NoWork; 23736 this.childExpirationTime = NoWork; 23737 this.alternate = null; 23738 23739 { 23740 // Note: The following is done to avoid a v8 performance cliff. 23741 // 23742 // Initializing the fields below to smis and later updating them with 23743 // double values will cause Fibers to end up having separate shapes. 23744 // This behavior/bug has something to do with Object.preventExtension(). 23745 // Fortunately this only impacts DEV builds. 23746 // Unfortunately it makes React unusably slow for some applications. 23747 // To work around this, initialize the fields below with doubles. 23748 // 23749 // Learn more about this here: 23750 // https://github.com/facebook/react/issues/14365 23751 // https://bugs.chromium.org/p/v8/issues/detail?id=8538 23752 this.actualDuration = Number.NaN; 23753 this.actualStartTime = Number.NaN; 23754 this.selfBaseDuration = Number.NaN; 23755 this.treeBaseDuration = Number.NaN; // It's okay to replace the initial doubles with smis after initialization. 23756 // This won't trigger the performance cliff mentioned above, 23757 // and it simplifies other profiler code (including DevTools). 23758 23759 this.actualDuration = 0; 23760 this.actualStartTime = -1; 23761 this.selfBaseDuration = 0; 23762 this.treeBaseDuration = 0; 23763 } // This is normally DEV-only except www when it adds listeners. 23764 // TODO: remove the User Timing integration in favor of Root Events. 23765 23766 23767 { 23768 this._debugID = debugCounter++; 23769 this._debugIsCurrentlyTiming = false; 23770 } 23771 23772 { 23773 this._debugSource = null; 23774 this._debugOwner = null; 23775 this._debugNeedsRemount = false; 23776 this._debugHookTypes = null; 23777 23778 if (!hasBadMapPolyfill && typeof Object.preventExtensions === 'function') { 23779 Object.preventExtensions(this); 23780 } 23781 } 23782 } // This is a constructor function, rather than a POJO constructor, still 23783 // please ensure we do the following: 23784 // 1) Nobody should add any instance methods on this. Instance methods can be 23785 // more difficult to predict when they get optimized and they are almost 23786 // never inlined properly in static compilers. 23787 // 2) Nobody should rely on `instanceof Fiber` for type testing. We should 23788 // always know when it is a fiber. 23789 // 3) We might want to experiment with using numeric keys since they are easier 23790 // to optimize in a non-JIT environment. 23791 // 4) We can easily go from a constructor to a createFiber object literal if that 23792 // is faster. 23793 // 5) It should be easy to port this to a C struct and keep a C implementation 23794 // compatible. 23795 23796 23797 var createFiber = function (tag, pendingProps, key, mode) { 23798 // $FlowFixMe: the shapes are exact here but Flow doesn't like constructors 23799 return new FiberNode(tag, pendingProps, key, mode); 23800 }; 23801 23802 function shouldConstruct(Component) { 23803 var prototype = Component.prototype; 23804 return !!(prototype && prototype.isReactComponent); 23805 } 23806 23807 function isSimpleFunctionComponent(type) { 23808 return typeof type === 'function' && !shouldConstruct(type) && type.defaultProps === undefined; 23809 } 23810 function resolveLazyComponentTag(Component) { 23811 if (typeof Component === 'function') { 23812 return shouldConstruct(Component) ? ClassComponent : FunctionComponent; 23813 } else if (Component !== undefined && Component !== null) { 23814 var $$typeof = Component.$$typeof; 23815 23816 if ($$typeof === REACT_FORWARD_REF_TYPE) { 23817 return ForwardRef; 23818 } 23819 23820 if ($$typeof === REACT_MEMO_TYPE) { 23821 return MemoComponent; 23822 } 23823 } 23824 23825 return IndeterminateComponent; 23826 } // This is used to create an alternate fiber to do work on. 23827 23828 function createWorkInProgress(current, pendingProps) { 23829 var workInProgress = current.alternate; 23830 23831 if (workInProgress === null) { 23832 // We use a double buffering pooling technique because we know that we'll 23833 // only ever need at most two versions of a tree. We pool the "other" unused 23834 // node that we're free to reuse. This is lazily created to avoid allocating 23835 // extra objects for things that are never updated. It also allow us to 23836 // reclaim the extra memory if needed. 23837 workInProgress = createFiber(current.tag, pendingProps, current.key, current.mode); 23838 workInProgress.elementType = current.elementType; 23839 workInProgress.type = current.type; 23840 workInProgress.stateNode = current.stateNode; 23841 23842 { 23843 // DEV-only fields 23844 { 23845 workInProgress._debugID = current._debugID; 23846 } 23847 23848 workInProgress._debugSource = current._debugSource; 23849 workInProgress._debugOwner = current._debugOwner; 23850 workInProgress._debugHookTypes = current._debugHookTypes; 23851 } 23852 23853 workInProgress.alternate = current; 23854 current.alternate = workInProgress; 23855 } else { 23856 workInProgress.pendingProps = pendingProps; // We already have an alternate. 23857 // Reset the effect tag. 23858 23859 workInProgress.effectTag = NoEffect; // The effect list is no longer valid. 23860 23861 workInProgress.nextEffect = null; 23862 workInProgress.firstEffect = null; 23863 workInProgress.lastEffect = null; 23864 23865 { 23866 // We intentionally reset, rather than copy, actualDuration & actualStartTime. 23867 // This prevents time from endlessly accumulating in new commits. 23868 // This has the downside of resetting values for different priority renders, 23869 // But works for yielding (the common case) and should support resuming. 23870 workInProgress.actualDuration = 0; 23871 workInProgress.actualStartTime = -1; 23872 } 23873 } 23874 23875 workInProgress.childExpirationTime = current.childExpirationTime; 23876 workInProgress.expirationTime = current.expirationTime; 23877 workInProgress.child = current.child; 23878 workInProgress.memoizedProps = current.memoizedProps; 23879 workInProgress.memoizedState = current.memoizedState; 23880 workInProgress.updateQueue = current.updateQueue; // Clone the dependencies object. This is mutated during the render phase, so 23881 // it cannot be shared with the current fiber. 23882 23883 var currentDependencies = current.dependencies; 23884 workInProgress.dependencies = currentDependencies === null ? null : { 23885 expirationTime: currentDependencies.expirationTime, 23886 firstContext: currentDependencies.firstContext, 23887 responders: currentDependencies.responders 23888 }; // These will be overridden during the parent's reconciliation 23889 23890 workInProgress.sibling = current.sibling; 23891 workInProgress.index = current.index; 23892 workInProgress.ref = current.ref; 23893 23894 { 23895 workInProgress.selfBaseDuration = current.selfBaseDuration; 23896 workInProgress.treeBaseDuration = current.treeBaseDuration; 23897 } 23898 23899 { 23900 workInProgress._debugNeedsRemount = current._debugNeedsRemount; 23901 23902 switch (workInProgress.tag) { 23903 case IndeterminateComponent: 23904 case FunctionComponent: 23905 case SimpleMemoComponent: 23906 workInProgress.type = resolveFunctionForHotReloading(current.type); 23907 break; 23908 23909 case ClassComponent: 23910 workInProgress.type = resolveClassForHotReloading(current.type); 23911 break; 23912 23913 case ForwardRef: 23914 workInProgress.type = resolveForwardRefForHotReloading(current.type); 23915 break; 23916 } 23917 } 23918 23919 return workInProgress; 23920 } // Used to reuse a Fiber for a second pass. 23921 23922 function resetWorkInProgress(workInProgress, renderExpirationTime) { 23923 // This resets the Fiber to what createFiber or createWorkInProgress would 23924 // have set the values to before during the first pass. Ideally this wouldn't 23925 // be necessary but unfortunately many code paths reads from the workInProgress 23926 // when they should be reading from current and writing to workInProgress. 23927 // We assume pendingProps, index, key, ref, return are still untouched to 23928 // avoid doing another reconciliation. 23929 // Reset the effect tag but keep any Placement tags, since that's something 23930 // that child fiber is setting, not the reconciliation. 23931 workInProgress.effectTag &= Placement; // The effect list is no longer valid. 23932 23933 workInProgress.nextEffect = null; 23934 workInProgress.firstEffect = null; 23935 workInProgress.lastEffect = null; 23936 var current = workInProgress.alternate; 23937 23938 if (current === null) { 23939 // Reset to createFiber's initial values. 23940 workInProgress.childExpirationTime = NoWork; 23941 workInProgress.expirationTime = renderExpirationTime; 23942 workInProgress.child = null; 23943 workInProgress.memoizedProps = null; 23944 workInProgress.memoizedState = null; 23945 workInProgress.updateQueue = null; 23946 workInProgress.dependencies = null; 23947 23948 { 23949 // Note: We don't reset the actualTime counts. It's useful to accumulate 23950 // actual time across multiple render passes. 23951 workInProgress.selfBaseDuration = 0; 23952 workInProgress.treeBaseDuration = 0; 23953 } 23954 } else { 23955 // Reset to the cloned values that createWorkInProgress would've. 23956 workInProgress.childExpirationTime = current.childExpirationTime; 23957 workInProgress.expirationTime = current.expirationTime; 23958 workInProgress.child = current.child; 23959 workInProgress.memoizedProps = current.memoizedProps; 23960 workInProgress.memoizedState = current.memoizedState; 23961 workInProgress.updateQueue = current.updateQueue; // Clone the dependencies object. This is mutated during the render phase, so 23962 // it cannot be shared with the current fiber. 23963 23964 var currentDependencies = current.dependencies; 23965 workInProgress.dependencies = currentDependencies === null ? null : { 23966 expirationTime: currentDependencies.expirationTime, 23967 firstContext: currentDependencies.firstContext, 23968 responders: currentDependencies.responders 23969 }; 23970 23971 { 23972 // Note: We don't reset the actualTime counts. It's useful to accumulate 23973 // actual time across multiple render passes. 23974 workInProgress.selfBaseDuration = current.selfBaseDuration; 23975 workInProgress.treeBaseDuration = current.treeBaseDuration; 23976 } 23977 } 23978 23979 return workInProgress; 23980 } 23981 function createHostRootFiber(tag) { 23982 var mode; 23983 23984 if (tag === ConcurrentRoot) { 23985 mode = ConcurrentMode | BlockingMode | StrictMode; 23986 } else if (tag === BlockingRoot) { 23987 mode = BlockingMode | StrictMode; 23988 } else { 23989 mode = NoMode; 23990 } 23991 23992 if ( isDevToolsPresent) { 23993 // Always collect profile timings when DevTools are present. 23994 // This enables DevTools to start capturing timing at any point– 23995 // Without some nodes in the tree having empty base times. 23996 mode |= ProfileMode; 23997 } 23998 23999 return createFiber(HostRoot, null, null, mode); 24000 } 24001 function createFiberFromTypeAndProps(type, // React$ElementType 24002 key, pendingProps, owner, mode, expirationTime) { 24003 var fiber; 24004 var fiberTag = IndeterminateComponent; // The resolved type is set if we know what the final type will be. I.e. it's not lazy. 24005 24006 var resolvedType = type; 24007 24008 if (typeof type === 'function') { 24009 if (shouldConstruct(type)) { 24010 fiberTag = ClassComponent; 24011 24012 { 24013 resolvedType = resolveClassForHotReloading(resolvedType); 24014 } 24015 } else { 24016 { 24017 resolvedType = resolveFunctionForHotReloading(resolvedType); 24018 } 24019 } 24020 } else if (typeof type === 'string') { 24021 fiberTag = HostComponent; 24022 } else { 24023 getTag: switch (type) { 24024 case REACT_FRAGMENT_TYPE: 24025 return createFiberFromFragment(pendingProps.children, mode, expirationTime, key); 24026 24027 case REACT_CONCURRENT_MODE_TYPE: 24028 fiberTag = Mode; 24029 mode |= ConcurrentMode | BlockingMode | StrictMode; 24030 break; 24031 24032 case REACT_STRICT_MODE_TYPE: 24033 fiberTag = Mode; 24034 mode |= StrictMode; 24035 break; 24036 24037 case REACT_PROFILER_TYPE: 24038 return createFiberFromProfiler(pendingProps, mode, expirationTime, key); 24039 24040 case REACT_SUSPENSE_TYPE: 24041 return createFiberFromSuspense(pendingProps, mode, expirationTime, key); 24042 24043 case REACT_SUSPENSE_LIST_TYPE: 24044 return createFiberFromSuspenseList(pendingProps, mode, expirationTime, key); 24045 24046 default: 24047 { 24048 if (typeof type === 'object' && type !== null) { 24049 switch (type.$$typeof) { 24050 case REACT_PROVIDER_TYPE: 24051 fiberTag = ContextProvider; 24052 break getTag; 24053 24054 case REACT_CONTEXT_TYPE: 24055 // This is a consumer 24056 fiberTag = ContextConsumer; 24057 break getTag; 24058 24059 case REACT_FORWARD_REF_TYPE: 24060 fiberTag = ForwardRef; 24061 24062 { 24063 resolvedType = resolveForwardRefForHotReloading(resolvedType); 24064 } 24065 24066 break getTag; 24067 24068 case REACT_MEMO_TYPE: 24069 fiberTag = MemoComponent; 24070 break getTag; 24071 24072 case REACT_LAZY_TYPE: 24073 fiberTag = LazyComponent; 24074 resolvedType = null; 24075 break getTag; 24076 24077 case REACT_BLOCK_TYPE: 24078 fiberTag = Block; 24079 break getTag; 24080 24081 } 24082 } 24083 24084 var info = ''; 24085 24086 { 24087 if (type === undefined || typeof type === 'object' && type !== null && Object.keys(type).length === 0) { 24088 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.'; 24089 } 24090 24091 var ownerName = owner ? getComponentName(owner.type) : null; 24092 24093 if (ownerName) { 24094 info += '\n\nCheck the render method of `' + ownerName + '`.'; 24095 } 24096 } 24097 24098 { 24099 { 24100 throw Error( "Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: " + (type == null ? type : typeof type) + "." + info ); 24101 } 24102 } 24103 } 24104 } 24105 } 24106 24107 fiber = createFiber(fiberTag, pendingProps, key, mode); 24108 fiber.elementType = type; 24109 fiber.type = resolvedType; 24110 fiber.expirationTime = expirationTime; 24111 return fiber; 24112 } 24113 function createFiberFromElement(element, mode, expirationTime) { 24114 var owner = null; 24115 24116 { 24117 owner = element._owner; 24118 } 24119 24120 var type = element.type; 24121 var key = element.key; 24122 var pendingProps = element.props; 24123 var fiber = createFiberFromTypeAndProps(type, key, pendingProps, owner, mode, expirationTime); 24124 24125 { 24126 fiber._debugSource = element._source; 24127 fiber._debugOwner = element._owner; 24128 } 24129 24130 return fiber; 24131 } 24132 function createFiberFromFragment(elements, mode, expirationTime, key) { 24133 var fiber = createFiber(Fragment, elements, key, mode); 24134 fiber.expirationTime = expirationTime; 24135 return fiber; 24136 } 24137 24138 function createFiberFromProfiler(pendingProps, mode, expirationTime, key) { 24139 { 24140 if (typeof pendingProps.id !== 'string' || typeof pendingProps.onRender !== 'function') { 24141 error('Profiler must specify an "id" string and "onRender" function as props'); 24142 } 24143 } 24144 24145 var fiber = createFiber(Profiler, pendingProps, key, mode | ProfileMode); // TODO: The Profiler fiber shouldn't have a type. It has a tag. 24146 24147 fiber.elementType = REACT_PROFILER_TYPE; 24148 fiber.type = REACT_PROFILER_TYPE; 24149 fiber.expirationTime = expirationTime; 24150 return fiber; 24151 } 24152 24153 function createFiberFromSuspense(pendingProps, mode, expirationTime, key) { 24154 var fiber = createFiber(SuspenseComponent, pendingProps, key, mode); // TODO: The SuspenseComponent fiber shouldn't have a type. It has a tag. 24155 // This needs to be fixed in getComponentName so that it relies on the tag 24156 // instead. 24157 24158 fiber.type = REACT_SUSPENSE_TYPE; 24159 fiber.elementType = REACT_SUSPENSE_TYPE; 24160 fiber.expirationTime = expirationTime; 24161 return fiber; 24162 } 24163 function createFiberFromSuspenseList(pendingProps, mode, expirationTime, key) { 24164 var fiber = createFiber(SuspenseListComponent, pendingProps, key, mode); 24165 24166 { 24167 // TODO: The SuspenseListComponent fiber shouldn't have a type. It has a tag. 24168 // This needs to be fixed in getComponentName so that it relies on the tag 24169 // instead. 24170 fiber.type = REACT_SUSPENSE_LIST_TYPE; 24171 } 24172 24173 fiber.elementType = REACT_SUSPENSE_LIST_TYPE; 24174 fiber.expirationTime = expirationTime; 24175 return fiber; 24176 } 24177 function createFiberFromText(content, mode, expirationTime) { 24178 var fiber = createFiber(HostText, content, null, mode); 24179 fiber.expirationTime = expirationTime; 24180 return fiber; 24181 } 24182 function createFiberFromHostInstanceForDeletion() { 24183 var fiber = createFiber(HostComponent, null, null, NoMode); // TODO: These should not need a type. 24184 24185 fiber.elementType = 'DELETED'; 24186 fiber.type = 'DELETED'; 24187 return fiber; 24188 } 24189 function createFiberFromPortal(portal, mode, expirationTime) { 24190 var pendingProps = portal.children !== null ? portal.children : []; 24191 var fiber = createFiber(HostPortal, pendingProps, portal.key, mode); 24192 fiber.expirationTime = expirationTime; 24193 fiber.stateNode = { 24194 containerInfo: portal.containerInfo, 24195 pendingChildren: null, 24196 // Used by persistent updates 24197 implementation: portal.implementation 24198 }; 24199 return fiber; 24200 } // Used for stashing WIP properties to replay failed work in DEV. 24201 24202 function assignFiberPropertiesInDEV(target, source) { 24203 if (target === null) { 24204 // This Fiber's initial properties will always be overwritten. 24205 // We only use a Fiber to ensure the same hidden class so DEV isn't slow. 24206 target = createFiber(IndeterminateComponent, null, null, NoMode); 24207 } // This is intentionally written as a list of all properties. 24208 // We tried to use Object.assign() instead but this is called in 24209 // the hottest path, and Object.assign() was too slow: 24210 // https://github.com/facebook/react/issues/12502 24211 // This code is DEV-only so size is not a concern. 24212 24213 24214 target.tag = source.tag; 24215 target.key = source.key; 24216 target.elementType = source.elementType; 24217 target.type = source.type; 24218 target.stateNode = source.stateNode; 24219 target.return = source.return; 24220 target.child = source.child; 24221 target.sibling = source.sibling; 24222 target.index = source.index; 24223 target.ref = source.ref; 24224 target.pendingProps = source.pendingProps; 24225 target.memoizedProps = source.memoizedProps; 24226 target.updateQueue = source.updateQueue; 24227 target.memoizedState = source.memoizedState; 24228 target.dependencies = source.dependencies; 24229 target.mode = source.mode; 24230 target.effectTag = source.effectTag; 24231 target.nextEffect = source.nextEffect; 24232 target.firstEffect = source.firstEffect; 24233 target.lastEffect = source.lastEffect; 24234 target.expirationTime = source.expirationTime; 24235 target.childExpirationTime = source.childExpirationTime; 24236 target.alternate = source.alternate; 24237 24238 { 24239 target.actualDuration = source.actualDuration; 24240 target.actualStartTime = source.actualStartTime; 24241 target.selfBaseDuration = source.selfBaseDuration; 24242 target.treeBaseDuration = source.treeBaseDuration; 24243 } 24244 24245 { 24246 target._debugID = source._debugID; 24247 } 24248 24249 target._debugSource = source._debugSource; 24250 target._debugOwner = source._debugOwner; 24251 target._debugIsCurrentlyTiming = source._debugIsCurrentlyTiming; 24252 target._debugNeedsRemount = source._debugNeedsRemount; 24253 target._debugHookTypes = source._debugHookTypes; 24254 return target; 24255 } 24256 24257 function FiberRootNode(containerInfo, tag, hydrate) { 24258 this.tag = tag; 24259 this.current = null; 24260 this.containerInfo = containerInfo; 24261 this.pendingChildren = null; 24262 this.pingCache = null; 24263 this.finishedExpirationTime = NoWork; 24264 this.finishedWork = null; 24265 this.timeoutHandle = noTimeout; 24266 this.context = null; 24267 this.pendingContext = null; 24268 this.hydrate = hydrate; 24269 this.callbackNode = null; 24270 this.callbackPriority = NoPriority; 24271 this.firstPendingTime = NoWork; 24272 this.firstSuspendedTime = NoWork; 24273 this.lastSuspendedTime = NoWork; 24274 this.nextKnownPendingLevel = NoWork; 24275 this.lastPingedTime = NoWork; 24276 this.lastExpiredTime = NoWork; 24277 24278 { 24279 this.interactionThreadID = unstable_getThreadID(); 24280 this.memoizedInteractions = new Set(); 24281 this.pendingInteractionMap = new Map(); 24282 } 24283 } 24284 24285 function createFiberRoot(containerInfo, tag, hydrate, hydrationCallbacks) { 24286 var root = new FiberRootNode(containerInfo, tag, hydrate); 24287 // stateNode is any. 24288 24289 24290 var uninitializedFiber = createHostRootFiber(tag); 24291 root.current = uninitializedFiber; 24292 uninitializedFiber.stateNode = root; 24293 initializeUpdateQueue(uninitializedFiber); 24294 return root; 24295 } 24296 function isRootSuspendedAtTime(root, expirationTime) { 24297 var firstSuspendedTime = root.firstSuspendedTime; 24298 var lastSuspendedTime = root.lastSuspendedTime; 24299 return firstSuspendedTime !== NoWork && firstSuspendedTime >= expirationTime && lastSuspendedTime <= expirationTime; 24300 } 24301 function markRootSuspendedAtTime(root, expirationTime) { 24302 var firstSuspendedTime = root.firstSuspendedTime; 24303 var lastSuspendedTime = root.lastSuspendedTime; 24304 24305 if (firstSuspendedTime < expirationTime) { 24306 root.firstSuspendedTime = expirationTime; 24307 } 24308 24309 if (lastSuspendedTime > expirationTime || firstSuspendedTime === NoWork) { 24310 root.lastSuspendedTime = expirationTime; 24311 } 24312 24313 if (expirationTime <= root.lastPingedTime) { 24314 root.lastPingedTime = NoWork; 24315 } 24316 24317 if (expirationTime <= root.lastExpiredTime) { 24318 root.lastExpiredTime = NoWork; 24319 } 24320 } 24321 function markRootUpdatedAtTime(root, expirationTime) { 24322 // Update the range of pending times 24323 var firstPendingTime = root.firstPendingTime; 24324 24325 if (expirationTime > firstPendingTime) { 24326 root.firstPendingTime = expirationTime; 24327 } // Update the range of suspended times. Treat everything lower priority or 24328 // equal to this update as unsuspended. 24329 24330 24331 var firstSuspendedTime = root.firstSuspendedTime; 24332 24333 if (firstSuspendedTime !== NoWork) { 24334 if (expirationTime >= firstSuspendedTime) { 24335 // The entire suspended range is now unsuspended. 24336 root.firstSuspendedTime = root.lastSuspendedTime = root.nextKnownPendingLevel = NoWork; 24337 } else if (expirationTime >= root.lastSuspendedTime) { 24338 root.lastSuspendedTime = expirationTime + 1; 24339 } // This is a pending level. Check if it's higher priority than the next 24340 // known pending level. 24341 24342 24343 if (expirationTime > root.nextKnownPendingLevel) { 24344 root.nextKnownPendingLevel = expirationTime; 24345 } 24346 } 24347 } 24348 function markRootFinishedAtTime(root, finishedExpirationTime, remainingExpirationTime) { 24349 // Update the range of pending times 24350 root.firstPendingTime = remainingExpirationTime; // Update the range of suspended times. Treat everything higher priority or 24351 // equal to this update as unsuspended. 24352 24353 if (finishedExpirationTime <= root.lastSuspendedTime) { 24354 // The entire suspended range is now unsuspended. 24355 root.firstSuspendedTime = root.lastSuspendedTime = root.nextKnownPendingLevel = NoWork; 24356 } else if (finishedExpirationTime <= root.firstSuspendedTime) { 24357 // Part of the suspended range is now unsuspended. Narrow the range to 24358 // include everything between the unsuspended time (non-inclusive) and the 24359 // last suspended time. 24360 root.firstSuspendedTime = finishedExpirationTime - 1; 24361 } 24362 24363 if (finishedExpirationTime <= root.lastPingedTime) { 24364 // Clear the pinged time 24365 root.lastPingedTime = NoWork; 24366 } 24367 24368 if (finishedExpirationTime <= root.lastExpiredTime) { 24369 // Clear the expired time 24370 root.lastExpiredTime = NoWork; 24371 } 24372 } 24373 function markRootExpiredAtTime(root, expirationTime) { 24374 var lastExpiredTime = root.lastExpiredTime; 24375 24376 if (lastExpiredTime === NoWork || lastExpiredTime > expirationTime) { 24377 root.lastExpiredTime = expirationTime; 24378 } 24379 } 24380 24381 var didWarnAboutNestedUpdates; 24382 var didWarnAboutFindNodeInStrictMode; 24383 24384 { 24385 didWarnAboutNestedUpdates = false; 24386 didWarnAboutFindNodeInStrictMode = {}; 24387 } 24388 24389 function getContextForSubtree(parentComponent) { 24390 if (!parentComponent) { 24391 return emptyContextObject; 24392 } 24393 24394 var fiber = get(parentComponent); 24395 var parentContext = findCurrentUnmaskedContext(fiber); 24396 24397 if (fiber.tag === ClassComponent) { 24398 var Component = fiber.type; 24399 24400 if (isContextProvider(Component)) { 24401 return processChildContext(fiber, Component, parentContext); 24402 } 24403 } 24404 24405 return parentContext; 24406 } 24407 24408 function findHostInstanceWithWarning(component, methodName) { 24409 { 24410 var fiber = get(component); 24411 24412 if (fiber === undefined) { 24413 if (typeof component.render === 'function') { 24414 { 24415 { 24416 throw Error( "Unable to find node on an unmounted component." ); 24417 } 24418 } 24419 } else { 24420 { 24421 { 24422 throw Error( "Argument appears to not be a ReactComponent. Keys: " + Object.keys(component) ); 24423 } 24424 } 24425 } 24426 } 24427 24428 var hostFiber = findCurrentHostFiber(fiber); 24429 24430 if (hostFiber === null) { 24431 return null; 24432 } 24433 24434 if (hostFiber.mode & StrictMode) { 24435 var componentName = getComponentName(fiber.type) || 'Component'; 24436 24437 if (!didWarnAboutFindNodeInStrictMode[componentName]) { 24438 didWarnAboutFindNodeInStrictMode[componentName] = true; 24439 24440 if (fiber.mode & StrictMode) { 24441 error('%s is deprecated in StrictMode. ' + '%s was passed an instance of %s which is inside StrictMode. ' + 'Instead, add a ref directly to the element you want to reference. ' + 'Learn more about using refs safely here: ' + 'https://fb.me/react-strict-mode-find-node%s', methodName, methodName, componentName, getStackByFiberInDevAndProd(hostFiber)); 24442 } else { 24443 error('%s is deprecated in StrictMode. ' + '%s was passed an instance of %s which renders StrictMode children. ' + 'Instead, add a ref directly to the element you want to reference. ' + 'Learn more about using refs safely here: ' + 'https://fb.me/react-strict-mode-find-node%s', methodName, methodName, componentName, getStackByFiberInDevAndProd(hostFiber)); 24444 } 24445 } 24446 } 24447 24448 return hostFiber.stateNode; 24449 } 24450 } 24451 24452 function createContainer(containerInfo, tag, hydrate, hydrationCallbacks) { 24453 return createFiberRoot(containerInfo, tag, hydrate); 24454 } 24455 function updateContainer(element, container, parentComponent, callback) { 24456 { 24457 onScheduleRoot(container, element); 24458 } 24459 24460 var current$1 = container.current; 24461 var currentTime = requestCurrentTimeForUpdate(); 24462 24463 { 24464 // $FlowExpectedError - jest isn't a global, and isn't recognized outside of tests 24465 if ('undefined' !== typeof jest) { 24466 warnIfUnmockedScheduler(current$1); 24467 warnIfNotScopedWithMatchingAct(current$1); 24468 } 24469 } 24470 24471 var suspenseConfig = requestCurrentSuspenseConfig(); 24472 var expirationTime = computeExpirationForFiber(currentTime, current$1, suspenseConfig); 24473 var context = getContextForSubtree(parentComponent); 24474 24475 if (container.context === null) { 24476 container.context = context; 24477 } else { 24478 container.pendingContext = context; 24479 } 24480 24481 { 24482 if (isRendering && current !== null && !didWarnAboutNestedUpdates) { 24483 didWarnAboutNestedUpdates = true; 24484 24485 error('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(current.type) || 'Unknown'); 24486 } 24487 } 24488 24489 var update = createUpdate(expirationTime, suspenseConfig); // Caution: React DevTools currently depends on this property 24490 // being called "element". 24491 24492 update.payload = { 24493 element: element 24494 }; 24495 callback = callback === undefined ? null : callback; 24496 24497 if (callback !== null) { 24498 { 24499 if (typeof callback !== 'function') { 24500 error('render(...): Expected the last optional `callback` argument to be a ' + 'function. Instead received: %s.', callback); 24501 } 24502 } 24503 24504 update.callback = callback; 24505 } 24506 24507 enqueueUpdate(current$1, update); 24508 scheduleWork(current$1, expirationTime); 24509 return expirationTime; 24510 } 24511 function getPublicRootInstance(container) { 24512 var containerFiber = container.current; 24513 24514 if (!containerFiber.child) { 24515 return null; 24516 } 24517 24518 switch (containerFiber.child.tag) { 24519 case HostComponent: 24520 return getPublicInstance(containerFiber.child.stateNode); 24521 24522 default: 24523 return containerFiber.child.stateNode; 24524 } 24525 } 24526 24527 function markRetryTimeImpl(fiber, retryTime) { 24528 var suspenseState = fiber.memoizedState; 24529 24530 if (suspenseState !== null && suspenseState.dehydrated !== null) { 24531 if (suspenseState.retryTime < retryTime) { 24532 suspenseState.retryTime = retryTime; 24533 } 24534 } 24535 } // Increases the priority of thennables when they resolve within this boundary. 24536 24537 24538 function markRetryTimeIfNotHydrated(fiber, retryTime) { 24539 markRetryTimeImpl(fiber, retryTime); 24540 var alternate = fiber.alternate; 24541 24542 if (alternate) { 24543 markRetryTimeImpl(alternate, retryTime); 24544 } 24545 } 24546 24547 function attemptUserBlockingHydration$1(fiber) { 24548 if (fiber.tag !== SuspenseComponent) { 24549 // We ignore HostRoots here because we can't increase 24550 // their priority and they should not suspend on I/O, 24551 // since you have to wrap anything that might suspend in 24552 // Suspense. 24553 return; 24554 } 24555 24556 var expTime = computeInteractiveExpiration(requestCurrentTimeForUpdate()); 24557 scheduleWork(fiber, expTime); 24558 markRetryTimeIfNotHydrated(fiber, expTime); 24559 } 24560 function attemptContinuousHydration$1(fiber) { 24561 if (fiber.tag !== SuspenseComponent) { 24562 // We ignore HostRoots here because we can't increase 24563 // their priority and they should not suspend on I/O, 24564 // since you have to wrap anything that might suspend in 24565 // Suspense. 24566 return; 24567 } 24568 24569 scheduleWork(fiber, ContinuousHydration); 24570 markRetryTimeIfNotHydrated(fiber, ContinuousHydration); 24571 } 24572 function attemptHydrationAtCurrentPriority$1(fiber) { 24573 if (fiber.tag !== SuspenseComponent) { 24574 // We ignore HostRoots here because we can't increase 24575 // their priority other than synchronously flush it. 24576 return; 24577 } 24578 24579 var currentTime = requestCurrentTimeForUpdate(); 24580 var expTime = computeExpirationForFiber(currentTime, fiber, null); 24581 scheduleWork(fiber, expTime); 24582 markRetryTimeIfNotHydrated(fiber, expTime); 24583 } 24584 function findHostInstanceWithNoPortals(fiber) { 24585 var hostFiber = findCurrentHostFiberWithNoPortals(fiber); 24586 24587 if (hostFiber === null) { 24588 return null; 24589 } 24590 24591 if (hostFiber.tag === FundamentalComponent) { 24592 return hostFiber.stateNode.instance; 24593 } 24594 24595 return hostFiber.stateNode; 24596 } 24597 24598 var shouldSuspendImpl = function (fiber) { 24599 return false; 24600 }; 24601 24602 function shouldSuspend(fiber) { 24603 return shouldSuspendImpl(fiber); 24604 } 24605 var overrideHookState = null; 24606 var overrideProps = null; 24607 var scheduleUpdate = null; 24608 var setSuspenseHandler = null; 24609 24610 { 24611 var copyWithSetImpl = function (obj, path, idx, value) { 24612 if (idx >= path.length) { 24613 return value; 24614 } 24615 24616 var key = path[idx]; 24617 var updated = Array.isArray(obj) ? obj.slice() : _assign({}, obj); // $FlowFixMe number or string is fine here 24618 24619 updated[key] = copyWithSetImpl(obj[key], path, idx + 1, value); 24620 return updated; 24621 }; 24622 24623 var copyWithSet = function (obj, path, value) { 24624 return copyWithSetImpl(obj, path, 0, value); 24625 }; // Support DevTools editable values for useState and useReducer. 24626 24627 24628 overrideHookState = function (fiber, id, path, value) { 24629 // For now, the "id" of stateful hooks is just the stateful hook index. 24630 // This may change in the future with e.g. nested hooks. 24631 var currentHook = fiber.memoizedState; 24632 24633 while (currentHook !== null && id > 0) { 24634 currentHook = currentHook.next; 24635 id--; 24636 } 24637 24638 if (currentHook !== null) { 24639 var newState = copyWithSet(currentHook.memoizedState, path, value); 24640 currentHook.memoizedState = newState; 24641 currentHook.baseState = newState; // We aren't actually adding an update to the queue, 24642 // because there is no update we can add for useReducer hooks that won't trigger an error. 24643 // (There's no appropriate action type for DevTools overrides.) 24644 // As a result though, React will see the scheduled update as a noop and bailout. 24645 // Shallow cloning props works as a workaround for now to bypass the bailout check. 24646 24647 fiber.memoizedProps = _assign({}, fiber.memoizedProps); 24648 scheduleWork(fiber, Sync); 24649 } 24650 }; // Support DevTools props for function components, forwardRef, memo, host components, etc. 24651 24652 24653 overrideProps = function (fiber, path, value) { 24654 fiber.pendingProps = copyWithSet(fiber.memoizedProps, path, value); 24655 24656 if (fiber.alternate) { 24657 fiber.alternate.pendingProps = fiber.pendingProps; 24658 } 24659 24660 scheduleWork(fiber, Sync); 24661 }; 24662 24663 scheduleUpdate = function (fiber) { 24664 scheduleWork(fiber, Sync); 24665 }; 24666 24667 setSuspenseHandler = function (newShouldSuspendImpl) { 24668 shouldSuspendImpl = newShouldSuspendImpl; 24669 }; 24670 } 24671 24672 function injectIntoDevTools(devToolsConfig) { 24673 var findFiberByHostInstance = devToolsConfig.findFiberByHostInstance; 24674 var ReactCurrentDispatcher = ReactSharedInternals.ReactCurrentDispatcher; 24675 return injectInternals(_assign({}, devToolsConfig, { 24676 overrideHookState: overrideHookState, 24677 overrideProps: overrideProps, 24678 setSuspenseHandler: setSuspenseHandler, 24679 scheduleUpdate: scheduleUpdate, 24680 currentDispatcherRef: ReactCurrentDispatcher, 24681 findHostInstanceByFiber: function (fiber) { 24682 var hostFiber = findCurrentHostFiber(fiber); 24683 24684 if (hostFiber === null) { 24685 return null; 24686 } 24687 24688 return hostFiber.stateNode; 24689 }, 24690 findFiberByHostInstance: function (instance) { 24691 if (!findFiberByHostInstance) { 24692 // Might not be implemented by the renderer. 24693 return null; 24694 } 24695 24696 return findFiberByHostInstance(instance); 24697 }, 24698 // React Refresh 24699 findHostInstancesForRefresh: findHostInstancesForRefresh , 24700 scheduleRefresh: scheduleRefresh , 24701 scheduleRoot: scheduleRoot , 24702 setRefreshHandler: setRefreshHandler , 24703 // Enables DevTools to append owner stacks to error messages in DEV mode. 24704 getCurrentFiber: function () { 24705 return current; 24706 } 24707 })); 24708 } 24709 var IsSomeRendererActing$1 = ReactSharedInternals.IsSomeRendererActing; 24710 24711 function ReactDOMRoot(container, options) { 24712 this._internalRoot = createRootImpl(container, ConcurrentRoot, options); 24713 } 24714 24715 function ReactDOMBlockingRoot(container, tag, options) { 24716 this._internalRoot = createRootImpl(container, tag, options); 24717 } 24718 24719 ReactDOMRoot.prototype.render = ReactDOMBlockingRoot.prototype.render = function (children) { 24720 var root = this._internalRoot; 24721 24722 { 24723 if (typeof arguments[1] === 'function') { 24724 error('render(...): does not support the second callback argument. ' + 'To execute a side effect after rendering, declare it in a component body with useEffect().'); 24725 } 24726 24727 var container = root.containerInfo; 24728 24729 if (container.nodeType !== COMMENT_NODE) { 24730 var hostInstance = findHostInstanceWithNoPortals(root.current); 24731 24732 if (hostInstance) { 24733 if (hostInstance.parentNode !== container) { 24734 error('render(...): It looks like the React-rendered content of the ' + 'root container was removed without using React. This is not ' + 'supported and will cause errors. Instead, call ' + "root.unmount() to empty a root's container."); 24735 } 24736 } 24737 } 24738 } 24739 24740 updateContainer(children, root, null, null); 24741 }; 24742 24743 ReactDOMRoot.prototype.unmount = ReactDOMBlockingRoot.prototype.unmount = function () { 24744 { 24745 if (typeof arguments[0] === 'function') { 24746 error('unmount(...): does not support a callback argument. ' + 'To execute a side effect after rendering, declare it in a component body with useEffect().'); 24747 } 24748 } 24749 24750 var root = this._internalRoot; 24751 var container = root.containerInfo; 24752 updateContainer(null, root, null, function () { 24753 unmarkContainerAsRoot(container); 24754 }); 24755 }; 24756 24757 function createRootImpl(container, tag, options) { 24758 // Tag is either LegacyRoot or Concurrent Root 24759 var hydrate = options != null && options.hydrate === true; 24760 var hydrationCallbacks = options != null && options.hydrationOptions || null; 24761 var root = createContainer(container, tag, hydrate); 24762 markContainerAsRoot(root.current, container); 24763 24764 if (hydrate && tag !== LegacyRoot) { 24765 var doc = container.nodeType === DOCUMENT_NODE ? container : container.ownerDocument; 24766 eagerlyTrapReplayableEvents(container, doc); 24767 } 24768 24769 return root; 24770 } 24771 function createLegacyRoot(container, options) { 24772 return new ReactDOMBlockingRoot(container, LegacyRoot, options); 24773 } 24774 function isValidContainer(node) { 24775 return !!(node && (node.nodeType === ELEMENT_NODE || node.nodeType === DOCUMENT_NODE || node.nodeType === DOCUMENT_FRAGMENT_NODE || node.nodeType === COMMENT_NODE && node.nodeValue === ' react-mount-point-unstable ')); 24776 } 24777 24778 var ReactCurrentOwner$3 = ReactSharedInternals.ReactCurrentOwner; 24779 var topLevelUpdateWarnings; 24780 var warnedAboutHydrateAPI = false; 24781 24782 { 24783 topLevelUpdateWarnings = function (container) { 24784 if (container._reactRootContainer && container.nodeType !== COMMENT_NODE) { 24785 var hostInstance = findHostInstanceWithNoPortals(container._reactRootContainer._internalRoot.current); 24786 24787 if (hostInstance) { 24788 if (hostInstance.parentNode !== container) { 24789 error('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.'); 24790 } 24791 } 24792 } 24793 24794 var isRootRenderedBySomeReact = !!container._reactRootContainer; 24795 var rootEl = getReactRootElementInContainer(container); 24796 var hasNonRootReactChild = !!(rootEl && getInstanceFromNode$1(rootEl)); 24797 24798 if (hasNonRootReactChild && !isRootRenderedBySomeReact) { 24799 error('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.'); 24800 } 24801 24802 if (container.nodeType === ELEMENT_NODE && container.tagName && container.tagName.toUpperCase() === 'BODY') { 24803 error('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.'); 24804 } 24805 }; 24806 } 24807 24808 function getReactRootElementInContainer(container) { 24809 if (!container) { 24810 return null; 24811 } 24812 24813 if (container.nodeType === DOCUMENT_NODE) { 24814 return container.documentElement; 24815 } else { 24816 return container.firstChild; 24817 } 24818 } 24819 24820 function shouldHydrateDueToLegacyHeuristic(container) { 24821 var rootElement = getReactRootElementInContainer(container); 24822 return !!(rootElement && rootElement.nodeType === ELEMENT_NODE && rootElement.hasAttribute(ROOT_ATTRIBUTE_NAME)); 24823 } 24824 24825 function legacyCreateRootFromDOMContainer(container, forceHydrate) { 24826 var shouldHydrate = forceHydrate || shouldHydrateDueToLegacyHeuristic(container); // First clear any existing content. 24827 24828 if (!shouldHydrate) { 24829 var warned = false; 24830 var rootSibling; 24831 24832 while (rootSibling = container.lastChild) { 24833 { 24834 if (!warned && rootSibling.nodeType === ELEMENT_NODE && rootSibling.hasAttribute(ROOT_ATTRIBUTE_NAME)) { 24835 warned = true; 24836 24837 error('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.'); 24838 } 24839 } 24840 24841 container.removeChild(rootSibling); 24842 } 24843 } 24844 24845 { 24846 if (shouldHydrate && !forceHydrate && !warnedAboutHydrateAPI) { 24847 warnedAboutHydrateAPI = true; 24848 24849 warn('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.'); 24850 } 24851 } 24852 24853 return createLegacyRoot(container, shouldHydrate ? { 24854 hydrate: true 24855 } : undefined); 24856 } 24857 24858 function warnOnInvalidCallback$1(callback, callerName) { 24859 { 24860 if (callback !== null && typeof callback !== 'function') { 24861 error('%s(...): Expected the last optional `callback` argument to be a ' + 'function. Instead received: %s.', callerName, callback); 24862 } 24863 } 24864 } 24865 24866 function legacyRenderSubtreeIntoContainer(parentComponent, children, container, forceHydrate, callback) { 24867 { 24868 topLevelUpdateWarnings(container); 24869 warnOnInvalidCallback$1(callback === undefined ? null : callback, 'render'); 24870 } // TODO: Without `any` type, Flow says "Property cannot be accessed on any 24871 // member of intersection type." Whyyyyyy. 24872 24873 24874 var root = container._reactRootContainer; 24875 var fiberRoot; 24876 24877 if (!root) { 24878 // Initial mount 24879 root = container._reactRootContainer = legacyCreateRootFromDOMContainer(container, forceHydrate); 24880 fiberRoot = root._internalRoot; 24881 24882 if (typeof callback === 'function') { 24883 var originalCallback = callback; 24884 24885 callback = function () { 24886 var instance = getPublicRootInstance(fiberRoot); 24887 originalCallback.call(instance); 24888 }; 24889 } // Initial mount should not be batched. 24890 24891 24892 unbatchedUpdates(function () { 24893 updateContainer(children, fiberRoot, parentComponent, callback); 24894 }); 24895 } else { 24896 fiberRoot = root._internalRoot; 24897 24898 if (typeof callback === 'function') { 24899 var _originalCallback = callback; 24900 24901 callback = function () { 24902 var instance = getPublicRootInstance(fiberRoot); 24903 24904 _originalCallback.call(instance); 24905 }; 24906 } // Update 24907 24908 24909 updateContainer(children, fiberRoot, parentComponent, callback); 24910 } 24911 24912 return getPublicRootInstance(fiberRoot); 24913 } 24914 24915 function findDOMNode(componentOrElement) { 24916 { 24917 var owner = ReactCurrentOwner$3.current; 24918 24919 if (owner !== null && owner.stateNode !== null) { 24920 var warnedAboutRefsInRender = owner.stateNode._warnedAboutRefsInRender; 24921 24922 if (!warnedAboutRefsInRender) { 24923 error('%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.type) || 'A component'); 24924 } 24925 24926 owner.stateNode._warnedAboutRefsInRender = true; 24927 } 24928 } 24929 24930 if (componentOrElement == null) { 24931 return null; 24932 } 24933 24934 if (componentOrElement.nodeType === ELEMENT_NODE) { 24935 return componentOrElement; 24936 } 24937 24938 { 24939 return findHostInstanceWithWarning(componentOrElement, 'findDOMNode'); 24940 } 24941 } 24942 function hydrate(element, container, callback) { 24943 if (!isValidContainer(container)) { 24944 { 24945 throw Error( "Target container is not a DOM element." ); 24946 } 24947 } 24948 24949 { 24950 var isModernRoot = isContainerMarkedAsRoot(container) && container._reactRootContainer === undefined; 24951 24952 if (isModernRoot) { 24953 error('You are calling ReactDOM.hydrate() on a container that was previously ' + 'passed to ReactDOM.createRoot(). This is not supported. ' + 'Did you mean to call createRoot(container, {hydrate: true}).render(element)?'); 24954 } 24955 } // TODO: throw or warn if we couldn't hydrate? 24956 24957 24958 return legacyRenderSubtreeIntoContainer(null, element, container, true, callback); 24959 } 24960 function render(element, container, callback) { 24961 if (!isValidContainer(container)) { 24962 { 24963 throw Error( "Target container is not a DOM element." ); 24964 } 24965 } 24966 24967 { 24968 var isModernRoot = isContainerMarkedAsRoot(container) && container._reactRootContainer === undefined; 24969 24970 if (isModernRoot) { 24971 error('You are calling ReactDOM.render() on a container that was previously ' + 'passed to ReactDOM.createRoot(). This is not supported. ' + 'Did you mean to call root.render(element)?'); 24972 } 24973 } 24974 24975 return legacyRenderSubtreeIntoContainer(null, element, container, false, callback); 24976 } 24977 function unstable_renderSubtreeIntoContainer(parentComponent, element, containerNode, callback) { 24978 if (!isValidContainer(containerNode)) { 24979 { 24980 throw Error( "Target container is not a DOM element." ); 24981 } 24982 } 24983 24984 if (!(parentComponent != null && has$1(parentComponent))) { 24985 { 24986 throw Error( "parentComponent must be a valid React Component" ); 24987 } 24988 } 24989 24990 return legacyRenderSubtreeIntoContainer(parentComponent, element, containerNode, false, callback); 24991 } 24992 function unmountComponentAtNode(container) { 24993 if (!isValidContainer(container)) { 24994 { 24995 throw Error( "unmountComponentAtNode(...): Target container is not a DOM element." ); 24996 } 24997 } 24998 24999 { 25000 var isModernRoot = isContainerMarkedAsRoot(container) && container._reactRootContainer === undefined; 25001 25002 if (isModernRoot) { 25003 error('You are calling ReactDOM.unmountComponentAtNode() on a container that was previously ' + 'passed to ReactDOM.createRoot(). This is not supported. Did you mean to call root.unmount()?'); 25004 } 25005 } 25006 25007 if (container._reactRootContainer) { 25008 { 25009 var rootEl = getReactRootElementInContainer(container); 25010 var renderedByDifferentReact = rootEl && !getInstanceFromNode$1(rootEl); 25011 25012 if (renderedByDifferentReact) { 25013 error("unmountComponentAtNode(): The node you're attempting to unmount " + 'was rendered by another copy of React.'); 25014 } 25015 } // Unmount should not be batched. 25016 25017 25018 unbatchedUpdates(function () { 25019 legacyRenderSubtreeIntoContainer(null, null, container, false, function () { 25020 // $FlowFixMe This should probably use `delete container._reactRootContainer` 25021 container._reactRootContainer = null; 25022 unmarkContainerAsRoot(container); 25023 }); 25024 }); // If you call unmountComponentAtNode twice in quick succession, you'll 25025 // get `true` twice. That's probably fine? 25026 25027 return true; 25028 } else { 25029 { 25030 var _rootEl = getReactRootElementInContainer(container); 25031 25032 var hasNonRootReactChild = !!(_rootEl && getInstanceFromNode$1(_rootEl)); // Check if the container itself is a React root node. 25033 25034 var isContainerReactRoot = container.nodeType === ELEMENT_NODE && isValidContainer(container.parentNode) && !!container.parentNode._reactRootContainer; 25035 25036 if (hasNonRootReactChild) { 25037 error("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.'); 25038 } 25039 } 25040 25041 return false; 25042 } 25043 } 25044 25045 function createPortal(children, containerInfo, // TODO: figure out the API for cross-renderer implementation. 25046 implementation) { 25047 var key = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null; 25048 return { 25049 // This tag allow us to uniquely identify this as a React Portal 25050 $$typeof: REACT_PORTAL_TYPE, 25051 key: key == null ? null : '' + key, 25052 children: children, 25053 containerInfo: containerInfo, 25054 implementation: implementation 25055 }; 25056 } 25057 25058 var ReactVersion = '16.13.1'; 25059 25060 setAttemptUserBlockingHydration(attemptUserBlockingHydration$1); 25061 setAttemptContinuousHydration(attemptContinuousHydration$1); 25062 setAttemptHydrationAtCurrentPriority(attemptHydrationAtCurrentPriority$1); 25063 var didWarnAboutUnstableCreatePortal = false; 25064 25065 { 25066 if (typeof Map !== 'function' || // $FlowIssue Flow incorrectly thinks Map has no prototype 25067 Map.prototype == null || typeof Map.prototype.forEach !== 'function' || typeof Set !== 'function' || // $FlowIssue Flow incorrectly thinks Set has no prototype 25068 Set.prototype == null || typeof Set.prototype.clear !== 'function' || typeof Set.prototype.forEach !== 'function') { 25069 error('React depends on Map and Set built-in types. Make sure that you load a ' + 'polyfill in older browsers. https://fb.me/react-polyfills'); 25070 } 25071 } 25072 25073 setRestoreImplementation(restoreControlledState$3); 25074 setBatchingImplementation(batchedUpdates$1, discreteUpdates$1, flushDiscreteUpdates, batchedEventUpdates$1); 25075 25076 function createPortal$1(children, container) { 25077 var key = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null; 25078 25079 if (!isValidContainer(container)) { 25080 { 25081 throw Error( "Target container is not a DOM element." ); 25082 } 25083 } // TODO: pass ReactDOM portal implementation as third argument 25084 // $FlowFixMe The Flow type is opaque but there's no way to actually create it. 25085 25086 25087 return createPortal(children, container, null, key); 25088 } 25089 25090 function renderSubtreeIntoContainer(parentComponent, element, containerNode, callback) { 25091 25092 return unstable_renderSubtreeIntoContainer(parentComponent, element, containerNode, callback); 25093 } 25094 25095 function unstable_createPortal(children, container) { 25096 var key = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null; 25097 25098 { 25099 if (!didWarnAboutUnstableCreatePortal) { 25100 didWarnAboutUnstableCreatePortal = true; 25101 25102 warn('The ReactDOM.unstable_createPortal() alias has been deprecated, ' + 'and will be removed in React 17+. Update your code to use ' + 'ReactDOM.createPortal() instead. It has the exact same API, ' + 'but without the "unstable_" prefix.'); 25103 } 25104 } 25105 25106 return createPortal$1(children, container, key); 25107 } 25108 25109 var Internals = { 25110 // Keep in sync with ReactDOMUnstableNativeDependencies.js 25111 // ReactTestUtils.js, and ReactTestUtilsAct.js. This is an array for better minification. 25112 Events: [getInstanceFromNode$1, getNodeFromInstance$1, getFiberCurrentPropsFromNode$1, injectEventPluginsByName, eventNameDispatchConfigs, accumulateTwoPhaseDispatches, accumulateDirectDispatches, enqueueStateRestore, restoreStateIfNeeded, dispatchEvent, runEventsInBatch, flushPassiveEffects, IsThisRendererActing] 25113 }; 25114 var foundDevTools = injectIntoDevTools({ 25115 findFiberByHostInstance: getClosestInstanceFromNode, 25116 bundleType: 1 , 25117 version: ReactVersion, 25118 rendererPackageName: 'react-dom' 25119 }); 25120 25121 { 25122 if (!foundDevTools && canUseDOM && window.top === window.self) { 25123 // If we're in Chrome or Firefox, provide a download link if not installed. 25124 if (navigator.userAgent.indexOf('Chrome') > -1 && navigator.userAgent.indexOf('Edge') === -1 || navigator.userAgent.indexOf('Firefox') > -1) { 25125 var protocol = window.location.protocol; // Don't warn in exotic cases like chrome-extension://. 25126 25127 if (/^(https?|file):$/.test(protocol)) { 25128 // eslint-disable-next-line react-internal/no-production-logging 25129 console.info('%cDownload the React DevTools ' + 'for a better development experience: ' + 'https://fb.me/react-devtools' + (protocol === 'file:' ? '\nYou might need to use a local HTTP server (instead of file://): ' + 'https://fb.me/react-devtools-faq' : ''), 'font-weight:bold'); 25130 } 25131 } 25132 } 25133 } 25134 25135 exports.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED = Internals; 25136 exports.createPortal = createPortal$1; 25137 exports.findDOMNode = findDOMNode; 25138 exports.flushSync = flushSync; 25139 exports.hydrate = hydrate; 25140 exports.render = render; 25141 exports.unmountComponentAtNode = unmountComponentAtNode; 25142 exports.unstable_batchedUpdates = batchedUpdates$1; 25143 exports.unstable_createPortal = unstable_createPortal; 25144 exports.unstable_renderSubtreeIntoContainer = renderSubtreeIntoContainer; 25145 exports.version = ReactVersion; 25146 25147 })));