react-dom.mjs (572098B)
1 /** @license React v16.8.6 2 * react-dom.production.min.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 import React from 'resource://devtools/client/shared/vendor/react.mjs'; 10 11 /** 12 * Use invariant() to assert state which your program assumes to be true. 13 * 14 * Provide sprintf-style format (only %s is supported) and arguments 15 * to provide information about what broke and what you were 16 * expecting. 17 * 18 * The invariant message will be stripped in production, but the invariant 19 * will remain to ensure logic does not differ in production. 20 */ 21 22 function invariant(condition, format, a, b, c, d, e, f) { 23 if (!condition) { 24 var error = void 0; 25 if (format === undefined) { 26 error = new Error('Minified exception occurred; use the non-minified dev environment ' + 'for the full error message and additional helpful warnings.'); 27 } else { 28 var args = [a, b, c, d, e, f]; 29 var argIndex = 0; 30 error = new Error(format.replace(/%s/g, function () { 31 return args[argIndex++]; 32 })); 33 error.name = 'Invariant Violation'; 34 } 35 36 error.framesToPop = 1; // we don't care about invariant's own frame 37 throw error; 38 } 39 } 40 41 // Relying on the `invariant()` implementation lets us 42 // preserve the format and params in the www builds. 43 /** 44 * WARNING: DO NOT manually require this module. 45 * This is a replacement for `invariant(...)` used by the error code system 46 * and will _only_ be required by the corresponding babel pass. 47 * It always throws. 48 */ 49 function reactProdInvariant(code) { 50 var argCount = arguments.length - 1; 51 var url = 'https://reactjs.org/docs/error-decoder.html?invariant=' + code; 52 for (var argIdx = 0; argIdx < argCount; argIdx++) { 53 url += '&args[]=' + encodeURIComponent(arguments[argIdx + 1]); 54 } 55 // Rename it so that our build transform doesn't attempt 56 // to replace this invariant() call with reactProdInvariant(). 57 var i = invariant; 58 i(false, 59 // The error code is intentionally part of the message (and 60 // not the format argument) so that we could deduplicate 61 // different errors in logs based on the code. 62 'Minified React error #' + code + '; visit %s ' + 'for the full message or use the non-minified dev environment ' + 'for full errors and additional helpful warnings. ', url); 63 } 64 65 !React ? reactProdInvariant('227') : void 0; 66 67 var invokeGuardedCallbackImpl = function (name, func, context, a, b, c, d, e, f) { 68 var funcArgs = Array.prototype.slice.call(arguments, 3); 69 try { 70 func.apply(context, funcArgs); 71 } catch (error) { 72 this.onError(error); 73 } 74 }; 75 76 // Used by Fiber to simulate a try-catch. 77 var hasError = false; 78 var caughtError = null; 79 80 // Used by event system to capture/rethrow the first error. 81 var hasRethrowError = false; 82 var rethrowError = null; 83 84 var reporter = { 85 onError: function (error) { 86 hasError = true; 87 caughtError = error; 88 } 89 }; 90 91 /** 92 * Call a function while guarding against errors that happens within it. 93 * Returns an error if it throws, otherwise null. 94 * 95 * In production, this is implemented using a try-catch. The reason we don't 96 * use a try-catch directly is so that we can swap out a different 97 * implementation in DEV mode. 98 * 99 * @param {String} name of the guard to use for logging or debugging 100 * @param {Function} func The function to invoke 101 * @param {*} context The context to use when calling the function 102 * @param {...*} args Arguments for function 103 */ 104 function invokeGuardedCallback(name, func, context, a, b, c, d, e, f) { 105 hasError = false; 106 caughtError = null; 107 invokeGuardedCallbackImpl.apply(reporter, arguments); 108 } 109 110 /** 111 * Same as invokeGuardedCallback, but instead of returning an error, it stores 112 * it in a global so it can be rethrown by `rethrowCaughtError` later. 113 * TODO: See if caughtError and rethrowError can be unified. 114 * 115 * @param {String} name of the guard to use for logging or debugging 116 * @param {Function} func The function to invoke 117 * @param {*} context The context to use when calling the function 118 * @param {...*} args Arguments for function 119 */ 120 function invokeGuardedCallbackAndCatchFirstError(name, func, context, a, b, c, d, e, f) { 121 invokeGuardedCallback.apply(this, arguments); 122 if (hasError) { 123 var error = clearCaughtError(); 124 if (!hasRethrowError) { 125 hasRethrowError = true; 126 rethrowError = error; 127 } 128 } 129 } 130 131 /** 132 * During execution of guarded functions we will capture the first error which 133 * we will rethrow to be handled by the top level error handler. 134 */ 135 function rethrowCaughtError() { 136 if (hasRethrowError) { 137 var error = rethrowError; 138 hasRethrowError = false; 139 rethrowError = null; 140 throw error; 141 } 142 } 143 144 145 146 function clearCaughtError() { 147 if (hasError) { 148 var error = caughtError; 149 hasError = false; 150 caughtError = null; 151 return error; 152 } else { 153 reactProdInvariant('198'); 154 } 155 } 156 157 /** 158 * Injectable ordering of event plugins. 159 */ 160 var eventPluginOrder = null; 161 162 /** 163 * Injectable mapping from names to event plugin modules. 164 */ 165 var namesToPlugins = {}; 166 167 /** 168 * Recomputes the plugin list using the injected plugins and plugin ordering. 169 * 170 * @private 171 */ 172 function recomputePluginOrdering() { 173 if (!eventPluginOrder) { 174 // Wait until an `eventPluginOrder` is injected. 175 return; 176 } 177 for (var pluginName in namesToPlugins) { 178 var pluginModule = namesToPlugins[pluginName]; 179 var pluginIndex = eventPluginOrder.indexOf(pluginName); 180 !(pluginIndex > -1) ? reactProdInvariant('96', pluginName) : void 0; 181 if (plugins[pluginIndex]) { 182 continue; 183 } 184 !pluginModule.extractEvents ? reactProdInvariant('97', pluginName) : void 0; 185 plugins[pluginIndex] = pluginModule; 186 var publishedEvents = pluginModule.eventTypes; 187 for (var eventName in publishedEvents) { 188 !publishEventForPlugin(publishedEvents[eventName], pluginModule, eventName) ? reactProdInvariant('98', eventName, pluginName) : void 0; 189 } 190 } 191 } 192 193 /** 194 * Publishes an event so that it can be dispatched by the supplied plugin. 195 * 196 * @param {object} dispatchConfig Dispatch configuration for the event. 197 * @param {object} PluginModule Plugin publishing the event. 198 * @return {boolean} True if the event was successfully published. 199 * @private 200 */ 201 function publishEventForPlugin(dispatchConfig, pluginModule, eventName) { 202 !!eventNameDispatchConfigs.hasOwnProperty(eventName) ? reactProdInvariant('99', eventName) : void 0; 203 eventNameDispatchConfigs[eventName] = dispatchConfig; 204 205 var phasedRegistrationNames = dispatchConfig.phasedRegistrationNames; 206 if (phasedRegistrationNames) { 207 for (var phaseName in phasedRegistrationNames) { 208 if (phasedRegistrationNames.hasOwnProperty(phaseName)) { 209 var phasedRegistrationName = phasedRegistrationNames[phaseName]; 210 publishRegistrationName(phasedRegistrationName, pluginModule, eventName); 211 } 212 } 213 return true; 214 } else if (dispatchConfig.registrationName) { 215 publishRegistrationName(dispatchConfig.registrationName, pluginModule, eventName); 216 return true; 217 } 218 return false; 219 } 220 221 /** 222 * Publishes a registration name that is used to identify dispatched events. 223 * 224 * @param {string} registrationName Registration name to add. 225 * @param {object} PluginModule Plugin publishing the event. 226 * @private 227 */ 228 function publishRegistrationName(registrationName, pluginModule, eventName) { 229 !!registrationNameModules[registrationName] ? reactProdInvariant('100', registrationName) : void 0; 230 registrationNameModules[registrationName] = pluginModule; 231 registrationNameDependencies[registrationName] = pluginModule.eventTypes[eventName].dependencies; 232 233 234 } 235 236 /** 237 * Registers plugins so that they can extract and dispatch events. 238 * 239 * @see {EventPluginHub} 240 */ 241 242 /** 243 * Ordered list of injected plugins. 244 */ 245 var plugins = []; 246 247 /** 248 * Mapping from event name to dispatch config 249 */ 250 var eventNameDispatchConfigs = {}; 251 252 /** 253 * Mapping from registration name to plugin module 254 */ 255 var registrationNameModules = {}; 256 257 /** 258 * Mapping from registration name to event name 259 */ 260 var registrationNameDependencies = {}; 261 262 /** 263 * Mapping from lowercase registration names to the properly cased version, 264 * used to warn in the case of missing event handlers. Available 265 * only in false. 266 * @type {Object} 267 */ 268 269 // Trust the developer to only use possibleRegistrationNames in false 270 271 /** 272 * Injects an ordering of plugins (by plugin name). This allows the ordering 273 * to be decoupled from injection of the actual plugins so that ordering is 274 * always deterministic regardless of packaging, on-the-fly injection, etc. 275 * 276 * @param {array} InjectedEventPluginOrder 277 * @internal 278 * @see {EventPluginHub.injection.injectEventPluginOrder} 279 */ 280 function injectEventPluginOrder(injectedEventPluginOrder) { 281 !!eventPluginOrder ? reactProdInvariant('101') : void 0; 282 // Clone the ordering so it cannot be dynamically mutated. 283 eventPluginOrder = Array.prototype.slice.call(injectedEventPluginOrder); 284 recomputePluginOrdering(); 285 } 286 287 /** 288 * Injects plugins to be used by `EventPluginHub`. The plugin names must be 289 * in the ordering injected by `injectEventPluginOrder`. 290 * 291 * Plugins can be injected as part of page initialization or on-the-fly. 292 * 293 * @param {object} injectedNamesToPlugins Map from names to plugin modules. 294 * @internal 295 * @see {EventPluginHub.injection.injectEventPluginsByName} 296 */ 297 function injectEventPluginsByName(injectedNamesToPlugins) { 298 var isOrderingDirty = false; 299 for (var pluginName in injectedNamesToPlugins) { 300 if (!injectedNamesToPlugins.hasOwnProperty(pluginName)) { 301 continue; 302 } 303 var pluginModule = injectedNamesToPlugins[pluginName]; 304 if (!namesToPlugins.hasOwnProperty(pluginName) || namesToPlugins[pluginName] !== pluginModule) { 305 !!namesToPlugins[pluginName] ? reactProdInvariant('102', pluginName) : void 0; 306 namesToPlugins[pluginName] = pluginModule; 307 isOrderingDirty = true; 308 } 309 } 310 if (isOrderingDirty) { 311 recomputePluginOrdering(); 312 } 313 } 314 315 /** 316 * Similar to invariant but only logs a warning if the condition is not met. 317 * This can be used to log issues in development environments in critical 318 * paths. Removing the logging code for production environments will keep the 319 * same logic and follow the same code paths. 320 */ 321 322 var getFiberCurrentPropsFromNode = null; 323 var getInstanceFromNode = null; 324 var getNodeFromInstance = null; 325 326 function setComponentTree(getFiberCurrentPropsFromNodeImpl, getInstanceFromNodeImpl, getNodeFromInstanceImpl) { 327 getFiberCurrentPropsFromNode = getFiberCurrentPropsFromNodeImpl; 328 getInstanceFromNode = getInstanceFromNodeImpl; 329 getNodeFromInstance = getNodeFromInstanceImpl; 330 331 } 332 333 /** 334 * Dispatch the event to the listener. 335 * @param {SyntheticEvent} event SyntheticEvent to handle 336 * @param {function} listener Application-level callback 337 * @param {*} inst Internal component instance 338 */ 339 function executeDispatch(event, listener, inst) { 340 var type = event.type || 'unknown-event'; 341 event.currentTarget = getNodeFromInstance(inst); 342 invokeGuardedCallbackAndCatchFirstError(type, listener, undefined, event); 343 event.currentTarget = null; 344 } 345 346 /** 347 * Standard/simple iteration through an event's collected dispatches. 348 */ 349 function executeDispatchesInOrder(event) { 350 var dispatchListeners = event._dispatchListeners; 351 var dispatchInstances = event._dispatchInstances; 352 if (Array.isArray(dispatchListeners)) { 353 for (var i = 0; i < dispatchListeners.length; i++) { 354 if (event.isPropagationStopped()) { 355 break; 356 } 357 // Listeners and Instances are two parallel arrays that are always in sync. 358 executeDispatch(event, dispatchListeners[i], dispatchInstances[i]); 359 } 360 } else if (dispatchListeners) { 361 executeDispatch(event, dispatchListeners, dispatchInstances); 362 } 363 event._dispatchListeners = null; 364 event._dispatchInstances = null; 365 } 366 367 /** 368 * @see executeDispatchesInOrderStopAtTrueImpl 369 */ 370 371 372 /** 373 * Execution of a "direct" dispatch - there must be at most one dispatch 374 * accumulated on the event or it is considered an error. It doesn't really make 375 * sense for an event with multiple dispatches (bubbled) to keep track of the 376 * return values at each dispatch execution, but it does tend to make sense when 377 * dealing with "direct" dispatches. 378 * 379 * @return {*} The return value of executing the single dispatch. 380 */ 381 382 383 /** 384 * @param {SyntheticEvent} event 385 * @return {boolean} True iff number of dispatches accumulated is greater than 0. 386 */ 387 388 /** 389 * Accumulates items that must not be null or undefined into the first one. This 390 * is used to conserve memory by avoiding array allocations, and thus sacrifices 391 * API cleanness. Since `current` can be null before being passed in and not 392 * null after this function, make sure to assign it back to `current`: 393 * 394 * `a = accumulateInto(a, b);` 395 * 396 * This API should be sparingly used. Try `accumulate` for something cleaner. 397 * 398 * @return {*|array<*>} An accumulation of items. 399 */ 400 401 function accumulateInto(current, next) { 402 !(next != null) ? reactProdInvariant('30') : void 0; 403 404 if (current == null) { 405 return next; 406 } 407 408 // Both are not empty. Warning: Never call x.concat(y) when you are not 409 // certain that x is an Array (x could be a string with concat method). 410 if (Array.isArray(current)) { 411 if (Array.isArray(next)) { 412 current.push.apply(current, next); 413 return current; 414 } 415 current.push(next); 416 return current; 417 } 418 419 if (Array.isArray(next)) { 420 // A bit too dangerous to mutate `next`. 421 return [current].concat(next); 422 } 423 424 return [current, next]; 425 } 426 427 /** 428 * @param {array} arr an "accumulation" of items which is either an Array or 429 * a single item. Useful when paired with the `accumulate` module. This is a 430 * simple utility that allows us to reason about a collection of items, but 431 * handling the case when there is exactly one item (and we do not need to 432 * allocate an array). 433 * @param {function} cb Callback invoked with each element or a collection. 434 * @param {?} [scope] Scope used as `this` in a callback. 435 */ 436 function forEachAccumulated(arr, cb, scope) { 437 if (Array.isArray(arr)) { 438 arr.forEach(cb, scope); 439 } else if (arr) { 440 cb.call(scope, arr); 441 } 442 } 443 444 /** 445 * Internal queue of events that have accumulated their dispatches and are 446 * waiting to have their dispatches executed. 447 */ 448 var eventQueue = null; 449 450 /** 451 * Dispatches an event and releases it back into the pool, unless persistent. 452 * 453 * @param {?object} event Synthetic event to be dispatched. 454 * @private 455 */ 456 var executeDispatchesAndRelease = function (event) { 457 if (event) { 458 executeDispatchesInOrder(event); 459 460 if (!event.isPersistent()) { 461 event.constructor.release(event); 462 } 463 } 464 }; 465 var executeDispatchesAndReleaseTopLevel = function (e) { 466 return executeDispatchesAndRelease(e); 467 }; 468 469 function isInteractive(tag) { 470 return tag === 'button' || tag === 'input' || tag === 'select' || tag === 'textarea'; 471 } 472 473 function shouldPreventMouseEvent(name, type, props) { 474 switch (name) { 475 case 'onClick': 476 case 'onClickCapture': 477 case 'onDoubleClick': 478 case 'onDoubleClickCapture': 479 case 'onMouseDown': 480 case 'onMouseDownCapture': 481 case 'onMouseMove': 482 case 'onMouseMoveCapture': 483 case 'onMouseUp': 484 case 'onMouseUpCapture': 485 return !!(props.disabled && isInteractive(type)); 486 default: 487 return false; 488 } 489 } 490 491 /** 492 * This is a unified interface for event plugins to be installed and configured. 493 * 494 * Event plugins can implement the following properties: 495 * 496 * `extractEvents` {function(string, DOMEventTarget, string, object): *} 497 * Required. When a top-level event is fired, this method is expected to 498 * extract synthetic events that will in turn be queued and dispatched. 499 * 500 * `eventTypes` {object} 501 * Optional, plugins that fire events must publish a mapping of registration 502 * names that are used to register listeners. Values of this mapping must 503 * be objects that contain `registrationName` or `phasedRegistrationNames`. 504 * 505 * `executeDispatch` {function(object, function, string)} 506 * Optional, allows plugins to override how an event gets dispatched. By 507 * default, the listener is simply invoked. 508 * 509 * Each plugin that is injected into `EventsPluginHub` is immediately operable. 510 * 511 * @public 512 */ 513 514 /** 515 * Methods for injecting dependencies. 516 */ 517 var injection = { 518 /** 519 * @param {array} InjectedEventPluginOrder 520 * @public 521 */ 522 injectEventPluginOrder: injectEventPluginOrder, 523 524 /** 525 * @param {object} injectedNamesToPlugins Map from names to plugin modules. 526 */ 527 injectEventPluginsByName: injectEventPluginsByName 528 }; 529 530 /** 531 * @param {object} inst The instance, which is the source of events. 532 * @param {string} registrationName Name of listener (e.g. `onClick`). 533 * @return {?function} The stored callback. 534 */ 535 function getListener(inst, registrationName) { 536 var listener = void 0; 537 538 // TODO: shouldPreventMouseEvent is DOM-specific and definitely should not 539 // live here; needs to be moved to a better place soon 540 var stateNode = inst.stateNode; 541 if (!stateNode) { 542 // Work in progress (ex: onload events in incremental mode). 543 return null; 544 } 545 var props = getFiberCurrentPropsFromNode(stateNode); 546 if (!props) { 547 // Work in progress. 548 return null; 549 } 550 listener = props[registrationName]; 551 if (shouldPreventMouseEvent(registrationName, inst.type, props)) { 552 return null; 553 } 554 !(!listener || typeof listener === 'function') ? reactProdInvariant('231', registrationName, typeof listener) : void 0; 555 return listener; 556 } 557 558 /** 559 * Allows registered plugins an opportunity to extract events from top-level 560 * native browser events. 561 * 562 * @return {*} An accumulation of synthetic events. 563 * @internal 564 */ 565 function extractEvents(topLevelType, targetInst, nativeEvent, nativeEventTarget) { 566 var events = null; 567 for (var i = 0; i < plugins.length; i++) { 568 // Not every plugin in the ordering may be loaded at runtime. 569 var possiblePlugin = plugins[i]; 570 if (possiblePlugin) { 571 var extractedEvents = possiblePlugin.extractEvents(topLevelType, targetInst, nativeEvent, nativeEventTarget); 572 if (extractedEvents) { 573 events = accumulateInto(events, extractedEvents); 574 } 575 } 576 } 577 return events; 578 } 579 580 function runEventsInBatch(events) { 581 if (events !== null) { 582 eventQueue = accumulateInto(eventQueue, events); 583 } 584 585 // Set `eventQueue` to null before processing it so that we can tell if more 586 // events get enqueued while processing. 587 var processingEventQueue = eventQueue; 588 eventQueue = null; 589 590 if (!processingEventQueue) { 591 return; 592 } 593 594 forEachAccumulated(processingEventQueue, executeDispatchesAndReleaseTopLevel); 595 !!eventQueue ? reactProdInvariant('95') : void 0; 596 // This would be a good time to rethrow if any of the event handlers threw. 597 rethrowCaughtError(); 598 } 599 600 function runExtractedEventsInBatch(topLevelType, targetInst, nativeEvent, nativeEventTarget) { 601 var events = extractEvents(topLevelType, targetInst, nativeEvent, nativeEventTarget); 602 runEventsInBatch(events); 603 } 604 605 var FunctionComponent = 0; 606 var ClassComponent = 1; 607 var IndeterminateComponent = 2; // Before we know whether it is function or class 608 var HostRoot = 3; // Root of a host tree. Could be nested inside another node. 609 var HostPortal = 4; // A subtree. Could be an entry point to a different renderer. 610 var HostComponent = 5; 611 var HostText = 6; 612 var Fragment = 7; 613 var Mode = 8; 614 var ContextConsumer = 9; 615 var ContextProvider = 10; 616 var ForwardRef = 11; 617 var Profiler = 12; 618 var SuspenseComponent = 13; 619 var MemoComponent = 14; 620 var SimpleMemoComponent = 15; 621 var LazyComponent = 16; 622 var IncompleteClassComponent = 17; 623 var DehydratedSuspenseComponent = 18; 624 625 var randomKey = Math.random().toString(36).slice(2); 626 var internalInstanceKey = '__reactInternalInstance$' + randomKey; 627 var internalEventHandlersKey = '__reactEventHandlers$' + randomKey; 628 629 function precacheFiberNode(hostInst, node) { 630 node[internalInstanceKey] = hostInst; 631 } 632 633 /** 634 * Given a DOM node, return the closest ReactDOMComponent or 635 * ReactDOMTextComponent instance ancestor. 636 */ 637 function getClosestInstanceFromNode(node) { 638 if (node[internalInstanceKey]) { 639 return node[internalInstanceKey]; 640 } 641 642 while (!node[internalInstanceKey]) { 643 if (node.parentNode) { 644 node = node.parentNode; 645 } else { 646 // Top of the tree. This node must not be part of a React tree (or is 647 // unmounted, potentially). 648 return null; 649 } 650 } 651 652 var inst = node[internalInstanceKey]; 653 if (inst.tag === HostComponent || inst.tag === HostText) { 654 // In Fiber, this will always be the deepest root. 655 return inst; 656 } 657 658 return null; 659 } 660 661 /** 662 * Given a DOM node, return the ReactDOMComponent or ReactDOMTextComponent 663 * instance, or null if the node was not rendered by this React. 664 */ 665 function getInstanceFromNode$1(node) { 666 var inst = node[internalInstanceKey]; 667 if (inst) { 668 if (inst.tag === HostComponent || inst.tag === HostText) { 669 return inst; 670 } else { 671 return null; 672 } 673 } 674 return null; 675 } 676 677 /** 678 * Given a ReactDOMComponent or ReactDOMTextComponent, return the corresponding 679 * DOM node. 680 */ 681 function getNodeFromInstance$1(inst) { 682 if (inst.tag === HostComponent || inst.tag === HostText) { 683 // In Fiber this, is just the state node right now. We assume it will be 684 // a host component or host text. 685 return inst.stateNode; 686 } 687 688 // Without this first invariant, passing a non-DOM-component triggers the next 689 // invariant for a missing parent, which is super confusing. 690 reactProdInvariant('33'); 691 } 692 693 function getFiberCurrentPropsFromNode$1(node) { 694 return node[internalEventHandlersKey] || null; 695 } 696 697 function updateFiberProps(node, props) { 698 node[internalEventHandlersKey] = props; 699 } 700 701 function getParent(inst) { 702 do { 703 inst = inst.return; 704 // TODO: If this is a HostRoot we might want to bail out. 705 // That is depending on if we want nested subtrees (layers) to bubble 706 // events to their parent. We could also go through parentNode on the 707 // host node but that wouldn't work for React Native and doesn't let us 708 // do the portal feature. 709 } while (inst && inst.tag !== HostComponent); 710 if (inst) { 711 return inst; 712 } 713 return null; 714 } 715 716 /** 717 * Return the lowest common ancestor of A and B, or null if they are in 718 * different trees. 719 */ 720 function getLowestCommonAncestor(instA, instB) { 721 var depthA = 0; 722 for (var tempA = instA; tempA; tempA = getParent(tempA)) { 723 depthA++; 724 } 725 var depthB = 0; 726 for (var tempB = instB; tempB; tempB = getParent(tempB)) { 727 depthB++; 728 } 729 730 // If A is deeper, crawl up. 731 while (depthA - depthB > 0) { 732 instA = getParent(instA); 733 depthA--; 734 } 735 736 // If B is deeper, crawl up. 737 while (depthB - depthA > 0) { 738 instB = getParent(instB); 739 depthB--; 740 } 741 742 // Walk in lockstep until we find a match. 743 var depth = depthA; 744 while (depth--) { 745 if (instA === instB || instA === instB.alternate) { 746 return instA; 747 } 748 instA = getParent(instA); 749 instB = getParent(instB); 750 } 751 return null; 752 } 753 754 /** 755 * Return if A is an ancestor of B. 756 */ 757 758 759 /** 760 * Return the parent instance of the passed-in instance. 761 */ 762 763 764 /** 765 * Simulates the traversal of a two-phase, capture/bubble event dispatch. 766 */ 767 function traverseTwoPhase(inst, fn, arg) { 768 var path = []; 769 while (inst) { 770 path.push(inst); 771 inst = getParent(inst); 772 } 773 var i = void 0; 774 for (i = path.length; i-- > 0;) { 775 fn(path[i], 'captured', arg); 776 } 777 for (i = 0; i < path.length; i++) { 778 fn(path[i], 'bubbled', arg); 779 } 780 } 781 782 /** 783 * Traverses the ID hierarchy and invokes the supplied `cb` on any IDs that 784 * should would receive a `mouseEnter` or `mouseLeave` event. 785 * 786 * Does not invoke the callback on the nearest common ancestor because nothing 787 * "entered" or "left" that element. 788 */ 789 function traverseEnterLeave(from, to, fn, argFrom, argTo) { 790 var common = from && to ? getLowestCommonAncestor(from, to) : null; 791 var pathFrom = []; 792 while (true) { 793 if (!from) { 794 break; 795 } 796 if (from === common) { 797 break; 798 } 799 var alternate = from.alternate; 800 if (alternate !== null && alternate === common) { 801 break; 802 } 803 pathFrom.push(from); 804 from = getParent(from); 805 } 806 var pathTo = []; 807 while (true) { 808 if (!to) { 809 break; 810 } 811 if (to === common) { 812 break; 813 } 814 var _alternate = to.alternate; 815 if (_alternate !== null && _alternate === common) { 816 break; 817 } 818 pathTo.push(to); 819 to = getParent(to); 820 } 821 for (var i = 0; i < pathFrom.length; i++) { 822 fn(pathFrom[i], 'bubbled', argFrom); 823 } 824 for (var _i = pathTo.length; _i-- > 0;) { 825 fn(pathTo[_i], 'captured', argTo); 826 } 827 } 828 829 /** 830 * Some event types have a notion of different registration names for different 831 * "phases" of propagation. This finds listeners by a given phase. 832 */ 833 function listenerAtPhase(inst, event, propagationPhase) { 834 var registrationName = event.dispatchConfig.phasedRegistrationNames[propagationPhase]; 835 return getListener(inst, registrationName); 836 } 837 838 /** 839 * A small set of propagation patterns, each of which will accept a small amount 840 * of information, and generate a set of "dispatch ready event objects" - which 841 * are sets of events that have already been annotated with a set of dispatched 842 * listener functions/ids. The API is designed this way to discourage these 843 * propagation strategies from actually executing the dispatches, since we 844 * always want to collect the entire set of dispatches before executing even a 845 * single one. 846 */ 847 848 /** 849 * Tags a `SyntheticEvent` with dispatched listeners. Creating this function 850 * here, allows us to not have to bind or create functions for each event. 851 * Mutating the event's members allows us to not have to create a wrapping 852 * "dispatch" object that pairs the event with the listener. 853 */ 854 function accumulateDirectionalDispatches(inst, phase, event) { 855 var listener = listenerAtPhase(inst, event, phase); 856 if (listener) { 857 event._dispatchListeners = accumulateInto(event._dispatchListeners, listener); 858 event._dispatchInstances = accumulateInto(event._dispatchInstances, inst); 859 } 860 } 861 862 /** 863 * Collect dispatches (must be entirely collected before dispatching - see unit 864 * tests). Lazily allocate the array to conserve memory. We must loop through 865 * each event and perform the traversal for each one. We cannot perform a 866 * single traversal for the entire collection of events because each event may 867 * have a different target. 868 */ 869 function accumulateTwoPhaseDispatchesSingle(event) { 870 if (event && event.dispatchConfig.phasedRegistrationNames) { 871 traverseTwoPhase(event._targetInst, accumulateDirectionalDispatches, event); 872 } 873 } 874 875 /** 876 * Accumulates without regard to direction, does not look for phased 877 * registration names. Same as `accumulateDirectDispatchesSingle` but without 878 * requiring that the `dispatchMarker` be the same as the dispatched ID. 879 */ 880 function accumulateDispatches(inst, ignoredDirection, event) { 881 if (inst && event && event.dispatchConfig.registrationName) { 882 var registrationName = event.dispatchConfig.registrationName; 883 var listener = getListener(inst, registrationName); 884 if (listener) { 885 event._dispatchListeners = accumulateInto(event._dispatchListeners, listener); 886 event._dispatchInstances = accumulateInto(event._dispatchInstances, inst); 887 } 888 } 889 } 890 891 /** 892 * Accumulates dispatches on an `SyntheticEvent`, but only for the 893 * `dispatchMarker`. 894 * @param {SyntheticEvent} event 895 */ 896 function accumulateDirectDispatchesSingle(event) { 897 if (event && event.dispatchConfig.registrationName) { 898 accumulateDispatches(event._targetInst, null, event); 899 } 900 } 901 902 function accumulateTwoPhaseDispatches(events) { 903 forEachAccumulated(events, accumulateTwoPhaseDispatchesSingle); 904 } 905 906 907 908 function accumulateEnterLeaveDispatches(leave, enter, from, to) { 909 traverseEnterLeave(from, to, accumulateDispatches, leave, enter); 910 } 911 912 function accumulateDirectDispatches(events) { 913 forEachAccumulated(events, accumulateDirectDispatchesSingle); 914 } 915 916 var canUseDOM = !!(typeof window !== 'undefined' && window.document && window.document.createElement); 917 918 // Do not uses the below two methods directly! 919 // Instead use constants exported from DOMTopLevelEventTypes in ReactDOM. 920 // (It is the only module that is allowed to access these methods.) 921 922 function unsafeCastStringToDOMTopLevelType(topLevelType) { 923 return topLevelType; 924 } 925 926 function unsafeCastDOMTopLevelTypeToString(topLevelType) { 927 return topLevelType; 928 } 929 930 /** 931 * Generate a mapping of standard vendor prefixes using the defined style property and event name. 932 * 933 * @param {string} styleProp 934 * @param {string} eventName 935 * @returns {object} 936 */ 937 function makePrefixMap(styleProp, eventName) { 938 var prefixes = {}; 939 940 prefixes[styleProp.toLowerCase()] = eventName.toLowerCase(); 941 prefixes['Webkit' + styleProp] = 'webkit' + eventName; 942 prefixes['Moz' + styleProp] = 'moz' + eventName; 943 944 return prefixes; 945 } 946 947 /** 948 * A list of event names to a configurable list of vendor prefixes. 949 */ 950 var vendorPrefixes = { 951 animationend: makePrefixMap('Animation', 'AnimationEnd'), 952 animationiteration: makePrefixMap('Animation', 'AnimationIteration'), 953 animationstart: makePrefixMap('Animation', 'AnimationStart'), 954 transitionend: makePrefixMap('Transition', 'TransitionEnd') 955 }; 956 957 /** 958 * Event names that have already been detected and prefixed (if applicable). 959 */ 960 var prefixedEventNames = {}; 961 962 /** 963 * Element to check for prefixes on. 964 */ 965 var style = {}; 966 967 /** 968 * Bootstrap if a DOM exists. 969 */ 970 if (canUseDOM) { 971 style = document.createElementNS('http://www.w3.org/1999/xhtml', 'div').style; 972 973 // On some platforms, in particular some releases of Android 4.x, 974 // the un-prefixed "animation" and "transition" properties are defined on the 975 // style object but the events that fire will still be prefixed, so we need 976 // to check if the un-prefixed events are usable, and if not remove them from the map. 977 if (!('AnimationEvent' in window)) { 978 delete vendorPrefixes.animationend.animation; 979 delete vendorPrefixes.animationiteration.animation; 980 delete vendorPrefixes.animationstart.animation; 981 } 982 983 // Same as above 984 if (!('TransitionEvent' in window)) { 985 delete vendorPrefixes.transitionend.transition; 986 } 987 } 988 989 /** 990 * Attempts to determine the correct vendor prefixed event name. 991 * 992 * @param {string} eventName 993 * @returns {string} 994 */ 995 function getVendorPrefixedEventName(eventName) { 996 if (prefixedEventNames[eventName]) { 997 return prefixedEventNames[eventName]; 998 } else if (!vendorPrefixes[eventName]) { 999 return eventName; 1000 } 1001 1002 var prefixMap = vendorPrefixes[eventName]; 1003 1004 for (var styleProp in prefixMap) { 1005 if (prefixMap.hasOwnProperty(styleProp) && styleProp in style) { 1006 return prefixedEventNames[eventName] = prefixMap[styleProp]; 1007 } 1008 } 1009 1010 return eventName; 1011 } 1012 1013 /** 1014 * To identify top level events in ReactDOM, we use constants defined by this 1015 * module. This is the only module that uses the unsafe* methods to express 1016 * that the constants actually correspond to the browser event names. This lets 1017 * us save some bundle size by avoiding a top level type -> event name map. 1018 * The rest of ReactDOM code should import top level types from this file. 1019 */ 1020 var TOP_ABORT = unsafeCastStringToDOMTopLevelType('abort'); 1021 var TOP_ANIMATION_END = unsafeCastStringToDOMTopLevelType(getVendorPrefixedEventName('animationend')); 1022 var TOP_ANIMATION_ITERATION = unsafeCastStringToDOMTopLevelType(getVendorPrefixedEventName('animationiteration')); 1023 var TOP_ANIMATION_START = unsafeCastStringToDOMTopLevelType(getVendorPrefixedEventName('animationstart')); 1024 var TOP_BLUR = unsafeCastStringToDOMTopLevelType('blur'); 1025 var TOP_CAN_PLAY = unsafeCastStringToDOMTopLevelType('canplay'); 1026 var TOP_CAN_PLAY_THROUGH = unsafeCastStringToDOMTopLevelType('canplaythrough'); 1027 var TOP_CANCEL = unsafeCastStringToDOMTopLevelType('cancel'); 1028 var TOP_CHANGE = unsafeCastStringToDOMTopLevelType('change'); 1029 var TOP_CLICK = unsafeCastStringToDOMTopLevelType('click'); 1030 var TOP_CLOSE = unsafeCastStringToDOMTopLevelType('close'); 1031 var TOP_COMPOSITION_END = unsafeCastStringToDOMTopLevelType('compositionend'); 1032 var TOP_COMPOSITION_START = unsafeCastStringToDOMTopLevelType('compositionstart'); 1033 var TOP_COMPOSITION_UPDATE = unsafeCastStringToDOMTopLevelType('compositionupdate'); 1034 var TOP_CONTEXT_MENU = unsafeCastStringToDOMTopLevelType('contextmenu'); 1035 var TOP_COPY = unsafeCastStringToDOMTopLevelType('copy'); 1036 var TOP_CUT = unsafeCastStringToDOMTopLevelType('cut'); 1037 var TOP_DOUBLE_CLICK = unsafeCastStringToDOMTopLevelType('dblclick'); 1038 var TOP_AUX_CLICK = unsafeCastStringToDOMTopLevelType('auxclick'); 1039 var TOP_DRAG = unsafeCastStringToDOMTopLevelType('drag'); 1040 var TOP_DRAG_END = unsafeCastStringToDOMTopLevelType('dragend'); 1041 var TOP_DRAG_ENTER = unsafeCastStringToDOMTopLevelType('dragenter'); 1042 var TOP_DRAG_EXIT = unsafeCastStringToDOMTopLevelType('dragexit'); 1043 var TOP_DRAG_LEAVE = unsafeCastStringToDOMTopLevelType('dragleave'); 1044 var TOP_DRAG_OVER = unsafeCastStringToDOMTopLevelType('dragover'); 1045 var TOP_DRAG_START = unsafeCastStringToDOMTopLevelType('dragstart'); 1046 var TOP_DROP = unsafeCastStringToDOMTopLevelType('drop'); 1047 var TOP_DURATION_CHANGE = unsafeCastStringToDOMTopLevelType('durationchange'); 1048 var TOP_EMPTIED = unsafeCastStringToDOMTopLevelType('emptied'); 1049 var TOP_ENCRYPTED = unsafeCastStringToDOMTopLevelType('encrypted'); 1050 var TOP_ENDED = unsafeCastStringToDOMTopLevelType('ended'); 1051 var TOP_ERROR = unsafeCastStringToDOMTopLevelType('error'); 1052 var TOP_FOCUS = unsafeCastStringToDOMTopLevelType('focus'); 1053 var TOP_GOT_POINTER_CAPTURE = unsafeCastStringToDOMTopLevelType('gotpointercapture'); 1054 var TOP_INPUT = unsafeCastStringToDOMTopLevelType('input'); 1055 var TOP_INVALID = unsafeCastStringToDOMTopLevelType('invalid'); 1056 var TOP_KEY_DOWN = unsafeCastStringToDOMTopLevelType('keydown'); 1057 var TOP_KEY_PRESS = unsafeCastStringToDOMTopLevelType('keypress'); 1058 var TOP_KEY_UP = unsafeCastStringToDOMTopLevelType('keyup'); 1059 var TOP_LOAD = unsafeCastStringToDOMTopLevelType('load'); 1060 var TOP_LOAD_START = unsafeCastStringToDOMTopLevelType('loadstart'); 1061 var TOP_LOADED_DATA = unsafeCastStringToDOMTopLevelType('loadeddata'); 1062 var TOP_LOADED_METADATA = unsafeCastStringToDOMTopLevelType('loadedmetadata'); 1063 var TOP_LOST_POINTER_CAPTURE = unsafeCastStringToDOMTopLevelType('lostpointercapture'); 1064 var TOP_MOUSE_DOWN = unsafeCastStringToDOMTopLevelType('mousedown'); 1065 var TOP_MOUSE_MOVE = unsafeCastStringToDOMTopLevelType('mousemove'); 1066 var TOP_MOUSE_OUT = unsafeCastStringToDOMTopLevelType('mouseout'); 1067 var TOP_MOUSE_OVER = unsafeCastStringToDOMTopLevelType('mouseover'); 1068 var TOP_MOUSE_UP = unsafeCastStringToDOMTopLevelType('mouseup'); 1069 var TOP_PASTE = unsafeCastStringToDOMTopLevelType('paste'); 1070 var TOP_PAUSE = unsafeCastStringToDOMTopLevelType('pause'); 1071 var TOP_PLAY = unsafeCastStringToDOMTopLevelType('play'); 1072 var TOP_PLAYING = unsafeCastStringToDOMTopLevelType('playing'); 1073 var TOP_POINTER_CANCEL = unsafeCastStringToDOMTopLevelType('pointercancel'); 1074 var TOP_POINTER_DOWN = unsafeCastStringToDOMTopLevelType('pointerdown'); 1075 1076 1077 var TOP_POINTER_MOVE = unsafeCastStringToDOMTopLevelType('pointermove'); 1078 var TOP_POINTER_OUT = unsafeCastStringToDOMTopLevelType('pointerout'); 1079 var TOP_POINTER_OVER = unsafeCastStringToDOMTopLevelType('pointerover'); 1080 var TOP_POINTER_UP = unsafeCastStringToDOMTopLevelType('pointerup'); 1081 var TOP_PROGRESS = unsafeCastStringToDOMTopLevelType('progress'); 1082 var TOP_RATE_CHANGE = unsafeCastStringToDOMTopLevelType('ratechange'); 1083 var TOP_RESET = unsafeCastStringToDOMTopLevelType('reset'); 1084 var TOP_SCROLL = unsafeCastStringToDOMTopLevelType('scroll'); 1085 var TOP_SEEKED = unsafeCastStringToDOMTopLevelType('seeked'); 1086 var TOP_SEEKING = unsafeCastStringToDOMTopLevelType('seeking'); 1087 var TOP_SELECTION_CHANGE = unsafeCastStringToDOMTopLevelType('selectionchange'); 1088 var TOP_STALLED = unsafeCastStringToDOMTopLevelType('stalled'); 1089 var TOP_SUBMIT = unsafeCastStringToDOMTopLevelType('submit'); 1090 var TOP_SUSPEND = unsafeCastStringToDOMTopLevelType('suspend'); 1091 var TOP_TEXT_INPUT = unsafeCastStringToDOMTopLevelType('textInput'); 1092 var TOP_TIME_UPDATE = unsafeCastStringToDOMTopLevelType('timeupdate'); 1093 var TOP_TOGGLE = unsafeCastStringToDOMTopLevelType('toggle'); 1094 var TOP_TOUCH_CANCEL = unsafeCastStringToDOMTopLevelType('touchcancel'); 1095 var TOP_TOUCH_END = unsafeCastStringToDOMTopLevelType('touchend'); 1096 var TOP_TOUCH_MOVE = unsafeCastStringToDOMTopLevelType('touchmove'); 1097 var TOP_TOUCH_START = unsafeCastStringToDOMTopLevelType('touchstart'); 1098 var TOP_TRANSITION_END = unsafeCastStringToDOMTopLevelType(getVendorPrefixedEventName('transitionend')); 1099 var TOP_VOLUME_CHANGE = unsafeCastStringToDOMTopLevelType('volumechange'); 1100 var TOP_WAITING = unsafeCastStringToDOMTopLevelType('waiting'); 1101 var TOP_WHEEL = unsafeCastStringToDOMTopLevelType('wheel'); 1102 1103 // List of events that need to be individually attached to media elements. 1104 // Note that events in this list will *not* be listened to at the top level 1105 // unless they're explicitly whitelisted in `ReactBrowserEventEmitter.listenTo`. 1106 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]; 1107 1108 function getRawEventName(topLevelType) { 1109 return unsafeCastDOMTopLevelTypeToString(topLevelType); 1110 } 1111 1112 /** 1113 * These variables store information about text content of a target node, 1114 * allowing comparison of content before and after a given event. 1115 * 1116 * Identify the node where selection currently begins, then observe 1117 * both its text content and its current position in the DOM. Since the 1118 * browser may natively replace the target node during composition, we can 1119 * use its position to find its replacement. 1120 * 1121 * 1122 */ 1123 1124 var root = null; 1125 var startText = null; 1126 var fallbackText = null; 1127 1128 function initialize(nativeEventTarget) { 1129 root = nativeEventTarget; 1130 startText = getText(); 1131 return true; 1132 } 1133 1134 function reset() { 1135 root = null; 1136 startText = null; 1137 fallbackText = null; 1138 } 1139 1140 function getData() { 1141 if (fallbackText) { 1142 return fallbackText; 1143 } 1144 1145 var start = void 0; 1146 var startValue = startText; 1147 var startLength = startValue.length; 1148 var end = void 0; 1149 var endValue = getText(); 1150 var endLength = endValue.length; 1151 1152 for (start = 0; start < startLength; start++) { 1153 if (startValue[start] !== endValue[start]) { 1154 break; 1155 } 1156 } 1157 1158 var minEnd = startLength - start; 1159 for (end = 1; end <= minEnd; end++) { 1160 if (startValue[startLength - end] !== endValue[endLength - end]) { 1161 break; 1162 } 1163 } 1164 1165 var sliceTail = end > 1 ? 1 - end : undefined; 1166 fallbackText = endValue.slice(start, sliceTail); 1167 return fallbackText; 1168 } 1169 1170 function getText() { 1171 if ('value' in root) { 1172 return root.value; 1173 } 1174 return root.textContent; 1175 } 1176 1177 var ReactInternals = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; 1178 1179 var _assign = ReactInternals.assign; 1180 1181 /* eslint valid-typeof: 0 */ 1182 1183 var EVENT_POOL_SIZE = 10; 1184 1185 /** 1186 * @interface Event 1187 * @see http://www.w3.org/TR/DOM-Level-3-Events/ 1188 */ 1189 var EventInterface = { 1190 type: null, 1191 target: null, 1192 // currentTarget is set when dispatching; no use in copying it here 1193 currentTarget: function () { 1194 return null; 1195 }, 1196 eventPhase: null, 1197 bubbles: null, 1198 cancelable: null, 1199 timeStamp: function (event) { 1200 return event.timeStamp || Date.now(); 1201 }, 1202 defaultPrevented: null, 1203 isTrusted: null 1204 }; 1205 1206 function functionThatReturnsTrue() { 1207 return true; 1208 } 1209 1210 function functionThatReturnsFalse() { 1211 return false; 1212 } 1213 1214 /** 1215 * Synthetic events are dispatched by event plugins, typically in response to a 1216 * top-level event delegation handler. 1217 * 1218 * These systems should generally use pooling to reduce the frequency of garbage 1219 * collection. The system should check `isPersistent` to determine whether the 1220 * event should be released into the pool after being dispatched. Users that 1221 * need a persisted event should invoke `persist`. 1222 * 1223 * Synthetic events (and subclasses) implement the DOM Level 3 Events API by 1224 * normalizing browser quirks. Subclasses do not necessarily have to implement a 1225 * DOM interface; custom application-specific events can also subclass this. 1226 * 1227 * @param {object} dispatchConfig Configuration used to dispatch this event. 1228 * @param {*} targetInst Marker identifying the event target. 1229 * @param {object} nativeEvent Native browser event. 1230 * @param {DOMEventTarget} nativeEventTarget Target node. 1231 */ 1232 function SyntheticEvent(dispatchConfig, targetInst, nativeEvent, nativeEventTarget) { 1233 this.dispatchConfig = dispatchConfig; 1234 this._targetInst = targetInst; 1235 this.nativeEvent = nativeEvent; 1236 1237 var Interface = this.constructor.Interface; 1238 for (var propName in Interface) { 1239 if (!Interface.hasOwnProperty(propName)) { 1240 continue; 1241 } 1242 var normalize = Interface[propName]; 1243 if (normalize) { 1244 this[propName] = normalize(nativeEvent); 1245 } else { 1246 if (propName === 'target') { 1247 this.target = nativeEventTarget; 1248 } else { 1249 this[propName] = nativeEvent[propName]; 1250 } 1251 } 1252 } 1253 1254 var defaultPrevented = nativeEvent.defaultPrevented != null ? nativeEvent.defaultPrevented : nativeEvent.returnValue === false; 1255 if (defaultPrevented) { 1256 this.isDefaultPrevented = functionThatReturnsTrue; 1257 } else { 1258 this.isDefaultPrevented = functionThatReturnsFalse; 1259 } 1260 this.isPropagationStopped = functionThatReturnsFalse; 1261 return this; 1262 } 1263 1264 _assign(SyntheticEvent.prototype, { 1265 preventDefault: function () { 1266 this.defaultPrevented = true; 1267 var event = this.nativeEvent; 1268 if (!event) { 1269 return; 1270 } 1271 1272 if (event.preventDefault) { 1273 event.preventDefault(); 1274 } else if (typeof event.returnValue !== 'unknown') { 1275 event.returnValue = false; 1276 } 1277 this.isDefaultPrevented = functionThatReturnsTrue; 1278 }, 1279 1280 stopPropagation: function () { 1281 var event = this.nativeEvent; 1282 if (!event) { 1283 return; 1284 } 1285 1286 if (event.stopPropagation) { 1287 event.stopPropagation(); 1288 } else if (typeof event.cancelBubble !== 'unknown') { 1289 // The ChangeEventPlugin registers a "propertychange" event for 1290 // IE. This event does not support bubbling or cancelling, and 1291 // any references to cancelBubble throw "Member not found". A 1292 // typeof check of "unknown" circumvents this issue (and is also 1293 // IE specific). 1294 event.cancelBubble = true; 1295 } 1296 1297 this.isPropagationStopped = functionThatReturnsTrue; 1298 }, 1299 1300 /** 1301 * We release all dispatched `SyntheticEvent`s after each event loop, adding 1302 * them back into the pool. This allows a way to hold onto a reference that 1303 * won't be added back into the pool. 1304 */ 1305 persist: function () { 1306 this.isPersistent = functionThatReturnsTrue; 1307 }, 1308 1309 /** 1310 * Checks if this event should be released back into the pool. 1311 * 1312 * @return {boolean} True if this should not be released, false otherwise. 1313 */ 1314 isPersistent: functionThatReturnsFalse, 1315 1316 /** 1317 * `PooledClass` looks for `destructor` on each instance it releases. 1318 */ 1319 destructor: function () { 1320 var Interface = this.constructor.Interface; 1321 for (var propName in Interface) { 1322 { 1323 this[propName] = null; 1324 } 1325 } 1326 this.dispatchConfig = null; 1327 this._targetInst = null; 1328 this.nativeEvent = null; 1329 this.isDefaultPrevented = functionThatReturnsFalse; 1330 this.isPropagationStopped = functionThatReturnsFalse; 1331 this._dispatchListeners = null; 1332 this._dispatchInstances = null; 1333 1334 } 1335 }); 1336 1337 SyntheticEvent.Interface = EventInterface; 1338 1339 /** 1340 * Helper to reduce boilerplate when creating subclasses. 1341 */ 1342 SyntheticEvent.extend = function (Interface) { 1343 var Super = this; 1344 1345 var E = function () {}; 1346 E.prototype = Super.prototype; 1347 var prototype = new E(); 1348 1349 function Class() { 1350 return Super.apply(this, arguments); 1351 } 1352 _assign(prototype, Class.prototype); 1353 Class.prototype = prototype; 1354 Class.prototype.constructor = Class; 1355 1356 Class.Interface = _assign({}, Super.Interface, Interface); 1357 Class.extend = Super.extend; 1358 addEventPoolingTo(Class); 1359 1360 return Class; 1361 }; 1362 1363 addEventPoolingTo(SyntheticEvent); 1364 1365 function getPooledEvent(dispatchConfig, targetInst, nativeEvent, nativeInst) { 1366 var EventConstructor = this; 1367 if (EventConstructor.eventPool.length) { 1368 var instance = EventConstructor.eventPool.pop(); 1369 EventConstructor.call(instance, dispatchConfig, targetInst, nativeEvent, nativeInst); 1370 return instance; 1371 } 1372 return new EventConstructor(dispatchConfig, targetInst, nativeEvent, nativeInst); 1373 } 1374 1375 function releasePooledEvent(event) { 1376 var EventConstructor = this; 1377 !(event instanceof EventConstructor) ? reactProdInvariant('279') : void 0; 1378 event.destructor(); 1379 if (EventConstructor.eventPool.length < EVENT_POOL_SIZE) { 1380 EventConstructor.eventPool.push(event); 1381 } 1382 } 1383 1384 function addEventPoolingTo(EventConstructor) { 1385 EventConstructor.eventPool = []; 1386 EventConstructor.getPooled = getPooledEvent; 1387 EventConstructor.release = releasePooledEvent; 1388 } 1389 1390 /** 1391 * @interface Event 1392 * @see http://www.w3.org/TR/DOM-Level-3-Events/#events-compositionevents 1393 */ 1394 var SyntheticCompositionEvent = SyntheticEvent.extend({ 1395 data: null 1396 }); 1397 1398 /** 1399 * @interface Event 1400 * @see http://www.w3.org/TR/2013/WD-DOM-Level-3-Events-20131105 1401 * /#events-inputevents 1402 */ 1403 var SyntheticInputEvent = SyntheticEvent.extend({ 1404 data: null 1405 }); 1406 1407 var END_KEYCODES = [9, 13, 27, 32]; // Tab, Return, Esc, Space 1408 var START_KEYCODE = 229; 1409 1410 var canUseCompositionEvent = canUseDOM && 'CompositionEvent' in window; 1411 1412 var documentMode = null; 1413 if (canUseDOM && 'documentMode' in document) { 1414 documentMode = document.documentMode; 1415 } 1416 1417 // Webkit offers a very useful `textInput` event that can be used to 1418 // directly represent `beforeInput`. The IE `textinput` event is not as 1419 // useful, so we don't use it. 1420 var canUseTextInputEvent = canUseDOM && 'TextEvent' in window && !documentMode; 1421 1422 // In IE9+, we have access to composition events, but the data supplied 1423 // by the native compositionend event may be incorrect. Japanese ideographic 1424 // spaces, for instance (\u3000) are not recorded correctly. 1425 var useFallbackCompositionData = canUseDOM && (!canUseCompositionEvent || documentMode && documentMode > 8 && documentMode <= 11); 1426 1427 var SPACEBAR_CODE = 32; 1428 var SPACEBAR_CHAR = String.fromCharCode(SPACEBAR_CODE); 1429 1430 // Events and their corresponding property names. 1431 var eventTypes = { 1432 beforeInput: { 1433 phasedRegistrationNames: { 1434 bubbled: 'onBeforeInput', 1435 captured: 'onBeforeInputCapture' 1436 }, 1437 dependencies: [TOP_COMPOSITION_END, TOP_KEY_PRESS, TOP_TEXT_INPUT, TOP_PASTE] 1438 }, 1439 compositionEnd: { 1440 phasedRegistrationNames: { 1441 bubbled: 'onCompositionEnd', 1442 captured: 'onCompositionEndCapture' 1443 }, 1444 dependencies: [TOP_BLUR, TOP_COMPOSITION_END, TOP_KEY_DOWN, TOP_KEY_PRESS, TOP_KEY_UP, TOP_MOUSE_DOWN] 1445 }, 1446 compositionStart: { 1447 phasedRegistrationNames: { 1448 bubbled: 'onCompositionStart', 1449 captured: 'onCompositionStartCapture' 1450 }, 1451 dependencies: [TOP_BLUR, TOP_COMPOSITION_START, TOP_KEY_DOWN, TOP_KEY_PRESS, TOP_KEY_UP, TOP_MOUSE_DOWN] 1452 }, 1453 compositionUpdate: { 1454 phasedRegistrationNames: { 1455 bubbled: 'onCompositionUpdate', 1456 captured: 'onCompositionUpdateCapture' 1457 }, 1458 dependencies: [TOP_BLUR, TOP_COMPOSITION_UPDATE, TOP_KEY_DOWN, TOP_KEY_PRESS, TOP_KEY_UP, TOP_MOUSE_DOWN] 1459 } 1460 }; 1461 1462 // Track whether we've ever handled a keypress on the space key. 1463 var hasSpaceKeypress = false; 1464 1465 /** 1466 * Return whether a native keypress event is assumed to be a command. 1467 * This is required because Firefox fires `keypress` events for key commands 1468 * (cut, copy, select-all, etc.) even though no character is inserted. 1469 */ 1470 function isKeypressCommand(nativeEvent) { 1471 return (nativeEvent.ctrlKey || nativeEvent.altKey || nativeEvent.metaKey) && 1472 // ctrlKey && altKey is equivalent to AltGr, and is not a command. 1473 !(nativeEvent.ctrlKey && nativeEvent.altKey); 1474 } 1475 1476 /** 1477 * Translate native top level events into event types. 1478 * 1479 * @param {string} topLevelType 1480 * @return {object} 1481 */ 1482 function getCompositionEventType(topLevelType) { 1483 switch (topLevelType) { 1484 case TOP_COMPOSITION_START: 1485 return eventTypes.compositionStart; 1486 case TOP_COMPOSITION_END: 1487 return eventTypes.compositionEnd; 1488 case TOP_COMPOSITION_UPDATE: 1489 return eventTypes.compositionUpdate; 1490 } 1491 } 1492 1493 /** 1494 * Does our fallback best-guess model think this event signifies that 1495 * composition has begun? 1496 * 1497 * @param {string} topLevelType 1498 * @param {object} nativeEvent 1499 * @return {boolean} 1500 */ 1501 function isFallbackCompositionStart(topLevelType, nativeEvent) { 1502 return topLevelType === TOP_KEY_DOWN && nativeEvent.keyCode === START_KEYCODE; 1503 } 1504 1505 /** 1506 * Does our fallback mode think that this event is the end of composition? 1507 * 1508 * @param {string} topLevelType 1509 * @param {object} nativeEvent 1510 * @return {boolean} 1511 */ 1512 function isFallbackCompositionEnd(topLevelType, nativeEvent) { 1513 switch (topLevelType) { 1514 case TOP_KEY_UP: 1515 // Command keys insert or clear IME input. 1516 return END_KEYCODES.indexOf(nativeEvent.keyCode) !== -1; 1517 case TOP_KEY_DOWN: 1518 // Expect IME keyCode on each keydown. If we get any other 1519 // code we must have exited earlier. 1520 return nativeEvent.keyCode !== START_KEYCODE; 1521 case TOP_KEY_PRESS: 1522 case TOP_MOUSE_DOWN: 1523 case TOP_BLUR: 1524 // Events are not possible without cancelling IME. 1525 return true; 1526 default: 1527 return false; 1528 } 1529 } 1530 1531 /** 1532 * Google Input Tools provides composition data via a CustomEvent, 1533 * with the `data` property populated in the `detail` object. If this 1534 * is available on the event object, use it. If not, this is a plain 1535 * composition event and we have nothing special to extract. 1536 * 1537 * @param {object} nativeEvent 1538 * @return {?string} 1539 */ 1540 function getDataFromCustomEvent(nativeEvent) { 1541 var detail = nativeEvent.detail; 1542 if (typeof detail === 'object' && 'data' in detail) { 1543 return detail.data; 1544 } 1545 return null; 1546 } 1547 1548 /** 1549 * Check if a composition event was triggered by Korean IME. 1550 * Our fallback mode does not work well with IE's Korean IME, 1551 * so just use native composition events when Korean IME is used. 1552 * Although CompositionEvent.locale property is deprecated, 1553 * it is available in IE, where our fallback mode is enabled. 1554 * 1555 * @param {object} nativeEvent 1556 * @return {boolean} 1557 */ 1558 function isUsingKoreanIME(nativeEvent) { 1559 return nativeEvent.locale === 'ko'; 1560 } 1561 1562 // Track the current IME composition status, if any. 1563 var isComposing = false; 1564 1565 /** 1566 * @return {?object} A SyntheticCompositionEvent. 1567 */ 1568 function extractCompositionEvent(topLevelType, targetInst, nativeEvent, nativeEventTarget) { 1569 var eventType = void 0; 1570 var fallbackData = void 0; 1571 1572 if (canUseCompositionEvent) { 1573 eventType = getCompositionEventType(topLevelType); 1574 } else if (!isComposing) { 1575 if (isFallbackCompositionStart(topLevelType, nativeEvent)) { 1576 eventType = eventTypes.compositionStart; 1577 } 1578 } else if (isFallbackCompositionEnd(topLevelType, nativeEvent)) { 1579 eventType = eventTypes.compositionEnd; 1580 } 1581 1582 if (!eventType) { 1583 return null; 1584 } 1585 1586 if (useFallbackCompositionData && !isUsingKoreanIME(nativeEvent)) { 1587 // The current composition is stored statically and must not be 1588 // overwritten while composition continues. 1589 if (!isComposing && eventType === eventTypes.compositionStart) { 1590 isComposing = initialize(nativeEventTarget); 1591 } else if (eventType === eventTypes.compositionEnd) { 1592 if (isComposing) { 1593 fallbackData = getData(); 1594 } 1595 } 1596 } 1597 1598 var event = SyntheticCompositionEvent.getPooled(eventType, targetInst, nativeEvent, nativeEventTarget); 1599 1600 if (fallbackData) { 1601 // Inject data generated from fallback path into the synthetic event. 1602 // This matches the property of native CompositionEventInterface. 1603 event.data = fallbackData; 1604 } else { 1605 var customData = getDataFromCustomEvent(nativeEvent); 1606 if (customData !== null) { 1607 event.data = customData; 1608 } 1609 } 1610 1611 accumulateTwoPhaseDispatches(event); 1612 return event; 1613 } 1614 1615 /** 1616 * @param {TopLevelType} topLevelType Number from `TopLevelType`. 1617 * @param {object} nativeEvent Native browser event. 1618 * @return {?string} The string corresponding to this `beforeInput` event. 1619 */ 1620 function getNativeBeforeInputChars(topLevelType, nativeEvent) { 1621 switch (topLevelType) { 1622 case TOP_COMPOSITION_END: 1623 return getDataFromCustomEvent(nativeEvent); 1624 case TOP_KEY_PRESS: 1625 /** 1626 * If native `textInput` events are available, our goal is to make 1627 * use of them. However, there is a special case: the spacebar key. 1628 * In Webkit, preventing default on a spacebar `textInput` event 1629 * cancels character insertion, but it *also* causes the browser 1630 * to fall back to its default spacebar behavior of scrolling the 1631 * page. 1632 * 1633 * Tracking at: 1634 * https://code.google.com/p/chromium/issues/detail?id=355103 1635 * 1636 * To avoid this issue, use the keypress event as if no `textInput` 1637 * event is available. 1638 */ 1639 var which = nativeEvent.which; 1640 if (which !== SPACEBAR_CODE) { 1641 return null; 1642 } 1643 1644 hasSpaceKeypress = true; 1645 return SPACEBAR_CHAR; 1646 1647 case TOP_TEXT_INPUT: 1648 // Record the characters to be added to the DOM. 1649 var chars = nativeEvent.data; 1650 1651 // If it's a spacebar character, assume that we have already handled 1652 // it at the keypress level and bail immediately. Android Chrome 1653 // doesn't give us keycodes, so we need to ignore it. 1654 if (chars === SPACEBAR_CHAR && hasSpaceKeypress) { 1655 return null; 1656 } 1657 1658 return chars; 1659 1660 default: 1661 // For other native event types, do nothing. 1662 return null; 1663 } 1664 } 1665 1666 /** 1667 * For browsers that do not provide the `textInput` event, extract the 1668 * appropriate string to use for SyntheticInputEvent. 1669 * 1670 * @param {number} topLevelType Number from `TopLevelEventTypes`. 1671 * @param {object} nativeEvent Native browser event. 1672 * @return {?string} The fallback string for this `beforeInput` event. 1673 */ 1674 function getFallbackBeforeInputChars(topLevelType, nativeEvent) { 1675 // If we are currently composing (IME) and using a fallback to do so, 1676 // try to extract the composed characters from the fallback object. 1677 // If composition event is available, we extract a string only at 1678 // compositionevent, otherwise extract it at fallback events. 1679 if (isComposing) { 1680 if (topLevelType === TOP_COMPOSITION_END || !canUseCompositionEvent && isFallbackCompositionEnd(topLevelType, nativeEvent)) { 1681 var chars = getData(); 1682 reset(); 1683 isComposing = false; 1684 return chars; 1685 } 1686 return null; 1687 } 1688 1689 switch (topLevelType) { 1690 case TOP_PASTE: 1691 // If a paste event occurs after a keypress, throw out the input 1692 // chars. Paste events should not lead to BeforeInput events. 1693 return null; 1694 case TOP_KEY_PRESS: 1695 /** 1696 * As of v27, Firefox may fire keypress events even when no character 1697 * will be inserted. A few possibilities: 1698 * 1699 * - `which` is `0`. Arrow keys, Esc key, etc. 1700 * 1701 * - `which` is the pressed key code, but no char is available. 1702 * Ex: 'AltGr + d` in Polish. There is no modified character for 1703 * this key combination and no character is inserted into the 1704 * document, but FF fires the keypress for char code `100` anyway. 1705 * No `input` event will occur. 1706 * 1707 * - `which` is the pressed key code, but a command combination is 1708 * being used. Ex: `Cmd+C`. No character is inserted, and no 1709 * `input` event will occur. 1710 */ 1711 if (!isKeypressCommand(nativeEvent)) { 1712 // IE fires the `keypress` event when a user types an emoji via 1713 // Touch keyboard of Windows. In such a case, the `char` property 1714 // holds an emoji character like `\uD83D\uDE0A`. Because its length 1715 // is 2, the property `which` does not represent an emoji correctly. 1716 // In such a case, we directly return the `char` property instead of 1717 // using `which`. 1718 if (nativeEvent.char && nativeEvent.char.length > 1) { 1719 return nativeEvent.char; 1720 } else if (nativeEvent.which) { 1721 return String.fromCharCode(nativeEvent.which); 1722 } 1723 } 1724 return null; 1725 case TOP_COMPOSITION_END: 1726 return useFallbackCompositionData && !isUsingKoreanIME(nativeEvent) ? null : nativeEvent.data; 1727 default: 1728 return null; 1729 } 1730 } 1731 1732 /** 1733 * Extract a SyntheticInputEvent for `beforeInput`, based on either native 1734 * `textInput` or fallback behavior. 1735 * 1736 * @return {?object} A SyntheticInputEvent. 1737 */ 1738 function extractBeforeInputEvent(topLevelType, targetInst, nativeEvent, nativeEventTarget) { 1739 var chars = void 0; 1740 1741 if (canUseTextInputEvent) { 1742 chars = getNativeBeforeInputChars(topLevelType, nativeEvent); 1743 } else { 1744 chars = getFallbackBeforeInputChars(topLevelType, nativeEvent); 1745 } 1746 1747 // If no characters are being inserted, no BeforeInput event should 1748 // be fired. 1749 if (!chars) { 1750 return null; 1751 } 1752 1753 var event = SyntheticInputEvent.getPooled(eventTypes.beforeInput, targetInst, nativeEvent, nativeEventTarget); 1754 1755 event.data = chars; 1756 accumulateTwoPhaseDispatches(event); 1757 return event; 1758 } 1759 1760 /** 1761 * Create an `onBeforeInput` event to match 1762 * http://www.w3.org/TR/2013/WD-DOM-Level-3-Events-20131105/#events-inputevents. 1763 * 1764 * This event plugin is based on the native `textInput` event 1765 * available in Chrome, Safari, Opera, and IE. This event fires after 1766 * `onKeyPress` and `onCompositionEnd`, but before `onInput`. 1767 * 1768 * `beforeInput` is spec'd but not implemented in any browsers, and 1769 * the `input` event does not provide any useful information about what has 1770 * actually been added, contrary to the spec. Thus, `textInput` is the best 1771 * available event to identify the characters that have actually been inserted 1772 * into the target node. 1773 * 1774 * This plugin is also responsible for emitting `composition` events, thus 1775 * allowing us to share composition fallback code for both `beforeInput` and 1776 * `composition` event types. 1777 */ 1778 var BeforeInputEventPlugin = { 1779 eventTypes: eventTypes, 1780 1781 extractEvents: function (topLevelType, targetInst, nativeEvent, nativeEventTarget) { 1782 var composition = extractCompositionEvent(topLevelType, targetInst, nativeEvent, nativeEventTarget); 1783 1784 var beforeInput = extractBeforeInputEvent(topLevelType, targetInst, nativeEvent, nativeEventTarget); 1785 1786 if (composition === null) { 1787 return beforeInput; 1788 } 1789 1790 if (beforeInput === null) { 1791 return composition; 1792 } 1793 1794 return [composition, beforeInput]; 1795 } 1796 }; 1797 1798 // Use to restore controlled state after a change event has fired. 1799 1800 var restoreImpl = null; 1801 var restoreTarget = null; 1802 var restoreQueue = null; 1803 1804 function restoreStateOfTarget(target) { 1805 // We perform this translation at the end of the event loop so that we 1806 // always receive the correct fiber here 1807 var internalInstance = getInstanceFromNode(target); 1808 if (!internalInstance) { 1809 // Unmounted 1810 return; 1811 } 1812 !(typeof restoreImpl === 'function') ? reactProdInvariant('280') : void 0; 1813 var props = getFiberCurrentPropsFromNode(internalInstance.stateNode); 1814 restoreImpl(internalInstance.stateNode, internalInstance.type, props); 1815 } 1816 1817 function setRestoreImplementation(impl) { 1818 restoreImpl = impl; 1819 } 1820 1821 function enqueueStateRestore(target) { 1822 if (restoreTarget) { 1823 if (restoreQueue) { 1824 restoreQueue.push(target); 1825 } else { 1826 restoreQueue = [target]; 1827 } 1828 } else { 1829 restoreTarget = target; 1830 } 1831 } 1832 1833 function needsStateRestore() { 1834 return restoreTarget !== null || restoreQueue !== null; 1835 } 1836 1837 function restoreStateIfNeeded() { 1838 if (!restoreTarget) { 1839 return; 1840 } 1841 var target = restoreTarget; 1842 var queuedTargets = restoreQueue; 1843 restoreTarget = null; 1844 restoreQueue = null; 1845 1846 restoreStateOfTarget(target); 1847 if (queuedTargets) { 1848 for (var i = 0; i < queuedTargets.length; i++) { 1849 restoreStateOfTarget(queuedTargets[i]); 1850 } 1851 } 1852 } 1853 1854 // Used as a way to call batchedUpdates when we don't have a reference to 1855 // the renderer. Such as when we're dispatching events or if third party 1856 // libraries need to call batchedUpdates. Eventually, this API will go away when 1857 // everything is batched by default. We'll then have a similar API to opt-out of 1858 // scheduled work and instead do synchronous work. 1859 1860 // Defaults 1861 var _batchedUpdatesImpl = function (fn, bookkeeping) { 1862 return fn(bookkeeping); 1863 }; 1864 var _interactiveUpdatesImpl = function (fn, a, b) { 1865 return fn(a, b); 1866 }; 1867 var _flushInteractiveUpdatesImpl = function () {}; 1868 1869 var isBatching = false; 1870 function batchedUpdates(fn, bookkeeping) { 1871 if (isBatching) { 1872 // If we are currently inside another batch, we need to wait until it 1873 // fully completes before restoring state. 1874 return fn(bookkeeping); 1875 } 1876 isBatching = true; 1877 try { 1878 return _batchedUpdatesImpl(fn, bookkeeping); 1879 } finally { 1880 // Here we wait until all updates have propagated, which is important 1881 // when using controlled components within layers: 1882 // https://github.com/facebook/react/issues/1698 1883 // Then we restore state of any controlled component. 1884 isBatching = false; 1885 var controlledComponentsHavePendingUpdates = needsStateRestore(); 1886 if (controlledComponentsHavePendingUpdates) { 1887 // If a controlled event was fired, we may need to restore the state of 1888 // the DOM node back to the controlled value. This is necessary when React 1889 // bails out of the update without touching the DOM. 1890 _flushInteractiveUpdatesImpl(); 1891 restoreStateIfNeeded(); 1892 } 1893 } 1894 } 1895 1896 function interactiveUpdates(fn, a, b) { 1897 return _interactiveUpdatesImpl(fn, a, b); 1898 } 1899 1900 1901 1902 function setBatchingImplementation(batchedUpdatesImpl, interactiveUpdatesImpl, flushInteractiveUpdatesImpl) { 1903 _batchedUpdatesImpl = batchedUpdatesImpl; 1904 _interactiveUpdatesImpl = interactiveUpdatesImpl; 1905 _flushInteractiveUpdatesImpl = flushInteractiveUpdatesImpl; 1906 } 1907 1908 /** 1909 * @see http://www.whatwg.org/specs/web-apps/current-work/multipage/the-input-element.html#input-type-attr-summary 1910 */ 1911 var supportedInputTypes = { 1912 color: true, 1913 date: true, 1914 datetime: true, 1915 'datetime-local': true, 1916 email: true, 1917 month: true, 1918 number: true, 1919 password: true, 1920 range: true, 1921 search: true, 1922 tel: true, 1923 text: true, 1924 time: true, 1925 url: true, 1926 week: true 1927 }; 1928 1929 function isTextInputElement(elem) { 1930 var nodeName = elem && elem.nodeName && elem.nodeName.toLowerCase(); 1931 1932 if (nodeName === 'input') { 1933 return !!supportedInputTypes[elem.type]; 1934 } 1935 1936 if (nodeName === 'textarea') { 1937 return true; 1938 } 1939 1940 return false; 1941 } 1942 1943 /** 1944 * HTML nodeType values that represent the type of the node 1945 */ 1946 1947 var ELEMENT_NODE = 1; 1948 var TEXT_NODE = 3; 1949 var COMMENT_NODE = 8; 1950 var DOCUMENT_NODE = 9; 1951 var DOCUMENT_FRAGMENT_NODE = 11; 1952 1953 /** 1954 * Gets the target node from a native browser event by accounting for 1955 * inconsistencies in browser DOM APIs. 1956 * 1957 * @param {object} nativeEvent Native browser event. 1958 * @return {DOMEventTarget} Target node. 1959 */ 1960 function getEventTarget(nativeEvent) { 1961 // Fallback to nativeEvent.srcElement for IE9 1962 // https://github.com/facebook/react/issues/12506 1963 var target = nativeEvent.target || nativeEvent.srcElement || window; 1964 1965 // Normalize SVG <use> element events #4963 1966 if (target.correspondingUseElement) { 1967 target = target.correspondingUseElement; 1968 } 1969 1970 // Safari may fire events on text nodes (Node.TEXT_NODE is 3). 1971 // @see http://www.quirksmode.org/js/events_properties.html 1972 return target.nodeType === TEXT_NODE ? target.parentNode : target; 1973 } 1974 1975 /** 1976 * Checks if an event is supported in the current execution environment. 1977 * 1978 * NOTE: This will not work correctly for non-generic events such as `change`, 1979 * `reset`, `load`, `error`, and `select`. 1980 * 1981 * Borrows from Modernizr. 1982 * 1983 * @param {string} eventNameSuffix Event name, e.g. "click". 1984 * @return {boolean} True if the event is supported. 1985 * @internal 1986 * @license Modernizr 3.0.0pre (Custom Build) | MIT 1987 */ 1988 function isEventSupported(eventNameSuffix) { 1989 if (!canUseDOM) { 1990 return false; 1991 } 1992 1993 var eventName = 'on' + eventNameSuffix; 1994 var isSupported = eventName in document; 1995 1996 if (!isSupported) { 1997 var element = document.createElementNS('http://www.w3.org/1999/xhtml', 'div'); 1998 element.setAttribute(eventName, 'return;'); 1999 isSupported = typeof element[eventName] === 'function'; 2000 } 2001 2002 return isSupported; 2003 } 2004 2005 function isCheckable(elem) { 2006 var type = elem.type; 2007 var nodeName = elem.nodeName; 2008 return nodeName && nodeName.toLowerCase() === 'input' && (type === 'checkbox' || type === 'radio'); 2009 } 2010 2011 function getTracker(node) { 2012 return node._valueTracker; 2013 } 2014 2015 function detachTracker(node) { 2016 node._valueTracker = null; 2017 } 2018 2019 function getValueFromNode(node) { 2020 var value = ''; 2021 if (!node) { 2022 return value; 2023 } 2024 2025 if (isCheckable(node)) { 2026 value = node.checked ? 'true' : 'false'; 2027 } else { 2028 value = node.value; 2029 } 2030 2031 return value; 2032 } 2033 2034 function trackValueOnNode(node) { 2035 var valueField = isCheckable(node) ? 'checked' : 'value'; 2036 var descriptor = Object.getOwnPropertyDescriptor(node.constructor.prototype, valueField); 2037 2038 var currentValue = '' + node[valueField]; 2039 2040 // if someone has already defined a value or Safari, then bail 2041 // and don't track value will cause over reporting of changes, 2042 // but it's better then a hard failure 2043 // (needed for certain tests that spyOn input values and Safari) 2044 if (node.hasOwnProperty(valueField) || typeof descriptor === 'undefined' || typeof descriptor.get !== 'function' || typeof descriptor.set !== 'function') { 2045 return; 2046 } 2047 var get = descriptor.get, 2048 set = descriptor.set; 2049 2050 Object.defineProperty(node, valueField, { 2051 configurable: true, 2052 get: function () { 2053 return get.call(this); 2054 }, 2055 set: function (value) { 2056 currentValue = '' + value; 2057 set.call(this, value); 2058 } 2059 }); 2060 // We could've passed this the first time 2061 // but it triggers a bug in IE11 and Edge 14/15. 2062 // Calling defineProperty() again should be equivalent. 2063 // https://github.com/facebook/react/issues/11768 2064 Object.defineProperty(node, valueField, { 2065 enumerable: descriptor.enumerable 2066 }); 2067 2068 var tracker = { 2069 getValue: function () { 2070 return currentValue; 2071 }, 2072 setValue: function (value) { 2073 currentValue = '' + value; 2074 }, 2075 stopTracking: function () { 2076 detachTracker(node); 2077 delete node[valueField]; 2078 } 2079 }; 2080 return tracker; 2081 } 2082 2083 function track(node) { 2084 if (getTracker(node)) { 2085 return; 2086 } 2087 2088 // TODO: Once it's just Fiber we can move this to node._wrapperState 2089 node._valueTracker = trackValueOnNode(node); 2090 } 2091 2092 function updateValueIfChanged(node) { 2093 if (!node) { 2094 return false; 2095 } 2096 2097 var tracker = getTracker(node); 2098 // if there is no tracker at this point it's unlikely 2099 // that trying again will succeed 2100 if (!tracker) { 2101 return true; 2102 } 2103 2104 var lastValue = tracker.getValue(); 2105 var nextValue = getValueFromNode(node); 2106 if (nextValue !== lastValue) { 2107 tracker.setValue(nextValue); 2108 return true; 2109 } 2110 return false; 2111 } 2112 2113 var ReactSharedInternals = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; 2114 2115 // Prevent newer renderers from RTE when used with older react package versions. 2116 // Current owner and dispatcher used to share the same ref, 2117 // but PR #14548 split them out to better support the react-debug-tools package. 2118 if (!ReactSharedInternals.hasOwnProperty('ReactCurrentDispatcher')) { 2119 ReactSharedInternals.ReactCurrentDispatcher = { 2120 current: null 2121 }; 2122 } 2123 2124 var BEFORE_SLASH_RE = /^(.*)[\\\/]/; 2125 2126 var describeComponentFrame = function (name, source, ownerName) { 2127 var sourceInfo = ''; 2128 if (source) { 2129 var path = source.fileName; 2130 var fileName = path.replace(BEFORE_SLASH_RE, ''); 2131 sourceInfo = ' (at ' + fileName + ':' + source.lineNumber + ')'; 2132 } else if (ownerName) { 2133 sourceInfo = ' (created by ' + ownerName + ')'; 2134 } 2135 return '\n in ' + (name || 'Unknown') + sourceInfo; 2136 }; 2137 2138 // The Symbol used to tag the ReactElement-like types. If there is no native Symbol 2139 // nor polyfill, then a plain number is used for performance. 2140 var hasSymbol = typeof Symbol === 'function' && Symbol.for; 2141 2142 var REACT_ELEMENT_TYPE = hasSymbol ? Symbol.for('react.element') : 0xeac7; 2143 var REACT_PORTAL_TYPE = hasSymbol ? Symbol.for('react.portal') : 0xeaca; 2144 var REACT_FRAGMENT_TYPE = hasSymbol ? Symbol.for('react.fragment') : 0xeacb; 2145 var REACT_STRICT_MODE_TYPE = hasSymbol ? Symbol.for('react.strict_mode') : 0xeacc; 2146 var REACT_PROFILER_TYPE = hasSymbol ? Symbol.for('react.profiler') : 0xead2; 2147 var REACT_PROVIDER_TYPE = hasSymbol ? Symbol.for('react.provider') : 0xeacd; 2148 var REACT_CONTEXT_TYPE = hasSymbol ? Symbol.for('react.context') : 0xeace; 2149 2150 var REACT_CONCURRENT_MODE_TYPE = hasSymbol ? Symbol.for('react.concurrent_mode') : 0xeacf; 2151 var REACT_FORWARD_REF_TYPE = hasSymbol ? Symbol.for('react.forward_ref') : 0xead0; 2152 var REACT_SUSPENSE_TYPE = hasSymbol ? Symbol.for('react.suspense') : 0xead1; 2153 var REACT_MEMO_TYPE = hasSymbol ? Symbol.for('react.memo') : 0xead3; 2154 var REACT_LAZY_TYPE = hasSymbol ? Symbol.for('react.lazy') : 0xead4; 2155 2156 var MAYBE_ITERATOR_SYMBOL = typeof Symbol === 'function' && Symbol.iterator; 2157 var FAUX_ITERATOR_SYMBOL = '@@iterator'; 2158 2159 function getIteratorFn(maybeIterable) { 2160 if (maybeIterable === null || typeof maybeIterable !== 'object') { 2161 return null; 2162 } 2163 var maybeIterator = MAYBE_ITERATOR_SYMBOL && maybeIterable[MAYBE_ITERATOR_SYMBOL] || maybeIterable[FAUX_ITERATOR_SYMBOL]; 2164 if (typeof maybeIterator === 'function') { 2165 return maybeIterator; 2166 } 2167 return null; 2168 } 2169 2170 var Pending = 0; 2171 var Resolved = 1; 2172 var Rejected = 2; 2173 2174 function refineResolvedLazyComponent(lazyComponent) { 2175 return lazyComponent._status === Resolved ? lazyComponent._result : null; 2176 } 2177 2178 function getWrappedName(outerType, innerType, wrapperName) { 2179 var functionName = innerType.displayName || innerType.name || ''; 2180 return outerType.displayName || (functionName !== '' ? wrapperName + '(' + functionName + ')' : wrapperName); 2181 } 2182 2183 function getComponentName(type) { 2184 if (type == null) { 2185 // Host root, text node or just invalid type. 2186 return null; 2187 } 2188 if (typeof type === 'function') { 2189 return type.displayName || type.name || null; 2190 } 2191 if (typeof type === 'string') { 2192 return type; 2193 } 2194 switch (type) { 2195 case REACT_CONCURRENT_MODE_TYPE: 2196 return 'ConcurrentMode'; 2197 case REACT_FRAGMENT_TYPE: 2198 return 'Fragment'; 2199 case REACT_PORTAL_TYPE: 2200 return 'Portal'; 2201 case REACT_PROFILER_TYPE: 2202 return 'Profiler'; 2203 case REACT_STRICT_MODE_TYPE: 2204 return 'StrictMode'; 2205 case REACT_SUSPENSE_TYPE: 2206 return 'Suspense'; 2207 } 2208 if (typeof type === 'object') { 2209 switch (type.$$typeof) { 2210 case REACT_CONTEXT_TYPE: 2211 return 'Context.Consumer'; 2212 case REACT_PROVIDER_TYPE: 2213 return 'Context.Provider'; 2214 case REACT_FORWARD_REF_TYPE: 2215 return getWrappedName(type, type.render, 'ForwardRef'); 2216 case REACT_MEMO_TYPE: 2217 return getComponentName(type.type); 2218 case REACT_LAZY_TYPE: 2219 { 2220 var thenable = type; 2221 var resolvedThenable = refineResolvedLazyComponent(thenable); 2222 if (resolvedThenable) { 2223 return getComponentName(resolvedThenable); 2224 } 2225 } 2226 } 2227 } 2228 return null; 2229 } 2230 2231 var ReactDebugCurrentFrame = ReactSharedInternals.ReactDebugCurrentFrame; 2232 2233 function describeFiber(fiber) { 2234 switch (fiber.tag) { 2235 case HostRoot: 2236 case HostPortal: 2237 case HostText: 2238 case Fragment: 2239 case ContextProvider: 2240 case ContextConsumer: 2241 return ''; 2242 default: 2243 var owner = fiber._debugOwner; 2244 var source = fiber._debugSource; 2245 var name = getComponentName(fiber.type); 2246 var ownerName = null; 2247 if (owner) { 2248 ownerName = getComponentName(owner.type); 2249 } 2250 return describeComponentFrame(name, source, ownerName); 2251 } 2252 } 2253 2254 function getStackByFiberInDevAndProd(workInProgress) { 2255 var info = ''; 2256 var node = workInProgress; 2257 do { 2258 info += describeFiber(node); 2259 node = node.return; 2260 } while (node); 2261 return info; 2262 } 2263 2264 // A reserved attribute. 2265 // It is handled by React separately and shouldn't be written to the DOM. 2266 var RESERVED = 0; 2267 2268 // A simple string attribute. 2269 // Attributes that aren't in the whitelist are presumed to have this type. 2270 var STRING = 1; 2271 2272 // A string attribute that accepts booleans in React. In HTML, these are called 2273 // "enumerated" attributes with "true" and "false" as possible values. 2274 // When true, it should be set to a "true" string. 2275 // When false, it should be set to a "false" string. 2276 var BOOLEANISH_STRING = 2; 2277 2278 // A real boolean attribute. 2279 // When true, it should be present (set either to an empty string or its name). 2280 // When false, it should be omitted. 2281 var BOOLEAN = 3; 2282 2283 // An attribute that can be used as a flag as well as with a value. 2284 // When true, it should be present (set either to an empty string or its name). 2285 // When false, it should be omitted. 2286 // For any other value, should be present with that value. 2287 var OVERLOADED_BOOLEAN = 4; 2288 2289 // An attribute that must be numeric or parse as a numeric. 2290 // When falsy, it should be removed. 2291 var NUMERIC = 5; 2292 2293 // An attribute that must be positive numeric or parse as a positive numeric. 2294 // When falsy, it should be removed. 2295 var POSITIVE_NUMERIC = 6; 2296 2297 /* eslint-disable max-len */ 2298 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'; 2299 /* eslint-enable max-len */ 2300 var ATTRIBUTE_NAME_CHAR = ATTRIBUTE_NAME_START_CHAR + '\\-.0-9\\u00B7\\u0300-\\u036F\\u203F-\\u2040'; 2301 2302 2303 var ROOT_ATTRIBUTE_NAME = 'data-reactroot'; 2304 var VALID_ATTRIBUTE_NAME_REGEX = new RegExp('^[' + ATTRIBUTE_NAME_START_CHAR + '][' + ATTRIBUTE_NAME_CHAR + ']*$'); 2305 2306 var hasOwnProperty = Object.prototype.hasOwnProperty; 2307 var illegalAttributeNameCache = {}; 2308 var validatedAttributeNameCache = {}; 2309 2310 function isAttributeNameSafe(attributeName) { 2311 if (hasOwnProperty.call(validatedAttributeNameCache, attributeName)) { 2312 return true; 2313 } 2314 if (hasOwnProperty.call(illegalAttributeNameCache, attributeName)) { 2315 return false; 2316 } 2317 if (VALID_ATTRIBUTE_NAME_REGEX.test(attributeName)) { 2318 validatedAttributeNameCache[attributeName] = true; 2319 return true; 2320 } 2321 illegalAttributeNameCache[attributeName] = true; 2322 return false; 2323 } 2324 2325 function shouldIgnoreAttribute(name, propertyInfo, isCustomComponentTag) { 2326 if (propertyInfo !== null) { 2327 return propertyInfo.type === RESERVED; 2328 } 2329 if (isCustomComponentTag) { 2330 return false; 2331 } 2332 if (name.length > 2 && (name[0] === 'o' || name[0] === 'O') && (name[1] === 'n' || name[1] === 'N')) { 2333 return true; 2334 } 2335 return false; 2336 } 2337 2338 function shouldRemoveAttributeWithWarning(name, value, propertyInfo, isCustomComponentTag) { 2339 if (propertyInfo !== null && propertyInfo.type === RESERVED) { 2340 return false; 2341 } 2342 switch (typeof value) { 2343 case 'function': 2344 // $FlowIssue symbol is perfectly valid here 2345 case 'symbol': 2346 // eslint-disable-line 2347 return true; 2348 case 'boolean': 2349 { 2350 if (isCustomComponentTag) { 2351 return false; 2352 } 2353 if (propertyInfo !== null) { 2354 return !propertyInfo.acceptsBooleans; 2355 } else { 2356 var prefix = name.toLowerCase().slice(0, 5); 2357 return prefix !== 'data-' && prefix !== 'aria-'; 2358 } 2359 } 2360 default: 2361 return false; 2362 } 2363 } 2364 2365 function shouldRemoveAttribute(name, value, propertyInfo, isCustomComponentTag) { 2366 if (value === null || typeof value === 'undefined') { 2367 return true; 2368 } 2369 if (shouldRemoveAttributeWithWarning(name, value, propertyInfo, isCustomComponentTag)) { 2370 return true; 2371 } 2372 if (isCustomComponentTag) { 2373 return false; 2374 } 2375 if (propertyInfo !== null) { 2376 switch (propertyInfo.type) { 2377 case BOOLEAN: 2378 return !value; 2379 case OVERLOADED_BOOLEAN: 2380 return value === false; 2381 case NUMERIC: 2382 return isNaN(value); 2383 case POSITIVE_NUMERIC: 2384 return isNaN(value) || value < 1; 2385 } 2386 } 2387 return false; 2388 } 2389 2390 function getPropertyInfo(name) { 2391 return properties.hasOwnProperty(name) ? properties[name] : null; 2392 } 2393 2394 function PropertyInfoRecord(name, type, mustUseProperty, attributeName, attributeNamespace) { 2395 this.acceptsBooleans = type === BOOLEANISH_STRING || type === BOOLEAN || type === OVERLOADED_BOOLEAN; 2396 this.attributeName = attributeName; 2397 this.attributeNamespace = attributeNamespace; 2398 this.mustUseProperty = mustUseProperty; 2399 this.propertyName = name; 2400 this.type = type; 2401 } 2402 2403 // When adding attributes to this list, be sure to also add them to 2404 // the `possibleStandardNames` module to ensure casing and incorrect 2405 // name warnings. 2406 var properties = {}; 2407 2408 // These props are reserved by React. They shouldn't be written to the DOM. 2409 ['children', 'dangerouslySetInnerHTML', 2410 // TODO: This prevents the assignment of defaultValue to regular 2411 // elements (not just inputs). Now that ReactDOMInput assigns to the 2412 // defaultValue property -- do we need this? 2413 'defaultValue', 'defaultChecked', 'innerHTML', 'suppressContentEditableWarning', 'suppressHydrationWarning', 'style'].forEach(function (name) { 2414 properties[name] = new PropertyInfoRecord(name, RESERVED, false, // mustUseProperty 2415 name, // attributeName 2416 null); 2417 } // attributeNamespace 2418 ); 2419 2420 // A few React string attributes have a different name. 2421 // This is a mapping from React prop names to the attribute names. 2422 [['acceptCharset', 'accept-charset'], ['className', 'class'], ['htmlFor', 'for'], ['httpEquiv', 'http-equiv']].forEach(function (_ref) { 2423 var name = _ref[0], 2424 attributeName = _ref[1]; 2425 2426 properties[name] = new PropertyInfoRecord(name, STRING, false, // mustUseProperty 2427 attributeName, // attributeName 2428 null); 2429 } // attributeNamespace 2430 ); 2431 2432 // These are "enumerated" HTML attributes that accept "true" and "false". 2433 // In React, we let users pass `true` and `false` even though technically 2434 // these aren't boolean attributes (they are coerced to strings). 2435 ['contentEditable', 'draggable', 'spellCheck', 'value'].forEach(function (name) { 2436 properties[name] = new PropertyInfoRecord(name, BOOLEANISH_STRING, false, // mustUseProperty 2437 name.toLowerCase(), // attributeName 2438 null); 2439 } // attributeNamespace 2440 ); 2441 2442 // These are "enumerated" SVG attributes that accept "true" and "false". 2443 // In React, we let users pass `true` and `false` even though technically 2444 // these aren't boolean attributes (they are coerced to strings). 2445 // Since these are SVG attributes, their attribute names are case-sensitive. 2446 ['autoReverse', 'externalResourcesRequired', 'focusable', 'preserveAlpha'].forEach(function (name) { 2447 properties[name] = new PropertyInfoRecord(name, BOOLEANISH_STRING, false, // mustUseProperty 2448 name, // attributeName 2449 null); 2450 } // attributeNamespace 2451 ); 2452 2453 // These are HTML boolean attributes. 2454 ['allowFullScreen', 'async', 2455 // Note: there is a special case that prevents it from being written to the DOM 2456 // on the client side because the browsers are inconsistent. Instead we call focus(). 2457 'autoFocus', 'autoPlay', 'controls', 'default', 'defer', 'disabled', 'formNoValidate', 'hidden', 'loop', 'noModule', 'noValidate', 'open', 'playsInline', 'readOnly', 'required', 'reversed', 'scoped', 'seamless', 2458 // Microdata 2459 'itemScope'].forEach(function (name) { 2460 properties[name] = new PropertyInfoRecord(name, BOOLEAN, false, // mustUseProperty 2461 name.toLowerCase(), // attributeName 2462 null); 2463 } // attributeNamespace 2464 ); 2465 2466 // These are the few React props that we set as DOM properties 2467 // rather than attributes. These are all booleans. 2468 ['checked', 2469 // Note: `option.selected` is not updated if `select.multiple` is 2470 // disabled with `removeAttribute`. We have special logic for handling this. 2471 'multiple', 'muted', 'selected'].forEach(function (name) { 2472 properties[name] = new PropertyInfoRecord(name, BOOLEAN, true, // mustUseProperty 2473 name, // attributeName 2474 null); 2475 } // attributeNamespace 2476 ); 2477 2478 // These are HTML attributes that are "overloaded booleans": they behave like 2479 // booleans, but can also accept a string value. 2480 ['capture', 'download'].forEach(function (name) { 2481 properties[name] = new PropertyInfoRecord(name, OVERLOADED_BOOLEAN, false, // mustUseProperty 2482 name, // attributeName 2483 null); 2484 } // attributeNamespace 2485 ); 2486 2487 // These are HTML attributes that must be positive numbers. 2488 ['cols', 'rows', 'size', 'span'].forEach(function (name) { 2489 properties[name] = new PropertyInfoRecord(name, POSITIVE_NUMERIC, false, // mustUseProperty 2490 name, // attributeName 2491 null); 2492 } // attributeNamespace 2493 ); 2494 2495 // These are HTML attributes that must be numbers. 2496 ['rowSpan', 'start'].forEach(function (name) { 2497 properties[name] = new PropertyInfoRecord(name, NUMERIC, false, // mustUseProperty 2498 name.toLowerCase(), // attributeName 2499 null); 2500 } // attributeNamespace 2501 ); 2502 2503 var CAMELIZE = /[\-\:]([a-z])/g; 2504 var capitalize = function (token) { 2505 return token[1].toUpperCase(); 2506 }; 2507 2508 // This is a list of all SVG attributes that need special casing, namespacing, 2509 // or boolean value assignment. Regular attributes that just accept strings 2510 // and have the same names are omitted, just like in the HTML whitelist. 2511 // Some of these attributes can be hard to find. This list was created by 2512 // scrapping the MDN documentation. 2513 ['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'].forEach(function (attributeName) { 2514 var name = attributeName.replace(CAMELIZE, capitalize); 2515 properties[name] = new PropertyInfoRecord(name, STRING, false, // mustUseProperty 2516 attributeName, null); 2517 } // attributeNamespace 2518 ); 2519 2520 // String SVG attributes with the xlink namespace. 2521 ['xlink:actuate', 'xlink:arcrole', 'xlink:href', 'xlink:role', 'xlink:show', 'xlink:title', 'xlink:type'].forEach(function (attributeName) { 2522 var name = attributeName.replace(CAMELIZE, capitalize); 2523 properties[name] = new PropertyInfoRecord(name, STRING, false, // mustUseProperty 2524 attributeName, 'http://www.w3.org/1999/xlink'); 2525 }); 2526 2527 // String SVG attributes with the xml namespace. 2528 ['xml:base', 'xml:lang', 'xml:space'].forEach(function (attributeName) { 2529 var name = attributeName.replace(CAMELIZE, capitalize); 2530 properties[name] = new PropertyInfoRecord(name, STRING, false, // mustUseProperty 2531 attributeName, 'http://www.w3.org/XML/1998/namespace'); 2532 }); 2533 2534 // These attribute exists both in HTML and SVG. 2535 // The attribute name is case-sensitive in SVG so we can't just use 2536 // the React name like we do for attributes that exist only in HTML. 2537 ['tabIndex', 'crossOrigin'].forEach(function (attributeName) { 2538 properties[attributeName] = new PropertyInfoRecord(attributeName, STRING, false, // mustUseProperty 2539 attributeName.toLowerCase(), // attributeName 2540 null); 2541 } // attributeNamespace 2542 ); 2543 2544 /** 2545 * Get the value for a property on a node. Only used in DEV for SSR validation. 2546 * The "expected" argument is used as a hint of what the expected value is. 2547 * Some properties have multiple equivalent values. 2548 */ 2549 2550 2551 /** 2552 * Get the value for a attribute on a node. Only used in DEV for SSR validation. 2553 * The third argument is used as a hint of what the expected value is. Some 2554 * attributes have multiple equivalent values. 2555 */ 2556 2557 2558 /** 2559 * Sets the value for a property on a node. 2560 * 2561 * @param {DOMElement} node 2562 * @param {string} name 2563 * @param {*} value 2564 */ 2565 function setValueForProperty(node, name, value, isCustomComponentTag) { 2566 var propertyInfo = getPropertyInfo(name); 2567 if (shouldIgnoreAttribute(name, propertyInfo, isCustomComponentTag)) { 2568 return; 2569 } 2570 if (shouldRemoveAttribute(name, value, propertyInfo, isCustomComponentTag)) { 2571 value = null; 2572 } 2573 // If the prop isn't in the special list, treat it as a simple attribute. 2574 if (isCustomComponentTag || propertyInfo === null) { 2575 if (isAttributeNameSafe(name)) { 2576 var _attributeName = name; 2577 if (value === null) { 2578 node.removeAttribute(_attributeName); 2579 } else { 2580 node.setAttribute(_attributeName, '' + value); 2581 } 2582 } 2583 return; 2584 } 2585 var mustUseProperty = propertyInfo.mustUseProperty; 2586 2587 if (mustUseProperty) { 2588 var propertyName = propertyInfo.propertyName; 2589 2590 if (value === null) { 2591 var type = propertyInfo.type; 2592 2593 node[propertyName] = type === BOOLEAN ? false : ''; 2594 } else { 2595 // Contrary to `setAttribute`, object properties are properly 2596 // `toString`ed by IE8/9. 2597 node[propertyName] = value; 2598 } 2599 return; 2600 } 2601 // The rest are treated as attributes with special cases. 2602 var attributeName = propertyInfo.attributeName, 2603 attributeNamespace = propertyInfo.attributeNamespace; 2604 2605 if (value === null) { 2606 node.removeAttribute(attributeName); 2607 } else { 2608 var _type = propertyInfo.type; 2609 2610 var attributeValue = void 0; 2611 if (_type === BOOLEAN || _type === OVERLOADED_BOOLEAN && value === true) { 2612 attributeValue = ''; 2613 } else { 2614 // `setAttribute` with objects becomes only `[object]` in IE8/9, 2615 // ('' + value) makes it output the correct toString()-value. 2616 attributeValue = '' + value; 2617 } 2618 if (attributeNamespace) { 2619 node.setAttributeNS(attributeNamespace, attributeName, attributeValue); 2620 } else { 2621 node.setAttribute(attributeName, attributeValue); 2622 } 2623 } 2624 } 2625 2626 // Flow does not allow string concatenation of most non-string types. To work 2627 // around this limitation, we use an opaque type that can only be obtained by 2628 // passing the value through getToStringValue first. 2629 function toString(value) { 2630 return '' + value; 2631 } 2632 2633 function getToStringValue(value) { 2634 switch (typeof value) { 2635 case 'boolean': 2636 case 'number': 2637 case 'object': 2638 case 'string': 2639 case 'undefined': 2640 return value; 2641 default: 2642 // function, symbol are assigned as empty strings 2643 return ''; 2644 } 2645 } 2646 2647 /** 2648 * Copyright (c) 2013-present, Facebook, Inc. 2649 * 2650 * This source code is licensed under the MIT license found in the 2651 * LICENSE file in the root directory of this source tree. 2652 */ 2653 2654 var enableUserTimingAPI = false; 2655 2656 // Helps identify side effects in begin-phase lifecycle hooks and setState reducers: 2657 2658 2659 // In some cases, StrictMode should also double-render lifecycles. 2660 // This can be confusing for tests though, 2661 // And it can be bad for performance in production. 2662 // This feature flag can be used to control the behavior: 2663 2664 2665 // To preserve the "Pause on caught exceptions" behavior of the debugger, we 2666 // replay the begin phase of a failed component inside invokeGuardedCallback. 2667 2668 2669 // Warn about deprecated, async-unsafe lifecycles; relates to RFC #6: 2670 2671 2672 // Gather advanced timing metrics for Profiler subtrees. 2673 var enableProfilerTimer = false; 2674 2675 // Trace which interactions trigger each commit. 2676 var enableSchedulerTracing = false; 2677 2678 // Only used in www builds. 2679 var enableSuspenseServerRenderer = false; // TODO: false? Here it might just be false. 2680 2681 // Only used in www builds. 2682 2683 2684 // Only used in www builds. 2685 2686 2687 // React Fire: prevent the value and checked attributes from syncing 2688 // with their related DOM properties 2689 var disableInputAttributeSyncing = false; 2690 2691 // These APIs will no longer be "unstable" in the upcoming 16.7 release, 2692 // Control this behavior with a flag to support 16.6 minor releases in the meanwhile. 2693 var enableStableConcurrentModeAPIs = false; 2694 2695 // TODO: direct imports like some-package/src/* are bad. Fix me. 2696 function isControlled(props) { 2697 var usesChecked = props.type === 'checkbox' || props.type === 'radio'; 2698 return usesChecked ? props.checked != null : props.value != null; 2699 } 2700 2701 /** 2702 * Implements an <input> host component that allows setting these optional 2703 * props: `checked`, `value`, `defaultChecked`, and `defaultValue`. 2704 * 2705 * If `checked` or `value` are not supplied (or null/undefined), user actions 2706 * that affect the checked state or value will trigger updates to the element. 2707 * 2708 * If they are supplied (and not null/undefined), the rendered element will not 2709 * trigger updates to the element. Instead, the props must change in order for 2710 * the rendered element to be updated. 2711 * 2712 * The rendered element will be initialized as unchecked (or `defaultChecked`) 2713 * with an empty value (or `defaultValue`). 2714 * 2715 * See http://www.w3.org/TR/2012/WD-html5-20121025/the-input-element.html 2716 */ 2717 2718 function getHostProps(element, props) { 2719 var node = element; 2720 var checked = props.checked; 2721 2722 var hostProps = _assign({}, props, { 2723 defaultChecked: undefined, 2724 defaultValue: undefined, 2725 value: undefined, 2726 checked: checked != null ? checked : node._wrapperState.initialChecked 2727 }); 2728 2729 return hostProps; 2730 } 2731 2732 function initWrapperState(element, props) { 2733 var node = element; 2734 var defaultValue = props.defaultValue == null ? '' : props.defaultValue; 2735 2736 node._wrapperState = { 2737 initialChecked: props.checked != null ? props.checked : props.defaultChecked, 2738 initialValue: getToStringValue(props.value != null ? props.value : defaultValue), 2739 controlled: isControlled(props) 2740 }; 2741 } 2742 2743 function updateChecked(element, props) { 2744 var node = element; 2745 var checked = props.checked; 2746 if (checked != null) { 2747 setValueForProperty(node, 'checked', checked, false); 2748 } 2749 } 2750 2751 function updateWrapper(element, props) { 2752 var node = element; 2753 updateChecked(element, props); 2754 2755 var value = getToStringValue(props.value); 2756 var type = props.type; 2757 2758 if (value != null) { 2759 if (type === 'number') { 2760 if (value === 0 && node.value === '' || 2761 // We explicitly want to coerce to number here if possible. 2762 // eslint-disable-next-line 2763 node.value != value) { 2764 node.value = toString(value); 2765 } 2766 } else if (node.value !== toString(value)) { 2767 node.value = toString(value); 2768 } 2769 } else if (type === 'submit' || type === 'reset') { 2770 // Submit/reset inputs need the attribute removed completely to avoid 2771 // blank-text buttons. 2772 node.removeAttribute('value'); 2773 return; 2774 } 2775 2776 if (disableInputAttributeSyncing) { 2777 // When not syncing the value attribute, React only assigns a new value 2778 // whenever the defaultValue React prop has changed. When not present, 2779 // React does nothing 2780 if (props.hasOwnProperty('defaultValue')) { 2781 setDefaultValue(node, props.type, getToStringValue(props.defaultValue)); 2782 } 2783 } else { 2784 // When syncing the value attribute, the value comes from a cascade of 2785 // properties: 2786 // 1. The value React property 2787 // 2. The defaultValue React property 2788 // 3. Otherwise there should be no change 2789 if (props.hasOwnProperty('value')) { 2790 setDefaultValue(node, props.type, value); 2791 } else if (props.hasOwnProperty('defaultValue')) { 2792 setDefaultValue(node, props.type, getToStringValue(props.defaultValue)); 2793 } 2794 } 2795 2796 if (disableInputAttributeSyncing) { 2797 // When not syncing the checked attribute, the attribute is directly 2798 // controllable from the defaultValue React property. It needs to be 2799 // updated as new props come in. 2800 if (props.defaultChecked == null) { 2801 node.removeAttribute('checked'); 2802 } else { 2803 node.defaultChecked = !!props.defaultChecked; 2804 } 2805 } else { 2806 // When syncing the checked attribute, it only changes when it needs 2807 // to be removed, such as transitioning from a checkbox into a text input 2808 if (props.checked == null && props.defaultChecked != null) { 2809 node.defaultChecked = !!props.defaultChecked; 2810 } 2811 } 2812 } 2813 2814 function postMountWrapper(element, props, isHydrating) { 2815 var node = element; 2816 2817 // Do not assign value if it is already set. This prevents user text input 2818 // from being lost during SSR hydration. 2819 if (props.hasOwnProperty('value') || props.hasOwnProperty('defaultValue')) { 2820 var type = props.type; 2821 var isButton = type === 'submit' || type === 'reset'; 2822 2823 // Avoid setting value attribute on submit/reset inputs as it overrides the 2824 // default value provided by the browser. See: #12872 2825 if (isButton && (props.value === undefined || props.value === null)) { 2826 return; 2827 } 2828 2829 var _initialValue = toString(node._wrapperState.initialValue); 2830 2831 // Do not assign value if it is already set. This prevents user text input 2832 // from being lost during SSR hydration. 2833 if (!isHydrating) { 2834 if (disableInputAttributeSyncing) { 2835 var value = getToStringValue(props.value); 2836 2837 // When not syncing the value attribute, the value property points 2838 // directly to the React prop. Only assign it if it exists. 2839 if (value != null) { 2840 // Always assign on buttons so that it is possible to assign an 2841 // empty string to clear button text. 2842 // 2843 // Otherwise, do not re-assign the value property if is empty. This 2844 // potentially avoids a DOM write and prevents Firefox (~60.0.1) from 2845 // prematurely marking required inputs as invalid. Equality is compared 2846 // to the current value in case the browser provided value is not an 2847 // empty string. 2848 if (isButton || value !== node.value) { 2849 node.value = toString(value); 2850 } 2851 } 2852 } else { 2853 // When syncing the value attribute, the value property should use 2854 // the wrapperState._initialValue property. This uses: 2855 // 2856 // 1. The value React property when present 2857 // 2. The defaultValue React property when present 2858 // 3. An empty string 2859 if (_initialValue !== node.value) { 2860 node.value = _initialValue; 2861 } 2862 } 2863 } 2864 2865 if (disableInputAttributeSyncing) { 2866 // When not syncing the value attribute, assign the value attribute 2867 // directly from the defaultValue React property (when present) 2868 var defaultValue = getToStringValue(props.defaultValue); 2869 if (defaultValue != null) { 2870 node.defaultValue = toString(defaultValue); 2871 } 2872 } else { 2873 // Otherwise, the value attribute is synchronized to the property, 2874 // so we assign defaultValue to the same thing as the value property 2875 // assignment step above. 2876 node.defaultValue = _initialValue; 2877 } 2878 } 2879 2880 // Normally, we'd just do `node.checked = node.checked` upon initial mount, less this bug 2881 // this is needed to work around a chrome bug where setting defaultChecked 2882 // will sometimes influence the value of checked (even after detachment). 2883 // Reference: https://bugs.chromium.org/p/chromium/issues/detail?id=608416 2884 // We need to temporarily unset name to avoid disrupting radio button groups. 2885 var name = node.name; 2886 if (name !== '') { 2887 node.name = ''; 2888 } 2889 2890 if (disableInputAttributeSyncing) { 2891 // When not syncing the checked attribute, the checked property 2892 // never gets assigned. It must be manually set. We don't want 2893 // to do this when hydrating so that existing user input isn't 2894 // modified 2895 if (!isHydrating) { 2896 updateChecked(element, props); 2897 } 2898 2899 // Only assign the checked attribute if it is defined. This saves 2900 // a DOM write when controlling the checked attribute isn't needed 2901 // (text inputs, submit/reset) 2902 if (props.hasOwnProperty('defaultChecked')) { 2903 node.defaultChecked = !node.defaultChecked; 2904 node.defaultChecked = !!props.defaultChecked; 2905 } 2906 } else { 2907 // When syncing the checked attribute, both the checked property and 2908 // attribute are assigned at the same time using defaultChecked. This uses: 2909 // 2910 // 1. The checked React property when present 2911 // 2. The defaultChecked React property when present 2912 // 3. Otherwise, false 2913 node.defaultChecked = !node.defaultChecked; 2914 node.defaultChecked = !!node._wrapperState.initialChecked; 2915 } 2916 2917 if (name !== '') { 2918 node.name = name; 2919 } 2920 } 2921 2922 function restoreControlledState(element, props) { 2923 var node = element; 2924 updateWrapper(node, props); 2925 updateNamedCousins(node, props); 2926 } 2927 2928 function updateNamedCousins(rootNode, props) { 2929 var name = props.name; 2930 if (props.type === 'radio' && name != null) { 2931 var queryRoot = rootNode; 2932 2933 while (queryRoot.parentNode) { 2934 queryRoot = queryRoot.parentNode; 2935 } 2936 2937 // If `rootNode.form` was non-null, then we could try `form.elements`, 2938 // but that sometimes behaves strangely in IE8. We could also try using 2939 // `form.getElementsByName`, but that will only return direct children 2940 // and won't include inputs that use the HTML5 `form=` attribute. Since 2941 // the input might not even be in a form. It might not even be in the 2942 // document. Let's just use the local `querySelectorAll` to ensure we don't 2943 // miss anything. 2944 var group = queryRoot.querySelectorAll('input[name=' + JSON.stringify('' + name) + '][type="radio"]'); 2945 2946 for (var i = 0; i < group.length; i++) { 2947 var otherNode = group[i]; 2948 if (otherNode === rootNode || otherNode.form !== rootNode.form) { 2949 continue; 2950 } 2951 // This will throw if radio buttons rendered by different copies of React 2952 // and the same name are rendered into the same form (same as #1939). 2953 // That's probably okay; we don't support it just as we don't support 2954 // mixing React radio buttons with non-React ones. 2955 var otherProps = getFiberCurrentPropsFromNode$1(otherNode); 2956 !otherProps ? reactProdInvariant('90') : void 0; 2957 2958 // We need update the tracked value on the named cousin since the value 2959 // was changed but the input saw no event or value set 2960 updateValueIfChanged(otherNode); 2961 2962 // If this is a controlled radio button group, forcing the input that 2963 // was previously checked to update will cause it to be come re-checked 2964 // as appropriate. 2965 updateWrapper(otherNode, otherProps); 2966 } 2967 } 2968 } 2969 2970 // In Chrome, assigning defaultValue to certain input types triggers input validation. 2971 // For number inputs, the display value loses trailing decimal points. For email inputs, 2972 // Chrome raises "The specified value <x> is not a valid email address". 2973 // 2974 // Here we check to see if the defaultValue has actually changed, avoiding these problems 2975 // when the user is inputting text 2976 // 2977 // https://github.com/facebook/react/issues/7253 2978 function setDefaultValue(node, type, value) { 2979 if ( 2980 // Focused number inputs synchronize on blur. See ChangeEventPlugin.js 2981 type !== 'number' || node.ownerDocument.activeElement !== node) { 2982 if (value == null) { 2983 node.defaultValue = toString(node._wrapperState.initialValue); 2984 } else if (node.defaultValue !== toString(value)) { 2985 node.defaultValue = toString(value); 2986 } 2987 } 2988 } 2989 2990 var eventTypes$1 = { 2991 change: { 2992 phasedRegistrationNames: { 2993 bubbled: 'onChange', 2994 captured: 'onChangeCapture' 2995 }, 2996 dependencies: [TOP_BLUR, TOP_CHANGE, TOP_CLICK, TOP_FOCUS, TOP_INPUT, TOP_KEY_DOWN, TOP_KEY_UP, TOP_SELECTION_CHANGE] 2997 } 2998 }; 2999 3000 function createAndAccumulateChangeEvent(inst, nativeEvent, target) { 3001 var event = SyntheticEvent.getPooled(eventTypes$1.change, inst, nativeEvent, target); 3002 event.type = 'change'; 3003 // Flag this event loop as needing state restore. 3004 enqueueStateRestore(target); 3005 accumulateTwoPhaseDispatches(event); 3006 return event; 3007 } 3008 /** 3009 * For IE shims 3010 */ 3011 var activeElement = null; 3012 var activeElementInst = null; 3013 3014 /** 3015 * SECTION: handle `change` event 3016 */ 3017 function shouldUseChangeEvent(elem) { 3018 var nodeName = elem.nodeName && elem.nodeName.toLowerCase(); 3019 return nodeName === 'select' || nodeName === 'input' && elem.type === 'file'; 3020 } 3021 3022 function manualDispatchChangeEvent(nativeEvent) { 3023 var event = createAndAccumulateChangeEvent(activeElementInst, nativeEvent, getEventTarget(nativeEvent)); 3024 3025 // If change and propertychange bubbled, we'd just bind to it like all the 3026 // other events and have it go through ReactBrowserEventEmitter. Since it 3027 // doesn't, we manually listen for the events and so we have to enqueue and 3028 // process the abstract event manually. 3029 // 3030 // Batching is necessary here in order to ensure that all event handlers run 3031 // before the next rerender (including event handlers attached to ancestor 3032 // elements instead of directly on the input). Without this, controlled 3033 // components don't work properly in conjunction with event bubbling because 3034 // the component is rerendered and the value reverted before all the event 3035 // handlers can run. See https://github.com/facebook/react/issues/708. 3036 batchedUpdates(runEventInBatch, event); 3037 } 3038 3039 function runEventInBatch(event) { 3040 runEventsInBatch(event); 3041 } 3042 3043 function getInstIfValueChanged(targetInst) { 3044 var targetNode = getNodeFromInstance$1(targetInst); 3045 if (updateValueIfChanged(targetNode)) { 3046 return targetInst; 3047 } 3048 } 3049 3050 function getTargetInstForChangeEvent(topLevelType, targetInst) { 3051 if (topLevelType === TOP_CHANGE) { 3052 return targetInst; 3053 } 3054 } 3055 3056 /** 3057 * SECTION: handle `input` event 3058 */ 3059 var isInputEventSupported = false; 3060 if (canUseDOM) { 3061 // IE9 claims to support the input event but fails to trigger it when 3062 // deleting text, so we ignore its input events. 3063 isInputEventSupported = isEventSupported('input') && (!document.documentMode || document.documentMode > 9); 3064 } 3065 3066 /** 3067 * (For IE <=9) Starts tracking propertychange events on the passed-in element 3068 * and override the value property so that we can distinguish user events from 3069 * value changes in JS. 3070 */ 3071 function startWatchingForValueChange(target, targetInst) { 3072 activeElement = target; 3073 activeElementInst = targetInst; 3074 activeElement.attachEvent('onpropertychange', handlePropertyChange); 3075 } 3076 3077 /** 3078 * (For IE <=9) Removes the event listeners from the currently-tracked element, 3079 * if any exists. 3080 */ 3081 function stopWatchingForValueChange() { 3082 if (!activeElement) { 3083 return; 3084 } 3085 activeElement.detachEvent('onpropertychange', handlePropertyChange); 3086 activeElement = null; 3087 activeElementInst = null; 3088 } 3089 3090 /** 3091 * (For IE <=9) Handles a propertychange event, sending a `change` event if 3092 * the value of the active element has changed. 3093 */ 3094 function handlePropertyChange(nativeEvent) { 3095 if (nativeEvent.propertyName !== 'value') { 3096 return; 3097 } 3098 if (getInstIfValueChanged(activeElementInst)) { 3099 manualDispatchChangeEvent(nativeEvent); 3100 } 3101 } 3102 3103 function handleEventsForInputEventPolyfill(topLevelType, target, targetInst) { 3104 if (topLevelType === TOP_FOCUS) { 3105 // In IE9, propertychange fires for most input events but is buggy and 3106 // doesn't fire when text is deleted, but conveniently, selectionchange 3107 // appears to fire in all of the remaining cases so we catch those and 3108 // forward the event if the value has changed 3109 // In either case, we don't want to call the event handler if the value 3110 // is changed from JS so we redefine a setter for `.value` that updates 3111 // our activeElementValue variable, allowing us to ignore those changes 3112 // 3113 // stopWatching() should be a noop here but we call it just in case we 3114 // missed a blur event somehow. 3115 stopWatchingForValueChange(); 3116 startWatchingForValueChange(target, targetInst); 3117 } else if (topLevelType === TOP_BLUR) { 3118 stopWatchingForValueChange(); 3119 } 3120 } 3121 3122 // For IE8 and IE9. 3123 function getTargetInstForInputEventPolyfill(topLevelType, targetInst) { 3124 if (topLevelType === TOP_SELECTION_CHANGE || topLevelType === TOP_KEY_UP || topLevelType === TOP_KEY_DOWN) { 3125 // On the selectionchange event, the target is just document which isn't 3126 // helpful for us so just check activeElement instead. 3127 // 3128 // 99% of the time, keydown and keyup aren't necessary. IE8 fails to fire 3129 // propertychange on the first input event after setting `value` from a 3130 // script and fires only keydown, keypress, keyup. Catching keyup usually 3131 // gets it and catching keydown lets us fire an event for the first 3132 // keystroke if user does a key repeat (it'll be a little delayed: right 3133 // before the second keystroke). Other input methods (e.g., paste) seem to 3134 // fire selectionchange normally. 3135 return getInstIfValueChanged(activeElementInst); 3136 } 3137 } 3138 3139 /** 3140 * SECTION: handle `click` event 3141 */ 3142 function shouldUseClickEvent(elem) { 3143 // Use the `click` event to detect changes to checkbox and radio inputs. 3144 // This approach works across all browsers, whereas `change` does not fire 3145 // until `blur` in IE8. 3146 var nodeName = elem.nodeName; 3147 return nodeName && nodeName.toLowerCase() === 'input' && (elem.type === 'checkbox' || elem.type === 'radio'); 3148 } 3149 3150 function getTargetInstForClickEvent(topLevelType, targetInst) { 3151 if (topLevelType === TOP_CLICK) { 3152 return getInstIfValueChanged(targetInst); 3153 } 3154 } 3155 3156 function getTargetInstForInputOrChangeEvent(topLevelType, targetInst) { 3157 if (topLevelType === TOP_INPUT || topLevelType === TOP_CHANGE) { 3158 return getInstIfValueChanged(targetInst); 3159 } 3160 } 3161 3162 function handleControlledInputBlur(node) { 3163 var state = node._wrapperState; 3164 3165 if (!state || !state.controlled || node.type !== 'number') { 3166 return; 3167 } 3168 3169 if (!disableInputAttributeSyncing) { 3170 // If controlled, assign the value attribute to the current value on blur 3171 setDefaultValue(node, 'number', node.value); 3172 } 3173 } 3174 3175 /** 3176 * This plugin creates an `onChange` event that normalizes change events 3177 * across form elements. This event fires at a time when it's possible to 3178 * change the element's value without seeing a flicker. 3179 * 3180 * Supported elements are: 3181 * - input (see `isTextInputElement`) 3182 * - textarea 3183 * - select 3184 */ 3185 var ChangeEventPlugin = { 3186 eventTypes: eventTypes$1, 3187 3188 _isInputEventSupported: isInputEventSupported, 3189 3190 extractEvents: function (topLevelType, targetInst, nativeEvent, nativeEventTarget) { 3191 var targetNode = targetInst ? getNodeFromInstance$1(targetInst) : window; 3192 3193 var getTargetInstFunc = void 0, 3194 handleEventFunc = void 0; 3195 if (shouldUseChangeEvent(targetNode)) { 3196 getTargetInstFunc = getTargetInstForChangeEvent; 3197 } else if (isTextInputElement(targetNode)) { 3198 if (isInputEventSupported) { 3199 getTargetInstFunc = getTargetInstForInputOrChangeEvent; 3200 } else { 3201 getTargetInstFunc = getTargetInstForInputEventPolyfill; 3202 handleEventFunc = handleEventsForInputEventPolyfill; 3203 } 3204 } else if (shouldUseClickEvent(targetNode)) { 3205 getTargetInstFunc = getTargetInstForClickEvent; 3206 } 3207 3208 if (getTargetInstFunc) { 3209 var inst = getTargetInstFunc(topLevelType, targetInst); 3210 if (inst) { 3211 var event = createAndAccumulateChangeEvent(inst, nativeEvent, nativeEventTarget); 3212 return event; 3213 } 3214 } 3215 3216 if (handleEventFunc) { 3217 handleEventFunc(topLevelType, targetNode, targetInst); 3218 } 3219 3220 // When blurring, set the value attribute for number inputs 3221 if (topLevelType === TOP_BLUR) { 3222 handleControlledInputBlur(targetNode); 3223 } 3224 } 3225 }; 3226 3227 /** 3228 * Module that is injectable into `EventPluginHub`, that specifies a 3229 * deterministic ordering of `EventPlugin`s. A convenient way to reason about 3230 * plugins, without having to package every one of them. This is better than 3231 * having plugins be ordered in the same order that they are injected because 3232 * that ordering would be influenced by the packaging order. 3233 * `ResponderEventPlugin` must occur before `SimpleEventPlugin` so that 3234 * preventing default on events is convenient in `SimpleEventPlugin` handlers. 3235 */ 3236 var DOMEventPluginOrder = ['ResponderEventPlugin', 'SimpleEventPlugin', 'EnterLeaveEventPlugin', 'ChangeEventPlugin', 'SelectEventPlugin', 'BeforeInputEventPlugin']; 3237 3238 var SyntheticUIEvent = SyntheticEvent.extend({ 3239 view: null, 3240 detail: null 3241 }); 3242 3243 var modifierKeyToProp = { 3244 Alt: 'altKey', 3245 Control: 'ctrlKey', 3246 Meta: 'metaKey', 3247 Shift: 'shiftKey' 3248 }; 3249 3250 // Older browsers (Safari <= 10, iOS Safari <= 10.2) do not support 3251 // getModifierState. If getModifierState is not supported, we map it to a set of 3252 // modifier keys exposed by the event. In this case, Lock-keys are not supported. 3253 /** 3254 * Translation from modifier key to the associated property in the event. 3255 * @see http://www.w3.org/TR/DOM-Level-3-Events/#keys-Modifiers 3256 */ 3257 3258 function modifierStateGetter(keyArg) { 3259 var syntheticEvent = this; 3260 var nativeEvent = syntheticEvent.nativeEvent; 3261 if (nativeEvent.getModifierState) { 3262 return nativeEvent.getModifierState(keyArg); 3263 } 3264 var keyProp = modifierKeyToProp[keyArg]; 3265 return keyProp ? !!nativeEvent[keyProp] : false; 3266 } 3267 3268 function getEventModifierState(nativeEvent) { 3269 return modifierStateGetter; 3270 } 3271 3272 var previousScreenX = 0; 3273 var previousScreenY = 0; 3274 // Use flags to signal movementX/Y has already been set 3275 var isMovementXSet = false; 3276 var isMovementYSet = false; 3277 3278 /** 3279 * @interface MouseEvent 3280 * @see http://www.w3.org/TR/DOM-Level-3-Events/ 3281 */ 3282 var SyntheticMouseEvent = SyntheticUIEvent.extend({ 3283 screenX: null, 3284 screenY: null, 3285 clientX: null, 3286 clientY: null, 3287 pageX: null, 3288 pageY: null, 3289 ctrlKey: null, 3290 shiftKey: null, 3291 altKey: null, 3292 metaKey: null, 3293 getModifierState: getEventModifierState, 3294 button: null, 3295 buttons: null, 3296 relatedTarget: function (event) { 3297 return event.relatedTarget || (event.fromElement === event.srcElement ? event.toElement : event.fromElement); 3298 }, 3299 movementX: function (event) { 3300 if ('movementX' in event) { 3301 return event.movementX; 3302 } 3303 3304 var screenX = previousScreenX; 3305 previousScreenX = event.screenX; 3306 3307 if (!isMovementXSet) { 3308 isMovementXSet = true; 3309 return 0; 3310 } 3311 3312 return event.type === 'mousemove' ? event.screenX - screenX : 0; 3313 }, 3314 movementY: function (event) { 3315 if ('movementY' in event) { 3316 return event.movementY; 3317 } 3318 3319 var screenY = previousScreenY; 3320 previousScreenY = event.screenY; 3321 3322 if (!isMovementYSet) { 3323 isMovementYSet = true; 3324 return 0; 3325 } 3326 3327 return event.type === 'mousemove' ? event.screenY - screenY : 0; 3328 } 3329 }); 3330 3331 /** 3332 * @interface PointerEvent 3333 * @see http://www.w3.org/TR/pointerevents/ 3334 */ 3335 var SyntheticPointerEvent = SyntheticMouseEvent.extend({ 3336 pointerId: null, 3337 width: null, 3338 height: null, 3339 pressure: null, 3340 tangentialPressure: null, 3341 tiltX: null, 3342 tiltY: null, 3343 twist: null, 3344 pointerType: null, 3345 isPrimary: null 3346 }); 3347 3348 var eventTypes$2 = { 3349 mouseEnter: { 3350 registrationName: 'onMouseEnter', 3351 dependencies: [TOP_MOUSE_OUT, TOP_MOUSE_OVER] 3352 }, 3353 mouseLeave: { 3354 registrationName: 'onMouseLeave', 3355 dependencies: [TOP_MOUSE_OUT, TOP_MOUSE_OVER] 3356 }, 3357 pointerEnter: { 3358 registrationName: 'onPointerEnter', 3359 dependencies: [TOP_POINTER_OUT, TOP_POINTER_OVER] 3360 }, 3361 pointerLeave: { 3362 registrationName: 'onPointerLeave', 3363 dependencies: [TOP_POINTER_OUT, TOP_POINTER_OVER] 3364 } 3365 }; 3366 3367 var EnterLeaveEventPlugin = { 3368 eventTypes: eventTypes$2, 3369 3370 /** 3371 * For almost every interaction we care about, there will be both a top-level 3372 * `mouseover` and `mouseout` event that occurs. Only use `mouseout` so that 3373 * we do not extract duplicate events. However, moving the mouse into the 3374 * browser from outside will not fire a `mouseout` event. In this case, we use 3375 * the `mouseover` top-level event. 3376 */ 3377 extractEvents: function (topLevelType, targetInst, nativeEvent, nativeEventTarget) { 3378 var isOverEvent = topLevelType === TOP_MOUSE_OVER || topLevelType === TOP_POINTER_OVER; 3379 var isOutEvent = topLevelType === TOP_MOUSE_OUT || topLevelType === TOP_POINTER_OUT; 3380 3381 if (isOverEvent && (nativeEvent.relatedTarget || nativeEvent.fromElement)) { 3382 return null; 3383 } 3384 3385 if (!isOutEvent && !isOverEvent) { 3386 // Must not be a mouse or pointer in or out - ignoring. 3387 return null; 3388 } 3389 3390 var win = void 0; 3391 if (nativeEventTarget.window === nativeEventTarget) { 3392 // `nativeEventTarget` is probably a window object. 3393 win = nativeEventTarget; 3394 } else { 3395 // TODO: Figure out why `ownerDocument` is sometimes undefined in IE8. 3396 var doc = nativeEventTarget.ownerDocument; 3397 if (doc) { 3398 win = doc.defaultView || doc.parentWindow; 3399 } else { 3400 win = window; 3401 } 3402 } 3403 3404 var from = void 0; 3405 var to = void 0; 3406 if (isOutEvent) { 3407 from = targetInst; 3408 var related = nativeEvent.relatedTarget || nativeEvent.toElement; 3409 to = related ? getClosestInstanceFromNode(related) : null; 3410 } else { 3411 // Moving to a node from outside the window. 3412 from = null; 3413 to = targetInst; 3414 } 3415 3416 if (from === to) { 3417 // Nothing pertains to our managed components. 3418 return null; 3419 } 3420 3421 var eventInterface = void 0, 3422 leaveEventType = void 0, 3423 enterEventType = void 0, 3424 eventTypePrefix = void 0; 3425 3426 if (topLevelType === TOP_MOUSE_OUT || topLevelType === TOP_MOUSE_OVER) { 3427 eventInterface = SyntheticMouseEvent; 3428 leaveEventType = eventTypes$2.mouseLeave; 3429 enterEventType = eventTypes$2.mouseEnter; 3430 eventTypePrefix = 'mouse'; 3431 } else if (topLevelType === TOP_POINTER_OUT || topLevelType === TOP_POINTER_OVER) { 3432 eventInterface = SyntheticPointerEvent; 3433 leaveEventType = eventTypes$2.pointerLeave; 3434 enterEventType = eventTypes$2.pointerEnter; 3435 eventTypePrefix = 'pointer'; 3436 } 3437 3438 var fromNode = from == null ? win : getNodeFromInstance$1(from); 3439 var toNode = to == null ? win : getNodeFromInstance$1(to); 3440 3441 var leave = eventInterface.getPooled(leaveEventType, from, nativeEvent, nativeEventTarget); 3442 leave.type = eventTypePrefix + 'leave'; 3443 leave.target = fromNode; 3444 leave.relatedTarget = toNode; 3445 3446 var enter = eventInterface.getPooled(enterEventType, to, nativeEvent, nativeEventTarget); 3447 enter.type = eventTypePrefix + 'enter'; 3448 enter.target = toNode; 3449 enter.relatedTarget = fromNode; 3450 3451 accumulateEnterLeaveDispatches(leave, enter, from, to); 3452 3453 return [leave, enter]; 3454 } 3455 }; 3456 3457 /** 3458 * inlined Object.is polyfill to avoid requiring consumers ship their own 3459 * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is 3460 */ 3461 function is(x, y) { 3462 return x === y && (x !== 0 || 1 / x === 1 / y) || x !== x && y !== y // eslint-disable-line no-self-compare 3463 ; 3464 } 3465 3466 var hasOwnProperty$1 = Object.prototype.hasOwnProperty; 3467 3468 /** 3469 * Performs equality by iterating through keys on an object and returning false 3470 * when any key has values which are not strictly equal between the arguments. 3471 * Returns true when the values of all keys are strictly equal. 3472 */ 3473 function shallowEqual(objA, objB) { 3474 if (is(objA, objB)) { 3475 return true; 3476 } 3477 3478 if (typeof objA !== 'object' || objA === null || typeof objB !== 'object' || objB === null) { 3479 return false; 3480 } 3481 3482 var keysA = Object.keys(objA); 3483 var keysB = Object.keys(objB); 3484 3485 if (keysA.length !== keysB.length) { 3486 return false; 3487 } 3488 3489 // Test for A's keys different from B. 3490 for (var i = 0; i < keysA.length; i++) { 3491 if (!hasOwnProperty$1.call(objB, keysA[i]) || !is(objA[keysA[i]], objB[keysA[i]])) { 3492 return false; 3493 } 3494 } 3495 3496 return true; 3497 } 3498 3499 /** 3500 * `ReactInstanceMap` maintains a mapping from a public facing stateful 3501 * instance (key) and the internal representation (value). This allows public 3502 * methods to accept the user facing instance as an argument and map them back 3503 * to internal methods. 3504 * 3505 * Note that this module is currently shared and assumed to be stateless. 3506 * If this becomes an actual Map, that will break. 3507 */ 3508 3509 /** 3510 * This API should be called `delete` but we'd have to make sure to always 3511 * transform these to strings for IE support. When this transform is fully 3512 * supported we can rename it. 3513 */ 3514 3515 3516 function get(key) { 3517 return key._reactInternalFiber; 3518 } 3519 3520 function has(key) { 3521 return key._reactInternalFiber !== undefined; 3522 } 3523 3524 function set(key, value) { 3525 key._reactInternalFiber = value; 3526 } 3527 3528 // Don't change these two values. They're used by React Dev Tools. 3529 var NoEffect = /* */0; 3530 var PerformedWork = /* */1; 3531 3532 // You can change the rest (and add more). 3533 var Placement = /* */2; 3534 var Update = /* */4; 3535 var PlacementAndUpdate = /* */6; 3536 var Deletion = /* */8; 3537 var ContentReset = /* */16; 3538 var Callback = /* */32; 3539 var DidCapture = /* */64; 3540 var Ref = /* */128; 3541 var Snapshot = /* */256; 3542 var Passive = /* */512; 3543 3544 // Passive & Update & Callback & Ref & Snapshot 3545 var LifecycleEffectMask = /* */932; 3546 3547 // Union of all host effects 3548 var HostEffectMask = /* */1023; 3549 3550 var Incomplete = /* */1024; 3551 var ShouldCapture = /* */2048; 3552 3553 var ReactCurrentOwner$1 = ReactSharedInternals.ReactCurrentOwner; 3554 3555 var MOUNTING = 1; 3556 var MOUNTED = 2; 3557 var UNMOUNTED = 3; 3558 3559 function isFiberMountedImpl(fiber) { 3560 var node = fiber; 3561 if (!fiber.alternate) { 3562 // If there is no alternate, this might be a new tree that isn't inserted 3563 // yet. If it is, then it will have a pending insertion effect on it. 3564 if ((node.effectTag & Placement) !== NoEffect) { 3565 return MOUNTING; 3566 } 3567 while (node.return) { 3568 node = node.return; 3569 if ((node.effectTag & Placement) !== NoEffect) { 3570 return MOUNTING; 3571 } 3572 } 3573 } else { 3574 while (node.return) { 3575 node = node.return; 3576 } 3577 } 3578 if (node.tag === HostRoot) { 3579 // TODO: Check if this was a nested HostRoot when used with 3580 // renderContainerIntoSubtree. 3581 return MOUNTED; 3582 } 3583 // If we didn't hit the root, that means that we're in an disconnected tree 3584 // that has been unmounted. 3585 return UNMOUNTED; 3586 } 3587 3588 function isFiberMounted(fiber) { 3589 return isFiberMountedImpl(fiber) === MOUNTED; 3590 } 3591 3592 function isMounted(component) { 3593 var fiber = get(component); 3594 if (!fiber) { 3595 return false; 3596 } 3597 return isFiberMountedImpl(fiber) === MOUNTED; 3598 } 3599 3600 function assertIsMounted(fiber) { 3601 !(isFiberMountedImpl(fiber) === MOUNTED) ? reactProdInvariant('188') : void 0; 3602 } 3603 3604 function findCurrentFiberUsingSlowPath(fiber) { 3605 var alternate = fiber.alternate; 3606 if (!alternate) { 3607 // If there is no alternate, then we only need to check if it is mounted. 3608 var state = isFiberMountedImpl(fiber); 3609 !(state !== UNMOUNTED) ? reactProdInvariant('188') : void 0; 3610 if (state === MOUNTING) { 3611 return null; 3612 } 3613 return fiber; 3614 } 3615 // If we have two possible branches, we'll walk backwards up to the root 3616 // to see what path the root points to. On the way we may hit one of the 3617 // special cases and we'll deal with them. 3618 var a = fiber; 3619 var b = alternate; 3620 while (true) { 3621 var parentA = a.return; 3622 var parentB = parentA ? parentA.alternate : null; 3623 if (!parentA || !parentB) { 3624 // We're at the root. 3625 break; 3626 } 3627 3628 // If both copies of the parent fiber point to the same child, we can 3629 // assume that the child is current. This happens when we bailout on low 3630 // priority: the bailed out fiber's child reuses the current child. 3631 if (parentA.child === parentB.child) { 3632 var child = parentA.child; 3633 while (child) { 3634 if (child === a) { 3635 // We've determined that A is the current branch. 3636 assertIsMounted(parentA); 3637 return fiber; 3638 } 3639 if (child === b) { 3640 // We've determined that B is the current branch. 3641 assertIsMounted(parentA); 3642 return alternate; 3643 } 3644 child = child.sibling; 3645 } 3646 // We should never have an alternate for any mounting node. So the only 3647 // way this could possibly happen is if this was unmounted, if at all. 3648 reactProdInvariant('188'); 3649 } 3650 3651 if (a.return !== b.return) { 3652 // The return pointer of A and the return pointer of B point to different 3653 // fibers. We assume that return pointers never criss-cross, so A must 3654 // belong to the child set of A.return, and B must belong to the child 3655 // set of B.return. 3656 a = parentA; 3657 b = parentB; 3658 } else { 3659 // The return pointers point to the same fiber. We'll have to use the 3660 // default, slow path: scan the child sets of each parent alternate to see 3661 // which child belongs to which set. 3662 // 3663 // Search parent A's child set 3664 var didFindChild = false; 3665 var _child = parentA.child; 3666 while (_child) { 3667 if (_child === a) { 3668 didFindChild = true; 3669 a = parentA; 3670 b = parentB; 3671 break; 3672 } 3673 if (_child === b) { 3674 didFindChild = true; 3675 b = parentA; 3676 a = parentB; 3677 break; 3678 } 3679 _child = _child.sibling; 3680 } 3681 if (!didFindChild) { 3682 // Search parent B's child set 3683 _child = parentB.child; 3684 while (_child) { 3685 if (_child === a) { 3686 didFindChild = true; 3687 a = parentB; 3688 b = parentA; 3689 break; 3690 } 3691 if (_child === b) { 3692 didFindChild = true; 3693 b = parentB; 3694 a = parentA; 3695 break; 3696 } 3697 _child = _child.sibling; 3698 } 3699 !didFindChild ? reactProdInvariant('189') : void 0; 3700 } 3701 } 3702 3703 !(a.alternate === b) ? reactProdInvariant('190') : void 0; 3704 } 3705 // If the root is not a host container, we're in a disconnected tree. I.e. 3706 // unmounted. 3707 !(a.tag === HostRoot) ? reactProdInvariant('188') : void 0; 3708 if (a.stateNode.current === a) { 3709 // We've determined that A is the current branch. 3710 return fiber; 3711 } 3712 // Otherwise B has to be current branch. 3713 return alternate; 3714 } 3715 3716 function findCurrentHostFiber(parent) { 3717 var currentParent = findCurrentFiberUsingSlowPath(parent); 3718 if (!currentParent) { 3719 return null; 3720 } 3721 3722 // Next we'll drill down this component to find the first HostComponent/Text. 3723 var node = currentParent; 3724 while (true) { 3725 if (node.tag === HostComponent || node.tag === HostText) { 3726 return node; 3727 } else if (node.child) { 3728 node.child.return = node; 3729 node = node.child; 3730 continue; 3731 } 3732 if (node === currentParent) { 3733 return null; 3734 } 3735 while (!node.sibling) { 3736 if (!node.return || node.return === currentParent) { 3737 return null; 3738 } 3739 node = node.return; 3740 } 3741 node.sibling.return = node.return; 3742 node = node.sibling; 3743 } 3744 // Flow needs the return null here, but ESLint complains about it. 3745 // eslint-disable-next-line no-unreachable 3746 return null; 3747 } 3748 3749 function addEventBubbleListener(element, eventType, listener) { 3750 element.addEventListener(eventType, listener, false); 3751 } 3752 3753 function addEventCaptureListener(element, eventType, listener) { 3754 element.addEventListener(eventType, listener, true); 3755 } 3756 3757 /** 3758 * @interface Event 3759 * @see http://www.w3.org/TR/css3-animations/#AnimationEvent-interface 3760 * @see https://developer.mozilla.org/en-US/docs/Web/API/AnimationEvent 3761 */ 3762 var SyntheticAnimationEvent = SyntheticEvent.extend({ 3763 animationName: null, 3764 elapsedTime: null, 3765 pseudoElement: null 3766 }); 3767 3768 /** 3769 * @interface Event 3770 * @see http://www.w3.org/TR/clipboard-apis/ 3771 */ 3772 var SyntheticClipboardEvent = SyntheticEvent.extend({ 3773 clipboardData: function (event) { 3774 return 'clipboardData' in event ? event.clipboardData : window.clipboardData; 3775 } 3776 }); 3777 3778 /** 3779 * @interface FocusEvent 3780 * @see http://www.w3.org/TR/DOM-Level-3-Events/ 3781 */ 3782 var SyntheticFocusEvent = SyntheticUIEvent.extend({ 3783 relatedTarget: null 3784 }); 3785 3786 /** 3787 * `charCode` represents the actual "character code" and is safe to use with 3788 * `String.fromCharCode`. As such, only keys that correspond to printable 3789 * characters produce a valid `charCode`, the only exception to this is Enter. 3790 * The Tab-key is considered non-printable and does not have a `charCode`, 3791 * presumably because it does not produce a tab-character in browsers. 3792 * 3793 * @param {object} nativeEvent Native browser event. 3794 * @return {number} Normalized `charCode` property. 3795 */ 3796 function getEventCharCode(nativeEvent) { 3797 var charCode = void 0; 3798 var keyCode = nativeEvent.keyCode; 3799 3800 if ('charCode' in nativeEvent) { 3801 charCode = nativeEvent.charCode; 3802 3803 // FF does not set `charCode` for the Enter-key, check against `keyCode`. 3804 if (charCode === 0 && keyCode === 13) { 3805 charCode = 13; 3806 } 3807 } else { 3808 // IE8 does not implement `charCode`, but `keyCode` has the correct value. 3809 charCode = keyCode; 3810 } 3811 3812 // IE and Edge (on Windows) and Chrome / Safari (on Windows and Linux) 3813 // report Enter as charCode 10 when ctrl is pressed. 3814 if (charCode === 10) { 3815 charCode = 13; 3816 } 3817 3818 // Some non-printable keys are reported in `charCode`/`keyCode`, discard them. 3819 // Must not discard the (non-)printable Enter-key. 3820 if (charCode >= 32 || charCode === 13) { 3821 return charCode; 3822 } 3823 3824 return 0; 3825 } 3826 3827 /** 3828 * Normalization of deprecated HTML5 `key` values 3829 * @see https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent#Key_names 3830 */ 3831 var normalizeKey = { 3832 Esc: 'Escape', 3833 Spacebar: ' ', 3834 Left: 'ArrowLeft', 3835 Up: 'ArrowUp', 3836 Right: 'ArrowRight', 3837 Down: 'ArrowDown', 3838 Del: 'Delete', 3839 Win: 'OS', 3840 Menu: 'ContextMenu', 3841 Apps: 'ContextMenu', 3842 Scroll: 'ScrollLock', 3843 MozPrintableKey: 'Unidentified' 3844 }; 3845 3846 /** 3847 * Translation from legacy `keyCode` to HTML5 `key` 3848 * Only special keys supported, all others depend on keyboard layout or browser 3849 * @see https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent#Key_names 3850 */ 3851 var translateToKey = { 3852 '8': 'Backspace', 3853 '9': 'Tab', 3854 '12': 'Clear', 3855 '13': 'Enter', 3856 '16': 'Shift', 3857 '17': 'Control', 3858 '18': 'Alt', 3859 '19': 'Pause', 3860 '20': 'CapsLock', 3861 '27': 'Escape', 3862 '32': ' ', 3863 '33': 'PageUp', 3864 '34': 'PageDown', 3865 '35': 'End', 3866 '36': 'Home', 3867 '37': 'ArrowLeft', 3868 '38': 'ArrowUp', 3869 '39': 'ArrowRight', 3870 '40': 'ArrowDown', 3871 '45': 'Insert', 3872 '46': 'Delete', 3873 '112': 'F1', 3874 '113': 'F2', 3875 '114': 'F3', 3876 '115': 'F4', 3877 '116': 'F5', 3878 '117': 'F6', 3879 '118': 'F7', 3880 '119': 'F8', 3881 '120': 'F9', 3882 '121': 'F10', 3883 '122': 'F11', 3884 '123': 'F12', 3885 '144': 'NumLock', 3886 '145': 'ScrollLock', 3887 '224': 'Meta' 3888 }; 3889 3890 /** 3891 * @param {object} nativeEvent Native browser event. 3892 * @return {string} Normalized `key` property. 3893 */ 3894 function getEventKey(nativeEvent) { 3895 if (nativeEvent.key) { 3896 // Normalize inconsistent values reported by browsers due to 3897 // implementations of a working draft specification. 3898 3899 // FireFox implements `key` but returns `MozPrintableKey` for all 3900 // printable characters (normalized to `Unidentified`), ignore it. 3901 var key = normalizeKey[nativeEvent.key] || nativeEvent.key; 3902 if (key !== 'Unidentified') { 3903 return key; 3904 } 3905 } 3906 3907 // Browser does not implement `key`, polyfill as much of it as we can. 3908 if (nativeEvent.type === 'keypress') { 3909 var charCode = getEventCharCode(nativeEvent); 3910 3911 // The enter-key is technically both printable and non-printable and can 3912 // thus be captured by `keypress`, no other non-printable key should. 3913 return charCode === 13 ? 'Enter' : String.fromCharCode(charCode); 3914 } 3915 if (nativeEvent.type === 'keydown' || nativeEvent.type === 'keyup') { 3916 // While user keyboard layout determines the actual meaning of each 3917 // `keyCode` value, almost all function keys have a universal value. 3918 return translateToKey[nativeEvent.keyCode] || 'Unidentified'; 3919 } 3920 return ''; 3921 } 3922 3923 /** 3924 * @interface KeyboardEvent 3925 * @see http://www.w3.org/TR/DOM-Level-3-Events/ 3926 */ 3927 var SyntheticKeyboardEvent = SyntheticUIEvent.extend({ 3928 key: getEventKey, 3929 location: null, 3930 ctrlKey: null, 3931 shiftKey: null, 3932 altKey: null, 3933 metaKey: null, 3934 repeat: null, 3935 locale: null, 3936 getModifierState: getEventModifierState, 3937 // Legacy Interface 3938 charCode: function (event) { 3939 // `charCode` is the result of a KeyPress event and represents the value of 3940 // the actual printable character. 3941 3942 // KeyPress is deprecated, but its replacement is not yet final and not 3943 // implemented in any major browser. Only KeyPress has charCode. 3944 if (event.type === 'keypress') { 3945 return getEventCharCode(event); 3946 } 3947 return 0; 3948 }, 3949 keyCode: function (event) { 3950 // `keyCode` is the result of a KeyDown/Up event and represents the value of 3951 // physical keyboard key. 3952 3953 // The actual meaning of the value depends on the users' keyboard layout 3954 // which cannot be detected. Assuming that it is a US keyboard layout 3955 // provides a surprisingly accurate mapping for US and European users. 3956 // Due to this, it is left to the user to implement at this time. 3957 if (event.type === 'keydown' || event.type === 'keyup') { 3958 return event.keyCode; 3959 } 3960 return 0; 3961 }, 3962 which: function (event) { 3963 // `which` is an alias for either `keyCode` or `charCode` depending on the 3964 // type of the event. 3965 if (event.type === 'keypress') { 3966 return getEventCharCode(event); 3967 } 3968 if (event.type === 'keydown' || event.type === 'keyup') { 3969 return event.keyCode; 3970 } 3971 return 0; 3972 } 3973 }); 3974 3975 /** 3976 * @interface DragEvent 3977 * @see http://www.w3.org/TR/DOM-Level-3-Events/ 3978 */ 3979 var SyntheticDragEvent = SyntheticMouseEvent.extend({ 3980 dataTransfer: null 3981 }); 3982 3983 /** 3984 * @interface TouchEvent 3985 * @see http://www.w3.org/TR/touch-events/ 3986 */ 3987 var SyntheticTouchEvent = SyntheticUIEvent.extend({ 3988 touches: null, 3989 targetTouches: null, 3990 changedTouches: null, 3991 altKey: null, 3992 metaKey: null, 3993 ctrlKey: null, 3994 shiftKey: null, 3995 getModifierState: getEventModifierState 3996 }); 3997 3998 /** 3999 * @interface Event 4000 * @see http://www.w3.org/TR/2009/WD-css3-transitions-20090320/#transition-events- 4001 * @see https://developer.mozilla.org/en-US/docs/Web/API/TransitionEvent 4002 */ 4003 var SyntheticTransitionEvent = SyntheticEvent.extend({ 4004 propertyName: null, 4005 elapsedTime: null, 4006 pseudoElement: null 4007 }); 4008 4009 /** 4010 * @interface WheelEvent 4011 * @see http://www.w3.org/TR/DOM-Level-3-Events/ 4012 */ 4013 var SyntheticWheelEvent = SyntheticMouseEvent.extend({ 4014 deltaX: function (event) { 4015 return 'deltaX' in event ? event.deltaX : // Fallback to `wheelDeltaX` for Webkit and normalize (right is positive). 4016 'wheelDeltaX' in event ? -event.wheelDeltaX : 0; 4017 }, 4018 deltaY: function (event) { 4019 return 'deltaY' in event ? event.deltaY : // Fallback to `wheelDeltaY` for Webkit and normalize (down is positive). 4020 'wheelDeltaY' in event ? -event.wheelDeltaY : // Fallback to `wheelDelta` for IE<9 and normalize (down is positive). 4021 'wheelDelta' in event ? -event.wheelDelta : 0; 4022 }, 4023 4024 deltaZ: null, 4025 4026 // Browsers without "deltaMode" is reporting in raw wheel delta where one 4027 // notch on the scroll is always +/- 120, roughly equivalent to pixels. 4028 // A good approximation of DOM_DELTA_LINE (1) is 5% of viewport size or 4029 // ~40 pixels, for DOM_DELTA_SCREEN (2) it is 87.5% of viewport size. 4030 deltaMode: null 4031 }); 4032 4033 /** 4034 * Turns 4035 * ['abort', ...] 4036 * into 4037 * eventTypes = { 4038 * 'abort': { 4039 * phasedRegistrationNames: { 4040 * bubbled: 'onAbort', 4041 * captured: 'onAbortCapture', 4042 * }, 4043 * dependencies: [TOP_ABORT], 4044 * }, 4045 * ... 4046 * }; 4047 * topLevelEventsToDispatchConfig = new Map([ 4048 * [TOP_ABORT, { sameConfig }], 4049 * ]); 4050 */ 4051 4052 var interactiveEventTypeNames = [[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']]; 4053 var nonInteractiveEventTypeNames = [[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_DRAG, 'drag'], [TOP_DRAG_ENTER, 'dragEnter'], [TOP_DRAG_EXIT, 'dragExit'], [TOP_DRAG_LEAVE, 'dragLeave'], [TOP_DRAG_OVER, 'dragOver'], [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_MOUSE_MOVE, 'mouseMove'], [TOP_MOUSE_OUT, 'mouseOut'], [TOP_MOUSE_OVER, 'mouseOver'], [TOP_PLAYING, 'playing'], [TOP_POINTER_MOVE, 'pointerMove'], [TOP_POINTER_OUT, 'pointerOut'], [TOP_POINTER_OVER, 'pointerOver'], [TOP_PROGRESS, 'progress'], [TOP_SCROLL, 'scroll'], [TOP_SEEKING, 'seeking'], [TOP_STALLED, 'stalled'], [TOP_SUSPEND, 'suspend'], [TOP_TIME_UPDATE, 'timeUpdate'], [TOP_TOGGLE, 'toggle'], [TOP_TOUCH_MOVE, 'touchMove'], [TOP_TRANSITION_END, 'transitionEnd'], [TOP_WAITING, 'waiting'], [TOP_WHEEL, 'wheel']]; 4054 4055 var eventTypes$4 = {}; 4056 var topLevelEventsToDispatchConfig = {}; 4057 4058 function addEventTypeNameToConfig(_ref, isInteractive) { 4059 var topEvent = _ref[0], 4060 event = _ref[1]; 4061 4062 var capitalizedEvent = event[0].toUpperCase() + event.slice(1); 4063 var onEvent = 'on' + capitalizedEvent; 4064 4065 var type = { 4066 phasedRegistrationNames: { 4067 bubbled: onEvent, 4068 captured: onEvent + 'Capture' 4069 }, 4070 dependencies: [topEvent], 4071 isInteractive: isInteractive 4072 }; 4073 eventTypes$4[event] = type; 4074 topLevelEventsToDispatchConfig[topEvent] = type; 4075 } 4076 4077 interactiveEventTypeNames.forEach(function (eventTuple) { 4078 addEventTypeNameToConfig(eventTuple, true); 4079 }); 4080 nonInteractiveEventTypeNames.forEach(function (eventTuple) { 4081 addEventTypeNameToConfig(eventTuple, false); 4082 }); 4083 4084 var SimpleEventPlugin = { 4085 eventTypes: eventTypes$4, 4086 4087 isInteractiveTopLevelEventType: function (topLevelType) { 4088 var config = topLevelEventsToDispatchConfig[topLevelType]; 4089 return config !== undefined && config.isInteractive === true; 4090 }, 4091 4092 4093 extractEvents: function (topLevelType, targetInst, nativeEvent, nativeEventTarget) { 4094 var dispatchConfig = topLevelEventsToDispatchConfig[topLevelType]; 4095 if (!dispatchConfig) { 4096 return null; 4097 } 4098 var EventConstructor = void 0; 4099 switch (topLevelType) { 4100 case TOP_KEY_PRESS: 4101 // Firefox creates a keypress event for function keys too. This removes 4102 // the unwanted keypress events. Enter is however both printable and 4103 // non-printable. One would expect Tab to be as well (but it isn't). 4104 if (getEventCharCode(nativeEvent) === 0) { 4105 return null; 4106 } 4107 /* falls through */ 4108 case TOP_KEY_DOWN: 4109 case TOP_KEY_UP: 4110 EventConstructor = SyntheticKeyboardEvent; 4111 break; 4112 case TOP_BLUR: 4113 case TOP_FOCUS: 4114 EventConstructor = SyntheticFocusEvent; 4115 break; 4116 case TOP_CLICK: 4117 // Firefox creates a click event on right mouse clicks. This removes the 4118 // unwanted click events. 4119 if (nativeEvent.button === 2) { 4120 return null; 4121 } 4122 /* falls through */ 4123 case TOP_AUX_CLICK: 4124 case TOP_DOUBLE_CLICK: 4125 case TOP_MOUSE_DOWN: 4126 case TOP_MOUSE_MOVE: 4127 case TOP_MOUSE_UP: 4128 // TODO: Disabled elements should not respond to mouse events 4129 /* falls through */ 4130 case TOP_MOUSE_OUT: 4131 case TOP_MOUSE_OVER: 4132 case TOP_CONTEXT_MENU: 4133 EventConstructor = SyntheticMouseEvent; 4134 break; 4135 case TOP_DRAG: 4136 case TOP_DRAG_END: 4137 case TOP_DRAG_ENTER: 4138 case TOP_DRAG_EXIT: 4139 case TOP_DRAG_LEAVE: 4140 case TOP_DRAG_OVER: 4141 case TOP_DRAG_START: 4142 case TOP_DROP: 4143 EventConstructor = SyntheticDragEvent; 4144 break; 4145 case TOP_TOUCH_CANCEL: 4146 case TOP_TOUCH_END: 4147 case TOP_TOUCH_MOVE: 4148 case TOP_TOUCH_START: 4149 EventConstructor = SyntheticTouchEvent; 4150 break; 4151 case TOP_ANIMATION_END: 4152 case TOP_ANIMATION_ITERATION: 4153 case TOP_ANIMATION_START: 4154 EventConstructor = SyntheticAnimationEvent; 4155 break; 4156 case TOP_TRANSITION_END: 4157 EventConstructor = SyntheticTransitionEvent; 4158 break; 4159 case TOP_SCROLL: 4160 EventConstructor = SyntheticUIEvent; 4161 break; 4162 case TOP_WHEEL: 4163 EventConstructor = SyntheticWheelEvent; 4164 break; 4165 case TOP_COPY: 4166 case TOP_CUT: 4167 case TOP_PASTE: 4168 EventConstructor = SyntheticClipboardEvent; 4169 break; 4170 case TOP_GOT_POINTER_CAPTURE: 4171 case TOP_LOST_POINTER_CAPTURE: 4172 case TOP_POINTER_CANCEL: 4173 case TOP_POINTER_DOWN: 4174 case TOP_POINTER_MOVE: 4175 case TOP_POINTER_OUT: 4176 case TOP_POINTER_OVER: 4177 case TOP_POINTER_UP: 4178 EventConstructor = SyntheticPointerEvent; 4179 break; 4180 default: 4181 4182 // HTML Events 4183 // @see http://www.w3.org/TR/html5/index.html#events-0 4184 EventConstructor = SyntheticEvent; 4185 break; 4186 } 4187 var event = EventConstructor.getPooled(dispatchConfig, targetInst, nativeEvent, nativeEventTarget); 4188 accumulateTwoPhaseDispatches(event); 4189 return event; 4190 } 4191 }; 4192 4193 var isInteractiveTopLevelEventType = SimpleEventPlugin.isInteractiveTopLevelEventType; 4194 4195 4196 var CALLBACK_BOOKKEEPING_POOL_SIZE = 10; 4197 var callbackBookkeepingPool = []; 4198 4199 /** 4200 * Find the deepest React component completely containing the root of the 4201 * passed-in instance (for use when entire React trees are nested within each 4202 * other). If React trees are not nested, returns null. 4203 */ 4204 function findRootContainerNode(inst) { 4205 // TODO: It may be a good idea to cache this to prevent unnecessary DOM 4206 // traversal, but caching is difficult to do correctly without using a 4207 // mutation observer to listen for all DOM changes. 4208 while (inst.return) { 4209 inst = inst.return; 4210 } 4211 if (inst.tag !== HostRoot) { 4212 // This can happen if we're in a detached tree. 4213 return null; 4214 } 4215 return inst.stateNode.containerInfo; 4216 } 4217 4218 // Used to store ancestor hierarchy in top level callback 4219 function getTopLevelCallbackBookKeeping(topLevelType, nativeEvent, targetInst) { 4220 if (callbackBookkeepingPool.length) { 4221 var instance = callbackBookkeepingPool.pop(); 4222 instance.topLevelType = topLevelType; 4223 instance.nativeEvent = nativeEvent; 4224 instance.targetInst = targetInst; 4225 return instance; 4226 } 4227 return { 4228 topLevelType: topLevelType, 4229 nativeEvent: nativeEvent, 4230 targetInst: targetInst, 4231 ancestors: [] 4232 }; 4233 } 4234 4235 function releaseTopLevelCallbackBookKeeping(instance) { 4236 instance.topLevelType = null; 4237 instance.nativeEvent = null; 4238 instance.targetInst = null; 4239 instance.ancestors.length = 0; 4240 if (callbackBookkeepingPool.length < CALLBACK_BOOKKEEPING_POOL_SIZE) { 4241 callbackBookkeepingPool.push(instance); 4242 } 4243 } 4244 4245 function handleTopLevel(bookKeeping) { 4246 var targetInst = bookKeeping.targetInst; 4247 4248 // Loop through the hierarchy, in case there's any nested components. 4249 // It's important that we build the array of ancestors before calling any 4250 // event handlers, because event handlers can modify the DOM, leading to 4251 // inconsistencies with ReactMount's node cache. See #1105. 4252 var ancestor = targetInst; 4253 do { 4254 if (!ancestor) { 4255 bookKeeping.ancestors.push(ancestor); 4256 break; 4257 } 4258 var root = findRootContainerNode(ancestor); 4259 if (!root) { 4260 break; 4261 } 4262 bookKeeping.ancestors.push(ancestor); 4263 ancestor = getClosestInstanceFromNode(root); 4264 } while (ancestor); 4265 4266 for (var i = 0; i < bookKeeping.ancestors.length; i++) { 4267 targetInst = bookKeeping.ancestors[i]; 4268 runExtractedEventsInBatch(bookKeeping.topLevelType, targetInst, bookKeeping.nativeEvent, getEventTarget(bookKeeping.nativeEvent)); 4269 } 4270 } 4271 4272 // TODO: can we stop exporting these? 4273 var _enabled = true; 4274 4275 function setEnabled(enabled) { 4276 _enabled = !!enabled; 4277 } 4278 4279 function isEnabled() { 4280 return _enabled; 4281 } 4282 4283 /** 4284 * Traps top-level events by using event bubbling. 4285 * 4286 * @param {number} topLevelType Number from `TopLevelEventTypes`. 4287 * @param {object} element Element on which to attach listener. 4288 * @return {?object} An object with a remove function which will forcefully 4289 * remove the listener. 4290 * @internal 4291 */ 4292 function trapBubbledEvent(topLevelType, element) { 4293 if (!element) { 4294 return null; 4295 } 4296 var dispatch = isInteractiveTopLevelEventType(topLevelType) ? dispatchInteractiveEvent : dispatchEvent; 4297 4298 addEventBubbleListener(element, getRawEventName(topLevelType), 4299 // Check if interactive and wrap in interactiveUpdates 4300 dispatch.bind(null, topLevelType)); 4301 } 4302 4303 /** 4304 * Traps a top-level event by using event capturing. 4305 * 4306 * @param {number} topLevelType Number from `TopLevelEventTypes`. 4307 * @param {object} element Element on which to attach listener. 4308 * @return {?object} An object with a remove function which will forcefully 4309 * remove the listener. 4310 * @internal 4311 */ 4312 function trapCapturedEvent(topLevelType, element) { 4313 if (!element) { 4314 return null; 4315 } 4316 var dispatch = isInteractiveTopLevelEventType(topLevelType) ? dispatchInteractiveEvent : dispatchEvent; 4317 4318 addEventCaptureListener(element, getRawEventName(topLevelType), 4319 // Check if interactive and wrap in interactiveUpdates 4320 dispatch.bind(null, topLevelType)); 4321 } 4322 4323 function dispatchInteractiveEvent(topLevelType, nativeEvent) { 4324 interactiveUpdates(dispatchEvent, topLevelType, nativeEvent); 4325 } 4326 4327 function dispatchEvent(topLevelType, nativeEvent) { 4328 if (!_enabled) { 4329 return; 4330 } 4331 4332 var nativeEventTarget = getEventTarget(nativeEvent); 4333 var targetInst = getClosestInstanceFromNode(nativeEventTarget); 4334 if (targetInst !== null && typeof targetInst.tag === 'number' && !isFiberMounted(targetInst)) { 4335 // If we get an event (ex: img onload) before committing that 4336 // component's mount, ignore it for now (that is, treat it as if it was an 4337 // event on a non-React tree). We might also consider queueing events and 4338 // dispatching them after the mount. 4339 targetInst = null; 4340 } 4341 4342 var bookKeeping = getTopLevelCallbackBookKeeping(topLevelType, nativeEvent, targetInst); 4343 4344 try { 4345 // Event queue being processed in the same cycle allows 4346 // `preventDefault`. 4347 batchedUpdates(handleTopLevel, bookKeeping); 4348 } finally { 4349 releaseTopLevelCallbackBookKeeping(bookKeeping); 4350 } 4351 } 4352 4353 /** 4354 * Summary of `ReactBrowserEventEmitter` event handling: 4355 * 4356 * - Top-level delegation is used to trap most native browser events. This 4357 * may only occur in the main thread and is the responsibility of 4358 * ReactDOMEventListener, which is injected and can therefore support 4359 * pluggable event sources. This is the only work that occurs in the main 4360 * thread. 4361 * 4362 * - We normalize and de-duplicate events to account for browser quirks. This 4363 * may be done in the worker thread. 4364 * 4365 * - Forward these native events (with the associated top-level type used to 4366 * trap it) to `EventPluginHub`, which in turn will ask plugins if they want 4367 * to extract any synthetic events. 4368 * 4369 * - The `EventPluginHub` will then process each event by annotating them with 4370 * "dispatches", a sequence of listeners and IDs that care about that event. 4371 * 4372 * - The `EventPluginHub` then dispatches the events. 4373 * 4374 * Overview of React and the event system: 4375 * 4376 * +------------+ . 4377 * | DOM | . 4378 * +------------+ . 4379 * | . 4380 * v . 4381 * +------------+ . 4382 * | ReactEvent | . 4383 * | Listener | . 4384 * +------------+ . +-----------+ 4385 * | . +--------+|SimpleEvent| 4386 * | . | |Plugin | 4387 * +-----|------+ . v +-----------+ 4388 * | | | . +--------------+ +------------+ 4389 * | +-----------.--->|EventPluginHub| | Event | 4390 * | | . | | +-----------+ | Propagators| 4391 * | ReactEvent | . | | |TapEvent | |------------| 4392 * | Emitter | . | |<---+|Plugin | |other plugin| 4393 * | | . | | +-----------+ | utilities | 4394 * | +-----------.--->| | +------------+ 4395 * | | | . +--------------+ 4396 * +-----|------+ . ^ +-----------+ 4397 * | . | |Enter/Leave| 4398 * + . +-------+|Plugin | 4399 * +-------------+ . +-----------+ 4400 * | application | . 4401 * |-------------| . 4402 * | | . 4403 * | | . 4404 * +-------------+ . 4405 * . 4406 * React Core . General Purpose Event Plugin System 4407 */ 4408 4409 var alreadyListeningTo = {}; 4410 var reactTopListenersCounter = 0; 4411 4412 /** 4413 * To ensure no conflicts with other potential React instances on the page 4414 */ 4415 var topListenersIDKey = '_reactListenersID' + ('' + Math.random()).slice(2); 4416 4417 function getListeningForDocument(mountAt) { 4418 // In IE8, `mountAt` is a host object and doesn't have `hasOwnProperty` 4419 // directly. 4420 if (!Object.prototype.hasOwnProperty.call(mountAt, topListenersIDKey)) { 4421 mountAt[topListenersIDKey] = reactTopListenersCounter++; 4422 alreadyListeningTo[mountAt[topListenersIDKey]] = {}; 4423 } 4424 return alreadyListeningTo[mountAt[topListenersIDKey]]; 4425 } 4426 4427 /** 4428 * We listen for bubbled touch events on the document object. 4429 * 4430 * Firefox v8.01 (and possibly others) exhibited strange behavior when 4431 * mounting `onmousemove` events at some node that was not the document 4432 * element. The symptoms were that if your mouse is not moving over something 4433 * contained within that mount point (for example on the background) the 4434 * top-level listeners for `onmousemove` won't be called. However, if you 4435 * register the `mousemove` on the document object, then it will of course 4436 * catch all `mousemove`s. This along with iOS quirks, justifies restricting 4437 * top-level listeners to the document object only, at least for these 4438 * movement types of events and possibly all events. 4439 * 4440 * @see http://www.quirksmode.org/blog/archives/2010/09/click_event_del.html 4441 * 4442 * Also, `keyup`/`keypress`/`keydown` do not bubble to the window on IE, but 4443 * they bubble to document. 4444 * 4445 * @param {string} registrationName Name of listener (e.g. `onClick`). 4446 * @param {object} mountAt Container where to mount the listener 4447 */ 4448 function listenTo(registrationName, mountAt) { 4449 var isListening = getListeningForDocument(mountAt); 4450 var dependencies = registrationNameDependencies[registrationName]; 4451 4452 for (var i = 0; i < dependencies.length; i++) { 4453 var dependency = dependencies[i]; 4454 if (!(isListening.hasOwnProperty(dependency) && isListening[dependency])) { 4455 switch (dependency) { 4456 case TOP_SCROLL: 4457 trapCapturedEvent(TOP_SCROLL, mountAt); 4458 break; 4459 case TOP_FOCUS: 4460 case TOP_BLUR: 4461 trapCapturedEvent(TOP_FOCUS, mountAt); 4462 trapCapturedEvent(TOP_BLUR, mountAt); 4463 // We set the flag for a single dependency later in this function, 4464 // but this ensures we mark both as attached rather than just one. 4465 isListening[TOP_BLUR] = true; 4466 isListening[TOP_FOCUS] = true; 4467 break; 4468 case TOP_CANCEL: 4469 case TOP_CLOSE: 4470 if (isEventSupported(getRawEventName(dependency))) { 4471 trapCapturedEvent(dependency, mountAt); 4472 } 4473 break; 4474 case TOP_INVALID: 4475 case TOP_SUBMIT: 4476 case TOP_RESET: 4477 // We listen to them on the target DOM elements. 4478 // Some of them bubble so we don't want them to fire twice. 4479 break; 4480 default: 4481 // By default, listen on the top level to all non-media events. 4482 // Media events don't bubble so adding the listener wouldn't do anything. 4483 var isMediaEvent = mediaEventTypes.indexOf(dependency) !== -1; 4484 if (!isMediaEvent) { 4485 trapBubbledEvent(dependency, mountAt); 4486 } 4487 break; 4488 } 4489 isListening[dependency] = true; 4490 } 4491 } 4492 } 4493 4494 function isListeningToAllDependencies(registrationName, mountAt) { 4495 var isListening = getListeningForDocument(mountAt); 4496 var dependencies = registrationNameDependencies[registrationName]; 4497 for (var i = 0; i < dependencies.length; i++) { 4498 var dependency = dependencies[i]; 4499 if (!(isListening.hasOwnProperty(dependency) && isListening[dependency])) { 4500 return false; 4501 } 4502 } 4503 return true; 4504 } 4505 4506 function getActiveElement(doc) { 4507 doc = doc || (typeof document !== 'undefined' ? document : undefined); 4508 if (typeof doc === 'undefined') { 4509 return null; 4510 } 4511 try { 4512 return doc.activeElement || doc.body; 4513 } catch (e) { 4514 return doc.body; 4515 } 4516 } 4517 4518 /** 4519 * Given any node return the first leaf node without children. 4520 * 4521 * @param {DOMElement|DOMTextNode} node 4522 * @return {DOMElement|DOMTextNode} 4523 */ 4524 function getLeafNode(node) { 4525 while (node && node.firstChild) { 4526 node = node.firstChild; 4527 } 4528 return node; 4529 } 4530 4531 /** 4532 * Get the next sibling within a container. This will walk up the 4533 * DOM if a node's siblings have been exhausted. 4534 * 4535 * @param {DOMElement|DOMTextNode} node 4536 * @return {?DOMElement|DOMTextNode} 4537 */ 4538 function getSiblingNode(node) { 4539 while (node) { 4540 if (node.nextSibling) { 4541 return node.nextSibling; 4542 } 4543 node = node.parentNode; 4544 } 4545 } 4546 4547 /** 4548 * Get object describing the nodes which contain characters at offset. 4549 * 4550 * @param {DOMElement|DOMTextNode} root 4551 * @param {number} offset 4552 * @return {?object} 4553 */ 4554 function getNodeForCharacterOffset(root, offset) { 4555 var node = getLeafNode(root); 4556 var nodeStart = 0; 4557 var nodeEnd = 0; 4558 4559 while (node) { 4560 if (node.nodeType === TEXT_NODE) { 4561 nodeEnd = nodeStart + node.textContent.length; 4562 4563 if (nodeStart <= offset && nodeEnd >= offset) { 4564 return { 4565 node: node, 4566 offset: offset - nodeStart 4567 }; 4568 } 4569 4570 nodeStart = nodeEnd; 4571 } 4572 4573 node = getLeafNode(getSiblingNode(node)); 4574 } 4575 } 4576 4577 /** 4578 * @param {DOMElement} outerNode 4579 * @return {?object} 4580 */ 4581 function getOffsets(outerNode) { 4582 var ownerDocument = outerNode.ownerDocument; 4583 4584 var win = ownerDocument && ownerDocument.defaultView || window; 4585 var selection = win.getSelection && win.getSelection(); 4586 4587 if (!selection || selection.rangeCount === 0) { 4588 return null; 4589 } 4590 4591 var anchorNode = selection.anchorNode, 4592 anchorOffset = selection.anchorOffset, 4593 focusNode = selection.focusNode, 4594 focusOffset = selection.focusOffset; 4595 4596 // In Firefox, anchorNode and focusNode can be "anonymous divs", e.g. the 4597 // up/down buttons on an <input type="number">. Anonymous divs do not seem to 4598 // expose properties, triggering a "Permission denied error" if any of its 4599 // properties are accessed. The only seemingly possible way to avoid erroring 4600 // is to access a property that typically works for non-anonymous divs and 4601 // catch any error that may otherwise arise. See 4602 // https://bugzilla.mozilla.org/show_bug.cgi?id=208427 4603 4604 try { 4605 /* eslint-disable no-unused-expressions */ 4606 anchorNode.nodeType; 4607 focusNode.nodeType; 4608 /* eslint-enable no-unused-expressions */ 4609 } catch (e) { 4610 return null; 4611 } 4612 4613 return getModernOffsetsFromPoints(outerNode, anchorNode, anchorOffset, focusNode, focusOffset); 4614 } 4615 4616 /** 4617 * Returns {start, end} where `start` is the character/codepoint index of 4618 * (anchorNode, anchorOffset) within the textContent of `outerNode`, and 4619 * `end` is the index of (focusNode, focusOffset). 4620 * 4621 * Returns null if you pass in garbage input but we should probably just crash. 4622 * 4623 * Exported only for testing. 4624 */ 4625 function getModernOffsetsFromPoints(outerNode, anchorNode, anchorOffset, focusNode, focusOffset) { 4626 var length = 0; 4627 var start = -1; 4628 var end = -1; 4629 var indexWithinAnchor = 0; 4630 var indexWithinFocus = 0; 4631 var node = outerNode; 4632 var parentNode = null; 4633 4634 outer: while (true) { 4635 var next = null; 4636 4637 while (true) { 4638 if (node === anchorNode && (anchorOffset === 0 || node.nodeType === TEXT_NODE)) { 4639 start = length + anchorOffset; 4640 } 4641 if (node === focusNode && (focusOffset === 0 || node.nodeType === TEXT_NODE)) { 4642 end = length + focusOffset; 4643 } 4644 4645 if (node.nodeType === TEXT_NODE) { 4646 length += node.nodeValue.length; 4647 } 4648 4649 if ((next = node.firstChild) === null) { 4650 break; 4651 } 4652 // Moving from `node` to its first child `next`. 4653 parentNode = node; 4654 node = next; 4655 } 4656 4657 while (true) { 4658 if (node === outerNode) { 4659 // If `outerNode` has children, this is always the second time visiting 4660 // it. If it has no children, this is still the first loop, and the only 4661 // valid selection is anchorNode and focusNode both equal to this node 4662 // and both offsets 0, in which case we will have handled above. 4663 break outer; 4664 } 4665 if (parentNode === anchorNode && ++indexWithinAnchor === anchorOffset) { 4666 start = length; 4667 } 4668 if (parentNode === focusNode && ++indexWithinFocus === focusOffset) { 4669 end = length; 4670 } 4671 if ((next = node.nextSibling) !== null) { 4672 break; 4673 } 4674 node = parentNode; 4675 parentNode = node.parentNode; 4676 } 4677 4678 // Moving from `node` to its next sibling `next`. 4679 node = next; 4680 } 4681 4682 if (start === -1 || end === -1) { 4683 // This should never happen. (Would happen if the anchor/focus nodes aren't 4684 // actually inside the passed-in node.) 4685 return null; 4686 } 4687 4688 return { 4689 start: start, 4690 end: end 4691 }; 4692 } 4693 4694 /** 4695 * In modern non-IE browsers, we can support both forward and backward 4696 * selections. 4697 * 4698 * Note: IE10+ supports the Selection object, but it does not support 4699 * the `extend` method, which means that even in modern IE, it's not possible 4700 * to programmatically create a backward selection. Thus, for all IE 4701 * versions, we use the old IE API to create our selections. 4702 * 4703 * @param {DOMElement|DOMTextNode} node 4704 * @param {object} offsets 4705 */ 4706 function setOffsets(node, offsets) { 4707 var doc = node.ownerDocument || document; 4708 var win = doc && doc.defaultView || window; 4709 4710 // Edge fails with "Object expected" in some scenarios. 4711 // (For instance: TinyMCE editor used in a list component that supports pasting to add more, 4712 // fails when pasting 100+ items) 4713 if (!win.getSelection) { 4714 return; 4715 } 4716 4717 var selection = win.getSelection(); 4718 var length = node.textContent.length; 4719 var start = Math.min(offsets.start, length); 4720 var end = offsets.end === undefined ? start : Math.min(offsets.end, length); 4721 4722 // IE 11 uses modern selection, but doesn't support the extend method. 4723 // Flip backward selections, so we can set with a single range. 4724 if (!selection.extend && start > end) { 4725 var temp = end; 4726 end = start; 4727 start = temp; 4728 } 4729 4730 var startMarker = getNodeForCharacterOffset(node, start); 4731 var endMarker = getNodeForCharacterOffset(node, end); 4732 4733 if (startMarker && endMarker) { 4734 if (selection.rangeCount === 1 && selection.anchorNode === startMarker.node && selection.anchorOffset === startMarker.offset && selection.focusNode === endMarker.node && selection.focusOffset === endMarker.offset) { 4735 return; 4736 } 4737 var range = doc.createRange(); 4738 range.setStart(startMarker.node, startMarker.offset); 4739 selection.removeAllRanges(); 4740 4741 if (start > end) { 4742 selection.addRange(range); 4743 selection.extend(endMarker.node, endMarker.offset); 4744 } else { 4745 range.setEnd(endMarker.node, endMarker.offset); 4746 selection.addRange(range); 4747 } 4748 } 4749 } 4750 4751 function isTextNode(node) { 4752 return node && node.nodeType === TEXT_NODE; 4753 } 4754 4755 function containsNode(outerNode, innerNode) { 4756 if (!outerNode || !innerNode) { 4757 return false; 4758 } else if (outerNode === innerNode) { 4759 return true; 4760 } else if (isTextNode(outerNode)) { 4761 return false; 4762 } else if (isTextNode(innerNode)) { 4763 return containsNode(outerNode, innerNode.parentNode); 4764 } else if ('contains' in outerNode) { 4765 return outerNode.contains(innerNode); 4766 } else if (outerNode.compareDocumentPosition) { 4767 return !!(outerNode.compareDocumentPosition(innerNode) & 16); 4768 } else { 4769 return false; 4770 } 4771 } 4772 4773 function isInDocument(node) { 4774 return node && node.ownerDocument && containsNode(node.ownerDocument.documentElement, node); 4775 } 4776 4777 function isSameOriginFrame(iframe) { 4778 try { 4779 // Accessing the contentDocument of a HTMLIframeElement can cause the browser 4780 // to throw, e.g. if it has a cross-origin src attribute. 4781 // Safari will show an error in the console when the access results in "Blocked a frame with origin". e.g: 4782 // iframe.contentDocument.defaultView; 4783 // A safety way is to access one of the cross origin properties: Window or Location 4784 // Which might result in "SecurityError" DOM Exception and it is compatible to Safari. 4785 // https://html.spec.whatwg.org/multipage/browsers.html#integration-with-idl 4786 4787 return typeof iframe.contentWindow.location.href === 'string'; 4788 } catch (err) { 4789 return false; 4790 } 4791 } 4792 4793 function getActiveElementDeep() { 4794 var win = window; 4795 var element = getActiveElement(); 4796 while (element instanceof win.HTMLIFrameElement) { 4797 if (isSameOriginFrame(element)) { 4798 win = element.contentWindow; 4799 } else { 4800 return element; 4801 } 4802 element = getActiveElement(win.document); 4803 } 4804 return element; 4805 } 4806 4807 /** 4808 * @ReactInputSelection: React input selection module. Based on Selection.js, 4809 * but modified to be suitable for react and has a couple of bug fixes (doesn't 4810 * assume buttons have range selections allowed). 4811 * Input selection module for React. 4812 */ 4813 4814 /** 4815 * @hasSelectionCapabilities: we get the element types that support selection 4816 * from https://html.spec.whatwg.org/#do-not-apply, looking at `selectionStart` 4817 * and `selectionEnd` rows. 4818 */ 4819 function hasSelectionCapabilities(elem) { 4820 var nodeName = elem && elem.nodeName && elem.nodeName.toLowerCase(); 4821 return nodeName && (nodeName === 'input' && (elem.type === 'text' || elem.type === 'search' || elem.type === 'tel' || elem.type === 'url' || elem.type === 'password') || nodeName === 'textarea' || elem.contentEditable === 'true'); 4822 } 4823 4824 function getSelectionInformation() { 4825 var focusedElem = getActiveElementDeep(); 4826 return { 4827 focusedElem: focusedElem, 4828 selectionRange: hasSelectionCapabilities(focusedElem) ? getSelection$1(focusedElem) : null 4829 }; 4830 } 4831 4832 /** 4833 * @restoreSelection: If any selection information was potentially lost, 4834 * restore it. This is useful when performing operations that could remove dom 4835 * nodes and place them back in, resulting in focus being lost. 4836 */ 4837 function restoreSelection(priorSelectionInformation) { 4838 var curFocusedElem = getActiveElementDeep(); 4839 var priorFocusedElem = priorSelectionInformation.focusedElem; 4840 var priorSelectionRange = priorSelectionInformation.selectionRange; 4841 if (curFocusedElem !== priorFocusedElem && isInDocument(priorFocusedElem)) { 4842 if (priorSelectionRange !== null && hasSelectionCapabilities(priorFocusedElem)) { 4843 setSelection(priorFocusedElem, priorSelectionRange); 4844 } 4845 4846 // Focusing a node can change the scroll position, which is undesirable 4847 var ancestors = []; 4848 var ancestor = priorFocusedElem; 4849 while (ancestor = ancestor.parentNode) { 4850 if (ancestor.nodeType === ELEMENT_NODE) { 4851 ancestors.push({ 4852 element: ancestor, 4853 left: ancestor.scrollLeft, 4854 top: ancestor.scrollTop 4855 }); 4856 } 4857 } 4858 4859 if (typeof priorFocusedElem.focus === 'function') { 4860 priorFocusedElem.focus(); 4861 } 4862 4863 for (var i = 0; i < ancestors.length; i++) { 4864 var info = ancestors[i]; 4865 info.element.scrollLeft = info.left; 4866 info.element.scrollTop = info.top; 4867 } 4868 } 4869 } 4870 4871 /** 4872 * @getSelection: Gets the selection bounds of a focused textarea, input or 4873 * contentEditable node. 4874 * -@input: Look up selection bounds of this input 4875 * -@return {start: selectionStart, end: selectionEnd} 4876 */ 4877 function getSelection$1(input) { 4878 var selection = void 0; 4879 4880 if ('selectionStart' in input) { 4881 // Modern browser with input or textarea. 4882 selection = { 4883 start: input.selectionStart, 4884 end: input.selectionEnd 4885 }; 4886 } else { 4887 // Content editable or old IE textarea. 4888 selection = getOffsets(input); 4889 } 4890 4891 return selection || { start: 0, end: 0 }; 4892 } 4893 4894 /** 4895 * @setSelection: Sets the selection bounds of a textarea or input and focuses 4896 * the input. 4897 * -@input Set selection bounds of this input or textarea 4898 * -@offsets Object of same form that is returned from get* 4899 */ 4900 function setSelection(input, offsets) { 4901 var start = offsets.start, 4902 end = offsets.end; 4903 4904 if (end === undefined) { 4905 end = start; 4906 } 4907 4908 if ('selectionStart' in input) { 4909 input.selectionStart = start; 4910 input.selectionEnd = Math.min(end, input.value.length); 4911 } else { 4912 setOffsets(input, offsets); 4913 } 4914 } 4915 4916 var skipSelectionChangeEvent = canUseDOM && 'documentMode' in document && document.documentMode <= 11; 4917 4918 var eventTypes$3 = { 4919 select: { 4920 phasedRegistrationNames: { 4921 bubbled: 'onSelect', 4922 captured: 'onSelectCapture' 4923 }, 4924 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] 4925 } 4926 }; 4927 4928 var activeElement$1 = null; 4929 var activeElementInst$1 = null; 4930 var lastSelection = null; 4931 var mouseDown = false; 4932 4933 /** 4934 * Get an object which is a unique representation of the current selection. 4935 * 4936 * The return value will not be consistent across nodes or browsers, but 4937 * two identical selections on the same node will return identical objects. 4938 * 4939 * @param {DOMElement} node 4940 * @return {object} 4941 */ 4942 function getSelection(node) { 4943 if ('selectionStart' in node && hasSelectionCapabilities(node)) { 4944 return { 4945 start: node.selectionStart, 4946 end: node.selectionEnd 4947 }; 4948 } else { 4949 var win = node.ownerDocument && node.ownerDocument.defaultView || window; 4950 var selection = win.getSelection(); 4951 return { 4952 anchorNode: selection.anchorNode, 4953 anchorOffset: selection.anchorOffset, 4954 focusNode: selection.focusNode, 4955 focusOffset: selection.focusOffset 4956 }; 4957 } 4958 } 4959 4960 /** 4961 * Get document associated with the event target. 4962 * 4963 * @param {object} nativeEventTarget 4964 * @return {Document} 4965 */ 4966 function getEventTargetDocument(eventTarget) { 4967 return eventTarget.window === eventTarget ? eventTarget.document : eventTarget.nodeType === DOCUMENT_NODE ? eventTarget : eventTarget.ownerDocument; 4968 } 4969 4970 /** 4971 * Poll selection to see whether it's changed. 4972 * 4973 * @param {object} nativeEvent 4974 * @param {object} nativeEventTarget 4975 * @return {?SyntheticEvent} 4976 */ 4977 function constructSelectEvent(nativeEvent, nativeEventTarget) { 4978 // Ensure we have the right element, and that the user is not dragging a 4979 // selection (this matches native `select` event behavior). In HTML5, select 4980 // fires only on input and textarea thus if there's no focused element we 4981 // won't dispatch. 4982 var doc = getEventTargetDocument(nativeEventTarget); 4983 4984 if (mouseDown || activeElement$1 == null || activeElement$1 !== getActiveElement(doc)) { 4985 return null; 4986 } 4987 4988 // Only fire when selection has actually changed. 4989 var currentSelection = getSelection(activeElement$1); 4990 if (!lastSelection || !shallowEqual(lastSelection, currentSelection)) { 4991 lastSelection = currentSelection; 4992 4993 var syntheticEvent = SyntheticEvent.getPooled(eventTypes$3.select, activeElementInst$1, nativeEvent, nativeEventTarget); 4994 4995 syntheticEvent.type = 'select'; 4996 syntheticEvent.target = activeElement$1; 4997 4998 accumulateTwoPhaseDispatches(syntheticEvent); 4999 5000 return syntheticEvent; 5001 } 5002 5003 return null; 5004 } 5005 5006 /** 5007 * This plugin creates an `onSelect` event that normalizes select events 5008 * across form elements. 5009 * 5010 * Supported elements are: 5011 * - input (see `isTextInputElement`) 5012 * - textarea 5013 * - contentEditable 5014 * 5015 * This differs from native browser implementations in the following ways: 5016 * - Fires on contentEditable fields as well as inputs. 5017 * - Fires for collapsed selection. 5018 * - Fires after user input. 5019 */ 5020 var SelectEventPlugin = { 5021 eventTypes: eventTypes$3, 5022 5023 extractEvents: function (topLevelType, targetInst, nativeEvent, nativeEventTarget) { 5024 var doc = getEventTargetDocument(nativeEventTarget); 5025 // Track whether all listeners exists for this plugin. If none exist, we do 5026 // not extract events. See #3639. 5027 if (!doc || !isListeningToAllDependencies('onSelect', doc)) { 5028 return null; 5029 } 5030 5031 var targetNode = targetInst ? getNodeFromInstance$1(targetInst) : window; 5032 5033 switch (topLevelType) { 5034 // Track the input node that has focus. 5035 case TOP_FOCUS: 5036 if (isTextInputElement(targetNode) || targetNode.contentEditable === 'true') { 5037 activeElement$1 = targetNode; 5038 activeElementInst$1 = targetInst; 5039 lastSelection = null; 5040 } 5041 break; 5042 case TOP_BLUR: 5043 activeElement$1 = null; 5044 activeElementInst$1 = null; 5045 lastSelection = null; 5046 break; 5047 // Don't fire the event while the user is dragging. This matches the 5048 // semantics of the native select event. 5049 case TOP_MOUSE_DOWN: 5050 mouseDown = true; 5051 break; 5052 case TOP_CONTEXT_MENU: 5053 case TOP_MOUSE_UP: 5054 case TOP_DRAG_END: 5055 mouseDown = false; 5056 return constructSelectEvent(nativeEvent, nativeEventTarget); 5057 // Chrome and IE fire non-standard event when selection is changed (and 5058 // sometimes when it hasn't). IE's event fires out of order with respect 5059 // to key and input events on deletion, so we discard it. 5060 // 5061 // Firefox doesn't support selectionchange, so check selection status 5062 // after each key entry. The selection changes after keydown and before 5063 // keyup, but we check on keydown as well in the case of holding down a 5064 // key, when multiple keydown events are fired but only one keyup is. 5065 // This is also our approach for IE handling, for the reason above. 5066 case TOP_SELECTION_CHANGE: 5067 if (skipSelectionChangeEvent) { 5068 break; 5069 } 5070 // falls through 5071 case TOP_KEY_DOWN: 5072 case TOP_KEY_UP: 5073 return constructSelectEvent(nativeEvent, nativeEventTarget); 5074 } 5075 5076 return null; 5077 } 5078 }; 5079 5080 /** 5081 * Inject modules for resolving DOM hierarchy and plugin ordering. 5082 */ 5083 injection.injectEventPluginOrder(DOMEventPluginOrder); 5084 setComponentTree(getFiberCurrentPropsFromNode$1, getInstanceFromNode$1, getNodeFromInstance$1); 5085 5086 /** 5087 * Some important event plugins included by default (without having to require 5088 * them). 5089 */ 5090 injection.injectEventPluginsByName({ 5091 SimpleEventPlugin: SimpleEventPlugin, 5092 EnterLeaveEventPlugin: EnterLeaveEventPlugin, 5093 ChangeEventPlugin: ChangeEventPlugin, 5094 SelectEventPlugin: SelectEventPlugin, 5095 BeforeInputEventPlugin: BeforeInputEventPlugin 5096 }); 5097 5098 function flattenChildren(children) { 5099 var content = ''; 5100 5101 // Flatten children. We'll warn if they are invalid 5102 // during validateProps() which runs for hydration too. 5103 // Note that this would throw on non-element objects. 5104 // Elements are stringified (which is normally irrelevant 5105 // but matters for <fbt>). 5106 React.Children.forEach(children, function (child) { 5107 if (child == null) { 5108 return; 5109 } 5110 content += child; 5111 // Note: we don't warn about invalid children here. 5112 // Instead, this is done separately below so that 5113 // it happens during the hydration codepath too. 5114 }); 5115 5116 return content; 5117 } 5118 5119 /** 5120 * Implements an <option> host component that warns when `selected` is set. 5121 */ 5122 5123 5124 5125 function postMountWrapper$1(element, props) { 5126 // value="" should make a value attribute (#6219) 5127 if (props.value != null) { 5128 element.setAttribute('value', toString(getToStringValue(props.value))); 5129 } 5130 } 5131 5132 function getHostProps$1(element, props) { 5133 var hostProps = _assign({ children: undefined }, props); 5134 var content = flattenChildren(props.children); 5135 5136 if (content) { 5137 hostProps.children = content; 5138 } 5139 5140 return hostProps; 5141 } 5142 5143 // TODO: direct imports like some-package/src/* are bad. Fix me. 5144 function updateOptions(node, multiple, propValue, setDefaultSelected) { 5145 var options = node.options; 5146 5147 if (multiple) { 5148 var selectedValues = propValue; 5149 var selectedValue = {}; 5150 for (var i = 0; i < selectedValues.length; i++) { 5151 // Prefix to avoid chaos with special keys. 5152 selectedValue['$' + selectedValues[i]] = true; 5153 } 5154 for (var _i = 0; _i < options.length; _i++) { 5155 var selected = selectedValue.hasOwnProperty('$' + options[_i].value); 5156 if (options[_i].selected !== selected) { 5157 options[_i].selected = selected; 5158 } 5159 if (selected && setDefaultSelected) { 5160 options[_i].defaultSelected = true; 5161 } 5162 } 5163 } else { 5164 // Do not set `select.value` as exact behavior isn't consistent across all 5165 // browsers for all cases. 5166 var _selectedValue = toString(getToStringValue(propValue)); 5167 var defaultSelected = null; 5168 for (var _i2 = 0; _i2 < options.length; _i2++) { 5169 if (options[_i2].value === _selectedValue) { 5170 options[_i2].selected = true; 5171 if (setDefaultSelected) { 5172 options[_i2].defaultSelected = true; 5173 } 5174 return; 5175 } 5176 if (defaultSelected === null && !options[_i2].disabled) { 5177 defaultSelected = options[_i2]; 5178 } 5179 } 5180 if (defaultSelected !== null) { 5181 defaultSelected.selected = true; 5182 } 5183 } 5184 } 5185 5186 /** 5187 * Implements a <select> host component that allows optionally setting the 5188 * props `value` and `defaultValue`. If `multiple` is false, the prop must be a 5189 * stringable. If `multiple` is true, the prop must be an array of stringables. 5190 * 5191 * If `value` is not supplied (or null/undefined), user actions that change the 5192 * selected option will trigger updates to the rendered options. 5193 * 5194 * If it is supplied (and not null/undefined), the rendered options will not 5195 * update in response to user actions. Instead, the `value` prop must change in 5196 * order for the rendered options to update. 5197 * 5198 * If `defaultValue` is provided, any options with the supplied values will be 5199 * selected. 5200 */ 5201 5202 function getHostProps$2(element, props) { 5203 return _assign({}, props, { 5204 value: undefined 5205 }); 5206 } 5207 5208 function initWrapperState$1(element, props) { 5209 var node = element; 5210 node._wrapperState = { 5211 wasMultiple: !!props.multiple 5212 }; 5213 5214 5215 } 5216 5217 function postMountWrapper$2(element, props) { 5218 var node = element; 5219 node.multiple = !!props.multiple; 5220 var value = props.value; 5221 if (value != null) { 5222 updateOptions(node, !!props.multiple, value, false); 5223 } else if (props.defaultValue != null) { 5224 updateOptions(node, !!props.multiple, props.defaultValue, true); 5225 } 5226 } 5227 5228 function postUpdateWrapper(element, props) { 5229 var node = element; 5230 var wasMultiple = node._wrapperState.wasMultiple; 5231 node._wrapperState.wasMultiple = !!props.multiple; 5232 5233 var value = props.value; 5234 if (value != null) { 5235 updateOptions(node, !!props.multiple, value, false); 5236 } else if (wasMultiple !== !!props.multiple) { 5237 // For simplicity, reapply `defaultValue` if `multiple` is toggled. 5238 if (props.defaultValue != null) { 5239 updateOptions(node, !!props.multiple, props.defaultValue, true); 5240 } else { 5241 // Revert the select back to its default unselected state. 5242 updateOptions(node, !!props.multiple, props.multiple ? [] : '', false); 5243 } 5244 } 5245 } 5246 5247 function restoreControlledState$2(element, props) { 5248 var node = element; 5249 var value = props.value; 5250 5251 if (value != null) { 5252 updateOptions(node, !!props.multiple, value, false); 5253 } 5254 } 5255 5256 /** 5257 * Implements a <textarea> host component that allows setting `value`, and 5258 * `defaultValue`. This differs from the traditional DOM API because value is 5259 * usually set as PCDATA children. 5260 * 5261 * If `value` is not supplied (or null/undefined), user actions that affect the 5262 * value will trigger updates to the element. 5263 * 5264 * If `value` is supplied (and not null/undefined), the rendered element will 5265 * not trigger updates to the element. Instead, the `value` prop must change in 5266 * order for the rendered element to be updated. 5267 * 5268 * The rendered element will be initialized with an empty value, the prop 5269 * `defaultValue` if specified, or the children content (deprecated). 5270 */ 5271 5272 function getHostProps$3(element, props) { 5273 var node = element; 5274 !(props.dangerouslySetInnerHTML == null) ? reactProdInvariant('91') : void 0; 5275 5276 // Always set children to the same thing. In IE9, the selection range will 5277 // get reset if `textContent` is mutated. We could add a check in setTextContent 5278 // to only set the value if/when the value differs from the node value (which would 5279 // completely solve this IE9 bug), but Sebastian+Sophie seemed to like this 5280 // solution. The value can be a boolean or object so that's why it's forced 5281 // to be a string. 5282 var hostProps = _assign({}, props, { 5283 value: undefined, 5284 defaultValue: undefined, 5285 children: toString(node._wrapperState.initialValue) 5286 }); 5287 5288 return hostProps; 5289 } 5290 5291 function initWrapperState$2(element, props) { 5292 var node = element; 5293 var initialValue = props.value; 5294 5295 // Only bother fetching default value if we're going to use it 5296 if (initialValue == null) { 5297 var defaultValue = props.defaultValue; 5298 // TODO (yungsters): Remove support for children content in <textarea>. 5299 var children = props.children; 5300 if (children != null) { 5301 !(defaultValue == null) ? reactProdInvariant('92') : void 0; 5302 if (Array.isArray(children)) { 5303 !(children.length <= 1) ? reactProdInvariant('93') : void 0; 5304 children = children[0]; 5305 } 5306 5307 defaultValue = children; 5308 } 5309 if (defaultValue == null) { 5310 defaultValue = ''; 5311 } 5312 initialValue = defaultValue; 5313 } 5314 5315 node._wrapperState = { 5316 initialValue: getToStringValue(initialValue) 5317 }; 5318 } 5319 5320 function updateWrapper$1(element, props) { 5321 var node = element; 5322 var value = getToStringValue(props.value); 5323 var defaultValue = getToStringValue(props.defaultValue); 5324 if (value != null) { 5325 // Cast `value` to a string to ensure the value is set correctly. While 5326 // browsers typically do this as necessary, jsdom doesn't. 5327 var newValue = toString(value); 5328 // To avoid side effects (such as losing text selection), only set value if changed 5329 if (newValue !== node.value) { 5330 node.value = newValue; 5331 } 5332 if (props.defaultValue == null && node.defaultValue !== newValue) { 5333 node.defaultValue = newValue; 5334 } 5335 } 5336 if (defaultValue != null) { 5337 node.defaultValue = toString(defaultValue); 5338 } 5339 } 5340 5341 function postMountWrapper$3(element, props) { 5342 var node = element; 5343 // This is in postMount because we need access to the DOM node, which is not 5344 // available until after the component has mounted. 5345 var textContent = node.textContent; 5346 5347 // Only set node.value if textContent is equal to the expected 5348 // initial value. In IE10/IE11 there is a bug where the placeholder attribute 5349 // will populate textContent as well. 5350 // https://developer.microsoft.com/microsoft-edge/platform/issues/101525/ 5351 if (textContent === node._wrapperState.initialValue) { 5352 node.value = textContent; 5353 } 5354 } 5355 5356 function restoreControlledState$3(element, props) { 5357 // DOM component is still mounted; update 5358 updateWrapper$1(element, props); 5359 } 5360 5361 var HTML_NAMESPACE$1 = 'http://www.w3.org/1999/xhtml'; 5362 var MATH_NAMESPACE = 'http://www.w3.org/1998/Math/MathML'; 5363 var SVG_NAMESPACE = 'http://www.w3.org/2000/svg'; 5364 5365 var Namespaces = { 5366 html: HTML_NAMESPACE$1, 5367 mathml: MATH_NAMESPACE, 5368 svg: SVG_NAMESPACE 5369 }; 5370 5371 // Assumes there is no parent namespace. 5372 function getIntrinsicNamespace(type) { 5373 switch (type) { 5374 case 'svg': 5375 return SVG_NAMESPACE; 5376 case 'math': 5377 return MATH_NAMESPACE; 5378 default: 5379 return HTML_NAMESPACE$1; 5380 } 5381 } 5382 5383 function getChildNamespace(parentNamespace, type) { 5384 if (parentNamespace == null || parentNamespace === HTML_NAMESPACE$1) { 5385 // No (or default) parent namespace: potential entry point. 5386 return getIntrinsicNamespace(type); 5387 } 5388 if (parentNamespace === SVG_NAMESPACE && type === 'foreignObject') { 5389 // We're leaving SVG. 5390 return HTML_NAMESPACE$1; 5391 } 5392 // By default, pass namespace below. 5393 return parentNamespace; 5394 } 5395 5396 /* globals MSApp */ 5397 5398 /** 5399 * Create a function which has 'unsafe' privileges (required by windows8 apps) 5400 */ 5401 var createMicrosoftUnsafeLocalFunction = function (func) { 5402 if (typeof MSApp !== 'undefined' && MSApp.execUnsafeLocalFunction) { 5403 return function (arg0, arg1, arg2, arg3) { 5404 MSApp.execUnsafeLocalFunction(function () { 5405 return func(arg0, arg1, arg2, arg3); 5406 }); 5407 }; 5408 } else { 5409 return func; 5410 } 5411 }; 5412 5413 // SVG temp container for IE lacking innerHTML 5414 var reusableSVGContainer = void 0; 5415 5416 /** 5417 * Set the innerHTML property of a node 5418 * 5419 * @param {DOMElement} node 5420 * @param {string} html 5421 * @internal 5422 */ 5423 var setInnerHTML = createMicrosoftUnsafeLocalFunction(function (node, html) { 5424 // IE does not have innerHTML for SVG nodes, so instead we inject the 5425 // new markup in a temp node and then move the child nodes across into 5426 // the target node 5427 5428 if (node.namespaceURI === Namespaces.svg && !('innerHTML' in node)) { 5429 reusableSVGContainer = reusableSVGContainer || document.createElementNS('http://www.w3.org/1999/xhtml', 'div'); 5430 reusableSVGContainer.innerHTML = '<svg>' + html + '</svg>'; 5431 var svgNode = reusableSVGContainer.firstChild; 5432 while (node.firstChild) { 5433 node.removeChild(node.firstChild); 5434 } 5435 while (svgNode.firstChild) { 5436 node.appendChild(svgNode.firstChild); 5437 } 5438 } else { 5439 node.innerHTML = html; 5440 } 5441 }); 5442 5443 /** 5444 * Set the textContent property of a node. For text updates, it's faster 5445 * to set the `nodeValue` of the Text node directly instead of using 5446 * `.textContent` which will remove the existing node and create a new one. 5447 * 5448 * @param {DOMElement} node 5449 * @param {string} text 5450 * @internal 5451 */ 5452 var setTextContent = function (node, text) { 5453 if (text) { 5454 var firstChild = node.firstChild; 5455 5456 if (firstChild && firstChild === node.lastChild && firstChild.nodeType === TEXT_NODE) { 5457 firstChild.nodeValue = text; 5458 return; 5459 } 5460 } 5461 node.textContent = text; 5462 }; 5463 5464 // List derived from Gecko source code: 5465 // https://github.com/mozilla/gecko-dev/blob/4e638efc71/layout/style/test/property_database.js 5466 5467 /** 5468 * CSS properties which accept numbers but are not in units of "px". 5469 */ 5470 var isUnitlessNumber = { 5471 animationIterationCount: true, 5472 borderImageOutset: true, 5473 borderImageSlice: true, 5474 borderImageWidth: true, 5475 boxFlex: true, 5476 boxFlexGroup: true, 5477 boxOrdinalGroup: true, 5478 columnCount: true, 5479 columns: true, 5480 flex: true, 5481 flexGrow: true, 5482 flexPositive: true, 5483 flexShrink: true, 5484 flexNegative: true, 5485 flexOrder: true, 5486 gridArea: true, 5487 gridRow: true, 5488 gridRowEnd: true, 5489 gridRowSpan: true, 5490 gridRowStart: true, 5491 gridColumn: true, 5492 gridColumnEnd: true, 5493 gridColumnSpan: true, 5494 gridColumnStart: true, 5495 fontWeight: true, 5496 lineClamp: true, 5497 lineHeight: true, 5498 opacity: true, 5499 order: true, 5500 orphans: true, 5501 tabSize: true, 5502 widows: true, 5503 zIndex: true, 5504 zoom: true, 5505 5506 // SVG-related properties 5507 fillOpacity: true, 5508 floodOpacity: true, 5509 stopOpacity: true, 5510 strokeDasharray: true, 5511 strokeDashoffset: true, 5512 strokeMiterlimit: true, 5513 strokeOpacity: true, 5514 strokeWidth: true 5515 }; 5516 5517 /** 5518 * @param {string} prefix vendor-specific prefix, eg: Webkit 5519 * @param {string} key style name, eg: transitionDuration 5520 * @return {string} style name prefixed with `prefix`, properly camelCased, eg: 5521 * WebkitTransitionDuration 5522 */ 5523 function prefixKey(prefix, key) { 5524 return prefix + key.charAt(0).toUpperCase() + key.substring(1); 5525 } 5526 5527 /** 5528 * Support style names that may come passed in prefixed by adding permutations 5529 * of vendor prefixes. 5530 */ 5531 var prefixes = ['Webkit', 'ms', 'Moz', 'O']; 5532 5533 // Using Object.keys here, or else the vanilla for-in loop makes IE8 go into an 5534 // infinite loop, because it iterates over the newly added props too. 5535 Object.keys(isUnitlessNumber).forEach(function (prop) { 5536 prefixes.forEach(function (prefix) { 5537 isUnitlessNumber[prefixKey(prefix, prop)] = isUnitlessNumber[prop]; 5538 }); 5539 }); 5540 5541 /** 5542 * Convert a value into the proper css writable value. The style name `name` 5543 * should be logical (no hyphens), as specified 5544 * in `CSSProperty.isUnitlessNumber`. 5545 * 5546 * @param {string} name CSS property name such as `topMargin`. 5547 * @param {*} value CSS property value such as `10px`. 5548 * @return {string} Normalized style value with dimensions applied. 5549 */ 5550 function dangerousStyleValue(name, value, isCustomProperty) { 5551 // Note that we've removed escapeTextForBrowser() calls here since the 5552 // whole string will be escaped when the attribute is injected into 5553 // the markup. If you provide unsafe user data here they can inject 5554 // arbitrary CSS which may be problematic (I couldn't repro this): 5555 // https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet 5556 // http://www.thespanner.co.uk/2007/11/26/ultimate-xss-css-injection/ 5557 // This is not an XSS hole but instead a potential CSS injection issue 5558 // which has lead to a greater discussion about how we're going to 5559 // trust URLs moving forward. See #2115901 5560 5561 var isEmpty = value == null || typeof value === 'boolean' || value === ''; 5562 if (isEmpty) { 5563 return ''; 5564 } 5565 5566 if (!isCustomProperty && typeof value === 'number' && value !== 0 && !(isUnitlessNumber.hasOwnProperty(name) && isUnitlessNumber[name])) { 5567 return value + 'px'; // Presumes implicit 'px' suffix for unitless numbers 5568 } 5569 5570 return ('' + value).trim(); 5571 } 5572 5573 /** 5574 * Operations for dealing with CSS properties. 5575 */ 5576 5577 /** 5578 * This creates a string that is expected to be equivalent to the style 5579 * attribute generated by server-side rendering. It by-passes warnings and 5580 * security checks so it's not safe to use this value for anything other than 5581 * comparison. It is only used in DEV for SSR validation. 5582 */ 5583 5584 5585 /** 5586 * Sets the value for multiple styles on a node. If a value is specified as 5587 * '' (empty string), the corresponding style property will be unset. 5588 * 5589 * @param {DOMElement} node 5590 * @param {object} styles 5591 */ 5592 function setValueForStyles(node, styles) { 5593 var style = node.style; 5594 for (var styleName in styles) { 5595 if (!styles.hasOwnProperty(styleName)) { 5596 continue; 5597 } 5598 var isCustomProperty = styleName.indexOf('--') === 0; 5599 var styleValue = dangerousStyleValue(styleName, styles[styleName], isCustomProperty); 5600 if (styleName === 'float') { 5601 styleName = 'cssFloat'; 5602 } 5603 if (isCustomProperty) { 5604 style.setProperty(styleName, styleValue); 5605 } else { 5606 style[styleName] = styleValue; 5607 } 5608 } 5609 } 5610 5611 /** 5612 * When mixing shorthand and longhand property names, we warn during updates if 5613 * we expect an incorrect result to occur. In particular, we warn for: 5614 * 5615 * Updating a shorthand property (longhand gets overwritten): 5616 * {font: 'foo', fontVariant: 'bar'} -> {font: 'baz', fontVariant: 'bar'} 5617 * becomes .style.font = 'baz' 5618 * Removing a shorthand property (longhand gets lost too): 5619 * {font: 'foo', fontVariant: 'bar'} -> {fontVariant: 'bar'} 5620 * becomes .style.font = '' 5621 * Removing a longhand property (should revert to shorthand; doesn't): 5622 * {font: 'foo', fontVariant: 'bar'} -> {font: 'foo'} 5623 * becomes .style.fontVariant = '' 5624 */ 5625 5626 // For HTML, certain tags should omit their close tag. We keep a whitelist for 5627 // those special-case tags. 5628 5629 var omittedCloseTags = { 5630 area: true, 5631 base: true, 5632 br: true, 5633 col: true, 5634 embed: true, 5635 hr: true, 5636 img: true, 5637 input: true, 5638 keygen: true, 5639 link: true, 5640 meta: true, 5641 param: true, 5642 source: true, 5643 track: true, 5644 wbr: true 5645 // NOTE: menuitem's close tag should be omitted, but that causes problems. 5646 }; 5647 5648 // For HTML, certain tags cannot have children. This has the same purpose as 5649 // `omittedCloseTags` except that `menuitem` should still have its closing tag. 5650 5651 var voidElementTags = _assign({ 5652 menuitem: true 5653 }, omittedCloseTags); 5654 5655 // TODO: We can remove this if we add invariantWithStack() 5656 // or add stack by default to invariants where possible. 5657 var HTML$1 = '__html'; 5658 5659 function assertValidProps(tag, props) { 5660 if (!props) { 5661 return; 5662 } 5663 // Note the use of `==` which checks for null or undefined. 5664 if (voidElementTags[tag]) { 5665 !(props.children == null && props.dangerouslySetInnerHTML == null) ? reactProdInvariant('137', tag, '') : void 0; 5666 } 5667 if (props.dangerouslySetInnerHTML != null) { 5668 !(props.children == null) ? reactProdInvariant('60') : void 0; 5669 !(typeof props.dangerouslySetInnerHTML === 'object' && HTML$1 in props.dangerouslySetInnerHTML) ? reactProdInvariant('61') : void 0; 5670 } 5671 !(props.style == null || typeof props.style === 'object') ? reactProdInvariant('62', '') : void 0; 5672 } 5673 5674 function isCustomComponent(tagName, props) { 5675 if (tagName.indexOf('-') === -1) { 5676 return typeof props.is === 'string'; 5677 } 5678 switch (tagName) { 5679 // These are reserved SVG and MathML elements. 5680 // We don't mind this whitelist too much because we expect it to never grow. 5681 // The alternative is to track the namespace in a few places which is convoluted. 5682 // https://w3c.github.io/webcomponents/spec/custom/#custom-elements-core-concepts 5683 case 'annotation-xml': 5684 case 'color-profile': 5685 case 'font-face': 5686 case 'font-face-src': 5687 case 'font-face-uri': 5688 case 'font-face-format': 5689 case 'font-face-name': 5690 case 'missing-glyph': 5691 return false; 5692 default: 5693 return true; 5694 } 5695 } 5696 5697 // When adding attributes to the HTML or SVG whitelist, be sure to 5698 // also add them to this module to ensure casing and incorrect name 5699 // warnings. 5700 5701 // TODO: direct imports like some-package/src/* are bad. Fix me. 5702 var DANGEROUSLY_SET_INNER_HTML = 'dangerouslySetInnerHTML'; 5703 var SUPPRESS_CONTENT_EDITABLE_WARNING = 'suppressContentEditableWarning'; 5704 var SUPPRESS_HYDRATION_WARNING$1 = 'suppressHydrationWarning'; 5705 var AUTOFOCUS = 'autoFocus'; 5706 var CHILDREN = 'children'; 5707 var STYLE$1 = 'style'; 5708 var HTML = '__html'; 5709 5710 var HTML_NAMESPACE = Namespaces.html; 5711 5712 5713 function ensureListeningTo(rootContainerElement, registrationName) { 5714 var isDocumentOrFragment = rootContainerElement.nodeType === DOCUMENT_NODE || rootContainerElement.nodeType === DOCUMENT_FRAGMENT_NODE; 5715 var doc = isDocumentOrFragment ? rootContainerElement : rootContainerElement.ownerDocument; 5716 listenTo(registrationName, doc); 5717 } 5718 5719 function getOwnerDocumentFromRootContainer(rootContainerElement) { 5720 return rootContainerElement.nodeType === DOCUMENT_NODE ? rootContainerElement : rootContainerElement.ownerDocument; 5721 } 5722 5723 function noop() {} 5724 5725 function trapClickOnNonInteractiveElement(node) { 5726 // Mobile Safari does not fire properly bubble click events on 5727 // non-interactive elements, which means delegated click listeners do not 5728 // fire. The workaround for this bug involves attaching an empty click 5729 // listener on the target node. 5730 // http://www.quirksmode.org/blog/archives/2010/09/click_event_del.html 5731 // Just set it using the onclick property so that we don't have to manage any 5732 // bookkeeping for it. Not sure if we need to clear it when the listener is 5733 // removed. 5734 // TODO: Only do this for the relevant Safaris maybe? 5735 node.onclick = noop; 5736 } 5737 5738 function setInitialDOMProperties(tag, domElement, rootContainerElement, nextProps, isCustomComponentTag) { 5739 for (var propKey in nextProps) { 5740 if (!nextProps.hasOwnProperty(propKey)) { 5741 continue; 5742 } 5743 var nextProp = nextProps[propKey]; 5744 if (propKey === STYLE$1) { 5745 setValueForStyles(domElement, nextProp); 5746 } else if (propKey === DANGEROUSLY_SET_INNER_HTML) { 5747 var nextHtml = nextProp ? nextProp[HTML] : undefined; 5748 if (nextHtml != null) { 5749 setInnerHTML(domElement, nextHtml); 5750 } 5751 } else if (propKey === CHILDREN) { 5752 if (typeof nextProp === 'string') { 5753 // Avoid setting initial textContent when the text is empty. In IE11 setting 5754 // textContent on a <textarea> will cause the placeholder to not 5755 // show within the <textarea> until it has been focused and blurred again. 5756 // https://github.com/facebook/react/issues/6731#issuecomment-254874553 5757 var canSetTextContent = tag !== 'textarea' || nextProp !== ''; 5758 if (canSetTextContent) { 5759 setTextContent(domElement, nextProp); 5760 } 5761 } else if (typeof nextProp === 'number') { 5762 setTextContent(domElement, '' + nextProp); 5763 } 5764 } else if (propKey === SUPPRESS_CONTENT_EDITABLE_WARNING || propKey === SUPPRESS_HYDRATION_WARNING$1) { 5765 // Noop 5766 } else if (propKey === AUTOFOCUS) { 5767 // We polyfill it separately on the client during commit. 5768 // We could have excluded it in the property list instead of 5769 // adding a special case here, but then it wouldn't be emitted 5770 // on server rendering (but we *do* want to emit it in SSR). 5771 } else if (registrationNameModules.hasOwnProperty(propKey)) { 5772 if (nextProp != null) { 5773 ensureListeningTo(rootContainerElement, propKey); 5774 } 5775 } else if (nextProp != null) { 5776 setValueForProperty(domElement, propKey, nextProp, isCustomComponentTag); 5777 } 5778 } 5779 } 5780 5781 function updateDOMProperties(domElement, updatePayload, wasCustomComponentTag, isCustomComponentTag) { 5782 // TODO: Handle wasCustomComponentTag 5783 for (var i = 0; i < updatePayload.length; i += 2) { 5784 var propKey = updatePayload[i]; 5785 var propValue = updatePayload[i + 1]; 5786 if (propKey === STYLE$1) { 5787 setValueForStyles(domElement, propValue); 5788 } else if (propKey === DANGEROUSLY_SET_INNER_HTML) { 5789 setInnerHTML(domElement, propValue); 5790 } else if (propKey === CHILDREN) { 5791 setTextContent(domElement, propValue); 5792 } else { 5793 setValueForProperty(domElement, propKey, propValue, isCustomComponentTag); 5794 } 5795 } 5796 } 5797 5798 function createElement(type, props, rootContainerElement, parentNamespace) { 5799 var ownerDocument = getOwnerDocumentFromRootContainer(rootContainerElement); 5800 var domElement = void 0; 5801 var namespaceURI = parentNamespace; 5802 if (namespaceURI === HTML_NAMESPACE) { 5803 namespaceURI = getIntrinsicNamespace(type); 5804 } 5805 if (namespaceURI === HTML_NAMESPACE) { 5806 if (type === 'script') { 5807 // Create the script via .innerHTML so its "parser-inserted" flag is 5808 // set to true and it does not execute 5809 var div = ownerDocument.createElementNS('http://www.w3.org/1999/xhtml', 'div'); 5810 div.innerHTML = '<script><' + '/script>'; // eslint-disable-line 5811 // This is guaranteed to yield a script element. 5812 var firstChild = div.firstChild; 5813 domElement = div.removeChild(firstChild); 5814 } else if (typeof props.is === 'string') { 5815 // $FlowIssue `createElement` should be updated for Web Components 5816 domElement = ownerDocument.createElementNS('http://www.w3.org/1999/xhtml', type, { is: props.is }); 5817 } else { 5818 // Separate else branch instead of using `props.is || undefined` above because of a Firefox bug. 5819 // See discussion in https://github.com/facebook/react/pull/6896 5820 // and discussion in https://bugzilla.mozilla.org/show_bug.cgi?id=1276240 5821 domElement = ownerDocument.createElementNS('http://www.w3.org/1999/xhtml', type); 5822 // Normally attributes are assigned in `setInitialDOMProperties`, however the `multiple` and `size` 5823 // attributes on `select`s needs to be added before `option`s are inserted. 5824 // This prevents: 5825 // - a bug where the `select` does not scroll to the correct option because singular 5826 // `select` elements automatically pick the first item #13222 5827 // - a bug where the `select` set the first item as selected despite the `size` attribute #14239 5828 // See https://github.com/facebook/react/issues/13222 5829 // and https://github.com/facebook/react/issues/14239 5830 if (type === 'select') { 5831 var node = domElement; 5832 if (props.multiple) { 5833 node.multiple = true; 5834 } else if (props.size) { 5835 // Setting a size greater than 1 causes a select to behave like `multiple=true`, where 5836 // it is possible that no option is selected. 5837 // 5838 // This is only necessary when a select in "single selection mode". 5839 node.size = props.size; 5840 } 5841 } 5842 } 5843 } else { 5844 domElement = ownerDocument.createElementNS(namespaceURI, type); 5845 } 5846 5847 return domElement; 5848 } 5849 5850 function createTextNode(text, rootContainerElement) { 5851 return getOwnerDocumentFromRootContainer(rootContainerElement).createTextNode(text); 5852 } 5853 5854 function setInitialProperties(domElement, tag, rawProps, rootContainerElement) { 5855 var isCustomComponentTag = isCustomComponent(tag, rawProps); 5856 var props = void 0; 5857 switch (tag) { 5858 case 'iframe': 5859 case 'object': 5860 trapBubbledEvent(TOP_LOAD, domElement); 5861 props = rawProps; 5862 break; 5863 case 'video': 5864 case 'audio': 5865 // Create listener for each media event 5866 for (var i = 0; i < mediaEventTypes.length; i++) { 5867 trapBubbledEvent(mediaEventTypes[i], domElement); 5868 } 5869 props = rawProps; 5870 break; 5871 case 'source': 5872 trapBubbledEvent(TOP_ERROR, domElement); 5873 props = rawProps; 5874 break; 5875 case 'img': 5876 case 'image': 5877 case 'link': 5878 trapBubbledEvent(TOP_ERROR, domElement); 5879 trapBubbledEvent(TOP_LOAD, domElement); 5880 props = rawProps; 5881 break; 5882 case 'form': 5883 trapBubbledEvent(TOP_RESET, domElement); 5884 trapBubbledEvent(TOP_SUBMIT, domElement); 5885 props = rawProps; 5886 break; 5887 case 'details': 5888 trapBubbledEvent(TOP_TOGGLE, domElement); 5889 props = rawProps; 5890 break; 5891 case 'input': 5892 initWrapperState(domElement, rawProps); 5893 props = getHostProps(domElement, rawProps); 5894 trapBubbledEvent(TOP_INVALID, domElement); 5895 // For controlled components we always need to ensure we're listening 5896 // to onChange. Even if there is no listener. 5897 ensureListeningTo(rootContainerElement, 'onChange'); 5898 break; 5899 case 'option': 5900 5901 props = getHostProps$1(domElement, rawProps); 5902 break; 5903 case 'select': 5904 initWrapperState$1(domElement, rawProps); 5905 props = getHostProps$2(domElement, rawProps); 5906 trapBubbledEvent(TOP_INVALID, domElement); 5907 // For controlled components we always need to ensure we're listening 5908 // to onChange. Even if there is no listener. 5909 ensureListeningTo(rootContainerElement, 'onChange'); 5910 break; 5911 case 'textarea': 5912 initWrapperState$2(domElement, rawProps); 5913 props = getHostProps$3(domElement, rawProps); 5914 trapBubbledEvent(TOP_INVALID, domElement); 5915 // For controlled components we always need to ensure we're listening 5916 // to onChange. Even if there is no listener. 5917 ensureListeningTo(rootContainerElement, 'onChange'); 5918 break; 5919 default: 5920 props = rawProps; 5921 } 5922 5923 assertValidProps(tag, props); 5924 5925 setInitialDOMProperties(tag, domElement, rootContainerElement, props, isCustomComponentTag); 5926 5927 switch (tag) { 5928 case 'input': 5929 // TODO: Make sure we check if this is still unmounted or do any clean 5930 // up necessary since we never stop tracking anymore. 5931 track(domElement); 5932 postMountWrapper(domElement, rawProps, false); 5933 break; 5934 case 'textarea': 5935 // TODO: Make sure we check if this is still unmounted or do any clean 5936 // up necessary since we never stop tracking anymore. 5937 track(domElement); 5938 postMountWrapper$3(domElement, rawProps); 5939 break; 5940 case 'option': 5941 postMountWrapper$1(domElement, rawProps); 5942 break; 5943 case 'select': 5944 postMountWrapper$2(domElement, rawProps); 5945 break; 5946 default: 5947 if (typeof props.onClick === 'function') { 5948 // TODO: This cast may not be sound for SVG, MathML or custom elements. 5949 trapClickOnNonInteractiveElement(domElement); 5950 } 5951 break; 5952 } 5953 } 5954 5955 // Calculate the diff between the two objects. 5956 function diffProperties(domElement, tag, lastRawProps, nextRawProps, rootContainerElement) { 5957 var updatePayload = null; 5958 5959 var lastProps = void 0; 5960 var nextProps = void 0; 5961 switch (tag) { 5962 case 'input': 5963 lastProps = getHostProps(domElement, lastRawProps); 5964 nextProps = getHostProps(domElement, nextRawProps); 5965 updatePayload = []; 5966 break; 5967 case 'option': 5968 lastProps = getHostProps$1(domElement, lastRawProps); 5969 nextProps = getHostProps$1(domElement, nextRawProps); 5970 updatePayload = []; 5971 break; 5972 case 'select': 5973 lastProps = getHostProps$2(domElement, lastRawProps); 5974 nextProps = getHostProps$2(domElement, nextRawProps); 5975 updatePayload = []; 5976 break; 5977 case 'textarea': 5978 lastProps = getHostProps$3(domElement, lastRawProps); 5979 nextProps = getHostProps$3(domElement, nextRawProps); 5980 updatePayload = []; 5981 break; 5982 default: 5983 lastProps = lastRawProps; 5984 nextProps = nextRawProps; 5985 if (typeof lastProps.onClick !== 'function' && typeof nextProps.onClick === 'function') { 5986 // TODO: This cast may not be sound for SVG, MathML or custom elements. 5987 trapClickOnNonInteractiveElement(domElement); 5988 } 5989 break; 5990 } 5991 5992 assertValidProps(tag, nextProps); 5993 5994 var propKey = void 0; 5995 var styleName = void 0; 5996 var styleUpdates = null; 5997 for (propKey in lastProps) { 5998 if (nextProps.hasOwnProperty(propKey) || !lastProps.hasOwnProperty(propKey) || lastProps[propKey] == null) { 5999 continue; 6000 } 6001 if (propKey === STYLE$1) { 6002 var lastStyle = lastProps[propKey]; 6003 for (styleName in lastStyle) { 6004 if (lastStyle.hasOwnProperty(styleName)) { 6005 if (!styleUpdates) { 6006 styleUpdates = {}; 6007 } 6008 styleUpdates[styleName] = ''; 6009 } 6010 } 6011 } else if (propKey === DANGEROUSLY_SET_INNER_HTML || propKey === CHILDREN) { 6012 // Noop. This is handled by the clear text mechanism. 6013 } else if (propKey === SUPPRESS_CONTENT_EDITABLE_WARNING || propKey === SUPPRESS_HYDRATION_WARNING$1) { 6014 // Noop 6015 } else if (propKey === AUTOFOCUS) { 6016 // Noop. It doesn't work on updates anyway. 6017 } else if (registrationNameModules.hasOwnProperty(propKey)) { 6018 // This is a special case. If any listener updates we need to ensure 6019 // that the "current" fiber pointer gets updated so we need a commit 6020 // to update this element. 6021 if (!updatePayload) { 6022 updatePayload = []; 6023 } 6024 } else { 6025 // For all other deleted properties we add it to the queue. We use 6026 // the whitelist in the commit phase instead. 6027 (updatePayload = updatePayload || []).push(propKey, null); 6028 } 6029 } 6030 for (propKey in nextProps) { 6031 var nextProp = nextProps[propKey]; 6032 var lastProp = lastProps != null ? lastProps[propKey] : undefined; 6033 if (!nextProps.hasOwnProperty(propKey) || nextProp === lastProp || nextProp == null && lastProp == null) { 6034 continue; 6035 } 6036 if (propKey === STYLE$1) { 6037 if (lastProp) { 6038 // Unset styles on `lastProp` but not on `nextProp`. 6039 for (styleName in lastProp) { 6040 if (lastProp.hasOwnProperty(styleName) && (!nextProp || !nextProp.hasOwnProperty(styleName))) { 6041 if (!styleUpdates) { 6042 styleUpdates = {}; 6043 } 6044 styleUpdates[styleName] = ''; 6045 } 6046 } 6047 // Update styles that changed since `lastProp`. 6048 for (styleName in nextProp) { 6049 if (nextProp.hasOwnProperty(styleName) && lastProp[styleName] !== nextProp[styleName]) { 6050 if (!styleUpdates) { 6051 styleUpdates = {}; 6052 } 6053 styleUpdates[styleName] = nextProp[styleName]; 6054 } 6055 } 6056 } else { 6057 // Relies on `updateStylesByID` not mutating `styleUpdates`. 6058 if (!styleUpdates) { 6059 if (!updatePayload) { 6060 updatePayload = []; 6061 } 6062 updatePayload.push(propKey, styleUpdates); 6063 } 6064 styleUpdates = nextProp; 6065 } 6066 } else if (propKey === DANGEROUSLY_SET_INNER_HTML) { 6067 var nextHtml = nextProp ? nextProp[HTML] : undefined; 6068 var lastHtml = lastProp ? lastProp[HTML] : undefined; 6069 if (nextHtml != null) { 6070 if (lastHtml !== nextHtml) { 6071 (updatePayload = updatePayload || []).push(propKey, '' + nextHtml); 6072 } 6073 } else { 6074 // TODO: It might be too late to clear this if we have children 6075 // inserted already. 6076 } 6077 } else if (propKey === CHILDREN) { 6078 if (lastProp !== nextProp && (typeof nextProp === 'string' || typeof nextProp === 'number')) { 6079 (updatePayload = updatePayload || []).push(propKey, '' + nextProp); 6080 } 6081 } else if (propKey === SUPPRESS_CONTENT_EDITABLE_WARNING || propKey === SUPPRESS_HYDRATION_WARNING$1) { 6082 // Noop 6083 } else if (registrationNameModules.hasOwnProperty(propKey)) { 6084 if (nextProp != null) { 6085 // We eagerly listen to this even though we haven't committed yet. 6086 ensureListeningTo(rootContainerElement, propKey); 6087 } 6088 if (!updatePayload && lastProp !== nextProp) { 6089 // This is a special case. If any listener updates we need to ensure 6090 // that the "current" props pointer gets updated so we need a commit 6091 // to update this element. 6092 updatePayload = []; 6093 } 6094 } else { 6095 // For any other property we always add it to the queue and then we 6096 // filter it out using the whitelist during the commit. 6097 (updatePayload = updatePayload || []).push(propKey, nextProp); 6098 } 6099 } 6100 if (styleUpdates) { 6101 (updatePayload = updatePayload || []).push(STYLE$1, styleUpdates); 6102 } 6103 return updatePayload; 6104 } 6105 6106 // Apply the diff. 6107 function updateProperties(domElement, updatePayload, tag, lastRawProps, nextRawProps) { 6108 // Update checked *before* name. 6109 // In the middle of an update, it is possible to have multiple checked. 6110 // When a checked radio tries to change name, browser makes another radio's checked false. 6111 if (tag === 'input' && nextRawProps.type === 'radio' && nextRawProps.name != null) { 6112 updateChecked(domElement, nextRawProps); 6113 } 6114 6115 var wasCustomComponentTag = isCustomComponent(tag, lastRawProps); 6116 var isCustomComponentTag = isCustomComponent(tag, nextRawProps); 6117 // Apply the diff. 6118 updateDOMProperties(domElement, updatePayload, wasCustomComponentTag, isCustomComponentTag); 6119 6120 // TODO: Ensure that an update gets scheduled if any of the special props 6121 // changed. 6122 switch (tag) { 6123 case 'input': 6124 // Update the wrapper around inputs *after* updating props. This has to 6125 // happen after `updateDOMProperties`. Otherwise HTML5 input validations 6126 // raise warnings and prevent the new value from being assigned. 6127 updateWrapper(domElement, nextRawProps); 6128 break; 6129 case 'textarea': 6130 updateWrapper$1(domElement, nextRawProps); 6131 break; 6132 case 'select': 6133 // <select> value update needs to occur after <option> children 6134 // reconciliation 6135 postUpdateWrapper(domElement, nextRawProps); 6136 break; 6137 } 6138 } 6139 6140 function diffHydratedProperties(domElement, tag, rawProps, parentNamespace, rootContainerElement) { 6141 var isCustomComponentTag = void 0; 6142 switch (tag) { 6143 case 'iframe': 6144 case 'object': 6145 trapBubbledEvent(TOP_LOAD, domElement); 6146 break; 6147 case 'video': 6148 case 'audio': 6149 // Create listener for each media event 6150 for (var i = 0; i < mediaEventTypes.length; i++) { 6151 trapBubbledEvent(mediaEventTypes[i], domElement); 6152 } 6153 break; 6154 case 'source': 6155 trapBubbledEvent(TOP_ERROR, domElement); 6156 break; 6157 case 'img': 6158 case 'image': 6159 case 'link': 6160 trapBubbledEvent(TOP_ERROR, domElement); 6161 trapBubbledEvent(TOP_LOAD, domElement); 6162 break; 6163 case 'form': 6164 trapBubbledEvent(TOP_RESET, domElement); 6165 trapBubbledEvent(TOP_SUBMIT, domElement); 6166 break; 6167 case 'details': 6168 trapBubbledEvent(TOP_TOGGLE, domElement); 6169 break; 6170 case 'input': 6171 initWrapperState(domElement, rawProps); 6172 trapBubbledEvent(TOP_INVALID, domElement); 6173 // For controlled components we always need to ensure we're listening 6174 // to onChange. Even if there is no listener. 6175 ensureListeningTo(rootContainerElement, 'onChange'); 6176 break; 6177 case 'option': 6178 6179 break; 6180 case 'select': 6181 initWrapperState$1(domElement, rawProps); 6182 trapBubbledEvent(TOP_INVALID, domElement); 6183 // For controlled components we always need to ensure we're listening 6184 // to onChange. Even if there is no listener. 6185 ensureListeningTo(rootContainerElement, 'onChange'); 6186 break; 6187 case 'textarea': 6188 initWrapperState$2(domElement, rawProps); 6189 trapBubbledEvent(TOP_INVALID, domElement); 6190 // For controlled components we always need to ensure we're listening 6191 // to onChange. Even if there is no listener. 6192 ensureListeningTo(rootContainerElement, 'onChange'); 6193 break; 6194 } 6195 6196 assertValidProps(tag, rawProps); 6197 6198 var updatePayload = null; 6199 for (var propKey in rawProps) { 6200 if (!rawProps.hasOwnProperty(propKey)) { 6201 continue; 6202 } 6203 var nextProp = rawProps[propKey]; 6204 if (propKey === CHILDREN) { 6205 // For text content children we compare against textContent. This 6206 // might match additional HTML that is hidden when we read it using 6207 // textContent. E.g. "foo" will match "f<span>oo</span>" but that still 6208 // satisfies our requirement. Our requirement is not to produce perfect 6209 // HTML and attributes. Ideally we should preserve structure but it's 6210 // ok not to if the visible content is still enough to indicate what 6211 // even listeners these nodes might be wired up to. 6212 // TODO: Warn if there is more than a single textNode as a child. 6213 // TODO: Should we use domElement.firstChild.nodeValue to compare? 6214 if (typeof nextProp === 'string') { 6215 if (domElement.textContent !== nextProp) { 6216 updatePayload = [CHILDREN, nextProp]; 6217 } 6218 } else if (typeof nextProp === 'number') { 6219 if (domElement.textContent !== '' + nextProp) { 6220 updatePayload = [CHILDREN, '' + nextProp]; 6221 } 6222 } 6223 } else if (registrationNameModules.hasOwnProperty(propKey)) { 6224 if (nextProp != null) { 6225 ensureListeningTo(rootContainerElement, propKey); 6226 } 6227 } else {} 6228 } 6229 6230 switch (tag) { 6231 case 'input': 6232 // TODO: Make sure we check if this is still unmounted or do any clean 6233 // up necessary since we never stop tracking anymore. 6234 track(domElement); 6235 postMountWrapper(domElement, rawProps, true); 6236 break; 6237 case 'textarea': 6238 // TODO: Make sure we check if this is still unmounted or do any clean 6239 // up necessary since we never stop tracking anymore. 6240 track(domElement); 6241 postMountWrapper$3(domElement, rawProps); 6242 break; 6243 case 'select': 6244 case 'option': 6245 // For input and textarea we current always set the value property at 6246 // post mount to force it to diverge from attributes. However, for 6247 // option and select we don't quite do the same thing and select 6248 // is not resilient to the DOM state changing so we don't do that here. 6249 // TODO: Consider not doing this for input and textarea. 6250 break; 6251 default: 6252 if (typeof rawProps.onClick === 'function') { 6253 // TODO: This cast may not be sound for SVG, MathML or custom elements. 6254 trapClickOnNonInteractiveElement(domElement); 6255 } 6256 break; 6257 } 6258 6259 return updatePayload; 6260 } 6261 6262 function diffHydratedText(textNode, text) { 6263 var isDifferent = textNode.nodeValue !== text; 6264 return isDifferent; 6265 } 6266 6267 6268 6269 6270 6271 6272 6273 6274 6275 6276 6277 function restoreControlledState$1(domElement, tag, props) { 6278 switch (tag) { 6279 case 'input': 6280 restoreControlledState(domElement, props); 6281 return; 6282 case 'textarea': 6283 restoreControlledState$3(domElement, props); 6284 return; 6285 case 'select': 6286 restoreControlledState$2(domElement, props); 6287 return; 6288 } 6289 } 6290 6291 // TODO: direct imports like some-package/src/* are bad. Fix me. 6292 6293 var ReactInternals$1 = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; 6294 6295 var _ReactInternals$Sched = ReactInternals$1.Scheduler; 6296 var unstable_cancelCallback = _ReactInternals$Sched.unstable_cancelCallback; 6297 var unstable_now = _ReactInternals$Sched.unstable_now; 6298 var unstable_scheduleCallback = _ReactInternals$Sched.unstable_scheduleCallback; 6299 var unstable_shouldYield = _ReactInternals$Sched.unstable_shouldYield; 6300 var unstable_getFirstCallbackNode = _ReactInternals$Sched.unstable_getFirstCallbackNode; 6301 var unstable_runWithPriority = _ReactInternals$Sched.unstable_runWithPriority; 6302 var unstable_next = _ReactInternals$Sched.unstable_next; 6303 var unstable_continueExecution = _ReactInternals$Sched.unstable_continueExecution; 6304 var unstable_pauseExecution = _ReactInternals$Sched.unstable_pauseExecution; 6305 var unstable_getCurrentPriorityLevel = _ReactInternals$Sched.unstable_getCurrentPriorityLevel; 6306 var unstable_ImmediatePriority = _ReactInternals$Sched.unstable_ImmediatePriority; 6307 var unstable_UserBlockingPriority = _ReactInternals$Sched.unstable_UserBlockingPriority; 6308 var unstable_NormalPriority = _ReactInternals$Sched.unstable_NormalPriority; 6309 var unstable_LowPriority = _ReactInternals$Sched.unstable_LowPriority; 6310 var unstable_IdlePriority = _ReactInternals$Sched.unstable_IdlePriority; 6311 6312 // Renderers that don't support persistence 6313 // can re-export everything from this module. 6314 6315 function shim() { 6316 reactProdInvariant('270'); 6317 } 6318 6319 // Persistence (when unsupported) 6320 var supportsPersistence = false; 6321 var cloneInstance = shim; 6322 var createContainerChildSet = shim; 6323 var appendChildToContainerChildSet = shim; 6324 var finalizeContainerChildren = shim; 6325 var replaceContainerChildren = shim; 6326 var cloneHiddenInstance = shim; 6327 var cloneUnhiddenInstance = shim; 6328 var createHiddenTextInstance = shim; 6329 6330 var SUSPENSE_START_DATA = '$'; 6331 var SUSPENSE_END_DATA = '/$'; 6332 6333 var STYLE = 'style'; 6334 6335 var eventsEnabled = null; 6336 var selectionInformation = null; 6337 6338 function shouldAutoFocusHostComponent(type, props) { 6339 switch (type) { 6340 case 'button': 6341 case 'input': 6342 case 'select': 6343 case 'textarea': 6344 return !!props.autoFocus; 6345 } 6346 return false; 6347 } 6348 6349 function getRootHostContext(rootContainerInstance) { 6350 var type = void 0; 6351 var namespace = void 0; 6352 var nodeType = rootContainerInstance.nodeType; 6353 switch (nodeType) { 6354 case DOCUMENT_NODE: 6355 case DOCUMENT_FRAGMENT_NODE: 6356 { 6357 type = nodeType === DOCUMENT_NODE ? '#document' : '#fragment'; 6358 var root = rootContainerInstance.documentElement; 6359 namespace = root ? root.namespaceURI : getChildNamespace(null, ''); 6360 break; 6361 } 6362 default: 6363 { 6364 var container = nodeType === COMMENT_NODE ? rootContainerInstance.parentNode : rootContainerInstance; 6365 var ownNamespace = container.namespaceURI || null; 6366 type = container.tagName; 6367 namespace = getChildNamespace(ownNamespace, type); 6368 break; 6369 } 6370 } 6371 return namespace; 6372 } 6373 6374 function getChildHostContext(parentHostContext, type, rootContainerInstance) { 6375 var parentNamespace = parentHostContext; 6376 return getChildNamespace(parentNamespace, type); 6377 } 6378 6379 function getPublicInstance(instance) { 6380 return instance; 6381 } 6382 6383 function prepareForCommit(containerInfo) { 6384 eventsEnabled = isEnabled(); 6385 selectionInformation = getSelectionInformation(); 6386 setEnabled(false); 6387 } 6388 6389 function resetAfterCommit(containerInfo) { 6390 restoreSelection(selectionInformation); 6391 selectionInformation = null; 6392 setEnabled(eventsEnabled); 6393 eventsEnabled = null; 6394 } 6395 6396 function createInstance(type, props, rootContainerInstance, hostContext, internalInstanceHandle) { 6397 var parentNamespace = void 0; 6398 { 6399 parentNamespace = hostContext; 6400 } 6401 var domElement = createElement(type, props, rootContainerInstance, parentNamespace); 6402 precacheFiberNode(internalInstanceHandle, domElement); 6403 updateFiberProps(domElement, props); 6404 return domElement; 6405 } 6406 6407 function appendInitialChild(parentInstance, child) { 6408 parentInstance.appendChild(child); 6409 } 6410 6411 function finalizeInitialChildren(domElement, type, props, rootContainerInstance, hostContext) { 6412 setInitialProperties(domElement, type, props, rootContainerInstance); 6413 return shouldAutoFocusHostComponent(type, props); 6414 } 6415 6416 function prepareUpdate(domElement, type, oldProps, newProps, rootContainerInstance, hostContext) { 6417 return diffProperties(domElement, type, oldProps, newProps, rootContainerInstance); 6418 } 6419 6420 function shouldSetTextContent(type, props) { 6421 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; 6422 } 6423 6424 function shouldDeprioritizeSubtree(type, props) { 6425 return !!props.hidden; 6426 } 6427 6428 function createTextInstance(text, rootContainerInstance, hostContext, internalInstanceHandle) { 6429 var textNode = createTextNode(text, rootContainerInstance); 6430 precacheFiberNode(internalInstanceHandle, textNode); 6431 return textNode; 6432 } 6433 6434 var isPrimaryRenderer = true; 6435 // This initialization code may run even on server environments 6436 // if a component just imports ReactDOM (e.g. for findDOMNode). 6437 // Some environments might not have setTimeout or clearTimeout. 6438 var scheduleTimeout = typeof setTimeout === 'function' ? setTimeout : undefined; 6439 var cancelTimeout = typeof clearTimeout === 'function' ? clearTimeout : undefined; 6440 var noTimeout = -1; 6441 var schedulePassiveEffects = unstable_scheduleCallback; 6442 var cancelPassiveEffects = unstable_cancelCallback; 6443 6444 // ------------------- 6445 // Mutation 6446 // ------------------- 6447 6448 var supportsMutation = true; 6449 6450 function commitMount(domElement, type, newProps, internalInstanceHandle) { 6451 // Despite the naming that might imply otherwise, this method only 6452 // fires if there is an `Update` effect scheduled during mounting. 6453 // This happens if `finalizeInitialChildren` returns `true` (which it 6454 // does to implement the `autoFocus` attribute on the client). But 6455 // there are also other cases when this might happen (such as patching 6456 // up text content during hydration mismatch). So we'll check this again. 6457 if (shouldAutoFocusHostComponent(type, newProps)) { 6458 domElement.focus(); 6459 } 6460 } 6461 6462 function commitUpdate(domElement, updatePayload, type, oldProps, newProps, internalInstanceHandle) { 6463 // Update the props handle so that we know which props are the ones with 6464 // with current event handlers. 6465 updateFiberProps(domElement, newProps); 6466 // Apply the diff to the DOM node. 6467 updateProperties(domElement, updatePayload, type, oldProps, newProps); 6468 } 6469 6470 function resetTextContent(domElement) { 6471 setTextContent(domElement, ''); 6472 } 6473 6474 function commitTextUpdate(textInstance, oldText, newText) { 6475 textInstance.nodeValue = newText; 6476 } 6477 6478 function appendChild(parentInstance, child) { 6479 parentInstance.appendChild(child); 6480 } 6481 6482 function appendChildToContainer(container, child) { 6483 var parentNode = void 0; 6484 if (container.nodeType === COMMENT_NODE) { 6485 parentNode = container.parentNode; 6486 parentNode.insertBefore(child, container); 6487 } else { 6488 parentNode = container; 6489 parentNode.appendChild(child); 6490 } 6491 // This container might be used for a portal. 6492 // If something inside a portal is clicked, that click should bubble 6493 // through the React tree. However, on Mobile Safari the click would 6494 // never bubble through the *DOM* tree unless an ancestor with onclick 6495 // event exists. So we wouldn't see it and dispatch it. 6496 // This is why we ensure that non React root containers have inline onclick 6497 // defined. 6498 // https://github.com/facebook/react/issues/11918 6499 var reactRootContainer = container._reactRootContainer; 6500 if ((reactRootContainer === null || reactRootContainer === undefined) && parentNode.onclick === null) { 6501 // TODO: This cast may not be sound for SVG, MathML or custom elements. 6502 trapClickOnNonInteractiveElement(parentNode); 6503 } 6504 } 6505 6506 function insertBefore(parentInstance, child, beforeChild) { 6507 parentInstance.insertBefore(child, beforeChild); 6508 } 6509 6510 function insertInContainerBefore(container, child, beforeChild) { 6511 if (container.nodeType === COMMENT_NODE) { 6512 container.parentNode.insertBefore(child, beforeChild); 6513 } else { 6514 container.insertBefore(child, beforeChild); 6515 } 6516 } 6517 6518 function removeChild(parentInstance, child) { 6519 parentInstance.removeChild(child); 6520 } 6521 6522 function removeChildFromContainer(container, child) { 6523 if (container.nodeType === COMMENT_NODE) { 6524 container.parentNode.removeChild(child); 6525 } else { 6526 container.removeChild(child); 6527 } 6528 } 6529 6530 function clearSuspenseBoundary(parentInstance, suspenseInstance) { 6531 var node = suspenseInstance; 6532 // Delete all nodes within this suspense boundary. 6533 // There might be nested nodes so we need to keep track of how 6534 // deep we are and only break out when we're back on top. 6535 var depth = 0; 6536 do { 6537 var nextNode = node.nextSibling; 6538 parentInstance.removeChild(node); 6539 if (nextNode && nextNode.nodeType === COMMENT_NODE) { 6540 var data = nextNode.data; 6541 if (data === SUSPENSE_END_DATA) { 6542 if (depth === 0) { 6543 parentInstance.removeChild(nextNode); 6544 return; 6545 } else { 6546 depth--; 6547 } 6548 } else if (data === SUSPENSE_START_DATA) { 6549 depth++; 6550 } 6551 } 6552 node = nextNode; 6553 } while (node); 6554 // TODO: Warn, we didn't find the end comment boundary. 6555 } 6556 6557 function clearSuspenseBoundaryFromContainer(container, suspenseInstance) { 6558 if (container.nodeType === COMMENT_NODE) { 6559 clearSuspenseBoundary(container.parentNode, suspenseInstance); 6560 } else if (container.nodeType === ELEMENT_NODE) { 6561 clearSuspenseBoundary(container, suspenseInstance); 6562 } else { 6563 // Document nodes should never contain suspense boundaries. 6564 } 6565 } 6566 6567 function hideInstance(instance) { 6568 // TODO: Does this work for all element types? What about MathML? Should we 6569 // pass host context to this method? 6570 instance = instance; 6571 instance.style.display = 'none'; 6572 } 6573 6574 function hideTextInstance(textInstance) { 6575 textInstance.nodeValue = ''; 6576 } 6577 6578 function unhideInstance(instance, props) { 6579 instance = instance; 6580 var styleProp = props[STYLE]; 6581 var display = styleProp !== undefined && styleProp !== null && styleProp.hasOwnProperty('display') ? styleProp.display : null; 6582 instance.style.display = dangerousStyleValue('display', display); 6583 } 6584 6585 function unhideTextInstance(textInstance, text) { 6586 textInstance.nodeValue = text; 6587 } 6588 6589 // ------------------- 6590 // Hydration 6591 // ------------------- 6592 6593 var supportsHydration = true; 6594 6595 function canHydrateInstance(instance, type, props) { 6596 if (instance.nodeType !== ELEMENT_NODE || type.toLowerCase() !== instance.nodeName.toLowerCase()) { 6597 return null; 6598 } 6599 // This has now been refined to an element node. 6600 return instance; 6601 } 6602 6603 function canHydrateTextInstance(instance, text) { 6604 if (text === '' || instance.nodeType !== TEXT_NODE) { 6605 // Empty strings are not parsed by HTML so there won't be a correct match here. 6606 return null; 6607 } 6608 // This has now been refined to a text node. 6609 return instance; 6610 } 6611 6612 function canHydrateSuspenseInstance(instance) { 6613 if (instance.nodeType !== COMMENT_NODE) { 6614 // Empty strings are not parsed by HTML so there won't be a correct match here. 6615 return null; 6616 } 6617 // This has now been refined to a suspense node. 6618 return instance; 6619 } 6620 6621 function getNextHydratableSibling(instance) { 6622 var node = instance.nextSibling; 6623 // Skip non-hydratable nodes. 6624 while (node && node.nodeType !== ELEMENT_NODE && node.nodeType !== TEXT_NODE && (!enableSuspenseServerRenderer || node.nodeType !== COMMENT_NODE || node.data !== SUSPENSE_START_DATA)) { 6625 node = node.nextSibling; 6626 } 6627 return node; 6628 } 6629 6630 function getFirstHydratableChild(parentInstance) { 6631 var next = parentInstance.firstChild; 6632 // Skip non-hydratable nodes. 6633 while (next && next.nodeType !== ELEMENT_NODE && next.nodeType !== TEXT_NODE && (!enableSuspenseServerRenderer || next.nodeType !== COMMENT_NODE || next.data !== SUSPENSE_START_DATA)) { 6634 next = next.nextSibling; 6635 } 6636 return next; 6637 } 6638 6639 function hydrateInstance(instance, type, props, rootContainerInstance, hostContext, internalInstanceHandle) { 6640 precacheFiberNode(internalInstanceHandle, instance); 6641 // TODO: Possibly defer this until the commit phase where all the events 6642 // get attached. 6643 updateFiberProps(instance, props); 6644 var parentNamespace = void 0; 6645 { 6646 parentNamespace = hostContext; 6647 } 6648 return diffHydratedProperties(instance, type, props, parentNamespace, rootContainerInstance); 6649 } 6650 6651 function hydrateTextInstance(textInstance, text, internalInstanceHandle) { 6652 precacheFiberNode(internalInstanceHandle, textInstance); 6653 return diffHydratedText(textInstance, text); 6654 } 6655 6656 function getNextHydratableInstanceAfterSuspenseInstance(suspenseInstance) { 6657 var node = suspenseInstance.nextSibling; 6658 // Skip past all nodes within this suspense boundary. 6659 // There might be nested nodes so we need to keep track of how 6660 // deep we are and only break out when we're back on top. 6661 var depth = 0; 6662 while (node) { 6663 if (node.nodeType === COMMENT_NODE) { 6664 var data = node.data; 6665 if (data === SUSPENSE_END_DATA) { 6666 if (depth === 0) { 6667 return getNextHydratableSibling(node); 6668 } else { 6669 depth--; 6670 } 6671 } else if (data === SUSPENSE_START_DATA) { 6672 depth++; 6673 } 6674 } 6675 node = node.nextSibling; 6676 } 6677 // TODO: Warn, we didn't find the end comment boundary. 6678 return null; 6679 } 6680 6681 // Prefix measurements so that it's possible to filter them. 6682 // Longer prefixes are hard to read in DevTools. 6683 var reactEmoji = '\u269B'; 6684 var warningEmoji = '\u26D4'; 6685 var supportsUserTiming = typeof performance !== 'undefined' && typeof performance.mark === 'function' && typeof performance.clearMarks === 'function' && typeof performance.measure === 'function' && typeof performance.clearMeasures === 'function'; 6686 6687 // Keep track of current fiber so that we know the path to unwind on pause. 6688 // TODO: this looks the same as nextUnitOfWork in scheduler. Can we unify them? 6689 var currentFiber = null; 6690 // If we're in the middle of user code, which fiber and method is it? 6691 // Reusing `currentFiber` would be confusing for this because user code fiber 6692 // can change during commit phase too, but we don't need to unwind it (since 6693 // lifecycles in the commit phase don't resemble a tree). 6694 var currentPhase = null; 6695 var currentPhaseFiber = null; 6696 // Did lifecycle hook schedule an update? This is often a performance problem, 6697 // so we will keep track of it, and include it in the report. 6698 // Track commits caused by cascading updates. 6699 var isCommitting = false; 6700 var hasScheduledUpdateInCurrentCommit = false; 6701 var hasScheduledUpdateInCurrentPhase = false; 6702 var commitCountInCurrentWorkLoop = 0; 6703 var effectCountInCurrentCommit = 0; 6704 var isWaitingForCallback = false; 6705 // During commits, we only show a measurement once per method name 6706 // to avoid stretch the commit phase with measurement overhead. 6707 var labelsInCurrentCommit = new Set(); 6708 6709 var formatMarkName = function (markName) { 6710 return reactEmoji + ' ' + markName; 6711 }; 6712 6713 var formatLabel = function (label, warning) { 6714 var prefix = warning ? warningEmoji + ' ' : reactEmoji + ' '; 6715 var suffix = warning ? ' Warning: ' + warning : ''; 6716 return '' + prefix + label + suffix; 6717 }; 6718 6719 var beginMark = function (markName) { 6720 performance.mark(formatMarkName(markName)); 6721 }; 6722 6723 var clearMark = function (markName) { 6724 performance.clearMarks(formatMarkName(markName)); 6725 }; 6726 6727 var endMark = function (label, markName, warning) { 6728 var formattedMarkName = formatMarkName(markName); 6729 var formattedLabel = formatLabel(label, warning); 6730 try { 6731 performance.measure(formattedLabel, formattedMarkName); 6732 } catch (err) {} 6733 // If previous mark was missing for some reason, this will throw. 6734 // This could only happen if React crashed in an unexpected place earlier. 6735 // Don't pile on with more errors. 6736 6737 // Clear marks immediately to avoid growing buffer. 6738 performance.clearMarks(formattedMarkName); 6739 performance.clearMeasures(formattedLabel); 6740 }; 6741 6742 var getFiberMarkName = function (label, debugID) { 6743 return label + ' (#' + debugID + ')'; 6744 }; 6745 6746 var getFiberLabel = function (componentName, isMounted, phase) { 6747 if (phase === null) { 6748 // These are composite component total time measurements. 6749 return componentName + ' [' + (isMounted ? 'update' : 'mount') + ']'; 6750 } else { 6751 // Composite component methods. 6752 return componentName + '.' + phase; 6753 } 6754 }; 6755 6756 var beginFiberMark = function (fiber, phase) { 6757 var componentName = getComponentName(fiber.type) || 'Unknown'; 6758 var debugID = fiber._debugID; 6759 var isMounted = fiber.alternate !== null; 6760 var label = getFiberLabel(componentName, isMounted, phase); 6761 6762 if (isCommitting && labelsInCurrentCommit.has(label)) { 6763 // During the commit phase, we don't show duplicate labels because 6764 // there is a fixed overhead for every measurement, and we don't 6765 // want to stretch the commit phase beyond necessary. 6766 return false; 6767 } 6768 labelsInCurrentCommit.add(label); 6769 6770 var markName = getFiberMarkName(label, debugID); 6771 beginMark(markName); 6772 return true; 6773 }; 6774 6775 var clearFiberMark = function (fiber, phase) { 6776 var componentName = getComponentName(fiber.type) || 'Unknown'; 6777 var debugID = fiber._debugID; 6778 var isMounted = fiber.alternate !== null; 6779 var label = getFiberLabel(componentName, isMounted, phase); 6780 var markName = getFiberMarkName(label, debugID); 6781 clearMark(markName); 6782 }; 6783 6784 var endFiberMark = function (fiber, phase, warning) { 6785 var componentName = getComponentName(fiber.type) || 'Unknown'; 6786 var debugID = fiber._debugID; 6787 var isMounted = fiber.alternate !== null; 6788 var label = getFiberLabel(componentName, isMounted, phase); 6789 var markName = getFiberMarkName(label, debugID); 6790 endMark(label, markName, warning); 6791 }; 6792 6793 var shouldIgnoreFiber = function (fiber) { 6794 // Host components should be skipped in the timeline. 6795 // We could check typeof fiber.type, but does this work with RN? 6796 switch (fiber.tag) { 6797 case HostRoot: 6798 case HostComponent: 6799 case HostText: 6800 case HostPortal: 6801 case Fragment: 6802 case ContextProvider: 6803 case ContextConsumer: 6804 case Mode: 6805 return true; 6806 default: 6807 return false; 6808 } 6809 }; 6810 6811 var clearPendingPhaseMeasurement = function () { 6812 if (currentPhase !== null && currentPhaseFiber !== null) { 6813 clearFiberMark(currentPhaseFiber, currentPhase); 6814 } 6815 currentPhaseFiber = null; 6816 currentPhase = null; 6817 hasScheduledUpdateInCurrentPhase = false; 6818 }; 6819 6820 var pauseTimers = function () { 6821 // Stops all currently active measurements so that they can be resumed 6822 // if we continue in a later deferred loop from the same unit of work. 6823 var fiber = currentFiber; 6824 while (fiber) { 6825 if (fiber._debugIsCurrentlyTiming) { 6826 endFiberMark(fiber, null, null); 6827 } 6828 fiber = fiber.return; 6829 } 6830 }; 6831 6832 var resumeTimersRecursively = function (fiber) { 6833 if (fiber.return !== null) { 6834 resumeTimersRecursively(fiber.return); 6835 } 6836 if (fiber._debugIsCurrentlyTiming) { 6837 beginFiberMark(fiber, null); 6838 } 6839 }; 6840 6841 var resumeTimers = function () { 6842 // Resumes all measurements that were active during the last deferred loop. 6843 if (currentFiber !== null) { 6844 resumeTimersRecursively(currentFiber); 6845 } 6846 }; 6847 6848 function recordEffect() { 6849 if (enableUserTimingAPI) { 6850 effectCountInCurrentCommit++; 6851 } 6852 } 6853 6854 function recordScheduleUpdate() { 6855 if (enableUserTimingAPI) { 6856 if (isCommitting) { 6857 hasScheduledUpdateInCurrentCommit = true; 6858 } 6859 if (currentPhase !== null && currentPhase !== 'componentWillMount' && currentPhase !== 'componentWillReceiveProps') { 6860 hasScheduledUpdateInCurrentPhase = true; 6861 } 6862 } 6863 } 6864 6865 function startRequestCallbackTimer() { 6866 if (enableUserTimingAPI) { 6867 if (supportsUserTiming && !isWaitingForCallback) { 6868 isWaitingForCallback = true; 6869 beginMark('(Waiting for async callback...)'); 6870 } 6871 } 6872 } 6873 6874 function stopRequestCallbackTimer(didExpire, expirationTime) { 6875 if (enableUserTimingAPI) { 6876 if (supportsUserTiming) { 6877 isWaitingForCallback = false; 6878 var warning = didExpire ? 'React was blocked by main thread' : null; 6879 endMark('(Waiting for async callback... will force flush in ' + expirationTime + ' ms)', '(Waiting for async callback...)', warning); 6880 } 6881 } 6882 } 6883 6884 function startWorkTimer(fiber) { 6885 if (enableUserTimingAPI) { 6886 if (!supportsUserTiming || shouldIgnoreFiber(fiber)) { 6887 return; 6888 } 6889 // If we pause, this is the fiber to unwind from. 6890 currentFiber = fiber; 6891 if (!beginFiberMark(fiber, null)) { 6892 return; 6893 } 6894 fiber._debugIsCurrentlyTiming = true; 6895 } 6896 } 6897 6898 function cancelWorkTimer(fiber) { 6899 if (enableUserTimingAPI) { 6900 if (!supportsUserTiming || shouldIgnoreFiber(fiber)) { 6901 return; 6902 } 6903 // Remember we shouldn't complete measurement for this fiber. 6904 // Otherwise flamechart will be deep even for small updates. 6905 fiber._debugIsCurrentlyTiming = false; 6906 clearFiberMark(fiber, null); 6907 } 6908 } 6909 6910 function stopWorkTimer(fiber) { 6911 if (enableUserTimingAPI) { 6912 if (!supportsUserTiming || shouldIgnoreFiber(fiber)) { 6913 return; 6914 } 6915 // If we pause, its parent is the fiber to unwind from. 6916 currentFiber = fiber.return; 6917 if (!fiber._debugIsCurrentlyTiming) { 6918 return; 6919 } 6920 fiber._debugIsCurrentlyTiming = false; 6921 endFiberMark(fiber, null, null); 6922 } 6923 } 6924 6925 function stopFailedWorkTimer(fiber) { 6926 if (enableUserTimingAPI) { 6927 if (!supportsUserTiming || shouldIgnoreFiber(fiber)) { 6928 return; 6929 } 6930 // If we pause, its parent is the fiber to unwind from. 6931 currentFiber = fiber.return; 6932 if (!fiber._debugIsCurrentlyTiming) { 6933 return; 6934 } 6935 fiber._debugIsCurrentlyTiming = false; 6936 var warning = fiber.tag === SuspenseComponent || fiber.tag === DehydratedSuspenseComponent ? 'Rendering was suspended' : 'An error was thrown inside this error boundary'; 6937 endFiberMark(fiber, null, warning); 6938 } 6939 } 6940 6941 function startPhaseTimer(fiber, phase) { 6942 if (enableUserTimingAPI) { 6943 if (!supportsUserTiming) { 6944 return; 6945 } 6946 clearPendingPhaseMeasurement(); 6947 if (!beginFiberMark(fiber, phase)) { 6948 return; 6949 } 6950 currentPhaseFiber = fiber; 6951 currentPhase = phase; 6952 } 6953 } 6954 6955 function stopPhaseTimer() { 6956 if (enableUserTimingAPI) { 6957 if (!supportsUserTiming) { 6958 return; 6959 } 6960 if (currentPhase !== null && currentPhaseFiber !== null) { 6961 var warning = hasScheduledUpdateInCurrentPhase ? 'Scheduled a cascading update' : null; 6962 endFiberMark(currentPhaseFiber, currentPhase, warning); 6963 } 6964 currentPhase = null; 6965 currentPhaseFiber = null; 6966 } 6967 } 6968 6969 function startWorkLoopTimer(nextUnitOfWork) { 6970 if (enableUserTimingAPI) { 6971 currentFiber = nextUnitOfWork; 6972 if (!supportsUserTiming) { 6973 return; 6974 } 6975 commitCountInCurrentWorkLoop = 0; 6976 // This is top level call. 6977 // Any other measurements are performed within. 6978 beginMark('(React Tree Reconciliation)'); 6979 // Resume any measurements that were in progress during the last loop. 6980 resumeTimers(); 6981 } 6982 } 6983 6984 function stopWorkLoopTimer(interruptedBy, didCompleteRoot) { 6985 if (enableUserTimingAPI) { 6986 if (!supportsUserTiming) { 6987 return; 6988 } 6989 var warning = null; 6990 if (interruptedBy !== null) { 6991 if (interruptedBy.tag === HostRoot) { 6992 warning = 'A top-level update interrupted the previous render'; 6993 } else { 6994 var componentName = getComponentName(interruptedBy.type) || 'Unknown'; 6995 warning = 'An update to ' + componentName + ' interrupted the previous render'; 6996 } 6997 } else if (commitCountInCurrentWorkLoop > 1) { 6998 warning = 'There were cascading updates'; 6999 } 7000 commitCountInCurrentWorkLoop = 0; 7001 var label = didCompleteRoot ? '(React Tree Reconciliation: Completed Root)' : '(React Tree Reconciliation: Yielded)'; 7002 // Pause any measurements until the next loop. 7003 pauseTimers(); 7004 endMark(label, '(React Tree Reconciliation)', warning); 7005 } 7006 } 7007 7008 function startCommitTimer() { 7009 if (enableUserTimingAPI) { 7010 if (!supportsUserTiming) { 7011 return; 7012 } 7013 isCommitting = true; 7014 hasScheduledUpdateInCurrentCommit = false; 7015 labelsInCurrentCommit.clear(); 7016 beginMark('(Committing Changes)'); 7017 } 7018 } 7019 7020 function stopCommitTimer() { 7021 if (enableUserTimingAPI) { 7022 if (!supportsUserTiming) { 7023 return; 7024 } 7025 7026 var warning = null; 7027 if (hasScheduledUpdateInCurrentCommit) { 7028 warning = 'Lifecycle hook scheduled a cascading update'; 7029 } else if (commitCountInCurrentWorkLoop > 0) { 7030 warning = 'Caused by a cascading update in earlier commit'; 7031 } 7032 hasScheduledUpdateInCurrentCommit = false; 7033 commitCountInCurrentWorkLoop++; 7034 isCommitting = false; 7035 labelsInCurrentCommit.clear(); 7036 7037 endMark('(Committing Changes)', '(Committing Changes)', warning); 7038 } 7039 } 7040 7041 function startCommitSnapshotEffectsTimer() { 7042 if (enableUserTimingAPI) { 7043 if (!supportsUserTiming) { 7044 return; 7045 } 7046 effectCountInCurrentCommit = 0; 7047 beginMark('(Committing Snapshot Effects)'); 7048 } 7049 } 7050 7051 function stopCommitSnapshotEffectsTimer() { 7052 if (enableUserTimingAPI) { 7053 if (!supportsUserTiming) { 7054 return; 7055 } 7056 var count = effectCountInCurrentCommit; 7057 effectCountInCurrentCommit = 0; 7058 endMark('(Committing Snapshot Effects: ' + count + ' Total)', '(Committing Snapshot Effects)', null); 7059 } 7060 } 7061 7062 function startCommitHostEffectsTimer() { 7063 if (enableUserTimingAPI) { 7064 if (!supportsUserTiming) { 7065 return; 7066 } 7067 effectCountInCurrentCommit = 0; 7068 beginMark('(Committing Host Effects)'); 7069 } 7070 } 7071 7072 function stopCommitHostEffectsTimer() { 7073 if (enableUserTimingAPI) { 7074 if (!supportsUserTiming) { 7075 return; 7076 } 7077 var count = effectCountInCurrentCommit; 7078 effectCountInCurrentCommit = 0; 7079 endMark('(Committing Host Effects: ' + count + ' Total)', '(Committing Host Effects)', null); 7080 } 7081 } 7082 7083 function startCommitLifeCyclesTimer() { 7084 if (enableUserTimingAPI) { 7085 if (!supportsUserTiming) { 7086 return; 7087 } 7088 effectCountInCurrentCommit = 0; 7089 beginMark('(Calling Lifecycle Methods)'); 7090 } 7091 } 7092 7093 function stopCommitLifeCyclesTimer() { 7094 if (enableUserTimingAPI) { 7095 if (!supportsUserTiming) { 7096 return; 7097 } 7098 var count = effectCountInCurrentCommit; 7099 effectCountInCurrentCommit = 0; 7100 endMark('(Calling Lifecycle Methods: ' + count + ' Total)', '(Calling Lifecycle Methods)', null); 7101 } 7102 } 7103 7104 var valueStack = []; 7105 7106 var index = -1; 7107 7108 function createCursor(defaultValue) { 7109 return { 7110 current: defaultValue 7111 }; 7112 } 7113 7114 function pop(cursor, fiber) { 7115 if (index < 0) { 7116 return; 7117 } 7118 7119 cursor.current = valueStack[index]; 7120 7121 valueStack[index] = null; 7122 7123 index--; 7124 } 7125 7126 function push(cursor, value, fiber) { 7127 index++; 7128 7129 valueStack[index] = cursor.current; 7130 7131 cursor.current = value; 7132 } 7133 7134 var emptyContextObject = {}; 7135 // A cursor to the current merged context object on the stack. 7136 var contextStackCursor = createCursor(emptyContextObject); 7137 // A cursor to a boolean indicating whether the context has changed. 7138 var didPerformWorkStackCursor = createCursor(false); 7139 // Keep track of the previous context object that was on the stack. 7140 // We use this to get access to the parent context after we have already 7141 // pushed the next context provider, and now need to merge their contexts. 7142 var previousContext = emptyContextObject; 7143 7144 function getUnmaskedContext(workInProgress, Component, didPushOwnContextIfProvider) { 7145 if (didPushOwnContextIfProvider && isContextProvider(Component)) { 7146 // If the fiber is a context provider itself, when we read its context 7147 // we may have already pushed its own child context on the stack. A context 7148 // provider should not "see" its own child context. Therefore we read the 7149 // previous (parent) context instead for a context provider. 7150 return previousContext; 7151 } 7152 return contextStackCursor.current; 7153 } 7154 7155 function cacheContext(workInProgress, unmaskedContext, maskedContext) { 7156 var instance = workInProgress.stateNode; 7157 instance.__reactInternalMemoizedUnmaskedChildContext = unmaskedContext; 7158 instance.__reactInternalMemoizedMaskedChildContext = maskedContext; 7159 } 7160 7161 function getMaskedContext(workInProgress, unmaskedContext) { 7162 var type = workInProgress.type; 7163 var contextTypes = type.contextTypes; 7164 if (!contextTypes) { 7165 return emptyContextObject; 7166 } 7167 7168 // Avoid recreating masked context unless unmasked context has changed. 7169 // Failing to do this will result in unnecessary calls to componentWillReceiveProps. 7170 // This may trigger infinite loops if componentWillReceiveProps calls setState. 7171 var instance = workInProgress.stateNode; 7172 if (instance && instance.__reactInternalMemoizedUnmaskedChildContext === unmaskedContext) { 7173 return instance.__reactInternalMemoizedMaskedChildContext; 7174 } 7175 7176 var context = {}; 7177 for (var key in contextTypes) { 7178 context[key] = unmaskedContext[key]; 7179 } 7180 7181 if (instance) { 7182 cacheContext(workInProgress, unmaskedContext, context); 7183 } 7184 7185 return context; 7186 } 7187 7188 function hasContextChanged() { 7189 return didPerformWorkStackCursor.current; 7190 } 7191 7192 function isContextProvider(type) { 7193 var childContextTypes = type.childContextTypes; 7194 return childContextTypes !== null && childContextTypes !== undefined; 7195 } 7196 7197 function popContext(fiber) { 7198 pop(didPerformWorkStackCursor, fiber); 7199 pop(contextStackCursor, fiber); 7200 } 7201 7202 function popTopLevelContextObject(fiber) { 7203 pop(didPerformWorkStackCursor, fiber); 7204 pop(contextStackCursor, fiber); 7205 } 7206 7207 function pushTopLevelContextObject(fiber, context, didChange) { 7208 !(contextStackCursor.current === emptyContextObject) ? reactProdInvariant('168') : void 0; 7209 7210 push(contextStackCursor, context, fiber); 7211 push(didPerformWorkStackCursor, didChange, fiber); 7212 } 7213 7214 function processChildContext(fiber, type, parentContext) { 7215 var instance = fiber.stateNode; 7216 var childContextTypes = type.childContextTypes; 7217 7218 // TODO (bvaughn) Replace this behavior with an invariant() in the future. 7219 // It has only been added in Fiber to match the (unintentional) behavior in Stack. 7220 if (typeof instance.getChildContext !== 'function') { 7221 return parentContext; 7222 } 7223 7224 var childContext = void 0; 7225 startPhaseTimer(fiber, 'getChildContext'); 7226 childContext = instance.getChildContext(); 7227 stopPhaseTimer(); 7228 for (var contextKey in childContext) { 7229 !(contextKey in childContextTypes) ? reactProdInvariant('108', getComponentName(type) || 'Unknown', contextKey) : void 0; 7230 } 7231 return _assign({}, parentContext, childContext); 7232 } 7233 7234 function pushContextProvider(workInProgress) { 7235 var instance = workInProgress.stateNode; 7236 // We push the context as early as possible to ensure stack integrity. 7237 // If the instance does not exist yet, we will push null at first, 7238 // and replace it on the stack later when invalidating the context. 7239 var memoizedMergedChildContext = instance && instance.__reactInternalMemoizedMergedChildContext || emptyContextObject; 7240 7241 // Remember the parent context so we can merge with it later. 7242 // Inherit the parent's did-perform-work value to avoid inadvertently blocking updates. 7243 previousContext = contextStackCursor.current; 7244 push(contextStackCursor, memoizedMergedChildContext, workInProgress); 7245 push(didPerformWorkStackCursor, didPerformWorkStackCursor.current, workInProgress); 7246 7247 return true; 7248 } 7249 7250 function invalidateContextProvider(workInProgress, type, didChange) { 7251 var instance = workInProgress.stateNode; 7252 !instance ? reactProdInvariant('169') : void 0; 7253 7254 if (didChange) { 7255 // Merge parent and own context. 7256 // Skip this if we're not updating due to sCU. 7257 // This avoids unnecessarily recomputing memoized values. 7258 var mergedContext = processChildContext(workInProgress, type, previousContext); 7259 instance.__reactInternalMemoizedMergedChildContext = mergedContext; 7260 7261 // Replace the old (or empty) context with the new one. 7262 // It is important to unwind the context in the reverse order. 7263 pop(didPerformWorkStackCursor, workInProgress); 7264 pop(contextStackCursor, workInProgress); 7265 // Now push the new context and mark that it has changed. 7266 push(contextStackCursor, mergedContext, workInProgress); 7267 push(didPerformWorkStackCursor, didChange, workInProgress); 7268 } else { 7269 pop(didPerformWorkStackCursor, workInProgress); 7270 push(didPerformWorkStackCursor, didChange, workInProgress); 7271 } 7272 } 7273 7274 function findCurrentUnmaskedContext(fiber) { 7275 // Currently this is only used with renderSubtreeIntoContainer; not sure if it 7276 // makes sense elsewhere 7277 !(isFiberMounted(fiber) && fiber.tag === ClassComponent) ? reactProdInvariant('170') : void 0; 7278 7279 var node = fiber; 7280 do { 7281 switch (node.tag) { 7282 case HostRoot: 7283 return node.stateNode.context; 7284 case ClassComponent: 7285 { 7286 var Component = node.type; 7287 if (isContextProvider(Component)) { 7288 return node.stateNode.__reactInternalMemoizedMergedChildContext; 7289 } 7290 break; 7291 } 7292 } 7293 node = node.return; 7294 } while (node !== null); 7295 reactProdInvariant('171'); 7296 } 7297 7298 var onCommitFiberRoot = null; 7299 var onCommitFiberUnmount = null; 7300 function catchErrors(fn) { 7301 return function (arg) { 7302 try { 7303 return fn(arg); 7304 } catch (err) { 7305 7306 } 7307 }; 7308 } 7309 7310 var isDevToolsPresent = typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ !== 'undefined'; 7311 7312 function injectInternals(internals) { 7313 if (typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ === 'undefined') { 7314 // No DevTools 7315 return false; 7316 } 7317 var hook = __REACT_DEVTOOLS_GLOBAL_HOOK__; 7318 if (hook.isDisabled) { 7319 // This isn't a real property on the hook, but it can be set to opt out 7320 // of DevTools integration and associated warnings and logs. 7321 // https://github.com/facebook/react/issues/3877 7322 return true; 7323 } 7324 if (!hook.supportsFiber) { 7325 return true; 7326 } 7327 try { 7328 var rendererID = hook.inject(internals); 7329 // We have successfully injected, so now it is safe to set up hooks. 7330 onCommitFiberRoot = catchErrors(function (root) { 7331 return hook.onCommitFiberRoot(rendererID, root); 7332 }); 7333 onCommitFiberUnmount = catchErrors(function (fiber) { 7334 return hook.onCommitFiberUnmount(rendererID, fiber); 7335 }); 7336 } catch (err) { 7337 // Catch all errors because it is unsafe to throw during initialization. 7338 7339 } 7340 // DevTools exists 7341 return true; 7342 } 7343 7344 function onCommitRoot(root) { 7345 if (typeof onCommitFiberRoot === 'function') { 7346 onCommitFiberRoot(root); 7347 } 7348 } 7349 7350 function onCommitUnmount(fiber) { 7351 if (typeof onCommitFiberUnmount === 'function') { 7352 onCommitFiberUnmount(fiber); 7353 } 7354 } 7355 7356 // Max 31 bit integer. The max integer size in V8 for 32-bit systems. 7357 // Math.pow(2, 30) - 1 7358 // 0b111111111111111111111111111111 7359 var maxSigned31BitInt = 1073741823; 7360 7361 var NoWork = 0; 7362 var Never = 1; 7363 var Sync = maxSigned31BitInt; 7364 7365 var UNIT_SIZE = 10; 7366 var MAGIC_NUMBER_OFFSET = maxSigned31BitInt - 1; 7367 7368 // 1 unit of expiration time represents 10ms. 7369 function msToExpirationTime(ms) { 7370 // Always add an offset so that we don't clash with the magic number for NoWork. 7371 return MAGIC_NUMBER_OFFSET - (ms / UNIT_SIZE | 0); 7372 } 7373 7374 function expirationTimeToMs(expirationTime) { 7375 return (MAGIC_NUMBER_OFFSET - expirationTime) * UNIT_SIZE; 7376 } 7377 7378 function ceiling(num, precision) { 7379 return ((num / precision | 0) + 1) * precision; 7380 } 7381 7382 function computeExpirationBucket(currentTime, expirationInMs, bucketSizeMs) { 7383 return MAGIC_NUMBER_OFFSET - ceiling(MAGIC_NUMBER_OFFSET - currentTime + expirationInMs / UNIT_SIZE, bucketSizeMs / UNIT_SIZE); 7384 } 7385 7386 var LOW_PRIORITY_EXPIRATION = 5000; 7387 var LOW_PRIORITY_BATCH_SIZE = 250; 7388 7389 function computeAsyncExpiration(currentTime) { 7390 return computeExpirationBucket(currentTime, LOW_PRIORITY_EXPIRATION, LOW_PRIORITY_BATCH_SIZE); 7391 } 7392 7393 // We intentionally set a higher expiration time for interactive updates in 7394 // dev than in production. 7395 // 7396 // If the main thread is being blocked so long that you hit the expiration, 7397 // it's a problem that could be solved with better scheduling. 7398 // 7399 // People will be more likely to notice this and fix it with the long 7400 // expiration time in development. 7401 // 7402 // In production we opt for better UX at the risk of masking scheduling 7403 // problems, by expiring fast. 7404 var HIGH_PRIORITY_EXPIRATION = 150; 7405 var HIGH_PRIORITY_BATCH_SIZE = 100; 7406 7407 function computeInteractiveExpiration(currentTime) { 7408 return computeExpirationBucket(currentTime, HIGH_PRIORITY_EXPIRATION, HIGH_PRIORITY_BATCH_SIZE); 7409 } 7410 7411 var NoContext = 0; 7412 var ConcurrentMode = 1; 7413 var StrictMode = 2; 7414 var ProfileMode = 4; 7415 7416 function FiberNode(tag, pendingProps, key, mode) { 7417 // Instance 7418 this.tag = tag; 7419 this.key = key; 7420 this.elementType = null; 7421 this.type = null; 7422 this.stateNode = null; 7423 7424 // Fiber 7425 this.return = null; 7426 this.child = null; 7427 this.sibling = null; 7428 this.index = 0; 7429 7430 this.ref = null; 7431 7432 this.pendingProps = pendingProps; 7433 this.memoizedProps = null; 7434 this.updateQueue = null; 7435 this.memoizedState = null; 7436 this.contextDependencies = null; 7437 7438 this.mode = mode; 7439 7440 // Effects 7441 this.effectTag = NoEffect; 7442 this.nextEffect = null; 7443 7444 this.firstEffect = null; 7445 this.lastEffect = null; 7446 7447 this.expirationTime = NoWork; 7448 this.childExpirationTime = NoWork; 7449 7450 this.alternate = null; 7451 7452 if (enableProfilerTimer) { 7453 // Note: The following is done to avoid a v8 performance cliff. 7454 // 7455 // Initializing the fields below to smis and later updating them with 7456 // double values will cause Fibers to end up having separate shapes. 7457 // This behavior/bug has something to do with Object.preventExtension(). 7458 // Fortunately this only impacts DEV builds. 7459 // Unfortunately it makes React unusably slow for some applications. 7460 // To work around this, initialize the fields below with doubles. 7461 // 7462 // Learn more about this here: 7463 // https://github.com/facebook/react/issues/14365 7464 // https://bugs.chromium.org/p/v8/issues/detail?id=8538 7465 this.actualDuration = Number.NaN; 7466 this.actualStartTime = Number.NaN; 7467 this.selfBaseDuration = Number.NaN; 7468 this.treeBaseDuration = Number.NaN; 7469 7470 // It's okay to replace the initial doubles with smis after initialization. 7471 // This won't trigger the performance cliff mentioned above, 7472 // and it simplifies other profiler code (including DevTools). 7473 this.actualDuration = 0; 7474 this.actualStartTime = -1; 7475 this.selfBaseDuration = 0; 7476 this.treeBaseDuration = 0; 7477 } 7478 7479 7480 } 7481 7482 // This is a constructor function, rather than a POJO constructor, still 7483 // please ensure we do the following: 7484 // 1) Nobody should add any instance methods on this. Instance methods can be 7485 // more difficult to predict when they get optimized and they are almost 7486 // never inlined properly in static compilers. 7487 // 2) Nobody should rely on `instanceof Fiber` for type testing. We should 7488 // always know when it is a fiber. 7489 // 3) We might want to experiment with using numeric keys since they are easier 7490 // to optimize in a non-JIT environment. 7491 // 4) We can easily go from a constructor to a createFiber object literal if that 7492 // is faster. 7493 // 5) It should be easy to port this to a C struct and keep a C implementation 7494 // compatible. 7495 var createFiber = function (tag, pendingProps, key, mode) { 7496 // $FlowFixMe: the shapes are exact here but Flow doesn't like constructors 7497 return new FiberNode(tag, pendingProps, key, mode); 7498 }; 7499 7500 function shouldConstruct(Component) { 7501 var prototype = Component.prototype; 7502 return !!(prototype && prototype.isReactComponent); 7503 } 7504 7505 function isSimpleFunctionComponent(type) { 7506 return typeof type === 'function' && !shouldConstruct(type) && type.defaultProps === undefined; 7507 } 7508 7509 function resolveLazyComponentTag(Component) { 7510 if (typeof Component === 'function') { 7511 return shouldConstruct(Component) ? ClassComponent : FunctionComponent; 7512 } else if (Component !== undefined && Component !== null) { 7513 var $$typeof = Component.$$typeof; 7514 if ($$typeof === REACT_FORWARD_REF_TYPE) { 7515 return ForwardRef; 7516 } 7517 if ($$typeof === REACT_MEMO_TYPE) { 7518 return MemoComponent; 7519 } 7520 } 7521 return IndeterminateComponent; 7522 } 7523 7524 // This is used to create an alternate fiber to do work on. 7525 function createWorkInProgress(current, pendingProps, expirationTime) { 7526 var workInProgress = current.alternate; 7527 if (workInProgress === null) { 7528 // We use a double buffering pooling technique because we know that we'll 7529 // only ever need at most two versions of a tree. We pool the "other" unused 7530 // node that we're free to reuse. This is lazily created to avoid allocating 7531 // extra objects for things that are never updated. It also allow us to 7532 // reclaim the extra memory if needed. 7533 workInProgress = createFiber(current.tag, pendingProps, current.key, current.mode); 7534 workInProgress.elementType = current.elementType; 7535 workInProgress.type = current.type; 7536 workInProgress.stateNode = current.stateNode; 7537 7538 workInProgress.alternate = current; 7539 current.alternate = workInProgress; 7540 } else { 7541 workInProgress.pendingProps = pendingProps; 7542 7543 // We already have an alternate. 7544 // Reset the effect tag. 7545 workInProgress.effectTag = NoEffect; 7546 7547 // The effect list is no longer valid. 7548 workInProgress.nextEffect = null; 7549 workInProgress.firstEffect = null; 7550 workInProgress.lastEffect = null; 7551 7552 if (enableProfilerTimer) { 7553 // We intentionally reset, rather than copy, actualDuration & actualStartTime. 7554 // This prevents time from endlessly accumulating in new commits. 7555 // This has the downside of resetting values for different priority renders, 7556 // But works for yielding (the common case) and should support resuming. 7557 workInProgress.actualDuration = 0; 7558 workInProgress.actualStartTime = -1; 7559 } 7560 } 7561 7562 workInProgress.childExpirationTime = current.childExpirationTime; 7563 workInProgress.expirationTime = current.expirationTime; 7564 7565 workInProgress.child = current.child; 7566 workInProgress.memoizedProps = current.memoizedProps; 7567 workInProgress.memoizedState = current.memoizedState; 7568 workInProgress.updateQueue = current.updateQueue; 7569 workInProgress.contextDependencies = current.contextDependencies; 7570 7571 // These will be overridden during the parent's reconciliation 7572 workInProgress.sibling = current.sibling; 7573 workInProgress.index = current.index; 7574 workInProgress.ref = current.ref; 7575 7576 if (enableProfilerTimer) { 7577 workInProgress.selfBaseDuration = current.selfBaseDuration; 7578 workInProgress.treeBaseDuration = current.treeBaseDuration; 7579 } 7580 7581 return workInProgress; 7582 } 7583 7584 function createHostRootFiber(isConcurrent) { 7585 var mode = isConcurrent ? ConcurrentMode | StrictMode : NoContext; 7586 7587 if (enableProfilerTimer && isDevToolsPresent) { 7588 // Always collect profile timings when DevTools are present. 7589 // This enables DevTools to start capturing timing at any point– 7590 // Without some nodes in the tree having empty base times. 7591 mode |= ProfileMode; 7592 } 7593 7594 return createFiber(HostRoot, null, null, mode); 7595 } 7596 7597 function createFiberFromTypeAndProps(type, // React$ElementType 7598 key, pendingProps, owner, mode, expirationTime) { 7599 var fiber = void 0; 7600 7601 var fiberTag = IndeterminateComponent; 7602 // The resolved type is set if we know what the final type will be. I.e. it's not lazy. 7603 var resolvedType = type; 7604 if (typeof type === 'function') { 7605 if (shouldConstruct(type)) { 7606 fiberTag = ClassComponent; 7607 } 7608 } else if (typeof type === 'string') { 7609 fiberTag = HostComponent; 7610 } else { 7611 getTag: switch (type) { 7612 case REACT_FRAGMENT_TYPE: 7613 return createFiberFromFragment(pendingProps.children, mode, expirationTime, key); 7614 case REACT_CONCURRENT_MODE_TYPE: 7615 return createFiberFromMode(pendingProps, mode | ConcurrentMode | StrictMode, expirationTime, key); 7616 case REACT_STRICT_MODE_TYPE: 7617 return createFiberFromMode(pendingProps, mode | StrictMode, expirationTime, key); 7618 case REACT_PROFILER_TYPE: 7619 return createFiberFromProfiler(pendingProps, mode, expirationTime, key); 7620 case REACT_SUSPENSE_TYPE: 7621 return createFiberFromSuspense(pendingProps, mode, expirationTime, key); 7622 default: 7623 { 7624 if (typeof type === 'object' && type !== null) { 7625 switch (type.$$typeof) { 7626 case REACT_PROVIDER_TYPE: 7627 fiberTag = ContextProvider; 7628 break getTag; 7629 case REACT_CONTEXT_TYPE: 7630 // This is a consumer 7631 fiberTag = ContextConsumer; 7632 break getTag; 7633 case REACT_FORWARD_REF_TYPE: 7634 fiberTag = ForwardRef; 7635 break getTag; 7636 case REACT_MEMO_TYPE: 7637 fiberTag = MemoComponent; 7638 break getTag; 7639 case REACT_LAZY_TYPE: 7640 fiberTag = LazyComponent; 7641 resolvedType = null; 7642 break getTag; 7643 } 7644 } 7645 var info = ''; 7646 reactProdInvariant('130', type == null ? type : typeof type, info); 7647 } 7648 } 7649 } 7650 7651 fiber = createFiber(fiberTag, pendingProps, key, mode); 7652 fiber.elementType = type; 7653 fiber.type = resolvedType; 7654 fiber.expirationTime = expirationTime; 7655 7656 return fiber; 7657 } 7658 7659 function createFiberFromElement(element, mode, expirationTime) { 7660 var owner = null; 7661 var type = element.type; 7662 var key = element.key; 7663 var pendingProps = element.props; 7664 var fiber = createFiberFromTypeAndProps(type, key, pendingProps, owner, mode, expirationTime); 7665 return fiber; 7666 } 7667 7668 function createFiberFromFragment(elements, mode, expirationTime, key) { 7669 var fiber = createFiber(Fragment, elements, key, mode); 7670 fiber.expirationTime = expirationTime; 7671 return fiber; 7672 } 7673 7674 function createFiberFromProfiler(pendingProps, mode, expirationTime, key) { 7675 var fiber = createFiber(Profiler, pendingProps, key, mode | ProfileMode); 7676 // TODO: The Profiler fiber shouldn't have a type. It has a tag. 7677 fiber.elementType = REACT_PROFILER_TYPE; 7678 fiber.type = REACT_PROFILER_TYPE; 7679 fiber.expirationTime = expirationTime; 7680 7681 return fiber; 7682 } 7683 7684 function createFiberFromMode(pendingProps, mode, expirationTime, key) { 7685 var fiber = createFiber(Mode, pendingProps, key, mode); 7686 7687 // TODO: The Mode fiber shouldn't have a type. It has a tag. 7688 var type = (mode & ConcurrentMode) === NoContext ? REACT_STRICT_MODE_TYPE : REACT_CONCURRENT_MODE_TYPE; 7689 fiber.elementType = type; 7690 fiber.type = type; 7691 7692 fiber.expirationTime = expirationTime; 7693 return fiber; 7694 } 7695 7696 function createFiberFromSuspense(pendingProps, mode, expirationTime, key) { 7697 var fiber = createFiber(SuspenseComponent, pendingProps, key, mode); 7698 7699 // TODO: The SuspenseComponent fiber shouldn't have a type. It has a tag. 7700 var type = REACT_SUSPENSE_TYPE; 7701 fiber.elementType = type; 7702 fiber.type = type; 7703 7704 fiber.expirationTime = expirationTime; 7705 return fiber; 7706 } 7707 7708 function createFiberFromText(content, mode, expirationTime) { 7709 var fiber = createFiber(HostText, content, null, mode); 7710 fiber.expirationTime = expirationTime; 7711 return fiber; 7712 } 7713 7714 function createFiberFromHostInstanceForDeletion() { 7715 var fiber = createFiber(HostComponent, null, null, NoContext); 7716 // TODO: These should not need a type. 7717 fiber.elementType = 'DELETED'; 7718 fiber.type = 'DELETED'; 7719 return fiber; 7720 } 7721 7722 function createFiberFromPortal(portal, mode, expirationTime) { 7723 var pendingProps = portal.children !== null ? portal.children : []; 7724 var fiber = createFiber(HostPortal, pendingProps, portal.key, mode); 7725 fiber.expirationTime = expirationTime; 7726 fiber.stateNode = { 7727 containerInfo: portal.containerInfo, 7728 pendingChildren: null, // Used by persistent updates 7729 implementation: portal.implementation 7730 }; 7731 return fiber; 7732 } 7733 7734 // Used for stashing WIP properties to replay failed work in DEV. 7735 7736 var ReactInternals$2 = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; 7737 7738 var _ReactInternals$Sched$1 = ReactInternals$2.SchedulerTracing; 7739 var __interactionsRef = _ReactInternals$Sched$1.__interactionsRef; 7740 var __subscriberRef = _ReactInternals$Sched$1.__subscriberRef; 7741 var unstable_clear = _ReactInternals$Sched$1.unstable_clear; 7742 var unstable_getCurrent = _ReactInternals$Sched$1.unstable_getCurrent; 7743 var unstable_getThreadID = _ReactInternals$Sched$1.unstable_getThreadID; 7744 var unstable_subscribe = _ReactInternals$Sched$1.unstable_subscribe; 7745 var unstable_trace = _ReactInternals$Sched$1.unstable_trace; 7746 var unstable_unsubscribe = _ReactInternals$Sched$1.unstable_unsubscribe; 7747 var unstable_wrap = _ReactInternals$Sched$1.unstable_wrap; 7748 7749 // TODO: This should be lifted into the renderer. 7750 7751 7752 // The following attributes are only used by interaction tracing builds. 7753 // They enable interactions to be associated with their async work, 7754 // And expose interaction metadata to the React DevTools Profiler plugin. 7755 // Note that these attributes are only defined when the enableSchedulerTracing flag is enabled. 7756 7757 7758 // Exported FiberRoot type includes all properties, 7759 // To avoid requiring potentially error-prone :any casts throughout the project. 7760 // Profiling properties are only safe to access in profiling builds (when enableSchedulerTracing is true). 7761 // The types are defined separately within this file to ensure they stay in sync. 7762 // (We don't have to use an inline :any cast when enableSchedulerTracing is disabled.) 7763 7764 7765 function createFiberRoot(containerInfo, isConcurrent, hydrate) { 7766 // Cyclic construction. This cheats the type system right now because 7767 // stateNode is any. 7768 var uninitializedFiber = createHostRootFiber(isConcurrent); 7769 7770 var root = void 0; 7771 if (enableSchedulerTracing) { 7772 root = { 7773 current: uninitializedFiber, 7774 containerInfo: containerInfo, 7775 pendingChildren: null, 7776 7777 earliestPendingTime: NoWork, 7778 latestPendingTime: NoWork, 7779 earliestSuspendedTime: NoWork, 7780 latestSuspendedTime: NoWork, 7781 latestPingedTime: NoWork, 7782 7783 pingCache: null, 7784 7785 didError: false, 7786 7787 pendingCommitExpirationTime: NoWork, 7788 finishedWork: null, 7789 timeoutHandle: noTimeout, 7790 context: null, 7791 pendingContext: null, 7792 hydrate: hydrate, 7793 nextExpirationTimeToWorkOn: NoWork, 7794 expirationTime: NoWork, 7795 firstBatch: null, 7796 nextScheduledRoot: null, 7797 7798 interactionThreadID: unstable_getThreadID(), 7799 memoizedInteractions: new Set(), 7800 pendingInteractionMap: new Map() 7801 }; 7802 } else { 7803 root = { 7804 current: uninitializedFiber, 7805 containerInfo: containerInfo, 7806 pendingChildren: null, 7807 7808 pingCache: null, 7809 7810 earliestPendingTime: NoWork, 7811 latestPendingTime: NoWork, 7812 earliestSuspendedTime: NoWork, 7813 latestSuspendedTime: NoWork, 7814 latestPingedTime: NoWork, 7815 7816 didError: false, 7817 7818 pendingCommitExpirationTime: NoWork, 7819 finishedWork: null, 7820 timeoutHandle: noTimeout, 7821 context: null, 7822 pendingContext: null, 7823 hydrate: hydrate, 7824 nextExpirationTimeToWorkOn: NoWork, 7825 expirationTime: NoWork, 7826 firstBatch: null, 7827 nextScheduledRoot: null 7828 }; 7829 } 7830 7831 uninitializedFiber.stateNode = root; 7832 7833 // The reason for the way the Flow types are structured in this file, 7834 // Is to avoid needing :any casts everywhere interaction tracing fields are used. 7835 // Unfortunately that requires an :any cast for non-interaction tracing capable builds. 7836 // $FlowFixMe Remove this :any cast and replace it with something better. 7837 return root; 7838 } 7839 7840 /** 7841 * Forked from fbjs/warning: 7842 * https://github.com/facebook/fbjs/blob/e66ba20ad5be433eb54423f2b097d829324d9de6/packages/fbjs/src/__forks__/warning.js 7843 * 7844 * Only change is we use console.warn instead of console.error, 7845 * and do nothing when 'console' is not supported. 7846 * This really simplifies the code. 7847 * --- 7848 * Similar to invariant but only logs a warning if the condition is not met. 7849 * This can be used to log issues in development environments in critical 7850 * paths. Removing the logging code for production environments will keep the 7851 * same logic and follow the same code paths. 7852 */ 7853 7854 // This lets us hook into Fiber to debug what it's doing. 7855 // See https://github.com/facebook/react/pull/8033. 7856 // This is not part of the public API, not even for React DevTools. 7857 // You may only inject a debugTool if you work on React Fiber itself. 7858 7859 // TODO: Offscreen updates should never suspend. However, a promise that 7860 // suspended inside an offscreen subtree should be able to ping at the priority 7861 // of the outer render. 7862 7863 function markPendingPriorityLevel(root, expirationTime) { 7864 // If there's a gap between completing a failed root and retrying it, 7865 // additional updates may be scheduled. Clear `didError`, in case the update 7866 // is sufficient to fix the error. 7867 root.didError = false; 7868 7869 // Update the latest and earliest pending times 7870 var earliestPendingTime = root.earliestPendingTime; 7871 if (earliestPendingTime === NoWork) { 7872 // No other pending updates. 7873 root.earliestPendingTime = root.latestPendingTime = expirationTime; 7874 } else { 7875 if (earliestPendingTime < expirationTime) { 7876 // This is the earliest pending update. 7877 root.earliestPendingTime = expirationTime; 7878 } else { 7879 var latestPendingTime = root.latestPendingTime; 7880 if (latestPendingTime > expirationTime) { 7881 // This is the latest pending update 7882 root.latestPendingTime = expirationTime; 7883 } 7884 } 7885 } 7886 findNextExpirationTimeToWorkOn(expirationTime, root); 7887 } 7888 7889 function markCommittedPriorityLevels(root, earliestRemainingTime) { 7890 root.didError = false; 7891 7892 if (earliestRemainingTime === NoWork) { 7893 // Fast path. There's no remaining work. Clear everything. 7894 root.earliestPendingTime = NoWork; 7895 root.latestPendingTime = NoWork; 7896 root.earliestSuspendedTime = NoWork; 7897 root.latestSuspendedTime = NoWork; 7898 root.latestPingedTime = NoWork; 7899 findNextExpirationTimeToWorkOn(NoWork, root); 7900 return; 7901 } 7902 7903 if (earliestRemainingTime < root.latestPingedTime) { 7904 root.latestPingedTime = NoWork; 7905 } 7906 7907 // Let's see if the previous latest known pending level was just flushed. 7908 var latestPendingTime = root.latestPendingTime; 7909 if (latestPendingTime !== NoWork) { 7910 if (latestPendingTime > earliestRemainingTime) { 7911 // We've flushed all the known pending levels. 7912 root.earliestPendingTime = root.latestPendingTime = NoWork; 7913 } else { 7914 var earliestPendingTime = root.earliestPendingTime; 7915 if (earliestPendingTime > earliestRemainingTime) { 7916 // We've flushed the earliest known pending level. Set this to the 7917 // latest pending time. 7918 root.earliestPendingTime = root.latestPendingTime; 7919 } 7920 } 7921 } 7922 7923 // Now let's handle the earliest remaining level in the whole tree. We need to 7924 // decide whether to treat it as a pending level or as suspended. Check 7925 // it falls within the range of known suspended levels. 7926 7927 var earliestSuspendedTime = root.earliestSuspendedTime; 7928 if (earliestSuspendedTime === NoWork) { 7929 // There's no suspended work. Treat the earliest remaining level as a 7930 // pending level. 7931 markPendingPriorityLevel(root, earliestRemainingTime); 7932 findNextExpirationTimeToWorkOn(NoWork, root); 7933 return; 7934 } 7935 7936 var latestSuspendedTime = root.latestSuspendedTime; 7937 if (earliestRemainingTime < latestSuspendedTime) { 7938 // The earliest remaining level is later than all the suspended work. That 7939 // means we've flushed all the suspended work. 7940 root.earliestSuspendedTime = NoWork; 7941 root.latestSuspendedTime = NoWork; 7942 root.latestPingedTime = NoWork; 7943 7944 // There's no suspended work. Treat the earliest remaining level as a 7945 // pending level. 7946 markPendingPriorityLevel(root, earliestRemainingTime); 7947 findNextExpirationTimeToWorkOn(NoWork, root); 7948 return; 7949 } 7950 7951 if (earliestRemainingTime > earliestSuspendedTime) { 7952 // The earliest remaining time is earlier than all the suspended work. 7953 // Treat it as a pending update. 7954 markPendingPriorityLevel(root, earliestRemainingTime); 7955 findNextExpirationTimeToWorkOn(NoWork, root); 7956 return; 7957 } 7958 7959 // The earliest remaining time falls within the range of known suspended 7960 // levels. We should treat this as suspended work. 7961 findNextExpirationTimeToWorkOn(NoWork, root); 7962 } 7963 7964 function hasLowerPriorityWork(root, erroredExpirationTime) { 7965 var latestPendingTime = root.latestPendingTime; 7966 var latestSuspendedTime = root.latestSuspendedTime; 7967 var latestPingedTime = root.latestPingedTime; 7968 return latestPendingTime !== NoWork && latestPendingTime < erroredExpirationTime || latestSuspendedTime !== NoWork && latestSuspendedTime < erroredExpirationTime || latestPingedTime !== NoWork && latestPingedTime < erroredExpirationTime; 7969 } 7970 7971 function isPriorityLevelSuspended(root, expirationTime) { 7972 var earliestSuspendedTime = root.earliestSuspendedTime; 7973 var latestSuspendedTime = root.latestSuspendedTime; 7974 return earliestSuspendedTime !== NoWork && expirationTime <= earliestSuspendedTime && expirationTime >= latestSuspendedTime; 7975 } 7976 7977 function markSuspendedPriorityLevel(root, suspendedTime) { 7978 root.didError = false; 7979 clearPing(root, suspendedTime); 7980 7981 // First, check the known pending levels and update them if needed. 7982 var earliestPendingTime = root.earliestPendingTime; 7983 var latestPendingTime = root.latestPendingTime; 7984 if (earliestPendingTime === suspendedTime) { 7985 if (latestPendingTime === suspendedTime) { 7986 // Both known pending levels were suspended. Clear them. 7987 root.earliestPendingTime = root.latestPendingTime = NoWork; 7988 } else { 7989 // The earliest pending level was suspended. Clear by setting it to the 7990 // latest pending level. 7991 root.earliestPendingTime = latestPendingTime; 7992 } 7993 } else if (latestPendingTime === suspendedTime) { 7994 // The latest pending level was suspended. Clear by setting it to the 7995 // latest pending level. 7996 root.latestPendingTime = earliestPendingTime; 7997 } 7998 7999 // Finally, update the known suspended levels. 8000 var earliestSuspendedTime = root.earliestSuspendedTime; 8001 var latestSuspendedTime = root.latestSuspendedTime; 8002 if (earliestSuspendedTime === NoWork) { 8003 // No other suspended levels. 8004 root.earliestSuspendedTime = root.latestSuspendedTime = suspendedTime; 8005 } else { 8006 if (earliestSuspendedTime < suspendedTime) { 8007 // This is the earliest suspended level. 8008 root.earliestSuspendedTime = suspendedTime; 8009 } else if (latestSuspendedTime > suspendedTime) { 8010 // This is the latest suspended level 8011 root.latestSuspendedTime = suspendedTime; 8012 } 8013 } 8014 8015 findNextExpirationTimeToWorkOn(suspendedTime, root); 8016 } 8017 8018 function markPingedPriorityLevel(root, pingedTime) { 8019 root.didError = false; 8020 8021 // TODO: When we add back resuming, we need to ensure the progressed work 8022 // is thrown out and not reused during the restarted render. One way to 8023 // invalidate the progressed work is to restart at expirationTime + 1. 8024 var latestPingedTime = root.latestPingedTime; 8025 if (latestPingedTime === NoWork || latestPingedTime > pingedTime) { 8026 root.latestPingedTime = pingedTime; 8027 } 8028 findNextExpirationTimeToWorkOn(pingedTime, root); 8029 } 8030 8031 function clearPing(root, completedTime) { 8032 var latestPingedTime = root.latestPingedTime; 8033 if (latestPingedTime >= completedTime) { 8034 root.latestPingedTime = NoWork; 8035 } 8036 } 8037 8038 function findEarliestOutstandingPriorityLevel(root, renderExpirationTime) { 8039 var earliestExpirationTime = renderExpirationTime; 8040 8041 var earliestPendingTime = root.earliestPendingTime; 8042 var earliestSuspendedTime = root.earliestSuspendedTime; 8043 if (earliestPendingTime > earliestExpirationTime) { 8044 earliestExpirationTime = earliestPendingTime; 8045 } 8046 if (earliestSuspendedTime > earliestExpirationTime) { 8047 earliestExpirationTime = earliestSuspendedTime; 8048 } 8049 return earliestExpirationTime; 8050 } 8051 8052 function didExpireAtExpirationTime(root, currentTime) { 8053 var expirationTime = root.expirationTime; 8054 if (expirationTime !== NoWork && currentTime <= expirationTime) { 8055 // The root has expired. Flush all work up to the current time. 8056 root.nextExpirationTimeToWorkOn = currentTime; 8057 } 8058 } 8059 8060 function findNextExpirationTimeToWorkOn(completedExpirationTime, root) { 8061 var earliestSuspendedTime = root.earliestSuspendedTime; 8062 var latestSuspendedTime = root.latestSuspendedTime; 8063 var earliestPendingTime = root.earliestPendingTime; 8064 var latestPingedTime = root.latestPingedTime; 8065 8066 // Work on the earliest pending time. Failing that, work on the latest 8067 // pinged time. 8068 var nextExpirationTimeToWorkOn = earliestPendingTime !== NoWork ? earliestPendingTime : latestPingedTime; 8069 8070 // If there is no pending or pinged work, check if there's suspended work 8071 // that's lower priority than what we just completed. 8072 if (nextExpirationTimeToWorkOn === NoWork && (completedExpirationTime === NoWork || latestSuspendedTime < completedExpirationTime)) { 8073 // The lowest priority suspended work is the work most likely to be 8074 // committed next. Let's start rendering it again, so that if it times out, 8075 // it's ready to commit. 8076 nextExpirationTimeToWorkOn = latestSuspendedTime; 8077 } 8078 8079 var expirationTime = nextExpirationTimeToWorkOn; 8080 if (expirationTime !== NoWork && earliestSuspendedTime > expirationTime) { 8081 // Expire using the earliest known expiration time. 8082 expirationTime = earliestSuspendedTime; 8083 } 8084 8085 root.nextExpirationTimeToWorkOn = nextExpirationTimeToWorkOn; 8086 root.expirationTime = expirationTime; 8087 } 8088 8089 function resolveDefaultProps(Component, baseProps) { 8090 if (Component && Component.defaultProps) { 8091 // Resolve default props. Taken from ReactElement 8092 var props = _assign({}, baseProps); 8093 var defaultProps = Component.defaultProps; 8094 for (var propName in defaultProps) { 8095 if (props[propName] === undefined) { 8096 props[propName] = defaultProps[propName]; 8097 } 8098 } 8099 return props; 8100 } 8101 return baseProps; 8102 } 8103 8104 function readLazyComponentType(lazyComponent) { 8105 var status = lazyComponent._status; 8106 var result = lazyComponent._result; 8107 switch (status) { 8108 case Resolved: 8109 { 8110 var Component = result; 8111 return Component; 8112 } 8113 case Rejected: 8114 { 8115 var error = result; 8116 throw error; 8117 } 8118 case Pending: 8119 { 8120 var thenable = result; 8121 throw thenable; 8122 } 8123 default: 8124 { 8125 lazyComponent._status = Pending; 8126 var ctor = lazyComponent._ctor; 8127 var _thenable = ctor(); 8128 _thenable.then(function (moduleObject) { 8129 if (lazyComponent._status === Pending) { 8130 var defaultExport = moduleObject.default; 8131 lazyComponent._status = Resolved; 8132 lazyComponent._result = defaultExport; 8133 } 8134 }, function (error) { 8135 if (lazyComponent._status === Pending) { 8136 lazyComponent._status = Rejected; 8137 lazyComponent._result = error; 8138 } 8139 }); 8140 // Handle synchronous thenables. 8141 switch (lazyComponent._status) { 8142 case Resolved: 8143 return lazyComponent._result; 8144 case Rejected: 8145 throw lazyComponent._result; 8146 } 8147 lazyComponent._result = _thenable; 8148 throw _thenable; 8149 } 8150 } 8151 } 8152 8153 // React.Component uses a shared frozen object by default. 8154 // We'll use it to determine whether we need to initialize legacy refs. 8155 var emptyRefsObject = new React.Component().refs; 8156 8157 function applyDerivedStateFromProps(workInProgress, ctor, getDerivedStateFromProps, nextProps) { 8158 var prevState = workInProgress.memoizedState; 8159 8160 var partialState = getDerivedStateFromProps(nextProps, prevState); 8161 8162 var memoizedState = partialState === null || partialState === undefined ? prevState : _assign({}, prevState, partialState); 8163 workInProgress.memoizedState = memoizedState; 8164 8165 // Once the update queue is empty, persist the derived state onto the 8166 // base state. 8167 var updateQueue = workInProgress.updateQueue; 8168 if (updateQueue !== null && workInProgress.expirationTime === NoWork) { 8169 updateQueue.baseState = memoizedState; 8170 } 8171 } 8172 8173 var classComponentUpdater = { 8174 isMounted: isMounted, 8175 enqueueSetState: function (inst, payload, callback) { 8176 var fiber = get(inst); 8177 var currentTime = requestCurrentTime(); 8178 var expirationTime = computeExpirationForFiber(currentTime, fiber); 8179 8180 var update = createUpdate(expirationTime); 8181 update.payload = payload; 8182 if (callback !== undefined && callback !== null) { 8183 update.callback = callback; 8184 } 8185 8186 flushPassiveEffects(); 8187 enqueueUpdate(fiber, update); 8188 scheduleWork(fiber, expirationTime); 8189 }, 8190 enqueueReplaceState: function (inst, payload, callback) { 8191 var fiber = get(inst); 8192 var currentTime = requestCurrentTime(); 8193 var expirationTime = computeExpirationForFiber(currentTime, fiber); 8194 8195 var update = createUpdate(expirationTime); 8196 update.tag = ReplaceState; 8197 update.payload = payload; 8198 8199 if (callback !== undefined && callback !== null) { 8200 update.callback = callback; 8201 } 8202 8203 flushPassiveEffects(); 8204 enqueueUpdate(fiber, update); 8205 scheduleWork(fiber, expirationTime); 8206 }, 8207 enqueueForceUpdate: function (inst, callback) { 8208 var fiber = get(inst); 8209 var currentTime = requestCurrentTime(); 8210 var expirationTime = computeExpirationForFiber(currentTime, fiber); 8211 8212 var update = createUpdate(expirationTime); 8213 update.tag = ForceUpdate; 8214 8215 if (callback !== undefined && callback !== null) { 8216 update.callback = callback; 8217 } 8218 8219 flushPassiveEffects(); 8220 enqueueUpdate(fiber, update); 8221 scheduleWork(fiber, expirationTime); 8222 } 8223 }; 8224 8225 function checkShouldComponentUpdate(workInProgress, ctor, oldProps, newProps, oldState, newState, nextContext) { 8226 var instance = workInProgress.stateNode; 8227 if (typeof instance.shouldComponentUpdate === 'function') { 8228 startPhaseTimer(workInProgress, 'shouldComponentUpdate'); 8229 var shouldUpdate = instance.shouldComponentUpdate(newProps, newState, nextContext); 8230 stopPhaseTimer(); 8231 8232 return shouldUpdate; 8233 } 8234 8235 if (ctor.prototype && ctor.prototype.isPureReactComponent) { 8236 return !shallowEqual(oldProps, newProps) || !shallowEqual(oldState, newState); 8237 } 8238 8239 return true; 8240 } 8241 8242 function adoptClassInstance(workInProgress, instance) { 8243 instance.updater = classComponentUpdater; 8244 workInProgress.stateNode = instance; 8245 // The instance needs access to the fiber so that it can schedule updates 8246 set(instance, workInProgress); 8247 8248 } 8249 8250 function constructClassInstance(workInProgress, ctor, props, renderExpirationTime) { 8251 var isLegacyContextConsumer = false; 8252 var unmaskedContext = emptyContextObject; 8253 var context = null; 8254 var contextType = ctor.contextType; 8255 8256 if (typeof contextType === 'object' && contextType !== null) { 8257 context = readContext(contextType); 8258 } else { 8259 unmaskedContext = getUnmaskedContext(workInProgress, ctor, true); 8260 var contextTypes = ctor.contextTypes; 8261 isLegacyContextConsumer = contextTypes !== null && contextTypes !== undefined; 8262 context = isLegacyContextConsumer ? getMaskedContext(workInProgress, unmaskedContext) : emptyContextObject; 8263 } 8264 8265 // Instantiate twice to help detect side-effects. 8266 var instance = new ctor(props, context); 8267 var state = workInProgress.memoizedState = instance.state !== null && instance.state !== undefined ? instance.state : null; 8268 adoptClassInstance(workInProgress, instance); 8269 8270 if (isLegacyContextConsumer) { 8271 cacheContext(workInProgress, unmaskedContext, context); 8272 } 8273 8274 return instance; 8275 } 8276 8277 function callComponentWillMount(workInProgress, instance) { 8278 startPhaseTimer(workInProgress, 'componentWillMount'); 8279 var oldState = instance.state; 8280 8281 if (typeof instance.componentWillMount === 'function') { 8282 instance.componentWillMount(); 8283 } 8284 if (typeof instance.UNSAFE_componentWillMount === 'function') { 8285 instance.UNSAFE_componentWillMount(); 8286 } 8287 8288 stopPhaseTimer(); 8289 8290 if (oldState !== instance.state) { 8291 classComponentUpdater.enqueueReplaceState(instance, instance.state, null); 8292 } 8293 } 8294 8295 function callComponentWillReceiveProps(workInProgress, instance, newProps, nextContext) { 8296 var oldState = instance.state; 8297 startPhaseTimer(workInProgress, 'componentWillReceiveProps'); 8298 if (typeof instance.componentWillReceiveProps === 'function') { 8299 instance.componentWillReceiveProps(newProps, nextContext); 8300 } 8301 if (typeof instance.UNSAFE_componentWillReceiveProps === 'function') { 8302 instance.UNSAFE_componentWillReceiveProps(newProps, nextContext); 8303 } 8304 stopPhaseTimer(); 8305 8306 if (instance.state !== oldState) { 8307 classComponentUpdater.enqueueReplaceState(instance, instance.state, null); 8308 } 8309 } 8310 8311 // Invokes the mount life-cycles on a previously never rendered instance. 8312 function mountClassInstance(workInProgress, ctor, newProps, renderExpirationTime) { 8313 var instance = workInProgress.stateNode; 8314 instance.props = newProps; 8315 instance.state = workInProgress.memoizedState; 8316 instance.refs = emptyRefsObject; 8317 8318 var contextType = ctor.contextType; 8319 if (typeof contextType === 'object' && contextType !== null) { 8320 instance.context = readContext(contextType); 8321 } else { 8322 var unmaskedContext = getUnmaskedContext(workInProgress, ctor, true); 8323 instance.context = getMaskedContext(workInProgress, unmaskedContext); 8324 } 8325 8326 var updateQueue = workInProgress.updateQueue; 8327 if (updateQueue !== null) { 8328 processUpdateQueue(workInProgress, updateQueue, newProps, instance, renderExpirationTime); 8329 instance.state = workInProgress.memoizedState; 8330 } 8331 8332 var getDerivedStateFromProps = ctor.getDerivedStateFromProps; 8333 if (typeof getDerivedStateFromProps === 'function') { 8334 applyDerivedStateFromProps(workInProgress, ctor, getDerivedStateFromProps, newProps); 8335 instance.state = workInProgress.memoizedState; 8336 } 8337 8338 // In order to support react-lifecycles-compat polyfilled components, 8339 // Unsafe lifecycles should not be invoked for components using the new APIs. 8340 if (typeof ctor.getDerivedStateFromProps !== 'function' && typeof instance.getSnapshotBeforeUpdate !== 'function' && (typeof instance.UNSAFE_componentWillMount === 'function' || typeof instance.componentWillMount === 'function')) { 8341 callComponentWillMount(workInProgress, instance); 8342 // If we had additional state updates during this life-cycle, let's 8343 // process them now. 8344 updateQueue = workInProgress.updateQueue; 8345 if (updateQueue !== null) { 8346 processUpdateQueue(workInProgress, updateQueue, newProps, instance, renderExpirationTime); 8347 instance.state = workInProgress.memoizedState; 8348 } 8349 } 8350 8351 if (typeof instance.componentDidMount === 'function') { 8352 workInProgress.effectTag |= Update; 8353 } 8354 } 8355 8356 function resumeMountClassInstance(workInProgress, ctor, newProps, renderExpirationTime) { 8357 var instance = workInProgress.stateNode; 8358 8359 var oldProps = workInProgress.memoizedProps; 8360 instance.props = oldProps; 8361 8362 var oldContext = instance.context; 8363 var contextType = ctor.contextType; 8364 var nextContext = void 0; 8365 if (typeof contextType === 'object' && contextType !== null) { 8366 nextContext = readContext(contextType); 8367 } else { 8368 var nextLegacyUnmaskedContext = getUnmaskedContext(workInProgress, ctor, true); 8369 nextContext = getMaskedContext(workInProgress, nextLegacyUnmaskedContext); 8370 } 8371 8372 var getDerivedStateFromProps = ctor.getDerivedStateFromProps; 8373 var hasNewLifecycles = typeof getDerivedStateFromProps === 'function' || typeof instance.getSnapshotBeforeUpdate === 'function'; 8374 8375 // Note: During these life-cycles, instance.props/instance.state are what 8376 // ever the previously attempted to render - not the "current". However, 8377 // during componentDidUpdate we pass the "current" props. 8378 8379 // In order to support react-lifecycles-compat polyfilled components, 8380 // Unsafe lifecycles should not be invoked for components using the new APIs. 8381 if (!hasNewLifecycles && (typeof instance.UNSAFE_componentWillReceiveProps === 'function' || typeof instance.componentWillReceiveProps === 'function')) { 8382 if (oldProps !== newProps || oldContext !== nextContext) { 8383 callComponentWillReceiveProps(workInProgress, instance, newProps, nextContext); 8384 } 8385 } 8386 8387 resetHasForceUpdateBeforeProcessing(); 8388 8389 var oldState = workInProgress.memoizedState; 8390 var newState = instance.state = oldState; 8391 var updateQueue = workInProgress.updateQueue; 8392 if (updateQueue !== null) { 8393 processUpdateQueue(workInProgress, updateQueue, newProps, instance, renderExpirationTime); 8394 newState = workInProgress.memoizedState; 8395 } 8396 if (oldProps === newProps && oldState === newState && !hasContextChanged() && !checkHasForceUpdateAfterProcessing()) { 8397 // If an update was already in progress, we should schedule an Update 8398 // effect even though we're bailing out, so that cWU/cDU are called. 8399 if (typeof instance.componentDidMount === 'function') { 8400 workInProgress.effectTag |= Update; 8401 } 8402 return false; 8403 } 8404 8405 if (typeof getDerivedStateFromProps === 'function') { 8406 applyDerivedStateFromProps(workInProgress, ctor, getDerivedStateFromProps, newProps); 8407 newState = workInProgress.memoizedState; 8408 } 8409 8410 var shouldUpdate = checkHasForceUpdateAfterProcessing() || checkShouldComponentUpdate(workInProgress, ctor, oldProps, newProps, oldState, newState, nextContext); 8411 8412 if (shouldUpdate) { 8413 // In order to support react-lifecycles-compat polyfilled components, 8414 // Unsafe lifecycles should not be invoked for components using the new APIs. 8415 if (!hasNewLifecycles && (typeof instance.UNSAFE_componentWillMount === 'function' || typeof instance.componentWillMount === 'function')) { 8416 startPhaseTimer(workInProgress, 'componentWillMount'); 8417 if (typeof instance.componentWillMount === 'function') { 8418 instance.componentWillMount(); 8419 } 8420 if (typeof instance.UNSAFE_componentWillMount === 'function') { 8421 instance.UNSAFE_componentWillMount(); 8422 } 8423 stopPhaseTimer(); 8424 } 8425 if (typeof instance.componentDidMount === 'function') { 8426 workInProgress.effectTag |= Update; 8427 } 8428 } else { 8429 // If an update was already in progress, we should schedule an Update 8430 // effect even though we're bailing out, so that cWU/cDU are called. 8431 if (typeof instance.componentDidMount === 'function') { 8432 workInProgress.effectTag |= Update; 8433 } 8434 8435 // If shouldComponentUpdate returned false, we should still update the 8436 // memoized state to indicate that this work can be reused. 8437 workInProgress.memoizedProps = newProps; 8438 workInProgress.memoizedState = newState; 8439 } 8440 8441 // Update the existing instance's state, props, and context pointers even 8442 // if shouldComponentUpdate returns false. 8443 instance.props = newProps; 8444 instance.state = newState; 8445 instance.context = nextContext; 8446 8447 return shouldUpdate; 8448 } 8449 8450 // Invokes the update life-cycles and returns false if it shouldn't rerender. 8451 function updateClassInstance(current, workInProgress, ctor, newProps, renderExpirationTime) { 8452 var instance = workInProgress.stateNode; 8453 8454 var oldProps = workInProgress.memoizedProps; 8455 instance.props = workInProgress.type === workInProgress.elementType ? oldProps : resolveDefaultProps(workInProgress.type, oldProps); 8456 8457 var oldContext = instance.context; 8458 var contextType = ctor.contextType; 8459 var nextContext = void 0; 8460 if (typeof contextType === 'object' && contextType !== null) { 8461 nextContext = readContext(contextType); 8462 } else { 8463 var nextUnmaskedContext = getUnmaskedContext(workInProgress, ctor, true); 8464 nextContext = getMaskedContext(workInProgress, nextUnmaskedContext); 8465 } 8466 8467 var getDerivedStateFromProps = ctor.getDerivedStateFromProps; 8468 var hasNewLifecycles = typeof getDerivedStateFromProps === 'function' || typeof instance.getSnapshotBeforeUpdate === 'function'; 8469 8470 // Note: During these life-cycles, instance.props/instance.state are what 8471 // ever the previously attempted to render - not the "current". However, 8472 // during componentDidUpdate we pass the "current" props. 8473 8474 // In order to support react-lifecycles-compat polyfilled components, 8475 // Unsafe lifecycles should not be invoked for components using the new APIs. 8476 if (!hasNewLifecycles && (typeof instance.UNSAFE_componentWillReceiveProps === 'function' || typeof instance.componentWillReceiveProps === 'function')) { 8477 if (oldProps !== newProps || oldContext !== nextContext) { 8478 callComponentWillReceiveProps(workInProgress, instance, newProps, nextContext); 8479 } 8480 } 8481 8482 resetHasForceUpdateBeforeProcessing(); 8483 8484 var oldState = workInProgress.memoizedState; 8485 var newState = instance.state = oldState; 8486 var updateQueue = workInProgress.updateQueue; 8487 if (updateQueue !== null) { 8488 processUpdateQueue(workInProgress, updateQueue, newProps, instance, renderExpirationTime); 8489 newState = workInProgress.memoizedState; 8490 } 8491 8492 if (oldProps === newProps && oldState === newState && !hasContextChanged() && !checkHasForceUpdateAfterProcessing()) { 8493 // If an update was already in progress, we should schedule an Update 8494 // effect even though we're bailing out, so that cWU/cDU are called. 8495 if (typeof instance.componentDidUpdate === 'function') { 8496 if (oldProps !== current.memoizedProps || oldState !== current.memoizedState) { 8497 workInProgress.effectTag |= Update; 8498 } 8499 } 8500 if (typeof instance.getSnapshotBeforeUpdate === 'function') { 8501 if (oldProps !== current.memoizedProps || oldState !== current.memoizedState) { 8502 workInProgress.effectTag |= Snapshot; 8503 } 8504 } 8505 return false; 8506 } 8507 8508 if (typeof getDerivedStateFromProps === 'function') { 8509 applyDerivedStateFromProps(workInProgress, ctor, getDerivedStateFromProps, newProps); 8510 newState = workInProgress.memoizedState; 8511 } 8512 8513 var shouldUpdate = checkHasForceUpdateAfterProcessing() || checkShouldComponentUpdate(workInProgress, ctor, oldProps, newProps, oldState, newState, nextContext); 8514 8515 if (shouldUpdate) { 8516 // In order to support react-lifecycles-compat polyfilled components, 8517 // Unsafe lifecycles should not be invoked for components using the new APIs. 8518 if (!hasNewLifecycles && (typeof instance.UNSAFE_componentWillUpdate === 'function' || typeof instance.componentWillUpdate === 'function')) { 8519 startPhaseTimer(workInProgress, 'componentWillUpdate'); 8520 if (typeof instance.componentWillUpdate === 'function') { 8521 instance.componentWillUpdate(newProps, newState, nextContext); 8522 } 8523 if (typeof instance.UNSAFE_componentWillUpdate === 'function') { 8524 instance.UNSAFE_componentWillUpdate(newProps, newState, nextContext); 8525 } 8526 stopPhaseTimer(); 8527 } 8528 if (typeof instance.componentDidUpdate === 'function') { 8529 workInProgress.effectTag |= Update; 8530 } 8531 if (typeof instance.getSnapshotBeforeUpdate === 'function') { 8532 workInProgress.effectTag |= Snapshot; 8533 } 8534 } else { 8535 // If an update was already in progress, we should schedule an Update 8536 // effect even though we're bailing out, so that cWU/cDU are called. 8537 if (typeof instance.componentDidUpdate === 'function') { 8538 if (oldProps !== current.memoizedProps || oldState !== current.memoizedState) { 8539 workInProgress.effectTag |= Update; 8540 } 8541 } 8542 if (typeof instance.getSnapshotBeforeUpdate === 'function') { 8543 if (oldProps !== current.memoizedProps || oldState !== current.memoizedState) { 8544 workInProgress.effectTag |= Snapshot; 8545 } 8546 } 8547 8548 // If shouldComponentUpdate returned false, we should still update the 8549 // memoized props/state to indicate that this work can be reused. 8550 workInProgress.memoizedProps = newProps; 8551 workInProgress.memoizedState = newState; 8552 } 8553 8554 // Update the existing instance's state, props, and context pointers even 8555 // if shouldComponentUpdate returns false. 8556 instance.props = newProps; 8557 instance.state = newState; 8558 instance.context = nextContext; 8559 8560 return shouldUpdate; 8561 } 8562 8563 var isArray = Array.isArray; 8564 8565 function coerceRef(returnFiber, current$$1, element) { 8566 var mixedRef = element.ref; 8567 if (mixedRef !== null && typeof mixedRef !== 'function' && typeof mixedRef !== 'object') { 8568 if (element._owner) { 8569 var owner = element._owner; 8570 var inst = void 0; 8571 if (owner) { 8572 var ownerFiber = owner; 8573 !(ownerFiber.tag === ClassComponent) ? reactProdInvariant('309') : void 0; 8574 inst = ownerFiber.stateNode; 8575 } 8576 !inst ? reactProdInvariant('147', mixedRef) : void 0; 8577 var stringRef = '' + mixedRef; 8578 // Check if previous string ref matches new string ref 8579 if (current$$1 !== null && current$$1.ref !== null && typeof current$$1.ref === 'function' && current$$1.ref._stringRef === stringRef) { 8580 return current$$1.ref; 8581 } 8582 var ref = function (value) { 8583 var refs = inst.refs; 8584 if (refs === emptyRefsObject) { 8585 // This is a lazy pooled frozen object, so we need to initialize. 8586 refs = inst.refs = {}; 8587 } 8588 if (value === null) { 8589 delete refs[stringRef]; 8590 } else { 8591 refs[stringRef] = value; 8592 } 8593 }; 8594 ref._stringRef = stringRef; 8595 return ref; 8596 } else { 8597 !(typeof mixedRef === 'string') ? reactProdInvariant('284') : void 0; 8598 !element._owner ? reactProdInvariant('290', mixedRef) : void 0; 8599 } 8600 } 8601 return mixedRef; 8602 } 8603 8604 function throwOnInvalidObjectType(returnFiber, newChild) { 8605 if (returnFiber.type !== 'textarea') { 8606 var addendum = ''; 8607 reactProdInvariant('31', Object.prototype.toString.call(newChild) === '[object Object]' ? 'object with keys {' + Object.keys(newChild).join(', ') + '}' : newChild, addendum); 8608 } 8609 } 8610 8611 // This wrapper function exists because I expect to clone the code in each path 8612 // to be able to optimize each path individually by branching early. This needs 8613 // a compiler or we can do it manually. Helpers that don't need this branching 8614 // live outside of this function. 8615 function ChildReconciler(shouldTrackSideEffects) { 8616 function deleteChild(returnFiber, childToDelete) { 8617 if (!shouldTrackSideEffects) { 8618 // Noop. 8619 return; 8620 } 8621 // Deletions are added in reversed order so we add it to the front. 8622 // At this point, the return fiber's effect list is empty except for 8623 // deletions, so we can just append the deletion to the list. The remaining 8624 // effects aren't added until the complete phase. Once we implement 8625 // resuming, this may not be true. 8626 var last = returnFiber.lastEffect; 8627 if (last !== null) { 8628 last.nextEffect = childToDelete; 8629 returnFiber.lastEffect = childToDelete; 8630 } else { 8631 returnFiber.firstEffect = returnFiber.lastEffect = childToDelete; 8632 } 8633 childToDelete.nextEffect = null; 8634 childToDelete.effectTag = Deletion; 8635 } 8636 8637 function deleteRemainingChildren(returnFiber, currentFirstChild) { 8638 if (!shouldTrackSideEffects) { 8639 // Noop. 8640 return null; 8641 } 8642 8643 // TODO: For the shouldClone case, this could be micro-optimized a bit by 8644 // assuming that after the first child we've already added everything. 8645 var childToDelete = currentFirstChild; 8646 while (childToDelete !== null) { 8647 deleteChild(returnFiber, childToDelete); 8648 childToDelete = childToDelete.sibling; 8649 } 8650 return null; 8651 } 8652 8653 function mapRemainingChildren(returnFiber, currentFirstChild) { 8654 // Add the remaining children to a temporary map so that we can find them by 8655 // keys quickly. Implicit (null) keys get added to this set with their index 8656 var existingChildren = new Map(); 8657 8658 var existingChild = currentFirstChild; 8659 while (existingChild !== null) { 8660 if (existingChild.key !== null) { 8661 existingChildren.set(existingChild.key, existingChild); 8662 } else { 8663 existingChildren.set(existingChild.index, existingChild); 8664 } 8665 existingChild = existingChild.sibling; 8666 } 8667 return existingChildren; 8668 } 8669 8670 function useFiber(fiber, pendingProps, expirationTime) { 8671 // We currently set sibling to null and index to 0 here because it is easy 8672 // to forget to do before returning it. E.g. for the single child case. 8673 var clone = createWorkInProgress(fiber, pendingProps, expirationTime); 8674 clone.index = 0; 8675 clone.sibling = null; 8676 return clone; 8677 } 8678 8679 function placeChild(newFiber, lastPlacedIndex, newIndex) { 8680 newFiber.index = newIndex; 8681 if (!shouldTrackSideEffects) { 8682 // Noop. 8683 return lastPlacedIndex; 8684 } 8685 var current$$1 = newFiber.alternate; 8686 if (current$$1 !== null) { 8687 var oldIndex = current$$1.index; 8688 if (oldIndex < lastPlacedIndex) { 8689 // This is a move. 8690 newFiber.effectTag = Placement; 8691 return lastPlacedIndex; 8692 } else { 8693 // This item can stay in place. 8694 return oldIndex; 8695 } 8696 } else { 8697 // This is an insertion. 8698 newFiber.effectTag = Placement; 8699 return lastPlacedIndex; 8700 } 8701 } 8702 8703 function placeSingleChild(newFiber) { 8704 // This is simpler for the single child case. We only need to do a 8705 // placement for inserting new children. 8706 if (shouldTrackSideEffects && newFiber.alternate === null) { 8707 newFiber.effectTag = Placement; 8708 } 8709 return newFiber; 8710 } 8711 8712 function updateTextNode(returnFiber, current$$1, textContent, expirationTime) { 8713 if (current$$1 === null || current$$1.tag !== HostText) { 8714 // Insert 8715 var created = createFiberFromText(textContent, returnFiber.mode, expirationTime); 8716 created.return = returnFiber; 8717 return created; 8718 } else { 8719 // Update 8720 var existing = useFiber(current$$1, textContent, expirationTime); 8721 existing.return = returnFiber; 8722 return existing; 8723 } 8724 } 8725 8726 function updateElement(returnFiber, current$$1, element, expirationTime) { 8727 if (current$$1 !== null && current$$1.elementType === element.type) { 8728 // Move based on index 8729 var existing = useFiber(current$$1, element.props, expirationTime); 8730 existing.ref = coerceRef(returnFiber, current$$1, element); 8731 existing.return = returnFiber; 8732 return existing; 8733 } else { 8734 // Insert 8735 var created = createFiberFromElement(element, returnFiber.mode, expirationTime); 8736 created.ref = coerceRef(returnFiber, current$$1, element); 8737 created.return = returnFiber; 8738 return created; 8739 } 8740 } 8741 8742 function updatePortal(returnFiber, current$$1, portal, expirationTime) { 8743 if (current$$1 === null || current$$1.tag !== HostPortal || current$$1.stateNode.containerInfo !== portal.containerInfo || current$$1.stateNode.implementation !== portal.implementation) { 8744 // Insert 8745 var created = createFiberFromPortal(portal, returnFiber.mode, expirationTime); 8746 created.return = returnFiber; 8747 return created; 8748 } else { 8749 // Update 8750 var existing = useFiber(current$$1, portal.children || [], expirationTime); 8751 existing.return = returnFiber; 8752 return existing; 8753 } 8754 } 8755 8756 function updateFragment(returnFiber, current$$1, fragment, expirationTime, key) { 8757 if (current$$1 === null || current$$1.tag !== Fragment) { 8758 // Insert 8759 var created = createFiberFromFragment(fragment, returnFiber.mode, expirationTime, key); 8760 created.return = returnFiber; 8761 return created; 8762 } else { 8763 // Update 8764 var existing = useFiber(current$$1, fragment, expirationTime); 8765 existing.return = returnFiber; 8766 return existing; 8767 } 8768 } 8769 8770 function createChild(returnFiber, newChild, expirationTime) { 8771 if (typeof newChild === 'string' || typeof newChild === 'number') { 8772 // Text nodes don't have keys. If the previous node is implicitly keyed 8773 // we can continue to replace it without aborting even if it is not a text 8774 // node. 8775 var created = createFiberFromText('' + newChild, returnFiber.mode, expirationTime); 8776 created.return = returnFiber; 8777 return created; 8778 } 8779 8780 if (typeof newChild === 'object' && newChild !== null) { 8781 switch (newChild.$$typeof) { 8782 case REACT_ELEMENT_TYPE: 8783 { 8784 var _created = createFiberFromElement(newChild, returnFiber.mode, expirationTime); 8785 _created.ref = coerceRef(returnFiber, null, newChild); 8786 _created.return = returnFiber; 8787 return _created; 8788 } 8789 case REACT_PORTAL_TYPE: 8790 { 8791 var _created2 = createFiberFromPortal(newChild, returnFiber.mode, expirationTime); 8792 _created2.return = returnFiber; 8793 return _created2; 8794 } 8795 } 8796 8797 if (isArray(newChild) || getIteratorFn(newChild)) { 8798 var _created3 = createFiberFromFragment(newChild, returnFiber.mode, expirationTime, null); 8799 _created3.return = returnFiber; 8800 return _created3; 8801 } 8802 8803 throwOnInvalidObjectType(returnFiber, newChild); 8804 } 8805 8806 return null; 8807 } 8808 8809 function updateSlot(returnFiber, oldFiber, newChild, expirationTime) { 8810 // Update the fiber if the keys match, otherwise return null. 8811 8812 var key = oldFiber !== null ? oldFiber.key : null; 8813 8814 if (typeof newChild === 'string' || typeof newChild === 'number') { 8815 // Text nodes don't have keys. If the previous node is implicitly keyed 8816 // we can continue to replace it without aborting even if it is not a text 8817 // node. 8818 if (key !== null) { 8819 return null; 8820 } 8821 return updateTextNode(returnFiber, oldFiber, '' + newChild, expirationTime); 8822 } 8823 8824 if (typeof newChild === 'object' && newChild !== null) { 8825 switch (newChild.$$typeof) { 8826 case REACT_ELEMENT_TYPE: 8827 { 8828 if (newChild.key === key) { 8829 if (newChild.type === REACT_FRAGMENT_TYPE) { 8830 return updateFragment(returnFiber, oldFiber, newChild.props.children, expirationTime, key); 8831 } 8832 return updateElement(returnFiber, oldFiber, newChild, expirationTime); 8833 } else { 8834 return null; 8835 } 8836 } 8837 case REACT_PORTAL_TYPE: 8838 { 8839 if (newChild.key === key) { 8840 return updatePortal(returnFiber, oldFiber, newChild, expirationTime); 8841 } else { 8842 return null; 8843 } 8844 } 8845 } 8846 8847 if (isArray(newChild) || getIteratorFn(newChild)) { 8848 if (key !== null) { 8849 return null; 8850 } 8851 8852 return updateFragment(returnFiber, oldFiber, newChild, expirationTime, null); 8853 } 8854 8855 throwOnInvalidObjectType(returnFiber, newChild); 8856 } 8857 8858 return null; 8859 } 8860 8861 function updateFromMap(existingChildren, returnFiber, newIdx, newChild, expirationTime) { 8862 if (typeof newChild === 'string' || typeof newChild === 'number') { 8863 // Text nodes don't have keys, so we neither have to check the old nor 8864 // new node for the key. If both are text nodes, they match. 8865 var matchedFiber = existingChildren.get(newIdx) || null; 8866 return updateTextNode(returnFiber, matchedFiber, '' + newChild, expirationTime); 8867 } 8868 8869 if (typeof newChild === 'object' && newChild !== null) { 8870 switch (newChild.$$typeof) { 8871 case REACT_ELEMENT_TYPE: 8872 { 8873 var _matchedFiber = existingChildren.get(newChild.key === null ? newIdx : newChild.key) || null; 8874 if (newChild.type === REACT_FRAGMENT_TYPE) { 8875 return updateFragment(returnFiber, _matchedFiber, newChild.props.children, expirationTime, newChild.key); 8876 } 8877 return updateElement(returnFiber, _matchedFiber, newChild, expirationTime); 8878 } 8879 case REACT_PORTAL_TYPE: 8880 { 8881 var _matchedFiber2 = existingChildren.get(newChild.key === null ? newIdx : newChild.key) || null; 8882 return updatePortal(returnFiber, _matchedFiber2, newChild, expirationTime); 8883 } 8884 } 8885 8886 if (isArray(newChild) || getIteratorFn(newChild)) { 8887 var _matchedFiber3 = existingChildren.get(newIdx) || null; 8888 return updateFragment(returnFiber, _matchedFiber3, newChild, expirationTime, null); 8889 } 8890 8891 throwOnInvalidObjectType(returnFiber, newChild); 8892 } 8893 8894 return null; 8895 } 8896 8897 /** 8898 * Warns if there is a duplicate or missing key 8899 */ 8900 function reconcileChildrenArray(returnFiber, currentFirstChild, newChildren, expirationTime) { 8901 // This algorithm can't optimize by searching from both ends since we 8902 // don't have backpointers on fibers. I'm trying to see how far we can get 8903 // with that model. If it ends up not being worth the tradeoffs, we can 8904 // add it later. 8905 8906 // Even with a two ended optimization, we'd want to optimize for the case 8907 // where there are few changes and brute force the comparison instead of 8908 // going for the Map. It'd like to explore hitting that path first in 8909 // forward-only mode and only go for the Map once we notice that we need 8910 // lots of look ahead. This doesn't handle reversal as well as two ended 8911 // search but that's unusual. Besides, for the two ended optimization to 8912 // work on Iterables, we'd need to copy the whole set. 8913 8914 // In this first iteration, we'll just live with hitting the bad case 8915 // (adding everything to a Map) in for every insert/move. 8916 8917 // If you change this code, also update reconcileChildrenIterator() which 8918 // uses the same algorithm. 8919 8920 var resultingFirstChild = null; 8921 var previousNewFiber = null; 8922 8923 var oldFiber = currentFirstChild; 8924 var lastPlacedIndex = 0; 8925 var newIdx = 0; 8926 var nextOldFiber = null; 8927 for (; oldFiber !== null && newIdx < newChildren.length; newIdx++) { 8928 if (oldFiber.index > newIdx) { 8929 nextOldFiber = oldFiber; 8930 oldFiber = null; 8931 } else { 8932 nextOldFiber = oldFiber.sibling; 8933 } 8934 var newFiber = updateSlot(returnFiber, oldFiber, newChildren[newIdx], expirationTime); 8935 if (newFiber === null) { 8936 // TODO: This breaks on empty slots like null children. That's 8937 // unfortunate because it triggers the slow path all the time. We need 8938 // a better way to communicate whether this was a miss or null, 8939 // boolean, undefined, etc. 8940 if (oldFiber === null) { 8941 oldFiber = nextOldFiber; 8942 } 8943 break; 8944 } 8945 if (shouldTrackSideEffects) { 8946 if (oldFiber && newFiber.alternate === null) { 8947 // We matched the slot, but we didn't reuse the existing fiber, so we 8948 // need to delete the existing child. 8949 deleteChild(returnFiber, oldFiber); 8950 } 8951 } 8952 lastPlacedIndex = placeChild(newFiber, lastPlacedIndex, newIdx); 8953 if (previousNewFiber === null) { 8954 // TODO: Move out of the loop. This only happens for the first run. 8955 resultingFirstChild = newFiber; 8956 } else { 8957 // TODO: Defer siblings if we're not at the right index for this slot. 8958 // I.e. if we had null values before, then we want to defer this 8959 // for each null value. However, we also don't want to call updateSlot 8960 // with the previous one. 8961 previousNewFiber.sibling = newFiber; 8962 } 8963 previousNewFiber = newFiber; 8964 oldFiber = nextOldFiber; 8965 } 8966 8967 if (newIdx === newChildren.length) { 8968 // We've reached the end of the new children. We can delete the rest. 8969 deleteRemainingChildren(returnFiber, oldFiber); 8970 return resultingFirstChild; 8971 } 8972 8973 if (oldFiber === null) { 8974 // If we don't have any more existing children we can choose a fast path 8975 // since the rest will all be insertions. 8976 for (; newIdx < newChildren.length; newIdx++) { 8977 var _newFiber = createChild(returnFiber, newChildren[newIdx], expirationTime); 8978 if (!_newFiber) { 8979 continue; 8980 } 8981 lastPlacedIndex = placeChild(_newFiber, lastPlacedIndex, newIdx); 8982 if (previousNewFiber === null) { 8983 // TODO: Move out of the loop. This only happens for the first run. 8984 resultingFirstChild = _newFiber; 8985 } else { 8986 previousNewFiber.sibling = _newFiber; 8987 } 8988 previousNewFiber = _newFiber; 8989 } 8990 return resultingFirstChild; 8991 } 8992 8993 // Add all children to a key map for quick lookups. 8994 var existingChildren = mapRemainingChildren(returnFiber, oldFiber); 8995 8996 // Keep scanning and use the map to restore deleted items as moves. 8997 for (; newIdx < newChildren.length; newIdx++) { 8998 var _newFiber2 = updateFromMap(existingChildren, returnFiber, newIdx, newChildren[newIdx], expirationTime); 8999 if (_newFiber2) { 9000 if (shouldTrackSideEffects) { 9001 if (_newFiber2.alternate !== null) { 9002 // The new fiber is a work in progress, but if there exists a 9003 // current, that means that we reused the fiber. We need to delete 9004 // it from the child list so that we don't add it to the deletion 9005 // list. 9006 existingChildren.delete(_newFiber2.key === null ? newIdx : _newFiber2.key); 9007 } 9008 } 9009 lastPlacedIndex = placeChild(_newFiber2, lastPlacedIndex, newIdx); 9010 if (previousNewFiber === null) { 9011 resultingFirstChild = _newFiber2; 9012 } else { 9013 previousNewFiber.sibling = _newFiber2; 9014 } 9015 previousNewFiber = _newFiber2; 9016 } 9017 } 9018 9019 if (shouldTrackSideEffects) { 9020 // Any existing children that weren't consumed above were deleted. We need 9021 // to add them to the deletion list. 9022 existingChildren.forEach(function (child) { 9023 return deleteChild(returnFiber, child); 9024 }); 9025 } 9026 9027 return resultingFirstChild; 9028 } 9029 9030 function reconcileChildrenIterator(returnFiber, currentFirstChild, newChildrenIterable, expirationTime) { 9031 // This is the same implementation as reconcileChildrenArray(), 9032 // but using the iterator instead. 9033 9034 var iteratorFn = getIteratorFn(newChildrenIterable); 9035 !(typeof iteratorFn === 'function') ? reactProdInvariant('150') : void 0; 9036 9037 var newChildren = iteratorFn.call(newChildrenIterable); 9038 !(newChildren != null) ? reactProdInvariant('151') : void 0; 9039 9040 var resultingFirstChild = null; 9041 var previousNewFiber = null; 9042 9043 var oldFiber = currentFirstChild; 9044 var lastPlacedIndex = 0; 9045 var newIdx = 0; 9046 var nextOldFiber = null; 9047 9048 var step = newChildren.next(); 9049 for (; oldFiber !== null && !step.done; newIdx++, step = newChildren.next()) { 9050 if (oldFiber.index > newIdx) { 9051 nextOldFiber = oldFiber; 9052 oldFiber = null; 9053 } else { 9054 nextOldFiber = oldFiber.sibling; 9055 } 9056 var newFiber = updateSlot(returnFiber, oldFiber, step.value, expirationTime); 9057 if (newFiber === null) { 9058 // TODO: This breaks on empty slots like null children. That's 9059 // unfortunate because it triggers the slow path all the time. We need 9060 // a better way to communicate whether this was a miss or null, 9061 // boolean, undefined, etc. 9062 if (!oldFiber) { 9063 oldFiber = nextOldFiber; 9064 } 9065 break; 9066 } 9067 if (shouldTrackSideEffects) { 9068 if (oldFiber && newFiber.alternate === null) { 9069 // We matched the slot, but we didn't reuse the existing fiber, so we 9070 // need to delete the existing child. 9071 deleteChild(returnFiber, oldFiber); 9072 } 9073 } 9074 lastPlacedIndex = placeChild(newFiber, lastPlacedIndex, newIdx); 9075 if (previousNewFiber === null) { 9076 // TODO: Move out of the loop. This only happens for the first run. 9077 resultingFirstChild = newFiber; 9078 } else { 9079 // TODO: Defer siblings if we're not at the right index for this slot. 9080 // I.e. if we had null values before, then we want to defer this 9081 // for each null value. However, we also don't want to call updateSlot 9082 // with the previous one. 9083 previousNewFiber.sibling = newFiber; 9084 } 9085 previousNewFiber = newFiber; 9086 oldFiber = nextOldFiber; 9087 } 9088 9089 if (step.done) { 9090 // We've reached the end of the new children. We can delete the rest. 9091 deleteRemainingChildren(returnFiber, oldFiber); 9092 return resultingFirstChild; 9093 } 9094 9095 if (oldFiber === null) { 9096 // If we don't have any more existing children we can choose a fast path 9097 // since the rest will all be insertions. 9098 for (; !step.done; newIdx++, step = newChildren.next()) { 9099 var _newFiber3 = createChild(returnFiber, step.value, expirationTime); 9100 if (_newFiber3 === null) { 9101 continue; 9102 } 9103 lastPlacedIndex = placeChild(_newFiber3, lastPlacedIndex, newIdx); 9104 if (previousNewFiber === null) { 9105 // TODO: Move out of the loop. This only happens for the first run. 9106 resultingFirstChild = _newFiber3; 9107 } else { 9108 previousNewFiber.sibling = _newFiber3; 9109 } 9110 previousNewFiber = _newFiber3; 9111 } 9112 return resultingFirstChild; 9113 } 9114 9115 // Add all children to a key map for quick lookups. 9116 var existingChildren = mapRemainingChildren(returnFiber, oldFiber); 9117 9118 // Keep scanning and use the map to restore deleted items as moves. 9119 for (; !step.done; newIdx++, step = newChildren.next()) { 9120 var _newFiber4 = updateFromMap(existingChildren, returnFiber, newIdx, step.value, expirationTime); 9121 if (_newFiber4 !== null) { 9122 if (shouldTrackSideEffects) { 9123 if (_newFiber4.alternate !== null) { 9124 // The new fiber is a work in progress, but if there exists a 9125 // current, that means that we reused the fiber. We need to delete 9126 // it from the child list so that we don't add it to the deletion 9127 // list. 9128 existingChildren.delete(_newFiber4.key === null ? newIdx : _newFiber4.key); 9129 } 9130 } 9131 lastPlacedIndex = placeChild(_newFiber4, lastPlacedIndex, newIdx); 9132 if (previousNewFiber === null) { 9133 resultingFirstChild = _newFiber4; 9134 } else { 9135 previousNewFiber.sibling = _newFiber4; 9136 } 9137 previousNewFiber = _newFiber4; 9138 } 9139 } 9140 9141 if (shouldTrackSideEffects) { 9142 // Any existing children that weren't consumed above were deleted. We need 9143 // to add them to the deletion list. 9144 existingChildren.forEach(function (child) { 9145 return deleteChild(returnFiber, child); 9146 }); 9147 } 9148 9149 return resultingFirstChild; 9150 } 9151 9152 function reconcileSingleTextNode(returnFiber, currentFirstChild, textContent, expirationTime) { 9153 // There's no need to check for keys on text nodes since we don't have a 9154 // way to define them. 9155 if (currentFirstChild !== null && currentFirstChild.tag === HostText) { 9156 // We already have an existing node so let's just update it and delete 9157 // the rest. 9158 deleteRemainingChildren(returnFiber, currentFirstChild.sibling); 9159 var existing = useFiber(currentFirstChild, textContent, expirationTime); 9160 existing.return = returnFiber; 9161 return existing; 9162 } 9163 // The existing first child is not a text node so we need to create one 9164 // and delete the existing ones. 9165 deleteRemainingChildren(returnFiber, currentFirstChild); 9166 var created = createFiberFromText(textContent, returnFiber.mode, expirationTime); 9167 created.return = returnFiber; 9168 return created; 9169 } 9170 9171 function reconcileSingleElement(returnFiber, currentFirstChild, element, expirationTime) { 9172 var key = element.key; 9173 var child = currentFirstChild; 9174 while (child !== null) { 9175 // TODO: If key === null and child.key === null, then this only applies to 9176 // the first item in the list. 9177 if (child.key === key) { 9178 if (child.tag === Fragment ? element.type === REACT_FRAGMENT_TYPE : child.elementType === element.type) { 9179 deleteRemainingChildren(returnFiber, child.sibling); 9180 var existing = useFiber(child, element.type === REACT_FRAGMENT_TYPE ? element.props.children : element.props, expirationTime); 9181 existing.ref = coerceRef(returnFiber, child, element); 9182 existing.return = returnFiber; 9183 return existing; 9184 } else { 9185 deleteRemainingChildren(returnFiber, child); 9186 break; 9187 } 9188 } else { 9189 deleteChild(returnFiber, child); 9190 } 9191 child = child.sibling; 9192 } 9193 9194 if (element.type === REACT_FRAGMENT_TYPE) { 9195 var created = createFiberFromFragment(element.props.children, returnFiber.mode, expirationTime, element.key); 9196 created.return = returnFiber; 9197 return created; 9198 } else { 9199 var _created4 = createFiberFromElement(element, returnFiber.mode, expirationTime); 9200 _created4.ref = coerceRef(returnFiber, currentFirstChild, element); 9201 _created4.return = returnFiber; 9202 return _created4; 9203 } 9204 } 9205 9206 function reconcileSinglePortal(returnFiber, currentFirstChild, portal, expirationTime) { 9207 var key = portal.key; 9208 var child = currentFirstChild; 9209 while (child !== null) { 9210 // TODO: If key === null and child.key === null, then this only applies to 9211 // the first item in the list. 9212 if (child.key === key) { 9213 if (child.tag === HostPortal && child.stateNode.containerInfo === portal.containerInfo && child.stateNode.implementation === portal.implementation) { 9214 deleteRemainingChildren(returnFiber, child.sibling); 9215 var existing = useFiber(child, portal.children || [], expirationTime); 9216 existing.return = returnFiber; 9217 return existing; 9218 } else { 9219 deleteRemainingChildren(returnFiber, child); 9220 break; 9221 } 9222 } else { 9223 deleteChild(returnFiber, child); 9224 } 9225 child = child.sibling; 9226 } 9227 9228 var created = createFiberFromPortal(portal, returnFiber.mode, expirationTime); 9229 created.return = returnFiber; 9230 return created; 9231 } 9232 9233 // This API will tag the children with the side-effect of the reconciliation 9234 // itself. They will be added to the side-effect list as we pass through the 9235 // children and the parent. 9236 function reconcileChildFibers(returnFiber, currentFirstChild, newChild, expirationTime) { 9237 // This function is not recursive. 9238 // If the top level item is an array, we treat it as a set of children, 9239 // not as a fragment. Nested arrays on the other hand will be treated as 9240 // fragment nodes. Recursion happens at the normal flow. 9241 9242 // Handle top level unkeyed fragments as if they were arrays. 9243 // This leads to an ambiguity between <>{[...]}</> and <>...</>. 9244 // We treat the ambiguous cases above the same. 9245 var isUnkeyedTopLevelFragment = typeof newChild === 'object' && newChild !== null && newChild.type === REACT_FRAGMENT_TYPE && newChild.key === null; 9246 if (isUnkeyedTopLevelFragment) { 9247 newChild = newChild.props.children; 9248 } 9249 9250 // Handle object types 9251 var isObject = typeof newChild === 'object' && newChild !== null; 9252 9253 if (isObject) { 9254 switch (newChild.$$typeof) { 9255 case REACT_ELEMENT_TYPE: 9256 return placeSingleChild(reconcileSingleElement(returnFiber, currentFirstChild, newChild, expirationTime)); 9257 case REACT_PORTAL_TYPE: 9258 return placeSingleChild(reconcileSinglePortal(returnFiber, currentFirstChild, newChild, expirationTime)); 9259 } 9260 } 9261 9262 if (typeof newChild === 'string' || typeof newChild === 'number') { 9263 return placeSingleChild(reconcileSingleTextNode(returnFiber, currentFirstChild, '' + newChild, expirationTime)); 9264 } 9265 9266 if (isArray(newChild)) { 9267 return reconcileChildrenArray(returnFiber, currentFirstChild, newChild, expirationTime); 9268 } 9269 9270 if (getIteratorFn(newChild)) { 9271 return reconcileChildrenIterator(returnFiber, currentFirstChild, newChild, expirationTime); 9272 } 9273 9274 if (isObject) { 9275 throwOnInvalidObjectType(returnFiber, newChild); 9276 } 9277 9278 if (typeof newChild === 'undefined' && !isUnkeyedTopLevelFragment) { 9279 // If the new child is undefined, and the return fiber is a composite 9280 // component, throw an error. If Fiber return types are disabled, 9281 // we already threw above. 9282 switch (returnFiber.tag) { 9283 case ClassComponent: 9284 { 9285 9286 } 9287 // Intentionally fall through to the next case, which handles both 9288 // functions and classes 9289 // eslint-disable-next-lined no-fallthrough 9290 case FunctionComponent: 9291 { 9292 var Component = returnFiber.type; 9293 reactProdInvariant('152', Component.displayName || Component.name || 'Component'); 9294 } 9295 } 9296 } 9297 9298 // Remaining cases are all treated as empty. 9299 return deleteRemainingChildren(returnFiber, currentFirstChild); 9300 } 9301 9302 return reconcileChildFibers; 9303 } 9304 9305 var reconcileChildFibers = ChildReconciler(true); 9306 var mountChildFibers = ChildReconciler(false); 9307 9308 function cloneChildFibers(current$$1, workInProgress) { 9309 !(current$$1 === null || workInProgress.child === current$$1.child) ? reactProdInvariant('153') : void 0; 9310 9311 if (workInProgress.child === null) { 9312 return; 9313 } 9314 9315 var currentChild = workInProgress.child; 9316 var newChild = createWorkInProgress(currentChild, currentChild.pendingProps, currentChild.expirationTime); 9317 workInProgress.child = newChild; 9318 9319 newChild.return = workInProgress; 9320 while (currentChild.sibling !== null) { 9321 currentChild = currentChild.sibling; 9322 newChild = newChild.sibling = createWorkInProgress(currentChild, currentChild.pendingProps, currentChild.expirationTime); 9323 newChild.return = workInProgress; 9324 } 9325 newChild.sibling = null; 9326 } 9327 9328 var NO_CONTEXT = {}; 9329 9330 var contextStackCursor$1 = createCursor(NO_CONTEXT); 9331 var contextFiberStackCursor = createCursor(NO_CONTEXT); 9332 var rootInstanceStackCursor = createCursor(NO_CONTEXT); 9333 9334 function requiredContext(c) { 9335 !(c !== NO_CONTEXT) ? reactProdInvariant('174') : void 0; 9336 return c; 9337 } 9338 9339 function getRootHostContainer() { 9340 var rootInstance = requiredContext(rootInstanceStackCursor.current); 9341 return rootInstance; 9342 } 9343 9344 function pushHostContainer(fiber, nextRootInstance) { 9345 // Push current root instance onto the stack; 9346 // This allows us to reset root when portals are popped. 9347 push(rootInstanceStackCursor, nextRootInstance, fiber); 9348 // Track the context and the Fiber that provided it. 9349 // This enables us to pop only Fibers that provide unique contexts. 9350 push(contextFiberStackCursor, fiber, fiber); 9351 9352 // Finally, we need to push the host context to the stack. 9353 // However, we can't just call getRootHostContext() and push it because 9354 // we'd have a different number of entries on the stack depending on 9355 // whether getRootHostContext() throws somewhere in renderer code or not. 9356 // So we push an empty value first. This lets us safely unwind on errors. 9357 push(contextStackCursor$1, NO_CONTEXT, fiber); 9358 var nextRootContext = getRootHostContext(nextRootInstance); 9359 // Now that we know this function doesn't throw, replace it. 9360 pop(contextStackCursor$1, fiber); 9361 push(contextStackCursor$1, nextRootContext, fiber); 9362 } 9363 9364 function popHostContainer(fiber) { 9365 pop(contextStackCursor$1, fiber); 9366 pop(contextFiberStackCursor, fiber); 9367 pop(rootInstanceStackCursor, fiber); 9368 } 9369 9370 function getHostContext() { 9371 var context = requiredContext(contextStackCursor$1.current); 9372 return context; 9373 } 9374 9375 function pushHostContext(fiber) { 9376 var rootInstance = requiredContext(rootInstanceStackCursor.current); 9377 var context = requiredContext(contextStackCursor$1.current); 9378 var nextContext = getChildHostContext(context, fiber.type, rootInstance); 9379 9380 // Don't push this Fiber's context unless it's unique. 9381 if (context === nextContext) { 9382 return; 9383 } 9384 9385 // Track the context and the Fiber that provided it. 9386 // This enables us to pop only Fibers that provide unique contexts. 9387 push(contextFiberStackCursor, fiber, fiber); 9388 push(contextStackCursor$1, nextContext, fiber); 9389 } 9390 9391 function popHostContext(fiber) { 9392 // Do not pop unless this Fiber provided the current context. 9393 // pushHostContext() only pushes Fibers that provide unique contexts. 9394 if (contextFiberStackCursor.current !== fiber) { 9395 return; 9396 } 9397 9398 pop(contextStackCursor$1, fiber); 9399 pop(contextFiberStackCursor, fiber); 9400 } 9401 9402 var NoEffect$1 = /* */0; 9403 var UnmountSnapshot = /* */2; 9404 var UnmountMutation = /* */4; 9405 var MountMutation = /* */8; 9406 var UnmountLayout = /* */16; 9407 var MountLayout = /* */32; 9408 var MountPassive = /* */64; 9409 var UnmountPassive = /* */128; 9410 9411 var ReactCurrentDispatcher$1 = ReactSharedInternals.ReactCurrentDispatcher; 9412 9413 9414 // These are set right before calling the component. 9415 var renderExpirationTime = NoWork; 9416 // The work-in-progress fiber. I've named it differently to distinguish it from 9417 // the work-in-progress hook. 9418 var currentlyRenderingFiber$1 = null; 9419 9420 // Hooks are stored as a linked list on the fiber's memoizedState field. The 9421 // current hook list is the list that belongs to the current fiber. The 9422 // work-in-progress hook list is a new list that will be added to the 9423 // work-in-progress fiber. 9424 var currentHook = null; 9425 var nextCurrentHook = null; 9426 var firstWorkInProgressHook = null; 9427 var workInProgressHook = null; 9428 var nextWorkInProgressHook = null; 9429 9430 var remainingExpirationTime = NoWork; 9431 var componentUpdateQueue = null; 9432 var sideEffectTag = 0; 9433 9434 // Updates scheduled during render will trigger an immediate re-render at the 9435 // end of the current pass. We can't store these updates on the normal queue, 9436 // because if the work is aborted, they should be discarded. Because this is 9437 // a relatively rare case, we also don't want to add an additional field to 9438 // either the hook or queue object types. So we store them in a lazily create 9439 // map of queue -> render-phase updates, which are discarded once the component 9440 // completes without re-rendering. 9441 9442 // Whether an update was scheduled during the currently executing render pass. 9443 var didScheduleRenderPhaseUpdate = false; 9444 // Lazily created map of render-phase updates 9445 var renderPhaseUpdates = null; 9446 // Counter to prevent infinite loops. 9447 var numberOfReRenders = 0; 9448 var RE_RENDER_LIMIT = 25; 9449 9450 function throwInvalidHookError() { 9451 reactProdInvariant('321'); 9452 } 9453 9454 function areHookInputsEqual(nextDeps, prevDeps) { 9455 if (prevDeps === null) { 9456 return false; 9457 } 9458 9459 for (var i = 0; i < prevDeps.length && i < nextDeps.length; i++) { 9460 if (is(nextDeps[i], prevDeps[i])) { 9461 continue; 9462 } 9463 return false; 9464 } 9465 return true; 9466 } 9467 9468 function renderWithHooks(current, workInProgress, Component, props, refOrContext, nextRenderExpirationTime) { 9469 renderExpirationTime = nextRenderExpirationTime; 9470 currentlyRenderingFiber$1 = workInProgress; 9471 nextCurrentHook = current !== null ? current.memoizedState : null; 9472 9473 { 9474 ReactCurrentDispatcher$1.current = nextCurrentHook === null ? HooksDispatcherOnMount : HooksDispatcherOnUpdate; 9475 } 9476 9477 var children = Component(props, refOrContext); 9478 9479 if (didScheduleRenderPhaseUpdate) { 9480 do { 9481 didScheduleRenderPhaseUpdate = false; 9482 numberOfReRenders += 1; 9483 9484 // Start over from the beginning of the list 9485 nextCurrentHook = current !== null ? current.memoizedState : null; 9486 nextWorkInProgressHook = firstWorkInProgressHook; 9487 9488 currentHook = null; 9489 workInProgressHook = null; 9490 componentUpdateQueue = null; 9491 9492 ReactCurrentDispatcher$1.current = HooksDispatcherOnUpdate; 9493 9494 children = Component(props, refOrContext); 9495 } while (didScheduleRenderPhaseUpdate); 9496 9497 renderPhaseUpdates = null; 9498 numberOfReRenders = 0; 9499 } 9500 9501 // We can assume the previous dispatcher is always this one, since we set it 9502 // at the beginning of the render phase and there's no re-entrancy. 9503 ReactCurrentDispatcher$1.current = ContextOnlyDispatcher; 9504 9505 var renderedWork = currentlyRenderingFiber$1; 9506 9507 renderedWork.memoizedState = firstWorkInProgressHook; 9508 renderedWork.expirationTime = remainingExpirationTime; 9509 renderedWork.updateQueue = componentUpdateQueue; 9510 renderedWork.effectTag |= sideEffectTag; 9511 9512 var didRenderTooFewHooks = currentHook !== null && currentHook.next !== null; 9513 9514 renderExpirationTime = NoWork; 9515 currentlyRenderingFiber$1 = null; 9516 9517 currentHook = null; 9518 nextCurrentHook = null; 9519 firstWorkInProgressHook = null; 9520 workInProgressHook = null; 9521 nextWorkInProgressHook = null; 9522 9523 remainingExpirationTime = NoWork; 9524 componentUpdateQueue = null; 9525 sideEffectTag = 0; 9526 9527 // These were reset above 9528 // didScheduleRenderPhaseUpdate = false; 9529 // renderPhaseUpdates = null; 9530 // numberOfReRenders = 0; 9531 9532 !!didRenderTooFewHooks ? reactProdInvariant('300') : void 0; 9533 9534 return children; 9535 } 9536 9537 function bailoutHooks(current, workInProgress, expirationTime) { 9538 workInProgress.updateQueue = current.updateQueue; 9539 workInProgress.effectTag &= ~(Passive | Update); 9540 if (current.expirationTime <= expirationTime) { 9541 current.expirationTime = NoWork; 9542 } 9543 } 9544 9545 function resetHooks() { 9546 // We can assume the previous dispatcher is always this one, since we set it 9547 // at the beginning of the render phase and there's no re-entrancy. 9548 ReactCurrentDispatcher$1.current = ContextOnlyDispatcher; 9549 9550 // This is used to reset the state of this module when a component throws. 9551 // It's also called inside mountIndeterminateComponent if we determine the 9552 // component is a module-style component. 9553 renderExpirationTime = NoWork; 9554 currentlyRenderingFiber$1 = null; 9555 9556 currentHook = null; 9557 nextCurrentHook = null; 9558 firstWorkInProgressHook = null; 9559 workInProgressHook = null; 9560 nextWorkInProgressHook = null; 9561 9562 remainingExpirationTime = NoWork; 9563 componentUpdateQueue = null; 9564 sideEffectTag = 0; 9565 9566 didScheduleRenderPhaseUpdate = false; 9567 renderPhaseUpdates = null; 9568 numberOfReRenders = 0; 9569 } 9570 9571 function mountWorkInProgressHook() { 9572 var hook = { 9573 memoizedState: null, 9574 9575 baseState: null, 9576 queue: null, 9577 baseUpdate: null, 9578 9579 next: null 9580 }; 9581 9582 if (workInProgressHook === null) { 9583 // This is the first hook in the list 9584 firstWorkInProgressHook = workInProgressHook = hook; 9585 } else { 9586 // Append to the end of the list 9587 workInProgressHook = workInProgressHook.next = hook; 9588 } 9589 return workInProgressHook; 9590 } 9591 9592 function updateWorkInProgressHook() { 9593 // This function is used both for updates and for re-renders triggered by a 9594 // render phase update. It assumes there is either a current hook we can 9595 // clone, or a work-in-progress hook from a previous render pass that we can 9596 // use as a base. When we reach the end of the base list, we must switch to 9597 // the dispatcher used for mounts. 9598 if (nextWorkInProgressHook !== null) { 9599 // There's already a work-in-progress. Reuse it. 9600 workInProgressHook = nextWorkInProgressHook; 9601 nextWorkInProgressHook = workInProgressHook.next; 9602 9603 currentHook = nextCurrentHook; 9604 nextCurrentHook = currentHook !== null ? currentHook.next : null; 9605 } else { 9606 // Clone from the current hook. 9607 !(nextCurrentHook !== null) ? reactProdInvariant('310') : void 0; 9608 currentHook = nextCurrentHook; 9609 9610 var newHook = { 9611 memoizedState: currentHook.memoizedState, 9612 9613 baseState: currentHook.baseState, 9614 queue: currentHook.queue, 9615 baseUpdate: currentHook.baseUpdate, 9616 9617 next: null 9618 }; 9619 9620 if (workInProgressHook === null) { 9621 // This is the first hook in the list. 9622 workInProgressHook = firstWorkInProgressHook = newHook; 9623 } else { 9624 // Append to the end of the list. 9625 workInProgressHook = workInProgressHook.next = newHook; 9626 } 9627 nextCurrentHook = currentHook.next; 9628 } 9629 return workInProgressHook; 9630 } 9631 9632 function createFunctionComponentUpdateQueue() { 9633 return { 9634 lastEffect: null 9635 }; 9636 } 9637 9638 function basicStateReducer(state, action) { 9639 return typeof action === 'function' ? action(state) : action; 9640 } 9641 9642 function mountReducer(reducer, initialArg, init) { 9643 var hook = mountWorkInProgressHook(); 9644 var initialState = void 0; 9645 if (init !== undefined) { 9646 initialState = init(initialArg); 9647 } else { 9648 initialState = initialArg; 9649 } 9650 hook.memoizedState = hook.baseState = initialState; 9651 var queue = hook.queue = { 9652 last: null, 9653 dispatch: null, 9654 lastRenderedReducer: reducer, 9655 lastRenderedState: initialState 9656 }; 9657 var dispatch = queue.dispatch = dispatchAction.bind(null, 9658 // Flow doesn't know this is non-null, but we do. 9659 currentlyRenderingFiber$1, queue); 9660 return [hook.memoizedState, dispatch]; 9661 } 9662 9663 function updateReducer(reducer, initialArg, init) { 9664 var hook = updateWorkInProgressHook(); 9665 var queue = hook.queue; 9666 !(queue !== null) ? reactProdInvariant('311') : void 0; 9667 9668 queue.lastRenderedReducer = reducer; 9669 9670 if (numberOfReRenders > 0) { 9671 // This is a re-render. Apply the new render phase updates to the previous 9672 var _dispatch = queue.dispatch; 9673 if (renderPhaseUpdates !== null) { 9674 // Render phase updates are stored in a map of queue -> linked list 9675 var firstRenderPhaseUpdate = renderPhaseUpdates.get(queue); 9676 if (firstRenderPhaseUpdate !== undefined) { 9677 renderPhaseUpdates.delete(queue); 9678 var newState = hook.memoizedState; 9679 var update = firstRenderPhaseUpdate; 9680 do { 9681 // Process this render phase update. We don't have to check the 9682 // priority because it will always be the same as the current 9683 // render's. 9684 var _action = update.action; 9685 newState = reducer(newState, _action); 9686 update = update.next; 9687 } while (update !== null); 9688 9689 // Mark that the fiber performed work, but only if the new state is 9690 // different from the current state. 9691 if (!is(newState, hook.memoizedState)) { 9692 markWorkInProgressReceivedUpdate(); 9693 } 9694 9695 hook.memoizedState = newState; 9696 // Don't persist the state accumlated from the render phase updates to 9697 // the base state unless the queue is empty. 9698 // TODO: Not sure if this is the desired semantics, but it's what we 9699 // do for gDSFP. I can't remember why. 9700 if (hook.baseUpdate === queue.last) { 9701 hook.baseState = newState; 9702 } 9703 9704 queue.lastRenderedState = newState; 9705 9706 return [newState, _dispatch]; 9707 } 9708 } 9709 return [hook.memoizedState, _dispatch]; 9710 } 9711 9712 // The last update in the entire queue 9713 var last = queue.last; 9714 // The last update that is part of the base state. 9715 var baseUpdate = hook.baseUpdate; 9716 var baseState = hook.baseState; 9717 9718 // Find the first unprocessed update. 9719 var first = void 0; 9720 if (baseUpdate !== null) { 9721 if (last !== null) { 9722 // For the first update, the queue is a circular linked list where 9723 // `queue.last.next = queue.first`. Once the first update commits, and 9724 // the `baseUpdate` is no longer empty, we can unravel the list. 9725 last.next = null; 9726 } 9727 first = baseUpdate.next; 9728 } else { 9729 first = last !== null ? last.next : null; 9730 } 9731 if (first !== null) { 9732 var _newState = baseState; 9733 var newBaseState = null; 9734 var newBaseUpdate = null; 9735 var prevUpdate = baseUpdate; 9736 var _update = first; 9737 var didSkip = false; 9738 do { 9739 var updateExpirationTime = _update.expirationTime; 9740 if (updateExpirationTime < renderExpirationTime) { 9741 // Priority is insufficient. Skip this update. If this is the first 9742 // skipped update, the previous update/state is the new base 9743 // update/state. 9744 if (!didSkip) { 9745 didSkip = true; 9746 newBaseUpdate = prevUpdate; 9747 newBaseState = _newState; 9748 } 9749 // Update the remaining priority in the queue. 9750 if (updateExpirationTime > remainingExpirationTime) { 9751 remainingExpirationTime = updateExpirationTime; 9752 } 9753 } else { 9754 // Process this update. 9755 if (_update.eagerReducer === reducer) { 9756 // If this update was processed eagerly, and its reducer matches the 9757 // current reducer, we can use the eagerly computed state. 9758 _newState = _update.eagerState; 9759 } else { 9760 var _action2 = _update.action; 9761 _newState = reducer(_newState, _action2); 9762 } 9763 } 9764 prevUpdate = _update; 9765 _update = _update.next; 9766 } while (_update !== null && _update !== first); 9767 9768 if (!didSkip) { 9769 newBaseUpdate = prevUpdate; 9770 newBaseState = _newState; 9771 } 9772 9773 // Mark that the fiber performed work, but only if the new state is 9774 // different from the current state. 9775 if (!is(_newState, hook.memoizedState)) { 9776 markWorkInProgressReceivedUpdate(); 9777 } 9778 9779 hook.memoizedState = _newState; 9780 hook.baseUpdate = newBaseUpdate; 9781 hook.baseState = newBaseState; 9782 9783 queue.lastRenderedState = _newState; 9784 } 9785 9786 var dispatch = queue.dispatch; 9787 return [hook.memoizedState, dispatch]; 9788 } 9789 9790 function mountState(initialState) { 9791 var hook = mountWorkInProgressHook(); 9792 if (typeof initialState === 'function') { 9793 initialState = initialState(); 9794 } 9795 hook.memoizedState = hook.baseState = initialState; 9796 var queue = hook.queue = { 9797 last: null, 9798 dispatch: null, 9799 lastRenderedReducer: basicStateReducer, 9800 lastRenderedState: initialState 9801 }; 9802 var dispatch = queue.dispatch = dispatchAction.bind(null, 9803 // Flow doesn't know this is non-null, but we do. 9804 currentlyRenderingFiber$1, queue); 9805 return [hook.memoizedState, dispatch]; 9806 } 9807 9808 function updateState(initialState) { 9809 return updateReducer(basicStateReducer, initialState); 9810 } 9811 9812 function pushEffect(tag, create, destroy, deps) { 9813 var effect = { 9814 tag: tag, 9815 create: create, 9816 destroy: destroy, 9817 deps: deps, 9818 // Circular 9819 next: null 9820 }; 9821 if (componentUpdateQueue === null) { 9822 componentUpdateQueue = createFunctionComponentUpdateQueue(); 9823 componentUpdateQueue.lastEffect = effect.next = effect; 9824 } else { 9825 var _lastEffect = componentUpdateQueue.lastEffect; 9826 if (_lastEffect === null) { 9827 componentUpdateQueue.lastEffect = effect.next = effect; 9828 } else { 9829 var firstEffect = _lastEffect.next; 9830 _lastEffect.next = effect; 9831 effect.next = firstEffect; 9832 componentUpdateQueue.lastEffect = effect; 9833 } 9834 } 9835 return effect; 9836 } 9837 9838 function mountRef(initialValue) { 9839 var hook = mountWorkInProgressHook(); 9840 var ref = { current: initialValue }; 9841 hook.memoizedState = ref; 9842 return ref; 9843 } 9844 9845 function updateRef(initialValue) { 9846 var hook = updateWorkInProgressHook(); 9847 return hook.memoizedState; 9848 } 9849 9850 function mountEffectImpl(fiberEffectTag, hookEffectTag, create, deps) { 9851 var hook = mountWorkInProgressHook(); 9852 var nextDeps = deps === undefined ? null : deps; 9853 sideEffectTag |= fiberEffectTag; 9854 hook.memoizedState = pushEffect(hookEffectTag, create, undefined, nextDeps); 9855 } 9856 9857 function updateEffectImpl(fiberEffectTag, hookEffectTag, create, deps) { 9858 var hook = updateWorkInProgressHook(); 9859 var nextDeps = deps === undefined ? null : deps; 9860 var destroy = undefined; 9861 9862 if (currentHook !== null) { 9863 var prevEffect = currentHook.memoizedState; 9864 destroy = prevEffect.destroy; 9865 if (nextDeps !== null) { 9866 var prevDeps = prevEffect.deps; 9867 if (areHookInputsEqual(nextDeps, prevDeps)) { 9868 pushEffect(NoEffect$1, create, destroy, nextDeps); 9869 return; 9870 } 9871 } 9872 } 9873 9874 sideEffectTag |= fiberEffectTag; 9875 hook.memoizedState = pushEffect(hookEffectTag, create, destroy, nextDeps); 9876 } 9877 9878 function mountEffect(create, deps) { 9879 return mountEffectImpl(Update | Passive, UnmountPassive | MountPassive, create, deps); 9880 } 9881 9882 function updateEffect(create, deps) { 9883 return updateEffectImpl(Update | Passive, UnmountPassive | MountPassive, create, deps); 9884 } 9885 9886 function mountLayoutEffect(create, deps) { 9887 return mountEffectImpl(Update, UnmountMutation | MountLayout, create, deps); 9888 } 9889 9890 function updateLayoutEffect(create, deps) { 9891 return updateEffectImpl(Update, UnmountMutation | MountLayout, create, deps); 9892 } 9893 9894 function imperativeHandleEffect(create, ref) { 9895 if (typeof ref === 'function') { 9896 var refCallback = ref; 9897 var _inst = create(); 9898 refCallback(_inst); 9899 return function () { 9900 refCallback(null); 9901 }; 9902 } else if (ref !== null && ref !== undefined) { 9903 var refObject = ref; 9904 var _inst2 = create(); 9905 refObject.current = _inst2; 9906 return function () { 9907 refObject.current = null; 9908 }; 9909 } 9910 } 9911 9912 function mountImperativeHandle(ref, create, deps) { 9913 var effectDeps = deps !== null && deps !== undefined ? deps.concat([ref]) : null; 9914 9915 return mountEffectImpl(Update, UnmountMutation | MountLayout, imperativeHandleEffect.bind(null, create, ref), effectDeps); 9916 } 9917 9918 function updateImperativeHandle(ref, create, deps) { 9919 var effectDeps = deps !== null && deps !== undefined ? deps.concat([ref]) : null; 9920 9921 return updateEffectImpl(Update, UnmountMutation | MountLayout, imperativeHandleEffect.bind(null, create, ref), effectDeps); 9922 } 9923 9924 function mountDebugValue(value, formatterFn) { 9925 // This hook is normally a no-op. 9926 // The react-debug-hooks package injects its own implementation 9927 // so that e.g. DevTools can display custom hook values. 9928 } 9929 9930 var updateDebugValue = mountDebugValue; 9931 9932 function mountCallback(callback, deps) { 9933 var hook = mountWorkInProgressHook(); 9934 var nextDeps = deps === undefined ? null : deps; 9935 hook.memoizedState = [callback, nextDeps]; 9936 return callback; 9937 } 9938 9939 function updateCallback(callback, deps) { 9940 var hook = updateWorkInProgressHook(); 9941 var nextDeps = deps === undefined ? null : deps; 9942 var prevState = hook.memoizedState; 9943 if (prevState !== null) { 9944 if (nextDeps !== null) { 9945 var prevDeps = prevState[1]; 9946 if (areHookInputsEqual(nextDeps, prevDeps)) { 9947 return prevState[0]; 9948 } 9949 } 9950 } 9951 hook.memoizedState = [callback, nextDeps]; 9952 return callback; 9953 } 9954 9955 function mountMemo(nextCreate, deps) { 9956 var hook = mountWorkInProgressHook(); 9957 var nextDeps = deps === undefined ? null : deps; 9958 var nextValue = nextCreate(); 9959 hook.memoizedState = [nextValue, nextDeps]; 9960 return nextValue; 9961 } 9962 9963 function updateMemo(nextCreate, deps) { 9964 var hook = updateWorkInProgressHook(); 9965 var nextDeps = deps === undefined ? null : deps; 9966 var prevState = hook.memoizedState; 9967 if (prevState !== null) { 9968 // Assume these are defined. If they're not, areHookInputsEqual will warn. 9969 if (nextDeps !== null) { 9970 var prevDeps = prevState[1]; 9971 if (areHookInputsEqual(nextDeps, prevDeps)) { 9972 return prevState[0]; 9973 } 9974 } 9975 } 9976 var nextValue = nextCreate(); 9977 hook.memoizedState = [nextValue, nextDeps]; 9978 return nextValue; 9979 } 9980 9981 function dispatchAction(fiber, queue, action) { 9982 !(numberOfReRenders < RE_RENDER_LIMIT) ? reactProdInvariant('301') : void 0; 9983 9984 var alternate = fiber.alternate; 9985 if (fiber === currentlyRenderingFiber$1 || alternate !== null && alternate === currentlyRenderingFiber$1) { 9986 // This is a render phase update. Stash it in a lazily-created map of 9987 // queue -> linked list of updates. After this render pass, we'll restart 9988 // and apply the stashed updates on top of the work-in-progress hook. 9989 didScheduleRenderPhaseUpdate = true; 9990 var update = { 9991 expirationTime: renderExpirationTime, 9992 action: action, 9993 eagerReducer: null, 9994 eagerState: null, 9995 next: null 9996 }; 9997 if (renderPhaseUpdates === null) { 9998 renderPhaseUpdates = new Map(); 9999 } 10000 var firstRenderPhaseUpdate = renderPhaseUpdates.get(queue); 10001 if (firstRenderPhaseUpdate === undefined) { 10002 renderPhaseUpdates.set(queue, update); 10003 } else { 10004 // Append the update to the end of the list. 10005 var lastRenderPhaseUpdate = firstRenderPhaseUpdate; 10006 while (lastRenderPhaseUpdate.next !== null) { 10007 lastRenderPhaseUpdate = lastRenderPhaseUpdate.next; 10008 } 10009 lastRenderPhaseUpdate.next = update; 10010 } 10011 } else { 10012 flushPassiveEffects(); 10013 10014 var currentTime = requestCurrentTime(); 10015 var _expirationTime = computeExpirationForFiber(currentTime, fiber); 10016 10017 var _update2 = { 10018 expirationTime: _expirationTime, 10019 action: action, 10020 eagerReducer: null, 10021 eagerState: null, 10022 next: null 10023 }; 10024 10025 // Append the update to the end of the list. 10026 var _last = queue.last; 10027 if (_last === null) { 10028 // This is the first update. Create a circular list. 10029 _update2.next = _update2; 10030 } else { 10031 var first = _last.next; 10032 if (first !== null) { 10033 // Still circular. 10034 _update2.next = first; 10035 } 10036 _last.next = _update2; 10037 } 10038 queue.last = _update2; 10039 10040 if (fiber.expirationTime === NoWork && (alternate === null || alternate.expirationTime === NoWork)) { 10041 // The queue is currently empty, which means we can eagerly compute the 10042 // next state before entering the render phase. If the new state is the 10043 // same as the current state, we may be able to bail out entirely. 10044 var _lastRenderedReducer = queue.lastRenderedReducer; 10045 if (_lastRenderedReducer !== null) { 10046 try { 10047 var currentState = queue.lastRenderedState; 10048 var _eagerState = _lastRenderedReducer(currentState, action); 10049 // Stash the eagerly computed state, and the reducer used to compute 10050 // it, on the update object. If the reducer hasn't changed by the 10051 // time we enter the render phase, then the eager state can be used 10052 // without calling the reducer again. 10053 _update2.eagerReducer = _lastRenderedReducer; 10054 _update2.eagerState = _eagerState; 10055 if (is(_eagerState, currentState)) { 10056 // Fast path. We can bail out without scheduling React to re-render. 10057 // It's still possible that we'll need to rebase this update later, 10058 // if the component re-renders for a different reason and by that 10059 // time the reducer has changed. 10060 return; 10061 } 10062 } catch (error) { 10063 // Suppress the error. It will throw again in the render phase. 10064 } finally { 10065 10066 } 10067 } 10068 } 10069 scheduleWork(fiber, _expirationTime); 10070 } 10071 } 10072 10073 var ContextOnlyDispatcher = { 10074 readContext: readContext, 10075 10076 useCallback: throwInvalidHookError, 10077 useContext: throwInvalidHookError, 10078 useEffect: throwInvalidHookError, 10079 useImperativeHandle: throwInvalidHookError, 10080 useLayoutEffect: throwInvalidHookError, 10081 useMemo: throwInvalidHookError, 10082 useReducer: throwInvalidHookError, 10083 useRef: throwInvalidHookError, 10084 useState: throwInvalidHookError, 10085 useDebugValue: throwInvalidHookError 10086 }; 10087 10088 var HooksDispatcherOnMount = { 10089 readContext: readContext, 10090 10091 useCallback: mountCallback, 10092 useContext: readContext, 10093 useEffect: mountEffect, 10094 useImperativeHandle: mountImperativeHandle, 10095 useLayoutEffect: mountLayoutEffect, 10096 useMemo: mountMemo, 10097 useReducer: mountReducer, 10098 useRef: mountRef, 10099 useState: mountState, 10100 useDebugValue: mountDebugValue 10101 }; 10102 10103 var HooksDispatcherOnUpdate = { 10104 readContext: readContext, 10105 10106 useCallback: updateCallback, 10107 useContext: readContext, 10108 useEffect: updateEffect, 10109 useImperativeHandle: updateImperativeHandle, 10110 useLayoutEffect: updateLayoutEffect, 10111 useMemo: updateMemo, 10112 useReducer: updateReducer, 10113 useRef: updateRef, 10114 useState: updateState, 10115 useDebugValue: updateDebugValue 10116 }; 10117 10118 var commitTime = 0; 10119 var profilerStartTime = -1; 10120 10121 function getCommitTime() { 10122 return commitTime; 10123 } 10124 10125 function recordCommitTime() { 10126 if (!enableProfilerTimer) { 10127 return; 10128 } 10129 commitTime = unstable_now(); 10130 } 10131 10132 function startProfilerTimer(fiber) { 10133 if (!enableProfilerTimer) { 10134 return; 10135 } 10136 10137 profilerStartTime = unstable_now(); 10138 10139 if (fiber.actualStartTime < 0) { 10140 fiber.actualStartTime = unstable_now(); 10141 } 10142 } 10143 10144 function stopProfilerTimerIfRunning(fiber) { 10145 if (!enableProfilerTimer) { 10146 return; 10147 } 10148 profilerStartTime = -1; 10149 } 10150 10151 function stopProfilerTimerIfRunningAndRecordDelta(fiber, overrideBaseTime) { 10152 if (!enableProfilerTimer) { 10153 return; 10154 } 10155 10156 if (profilerStartTime >= 0) { 10157 var elapsedTime = unstable_now() - profilerStartTime; 10158 fiber.actualDuration += elapsedTime; 10159 if (overrideBaseTime) { 10160 fiber.selfBaseDuration = elapsedTime; 10161 } 10162 profilerStartTime = -1; 10163 } 10164 } 10165 10166 // The deepest Fiber on the stack involved in a hydration context. 10167 // This may have been an insertion or a hydration. 10168 var hydrationParentFiber = null; 10169 var nextHydratableInstance = null; 10170 var isHydrating = false; 10171 10172 function enterHydrationState(fiber) { 10173 if (!supportsHydration) { 10174 return false; 10175 } 10176 10177 var parentInstance = fiber.stateNode.containerInfo; 10178 nextHydratableInstance = getFirstHydratableChild(parentInstance); 10179 hydrationParentFiber = fiber; 10180 isHydrating = true; 10181 return true; 10182 } 10183 10184 function reenterHydrationStateFromDehydratedSuspenseInstance(fiber) { 10185 if (!supportsHydration) { 10186 return false; 10187 } 10188 10189 var suspenseInstance = fiber.stateNode; 10190 nextHydratableInstance = getNextHydratableSibling(suspenseInstance); 10191 popToNextHostParent(fiber); 10192 isHydrating = true; 10193 return true; 10194 } 10195 10196 function deleteHydratableInstance(returnFiber, instance) { 10197 var childToDelete = createFiberFromHostInstanceForDeletion(); 10198 childToDelete.stateNode = instance; 10199 childToDelete.return = returnFiber; 10200 childToDelete.effectTag = Deletion; 10201 10202 // This might seem like it belongs on progressedFirstDeletion. However, 10203 // these children are not part of the reconciliation list of children. 10204 // Even if we abort and rereconcile the children, that will try to hydrate 10205 // again and the nodes are still in the host tree so these will be 10206 // recreated. 10207 if (returnFiber.lastEffect !== null) { 10208 returnFiber.lastEffect.nextEffect = childToDelete; 10209 returnFiber.lastEffect = childToDelete; 10210 } else { 10211 returnFiber.firstEffect = returnFiber.lastEffect = childToDelete; 10212 } 10213 } 10214 10215 function insertNonHydratedInstance(returnFiber, fiber) { 10216 fiber.effectTag |= Placement; 10217 10218 } 10219 10220 function tryHydrate(fiber, nextInstance) { 10221 switch (fiber.tag) { 10222 case HostComponent: 10223 { 10224 var type = fiber.type; 10225 var props = fiber.pendingProps; 10226 var instance = canHydrateInstance(nextInstance, type, props); 10227 if (instance !== null) { 10228 fiber.stateNode = instance; 10229 return true; 10230 } 10231 return false; 10232 } 10233 case HostText: 10234 { 10235 var text = fiber.pendingProps; 10236 var textInstance = canHydrateTextInstance(nextInstance, text); 10237 if (textInstance !== null) { 10238 fiber.stateNode = textInstance; 10239 return true; 10240 } 10241 return false; 10242 } 10243 case SuspenseComponent: 10244 { 10245 if (enableSuspenseServerRenderer) { 10246 var suspenseInstance = canHydrateSuspenseInstance(nextInstance); 10247 if (suspenseInstance !== null) { 10248 // Downgrade the tag to a dehydrated component until we've hydrated it. 10249 fiber.tag = DehydratedSuspenseComponent; 10250 fiber.stateNode = suspenseInstance; 10251 return true; 10252 } 10253 } 10254 return false; 10255 } 10256 default: 10257 return false; 10258 } 10259 } 10260 10261 function tryToClaimNextHydratableInstance(fiber) { 10262 if (!isHydrating) { 10263 return; 10264 } 10265 var nextInstance = nextHydratableInstance; 10266 if (!nextInstance) { 10267 // Nothing to hydrate. Make it an insertion. 10268 insertNonHydratedInstance(hydrationParentFiber, fiber); 10269 isHydrating = false; 10270 hydrationParentFiber = fiber; 10271 return; 10272 } 10273 var firstAttemptedInstance = nextInstance; 10274 if (!tryHydrate(fiber, nextInstance)) { 10275 // If we can't hydrate this instance let's try the next one. 10276 // We use this as a heuristic. It's based on intuition and not data so it 10277 // might be flawed or unnecessary. 10278 nextInstance = getNextHydratableSibling(firstAttemptedInstance); 10279 if (!nextInstance || !tryHydrate(fiber, nextInstance)) { 10280 // Nothing to hydrate. Make it an insertion. 10281 insertNonHydratedInstance(hydrationParentFiber, fiber); 10282 isHydrating = false; 10283 hydrationParentFiber = fiber; 10284 return; 10285 } 10286 // We matched the next one, we'll now assume that the first one was 10287 // superfluous and we'll delete it. Since we can't eagerly delete it 10288 // we'll have to schedule a deletion. To do that, this node needs a dummy 10289 // fiber associated with it. 10290 deleteHydratableInstance(hydrationParentFiber, firstAttemptedInstance); 10291 } 10292 hydrationParentFiber = fiber; 10293 nextHydratableInstance = getFirstHydratableChild(nextInstance); 10294 } 10295 10296 function prepareToHydrateHostInstance(fiber, rootContainerInstance, hostContext) { 10297 if (!supportsHydration) { 10298 reactProdInvariant('175'); 10299 } 10300 10301 var instance = fiber.stateNode; 10302 var updatePayload = hydrateInstance(instance, fiber.type, fiber.memoizedProps, rootContainerInstance, hostContext, fiber); 10303 // TODO: Type this specific to this type of component. 10304 fiber.updateQueue = updatePayload; 10305 // If the update payload indicates that there is a change or if there 10306 // is a new ref we mark this as an update. 10307 if (updatePayload !== null) { 10308 return true; 10309 } 10310 return false; 10311 } 10312 10313 function prepareToHydrateHostTextInstance(fiber) { 10314 if (!supportsHydration) { 10315 reactProdInvariant('176'); 10316 } 10317 10318 var textInstance = fiber.stateNode; 10319 var textContent = fiber.memoizedProps; 10320 var shouldUpdate = hydrateTextInstance(textInstance, textContent, fiber); 10321 return shouldUpdate; 10322 } 10323 10324 function skipPastDehydratedSuspenseInstance(fiber) { 10325 if (!supportsHydration) { 10326 reactProdInvariant('316'); 10327 } 10328 var suspenseInstance = fiber.stateNode; 10329 !suspenseInstance ? reactProdInvariant('317') : void 0; 10330 nextHydratableInstance = getNextHydratableInstanceAfterSuspenseInstance(suspenseInstance); 10331 } 10332 10333 function popToNextHostParent(fiber) { 10334 var parent = fiber.return; 10335 while (parent !== null && parent.tag !== HostComponent && parent.tag !== HostRoot && parent.tag !== DehydratedSuspenseComponent) { 10336 parent = parent.return; 10337 } 10338 hydrationParentFiber = parent; 10339 } 10340 10341 function popHydrationState(fiber) { 10342 if (!supportsHydration) { 10343 return false; 10344 } 10345 if (fiber !== hydrationParentFiber) { 10346 // We're deeper than the current hydration context, inside an inserted 10347 // tree. 10348 return false; 10349 } 10350 if (!isHydrating) { 10351 // If we're not currently hydrating but we're in a hydration context, then 10352 // we were an insertion and now need to pop up reenter hydration of our 10353 // siblings. 10354 popToNextHostParent(fiber); 10355 isHydrating = true; 10356 return false; 10357 } 10358 10359 var type = fiber.type; 10360 10361 // If we have any remaining hydratable nodes, we need to delete them now. 10362 // We only do this deeper than head and body since they tend to have random 10363 // other nodes in them. We also ignore components with pure text content in 10364 // side of them. 10365 // TODO: Better heuristic. 10366 if (fiber.tag !== HostComponent || type !== 'head' && type !== 'body' && !shouldSetTextContent(type, fiber.memoizedProps)) { 10367 var nextInstance = nextHydratableInstance; 10368 while (nextInstance) { 10369 deleteHydratableInstance(fiber, nextInstance); 10370 nextInstance = getNextHydratableSibling(nextInstance); 10371 } 10372 } 10373 10374 popToNextHostParent(fiber); 10375 nextHydratableInstance = hydrationParentFiber ? getNextHydratableSibling(fiber.stateNode) : null; 10376 return true; 10377 } 10378 10379 function resetHydrationState() { 10380 if (!supportsHydration) { 10381 return; 10382 } 10383 10384 hydrationParentFiber = null; 10385 nextHydratableInstance = null; 10386 isHydrating = false; 10387 } 10388 10389 var ReactCurrentOwner$3 = ReactSharedInternals.ReactCurrentOwner; 10390 10391 var didReceiveUpdate = false; 10392 10393 10394 10395 function reconcileChildren(current$$1, workInProgress, nextChildren, renderExpirationTime) { 10396 if (current$$1 === null) { 10397 // If this is a fresh new component that hasn't been rendered yet, we 10398 // won't update its child set by applying minimal side-effects. Instead, 10399 // we will add them all to the child before it gets rendered. That means 10400 // we can optimize this reconciliation pass by not tracking side-effects. 10401 workInProgress.child = mountChildFibers(workInProgress, null, nextChildren, renderExpirationTime); 10402 } else { 10403 // If the current child is the same as the work in progress, it means that 10404 // we haven't yet started any work on these children. Therefore, we use 10405 // the clone algorithm to create a copy of all the current children. 10406 10407 // If we had any progressed work already, that is invalid at this point so 10408 // let's throw it out. 10409 workInProgress.child = reconcileChildFibers(workInProgress, current$$1.child, nextChildren, renderExpirationTime); 10410 } 10411 } 10412 10413 function forceUnmountCurrentAndReconcile(current$$1, workInProgress, nextChildren, renderExpirationTime) { 10414 // This function is fork of reconcileChildren. It's used in cases where we 10415 // want to reconcile without matching against the existing set. This has the 10416 // effect of all current children being unmounted; even if the type and key 10417 // are the same, the old child is unmounted and a new child is created. 10418 // 10419 // To do this, we're going to go through the reconcile algorithm twice. In 10420 // the first pass, we schedule a deletion for all the current children by 10421 // passing null. 10422 workInProgress.child = reconcileChildFibers(workInProgress, current$$1.child, null, renderExpirationTime); 10423 // In the second pass, we mount the new children. The trick here is that we 10424 // pass null in place of where we usually pass the current child set. This has 10425 // the effect of remounting all children regardless of whether their their 10426 // identity matches. 10427 workInProgress.child = reconcileChildFibers(workInProgress, null, nextChildren, renderExpirationTime); 10428 } 10429 10430 function updateForwardRef(current$$1, workInProgress, Component, nextProps, renderExpirationTime) { 10431 // TODO: current can be non-null here even if the component 10432 // hasn't yet mounted. This happens after the first render suspends. 10433 // We'll need to figure out if this is fine or can cause issues. 10434 10435 var render = Component.render; 10436 var ref = workInProgress.ref; 10437 10438 // The rest is a fork of updateFunctionComponent 10439 var nextChildren = void 0; 10440 prepareToReadContext(workInProgress, renderExpirationTime); 10441 { 10442 nextChildren = renderWithHooks(current$$1, workInProgress, render, nextProps, ref, renderExpirationTime); 10443 } 10444 10445 if (current$$1 !== null && !didReceiveUpdate) { 10446 bailoutHooks(current$$1, workInProgress, renderExpirationTime); 10447 return bailoutOnAlreadyFinishedWork(current$$1, workInProgress, renderExpirationTime); 10448 } 10449 10450 // React DevTools reads this flag. 10451 workInProgress.effectTag |= PerformedWork; 10452 reconcileChildren(current$$1, workInProgress, nextChildren, renderExpirationTime); 10453 return workInProgress.child; 10454 } 10455 10456 function updateMemoComponent(current$$1, workInProgress, Component, nextProps, updateExpirationTime, renderExpirationTime) { 10457 if (current$$1 === null) { 10458 var type = Component.type; 10459 if (isSimpleFunctionComponent(type) && Component.compare === null && 10460 // SimpleMemoComponent codepath doesn't resolve outer props either. 10461 Component.defaultProps === undefined) { 10462 // If this is a plain function component without default props, 10463 // and with only the default shallow comparison, we upgrade it 10464 // to a SimpleMemoComponent to allow fast path updates. 10465 workInProgress.tag = SimpleMemoComponent; 10466 workInProgress.type = type; 10467 return updateSimpleMemoComponent(current$$1, workInProgress, type, nextProps, updateExpirationTime, renderExpirationTime); 10468 } 10469 var child = createFiberFromTypeAndProps(Component.type, null, nextProps, null, workInProgress.mode, renderExpirationTime); 10470 child.ref = workInProgress.ref; 10471 child.return = workInProgress; 10472 workInProgress.child = child; 10473 return child; 10474 } 10475 var currentChild = current$$1.child; // This is always exactly one child 10476 if (updateExpirationTime < renderExpirationTime) { 10477 // This will be the props with resolved defaultProps, 10478 // unlike current.memoizedProps which will be the unresolved ones. 10479 var prevProps = currentChild.memoizedProps; 10480 // Default to shallow comparison 10481 var compare = Component.compare; 10482 compare = compare !== null ? compare : shallowEqual; 10483 if (compare(prevProps, nextProps) && current$$1.ref === workInProgress.ref) { 10484 return bailoutOnAlreadyFinishedWork(current$$1, workInProgress, renderExpirationTime); 10485 } 10486 } 10487 // React DevTools reads this flag. 10488 workInProgress.effectTag |= PerformedWork; 10489 var newChild = createWorkInProgress(currentChild, nextProps, renderExpirationTime); 10490 newChild.ref = workInProgress.ref; 10491 newChild.return = workInProgress; 10492 workInProgress.child = newChild; 10493 return newChild; 10494 } 10495 10496 function updateSimpleMemoComponent(current$$1, workInProgress, Component, nextProps, updateExpirationTime, renderExpirationTime) { 10497 // TODO: current can be non-null here even if the component 10498 // hasn't yet mounted. This happens when the inner render suspends. 10499 // We'll need to figure out if this is fine or can cause issues. 10500 10501 if (current$$1 !== null) { 10502 var prevProps = current$$1.memoizedProps; 10503 if (shallowEqual(prevProps, nextProps) && current$$1.ref === workInProgress.ref) { 10504 didReceiveUpdate = false; 10505 if (updateExpirationTime < renderExpirationTime) { 10506 return bailoutOnAlreadyFinishedWork(current$$1, workInProgress, renderExpirationTime); 10507 } 10508 } 10509 } 10510 return updateFunctionComponent(current$$1, workInProgress, Component, nextProps, renderExpirationTime); 10511 } 10512 10513 function updateFragment(current$$1, workInProgress, renderExpirationTime) { 10514 var nextChildren = workInProgress.pendingProps; 10515 reconcileChildren(current$$1, workInProgress, nextChildren, renderExpirationTime); 10516 return workInProgress.child; 10517 } 10518 10519 function updateMode(current$$1, workInProgress, renderExpirationTime) { 10520 var nextChildren = workInProgress.pendingProps.children; 10521 reconcileChildren(current$$1, workInProgress, nextChildren, renderExpirationTime); 10522 return workInProgress.child; 10523 } 10524 10525 function updateProfiler(current$$1, workInProgress, renderExpirationTime) { 10526 if (enableProfilerTimer) { 10527 workInProgress.effectTag |= Update; 10528 } 10529 var nextProps = workInProgress.pendingProps; 10530 var nextChildren = nextProps.children; 10531 reconcileChildren(current$$1, workInProgress, nextChildren, renderExpirationTime); 10532 return workInProgress.child; 10533 } 10534 10535 function markRef(current$$1, workInProgress) { 10536 var ref = workInProgress.ref; 10537 if (current$$1 === null && ref !== null || current$$1 !== null && current$$1.ref !== ref) { 10538 // Schedule a Ref effect 10539 workInProgress.effectTag |= Ref; 10540 } 10541 } 10542 10543 function updateFunctionComponent(current$$1, workInProgress, Component, nextProps, renderExpirationTime) { 10544 var unmaskedContext = getUnmaskedContext(workInProgress, Component, true); 10545 var context = getMaskedContext(workInProgress, unmaskedContext); 10546 10547 var nextChildren = void 0; 10548 prepareToReadContext(workInProgress, renderExpirationTime); 10549 { 10550 nextChildren = renderWithHooks(current$$1, workInProgress, Component, nextProps, context, renderExpirationTime); 10551 } 10552 10553 if (current$$1 !== null && !didReceiveUpdate) { 10554 bailoutHooks(current$$1, workInProgress, renderExpirationTime); 10555 return bailoutOnAlreadyFinishedWork(current$$1, workInProgress, renderExpirationTime); 10556 } 10557 10558 // React DevTools reads this flag. 10559 workInProgress.effectTag |= PerformedWork; 10560 reconcileChildren(current$$1, workInProgress, nextChildren, renderExpirationTime); 10561 return workInProgress.child; 10562 } 10563 10564 function updateClassComponent(current$$1, workInProgress, Component, nextProps, renderExpirationTime) { 10565 var hasContext = void 0; 10566 if (isContextProvider(Component)) { 10567 hasContext = true; 10568 pushContextProvider(workInProgress); 10569 } else { 10570 hasContext = false; 10571 } 10572 prepareToReadContext(workInProgress, renderExpirationTime); 10573 10574 var instance = workInProgress.stateNode; 10575 var shouldUpdate = void 0; 10576 if (instance === null) { 10577 if (current$$1 !== null) { 10578 // An class component without an instance only mounts if it suspended 10579 // inside a non- concurrent tree, in an inconsistent state. We want to 10580 // tree it like a new mount, even though an empty version of it already 10581 // committed. Disconnect the alternate pointers. 10582 current$$1.alternate = null; 10583 workInProgress.alternate = null; 10584 // Since this is conceptually a new fiber, schedule a Placement effect 10585 workInProgress.effectTag |= Placement; 10586 } 10587 // In the initial pass we might need to construct the instance. 10588 constructClassInstance(workInProgress, Component, nextProps, renderExpirationTime); 10589 mountClassInstance(workInProgress, Component, nextProps, renderExpirationTime); 10590 shouldUpdate = true; 10591 } else if (current$$1 === null) { 10592 // In a resume, we'll already have an instance we can reuse. 10593 shouldUpdate = resumeMountClassInstance(workInProgress, Component, nextProps, renderExpirationTime); 10594 } else { 10595 shouldUpdate = updateClassInstance(current$$1, workInProgress, Component, nextProps, renderExpirationTime); 10596 } 10597 var nextUnitOfWork = finishClassComponent(current$$1, workInProgress, Component, shouldUpdate, hasContext, renderExpirationTime); 10598 return nextUnitOfWork; 10599 } 10600 10601 function finishClassComponent(current$$1, workInProgress, Component, shouldUpdate, hasContext, renderExpirationTime) { 10602 // Refs should update even if shouldComponentUpdate returns false 10603 markRef(current$$1, workInProgress); 10604 10605 var didCaptureError = (workInProgress.effectTag & DidCapture) !== NoEffect; 10606 10607 if (!shouldUpdate && !didCaptureError) { 10608 // Context providers should defer to sCU for rendering 10609 if (hasContext) { 10610 invalidateContextProvider(workInProgress, Component, false); 10611 } 10612 10613 return bailoutOnAlreadyFinishedWork(current$$1, workInProgress, renderExpirationTime); 10614 } 10615 10616 var instance = workInProgress.stateNode; 10617 10618 // Rerender 10619 ReactCurrentOwner$3.current = workInProgress; 10620 var nextChildren = void 0; 10621 if (didCaptureError && typeof Component.getDerivedStateFromError !== 'function') { 10622 // If we captured an error, but getDerivedStateFrom catch is not defined, 10623 // unmount all the children. componentDidCatch will schedule an update to 10624 // re-render a fallback. This is temporary until we migrate everyone to 10625 // the new API. 10626 // TODO: Warn in a future release. 10627 nextChildren = null; 10628 10629 if (enableProfilerTimer) { 10630 stopProfilerTimerIfRunning(workInProgress); 10631 } 10632 } else { 10633 { 10634 nextChildren = instance.render(); 10635 } 10636 } 10637 10638 // React DevTools reads this flag. 10639 workInProgress.effectTag |= PerformedWork; 10640 if (current$$1 !== null && didCaptureError) { 10641 // If we're recovering from an error, reconcile without reusing any of 10642 // the existing children. Conceptually, the normal children and the children 10643 // that are shown on error are two different sets, so we shouldn't reuse 10644 // normal children even if their identities match. 10645 forceUnmountCurrentAndReconcile(current$$1, workInProgress, nextChildren, renderExpirationTime); 10646 } else { 10647 reconcileChildren(current$$1, workInProgress, nextChildren, renderExpirationTime); 10648 } 10649 10650 // Memoize state using the values we just used to render. 10651 // TODO: Restructure so we never read values from the instance. 10652 workInProgress.memoizedState = instance.state; 10653 10654 // The context might have changed so we need to recalculate it. 10655 if (hasContext) { 10656 invalidateContextProvider(workInProgress, Component, true); 10657 } 10658 10659 return workInProgress.child; 10660 } 10661 10662 function pushHostRootContext(workInProgress) { 10663 var root = workInProgress.stateNode; 10664 if (root.pendingContext) { 10665 pushTopLevelContextObject(workInProgress, root.pendingContext, root.pendingContext !== root.context); 10666 } else if (root.context) { 10667 // Should always be set 10668 pushTopLevelContextObject(workInProgress, root.context, false); 10669 } 10670 pushHostContainer(workInProgress, root.containerInfo); 10671 } 10672 10673 function updateHostRoot(current$$1, workInProgress, renderExpirationTime) { 10674 pushHostRootContext(workInProgress); 10675 var updateQueue = workInProgress.updateQueue; 10676 !(updateQueue !== null) ? reactProdInvariant('282') : void 0; 10677 var nextProps = workInProgress.pendingProps; 10678 var prevState = workInProgress.memoizedState; 10679 var prevChildren = prevState !== null ? prevState.element : null; 10680 processUpdateQueue(workInProgress, updateQueue, nextProps, null, renderExpirationTime); 10681 var nextState = workInProgress.memoizedState; 10682 // Caution: React DevTools currently depends on this property 10683 // being called "element". 10684 var nextChildren = nextState.element; 10685 if (nextChildren === prevChildren) { 10686 // If the state is the same as before, that's a bailout because we had 10687 // no work that expires at this time. 10688 resetHydrationState(); 10689 return bailoutOnAlreadyFinishedWork(current$$1, workInProgress, renderExpirationTime); 10690 } 10691 var root = workInProgress.stateNode; 10692 if ((current$$1 === null || current$$1.child === null) && root.hydrate && enterHydrationState(workInProgress)) { 10693 // If we don't have any current children this might be the first pass. 10694 // We always try to hydrate. If this isn't a hydration pass there won't 10695 // be any children to hydrate which is effectively the same thing as 10696 // not hydrating. 10697 10698 // This is a bit of a hack. We track the host root as a placement to 10699 // know that we're currently in a mounting state. That way isMounted 10700 // works as expected. We must reset this before committing. 10701 // TODO: Delete this when we delete isMounted and findDOMNode. 10702 workInProgress.effectTag |= Placement; 10703 10704 // Ensure that children mount into this root without tracking 10705 // side-effects. This ensures that we don't store Placement effects on 10706 // nodes that will be hydrated. 10707 workInProgress.child = mountChildFibers(workInProgress, null, nextChildren, renderExpirationTime); 10708 } else { 10709 // Otherwise reset hydration state in case we aborted and resumed another 10710 // root. 10711 reconcileChildren(current$$1, workInProgress, nextChildren, renderExpirationTime); 10712 resetHydrationState(); 10713 } 10714 return workInProgress.child; 10715 } 10716 10717 function updateHostComponent(current$$1, workInProgress, renderExpirationTime) { 10718 pushHostContext(workInProgress); 10719 10720 if (current$$1 === null) { 10721 tryToClaimNextHydratableInstance(workInProgress); 10722 } 10723 10724 var type = workInProgress.type; 10725 var nextProps = workInProgress.pendingProps; 10726 var prevProps = current$$1 !== null ? current$$1.memoizedProps : null; 10727 10728 var nextChildren = nextProps.children; 10729 var isDirectTextChild = shouldSetTextContent(type, nextProps); 10730 10731 if (isDirectTextChild) { 10732 // We special case a direct text child of a host node. This is a common 10733 // case. We won't handle it as a reified child. We will instead handle 10734 // this in the host environment that also have access to this prop. That 10735 // avoids allocating another HostText fiber and traversing it. 10736 nextChildren = null; 10737 } else if (prevProps !== null && shouldSetTextContent(type, prevProps)) { 10738 // If we're switching from a direct text child to a normal child, or to 10739 // empty, we need to schedule the text content to be reset. 10740 workInProgress.effectTag |= ContentReset; 10741 } 10742 10743 markRef(current$$1, workInProgress); 10744 10745 // Check the host config to see if the children are offscreen/hidden. 10746 if (renderExpirationTime !== Never && workInProgress.mode & ConcurrentMode && shouldDeprioritizeSubtree(type, nextProps)) { 10747 // Schedule this fiber to re-render at offscreen priority. Then bailout. 10748 workInProgress.expirationTime = workInProgress.childExpirationTime = Never; 10749 return null; 10750 } 10751 10752 reconcileChildren(current$$1, workInProgress, nextChildren, renderExpirationTime); 10753 return workInProgress.child; 10754 } 10755 10756 function updateHostText(current$$1, workInProgress) { 10757 if (current$$1 === null) { 10758 tryToClaimNextHydratableInstance(workInProgress); 10759 } 10760 // Nothing to do here. This is terminal. We'll do the completion step 10761 // immediately after. 10762 return null; 10763 } 10764 10765 function mountLazyComponent(_current, workInProgress, elementType, updateExpirationTime, renderExpirationTime) { 10766 if (_current !== null) { 10767 // An lazy component only mounts if it suspended inside a non- 10768 // concurrent tree, in an inconsistent state. We want to treat it like 10769 // a new mount, even though an empty version of it already committed. 10770 // Disconnect the alternate pointers. 10771 _current.alternate = null; 10772 workInProgress.alternate = null; 10773 // Since this is conceptually a new fiber, schedule a Placement effect 10774 workInProgress.effectTag |= Placement; 10775 } 10776 10777 var props = workInProgress.pendingProps; 10778 // We can't start a User Timing measurement with correct label yet. 10779 // Cancel and resume right after we know the tag. 10780 cancelWorkTimer(workInProgress); 10781 var Component = readLazyComponentType(elementType); 10782 // Store the unwrapped component in the type. 10783 workInProgress.type = Component; 10784 var resolvedTag = workInProgress.tag = resolveLazyComponentTag(Component); 10785 startWorkTimer(workInProgress); 10786 var resolvedProps = resolveDefaultProps(Component, props); 10787 var child = void 0; 10788 switch (resolvedTag) { 10789 case FunctionComponent: 10790 { 10791 child = updateFunctionComponent(null, workInProgress, Component, resolvedProps, renderExpirationTime); 10792 break; 10793 } 10794 case ClassComponent: 10795 { 10796 child = updateClassComponent(null, workInProgress, Component, resolvedProps, renderExpirationTime); 10797 break; 10798 } 10799 case ForwardRef: 10800 { 10801 child = updateForwardRef(null, workInProgress, Component, resolvedProps, renderExpirationTime); 10802 break; 10803 } 10804 case MemoComponent: 10805 { 10806 child = updateMemoComponent(null, workInProgress, Component, resolveDefaultProps(Component.type, resolvedProps), // The inner type can have defaults too 10807 updateExpirationTime, renderExpirationTime); 10808 break; 10809 } 10810 default: 10811 { 10812 var hint = ''; 10813 reactProdInvariant('306', Component, hint); 10814 } 10815 } 10816 return child; 10817 } 10818 10819 function mountIncompleteClassComponent(_current, workInProgress, Component, nextProps, renderExpirationTime) { 10820 if (_current !== null) { 10821 // An incomplete component only mounts if it suspended inside a non- 10822 // concurrent tree, in an inconsistent state. We want to treat it like 10823 // a new mount, even though an empty version of it already committed. 10824 // Disconnect the alternate pointers. 10825 _current.alternate = null; 10826 workInProgress.alternate = null; 10827 // Since this is conceptually a new fiber, schedule a Placement effect 10828 workInProgress.effectTag |= Placement; 10829 } 10830 10831 // Promote the fiber to a class and try rendering again. 10832 workInProgress.tag = ClassComponent; 10833 10834 // The rest of this function is a fork of `updateClassComponent` 10835 10836 // Push context providers early to prevent context stack mismatches. 10837 // During mounting we don't know the child context yet as the instance doesn't exist. 10838 // We will invalidate the child context in finishClassComponent() right after rendering. 10839 var hasContext = void 0; 10840 if (isContextProvider(Component)) { 10841 hasContext = true; 10842 pushContextProvider(workInProgress); 10843 } else { 10844 hasContext = false; 10845 } 10846 prepareToReadContext(workInProgress, renderExpirationTime); 10847 10848 constructClassInstance(workInProgress, Component, nextProps, renderExpirationTime); 10849 mountClassInstance(workInProgress, Component, nextProps, renderExpirationTime); 10850 10851 return finishClassComponent(null, workInProgress, Component, true, hasContext, renderExpirationTime); 10852 } 10853 10854 function mountIndeterminateComponent(_current, workInProgress, Component, renderExpirationTime) { 10855 if (_current !== null) { 10856 // An indeterminate component only mounts if it suspended inside a non- 10857 // concurrent tree, in an inconsistent state. We want to treat it like 10858 // a new mount, even though an empty version of it already committed. 10859 // Disconnect the alternate pointers. 10860 _current.alternate = null; 10861 workInProgress.alternate = null; 10862 // Since this is conceptually a new fiber, schedule a Placement effect 10863 workInProgress.effectTag |= Placement; 10864 } 10865 10866 var props = workInProgress.pendingProps; 10867 var unmaskedContext = getUnmaskedContext(workInProgress, Component, false); 10868 var context = getMaskedContext(workInProgress, unmaskedContext); 10869 10870 prepareToReadContext(workInProgress, renderExpirationTime); 10871 10872 var value = void 0; 10873 10874 { 10875 value = renderWithHooks(null, workInProgress, Component, props, context, renderExpirationTime); 10876 } 10877 // React DevTools reads this flag. 10878 workInProgress.effectTag |= PerformedWork; 10879 10880 if (typeof value === 'object' && value !== null && typeof value.render === 'function' && value.$$typeof === undefined) { 10881 // Proceed under the assumption that this is a class instance 10882 workInProgress.tag = ClassComponent; 10883 10884 // Throw out any hooks that were used. 10885 resetHooks(); 10886 10887 // Push context providers early to prevent context stack mismatches. 10888 // During mounting we don't know the child context yet as the instance doesn't exist. 10889 // We will invalidate the child context in finishClassComponent() right after rendering. 10890 var hasContext = false; 10891 if (isContextProvider(Component)) { 10892 hasContext = true; 10893 pushContextProvider(workInProgress); 10894 } else { 10895 hasContext = false; 10896 } 10897 10898 workInProgress.memoizedState = value.state !== null && value.state !== undefined ? value.state : null; 10899 10900 var getDerivedStateFromProps = Component.getDerivedStateFromProps; 10901 if (typeof getDerivedStateFromProps === 'function') { 10902 applyDerivedStateFromProps(workInProgress, Component, getDerivedStateFromProps, props); 10903 } 10904 10905 adoptClassInstance(workInProgress, value); 10906 mountClassInstance(workInProgress, Component, props, renderExpirationTime); 10907 return finishClassComponent(null, workInProgress, Component, true, hasContext, renderExpirationTime); 10908 } else { 10909 // Proceed under the assumption that this is a function component 10910 workInProgress.tag = FunctionComponent; 10911 reconcileChildren(null, workInProgress, value, renderExpirationTime); 10912 return workInProgress.child; 10913 } 10914 } 10915 10916 function updateSuspenseComponent(current$$1, workInProgress, renderExpirationTime) { 10917 var mode = workInProgress.mode; 10918 var nextProps = workInProgress.pendingProps; 10919 10920 // We should attempt to render the primary children unless this boundary 10921 // already suspended during this render (`alreadyCaptured` is true). 10922 var nextState = workInProgress.memoizedState; 10923 10924 var nextDidTimeout = void 0; 10925 if ((workInProgress.effectTag & DidCapture) === NoEffect) { 10926 // This is the first attempt. 10927 nextState = null; 10928 nextDidTimeout = false; 10929 } else { 10930 // Something in this boundary's subtree already suspended. Switch to 10931 // rendering the fallback children. 10932 nextState = { 10933 timedOutAt: nextState !== null ? nextState.timedOutAt : NoWork 10934 }; 10935 nextDidTimeout = true; 10936 workInProgress.effectTag &= ~DidCapture; 10937 } 10938 10939 // This next part is a bit confusing. If the children timeout, we switch to 10940 // showing the fallback children in place of the "primary" children. 10941 // However, we don't want to delete the primary children because then their 10942 // state will be lost (both the React state and the host state, e.g. 10943 // uncontrolled form inputs). Instead we keep them mounted and hide them. 10944 // Both the fallback children AND the primary children are rendered at the 10945 // same time. Once the primary children are un-suspended, we can delete 10946 // the fallback children — don't need to preserve their state. 10947 // 10948 // The two sets of children are siblings in the host environment, but 10949 // semantically, for purposes of reconciliation, they are two separate sets. 10950 // So we store them using two fragment fibers. 10951 // 10952 // However, we want to avoid allocating extra fibers for every placeholder. 10953 // They're only necessary when the children time out, because that's the 10954 // only time when both sets are mounted. 10955 // 10956 // So, the extra fragment fibers are only used if the children time out. 10957 // Otherwise, we render the primary children directly. This requires some 10958 // custom reconciliation logic to preserve the state of the primary 10959 // children. It's essentially a very basic form of re-parenting. 10960 10961 // `child` points to the child fiber. In the normal case, this is the first 10962 // fiber of the primary children set. In the timed-out case, it's a 10963 // a fragment fiber containing the primary children. 10964 var child = void 0; 10965 // `next` points to the next fiber React should render. In the normal case, 10966 // it's the same as `child`: the first fiber of the primary children set. 10967 // In the timed-out case, it's a fragment fiber containing the *fallback* 10968 // children -- we skip over the primary children entirely. 10969 var next = void 0; 10970 if (current$$1 === null) { 10971 if (enableSuspenseServerRenderer) { 10972 // If we're currently hydrating, try to hydrate this boundary. 10973 // But only if this has a fallback. 10974 if (nextProps.fallback !== undefined) { 10975 tryToClaimNextHydratableInstance(workInProgress); 10976 // This could've changed the tag if this was a dehydrated suspense component. 10977 if (workInProgress.tag === DehydratedSuspenseComponent) { 10978 return updateDehydratedSuspenseComponent(null, workInProgress, renderExpirationTime); 10979 } 10980 } 10981 } 10982 10983 // This is the initial mount. This branch is pretty simple because there's 10984 // no previous state that needs to be preserved. 10985 if (nextDidTimeout) { 10986 // Mount separate fragments for primary and fallback children. 10987 var nextFallbackChildren = nextProps.fallback; 10988 var primaryChildFragment = createFiberFromFragment(null, mode, NoWork, null); 10989 10990 if ((workInProgress.mode & ConcurrentMode) === NoContext) { 10991 // Outside of concurrent mode, we commit the effects from the 10992 var progressedState = workInProgress.memoizedState; 10993 var progressedPrimaryChild = progressedState !== null ? workInProgress.child.child : workInProgress.child; 10994 primaryChildFragment.child = progressedPrimaryChild; 10995 } 10996 10997 var fallbackChildFragment = createFiberFromFragment(nextFallbackChildren, mode, renderExpirationTime, null); 10998 primaryChildFragment.sibling = fallbackChildFragment; 10999 child = primaryChildFragment; 11000 // Skip the primary children, and continue working on the 11001 // fallback children. 11002 next = fallbackChildFragment; 11003 child.return = next.return = workInProgress; 11004 } else { 11005 // Mount the primary children without an intermediate fragment fiber. 11006 var nextPrimaryChildren = nextProps.children; 11007 child = next = mountChildFibers(workInProgress, null, nextPrimaryChildren, renderExpirationTime); 11008 } 11009 } else { 11010 // This is an update. This branch is more complicated because we need to 11011 // ensure the state of the primary children is preserved. 11012 var prevState = current$$1.memoizedState; 11013 var prevDidTimeout = prevState !== null; 11014 if (prevDidTimeout) { 11015 // The current tree already timed out. That means each child set is 11016 var currentPrimaryChildFragment = current$$1.child; 11017 var currentFallbackChildFragment = currentPrimaryChildFragment.sibling; 11018 if (nextDidTimeout) { 11019 // Still timed out. Reuse the current primary children by cloning 11020 // its fragment. We're going to skip over these entirely. 11021 var _nextFallbackChildren = nextProps.fallback; 11022 var _primaryChildFragment = createWorkInProgress(currentPrimaryChildFragment, currentPrimaryChildFragment.pendingProps, NoWork); 11023 11024 if ((workInProgress.mode & ConcurrentMode) === NoContext) { 11025 // Outside of concurrent mode, we commit the effects from the 11026 var _progressedState = workInProgress.memoizedState; 11027 var _progressedPrimaryChild = _progressedState !== null ? workInProgress.child.child : workInProgress.child; 11028 if (_progressedPrimaryChild !== currentPrimaryChildFragment.child) { 11029 _primaryChildFragment.child = _progressedPrimaryChild; 11030 } 11031 } 11032 11033 // Because primaryChildFragment is a new fiber that we're inserting as the 11034 // parent of a new tree, we need to set its treeBaseDuration. 11035 if (enableProfilerTimer && workInProgress.mode & ProfileMode) { 11036 // treeBaseDuration is the sum of all the child tree base durations. 11037 var treeBaseDuration = 0; 11038 var hiddenChild = _primaryChildFragment.child; 11039 while (hiddenChild !== null) { 11040 treeBaseDuration += hiddenChild.treeBaseDuration; 11041 hiddenChild = hiddenChild.sibling; 11042 } 11043 _primaryChildFragment.treeBaseDuration = treeBaseDuration; 11044 } 11045 11046 // Clone the fallback child fragment, too. These we'll continue 11047 // working on. 11048 var _fallbackChildFragment = _primaryChildFragment.sibling = createWorkInProgress(currentFallbackChildFragment, _nextFallbackChildren, currentFallbackChildFragment.expirationTime); 11049 child = _primaryChildFragment; 11050 _primaryChildFragment.childExpirationTime = NoWork; 11051 // Skip the primary children, and continue working on the 11052 // fallback children. 11053 next = _fallbackChildFragment; 11054 child.return = next.return = workInProgress; 11055 } else { 11056 // No longer suspended. Switch back to showing the primary children, 11057 // and remove the intermediate fragment fiber. 11058 var _nextPrimaryChildren = nextProps.children; 11059 var currentPrimaryChild = currentPrimaryChildFragment.child; 11060 var primaryChild = reconcileChildFibers(workInProgress, currentPrimaryChild, _nextPrimaryChildren, renderExpirationTime); 11061 11062 // If this render doesn't suspend, we need to delete the fallback 11063 // children. Wait until the complete phase, after we've confirmed the 11064 // fallback is no longer needed. 11065 // TODO: Would it be better to store the fallback fragment on 11066 // the stateNode? 11067 11068 // Continue rendering the children, like we normally do. 11069 child = next = primaryChild; 11070 } 11071 } else { 11072 // The current tree has not already timed out. That means the primary 11073 // children are not wrapped in a fragment fiber. 11074 var _currentPrimaryChild = current$$1.child; 11075 if (nextDidTimeout) { 11076 // Timed out. Wrap the children in a fragment fiber to keep them 11077 // separate from the fallback children. 11078 var _nextFallbackChildren2 = nextProps.fallback; 11079 var _primaryChildFragment2 = createFiberFromFragment( 11080 // It shouldn't matter what the pending props are because we aren't 11081 // going to render this fragment. 11082 null, mode, NoWork, null); 11083 _primaryChildFragment2.child = _currentPrimaryChild; 11084 11085 // Even though we're creating a new fiber, there are no new children, 11086 // because we're reusing an already mounted tree. So we don't need to 11087 // schedule a placement. 11088 // primaryChildFragment.effectTag |= Placement; 11089 11090 if ((workInProgress.mode & ConcurrentMode) === NoContext) { 11091 // Outside of concurrent mode, we commit the effects from the 11092 var _progressedState2 = workInProgress.memoizedState; 11093 var _progressedPrimaryChild2 = _progressedState2 !== null ? workInProgress.child.child : workInProgress.child; 11094 _primaryChildFragment2.child = _progressedPrimaryChild2; 11095 } 11096 11097 // Because primaryChildFragment is a new fiber that we're inserting as the 11098 // parent of a new tree, we need to set its treeBaseDuration. 11099 if (enableProfilerTimer && workInProgress.mode & ProfileMode) { 11100 // treeBaseDuration is the sum of all the child tree base durations. 11101 var _treeBaseDuration = 0; 11102 var _hiddenChild = _primaryChildFragment2.child; 11103 while (_hiddenChild !== null) { 11104 _treeBaseDuration += _hiddenChild.treeBaseDuration; 11105 _hiddenChild = _hiddenChild.sibling; 11106 } 11107 _primaryChildFragment2.treeBaseDuration = _treeBaseDuration; 11108 } 11109 11110 // Create a fragment from the fallback children, too. 11111 var _fallbackChildFragment2 = _primaryChildFragment2.sibling = createFiberFromFragment(_nextFallbackChildren2, mode, renderExpirationTime, null); 11112 _fallbackChildFragment2.effectTag |= Placement; 11113 child = _primaryChildFragment2; 11114 _primaryChildFragment2.childExpirationTime = NoWork; 11115 // Skip the primary children, and continue working on the 11116 // fallback children. 11117 next = _fallbackChildFragment2; 11118 child.return = next.return = workInProgress; 11119 } else { 11120 // Still haven't timed out. Continue rendering the children, like we 11121 // normally do. 11122 var _nextPrimaryChildren2 = nextProps.children; 11123 next = child = reconcileChildFibers(workInProgress, _currentPrimaryChild, _nextPrimaryChildren2, renderExpirationTime); 11124 } 11125 } 11126 workInProgress.stateNode = current$$1.stateNode; 11127 } 11128 11129 workInProgress.memoizedState = nextState; 11130 workInProgress.child = child; 11131 return next; 11132 } 11133 11134 function updateDehydratedSuspenseComponent(current$$1, workInProgress, renderExpirationTime) { 11135 if (current$$1 === null) { 11136 // During the first pass, we'll bail out and not drill into the children. 11137 // Instead, we'll leave the content in place and try to hydrate it later. 11138 workInProgress.expirationTime = Never; 11139 return null; 11140 } 11141 // We use childExpirationTime to indicate that a child might depend on context, so if 11142 // any context has changed, we need to treat is as if the input might have changed. 11143 var hasContextChanged$$1 = current$$1.childExpirationTime >= renderExpirationTime; 11144 if (didReceiveUpdate || hasContextChanged$$1) { 11145 // This boundary has changed since the first render. This means that we are now unable to 11146 // hydrate it. We might still be able to hydrate it using an earlier expiration time but 11147 // during this render we can't. Instead, we're going to delete the whole subtree and 11148 // instead inject a new real Suspense boundary to take its place, which may render content 11149 // or fallback. The real Suspense boundary will suspend for a while so we have some time 11150 // to ensure it can produce real content, but all state and pending events will be lost. 11151 11152 // Detach from the current dehydrated boundary. 11153 current$$1.alternate = null; 11154 workInProgress.alternate = null; 11155 11156 // Insert a deletion in the effect list. 11157 var returnFiber = workInProgress.return; 11158 !(returnFiber !== null) ? reactProdInvariant('315') : void 0; 11159 var last = returnFiber.lastEffect; 11160 if (last !== null) { 11161 last.nextEffect = current$$1; 11162 returnFiber.lastEffect = current$$1; 11163 } else { 11164 returnFiber.firstEffect = returnFiber.lastEffect = current$$1; 11165 } 11166 current$$1.nextEffect = null; 11167 current$$1.effectTag = Deletion; 11168 11169 // Upgrade this work in progress to a real Suspense component. 11170 workInProgress.tag = SuspenseComponent; 11171 workInProgress.stateNode = null; 11172 workInProgress.memoizedState = null; 11173 // This is now an insertion. 11174 workInProgress.effectTag |= Placement; 11175 // Retry as a real Suspense component. 11176 return updateSuspenseComponent(null, workInProgress, renderExpirationTime); 11177 } 11178 if ((workInProgress.effectTag & DidCapture) === NoEffect) { 11179 // This is the first attempt. 11180 reenterHydrationStateFromDehydratedSuspenseInstance(workInProgress); 11181 var nextProps = workInProgress.pendingProps; 11182 var nextChildren = nextProps.children; 11183 workInProgress.child = mountChildFibers(workInProgress, null, nextChildren, renderExpirationTime); 11184 return workInProgress.child; 11185 } else { 11186 // Something suspended. Leave the existing children in place. 11187 // TODO: In non-concurrent mode, should we commit the nodes we have hydrated so far? 11188 workInProgress.child = null; 11189 return null; 11190 } 11191 } 11192 11193 function updatePortalComponent(current$$1, workInProgress, renderExpirationTime) { 11194 pushHostContainer(workInProgress, workInProgress.stateNode.containerInfo); 11195 var nextChildren = workInProgress.pendingProps; 11196 if (current$$1 === null) { 11197 // Portals are special because we don't append the children during mount 11198 // but at commit. Therefore we need to track insertions which the normal 11199 // flow doesn't do during mount. This doesn't happen at the root because 11200 // the root always starts with a "current" with a null child. 11201 // TODO: Consider unifying this with how the root works. 11202 workInProgress.child = reconcileChildFibers(workInProgress, null, nextChildren, renderExpirationTime); 11203 } else { 11204 reconcileChildren(current$$1, workInProgress, nextChildren, renderExpirationTime); 11205 } 11206 return workInProgress.child; 11207 } 11208 11209 function updateContextProvider(current$$1, workInProgress, renderExpirationTime) { 11210 var providerType = workInProgress.type; 11211 var context = providerType._context; 11212 11213 var newProps = workInProgress.pendingProps; 11214 var oldProps = workInProgress.memoizedProps; 11215 11216 var newValue = newProps.value; 11217 11218 pushProvider(workInProgress, newValue); 11219 11220 if (oldProps !== null) { 11221 var oldValue = oldProps.value; 11222 var changedBits = calculateChangedBits(context, newValue, oldValue); 11223 if (changedBits === 0) { 11224 // No change. Bailout early if children are the same. 11225 if (oldProps.children === newProps.children && !hasContextChanged()) { 11226 return bailoutOnAlreadyFinishedWork(current$$1, workInProgress, renderExpirationTime); 11227 } 11228 } else { 11229 // The context value changed. Search for matching consumers and schedule 11230 // them to update. 11231 propagateContextChange(workInProgress, context, changedBits, renderExpirationTime); 11232 } 11233 } 11234 11235 var newChildren = newProps.children; 11236 reconcileChildren(current$$1, workInProgress, newChildren, renderExpirationTime); 11237 return workInProgress.child; 11238 } 11239 11240 function updateContextConsumer(current$$1, workInProgress, renderExpirationTime) { 11241 var context = workInProgress.type; 11242 // The logic below for Context differs depending on PROD or DEV mode. In 11243 // DEV mode, we create a separate object for Context.Consumer that acts 11244 // like a proxy to Context. This proxy object adds unnecessary code in PROD 11245 // so we use the old behaviour (Context.Consumer references Context) to 11246 // reduce size and overhead. The separate object references context via 11247 // a property called "_context", which also gives us the ability to check 11248 // in DEV mode if this property exists or not and warn if it does not. 11249 var newProps = workInProgress.pendingProps; 11250 var render = newProps.children; 11251 11252 prepareToReadContext(workInProgress, renderExpirationTime); 11253 var newValue = readContext(context, newProps.unstable_observedBits); 11254 var newChildren = void 0; 11255 { 11256 newChildren = render(newValue); 11257 } 11258 11259 // React DevTools reads this flag. 11260 workInProgress.effectTag |= PerformedWork; 11261 reconcileChildren(current$$1, workInProgress, newChildren, renderExpirationTime); 11262 return workInProgress.child; 11263 } 11264 11265 function markWorkInProgressReceivedUpdate() { 11266 didReceiveUpdate = true; 11267 } 11268 11269 function bailoutOnAlreadyFinishedWork(current$$1, workInProgress, renderExpirationTime) { 11270 cancelWorkTimer(workInProgress); 11271 11272 if (current$$1 !== null) { 11273 // Reuse previous context list 11274 workInProgress.contextDependencies = current$$1.contextDependencies; 11275 } 11276 11277 if (enableProfilerTimer) { 11278 // Don't update "base" render times for bailouts. 11279 stopProfilerTimerIfRunning(workInProgress); 11280 } 11281 11282 // Check if the children have any pending work. 11283 var childExpirationTime = workInProgress.childExpirationTime; 11284 if (childExpirationTime < renderExpirationTime) { 11285 // The children don't have any work either. We can skip them. 11286 // TODO: Once we add back resuming, we should check if the children are 11287 // a work-in-progress set. If so, we need to transfer their effects. 11288 return null; 11289 } else { 11290 // This fiber doesn't have work, but its subtree does. Clone the child 11291 // fibers and continue. 11292 cloneChildFibers(current$$1, workInProgress); 11293 return workInProgress.child; 11294 } 11295 } 11296 11297 function beginWork(current$$1, workInProgress, renderExpirationTime) { 11298 var updateExpirationTime = workInProgress.expirationTime; 11299 11300 if (current$$1 !== null) { 11301 var oldProps = current$$1.memoizedProps; 11302 var newProps = workInProgress.pendingProps; 11303 11304 if (oldProps !== newProps || hasContextChanged()) { 11305 // If props or context changed, mark the fiber as having performed work. 11306 // This may be unset if the props are determined to be equal later (memo). 11307 didReceiveUpdate = true; 11308 } else if (updateExpirationTime < renderExpirationTime) { 11309 didReceiveUpdate = false; 11310 // This fiber does not have any pending work. Bailout without entering 11311 // the begin phase. There's still some bookkeeping we that needs to be done 11312 // in this optimized path, mostly pushing stuff onto the stack. 11313 switch (workInProgress.tag) { 11314 case HostRoot: 11315 pushHostRootContext(workInProgress); 11316 resetHydrationState(); 11317 break; 11318 case HostComponent: 11319 pushHostContext(workInProgress); 11320 break; 11321 case ClassComponent: 11322 { 11323 var Component = workInProgress.type; 11324 if (isContextProvider(Component)) { 11325 pushContextProvider(workInProgress); 11326 } 11327 break; 11328 } 11329 case HostPortal: 11330 pushHostContainer(workInProgress, workInProgress.stateNode.containerInfo); 11331 break; 11332 case ContextProvider: 11333 { 11334 var newValue = workInProgress.memoizedProps.value; 11335 pushProvider(workInProgress, newValue); 11336 break; 11337 } 11338 case Profiler: 11339 if (enableProfilerTimer) { 11340 workInProgress.effectTag |= Update; 11341 } 11342 break; 11343 case SuspenseComponent: 11344 { 11345 var state = workInProgress.memoizedState; 11346 var didTimeout = state !== null; 11347 if (didTimeout) { 11348 // If this boundary is currently timed out, we need to decide 11349 // whether to retry the primary children, or to skip over it and 11350 // go straight to the fallback. Check the priority of the primary 11351 var primaryChildFragment = workInProgress.child; 11352 var primaryChildExpirationTime = primaryChildFragment.childExpirationTime; 11353 if (primaryChildExpirationTime !== NoWork && primaryChildExpirationTime >= renderExpirationTime) { 11354 // The primary children have pending work. Use the normal path 11355 // to attempt to render the primary children again. 11356 return updateSuspenseComponent(current$$1, workInProgress, renderExpirationTime); 11357 } else { 11358 // The primary children do not have pending work with sufficient 11359 // priority. Bailout. 11360 var child = bailoutOnAlreadyFinishedWork(current$$1, workInProgress, renderExpirationTime); 11361 if (child !== null) { 11362 // The fallback children have pending work. Skip over the 11363 // primary children and work on the fallback. 11364 return child.sibling; 11365 } else { 11366 return null; 11367 } 11368 } 11369 } 11370 break; 11371 } 11372 case DehydratedSuspenseComponent: 11373 { 11374 if (enableSuspenseServerRenderer) { 11375 // We know that this component will suspend again because if it has 11376 // been unsuspended it has committed as a regular Suspense component. 11377 // If it needs to be retried, it should have work scheduled on it. 11378 workInProgress.effectTag |= DidCapture; 11379 break; 11380 } 11381 } 11382 } 11383 return bailoutOnAlreadyFinishedWork(current$$1, workInProgress, renderExpirationTime); 11384 } 11385 } else { 11386 didReceiveUpdate = false; 11387 } 11388 11389 // Before entering the begin phase, clear the expiration time. 11390 workInProgress.expirationTime = NoWork; 11391 11392 switch (workInProgress.tag) { 11393 case IndeterminateComponent: 11394 { 11395 var elementType = workInProgress.elementType; 11396 return mountIndeterminateComponent(current$$1, workInProgress, elementType, renderExpirationTime); 11397 } 11398 case LazyComponent: 11399 { 11400 var _elementType = workInProgress.elementType; 11401 return mountLazyComponent(current$$1, workInProgress, _elementType, updateExpirationTime, renderExpirationTime); 11402 } 11403 case FunctionComponent: 11404 { 11405 var _Component = workInProgress.type; 11406 var unresolvedProps = workInProgress.pendingProps; 11407 var resolvedProps = workInProgress.elementType === _Component ? unresolvedProps : resolveDefaultProps(_Component, unresolvedProps); 11408 return updateFunctionComponent(current$$1, workInProgress, _Component, resolvedProps, renderExpirationTime); 11409 } 11410 case ClassComponent: 11411 { 11412 var _Component2 = workInProgress.type; 11413 var _unresolvedProps = workInProgress.pendingProps; 11414 var _resolvedProps = workInProgress.elementType === _Component2 ? _unresolvedProps : resolveDefaultProps(_Component2, _unresolvedProps); 11415 return updateClassComponent(current$$1, workInProgress, _Component2, _resolvedProps, renderExpirationTime); 11416 } 11417 case HostRoot: 11418 return updateHostRoot(current$$1, workInProgress, renderExpirationTime); 11419 case HostComponent: 11420 return updateHostComponent(current$$1, workInProgress, renderExpirationTime); 11421 case HostText: 11422 return updateHostText(current$$1, workInProgress); 11423 case SuspenseComponent: 11424 return updateSuspenseComponent(current$$1, workInProgress, renderExpirationTime); 11425 case HostPortal: 11426 return updatePortalComponent(current$$1, workInProgress, renderExpirationTime); 11427 case ForwardRef: 11428 { 11429 var type = workInProgress.type; 11430 var _unresolvedProps2 = workInProgress.pendingProps; 11431 var _resolvedProps2 = workInProgress.elementType === type ? _unresolvedProps2 : resolveDefaultProps(type, _unresolvedProps2); 11432 return updateForwardRef(current$$1, workInProgress, type, _resolvedProps2, renderExpirationTime); 11433 } 11434 case Fragment: 11435 return updateFragment(current$$1, workInProgress, renderExpirationTime); 11436 case Mode: 11437 return updateMode(current$$1, workInProgress, renderExpirationTime); 11438 case Profiler: 11439 return updateProfiler(current$$1, workInProgress, renderExpirationTime); 11440 case ContextProvider: 11441 return updateContextProvider(current$$1, workInProgress, renderExpirationTime); 11442 case ContextConsumer: 11443 return updateContextConsumer(current$$1, workInProgress, renderExpirationTime); 11444 case MemoComponent: 11445 { 11446 var _type2 = workInProgress.type; 11447 var _unresolvedProps3 = workInProgress.pendingProps; 11448 // Resolve outer props first, then resolve inner props. 11449 var _resolvedProps3 = resolveDefaultProps(_type2, _unresolvedProps3); 11450 _resolvedProps3 = resolveDefaultProps(_type2.type, _resolvedProps3); 11451 return updateMemoComponent(current$$1, workInProgress, _type2, _resolvedProps3, updateExpirationTime, renderExpirationTime); 11452 } 11453 case SimpleMemoComponent: 11454 { 11455 return updateSimpleMemoComponent(current$$1, workInProgress, workInProgress.type, workInProgress.pendingProps, updateExpirationTime, renderExpirationTime); 11456 } 11457 case IncompleteClassComponent: 11458 { 11459 var _Component3 = workInProgress.type; 11460 var _unresolvedProps4 = workInProgress.pendingProps; 11461 var _resolvedProps4 = workInProgress.elementType === _Component3 ? _unresolvedProps4 : resolveDefaultProps(_Component3, _unresolvedProps4); 11462 return mountIncompleteClassComponent(current$$1, workInProgress, _Component3, _resolvedProps4, renderExpirationTime); 11463 } 11464 case DehydratedSuspenseComponent: 11465 { 11466 if (enableSuspenseServerRenderer) { 11467 return updateDehydratedSuspenseComponent(current$$1, workInProgress, renderExpirationTime); 11468 } 11469 break; 11470 } 11471 } 11472 reactProdInvariant('156'); 11473 } 11474 11475 var valueCursor = createCursor(null); 11476 11477 var currentlyRenderingFiber = null; 11478 var lastContextDependency = null; 11479 var lastContextWithAllBitsObserved = null; 11480 11481 function resetContextDependences() { 11482 // This is called right before React yields execution, to ensure `readContext` 11483 // cannot be called outside the render phase. 11484 currentlyRenderingFiber = null; 11485 lastContextDependency = null; 11486 lastContextWithAllBitsObserved = null; 11487 11488 } 11489 11490 11491 11492 11493 11494 function pushProvider(providerFiber, nextValue) { 11495 var context = providerFiber.type._context; 11496 11497 if (isPrimaryRenderer) { 11498 push(valueCursor, context._currentValue, providerFiber); 11499 11500 context._currentValue = nextValue; 11501 11502 } else { 11503 push(valueCursor, context._currentValue2, providerFiber); 11504 11505 context._currentValue2 = nextValue; 11506 11507 } 11508 } 11509 11510 function popProvider(providerFiber) { 11511 var currentValue = valueCursor.current; 11512 11513 pop(valueCursor, providerFiber); 11514 11515 var context = providerFiber.type._context; 11516 if (isPrimaryRenderer) { 11517 context._currentValue = currentValue; 11518 } else { 11519 context._currentValue2 = currentValue; 11520 } 11521 } 11522 11523 function calculateChangedBits(context, newValue, oldValue) { 11524 if (is(oldValue, newValue)) { 11525 // No change 11526 return 0; 11527 } else { 11528 var changedBits = typeof context._calculateChangedBits === 'function' ? context._calculateChangedBits(oldValue, newValue) : maxSigned31BitInt; 11529 11530 return changedBits | 0; 11531 } 11532 } 11533 11534 function scheduleWorkOnParentPath(parent, renderExpirationTime) { 11535 // Update the child expiration time of all the ancestors, including 11536 // the alternates. 11537 var node = parent; 11538 while (node !== null) { 11539 var alternate = node.alternate; 11540 if (node.childExpirationTime < renderExpirationTime) { 11541 node.childExpirationTime = renderExpirationTime; 11542 if (alternate !== null && alternate.childExpirationTime < renderExpirationTime) { 11543 alternate.childExpirationTime = renderExpirationTime; 11544 } 11545 } else if (alternate !== null && alternate.childExpirationTime < renderExpirationTime) { 11546 alternate.childExpirationTime = renderExpirationTime; 11547 } else { 11548 // Neither alternate was updated, which means the rest of the 11549 // ancestor path already has sufficient priority. 11550 break; 11551 } 11552 node = node.return; 11553 } 11554 } 11555 11556 function propagateContextChange(workInProgress, context, changedBits, renderExpirationTime) { 11557 var fiber = workInProgress.child; 11558 if (fiber !== null) { 11559 // Set the return pointer of the child to the work-in-progress fiber. 11560 fiber.return = workInProgress; 11561 } 11562 while (fiber !== null) { 11563 var nextFiber = void 0; 11564 11565 // Visit this fiber. 11566 var list = fiber.contextDependencies; 11567 if (list !== null) { 11568 nextFiber = fiber.child; 11569 11570 var dependency = list.first; 11571 while (dependency !== null) { 11572 // Check if the context matches. 11573 if (dependency.context === context && (dependency.observedBits & changedBits) !== 0) { 11574 // Match! Schedule an update on this fiber. 11575 11576 if (fiber.tag === ClassComponent) { 11577 // Schedule a force update on the work-in-progress. 11578 var update = createUpdate(renderExpirationTime); 11579 update.tag = ForceUpdate; 11580 // TODO: Because we don't have a work-in-progress, this will add the 11581 // update to the current fiber, too, which means it will persist even if 11582 // this render is thrown away. Since it's a race condition, not sure it's 11583 // worth fixing. 11584 enqueueUpdate(fiber, update); 11585 } 11586 11587 if (fiber.expirationTime < renderExpirationTime) { 11588 fiber.expirationTime = renderExpirationTime; 11589 } 11590 var alternate = fiber.alternate; 11591 if (alternate !== null && alternate.expirationTime < renderExpirationTime) { 11592 alternate.expirationTime = renderExpirationTime; 11593 } 11594 11595 scheduleWorkOnParentPath(fiber.return, renderExpirationTime); 11596 11597 // Mark the expiration time on the list, too. 11598 if (list.expirationTime < renderExpirationTime) { 11599 list.expirationTime = renderExpirationTime; 11600 } 11601 11602 // Since we already found a match, we can stop traversing the 11603 // dependency list. 11604 break; 11605 } 11606 dependency = dependency.next; 11607 } 11608 } else if (fiber.tag === ContextProvider) { 11609 // Don't scan deeper if this is a matching provider 11610 nextFiber = fiber.type === workInProgress.type ? null : fiber.child; 11611 } else if (enableSuspenseServerRenderer && fiber.tag === DehydratedSuspenseComponent) { 11612 // If a dehydrated suspense component is in this subtree, we don't know 11613 // if it will have any context consumers in it. The best we can do is 11614 // mark it as having updates on its children. 11615 if (fiber.expirationTime < renderExpirationTime) { 11616 fiber.expirationTime = renderExpirationTime; 11617 } 11618 var _alternate = fiber.alternate; 11619 if (_alternate !== null && _alternate.expirationTime < renderExpirationTime) { 11620 _alternate.expirationTime = renderExpirationTime; 11621 } 11622 // This is intentionally passing this fiber as the parent 11623 // because we want to schedule this fiber as having work 11624 // on its children. We'll use the childExpirationTime on 11625 // this fiber to indicate that a context has changed. 11626 scheduleWorkOnParentPath(fiber, renderExpirationTime); 11627 nextFiber = fiber.sibling; 11628 } else { 11629 // Traverse down. 11630 nextFiber = fiber.child; 11631 } 11632 11633 if (nextFiber !== null) { 11634 // Set the return pointer of the child to the work-in-progress fiber. 11635 nextFiber.return = fiber; 11636 } else { 11637 // No child. Traverse to next sibling. 11638 nextFiber = fiber; 11639 while (nextFiber !== null) { 11640 if (nextFiber === workInProgress) { 11641 // We're back to the root of this subtree. Exit. 11642 nextFiber = null; 11643 break; 11644 } 11645 var sibling = nextFiber.sibling; 11646 if (sibling !== null) { 11647 // Set the return pointer of the sibling to the work-in-progress fiber. 11648 sibling.return = nextFiber.return; 11649 nextFiber = sibling; 11650 break; 11651 } 11652 // No more siblings. Traverse up. 11653 nextFiber = nextFiber.return; 11654 } 11655 } 11656 fiber = nextFiber; 11657 } 11658 } 11659 11660 function prepareToReadContext(workInProgress, renderExpirationTime) { 11661 currentlyRenderingFiber = workInProgress; 11662 lastContextDependency = null; 11663 lastContextWithAllBitsObserved = null; 11664 11665 var currentDependencies = workInProgress.contextDependencies; 11666 if (currentDependencies !== null && currentDependencies.expirationTime >= renderExpirationTime) { 11667 // Context list has a pending update. Mark that this fiber performed work. 11668 markWorkInProgressReceivedUpdate(); 11669 } 11670 11671 // Reset the work-in-progress list 11672 workInProgress.contextDependencies = null; 11673 } 11674 11675 function readContext(context, observedBits) { 11676 if (lastContextWithAllBitsObserved === context) { 11677 // Nothing to do. We already observe everything in this context. 11678 } else if (observedBits === false || observedBits === 0) { 11679 // Do not observe any updates. 11680 } else { 11681 var resolvedObservedBits = void 0; // Avoid deopting on observable arguments or heterogeneous types. 11682 if (typeof observedBits !== 'number' || observedBits === maxSigned31BitInt) { 11683 // Observe all updates. 11684 lastContextWithAllBitsObserved = context; 11685 resolvedObservedBits = maxSigned31BitInt; 11686 } else { 11687 resolvedObservedBits = observedBits; 11688 } 11689 11690 var contextItem = { 11691 context: context, 11692 observedBits: resolvedObservedBits, 11693 next: null 11694 }; 11695 11696 if (lastContextDependency === null) { 11697 !(currentlyRenderingFiber !== null) ? reactProdInvariant('308') : void 0; 11698 11699 // This is the first dependency for this component. Create a new list. 11700 lastContextDependency = contextItem; 11701 currentlyRenderingFiber.contextDependencies = { 11702 first: contextItem, 11703 expirationTime: NoWork 11704 }; 11705 } else { 11706 // Append a new context item. 11707 lastContextDependency = lastContextDependency.next = contextItem; 11708 } 11709 } 11710 return isPrimaryRenderer ? context._currentValue : context._currentValue2; 11711 } 11712 11713 // UpdateQueue is a linked list of prioritized updates. 11714 // 11715 // Like fibers, update queues come in pairs: a current queue, which represents 11716 // the visible state of the screen, and a work-in-progress queue, which can be 11717 // mutated and processed asynchronously before it is committed — a form of 11718 // double buffering. If a work-in-progress render is discarded before finishing, 11719 // we create a new work-in-progress by cloning the current queue. 11720 // 11721 // Both queues share a persistent, singly-linked list structure. To schedule an 11722 // update, we append it to the end of both queues. Each queue maintains a 11723 // pointer to first update in the persistent list that hasn't been processed. 11724 // The work-in-progress pointer always has a position equal to or greater than 11725 // the current queue, since we always work on that one. The current queue's 11726 // pointer is only updated during the commit phase, when we swap in the 11727 // work-in-progress. 11728 // 11729 // For example: 11730 // 11731 // Current pointer: A - B - C - D - E - F 11732 // Work-in-progress pointer: D - E - F 11733 // ^ 11734 // The work-in-progress queue has 11735 // processed more updates than current. 11736 // 11737 // The reason we append to both queues is because otherwise we might drop 11738 // updates without ever processing them. For example, if we only add updates to 11739 // the work-in-progress queue, some updates could be lost whenever a work-in 11740 // -progress render restarts by cloning from current. Similarly, if we only add 11741 // updates to the current queue, the updates will be lost whenever an already 11742 // in-progress queue commits and swaps with the current queue. However, by 11743 // adding to both queues, we guarantee that the update will be part of the next 11744 // work-in-progress. (And because the work-in-progress queue becomes the 11745 // current queue once it commits, there's no danger of applying the same 11746 // update twice.) 11747 // 11748 // Prioritization 11749 // -------------- 11750 // 11751 // Updates are not sorted by priority, but by insertion; new updates are always 11752 // appended to the end of the list. 11753 // 11754 // The priority is still important, though. When processing the update queue 11755 // during the render phase, only the updates with sufficient priority are 11756 // included in the result. If we skip an update because it has insufficient 11757 // priority, it remains in the queue to be processed later, during a lower 11758 // priority render. Crucially, all updates subsequent to a skipped update also 11759 // remain in the queue *regardless of their priority*. That means high priority 11760 // updates are sometimes processed twice, at two separate priorities. We also 11761 // keep track of a base state, that represents the state before the first 11762 // update in the queue is applied. 11763 // 11764 // For example: 11765 // 11766 // Given a base state of '', and the following queue of updates 11767 // 11768 // A1 - B2 - C1 - D2 11769 // 11770 // where the number indicates the priority, and the update is applied to the 11771 // previous state by appending a letter, React will process these updates as 11772 // two separate renders, one per distinct priority level: 11773 // 11774 // First render, at priority 1: 11775 // Base state: '' 11776 // Updates: [A1, C1] 11777 // Result state: 'AC' 11778 // 11779 // Second render, at priority 2: 11780 // Base state: 'A' <- The base state does not include C1, 11781 // because B2 was skipped. 11782 // Updates: [B2, C1, D2] <- C1 was rebased on top of B2 11783 // Result state: 'ABCD' 11784 // 11785 // Because we process updates in insertion order, and rebase high priority 11786 // updates when preceding updates are skipped, the final result is deterministic 11787 // regardless of priority. Intermediate state may vary according to system 11788 // resources, but the final state is always the same. 11789 11790 var UpdateState = 0; 11791 var ReplaceState = 1; 11792 var ForceUpdate = 2; 11793 var CaptureUpdate = 3; 11794 11795 // Global state that is reset at the beginning of calling `processUpdateQueue`. 11796 // It should only be read right after calling `processUpdateQueue`, via 11797 // `checkHasForceUpdateAfterProcessing`. 11798 var hasForceUpdate = false; 11799 11800 11801 function createUpdateQueue(baseState) { 11802 var queue = { 11803 baseState: baseState, 11804 firstUpdate: null, 11805 lastUpdate: null, 11806 firstCapturedUpdate: null, 11807 lastCapturedUpdate: null, 11808 firstEffect: null, 11809 lastEffect: null, 11810 firstCapturedEffect: null, 11811 lastCapturedEffect: null 11812 }; 11813 return queue; 11814 } 11815 11816 function cloneUpdateQueue(currentQueue) { 11817 var queue = { 11818 baseState: currentQueue.baseState, 11819 firstUpdate: currentQueue.firstUpdate, 11820 lastUpdate: currentQueue.lastUpdate, 11821 11822 // TODO: With resuming, if we bail out and resuse the child tree, we should 11823 // keep these effects. 11824 firstCapturedUpdate: null, 11825 lastCapturedUpdate: null, 11826 11827 firstEffect: null, 11828 lastEffect: null, 11829 11830 firstCapturedEffect: null, 11831 lastCapturedEffect: null 11832 }; 11833 return queue; 11834 } 11835 11836 function createUpdate(expirationTime) { 11837 return { 11838 expirationTime: expirationTime, 11839 11840 tag: UpdateState, 11841 payload: null, 11842 callback: null, 11843 11844 next: null, 11845 nextEffect: null 11846 }; 11847 } 11848 11849 function appendUpdateToQueue(queue, update) { 11850 // Append the update to the end of the list. 11851 if (queue.lastUpdate === null) { 11852 // Queue is empty 11853 queue.firstUpdate = queue.lastUpdate = update; 11854 } else { 11855 queue.lastUpdate.next = update; 11856 queue.lastUpdate = update; 11857 } 11858 } 11859 11860 function enqueueUpdate(fiber, update) { 11861 // Update queues are created lazily. 11862 var alternate = fiber.alternate; 11863 var queue1 = void 0; 11864 var queue2 = void 0; 11865 if (alternate === null) { 11866 // There's only one fiber. 11867 queue1 = fiber.updateQueue; 11868 queue2 = null; 11869 if (queue1 === null) { 11870 queue1 = fiber.updateQueue = createUpdateQueue(fiber.memoizedState); 11871 } 11872 } else { 11873 // There are two owners. 11874 queue1 = fiber.updateQueue; 11875 queue2 = alternate.updateQueue; 11876 if (queue1 === null) { 11877 if (queue2 === null) { 11878 // Neither fiber has an update queue. Create new ones. 11879 queue1 = fiber.updateQueue = createUpdateQueue(fiber.memoizedState); 11880 queue2 = alternate.updateQueue = createUpdateQueue(alternate.memoizedState); 11881 } else { 11882 // Only one fiber has an update queue. Clone to create a new one. 11883 queue1 = fiber.updateQueue = cloneUpdateQueue(queue2); 11884 } 11885 } else { 11886 if (queue2 === null) { 11887 // Only one fiber has an update queue. Clone to create a new one. 11888 queue2 = alternate.updateQueue = cloneUpdateQueue(queue1); 11889 } else { 11890 // Both owners have an update queue. 11891 } 11892 } 11893 } 11894 if (queue2 === null || queue1 === queue2) { 11895 // There's only a single queue. 11896 appendUpdateToQueue(queue1, update); 11897 } else { 11898 // There are two queues. We need to append the update to both queues, 11899 // while accounting for the persistent structure of the list — we don't 11900 // want the same update to be added multiple times. 11901 if (queue1.lastUpdate === null || queue2.lastUpdate === null) { 11902 // One of the queues is not empty. We must add the update to both queues. 11903 appendUpdateToQueue(queue1, update); 11904 appendUpdateToQueue(queue2, update); 11905 } else { 11906 // Both queues are non-empty. The last update is the same in both lists, 11907 // because of structural sharing. So, only append to one of the lists. 11908 appendUpdateToQueue(queue1, update); 11909 // But we still need to update the `lastUpdate` pointer of queue2. 11910 queue2.lastUpdate = update; 11911 } 11912 } 11913 11914 11915 } 11916 11917 function enqueueCapturedUpdate(workInProgress, update) { 11918 // Captured updates go into a separate list, and only on the work-in- 11919 // progress queue. 11920 var workInProgressQueue = workInProgress.updateQueue; 11921 if (workInProgressQueue === null) { 11922 workInProgressQueue = workInProgress.updateQueue = createUpdateQueue(workInProgress.memoizedState); 11923 } else { 11924 // TODO: I put this here rather than createWorkInProgress so that we don't 11925 // clone the queue unnecessarily. There's probably a better way to 11926 // structure this. 11927 workInProgressQueue = ensureWorkInProgressQueueIsAClone(workInProgress, workInProgressQueue); 11928 } 11929 11930 // Append the update to the end of the list. 11931 if (workInProgressQueue.lastCapturedUpdate === null) { 11932 // This is the first render phase update 11933 workInProgressQueue.firstCapturedUpdate = workInProgressQueue.lastCapturedUpdate = update; 11934 } else { 11935 workInProgressQueue.lastCapturedUpdate.next = update; 11936 workInProgressQueue.lastCapturedUpdate = update; 11937 } 11938 } 11939 11940 function ensureWorkInProgressQueueIsAClone(workInProgress, queue) { 11941 var current = workInProgress.alternate; 11942 if (current !== null) { 11943 // If the work-in-progress queue is equal to the current queue, 11944 // we need to clone it first. 11945 if (queue === current.updateQueue) { 11946 queue = workInProgress.updateQueue = cloneUpdateQueue(queue); 11947 } 11948 } 11949 return queue; 11950 } 11951 11952 function getStateFromUpdate(workInProgress, queue, update, prevState, nextProps, instance) { 11953 switch (update.tag) { 11954 case ReplaceState: 11955 { 11956 var _payload = update.payload; 11957 if (typeof _payload === 'function') { 11958 // Updater function 11959 var nextState = _payload.call(instance, prevState, nextProps); 11960 return nextState; 11961 } 11962 // State object 11963 return _payload; 11964 } 11965 case CaptureUpdate: 11966 { 11967 workInProgress.effectTag = workInProgress.effectTag & ~ShouldCapture | DidCapture; 11968 } 11969 // Intentional fallthrough 11970 case UpdateState: 11971 { 11972 var _payload2 = update.payload; 11973 var partialState = void 0; 11974 if (typeof _payload2 === 'function') { 11975 // Updater function 11976 partialState = _payload2.call(instance, prevState, nextProps); 11977 11978 } else { 11979 // Partial state object 11980 partialState = _payload2; 11981 } 11982 if (partialState === null || partialState === undefined) { 11983 // Null and undefined are treated as no-ops. 11984 return prevState; 11985 } 11986 // Merge the partial state and the previous state. 11987 return _assign({}, prevState, partialState); 11988 } 11989 case ForceUpdate: 11990 { 11991 hasForceUpdate = true; 11992 return prevState; 11993 } 11994 } 11995 return prevState; 11996 } 11997 11998 function processUpdateQueue(workInProgress, queue, props, instance, renderExpirationTime) { 11999 hasForceUpdate = false; 12000 12001 queue = ensureWorkInProgressQueueIsAClone(workInProgress, queue); 12002 12003 var newBaseState = queue.baseState; 12004 var newFirstUpdate = null; 12005 var newExpirationTime = NoWork; 12006 12007 // Iterate through the list of updates to compute the result. 12008 var update = queue.firstUpdate; 12009 var resultState = newBaseState; 12010 while (update !== null) { 12011 var updateExpirationTime = update.expirationTime; 12012 if (updateExpirationTime < renderExpirationTime) { 12013 // This update does not have sufficient priority. Skip it. 12014 if (newFirstUpdate === null) { 12015 // This is the first skipped update. It will be the first update in 12016 // the new list. 12017 newFirstUpdate = update; 12018 // Since this is the first update that was skipped, the current result 12019 // is the new base state. 12020 newBaseState = resultState; 12021 } 12022 // Since this update will remain in the list, update the remaining 12023 // expiration time. 12024 if (newExpirationTime < updateExpirationTime) { 12025 newExpirationTime = updateExpirationTime; 12026 } 12027 } else { 12028 // This update does have sufficient priority. Process it and compute 12029 // a new result. 12030 resultState = getStateFromUpdate(workInProgress, queue, update, resultState, props, instance); 12031 var _callback = update.callback; 12032 if (_callback !== null) { 12033 workInProgress.effectTag |= Callback; 12034 // Set this to null, in case it was mutated during an aborted render. 12035 update.nextEffect = null; 12036 if (queue.lastEffect === null) { 12037 queue.firstEffect = queue.lastEffect = update; 12038 } else { 12039 queue.lastEffect.nextEffect = update; 12040 queue.lastEffect = update; 12041 } 12042 } 12043 } 12044 // Continue to the next update. 12045 update = update.next; 12046 } 12047 12048 // Separately, iterate though the list of captured updates. 12049 var newFirstCapturedUpdate = null; 12050 update = queue.firstCapturedUpdate; 12051 while (update !== null) { 12052 var _updateExpirationTime = update.expirationTime; 12053 if (_updateExpirationTime < renderExpirationTime) { 12054 // This update does not have sufficient priority. Skip it. 12055 if (newFirstCapturedUpdate === null) { 12056 // This is the first skipped captured update. It will be the first 12057 // update in the new list. 12058 newFirstCapturedUpdate = update; 12059 // If this is the first update that was skipped, the current result is 12060 // the new base state. 12061 if (newFirstUpdate === null) { 12062 newBaseState = resultState; 12063 } 12064 } 12065 // Since this update will remain in the list, update the remaining 12066 // expiration time. 12067 if (newExpirationTime < _updateExpirationTime) { 12068 newExpirationTime = _updateExpirationTime; 12069 } 12070 } else { 12071 // This update does have sufficient priority. Process it and compute 12072 // a new result. 12073 resultState = getStateFromUpdate(workInProgress, queue, update, resultState, props, instance); 12074 var _callback2 = update.callback; 12075 if (_callback2 !== null) { 12076 workInProgress.effectTag |= Callback; 12077 // Set this to null, in case it was mutated during an aborted render. 12078 update.nextEffect = null; 12079 if (queue.lastCapturedEffect === null) { 12080 queue.firstCapturedEffect = queue.lastCapturedEffect = update; 12081 } else { 12082 queue.lastCapturedEffect.nextEffect = update; 12083 queue.lastCapturedEffect = update; 12084 } 12085 } 12086 } 12087 update = update.next; 12088 } 12089 12090 if (newFirstUpdate === null) { 12091 queue.lastUpdate = null; 12092 } 12093 if (newFirstCapturedUpdate === null) { 12094 queue.lastCapturedUpdate = null; 12095 } else { 12096 workInProgress.effectTag |= Callback; 12097 } 12098 if (newFirstUpdate === null && newFirstCapturedUpdate === null) { 12099 // We processed every update, without skipping. That means the new base 12100 // state is the same as the result state. 12101 newBaseState = resultState; 12102 } 12103 12104 queue.baseState = newBaseState; 12105 queue.firstUpdate = newFirstUpdate; 12106 queue.firstCapturedUpdate = newFirstCapturedUpdate; 12107 12108 // Set the remaining expiration time to be whatever is remaining in the queue. 12109 // This should be fine because the only two other things that contribute to 12110 // expiration time are props and context. We're already in the middle of the 12111 // begin phase by the time we start processing the queue, so we've already 12112 // dealt with the props. Context in components that specify 12113 // shouldComponentUpdate is tricky; but we'll have to account for 12114 // that regardless. 12115 workInProgress.expirationTime = newExpirationTime; 12116 workInProgress.memoizedState = resultState; 12117 12118 12119 } 12120 12121 function callCallback(callback, context) { 12122 !(typeof callback === 'function') ? reactProdInvariant('191', callback) : void 0; 12123 callback.call(context); 12124 } 12125 12126 function resetHasForceUpdateBeforeProcessing() { 12127 hasForceUpdate = false; 12128 } 12129 12130 function checkHasForceUpdateAfterProcessing() { 12131 return hasForceUpdate; 12132 } 12133 12134 function commitUpdateQueue(finishedWork, finishedQueue, instance, renderExpirationTime) { 12135 // If the finished render included captured updates, and there are still 12136 // lower priority updates left over, we need to keep the captured updates 12137 // in the queue so that they are rebased and not dropped once we process the 12138 // queue again at the lower priority. 12139 if (finishedQueue.firstCapturedUpdate !== null) { 12140 // Join the captured update list to the end of the normal list. 12141 if (finishedQueue.lastUpdate !== null) { 12142 finishedQueue.lastUpdate.next = finishedQueue.firstCapturedUpdate; 12143 finishedQueue.lastUpdate = finishedQueue.lastCapturedUpdate; 12144 } 12145 // Clear the list of captured updates. 12146 finishedQueue.firstCapturedUpdate = finishedQueue.lastCapturedUpdate = null; 12147 } 12148 12149 // Commit the effects 12150 commitUpdateEffects(finishedQueue.firstEffect, instance); 12151 finishedQueue.firstEffect = finishedQueue.lastEffect = null; 12152 12153 commitUpdateEffects(finishedQueue.firstCapturedEffect, instance); 12154 finishedQueue.firstCapturedEffect = finishedQueue.lastCapturedEffect = null; 12155 } 12156 12157 function commitUpdateEffects(effect, instance) { 12158 while (effect !== null) { 12159 var _callback3 = effect.callback; 12160 if (_callback3 !== null) { 12161 effect.callback = null; 12162 callCallback(_callback3, instance); 12163 } 12164 effect = effect.nextEffect; 12165 } 12166 } 12167 12168 function createCapturedValue(value, source) { 12169 // If the value is an error, call this function immediately after it is thrown 12170 // so the stack is accurate. 12171 return { 12172 value: value, 12173 source: source, 12174 stack: getStackByFiberInDevAndProd(source) 12175 }; 12176 } 12177 12178 function markUpdate(workInProgress) { 12179 // Tag the fiber with an update effect. This turns a Placement into 12180 // a PlacementAndUpdate. 12181 workInProgress.effectTag |= Update; 12182 } 12183 12184 function markRef$1(workInProgress) { 12185 workInProgress.effectTag |= Ref; 12186 } 12187 12188 var appendAllChildren = void 0; 12189 var updateHostContainer = void 0; 12190 var updateHostComponent$1 = void 0; 12191 var updateHostText$1 = void 0; 12192 if (supportsMutation) { 12193 // Mutation mode 12194 12195 appendAllChildren = function (parent, workInProgress, needsVisibilityToggle, isHidden) { 12196 // We only have the top Fiber that was created but we need recurse down its 12197 // children to find all the terminal nodes. 12198 var node = workInProgress.child; 12199 while (node !== null) { 12200 if (node.tag === HostComponent || node.tag === HostText) { 12201 appendInitialChild(parent, node.stateNode); 12202 } else if (node.tag === HostPortal) { 12203 // If we have a portal child, then we don't want to traverse 12204 // down its children. Instead, we'll get insertions from each child in 12205 // the portal directly. 12206 } else if (node.child !== null) { 12207 node.child.return = node; 12208 node = node.child; 12209 continue; 12210 } 12211 if (node === workInProgress) { 12212 return; 12213 } 12214 while (node.sibling === null) { 12215 if (node.return === null || node.return === workInProgress) { 12216 return; 12217 } 12218 node = node.return; 12219 } 12220 node.sibling.return = node.return; 12221 node = node.sibling; 12222 } 12223 }; 12224 12225 updateHostContainer = function (workInProgress) { 12226 // Noop 12227 }; 12228 updateHostComponent$1 = function (current, workInProgress, type, newProps, rootContainerInstance) { 12229 // If we have an alternate, that means this is an update and we need to 12230 // schedule a side-effect to do the updates. 12231 var oldProps = current.memoizedProps; 12232 if (oldProps === newProps) { 12233 // In mutation mode, this is sufficient for a bailout because 12234 // we won't touch this node even if children changed. 12235 return; 12236 } 12237 12238 // If we get updated because one of our children updated, we don't 12239 // have newProps so we'll have to reuse them. 12240 // TODO: Split the update API as separate for the props vs. children. 12241 // Even better would be if children weren't special cased at all tho. 12242 var instance = workInProgress.stateNode; 12243 var currentHostContext = getHostContext(); 12244 // TODO: Experiencing an error where oldProps is null. Suggests a host 12245 // component is hitting the resume path. Figure out why. Possibly 12246 // related to `hidden`. 12247 var updatePayload = prepareUpdate(instance, type, oldProps, newProps, rootContainerInstance, currentHostContext); 12248 // TODO: Type this specific to this type of component. 12249 workInProgress.updateQueue = updatePayload; 12250 // If the update payload indicates that there is a change or if there 12251 // is a new ref we mark this as an update. All the work is done in commitWork. 12252 if (updatePayload) { 12253 markUpdate(workInProgress); 12254 } 12255 }; 12256 updateHostText$1 = function (current, workInProgress, oldText, newText) { 12257 // If the text differs, mark it as an update. All the work in done in commitWork. 12258 if (oldText !== newText) { 12259 markUpdate(workInProgress); 12260 } 12261 }; 12262 } else if (supportsPersistence) { 12263 // Persistent host tree mode 12264 12265 appendAllChildren = function (parent, workInProgress, needsVisibilityToggle, isHidden) { 12266 // We only have the top Fiber that was created but we need recurse down its 12267 // children to find all the terminal nodes. 12268 var node = workInProgress.child; 12269 while (node !== null) { 12270 // eslint-disable-next-line no-labels 12271 branches: if (node.tag === HostComponent) { 12272 var instance = node.stateNode; 12273 if (needsVisibilityToggle) { 12274 var props = node.memoizedProps; 12275 var type = node.type; 12276 if (isHidden) { 12277 // This child is inside a timed out tree. Hide it. 12278 instance = cloneHiddenInstance(instance, type, props, node); 12279 } else { 12280 // This child was previously inside a timed out tree. If it was not 12281 // updated during this render, it may need to be unhidden. Clone 12282 // again to be sure. 12283 instance = cloneUnhiddenInstance(instance, type, props, node); 12284 } 12285 node.stateNode = instance; 12286 } 12287 appendInitialChild(parent, instance); 12288 } else if (node.tag === HostText) { 12289 var _instance = node.stateNode; 12290 if (needsVisibilityToggle) { 12291 var text = node.memoizedProps; 12292 var rootContainerInstance = getRootHostContainer(); 12293 var currentHostContext = getHostContext(); 12294 if (isHidden) { 12295 _instance = createHiddenTextInstance(text, rootContainerInstance, currentHostContext, workInProgress); 12296 } else { 12297 _instance = createTextInstance(text, rootContainerInstance, currentHostContext, workInProgress); 12298 } 12299 node.stateNode = _instance; 12300 } 12301 appendInitialChild(parent, _instance); 12302 } else if (node.tag === HostPortal) { 12303 // If we have a portal child, then we don't want to traverse 12304 // down its children. Instead, we'll get insertions from each child in 12305 // the portal directly. 12306 } else if (node.tag === SuspenseComponent) { 12307 var current = node.alternate; 12308 if (current !== null) { 12309 var oldState = current.memoizedState; 12310 var newState = node.memoizedState; 12311 var oldIsHidden = oldState !== null; 12312 var newIsHidden = newState !== null; 12313 if (oldIsHidden !== newIsHidden) { 12314 // The placeholder either just timed out or switched back to the normal 12315 // children after having previously timed out. Toggle the visibility of 12316 // the direct host children. 12317 var primaryChildParent = newIsHidden ? node.child : node; 12318 if (primaryChildParent !== null) { 12319 appendAllChildren(parent, primaryChildParent, true, newIsHidden); 12320 } 12321 // eslint-disable-next-line no-labels 12322 break branches; 12323 } 12324 } 12325 if (node.child !== null) { 12326 // Continue traversing like normal 12327 node.child.return = node; 12328 node = node.child; 12329 continue; 12330 } 12331 } else if (node.child !== null) { 12332 node.child.return = node; 12333 node = node.child; 12334 continue; 12335 } 12336 // $FlowFixMe This is correct but Flow is confused by the labeled break. 12337 node = node; 12338 if (node === workInProgress) { 12339 return; 12340 } 12341 while (node.sibling === null) { 12342 if (node.return === null || node.return === workInProgress) { 12343 return; 12344 } 12345 node = node.return; 12346 } 12347 node.sibling.return = node.return; 12348 node = node.sibling; 12349 } 12350 }; 12351 12352 // An unfortunate fork of appendAllChildren because we have two different parent types. 12353 var appendAllChildrenToContainer = function (containerChildSet, workInProgress, needsVisibilityToggle, isHidden) { 12354 // We only have the top Fiber that was created but we need recurse down its 12355 // children to find all the terminal nodes. 12356 var node = workInProgress.child; 12357 while (node !== null) { 12358 // eslint-disable-next-line no-labels 12359 branches: if (node.tag === HostComponent) { 12360 var instance = node.stateNode; 12361 if (needsVisibilityToggle) { 12362 var props = node.memoizedProps; 12363 var type = node.type; 12364 if (isHidden) { 12365 // This child is inside a timed out tree. Hide it. 12366 instance = cloneHiddenInstance(instance, type, props, node); 12367 } else { 12368 // This child was previously inside a timed out tree. If it was not 12369 // updated during this render, it may need to be unhidden. Clone 12370 // again to be sure. 12371 instance = cloneUnhiddenInstance(instance, type, props, node); 12372 } 12373 node.stateNode = instance; 12374 } 12375 appendChildToContainerChildSet(containerChildSet, instance); 12376 } else if (node.tag === HostText) { 12377 var _instance2 = node.stateNode; 12378 if (needsVisibilityToggle) { 12379 var text = node.memoizedProps; 12380 var rootContainerInstance = getRootHostContainer(); 12381 var currentHostContext = getHostContext(); 12382 if (isHidden) { 12383 _instance2 = createHiddenTextInstance(text, rootContainerInstance, currentHostContext, workInProgress); 12384 } else { 12385 _instance2 = createTextInstance(text, rootContainerInstance, currentHostContext, workInProgress); 12386 } 12387 node.stateNode = _instance2; 12388 } 12389 appendChildToContainerChildSet(containerChildSet, _instance2); 12390 } else if (node.tag === HostPortal) { 12391 // If we have a portal child, then we don't want to traverse 12392 // down its children. Instead, we'll get insertions from each child in 12393 // the portal directly. 12394 } else if (node.tag === SuspenseComponent) { 12395 var current = node.alternate; 12396 if (current !== null) { 12397 var oldState = current.memoizedState; 12398 var newState = node.memoizedState; 12399 var oldIsHidden = oldState !== null; 12400 var newIsHidden = newState !== null; 12401 if (oldIsHidden !== newIsHidden) { 12402 // The placeholder either just timed out or switched back to the normal 12403 // children after having previously timed out. Toggle the visibility of 12404 // the direct host children. 12405 var primaryChildParent = newIsHidden ? node.child : node; 12406 if (primaryChildParent !== null) { 12407 appendAllChildrenToContainer(containerChildSet, primaryChildParent, true, newIsHidden); 12408 } 12409 // eslint-disable-next-line no-labels 12410 break branches; 12411 } 12412 } 12413 if (node.child !== null) { 12414 // Continue traversing like normal 12415 node.child.return = node; 12416 node = node.child; 12417 continue; 12418 } 12419 } else if (node.child !== null) { 12420 node.child.return = node; 12421 node = node.child; 12422 continue; 12423 } 12424 // $FlowFixMe This is correct but Flow is confused by the labeled break. 12425 node = node; 12426 if (node === workInProgress) { 12427 return; 12428 } 12429 while (node.sibling === null) { 12430 if (node.return === null || node.return === workInProgress) { 12431 return; 12432 } 12433 node = node.return; 12434 } 12435 node.sibling.return = node.return; 12436 node = node.sibling; 12437 } 12438 }; 12439 updateHostContainer = function (workInProgress) { 12440 var portalOrRoot = workInProgress.stateNode; 12441 var childrenUnchanged = workInProgress.firstEffect === null; 12442 if (childrenUnchanged) { 12443 // No changes, just reuse the existing instance. 12444 } else { 12445 var container = portalOrRoot.containerInfo; 12446 var newChildSet = createContainerChildSet(container); 12447 // If children might have changed, we have to add them all to the set. 12448 appendAllChildrenToContainer(newChildSet, workInProgress, false, false); 12449 portalOrRoot.pendingChildren = newChildSet; 12450 // Schedule an update on the container to swap out the container. 12451 markUpdate(workInProgress); 12452 finalizeContainerChildren(container, newChildSet); 12453 } 12454 }; 12455 updateHostComponent$1 = function (current, workInProgress, type, newProps, rootContainerInstance) { 12456 var currentInstance = current.stateNode; 12457 var oldProps = current.memoizedProps; 12458 // If there are no effects associated with this node, then none of our children had any updates. 12459 // This guarantees that we can reuse all of them. 12460 var childrenUnchanged = workInProgress.firstEffect === null; 12461 if (childrenUnchanged && oldProps === newProps) { 12462 // No changes, just reuse the existing instance. 12463 // Note that this might release a previous clone. 12464 workInProgress.stateNode = currentInstance; 12465 return; 12466 } 12467 var recyclableInstance = workInProgress.stateNode; 12468 var currentHostContext = getHostContext(); 12469 var updatePayload = null; 12470 if (oldProps !== newProps) { 12471 updatePayload = prepareUpdate(recyclableInstance, type, oldProps, newProps, rootContainerInstance, currentHostContext); 12472 } 12473 if (childrenUnchanged && updatePayload === null) { 12474 // No changes, just reuse the existing instance. 12475 // Note that this might release a previous clone. 12476 workInProgress.stateNode = currentInstance; 12477 return; 12478 } 12479 var newInstance = cloneInstance(currentInstance, updatePayload, type, oldProps, newProps, workInProgress, childrenUnchanged, recyclableInstance); 12480 if (finalizeInitialChildren(newInstance, type, newProps, rootContainerInstance, currentHostContext)) { 12481 markUpdate(workInProgress); 12482 } 12483 workInProgress.stateNode = newInstance; 12484 if (childrenUnchanged) { 12485 // If there are no other effects in this tree, we need to flag this node as having one. 12486 // Even though we're not going to use it for anything. 12487 // Otherwise parents won't know that there are new children to propagate upwards. 12488 markUpdate(workInProgress); 12489 } else { 12490 // If children might have changed, we have to add them all to the set. 12491 appendAllChildren(newInstance, workInProgress, false, false); 12492 } 12493 }; 12494 updateHostText$1 = function (current, workInProgress, oldText, newText) { 12495 if (oldText !== newText) { 12496 // If the text content differs, we'll create a new text instance for it. 12497 var rootContainerInstance = getRootHostContainer(); 12498 var currentHostContext = getHostContext(); 12499 workInProgress.stateNode = createTextInstance(newText, rootContainerInstance, currentHostContext, workInProgress); 12500 // We'll have to mark it as having an effect, even though we won't use the effect for anything. 12501 // This lets the parents know that at least one of their children has changed. 12502 markUpdate(workInProgress); 12503 } 12504 }; 12505 } else { 12506 // No host operations 12507 updateHostContainer = function (workInProgress) { 12508 // Noop 12509 }; 12510 updateHostComponent$1 = function (current, workInProgress, type, newProps, rootContainerInstance) { 12511 // Noop 12512 }; 12513 updateHostText$1 = function (current, workInProgress, oldText, newText) { 12514 // Noop 12515 }; 12516 } 12517 12518 function completeWork(current, workInProgress, renderExpirationTime) { 12519 var newProps = workInProgress.pendingProps; 12520 12521 switch (workInProgress.tag) { 12522 case IndeterminateComponent: 12523 break; 12524 case LazyComponent: 12525 break; 12526 case SimpleMemoComponent: 12527 case FunctionComponent: 12528 break; 12529 case ClassComponent: 12530 { 12531 var Component = workInProgress.type; 12532 if (isContextProvider(Component)) { 12533 popContext(workInProgress); 12534 } 12535 break; 12536 } 12537 case HostRoot: 12538 { 12539 popHostContainer(workInProgress); 12540 popTopLevelContextObject(workInProgress); 12541 var fiberRoot = workInProgress.stateNode; 12542 if (fiberRoot.pendingContext) { 12543 fiberRoot.context = fiberRoot.pendingContext; 12544 fiberRoot.pendingContext = null; 12545 } 12546 if (current === null || current.child === null) { 12547 // If we hydrated, pop so that we can delete any remaining children 12548 // that weren't hydrated. 12549 popHydrationState(workInProgress); 12550 // This resets the hacky state to fix isMounted before committing. 12551 // TODO: Delete this when we delete isMounted and findDOMNode. 12552 workInProgress.effectTag &= ~Placement; 12553 } 12554 updateHostContainer(workInProgress); 12555 break; 12556 } 12557 case HostComponent: 12558 { 12559 popHostContext(workInProgress); 12560 var rootContainerInstance = getRootHostContainer(); 12561 var type = workInProgress.type; 12562 if (current !== null && workInProgress.stateNode != null) { 12563 updateHostComponent$1(current, workInProgress, type, newProps, rootContainerInstance); 12564 12565 if (current.ref !== workInProgress.ref) { 12566 markRef$1(workInProgress); 12567 } 12568 } else { 12569 if (!newProps) { 12570 !(workInProgress.stateNode !== null) ? reactProdInvariant('166') : void 0; 12571 // This can happen when we abort work. 12572 break; 12573 } 12574 12575 var currentHostContext = getHostContext(); 12576 // TODO: Move createInstance to beginWork and keep it on a context 12577 // "stack" as the parent. Then append children as we go in beginWork 12578 // or completeWork depending on we want to add then top->down or 12579 // bottom->up. Top->down is faster in IE11. 12580 var wasHydrated = popHydrationState(workInProgress); 12581 if (wasHydrated) { 12582 // TODO: Move this and createInstance step into the beginPhase 12583 // to consolidate. 12584 if (prepareToHydrateHostInstance(workInProgress, rootContainerInstance, currentHostContext)) { 12585 // If changes to the hydrated node needs to be applied at the 12586 // commit-phase we mark this as such. 12587 markUpdate(workInProgress); 12588 } 12589 } else { 12590 var instance = createInstance(type, newProps, rootContainerInstance, currentHostContext, workInProgress); 12591 12592 appendAllChildren(instance, workInProgress, false, false); 12593 12594 // Certain renderers require commit-time effects for initial mount. 12595 // (eg DOM renderer supports auto-focus for certain elements). 12596 // Make sure such renderers get scheduled for later work. 12597 if (finalizeInitialChildren(instance, type, newProps, rootContainerInstance, currentHostContext)) { 12598 markUpdate(workInProgress); 12599 } 12600 workInProgress.stateNode = instance; 12601 } 12602 12603 if (workInProgress.ref !== null) { 12604 // If there is a ref on a host node we need to schedule a callback 12605 markRef$1(workInProgress); 12606 } 12607 } 12608 break; 12609 } 12610 case HostText: 12611 { 12612 var newText = newProps; 12613 if (current && workInProgress.stateNode != null) { 12614 var oldText = current.memoizedProps; 12615 // If we have an alternate, that means this is an update and we need 12616 // to schedule a side-effect to do the updates. 12617 updateHostText$1(current, workInProgress, oldText, newText); 12618 } else { 12619 if (typeof newText !== 'string') { 12620 !(workInProgress.stateNode !== null) ? reactProdInvariant('166') : void 0; 12621 // This can happen when we abort work. 12622 } 12623 var _rootContainerInstance = getRootHostContainer(); 12624 var _currentHostContext = getHostContext(); 12625 var _wasHydrated = popHydrationState(workInProgress); 12626 if (_wasHydrated) { 12627 if (prepareToHydrateHostTextInstance(workInProgress)) { 12628 markUpdate(workInProgress); 12629 } 12630 } else { 12631 workInProgress.stateNode = createTextInstance(newText, _rootContainerInstance, _currentHostContext, workInProgress); 12632 } 12633 } 12634 break; 12635 } 12636 case ForwardRef: 12637 break; 12638 case SuspenseComponent: 12639 { 12640 var nextState = workInProgress.memoizedState; 12641 if ((workInProgress.effectTag & DidCapture) !== NoEffect) { 12642 // Something suspended. Re-render with the fallback children. 12643 workInProgress.expirationTime = renderExpirationTime; 12644 // Do not reset the effect list. 12645 return workInProgress; 12646 } 12647 12648 var nextDidTimeout = nextState !== null; 12649 var prevDidTimeout = current !== null && current.memoizedState !== null; 12650 12651 if (current !== null && !nextDidTimeout && prevDidTimeout) { 12652 // We just switched from the fallback to the normal children. Delete 12653 // the fallback. 12654 // TODO: Would it be better to store the fallback fragment on 12655 var currentFallbackChild = current.child.sibling; 12656 if (currentFallbackChild !== null) { 12657 // Deletions go at the beginning of the return fiber's effect list 12658 var first = workInProgress.firstEffect; 12659 if (first !== null) { 12660 workInProgress.firstEffect = currentFallbackChild; 12661 currentFallbackChild.nextEffect = first; 12662 } else { 12663 workInProgress.firstEffect = workInProgress.lastEffect = currentFallbackChild; 12664 currentFallbackChild.nextEffect = null; 12665 } 12666 currentFallbackChild.effectTag = Deletion; 12667 } 12668 } 12669 12670 if (nextDidTimeout || prevDidTimeout) { 12671 // If the children are hidden, or if they were previous hidden, schedule 12672 // an effect to toggle their visibility. This is also used to attach a 12673 // retry listener to the promise. 12674 workInProgress.effectTag |= Update; 12675 } 12676 break; 12677 } 12678 case Fragment: 12679 break; 12680 case Mode: 12681 break; 12682 case Profiler: 12683 break; 12684 case HostPortal: 12685 popHostContainer(workInProgress); 12686 updateHostContainer(workInProgress); 12687 break; 12688 case ContextProvider: 12689 // Pop provider fiber 12690 popProvider(workInProgress); 12691 break; 12692 case ContextConsumer: 12693 break; 12694 case MemoComponent: 12695 break; 12696 case IncompleteClassComponent: 12697 { 12698 // Same as class component case. I put it down here so that the tags are 12699 // sequential to ensure this switch is compiled to a jump table. 12700 var _Component = workInProgress.type; 12701 if (isContextProvider(_Component)) { 12702 popContext(workInProgress); 12703 } 12704 break; 12705 } 12706 case DehydratedSuspenseComponent: 12707 { 12708 if (enableSuspenseServerRenderer) { 12709 if (current === null) { 12710 var _wasHydrated2 = popHydrationState(workInProgress); 12711 !_wasHydrated2 ? reactProdInvariant('318') : void 0; 12712 skipPastDehydratedSuspenseInstance(workInProgress); 12713 } else if ((workInProgress.effectTag & DidCapture) === NoEffect) { 12714 // This boundary did not suspend so it's now hydrated. 12715 // To handle any future suspense cases, we're going to now upgrade it 12716 // to a Suspense component. We detach it from the existing current fiber. 12717 current.alternate = null; 12718 workInProgress.alternate = null; 12719 workInProgress.tag = SuspenseComponent; 12720 workInProgress.memoizedState = null; 12721 workInProgress.stateNode = null; 12722 } 12723 } 12724 break; 12725 } 12726 default: 12727 reactProdInvariant('156'); 12728 } 12729 12730 return null; 12731 } 12732 12733 function shouldCaptureSuspense(workInProgress) { 12734 // In order to capture, the Suspense component must have a fallback prop. 12735 if (workInProgress.memoizedProps.fallback === undefined) { 12736 return false; 12737 } 12738 // If it was the primary children that just suspended, capture and render the 12739 // fallback. Otherwise, don't capture and bubble to the next boundary. 12740 var nextState = workInProgress.memoizedState; 12741 return nextState === null; 12742 } 12743 12744 // This module is forked in different environments. 12745 // By default, return `true` to log errors to the console. 12746 // Forks can return `false` if this isn't desirable. 12747 function showErrorDialog(capturedError) { 12748 return true; 12749 } 12750 12751 function logCapturedError(capturedError) { 12752 var logError = showErrorDialog(capturedError); 12753 12754 // Allow injected showErrorDialog() to prevent default console.error logging. 12755 // This enables renderers like ReactNative to better manage redbox behavior. 12756 if (logError === false) { 12757 return; 12758 } 12759 12760 var error = capturedError.error; 12761 { 12762 // In production, we print the error directly. 12763 // This will include the message, the JS stack, and anything the browser wants to show. 12764 // We pass the error object instead of custom message so that the browser displays the error natively. 12765 console.error(error); 12766 } 12767 } 12768 12769 var PossiblyWeakSet$1 = typeof WeakSet === 'function' ? WeakSet : Set; 12770 12771 function logError(boundary, errorInfo) { 12772 var source = errorInfo.source; 12773 var stack = errorInfo.stack; 12774 if (stack === null && source !== null) { 12775 stack = getStackByFiberInDevAndProd(source); 12776 } 12777 12778 var capturedError = { 12779 componentName: source !== null ? getComponentName(source.type) : null, 12780 componentStack: stack !== null ? stack : '', 12781 error: errorInfo.value, 12782 errorBoundary: null, 12783 errorBoundaryName: null, 12784 errorBoundaryFound: false, 12785 willRetry: false 12786 }; 12787 12788 if (boundary !== null && boundary.tag === ClassComponent) { 12789 capturedError.errorBoundary = boundary.stateNode; 12790 capturedError.errorBoundaryName = getComponentName(boundary.type); 12791 capturedError.errorBoundaryFound = true; 12792 capturedError.willRetry = true; 12793 } 12794 12795 try { 12796 logCapturedError(capturedError); 12797 } catch (e) { 12798 // This method must not throw, or React internal state will get messed up. 12799 // If console.error is overridden, or logCapturedError() shows a dialog that throws, 12800 // we want to report this error outside of the normal stack as a last resort. 12801 // https://github.com/facebook/react/issues/13188 12802 setTimeout(function () { 12803 throw e; 12804 }); 12805 } 12806 } 12807 12808 var callComponentWillUnmountWithTimer = function (current$$1, instance) { 12809 startPhaseTimer(current$$1, 'componentWillUnmount'); 12810 instance.props = current$$1.memoizedProps; 12811 instance.state = current$$1.memoizedState; 12812 instance.componentWillUnmount(); 12813 stopPhaseTimer(); 12814 }; 12815 12816 // Capture errors so they don't interrupt unmounting. 12817 function safelyCallComponentWillUnmount(current$$1, instance) { 12818 { 12819 try { 12820 callComponentWillUnmountWithTimer(current$$1, instance); 12821 } catch (unmountError) { 12822 captureCommitPhaseError(current$$1, unmountError); 12823 } 12824 } 12825 } 12826 12827 function safelyDetachRef(current$$1) { 12828 var ref = current$$1.ref; 12829 if (ref !== null) { 12830 if (typeof ref === 'function') { 12831 { 12832 try { 12833 ref(null); 12834 } catch (refError) { 12835 captureCommitPhaseError(current$$1, refError); 12836 } 12837 } 12838 } else { 12839 ref.current = null; 12840 } 12841 } 12842 } 12843 12844 function safelyCallDestroy(current$$1, destroy) { 12845 { 12846 try { 12847 destroy(); 12848 } catch (error) { 12849 captureCommitPhaseError(current$$1, error); 12850 } 12851 } 12852 } 12853 12854 function commitBeforeMutationLifeCycles(current$$1, finishedWork) { 12855 switch (finishedWork.tag) { 12856 case FunctionComponent: 12857 case ForwardRef: 12858 case SimpleMemoComponent: 12859 { 12860 commitHookEffectList(UnmountSnapshot, NoEffect$1, finishedWork); 12861 return; 12862 } 12863 case ClassComponent: 12864 { 12865 if (finishedWork.effectTag & Snapshot) { 12866 if (current$$1 !== null) { 12867 var prevProps = current$$1.memoizedProps; 12868 var prevState = current$$1.memoizedState; 12869 startPhaseTimer(finishedWork, 'getSnapshotBeforeUpdate'); 12870 var instance = finishedWork.stateNode; 12871 // We could update instance props and state here, 12872 // but instead we rely on them being set during last render. 12873 // TODO: revisit this when we implement resuming. 12874 var snapshot = instance.getSnapshotBeforeUpdate(finishedWork.elementType === finishedWork.type ? prevProps : resolveDefaultProps(finishedWork.type, prevProps), prevState); 12875 instance.__reactInternalSnapshotBeforeUpdate = snapshot; 12876 stopPhaseTimer(); 12877 } 12878 } 12879 return; 12880 } 12881 case HostRoot: 12882 case HostComponent: 12883 case HostText: 12884 case HostPortal: 12885 case IncompleteClassComponent: 12886 // Nothing to do for these component types 12887 return; 12888 default: 12889 { 12890 reactProdInvariant('163'); 12891 } 12892 } 12893 } 12894 12895 function commitHookEffectList(unmountTag, mountTag, finishedWork) { 12896 var updateQueue = finishedWork.updateQueue; 12897 var lastEffect = updateQueue !== null ? updateQueue.lastEffect : null; 12898 if (lastEffect !== null) { 12899 var firstEffect = lastEffect.next; 12900 var effect = firstEffect; 12901 do { 12902 if ((effect.tag & unmountTag) !== NoEffect$1) { 12903 // Unmount 12904 var destroy = effect.destroy; 12905 effect.destroy = undefined; 12906 if (destroy !== undefined) { 12907 destroy(); 12908 } 12909 } 12910 if ((effect.tag & mountTag) !== NoEffect$1) { 12911 // Mount 12912 var create = effect.create; 12913 effect.destroy = create(); 12914 12915 12916 } 12917 effect = effect.next; 12918 } while (effect !== firstEffect); 12919 } 12920 } 12921 12922 function commitPassiveHookEffects(finishedWork) { 12923 commitHookEffectList(UnmountPassive, NoEffect$1, finishedWork); 12924 commitHookEffectList(NoEffect$1, MountPassive, finishedWork); 12925 } 12926 12927 function commitLifeCycles(finishedRoot, current$$1, finishedWork, committedExpirationTime) { 12928 switch (finishedWork.tag) { 12929 case FunctionComponent: 12930 case ForwardRef: 12931 case SimpleMemoComponent: 12932 { 12933 commitHookEffectList(UnmountLayout, MountLayout, finishedWork); 12934 break; 12935 } 12936 case ClassComponent: 12937 { 12938 var instance = finishedWork.stateNode; 12939 if (finishedWork.effectTag & Update) { 12940 if (current$$1 === null) { 12941 startPhaseTimer(finishedWork, 'componentDidMount'); 12942 // We could update instance props and state here, 12943 // but instead we rely on them being set during last render. 12944 // TODO: revisit this when we implement resuming. 12945 instance.componentDidMount(); 12946 stopPhaseTimer(); 12947 } else { 12948 var prevProps = finishedWork.elementType === finishedWork.type ? current$$1.memoizedProps : resolveDefaultProps(finishedWork.type, current$$1.memoizedProps); 12949 var prevState = current$$1.memoizedState; 12950 startPhaseTimer(finishedWork, 'componentDidUpdate'); 12951 // We could update instance props and state here, 12952 // but instead we rely on them being set during last render. 12953 // TODO: revisit this when we implement resuming. 12954 instance.componentDidUpdate(prevProps, prevState, instance.__reactInternalSnapshotBeforeUpdate); 12955 stopPhaseTimer(); 12956 } 12957 } 12958 var updateQueue = finishedWork.updateQueue; 12959 if (updateQueue !== null) { 12960 commitUpdateQueue(finishedWork, updateQueue, instance, committedExpirationTime); 12961 } 12962 return; 12963 } 12964 case HostRoot: 12965 { 12966 var _updateQueue = finishedWork.updateQueue; 12967 if (_updateQueue !== null) { 12968 var _instance = null; 12969 if (finishedWork.child !== null) { 12970 switch (finishedWork.child.tag) { 12971 case HostComponent: 12972 _instance = getPublicInstance(finishedWork.child.stateNode); 12973 break; 12974 case ClassComponent: 12975 _instance = finishedWork.child.stateNode; 12976 break; 12977 } 12978 } 12979 commitUpdateQueue(finishedWork, _updateQueue, _instance, committedExpirationTime); 12980 } 12981 return; 12982 } 12983 case HostComponent: 12984 { 12985 var _instance2 = finishedWork.stateNode; 12986 12987 // Renderers may schedule work to be done after host components are mounted 12988 // (eg DOM renderer may schedule auto-focus for inputs and form controls). 12989 // These effects should only be committed when components are first mounted, 12990 // aka when there is no current/alternate. 12991 if (current$$1 === null && finishedWork.effectTag & Update) { 12992 var type = finishedWork.type; 12993 var props = finishedWork.memoizedProps; 12994 commitMount(_instance2, type, props, finishedWork); 12995 } 12996 12997 return; 12998 } 12999 case HostText: 13000 { 13001 // We have no life-cycles associated with text. 13002 return; 13003 } 13004 case HostPortal: 13005 { 13006 // We have no life-cycles associated with portals. 13007 return; 13008 } 13009 case Profiler: 13010 { 13011 if (enableProfilerTimer) { 13012 var onRender = finishedWork.memoizedProps.onRender; 13013 13014 if (enableSchedulerTracing) { 13015 onRender(finishedWork.memoizedProps.id, current$$1 === null ? 'mount' : 'update', finishedWork.actualDuration, finishedWork.treeBaseDuration, finishedWork.actualStartTime, getCommitTime(), finishedRoot.memoizedInteractions); 13016 } else { 13017 onRender(finishedWork.memoizedProps.id, current$$1 === null ? 'mount' : 'update', finishedWork.actualDuration, finishedWork.treeBaseDuration, finishedWork.actualStartTime, getCommitTime()); 13018 } 13019 } 13020 return; 13021 } 13022 case SuspenseComponent: 13023 break; 13024 case IncompleteClassComponent: 13025 break; 13026 default: 13027 { 13028 reactProdInvariant('163'); 13029 } 13030 } 13031 } 13032 13033 function hideOrUnhideAllChildren(finishedWork, isHidden) { 13034 if (supportsMutation) { 13035 // We only have the top Fiber that was inserted but we need to recurse down its 13036 var node = finishedWork; 13037 while (true) { 13038 if (node.tag === HostComponent) { 13039 var instance = node.stateNode; 13040 if (isHidden) { 13041 hideInstance(instance); 13042 } else { 13043 unhideInstance(node.stateNode, node.memoizedProps); 13044 } 13045 } else if (node.tag === HostText) { 13046 var _instance3 = node.stateNode; 13047 if (isHidden) { 13048 hideTextInstance(_instance3); 13049 } else { 13050 unhideTextInstance(_instance3, node.memoizedProps); 13051 } 13052 } else if (node.tag === SuspenseComponent && node.memoizedState !== null) { 13053 // Found a nested Suspense component that timed out. Skip over the 13054 var fallbackChildFragment = node.child.sibling; 13055 fallbackChildFragment.return = node; 13056 node = fallbackChildFragment; 13057 continue; 13058 } else if (node.child !== null) { 13059 node.child.return = node; 13060 node = node.child; 13061 continue; 13062 } 13063 if (node === finishedWork) { 13064 return; 13065 } 13066 while (node.sibling === null) { 13067 if (node.return === null || node.return === finishedWork) { 13068 return; 13069 } 13070 node = node.return; 13071 } 13072 node.sibling.return = node.return; 13073 node = node.sibling; 13074 } 13075 } 13076 } 13077 13078 function commitAttachRef(finishedWork) { 13079 var ref = finishedWork.ref; 13080 if (ref !== null) { 13081 var instance = finishedWork.stateNode; 13082 var instanceToUse = void 0; 13083 switch (finishedWork.tag) { 13084 case HostComponent: 13085 instanceToUse = getPublicInstance(instance); 13086 break; 13087 default: 13088 instanceToUse = instance; 13089 } 13090 if (typeof ref === 'function') { 13091 ref(instanceToUse); 13092 } else { 13093 ref.current = instanceToUse; 13094 } 13095 } 13096 } 13097 13098 function commitDetachRef(current$$1) { 13099 var currentRef = current$$1.ref; 13100 if (currentRef !== null) { 13101 if (typeof currentRef === 'function') { 13102 currentRef(null); 13103 } else { 13104 currentRef.current = null; 13105 } 13106 } 13107 } 13108 13109 // User-originating errors (lifecycles and refs) should not interrupt 13110 // deletion, so don't let them throw. Host-originating errors should 13111 // interrupt deletion, so it's okay 13112 function commitUnmount(current$$1) { 13113 onCommitUnmount(current$$1); 13114 13115 switch (current$$1.tag) { 13116 case FunctionComponent: 13117 case ForwardRef: 13118 case MemoComponent: 13119 case SimpleMemoComponent: 13120 { 13121 var updateQueue = current$$1.updateQueue; 13122 if (updateQueue !== null) { 13123 var lastEffect = updateQueue.lastEffect; 13124 if (lastEffect !== null) { 13125 var firstEffect = lastEffect.next; 13126 var effect = firstEffect; 13127 do { 13128 var destroy = effect.destroy; 13129 if (destroy !== undefined) { 13130 safelyCallDestroy(current$$1, destroy); 13131 } 13132 effect = effect.next; 13133 } while (effect !== firstEffect); 13134 } 13135 } 13136 break; 13137 } 13138 case ClassComponent: 13139 { 13140 safelyDetachRef(current$$1); 13141 var instance = current$$1.stateNode; 13142 if (typeof instance.componentWillUnmount === 'function') { 13143 safelyCallComponentWillUnmount(current$$1, instance); 13144 } 13145 return; 13146 } 13147 case HostComponent: 13148 { 13149 safelyDetachRef(current$$1); 13150 return; 13151 } 13152 case HostPortal: 13153 { 13154 // TODO: this is recursive. 13155 // We are also not using this parent because 13156 // the portal will get pushed immediately. 13157 if (supportsMutation) { 13158 unmountHostComponents(current$$1); 13159 } else if (supportsPersistence) { 13160 emptyPortalContainer(current$$1); 13161 } 13162 return; 13163 } 13164 } 13165 } 13166 13167 function commitNestedUnmounts(root) { 13168 // While we're inside a removed host node we don't want to call 13169 // removeChild on the inner nodes because they're removed by the top 13170 // call anyway. We also want to call componentWillUnmount on all 13171 // composites before this host node is removed from the tree. Therefore 13172 var node = root; 13173 while (true) { 13174 commitUnmount(node); 13175 // Visit children because they may contain more composite or host nodes. 13176 // Skip portals because commitUnmount() currently visits them recursively. 13177 if (node.child !== null && ( 13178 // If we use mutation we drill down into portals using commitUnmount above. 13179 // If we don't use mutation we drill down into portals here instead. 13180 !supportsMutation || node.tag !== HostPortal)) { 13181 node.child.return = node; 13182 node = node.child; 13183 continue; 13184 } 13185 if (node === root) { 13186 return; 13187 } 13188 while (node.sibling === null) { 13189 if (node.return === null || node.return === root) { 13190 return; 13191 } 13192 node = node.return; 13193 } 13194 node.sibling.return = node.return; 13195 node = node.sibling; 13196 } 13197 } 13198 13199 function detachFiber(current$$1) { 13200 // Cut off the return pointers to disconnect it from the tree. Ideally, we 13201 // should clear the child pointer of the parent alternate to let this 13202 // get GC:ed but we don't know which for sure which parent is the current 13203 // one so we'll settle for GC:ing the subtree of this child. This child 13204 // itself will be GC:ed when the parent updates the next time. 13205 current$$1.return = null; 13206 current$$1.child = null; 13207 current$$1.memoizedState = null; 13208 current$$1.updateQueue = null; 13209 var alternate = current$$1.alternate; 13210 if (alternate !== null) { 13211 alternate.return = null; 13212 alternate.child = null; 13213 alternate.memoizedState = null; 13214 alternate.updateQueue = null; 13215 } 13216 } 13217 13218 function emptyPortalContainer(current$$1) { 13219 if (!supportsPersistence) { 13220 return; 13221 } 13222 13223 var portal = current$$1.stateNode; 13224 var containerInfo = portal.containerInfo; 13225 13226 var emptyChildSet = createContainerChildSet(containerInfo); 13227 replaceContainerChildren(containerInfo, emptyChildSet); 13228 } 13229 13230 function commitContainer(finishedWork) { 13231 if (!supportsPersistence) { 13232 return; 13233 } 13234 13235 switch (finishedWork.tag) { 13236 case ClassComponent: 13237 { 13238 return; 13239 } 13240 case HostComponent: 13241 { 13242 return; 13243 } 13244 case HostText: 13245 { 13246 return; 13247 } 13248 case HostRoot: 13249 case HostPortal: 13250 { 13251 var portalOrRoot = finishedWork.stateNode; 13252 var containerInfo = portalOrRoot.containerInfo, 13253 _pendingChildren = portalOrRoot.pendingChildren; 13254 13255 replaceContainerChildren(containerInfo, _pendingChildren); 13256 return; 13257 } 13258 default: 13259 { 13260 reactProdInvariant('163'); 13261 } 13262 } 13263 } 13264 13265 function getHostParentFiber(fiber) { 13266 var parent = fiber.return; 13267 while (parent !== null) { 13268 if (isHostParent(parent)) { 13269 return parent; 13270 } 13271 parent = parent.return; 13272 } 13273 reactProdInvariant('160'); 13274 } 13275 13276 function isHostParent(fiber) { 13277 return fiber.tag === HostComponent || fiber.tag === HostRoot || fiber.tag === HostPortal; 13278 } 13279 13280 function getHostSibling(fiber) { 13281 // We're going to search forward into the tree until we find a sibling host 13282 // node. Unfortunately, if multiple insertions are done in a row we have to 13283 // search past them. This leads to exponential search for the next sibling. 13284 var node = fiber; 13285 siblings: while (true) { 13286 // If we didn't find anything, let's try the next sibling. 13287 while (node.sibling === null) { 13288 if (node.return === null || isHostParent(node.return)) { 13289 // If we pop out of the root or hit the parent the fiber we are the 13290 // last sibling. 13291 return null; 13292 } 13293 node = node.return; 13294 } 13295 node.sibling.return = node.return; 13296 node = node.sibling; 13297 while (node.tag !== HostComponent && node.tag !== HostText && node.tag !== DehydratedSuspenseComponent) { 13298 // If it is not host node and, we might have a host node inside it. 13299 // Try to search down until we find one. 13300 if (node.effectTag & Placement) { 13301 // If we don't have a child, try the siblings instead. 13302 continue siblings; 13303 } 13304 // If we don't have a child, try the siblings instead. 13305 // We also skip portals because they are not part of this host tree. 13306 if (node.child === null || node.tag === HostPortal) { 13307 continue siblings; 13308 } else { 13309 node.child.return = node; 13310 node = node.child; 13311 } 13312 } 13313 // Check if this host node is stable or about to be placed. 13314 if (!(node.effectTag & Placement)) { 13315 // Found it! 13316 return node.stateNode; 13317 } 13318 } 13319 } 13320 13321 function commitPlacement(finishedWork) { 13322 if (!supportsMutation) { 13323 return; 13324 } 13325 13326 // Recursively insert all host nodes into the parent. 13327 var parentFiber = getHostParentFiber(finishedWork); 13328 13329 // Note: these two variables *must* always be updated together. 13330 var parent = void 0; 13331 var isContainer = void 0; 13332 13333 switch (parentFiber.tag) { 13334 case HostComponent: 13335 parent = parentFiber.stateNode; 13336 isContainer = false; 13337 break; 13338 case HostRoot: 13339 parent = parentFiber.stateNode.containerInfo; 13340 isContainer = true; 13341 break; 13342 case HostPortal: 13343 parent = parentFiber.stateNode.containerInfo; 13344 isContainer = true; 13345 break; 13346 default: 13347 reactProdInvariant('161'); 13348 } 13349 if (parentFiber.effectTag & ContentReset) { 13350 // Reset the text content of the parent before doing any insertions 13351 resetTextContent(parent); 13352 // Clear ContentReset from the effect tag 13353 parentFiber.effectTag &= ~ContentReset; 13354 } 13355 13356 var before = getHostSibling(finishedWork); 13357 // We only have the top Fiber that was inserted but we need to recurse down its 13358 // children to find all the terminal nodes. 13359 var node = finishedWork; 13360 while (true) { 13361 if (node.tag === HostComponent || node.tag === HostText) { 13362 if (before) { 13363 if (isContainer) { 13364 insertInContainerBefore(parent, node.stateNode, before); 13365 } else { 13366 insertBefore(parent, node.stateNode, before); 13367 } 13368 } else { 13369 if (isContainer) { 13370 appendChildToContainer(parent, node.stateNode); 13371 } else { 13372 appendChild(parent, node.stateNode); 13373 } 13374 } 13375 } else if (node.tag === HostPortal) { 13376 // If the insertion itself is a portal, then we don't want to traverse 13377 // down its children. Instead, we'll get insertions from each child in 13378 // the portal directly. 13379 } else if (node.child !== null) { 13380 node.child.return = node; 13381 node = node.child; 13382 continue; 13383 } 13384 if (node === finishedWork) { 13385 return; 13386 } 13387 while (node.sibling === null) { 13388 if (node.return === null || node.return === finishedWork) { 13389 return; 13390 } 13391 node = node.return; 13392 } 13393 node.sibling.return = node.return; 13394 node = node.sibling; 13395 } 13396 } 13397 13398 function unmountHostComponents(current$$1) { 13399 // We only have the top Fiber that was deleted but we need to recurse down its 13400 var node = current$$1; 13401 13402 // Each iteration, currentParent is populated with node's host parent if not 13403 // currentParentIsValid. 13404 var currentParentIsValid = false; 13405 13406 // Note: these two variables *must* always be updated together. 13407 var currentParent = void 0; 13408 var currentParentIsContainer = void 0; 13409 13410 while (true) { 13411 if (!currentParentIsValid) { 13412 var parent = node.return; 13413 findParent: while (true) { 13414 !(parent !== null) ? reactProdInvariant('160') : void 0; 13415 switch (parent.tag) { 13416 case HostComponent: 13417 currentParent = parent.stateNode; 13418 currentParentIsContainer = false; 13419 break findParent; 13420 case HostRoot: 13421 currentParent = parent.stateNode.containerInfo; 13422 currentParentIsContainer = true; 13423 break findParent; 13424 case HostPortal: 13425 currentParent = parent.stateNode.containerInfo; 13426 currentParentIsContainer = true; 13427 break findParent; 13428 } 13429 parent = parent.return; 13430 } 13431 currentParentIsValid = true; 13432 } 13433 13434 if (node.tag === HostComponent || node.tag === HostText) { 13435 commitNestedUnmounts(node); 13436 // After all the children have unmounted, it is now safe to remove the 13437 // node from the tree. 13438 if (currentParentIsContainer) { 13439 removeChildFromContainer(currentParent, node.stateNode); 13440 } else { 13441 removeChild(currentParent, node.stateNode); 13442 } 13443 // Don't visit children because we already visited them. 13444 } else if (enableSuspenseServerRenderer && node.tag === DehydratedSuspenseComponent) { 13445 // Delete the dehydrated suspense boundary and all of its content. 13446 if (currentParentIsContainer) { 13447 clearSuspenseBoundaryFromContainer(currentParent, node.stateNode); 13448 } else { 13449 clearSuspenseBoundary(currentParent, node.stateNode); 13450 } 13451 } else if (node.tag === HostPortal) { 13452 if (node.child !== null) { 13453 // When we go into a portal, it becomes the parent to remove from. 13454 // We will reassign it back when we pop the portal on the way up. 13455 currentParent = node.stateNode.containerInfo; 13456 currentParentIsContainer = true; 13457 // Visit children because portals might contain host components. 13458 node.child.return = node; 13459 node = node.child; 13460 continue; 13461 } 13462 } else { 13463 commitUnmount(node); 13464 // Visit children because we may find more host components below. 13465 if (node.child !== null) { 13466 node.child.return = node; 13467 node = node.child; 13468 continue; 13469 } 13470 } 13471 if (node === current$$1) { 13472 return; 13473 } 13474 while (node.sibling === null) { 13475 if (node.return === null || node.return === current$$1) { 13476 return; 13477 } 13478 node = node.return; 13479 if (node.tag === HostPortal) { 13480 // When we go out of the portal, we need to restore the parent. 13481 // Since we don't keep a stack of them, we will search for it. 13482 currentParentIsValid = false; 13483 } 13484 } 13485 node.sibling.return = node.return; 13486 node = node.sibling; 13487 } 13488 } 13489 13490 function commitDeletion(current$$1) { 13491 if (supportsMutation) { 13492 // Recursively delete all host nodes from the parent. 13493 // Detach refs and call componentWillUnmount() on the whole subtree. 13494 unmountHostComponents(current$$1); 13495 } else { 13496 // Detach refs and call componentWillUnmount() on the whole subtree. 13497 commitNestedUnmounts(current$$1); 13498 } 13499 detachFiber(current$$1); 13500 } 13501 13502 function commitWork(current$$1, finishedWork) { 13503 if (!supportsMutation) { 13504 switch (finishedWork.tag) { 13505 case FunctionComponent: 13506 case ForwardRef: 13507 case MemoComponent: 13508 case SimpleMemoComponent: 13509 { 13510 // Note: We currently never use MountMutation, but useLayout uses 13511 // UnmountMutation. 13512 commitHookEffectList(UnmountMutation, MountMutation, finishedWork); 13513 return; 13514 } 13515 } 13516 13517 commitContainer(finishedWork); 13518 return; 13519 } 13520 13521 switch (finishedWork.tag) { 13522 case FunctionComponent: 13523 case ForwardRef: 13524 case MemoComponent: 13525 case SimpleMemoComponent: 13526 { 13527 // Note: We currently never use MountMutation, but useLayout uses 13528 // UnmountMutation. 13529 commitHookEffectList(UnmountMutation, MountMutation, finishedWork); 13530 return; 13531 } 13532 case ClassComponent: 13533 { 13534 return; 13535 } 13536 case HostComponent: 13537 { 13538 var instance = finishedWork.stateNode; 13539 if (instance != null) { 13540 // Commit the work prepared earlier. 13541 var newProps = finishedWork.memoizedProps; 13542 // For hydration we reuse the update path but we treat the oldProps 13543 // as the newProps. The updatePayload will contain the real change in 13544 // this case. 13545 var oldProps = current$$1 !== null ? current$$1.memoizedProps : newProps; 13546 var type = finishedWork.type; 13547 // TODO: Type the updateQueue to be specific to host components. 13548 var updatePayload = finishedWork.updateQueue; 13549 finishedWork.updateQueue = null; 13550 if (updatePayload !== null) { 13551 commitUpdate(instance, updatePayload, type, oldProps, newProps, finishedWork); 13552 } 13553 } 13554 return; 13555 } 13556 case HostText: 13557 { 13558 !(finishedWork.stateNode !== null) ? reactProdInvariant('162') : void 0; 13559 var textInstance = finishedWork.stateNode; 13560 var newText = finishedWork.memoizedProps; 13561 // For hydration we reuse the update path but we treat the oldProps 13562 // as the newProps. The updatePayload will contain the real change in 13563 // this case. 13564 var oldText = current$$1 !== null ? current$$1.memoizedProps : newText; 13565 commitTextUpdate(textInstance, oldText, newText); 13566 return; 13567 } 13568 case HostRoot: 13569 { 13570 return; 13571 } 13572 case Profiler: 13573 { 13574 return; 13575 } 13576 case SuspenseComponent: 13577 { 13578 var newState = finishedWork.memoizedState; 13579 13580 var newDidTimeout = void 0; 13581 var primaryChildParent = finishedWork; 13582 if (newState === null) { 13583 newDidTimeout = false; 13584 } else { 13585 newDidTimeout = true; 13586 primaryChildParent = finishedWork.child; 13587 if (newState.timedOutAt === NoWork) { 13588 // If the children had not already timed out, record the time. 13589 // This is used to compute the elapsed time during subsequent 13590 // attempts to render the children. 13591 newState.timedOutAt = requestCurrentTime(); 13592 } 13593 } 13594 13595 if (primaryChildParent !== null) { 13596 hideOrUnhideAllChildren(primaryChildParent, newDidTimeout); 13597 } 13598 13599 // If this boundary just timed out, then it will have a set of thenables. 13600 // For each thenable, attach a listener so that when it resolves, React 13601 // attempts to re-render the boundary in the primary (pre-timeout) state. 13602 var thenables = finishedWork.updateQueue; 13603 if (thenables !== null) { 13604 finishedWork.updateQueue = null; 13605 var retryCache = finishedWork.stateNode; 13606 if (retryCache === null) { 13607 retryCache = finishedWork.stateNode = new PossiblyWeakSet$1(); 13608 } 13609 thenables.forEach(function (thenable) { 13610 // Memoize using the boundary fiber to prevent redundant listeners. 13611 var retry = retryTimedOutBoundary.bind(null, finishedWork, thenable); 13612 if (enableSchedulerTracing) { 13613 retry = unstable_wrap(retry); 13614 } 13615 if (!retryCache.has(thenable)) { 13616 retryCache.add(thenable); 13617 thenable.then(retry, retry); 13618 } 13619 }); 13620 } 13621 13622 return; 13623 } 13624 case IncompleteClassComponent: 13625 { 13626 return; 13627 } 13628 default: 13629 { 13630 reactProdInvariant('163'); 13631 } 13632 } 13633 } 13634 13635 function commitResetTextContent(current$$1) { 13636 if (!supportsMutation) { 13637 return; 13638 } 13639 resetTextContent(current$$1.stateNode); 13640 } 13641 13642 var PossiblyWeakSet = typeof WeakSet === 'function' ? WeakSet : Set; 13643 var PossiblyWeakMap = typeof WeakMap === 'function' ? WeakMap : Map; 13644 13645 function createRootErrorUpdate(fiber, errorInfo, expirationTime) { 13646 var update = createUpdate(expirationTime); 13647 // Unmount the root by rendering null. 13648 update.tag = CaptureUpdate; 13649 // Caution: React DevTools currently depends on this property 13650 // being called "element". 13651 update.payload = { element: null }; 13652 var error = errorInfo.value; 13653 update.callback = function () { 13654 onUncaughtError(error); 13655 logError(fiber, errorInfo); 13656 }; 13657 return update; 13658 } 13659 13660 function createClassErrorUpdate(fiber, errorInfo, expirationTime) { 13661 var update = createUpdate(expirationTime); 13662 update.tag = CaptureUpdate; 13663 var getDerivedStateFromError = fiber.type.getDerivedStateFromError; 13664 if (typeof getDerivedStateFromError === 'function') { 13665 var error = errorInfo.value; 13666 update.payload = function () { 13667 return getDerivedStateFromError(error); 13668 }; 13669 } 13670 13671 var inst = fiber.stateNode; 13672 if (inst !== null && typeof inst.componentDidCatch === 'function') { 13673 update.callback = function callback() { 13674 if (typeof getDerivedStateFromError !== 'function') { 13675 // To preserve the preexisting retry behavior of error boundaries, 13676 // we keep track of which ones already failed during this batch. 13677 // This gets reset before we yield back to the browser. 13678 // TODO: Warn in strict mode if getDerivedStateFromError is 13679 // not defined. 13680 markLegacyErrorBoundaryAsFailed(this); 13681 } 13682 var error = errorInfo.value; 13683 var stack = errorInfo.stack; 13684 logError(fiber, errorInfo); 13685 this.componentDidCatch(error, { 13686 componentStack: stack !== null ? stack : '' 13687 }); 13688 13689 }; 13690 } 13691 return update; 13692 } 13693 13694 function attachPingListener(root, renderExpirationTime, thenable) { 13695 // Attach a listener to the promise to "ping" the root and retry. But 13696 // only if one does not already exist for the current render expiration 13697 // time (which acts like a "thread ID" here). 13698 var pingCache = root.pingCache; 13699 var threadIDs = void 0; 13700 if (pingCache === null) { 13701 pingCache = root.pingCache = new PossiblyWeakMap(); 13702 threadIDs = new Set(); 13703 pingCache.set(thenable, threadIDs); 13704 } else { 13705 threadIDs = pingCache.get(thenable); 13706 if (threadIDs === undefined) { 13707 threadIDs = new Set(); 13708 pingCache.set(thenable, threadIDs); 13709 } 13710 } 13711 if (!threadIDs.has(renderExpirationTime)) { 13712 // Memoize using the thread ID to prevent redundant listeners. 13713 threadIDs.add(renderExpirationTime); 13714 var ping = pingSuspendedRoot.bind(null, root, thenable, renderExpirationTime); 13715 if (enableSchedulerTracing) { 13716 ping = unstable_wrap(ping); 13717 } 13718 thenable.then(ping, ping); 13719 } 13720 } 13721 13722 function throwException(root, returnFiber, sourceFiber, value, renderExpirationTime) { 13723 // The source fiber did not complete. 13724 sourceFiber.effectTag |= Incomplete; 13725 // Its effect list is no longer valid. 13726 sourceFiber.firstEffect = sourceFiber.lastEffect = null; 13727 13728 if (value !== null && typeof value === 'object' && typeof value.then === 'function') { 13729 // This is a thenable. 13730 var thenable = value; 13731 13732 // Find the earliest timeout threshold of all the placeholders in the 13733 // ancestor path. We could avoid this traversal by storing the thresholds on 13734 // the stack, but we choose not to because we only hit this path if we're 13735 // IO-bound (i.e. if something suspends). Whereas the stack is used even in 13736 // the non-IO- bound case. 13737 var _workInProgress = returnFiber; 13738 var earliestTimeoutMs = -1; 13739 var startTimeMs = -1; 13740 do { 13741 if (_workInProgress.tag === SuspenseComponent) { 13742 var current$$1 = _workInProgress.alternate; 13743 if (current$$1 !== null) { 13744 var currentState = current$$1.memoizedState; 13745 if (currentState !== null) { 13746 // Reached a boundary that already timed out. Do not search 13747 // any further. 13748 var timedOutAt = currentState.timedOutAt; 13749 startTimeMs = expirationTimeToMs(timedOutAt); 13750 // Do not search any further. 13751 break; 13752 } 13753 } 13754 var timeoutPropMs = _workInProgress.pendingProps.maxDuration; 13755 if (typeof timeoutPropMs === 'number') { 13756 if (timeoutPropMs <= 0) { 13757 earliestTimeoutMs = 0; 13758 } else if (earliestTimeoutMs === -1 || timeoutPropMs < earliestTimeoutMs) { 13759 earliestTimeoutMs = timeoutPropMs; 13760 } 13761 } 13762 } 13763 // If there is a DehydratedSuspenseComponent we don't have to do anything because 13764 // if something suspends inside it, we will simply leave that as dehydrated. It 13765 // will never timeout. 13766 _workInProgress = _workInProgress.return; 13767 } while (_workInProgress !== null); 13768 13769 // Schedule the nearest Suspense to re-render the timed out view. 13770 _workInProgress = returnFiber; 13771 do { 13772 if (_workInProgress.tag === SuspenseComponent && shouldCaptureSuspense(_workInProgress)) { 13773 // Found the nearest boundary. 13774 13775 // Stash the promise on the boundary fiber. If the boundary times out, we'll 13776 var thenables = _workInProgress.updateQueue; 13777 if (thenables === null) { 13778 var updateQueue = new Set(); 13779 updateQueue.add(thenable); 13780 _workInProgress.updateQueue = updateQueue; 13781 } else { 13782 thenables.add(thenable); 13783 } 13784 13785 // If the boundary is outside of concurrent mode, we should *not* 13786 // suspend the commit. Pretend as if the suspended component rendered 13787 // null and keep rendering. In the commit phase, we'll schedule a 13788 // subsequent synchronous update to re-render the Suspense. 13789 // 13790 // Note: It doesn't matter whether the component that suspended was 13791 // inside a concurrent mode tree. If the Suspense is outside of it, we 13792 // should *not* suspend the commit. 13793 if ((_workInProgress.mode & ConcurrentMode) === NoEffect) { 13794 _workInProgress.effectTag |= DidCapture; 13795 13796 // We're going to commit this fiber even though it didn't complete. 13797 // But we shouldn't call any lifecycle methods or callbacks. Remove 13798 // all lifecycle effect tags. 13799 sourceFiber.effectTag &= ~(LifecycleEffectMask | Incomplete); 13800 13801 if (sourceFiber.tag === ClassComponent) { 13802 var currentSourceFiber = sourceFiber.alternate; 13803 if (currentSourceFiber === null) { 13804 // This is a new mount. Change the tag so it's not mistaken for a 13805 // completed class component. For example, we should not call 13806 // componentWillUnmount if it is deleted. 13807 sourceFiber.tag = IncompleteClassComponent; 13808 } else { 13809 // When we try rendering again, we should not reuse the current fiber, 13810 // since it's known to be in an inconsistent state. Use a force updte to 13811 // prevent a bail out. 13812 var update = createUpdate(Sync); 13813 update.tag = ForceUpdate; 13814 enqueueUpdate(sourceFiber, update); 13815 } 13816 } 13817 13818 // The source fiber did not complete. Mark it with Sync priority to 13819 // indicate that it still has pending work. 13820 sourceFiber.expirationTime = Sync; 13821 13822 // Exit without suspending. 13823 return; 13824 } 13825 13826 // Confirmed that the boundary is in a concurrent mode tree. Continue 13827 // with the normal suspend path. 13828 13829 attachPingListener(root, renderExpirationTime, thenable); 13830 13831 var absoluteTimeoutMs = void 0; 13832 if (earliestTimeoutMs === -1) { 13833 // If no explicit threshold is given, default to an arbitrarily large 13834 // value. The actual size doesn't matter because the threshold for the 13835 // whole tree will be clamped to the expiration time. 13836 absoluteTimeoutMs = maxSigned31BitInt; 13837 } else { 13838 if (startTimeMs === -1) { 13839 // This suspend happened outside of any already timed-out 13840 // placeholders. We don't know exactly when the update was 13841 // scheduled, but we can infer an approximate start time from the 13842 // expiration time. First, find the earliest uncommitted expiration 13843 // time in the tree, including work that is suspended. Then subtract 13844 // the offset used to compute an async update's expiration time. 13845 // This will cause high priority (interactive) work to expire 13846 // earlier than necessary, but we can account for this by adjusting 13847 // for the Just Noticeable Difference. 13848 var earliestExpirationTime = findEarliestOutstandingPriorityLevel(root, renderExpirationTime); 13849 var earliestExpirationTimeMs = expirationTimeToMs(earliestExpirationTime); 13850 startTimeMs = earliestExpirationTimeMs - LOW_PRIORITY_EXPIRATION; 13851 } 13852 absoluteTimeoutMs = startTimeMs + earliestTimeoutMs; 13853 } 13854 13855 // Mark the earliest timeout in the suspended fiber's ancestor path. 13856 // After completing the root, we'll take the largest of all the 13857 // suspended fiber's timeouts and use it to compute a timeout for the 13858 // whole tree. 13859 renderDidSuspend(root, absoluteTimeoutMs, renderExpirationTime); 13860 13861 _workInProgress.effectTag |= ShouldCapture; 13862 _workInProgress.expirationTime = renderExpirationTime; 13863 return; 13864 } else if (enableSuspenseServerRenderer && _workInProgress.tag === DehydratedSuspenseComponent) { 13865 attachPingListener(root, renderExpirationTime, thenable); 13866 13867 // Since we already have a current fiber, we can eagerly add a retry listener. 13868 var retryCache = _workInProgress.memoizedState; 13869 if (retryCache === null) { 13870 retryCache = _workInProgress.memoizedState = new PossiblyWeakSet(); 13871 var _current = _workInProgress.alternate; 13872 !_current ? reactProdInvariant('319') : void 0; 13873 _current.memoizedState = retryCache; 13874 } 13875 // Memoize using the boundary fiber to prevent redundant listeners. 13876 if (!retryCache.has(thenable)) { 13877 retryCache.add(thenable); 13878 var retry = retryTimedOutBoundary.bind(null, _workInProgress, thenable); 13879 if (enableSchedulerTracing) { 13880 retry = unstable_wrap(retry); 13881 } 13882 thenable.then(retry, retry); 13883 } 13884 _workInProgress.effectTag |= ShouldCapture; 13885 _workInProgress.expirationTime = renderExpirationTime; 13886 return; 13887 } 13888 // This boundary already captured during this render. Continue to the next 13889 // boundary. 13890 _workInProgress = _workInProgress.return; 13891 } while (_workInProgress !== null); 13892 // No boundary was found. Fallthrough to error mode. 13893 // TODO: Use invariant so the message is stripped in prod? 13894 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)); 13895 } 13896 13897 // We didn't find a boundary that could handle this type of exception. Start 13898 // over and traverse parent path again, this time treating the exception 13899 // as an error. 13900 renderDidError(); 13901 value = createCapturedValue(value, sourceFiber); 13902 var workInProgress = returnFiber; 13903 do { 13904 switch (workInProgress.tag) { 13905 case HostRoot: 13906 { 13907 var _errorInfo = value; 13908 workInProgress.effectTag |= ShouldCapture; 13909 workInProgress.expirationTime = renderExpirationTime; 13910 var _update = createRootErrorUpdate(workInProgress, _errorInfo, renderExpirationTime); 13911 enqueueCapturedUpdate(workInProgress, _update); 13912 return; 13913 } 13914 case ClassComponent: 13915 // Capture and retry 13916 var errorInfo = value; 13917 var ctor = workInProgress.type; 13918 var instance = workInProgress.stateNode; 13919 if ((workInProgress.effectTag & DidCapture) === NoEffect && (typeof ctor.getDerivedStateFromError === 'function' || instance !== null && typeof instance.componentDidCatch === 'function' && !isAlreadyFailedLegacyErrorBoundary(instance))) { 13920 workInProgress.effectTag |= ShouldCapture; 13921 workInProgress.expirationTime = renderExpirationTime; 13922 // Schedule the error boundary to re-render using updated state 13923 var _update2 = createClassErrorUpdate(workInProgress, errorInfo, renderExpirationTime); 13924 enqueueCapturedUpdate(workInProgress, _update2); 13925 return; 13926 } 13927 break; 13928 default: 13929 break; 13930 } 13931 workInProgress = workInProgress.return; 13932 } while (workInProgress !== null); 13933 } 13934 13935 function unwindWork(workInProgress, renderExpirationTime) { 13936 switch (workInProgress.tag) { 13937 case ClassComponent: 13938 { 13939 var Component = workInProgress.type; 13940 if (isContextProvider(Component)) { 13941 popContext(workInProgress); 13942 } 13943 var effectTag = workInProgress.effectTag; 13944 if (effectTag & ShouldCapture) { 13945 workInProgress.effectTag = effectTag & ~ShouldCapture | DidCapture; 13946 return workInProgress; 13947 } 13948 return null; 13949 } 13950 case HostRoot: 13951 { 13952 popHostContainer(workInProgress); 13953 popTopLevelContextObject(workInProgress); 13954 var _effectTag = workInProgress.effectTag; 13955 !((_effectTag & DidCapture) === NoEffect) ? reactProdInvariant('285') : void 0; 13956 workInProgress.effectTag = _effectTag & ~ShouldCapture | DidCapture; 13957 return workInProgress; 13958 } 13959 case HostComponent: 13960 { 13961 // TODO: popHydrationState 13962 popHostContext(workInProgress); 13963 return null; 13964 } 13965 case SuspenseComponent: 13966 { 13967 var _effectTag2 = workInProgress.effectTag; 13968 if (_effectTag2 & ShouldCapture) { 13969 workInProgress.effectTag = _effectTag2 & ~ShouldCapture | DidCapture; 13970 // Captured a suspense effect. Re-render the boundary. 13971 return workInProgress; 13972 } 13973 return null; 13974 } 13975 case DehydratedSuspenseComponent: 13976 { 13977 if (enableSuspenseServerRenderer) { 13978 // TODO: popHydrationState 13979 var _effectTag3 = workInProgress.effectTag; 13980 if (_effectTag3 & ShouldCapture) { 13981 workInProgress.effectTag = _effectTag3 & ~ShouldCapture | DidCapture; 13982 // Captured a suspense effect. Re-render the boundary. 13983 return workInProgress; 13984 } 13985 } 13986 return null; 13987 } 13988 case HostPortal: 13989 popHostContainer(workInProgress); 13990 return null; 13991 case ContextProvider: 13992 popProvider(workInProgress); 13993 return null; 13994 default: 13995 return null; 13996 } 13997 } 13998 13999 function unwindInterruptedWork(interruptedWork) { 14000 switch (interruptedWork.tag) { 14001 case ClassComponent: 14002 { 14003 var childContextTypes = interruptedWork.type.childContextTypes; 14004 if (childContextTypes !== null && childContextTypes !== undefined) { 14005 popContext(interruptedWork); 14006 } 14007 break; 14008 } 14009 case HostRoot: 14010 { 14011 popHostContainer(interruptedWork); 14012 popTopLevelContextObject(interruptedWork); 14013 break; 14014 } 14015 case HostComponent: 14016 { 14017 popHostContext(interruptedWork); 14018 break; 14019 } 14020 case HostPortal: 14021 popHostContainer(interruptedWork); 14022 break; 14023 case ContextProvider: 14024 popProvider(interruptedWork); 14025 break; 14026 default: 14027 break; 14028 } 14029 } 14030 14031 var ReactCurrentDispatcher = ReactSharedInternals.ReactCurrentDispatcher; 14032 var ReactCurrentOwner$2 = ReactSharedInternals.ReactCurrentOwner; 14033 14034 14035 if (enableSchedulerTracing) { 14036 // Provide explicit error message when production+profiling bundle of e.g. react-dom 14037 // is used with production (non-profiling) bundle of scheduler/tracing 14038 !(__interactionsRef != null && __interactionsRef.current != null) ? reactProdInvariant('302') : void 0; 14039 } 14040 14041 // Used to ensure computeUniqueAsyncExpiration is monotonically decreasing. 14042 var lastUniqueAsyncExpiration = Sync - 1; 14043 14044 var isWorking = false; 14045 14046 // The next work in progress fiber that we're currently working on. 14047 var nextUnitOfWork = null; 14048 var nextRoot = null; 14049 // The time at which we're currently rendering work. 14050 var nextRenderExpirationTime = NoWork; 14051 var nextLatestAbsoluteTimeoutMs = -1; 14052 var nextRenderDidError = false; 14053 14054 // The next fiber with an effect that we're currently committing. 14055 var nextEffect = null; 14056 14057 var isCommitting$1 = false; 14058 var rootWithPendingPassiveEffects = null; 14059 var passiveEffectCallbackHandle = null; 14060 var passiveEffectCallback = null; 14061 14062 var legacyErrorBoundariesThatAlreadyFailed = null; 14063 14064 // Used for performance tracking. 14065 var interruptedBy = null; 14066 14067 function resetStack() { 14068 if (nextUnitOfWork !== null) { 14069 var interruptedWork = nextUnitOfWork.return; 14070 while (interruptedWork !== null) { 14071 unwindInterruptedWork(interruptedWork); 14072 interruptedWork = interruptedWork.return; 14073 } 14074 } 14075 14076 nextRoot = null; 14077 nextRenderExpirationTime = NoWork; 14078 nextLatestAbsoluteTimeoutMs = -1; 14079 nextRenderDidError = false; 14080 nextUnitOfWork = null; 14081 } 14082 14083 function commitAllHostEffects() { 14084 while (nextEffect !== null) { 14085 recordEffect(); 14086 14087 var effectTag = nextEffect.effectTag; 14088 14089 if (effectTag & ContentReset) { 14090 commitResetTextContent(nextEffect); 14091 } 14092 14093 if (effectTag & Ref) { 14094 var current$$1 = nextEffect.alternate; 14095 if (current$$1 !== null) { 14096 commitDetachRef(current$$1); 14097 } 14098 } 14099 14100 // The following switch statement is only concerned about placement, 14101 // updates, and deletions. To avoid needing to add a case for every 14102 // possible bitmap value, we remove the secondary effects from the 14103 // effect tag and switch on that value. 14104 var primaryEffectTag = effectTag & (Placement | Update | Deletion); 14105 switch (primaryEffectTag) { 14106 case Placement: 14107 { 14108 commitPlacement(nextEffect); 14109 // Clear the "placement" from effect tag so that we know that this is inserted, before 14110 // any life-cycles like componentDidMount gets called. 14111 // TODO: findDOMNode doesn't rely on this any more but isMounted 14112 // does and isMounted is deprecated anyway so we should be able 14113 // to kill this. 14114 nextEffect.effectTag &= ~Placement; 14115 break; 14116 } 14117 case PlacementAndUpdate: 14118 { 14119 // Placement 14120 commitPlacement(nextEffect); 14121 // Clear the "placement" from effect tag so that we know that this is inserted, before 14122 // any life-cycles like componentDidMount gets called. 14123 nextEffect.effectTag &= ~Placement; 14124 14125 // Update 14126 var _current = nextEffect.alternate; 14127 commitWork(_current, nextEffect); 14128 break; 14129 } 14130 case Update: 14131 { 14132 var _current2 = nextEffect.alternate; 14133 commitWork(_current2, nextEffect); 14134 break; 14135 } 14136 case Deletion: 14137 { 14138 commitDeletion(nextEffect); 14139 break; 14140 } 14141 } 14142 nextEffect = nextEffect.nextEffect; 14143 } 14144 14145 14146 } 14147 14148 function commitBeforeMutationLifecycles() { 14149 while (nextEffect !== null) { 14150 var effectTag = nextEffect.effectTag; 14151 if (effectTag & Snapshot) { 14152 recordEffect(); 14153 var current$$1 = nextEffect.alternate; 14154 commitBeforeMutationLifeCycles(current$$1, nextEffect); 14155 } 14156 14157 nextEffect = nextEffect.nextEffect; 14158 } 14159 14160 14161 } 14162 14163 function commitAllLifeCycles(finishedRoot, committedExpirationTime) { 14164 while (nextEffect !== null) { 14165 var effectTag = nextEffect.effectTag; 14166 14167 if (effectTag & (Update | Callback)) { 14168 recordEffect(); 14169 var current$$1 = nextEffect.alternate; 14170 commitLifeCycles(finishedRoot, current$$1, nextEffect, committedExpirationTime); 14171 } 14172 14173 if (effectTag & Ref) { 14174 recordEffect(); 14175 commitAttachRef(nextEffect); 14176 } 14177 14178 if (effectTag & Passive) { 14179 rootWithPendingPassiveEffects = finishedRoot; 14180 } 14181 14182 nextEffect = nextEffect.nextEffect; 14183 } 14184 14185 } 14186 14187 function commitPassiveEffects(root, firstEffect) { 14188 rootWithPendingPassiveEffects = null; 14189 passiveEffectCallbackHandle = null; 14190 passiveEffectCallback = null; 14191 14192 // Set this to true to prevent re-entrancy 14193 var previousIsRendering = isRendering; 14194 isRendering = true; 14195 14196 var effect = firstEffect; 14197 do { 14198 if (effect.effectTag & Passive) { 14199 var didError = false; 14200 var error = void 0; 14201 { 14202 try { 14203 commitPassiveHookEffects(effect); 14204 } catch (e) { 14205 didError = true; 14206 error = e; 14207 } 14208 } 14209 if (didError) { 14210 captureCommitPhaseError(effect, error); 14211 } 14212 } 14213 effect = effect.nextEffect; 14214 } while (effect !== null); 14215 isRendering = previousIsRendering; 14216 14217 // Check if work was scheduled by one of the effects 14218 var rootExpirationTime = root.expirationTime; 14219 if (rootExpirationTime !== NoWork) { 14220 requestWork(root, rootExpirationTime); 14221 } 14222 // Flush any sync work that was scheduled by effects 14223 if (!isBatchingUpdates && !isRendering) { 14224 performSyncWork(); 14225 } 14226 } 14227 14228 function isAlreadyFailedLegacyErrorBoundary(instance) { 14229 return legacyErrorBoundariesThatAlreadyFailed !== null && legacyErrorBoundariesThatAlreadyFailed.has(instance); 14230 } 14231 14232 function markLegacyErrorBoundaryAsFailed(instance) { 14233 if (legacyErrorBoundariesThatAlreadyFailed === null) { 14234 legacyErrorBoundariesThatAlreadyFailed = new Set([instance]); 14235 } else { 14236 legacyErrorBoundariesThatAlreadyFailed.add(instance); 14237 } 14238 } 14239 14240 function flushPassiveEffects() { 14241 if (passiveEffectCallbackHandle !== null) { 14242 cancelPassiveEffects(passiveEffectCallbackHandle); 14243 } 14244 if (passiveEffectCallback !== null) { 14245 // We call the scheduled callback instead of commitPassiveEffects directly 14246 // to ensure tracing works correctly. 14247 passiveEffectCallback(); 14248 } 14249 } 14250 14251 function commitRoot(root, finishedWork) { 14252 isWorking = true; 14253 isCommitting$1 = true; 14254 startCommitTimer(); 14255 14256 !(root.current !== finishedWork) ? reactProdInvariant('177') : void 0; 14257 var committedExpirationTime = root.pendingCommitExpirationTime; 14258 !(committedExpirationTime !== NoWork) ? reactProdInvariant('261') : void 0; 14259 root.pendingCommitExpirationTime = NoWork; 14260 14261 // Update the pending priority levels to account for the work that we are 14262 // about to commit. This needs to happen before calling the lifecycles, since 14263 // they may schedule additional updates. 14264 var updateExpirationTimeBeforeCommit = finishedWork.expirationTime; 14265 var childExpirationTimeBeforeCommit = finishedWork.childExpirationTime; 14266 var earliestRemainingTimeBeforeCommit = childExpirationTimeBeforeCommit > updateExpirationTimeBeforeCommit ? childExpirationTimeBeforeCommit : updateExpirationTimeBeforeCommit; 14267 markCommittedPriorityLevels(root, earliestRemainingTimeBeforeCommit); 14268 14269 var prevInteractions = null; 14270 if (enableSchedulerTracing) { 14271 // Restore any pending interactions at this point, 14272 // So that cascading work triggered during the render phase will be accounted for. 14273 prevInteractions = __interactionsRef.current; 14274 __interactionsRef.current = root.memoizedInteractions; 14275 } 14276 14277 // Reset this to null before calling lifecycles 14278 ReactCurrentOwner$2.current = null; 14279 14280 var firstEffect = void 0; 14281 if (finishedWork.effectTag > PerformedWork) { 14282 // A fiber's effect list consists only of its children, not itself. So if 14283 // the root has an effect, we need to add it to the end of the list. The 14284 // resulting list is the set that would belong to the root's parent, if 14285 // it had one; that is, all the effects in the tree including the root. 14286 if (finishedWork.lastEffect !== null) { 14287 finishedWork.lastEffect.nextEffect = finishedWork; 14288 firstEffect = finishedWork.firstEffect; 14289 } else { 14290 firstEffect = finishedWork; 14291 } 14292 } else { 14293 // There is no effect on the root. 14294 firstEffect = finishedWork.firstEffect; 14295 } 14296 14297 prepareForCommit(root.containerInfo); 14298 14299 // Invoke instances of getSnapshotBeforeUpdate before mutation. 14300 nextEffect = firstEffect; 14301 startCommitSnapshotEffectsTimer(); 14302 while (nextEffect !== null) { 14303 var didError = false; 14304 var error = void 0; 14305 { 14306 try { 14307 commitBeforeMutationLifecycles(); 14308 } catch (e) { 14309 didError = true; 14310 error = e; 14311 } 14312 } 14313 if (didError) { 14314 !(nextEffect !== null) ? reactProdInvariant('178') : void 0; 14315 captureCommitPhaseError(nextEffect, error); 14316 // Clean-up 14317 if (nextEffect !== null) { 14318 nextEffect = nextEffect.nextEffect; 14319 } 14320 } 14321 } 14322 stopCommitSnapshotEffectsTimer(); 14323 14324 if (enableProfilerTimer) { 14325 // Mark the current commit time to be shared by all Profilers in this batch. 14326 // This enables them to be grouped later. 14327 recordCommitTime(); 14328 } 14329 14330 // Commit all the side-effects within a tree. We'll do this in two passes. 14331 // The first pass performs all the host insertions, updates, deletions and 14332 // ref unmounts. 14333 nextEffect = firstEffect; 14334 startCommitHostEffectsTimer(); 14335 while (nextEffect !== null) { 14336 var _didError = false; 14337 var _error = void 0; 14338 { 14339 try { 14340 commitAllHostEffects(); 14341 } catch (e) { 14342 _didError = true; 14343 _error = e; 14344 } 14345 } 14346 if (_didError) { 14347 !(nextEffect !== null) ? reactProdInvariant('178') : void 0; 14348 captureCommitPhaseError(nextEffect, _error); 14349 // Clean-up 14350 if (nextEffect !== null) { 14351 nextEffect = nextEffect.nextEffect; 14352 } 14353 } 14354 } 14355 stopCommitHostEffectsTimer(); 14356 14357 resetAfterCommit(root.containerInfo); 14358 14359 // The work-in-progress tree is now the current tree. This must come after 14360 // the first pass of the commit phase, so that the previous tree is still 14361 // current during componentWillUnmount, but before the second pass, so that 14362 // the finished work is current during componentDidMount/Update. 14363 root.current = finishedWork; 14364 14365 // In the second pass we'll perform all life-cycles and ref callbacks. 14366 // Life-cycles happen as a separate pass so that all placements, updates, 14367 // and deletions in the entire tree have already been invoked. 14368 // This pass also triggers any renderer-specific initial effects. 14369 nextEffect = firstEffect; 14370 startCommitLifeCyclesTimer(); 14371 while (nextEffect !== null) { 14372 var _didError2 = false; 14373 var _error2 = void 0; 14374 { 14375 try { 14376 commitAllLifeCycles(root, committedExpirationTime); 14377 } catch (e) { 14378 _didError2 = true; 14379 _error2 = e; 14380 } 14381 } 14382 if (_didError2) { 14383 !(nextEffect !== null) ? reactProdInvariant('178') : void 0; 14384 captureCommitPhaseError(nextEffect, _error2); 14385 if (nextEffect !== null) { 14386 nextEffect = nextEffect.nextEffect; 14387 } 14388 } 14389 } 14390 14391 if (firstEffect !== null && rootWithPendingPassiveEffects !== null) { 14392 // This commit included a passive effect. These do not need to fire until 14393 // after the next paint. Schedule an callback to fire them in an async 14394 // event. To ensure serial execution, the callback will be flushed early if 14395 // we enter rootWithPendingPassiveEffects commit phase before then. 14396 var callback = commitPassiveEffects.bind(null, root, firstEffect); 14397 if (enableSchedulerTracing) { 14398 // TODO: Avoid this extra callback by mutating the tracing ref directly, 14399 // like we do at the beginning of commitRoot. I've opted not to do that 14400 // here because that code is still in flux. 14401 callback = unstable_wrap(callback); 14402 } 14403 passiveEffectCallbackHandle = unstable_runWithPriority(unstable_NormalPriority, function () { 14404 return schedulePassiveEffects(callback); 14405 }); 14406 passiveEffectCallback = callback; 14407 } 14408 14409 isCommitting$1 = false; 14410 isWorking = false; 14411 stopCommitLifeCyclesTimer(); 14412 stopCommitTimer(); 14413 onCommitRoot(finishedWork.stateNode); 14414 var updateExpirationTimeAfterCommit = finishedWork.expirationTime; 14415 var childExpirationTimeAfterCommit = finishedWork.childExpirationTime; 14416 var earliestRemainingTimeAfterCommit = childExpirationTimeAfterCommit > updateExpirationTimeAfterCommit ? childExpirationTimeAfterCommit : updateExpirationTimeAfterCommit; 14417 if (earliestRemainingTimeAfterCommit === NoWork) { 14418 // If there's no remaining work, we can clear the set of already failed 14419 // error boundaries. 14420 legacyErrorBoundariesThatAlreadyFailed = null; 14421 } 14422 onCommit(root, earliestRemainingTimeAfterCommit); 14423 14424 if (enableSchedulerTracing) { 14425 __interactionsRef.current = prevInteractions; 14426 14427 var subscriber = void 0; 14428 14429 try { 14430 subscriber = __subscriberRef.current; 14431 if (subscriber !== null && root.memoizedInteractions.size > 0) { 14432 var threadID = computeThreadID(committedExpirationTime, root.interactionThreadID); 14433 subscriber.onWorkStopped(root.memoizedInteractions, threadID); 14434 } 14435 } catch (error) { 14436 // It's not safe for commitRoot() to throw. 14437 // Store the error for now and we'll re-throw in finishRendering(). 14438 if (!hasUnhandledError) { 14439 hasUnhandledError = true; 14440 unhandledError = error; 14441 } 14442 } finally { 14443 // Clear completed interactions from the pending Map. 14444 // Unless the render was suspended or cascading work was scheduled, 14445 // In which case– leave pending interactions until the subsequent render. 14446 var pendingInteractionMap = root.pendingInteractionMap; 14447 pendingInteractionMap.forEach(function (scheduledInteractions, scheduledExpirationTime) { 14448 // Only decrement the pending interaction count if we're done. 14449 // If there's still work at the current priority, 14450 // That indicates that we are waiting for suspense data. 14451 if (scheduledExpirationTime > earliestRemainingTimeAfterCommit) { 14452 pendingInteractionMap.delete(scheduledExpirationTime); 14453 14454 scheduledInteractions.forEach(function (interaction) { 14455 interaction.__count--; 14456 14457 if (subscriber !== null && interaction.__count === 0) { 14458 try { 14459 subscriber.onInteractionScheduledWorkCompleted(interaction); 14460 } catch (error) { 14461 // It's not safe for commitRoot() to throw. 14462 // Store the error for now and we'll re-throw in finishRendering(). 14463 if (!hasUnhandledError) { 14464 hasUnhandledError = true; 14465 unhandledError = error; 14466 } 14467 } 14468 } 14469 }); 14470 } 14471 }); 14472 } 14473 } 14474 } 14475 14476 function resetChildExpirationTime(workInProgress, renderTime) { 14477 if (renderTime !== Never && workInProgress.childExpirationTime === Never) { 14478 // The children of this component are hidden. Don't bubble their 14479 // expiration times. 14480 return; 14481 } 14482 14483 var newChildExpirationTime = NoWork; 14484 14485 // Bubble up the earliest expiration time. 14486 if (enableProfilerTimer && workInProgress.mode & ProfileMode) { 14487 // We're in profiling mode. 14488 // Let's use this same traversal to update the render durations. 14489 var actualDuration = workInProgress.actualDuration; 14490 var treeBaseDuration = workInProgress.selfBaseDuration; 14491 14492 // When a fiber is cloned, its actualDuration is reset to 0. 14493 // This value will only be updated if work is done on the fiber (i.e. it doesn't bailout). 14494 // When work is done, it should bubble to the parent's actualDuration. 14495 // If the fiber has not been cloned though, (meaning no work was done), 14496 // Then this value will reflect the amount of time spent working on a previous render. 14497 // In that case it should not bubble. 14498 // We determine whether it was cloned by comparing the child pointer. 14499 var shouldBubbleActualDurations = workInProgress.alternate === null || workInProgress.child !== workInProgress.alternate.child; 14500 14501 var child = workInProgress.child; 14502 while (child !== null) { 14503 var childUpdateExpirationTime = child.expirationTime; 14504 var childChildExpirationTime = child.childExpirationTime; 14505 if (childUpdateExpirationTime > newChildExpirationTime) { 14506 newChildExpirationTime = childUpdateExpirationTime; 14507 } 14508 if (childChildExpirationTime > newChildExpirationTime) { 14509 newChildExpirationTime = childChildExpirationTime; 14510 } 14511 if (shouldBubbleActualDurations) { 14512 actualDuration += child.actualDuration; 14513 } 14514 treeBaseDuration += child.treeBaseDuration; 14515 child = child.sibling; 14516 } 14517 workInProgress.actualDuration = actualDuration; 14518 workInProgress.treeBaseDuration = treeBaseDuration; 14519 } else { 14520 var _child = workInProgress.child; 14521 while (_child !== null) { 14522 var _childUpdateExpirationTime = _child.expirationTime; 14523 var _childChildExpirationTime = _child.childExpirationTime; 14524 if (_childUpdateExpirationTime > newChildExpirationTime) { 14525 newChildExpirationTime = _childUpdateExpirationTime; 14526 } 14527 if (_childChildExpirationTime > newChildExpirationTime) { 14528 newChildExpirationTime = _childChildExpirationTime; 14529 } 14530 _child = _child.sibling; 14531 } 14532 } 14533 14534 workInProgress.childExpirationTime = newChildExpirationTime; 14535 } 14536 14537 function completeUnitOfWork(workInProgress) { 14538 // Attempt to complete the current unit of work, then move to the 14539 // next sibling. If there are no more siblings, return to the 14540 // parent fiber. 14541 while (true) { 14542 // The current, flushed, state of this fiber is the alternate. 14543 // Ideally nothing should rely on this, but relying on it here 14544 // means that we don't need an additional field on the work in 14545 // progress. 14546 var current$$1 = workInProgress.alternate; 14547 var returnFiber = workInProgress.return; 14548 var siblingFiber = workInProgress.sibling; 14549 14550 if ((workInProgress.effectTag & Incomplete) === NoEffect) { 14551 nextUnitOfWork = workInProgress; 14552 if (enableProfilerTimer) { 14553 if (workInProgress.mode & ProfileMode) { 14554 startProfilerTimer(workInProgress); 14555 } 14556 nextUnitOfWork = completeWork(current$$1, workInProgress, nextRenderExpirationTime); 14557 if (workInProgress.mode & ProfileMode) { 14558 // Update render duration assuming we didn't error. 14559 stopProfilerTimerIfRunningAndRecordDelta(workInProgress, false); 14560 } 14561 } else { 14562 nextUnitOfWork = completeWork(current$$1, workInProgress, nextRenderExpirationTime); 14563 } 14564 stopWorkTimer(workInProgress); 14565 resetChildExpirationTime(workInProgress, nextRenderExpirationTime); 14566 if (nextUnitOfWork !== null) { 14567 // Completing this fiber spawned new work. Work on that next. 14568 return nextUnitOfWork; 14569 } 14570 14571 if (returnFiber !== null && 14572 // Do not append effects to parents if a sibling failed to complete 14573 (returnFiber.effectTag & Incomplete) === NoEffect) { 14574 // Append all the effects of the subtree and this fiber onto the effect 14575 // list of the parent. The completion order of the children affects the 14576 // side-effect order. 14577 if (returnFiber.firstEffect === null) { 14578 returnFiber.firstEffect = workInProgress.firstEffect; 14579 } 14580 if (workInProgress.lastEffect !== null) { 14581 if (returnFiber.lastEffect !== null) { 14582 returnFiber.lastEffect.nextEffect = workInProgress.firstEffect; 14583 } 14584 returnFiber.lastEffect = workInProgress.lastEffect; 14585 } 14586 14587 // If this fiber had side-effects, we append it AFTER the children's 14588 // side-effects. We can perform certain side-effects earlier if 14589 // needed, by doing multiple passes over the effect list. We don't want 14590 // to schedule our own side-effect on our own list because if end up 14591 // reusing children we'll schedule this effect onto itself since we're 14592 // at the end. 14593 var effectTag = workInProgress.effectTag; 14594 // Skip both NoWork and PerformedWork tags when creating the effect list. 14595 // PerformedWork effect is read by React DevTools but shouldn't be committed. 14596 if (effectTag > PerformedWork) { 14597 if (returnFiber.lastEffect !== null) { 14598 returnFiber.lastEffect.nextEffect = workInProgress; 14599 } else { 14600 returnFiber.firstEffect = workInProgress; 14601 } 14602 returnFiber.lastEffect = workInProgress; 14603 } 14604 } 14605 14606 if (siblingFiber !== null) { 14607 // If there is more work to do in this returnFiber, do that next. 14608 return siblingFiber; 14609 } else if (returnFiber !== null) { 14610 // If there's no more work in this returnFiber. Complete the returnFiber. 14611 workInProgress = returnFiber; 14612 continue; 14613 } else { 14614 // We've reached the root. 14615 return null; 14616 } 14617 } else { 14618 if (enableProfilerTimer && workInProgress.mode & ProfileMode) { 14619 // Record the render duration for the fiber that errored. 14620 stopProfilerTimerIfRunningAndRecordDelta(workInProgress, false); 14621 14622 // Include the time spent working on failed children before continuing. 14623 var actualDuration = workInProgress.actualDuration; 14624 var child = workInProgress.child; 14625 while (child !== null) { 14626 actualDuration += child.actualDuration; 14627 child = child.sibling; 14628 } 14629 workInProgress.actualDuration = actualDuration; 14630 } 14631 14632 // This fiber did not complete because something threw. Pop values off 14633 // the stack without entering the complete phase. If this is a boundary, 14634 // capture values if possible. 14635 var next = unwindWork(workInProgress, nextRenderExpirationTime); 14636 // Because this fiber did not complete, don't reset its expiration time. 14637 if (workInProgress.effectTag & DidCapture) { 14638 // Restarting an error boundary 14639 stopFailedWorkTimer(workInProgress); 14640 } else { 14641 stopWorkTimer(workInProgress); 14642 } 14643 14644 if (next !== null) { 14645 stopWorkTimer(workInProgress); 14646 next.effectTag &= HostEffectMask; 14647 return next; 14648 } 14649 14650 if (returnFiber !== null) { 14651 // Mark the parent fiber as incomplete and clear its effect list. 14652 returnFiber.firstEffect = returnFiber.lastEffect = null; 14653 returnFiber.effectTag |= Incomplete; 14654 } 14655 14656 if (siblingFiber !== null) { 14657 // If there is more work to do in this returnFiber, do that next. 14658 return siblingFiber; 14659 } else if (returnFiber !== null) { 14660 // If there's no more work in this returnFiber. Complete the returnFiber. 14661 workInProgress = returnFiber; 14662 continue; 14663 } else { 14664 return null; 14665 } 14666 } 14667 } 14668 14669 // Without this explicit null return Flow complains of invalid return type 14670 // TODO Remove the above while(true) loop 14671 // eslint-disable-next-line no-unreachable 14672 return null; 14673 } 14674 14675 function performUnitOfWork(workInProgress) { 14676 // The current, flushed, state of this fiber is the alternate. 14677 // Ideally nothing should rely on this, but relying on it here 14678 // means that we don't need an additional field on the work in 14679 // progress. 14680 var current$$1 = workInProgress.alternate; 14681 14682 // See if beginning this work spawns more work. 14683 startWorkTimer(workInProgress); 14684 var next = void 0; 14685 if (enableProfilerTimer) { 14686 if (workInProgress.mode & ProfileMode) { 14687 startProfilerTimer(workInProgress); 14688 } 14689 14690 next = beginWork(current$$1, workInProgress, nextRenderExpirationTime); 14691 workInProgress.memoizedProps = workInProgress.pendingProps; 14692 14693 if (workInProgress.mode & ProfileMode) { 14694 // Record the render duration assuming we didn't bailout (or error). 14695 stopProfilerTimerIfRunningAndRecordDelta(workInProgress, true); 14696 } 14697 } else { 14698 next = beginWork(current$$1, workInProgress, nextRenderExpirationTime); 14699 workInProgress.memoizedProps = workInProgress.pendingProps; 14700 } 14701 14702 if (next === null) { 14703 // If this doesn't spawn new work, complete the current work. 14704 next = completeUnitOfWork(workInProgress); 14705 } 14706 14707 ReactCurrentOwner$2.current = null; 14708 14709 return next; 14710 } 14711 14712 function workLoop(isYieldy) { 14713 if (!isYieldy) { 14714 // Flush work without yielding 14715 while (nextUnitOfWork !== null) { 14716 nextUnitOfWork = performUnitOfWork(nextUnitOfWork); 14717 } 14718 } else { 14719 // Flush asynchronous work until there's a higher priority event 14720 while (nextUnitOfWork !== null && !shouldYieldToRenderer()) { 14721 nextUnitOfWork = performUnitOfWork(nextUnitOfWork); 14722 } 14723 } 14724 } 14725 14726 function renderRoot(root, isYieldy) { 14727 !!isWorking ? reactProdInvariant('243') : void 0; 14728 14729 flushPassiveEffects(); 14730 14731 isWorking = true; 14732 var previousDispatcher = ReactCurrentDispatcher.current; 14733 ReactCurrentDispatcher.current = ContextOnlyDispatcher; 14734 14735 var expirationTime = root.nextExpirationTimeToWorkOn; 14736 14737 // Check if we're starting from a fresh stack, or if we're resuming from 14738 // previously yielded work. 14739 if (expirationTime !== nextRenderExpirationTime || root !== nextRoot || nextUnitOfWork === null) { 14740 // Reset the stack and start working from the root. 14741 resetStack(); 14742 nextRoot = root; 14743 nextRenderExpirationTime = expirationTime; 14744 nextUnitOfWork = createWorkInProgress(nextRoot.current, null, nextRenderExpirationTime); 14745 root.pendingCommitExpirationTime = NoWork; 14746 14747 if (enableSchedulerTracing) { 14748 // Determine which interactions this batch of work currently includes, 14749 // So that we can accurately attribute time spent working on it, 14750 var interactions = new Set(); 14751 root.pendingInteractionMap.forEach(function (scheduledInteractions, scheduledExpirationTime) { 14752 if (scheduledExpirationTime >= expirationTime) { 14753 scheduledInteractions.forEach(function (interaction) { 14754 return interactions.add(interaction); 14755 }); 14756 } 14757 }); 14758 14759 // Store the current set of interactions on the FiberRoot for a few reasons: 14760 // We can re-use it in hot functions like renderRoot() without having to recalculate it. 14761 // We will also use it in commitWork() to pass to any Profiler onRender() hooks. 14762 // This also provides DevTools with a way to access it when the onCommitRoot() hook is called. 14763 root.memoizedInteractions = interactions; 14764 14765 if (interactions.size > 0) { 14766 var subscriber = __subscriberRef.current; 14767 if (subscriber !== null) { 14768 var threadID = computeThreadID(expirationTime, root.interactionThreadID); 14769 try { 14770 subscriber.onWorkStarted(interactions, threadID); 14771 } catch (error) { 14772 // Work thrown by an interaction tracing subscriber should be rethrown, 14773 // But only once it's safe (to avoid leaving the scheduler in an invalid state). 14774 // Store the error for now and we'll re-throw in finishRendering(). 14775 if (!hasUnhandledError) { 14776 hasUnhandledError = true; 14777 unhandledError = error; 14778 } 14779 } 14780 } 14781 } 14782 } 14783 } 14784 14785 var prevInteractions = null; 14786 if (enableSchedulerTracing) { 14787 // We're about to start new traced work. 14788 // Restore pending interactions so cascading work triggered during the render phase will be accounted for. 14789 prevInteractions = __interactionsRef.current; 14790 __interactionsRef.current = root.memoizedInteractions; 14791 } 14792 14793 var didFatal = false; 14794 14795 startWorkLoopTimer(nextUnitOfWork); 14796 14797 do { 14798 try { 14799 workLoop(isYieldy); 14800 } catch (thrownValue) { 14801 resetContextDependences(); 14802 resetHooks(); 14803 14804 // Reset in case completion throws. 14805 // This is only used in DEV and when replaying is on. 14806 if (nextUnitOfWork === null) { 14807 // This is a fatal error. 14808 didFatal = true; 14809 onUncaughtError(thrownValue); 14810 } else { 14811 if (enableProfilerTimer && nextUnitOfWork.mode & ProfileMode) { 14812 // Record the time spent rendering before an error was thrown. 14813 // This avoids inaccurate Profiler durations in the case of a suspended render. 14814 stopProfilerTimerIfRunningAndRecordDelta(nextUnitOfWork, true); 14815 } 14816 14817 !(nextUnitOfWork !== null) ? reactProdInvariant('271') : void 0; 14818 14819 var sourceFiber = nextUnitOfWork; 14820 var returnFiber = sourceFiber.return; 14821 if (returnFiber === null) { 14822 // This is the root. The root could capture its own errors. However, 14823 // we don't know if it errors before or after we pushed the host 14824 // context. This information is needed to avoid a stack mismatch. 14825 // Because we're not sure, treat this as a fatal error. We could track 14826 // which phase it fails in, but doesn't seem worth it. At least 14827 // for now. 14828 didFatal = true; 14829 onUncaughtError(thrownValue); 14830 } else { 14831 throwException(root, returnFiber, sourceFiber, thrownValue, nextRenderExpirationTime); 14832 nextUnitOfWork = completeUnitOfWork(sourceFiber); 14833 continue; 14834 } 14835 } 14836 } 14837 break; 14838 } while (true); 14839 14840 if (enableSchedulerTracing) { 14841 // Traced work is done for now; restore the previous interactions. 14842 __interactionsRef.current = prevInteractions; 14843 } 14844 14845 // We're done performing work. Time to clean up. 14846 isWorking = false; 14847 ReactCurrentDispatcher.current = previousDispatcher; 14848 resetContextDependences(); 14849 resetHooks(); 14850 14851 // Yield back to main thread. 14852 if (didFatal) { 14853 var _didCompleteRoot = false; 14854 stopWorkLoopTimer(interruptedBy, _didCompleteRoot); 14855 interruptedBy = null; 14856 // There was a fatal error. 14857 nextRoot = null; 14858 onFatal(root); 14859 return; 14860 } 14861 14862 if (nextUnitOfWork !== null) { 14863 // There's still remaining async work in this tree, but we ran out of time 14864 // in the current frame. Yield back to the renderer. Unless we're 14865 // interrupted by a higher priority update, we'll continue later from where 14866 // we left off. 14867 var _didCompleteRoot2 = false; 14868 stopWorkLoopTimer(interruptedBy, _didCompleteRoot2); 14869 interruptedBy = null; 14870 onYield(root); 14871 return; 14872 } 14873 14874 // We completed the whole tree. 14875 var didCompleteRoot = true; 14876 stopWorkLoopTimer(interruptedBy, didCompleteRoot); 14877 var rootWorkInProgress = root.current.alternate; 14878 !(rootWorkInProgress !== null) ? reactProdInvariant('281') : void 0; 14879 14880 // `nextRoot` points to the in-progress root. A non-null value indicates 14881 // that we're in the middle of an async render. Set it to null to indicate 14882 // there's no more work to be done in the current batch. 14883 nextRoot = null; 14884 interruptedBy = null; 14885 14886 if (nextRenderDidError) { 14887 // There was an error 14888 if (hasLowerPriorityWork(root, expirationTime)) { 14889 // There's lower priority work. If so, it may have the effect of fixing 14890 // the exception that was just thrown. Exit without committing. This is 14891 // similar to a suspend, but without a timeout because we're not waiting 14892 // for a promise to resolve. React will restart at the lower 14893 // priority level. 14894 markSuspendedPriorityLevel(root, expirationTime); 14895 var suspendedExpirationTime = expirationTime; 14896 var rootExpirationTime = root.expirationTime; 14897 onSuspend(root, rootWorkInProgress, suspendedExpirationTime, rootExpirationTime, -1 // Indicates no timeout 14898 ); 14899 return; 14900 } else if ( 14901 // There's no lower priority work, but we're rendering asynchronously. 14902 // Synchronously attempt to render the same level one more time. This is 14903 // similar to a suspend, but without a timeout because we're not waiting 14904 // for a promise to resolve. 14905 !root.didError && isYieldy) { 14906 root.didError = true; 14907 var _suspendedExpirationTime = root.nextExpirationTimeToWorkOn = expirationTime; 14908 var _rootExpirationTime = root.expirationTime = Sync; 14909 onSuspend(root, rootWorkInProgress, _suspendedExpirationTime, _rootExpirationTime, -1 // Indicates no timeout 14910 ); 14911 return; 14912 } 14913 } 14914 14915 if (isYieldy && nextLatestAbsoluteTimeoutMs !== -1) { 14916 // The tree was suspended. 14917 var _suspendedExpirationTime2 = expirationTime; 14918 markSuspendedPriorityLevel(root, _suspendedExpirationTime2); 14919 14920 // Find the earliest uncommitted expiration time in the tree, including 14921 // work that is suspended. The timeout threshold cannot be longer than 14922 // the overall expiration. 14923 var earliestExpirationTime = findEarliestOutstandingPriorityLevel(root, expirationTime); 14924 var earliestExpirationTimeMs = expirationTimeToMs(earliestExpirationTime); 14925 if (earliestExpirationTimeMs < nextLatestAbsoluteTimeoutMs) { 14926 nextLatestAbsoluteTimeoutMs = earliestExpirationTimeMs; 14927 } 14928 14929 // Subtract the current time from the absolute timeout to get the number 14930 // of milliseconds until the timeout. In other words, convert an absolute 14931 // timestamp to a relative time. This is the value that is passed 14932 // to `setTimeout`. 14933 var currentTimeMs = expirationTimeToMs(requestCurrentTime()); 14934 var msUntilTimeout = nextLatestAbsoluteTimeoutMs - currentTimeMs; 14935 msUntilTimeout = msUntilTimeout < 0 ? 0 : msUntilTimeout; 14936 14937 // TODO: Account for the Just Noticeable Difference 14938 14939 var _rootExpirationTime2 = root.expirationTime; 14940 onSuspend(root, rootWorkInProgress, _suspendedExpirationTime2, _rootExpirationTime2, msUntilTimeout); 14941 return; 14942 } 14943 14944 // Ready to commit. 14945 onComplete(root, rootWorkInProgress, expirationTime); 14946 } 14947 14948 function captureCommitPhaseError(sourceFiber, value) { 14949 var expirationTime = Sync; 14950 var fiber = sourceFiber.return; 14951 while (fiber !== null) { 14952 switch (fiber.tag) { 14953 case ClassComponent: 14954 var ctor = fiber.type; 14955 var instance = fiber.stateNode; 14956 if (typeof ctor.getDerivedStateFromError === 'function' || typeof instance.componentDidCatch === 'function' && !isAlreadyFailedLegacyErrorBoundary(instance)) { 14957 var errorInfo = createCapturedValue(value, sourceFiber); 14958 var update = createClassErrorUpdate(fiber, errorInfo, expirationTime); 14959 enqueueUpdate(fiber, update); 14960 scheduleWork(fiber, expirationTime); 14961 return; 14962 } 14963 break; 14964 case HostRoot: 14965 { 14966 var _errorInfo = createCapturedValue(value, sourceFiber); 14967 var _update = createRootErrorUpdate(fiber, _errorInfo, expirationTime); 14968 enqueueUpdate(fiber, _update); 14969 scheduleWork(fiber, expirationTime); 14970 return; 14971 } 14972 } 14973 fiber = fiber.return; 14974 } 14975 14976 if (sourceFiber.tag === HostRoot) { 14977 // Error was thrown at the root. There is no parent, so the root 14978 // itself should capture it. 14979 var rootFiber = sourceFiber; 14980 var _errorInfo2 = createCapturedValue(value, rootFiber); 14981 var _update2 = createRootErrorUpdate(rootFiber, _errorInfo2, expirationTime); 14982 enqueueUpdate(rootFiber, _update2); 14983 scheduleWork(rootFiber, expirationTime); 14984 } 14985 } 14986 14987 function computeThreadID(expirationTime, interactionThreadID) { 14988 // Interaction threads are unique per root and expiration time. 14989 return expirationTime * 1000 + interactionThreadID; 14990 } 14991 14992 // Creates a unique async expiration time. 14993 function computeUniqueAsyncExpiration() { 14994 var currentTime = requestCurrentTime(); 14995 var result = computeAsyncExpiration(currentTime); 14996 if (result >= lastUniqueAsyncExpiration) { 14997 // Since we assume the current time monotonically increases, we only hit 14998 // this branch when computeUniqueAsyncExpiration is fired multiple times 14999 // within a 200ms window (or whatever the async bucket size is). 15000 result = lastUniqueAsyncExpiration - 1; 15001 } 15002 lastUniqueAsyncExpiration = result; 15003 return lastUniqueAsyncExpiration; 15004 } 15005 15006 function computeExpirationForFiber(currentTime, fiber) { 15007 var priorityLevel = unstable_getCurrentPriorityLevel(); 15008 15009 var expirationTime = void 0; 15010 if ((fiber.mode & ConcurrentMode) === NoContext) { 15011 // Outside of concurrent mode, updates are always synchronous. 15012 expirationTime = Sync; 15013 } else if (isWorking && !isCommitting$1) { 15014 // During render phase, updates expire during as the current render. 15015 expirationTime = nextRenderExpirationTime; 15016 } else { 15017 switch (priorityLevel) { 15018 case unstable_ImmediatePriority: 15019 expirationTime = Sync; 15020 break; 15021 case unstable_UserBlockingPriority: 15022 expirationTime = computeInteractiveExpiration(currentTime); 15023 break; 15024 case unstable_NormalPriority: 15025 // This is a normal, concurrent update 15026 expirationTime = computeAsyncExpiration(currentTime); 15027 break; 15028 case unstable_LowPriority: 15029 case unstable_IdlePriority: 15030 expirationTime = Never; 15031 break; 15032 default: 15033 reactProdInvariant('313'); 15034 } 15035 15036 // If we're in the middle of rendering a tree, do not update at the same 15037 // expiration time that is already rendering. 15038 if (nextRoot !== null && expirationTime === nextRenderExpirationTime) { 15039 expirationTime -= 1; 15040 } 15041 } 15042 15043 // Keep track of the lowest pending interactive expiration time. This 15044 // allows us to synchronously flush all interactive updates 15045 // when needed. 15046 // TODO: Move this to renderer? 15047 if (priorityLevel === unstable_UserBlockingPriority && (lowestPriorityPendingInteractiveExpirationTime === NoWork || expirationTime < lowestPriorityPendingInteractiveExpirationTime)) { 15048 lowestPriorityPendingInteractiveExpirationTime = expirationTime; 15049 } 15050 15051 return expirationTime; 15052 } 15053 15054 function renderDidSuspend(root, absoluteTimeoutMs, suspendedTime) { 15055 // Schedule the timeout. 15056 if (absoluteTimeoutMs >= 0 && nextLatestAbsoluteTimeoutMs < absoluteTimeoutMs) { 15057 nextLatestAbsoluteTimeoutMs = absoluteTimeoutMs; 15058 } 15059 } 15060 15061 function renderDidError() { 15062 nextRenderDidError = true; 15063 } 15064 15065 function pingSuspendedRoot(root, thenable, pingTime) { 15066 // A promise that previously suspended React from committing has resolved. 15067 // If React is still suspended, try again at the previous level (pingTime). 15068 15069 var pingCache = root.pingCache; 15070 if (pingCache !== null) { 15071 // The thenable resolved, so we no longer need to memoize, because it will 15072 // never be thrown again. 15073 pingCache.delete(thenable); 15074 } 15075 15076 if (nextRoot !== null && nextRenderExpirationTime === pingTime) { 15077 // Received a ping at the same priority level at which we're currently 15078 // rendering. Restart from the root. 15079 nextRoot = null; 15080 } else { 15081 // Confirm that the root is still suspended at this level. Otherwise exit. 15082 if (isPriorityLevelSuspended(root, pingTime)) { 15083 // Ping at the original level 15084 markPingedPriorityLevel(root, pingTime); 15085 var rootExpirationTime = root.expirationTime; 15086 if (rootExpirationTime !== NoWork) { 15087 requestWork(root, rootExpirationTime); 15088 } 15089 } 15090 } 15091 } 15092 15093 function retryTimedOutBoundary(boundaryFiber, thenable) { 15094 // The boundary fiber (a Suspense component) previously timed out and was 15095 // rendered in its fallback state. One of the promises that suspended it has 15096 // resolved, which means at least part of the tree was likely unblocked. Try 15097 var retryCache = void 0; 15098 if (enableSuspenseServerRenderer) { 15099 switch (boundaryFiber.tag) { 15100 case SuspenseComponent: 15101 retryCache = boundaryFiber.stateNode; 15102 break; 15103 case DehydratedSuspenseComponent: 15104 retryCache = boundaryFiber.memoizedState; 15105 break; 15106 default: 15107 reactProdInvariant('314'); 15108 } 15109 } else { 15110 retryCache = boundaryFiber.stateNode; 15111 } 15112 if (retryCache !== null) { 15113 // The thenable resolved, so we no longer need to memoize, because it will 15114 // never be thrown again. 15115 retryCache.delete(thenable); 15116 } 15117 15118 var currentTime = requestCurrentTime(); 15119 var retryTime = computeExpirationForFiber(currentTime, boundaryFiber); 15120 var root = scheduleWorkToRoot(boundaryFiber, retryTime); 15121 if (root !== null) { 15122 markPendingPriorityLevel(root, retryTime); 15123 var rootExpirationTime = root.expirationTime; 15124 if (rootExpirationTime !== NoWork) { 15125 requestWork(root, rootExpirationTime); 15126 } 15127 } 15128 } 15129 15130 function scheduleWorkToRoot(fiber, expirationTime) { 15131 recordScheduleUpdate(); 15132 15133 if (fiber.expirationTime < expirationTime) { 15134 fiber.expirationTime = expirationTime; 15135 } 15136 var alternate = fiber.alternate; 15137 if (alternate !== null && alternate.expirationTime < expirationTime) { 15138 alternate.expirationTime = expirationTime; 15139 } 15140 // Walk the parent path to the root and update the child expiration time. 15141 var node = fiber.return; 15142 var root = null; 15143 if (node === null && fiber.tag === HostRoot) { 15144 root = fiber.stateNode; 15145 } else { 15146 while (node !== null) { 15147 alternate = node.alternate; 15148 if (node.childExpirationTime < expirationTime) { 15149 node.childExpirationTime = expirationTime; 15150 if (alternate !== null && alternate.childExpirationTime < expirationTime) { 15151 alternate.childExpirationTime = expirationTime; 15152 } 15153 } else if (alternate !== null && alternate.childExpirationTime < expirationTime) { 15154 alternate.childExpirationTime = expirationTime; 15155 } 15156 if (node.return === null && node.tag === HostRoot) { 15157 root = node.stateNode; 15158 break; 15159 } 15160 node = node.return; 15161 } 15162 } 15163 15164 if (enableSchedulerTracing) { 15165 if (root !== null) { 15166 var interactions = __interactionsRef.current; 15167 if (interactions.size > 0) { 15168 var pendingInteractionMap = root.pendingInteractionMap; 15169 var pendingInteractions = pendingInteractionMap.get(expirationTime); 15170 if (pendingInteractions != null) { 15171 interactions.forEach(function (interaction) { 15172 if (!pendingInteractions.has(interaction)) { 15173 // Update the pending async work count for previously unscheduled interaction. 15174 interaction.__count++; 15175 } 15176 15177 pendingInteractions.add(interaction); 15178 }); 15179 } else { 15180 pendingInteractionMap.set(expirationTime, new Set(interactions)); 15181 15182 // Update the pending async work count for the current interactions. 15183 interactions.forEach(function (interaction) { 15184 interaction.__count++; 15185 }); 15186 } 15187 15188 var subscriber = __subscriberRef.current; 15189 if (subscriber !== null) { 15190 var threadID = computeThreadID(expirationTime, root.interactionThreadID); 15191 subscriber.onWorkScheduled(interactions, threadID); 15192 } 15193 } 15194 } 15195 } 15196 return root; 15197 } 15198 15199 15200 15201 function scheduleWork(fiber, expirationTime) { 15202 var root = scheduleWorkToRoot(fiber, expirationTime); 15203 if (root === null) { 15204 return; 15205 } 15206 15207 if (!isWorking && nextRenderExpirationTime !== NoWork && expirationTime > nextRenderExpirationTime) { 15208 // This is an interruption. (Used for performance tracking.) 15209 interruptedBy = fiber; 15210 resetStack(); 15211 } 15212 markPendingPriorityLevel(root, expirationTime); 15213 if ( 15214 // If we're in the render phase, we don't need to schedule this root 15215 // for an update, because we'll do it before we exit... 15216 !isWorking || isCommitting$1 || 15217 // ...unless this is a different root than the one we're rendering. 15218 nextRoot !== root) { 15219 var rootExpirationTime = root.expirationTime; 15220 requestWork(root, rootExpirationTime); 15221 } 15222 if (nestedUpdateCount > NESTED_UPDATE_LIMIT) { 15223 // Reset this back to zero so subsequent updates don't throw. 15224 nestedUpdateCount = 0; 15225 reactProdInvariant('185'); 15226 } 15227 } 15228 15229 function syncUpdates(fn, a, b, c, d) { 15230 return unstable_runWithPriority(unstable_ImmediatePriority, function () { 15231 return fn(a, b, c, d); 15232 }); 15233 } 15234 15235 // TODO: Everything below this is written as if it has been lifted to the 15236 // renderers. I'll do this in a follow-up. 15237 15238 // Linked-list of roots 15239 var firstScheduledRoot = null; 15240 var lastScheduledRoot = null; 15241 15242 var callbackExpirationTime = NoWork; 15243 var callbackID = void 0; 15244 var isRendering = false; 15245 var nextFlushedRoot = null; 15246 var nextFlushedExpirationTime = NoWork; 15247 var lowestPriorityPendingInteractiveExpirationTime = NoWork; 15248 var hasUnhandledError = false; 15249 var unhandledError = null; 15250 15251 var isBatchingUpdates = false; 15252 var isUnbatchingUpdates = false; 15253 15254 var completedBatches = null; 15255 15256 var originalStartTimeMs = unstable_now(); 15257 var currentRendererTime = msToExpirationTime(originalStartTimeMs); 15258 var currentSchedulerTime = currentRendererTime; 15259 15260 // Use these to prevent an infinite loop of nested updates 15261 var NESTED_UPDATE_LIMIT = 50; 15262 var nestedUpdateCount = 0; 15263 var lastCommittedRootDuringThisBatch = null; 15264 15265 function recomputeCurrentRendererTime() { 15266 var currentTimeMs = unstable_now() - originalStartTimeMs; 15267 currentRendererTime = msToExpirationTime(currentTimeMs); 15268 } 15269 15270 function scheduleCallbackWithExpirationTime(root, expirationTime) { 15271 if (callbackExpirationTime !== NoWork) { 15272 // A callback is already scheduled. Check its expiration time (timeout). 15273 if (expirationTime < callbackExpirationTime) { 15274 // Existing callback has sufficient timeout. Exit. 15275 return; 15276 } else { 15277 if (callbackID !== null) { 15278 // Existing callback has insufficient timeout. Cancel and schedule a 15279 // new one. 15280 unstable_cancelCallback(callbackID); 15281 } 15282 } 15283 // The request callback timer is already running. Don't start a new one. 15284 } else { 15285 startRequestCallbackTimer(); 15286 } 15287 15288 callbackExpirationTime = expirationTime; 15289 var currentMs = unstable_now() - originalStartTimeMs; 15290 var expirationTimeMs = expirationTimeToMs(expirationTime); 15291 var timeout = expirationTimeMs - currentMs; 15292 callbackID = unstable_scheduleCallback(performAsyncWork, { timeout: timeout }); 15293 } 15294 15295 // For every call to renderRoot, one of onFatal, onComplete, onSuspend, and 15296 // onYield is called upon exiting. We use these in lieu of returning a tuple. 15297 // I've also chosen not to inline them into renderRoot because these will 15298 // eventually be lifted into the renderer. 15299 function onFatal(root) { 15300 root.finishedWork = null; 15301 } 15302 15303 function onComplete(root, finishedWork, expirationTime) { 15304 root.pendingCommitExpirationTime = expirationTime; 15305 root.finishedWork = finishedWork; 15306 } 15307 15308 function onSuspend(root, finishedWork, suspendedExpirationTime, rootExpirationTime, msUntilTimeout) { 15309 root.expirationTime = rootExpirationTime; 15310 if (msUntilTimeout === 0 && !shouldYieldToRenderer()) { 15311 // Don't wait an additional tick. Commit the tree immediately. 15312 root.pendingCommitExpirationTime = suspendedExpirationTime; 15313 root.finishedWork = finishedWork; 15314 } else if (msUntilTimeout > 0) { 15315 // Wait `msUntilTimeout` milliseconds before committing. 15316 root.timeoutHandle = scheduleTimeout(onTimeout.bind(null, root, finishedWork, suspendedExpirationTime), msUntilTimeout); 15317 } 15318 } 15319 15320 function onYield(root) { 15321 root.finishedWork = null; 15322 } 15323 15324 function onTimeout(root, finishedWork, suspendedExpirationTime) { 15325 // The root timed out. Commit it. 15326 root.pendingCommitExpirationTime = suspendedExpirationTime; 15327 root.finishedWork = finishedWork; 15328 // Read the current time before entering the commit phase. We can be 15329 // certain this won't cause tearing related to batching of event updates 15330 // because we're at the top of a timer event. 15331 recomputeCurrentRendererTime(); 15332 currentSchedulerTime = currentRendererTime; 15333 flushRoot(root, suspendedExpirationTime); 15334 } 15335 15336 function onCommit(root, expirationTime) { 15337 root.expirationTime = expirationTime; 15338 root.finishedWork = null; 15339 } 15340 15341 function requestCurrentTime() { 15342 // requestCurrentTime is called by the scheduler to compute an expiration 15343 // time. 15344 // 15345 // Expiration times are computed by adding to the current time (the start 15346 // time). However, if two updates are scheduled within the same event, we 15347 // should treat their start times as simultaneous, even if the actual clock 15348 // time has advanced between the first and second call. 15349 15350 // In other words, because expiration times determine how updates are batched, 15351 // we want all updates of like priority that occur within the same event to 15352 // receive the same expiration time. Otherwise we get tearing. 15353 // 15354 // We keep track of two separate times: the current "renderer" time and the 15355 // current "scheduler" time. The renderer time can be updated whenever; it 15356 // only exists to minimize the calls performance.now. 15357 // 15358 // But the scheduler time can only be updated if there's no pending work, or 15359 // if we know for certain that we're not in the middle of an event. 15360 15361 if (isRendering) { 15362 // We're already rendering. Return the most recently read time. 15363 return currentSchedulerTime; 15364 } 15365 // Check if there's pending work. 15366 findHighestPriorityRoot(); 15367 if (nextFlushedExpirationTime === NoWork || nextFlushedExpirationTime === Never) { 15368 // If there's no pending work, or if the pending work is offscreen, we can 15369 // read the current time without risk of tearing. 15370 recomputeCurrentRendererTime(); 15371 currentSchedulerTime = currentRendererTime; 15372 return currentSchedulerTime; 15373 } 15374 // There's already pending work. We might be in the middle of a browser 15375 // event. If we were to read the current time, it could cause multiple updates 15376 // within the same event to receive different expiration times, leading to 15377 // tearing. Return the last read time. During the next idle callback, the 15378 // time will be updated. 15379 return currentSchedulerTime; 15380 } 15381 15382 // requestWork is called by the scheduler whenever a root receives an update. 15383 // It's up to the renderer to call renderRoot at some point in the future. 15384 function requestWork(root, expirationTime) { 15385 addRootToSchedule(root, expirationTime); 15386 if (isRendering) { 15387 // Prevent reentrancy. Remaining work will be scheduled at the end of 15388 // the currently rendering batch. 15389 return; 15390 } 15391 15392 if (isBatchingUpdates) { 15393 // Flush work at the end of the batch. 15394 if (isUnbatchingUpdates) { 15395 // ...unless we're inside unbatchedUpdates, in which case we should 15396 // flush it now. 15397 nextFlushedRoot = root; 15398 nextFlushedExpirationTime = Sync; 15399 performWorkOnRoot(root, Sync, false); 15400 } 15401 return; 15402 } 15403 15404 // TODO: Get rid of Sync and use current time? 15405 if (expirationTime === Sync) { 15406 performSyncWork(); 15407 } else { 15408 scheduleCallbackWithExpirationTime(root, expirationTime); 15409 } 15410 } 15411 15412 function addRootToSchedule(root, expirationTime) { 15413 // Add the root to the schedule. 15414 // Check if this root is already part of the schedule. 15415 if (root.nextScheduledRoot === null) { 15416 // This root is not already scheduled. Add it. 15417 root.expirationTime = expirationTime; 15418 if (lastScheduledRoot === null) { 15419 firstScheduledRoot = lastScheduledRoot = root; 15420 root.nextScheduledRoot = root; 15421 } else { 15422 lastScheduledRoot.nextScheduledRoot = root; 15423 lastScheduledRoot = root; 15424 lastScheduledRoot.nextScheduledRoot = firstScheduledRoot; 15425 } 15426 } else { 15427 // This root is already scheduled, but its priority may have increased. 15428 var remainingExpirationTime = root.expirationTime; 15429 if (expirationTime > remainingExpirationTime) { 15430 // Update the priority. 15431 root.expirationTime = expirationTime; 15432 } 15433 } 15434 } 15435 15436 function findHighestPriorityRoot() { 15437 var highestPriorityWork = NoWork; 15438 var highestPriorityRoot = null; 15439 if (lastScheduledRoot !== null) { 15440 var previousScheduledRoot = lastScheduledRoot; 15441 var root = firstScheduledRoot; 15442 while (root !== null) { 15443 var remainingExpirationTime = root.expirationTime; 15444 if (remainingExpirationTime === NoWork) { 15445 // This root no longer has work. Remove it from the scheduler. 15446 15447 // TODO: This check is redudant, but Flow is confused by the branch 15448 // below where we set lastScheduledRoot to null, even though we break 15449 // from the loop right after. 15450 !(previousScheduledRoot !== null && lastScheduledRoot !== null) ? reactProdInvariant('244') : void 0; 15451 if (root === root.nextScheduledRoot) { 15452 // This is the only root in the list. 15453 root.nextScheduledRoot = null; 15454 firstScheduledRoot = lastScheduledRoot = null; 15455 break; 15456 } else if (root === firstScheduledRoot) { 15457 // This is the first root in the list. 15458 var next = root.nextScheduledRoot; 15459 firstScheduledRoot = next; 15460 lastScheduledRoot.nextScheduledRoot = next; 15461 root.nextScheduledRoot = null; 15462 } else if (root === lastScheduledRoot) { 15463 // This is the last root in the list. 15464 lastScheduledRoot = previousScheduledRoot; 15465 lastScheduledRoot.nextScheduledRoot = firstScheduledRoot; 15466 root.nextScheduledRoot = null; 15467 break; 15468 } else { 15469 previousScheduledRoot.nextScheduledRoot = root.nextScheduledRoot; 15470 root.nextScheduledRoot = null; 15471 } 15472 root = previousScheduledRoot.nextScheduledRoot; 15473 } else { 15474 if (remainingExpirationTime > highestPriorityWork) { 15475 // Update the priority, if it's higher 15476 highestPriorityWork = remainingExpirationTime; 15477 highestPriorityRoot = root; 15478 } 15479 if (root === lastScheduledRoot) { 15480 break; 15481 } 15482 if (highestPriorityWork === Sync) { 15483 // Sync is highest priority by definition so 15484 // we can stop searching. 15485 break; 15486 } 15487 previousScheduledRoot = root; 15488 root = root.nextScheduledRoot; 15489 } 15490 } 15491 } 15492 15493 nextFlushedRoot = highestPriorityRoot; 15494 nextFlushedExpirationTime = highestPriorityWork; 15495 } 15496 15497 // TODO: This wrapper exists because many of the older tests (the ones that use 15498 // flushDeferredPri) rely on the number of times `shouldYield` is called. We 15499 // should get rid of it. 15500 var didYield = false; 15501 function shouldYieldToRenderer() { 15502 if (didYield) { 15503 return true; 15504 } 15505 if (unstable_shouldYield()) { 15506 didYield = true; 15507 return true; 15508 } 15509 return false; 15510 } 15511 15512 function performAsyncWork() { 15513 try { 15514 if (!shouldYieldToRenderer()) { 15515 // The callback timed out. That means at least one update has expired. 15516 // Iterate through the root schedule. If they contain expired work, set 15517 // the next render expiration time to the current time. This has the effect 15518 // of flushing all expired work in a single batch, instead of flushing each 15519 // level one at a time. 15520 if (firstScheduledRoot !== null) { 15521 recomputeCurrentRendererTime(); 15522 var root = firstScheduledRoot; 15523 do { 15524 didExpireAtExpirationTime(root, currentRendererTime); 15525 // The root schedule is circular, so this is never null. 15526 root = root.nextScheduledRoot; 15527 } while (root !== firstScheduledRoot); 15528 } 15529 } 15530 performWork(NoWork, true); 15531 } finally { 15532 didYield = false; 15533 } 15534 } 15535 15536 function performSyncWork() { 15537 performWork(Sync, false); 15538 } 15539 15540 function performWork(minExpirationTime, isYieldy) { 15541 // Keep working on roots until there's no more work, or until there's a higher 15542 // priority event. 15543 findHighestPriorityRoot(); 15544 15545 if (isYieldy) { 15546 recomputeCurrentRendererTime(); 15547 currentSchedulerTime = currentRendererTime; 15548 15549 if (enableUserTimingAPI) { 15550 var didExpire = nextFlushedExpirationTime > currentRendererTime; 15551 var timeout = expirationTimeToMs(nextFlushedExpirationTime); 15552 stopRequestCallbackTimer(didExpire, timeout); 15553 } 15554 15555 while (nextFlushedRoot !== null && nextFlushedExpirationTime !== NoWork && minExpirationTime <= nextFlushedExpirationTime && !(didYield && currentRendererTime > nextFlushedExpirationTime)) { 15556 performWorkOnRoot(nextFlushedRoot, nextFlushedExpirationTime, currentRendererTime > nextFlushedExpirationTime); 15557 findHighestPriorityRoot(); 15558 recomputeCurrentRendererTime(); 15559 currentSchedulerTime = currentRendererTime; 15560 } 15561 } else { 15562 while (nextFlushedRoot !== null && nextFlushedExpirationTime !== NoWork && minExpirationTime <= nextFlushedExpirationTime) { 15563 performWorkOnRoot(nextFlushedRoot, nextFlushedExpirationTime, false); 15564 findHighestPriorityRoot(); 15565 } 15566 } 15567 15568 // We're done flushing work. Either we ran out of time in this callback, 15569 // or there's no more work left with sufficient priority. 15570 15571 // If we're inside a callback, set this to false since we just completed it. 15572 if (isYieldy) { 15573 callbackExpirationTime = NoWork; 15574 callbackID = null; 15575 } 15576 // If there's work left over, schedule a new callback. 15577 if (nextFlushedExpirationTime !== NoWork) { 15578 scheduleCallbackWithExpirationTime(nextFlushedRoot, nextFlushedExpirationTime); 15579 } 15580 15581 // Clean-up. 15582 finishRendering(); 15583 } 15584 15585 function flushRoot(root, expirationTime) { 15586 !!isRendering ? reactProdInvariant('253') : void 0; 15587 // Perform work on root as if the given expiration time is the current time. 15588 // This has the effect of synchronously flushing all work up to and 15589 // including the given time. 15590 nextFlushedRoot = root; 15591 nextFlushedExpirationTime = expirationTime; 15592 performWorkOnRoot(root, expirationTime, false); 15593 // Flush any sync work that was scheduled by lifecycles 15594 performSyncWork(); 15595 } 15596 15597 function finishRendering() { 15598 nestedUpdateCount = 0; 15599 lastCommittedRootDuringThisBatch = null; 15600 15601 if (completedBatches !== null) { 15602 var batches = completedBatches; 15603 completedBatches = null; 15604 for (var i = 0; i < batches.length; i++) { 15605 var batch = batches[i]; 15606 try { 15607 batch._onComplete(); 15608 } catch (error) { 15609 if (!hasUnhandledError) { 15610 hasUnhandledError = true; 15611 unhandledError = error; 15612 } 15613 } 15614 } 15615 } 15616 15617 if (hasUnhandledError) { 15618 var error = unhandledError; 15619 unhandledError = null; 15620 hasUnhandledError = false; 15621 throw error; 15622 } 15623 } 15624 15625 function performWorkOnRoot(root, expirationTime, isYieldy) { 15626 !!isRendering ? reactProdInvariant('245') : void 0; 15627 15628 isRendering = true; 15629 15630 // Check if this is async work or sync/expired work. 15631 if (!isYieldy) { 15632 // Flush work without yielding. 15633 // TODO: Non-yieldy work does not necessarily imply expired work. A renderer 15634 // may want to perform some work without yielding, but also without 15635 // requiring the root to complete (by triggering placeholders). 15636 15637 var finishedWork = root.finishedWork; 15638 if (finishedWork !== null) { 15639 // This root is already complete. We can commit it. 15640 completeRoot(root, finishedWork, expirationTime); 15641 } else { 15642 root.finishedWork = null; 15643 // If this root previously suspended, clear its existing timeout, since 15644 // we're about to try rendering again. 15645 var timeoutHandle = root.timeoutHandle; 15646 if (timeoutHandle !== noTimeout) { 15647 root.timeoutHandle = noTimeout; 15648 // $FlowFixMe Complains noTimeout is not a TimeoutID, despite the check above 15649 cancelTimeout(timeoutHandle); 15650 } 15651 renderRoot(root, isYieldy); 15652 finishedWork = root.finishedWork; 15653 if (finishedWork !== null) { 15654 // We've completed the root. Commit it. 15655 completeRoot(root, finishedWork, expirationTime); 15656 } 15657 } 15658 } else { 15659 // Flush async work. 15660 var _finishedWork = root.finishedWork; 15661 if (_finishedWork !== null) { 15662 // This root is already complete. We can commit it. 15663 completeRoot(root, _finishedWork, expirationTime); 15664 } else { 15665 root.finishedWork = null; 15666 // If this root previously suspended, clear its existing timeout, since 15667 // we're about to try rendering again. 15668 var _timeoutHandle = root.timeoutHandle; 15669 if (_timeoutHandle !== noTimeout) { 15670 root.timeoutHandle = noTimeout; 15671 // $FlowFixMe Complains noTimeout is not a TimeoutID, despite the check above 15672 cancelTimeout(_timeoutHandle); 15673 } 15674 renderRoot(root, isYieldy); 15675 _finishedWork = root.finishedWork; 15676 if (_finishedWork !== null) { 15677 // We've completed the root. Check the if we should yield one more time 15678 // before committing. 15679 if (!shouldYieldToRenderer()) { 15680 // Still time left. Commit the root. 15681 completeRoot(root, _finishedWork, expirationTime); 15682 } else { 15683 // There's no time left. Mark this root as complete. We'll come 15684 // back and commit it later. 15685 root.finishedWork = _finishedWork; 15686 } 15687 } 15688 } 15689 } 15690 15691 isRendering = false; 15692 } 15693 15694 function completeRoot(root, finishedWork, expirationTime) { 15695 // Check if there's a batch that matches this expiration time. 15696 var firstBatch = root.firstBatch; 15697 if (firstBatch !== null && firstBatch._expirationTime >= expirationTime) { 15698 if (completedBatches === null) { 15699 completedBatches = [firstBatch]; 15700 } else { 15701 completedBatches.push(firstBatch); 15702 } 15703 if (firstBatch._defer) { 15704 // This root is blocked from committing by a batch. Unschedule it until 15705 // we receive another update. 15706 root.finishedWork = finishedWork; 15707 root.expirationTime = NoWork; 15708 return; 15709 } 15710 } 15711 15712 // Commit the root. 15713 root.finishedWork = null; 15714 15715 // Check if this is a nested update (a sync update scheduled during the 15716 // commit phase). 15717 if (root === lastCommittedRootDuringThisBatch) { 15718 // If the next root is the same as the previous root, this is a nested 15719 // update. To prevent an infinite loop, increment the nested update count. 15720 nestedUpdateCount++; 15721 } else { 15722 // Reset whenever we switch roots. 15723 lastCommittedRootDuringThisBatch = root; 15724 nestedUpdateCount = 0; 15725 } 15726 unstable_runWithPriority(unstable_ImmediatePriority, function () { 15727 commitRoot(root, finishedWork); 15728 }); 15729 } 15730 15731 function onUncaughtError(error) { 15732 !(nextFlushedRoot !== null) ? reactProdInvariant('246') : void 0; 15733 // Unschedule this root so we don't work on it again until there's 15734 // another update. 15735 nextFlushedRoot.expirationTime = NoWork; 15736 if (!hasUnhandledError) { 15737 hasUnhandledError = true; 15738 unhandledError = error; 15739 } 15740 } 15741 15742 // TODO: Batching should be implemented at the renderer level, not inside 15743 // the reconciler. 15744 function batchedUpdates$1(fn, a) { 15745 var previousIsBatchingUpdates = isBatchingUpdates; 15746 isBatchingUpdates = true; 15747 try { 15748 return fn(a); 15749 } finally { 15750 isBatchingUpdates = previousIsBatchingUpdates; 15751 if (!isBatchingUpdates && !isRendering) { 15752 performSyncWork(); 15753 } 15754 } 15755 } 15756 15757 // TODO: Batching should be implemented at the renderer level, not inside 15758 // the reconciler. 15759 function unbatchedUpdates(fn, a) { 15760 if (isBatchingUpdates && !isUnbatchingUpdates) { 15761 isUnbatchingUpdates = true; 15762 try { 15763 return fn(a); 15764 } finally { 15765 isUnbatchingUpdates = false; 15766 } 15767 } 15768 return fn(a); 15769 } 15770 15771 // TODO: Batching should be implemented at the renderer level, not within 15772 // the reconciler. 15773 function flushSync(fn, a) { 15774 !!isRendering ? reactProdInvariant('187') : void 0; 15775 var previousIsBatchingUpdates = isBatchingUpdates; 15776 isBatchingUpdates = true; 15777 try { 15778 return syncUpdates(fn, a); 15779 } finally { 15780 isBatchingUpdates = previousIsBatchingUpdates; 15781 performSyncWork(); 15782 } 15783 } 15784 15785 function interactiveUpdates$1(fn, a, b) { 15786 // If there are any pending interactive updates, synchronously flush them. 15787 // This needs to happen before we read any handlers, because the effect of 15788 // the previous event may influence which handlers are called during 15789 // this event. 15790 if (!isBatchingUpdates && !isRendering && lowestPriorityPendingInteractiveExpirationTime !== NoWork) { 15791 // Synchronously flush pending interactive updates. 15792 performWork(lowestPriorityPendingInteractiveExpirationTime, false); 15793 lowestPriorityPendingInteractiveExpirationTime = NoWork; 15794 } 15795 var previousIsBatchingUpdates = isBatchingUpdates; 15796 isBatchingUpdates = true; 15797 try { 15798 return unstable_runWithPriority(unstable_UserBlockingPriority, function () { 15799 return fn(a, b); 15800 }); 15801 } finally { 15802 isBatchingUpdates = previousIsBatchingUpdates; 15803 if (!isBatchingUpdates && !isRendering) { 15804 performSyncWork(); 15805 } 15806 } 15807 } 15808 15809 function flushInteractiveUpdates$1() { 15810 if (!isRendering && lowestPriorityPendingInteractiveExpirationTime !== NoWork) { 15811 // Synchronously flush pending interactive updates. 15812 performWork(lowestPriorityPendingInteractiveExpirationTime, false); 15813 lowestPriorityPendingInteractiveExpirationTime = NoWork; 15814 } 15815 } 15816 15817 function flushControlled(fn) { 15818 var previousIsBatchingUpdates = isBatchingUpdates; 15819 isBatchingUpdates = true; 15820 try { 15821 syncUpdates(fn); 15822 } finally { 15823 isBatchingUpdates = previousIsBatchingUpdates; 15824 if (!isBatchingUpdates && !isRendering) { 15825 performSyncWork(); 15826 } 15827 } 15828 } 15829 15830 function getContextForSubtree(parentComponent) { 15831 if (!parentComponent) { 15832 return emptyContextObject; 15833 } 15834 15835 var fiber = get(parentComponent); 15836 var parentContext = findCurrentUnmaskedContext(fiber); 15837 15838 if (fiber.tag === ClassComponent) { 15839 var Component = fiber.type; 15840 if (isContextProvider(Component)) { 15841 return processChildContext(fiber, Component, parentContext); 15842 } 15843 } 15844 15845 return parentContext; 15846 } 15847 15848 function scheduleRootUpdate(current$$1, element, expirationTime, callback) { 15849 var update = createUpdate(expirationTime); 15850 // Caution: React DevTools currently depends on this property 15851 // being called "element". 15852 update.payload = { element: element }; 15853 15854 callback = callback === undefined ? null : callback; 15855 if (callback !== null) { 15856 update.callback = callback; 15857 } 15858 15859 flushPassiveEffects(); 15860 enqueueUpdate(current$$1, update); 15861 scheduleWork(current$$1, expirationTime); 15862 15863 return expirationTime; 15864 } 15865 15866 function updateContainerAtExpirationTime(element, container, parentComponent, expirationTime, callback) { 15867 // TODO: If this is a nested container, this won't be the root. 15868 var current$$1 = container.current; 15869 15870 var context = getContextForSubtree(parentComponent); 15871 if (container.context === null) { 15872 container.context = context; 15873 } else { 15874 container.pendingContext = context; 15875 } 15876 15877 return scheduleRootUpdate(current$$1, element, expirationTime, callback); 15878 } 15879 15880 function findHostInstance(component) { 15881 var fiber = get(component); 15882 if (fiber === undefined) { 15883 if (typeof component.render === 'function') { 15884 reactProdInvariant('188'); 15885 } else { 15886 reactProdInvariant('268', Object.keys(component)); 15887 } 15888 } 15889 var hostFiber = findCurrentHostFiber(fiber); 15890 if (hostFiber === null) { 15891 return null; 15892 } 15893 return hostFiber.stateNode; 15894 } 15895 15896 function createContainer(containerInfo, isConcurrent, hydrate) { 15897 return createFiberRoot(containerInfo, isConcurrent, hydrate); 15898 } 15899 15900 function updateContainer(element, container, parentComponent, callback) { 15901 var current$$1 = container.current; 15902 var currentTime = requestCurrentTime(); 15903 var expirationTime = computeExpirationForFiber(currentTime, current$$1); 15904 return updateContainerAtExpirationTime(element, container, parentComponent, expirationTime, callback); 15905 } 15906 15907 function getPublicRootInstance(container) { 15908 var containerFiber = container.current; 15909 if (!containerFiber.child) { 15910 return null; 15911 } 15912 switch (containerFiber.child.tag) { 15913 case HostComponent: 15914 return getPublicInstance(containerFiber.child.stateNode); 15915 default: 15916 return containerFiber.child.stateNode; 15917 } 15918 } 15919 15920 15921 15922 var overrideProps = null; 15923 15924 function injectIntoDevTools(devToolsConfig) { 15925 var findFiberByHostInstance = devToolsConfig.findFiberByHostInstance; 15926 var ReactCurrentDispatcher = ReactSharedInternals.ReactCurrentDispatcher; 15927 15928 15929 return injectInternals(_assign({}, devToolsConfig, { 15930 overrideProps: overrideProps, 15931 currentDispatcherRef: ReactCurrentDispatcher, 15932 findHostInstanceByFiber: function (fiber) { 15933 var hostFiber = findCurrentHostFiber(fiber); 15934 if (hostFiber === null) { 15935 return null; 15936 } 15937 return hostFiber.stateNode; 15938 }, 15939 findFiberByHostInstance: function (instance) { 15940 if (!findFiberByHostInstance) { 15941 // Might not be implemented by the renderer. 15942 return null; 15943 } 15944 return findFiberByHostInstance(instance); 15945 } 15946 })); 15947 } 15948 15949 // This file intentionally does *not* have the Flow annotation. 15950 // Don't add it. See `./inline-typed.js` for an explanation. 15951 15952 function createPortal$1(children, containerInfo, 15953 // TODO: figure out the API for cross-renderer implementation. 15954 implementation) { 15955 var key = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null; 15956 15957 return { 15958 // This tag allow us to uniquely identify this as a React Portal 15959 $$typeof: REACT_PORTAL_TYPE, 15960 key: key == null ? null : '' + key, 15961 children: children, 15962 containerInfo: containerInfo, 15963 implementation: implementation 15964 }; 15965 } 15966 15967 // TODO: this is special because it gets imported during build. 15968 15969 var ReactVersion = '16.8.6'; 15970 15971 // TODO: This type is shared between the reconciler and ReactDOM, but will 15972 // eventually be lifted out to the renderer. 15973 15974 var ReactCurrentOwner = ReactSharedInternals.ReactCurrentOwner; 15975 15976 setRestoreImplementation(restoreControlledState$1); 15977 15978 function ReactBatch(root) { 15979 var expirationTime = computeUniqueAsyncExpiration(); 15980 this._expirationTime = expirationTime; 15981 this._root = root; 15982 this._next = null; 15983 this._callbacks = null; 15984 this._didComplete = false; 15985 this._hasChildren = false; 15986 this._children = null; 15987 this._defer = true; 15988 } 15989 ReactBatch.prototype.render = function (children) { 15990 !this._defer ? reactProdInvariant('250') : void 0; 15991 this._hasChildren = true; 15992 this._children = children; 15993 var internalRoot = this._root._internalRoot; 15994 var expirationTime = this._expirationTime; 15995 var work = new ReactWork(); 15996 updateContainerAtExpirationTime(children, internalRoot, null, expirationTime, work._onCommit); 15997 return work; 15998 }; 15999 ReactBatch.prototype.then = function (onComplete) { 16000 if (this._didComplete) { 16001 onComplete(); 16002 return; 16003 } 16004 var callbacks = this._callbacks; 16005 if (callbacks === null) { 16006 callbacks = this._callbacks = []; 16007 } 16008 callbacks.push(onComplete); 16009 }; 16010 ReactBatch.prototype.commit = function () { 16011 var internalRoot = this._root._internalRoot; 16012 var firstBatch = internalRoot.firstBatch; 16013 !(this._defer && firstBatch !== null) ? reactProdInvariant('251') : void 0; 16014 16015 if (!this._hasChildren) { 16016 // This batch is empty. Return. 16017 this._next = null; 16018 this._defer = false; 16019 return; 16020 } 16021 16022 var expirationTime = this._expirationTime; 16023 16024 // Ensure this is the first batch in the list. 16025 if (firstBatch !== this) { 16026 // This batch is not the earliest batch. We need to move it to the front. 16027 // Update its expiration time to be the expiration time of the earliest 16028 // batch, so that we can flush it without flushing the other batches. 16029 if (this._hasChildren) { 16030 expirationTime = this._expirationTime = firstBatch._expirationTime; 16031 // Rendering this batch again ensures its children will be the final state 16032 // when we flush (updates are processed in insertion order: last 16033 // update wins). 16034 // TODO: This forces a restart. Should we print a warning? 16035 this.render(this._children); 16036 } 16037 16038 // Remove the batch from the list. 16039 var previous = null; 16040 var batch = firstBatch; 16041 while (batch !== this) { 16042 previous = batch; 16043 batch = batch._next; 16044 } 16045 !(previous !== null) ? reactProdInvariant('251') : void 0; 16046 previous._next = batch._next; 16047 16048 // Add it to the front. 16049 this._next = firstBatch; 16050 firstBatch = internalRoot.firstBatch = this; 16051 } 16052 16053 // Synchronously flush all the work up to this batch's expiration time. 16054 this._defer = false; 16055 flushRoot(internalRoot, expirationTime); 16056 16057 // Pop the batch from the list. 16058 var next = this._next; 16059 this._next = null; 16060 firstBatch = internalRoot.firstBatch = next; 16061 16062 // Append the next earliest batch's children to the update queue. 16063 if (firstBatch !== null && firstBatch._hasChildren) { 16064 firstBatch.render(firstBatch._children); 16065 } 16066 }; 16067 ReactBatch.prototype._onComplete = function () { 16068 if (this._didComplete) { 16069 return; 16070 } 16071 this._didComplete = true; 16072 var callbacks = this._callbacks; 16073 if (callbacks === null) { 16074 return; 16075 } 16076 // TODO: Error handling. 16077 for (var i = 0; i < callbacks.length; i++) { 16078 var _callback = callbacks[i]; 16079 _callback(); 16080 } 16081 }; 16082 16083 function ReactWork() { 16084 this._callbacks = null; 16085 this._didCommit = false; 16086 // TODO: Avoid need to bind by replacing callbacks in the update queue with 16087 // list of Work objects. 16088 this._onCommit = this._onCommit.bind(this); 16089 } 16090 ReactWork.prototype.then = function (onCommit) { 16091 if (this._didCommit) { 16092 onCommit(); 16093 return; 16094 } 16095 var callbacks = this._callbacks; 16096 if (callbacks === null) { 16097 callbacks = this._callbacks = []; 16098 } 16099 callbacks.push(onCommit); 16100 }; 16101 ReactWork.prototype._onCommit = function () { 16102 if (this._didCommit) { 16103 return; 16104 } 16105 this._didCommit = true; 16106 var callbacks = this._callbacks; 16107 if (callbacks === null) { 16108 return; 16109 } 16110 // TODO: Error handling. 16111 for (var i = 0; i < callbacks.length; i++) { 16112 var _callback2 = callbacks[i]; 16113 !(typeof _callback2 === 'function') ? reactProdInvariant('191', _callback2) : void 0; 16114 _callback2(); 16115 } 16116 }; 16117 16118 function ReactRoot(container, isConcurrent, hydrate) { 16119 var root = createContainer(container, isConcurrent, hydrate); 16120 this._internalRoot = root; 16121 } 16122 ReactRoot.prototype.render = function (children, callback) { 16123 var root = this._internalRoot; 16124 var work = new ReactWork(); 16125 callback = callback === undefined ? null : callback; 16126 if (callback !== null) { 16127 work.then(callback); 16128 } 16129 updateContainer(children, root, null, work._onCommit); 16130 return work; 16131 }; 16132 ReactRoot.prototype.unmount = function (callback) { 16133 var root = this._internalRoot; 16134 var work = new ReactWork(); 16135 callback = callback === undefined ? null : callback; 16136 if (callback !== null) { 16137 work.then(callback); 16138 } 16139 updateContainer(null, root, null, work._onCommit); 16140 return work; 16141 }; 16142 ReactRoot.prototype.legacy_renderSubtreeIntoContainer = function (parentComponent, children, callback) { 16143 var root = this._internalRoot; 16144 var work = new ReactWork(); 16145 callback = callback === undefined ? null : callback; 16146 if (callback !== null) { 16147 work.then(callback); 16148 } 16149 updateContainer(children, root, parentComponent, work._onCommit); 16150 return work; 16151 }; 16152 ReactRoot.prototype.createBatch = function () { 16153 var batch = new ReactBatch(this); 16154 var expirationTime = batch._expirationTime; 16155 16156 var internalRoot = this._internalRoot; 16157 var firstBatch = internalRoot.firstBatch; 16158 if (firstBatch === null) { 16159 internalRoot.firstBatch = batch; 16160 batch._next = null; 16161 } else { 16162 // Insert sorted by expiration time then insertion order 16163 var insertAfter = null; 16164 var insertBefore = firstBatch; 16165 while (insertBefore !== null && insertBefore._expirationTime >= expirationTime) { 16166 insertAfter = insertBefore; 16167 insertBefore = insertBefore._next; 16168 } 16169 batch._next = insertBefore; 16170 if (insertAfter !== null) { 16171 insertAfter._next = batch; 16172 } 16173 } 16174 16175 return batch; 16176 }; 16177 16178 /** 16179 * True if the supplied DOM node is a valid node element. 16180 * 16181 * @param {?DOMElement} node The candidate DOM node. 16182 * @return {boolean} True if the DOM is a valid DOM node. 16183 * @internal 16184 */ 16185 function isValidContainer(node) { 16186 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 ')); 16187 } 16188 16189 function getReactRootElementInContainer(container) { 16190 if (!container) { 16191 return null; 16192 } 16193 16194 if (container.nodeType === DOCUMENT_NODE) { 16195 return container.documentElement; 16196 } else { 16197 return container.firstChild; 16198 } 16199 } 16200 16201 function shouldHydrateDueToLegacyHeuristic(container) { 16202 var rootElement = getReactRootElementInContainer(container); 16203 return !!(rootElement && rootElement.nodeType === ELEMENT_NODE && rootElement.hasAttribute(ROOT_ATTRIBUTE_NAME)); 16204 } 16205 16206 setBatchingImplementation(batchedUpdates$1, interactiveUpdates$1, flushInteractiveUpdates$1); 16207 16208 function legacyCreateRootFromDOMContainer(container, forceHydrate) { 16209 var shouldHydrate = forceHydrate || shouldHydrateDueToLegacyHeuristic(container); 16210 // First clear any existing content. 16211 if (!shouldHydrate) { 16212 var rootSibling = void 0; 16213 while (rootSibling = container.lastChild) { 16214 container.removeChild(rootSibling); 16215 } 16216 } 16217 var isConcurrent = false; 16218 return new ReactRoot(container, isConcurrent, shouldHydrate); 16219 } 16220 16221 function legacyRenderSubtreeIntoContainer(parentComponent, children, container, forceHydrate, callback) { 16222 var root = container._reactRootContainer; 16223 if (!root) { 16224 // Initial mount 16225 root = container._reactRootContainer = legacyCreateRootFromDOMContainer(container, forceHydrate); 16226 if (typeof callback === 'function') { 16227 var originalCallback = callback; 16228 callback = function () { 16229 var instance = getPublicRootInstance(root._internalRoot); 16230 originalCallback.call(instance); 16231 }; 16232 } 16233 // Initial mount should not be batched. 16234 unbatchedUpdates(function () { 16235 if (parentComponent != null) { 16236 root.legacy_renderSubtreeIntoContainer(parentComponent, children, callback); 16237 } else { 16238 root.render(children, callback); 16239 } 16240 }); 16241 } else { 16242 if (typeof callback === 'function') { 16243 var _originalCallback = callback; 16244 callback = function () { 16245 var instance = getPublicRootInstance(root._internalRoot); 16246 _originalCallback.call(instance); 16247 }; 16248 } 16249 // Update 16250 if (parentComponent != null) { 16251 root.legacy_renderSubtreeIntoContainer(parentComponent, children, callback); 16252 } else { 16253 root.render(children, callback); 16254 } 16255 } 16256 return getPublicRootInstance(root._internalRoot); 16257 } 16258 16259 function createPortal$$1(children, container) { 16260 var key = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null; 16261 16262 !isValidContainer(container) ? reactProdInvariant('200') : void 0; 16263 // TODO: pass ReactDOM portal implementation as third argument 16264 return createPortal$1(children, container, null, key); 16265 } 16266 16267 var ReactDOM = { 16268 createPortal: createPortal$$1, 16269 16270 findDOMNode: function (componentOrElement) { 16271 if (componentOrElement == null) { 16272 return null; 16273 } 16274 if (componentOrElement.nodeType === ELEMENT_NODE) { 16275 return componentOrElement; 16276 } 16277 return findHostInstance(componentOrElement); 16278 }, 16279 hydrate: function (element, container, callback) { 16280 !isValidContainer(container) ? reactProdInvariant('200') : void 0; 16281 return legacyRenderSubtreeIntoContainer(null, element, container, true, callback); 16282 }, 16283 render: function (element, container, callback) { 16284 !isValidContainer(container) ? reactProdInvariant('200') : void 0; 16285 return legacyRenderSubtreeIntoContainer(null, element, container, false, callback); 16286 }, 16287 unstable_renderSubtreeIntoContainer: function (parentComponent, element, containerNode, callback) { 16288 !isValidContainer(containerNode) ? reactProdInvariant('200') : void 0; 16289 !(parentComponent != null && has(parentComponent)) ? reactProdInvariant('38') : void 0; 16290 return legacyRenderSubtreeIntoContainer(parentComponent, element, containerNode, false, callback); 16291 }, 16292 unmountComponentAtNode: function (container) { 16293 !isValidContainer(container) ? reactProdInvariant('40') : void 0; 16294 16295 if (container._reactRootContainer) { 16296 unbatchedUpdates(function () { 16297 legacyRenderSubtreeIntoContainer(null, null, container, false, function () { 16298 container._reactRootContainer = null; 16299 }); 16300 }); 16301 // If you call unmountComponentAtNode twice in quick succession, you'll 16302 // get `true` twice. That's probably fine? 16303 return true; 16304 } else { 16305 return false; 16306 } 16307 }, 16308 16309 16310 // Temporary alias since we already shipped React 16 RC with it. 16311 // TODO: remove in React 17. 16312 unstable_createPortal: function () { 16313 return createPortal$$1.apply(undefined, arguments); 16314 }, 16315 16316 16317 unstable_batchedUpdates: batchedUpdates$1, 16318 16319 unstable_interactiveUpdates: interactiveUpdates$1, 16320 16321 flushSync: flushSync, 16322 16323 unstable_createRoot: createRoot, 16324 unstable_flushControlled: flushControlled, 16325 16326 __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: { 16327 // Keep in sync with ReactDOMUnstableNativeDependencies.js 16328 // and ReactTestUtils.js. This is an array for better minification. 16329 Events: [getInstanceFromNode$1, getNodeFromInstance$1, getFiberCurrentPropsFromNode$1, injection.injectEventPluginsByName, eventNameDispatchConfigs, accumulateTwoPhaseDispatches, accumulateDirectDispatches, enqueueStateRestore, restoreStateIfNeeded, dispatchEvent, runEventsInBatch] 16330 } 16331 }; 16332 16333 function createRoot(container, options) { 16334 var functionName = enableStableConcurrentModeAPIs ? 'createRoot' : 'unstable_createRoot'; 16335 !isValidContainer(container) ? reactProdInvariant('299', functionName) : void 0; 16336 var hydrate = options != null && options.hydrate === true; 16337 return new ReactRoot(container, true, hydrate); 16338 } 16339 16340 if (enableStableConcurrentModeAPIs) { 16341 ReactDOM.createRoot = createRoot; 16342 ReactDOM.unstable_createRoot = undefined; 16343 } 16344 16345 var foundDevTools = injectIntoDevTools({ 16346 findFiberByHostInstance: getClosestInstanceFromNode, 16347 bundleType: 0, 16348 version: ReactVersion, 16349 rendererPackageName: 'react-dom' 16350 }); 16351 16352 16353 16354 var ReactDOM$2 = ({ 16355 default: ReactDOM 16356 }); 16357 16358 var ReactDOM$3 = ( ReactDOM$2 && ReactDOM ) || ReactDOM$2; 16359 16360 // TODO: decide on the top-level export form. 16361 // This is hacky but makes it work with both Rollup and Jest. 16362 var reactDom = ReactDOM$3.default || ReactDOM$3; 16363 16364 export default reactDom;