[ Index ] |
PHP Cross Reference of WordPress |
[Summary view] [Print] [Text view]
1 /** @license React v16.13.1 2 * react-dom.development.js 3 * 4 * Copyright (c) Facebook, Inc. and its affiliates. 5 * 6 * This source code is licensed under the MIT license found in the 7 * LICENSE file in the root directory of this source tree. 8 */ 9 10 'use strict'; 11 12 (function (global, factory) { 13 typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('react')) : 14 typeof define === 'function' && define.amd ? define(['exports', 'react'], factory) : 15 (global = global || self, factory(global.ReactDOM = {}, global.React)); 16 }(this, (function (exports, React) { 'use strict'; 17 18 var ReactSharedInternals = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; // Prevent newer renderers from RTE when used with older react package versions. 19 // Current owner and dispatcher used to share the same ref, 20 // but PR #14548 split them out to better support the react-debug-tools package. 21 22 if (!ReactSharedInternals.hasOwnProperty('ReactCurrentDispatcher')) { 23 ReactSharedInternals.ReactCurrentDispatcher = { 24 current: null 25 }; 26 } 27 28 if (!ReactSharedInternals.hasOwnProperty('ReactCurrentBatchConfig')) { 29 ReactSharedInternals.ReactCurrentBatchConfig = { 30 suspense: null 31 }; 32 } 33 34 // by calls to these methods by a Babel plugin. 35 // 36 // In PROD (or in packages without access to React internals), 37 // they are left as they are instead. 38 39 function warn(format) { 40 { 41 for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { 42 args[_key - 1] = arguments[_key]; 43 } 44 45 printWarning('warn', format, args); 46 } 47 } 48 function error(format) { 49 { 50 for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) { 51 args[_key2 - 1] = arguments[_key2]; 52 } 53 54 printWarning('error', format, args); 55 } 56 } 57 58 function printWarning(level, format, args) { 59 // When changing this logic, you might want to also 60 // update consoleWithStackDev.www.js as well. 61 { 62 var hasExistingStack = args.length > 0 && typeof args[args.length - 1] === 'string' && args[args.length - 1].indexOf('\n in') === 0; 63 64 if (!hasExistingStack) { 65 var ReactDebugCurrentFrame = ReactSharedInternals.ReactDebugCurrentFrame; 66 var stack = ReactDebugCurrentFrame.getStackAddendum(); 67 68 if (stack !== '') { 69 format += '%s'; 70 args = args.concat([stack]); 71 } 72 } 73 74 var argsWithFormat = args.map(function (item) { 75 return '' + item; 76 }); // Careful: RN currently depends on this prefix 77 78 argsWithFormat.unshift('Warning: ' + format); // We intentionally don't use spread (or .apply) directly because it 79 // breaks IE9: https://github.com/facebook/react/issues/13610 80 // eslint-disable-next-line react-internal/no-production-logging 81 82 Function.prototype.apply.call(console[level], console, argsWithFormat); 83 84 try { 85 // --- Welcome to debugging React --- 86 // This error was thrown as a convenience so that you can use this stack 87 // to find the callsite that caused this warning to fire. 88 var argIndex = 0; 89 var message = 'Warning: ' + format.replace(/%s/g, function () { 90 return args[argIndex++]; 91 }); 92 throw new Error(message); 93 } catch (x) {} 94 } 95 } 96 97 if (!React) { 98 { 99 throw Error( "ReactDOM was loaded before React. Make sure you load the React package before loading ReactDOM." ); 100 } 101 } 102 103 var invokeGuardedCallbackImpl = function (name, func, context, a, b, c, d, e, f) { 104 var funcArgs = Array.prototype.slice.call(arguments, 3); 105 106 try { 107 func.apply(context, funcArgs); 108 } catch (error) { 109 this.onError(error); 110 } 111 }; 112 113 { 114 // In DEV mode, we swap out invokeGuardedCallback for a special version 115 // that plays more nicely with the browser's DevTools. The idea is to preserve 116 // "Pause on exceptions" behavior. Because React wraps all user-provided 117 // functions in invokeGuardedCallback, and the production version of 118 // invokeGuardedCallback uses a try-catch, all user exceptions are treated 119 // like caught exceptions, and the DevTools won't pause unless the developer 120 // takes the extra step of enabling pause on caught exceptions. This is 121 // unintuitive, though, because even though React has caught the error, from 122 // the developer's perspective, the error is uncaught. 123 // 124 // To preserve the expected "Pause on exceptions" behavior, we don't use a 125 // try-catch in DEV. Instead, we synchronously dispatch a fake event to a fake 126 // DOM node, and call the user-provided callback from inside an event handler 127 // for that fake event. If the callback throws, the error is "captured" using 128 // a global event handler. But because the error happens in a different 129 // event loop context, it does not interrupt the normal program flow. 130 // Effectively, this gives us try-catch behavior without actually using 131 // try-catch. Neat! 132 // Check that the browser supports the APIs we need to implement our special 133 // DEV version of invokeGuardedCallback 134 if (typeof window !== 'undefined' && typeof window.dispatchEvent === 'function' && typeof document !== 'undefined' && typeof document.createEvent === 'function') { 135 var fakeNode = document.createElement('react'); 136 137 var invokeGuardedCallbackDev = function (name, func, context, a, b, c, d, e, f) { 138 // If document doesn't exist we know for sure we will crash in this method 139 // when we call document.createEvent(). However this can cause confusing 140 // errors: https://github.com/facebookincubator/create-react-app/issues/3482 141 // So we preemptively throw with a better message instead. 142 if (!(typeof document !== 'undefined')) { 143 { 144 throw Error( "The `document` global was defined when React was initialized, but is not defined anymore. This can happen in a test environment if a component schedules an update from an asynchronous callback, but the test has already finished running. To solve this, you can either unmount the component at the end of your test (and ensure that any asynchronous operations get canceled in `componentWillUnmount`), or you can change the test itself to be asynchronous." ); 145 } 146 } 147 148 var evt = document.createEvent('Event'); // Keeps track of whether the user-provided callback threw an error. We 149 // set this to true at the beginning, then set it to false right after 150 // calling the function. If the function errors, `didError` will never be 151 // set to false. This strategy works even if the browser is flaky and 152 // fails to call our global error handler, because it doesn't rely on 153 // the error event at all. 154 155 var didError = true; // Keeps track of the value of window.event so that we can reset it 156 // during the callback to let user code access window.event in the 157 // browsers that support it. 158 159 var windowEvent = window.event; // Keeps track of the descriptor of window.event to restore it after event 160 // dispatching: https://github.com/facebook/react/issues/13688 161 162 var windowEventDescriptor = Object.getOwnPropertyDescriptor(window, 'event'); // Create an event handler for our fake event. We will synchronously 163 // dispatch our fake event using `dispatchEvent`. Inside the handler, we 164 // call the user-provided callback. 165 166 var funcArgs = Array.prototype.slice.call(arguments, 3); 167 168 function callCallback() { 169 // We immediately remove the callback from event listeners so that 170 // nested `invokeGuardedCallback` calls do not clash. Otherwise, a 171 // nested call would trigger the fake event handlers of any call higher 172 // in the stack. 173 fakeNode.removeEventListener(evtType, callCallback, false); // We check for window.hasOwnProperty('event') to prevent the 174 // window.event assignment in both IE <= 10 as they throw an error 175 // "Member not found" in strict mode, and in Firefox which does not 176 // support window.event. 177 178 if (typeof window.event !== 'undefined' && window.hasOwnProperty('event')) { 179 window.event = windowEvent; 180 } 181 182 func.apply(context, funcArgs); 183 didError = false; 184 } // Create a global error event handler. We use this to capture the value 185 // that was thrown. It's possible that this error handler will fire more 186 // than once; for example, if non-React code also calls `dispatchEvent` 187 // and a handler for that event throws. We should be resilient to most of 188 // those cases. Even if our error event handler fires more than once, the 189 // last error event is always used. If the callback actually does error, 190 // we know that the last error event is the correct one, because it's not 191 // possible for anything else to have happened in between our callback 192 // erroring and the code that follows the `dispatchEvent` call below. If 193 // the callback doesn't error, but the error event was fired, we know to 194 // ignore it because `didError` will be false, as described above. 195 196 197 var error; // Use this to track whether the error event is ever called. 198 199 var didSetError = false; 200 var isCrossOriginError = false; 201 202 function handleWindowError(event) { 203 error = event.error; 204 didSetError = true; 205 206 if (error === null && event.colno === 0 && event.lineno === 0) { 207 isCrossOriginError = true; 208 } 209 210 if (event.defaultPrevented) { 211 // Some other error handler has prevented default. 212 // Browsers silence the error report if this happens. 213 // We'll remember this to later decide whether to log it or not. 214 if (error != null && typeof error === 'object') { 215 try { 216 error._suppressLogging = true; 217 } catch (inner) {// Ignore. 218 } 219 } 220 } 221 } // Create a fake event type. 222 223 224 var evtType = "react-" + (name ? name : 'invokeguardedcallback'); // Attach our event handlers 225 226 window.addEventListener('error', handleWindowError); 227 fakeNode.addEventListener(evtType, callCallback, false); // Synchronously dispatch our fake event. If the user-provided function 228 // errors, it will trigger our global error handler. 229 230 evt.initEvent(evtType, false, false); 231 fakeNode.dispatchEvent(evt); 232 233 if (windowEventDescriptor) { 234 Object.defineProperty(window, 'event', windowEventDescriptor); 235 } 236 237 if (didError) { 238 if (!didSetError) { 239 // The callback errored, but the error event never fired. 240 error = new Error('An error was thrown inside one of your components, but React ' + "doesn't know what it was. This is likely due to browser " + 'flakiness. React does its best to preserve the "Pause on ' + 'exceptions" behavior of the DevTools, which requires some ' + "DEV-mode only tricks. It's possible that these don't work in " + 'your browser. Try triggering the error in production mode, ' + 'or switching to a modern browser. If you suspect that this is ' + 'actually an issue with React, please file an issue.'); 241 } else if (isCrossOriginError) { 242 error = new Error("A cross-origin error was thrown. React doesn't have access to " + 'the actual error object in development. ' + 'See https://fb.me/react-crossorigin-error for more information.'); 243 } 244 245 this.onError(error); 246 } // Remove our event listeners 247 248 249 window.removeEventListener('error', handleWindowError); 250 }; 251 252 invokeGuardedCallbackImpl = invokeGuardedCallbackDev; 253 } 254 } 255 256 var invokeGuardedCallbackImpl$1 = invokeGuardedCallbackImpl; 257 258 var hasError = false; 259 var caughtError = null; // Used by event system to capture/rethrow the first error. 260 261 var hasRethrowError = false; 262 var rethrowError = null; 263 var reporter = { 264 onError: function (error) { 265 hasError = true; 266 caughtError = error; 267 } 268 }; 269 /** 270 * Call a function while guarding against errors that happens within it. 271 * Returns an error if it throws, otherwise null. 272 * 273 * In production, this is implemented using a try-catch. The reason we don't 274 * use a try-catch directly is so that we can swap out a different 275 * implementation in DEV mode. 276 * 277 * @param {String} name of the guard to use for logging or debugging 278 * @param {Function} func The function to invoke 279 * @param {*} context The context to use when calling the function 280 * @param {...*} args Arguments for function 281 */ 282 283 function invokeGuardedCallback(name, func, context, a, b, c, d, e, f) { 284 hasError = false; 285 caughtError = null; 286 invokeGuardedCallbackImpl$1.apply(reporter, arguments); 287 } 288 /** 289 * Same as invokeGuardedCallback, but instead of returning an error, it stores 290 * it in a global so it can be rethrown by `rethrowCaughtError` later. 291 * TODO: See if caughtError and rethrowError can be unified. 292 * 293 * @param {String} name of the guard to use for logging or debugging 294 * @param {Function} func The function to invoke 295 * @param {*} context The context to use when calling the function 296 * @param {...*} args Arguments for function 297 */ 298 299 function invokeGuardedCallbackAndCatchFirstError(name, func, context, a, b, c, d, e, f) { 300 invokeGuardedCallback.apply(this, arguments); 301 302 if (hasError) { 303 var error = clearCaughtError(); 304 305 if (!hasRethrowError) { 306 hasRethrowError = true; 307 rethrowError = error; 308 } 309 } 310 } 311 /** 312 * During execution of guarded functions we will capture the first error which 313 * we will rethrow to be handled by the top level error handler. 314 */ 315 316 function rethrowCaughtError() { 317 if (hasRethrowError) { 318 var error = rethrowError; 319 hasRethrowError = false; 320 rethrowError = null; 321 throw error; 322 } 323 } 324 function hasCaughtError() { 325 return hasError; 326 } 327 function clearCaughtError() { 328 if (hasError) { 329 var error = caughtError; 330 hasError = false; 331 caughtError = null; 332 return error; 333 } else { 334 { 335 { 336 throw Error( "clearCaughtError was called but no error was captured. This error is likely caused by a bug in React. Please file an issue." ); 337 } 338 } 339 } 340 } 341 342 var getFiberCurrentPropsFromNode = null; 343 var getInstanceFromNode = null; 344 var getNodeFromInstance = null; 345 function setComponentTree(getFiberCurrentPropsFromNodeImpl, getInstanceFromNodeImpl, getNodeFromInstanceImpl) { 346 getFiberCurrentPropsFromNode = getFiberCurrentPropsFromNodeImpl; 347 getInstanceFromNode = getInstanceFromNodeImpl; 348 getNodeFromInstance = getNodeFromInstanceImpl; 349 350 { 351 if (!getNodeFromInstance || !getInstanceFromNode) { 352 error('EventPluginUtils.setComponentTree(...): Injected ' + 'module is missing getNodeFromInstance or getInstanceFromNode.'); 353 } 354 } 355 } 356 var validateEventDispatches; 357 358 { 359 validateEventDispatches = function (event) { 360 var dispatchListeners = event._dispatchListeners; 361 var dispatchInstances = event._dispatchInstances; 362 var listenersIsArr = Array.isArray(dispatchListeners); 363 var listenersLen = listenersIsArr ? dispatchListeners.length : dispatchListeners ? 1 : 0; 364 var instancesIsArr = Array.isArray(dispatchInstances); 365 var instancesLen = instancesIsArr ? dispatchInstances.length : dispatchInstances ? 1 : 0; 366 367 if (instancesIsArr !== listenersIsArr || instancesLen !== listenersLen) { 368 error('EventPluginUtils: Invalid `event`.'); 369 } 370 }; 371 } 372 /** 373 * Dispatch the event to the listener. 374 * @param {SyntheticEvent} event SyntheticEvent to handle 375 * @param {function} listener Application-level callback 376 * @param {*} inst Internal component instance 377 */ 378 379 380 function executeDispatch(event, listener, inst) { 381 var type = event.type || 'unknown-event'; 382 event.currentTarget = getNodeFromInstance(inst); 383 invokeGuardedCallbackAndCatchFirstError(type, listener, undefined, event); 384 event.currentTarget = null; 385 } 386 /** 387 * Standard/simple iteration through an event's collected dispatches. 388 */ 389 390 function executeDispatchesInOrder(event) { 391 var dispatchListeners = event._dispatchListeners; 392 var dispatchInstances = event._dispatchInstances; 393 394 { 395 validateEventDispatches(event); 396 } 397 398 if (Array.isArray(dispatchListeners)) { 399 for (var i = 0; i < dispatchListeners.length; i++) { 400 if (event.isPropagationStopped()) { 401 break; 402 } // Listeners and Instances are two parallel arrays that are always in sync. 403 404 405 executeDispatch(event, dispatchListeners[i], dispatchInstances[i]); 406 } 407 } else if (dispatchListeners) { 408 executeDispatch(event, dispatchListeners, dispatchInstances); 409 } 410 411 event._dispatchListeners = null; 412 event._dispatchInstances = null; 413 } 414 415 var FunctionComponent = 0; 416 var ClassComponent = 1; 417 var IndeterminateComponent = 2; // Before we know whether it is function or class 418 419 var HostRoot = 3; // Root of a host tree. Could be nested inside another node. 420 421 var HostPortal = 4; // A subtree. Could be an entry point to a different renderer. 422 423 var HostComponent = 5; 424 var HostText = 6; 425 var Fragment = 7; 426 var Mode = 8; 427 var ContextConsumer = 9; 428 var ContextProvider = 10; 429 var ForwardRef = 11; 430 var Profiler = 12; 431 var SuspenseComponent = 13; 432 var MemoComponent = 14; 433 var SimpleMemoComponent = 15; 434 var LazyComponent = 16; 435 var IncompleteClassComponent = 17; 436 var DehydratedFragment = 18; 437 var SuspenseListComponent = 19; 438 var FundamentalComponent = 20; 439 var ScopeComponent = 21; 440 var Block = 22; 441 442 /** 443 * Injectable ordering of event plugins. 444 */ 445 var eventPluginOrder = null; 446 /** 447 * Injectable mapping from names to event plugin modules. 448 */ 449 450 var namesToPlugins = {}; 451 /** 452 * Recomputes the plugin list using the injected plugins and plugin ordering. 453 * 454 * @private 455 */ 456 457 function recomputePluginOrdering() { 458 if (!eventPluginOrder) { 459 // Wait until an `eventPluginOrder` is injected. 460 return; 461 } 462 463 for (var pluginName in namesToPlugins) { 464 var pluginModule = namesToPlugins[pluginName]; 465 var pluginIndex = eventPluginOrder.indexOf(pluginName); 466 467 if (!(pluginIndex > -1)) { 468 { 469 throw Error( "EventPluginRegistry: Cannot inject event plugins that do not exist in the plugin ordering, `" + pluginName + "`." ); 470 } 471 } 472 473 if (plugins[pluginIndex]) { 474 continue; 475 } 476 477 if (!pluginModule.extractEvents) { 478 { 479 throw Error( "EventPluginRegistry: Event plugins must implement an `extractEvents` method, but `" + pluginName + "` does not." ); 480 } 481 } 482 483 plugins[pluginIndex] = pluginModule; 484 var publishedEvents = pluginModule.eventTypes; 485 486 for (var eventName in publishedEvents) { 487 if (!publishEventForPlugin(publishedEvents[eventName], pluginModule, eventName)) { 488 { 489 throw Error( "EventPluginRegistry: Failed to publish event `" + eventName + "` for plugin `" + pluginName + "`." ); 490 } 491 } 492 } 493 } 494 } 495 /** 496 * Publishes an event so that it can be dispatched by the supplied plugin. 497 * 498 * @param {object} dispatchConfig Dispatch configuration for the event. 499 * @param {object} PluginModule Plugin publishing the event. 500 * @return {boolean} True if the event was successfully published. 501 * @private 502 */ 503 504 505 function publishEventForPlugin(dispatchConfig, pluginModule, eventName) { 506 if (!!eventNameDispatchConfigs.hasOwnProperty(eventName)) { 507 { 508 throw Error( "EventPluginRegistry: More than one plugin attempted to publish the same event name, `" + eventName + "`." ); 509 } 510 } 511 512 eventNameDispatchConfigs[eventName] = dispatchConfig; 513 var phasedRegistrationNames = dispatchConfig.phasedRegistrationNames; 514 515 if (phasedRegistrationNames) { 516 for (var phaseName in phasedRegistrationNames) { 517 if (phasedRegistrationNames.hasOwnProperty(phaseName)) { 518 var phasedRegistrationName = phasedRegistrationNames[phaseName]; 519 publishRegistrationName(phasedRegistrationName, pluginModule, eventName); 520 } 521 } 522 523 return true; 524 } else if (dispatchConfig.registrationName) { 525 publishRegistrationName(dispatchConfig.registrationName, pluginModule, eventName); 526 return true; 527 } 528 529 return false; 530 } 531 /** 532 * Publishes a registration name that is used to identify dispatched events. 533 * 534 * @param {string} registrationName Registration name to add. 535 * @param {object} PluginModule Plugin publishing the event. 536 * @private 537 */ 538 539 540 function publishRegistrationName(registrationName, pluginModule, eventName) { 541 if (!!registrationNameModules[registrationName]) { 542 { 543 throw Error( "EventPluginRegistry: More than one plugin attempted to publish the same registration name, `" + registrationName + "`." ); 544 } 545 } 546 547 registrationNameModules[registrationName] = pluginModule; 548 registrationNameDependencies[registrationName] = pluginModule.eventTypes[eventName].dependencies; 549 550 { 551 var lowerCasedName = registrationName.toLowerCase(); 552 possibleRegistrationNames[lowerCasedName] = registrationName; 553 554 if (registrationName === 'onDoubleClick') { 555 possibleRegistrationNames.ondblclick = registrationName; 556 } 557 } 558 } 559 /** 560 * Registers plugins so that they can extract and dispatch events. 561 */ 562 563 /** 564 * Ordered list of injected plugins. 565 */ 566 567 568 var plugins = []; 569 /** 570 * Mapping from event name to dispatch config 571 */ 572 573 var eventNameDispatchConfigs = {}; 574 /** 575 * Mapping from registration name to plugin module 576 */ 577 578 var registrationNameModules = {}; 579 /** 580 * Mapping from registration name to event name 581 */ 582 583 var registrationNameDependencies = {}; 584 /** 585 * Mapping from lowercase registration names to the properly cased version, 586 * used to warn in the case of missing event handlers. Available 587 * only in true. 588 * @type {Object} 589 */ 590 591 var possibleRegistrationNames = {} ; // Trust the developer to only use possibleRegistrationNames in true 592 593 /** 594 * Injects an ordering of plugins (by plugin name). This allows the ordering 595 * to be decoupled from injection of the actual plugins so that ordering is 596 * always deterministic regardless of packaging, on-the-fly injection, etc. 597 * 598 * @param {array} InjectedEventPluginOrder 599 * @internal 600 */ 601 602 function injectEventPluginOrder(injectedEventPluginOrder) { 603 if (!!eventPluginOrder) { 604 { 605 throw Error( "EventPluginRegistry: Cannot inject event plugin ordering more than once. You are likely trying to load more than one copy of React." ); 606 } 607 } // Clone the ordering so it cannot be dynamically mutated. 608 609 610 eventPluginOrder = Array.prototype.slice.call(injectedEventPluginOrder); 611 recomputePluginOrdering(); 612 } 613 /** 614 * Injects plugins to be used by plugin event system. The plugin names must be 615 * in the ordering injected by `injectEventPluginOrder`. 616 * 617 * Plugins can be injected as part of page initialization or on-the-fly. 618 * 619 * @param {object} injectedNamesToPlugins Map from names to plugin modules. 620 * @internal 621 */ 622 623 function injectEventPluginsByName(injectedNamesToPlugins) { 624 var isOrderingDirty = false; 625 626 for (var pluginName in injectedNamesToPlugins) { 627 if (!injectedNamesToPlugins.hasOwnProperty(pluginName)) { 628 continue; 629 } 630 631 var pluginModule = injectedNamesToPlugins[pluginName]; 632 633 if (!namesToPlugins.hasOwnProperty(pluginName) || namesToPlugins[pluginName] !== pluginModule) { 634 if (!!namesToPlugins[pluginName]) { 635 { 636 throw Error( "EventPluginRegistry: Cannot inject two different event plugins using the same name, `" + pluginName + "`." ); 637 } 638 } 639 640 namesToPlugins[pluginName] = pluginModule; 641 isOrderingDirty = true; 642 } 643 } 644 645 if (isOrderingDirty) { 646 recomputePluginOrdering(); 647 } 648 } 649 650 var canUseDOM = !!(typeof window !== 'undefined' && typeof window.document !== 'undefined' && typeof window.document.createElement !== 'undefined'); 651 652 var ReactInternals = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; 653 var _assign = ReactInternals.assign; 654 655 var PLUGIN_EVENT_SYSTEM = 1; 656 var IS_REPLAYED = 1 << 5; 657 var IS_FIRST_ANCESTOR = 1 << 6; 658 659 var restoreImpl = null; 660 var restoreTarget = null; 661 var restoreQueue = null; 662 663 function restoreStateOfTarget(target) { 664 // We perform this translation at the end of the event loop so that we 665 // always receive the correct fiber here 666 var internalInstance = getInstanceFromNode(target); 667 668 if (!internalInstance) { 669 // Unmounted 670 return; 671 } 672 673 if (!(typeof restoreImpl === 'function')) { 674 { 675 throw Error( "setRestoreImplementation() needs to be called to handle a target for controlled events. This error is likely caused by a bug in React. Please file an issue." ); 676 } 677 } 678 679 var stateNode = internalInstance.stateNode; // Guard against Fiber being unmounted. 680 681 if (stateNode) { 682 var _props = getFiberCurrentPropsFromNode(stateNode); 683 684 restoreImpl(internalInstance.stateNode, internalInstance.type, _props); 685 } 686 } 687 688 function setRestoreImplementation(impl) { 689 restoreImpl = impl; 690 } 691 function enqueueStateRestore(target) { 692 if (restoreTarget) { 693 if (restoreQueue) { 694 restoreQueue.push(target); 695 } else { 696 restoreQueue = [target]; 697 } 698 } else { 699 restoreTarget = target; 700 } 701 } 702 function needsStateRestore() { 703 return restoreTarget !== null || restoreQueue !== null; 704 } 705 function restoreStateIfNeeded() { 706 if (!restoreTarget) { 707 return; 708 } 709 710 var target = restoreTarget; 711 var queuedTargets = restoreQueue; 712 restoreTarget = null; 713 restoreQueue = null; 714 restoreStateOfTarget(target); 715 716 if (queuedTargets) { 717 for (var i = 0; i < queuedTargets.length; i++) { 718 restoreStateOfTarget(queuedTargets[i]); 719 } 720 } 721 } 722 723 var enableProfilerTimer = true; // Trace which interactions trigger each commit. 724 725 var enableDeprecatedFlareAPI = false; // Experimental Host Component support. 726 727 var enableFundamentalAPI = false; // Experimental Scope support. 728 var warnAboutStringRefs = false; 729 730 // the renderer. Such as when we're dispatching events or if third party 731 // libraries need to call batchedUpdates. Eventually, this API will go away when 732 // everything is batched by default. We'll then have a similar API to opt-out of 733 // scheduled work and instead do synchronous work. 734 // Defaults 735 736 var batchedUpdatesImpl = function (fn, bookkeeping) { 737 return fn(bookkeeping); 738 }; 739 740 var discreteUpdatesImpl = function (fn, a, b, c, d) { 741 return fn(a, b, c, d); 742 }; 743 744 var flushDiscreteUpdatesImpl = function () {}; 745 746 var batchedEventUpdatesImpl = batchedUpdatesImpl; 747 var isInsideEventHandler = false; 748 var isBatchingEventUpdates = false; 749 750 function finishEventHandler() { 751 // Here we wait until all updates have propagated, which is important 752 // when using controlled components within layers: 753 // https://github.com/facebook/react/issues/1698 754 // Then we restore state of any controlled component. 755 var controlledComponentsHavePendingUpdates = needsStateRestore(); 756 757 if (controlledComponentsHavePendingUpdates) { 758 // If a controlled event was fired, we may need to restore the state of 759 // the DOM node back to the controlled value. This is necessary when React 760 // bails out of the update without touching the DOM. 761 flushDiscreteUpdatesImpl(); 762 restoreStateIfNeeded(); 763 } 764 } 765 766 function batchedUpdates(fn, bookkeeping) { 767 if (isInsideEventHandler) { 768 // If we are currently inside another batch, we need to wait until it 769 // fully completes before restoring state. 770 return fn(bookkeeping); 771 } 772 773 isInsideEventHandler = true; 774 775 try { 776 return batchedUpdatesImpl(fn, bookkeeping); 777 } finally { 778 isInsideEventHandler = false; 779 finishEventHandler(); 780 } 781 } 782 function batchedEventUpdates(fn, a, b) { 783 if (isBatchingEventUpdates) { 784 // If we are currently inside another batch, we need to wait until it 785 // fully completes before restoring state. 786 return fn(a, b); 787 } 788 789 isBatchingEventUpdates = true; 790 791 try { 792 return batchedEventUpdatesImpl(fn, a, b); 793 } finally { 794 isBatchingEventUpdates = false; 795 finishEventHandler(); 796 } 797 } // This is for the React Flare event system 798 function discreteUpdates(fn, a, b, c, d) { 799 var prevIsInsideEventHandler = isInsideEventHandler; 800 isInsideEventHandler = true; 801 802 try { 803 return discreteUpdatesImpl(fn, a, b, c, d); 804 } finally { 805 isInsideEventHandler = prevIsInsideEventHandler; 806 807 if (!isInsideEventHandler) { 808 finishEventHandler(); 809 } 810 } 811 } 812 function flushDiscreteUpdatesIfNeeded(timeStamp) { 813 // event.timeStamp isn't overly reliable due to inconsistencies in 814 // how different browsers have historically provided the time stamp. 815 // Some browsers provide high-resolution time stamps for all events, 816 // some provide low-resolution time stamps for all events. FF < 52 817 // even mixes both time stamps together. Some browsers even report 818 // negative time stamps or time stamps that are 0 (iOS9) in some cases. 819 // Given we are only comparing two time stamps with equality (!==), 820 // we are safe from the resolution differences. If the time stamp is 0 821 // we bail-out of preventing the flush, which can affect semantics, 822 // such as if an earlier flush removes or adds event listeners that 823 // are fired in the subsequent flush. However, this is the same 824 // behaviour as we had before this change, so the risks are low. 825 if (!isInsideEventHandler && (!enableDeprecatedFlareAPI )) { 826 flushDiscreteUpdatesImpl(); 827 } 828 } 829 function setBatchingImplementation(_batchedUpdatesImpl, _discreteUpdatesImpl, _flushDiscreteUpdatesImpl, _batchedEventUpdatesImpl) { 830 batchedUpdatesImpl = _batchedUpdatesImpl; 831 discreteUpdatesImpl = _discreteUpdatesImpl; 832 flushDiscreteUpdatesImpl = _flushDiscreteUpdatesImpl; 833 batchedEventUpdatesImpl = _batchedEventUpdatesImpl; 834 } 835 836 var DiscreteEvent = 0; 837 var UserBlockingEvent = 1; 838 var ContinuousEvent = 2; 839 840 var ReactInternals$1 = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; 841 var _ReactInternals$Sched = ReactInternals$1.Scheduler, 842 unstable_cancelCallback = _ReactInternals$Sched.unstable_cancelCallback, 843 unstable_now = _ReactInternals$Sched.unstable_now, 844 unstable_scheduleCallback = _ReactInternals$Sched.unstable_scheduleCallback, 845 unstable_shouldYield = _ReactInternals$Sched.unstable_shouldYield, 846 unstable_requestPaint = _ReactInternals$Sched.unstable_requestPaint, 847 unstable_getFirstCallbackNode = _ReactInternals$Sched.unstable_getFirstCallbackNode, 848 unstable_runWithPriority = _ReactInternals$Sched.unstable_runWithPriority, 849 unstable_next = _ReactInternals$Sched.unstable_next, 850 unstable_continueExecution = _ReactInternals$Sched.unstable_continueExecution, 851 unstable_pauseExecution = _ReactInternals$Sched.unstable_pauseExecution, 852 unstable_getCurrentPriorityLevel = _ReactInternals$Sched.unstable_getCurrentPriorityLevel, 853 unstable_ImmediatePriority = _ReactInternals$Sched.unstable_ImmediatePriority, 854 unstable_UserBlockingPriority = _ReactInternals$Sched.unstable_UserBlockingPriority, 855 unstable_NormalPriority = _ReactInternals$Sched.unstable_NormalPriority, 856 unstable_LowPriority = _ReactInternals$Sched.unstable_LowPriority, 857 unstable_IdlePriority = _ReactInternals$Sched.unstable_IdlePriority, 858 unstable_forceFrameRate = _ReactInternals$Sched.unstable_forceFrameRate, 859 unstable_flushAllWithoutAsserting = _ReactInternals$Sched.unstable_flushAllWithoutAsserting; 860 861 // A reserved attribute. 862 // It is handled by React separately and shouldn't be written to the DOM. 863 var RESERVED = 0; // A simple string attribute. 864 // Attributes that aren't in the whitelist are presumed to have this type. 865 866 var STRING = 1; // A string attribute that accepts booleans in React. In HTML, these are called 867 // "enumerated" attributes with "true" and "false" as possible values. 868 // When true, it should be set to a "true" string. 869 // When false, it should be set to a "false" string. 870 871 var BOOLEANISH_STRING = 2; // A real boolean attribute. 872 // When true, it should be present (set either to an empty string or its name). 873 // When false, it should be omitted. 874 875 var BOOLEAN = 3; // An attribute that can be used as a flag as well as with a value. 876 // When true, it should be present (set either to an empty string or its name). 877 // When false, it should be omitted. 878 // For any other value, should be present with that value. 879 880 var OVERLOADED_BOOLEAN = 4; // An attribute that must be numeric or parse as a numeric. 881 // When falsy, it should be removed. 882 883 var NUMERIC = 5; // An attribute that must be positive numeric or parse as a positive numeric. 884 // When falsy, it should be removed. 885 886 var POSITIVE_NUMERIC = 6; 887 888 /* eslint-disable max-len */ 889 var ATTRIBUTE_NAME_START_CHAR = ":A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD"; 890 /* eslint-enable max-len */ 891 892 var ATTRIBUTE_NAME_CHAR = ATTRIBUTE_NAME_START_CHAR + "\\-.0-9\\u00B7\\u0300-\\u036F\\u203F-\\u2040"; 893 var ROOT_ATTRIBUTE_NAME = 'data-reactroot'; 894 var VALID_ATTRIBUTE_NAME_REGEX = new RegExp('^[' + ATTRIBUTE_NAME_START_CHAR + '][' + ATTRIBUTE_NAME_CHAR + ']*$'); 895 var hasOwnProperty = Object.prototype.hasOwnProperty; 896 var illegalAttributeNameCache = {}; 897 var validatedAttributeNameCache = {}; 898 function isAttributeNameSafe(attributeName) { 899 if (hasOwnProperty.call(validatedAttributeNameCache, attributeName)) { 900 return true; 901 } 902 903 if (hasOwnProperty.call(illegalAttributeNameCache, attributeName)) { 904 return false; 905 } 906 907 if (VALID_ATTRIBUTE_NAME_REGEX.test(attributeName)) { 908 validatedAttributeNameCache[attributeName] = true; 909 return true; 910 } 911 912 illegalAttributeNameCache[attributeName] = true; 913 914 { 915 error('Invalid attribute name: `%s`', attributeName); 916 } 917 918 return false; 919 } 920 function shouldIgnoreAttribute(name, propertyInfo, isCustomComponentTag) { 921 if (propertyInfo !== null) { 922 return propertyInfo.type === RESERVED; 923 } 924 925 if (isCustomComponentTag) { 926 return false; 927 } 928 929 if (name.length > 2 && (name[0] === 'o' || name[0] === 'O') && (name[1] === 'n' || name[1] === 'N')) { 930 return true; 931 } 932 933 return false; 934 } 935 function shouldRemoveAttributeWithWarning(name, value, propertyInfo, isCustomComponentTag) { 936 if (propertyInfo !== null && propertyInfo.type === RESERVED) { 937 return false; 938 } 939 940 switch (typeof value) { 941 case 'function': // $FlowIssue symbol is perfectly valid here 942 943 case 'symbol': 944 // eslint-disable-line 945 return true; 946 947 case 'boolean': 948 { 949 if (isCustomComponentTag) { 950 return false; 951 } 952 953 if (propertyInfo !== null) { 954 return !propertyInfo.acceptsBooleans; 955 } else { 956 var prefix = name.toLowerCase().slice(0, 5); 957 return prefix !== 'data-' && prefix !== 'aria-'; 958 } 959 } 960 961 default: 962 return false; 963 } 964 } 965 function shouldRemoveAttribute(name, value, propertyInfo, isCustomComponentTag) { 966 if (value === null || typeof value === 'undefined') { 967 return true; 968 } 969 970 if (shouldRemoveAttributeWithWarning(name, value, propertyInfo, isCustomComponentTag)) { 971 return true; 972 } 973 974 if (isCustomComponentTag) { 975 return false; 976 } 977 978 if (propertyInfo !== null) { 979 switch (propertyInfo.type) { 980 case BOOLEAN: 981 return !value; 982 983 case OVERLOADED_BOOLEAN: 984 return value === false; 985 986 case NUMERIC: 987 return isNaN(value); 988 989 case POSITIVE_NUMERIC: 990 return isNaN(value) || value < 1; 991 } 992 } 993 994 return false; 995 } 996 function getPropertyInfo(name) { 997 return properties.hasOwnProperty(name) ? properties[name] : null; 998 } 999 1000 function PropertyInfoRecord(name, type, mustUseProperty, attributeName, attributeNamespace, sanitizeURL) { 1001 this.acceptsBooleans = type === BOOLEANISH_STRING || type === BOOLEAN || type === OVERLOADED_BOOLEAN; 1002 this.attributeName = attributeName; 1003 this.attributeNamespace = attributeNamespace; 1004 this.mustUseProperty = mustUseProperty; 1005 this.propertyName = name; 1006 this.type = type; 1007 this.sanitizeURL = sanitizeURL; 1008 } // When adding attributes to this list, be sure to also add them to 1009 // the `possibleStandardNames` module to ensure casing and incorrect 1010 // name warnings. 1011 1012 1013 var properties = {}; // These props are reserved by React. They shouldn't be written to the DOM. 1014 1015 var reservedProps = ['children', 'dangerouslySetInnerHTML', // TODO: This prevents the assignment of defaultValue to regular 1016 // elements (not just inputs). Now that ReactDOMInput assigns to the 1017 // defaultValue property -- do we need this? 1018 'defaultValue', 'defaultChecked', 'innerHTML', 'suppressContentEditableWarning', 'suppressHydrationWarning', 'style']; 1019 1020 reservedProps.forEach(function (name) { 1021 properties[name] = new PropertyInfoRecord(name, RESERVED, false, // mustUseProperty 1022 name, // attributeName 1023 null, // attributeNamespace 1024 false); 1025 }); // A few React string attributes have a different name. 1026 // This is a mapping from React prop names to the attribute names. 1027 1028 [['acceptCharset', 'accept-charset'], ['className', 'class'], ['htmlFor', 'for'], ['httpEquiv', 'http-equiv']].forEach(function (_ref) { 1029 var name = _ref[0], 1030 attributeName = _ref[1]; 1031 properties[name] = new PropertyInfoRecord(name, STRING, false, // mustUseProperty 1032 attributeName, // attributeName 1033 null, // attributeNamespace 1034 false); 1035 }); // These are "enumerated" HTML attributes that accept "true" and "false". 1036 // In React, we let users pass `true` and `false` even though technically 1037 // these aren't boolean attributes (they are coerced to strings). 1038 1039 ['contentEditable', 'draggable', 'spellCheck', 'value'].forEach(function (name) { 1040 properties[name] = new PropertyInfoRecord(name, BOOLEANISH_STRING, false, // mustUseProperty 1041 name.toLowerCase(), // attributeName 1042 null, // attributeNamespace 1043 false); 1044 }); // These are "enumerated" SVG attributes that accept "true" and "false". 1045 // In React, we let users pass `true` and `false` even though technically 1046 // these aren't boolean attributes (they are coerced to strings). 1047 // Since these are SVG attributes, their attribute names are case-sensitive. 1048 1049 ['autoReverse', 'externalResourcesRequired', 'focusable', 'preserveAlpha'].forEach(function (name) { 1050 properties[name] = new PropertyInfoRecord(name, BOOLEANISH_STRING, false, // mustUseProperty 1051 name, // attributeName 1052 null, // attributeNamespace 1053 false); 1054 }); // These are HTML boolean attributes. 1055 1056 ['allowFullScreen', 'async', // Note: there is a special case that prevents it from being written to the DOM 1057 // on the client side because the browsers are inconsistent. Instead we call focus(). 1058 'autoFocus', 'autoPlay', 'controls', 'default', 'defer', 'disabled', 'disablePictureInPicture', 'formNoValidate', 'hidden', 'loop', 'noModule', 'noValidate', 'open', 'playsInline', 'readOnly', 'required', 'reversed', 'scoped', 'seamless', // Microdata 1059 'itemScope'].forEach(function (name) { 1060 properties[name] = new PropertyInfoRecord(name, BOOLEAN, false, // mustUseProperty 1061 name.toLowerCase(), // attributeName 1062 null, // attributeNamespace 1063 false); 1064 }); // These are the few React props that we set as DOM properties 1065 // rather than attributes. These are all booleans. 1066 1067 ['checked', // Note: `option.selected` is not updated if `select.multiple` is 1068 // disabled with `removeAttribute`. We have special logic for handling this. 1069 'multiple', 'muted', 'selected' // NOTE: if you add a camelCased prop to this list, 1070 // you'll need to set attributeName to name.toLowerCase() 1071 // instead in the assignment below. 1072 ].forEach(function (name) { 1073 properties[name] = new PropertyInfoRecord(name, BOOLEAN, true, // mustUseProperty 1074 name, // attributeName 1075 null, // attributeNamespace 1076 false); 1077 }); // These are HTML attributes that are "overloaded booleans": they behave like 1078 // booleans, but can also accept a string value. 1079 1080 ['capture', 'download' // NOTE: if you add a camelCased prop to this list, 1081 // you'll need to set attributeName to name.toLowerCase() 1082 // instead in the assignment below. 1083 ].forEach(function (name) { 1084 properties[name] = new PropertyInfoRecord(name, OVERLOADED_BOOLEAN, false, // mustUseProperty 1085 name, // attributeName 1086 null, // attributeNamespace 1087 false); 1088 }); // These are HTML attributes that must be positive numbers. 1089 1090 ['cols', 'rows', 'size', 'span' // NOTE: if you add a camelCased prop to this list, 1091 // you'll need to set attributeName to name.toLowerCase() 1092 // instead in the assignment below. 1093 ].forEach(function (name) { 1094 properties[name] = new PropertyInfoRecord(name, POSITIVE_NUMERIC, false, // mustUseProperty 1095 name, // attributeName 1096 null, // attributeNamespace 1097 false); 1098 }); // These are HTML attributes that must be numbers. 1099 1100 ['rowSpan', 'start'].forEach(function (name) { 1101 properties[name] = new PropertyInfoRecord(name, NUMERIC, false, // mustUseProperty 1102 name.toLowerCase(), // attributeName 1103 null, // attributeNamespace 1104 false); 1105 }); 1106 var CAMELIZE = /[\-\:]([a-z])/g; 1107 1108 var capitalize = function (token) { 1109 return token[1].toUpperCase(); 1110 }; // This is a list of all SVG attributes that need special casing, namespacing, 1111 // or boolean value assignment. Regular attributes that just accept strings 1112 // and have the same names are omitted, just like in the HTML whitelist. 1113 // Some of these attributes can be hard to find. This list was created by 1114 // scraping the MDN documentation. 1115 1116 1117 ['accent-height', 'alignment-baseline', 'arabic-form', 'baseline-shift', 'cap-height', 'clip-path', 'clip-rule', 'color-interpolation', 'color-interpolation-filters', 'color-profile', 'color-rendering', 'dominant-baseline', 'enable-background', 'fill-opacity', 'fill-rule', 'flood-color', 'flood-opacity', 'font-family', 'font-size', 'font-size-adjust', 'font-stretch', 'font-style', 'font-variant', 'font-weight', 'glyph-name', 'glyph-orientation-horizontal', 'glyph-orientation-vertical', 'horiz-adv-x', 'horiz-origin-x', 'image-rendering', 'letter-spacing', 'lighting-color', 'marker-end', 'marker-mid', 'marker-start', 'overline-position', 'overline-thickness', 'paint-order', 'panose-1', 'pointer-events', 'rendering-intent', 'shape-rendering', 'stop-color', 'stop-opacity', 'strikethrough-position', 'strikethrough-thickness', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'text-anchor', 'text-decoration', 'text-rendering', 'underline-position', 'underline-thickness', 'unicode-bidi', 'unicode-range', 'units-per-em', 'v-alphabetic', 'v-hanging', 'v-ideographic', 'v-mathematical', 'vector-effect', 'vert-adv-y', 'vert-origin-x', 'vert-origin-y', 'word-spacing', 'writing-mode', 'xmlns:xlink', 'x-height' // NOTE: if you add a camelCased prop to this list, 1118 // you'll need to set attributeName to name.toLowerCase() 1119 // instead in the assignment below. 1120 ].forEach(function (attributeName) { 1121 var name = attributeName.replace(CAMELIZE, capitalize); 1122 properties[name] = new PropertyInfoRecord(name, STRING, false, // mustUseProperty 1123 attributeName, null, // attributeNamespace 1124 false); 1125 }); // String SVG attributes with the xlink namespace. 1126 1127 ['xlink:actuate', 'xlink:arcrole', 'xlink:role', 'xlink:show', 'xlink:title', 'xlink:type' // NOTE: if you add a camelCased prop to this list, 1128 // you'll need to set attributeName to name.toLowerCase() 1129 // instead in the assignment below. 1130 ].forEach(function (attributeName) { 1131 var name = attributeName.replace(CAMELIZE, capitalize); 1132 properties[name] = new PropertyInfoRecord(name, STRING, false, // mustUseProperty 1133 attributeName, 'http://www.w3.org/1999/xlink', false); 1134 }); // String SVG attributes with the xml namespace. 1135 1136 ['xml:base', 'xml:lang', 'xml:space' // NOTE: if you add a camelCased prop to this list, 1137 // you'll need to set attributeName to name.toLowerCase() 1138 // instead in the assignment below. 1139 ].forEach(function (attributeName) { 1140 var name = attributeName.replace(CAMELIZE, capitalize); 1141 properties[name] = new PropertyInfoRecord(name, STRING, false, // mustUseProperty 1142 attributeName, 'http://www.w3.org/XML/1998/namespace', false); 1143 }); // These attribute exists both in HTML and SVG. 1144 // The attribute name is case-sensitive in SVG so we can't just use 1145 // the React name like we do for attributes that exist only in HTML. 1146 1147 ['tabIndex', 'crossOrigin'].forEach(function (attributeName) { 1148 properties[attributeName] = new PropertyInfoRecord(attributeName, STRING, false, // mustUseProperty 1149 attributeName.toLowerCase(), // attributeName 1150 null, // attributeNamespace 1151 false); 1152 }); // These attributes accept URLs. These must not allow javascript: URLS. 1153 // These will also need to accept Trusted Types object in the future. 1154 1155 var xlinkHref = 'xlinkHref'; 1156 properties[xlinkHref] = new PropertyInfoRecord('xlinkHref', STRING, false, // mustUseProperty 1157 'xlink:href', 'http://www.w3.org/1999/xlink', true); 1158 ['src', 'href', 'action', 'formAction'].forEach(function (attributeName) { 1159 properties[attributeName] = new PropertyInfoRecord(attributeName, STRING, false, // mustUseProperty 1160 attributeName.toLowerCase(), // attributeName 1161 null, // attributeNamespace 1162 true); 1163 }); 1164 1165 var ReactDebugCurrentFrame = null; 1166 1167 { 1168 ReactDebugCurrentFrame = ReactSharedInternals.ReactDebugCurrentFrame; 1169 } // A javascript: URL can contain leading C0 control or \u0020 SPACE, 1170 // and any newline or tab are filtered out as if they're not part of the URL. 1171 // https://url.spec.whatwg.org/#url-parsing 1172 // Tab or newline are defined as \r\n\t: 1173 // https://infra.spec.whatwg.org/#ascii-tab-or-newline 1174 // A C0 control is a code point in the range \u0000 NULL to \u001F 1175 // INFORMATION SEPARATOR ONE, inclusive: 1176 // https://infra.spec.whatwg.org/#c0-control-or-space 1177 1178 /* eslint-disable max-len */ 1179 1180 1181 var isJavaScriptProtocol = /^[\u0000-\u001F ]*j[\r\n\t]*a[\r\n\t]*v[\r\n\t]*a[\r\n\t]*s[\r\n\t]*c[\r\n\t]*r[\r\n\t]*i[\r\n\t]*p[\r\n\t]*t[\r\n\t]*\:/i; 1182 var didWarn = false; 1183 1184 function sanitizeURL(url) { 1185 { 1186 if (!didWarn && isJavaScriptProtocol.test(url)) { 1187 didWarn = true; 1188 1189 error('A future version of React will block javascript: URLs as a security precaution. ' + 'Use event handlers instead if you can. If you need to generate unsafe HTML try ' + 'using dangerouslySetInnerHTML instead. React was passed %s.', JSON.stringify(url)); 1190 } 1191 } 1192 } 1193 1194 /** 1195 * Get the value for a property on a node. Only used in DEV for SSR validation. 1196 * The "expected" argument is used as a hint of what the expected value is. 1197 * Some properties have multiple equivalent values. 1198 */ 1199 function getValueForProperty(node, name, expected, propertyInfo) { 1200 { 1201 if (propertyInfo.mustUseProperty) { 1202 var propertyName = propertyInfo.propertyName; 1203 return node[propertyName]; 1204 } else { 1205 if ( propertyInfo.sanitizeURL) { 1206 // If we haven't fully disabled javascript: URLs, and if 1207 // the hydration is successful of a javascript: URL, we 1208 // still want to warn on the client. 1209 sanitizeURL('' + expected); 1210 } 1211 1212 var attributeName = propertyInfo.attributeName; 1213 var stringValue = null; 1214 1215 if (propertyInfo.type === OVERLOADED_BOOLEAN) { 1216 if (node.hasAttribute(attributeName)) { 1217 var value = node.getAttribute(attributeName); 1218 1219 if (value === '') { 1220 return true; 1221 } 1222 1223 if (shouldRemoveAttribute(name, expected, propertyInfo, false)) { 1224 return value; 1225 } 1226 1227 if (value === '' + expected) { 1228 return expected; 1229 } 1230 1231 return value; 1232 } 1233 } else if (node.hasAttribute(attributeName)) { 1234 if (shouldRemoveAttribute(name, expected, propertyInfo, false)) { 1235 // We had an attribute but shouldn't have had one, so read it 1236 // for the error message. 1237 return node.getAttribute(attributeName); 1238 } 1239 1240 if (propertyInfo.type === BOOLEAN) { 1241 // If this was a boolean, it doesn't matter what the value is 1242 // the fact that we have it is the same as the expected. 1243 return expected; 1244 } // Even if this property uses a namespace we use getAttribute 1245 // because we assume its namespaced name is the same as our config. 1246 // To use getAttributeNS we need the local name which we don't have 1247 // in our config atm. 1248 1249 1250 stringValue = node.getAttribute(attributeName); 1251 } 1252 1253 if (shouldRemoveAttribute(name, expected, propertyInfo, false)) { 1254 return stringValue === null ? expected : stringValue; 1255 } else if (stringValue === '' + expected) { 1256 return expected; 1257 } else { 1258 return stringValue; 1259 } 1260 } 1261 } 1262 } 1263 /** 1264 * Get the value for a attribute on a node. Only used in DEV for SSR validation. 1265 * The third argument is used as a hint of what the expected value is. Some 1266 * attributes have multiple equivalent values. 1267 */ 1268 1269 function getValueForAttribute(node, name, expected) { 1270 { 1271 if (!isAttributeNameSafe(name)) { 1272 return; 1273 } 1274 1275 if (!node.hasAttribute(name)) { 1276 return expected === undefined ? undefined : null; 1277 } 1278 1279 var value = node.getAttribute(name); 1280 1281 if (value === '' + expected) { 1282 return expected; 1283 } 1284 1285 return value; 1286 } 1287 } 1288 /** 1289 * Sets the value for a property on a node. 1290 * 1291 * @param {DOMElement} node 1292 * @param {string} name 1293 * @param {*} value 1294 */ 1295 1296 function setValueForProperty(node, name, value, isCustomComponentTag) { 1297 var propertyInfo = getPropertyInfo(name); 1298 1299 if (shouldIgnoreAttribute(name, propertyInfo, isCustomComponentTag)) { 1300 return; 1301 } 1302 1303 if (shouldRemoveAttribute(name, value, propertyInfo, isCustomComponentTag)) { 1304 value = null; 1305 } // If the prop isn't in the special list, treat it as a simple attribute. 1306 1307 1308 if (isCustomComponentTag || propertyInfo === null) { 1309 if (isAttributeNameSafe(name)) { 1310 var _attributeName = name; 1311 1312 if (value === null) { 1313 node.removeAttribute(_attributeName); 1314 } else { 1315 node.setAttribute(_attributeName, '' + value); 1316 } 1317 } 1318 1319 return; 1320 } 1321 1322 var mustUseProperty = propertyInfo.mustUseProperty; 1323 1324 if (mustUseProperty) { 1325 var propertyName = propertyInfo.propertyName; 1326 1327 if (value === null) { 1328 var type = propertyInfo.type; 1329 node[propertyName] = type === BOOLEAN ? false : ''; 1330 } else { 1331 // Contrary to `setAttribute`, object properties are properly 1332 // `toString`ed by IE8/9. 1333 node[propertyName] = value; 1334 } 1335 1336 return; 1337 } // The rest are treated as attributes with special cases. 1338 1339 1340 var attributeName = propertyInfo.attributeName, 1341 attributeNamespace = propertyInfo.attributeNamespace; 1342 1343 if (value === null) { 1344 node.removeAttribute(attributeName); 1345 } else { 1346 var _type = propertyInfo.type; 1347 var attributeValue; 1348 1349 if (_type === BOOLEAN || _type === OVERLOADED_BOOLEAN && value === true) { 1350 // If attribute type is boolean, we know for sure it won't be an execution sink 1351 // and we won't require Trusted Type here. 1352 attributeValue = ''; 1353 } else { 1354 // `setAttribute` with objects becomes only `[object]` in IE8/9, 1355 // ('' + value) makes it output the correct toString()-value. 1356 { 1357 attributeValue = '' + value; 1358 } 1359 1360 if (propertyInfo.sanitizeURL) { 1361 sanitizeURL(attributeValue.toString()); 1362 } 1363 } 1364 1365 if (attributeNamespace) { 1366 node.setAttributeNS(attributeNamespace, attributeName, attributeValue); 1367 } else { 1368 node.setAttribute(attributeName, attributeValue); 1369 } 1370 } 1371 } 1372 1373 var BEFORE_SLASH_RE = /^(.*)[\\\/]/; 1374 function describeComponentFrame (name, source, ownerName) { 1375 var sourceInfo = ''; 1376 1377 if (source) { 1378 var path = source.fileName; 1379 var fileName = path.replace(BEFORE_SLASH_RE, ''); 1380 1381 { 1382 // In DEV, include code for a common special case: 1383 // prefer "folder/index.js" instead of just "index.js". 1384 if (/^index\./.test(fileName)) { 1385 var match = path.match(BEFORE_SLASH_RE); 1386 1387 if (match) { 1388 var pathBeforeSlash = match[1]; 1389 1390 if (pathBeforeSlash) { 1391 var folderName = pathBeforeSlash.replace(BEFORE_SLASH_RE, ''); 1392 fileName = folderName + '/' + fileName; 1393 } 1394 } 1395 } 1396 } 1397 1398 sourceInfo = ' (at ' + fileName + ':' + source.lineNumber + ')'; 1399 } else if (ownerName) { 1400 sourceInfo = ' (created by ' + ownerName + ')'; 1401 } 1402 1403 return '\n in ' + (name || 'Unknown') + sourceInfo; 1404 } 1405 1406 // The Symbol used to tag the ReactElement-like types. If there is no native Symbol 1407 // nor polyfill, then a plain number is used for performance. 1408 var hasSymbol = typeof Symbol === 'function' && Symbol.for; 1409 var REACT_ELEMENT_TYPE = hasSymbol ? Symbol.for('react.element') : 0xeac7; 1410 var REACT_PORTAL_TYPE = hasSymbol ? Symbol.for('react.portal') : 0xeaca; 1411 var REACT_FRAGMENT_TYPE = hasSymbol ? Symbol.for('react.fragment') : 0xeacb; 1412 var REACT_STRICT_MODE_TYPE = hasSymbol ? Symbol.for('react.strict_mode') : 0xeacc; 1413 var REACT_PROFILER_TYPE = hasSymbol ? Symbol.for('react.profiler') : 0xead2; 1414 var REACT_PROVIDER_TYPE = hasSymbol ? Symbol.for('react.provider') : 0xeacd; 1415 var REACT_CONTEXT_TYPE = hasSymbol ? Symbol.for('react.context') : 0xeace; // TODO: We don't use AsyncMode or ConcurrentMode anymore. They were temporary 1416 var REACT_CONCURRENT_MODE_TYPE = hasSymbol ? Symbol.for('react.concurrent_mode') : 0xeacf; 1417 var REACT_FORWARD_REF_TYPE = hasSymbol ? Symbol.for('react.forward_ref') : 0xead0; 1418 var REACT_SUSPENSE_TYPE = hasSymbol ? Symbol.for('react.suspense') : 0xead1; 1419 var REACT_SUSPENSE_LIST_TYPE = hasSymbol ? Symbol.for('react.suspense_list') : 0xead8; 1420 var REACT_MEMO_TYPE = hasSymbol ? Symbol.for('react.memo') : 0xead3; 1421 var REACT_LAZY_TYPE = hasSymbol ? Symbol.for('react.lazy') : 0xead4; 1422 var REACT_BLOCK_TYPE = hasSymbol ? Symbol.for('react.block') : 0xead9; 1423 var MAYBE_ITERATOR_SYMBOL = typeof Symbol === 'function' && Symbol.iterator; 1424 var FAUX_ITERATOR_SYMBOL = '@@iterator'; 1425 function getIteratorFn(maybeIterable) { 1426 if (maybeIterable === null || typeof maybeIterable !== 'object') { 1427 return null; 1428 } 1429 1430 var maybeIterator = MAYBE_ITERATOR_SYMBOL && maybeIterable[MAYBE_ITERATOR_SYMBOL] || maybeIterable[FAUX_ITERATOR_SYMBOL]; 1431 1432 if (typeof maybeIterator === 'function') { 1433 return maybeIterator; 1434 } 1435 1436 return null; 1437 } 1438 1439 var Uninitialized = -1; 1440 var Pending = 0; 1441 var Resolved = 1; 1442 var Rejected = 2; 1443 function refineResolvedLazyComponent(lazyComponent) { 1444 return lazyComponent._status === Resolved ? lazyComponent._result : null; 1445 } 1446 function initializeLazyComponentType(lazyComponent) { 1447 if (lazyComponent._status === Uninitialized) { 1448 lazyComponent._status = Pending; 1449 var ctor = lazyComponent._ctor; 1450 var thenable = ctor(); 1451 lazyComponent._result = thenable; 1452 thenable.then(function (moduleObject) { 1453 if (lazyComponent._status === Pending) { 1454 var defaultExport = moduleObject.default; 1455 1456 { 1457 if (defaultExport === undefined) { 1458 error('lazy: Expected the result of a dynamic import() call. ' + 'Instead received: %s\n\nYour code should look like: \n ' + "const MyComponent = lazy(() => import('./MyComponent'))", moduleObject); 1459 } 1460 } 1461 1462 lazyComponent._status = Resolved; 1463 lazyComponent._result = defaultExport; 1464 } 1465 }, function (error) { 1466 if (lazyComponent._status === Pending) { 1467 lazyComponent._status = Rejected; 1468 lazyComponent._result = error; 1469 } 1470 }); 1471 } 1472 } 1473 1474 function getWrappedName(outerType, innerType, wrapperName) { 1475 var functionName = innerType.displayName || innerType.name || ''; 1476 return outerType.displayName || (functionName !== '' ? wrapperName + "(" + functionName + ")" : wrapperName); 1477 } 1478 1479 function getComponentName(type) { 1480 if (type == null) { 1481 // Host root, text node or just invalid type. 1482 return null; 1483 } 1484 1485 { 1486 if (typeof type.tag === 'number') { 1487 error('Received an unexpected object in getComponentName(). ' + 'This is likely a bug in React. Please file an issue.'); 1488 } 1489 } 1490 1491 if (typeof type === 'function') { 1492 return type.displayName || type.name || null; 1493 } 1494 1495 if (typeof type === 'string') { 1496 return type; 1497 } 1498 1499 switch (type) { 1500 case REACT_FRAGMENT_TYPE: 1501 return 'Fragment'; 1502 1503 case REACT_PORTAL_TYPE: 1504 return 'Portal'; 1505 1506 case REACT_PROFILER_TYPE: 1507 return "Profiler"; 1508 1509 case REACT_STRICT_MODE_TYPE: 1510 return 'StrictMode'; 1511 1512 case REACT_SUSPENSE_TYPE: 1513 return 'Suspense'; 1514 1515 case REACT_SUSPENSE_LIST_TYPE: 1516 return 'SuspenseList'; 1517 } 1518 1519 if (typeof type === 'object') { 1520 switch (type.$$typeof) { 1521 case REACT_CONTEXT_TYPE: 1522 return 'Context.Consumer'; 1523 1524 case REACT_PROVIDER_TYPE: 1525 return 'Context.Provider'; 1526 1527 case REACT_FORWARD_REF_TYPE: 1528 return getWrappedName(type, type.render, 'ForwardRef'); 1529 1530 case REACT_MEMO_TYPE: 1531 return getComponentName(type.type); 1532 1533 case REACT_BLOCK_TYPE: 1534 return getComponentName(type.render); 1535 1536 case REACT_LAZY_TYPE: 1537 { 1538 var thenable = type; 1539 var resolvedThenable = refineResolvedLazyComponent(thenable); 1540 1541 if (resolvedThenable) { 1542 return getComponentName(resolvedThenable); 1543 } 1544 1545 break; 1546 } 1547 } 1548 } 1549 1550 return null; 1551 } 1552 1553 var ReactDebugCurrentFrame$1 = ReactSharedInternals.ReactDebugCurrentFrame; 1554 1555 function describeFiber(fiber) { 1556 switch (fiber.tag) { 1557 case HostRoot: 1558 case HostPortal: 1559 case HostText: 1560 case Fragment: 1561 case ContextProvider: 1562 case ContextConsumer: 1563 return ''; 1564 1565 default: 1566 var owner = fiber._debugOwner; 1567 var source = fiber._debugSource; 1568 var name = getComponentName(fiber.type); 1569 var ownerName = null; 1570 1571 if (owner) { 1572 ownerName = getComponentName(owner.type); 1573 } 1574 1575 return describeComponentFrame(name, source, ownerName); 1576 } 1577 } 1578 1579 function getStackByFiberInDevAndProd(workInProgress) { 1580 var info = ''; 1581 var node = workInProgress; 1582 1583 do { 1584 info += describeFiber(node); 1585 node = node.return; 1586 } while (node); 1587 1588 return info; 1589 } 1590 var current = null; 1591 var isRendering = false; 1592 function getCurrentFiberOwnerNameInDevOrNull() { 1593 { 1594 if (current === null) { 1595 return null; 1596 } 1597 1598 var owner = current._debugOwner; 1599 1600 if (owner !== null && typeof owner !== 'undefined') { 1601 return getComponentName(owner.type); 1602 } 1603 } 1604 1605 return null; 1606 } 1607 function getCurrentFiberStackInDev() { 1608 { 1609 if (current === null) { 1610 return ''; 1611 } // Safe because if current fiber exists, we are reconciling, 1612 // and it is guaranteed to be the work-in-progress version. 1613 1614 1615 return getStackByFiberInDevAndProd(current); 1616 } 1617 } 1618 function resetCurrentFiber() { 1619 { 1620 ReactDebugCurrentFrame$1.getCurrentStack = null; 1621 current = null; 1622 isRendering = false; 1623 } 1624 } 1625 function setCurrentFiber(fiber) { 1626 { 1627 ReactDebugCurrentFrame$1.getCurrentStack = getCurrentFiberStackInDev; 1628 current = fiber; 1629 isRendering = false; 1630 } 1631 } 1632 function setIsRendering(rendering) { 1633 { 1634 isRendering = rendering; 1635 } 1636 } 1637 1638 // Flow does not allow string concatenation of most non-string types. To work 1639 // around this limitation, we use an opaque type that can only be obtained by 1640 // passing the value through getToStringValue first. 1641 function toString(value) { 1642 return '' + value; 1643 } 1644 function getToStringValue(value) { 1645 switch (typeof value) { 1646 case 'boolean': 1647 case 'number': 1648 case 'object': 1649 case 'string': 1650 case 'undefined': 1651 return value; 1652 1653 default: 1654 // function, symbol are assigned as empty strings 1655 return ''; 1656 } 1657 } 1658 1659 /** 1660 * Copyright (c) 2013-present, Facebook, Inc. 1661 * 1662 * This source code is licensed under the MIT license found in the 1663 * LICENSE file in the root directory of this source tree. 1664 */ 1665 1666 var ReactPropTypesSecret = 'SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED'; 1667 1668 var ReactPropTypesSecret_1 = ReactPropTypesSecret; 1669 1670 var printWarning$1 = function() {}; 1671 1672 { 1673 var ReactPropTypesSecret$1 = ReactPropTypesSecret_1; 1674 var loggedTypeFailures = {}; 1675 var has = Function.call.bind(Object.prototype.hasOwnProperty); 1676 1677 printWarning$1 = function(text) { 1678 var message = 'Warning: ' + text; 1679 if (typeof console !== 'undefined') { 1680 console.error(message); 1681 } 1682 try { 1683 // --- Welcome to debugging React --- 1684 // This error was thrown as a convenience so that you can use this stack 1685 // to find the callsite that caused this warning to fire. 1686 throw new Error(message); 1687 } catch (x) {} 1688 }; 1689 } 1690 1691 /** 1692 * Assert that the values match with the type specs. 1693 * Error messages are memorized and will only be shown once. 1694 * 1695 * @param {object} typeSpecs Map of name to a ReactPropType 1696 * @param {object} values Runtime values that need to be type-checked 1697 * @param {string} location e.g. "prop", "context", "child context" 1698 * @param {string} componentName Name of the component for error messages. 1699 * @param {?Function} getStack Returns the component stack. 1700 * @private 1701 */ 1702 function checkPropTypes(typeSpecs, values, location, componentName, getStack) { 1703 { 1704 for (var typeSpecName in typeSpecs) { 1705 if (has(typeSpecs, typeSpecName)) { 1706 var error; 1707 // Prop type validation may throw. In case they do, we don't want to 1708 // fail the render phase where it didn't fail before. So we log it. 1709 // After these have been cleaned up, we'll let them throw. 1710 try { 1711 // This is intentionally an invariant that gets caught. It's the same 1712 // behavior as without this statement except with a better message. 1713 if (typeof typeSpecs[typeSpecName] !== 'function') { 1714 var err = Error( 1715 (componentName || 'React class') + ': ' + location + ' type `' + typeSpecName + '` is invalid; ' + 1716 'it must be a function, usually from the `prop-types` package, but received `' + typeof typeSpecs[typeSpecName] + '`.' 1717 ); 1718 err.name = 'Invariant Violation'; 1719 throw err; 1720 } 1721 error = typeSpecs[typeSpecName](values, typeSpecName, componentName, location, null, ReactPropTypesSecret$1); 1722 } catch (ex) { 1723 error = ex; 1724 } 1725 if (error && !(error instanceof Error)) { 1726 printWarning$1( 1727 (componentName || 'React class') + ': type specification of ' + 1728 location + ' `' + typeSpecName + '` is invalid; the type checker ' + 1729 'function must return `null` or an `Error` but returned a ' + typeof error + '. ' + 1730 'You may have forgotten to pass an argument to the type checker ' + 1731 'creator (arrayOf, instanceOf, objectOf, oneOf, oneOfType, and ' + 1732 'shape all require an argument).' 1733 ); 1734 } 1735 if (error instanceof Error && !(error.message in loggedTypeFailures)) { 1736 // Only monitor this failure once because there tends to be a lot of the 1737 // same error. 1738 loggedTypeFailures[error.message] = true; 1739 1740 var stack = getStack ? getStack() : ''; 1741 1742 printWarning$1( 1743 'Failed ' + location + ' type: ' + error.message + (stack != null ? stack : '') 1744 ); 1745 } 1746 } 1747 } 1748 } 1749 } 1750 1751 /** 1752 * Resets warning cache when testing. 1753 * 1754 * @private 1755 */ 1756 checkPropTypes.resetWarningCache = function() { 1757 { 1758 loggedTypeFailures = {}; 1759 } 1760 }; 1761 1762 var checkPropTypes_1 = checkPropTypes; 1763 1764 var ReactDebugCurrentFrame$2 = null; 1765 var ReactControlledValuePropTypes = { 1766 checkPropTypes: null 1767 }; 1768 1769 { 1770 ReactDebugCurrentFrame$2 = ReactSharedInternals.ReactDebugCurrentFrame; 1771 var hasReadOnlyValue = { 1772 button: true, 1773 checkbox: true, 1774 image: true, 1775 hidden: true, 1776 radio: true, 1777 reset: true, 1778 submit: true 1779 }; 1780 var propTypes = { 1781 value: function (props, propName, componentName) { 1782 if (hasReadOnlyValue[props.type] || props.onChange || props.readOnly || props.disabled || props[propName] == null || enableDeprecatedFlareAPI ) { 1783 return null; 1784 } 1785 1786 return new Error('You provided a `value` prop to a form field without an ' + '`onChange` handler. This will render a read-only field. If ' + 'the field should be mutable use `defaultValue`. Otherwise, ' + 'set either `onChange` or `readOnly`.'); 1787 }, 1788 checked: function (props, propName, componentName) { 1789 if (props.onChange || props.readOnly || props.disabled || props[propName] == null || enableDeprecatedFlareAPI ) { 1790 return null; 1791 } 1792 1793 return new Error('You provided a `checked` prop to a form field without an ' + '`onChange` handler. This will render a read-only field. If ' + 'the field should be mutable use `defaultChecked`. Otherwise, ' + 'set either `onChange` or `readOnly`.'); 1794 } 1795 }; 1796 /** 1797 * Provide a linked `value` attribute for controlled forms. You should not use 1798 * this outside of the ReactDOM controlled form components. 1799 */ 1800 1801 ReactControlledValuePropTypes.checkPropTypes = function (tagName, props) { 1802 checkPropTypes_1(propTypes, props, 'prop', tagName, ReactDebugCurrentFrame$2.getStackAddendum); 1803 }; 1804 } 1805 1806 function isCheckable(elem) { 1807 var type = elem.type; 1808 var nodeName = elem.nodeName; 1809 return nodeName && nodeName.toLowerCase() === 'input' && (type === 'checkbox' || type === 'radio'); 1810 } 1811 1812 function getTracker(node) { 1813 return node._valueTracker; 1814 } 1815 1816 function detachTracker(node) { 1817 node._valueTracker = null; 1818 } 1819 1820 function getValueFromNode(node) { 1821 var value = ''; 1822 1823 if (!node) { 1824 return value; 1825 } 1826 1827 if (isCheckable(node)) { 1828 value = node.checked ? 'true' : 'false'; 1829 } else { 1830 value = node.value; 1831 } 1832 1833 return value; 1834 } 1835 1836 function trackValueOnNode(node) { 1837 var valueField = isCheckable(node) ? 'checked' : 'value'; 1838 var descriptor = Object.getOwnPropertyDescriptor(node.constructor.prototype, valueField); 1839 var currentValue = '' + node[valueField]; // if someone has already defined a value or Safari, then bail 1840 // and don't track value will cause over reporting of changes, 1841 // but it's better then a hard failure 1842 // (needed for certain tests that spyOn input values and Safari) 1843 1844 if (node.hasOwnProperty(valueField) || typeof descriptor === 'undefined' || typeof descriptor.get !== 'function' || typeof descriptor.set !== 'function') { 1845 return; 1846 } 1847 1848 var get = descriptor.get, 1849 set = descriptor.set; 1850 Object.defineProperty(node, valueField, { 1851 configurable: true, 1852 get: function () { 1853 return get.call(this); 1854 }, 1855 set: function (value) { 1856 currentValue = '' + value; 1857 set.call(this, value); 1858 } 1859 }); // We could've passed this the first time 1860 // but it triggers a bug in IE11 and Edge 14/15. 1861 // Calling defineProperty() again should be equivalent. 1862 // https://github.com/facebook/react/issues/11768 1863 1864 Object.defineProperty(node, valueField, { 1865 enumerable: descriptor.enumerable 1866 }); 1867 var tracker = { 1868 getValue: function () { 1869 return currentValue; 1870 }, 1871 setValue: function (value) { 1872 currentValue = '' + value; 1873 }, 1874 stopTracking: function () { 1875 detachTracker(node); 1876 delete node[valueField]; 1877 } 1878 }; 1879 return tracker; 1880 } 1881 1882 function track(node) { 1883 if (getTracker(node)) { 1884 return; 1885 } // TODO: Once it's just Fiber we can move this to node._wrapperState 1886 1887 1888 node._valueTracker = trackValueOnNode(node); 1889 } 1890 function updateValueIfChanged(node) { 1891 if (!node) { 1892 return false; 1893 } 1894 1895 var tracker = getTracker(node); // if there is no tracker at this point it's unlikely 1896 // that trying again will succeed 1897 1898 if (!tracker) { 1899 return true; 1900 } 1901 1902 var lastValue = tracker.getValue(); 1903 var nextValue = getValueFromNode(node); 1904 1905 if (nextValue !== lastValue) { 1906 tracker.setValue(nextValue); 1907 return true; 1908 } 1909 1910 return false; 1911 } 1912 1913 var didWarnValueDefaultValue = false; 1914 var didWarnCheckedDefaultChecked = false; 1915 var didWarnControlledToUncontrolled = false; 1916 var didWarnUncontrolledToControlled = false; 1917 1918 function isControlled(props) { 1919 var usesChecked = props.type === 'checkbox' || props.type === 'radio'; 1920 return usesChecked ? props.checked != null : props.value != null; 1921 } 1922 /** 1923 * Implements an <input> host component that allows setting these optional 1924 * props: `checked`, `value`, `defaultChecked`, and `defaultValue`. 1925 * 1926 * If `checked` or `value` are not supplied (or null/undefined), user actions 1927 * that affect the checked state or value will trigger updates to the element. 1928 * 1929 * If they are supplied (and not null/undefined), the rendered element will not 1930 * trigger updates to the element. Instead, the props must change in order for 1931 * the rendered element to be updated. 1932 * 1933 * The rendered element will be initialized as unchecked (or `defaultChecked`) 1934 * with an empty value (or `defaultValue`). 1935 * 1936 * See http://www.w3.org/TR/2012/WD-html5-20121025/the-input-element.html 1937 */ 1938 1939 1940 function getHostProps(element, props) { 1941 var node = element; 1942 var checked = props.checked; 1943 1944 var hostProps = _assign({}, props, { 1945 defaultChecked: undefined, 1946 defaultValue: undefined, 1947 value: undefined, 1948 checked: checked != null ? checked : node._wrapperState.initialChecked 1949 }); 1950 1951 return hostProps; 1952 } 1953 function initWrapperState(element, props) { 1954 { 1955 ReactControlledValuePropTypes.checkPropTypes('input', props); 1956 1957 if (props.checked !== undefined && props.defaultChecked !== undefined && !didWarnCheckedDefaultChecked) { 1958 error('%s contains an input of type %s with both checked and defaultChecked props. ' + 'Input elements must be either controlled or uncontrolled ' + '(specify either the checked prop, or the defaultChecked prop, but not ' + 'both). Decide between using a controlled or uncontrolled input ' + 'element and remove one of these props. More info: ' + 'https://fb.me/react-controlled-components', getCurrentFiberOwnerNameInDevOrNull() || 'A component', props.type); 1959 1960 didWarnCheckedDefaultChecked = true; 1961 } 1962 1963 if (props.value !== undefined && props.defaultValue !== undefined && !didWarnValueDefaultValue) { 1964 error('%s contains an input of type %s with both value and defaultValue props. ' + 'Input elements must be either controlled or uncontrolled ' + '(specify either the value prop, or the defaultValue prop, but not ' + 'both). Decide between using a controlled or uncontrolled input ' + 'element and remove one of these props. More info: ' + 'https://fb.me/react-controlled-components', getCurrentFiberOwnerNameInDevOrNull() || 'A component', props.type); 1965 1966 didWarnValueDefaultValue = true; 1967 } 1968 } 1969 1970 var node = element; 1971 var defaultValue = props.defaultValue == null ? '' : props.defaultValue; 1972 node._wrapperState = { 1973 initialChecked: props.checked != null ? props.checked : props.defaultChecked, 1974 initialValue: getToStringValue(props.value != null ? props.value : defaultValue), 1975 controlled: isControlled(props) 1976 }; 1977 } 1978 function updateChecked(element, props) { 1979 var node = element; 1980 var checked = props.checked; 1981 1982 if (checked != null) { 1983 setValueForProperty(node, 'checked', checked, false); 1984 } 1985 } 1986 function updateWrapper(element, props) { 1987 var node = element; 1988 1989 { 1990 var controlled = isControlled(props); 1991 1992 if (!node._wrapperState.controlled && controlled && !didWarnUncontrolledToControlled) { 1993 error('A component is changing an uncontrolled input of type %s to be controlled. ' + 'Input elements should not switch from uncontrolled to controlled (or vice versa). ' + 'Decide between using a controlled or uncontrolled input ' + 'element for the lifetime of the component. More info: https://fb.me/react-controlled-components', props.type); 1994 1995 didWarnUncontrolledToControlled = true; 1996 } 1997 1998 if (node._wrapperState.controlled && !controlled && !didWarnControlledToUncontrolled) { 1999 error('A component is changing a controlled input of type %s to be uncontrolled. ' + 'Input elements should not switch from controlled to uncontrolled (or vice versa). ' + 'Decide between using a controlled or uncontrolled input ' + 'element for the lifetime of the component. More info: https://fb.me/react-controlled-components', props.type); 2000 2001 didWarnControlledToUncontrolled = true; 2002 } 2003 } 2004 2005 updateChecked(element, props); 2006 var value = getToStringValue(props.value); 2007 var type = props.type; 2008 2009 if (value != null) { 2010 if (type === 'number') { 2011 if (value === 0 && node.value === '' || // We explicitly want to coerce to number here if possible. 2012 // eslint-disable-next-line 2013 node.value != value) { 2014 node.value = toString(value); 2015 } 2016 } else if (node.value !== toString(value)) { 2017 node.value = toString(value); 2018 } 2019 } else if (type === 'submit' || type === 'reset') { 2020 // Submit/reset inputs need the attribute removed completely to avoid 2021 // blank-text buttons. 2022 node.removeAttribute('value'); 2023 return; 2024 } 2025 2026 { 2027 // When syncing the value attribute, the value comes from a cascade of 2028 // properties: 2029 // 1. The value React property 2030 // 2. The defaultValue React property 2031 // 3. Otherwise there should be no change 2032 if (props.hasOwnProperty('value')) { 2033 setDefaultValue(node, props.type, value); 2034 } else if (props.hasOwnProperty('defaultValue')) { 2035 setDefaultValue(node, props.type, getToStringValue(props.defaultValue)); 2036 } 2037 } 2038 2039 { 2040 // When syncing the checked attribute, it only changes when it needs 2041 // to be removed, such as transitioning from a checkbox into a text input 2042 if (props.checked == null && props.defaultChecked != null) { 2043 node.defaultChecked = !!props.defaultChecked; 2044 } 2045 } 2046 } 2047 function postMountWrapper(element, props, isHydrating) { 2048 var node = element; // Do not assign value if it is already set. This prevents user text input 2049 // from being lost during SSR hydration. 2050 2051 if (props.hasOwnProperty('value') || props.hasOwnProperty('defaultValue')) { 2052 var type = props.type; 2053 var isButton = type === 'submit' || type === 'reset'; // Avoid setting value attribute on submit/reset inputs as it overrides the 2054 // default value provided by the browser. See: #12872 2055 2056 if (isButton && (props.value === undefined || props.value === null)) { 2057 return; 2058 } 2059 2060 var initialValue = toString(node._wrapperState.initialValue); // Do not assign value if it is already set. This prevents user text input 2061 // from being lost during SSR hydration. 2062 2063 if (!isHydrating) { 2064 { 2065 // When syncing the value attribute, the value property should use 2066 // the wrapperState._initialValue property. This uses: 2067 // 2068 // 1. The value React property when present 2069 // 2. The defaultValue React property when present 2070 // 3. An empty string 2071 if (initialValue !== node.value) { 2072 node.value = initialValue; 2073 } 2074 } 2075 } 2076 2077 { 2078 // Otherwise, the value attribute is synchronized to the property, 2079 // so we assign defaultValue to the same thing as the value property 2080 // assignment step above. 2081 node.defaultValue = initialValue; 2082 } 2083 } // Normally, we'd just do `node.checked = node.checked` upon initial mount, less this bug 2084 // this is needed to work around a chrome bug where setting defaultChecked 2085 // will sometimes influence the value of checked (even after detachment). 2086 // Reference: https://bugs.chromium.org/p/chromium/issues/detail?id=608416 2087 // We need to temporarily unset name to avoid disrupting radio button groups. 2088 2089 2090 var name = node.name; 2091 2092 if (name !== '') { 2093 node.name = ''; 2094 } 2095 2096 { 2097 // When syncing the checked attribute, both the checked property and 2098 // attribute are assigned at the same time using defaultChecked. This uses: 2099 // 2100 // 1. The checked React property when present 2101 // 2. The defaultChecked React property when present 2102 // 3. Otherwise, false 2103 node.defaultChecked = !node.defaultChecked; 2104 node.defaultChecked = !!node._wrapperState.initialChecked; 2105 } 2106 2107 if (name !== '') { 2108 node.name = name; 2109 } 2110 } 2111 function restoreControlledState(element, props) { 2112 var node = element; 2113 updateWrapper(node, props); 2114 updateNamedCousins(node, props); 2115 } 2116 2117 function updateNamedCousins(rootNode, props) { 2118 var name = props.name; 2119 2120 if (props.type === 'radio' && name != null) { 2121 var queryRoot = rootNode; 2122 2123 while (queryRoot.parentNode) { 2124 queryRoot = queryRoot.parentNode; 2125 } // If `rootNode.form` was non-null, then we could try `form.elements`, 2126 // but that sometimes behaves strangely in IE8. We could also try using 2127 // `form.getElementsByName`, but that will only return direct children 2128 // and won't include inputs that use the HTML5 `form=` attribute. Since 2129 // the input might not even be in a form. It might not even be in the 2130 // document. Let's just use the local `querySelectorAll` to ensure we don't 2131 // miss anything. 2132 2133 2134 var group = queryRoot.querySelectorAll('input[name=' + JSON.stringify('' + name) + '][type="radio"]'); 2135 2136 for (var i = 0; i < group.length; i++) { 2137 var otherNode = group[i]; 2138 2139 if (otherNode === rootNode || otherNode.form !== rootNode.form) { 2140 continue; 2141 } // This will throw if radio buttons rendered by different copies of React 2142 // and the same name are rendered into the same form (same as #1939). 2143 // That's probably okay; we don't support it just as we don't support 2144 // mixing React radio buttons with non-React ones. 2145 2146 2147 var otherProps = getFiberCurrentPropsFromNode$1(otherNode); 2148 2149 if (!otherProps) { 2150 { 2151 throw Error( "ReactDOMInput: Mixing React and non-React radio inputs with the same `name` is not supported." ); 2152 } 2153 } // We need update the tracked value on the named cousin since the value 2154 // was changed but the input saw no event or value set 2155 2156 2157 updateValueIfChanged(otherNode); // If this is a controlled radio button group, forcing the input that 2158 // was previously checked to update will cause it to be come re-checked 2159 // as appropriate. 2160 2161 updateWrapper(otherNode, otherProps); 2162 } 2163 } 2164 } // In Chrome, assigning defaultValue to certain input types triggers input validation. 2165 // For number inputs, the display value loses trailing decimal points. For email inputs, 2166 // Chrome raises "The specified value <x> is not a valid email address". 2167 // 2168 // Here we check to see if the defaultValue has actually changed, avoiding these problems 2169 // when the user is inputting text 2170 // 2171 // https://github.com/facebook/react/issues/7253 2172 2173 2174 function setDefaultValue(node, type, value) { 2175 if ( // Focused number inputs synchronize on blur. See ChangeEventPlugin.js 2176 type !== 'number' || node.ownerDocument.activeElement !== node) { 2177 if (value == null) { 2178 node.defaultValue = toString(node._wrapperState.initialValue); 2179 } else if (node.defaultValue !== toString(value)) { 2180 node.defaultValue = toString(value); 2181 } 2182 } 2183 } 2184 2185 var didWarnSelectedSetOnOption = false; 2186 var didWarnInvalidChild = false; 2187 2188 function flattenChildren(children) { 2189 var content = ''; // Flatten children. We'll warn if they are invalid 2190 // during validateProps() which runs for hydration too. 2191 // Note that this would throw on non-element objects. 2192 // Elements are stringified (which is normally irrelevant 2193 // but matters for <fbt>). 2194 2195 React.Children.forEach(children, function (child) { 2196 if (child == null) { 2197 return; 2198 } 2199 2200 content += child; // Note: we don't warn about invalid children here. 2201 // Instead, this is done separately below so that 2202 // it happens during the hydration codepath too. 2203 }); 2204 return content; 2205 } 2206 /** 2207 * Implements an <option> host component that warns when `selected` is set. 2208 */ 2209 2210 2211 function validateProps(element, props) { 2212 { 2213 // This mirrors the codepath above, but runs for hydration too. 2214 // Warn about invalid children here so that client and hydration are consistent. 2215 // TODO: this seems like it could cause a DEV-only throw for hydration 2216 // if children contains a non-element object. We should try to avoid that. 2217 if (typeof props.children === 'object' && props.children !== null) { 2218 React.Children.forEach(props.children, function (child) { 2219 if (child == null) { 2220 return; 2221 } 2222 2223 if (typeof child === 'string' || typeof child === 'number') { 2224 return; 2225 } 2226 2227 if (typeof child.type !== 'string') { 2228 return; 2229 } 2230 2231 if (!didWarnInvalidChild) { 2232 didWarnInvalidChild = true; 2233 2234 error('Only strings and numbers are supported as <option> children.'); 2235 } 2236 }); 2237 } // TODO: Remove support for `selected` in <option>. 2238 2239 2240 if (props.selected != null && !didWarnSelectedSetOnOption) { 2241 error('Use the `defaultValue` or `value` props on <select> instead of ' + 'setting `selected` on <option>.'); 2242 2243 didWarnSelectedSetOnOption = true; 2244 } 2245 } 2246 } 2247 function postMountWrapper$1(element, props) { 2248 // value="" should make a value attribute (#6219) 2249 if (props.value != null) { 2250 element.setAttribute('value', toString(getToStringValue(props.value))); 2251 } 2252 } 2253 function getHostProps$1(element, props) { 2254 var hostProps = _assign({ 2255 children: undefined 2256 }, props); 2257 2258 var content = flattenChildren(props.children); 2259 2260 if (content) { 2261 hostProps.children = content; 2262 } 2263 2264 return hostProps; 2265 } 2266 2267 var didWarnValueDefaultValue$1; 2268 2269 { 2270 didWarnValueDefaultValue$1 = false; 2271 } 2272 2273 function getDeclarationErrorAddendum() { 2274 var ownerName = getCurrentFiberOwnerNameInDevOrNull(); 2275 2276 if (ownerName) { 2277 return '\n\nCheck the render method of `' + ownerName + '`.'; 2278 } 2279 2280 return ''; 2281 } 2282 2283 var valuePropNames = ['value', 'defaultValue']; 2284 /** 2285 * Validation function for `value` and `defaultValue`. 2286 */ 2287 2288 function checkSelectPropTypes(props) { 2289 { 2290 ReactControlledValuePropTypes.checkPropTypes('select', props); 2291 2292 for (var i = 0; i < valuePropNames.length; i++) { 2293 var propName = valuePropNames[i]; 2294 2295 if (props[propName] == null) { 2296 continue; 2297 } 2298 2299 var isArray = Array.isArray(props[propName]); 2300 2301 if (props.multiple && !isArray) { 2302 error('The `%s` prop supplied to <select> must be an array if ' + '`multiple` is true.%s', propName, getDeclarationErrorAddendum()); 2303 } else if (!props.multiple && isArray) { 2304 error('The `%s` prop supplied to <select> must be a scalar ' + 'value if `multiple` is false.%s', propName, getDeclarationErrorAddendum()); 2305 } 2306 } 2307 } 2308 } 2309 2310 function updateOptions(node, multiple, propValue, setDefaultSelected) { 2311 var options = node.options; 2312 2313 if (multiple) { 2314 var selectedValues = propValue; 2315 var selectedValue = {}; 2316 2317 for (var i = 0; i < selectedValues.length; i++) { 2318 // Prefix to avoid chaos with special keys. 2319 selectedValue['$' + selectedValues[i]] = true; 2320 } 2321 2322 for (var _i = 0; _i < options.length; _i++) { 2323 var selected = selectedValue.hasOwnProperty('$' + options[_i].value); 2324 2325 if (options[_i].selected !== selected) { 2326 options[_i].selected = selected; 2327 } 2328 2329 if (selected && setDefaultSelected) { 2330 options[_i].defaultSelected = true; 2331 } 2332 } 2333 } else { 2334 // Do not set `select.value` as exact behavior isn't consistent across all 2335 // browsers for all cases. 2336 var _selectedValue = toString(getToStringValue(propValue)); 2337 2338 var defaultSelected = null; 2339 2340 for (var _i2 = 0; _i2 < options.length; _i2++) { 2341 if (options[_i2].value === _selectedValue) { 2342 options[_i2].selected = true; 2343 2344 if (setDefaultSelected) { 2345 options[_i2].defaultSelected = true; 2346 } 2347 2348 return; 2349 } 2350 2351 if (defaultSelected === null && !options[_i2].disabled) { 2352 defaultSelected = options[_i2]; 2353 } 2354 } 2355 2356 if (defaultSelected !== null) { 2357 defaultSelected.selected = true; 2358 } 2359 } 2360 } 2361 /** 2362 * Implements a <select> host component that allows optionally setting the 2363 * props `value` and `defaultValue`. If `multiple` is false, the prop must be a 2364 * stringable. If `multiple` is true, the prop must be an array of stringables. 2365 * 2366 * If `value` is not supplied (or null/undefined), user actions that change the 2367 * selected option will trigger updates to the rendered options. 2368 * 2369 * If it is supplied (and not null/undefined), the rendered options will not 2370 * update in response to user actions. Instead, the `value` prop must change in 2371 * order for the rendered options to update. 2372 * 2373 * If `defaultValue` is provided, any options with the supplied values will be 2374 * selected. 2375 */ 2376 2377 2378 function getHostProps$2(element, props) { 2379 return _assign({}, props, { 2380 value: undefined 2381 }); 2382 } 2383 function initWrapperState$1(element, props) { 2384 var node = element; 2385 2386 { 2387 checkSelectPropTypes(props); 2388 } 2389 2390 node._wrapperState = { 2391 wasMultiple: !!props.multiple 2392 }; 2393 2394 { 2395 if (props.value !== undefined && props.defaultValue !== undefined && !didWarnValueDefaultValue$1) { 2396 error('Select elements must be either controlled or uncontrolled ' + '(specify either the value prop, or the defaultValue prop, but not ' + 'both). Decide between using a controlled or uncontrolled select ' + 'element and remove one of these props. More info: ' + 'https://fb.me/react-controlled-components'); 2397 2398 didWarnValueDefaultValue$1 = true; 2399 } 2400 } 2401 } 2402 function postMountWrapper$2(element, props) { 2403 var node = element; 2404 node.multiple = !!props.multiple; 2405 var value = props.value; 2406 2407 if (value != null) { 2408 updateOptions(node, !!props.multiple, value, false); 2409 } else if (props.defaultValue != null) { 2410 updateOptions(node, !!props.multiple, props.defaultValue, true); 2411 } 2412 } 2413 function postUpdateWrapper(element, props) { 2414 var node = element; 2415 var wasMultiple = node._wrapperState.wasMultiple; 2416 node._wrapperState.wasMultiple = !!props.multiple; 2417 var value = props.value; 2418 2419 if (value != null) { 2420 updateOptions(node, !!props.multiple, value, false); 2421 } else if (wasMultiple !== !!props.multiple) { 2422 // For simplicity, reapply `defaultValue` if `multiple` is toggled. 2423 if (props.defaultValue != null) { 2424 updateOptions(node, !!props.multiple, props.defaultValue, true); 2425 } else { 2426 // Revert the select back to its default unselected state. 2427 updateOptions(node, !!props.multiple, props.multiple ? [] : '', false); 2428 } 2429 } 2430 } 2431 function restoreControlledState$1(element, props) { 2432 var node = element; 2433 var value = props.value; 2434 2435 if (value != null) { 2436 updateOptions(node, !!props.multiple, value, false); 2437 } 2438 } 2439 2440 var didWarnValDefaultVal = false; 2441 2442 /** 2443 * Implements a <textarea> host component that allows setting `value`, and 2444 * `defaultValue`. This differs from the traditional DOM API because value is 2445 * usually set as PCDATA children. 2446 * 2447 * If `value` is not supplied (or null/undefined), user actions that affect the 2448 * value will trigger updates to the element. 2449 * 2450 * If `value` is supplied (and not null/undefined), the rendered element will 2451 * not trigger updates to the element. Instead, the `value` prop must change in 2452 * order for the rendered element to be updated. 2453 * 2454 * The rendered element will be initialized with an empty value, the prop 2455 * `defaultValue` if specified, or the children content (deprecated). 2456 */ 2457 function getHostProps$3(element, props) { 2458 var node = element; 2459 2460 if (!(props.dangerouslySetInnerHTML == null)) { 2461 { 2462 throw Error( "`dangerouslySetInnerHTML` does not make sense on <textarea>." ); 2463 } 2464 } // Always set children to the same thing. In IE9, the selection range will 2465 // get reset if `textContent` is mutated. We could add a check in setTextContent 2466 // to only set the value if/when the value differs from the node value (which would 2467 // completely solve this IE9 bug), but Sebastian+Sophie seemed to like this 2468 // solution. The value can be a boolean or object so that's why it's forced 2469 // to be a string. 2470 2471 2472 var hostProps = _assign({}, props, { 2473 value: undefined, 2474 defaultValue: undefined, 2475 children: toString(node._wrapperState.initialValue) 2476 }); 2477 2478 return hostProps; 2479 } 2480 function initWrapperState$2(element, props) { 2481 var node = element; 2482 2483 { 2484 ReactControlledValuePropTypes.checkPropTypes('textarea', props); 2485 2486 if (props.value !== undefined && props.defaultValue !== undefined && !didWarnValDefaultVal) { 2487 error('%s contains a textarea with both value and defaultValue props. ' + 'Textarea elements must be either controlled or uncontrolled ' + '(specify either the value prop, or the defaultValue prop, but not ' + 'both). Decide between using a controlled or uncontrolled textarea ' + 'and remove one of these props. More info: ' + 'https://fb.me/react-controlled-components', getCurrentFiberOwnerNameInDevOrNull() || 'A component'); 2488 2489 didWarnValDefaultVal = true; 2490 } 2491 } 2492 2493 var initialValue = props.value; // Only bother fetching default value if we're going to use it 2494 2495 if (initialValue == null) { 2496 var children = props.children, 2497 defaultValue = props.defaultValue; 2498 2499 if (children != null) { 2500 { 2501 error('Use the `defaultValue` or `value` props instead of setting ' + 'children on <textarea>.'); 2502 } 2503 2504 { 2505 if (!(defaultValue == null)) { 2506 { 2507 throw Error( "If you supply `defaultValue` on a <textarea>, do not pass children." ); 2508 } 2509 } 2510 2511 if (Array.isArray(children)) { 2512 if (!(children.length <= 1)) { 2513 { 2514 throw Error( "<textarea> can only have at most one child." ); 2515 } 2516 } 2517 2518 children = children[0]; 2519 } 2520 2521 defaultValue = children; 2522 } 2523 } 2524 2525 if (defaultValue == null) { 2526 defaultValue = ''; 2527 } 2528 2529 initialValue = defaultValue; 2530 } 2531 2532 node._wrapperState = { 2533 initialValue: getToStringValue(initialValue) 2534 }; 2535 } 2536 function updateWrapper$1(element, props) { 2537 var node = element; 2538 var value = getToStringValue(props.value); 2539 var defaultValue = getToStringValue(props.defaultValue); 2540 2541 if (value != null) { 2542 // Cast `value` to a string to ensure the value is set correctly. While 2543 // browsers typically do this as necessary, jsdom doesn't. 2544 var newValue = toString(value); // To avoid side effects (such as losing text selection), only set value if changed 2545 2546 if (newValue !== node.value) { 2547 node.value = newValue; 2548 } 2549 2550 if (props.defaultValue == null && node.defaultValue !== newValue) { 2551 node.defaultValue = newValue; 2552 } 2553 } 2554 2555 if (defaultValue != null) { 2556 node.defaultValue = toString(defaultValue); 2557 } 2558 } 2559 function postMountWrapper$3(element, props) { 2560 var node = element; // This is in postMount because we need access to the DOM node, which is not 2561 // available until after the component has mounted. 2562 2563 var textContent = node.textContent; // Only set node.value if textContent is equal to the expected 2564 // initial value. In IE10/IE11 there is a bug where the placeholder attribute 2565 // will populate textContent as well. 2566 // https://developer.microsoft.com/microsoft-edge/platform/issues/101525/ 2567 2568 if (textContent === node._wrapperState.initialValue) { 2569 if (textContent !== '' && textContent !== null) { 2570 node.value = textContent; 2571 } 2572 } 2573 } 2574 function restoreControlledState$2(element, props) { 2575 // DOM component is still mounted; update 2576 updateWrapper$1(element, props); 2577 } 2578 2579 var HTML_NAMESPACE = 'http://www.w3.org/1999/xhtml'; 2580 var MATH_NAMESPACE = 'http://www.w3.org/1998/Math/MathML'; 2581 var SVG_NAMESPACE = 'http://www.w3.org/2000/svg'; 2582 var Namespaces = { 2583 html: HTML_NAMESPACE, 2584 mathml: MATH_NAMESPACE, 2585 svg: SVG_NAMESPACE 2586 }; // Assumes there is no parent namespace. 2587 2588 function getIntrinsicNamespace(type) { 2589 switch (type) { 2590 case 'svg': 2591 return SVG_NAMESPACE; 2592 2593 case 'math': 2594 return MATH_NAMESPACE; 2595 2596 default: 2597 return HTML_NAMESPACE; 2598 } 2599 } 2600 function getChildNamespace(parentNamespace, type) { 2601 if (parentNamespace == null || parentNamespace === HTML_NAMESPACE) { 2602 // No (or default) parent namespace: potential entry point. 2603 return getIntrinsicNamespace(type); 2604 } 2605 2606 if (parentNamespace === SVG_NAMESPACE && type === 'foreignObject') { 2607 // We're leaving SVG. 2608 return HTML_NAMESPACE; 2609 } // By default, pass namespace below. 2610 2611 2612 return parentNamespace; 2613 } 2614 2615 /* globals MSApp */ 2616 2617 /** 2618 * Create a function which has 'unsafe' privileges (required by windows8 apps) 2619 */ 2620 var createMicrosoftUnsafeLocalFunction = function (func) { 2621 if (typeof MSApp !== 'undefined' && MSApp.execUnsafeLocalFunction) { 2622 return function (arg0, arg1, arg2, arg3) { 2623 MSApp.execUnsafeLocalFunction(function () { 2624 return func(arg0, arg1, arg2, arg3); 2625 }); 2626 }; 2627 } else { 2628 return func; 2629 } 2630 }; 2631 2632 var reusableSVGContainer; 2633 /** 2634 * Set the innerHTML property of a node 2635 * 2636 * @param {DOMElement} node 2637 * @param {string} html 2638 * @internal 2639 */ 2640 2641 var setInnerHTML = createMicrosoftUnsafeLocalFunction(function (node, html) { 2642 if (node.namespaceURI === Namespaces.svg) { 2643 2644 if (!('innerHTML' in node)) { 2645 // IE does not have innerHTML for SVG nodes, so instead we inject the 2646 // new markup in a temp node and then move the child nodes across into 2647 // the target node 2648 reusableSVGContainer = reusableSVGContainer || document.createElement('div'); 2649 reusableSVGContainer.innerHTML = '<svg>' + html.valueOf().toString() + '</svg>'; 2650 var svgNode = reusableSVGContainer.firstChild; 2651 2652 while (node.firstChild) { 2653 node.removeChild(node.firstChild); 2654 } 2655 2656 while (svgNode.firstChild) { 2657 node.appendChild(svgNode.firstChild); 2658 } 2659 2660 return; 2661 } 2662 } 2663 2664 node.innerHTML = html; 2665 }); 2666 2667 /** 2668 * HTML nodeType values that represent the type of the node 2669 */ 2670 var ELEMENT_NODE = 1; 2671 var TEXT_NODE = 3; 2672 var COMMENT_NODE = 8; 2673 var DOCUMENT_NODE = 9; 2674 var DOCUMENT_FRAGMENT_NODE = 11; 2675 2676 /** 2677 * Set the textContent property of a node. For text updates, it's faster 2678 * to set the `nodeValue` of the Text node directly instead of using 2679 * `.textContent` which will remove the existing node and create a new one. 2680 * 2681 * @param {DOMElement} node 2682 * @param {string} text 2683 * @internal 2684 */ 2685 2686 var setTextContent = function (node, text) { 2687 if (text) { 2688 var firstChild = node.firstChild; 2689 2690 if (firstChild && firstChild === node.lastChild && firstChild.nodeType === TEXT_NODE) { 2691 firstChild.nodeValue = text; 2692 return; 2693 } 2694 } 2695 2696 node.textContent = text; 2697 }; 2698 2699 // Do not use the below two methods directly! 2700 // Instead use constants exported from DOMTopLevelEventTypes in ReactDOM. 2701 // (It is the only module that is allowed to access these methods.) 2702 function unsafeCastStringToDOMTopLevelType(topLevelType) { 2703 return topLevelType; 2704 } 2705 function unsafeCastDOMTopLevelTypeToString(topLevelType) { 2706 return topLevelType; 2707 } 2708 2709 /** 2710 * Generate a mapping of standard vendor prefixes using the defined style property and event name. 2711 * 2712 * @param {string} styleProp 2713 * @param {string} eventName 2714 * @returns {object} 2715 */ 2716 2717 function makePrefixMap(styleProp, eventName) { 2718 var prefixes = {}; 2719 prefixes[styleProp.toLowerCase()] = eventName.toLowerCase(); 2720 prefixes['Webkit' + styleProp] = 'webkit' + eventName; 2721 prefixes['Moz' + styleProp] = 'moz' + eventName; 2722 return prefixes; 2723 } 2724 /** 2725 * A list of event names to a configurable list of vendor prefixes. 2726 */ 2727 2728 2729 var vendorPrefixes = { 2730 animationend: makePrefixMap('Animation', 'AnimationEnd'), 2731 animationiteration: makePrefixMap('Animation', 'AnimationIteration'), 2732 animationstart: makePrefixMap('Animation', 'AnimationStart'), 2733 transitionend: makePrefixMap('Transition', 'TransitionEnd') 2734 }; 2735 /** 2736 * Event names that have already been detected and prefixed (if applicable). 2737 */ 2738 2739 var prefixedEventNames = {}; 2740 /** 2741 * Element to check for prefixes on. 2742 */ 2743 2744 var style = {}; 2745 /** 2746 * Bootstrap if a DOM exists. 2747 */ 2748 2749 if (canUseDOM) { 2750 style = document.createElement('div').style; // On some platforms, in particular some releases of Android 4.x, 2751 // the un-prefixed "animation" and "transition" properties are defined on the 2752 // style object but the events that fire will still be prefixed, so we need 2753 // to check if the un-prefixed events are usable, and if not remove them from the map. 2754 2755 if (!('AnimationEvent' in window)) { 2756 delete vendorPrefixes.animationend.animation; 2757 delete vendorPrefixes.animationiteration.animation; 2758 delete vendorPrefixes.animationstart.animation; 2759 } // Same as above 2760 2761 2762 if (!('TransitionEvent' in window)) { 2763 delete vendorPrefixes.transitionend.transition; 2764 } 2765 } 2766 /** 2767 * Attempts to determine the correct vendor prefixed event name. 2768 * 2769 * @param {string} eventName 2770 * @returns {string} 2771 */ 2772 2773 2774 function getVendorPrefixedEventName(eventName) { 2775 if (prefixedEventNames[eventName]) { 2776 return prefixedEventNames[eventName]; 2777 } else if (!vendorPrefixes[eventName]) { 2778 return eventName; 2779 } 2780 2781 var prefixMap = vendorPrefixes[eventName]; 2782 2783 for (var styleProp in prefixMap) { 2784 if (prefixMap.hasOwnProperty(styleProp) && styleProp in style) { 2785 return prefixedEventNames[eventName] = prefixMap[styleProp]; 2786 } 2787 } 2788 2789 return eventName; 2790 } 2791 2792 /** 2793 * To identify top level events in ReactDOM, we use constants defined by this 2794 * module. This is the only module that uses the unsafe* methods to express 2795 * that the constants actually correspond to the browser event names. This lets 2796 * us save some bundle size by avoiding a top level type -> event name map. 2797 * The rest of ReactDOM code should import top level types from this file. 2798 */ 2799 2800 var TOP_ABORT = unsafeCastStringToDOMTopLevelType('abort'); 2801 var TOP_ANIMATION_END = unsafeCastStringToDOMTopLevelType(getVendorPrefixedEventName('animationend')); 2802 var TOP_ANIMATION_ITERATION = unsafeCastStringToDOMTopLevelType(getVendorPrefixedEventName('animationiteration')); 2803 var TOP_ANIMATION_START = unsafeCastStringToDOMTopLevelType(getVendorPrefixedEventName('animationstart')); 2804 var TOP_BLUR = unsafeCastStringToDOMTopLevelType('blur'); 2805 var TOP_CAN_PLAY = unsafeCastStringToDOMTopLevelType('canplay'); 2806 var TOP_CAN_PLAY_THROUGH = unsafeCastStringToDOMTopLevelType('canplaythrough'); 2807 var TOP_CANCEL = unsafeCastStringToDOMTopLevelType('cancel'); 2808 var TOP_CHANGE = unsafeCastStringToDOMTopLevelType('change'); 2809 var TOP_CLICK = unsafeCastStringToDOMTopLevelType('click'); 2810 var TOP_CLOSE = unsafeCastStringToDOMTopLevelType('close'); 2811 var TOP_COMPOSITION_END = unsafeCastStringToDOMTopLevelType('compositionend'); 2812 var TOP_COMPOSITION_START = unsafeCastStringToDOMTopLevelType('compositionstart'); 2813 var TOP_COMPOSITION_UPDATE = unsafeCastStringToDOMTopLevelType('compositionupdate'); 2814 var TOP_CONTEXT_MENU = unsafeCastStringToDOMTopLevelType('contextmenu'); 2815 var TOP_COPY = unsafeCastStringToDOMTopLevelType('copy'); 2816 var TOP_CUT = unsafeCastStringToDOMTopLevelType('cut'); 2817 var TOP_DOUBLE_CLICK = unsafeCastStringToDOMTopLevelType('dblclick'); 2818 var TOP_AUX_CLICK = unsafeCastStringToDOMTopLevelType('auxclick'); 2819 var TOP_DRAG = unsafeCastStringToDOMTopLevelType('drag'); 2820 var TOP_DRAG_END = unsafeCastStringToDOMTopLevelType('dragend'); 2821 var TOP_DRAG_ENTER = unsafeCastStringToDOMTopLevelType('dragenter'); 2822 var TOP_DRAG_EXIT = unsafeCastStringToDOMTopLevelType('dragexit'); 2823 var TOP_DRAG_LEAVE = unsafeCastStringToDOMTopLevelType('dragleave'); 2824 var TOP_DRAG_OVER = unsafeCastStringToDOMTopLevelType('dragover'); 2825 var TOP_DRAG_START = unsafeCastStringToDOMTopLevelType('dragstart'); 2826 var TOP_DROP = unsafeCastStringToDOMTopLevelType('drop'); 2827 var TOP_DURATION_CHANGE = unsafeCastStringToDOMTopLevelType('durationchange'); 2828 var TOP_EMPTIED = unsafeCastStringToDOMTopLevelType('emptied'); 2829 var TOP_ENCRYPTED = unsafeCastStringToDOMTopLevelType('encrypted'); 2830 var TOP_ENDED = unsafeCastStringToDOMTopLevelType('ended'); 2831 var TOP_ERROR = unsafeCastStringToDOMTopLevelType('error'); 2832 var TOP_FOCUS = unsafeCastStringToDOMTopLevelType('focus'); 2833 var TOP_GOT_POINTER_CAPTURE = unsafeCastStringToDOMTopLevelType('gotpointercapture'); 2834 var TOP_INPUT = unsafeCastStringToDOMTopLevelType('input'); 2835 var TOP_INVALID = unsafeCastStringToDOMTopLevelType('invalid'); 2836 var TOP_KEY_DOWN = unsafeCastStringToDOMTopLevelType('keydown'); 2837 var TOP_KEY_PRESS = unsafeCastStringToDOMTopLevelType('keypress'); 2838 var TOP_KEY_UP = unsafeCastStringToDOMTopLevelType('keyup'); 2839 var TOP_LOAD = unsafeCastStringToDOMTopLevelType('load'); 2840 var TOP_LOAD_START = unsafeCastStringToDOMTopLevelType('loadstart'); 2841 var TOP_LOADED_DATA = unsafeCastStringToDOMTopLevelType('loadeddata'); 2842 var TOP_LOADED_METADATA = unsafeCastStringToDOMTopLevelType('loadedmetadata'); 2843 var TOP_LOST_POINTER_CAPTURE = unsafeCastStringToDOMTopLevelType('lostpointercapture'); 2844 var TOP_MOUSE_DOWN = unsafeCastStringToDOMTopLevelType('mousedown'); 2845 var TOP_MOUSE_MOVE = unsafeCastStringToDOMTopLevelType('mousemove'); 2846 var TOP_MOUSE_OUT = unsafeCastStringToDOMTopLevelType('mouseout'); 2847 var TOP_MOUSE_OVER = unsafeCastStringToDOMTopLevelType('mouseover'); 2848 var TOP_MOUSE_UP = unsafeCastStringToDOMTopLevelType('mouseup'); 2849 var TOP_PASTE = unsafeCastStringToDOMTopLevelType('paste'); 2850 var TOP_PAUSE = unsafeCastStringToDOMTopLevelType('pause'); 2851 var TOP_PLAY = unsafeCastStringToDOMTopLevelType('play'); 2852 var TOP_PLAYING = unsafeCastStringToDOMTopLevelType('playing'); 2853 var TOP_POINTER_CANCEL = unsafeCastStringToDOMTopLevelType('pointercancel'); 2854 var TOP_POINTER_DOWN = unsafeCastStringToDOMTopLevelType('pointerdown'); 2855 var TOP_POINTER_MOVE = unsafeCastStringToDOMTopLevelType('pointermove'); 2856 var TOP_POINTER_OUT = unsafeCastStringToDOMTopLevelType('pointerout'); 2857 var TOP_POINTER_OVER = unsafeCastStringToDOMTopLevelType('pointerover'); 2858 var TOP_POINTER_UP = unsafeCastStringToDOMTopLevelType('pointerup'); 2859 var TOP_PROGRESS = unsafeCastStringToDOMTopLevelType('progress'); 2860 var TOP_RATE_CHANGE = unsafeCastStringToDOMTopLevelType('ratechange'); 2861 var TOP_RESET = unsafeCastStringToDOMTopLevelType('reset'); 2862 var TOP_SCROLL = unsafeCastStringToDOMTopLevelType('scroll'); 2863 var TOP_SEEKED = unsafeCastStringToDOMTopLevelType('seeked'); 2864 var TOP_SEEKING = unsafeCastStringToDOMTopLevelType('seeking'); 2865 var TOP_SELECTION_CHANGE = unsafeCastStringToDOMTopLevelType('selectionchange'); 2866 var TOP_STALLED = unsafeCastStringToDOMTopLevelType('stalled'); 2867 var TOP_SUBMIT = unsafeCastStringToDOMTopLevelType('submit'); 2868 var TOP_SUSPEND = unsafeCastStringToDOMTopLevelType('suspend'); 2869 var TOP_TEXT_INPUT = unsafeCastStringToDOMTopLevelType('textInput'); 2870 var TOP_TIME_UPDATE = unsafeCastStringToDOMTopLevelType('timeupdate'); 2871 var TOP_TOGGLE = unsafeCastStringToDOMTopLevelType('toggle'); 2872 var TOP_TOUCH_CANCEL = unsafeCastStringToDOMTopLevelType('touchcancel'); 2873 var TOP_TOUCH_END = unsafeCastStringToDOMTopLevelType('touchend'); 2874 var TOP_TOUCH_MOVE = unsafeCastStringToDOMTopLevelType('touchmove'); 2875 var TOP_TOUCH_START = unsafeCastStringToDOMTopLevelType('touchstart'); 2876 var TOP_TRANSITION_END = unsafeCastStringToDOMTopLevelType(getVendorPrefixedEventName('transitionend')); 2877 var TOP_VOLUME_CHANGE = unsafeCastStringToDOMTopLevelType('volumechange'); 2878 var TOP_WAITING = unsafeCastStringToDOMTopLevelType('waiting'); 2879 var TOP_WHEEL = unsafeCastStringToDOMTopLevelType('wheel'); // List of events that need to be individually attached to media elements. 2880 // Note that events in this list will *not* be listened to at the top level 2881 // unless they're explicitly whitelisted in `ReactBrowserEventEmitter.listenTo`. 2882 2883 var mediaEventTypes = [TOP_ABORT, TOP_CAN_PLAY, TOP_CAN_PLAY_THROUGH, TOP_DURATION_CHANGE, TOP_EMPTIED, TOP_ENCRYPTED, TOP_ENDED, TOP_ERROR, TOP_LOADED_DATA, TOP_LOADED_METADATA, TOP_LOAD_START, TOP_PAUSE, TOP_PLAY, TOP_PLAYING, TOP_PROGRESS, TOP_RATE_CHANGE, TOP_SEEKED, TOP_SEEKING, TOP_STALLED, TOP_SUSPEND, TOP_TIME_UPDATE, TOP_VOLUME_CHANGE, TOP_WAITING]; 2884 function getRawEventName(topLevelType) { 2885 return unsafeCastDOMTopLevelTypeToString(topLevelType); 2886 } 2887 2888 var PossiblyWeakMap = typeof WeakMap === 'function' ? WeakMap : Map; // prettier-ignore 2889 2890 var elementListenerMap = new PossiblyWeakMap(); 2891 function getListenerMapForElement(element) { 2892 var listenerMap = elementListenerMap.get(element); 2893 2894 if (listenerMap === undefined) { 2895 listenerMap = new Map(); 2896 elementListenerMap.set(element, listenerMap); 2897 } 2898 2899 return listenerMap; 2900 } 2901 2902 /** 2903 * `ReactInstanceMap` maintains a mapping from a public facing stateful 2904 * instance (key) and the internal representation (value). This allows public 2905 * methods to accept the user facing instance as an argument and map them back 2906 * to internal methods. 2907 * 2908 * Note that this module is currently shared and assumed to be stateless. 2909 * If this becomes an actual Map, that will break. 2910 */ 2911 function get(key) { 2912 return key._reactInternalFiber; 2913 } 2914 function has$1(key) { 2915 return key._reactInternalFiber !== undefined; 2916 } 2917 function set(key, value) { 2918 key._reactInternalFiber = value; 2919 } 2920 2921 // Don't change these two values. They're used by React Dev Tools. 2922 var NoEffect = 2923 /* */ 2924 0; 2925 var PerformedWork = 2926 /* */ 2927 1; // You can change the rest (and add more). 2928 2929 var Placement = 2930 /* */ 2931 2; 2932 var Update = 2933 /* */ 2934 4; 2935 var PlacementAndUpdate = 2936 /* */ 2937 6; 2938 var Deletion = 2939 /* */ 2940 8; 2941 var ContentReset = 2942 /* */ 2943 16; 2944 var Callback = 2945 /* */ 2946 32; 2947 var DidCapture = 2948 /* */ 2949 64; 2950 var Ref = 2951 /* */ 2952 128; 2953 var Snapshot = 2954 /* */ 2955 256; 2956 var Passive = 2957 /* */ 2958 512; 2959 var Hydrating = 2960 /* */ 2961 1024; 2962 var HydratingAndUpdate = 2963 /* */ 2964 1028; // Passive & Update & Callback & Ref & Snapshot 2965 2966 var LifecycleEffectMask = 2967 /* */ 2968 932; // Union of all host effects 2969 2970 var HostEffectMask = 2971 /* */ 2972 2047; 2973 var Incomplete = 2974 /* */ 2975 2048; 2976 var ShouldCapture = 2977 /* */ 2978 4096; 2979 2980 var ReactCurrentOwner = ReactSharedInternals.ReactCurrentOwner; 2981 function getNearestMountedFiber(fiber) { 2982 var node = fiber; 2983 var nearestMounted = fiber; 2984 2985 if (!fiber.alternate) { 2986 // If there is no alternate, this might be a new tree that isn't inserted 2987 // yet. If it is, then it will have a pending insertion effect on it. 2988 var nextNode = node; 2989 2990 do { 2991 node = nextNode; 2992 2993 if ((node.effectTag & (Placement | Hydrating)) !== NoEffect) { 2994 // This is an insertion or in-progress hydration. The nearest possible 2995 // mounted fiber is the parent but we need to continue to figure out 2996 // if that one is still mounted. 2997 nearestMounted = node.return; 2998 } 2999 3000 nextNode = node.return; 3001 } while (nextNode); 3002 } else { 3003 while (node.return) { 3004 node = node.return; 3005 } 3006 } 3007 3008 if (node.tag === HostRoot) { 3009 // TODO: Check if this was a nested HostRoot when used with 3010 // renderContainerIntoSubtree. 3011 return nearestMounted; 3012 } // If we didn't hit the root, that means that we're in an disconnected tree 3013 // that has been unmounted. 3014 3015 3016 return null; 3017 } 3018 function getSuspenseInstanceFromFiber(fiber) { 3019 if (fiber.tag === SuspenseComponent) { 3020 var suspenseState = fiber.memoizedState; 3021 3022 if (suspenseState === null) { 3023 var current = fiber.alternate; 3024 3025 if (current !== null) { 3026 suspenseState = current.memoizedState; 3027 } 3028 } 3029 3030 if (suspenseState !== null) { 3031 return suspenseState.dehydrated; 3032 } 3033 } 3034 3035 return null; 3036 } 3037 function getContainerFromFiber(fiber) { 3038 return fiber.tag === HostRoot ? fiber.stateNode.containerInfo : null; 3039 } 3040 function isFiberMounted(fiber) { 3041 return getNearestMountedFiber(fiber) === fiber; 3042 } 3043 function isMounted(component) { 3044 { 3045 var owner = ReactCurrentOwner.current; 3046 3047 if (owner !== null && owner.tag === ClassComponent) { 3048 var ownerFiber = owner; 3049 var instance = ownerFiber.stateNode; 3050 3051 if (!instance._warnedAboutRefsInRender) { 3052 error('%s is accessing isMounted inside its render() function. ' + 'render() should be a pure function of props and state. It should ' + 'never access something that requires stale data from the previous ' + 'render, such as refs. Move this logic to componentDidMount and ' + 'componentDidUpdate instead.', getComponentName(ownerFiber.type) || 'A component'); 3053 } 3054 3055 instance._warnedAboutRefsInRender = true; 3056 } 3057 } 3058 3059 var fiber = get(component); 3060 3061 if (!fiber) { 3062 return false; 3063 } 3064 3065 return getNearestMountedFiber(fiber) === fiber; 3066 } 3067 3068 function assertIsMounted(fiber) { 3069 if (!(getNearestMountedFiber(fiber) === fiber)) { 3070 { 3071 throw Error( "Unable to find node on an unmounted component." ); 3072 } 3073 } 3074 } 3075 3076 function findCurrentFiberUsingSlowPath(fiber) { 3077 var alternate = fiber.alternate; 3078 3079 if (!alternate) { 3080 // If there is no alternate, then we only need to check if it is mounted. 3081 var nearestMounted = getNearestMountedFiber(fiber); 3082 3083 if (!(nearestMounted !== null)) { 3084 { 3085 throw Error( "Unable to find node on an unmounted component." ); 3086 } 3087 } 3088 3089 if (nearestMounted !== fiber) { 3090 return null; 3091 } 3092 3093 return fiber; 3094 } // If we have two possible branches, we'll walk backwards up to the root 3095 // to see what path the root points to. On the way we may hit one of the 3096 // special cases and we'll deal with them. 3097 3098 3099 var a = fiber; 3100 var b = alternate; 3101 3102 while (true) { 3103 var parentA = a.return; 3104 3105 if (parentA === null) { 3106 // We're at the root. 3107 break; 3108 } 3109 3110 var parentB = parentA.alternate; 3111 3112 if (parentB === null) { 3113 // There is no alternate. This is an unusual case. Currently, it only 3114 // happens when a Suspense component is hidden. An extra fragment fiber 3115 // is inserted in between the Suspense fiber and its children. Skip 3116 // over this extra fragment fiber and proceed to the next parent. 3117 var nextParent = parentA.return; 3118 3119 if (nextParent !== null) { 3120 a = b = nextParent; 3121 continue; 3122 } // If there's no parent, we're at the root. 3123 3124 3125 break; 3126 } // If both copies of the parent fiber point to the same child, we can 3127 // assume that the child is current. This happens when we bailout on low 3128 // priority: the bailed out fiber's child reuses the current child. 3129 3130 3131 if (parentA.child === parentB.child) { 3132 var child = parentA.child; 3133 3134 while (child) { 3135 if (child === a) { 3136 // We've determined that A is the current branch. 3137 assertIsMounted(parentA); 3138 return fiber; 3139 } 3140 3141 if (child === b) { 3142 // We've determined that B is the current branch. 3143 assertIsMounted(parentA); 3144 return alternate; 3145 } 3146 3147 child = child.sibling; 3148 } // We should never have an alternate for any mounting node. So the only 3149 // way this could possibly happen is if this was unmounted, if at all. 3150 3151 3152 { 3153 { 3154 throw Error( "Unable to find node on an unmounted component." ); 3155 } 3156 } 3157 } 3158 3159 if (a.return !== b.return) { 3160 // The return pointer of A and the return pointer of B point to different 3161 // fibers. We assume that return pointers never criss-cross, so A must 3162 // belong to the child set of A.return, and B must belong to the child 3163 // set of B.return. 3164 a = parentA; 3165 b = parentB; 3166 } else { 3167 // The return pointers point to the same fiber. We'll have to use the 3168 // default, slow path: scan the child sets of each parent alternate to see 3169 // which child belongs to which set. 3170 // 3171 // Search parent A's child set 3172 var didFindChild = false; 3173 var _child = parentA.child; 3174 3175 while (_child) { 3176 if (_child === a) { 3177 didFindChild = true; 3178 a = parentA; 3179 b = parentB; 3180 break; 3181 } 3182 3183 if (_child === b) { 3184 didFindChild = true; 3185 b = parentA; 3186 a = parentB; 3187 break; 3188 } 3189 3190 _child = _child.sibling; 3191 } 3192 3193 if (!didFindChild) { 3194 // Search parent B's child set 3195 _child = parentB.child; 3196 3197 while (_child) { 3198 if (_child === a) { 3199 didFindChild = true; 3200 a = parentB; 3201 b = parentA; 3202 break; 3203 } 3204 3205 if (_child === b) { 3206 didFindChild = true; 3207 b = parentB; 3208 a = parentA; 3209 break; 3210 } 3211 3212 _child = _child.sibling; 3213 } 3214 3215 if (!didFindChild) { 3216 { 3217 throw Error( "Child was not found in either parent set. This indicates a bug in React related to the return pointer. Please file an issue." ); 3218 } 3219 } 3220 } 3221 } 3222 3223 if (!(a.alternate === b)) { 3224 { 3225 throw Error( "Return fibers should always be each others' alternates. This error is likely caused by a bug in React. Please file an issue." ); 3226 } 3227 } 3228 } // If the root is not a host container, we're in a disconnected tree. I.e. 3229 // unmounted. 3230 3231 3232 if (!(a.tag === HostRoot)) { 3233 { 3234 throw Error( "Unable to find node on an unmounted component." ); 3235 } 3236 } 3237 3238 if (a.stateNode.current === a) { 3239 // We've determined that A is the current branch. 3240 return fiber; 3241 } // Otherwise B has to be current branch. 3242 3243 3244 return alternate; 3245 } 3246 function findCurrentHostFiber(parent) { 3247 var currentParent = findCurrentFiberUsingSlowPath(parent); 3248 3249 if (!currentParent) { 3250 return null; 3251 } // Next we'll drill down this component to find the first HostComponent/Text. 3252 3253 3254 var node = currentParent; 3255 3256 while (true) { 3257 if (node.tag === HostComponent || node.tag === HostText) { 3258 return node; 3259 } else if (node.child) { 3260 node.child.return = node; 3261 node = node.child; 3262 continue; 3263 } 3264 3265 if (node === currentParent) { 3266 return null; 3267 } 3268 3269 while (!node.sibling) { 3270 if (!node.return || node.return === currentParent) { 3271 return null; 3272 } 3273 3274 node = node.return; 3275 } 3276 3277 node.sibling.return = node.return; 3278 node = node.sibling; 3279 } // Flow needs the return null here, but ESLint complains about it. 3280 // eslint-disable-next-line no-unreachable 3281 3282 3283 return null; 3284 } 3285 function findCurrentHostFiberWithNoPortals(parent) { 3286 var currentParent = findCurrentFiberUsingSlowPath(parent); 3287 3288 if (!currentParent) { 3289 return null; 3290 } // Next we'll drill down this component to find the first HostComponent/Text. 3291 3292 3293 var node = currentParent; 3294 3295 while (true) { 3296 if (node.tag === HostComponent || node.tag === HostText || enableFundamentalAPI ) { 3297 return node; 3298 } else if (node.child && node.tag !== HostPortal) { 3299 node.child.return = node; 3300 node = node.child; 3301 continue; 3302 } 3303 3304 if (node === currentParent) { 3305 return null; 3306 } 3307 3308 while (!node.sibling) { 3309 if (!node.return || node.return === currentParent) { 3310 return null; 3311 } 3312 3313 node = node.return; 3314 } 3315 3316 node.sibling.return = node.return; 3317 node = node.sibling; 3318 } // Flow needs the return null here, but ESLint complains about it. 3319 // eslint-disable-next-line no-unreachable 3320 3321 3322 return null; 3323 } 3324 3325 /** 3326 * Accumulates items that must not be null or undefined into the first one. This 3327 * is used to conserve memory by avoiding array allocations, and thus sacrifices 3328 * API cleanness. Since `current` can be null before being passed in and not 3329 * null after this function, make sure to assign it back to `current`: 3330 * 3331 * `a = accumulateInto(a, b);` 3332 * 3333 * This API should be sparingly used. Try `accumulate` for something cleaner. 3334 * 3335 * @return {*|array<*>} An accumulation of items. 3336 */ 3337 3338 function accumulateInto(current, next) { 3339 if (!(next != null)) { 3340 { 3341 throw Error( "accumulateInto(...): Accumulated items must not be null or undefined." ); 3342 } 3343 } 3344 3345 if (current == null) { 3346 return next; 3347 } // Both are not empty. Warning: Never call x.concat(y) when you are not 3348 // certain that x is an Array (x could be a string with concat method). 3349 3350 3351 if (Array.isArray(current)) { 3352 if (Array.isArray(next)) { 3353 current.push.apply(current, next); 3354 return current; 3355 } 3356 3357 current.push(next); 3358 return current; 3359 } 3360 3361 if (Array.isArray(next)) { 3362 // A bit too dangerous to mutate `next`. 3363 return [current].concat(next); 3364 } 3365 3366 return [current, next]; 3367 } 3368 3369 /** 3370 * @param {array} arr an "accumulation" of items which is either an Array or 3371 * a single item. Useful when paired with the `accumulate` module. This is a 3372 * simple utility that allows us to reason about a collection of items, but 3373 * handling the case when there is exactly one item (and we do not need to 3374 * allocate an array). 3375 * @param {function} cb Callback invoked with each element or a collection. 3376 * @param {?} [scope] Scope used as `this` in a callback. 3377 */ 3378 function forEachAccumulated(arr, cb, scope) { 3379 if (Array.isArray(arr)) { 3380 arr.forEach(cb, scope); 3381 } else if (arr) { 3382 cb.call(scope, arr); 3383 } 3384 } 3385 3386 /** 3387 * Internal queue of events that have accumulated their dispatches and are 3388 * waiting to have their dispatches executed. 3389 */ 3390 3391 var eventQueue = null; 3392 /** 3393 * Dispatches an event and releases it back into the pool, unless persistent. 3394 * 3395 * @param {?object} event Synthetic event to be dispatched. 3396 * @private 3397 */ 3398 3399 var executeDispatchesAndRelease = function (event) { 3400 if (event) { 3401 executeDispatchesInOrder(event); 3402 3403 if (!event.isPersistent()) { 3404 event.constructor.release(event); 3405 } 3406 } 3407 }; 3408 3409 var executeDispatchesAndReleaseTopLevel = function (e) { 3410 return executeDispatchesAndRelease(e); 3411 }; 3412 3413 function runEventsInBatch(events) { 3414 if (events !== null) { 3415 eventQueue = accumulateInto(eventQueue, events); 3416 } // Set `eventQueue` to null before processing it so that we can tell if more 3417 // events get enqueued while processing. 3418 3419 3420 var processingEventQueue = eventQueue; 3421 eventQueue = null; 3422 3423 if (!processingEventQueue) { 3424 return; 3425 } 3426 3427 forEachAccumulated(processingEventQueue, executeDispatchesAndReleaseTopLevel); 3428 3429 if (!!eventQueue) { 3430 { 3431 throw Error( "processEventQueue(): Additional events were enqueued while processing an event queue. Support for this has not yet been implemented." ); 3432 } 3433 } // This would be a good time to rethrow if any of the event handlers threw. 3434 3435 3436 rethrowCaughtError(); 3437 } 3438 3439 /** 3440 * Gets the target node from a native browser event by accounting for 3441 * inconsistencies in browser DOM APIs. 3442 * 3443 * @param {object} nativeEvent Native browser event. 3444 * @return {DOMEventTarget} Target node. 3445 */ 3446 3447 function getEventTarget(nativeEvent) { 3448 // Fallback to nativeEvent.srcElement for IE9 3449 // https://github.com/facebook/react/issues/12506 3450 var target = nativeEvent.target || nativeEvent.srcElement || window; // Normalize SVG <use> element events #4963 3451 3452 if (target.correspondingUseElement) { 3453 target = target.correspondingUseElement; 3454 } // Safari may fire events on text nodes (Node.TEXT_NODE is 3). 3455 // @see http://www.quirksmode.org/js/events_properties.html 3456 3457 3458 return target.nodeType === TEXT_NODE ? target.parentNode : target; 3459 } 3460 3461 /** 3462 * Checks if an event is supported in the current execution environment. 3463 * 3464 * NOTE: This will not work correctly for non-generic events such as `change`, 3465 * `reset`, `load`, `error`, and `select`. 3466 * 3467 * Borrows from Modernizr. 3468 * 3469 * @param {string} eventNameSuffix Event name, e.g. "click". 3470 * @return {boolean} True if the event is supported. 3471 * @internal 3472 * @license Modernizr 3.0.0pre (Custom Build) | MIT 3473 */ 3474 3475 function isEventSupported(eventNameSuffix) { 3476 if (!canUseDOM) { 3477 return false; 3478 } 3479 3480 var eventName = 'on' + eventNameSuffix; 3481 var isSupported = eventName in document; 3482 3483 if (!isSupported) { 3484 var element = document.createElement('div'); 3485 element.setAttribute(eventName, 'return;'); 3486 isSupported = typeof element[eventName] === 'function'; 3487 } 3488 3489 return isSupported; 3490 } 3491 3492 /** 3493 * Summary of `DOMEventPluginSystem` event handling: 3494 * 3495 * - Top-level delegation is used to trap most native browser events. This 3496 * may only occur in the main thread and is the responsibility of 3497 * ReactDOMEventListener, which is injected and can therefore support 3498 * pluggable event sources. This is the only work that occurs in the main 3499 * thread. 3500 * 3501 * - We normalize and de-duplicate events to account for browser quirks. This 3502 * may be done in the worker thread. 3503 * 3504 * - Forward these native events (with the associated top-level type used to 3505 * trap it) to `EventPluginRegistry`, which in turn will ask plugins if they want 3506 * to extract any synthetic events. 3507 * 3508 * - The `EventPluginRegistry` will then process each event by annotating them with 3509 * "dispatches", a sequence of listeners and IDs that care about that event. 3510 * 3511 * - The `EventPluginRegistry` then dispatches the events. 3512 * 3513 * Overview of React and the event system: 3514 * 3515 * +------------+ . 3516 * | DOM | . 3517 * +------------+ . 3518 * | . 3519 * v . 3520 * +------------+ . 3521 * | ReactEvent | . 3522 * | Listener | . 3523 * +------------+ . +-----------+ 3524 * | . +--------+|SimpleEvent| 3525 * | . | |Plugin | 3526 * +-----|------+ . v +-----------+ 3527 * | | | . +--------------+ +------------+ 3528 * | +-----------.--->|PluginRegistry| | Event | 3529 * | | . | | +-----------+ | Propagators| 3530 * | ReactEvent | . | | |TapEvent | |------------| 3531 * | Emitter | . | |<---+|Plugin | |other plugin| 3532 * | | . | | +-----------+ | utilities | 3533 * | +-----------.--->| | +------------+ 3534 * | | | . +--------------+ 3535 * +-----|------+ . ^ +-----------+ 3536 * | . | |Enter/Leave| 3537 * + . +-------+|Plugin | 3538 * +-------------+ . +-----------+ 3539 * | application | . 3540 * |-------------| . 3541 * | | . 3542 * | | . 3543 * +-------------+ . 3544 * . 3545 * React Core . General Purpose Event Plugin System 3546 */ 3547 3548 var CALLBACK_BOOKKEEPING_POOL_SIZE = 10; 3549 var callbackBookkeepingPool = []; 3550 3551 function releaseTopLevelCallbackBookKeeping(instance) { 3552 instance.topLevelType = null; 3553 instance.nativeEvent = null; 3554 instance.targetInst = null; 3555 instance.ancestors.length = 0; 3556 3557 if (callbackBookkeepingPool.length < CALLBACK_BOOKKEEPING_POOL_SIZE) { 3558 callbackBookkeepingPool.push(instance); 3559 } 3560 } // Used to store ancestor hierarchy in top level callback 3561 3562 3563 function getTopLevelCallbackBookKeeping(topLevelType, nativeEvent, targetInst, eventSystemFlags) { 3564 if (callbackBookkeepingPool.length) { 3565 var instance = callbackBookkeepingPool.pop(); 3566 instance.topLevelType = topLevelType; 3567 instance.eventSystemFlags = eventSystemFlags; 3568 instance.nativeEvent = nativeEvent; 3569 instance.targetInst = targetInst; 3570 return instance; 3571 } 3572 3573 return { 3574 topLevelType: topLevelType, 3575 eventSystemFlags: eventSystemFlags, 3576 nativeEvent: nativeEvent, 3577 targetInst: targetInst, 3578 ancestors: [] 3579 }; 3580 } 3581 /** 3582 * Find the deepest React component completely containing the root of the 3583 * passed-in instance (for use when entire React trees are nested within each 3584 * other). If React trees are not nested, returns null. 3585 */ 3586 3587 3588 function findRootContainerNode(inst) { 3589 if (inst.tag === HostRoot) { 3590 return inst.stateNode.containerInfo; 3591 } // TODO: It may be a good idea to cache this to prevent unnecessary DOM 3592 // traversal, but caching is difficult to do correctly without using a 3593 // mutation observer to listen for all DOM changes. 3594 3595 3596 while (inst.return) { 3597 inst = inst.return; 3598 } 3599 3600 if (inst.tag !== HostRoot) { 3601 // This can happen if we're in a detached tree. 3602 return null; 3603 } 3604 3605 return inst.stateNode.containerInfo; 3606 } 3607 /** 3608 * Allows registered plugins an opportunity to extract events from top-level 3609 * native browser events. 3610 * 3611 * @return {*} An accumulation of synthetic events. 3612 * @internal 3613 */ 3614 3615 3616 function extractPluginEvents(topLevelType, targetInst, nativeEvent, nativeEventTarget, eventSystemFlags) { 3617 var events = null; 3618 3619 for (var i = 0; i < plugins.length; i++) { 3620 // Not every plugin in the ordering may be loaded at runtime. 3621 var possiblePlugin = plugins[i]; 3622 3623 if (possiblePlugin) { 3624 var extractedEvents = possiblePlugin.extractEvents(topLevelType, targetInst, nativeEvent, nativeEventTarget, eventSystemFlags); 3625 3626 if (extractedEvents) { 3627 events = accumulateInto(events, extractedEvents); 3628 } 3629 } 3630 } 3631 3632 return events; 3633 } 3634 3635 function runExtractedPluginEventsInBatch(topLevelType, targetInst, nativeEvent, nativeEventTarget, eventSystemFlags) { 3636 var events = extractPluginEvents(topLevelType, targetInst, nativeEvent, nativeEventTarget, eventSystemFlags); 3637 runEventsInBatch(events); 3638 } 3639 3640 function handleTopLevel(bookKeeping) { 3641 var targetInst = bookKeeping.targetInst; // Loop through the hierarchy, in case there's any nested components. 3642 // It's important that we build the array of ancestors before calling any 3643 // event handlers, because event handlers can modify the DOM, leading to 3644 // inconsistencies with ReactMount's node cache. See #1105. 3645 3646 var ancestor = targetInst; 3647 3648 do { 3649 if (!ancestor) { 3650 var ancestors = bookKeeping.ancestors; 3651 ancestors.push(ancestor); 3652 break; 3653 } 3654 3655 var root = findRootContainerNode(ancestor); 3656 3657 if (!root) { 3658 break; 3659 } 3660 3661 var tag = ancestor.tag; 3662 3663 if (tag === HostComponent || tag === HostText) { 3664 bookKeeping.ancestors.push(ancestor); 3665 } 3666 3667 ancestor = getClosestInstanceFromNode(root); 3668 } while (ancestor); 3669 3670 for (var i = 0; i < bookKeeping.ancestors.length; i++) { 3671 targetInst = bookKeeping.ancestors[i]; 3672 var eventTarget = getEventTarget(bookKeeping.nativeEvent); 3673 var topLevelType = bookKeeping.topLevelType; 3674 var nativeEvent = bookKeeping.nativeEvent; 3675 var eventSystemFlags = bookKeeping.eventSystemFlags; // If this is the first ancestor, we mark it on the system flags 3676 3677 if (i === 0) { 3678 eventSystemFlags |= IS_FIRST_ANCESTOR; 3679 } 3680 3681 runExtractedPluginEventsInBatch(topLevelType, targetInst, nativeEvent, eventTarget, eventSystemFlags); 3682 } 3683 } 3684 3685 function dispatchEventForLegacyPluginEventSystem(topLevelType, eventSystemFlags, nativeEvent, targetInst) { 3686 var bookKeeping = getTopLevelCallbackBookKeeping(topLevelType, nativeEvent, targetInst, eventSystemFlags); 3687 3688 try { 3689 // Event queue being processed in the same cycle allows 3690 // `preventDefault`. 3691 batchedEventUpdates(handleTopLevel, bookKeeping); 3692 } finally { 3693 releaseTopLevelCallbackBookKeeping(bookKeeping); 3694 } 3695 } 3696 /** 3697 * We listen for bubbled touch events on the document object. 3698 * 3699 * Firefox v8.01 (and possibly others) exhibited strange behavior when 3700 * mounting `onmousemove` events at some node that was not the document 3701 * element. The symptoms were that if your mouse is not moving over something 3702 * contained within that mount point (for example on the background) the 3703 * top-level listeners for `onmousemove` won't be called. However, if you 3704 * register the `mousemove` on the document object, then it will of course 3705 * catch all `mousemove`s. This along with iOS quirks, justifies restricting 3706 * top-level listeners to the document object only, at least for these 3707 * movement types of events and possibly all events. 3708 * 3709 * @see http://www.quirksmode.org/blog/archives/2010/09/click_event_del.html 3710 * 3711 * Also, `keyup`/`keypress`/`keydown` do not bubble to the window on IE, but 3712 * they bubble to document. 3713 * 3714 * @param {string} registrationName Name of listener (e.g. `onClick`). 3715 * @param {object} mountAt Container where to mount the listener 3716 */ 3717 3718 function legacyListenToEvent(registrationName, mountAt) { 3719 var listenerMap = getListenerMapForElement(mountAt); 3720 var dependencies = registrationNameDependencies[registrationName]; 3721 3722 for (var i = 0; i < dependencies.length; i++) { 3723 var dependency = dependencies[i]; 3724 legacyListenToTopLevelEvent(dependency, mountAt, listenerMap); 3725 } 3726 } 3727 function legacyListenToTopLevelEvent(topLevelType, mountAt, listenerMap) { 3728 if (!listenerMap.has(topLevelType)) { 3729 switch (topLevelType) { 3730 case TOP_SCROLL: 3731 trapCapturedEvent(TOP_SCROLL, mountAt); 3732 break; 3733 3734 case TOP_FOCUS: 3735 case TOP_BLUR: 3736 trapCapturedEvent(TOP_FOCUS, mountAt); 3737 trapCapturedEvent(TOP_BLUR, mountAt); // We set the flag for a single dependency later in this function, 3738 // but this ensures we mark both as attached rather than just one. 3739 3740 listenerMap.set(TOP_BLUR, null); 3741 listenerMap.set(TOP_FOCUS, null); 3742 break; 3743 3744 case TOP_CANCEL: 3745 case TOP_CLOSE: 3746 if (isEventSupported(getRawEventName(topLevelType))) { 3747 trapCapturedEvent(topLevelType, mountAt); 3748 } 3749 3750 break; 3751 3752 case TOP_INVALID: 3753 case TOP_SUBMIT: 3754 case TOP_RESET: 3755 // We listen to them on the target DOM elements. 3756 // Some of them bubble so we don't want them to fire twice. 3757 break; 3758 3759 default: 3760 // By default, listen on the top level to all non-media events. 3761 // Media events don't bubble so adding the listener wouldn't do anything. 3762 var isMediaEvent = mediaEventTypes.indexOf(topLevelType) !== -1; 3763 3764 if (!isMediaEvent) { 3765 trapBubbledEvent(topLevelType, mountAt); 3766 } 3767 3768 break; 3769 } 3770 3771 listenerMap.set(topLevelType, null); 3772 } 3773 } 3774 function isListeningToAllDependencies(registrationName, mountAt) { 3775 var listenerMap = getListenerMapForElement(mountAt); 3776 var dependencies = registrationNameDependencies[registrationName]; 3777 3778 for (var i = 0; i < dependencies.length; i++) { 3779 var dependency = dependencies[i]; 3780 3781 if (!listenerMap.has(dependency)) { 3782 return false; 3783 } 3784 } 3785 3786 return true; 3787 } 3788 3789 var attemptUserBlockingHydration; 3790 function setAttemptUserBlockingHydration(fn) { 3791 attemptUserBlockingHydration = fn; 3792 } 3793 var attemptContinuousHydration; 3794 function setAttemptContinuousHydration(fn) { 3795 attemptContinuousHydration = fn; 3796 } 3797 var attemptHydrationAtCurrentPriority; 3798 function setAttemptHydrationAtCurrentPriority(fn) { 3799 attemptHydrationAtCurrentPriority = fn; 3800 } // TODO: Upgrade this definition once we're on a newer version of Flow that 3801 var hasScheduledReplayAttempt = false; // The queue of discrete events to be replayed. 3802 3803 var queuedDiscreteEvents = []; // Indicates if any continuous event targets are non-null for early bailout. 3804 // if the last target was dehydrated. 3805 3806 var queuedFocus = null; 3807 var queuedDrag = null; 3808 var queuedMouse = null; // For pointer events there can be one latest event per pointerId. 3809 3810 var queuedPointers = new Map(); 3811 var queuedPointerCaptures = new Map(); // We could consider replaying selectionchange and touchmoves too. 3812 3813 var queuedExplicitHydrationTargets = []; 3814 function hasQueuedDiscreteEvents() { 3815 return queuedDiscreteEvents.length > 0; 3816 } 3817 var discreteReplayableEvents = [TOP_MOUSE_DOWN, TOP_MOUSE_UP, TOP_TOUCH_CANCEL, TOP_TOUCH_END, TOP_TOUCH_START, TOP_AUX_CLICK, TOP_DOUBLE_CLICK, TOP_POINTER_CANCEL, TOP_POINTER_DOWN, TOP_POINTER_UP, TOP_DRAG_END, TOP_DRAG_START, TOP_DROP, TOP_COMPOSITION_END, TOP_COMPOSITION_START, TOP_KEY_DOWN, TOP_KEY_PRESS, TOP_KEY_UP, TOP_INPUT, TOP_TEXT_INPUT, TOP_CLOSE, TOP_CANCEL, TOP_COPY, TOP_CUT, TOP_PASTE, TOP_CLICK, TOP_CHANGE, TOP_CONTEXT_MENU, TOP_RESET, TOP_SUBMIT]; 3818 var continuousReplayableEvents = [TOP_FOCUS, TOP_BLUR, TOP_DRAG_ENTER, TOP_DRAG_LEAVE, TOP_MOUSE_OVER, TOP_MOUSE_OUT, TOP_POINTER_OVER, TOP_POINTER_OUT, TOP_GOT_POINTER_CAPTURE, TOP_LOST_POINTER_CAPTURE]; 3819 function isReplayableDiscreteEvent(eventType) { 3820 return discreteReplayableEvents.indexOf(eventType) > -1; 3821 } 3822 3823 function trapReplayableEventForDocument(topLevelType, document, listenerMap) { 3824 legacyListenToTopLevelEvent(topLevelType, document, listenerMap); 3825 } 3826 3827 function eagerlyTrapReplayableEvents(container, document) { 3828 var listenerMapForDoc = getListenerMapForElement(document); // Discrete 3829 3830 discreteReplayableEvents.forEach(function (topLevelType) { 3831 trapReplayableEventForDocument(topLevelType, document, listenerMapForDoc); 3832 }); // Continuous 3833 3834 continuousReplayableEvents.forEach(function (topLevelType) { 3835 trapReplayableEventForDocument(topLevelType, document, listenerMapForDoc); 3836 }); 3837 } 3838 3839 function createQueuedReplayableEvent(blockedOn, topLevelType, eventSystemFlags, container, nativeEvent) { 3840 return { 3841 blockedOn: blockedOn, 3842 topLevelType: topLevelType, 3843 eventSystemFlags: eventSystemFlags | IS_REPLAYED, 3844 nativeEvent: nativeEvent, 3845 container: container 3846 }; 3847 } 3848 3849 function queueDiscreteEvent(blockedOn, topLevelType, eventSystemFlags, container, nativeEvent) { 3850 var queuedEvent = createQueuedReplayableEvent(blockedOn, topLevelType, eventSystemFlags, container, nativeEvent); 3851 queuedDiscreteEvents.push(queuedEvent); 3852 } // Resets the replaying for this type of continuous event to no event. 3853 3854 function clearIfContinuousEvent(topLevelType, nativeEvent) { 3855 switch (topLevelType) { 3856 case TOP_FOCUS: 3857 case TOP_BLUR: 3858 queuedFocus = null; 3859 break; 3860 3861 case TOP_DRAG_ENTER: 3862 case TOP_DRAG_LEAVE: 3863 queuedDrag = null; 3864 break; 3865 3866 case TOP_MOUSE_OVER: 3867 case TOP_MOUSE_OUT: 3868 queuedMouse = null; 3869 break; 3870 3871 case TOP_POINTER_OVER: 3872 case TOP_POINTER_OUT: 3873 { 3874 var pointerId = nativeEvent.pointerId; 3875 queuedPointers.delete(pointerId); 3876 break; 3877 } 3878 3879 case TOP_GOT_POINTER_CAPTURE: 3880 case TOP_LOST_POINTER_CAPTURE: 3881 { 3882 var _pointerId = nativeEvent.pointerId; 3883 queuedPointerCaptures.delete(_pointerId); 3884 break; 3885 } 3886 } 3887 } 3888 3889 function accumulateOrCreateContinuousQueuedReplayableEvent(existingQueuedEvent, blockedOn, topLevelType, eventSystemFlags, container, nativeEvent) { 3890 if (existingQueuedEvent === null || existingQueuedEvent.nativeEvent !== nativeEvent) { 3891 var queuedEvent = createQueuedReplayableEvent(blockedOn, topLevelType, eventSystemFlags, container, nativeEvent); 3892 3893 if (blockedOn !== null) { 3894 var _fiber2 = getInstanceFromNode$1(blockedOn); 3895 3896 if (_fiber2 !== null) { 3897 // Attempt to increase the priority of this target. 3898 attemptContinuousHydration(_fiber2); 3899 } 3900 } 3901 3902 return queuedEvent; 3903 } // If we have already queued this exact event, then it's because 3904 // the different event systems have different DOM event listeners. 3905 // We can accumulate the flags and store a single event to be 3906 // replayed. 3907 3908 3909 existingQueuedEvent.eventSystemFlags |= eventSystemFlags; 3910 return existingQueuedEvent; 3911 } 3912 3913 function queueIfContinuousEvent(blockedOn, topLevelType, eventSystemFlags, container, nativeEvent) { 3914 // These set relatedTarget to null because the replayed event will be treated as if we 3915 // moved from outside the window (no target) onto the target once it hydrates. 3916 // Instead of mutating we could clone the event. 3917 switch (topLevelType) { 3918 case TOP_FOCUS: 3919 { 3920 var focusEvent = nativeEvent; 3921 queuedFocus = accumulateOrCreateContinuousQueuedReplayableEvent(queuedFocus, blockedOn, topLevelType, eventSystemFlags, container, focusEvent); 3922 return true; 3923 } 3924 3925 case TOP_DRAG_ENTER: 3926 { 3927 var dragEvent = nativeEvent; 3928 queuedDrag = accumulateOrCreateContinuousQueuedReplayableEvent(queuedDrag, blockedOn, topLevelType, eventSystemFlags, container, dragEvent); 3929 return true; 3930 } 3931 3932 case TOP_MOUSE_OVER: 3933 { 3934 var mouseEvent = nativeEvent; 3935 queuedMouse = accumulateOrCreateContinuousQueuedReplayableEvent(queuedMouse, blockedOn, topLevelType, eventSystemFlags, container, mouseEvent); 3936 return true; 3937 } 3938 3939 case TOP_POINTER_OVER: 3940 { 3941 var pointerEvent = nativeEvent; 3942 var pointerId = pointerEvent.pointerId; 3943 queuedPointers.set(pointerId, accumulateOrCreateContinuousQueuedReplayableEvent(queuedPointers.get(pointerId) || null, blockedOn, topLevelType, eventSystemFlags, container, pointerEvent)); 3944 return true; 3945 } 3946 3947 case TOP_GOT_POINTER_CAPTURE: 3948 { 3949 var _pointerEvent = nativeEvent; 3950 var _pointerId2 = _pointerEvent.pointerId; 3951 queuedPointerCaptures.set(_pointerId2, accumulateOrCreateContinuousQueuedReplayableEvent(queuedPointerCaptures.get(_pointerId2) || null, blockedOn, topLevelType, eventSystemFlags, container, _pointerEvent)); 3952 return true; 3953 } 3954 } 3955 3956 return false; 3957 } // Check if this target is unblocked. Returns true if it's unblocked. 3958 3959 function attemptExplicitHydrationTarget(queuedTarget) { 3960 // TODO: This function shares a lot of logic with attemptToDispatchEvent. 3961 // Try to unify them. It's a bit tricky since it would require two return 3962 // values. 3963 var targetInst = getClosestInstanceFromNode(queuedTarget.target); 3964 3965 if (targetInst !== null) { 3966 var nearestMounted = getNearestMountedFiber(targetInst); 3967 3968 if (nearestMounted !== null) { 3969 var tag = nearestMounted.tag; 3970 3971 if (tag === SuspenseComponent) { 3972 var instance = getSuspenseInstanceFromFiber(nearestMounted); 3973 3974 if (instance !== null) { 3975 // We're blocked on hydrating this boundary. 3976 // Increase its priority. 3977 queuedTarget.blockedOn = instance; 3978 unstable_runWithPriority(queuedTarget.priority, function () { 3979 attemptHydrationAtCurrentPriority(nearestMounted); 3980 }); 3981 return; 3982 } 3983 } else if (tag === HostRoot) { 3984 var root = nearestMounted.stateNode; 3985 3986 if (root.hydrate) { 3987 queuedTarget.blockedOn = getContainerFromFiber(nearestMounted); // We don't currently have a way to increase the priority of 3988 // a root other than sync. 3989 3990 return; 3991 } 3992 } 3993 } 3994 } 3995 3996 queuedTarget.blockedOn = null; 3997 } 3998 3999 function attemptReplayContinuousQueuedEvent(queuedEvent) { 4000 if (queuedEvent.blockedOn !== null) { 4001 return false; 4002 } 4003 4004 var nextBlockedOn = attemptToDispatchEvent(queuedEvent.topLevelType, queuedEvent.eventSystemFlags, queuedEvent.container, queuedEvent.nativeEvent); 4005 4006 if (nextBlockedOn !== null) { 4007 // We're still blocked. Try again later. 4008 var _fiber3 = getInstanceFromNode$1(nextBlockedOn); 4009 4010 if (_fiber3 !== null) { 4011 attemptContinuousHydration(_fiber3); 4012 } 4013 4014 queuedEvent.blockedOn = nextBlockedOn; 4015 return false; 4016 } 4017 4018 return true; 4019 } 4020 4021 function attemptReplayContinuousQueuedEventInMap(queuedEvent, key, map) { 4022 if (attemptReplayContinuousQueuedEvent(queuedEvent)) { 4023 map.delete(key); 4024 } 4025 } 4026 4027 function replayUnblockedEvents() { 4028 hasScheduledReplayAttempt = false; // First replay discrete events. 4029 4030 while (queuedDiscreteEvents.length > 0) { 4031 var nextDiscreteEvent = queuedDiscreteEvents[0]; 4032 4033 if (nextDiscreteEvent.blockedOn !== null) { 4034 // We're still blocked. 4035 // Increase the priority of this boundary to unblock 4036 // the next discrete event. 4037 var _fiber4 = getInstanceFromNode$1(nextDiscreteEvent.blockedOn); 4038 4039 if (_fiber4 !== null) { 4040 attemptUserBlockingHydration(_fiber4); 4041 } 4042 4043 break; 4044 } 4045 4046 var nextBlockedOn = attemptToDispatchEvent(nextDiscreteEvent.topLevelType, nextDiscreteEvent.eventSystemFlags, nextDiscreteEvent.container, nextDiscreteEvent.nativeEvent); 4047 4048 if (nextBlockedOn !== null) { 4049 // We're still blocked. Try again later. 4050 nextDiscreteEvent.blockedOn = nextBlockedOn; 4051 } else { 4052 // We've successfully replayed the first event. Let's try the next one. 4053 queuedDiscreteEvents.shift(); 4054 } 4055 } // Next replay any continuous events. 4056 4057 4058 if (queuedFocus !== null && attemptReplayContinuousQueuedEvent(queuedFocus)) { 4059 queuedFocus = null; 4060 } 4061 4062 if (queuedDrag !== null && attemptReplayContinuousQueuedEvent(queuedDrag)) { 4063 queuedDrag = null; 4064 } 4065 4066 if (queuedMouse !== null && attemptReplayContinuousQueuedEvent(queuedMouse)) { 4067 queuedMouse = null; 4068 } 4069 4070 queuedPointers.forEach(attemptReplayContinuousQueuedEventInMap); 4071 queuedPointerCaptures.forEach(attemptReplayContinuousQueuedEventInMap); 4072 } 4073 4074 function scheduleCallbackIfUnblocked(queuedEvent, unblocked) { 4075 if (queuedEvent.blockedOn === unblocked) { 4076 queuedEvent.blockedOn = null; 4077 4078 if (!hasScheduledReplayAttempt) { 4079 hasScheduledReplayAttempt = true; // Schedule a callback to attempt replaying as many events as are 4080 // now unblocked. This first might not actually be unblocked yet. 4081 // We could check it early to avoid scheduling an unnecessary callback. 4082 4083 unstable_scheduleCallback(unstable_NormalPriority, replayUnblockedEvents); 4084 } 4085 } 4086 } 4087 4088 function retryIfBlockedOn(unblocked) { 4089 // Mark anything that was blocked on this as no longer blocked 4090 // and eligible for a replay. 4091 if (queuedDiscreteEvents.length > 0) { 4092 scheduleCallbackIfUnblocked(queuedDiscreteEvents[0], unblocked); // This is a exponential search for each boundary that commits. I think it's 4093 // worth it because we expect very few discrete events to queue up and once 4094 // we are actually fully unblocked it will be fast to replay them. 4095 4096 for (var i = 1; i < queuedDiscreteEvents.length; i++) { 4097 var queuedEvent = queuedDiscreteEvents[i]; 4098 4099 if (queuedEvent.blockedOn === unblocked) { 4100 queuedEvent.blockedOn = null; 4101 } 4102 } 4103 } 4104 4105 if (queuedFocus !== null) { 4106 scheduleCallbackIfUnblocked(queuedFocus, unblocked); 4107 } 4108 4109 if (queuedDrag !== null) { 4110 scheduleCallbackIfUnblocked(queuedDrag, unblocked); 4111 } 4112 4113 if (queuedMouse !== null) { 4114 scheduleCallbackIfUnblocked(queuedMouse, unblocked); 4115 } 4116 4117 var unblock = function (queuedEvent) { 4118 return scheduleCallbackIfUnblocked(queuedEvent, unblocked); 4119 }; 4120 4121 queuedPointers.forEach(unblock); 4122 queuedPointerCaptures.forEach(unblock); 4123 4124 for (var _i = 0; _i < queuedExplicitHydrationTargets.length; _i++) { 4125 var queuedTarget = queuedExplicitHydrationTargets[_i]; 4126 4127 if (queuedTarget.blockedOn === unblocked) { 4128 queuedTarget.blockedOn = null; 4129 } 4130 } 4131 4132 while (queuedExplicitHydrationTargets.length > 0) { 4133 var nextExplicitTarget = queuedExplicitHydrationTargets[0]; 4134 4135 if (nextExplicitTarget.blockedOn !== null) { 4136 // We're still blocked. 4137 break; 4138 } else { 4139 attemptExplicitHydrationTarget(nextExplicitTarget); 4140 4141 if (nextExplicitTarget.blockedOn === null) { 4142 // We're unblocked. 4143 queuedExplicitHydrationTargets.shift(); 4144 } 4145 } 4146 } 4147 } 4148 4149 function addEventBubbleListener(element, eventType, listener) { 4150 element.addEventListener(eventType, listener, false); 4151 } 4152 function addEventCaptureListener(element, eventType, listener) { 4153 element.addEventListener(eventType, listener, true); 4154 } 4155 4156 // do it in two places, which duplicates logic 4157 // and increases the bundle size, we do it all 4158 // here once. If we remove or refactor the 4159 // SimpleEventPlugin, we should also remove or 4160 // update the below line. 4161 4162 var simpleEventPluginEventTypes = {}; 4163 var topLevelEventsToDispatchConfig = new Map(); 4164 var eventPriorities = new Map(); // We store most of the events in this module in pairs of two strings so we can re-use 4165 // the code required to apply the same logic for event prioritization and that of the 4166 // SimpleEventPlugin. This complicates things slightly, but the aim is to reduce code 4167 // duplication (for which there would be quite a bit). For the events that are not needed 4168 // for the SimpleEventPlugin (otherDiscreteEvents) we process them separately as an 4169 // array of top level events. 4170 // Lastly, we ignore prettier so we can keep the formatting sane. 4171 // prettier-ignore 4172 4173 var discreteEventPairsForSimpleEventPlugin = [TOP_BLUR, 'blur', TOP_CANCEL, 'cancel', TOP_CLICK, 'click', TOP_CLOSE, 'close', TOP_CONTEXT_MENU, 'contextMenu', TOP_COPY, 'copy', TOP_CUT, 'cut', TOP_AUX_CLICK, 'auxClick', TOP_DOUBLE_CLICK, 'doubleClick', TOP_DRAG_END, 'dragEnd', TOP_DRAG_START, 'dragStart', TOP_DROP, 'drop', TOP_FOCUS, 'focus', TOP_INPUT, 'input', TOP_INVALID, 'invalid', TOP_KEY_DOWN, 'keyDown', TOP_KEY_PRESS, 'keyPress', TOP_KEY_UP, 'keyUp', TOP_MOUSE_DOWN, 'mouseDown', TOP_MOUSE_UP, 'mouseUp', TOP_PASTE, 'paste', TOP_PAUSE, 'pause', TOP_PLAY, 'play', TOP_POINTER_CANCEL, 'pointerCancel', TOP_POINTER_DOWN, 'pointerDown', TOP_POINTER_UP, 'pointerUp', TOP_RATE_CHANGE, 'rateChange', TOP_RESET, 'reset', TOP_SEEKED, 'seeked', TOP_SUBMIT, 'submit', TOP_TOUCH_CANCEL, 'touchCancel', TOP_TOUCH_END, 'touchEnd', TOP_TOUCH_START, 'touchStart', TOP_VOLUME_CHANGE, 'volumeChange']; 4174 var otherDiscreteEvents = [TOP_CHANGE, TOP_SELECTION_CHANGE, TOP_TEXT_INPUT, TOP_COMPOSITION_START, TOP_COMPOSITION_END, TOP_COMPOSITION_UPDATE]; // prettier-ignore 4175 4176 var userBlockingPairsForSimpleEventPlugin = [TOP_DRAG, 'drag', TOP_DRAG_ENTER, 'dragEnter', TOP_DRAG_EXIT, 'dragExit', TOP_DRAG_LEAVE, 'dragLeave', TOP_DRAG_OVER, 'dragOver', TOP_MOUSE_MOVE, 'mouseMove', TOP_MOUSE_OUT, 'mouseOut', TOP_MOUSE_OVER, 'mouseOver', TOP_POINTER_MOVE, 'pointerMove', TOP_POINTER_OUT, 'pointerOut', TOP_POINTER_OVER, 'pointerOver', TOP_SCROLL, 'scroll', TOP_TOGGLE, 'toggle', TOP_TOUCH_MOVE, 'touchMove', TOP_WHEEL, 'wheel']; // prettier-ignore 4177 4178 var continuousPairsForSimpleEventPlugin = [TOP_ABORT, 'abort', TOP_ANIMATION_END, 'animationEnd', TOP_ANIMATION_ITERATION, 'animationIteration', TOP_ANIMATION_START, 'animationStart', TOP_CAN_PLAY, 'canPlay', TOP_CAN_PLAY_THROUGH, 'canPlayThrough', TOP_DURATION_CHANGE, 'durationChange', TOP_EMPTIED, 'emptied', TOP_ENCRYPTED, 'encrypted', TOP_ENDED, 'ended', TOP_ERROR, 'error', TOP_GOT_POINTER_CAPTURE, 'gotPointerCapture', TOP_LOAD, 'load', TOP_LOADED_DATA, 'loadedData', TOP_LOADED_METADATA, 'loadedMetadata', TOP_LOAD_START, 'loadStart', TOP_LOST_POINTER_CAPTURE, 'lostPointerCapture', TOP_PLAYING, 'playing', TOP_PROGRESS, 'progress', TOP_SEEKING, 'seeking', TOP_STALLED, 'stalled', TOP_SUSPEND, 'suspend', TOP_TIME_UPDATE, 'timeUpdate', TOP_TRANSITION_END, 'transitionEnd', TOP_WAITING, 'waiting']; 4179 /** 4180 * Turns 4181 * ['abort', ...] 4182 * into 4183 * eventTypes = { 4184 * 'abort': { 4185 * phasedRegistrationNames: { 4186 * bubbled: 'onAbort', 4187 * captured: 'onAbortCapture', 4188 * }, 4189 * dependencies: [TOP_ABORT], 4190 * }, 4191 * ... 4192 * }; 4193 * topLevelEventsToDispatchConfig = new Map([ 4194 * [TOP_ABORT, { sameConfig }], 4195 * ]); 4196 */ 4197 4198 function processSimpleEventPluginPairsByPriority(eventTypes, priority) { 4199 // As the event types are in pairs of two, we need to iterate 4200 // through in twos. The events are in pairs of two to save code 4201 // and improve init perf of processing this array, as it will 4202 // result in far fewer object allocations and property accesses 4203 // if we only use three arrays to process all the categories of 4204 // instead of tuples. 4205 for (var i = 0; i < eventTypes.length; i += 2) { 4206 var topEvent = eventTypes[i]; 4207 var event = eventTypes[i + 1]; 4208 var capitalizedEvent = event[0].toUpperCase() + event.slice(1); 4209 var onEvent = 'on' + capitalizedEvent; 4210 var config = { 4211 phasedRegistrationNames: { 4212 bubbled: onEvent, 4213 captured: onEvent + 'Capture' 4214 }, 4215 dependencies: [topEvent], 4216 eventPriority: priority 4217 }; 4218 eventPriorities.set(topEvent, priority); 4219 topLevelEventsToDispatchConfig.set(topEvent, config); 4220 simpleEventPluginEventTypes[event] = config; 4221 } 4222 } 4223 4224 function processTopEventPairsByPriority(eventTypes, priority) { 4225 for (var i = 0; i < eventTypes.length; i++) { 4226 eventPriorities.set(eventTypes[i], priority); 4227 } 4228 } // SimpleEventPlugin 4229 4230 4231 processSimpleEventPluginPairsByPriority(discreteEventPairsForSimpleEventPlugin, DiscreteEvent); 4232 processSimpleEventPluginPairsByPriority(userBlockingPairsForSimpleEventPlugin, UserBlockingEvent); 4233 processSimpleEventPluginPairsByPriority(continuousPairsForSimpleEventPlugin, ContinuousEvent); // Not used by SimpleEventPlugin 4234 4235 processTopEventPairsByPriority(otherDiscreteEvents, DiscreteEvent); 4236 function getEventPriorityForPluginSystem(topLevelType) { 4237 var priority = eventPriorities.get(topLevelType); // Default to a ContinuousEvent. Note: we might 4238 // want to warn if we can't detect the priority 4239 // for the event. 4240 4241 return priority === undefined ? ContinuousEvent : priority; 4242 } 4243 4244 // Intentionally not named imports because Rollup would use dynamic dispatch for 4245 var UserBlockingPriority = unstable_UserBlockingPriority, 4246 runWithPriority = unstable_runWithPriority; // TODO: can we stop exporting these? 4247 4248 var _enabled = true; 4249 function setEnabled(enabled) { 4250 _enabled = !!enabled; 4251 } 4252 function isEnabled() { 4253 return _enabled; 4254 } 4255 function trapBubbledEvent(topLevelType, element) { 4256 trapEventForPluginEventSystem(element, topLevelType, false); 4257 } 4258 function trapCapturedEvent(topLevelType, element) { 4259 trapEventForPluginEventSystem(element, topLevelType, true); 4260 } 4261 4262 function trapEventForPluginEventSystem(container, topLevelType, capture) { 4263 var listener; 4264 4265 switch (getEventPriorityForPluginSystem(topLevelType)) { 4266 case DiscreteEvent: 4267 listener = dispatchDiscreteEvent.bind(null, topLevelType, PLUGIN_EVENT_SYSTEM, container); 4268 break; 4269 4270 case UserBlockingEvent: 4271 listener = dispatchUserBlockingUpdate.bind(null, topLevelType, PLUGIN_EVENT_SYSTEM, container); 4272 break; 4273 4274 case ContinuousEvent: 4275 default: 4276 listener = dispatchEvent.bind(null, topLevelType, PLUGIN_EVENT_SYSTEM, container); 4277 break; 4278 } 4279 4280 var rawEventName = getRawEventName(topLevelType); 4281 4282 if (capture) { 4283 addEventCaptureListener(container, rawEventName, listener); 4284 } else { 4285 addEventBubbleListener(container, rawEventName, listener); 4286 } 4287 } 4288 4289 function dispatchDiscreteEvent(topLevelType, eventSystemFlags, container, nativeEvent) { 4290 flushDiscreteUpdatesIfNeeded(nativeEvent.timeStamp); 4291 discreteUpdates(dispatchEvent, topLevelType, eventSystemFlags, container, nativeEvent); 4292 } 4293 4294 function dispatchUserBlockingUpdate(topLevelType, eventSystemFlags, container, nativeEvent) { 4295 runWithPriority(UserBlockingPriority, dispatchEvent.bind(null, topLevelType, eventSystemFlags, container, nativeEvent)); 4296 } 4297 4298 function dispatchEvent(topLevelType, eventSystemFlags, container, nativeEvent) { 4299 if (!_enabled) { 4300 return; 4301 } 4302 4303 if (hasQueuedDiscreteEvents() && isReplayableDiscreteEvent(topLevelType)) { 4304 // If we already have a queue of discrete events, and this is another discrete 4305 // event, then we can't dispatch it regardless of its target, since they 4306 // need to dispatch in order. 4307 queueDiscreteEvent(null, // Flags that we're not actually blocked on anything as far as we know. 4308 topLevelType, eventSystemFlags, container, nativeEvent); 4309 return; 4310 } 4311 4312 var blockedOn = attemptToDispatchEvent(topLevelType, eventSystemFlags, container, nativeEvent); 4313 4314 if (blockedOn === null) { 4315 // We successfully dispatched this event. 4316 clearIfContinuousEvent(topLevelType, nativeEvent); 4317 return; 4318 } 4319 4320 if (isReplayableDiscreteEvent(topLevelType)) { 4321 // This this to be replayed later once the target is available. 4322 queueDiscreteEvent(blockedOn, topLevelType, eventSystemFlags, container, nativeEvent); 4323 return; 4324 } 4325 4326 if (queueIfContinuousEvent(blockedOn, topLevelType, eventSystemFlags, container, nativeEvent)) { 4327 return; 4328 } // We need to clear only if we didn't queue because 4329 // queueing is accummulative. 4330 4331 4332 clearIfContinuousEvent(topLevelType, nativeEvent); // This is not replayable so we'll invoke it but without a target, 4333 // in case the event system needs to trace it. 4334 4335 { 4336 dispatchEventForLegacyPluginEventSystem(topLevelType, eventSystemFlags, nativeEvent, null); 4337 } 4338 } // Attempt dispatching an event. Returns a SuspenseInstance or Container if it's blocked. 4339 4340 function attemptToDispatchEvent(topLevelType, eventSystemFlags, container, nativeEvent) { 4341 // TODO: Warn if _enabled is false. 4342 var nativeEventTarget = getEventTarget(nativeEvent); 4343 var targetInst = getClosestInstanceFromNode(nativeEventTarget); 4344 4345 if (targetInst !== null) { 4346 var nearestMounted = getNearestMountedFiber(targetInst); 4347 4348 if (nearestMounted === null) { 4349 // This tree has been unmounted already. Dispatch without a target. 4350 targetInst = null; 4351 } else { 4352 var tag = nearestMounted.tag; 4353 4354 if (tag === SuspenseComponent) { 4355 var instance = getSuspenseInstanceFromFiber(nearestMounted); 4356 4357 if (instance !== null) { 4358 // Queue the event to be replayed later. Abort dispatching since we 4359 // don't want this event dispatched twice through the event system. 4360 // TODO: If this is the first discrete event in the queue. Schedule an increased 4361 // priority for this boundary. 4362 return instance; 4363 } // This shouldn't happen, something went wrong but to avoid blocking 4364 // the whole system, dispatch the event without a target. 4365 // TODO: Warn. 4366 4367 4368 targetInst = null; 4369 } else if (tag === HostRoot) { 4370 var root = nearestMounted.stateNode; 4371 4372 if (root.hydrate) { 4373 // If this happens during a replay something went wrong and it might block 4374 // the whole system. 4375 return getContainerFromFiber(nearestMounted); 4376 } 4377 4378 targetInst = null; 4379 } else if (nearestMounted !== targetInst) { 4380 // If we get an event (ex: img onload) before committing that 4381 // component's mount, ignore it for now (that is, treat it as if it was an 4382 // event on a non-React tree). We might also consider queueing events and 4383 // dispatching them after the mount. 4384 targetInst = null; 4385 } 4386 } 4387 } 4388 4389 { 4390 dispatchEventForLegacyPluginEventSystem(topLevelType, eventSystemFlags, nativeEvent, targetInst); 4391 } // We're not blocked on anything. 4392 4393 4394 return null; 4395 } 4396 4397 // List derived from Gecko source code: 4398 // https://github.com/mozilla/gecko-dev/blob/4e638efc71/layout/style/test/property_database.js 4399 var shorthandToLonghand = { 4400 animation: ['animationDelay', 'animationDirection', 'animationDuration', 'animationFillMode', 'animationIterationCount', 'animationName', 'animationPlayState', 'animationTimingFunction'], 4401 background: ['backgroundAttachment', 'backgroundClip', 'backgroundColor', 'backgroundImage', 'backgroundOrigin', 'backgroundPositionX', 'backgroundPositionY', 'backgroundRepeat', 'backgroundSize'], 4402 backgroundPosition: ['backgroundPositionX', 'backgroundPositionY'], 4403 border: ['borderBottomColor', 'borderBottomStyle', 'borderBottomWidth', 'borderImageOutset', 'borderImageRepeat', 'borderImageSlice', 'borderImageSource', 'borderImageWidth', 'borderLeftColor', 'borderLeftStyle', 'borderLeftWidth', 'borderRightColor', 'borderRightStyle', 'borderRightWidth', 'borderTopColor', 'borderTopStyle', 'borderTopWidth'], 4404 borderBlockEnd: ['borderBlockEndColor', 'borderBlockEndStyle', 'borderBlockEndWidth'], 4405 borderBlockStart: ['borderBlockStartColor', 'borderBlockStartStyle', 'borderBlockStartWidth'], 4406 borderBottom: ['borderBottomColor', 'borderBottomStyle', 'borderBottomWidth'], 4407 borderColor: ['borderBottomColor', 'borderLeftColor', 'borderRightColor', 'borderTopColor'], 4408 borderImage: ['borderImageOutset', 'borderImageRepeat', 'borderImageSlice', 'borderImageSource', 'borderImageWidth'], 4409 borderInlineEnd: ['borderInlineEndColor', 'borderInlineEndStyle', 'borderInlineEndWidth'], 4410 borderInlineStart: ['borderInlineStartColor', 'borderInlineStartStyle', 'borderInlineStartWidth'], 4411 borderLeft: ['borderLeftColor', 'borderLeftStyle', 'borderLeftWidth'], 4412 borderRadius: ['borderBottomLeftRadius', 'borderBottomRightRadius', 'borderTopLeftRadius', 'borderTopRightRadius'], 4413 borderRight: ['borderRightColor', 'borderRightStyle', 'borderRightWidth'], 4414 borderStyle: ['borderBottomStyle', 'borderLeftStyle', 'borderRightStyle', 'borderTopStyle'], 4415 borderTop: ['borderTopColor', 'borderTopStyle', 'borderTopWidth'], 4416 borderWidth: ['borderBottomWidth', 'borderLeftWidth', 'borderRightWidth', 'borderTopWidth'], 4417 columnRule: ['columnRuleColor', 'columnRuleStyle', 'columnRuleWidth'], 4418 columns: ['columnCount', 'columnWidth'], 4419 flex: ['flexBasis', 'flexGrow', 'flexShrink'], 4420 flexFlow: ['flexDirection', 'flexWrap'], 4421 font: ['fontFamily', 'fontFeatureSettings', 'fontKerning', 'fontLanguageOverride', 'fontSize', 'fontSizeAdjust', 'fontStretch', 'fontStyle', 'fontVariant', 'fontVariantAlternates', 'fontVariantCaps', 'fontVariantEastAsian', 'fontVariantLigatures', 'fontVariantNumeric', 'fontVariantPosition', 'fontWeight', 'lineHeight'], 4422 fontVariant: ['fontVariantAlternates', 'fontVariantCaps', 'fontVariantEastAsian', 'fontVariantLigatures', 'fontVariantNumeric', 'fontVariantPosition'], 4423 gap: ['columnGap', 'rowGap'], 4424 grid: ['gridAutoColumns', 'gridAutoFlow', 'gridAutoRows', 'gridTemplateAreas', 'gridTemplateColumns', 'gridTemplateRows'], 4425 gridArea: ['gridColumnEnd', 'gridColumnStart', 'gridRowEnd', 'gridRowStart'], 4426 gridColumn: ['gridColumnEnd', 'gridColumnStart'], 4427 gridColumnGap: ['columnGap'], 4428 gridGap: ['columnGap', 'rowGap'], 4429 gridRow: ['gridRowEnd', 'gridRowStart'], 4430 gridRowGap: ['rowGap'], 4431 gridTemplate: ['gridTemplateAreas', 'gridTemplateColumns', 'gridTemplateRows'], 4432 listStyle: ['listStyleImage', 'listStylePosition', 'listStyleType'], 4433 margin: ['marginBottom', 'marginLeft', 'marginRight', 'marginTop'], 4434 marker: ['markerEnd', 'markerMid', 'markerStart'], 4435 mask: ['maskClip', 'maskComposite', 'maskImage', 'maskMode', 'maskOrigin', 'maskPositionX', 'maskPositionY', 'maskRepeat', 'maskSize'], 4436 maskPosition: ['maskPositionX', 'maskPositionY'], 4437 outline: ['outlineColor', 'outlineStyle', 'outlineWidth'], 4438 overflow: ['overflowX', 'overflowY'], 4439 padding: ['paddingBottom', 'paddingLeft', 'paddingRight', 'paddingTop'], 4440 placeContent: ['alignContent', 'justifyContent'], 4441 placeItems: ['alignItems', 'justifyItems'], 4442 placeSelf: ['alignSelf', 'justifySelf'], 4443 textDecoration: ['textDecorationColor', 'textDecorationLine', 'textDecorationStyle'], 4444 textEmphasis: ['textEmphasisColor', 'textEmphasisStyle'], 4445 transition: ['transitionDelay', 'transitionDuration', 'transitionProperty', 'transitionTimingFunction'], 4446 wordWrap: ['overflowWrap'] 4447 }; 4448 4449 /** 4450 * CSS properties which accept numbers but are not in units of "px". 4451 */ 4452 var isUnitlessNumber = { 4453 animationIterationCount: true, 4454 borderImageOutset: true, 4455 borderImageSlice: true, 4456 borderImageWidth: true, 4457 boxFlex: true, 4458 boxFlexGroup: true, 4459 boxOrdinalGroup: true, 4460 columnCount: true, 4461 columns: true, 4462 flex: true, 4463 flexGrow: true, 4464 flexPositive: true, 4465 flexShrink: true, 4466 flexNegative: true, 4467 flexOrder: true, 4468 gridArea: true, 4469 gridRow: true, 4470 gridRowEnd: true, 4471 gridRowSpan: true, 4472 gridRowStart: true, 4473 gridColumn: true, 4474 gridColumnEnd: true, 4475 gridColumnSpan: true, 4476 gridColumnStart: true, 4477 fontWeight: true, 4478 lineClamp: true, 4479 lineHeight: true, 4480 opacity: true, 4481 order: true, 4482 orphans: true, 4483 tabSize: true, 4484 widows: true, 4485 zIndex: true, 4486 zoom: true, 4487 // SVG-related properties 4488 fillOpacity: true, 4489 floodOpacity: true, 4490 stopOpacity: true, 4491 strokeDasharray: true, 4492 strokeDashoffset: true, 4493 strokeMiterlimit: true, 4494 strokeOpacity: true, 4495 strokeWidth: true 4496 }; 4497 /** 4498 * @param {string} prefix vendor-specific prefix, eg: Webkit 4499 * @param {string} key style name, eg: transitionDuration 4500 * @return {string} style name prefixed with `prefix`, properly camelCased, eg: 4501 * WebkitTransitionDuration 4502 */ 4503 4504 function prefixKey(prefix, key) { 4505 return prefix + key.charAt(0).toUpperCase() + key.substring(1); 4506 } 4507 /** 4508 * Support style names that may come passed in prefixed by adding permutations 4509 * of vendor prefixes. 4510 */ 4511 4512 4513 var prefixes = ['Webkit', 'ms', 'Moz', 'O']; // Using Object.keys here, or else the vanilla for-in loop makes IE8 go into an 4514 // infinite loop, because it iterates over the newly added props too. 4515 4516 Object.keys(isUnitlessNumber).forEach(function (prop) { 4517 prefixes.forEach(function (prefix) { 4518 isUnitlessNumber[prefixKey(prefix, prop)] = isUnitlessNumber[prop]; 4519 }); 4520 }); 4521 4522 /** 4523 * Convert a value into the proper css writable value. The style name `name` 4524 * should be logical (no hyphens), as specified 4525 * in `CSSProperty.isUnitlessNumber`. 4526 * 4527 * @param {string} name CSS property name such as `topMargin`. 4528 * @param {*} value CSS property value such as `10px`. 4529 * @return {string} Normalized style value with dimensions applied. 4530 */ 4531 4532 function dangerousStyleValue(name, value, isCustomProperty) { 4533 // Note that we've removed escapeTextForBrowser() calls here since the 4534 // whole string will be escaped when the attribute is injected into 4535 // the markup. If you provide unsafe user data here they can inject 4536 // arbitrary CSS which may be problematic (I couldn't repro this): 4537 // https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet 4538 // http://www.thespanner.co.uk/2007/11/26/ultimate-xss-css-injection/ 4539 // This is not an XSS hole but instead a potential CSS injection issue 4540 // which has lead to a greater discussion about how we're going to 4541 // trust URLs moving forward. See #2115901 4542 var isEmpty = value == null || typeof value === 'boolean' || value === ''; 4543 4544 if (isEmpty) { 4545 return ''; 4546 } 4547 4548 if (!isCustomProperty && typeof value === 'number' && value !== 0 && !(isUnitlessNumber.hasOwnProperty(name) && isUnitlessNumber[name])) { 4549 return value + 'px'; // Presumes implicit 'px' suffix for unitless numbers 4550 } 4551 4552 return ('' + value).trim(); 4553 } 4554 4555 var uppercasePattern = /([A-Z])/g; 4556 var msPattern = /^ms-/; 4557 /** 4558 * Hyphenates a camelcased CSS property name, for example: 4559 * 4560 * > hyphenateStyleName('backgroundColor') 4561 * < "background-color" 4562 * > hyphenateStyleName('MozTransition') 4563 * < "-moz-transition" 4564 * > hyphenateStyleName('msTransition') 4565 * < "-ms-transition" 4566 * 4567 * As Modernizr suggests (http://modernizr.com/docs/#prefixed), an `ms` prefix 4568 * is converted to `-ms-`. 4569 */ 4570 4571 function hyphenateStyleName(name) { 4572 return name.replace(uppercasePattern, '-$1').toLowerCase().replace(msPattern, '-ms-'); 4573 } 4574 4575 var warnValidStyle = function () {}; 4576 4577 { 4578 // 'msTransform' is correct, but the other prefixes should be capitalized 4579 var badVendoredStyleNamePattern = /^(?:webkit|moz|o)[A-Z]/; 4580 var msPattern$1 = /^-ms-/; 4581 var hyphenPattern = /-(.)/g; // style values shouldn't contain a semicolon 4582 4583 var badStyleValueWithSemicolonPattern = /;\s*$/; 4584 var warnedStyleNames = {}; 4585 var warnedStyleValues = {}; 4586 var warnedForNaNValue = false; 4587 var warnedForInfinityValue = false; 4588 4589 var camelize = function (string) { 4590 return string.replace(hyphenPattern, function (_, character) { 4591 return character.toUpperCase(); 4592 }); 4593 }; 4594 4595 var warnHyphenatedStyleName = function (name) { 4596 if (warnedStyleNames.hasOwnProperty(name) && warnedStyleNames[name]) { 4597 return; 4598 } 4599 4600 warnedStyleNames[name] = true; 4601 4602 error('Unsupported style property %s. Did you mean %s?', name, // As Andi Smith suggests 4603 // (http://www.andismith.com/blog/2012/02/modernizr-prefixed/), an `-ms` prefix 4604 // is converted to lowercase `ms`. 4605 camelize(name.replace(msPattern$1, 'ms-'))); 4606 }; 4607 4608 var warnBadVendoredStyleName = function (name) { 4609 if (warnedStyleNames.hasOwnProperty(name) && warnedStyleNames[name]) { 4610 return; 4611 } 4612 4613 warnedStyleNames[name] = true; 4614 4615 error('Unsupported vendor-prefixed style property %s. Did you mean %s?', name, name.charAt(0).toUpperCase() + name.slice(1)); 4616 }; 4617 4618 var warnStyleValueWithSemicolon = function (name, value) { 4619 if (warnedStyleValues.hasOwnProperty(value) && warnedStyleValues[value]) { 4620 return; 4621 } 4622 4623 warnedStyleValues[value] = true; 4624 4625 error("Style property values shouldn't contain a semicolon. " + 'Try "%s: %s" instead.', name, value.replace(badStyleValueWithSemicolonPattern, '')); 4626 }; 4627 4628 var warnStyleValueIsNaN = function (name, value) { 4629 if (warnedForNaNValue) { 4630 return; 4631 } 4632 4633 warnedForNaNValue = true; 4634 4635 error('`NaN` is an invalid value for the `%s` css style property.', name); 4636 }; 4637 4638 var warnStyleValueIsInfinity = function (name, value) { 4639 if (warnedForInfinityValue) { 4640 return; 4641 } 4642 4643 warnedForInfinityValue = true; 4644 4645 error('`Infinity` is an invalid value for the `%s` css style property.', name); 4646 }; 4647 4648 warnValidStyle = function (name, value) { 4649 if (name.indexOf('-') > -1) { 4650 warnHyphenatedStyleName(name); 4651 } else if (badVendoredStyleNamePattern.test(name)) { 4652 warnBadVendoredStyleName(name); 4653 } else if (badStyleValueWithSemicolonPattern.test(value)) { 4654 warnStyleValueWithSemicolon(name, value); 4655 } 4656 4657 if (typeof value === 'number') { 4658 if (isNaN(value)) { 4659 warnStyleValueIsNaN(name, value); 4660 } else if (!isFinite(value)) { 4661 warnStyleValueIsInfinity(name, value); 4662 } 4663 } 4664 }; 4665 } 4666 4667 var warnValidStyle$1 = warnValidStyle; 4668 4669 /** 4670 * Operations for dealing with CSS properties. 4671 */ 4672 4673 /** 4674 * This creates a string that is expected to be equivalent to the style 4675 * attribute generated by server-side rendering. It by-passes warnings and 4676 * security checks so it's not safe to use this value for anything other than 4677 * comparison. It is only used in DEV for SSR validation. 4678 */ 4679 4680 function createDangerousStringForStyles(styles) { 4681 { 4682 var serialized = ''; 4683 var delimiter = ''; 4684 4685 for (var styleName in styles) { 4686 if (!styles.hasOwnProperty(styleName)) { 4687 continue; 4688 } 4689 4690 var styleValue = styles[styleName]; 4691 4692 if (styleValue != null) { 4693 var isCustomProperty = styleName.indexOf('--') === 0; 4694 serialized += delimiter + (isCustomProperty ? styleName : hyphenateStyleName(styleName)) + ':'; 4695 serialized += dangerousStyleValue(styleName, styleValue, isCustomProperty); 4696 delimiter = ';'; 4697 } 4698 } 4699 4700 return serialized || null; 4701 } 4702 } 4703 /** 4704 * Sets the value for multiple styles on a node. If a value is specified as 4705 * '' (empty string), the corresponding style property will be unset. 4706 * 4707 * @param {DOMElement} node 4708 * @param {object} styles 4709 */ 4710 4711 function setValueForStyles(node, styles) { 4712 var style = node.style; 4713 4714 for (var styleName in styles) { 4715 if (!styles.hasOwnProperty(styleName)) { 4716 continue; 4717 } 4718 4719 var isCustomProperty = styleName.indexOf('--') === 0; 4720 4721 { 4722 if (!isCustomProperty) { 4723 warnValidStyle$1(styleName, styles[styleName]); 4724 } 4725 } 4726 4727 var styleValue = dangerousStyleValue(styleName, styles[styleName], isCustomProperty); 4728 4729 if (styleName === 'float') { 4730 styleName = 'cssFloat'; 4731 } 4732 4733 if (isCustomProperty) { 4734 style.setProperty(styleName, styleValue); 4735 } else { 4736 style[styleName] = styleValue; 4737 } 4738 } 4739 } 4740 4741 function isValueEmpty(value) { 4742 return value == null || typeof value === 'boolean' || value === ''; 4743 } 4744 /** 4745 * Given {color: 'red', overflow: 'hidden'} returns { 4746 * color: 'color', 4747 * overflowX: 'overflow', 4748 * overflowY: 'overflow', 4749 * }. This can be read as "the overflowY property was set by the overflow 4750 * shorthand". That is, the values are the property that each was derived from. 4751 */ 4752 4753 4754 function expandShorthandMap(styles) { 4755 var expanded = {}; 4756 4757 for (var key in styles) { 4758 var longhands = shorthandToLonghand[key] || [key]; 4759 4760 for (var i = 0; i < longhands.length; i++) { 4761 expanded[longhands[i]] = key; 4762 } 4763 } 4764 4765 return expanded; 4766 } 4767 /** 4768 * When mixing shorthand and longhand property names, we warn during updates if 4769 * we expect an incorrect result to occur. In particular, we warn for: 4770 * 4771 * Updating a shorthand property (longhand gets overwritten): 4772 * {font: 'foo', fontVariant: 'bar'} -> {font: 'baz', fontVariant: 'bar'} 4773 * becomes .style.font = 'baz' 4774 * Removing a shorthand property (longhand gets lost too): 4775 * {font: 'foo', fontVariant: 'bar'} -> {fontVariant: 'bar'} 4776 * becomes .style.font = '' 4777 * Removing a longhand property (should revert to shorthand; doesn't): 4778 * {font: 'foo', fontVariant: 'bar'} -> {font: 'foo'} 4779 * becomes .style.fontVariant = '' 4780 */ 4781 4782 4783 function validateShorthandPropertyCollisionInDev(styleUpdates, nextStyles) { 4784 { 4785 4786 if (!nextStyles) { 4787 return; 4788 } 4789 4790 var expandedUpdates = expandShorthandMap(styleUpdates); 4791 var expandedStyles = expandShorthandMap(nextStyles); 4792 var warnedAbout = {}; 4793 4794 for (var key in expandedUpdates) { 4795 var originalKey = expandedUpdates[key]; 4796 var correctOriginalKey = expandedStyles[key]; 4797 4798 if (correctOriginalKey && originalKey !== correctOriginalKey) { 4799 var warningKey = originalKey + ',' + correctOriginalKey; 4800 4801 if (warnedAbout[warningKey]) { 4802 continue; 4803 } 4804 4805 warnedAbout[warningKey] = true; 4806 4807 error('%s a style property during rerender (%s) when a ' + 'conflicting property is set (%s) can lead to styling bugs. To ' + "avoid this, don't mix shorthand and non-shorthand properties " + 'for the same value; instead, replace the shorthand with ' + 'separate values.', isValueEmpty(styleUpdates[originalKey]) ? 'Removing' : 'Updating', originalKey, correctOriginalKey); 4808 } 4809 } 4810 } 4811 } 4812 4813 // For HTML, certain tags should omit their close tag. We keep a whitelist for 4814 // those special-case tags. 4815 var omittedCloseTags = { 4816 area: true, 4817 base: true, 4818 br: true, 4819 col: true, 4820 embed: true, 4821 hr: true, 4822 img: true, 4823 input: true, 4824 keygen: true, 4825 link: true, 4826 meta: true, 4827 param: true, 4828 source: true, 4829 track: true, 4830 wbr: true // NOTE: menuitem's close tag should be omitted, but that causes problems. 4831 4832 }; 4833 4834 // `omittedCloseTags` except that `menuitem` should still have its closing tag. 4835 4836 var voidElementTags = _assign({ 4837 menuitem: true 4838 }, omittedCloseTags); 4839 4840 var HTML = '__html'; 4841 var ReactDebugCurrentFrame$3 = null; 4842 4843 { 4844 ReactDebugCurrentFrame$3 = ReactSharedInternals.ReactDebugCurrentFrame; 4845 } 4846 4847 function assertValidProps(tag, props) { 4848 if (!props) { 4849 return; 4850 } // Note the use of `==` which checks for null or undefined. 4851 4852 4853 if (voidElementTags[tag]) { 4854 if (!(props.children == null && props.dangerouslySetInnerHTML == null)) { 4855 { 4856 throw Error( tag + " is a void element tag and must neither have `children` nor use `dangerouslySetInnerHTML`." + ( ReactDebugCurrentFrame$3.getStackAddendum() ) ); 4857 } 4858 } 4859 } 4860 4861 if (props.dangerouslySetInnerHTML != null) { 4862 if (!(props.children == null)) { 4863 { 4864 throw Error( "Can only set one of `children` or `props.dangerouslySetInnerHTML`." ); 4865 } 4866 } 4867 4868 if (!(typeof props.dangerouslySetInnerHTML === 'object' && HTML in props.dangerouslySetInnerHTML)) { 4869 { 4870 throw Error( "`props.dangerouslySetInnerHTML` must be in the form `{__html: ...}`. Please visit https://fb.me/react-invariant-dangerously-set-inner-html for more information." ); 4871 } 4872 } 4873 } 4874 4875 { 4876 if (!props.suppressContentEditableWarning && props.contentEditable && props.children != null) { 4877 error('A component is `contentEditable` and contains `children` managed by ' + 'React. It is now your responsibility to guarantee that none of ' + 'those nodes are unexpectedly modified or duplicated. This is ' + 'probably not intentional.'); 4878 } 4879 } 4880 4881 if (!(props.style == null || typeof props.style === 'object')) { 4882 { 4883 throw Error( "The `style` prop expects a mapping from style properties to values, not a string. For example, style={{marginRight: spacing + 'em'}} when using JSX." + ( ReactDebugCurrentFrame$3.getStackAddendum() ) ); 4884 } 4885 } 4886 } 4887 4888 function isCustomComponent(tagName, props) { 4889 if (tagName.indexOf('-') === -1) { 4890 return typeof props.is === 'string'; 4891 } 4892 4893 switch (tagName) { 4894 // These are reserved SVG and MathML elements. 4895 // We don't mind this whitelist too much because we expect it to never grow. 4896 // The alternative is to track the namespace in a few places which is convoluted. 4897 // https://w3c.github.io/webcomponents/spec/custom/#custom-elements-core-concepts 4898 case 'annotation-xml': 4899 case 'color-profile': 4900 case 'font-face': 4901 case 'font-face-src': 4902 case 'font-face-uri': 4903 case 'font-face-format': 4904 case 'font-face-name': 4905 case 'missing-glyph': 4906 return false; 4907 4908 default: 4909 return true; 4910 } 4911 } 4912 4913 // When adding attributes to the HTML or SVG whitelist, be sure to 4914 // also add them to this module to ensure casing and incorrect name 4915 // warnings. 4916 var possibleStandardNames = { 4917 // HTML 4918 accept: 'accept', 4919 acceptcharset: 'acceptCharset', 4920 'accept-charset': 'acceptCharset', 4921 accesskey: 'accessKey', 4922 action: 'action', 4923 allowfullscreen: 'allowFullScreen', 4924 alt: 'alt', 4925 as: 'as', 4926 async: 'async', 4927 autocapitalize: 'autoCapitalize', 4928 autocomplete: 'autoComplete', 4929 autocorrect: 'autoCorrect', 4930 autofocus: 'autoFocus', 4931 autoplay: 'autoPlay', 4932 autosave: 'autoSave', 4933 capture: 'capture', 4934 cellpadding: 'cellPadding', 4935 cellspacing: 'cellSpacing', 4936 challenge: 'challenge', 4937 charset: 'charSet', 4938 checked: 'checked', 4939 children: 'children', 4940 cite: 'cite', 4941 class: 'className', 4942 classid: 'classID', 4943 classname: 'className', 4944 cols: 'cols', 4945 colspan: 'colSpan', 4946 content: 'content', 4947 contenteditable: 'contentEditable', 4948 contextmenu: 'contextMenu', 4949 controls: 'controls', 4950 controlslist: 'controlsList', 4951 coords: 'coords', 4952 crossorigin: 'crossOrigin', 4953 dangerouslysetinnerhtml: 'dangerouslySetInnerHTML', 4954 data: 'data', 4955 datetime: 'dateTime', 4956 default: 'default', 4957 defaultchecked: 'defaultChecked', 4958 defaultvalue: 'defaultValue', 4959 defer: 'defer', 4960 dir: 'dir', 4961 disabled: 'disabled', 4962 disablepictureinpicture: 'disablePictureInPicture', 4963 download: 'download', 4964 draggable: 'draggable', 4965 enctype: 'encType', 4966 for: 'htmlFor', 4967 form: 'form', 4968 formmethod: 'formMethod', 4969 formaction: 'formAction', 4970 formenctype: 'formEncType', 4971 formnovalidate: 'formNoValidate', 4972 formtarget: 'formTarget', 4973 frameborder: 'frameBorder', 4974 headers: 'headers', 4975 height: 'height', 4976 hidden: 'hidden', 4977 high: 'high', 4978 href: 'href', 4979 hreflang: 'hrefLang', 4980 htmlfor: 'htmlFor', 4981 httpequiv: 'httpEquiv', 4982 'http-equiv': 'httpEquiv', 4983 icon: 'icon', 4984 id: 'id', 4985 innerhtml: 'innerHTML', 4986 inputmode: 'inputMode', 4987 integrity: 'integrity', 4988 is: 'is', 4989 itemid: 'itemID', 4990 itemprop: 'itemProp', 4991 itemref: 'itemRef', 4992 itemscope: 'itemScope', 4993 itemtype: 'itemType', 4994 keyparams: 'keyParams', 4995 keytype: 'keyType', 4996 kind: 'kind', 4997 label: 'label', 4998 lang: 'lang', 4999 list: 'list', 5000 loop: 'loop', 5001 low: 'low', 5002 manifest: 'manifest', 5003 marginwidth: 'marginWidth', 5004 marginheight: 'marginHeight', 5005 max: 'max', 5006 maxlength: 'maxLength', 5007 media: 'media', 5008 mediagroup: 'mediaGroup', 5009 method: 'method', 5010 min: 'min', 5011 minlength: 'minLength', 5012 multiple: 'multiple', 5013 muted: 'muted', 5014 name: 'name', 5015 nomodule: 'noModule', 5016 nonce: 'nonce', 5017 novalidate: 'noValidate', 5018 open: 'open', 5019 optimum: 'optimum', 5020 pattern: 'pattern', 5021 placeholder: 'placeholder', 5022 playsinline: 'playsInline', 5023 poster: 'poster', 5024 preload: 'preload', 5025 profile: 'profile', 5026 radiogroup: 'radioGroup', 5027 readonly: 'readOnly', 5028 referrerpolicy: 'referrerPolicy', 5029 rel: 'rel', 5030 required: 'required', 5031 reversed: 'reversed', 5032 role: 'role', 5033 rows: 'rows', 5034 rowspan: 'rowSpan', 5035 sandbox: 'sandbox', 5036 scope: 'scope', 5037 scoped: 'scoped', 5038 scrolling: 'scrolling', 5039 seamless: 'seamless', 5040 selected: 'selected', 5041 shape: 'shape', 5042 size: 'size', 5043 sizes: 'sizes', 5044 span: 'span', 5045 spellcheck: 'spellCheck', 5046 src: 'src', 5047 srcdoc: 'srcDoc', 5048 srclang: 'srcLang', 5049 srcset: 'srcSet', 5050 start: 'start', 5051 step: 'step', 5052 style: 'style', 5053 summary: 'summary', 5054 tabindex: 'tabIndex', 5055 target: 'target', 5056 title: 'title', 5057 type: 'type', 5058 usemap: 'useMap', 5059 value: 'value', 5060 width: 'width', 5061 wmode: 'wmode', 5062 wrap: 'wrap', 5063 // SVG 5064 about: 'about', 5065 accentheight: 'accentHeight', 5066 'accent-height': 'accentHeight', 5067 accumulate: 'accumulate', 5068 additive: 'additive', 5069 alignmentbaseline: 'alignmentBaseline', 5070 'alignment-baseline': 'alignmentBaseline', 5071 allowreorder: 'allowReorder', 5072 alphabetic: 'alphabetic', 5073 amplitude: 'amplitude', 5074 arabicform: 'arabicForm', 5075 'arabic-form': 'arabicForm', 5076 ascent: 'ascent', 5077 attributename: 'attributeName', 5078 attributetype: 'attributeType', 5079 autoreverse: 'autoReverse', 5080 azimuth: 'azimuth', 5081 basefrequency: 'baseFrequency', 5082 baselineshift: 'baselineShift', 5083 'baseline-shift': 'baselineShift', 5084 baseprofile: 'baseProfile', 5085 bbox: 'bbox', 5086 begin: 'begin', 5087 bias: 'bias', 5088 by: 'by', 5089 calcmode: 'calcMode', 5090 capheight: 'capHeight', 5091 'cap-height': 'capHeight', 5092 clip: 'clip', 5093 clippath: 'clipPath', 5094 'clip-path': 'clipPath', 5095 clippathunits: 'clipPathUnits', 5096 cliprule: 'clipRule', 5097 'clip-rule': 'clipRule', 5098 color: 'color', 5099 colorinterpolation: 'colorInterpolation', 5100 'color-interpolation': 'colorInterpolation', 5101 colorinterpolationfilters: 'colorInterpolationFilters', 5102 'color-interpolation-filters': 'colorInterpolationFilters', 5103 colorprofile: 'colorProfile', 5104 'color-profile': 'colorProfile', 5105 colorrendering: 'colorRendering', 5106 'color-rendering': 'colorRendering', 5107 contentscripttype: 'contentScriptType', 5108 contentstyletype: 'contentStyleType', 5109 cursor: 'cursor', 5110 cx: 'cx', 5111 cy: 'cy', 5112 d: 'd', 5113 datatype: 'datatype', 5114 decelerate: 'decelerate', 5115 descent: 'descent', 5116 diffuseconstant: 'diffuseConstant', 5117 direction: 'direction', 5118 display: 'display', 5119 divisor: 'divisor', 5120 dominantbaseline: 'dominantBaseline', 5121 'dominant-baseline': 'dominantBaseline', 5122 dur: 'dur', 5123 dx: 'dx', 5124 dy: 'dy', 5125 edgemode: 'edgeMode', 5126 elevation: 'elevation', 5127 enablebackground: 'enableBackground', 5128 'enable-background': 'enableBackground', 5129 end: 'end', 5130 exponent: 'exponent', 5131 externalresourcesrequired: 'externalResourcesRequired', 5132 fill: 'fill', 5133 fillopacity: 'fillOpacity', 5134 'fill-opacity': 'fillOpacity', 5135 fillrule: 'fillRule', 5136 'fill-rule': 'fillRule', 5137 filter: 'filter', 5138 filterres: 'filterRes', 5139 filterunits: 'filterUnits', 5140 floodopacity: 'floodOpacity', 5141 'flood-opacity': 'floodOpacity', 5142 floodcolor: 'floodColor', 5143 'flood-color': 'floodColor', 5144 focusable: 'focusable', 5145 fontfamily: 'fontFamily', 5146 'font-family': 'fontFamily', 5147 fontsize: 'fontSize', 5148 'font-size': 'fontSize', 5149 fontsizeadjust: 'fontSizeAdjust', 5150 'font-size-adjust': 'fontSizeAdjust', 5151 fontstretch: 'fontStretch', 5152 'font-stretch': 'fontStretch', 5153 fontstyle: 'fontStyle', 5154 'font-style': 'fontStyle', 5155 fontvariant: 'fontVariant', 5156 'font-variant': 'fontVariant', 5157 fontweight: 'fontWeight', 5158 'font-weight': 'fontWeight', 5159 format: 'format', 5160 from: 'from', 5161 fx: 'fx', 5162 fy: 'fy', 5163 g1: 'g1', 5164 g2: 'g2', 5165 glyphname: 'glyphName', 5166 'glyph-name': 'glyphName', 5167 glyphorientationhorizontal: 'glyphOrientationHorizontal', 5168 'glyph-orientation-horizontal': 'glyphOrientationHorizontal', 5169 glyphorientationvertical: 'glyphOrientationVertical', 5170 'glyph-orientation-vertical': 'glyphOrientationVertical', 5171 glyphref: 'glyphRef', 5172 gradienttransform: 'gradientTransform', 5173 gradientunits: 'gradientUnits', 5174 hanging: 'hanging', 5175 horizadvx: 'horizAdvX', 5176 'horiz-adv-x': 'horizAdvX', 5177 horizoriginx: 'horizOriginX', 5178 'horiz-origin-x': 'horizOriginX', 5179 ideographic: 'ideographic', 5180 imagerendering: 'imageRendering', 5181 'image-rendering': 'imageRendering', 5182 in2: 'in2', 5183 in: 'in', 5184 inlist: 'inlist', 5185 intercept: 'intercept', 5186 k1: 'k1', 5187 k2: 'k2', 5188 k3: 'k3', 5189 k4: 'k4', 5190 k: 'k', 5191 kernelmatrix: 'kernelMatrix', 5192 kernelunitlength: 'kernelUnitLength', 5193 kerning: 'kerning', 5194 keypoints: 'keyPoints', 5195 keysplines: 'keySplines', 5196 keytimes: 'keyTimes', 5197 lengthadjust: 'lengthAdjust', 5198 letterspacing: 'letterSpacing', 5199 'letter-spacing': 'letterSpacing', 5200 lightingcolor: 'lightingColor', 5201 'lighting-color': 'lightingColor', 5202 limitingconeangle: 'limitingConeAngle', 5203 local: 'local', 5204 markerend: 'markerEnd', 5205 'marker-end': 'markerEnd', 5206 markerheight: 'markerHeight', 5207 markermid: 'markerMid', 5208 'marker-mid': 'markerMid', 5209 markerstart: 'markerStart', 5210 'marker-start': 'markerStart', 5211 markerunits: 'markerUnits', 5212 markerwidth: 'markerWidth', 5213 mask: 'mask', 5214 maskcontentunits: 'maskContentUnits', 5215 maskunits: 'maskUnits', 5216 mathematical: 'mathematical', 5217 mode: 'mode', 5218 numoctaves: 'numOctaves', 5219 offset: 'offset', 5220 opacity: 'opacity', 5221 operator: 'operator', 5222 order: 'order', 5223 orient: 'orient', 5224 orientation: 'orientation', 5225 origin: 'origin', 5226 overflow: 'overflow', 5227 overlineposition: 'overlinePosition', 5228 'overline-position': 'overlinePosition', 5229 overlinethickness: 'overlineThickness', 5230 'overline-thickness': 'overlineThickness', 5231 paintorder: 'paintOrder', 5232 'paint-order': 'paintOrder', 5233 panose1: 'panose1', 5234 'panose-1': 'panose1', 5235 pathlength: 'pathLength', 5236 patterncontentunits: 'patternContentUnits', 5237 patterntransform: 'patternTransform', 5238 patternunits: 'patternUnits', 5239 pointerevents: 'pointerEvents', 5240 'pointer-events': 'pointerEvents', 5241 points: 'points', 5242 pointsatx: 'pointsAtX', 5243 pointsaty: 'pointsAtY', 5244 pointsatz: 'pointsAtZ', 5245 prefix: 'prefix', 5246 preservealpha: 'preserveAlpha', 5247 preserveaspectratio: 'preserveAspectRatio', 5248 primitiveunits: 'primitiveUnits', 5249 property: 'property', 5250 r: 'r', 5251 radius: 'radius', 5252 refx: 'refX', 5253 refy: 'refY', 5254 renderingintent: 'renderingIntent', 5255 'rendering-intent': 'renderingIntent', 5256 repeatcount: 'repeatCount', 5257 repeatdur: 'repeatDur', 5258 requiredextensions: 'requiredExtensions', 5259 requiredfeatures: 'requiredFeatures', 5260 resource: 'resource', 5261 restart: 'restart', 5262 result: 'result', 5263 results: 'results', 5264 rotate: 'rotate', 5265 rx: 'rx', 5266 ry: 'ry', 5267 scale: 'scale', 5268 security: 'security', 5269 seed: 'seed', 5270 shaperendering: 'shapeRendering', 5271 'shape-rendering': 'shapeRendering', 5272 slope: 'slope', 5273 spacing: 'spacing', 5274 specularconstant: 'specularConstant', 5275 specularexponent: 'specularExponent', 5276 speed: 'speed', 5277 spreadmethod: 'spreadMethod', 5278 startoffset: 'startOffset', 5279 stddeviation: 'stdDeviation', 5280 stemh: 'stemh', 5281 stemv: 'stemv', 5282 stitchtiles: 'stitchTiles', 5283 stopcolor: 'stopColor', 5284 'stop-color': 'stopColor', 5285 stopopacity: 'stopOpacity', 5286 'stop-opacity': 'stopOpacity', 5287 strikethroughposition: 'strikethroughPosition', 5288 'strikethrough-position': 'strikethroughPosition', 5289 strikethroughthickness: 'strikethroughThickness', 5290 'strikethrough-thickness': 'strikethroughThickness', 5291 string: 'string', 5292 stroke: 'stroke', 5293 strokedasharray: 'strokeDasharray', 5294 'stroke-dasharray': 'strokeDasharray', 5295 strokedashoffset: 'strokeDashoffset', 5296 'stroke-dashoffset': 'strokeDashoffset', 5297 strokelinecap: 'strokeLinecap', 5298 'stroke-linecap': 'strokeLinecap', 5299 strokelinejoin: 'strokeLinejoin', 5300 'stroke-linejoin': 'strokeLinejoin', 5301 strokemiterlimit: 'strokeMiterlimit', 5302 'stroke-miterlimit': 'strokeMiterlimit', 5303 strokewidth: 'strokeWidth', 5304 'stroke-width': 'strokeWidth', 5305 strokeopacity: 'strokeOpacity', 5306 'stroke-opacity': 'strokeOpacity', 5307 suppresscontenteditablewarning: 'suppressContentEditableWarning', 5308 suppresshydrationwarning: 'suppressHydrationWarning', 5309 surfacescale: 'surfaceScale', 5310 systemlanguage: 'systemLanguage', 5311 tablevalues: 'tableValues', 5312 targetx: 'targetX', 5313 targety: 'targetY', 5314 textanchor: 'textAnchor', 5315 'text-anchor': 'textAnchor', 5316 textdecoration: 'textDecoration', 5317 'text-decoration': 'textDecoration', 5318 textlength: 'textLength', 5319 textrendering: 'textRendering', 5320 'text-rendering': 'textRendering', 5321 to: 'to', 5322 transform: 'transform', 5323 typeof: 'typeof', 5324 u1: 'u1', 5325 u2: 'u2', 5326 underlineposition: 'underlinePosition', 5327 'underline-position': 'underlinePosition', 5328 underlinethickness: 'underlineThickness', 5329 'underline-thickness': 'underlineThickness', 5330 unicode: 'unicode', 5331 unicodebidi: 'unicodeBidi', 5332 'unicode-bidi': 'unicodeBidi', 5333 unicoderange: 'unicodeRange', 5334 'unicode-range': 'unicodeRange', 5335 unitsperem: 'unitsPerEm', 5336 'units-per-em': 'unitsPerEm', 5337 unselectable: 'unselectable', 5338 valphabetic: 'vAlphabetic', 5339 'v-alphabetic': 'vAlphabetic', 5340 values: 'values', 5341 vectoreffect: 'vectorEffect', 5342 'vector-effect': 'vectorEffect', 5343 version: 'version', 5344 vertadvy: 'vertAdvY', 5345 'vert-adv-y': 'vertAdvY', 5346 vertoriginx: 'vertOriginX', 5347 'vert-origin-x': 'vertOriginX', 5348 vertoriginy: 'vertOriginY', 5349 'vert-origin-y': 'vertOriginY', 5350 vhanging: 'vHanging', 5351 'v-hanging': 'vHanging', 5352 videographic: 'vIdeographic', 5353 'v-ideographic': 'vIdeographic', 5354 viewbox: 'viewBox', 5355 viewtarget: 'viewTarget', 5356 visibility: 'visibility', 5357 vmathematical: 'vMathematical', 5358 'v-mathematical': 'vMathematical', 5359 vocab: 'vocab', 5360 widths: 'widths', 5361 wordspacing: 'wordSpacing', 5362 'word-spacing': 'wordSpacing', 5363 writingmode: 'writingMode', 5364 'writing-mode': 'writingMode', 5365 x1: 'x1', 5366 x2: 'x2', 5367 x: 'x', 5368 xchannelselector: 'xChannelSelector', 5369 xheight: 'xHeight', 5370 'x-height': 'xHeight', 5371 xlinkactuate: 'xlinkActuate', 5372 'xlink:actuate': 'xlinkActuate', 5373 xlinkarcrole: 'xlinkArcrole', 5374 'xlink:arcrole': 'xlinkArcrole', 5375 xlinkhref: 'xlinkHref', 5376 'xlink:href': 'xlinkHref', 5377 xlinkrole: 'xlinkRole', 5378 'xlink:role': 'xlinkRole', 5379 xlinkshow: 'xlinkShow', 5380 'xlink:show': 'xlinkShow', 5381 xlinktitle: 'xlinkTitle', 5382 'xlink:title': 'xlinkTitle', 5383 xlinktype: 'xlinkType', 5384 'xlink:type': 'xlinkType', 5385 xmlbase: 'xmlBase', 5386 'xml:base': 'xmlBase', 5387 xmllang: 'xmlLang', 5388 'xml:lang': 'xmlLang', 5389 xmlns: 'xmlns', 5390 'xml:space': 'xmlSpace', 5391 xmlnsxlink: 'xmlnsXlink', 5392 'xmlns:xlink': 'xmlnsXlink', 5393 xmlspace: 'xmlSpace', 5394 y1: 'y1', 5395 y2: 'y2', 5396 y: 'y', 5397 ychannelselector: 'yChannelSelector', 5398 z: 'z', 5399 zoomandpan: 'zoomAndPan' 5400 }; 5401 5402 var ariaProperties = { 5403 'aria-current': 0, 5404 // state 5405 'aria-details': 0, 5406 'aria-disabled': 0, 5407 // state 5408 'aria-hidden': 0, 5409 // state 5410 'aria-invalid': 0, 5411 // state 5412 'aria-keyshortcuts': 0, 5413 'aria-label': 0, 5414 'aria-roledescription': 0, 5415 // Widget Attributes 5416 'aria-autocomplete': 0, 5417 'aria-checked': 0, 5418 'aria-expanded': 0, 5419 'aria-haspopup': 0, 5420 'aria-level': 0, 5421 'aria-modal': 0, 5422 'aria-multiline': 0, 5423 'aria-multiselectable': 0, 5424 'aria-orientation': 0, 5425 'aria-placeholder': 0, 5426 'aria-pressed': 0, 5427 'aria-readonly': 0, 5428 'aria-required': 0, 5429 'aria-selected': 0, 5430 'aria-sort': 0, 5431 'aria-valuemax': 0, 5432 'aria-valuemin': 0, 5433 'aria-valuenow': 0, 5434 'aria-valuetext': 0, 5435 // Live Region Attributes 5436 'aria-atomic': 0, 5437 'aria-busy': 0, 5438 'aria-live': 0, 5439 'aria-relevant': 0, 5440 // Drag-and-Drop Attributes 5441 'aria-dropeffect': 0, 5442 'aria-grabbed': 0, 5443 // Relationship Attributes 5444 'aria-activedescendant': 0, 5445 'aria-colcount': 0, 5446 'aria-colindex': 0, 5447 'aria-colspan': 0, 5448 'aria-controls': 0, 5449 'aria-describedby': 0, 5450 'aria-errormessage': 0, 5451 'aria-flowto': 0, 5452 'aria-labelledby': 0, 5453 'aria-owns': 0, 5454 'aria-posinset': 0, 5455 'aria-rowcount': 0, 5456 'aria-rowindex': 0, 5457 'aria-rowspan': 0, 5458 'aria-setsize': 0 5459 }; 5460 5461 var warnedProperties = {}; 5462 var rARIA = new RegExp('^(aria)-[' + ATTRIBUTE_NAME_CHAR + ']*$'); 5463 var rARIACamel = new RegExp('^(aria)[A-Z][' + ATTRIBUTE_NAME_CHAR + ']*$'); 5464 var hasOwnProperty$1 = Object.prototype.hasOwnProperty; 5465 5466 function validateProperty(tagName, name) { 5467 { 5468 if (hasOwnProperty$1.call(warnedProperties, name) && warnedProperties[name]) { 5469 return true; 5470 } 5471 5472 if (rARIACamel.test(name)) { 5473 var ariaName = 'aria-' + name.slice(4).toLowerCase(); 5474 var correctName = ariaProperties.hasOwnProperty(ariaName) ? ariaName : null; // If this is an aria-* attribute, but is not listed in the known DOM 5475 // DOM properties, then it is an invalid aria-* attribute. 5476 5477 if (correctName == null) { 5478 error('Invalid ARIA attribute `%s`. ARIA attributes follow the pattern aria-* and must be lowercase.', name); 5479 5480 warnedProperties[name] = true; 5481 return true; 5482 } // aria-* attributes should be lowercase; suggest the lowercase version. 5483 5484 5485 if (name !== correctName) { 5486 error('Invalid ARIA attribute `%s`. Did you mean `%s`?', name, correctName); 5487 5488 warnedProperties[name] = true; 5489 return true; 5490 } 5491 } 5492 5493 if (rARIA.test(name)) { 5494 var lowerCasedName = name.toLowerCase(); 5495 var standardName = ariaProperties.hasOwnProperty(lowerCasedName) ? lowerCasedName : null; // If this is an aria-* attribute, but is not listed in the known DOM 5496 // DOM properties, then it is an invalid aria-* attribute. 5497 5498 if (standardName == null) { 5499 warnedProperties[name] = true; 5500 return false; 5501 } // aria-* attributes should be lowercase; suggest the lowercase version. 5502 5503 5504 if (name !== standardName) { 5505 error('Unknown ARIA attribute `%s`. Did you mean `%s`?', name, standardName); 5506 5507 warnedProperties[name] = true; 5508 return true; 5509 } 5510 } 5511 } 5512 5513 return true; 5514 } 5515 5516 function warnInvalidARIAProps(type, props) { 5517 { 5518 var invalidProps = []; 5519 5520 for (var key in props) { 5521 var isValid = validateProperty(type, key); 5522 5523 if (!isValid) { 5524 invalidProps.push(key); 5525 } 5526 } 5527 5528 var unknownPropString = invalidProps.map(function (prop) { 5529 return '`' + prop + '`'; 5530 }).join(', '); 5531 5532 if (invalidProps.length === 1) { 5533 error('Invalid aria prop %s on <%s> tag. ' + 'For details, see https://fb.me/invalid-aria-prop', unknownPropString, type); 5534 } else if (invalidProps.length > 1) { 5535 error('Invalid aria props %s on <%s> tag. ' + 'For details, see https://fb.me/invalid-aria-prop', unknownPropString, type); 5536 } 5537 } 5538 } 5539 5540 function validateProperties(type, props) { 5541 if (isCustomComponent(type, props)) { 5542 return; 5543 } 5544 5545 warnInvalidARIAProps(type, props); 5546 } 5547 5548 var didWarnValueNull = false; 5549 function validateProperties$1(type, props) { 5550 { 5551 if (type !== 'input' && type !== 'textarea' && type !== 'select') { 5552 return; 5553 } 5554 5555 if (props != null && props.value === null && !didWarnValueNull) { 5556 didWarnValueNull = true; 5557 5558 if (type === 'select' && props.multiple) { 5559 error('`value` prop on `%s` should not be null. ' + 'Consider using an empty array when `multiple` is set to `true` ' + 'to clear the component or `undefined` for uncontrolled components.', type); 5560 } else { 5561 error('`value` prop on `%s` should not be null. ' + 'Consider using an empty string to clear the component or `undefined` ' + 'for uncontrolled components.', type); 5562 } 5563 } 5564 } 5565 } 5566 5567 var validateProperty$1 = function () {}; 5568 5569 { 5570 var warnedProperties$1 = {}; 5571 var _hasOwnProperty = Object.prototype.hasOwnProperty; 5572 var EVENT_NAME_REGEX = /^on./; 5573 var INVALID_EVENT_NAME_REGEX = /^on[^A-Z]/; 5574 var rARIA$1 = new RegExp('^(aria)-[' + ATTRIBUTE_NAME_CHAR + ']*$'); 5575 var rARIACamel$1 = new RegExp('^(aria)[A-Z][' + ATTRIBUTE_NAME_CHAR + ']*$'); 5576 5577 validateProperty$1 = function (tagName, name, value, canUseEventSystem) { 5578 if (_hasOwnProperty.call(warnedProperties$1, name) && warnedProperties$1[name]) { 5579 return true; 5580 } 5581 5582 var lowerCasedName = name.toLowerCase(); 5583 5584 if (lowerCasedName === 'onfocusin' || lowerCasedName === 'onfocusout') { 5585 error('React uses onFocus and onBlur instead of onFocusIn and onFocusOut. ' + 'All React events are normalized to bubble, so onFocusIn and onFocusOut ' + 'are not needed/supported by React.'); 5586 5587 warnedProperties$1[name] = true; 5588 return true; 5589 } // We can't rely on the event system being injected on the server. 5590 5591 5592 if (canUseEventSystem) { 5593 if (registrationNameModules.hasOwnProperty(name)) { 5594 return true; 5595 } 5596 5597 var registrationName = possibleRegistrationNames.hasOwnProperty(lowerCasedName) ? possibleRegistrationNames[lowerCasedName] : null; 5598 5599 if (registrationName != null) { 5600 error('Invalid event handler property `%s`. Did you mean `%s`?', name, registrationName); 5601 5602 warnedProperties$1[name] = true; 5603 return true; 5604 } 5605 5606 if (EVENT_NAME_REGEX.test(name)) { 5607 error('Unknown event handler property `%s`. It will be ignored.', name); 5608 5609 warnedProperties$1[name] = true; 5610 return true; 5611 } 5612 } else if (EVENT_NAME_REGEX.test(name)) { 5613 // If no event plugins have been injected, we are in a server environment. 5614 // So we can't tell if the event name is correct for sure, but we can filter 5615 // out known bad ones like `onclick`. We can't suggest a specific replacement though. 5616 if (INVALID_EVENT_NAME_REGEX.test(name)) { 5617 error('Invalid event handler property `%s`. ' + 'React events use the camelCase naming convention, for example `onClick`.', name); 5618 } 5619 5620 warnedProperties$1[name] = true; 5621 return true; 5622 } // Let the ARIA attribute hook validate ARIA attributes 5623 5624 5625 if (rARIA$1.test(name) || rARIACamel$1.test(name)) { 5626 return true; 5627 } 5628 5629 if (lowerCasedName === 'innerhtml') { 5630 error('Directly setting property `innerHTML` is not permitted. ' + 'For more information, lookup documentation on `dangerouslySetInnerHTML`.'); 5631 5632 warnedProperties$1[name] = true; 5633 return true; 5634 } 5635 5636 if (lowerCasedName === 'aria') { 5637 error('The `aria` attribute is reserved for future use in React. ' + 'Pass individual `aria-` attributes instead.'); 5638 5639 warnedProperties$1[name] = true; 5640 return true; 5641 } 5642 5643 if (lowerCasedName === 'is' && value !== null && value !== undefined && typeof value !== 'string') { 5644 error('Received a `%s` for a string attribute `is`. If this is expected, cast ' + 'the value to a string.', typeof value); 5645 5646 warnedProperties$1[name] = true; 5647 return true; 5648 } 5649 5650 if (typeof value === 'number' && isNaN(value)) { 5651 error('Received NaN for the `%s` attribute. If this is expected, cast ' + 'the value to a string.', name); 5652 5653 warnedProperties$1[name] = true; 5654 return true; 5655 } 5656 5657 var propertyInfo = getPropertyInfo(name); 5658 var isReserved = propertyInfo !== null && propertyInfo.type === RESERVED; // Known attributes should match the casing specified in the property config. 5659 5660 if (possibleStandardNames.hasOwnProperty(lowerCasedName)) { 5661 var standardName = possibleStandardNames[lowerCasedName]; 5662 5663 if (standardName !== name) { 5664 error('Invalid DOM property `%s`. Did you mean `%s`?', name, standardName); 5665 5666 warnedProperties$1[name] = true; 5667 return true; 5668 } 5669 } else if (!isReserved && name !== lowerCasedName) { 5670 // Unknown attributes should have lowercase casing since that's how they 5671 // will be cased anyway with server rendering. 5672 error('React does not recognize the `%s` prop on a DOM element. If you ' + 'intentionally want it to appear in the DOM as a custom ' + 'attribute, spell it as lowercase `%s` instead. ' + 'If you accidentally passed it from a parent component, remove ' + 'it from the DOM element.', name, lowerCasedName); 5673 5674 warnedProperties$1[name] = true; 5675 return true; 5676 } 5677 5678 if (typeof value === 'boolean' && shouldRemoveAttributeWithWarning(name, value, propertyInfo, false)) { 5679 if (value) { 5680 error('Received `%s` for a non-boolean attribute `%s`.\n\n' + 'If you want to write it to the DOM, pass a string instead: ' + '%s="%s" or %s={value.toString()}.', value, name, name, value, name); 5681 } else { 5682 error('Received `%s` for a non-boolean attribute `%s`.\n\n' + 'If you want to write it to the DOM, pass a string instead: ' + '%s="%s" or %s={value.toString()}.\n\n' + 'If you used to conditionally omit it with %s={condition && value}, ' + 'pass %s={condition ? value : undefined} instead.', value, name, name, value, name, name, name); 5683 } 5684 5685 warnedProperties$1[name] = true; 5686 return true; 5687 } // Now that we've validated casing, do not validate 5688 // data types for reserved props 5689 5690 5691 if (isReserved) { 5692 return true; 5693 } // Warn when a known attribute is a bad type 5694 5695 5696 if (shouldRemoveAttributeWithWarning(name, value, propertyInfo, false)) { 5697 warnedProperties$1[name] = true; 5698 return false; 5699 } // Warn when passing the strings 'false' or 'true' into a boolean prop 5700 5701 5702 if ((value === 'false' || value === 'true') && propertyInfo !== null && propertyInfo.type === BOOLEAN) { 5703 error('Received the string `%s` for the boolean attribute `%s`. ' + '%s ' + 'Did you mean %s={%s}?', value, name, value === 'false' ? 'The browser will interpret it as a truthy value.' : 'Although this works, it will not work as expected if you pass the string "false".', name, value); 5704 5705 warnedProperties$1[name] = true; 5706 return true; 5707 } 5708 5709 return true; 5710 }; 5711 } 5712 5713 var warnUnknownProperties = function (type, props, canUseEventSystem) { 5714 { 5715 var unknownProps = []; 5716 5717 for (var key in props) { 5718 var isValid = validateProperty$1(type, key, props[key], canUseEventSystem); 5719 5720 if (!isValid) { 5721 unknownProps.push(key); 5722 } 5723 } 5724 5725 var unknownPropString = unknownProps.map(function (prop) { 5726 return '`' + prop + '`'; 5727 }).join(', '); 5728 5729 if (unknownProps.length === 1) { 5730 error('Invalid value for prop %s on <%s> tag. Either remove it from the element, ' + 'or pass a string or number value to keep it in the DOM. ' + 'For details, see https://fb.me/react-attribute-behavior', unknownPropString, type); 5731 } else if (unknownProps.length > 1) { 5732 error('Invalid values for props %s on <%s> tag. Either remove them from the element, ' + 'or pass a string or number value to keep them in the DOM. ' + 'For details, see https://fb.me/react-attribute-behavior', unknownPropString, type); 5733 } 5734 } 5735 }; 5736 5737 function validateProperties$2(type, props, canUseEventSystem) { 5738 if (isCustomComponent(type, props)) { 5739 return; 5740 } 5741 5742 warnUnknownProperties(type, props, canUseEventSystem); 5743 } 5744 5745 var didWarnInvalidHydration = false; 5746 var DANGEROUSLY_SET_INNER_HTML = 'dangerouslySetInnerHTML'; 5747 var SUPPRESS_CONTENT_EDITABLE_WARNING = 'suppressContentEditableWarning'; 5748 var SUPPRESS_HYDRATION_WARNING = 'suppressHydrationWarning'; 5749 var AUTOFOCUS = 'autoFocus'; 5750 var CHILDREN = 'children'; 5751 var STYLE = 'style'; 5752 var HTML$1 = '__html'; 5753 var HTML_NAMESPACE$1 = Namespaces.html; 5754 var warnedUnknownTags; 5755 var suppressHydrationWarning; 5756 var validatePropertiesInDevelopment; 5757 var warnForTextDifference; 5758 var warnForPropDifference; 5759 var warnForExtraAttributes; 5760 var warnForInvalidEventListener; 5761 var canDiffStyleForHydrationWarning; 5762 var normalizeMarkupForTextOrAttribute; 5763 var normalizeHTML; 5764 5765 { 5766 warnedUnknownTags = { 5767 // Chrome is the only major browser not shipping <time>. But as of July 5768 // 2017 it intends to ship it due to widespread usage. We intentionally 5769 // *don't* warn for <time> even if it's unrecognized by Chrome because 5770 // it soon will be, and many apps have been using it anyway. 5771 time: true, 5772 // There are working polyfills for <dialog>. Let people use it. 5773 dialog: true, 5774 // Electron ships a custom <webview> tag to display external web content in 5775 // an isolated frame and process. 5776 // This tag is not present in non Electron environments such as JSDom which 5777 // is often used for testing purposes. 5778 // @see https://electronjs.org/docs/api/webview-tag 5779 webview: true 5780 }; 5781 5782 validatePropertiesInDevelopment = function (type, props) { 5783 validateProperties(type, props); 5784 validateProperties$1(type, props); 5785 validateProperties$2(type, props, 5786 /* canUseEventSystem */ 5787 true); 5788 }; // IE 11 parses & normalizes the style attribute as opposed to other 5789 // browsers. It adds spaces and sorts the properties in some 5790 // non-alphabetical order. Handling that would require sorting CSS 5791 // properties in the client & server versions or applying 5792 // `expectedStyle` to a temporary DOM node to read its `style` attribute 5793 // normalized. Since it only affects IE, we're skipping style warnings 5794 // in that browser completely in favor of doing all that work. 5795 // See https://github.com/facebook/react/issues/11807 5796 5797 5798 canDiffStyleForHydrationWarning = canUseDOM && !document.documentMode; // HTML parsing normalizes CR and CRLF to LF. 5799 // It also can turn \u0000 into \uFFFD inside attributes. 5800 // https://www.w3.org/TR/html5/single-page.html#preprocessing-the-input-stream 5801 // If we have a mismatch, it might be caused by that. 5802 // We will still patch up in this case but not fire the warning. 5803 5804 var NORMALIZE_NEWLINES_REGEX = /\r\n?/g; 5805 var NORMALIZE_NULL_AND_REPLACEMENT_REGEX = /\u0000|\uFFFD/g; 5806 5807 normalizeMarkupForTextOrAttribute = function (markup) { 5808 var markupString = typeof markup === 'string' ? markup : '' + markup; 5809 return markupString.replace(NORMALIZE_NEWLINES_REGEX, '\n').replace(NORMALIZE_NULL_AND_REPLACEMENT_REGEX, ''); 5810 }; 5811 5812 warnForTextDifference = function (serverText, clientText) { 5813 if (didWarnInvalidHydration) { 5814 return; 5815 } 5816 5817 var normalizedClientText = normalizeMarkupForTextOrAttribute(clientText); 5818 var normalizedServerText = normalizeMarkupForTextOrAttribute(serverText); 5819 5820 if (normalizedServerText === normalizedClientText) { 5821 return; 5822 } 5823 5824 didWarnInvalidHydration = true; 5825 5826 error('Text content did not match. Server: "%s" Client: "%s"', normalizedServerText, normalizedClientText); 5827 }; 5828 5829 warnForPropDifference = function (propName, serverValue, clientValue) { 5830 if (didWarnInvalidHydration) { 5831 return; 5832 } 5833 5834 var normalizedClientValue = normalizeMarkupForTextOrAttribute(clientValue); 5835 var normalizedServerValue = normalizeMarkupForTextOrAttribute(serverValue); 5836 5837 if (normalizedServerValue === normalizedClientValue) { 5838 return; 5839 } 5840 5841 didWarnInvalidHydration = true; 5842 5843 error('Prop `%s` did not match. Server: %s Client: %s', propName, JSON.stringify(normalizedServerValue), JSON.stringify(normalizedClientValue)); 5844 }; 5845 5846 warnForExtraAttributes = function (attributeNames) { 5847 if (didWarnInvalidHydration) { 5848 return; 5849 } 5850 5851 didWarnInvalidHydration = true; 5852 var names = []; 5853 attributeNames.forEach(function (name) { 5854 names.push(name); 5855 }); 5856 5857 error('Extra attributes from the server: %s', names); 5858 }; 5859 5860 warnForInvalidEventListener = function (registrationName, listener) { 5861 if (listener === false) { 5862 error('Expected `%s` listener to be a function, instead got `false`.\n\n' + 'If you used to conditionally omit it with %s={condition && value}, ' + 'pass %s={condition ? value : undefined} instead.', registrationName, registrationName, registrationName); 5863 } else { 5864 error('Expected `%s` listener to be a function, instead got a value of `%s` type.', registrationName, typeof listener); 5865 } 5866 }; // Parse the HTML and read it back to normalize the HTML string so that it 5867 // can be used for comparison. 5868 5869 5870 normalizeHTML = function (parent, html) { 5871 // We could have created a separate document here to avoid 5872 // re-initializing custom elements if they exist. But this breaks 5873 // how <noscript> is being handled. So we use the same document. 5874 // See the discussion in https://github.com/facebook/react/pull/11157. 5875 var testElement = parent.namespaceURI === HTML_NAMESPACE$1 ? parent.ownerDocument.createElement(parent.tagName) : parent.ownerDocument.createElementNS(parent.namespaceURI, parent.tagName); 5876 testElement.innerHTML = html; 5877 return testElement.innerHTML; 5878 }; 5879 } 5880 5881 function ensureListeningTo(rootContainerElement, registrationName) { 5882 var isDocumentOrFragment = rootContainerElement.nodeType === DOCUMENT_NODE || rootContainerElement.nodeType === DOCUMENT_FRAGMENT_NODE; 5883 var doc = isDocumentOrFragment ? rootContainerElement : rootContainerElement.ownerDocument; 5884 legacyListenToEvent(registrationName, doc); 5885 } 5886 5887 function getOwnerDocumentFromRootContainer(rootContainerElement) { 5888 return rootContainerElement.nodeType === DOCUMENT_NODE ? rootContainerElement : rootContainerElement.ownerDocument; 5889 } 5890 5891 function noop() {} 5892 5893 function trapClickOnNonInteractiveElement(node) { 5894 // Mobile Safari does not fire properly bubble click events on 5895 // non-interactive elements, which means delegated click listeners do not 5896 // fire. The workaround for this bug involves attaching an empty click 5897 // listener on the target node. 5898 // http://www.quirksmode.org/blog/archives/2010/09/click_event_del.html 5899 // Just set it using the onclick property so that we don't have to manage any 5900 // bookkeeping for it. Not sure if we need to clear it when the listener is 5901 // removed. 5902 // TODO: Only do this for the relevant Safaris maybe? 5903 node.onclick = noop; 5904 } 5905 5906 function setInitialDOMProperties(tag, domElement, rootContainerElement, nextProps, isCustomComponentTag) { 5907 for (var propKey in nextProps) { 5908 if (!nextProps.hasOwnProperty(propKey)) { 5909 continue; 5910 } 5911 5912 var nextProp = nextProps[propKey]; 5913 5914 if (propKey === STYLE) { 5915 { 5916 if (nextProp) { 5917 // Freeze the next style object so that we can assume it won't be 5918 // mutated. We have already warned for this in the past. 5919 Object.freeze(nextProp); 5920 } 5921 } // Relies on `updateStylesByID` not mutating `styleUpdates`. 5922 5923 5924 setValueForStyles(domElement, nextProp); 5925 } else if (propKey === DANGEROUSLY_SET_INNER_HTML) { 5926 var nextHtml = nextProp ? nextProp[HTML$1] : undefined; 5927 5928 if (nextHtml != null) { 5929 setInnerHTML(domElement, nextHtml); 5930 } 5931 } else if (propKey === CHILDREN) { 5932 if (typeof nextProp === 'string') { 5933 // Avoid setting initial textContent when the text is empty. In IE11 setting 5934 // textContent on a <textarea> will cause the placeholder to not 5935 // show within the <textarea> until it has been focused and blurred again. 5936 // https://github.com/facebook/react/issues/6731#issuecomment-254874553 5937 var canSetTextContent = tag !== 'textarea' || nextProp !== ''; 5938 5939 if (canSetTextContent) { 5940 setTextContent(domElement, nextProp); 5941 } 5942 } else if (typeof nextProp === 'number') { 5943 setTextContent(domElement, '' + nextProp); 5944 } 5945 } else if ( propKey === SUPPRESS_CONTENT_EDITABLE_WARNING || propKey === SUPPRESS_HYDRATION_WARNING) ; else if (propKey === AUTOFOCUS) ; else if (registrationNameModules.hasOwnProperty(propKey)) { 5946 if (nextProp != null) { 5947 if ( typeof nextProp !== 'function') { 5948 warnForInvalidEventListener(propKey, nextProp); 5949 } 5950 5951 ensureListeningTo(rootContainerElement, propKey); 5952 } 5953 } else if (nextProp != null) { 5954 setValueForProperty(domElement, propKey, nextProp, isCustomComponentTag); 5955 } 5956 } 5957 } 5958 5959 function updateDOMProperties(domElement, updatePayload, wasCustomComponentTag, isCustomComponentTag) { 5960 // TODO: Handle wasCustomComponentTag 5961 for (var i = 0; i < updatePayload.length; i += 2) { 5962 var propKey = updatePayload[i]; 5963 var propValue = updatePayload[i + 1]; 5964 5965 if (propKey === STYLE) { 5966 setValueForStyles(domElement, propValue); 5967 } else if (propKey === DANGEROUSLY_SET_INNER_HTML) { 5968 setInnerHTML(domElement, propValue); 5969 } else if (propKey === CHILDREN) { 5970 setTextContent(domElement, propValue); 5971 } else { 5972 setValueForProperty(domElement, propKey, propValue, isCustomComponentTag); 5973 } 5974 } 5975 } 5976 5977 function createElement(type, props, rootContainerElement, parentNamespace) { 5978 var isCustomComponentTag; // We create tags in the namespace of their parent container, except HTML 5979 // tags get no namespace. 5980 5981 var ownerDocument = getOwnerDocumentFromRootContainer(rootContainerElement); 5982 var domElement; 5983 var namespaceURI = parentNamespace; 5984 5985 if (namespaceURI === HTML_NAMESPACE$1) { 5986 namespaceURI = getIntrinsicNamespace(type); 5987 } 5988 5989 if (namespaceURI === HTML_NAMESPACE$1) { 5990 { 5991 isCustomComponentTag = isCustomComponent(type, props); // Should this check be gated by parent namespace? Not sure we want to 5992 // allow <SVG> or <mATH>. 5993 5994 if (!isCustomComponentTag && type !== type.toLowerCase()) { 5995 error('<%s /> is using incorrect casing. ' + 'Use PascalCase for React components, ' + 'or lowercase for HTML elements.', type); 5996 } 5997 } 5998 5999 if (type === 'script') { 6000 // Create the script via .innerHTML so its "parser-inserted" flag is 6001 // set to true and it does not execute 6002 var div = ownerDocument.createElement('div'); 6003 6004 div.innerHTML = '<script><' + '/script>'; // eslint-disable-line 6005 // This is guaranteed to yield a script element. 6006 6007 var firstChild = div.firstChild; 6008 domElement = div.removeChild(firstChild); 6009 } else if (typeof props.is === 'string') { 6010 // $FlowIssue `createElement` should be updated for Web Components 6011 domElement = ownerDocument.createElement(type, { 6012 is: props.is 6013 }); 6014 } else { 6015 // Separate else branch instead of using `props.is || undefined` above because of a Firefox bug. 6016 // See discussion in https://github.com/facebook/react/pull/6896 6017 // and discussion in https://bugzilla.mozilla.org/show_bug.cgi?id=1276240 6018 domElement = ownerDocument.createElement(type); // Normally attributes are assigned in `setInitialDOMProperties`, however the `multiple` and `size` 6019 // attributes on `select`s needs to be added before `option`s are inserted. 6020 // This prevents: 6021 // - a bug where the `select` does not scroll to the correct option because singular 6022 // `select` elements automatically pick the first item #13222 6023 // - a bug where the `select` set the first item as selected despite the `size` attribute #14239 6024 // See https://github.com/facebook/react/issues/13222 6025 // and https://github.com/facebook/react/issues/14239 6026 6027 if (type === 'select') { 6028 var node = domElement; 6029 6030 if (props.multiple) { 6031 node.multiple = true; 6032 } else if (props.size) { 6033 // Setting a size greater than 1 causes a select to behave like `multiple=true`, where 6034 // it is possible that no option is selected. 6035 // 6036 // This is only necessary when a select in "single selection mode". 6037 node.size = props.size; 6038 } 6039 } 6040 } 6041 } else { 6042 domElement = ownerDocument.createElementNS(namespaceURI, type); 6043 } 6044 6045 { 6046 if (namespaceURI === HTML_NAMESPACE$1) { 6047 if (!isCustomComponentTag && Object.prototype.toString.call(domElement) === '[object HTMLUnknownElement]' && !Object.prototype.hasOwnProperty.call(warnedUnknownTags, type)) { 6048 warnedUnknownTags[type] = true; 6049 6050 error('The tag <%s> is unrecognized in this browser. ' + 'If you meant to render a React component, start its name with ' + 'an uppercase letter.', type); 6051 } 6052 } 6053 } 6054 6055 return domElement; 6056 } 6057 function createTextNode(text, rootContainerElement) { 6058 return getOwnerDocumentFromRootContainer(rootContainerElement).createTextNode(text); 6059 } 6060 function setInitialProperties(domElement, tag, rawProps, rootContainerElement) { 6061 var isCustomComponentTag = isCustomComponent(tag, rawProps); 6062 6063 { 6064 validatePropertiesInDevelopment(tag, rawProps); 6065 } // TODO: Make sure that we check isMounted before firing any of these events. 6066 6067 6068 var props; 6069 6070 switch (tag) { 6071 case 'iframe': 6072 case 'object': 6073 case 'embed': 6074 trapBubbledEvent(TOP_LOAD, domElement); 6075 props = rawProps; 6076 break; 6077 6078 case 'video': 6079 case 'audio': 6080 // Create listener for each media event 6081 for (var i = 0; i < mediaEventTypes.length; i++) { 6082 trapBubbledEvent(mediaEventTypes[i], domElement); 6083 } 6084 6085 props = rawProps; 6086 break; 6087 6088 case 'source': 6089 trapBubbledEvent(TOP_ERROR, domElement); 6090 props = rawProps; 6091 break; 6092 6093 case 'img': 6094 case 'image': 6095 case 'link': 6096 trapBubbledEvent(TOP_ERROR, domElement); 6097 trapBubbledEvent(TOP_LOAD, domElement); 6098 props = rawProps; 6099 break; 6100 6101 case 'form': 6102 trapBubbledEvent(TOP_RESET, domElement); 6103 trapBubbledEvent(TOP_SUBMIT, domElement); 6104 props = rawProps; 6105 break; 6106 6107 case 'details': 6108 trapBubbledEvent(TOP_TOGGLE, domElement); 6109 props = rawProps; 6110 break; 6111 6112 case 'input': 6113 initWrapperState(domElement, rawProps); 6114 props = getHostProps(domElement, rawProps); 6115 trapBubbledEvent(TOP_INVALID, domElement); // For controlled components we always need to ensure we're listening 6116 // to onChange. Even if there is no listener. 6117 6118 ensureListeningTo(rootContainerElement, 'onChange'); 6119 break; 6120 6121 case 'option': 6122 validateProps(domElement, rawProps); 6123 props = getHostProps$1(domElement, rawProps); 6124 break; 6125 6126 case 'select': 6127 initWrapperState$1(domElement, rawProps); 6128 props = getHostProps$2(domElement, rawProps); 6129 trapBubbledEvent(TOP_INVALID, domElement); // For controlled components we always need to ensure we're listening 6130 // to onChange. Even if there is no listener. 6131 6132 ensureListeningTo(rootContainerElement, 'onChange'); 6133 break; 6134 6135 case 'textarea': 6136 initWrapperState$2(domElement, rawProps); 6137 props = getHostProps$3(domElement, rawProps); 6138 trapBubbledEvent(TOP_INVALID, domElement); // For controlled components we always need to ensure we're listening 6139 // to onChange. Even if there is no listener. 6140 6141 ensureListeningTo(rootContainerElement, 'onChange'); 6142 break; 6143 6144 default: 6145 props = rawProps; 6146 } 6147 6148 assertValidProps(tag, props); 6149 setInitialDOMProperties(tag, domElement, rootContainerElement, props, isCustomComponentTag); 6150 6151 switch (tag) { 6152 case 'input': 6153 // TODO: Make sure we check if this is still unmounted or do any clean 6154 // up necessary since we never stop tracking anymore. 6155 track(domElement); 6156 postMountWrapper(domElement, rawProps, false); 6157 break; 6158 6159 case 'textarea': 6160 // TODO: Make sure we check if this is still unmounted or do any clean 6161 // up necessary since we never stop tracking anymore. 6162 track(domElement); 6163 postMountWrapper$3(domElement); 6164 break; 6165 6166 case 'option': 6167 postMountWrapper$1(domElement, rawProps); 6168 break; 6169 6170 case 'select': 6171 postMountWrapper$2(domElement, rawProps); 6172 break; 6173 6174 default: 6175 if (typeof props.onClick === 'function') { 6176 // TODO: This cast may not be sound for SVG, MathML or custom elements. 6177 trapClickOnNonInteractiveElement(domElement); 6178 } 6179 6180 break; 6181 } 6182 } // Calculate the diff between the two objects. 6183 6184 function diffProperties(domElement, tag, lastRawProps, nextRawProps, rootContainerElement) { 6185 { 6186 validatePropertiesInDevelopment(tag, nextRawProps); 6187 } 6188 6189 var updatePayload = null; 6190 var lastProps; 6191 var nextProps; 6192 6193 switch (tag) { 6194 case 'input': 6195 lastProps = getHostProps(domElement, lastRawProps); 6196 nextProps = getHostProps(domElement, nextRawProps); 6197 updatePayload = []; 6198 break; 6199 6200 case 'option': 6201 lastProps = getHostProps$1(domElement, lastRawProps); 6202 nextProps = getHostProps$1(domElement, nextRawProps); 6203 updatePayload = []; 6204 break; 6205 6206 case 'select': 6207 lastProps = getHostProps$2(domElement, lastRawProps); 6208 nextProps = getHostProps$2(domElement, nextRawProps); 6209 updatePayload = []; 6210 break; 6211 6212 case 'textarea': 6213 lastProps = getHostProps$3(domElement, lastRawProps); 6214 nextProps = getHostProps$3(domElement, nextRawProps); 6215 updatePayload = []; 6216 break; 6217 6218 default: 6219 lastProps = lastRawProps; 6220 nextProps = nextRawProps; 6221 6222 if (typeof lastProps.onClick !== 'function' && typeof nextProps.onClick === 'function') { 6223 // TODO: This cast may not be sound for SVG, MathML or custom elements. 6224 trapClickOnNonInteractiveElement(domElement); 6225 } 6226 6227 break; 6228 } 6229 6230 assertValidProps(tag, nextProps); 6231 var propKey; 6232 var styleName; 6233 var styleUpdates = null; 6234 6235 for (propKey in lastProps) { 6236 if (nextProps.hasOwnProperty(propKey) || !lastProps.hasOwnProperty(propKey) || lastProps[propKey] == null) { 6237 continue; 6238 } 6239 6240 if (propKey === STYLE) { 6241 var lastStyle = lastProps[propKey]; 6242 6243 for (styleName in lastStyle) { 6244 if (lastStyle.hasOwnProperty(styleName)) { 6245 if (!styleUpdates) { 6246 styleUpdates = {}; 6247 } 6248 6249 styleUpdates[styleName] = ''; 6250 } 6251 } 6252 } else if (propKey === DANGEROUSLY_SET_INNER_HTML || propKey === CHILDREN) ; else if ( propKey === SUPPRESS_CONTENT_EDITABLE_WARNING || propKey === SUPPRESS_HYDRATION_WARNING) ; else if (propKey === AUTOFOCUS) ; else if (registrationNameModules.hasOwnProperty(propKey)) { 6253 // This is a special case. If any listener updates we need to ensure 6254 // that the "current" fiber pointer gets updated so we need a commit 6255 // to update this element. 6256 if (!updatePayload) { 6257 updatePayload = []; 6258 } 6259 } else { 6260 // For all other deleted properties we add it to the queue. We use 6261 // the whitelist in the commit phase instead. 6262 (updatePayload = updatePayload || []).push(propKey, null); 6263 } 6264 } 6265 6266 for (propKey in nextProps) { 6267 var nextProp = nextProps[propKey]; 6268 var lastProp = lastProps != null ? lastProps[propKey] : undefined; 6269 6270 if (!nextProps.hasOwnProperty(propKey) || nextProp === lastProp || nextProp == null && lastProp == null) { 6271 continue; 6272 } 6273 6274 if (propKey === STYLE) { 6275 { 6276 if (nextProp) { 6277 // Freeze the next style object so that we can assume it won't be 6278 // mutated. We have already warned for this in the past. 6279 Object.freeze(nextProp); 6280 } 6281 } 6282 6283 if (lastProp) { 6284 // Unset styles on `lastProp` but not on `nextProp`. 6285 for (styleName in lastProp) { 6286 if (lastProp.hasOwnProperty(styleName) && (!nextProp || !nextProp.hasOwnProperty(styleName))) { 6287 if (!styleUpdates) { 6288 styleUpdates = {}; 6289 } 6290 6291 styleUpdates[styleName] = ''; 6292 } 6293 } // Update styles that changed since `lastProp`. 6294 6295 6296 for (styleName in nextProp) { 6297 if (nextProp.hasOwnProperty(styleName) && lastProp[styleName] !== nextProp[styleName]) { 6298 if (!styleUpdates) { 6299 styleUpdates = {}; 6300 } 6301 6302 styleUpdates[styleName] = nextProp[styleName]; 6303 } 6304 } 6305 } else { 6306 // Relies on `updateStylesByID` not mutating `styleUpdates`. 6307 if (!styleUpdates) { 6308 if (!updatePayload) { 6309 updatePayload = []; 6310 } 6311 6312 updatePayload.push(propKey, styleUpdates); 6313 } 6314 6315 styleUpdates = nextProp; 6316 } 6317 } else if (propKey === DANGEROUSLY_SET_INNER_HTML) { 6318 var nextHtml = nextProp ? nextProp[HTML$1] : undefined; 6319 var lastHtml = lastProp ? lastProp[HTML$1] : undefined; 6320 6321 if (nextHtml != null) { 6322 if (lastHtml !== nextHtml) { 6323 (updatePayload = updatePayload || []).push(propKey, nextHtml); 6324 } 6325 } 6326 } else if (propKey === CHILDREN) { 6327 if (lastProp !== nextProp && (typeof nextProp === 'string' || typeof nextProp === 'number')) { 6328 (updatePayload = updatePayload || []).push(propKey, '' + nextProp); 6329 } 6330 } else if ( propKey === SUPPRESS_CONTENT_EDITABLE_WARNING || propKey === SUPPRESS_HYDRATION_WARNING) ; else if (registrationNameModules.hasOwnProperty(propKey)) { 6331 if (nextProp != null) { 6332 // We eagerly listen to this even though we haven't committed yet. 6333 if ( typeof nextProp !== 'function') { 6334 warnForInvalidEventListener(propKey, nextProp); 6335 } 6336 6337 ensureListeningTo(rootContainerElement, propKey); 6338 } 6339 6340 if (!updatePayload && lastProp !== nextProp) { 6341 // This is a special case. If any listener updates we need to ensure 6342 // that the "current" props pointer gets updated so we need a commit 6343 // to update this element. 6344 updatePayload = []; 6345 } 6346 } else { 6347 // For any other property we always add it to the queue and then we 6348 // filter it out using the whitelist during the commit. 6349 (updatePayload = updatePayload || []).push(propKey, nextProp); 6350 } 6351 } 6352 6353 if (styleUpdates) { 6354 { 6355 validateShorthandPropertyCollisionInDev(styleUpdates, nextProps[STYLE]); 6356 } 6357 6358 (updatePayload = updatePayload || []).push(STYLE, styleUpdates); 6359 } 6360 6361 return updatePayload; 6362 } // Apply the diff. 6363 6364 function updateProperties(domElement, updatePayload, tag, lastRawProps, nextRawProps) { 6365 // Update checked *before* name. 6366 // In the middle of an update, it is possible to have multiple checked. 6367 // When a checked radio tries to change name, browser makes another radio's checked false. 6368 if (tag === 'input' && nextRawProps.type === 'radio' && nextRawProps.name != null) { 6369 updateChecked(domElement, nextRawProps); 6370 } 6371 6372 var wasCustomComponentTag = isCustomComponent(tag, lastRawProps); 6373 var isCustomComponentTag = isCustomComponent(tag, nextRawProps); // Apply the diff. 6374 6375 updateDOMProperties(domElement, updatePayload, wasCustomComponentTag, isCustomComponentTag); // TODO: Ensure that an update gets scheduled if any of the special props 6376 // changed. 6377 6378 switch (tag) { 6379 case 'input': 6380 // Update the wrapper around inputs *after* updating props. This has to 6381 // happen after `updateDOMProperties`. Otherwise HTML5 input validations 6382 // raise warnings and prevent the new value from being assigned. 6383 updateWrapper(domElement, nextRawProps); 6384 break; 6385 6386 case 'textarea': 6387 updateWrapper$1(domElement, nextRawProps); 6388 break; 6389 6390 case 'select': 6391 // <select> value update needs to occur after <option> children 6392 // reconciliation 6393 postUpdateWrapper(domElement, nextRawProps); 6394 break; 6395 } 6396 } 6397 6398 function getPossibleStandardName(propName) { 6399 { 6400 var lowerCasedName = propName.toLowerCase(); 6401 6402 if (!possibleStandardNames.hasOwnProperty(lowerCasedName)) { 6403 return null; 6404 } 6405 6406 return possibleStandardNames[lowerCasedName] || null; 6407 } 6408 } 6409 6410 function diffHydratedProperties(domElement, tag, rawProps, parentNamespace, rootContainerElement) { 6411 var isCustomComponentTag; 6412 var extraAttributeNames; 6413 6414 { 6415 suppressHydrationWarning = rawProps[SUPPRESS_HYDRATION_WARNING] === true; 6416 isCustomComponentTag = isCustomComponent(tag, rawProps); 6417 validatePropertiesInDevelopment(tag, rawProps); 6418 } // TODO: Make sure that we check isMounted before firing any of these events. 6419 6420 6421 switch (tag) { 6422 case 'iframe': 6423 case 'object': 6424 case 'embed': 6425 trapBubbledEvent(TOP_LOAD, domElement); 6426 break; 6427 6428 case 'video': 6429 case 'audio': 6430 // Create listener for each media event 6431 for (var i = 0; i < mediaEventTypes.length; i++) { 6432 trapBubbledEvent(mediaEventTypes[i], domElement); 6433 } 6434 6435 break; 6436 6437 case 'source': 6438 trapBubbledEvent(TOP_ERROR, domElement); 6439 break; 6440 6441 case 'img': 6442 case 'image': 6443 case 'link': 6444 trapBubbledEvent(TOP_ERROR, domElement); 6445 trapBubbledEvent(TOP_LOAD, domElement); 6446 break; 6447 6448 case 'form': 6449 trapBubbledEvent(TOP_RESET, domElement); 6450 trapBubbledEvent(TOP_SUBMIT, domElement); 6451 break; 6452 6453 case 'details': 6454 trapBubbledEvent(TOP_TOGGLE, domElement); 6455 break; 6456 6457 case 'input': 6458 initWrapperState(domElement, rawProps); 6459 trapBubbledEvent(TOP_INVALID, domElement); // For controlled components we always need to ensure we're listening 6460 // to onChange. Even if there is no listener. 6461 6462 ensureListeningTo(rootContainerElement, 'onChange'); 6463 break; 6464 6465 case 'option': 6466 validateProps(domElement, rawProps); 6467 break; 6468 6469 case 'select': 6470 initWrapperState$1(domElement, rawProps); 6471 trapBubbledEvent(TOP_INVALID, domElement); // For controlled components we always need to ensure we're listening 6472 // to onChange. Even if there is no listener. 6473 6474 ensureListeningTo(rootContainerElement, 'onChange'); 6475 break; 6476 6477 case 'textarea': 6478 initWrapperState$2(domElement, rawProps); 6479 trapBubbledEvent(TOP_INVALID, domElement); // For controlled components we always need to ensure we're listening 6480 // to onChange. Even if there is no listener. 6481 6482 ensureListeningTo(rootContainerElement, 'onChange'); 6483 break; 6484 } 6485 6486 assertValidProps(tag, rawProps); 6487 6488 { 6489 extraAttributeNames = new Set(); 6490 var attributes = domElement.attributes; 6491 6492 for (var _i = 0; _i < attributes.length; _i++) { 6493 var name = attributes[_i].name.toLowerCase(); 6494 6495 switch (name) { 6496 // Built-in SSR attribute is whitelisted 6497 case 'data-reactroot': 6498 break; 6499 // Controlled attributes are not validated 6500 // TODO: Only ignore them on controlled tags. 6501 6502 case 'value': 6503 break; 6504 6505 case 'checked': 6506 break; 6507 6508 case 'selected': 6509 break; 6510 6511 default: 6512 // Intentionally use the original name. 6513 // See discussion in https://github.com/facebook/react/pull/10676. 6514 extraAttributeNames.add(attributes[_i].name); 6515 } 6516 } 6517 } 6518 6519 var updatePayload = null; 6520 6521 for (var propKey in rawProps) { 6522 if (!rawProps.hasOwnProperty(propKey)) { 6523 continue; 6524 } 6525 6526 var nextProp = rawProps[propKey]; 6527 6528 if (propKey === CHILDREN) { 6529 // For text content children we compare against textContent. This 6530 // might match additional HTML that is hidden when we read it using 6531 // textContent. E.g. "foo" will match "f<span>oo</span>" but that still 6532 // satisfies our requirement. Our requirement is not to produce perfect 6533 // HTML and attributes. Ideally we should preserve structure but it's 6534 // ok not to if the visible content is still enough to indicate what 6535 // even listeners these nodes might be wired up to. 6536 // TODO: Warn if there is more than a single textNode as a child. 6537 // TODO: Should we use domElement.firstChild.nodeValue to compare? 6538 if (typeof nextProp === 'string') { 6539 if (domElement.textContent !== nextProp) { 6540 if ( !suppressHydrationWarning) { 6541 warnForTextDifference(domElement.textContent, nextProp); 6542 } 6543 6544 updatePayload = [CHILDREN, nextProp]; 6545 } 6546 } else if (typeof nextProp === 'number') { 6547 if (domElement.textContent !== '' + nextProp) { 6548 if ( !suppressHydrationWarning) { 6549 warnForTextDifference(domElement.textContent, nextProp); 6550 } 6551 6552 updatePayload = [CHILDREN, '' + nextProp]; 6553 } 6554 } 6555 } else if (registrationNameModules.hasOwnProperty(propKey)) { 6556 if (nextProp != null) { 6557 if ( typeof nextProp !== 'function') { 6558 warnForInvalidEventListener(propKey, nextProp); 6559 } 6560 6561 ensureListeningTo(rootContainerElement, propKey); 6562 } 6563 } else if ( // Convince Flow we've calculated it (it's DEV-only in this method.) 6564 typeof isCustomComponentTag === 'boolean') { 6565 // Validate that the properties correspond to their expected values. 6566 var serverValue = void 0; 6567 var propertyInfo = getPropertyInfo(propKey); 6568 6569 if (suppressHydrationWarning) ; else if ( propKey === SUPPRESS_CONTENT_EDITABLE_WARNING || propKey === SUPPRESS_HYDRATION_WARNING || // Controlled attributes are not validated 6570 // TODO: Only ignore them on controlled tags. 6571 propKey === 'value' || propKey === 'checked' || propKey === 'selected') ; else if (propKey === DANGEROUSLY_SET_INNER_HTML) { 6572 var serverHTML = domElement.innerHTML; 6573 var nextHtml = nextProp ? nextProp[HTML$1] : undefined; 6574 var expectedHTML = normalizeHTML(domElement, nextHtml != null ? nextHtml : ''); 6575 6576 if (expectedHTML !== serverHTML) { 6577 warnForPropDifference(propKey, serverHTML, expectedHTML); 6578 } 6579 } else if (propKey === STYLE) { 6580 // $FlowFixMe - Should be inferred as not undefined. 6581 extraAttributeNames.delete(propKey); 6582 6583 if (canDiffStyleForHydrationWarning) { 6584 var expectedStyle = createDangerousStringForStyles(nextProp); 6585 serverValue = domElement.getAttribute('style'); 6586 6587 if (expectedStyle !== serverValue) { 6588 warnForPropDifference(propKey, serverValue, expectedStyle); 6589 } 6590 } 6591 } else if (isCustomComponentTag) { 6592 // $FlowFixMe - Should be inferred as not undefined. 6593 extraAttributeNames.delete(propKey.toLowerCase()); 6594 serverValue = getValueForAttribute(domElement, propKey, nextProp); 6595 6596 if (nextProp !== serverValue) { 6597 warnForPropDifference(propKey, serverValue, nextProp); 6598 } 6599 } else if (!shouldIgnoreAttribute(propKey, propertyInfo, isCustomComponentTag) && !shouldRemoveAttribute(propKey, nextProp, propertyInfo, isCustomComponentTag)) { 6600 var isMismatchDueToBadCasing = false; 6601 6602 if (propertyInfo !== null) { 6603 // $FlowFixMe - Should be inferred as not undefined. 6604 extraAttributeNames.delete(propertyInfo.attributeName); 6605 serverValue = getValueForProperty(domElement, propKey, nextProp, propertyInfo); 6606 } else { 6607 var ownNamespace = parentNamespace; 6608 6609 if (ownNamespace === HTML_NAMESPACE$1) { 6610 ownNamespace = getIntrinsicNamespace(tag); 6611 } 6612 6613 if (ownNamespace === HTML_NAMESPACE$1) { 6614 // $FlowFixMe - Should be inferred as not undefined. 6615 extraAttributeNames.delete(propKey.toLowerCase()); 6616 } else { 6617 var standardName = getPossibleStandardName(propKey); 6618 6619 if (standardName !== null && standardName !== propKey) { 6620 // If an SVG prop is supplied with bad casing, it will 6621 // be successfully parsed from HTML, but will produce a mismatch 6622 // (and would be incorrectly rendered on the client). 6623 // However, we already warn about bad casing elsewhere. 6624 // So we'll skip the misleading extra mismatch warning in this case. 6625 isMismatchDueToBadCasing = true; // $FlowFixMe - Should be inferred as not undefined. 6626 6627 extraAttributeNames.delete(standardName); 6628 } // $FlowFixMe - Should be inferred as not undefined. 6629 6630 6631 extraAttributeNames.delete(propKey); 6632 } 6633 6634 serverValue = getValueForAttribute(domElement, propKey, nextProp); 6635 } 6636 6637 if (nextProp !== serverValue && !isMismatchDueToBadCasing) { 6638 warnForPropDifference(propKey, serverValue, nextProp); 6639 } 6640 } 6641 } 6642 } 6643 6644 { 6645 // $FlowFixMe - Should be inferred as not undefined. 6646 if (extraAttributeNames.size > 0 && !suppressHydrationWarning) { 6647 // $FlowFixMe - Should be inferred as not undefined. 6648 warnForExtraAttributes(extraAttributeNames); 6649 } 6650 } 6651 6652 switch (tag) { 6653 case 'input': 6654 // TODO: Make sure we check if this is still unmounted or do any clean 6655 // up necessary since we never stop tracking anymore. 6656 track(domElement); 6657 postMountWrapper(domElement, rawProps, true); 6658 break; 6659 6660 case 'textarea': 6661 // TODO: Make sure we check if this is still unmounted or do any clean 6662 // up necessary since we never stop tracking anymore. 6663 track(domElement); 6664 postMountWrapper$3(domElement); 6665 break; 6666 6667 case 'select': 6668 case 'option': 6669 // For input and textarea we current always set the value property at 6670 // post mount to force it to diverge from attributes. However, for 6671 // option and select we don't quite do the same thing and select 6672 // is not resilient to the DOM state changing so we don't do that here. 6673 // TODO: Consider not doing this for input and textarea. 6674 break; 6675 6676 default: 6677 if (typeof rawProps.onClick === 'function') { 6678 // TODO: This cast may not be sound for SVG, MathML or custom elements. 6679 trapClickOnNonInteractiveElement(domElement); 6680 } 6681 6682 break; 6683 } 6684 6685 return updatePayload; 6686 } 6687 function diffHydratedText(textNode, text) { 6688 var isDifferent = textNode.nodeValue !== text; 6689 return isDifferent; 6690 } 6691 function warnForUnmatchedText(textNode, text) { 6692 { 6693 warnForTextDifference(textNode.nodeValue, text); 6694 } 6695 } 6696 function warnForDeletedHydratableElement(parentNode, child) { 6697 { 6698 if (didWarnInvalidHydration) { 6699 return; 6700 } 6701 6702 didWarnInvalidHydration = true; 6703 6704 error('Did not expect server HTML to contain a <%s> in <%s>.', child.nodeName.toLowerCase(), parentNode.nodeName.toLowerCase()); 6705 } 6706 } 6707 function warnForDeletedHydratableText(parentNode, child) { 6708 { 6709 if (didWarnInvalidHydration) { 6710 return; 6711 } 6712 6713 didWarnInvalidHydration = true; 6714 6715 error('Did not expect server HTML to contain the text node "%s" in <%s>.', child.nodeValue, parentNode.nodeName.toLowerCase()); 6716 } 6717 } 6718 function warnForInsertedHydratedElement(parentNode, tag, props) { 6719 { 6720 if (didWarnInvalidHydration) { 6721 return; 6722 } 6723 6724 didWarnInvalidHydration = true; 6725 6726 error('Expected server HTML to contain a matching <%s> in <%s>.', tag, parentNode.nodeName.toLowerCase()); 6727 } 6728 } 6729 function warnForInsertedHydratedText(parentNode, text) { 6730 { 6731 if (text === '') { 6732 // We expect to insert empty text nodes since they're not represented in 6733 // the HTML. 6734 // TODO: Remove this special case if we can just avoid inserting empty 6735 // text nodes. 6736 return; 6737 } 6738 6739 if (didWarnInvalidHydration) { 6740 return; 6741 } 6742 6743 didWarnInvalidHydration = true; 6744 6745 error('Expected server HTML to contain a matching text node for "%s" in <%s>.', text, parentNode.nodeName.toLowerCase()); 6746 } 6747 } 6748 function restoreControlledState$3(domElement, tag, props) { 6749 switch (tag) { 6750 case 'input': 6751 restoreControlledState(domElement, props); 6752 return; 6753 6754 case 'textarea': 6755 restoreControlledState$2(domElement, props); 6756 return; 6757 6758 case 'select': 6759 restoreControlledState$1(domElement, props); 6760 return; 6761 } 6762 } 6763 6764 function getActiveElement(doc) { 6765 doc = doc || (typeof document !== 'undefined' ? document : undefined); 6766 6767 if (typeof doc === 'undefined') { 6768 return null; 6769 } 6770 6771 try { 6772 return doc.activeElement || doc.body; 6773 } catch (e) { 6774 return doc.body; 6775 } 6776 } 6777 6778 /** 6779 * Given any node return the first leaf node without children. 6780 * 6781 * @param {DOMElement|DOMTextNode} node 6782 * @return {DOMElement|DOMTextNode} 6783 */ 6784 6785 function getLeafNode(node) { 6786 while (node && node.firstChild) { 6787 node = node.firstChild; 6788 } 6789 6790 return node; 6791 } 6792 /** 6793 * Get the next sibling within a container. This will walk up the 6794 * DOM if a node's siblings have been exhausted. 6795 * 6796 * @param {DOMElement|DOMTextNode} node 6797 * @return {?DOMElement|DOMTextNode} 6798 */ 6799 6800 6801 function getSiblingNode(node) { 6802 while (node) { 6803 if (node.nextSibling) { 6804 return node.nextSibling; 6805 } 6806 6807 node = node.parentNode; 6808 } 6809 } 6810 /** 6811 * Get object describing the nodes which contain characters at offset. 6812 * 6813 * @param {DOMElement|DOMTextNode} root 6814 * @param {number} offset 6815 * @return {?object} 6816 */ 6817 6818 6819 function getNodeForCharacterOffset(root, offset) { 6820 var node = getLeafNode(root); 6821 var nodeStart = 0; 6822 var nodeEnd = 0; 6823 6824 while (node) { 6825 if (node.nodeType === TEXT_NODE) { 6826 nodeEnd = nodeStart + node.textContent.length; 6827 6828 if (nodeStart <= offset && nodeEnd >= offset) { 6829 return { 6830 node: node, 6831 offset: offset - nodeStart 6832 }; 6833 } 6834 6835 nodeStart = nodeEnd; 6836 } 6837 6838 node = getLeafNode(getSiblingNode(node)); 6839 } 6840 } 6841 6842 /** 6843 * @param {DOMElement} outerNode 6844 * @return {?object} 6845 */ 6846 6847 function getOffsets(outerNode) { 6848 var ownerDocument = outerNode.ownerDocument; 6849 var win = ownerDocument && ownerDocument.defaultView || window; 6850 var selection = win.getSelection && win.getSelection(); 6851 6852 if (!selection || selection.rangeCount === 0) { 6853 return null; 6854 } 6855 6856 var anchorNode = selection.anchorNode, 6857 anchorOffset = selection.anchorOffset, 6858 focusNode = selection.focusNode, 6859 focusOffset = selection.focusOffset; // In Firefox, anchorNode and focusNode can be "anonymous divs", e.g. the 6860 // up/down buttons on an <input type="number">. Anonymous divs do not seem to 6861 // expose properties, triggering a "Permission denied error" if any of its 6862 // properties are accessed. The only seemingly possible way to avoid erroring 6863 // is to access a property that typically works for non-anonymous divs and 6864 // catch any error that may otherwise arise. See 6865 // https://bugzilla.mozilla.org/show_bug.cgi?id=208427 6866 6867 try { 6868 /* eslint-disable no-unused-expressions */ 6869 anchorNode.nodeType; 6870 focusNode.nodeType; 6871 /* eslint-enable no-unused-expressions */ 6872 } catch (e) { 6873 return null; 6874 } 6875 6876 return getModernOffsetsFromPoints(outerNode, anchorNode, anchorOffset, focusNode, focusOffset); 6877 } 6878 /** 6879 * Returns {start, end} where `start` is the character/codepoint index of 6880 * (anchorNode, anchorOffset) within the textContent of `outerNode`, and 6881 * `end` is the index of (focusNode, focusOffset). 6882 * 6883 * Returns null if you pass in garbage input but we should probably just crash. 6884 * 6885 * Exported only for testing. 6886 */ 6887 6888 function getModernOffsetsFromPoints(outerNode, anchorNode, anchorOffset, focusNode, focusOffset) { 6889 var length = 0; 6890 var start = -1; 6891 var end = -1; 6892 var indexWithinAnchor = 0; 6893 var indexWithinFocus = 0; 6894 var node = outerNode; 6895 var parentNode = null; 6896 6897 outer: while (true) { 6898 var next = null; 6899 6900 while (true) { 6901 if (node === anchorNode && (anchorOffset === 0 || node.nodeType === TEXT_NODE)) { 6902 start = length + anchorOffset; 6903 } 6904 6905 if (node === focusNode && (focusOffset === 0 || node.nodeType === TEXT_NODE)) { 6906 end = length + focusOffset; 6907 } 6908 6909 if (node.nodeType === TEXT_NODE) { 6910 length += node.nodeValue.length; 6911 } 6912 6913 if ((next = node.firstChild) === null) { 6914 break; 6915 } // Moving from `node` to its first child `next`. 6916 6917 6918 parentNode = node; 6919 node = next; 6920 } 6921 6922 while (true) { 6923 if (node === outerNode) { 6924 // If `outerNode` has children, this is always the second time visiting 6925 // it. If it has no children, this is still the first loop, and the only 6926 // valid selection is anchorNode and focusNode both equal to this node 6927 // and both offsets 0, in which case we will have handled above. 6928 break outer; 6929 } 6930 6931 if (parentNode === anchorNode && ++indexWithinAnchor === anchorOffset) { 6932 start = length; 6933 } 6934 6935 if (parentNode === focusNode && ++indexWithinFocus === focusOffset) { 6936 end = length; 6937 } 6938 6939 if ((next = node.nextSibling) !== null) { 6940 break; 6941 } 6942 6943 node = parentNode; 6944 parentNode = node.parentNode; 6945 } // Moving from `node` to its next sibling `next`. 6946 6947 6948 node = next; 6949 } 6950 6951 if (start === -1 || end === -1) { 6952 // This should never happen. (Would happen if the anchor/focus nodes aren't 6953 // actually inside the passed-in node.) 6954 return null; 6955 } 6956 6957 return { 6958 start: start, 6959 end: end 6960 }; 6961 } 6962 /** 6963 * In modern non-IE browsers, we can support both forward and backward 6964 * selections. 6965 * 6966 * Note: IE10+ supports the Selection object, but it does not support 6967 * the `extend` method, which means that even in modern IE, it's not possible 6968 * to programmatically create a backward selection. Thus, for all IE 6969 * versions, we use the old IE API to create our selections. 6970 * 6971 * @param {DOMElement|DOMTextNode} node 6972 * @param {object} offsets 6973 */ 6974 6975 function setOffsets(node, offsets) { 6976 var doc = node.ownerDocument || document; 6977 var win = doc && doc.defaultView || window; // Edge fails with "Object expected" in some scenarios. 6978 // (For instance: TinyMCE editor used in a list component that supports pasting to add more, 6979 // fails when pasting 100+ items) 6980 6981 if (!win.getSelection) { 6982 return; 6983 } 6984 6985 var selection = win.getSelection(); 6986 var length = node.textContent.length; 6987 var start = Math.min(offsets.start, length); 6988 var end = offsets.end === undefined ? start : Math.min(offsets.end, length); // IE 11 uses modern selection, but doesn't support the extend method. 6989 // Flip backward selections, so we can set with a single range. 6990 6991 if (!selection.extend && start > end) { 6992 var temp = end; 6993 end = start; 6994 start = temp; 6995 } 6996 6997 var startMarker = getNodeForCharacterOffset(node, start); 6998 var endMarker = getNodeForCharacterOffset(node, end); 6999 7000 if (startMarker && endMarker) { 7001 if (selection.rangeCount === 1 && selection.anchorNode === startMarker.node && selection.anchorOffset === startMarker.offset && selection.focusNode === endMarker.node && selection.focusOffset === endMarker.offset) { 7002 return; 7003 } 7004 7005 var range = doc.createRange(); 7006 range.setStart(startMarker.node, startMarker.offset); 7007 selection.removeAllRanges(); 7008 7009 if (start > end) { 7010 selection.addRange(range); 7011 selection.extend(endMarker.node, endMarker.offset); 7012 } else { 7013 range.setEnd(endMarker.node, endMarker.offset); 7014 selection.addRange(range); 7015 } 7016 } 7017 } 7018 7019 function isTextNode(node) { 7020 return node && node.nodeType === TEXT_NODE; 7021 } 7022 7023 function containsNode(outerNode, innerNode) { 7024 if (!outerNode || !innerNode) { 7025 return false; 7026 } else if (outerNode === innerNode) { 7027 return true; 7028 } else if (isTextNode(outerNode)) { 7029 return false; 7030 } else if (isTextNode(innerNode)) { 7031 return containsNode(outerNode, innerNode.parentNode); 7032 } else if ('contains' in outerNode) { 7033 return outerNode.contains(innerNode); 7034 } else if (outerNode.compareDocumentPosition) { 7035 return !!(outerNode.compareDocumentPosition(innerNode) & 16); 7036 } else { 7037 return false; 7038 } 7039 } 7040 7041 function isInDocument(node) { 7042 return node && node.ownerDocument && containsNode(node.ownerDocument.documentElement, node); 7043 } 7044 7045 function isSameOriginFrame(iframe) { 7046 try { 7047 // Accessing the contentDocument of a HTMLIframeElement can cause the browser 7048 // to throw, e.g. if it has a cross-origin src attribute. 7049 // Safari will show an error in the console when the access results in "Blocked a frame with origin". e.g: 7050 // iframe.contentDocument.defaultView; 7051 // A safety way is to access one of the cross origin properties: Window or Location 7052 // Which might result in "SecurityError" DOM Exception and it is compatible to Safari. 7053 // https://html.spec.whatwg.org/multipage/browsers.html#integration-with-idl 7054 return typeof iframe.contentWindow.location.href === 'string'; 7055 } catch (err) { 7056 return false; 7057 } 7058 } 7059 7060 function getActiveElementDeep() { 7061 var win = window; 7062 var element = getActiveElement(); 7063 7064 while (element instanceof win.HTMLIFrameElement) { 7065 if (isSameOriginFrame(element)) { 7066 win = element.contentWindow; 7067 } else { 7068 return element; 7069 } 7070 7071 element = getActiveElement(win.document); 7072 } 7073 7074 return element; 7075 } 7076 /** 7077 * @ReactInputSelection: React input selection module. Based on Selection.js, 7078 * but modified to be suitable for react and has a couple of bug fixes (doesn't 7079 * assume buttons have range selections allowed). 7080 * Input selection module for React. 7081 */ 7082 7083 /** 7084 * @hasSelectionCapabilities: we get the element types that support selection 7085 * from https://html.spec.whatwg.org/#do-not-apply, looking at `selectionStart` 7086 * and `selectionEnd` rows. 7087 */ 7088 7089 7090 function hasSelectionCapabilities(elem) { 7091 var nodeName = elem && elem.nodeName && elem.nodeName.toLowerCase(); 7092 return nodeName && (nodeName === 'input' && (elem.type === 'text' || elem.type === 'search' || elem.type === 'tel' || elem.type === 'url' || elem.type === 'password') || nodeName === 'textarea' || elem.contentEditable === 'true'); 7093 } 7094 function getSelectionInformation() { 7095 var focusedElem = getActiveElementDeep(); 7096 return { 7097 // Used by Flare 7098 activeElementDetached: null, 7099 focusedElem: focusedElem, 7100 selectionRange: hasSelectionCapabilities(focusedElem) ? getSelection(focusedElem) : null 7101 }; 7102 } 7103 /** 7104 * @restoreSelection: If any selection information was potentially lost, 7105 * restore it. This is useful when performing operations that could remove dom 7106 * nodes and place them back in, resulting in focus being lost. 7107 */ 7108 7109 function restoreSelection(priorSelectionInformation) { 7110 var curFocusedElem = getActiveElementDeep(); 7111 var priorFocusedElem = priorSelectionInformation.focusedElem; 7112 var priorSelectionRange = priorSelectionInformation.selectionRange; 7113 7114 if (curFocusedElem !== priorFocusedElem && isInDocument(priorFocusedElem)) { 7115 if (priorSelectionRange !== null && hasSelectionCapabilities(priorFocusedElem)) { 7116 setSelection(priorFocusedElem, priorSelectionRange); 7117 } // Focusing a node can change the scroll position, which is undesirable 7118 7119 7120 var ancestors = []; 7121 var ancestor = priorFocusedElem; 7122 7123 while (ancestor = ancestor.parentNode) { 7124 if (ancestor.nodeType === ELEMENT_NODE) { 7125 ancestors.push({ 7126 element: ancestor, 7127 left: ancestor.scrollLeft, 7128 top: ancestor.scrollTop 7129 }); 7130 } 7131 } 7132 7133 if (typeof priorFocusedElem.focus === 'function') { 7134 priorFocusedElem.focus(); 7135 } 7136 7137 for (var i = 0; i < ancestors.length; i++) { 7138 var info = ancestors[i]; 7139 info.element.scrollLeft = info.left; 7140 info.element.scrollTop = info.top; 7141 } 7142 } 7143 } 7144 /** 7145 * @getSelection: Gets the selection bounds of a focused textarea, input or 7146 * contentEditable node. 7147 * -@input: Look up selection bounds of this input 7148 * -@return {start: selectionStart, end: selectionEnd} 7149 */ 7150 7151 function getSelection(input) { 7152 var selection; 7153 7154 if ('selectionStart' in input) { 7155 // Modern browser with input or textarea. 7156 selection = { 7157 start: input.selectionStart, 7158 end: input.selectionEnd 7159 }; 7160 } else { 7161 // Content editable or old IE textarea. 7162 selection = getOffsets(input); 7163 } 7164 7165 return selection || { 7166 start: 0, 7167 end: 0 7168 }; 7169 } 7170 /** 7171 * @setSelection: Sets the selection bounds of a textarea or input and focuses 7172 * the input. 7173 * -@input Set selection bounds of this input or textarea 7174 * -@offsets Object of same form that is returned from get* 7175 */ 7176 7177 function setSelection(input, offsets) { 7178 var start = offsets.start, 7179 end = offsets.end; 7180 7181 if (end === undefined) { 7182 end = start; 7183 } 7184 7185 if ('selectionStart' in input) { 7186 input.selectionStart = start; 7187 input.selectionEnd = Math.min(end, input.value.length); 7188 } else { 7189 setOffsets(input, offsets); 7190 } 7191 } 7192 7193 var validateDOMNesting = function () {}; 7194 7195 var updatedAncestorInfo = function () {}; 7196 7197 { 7198 // This validation code was written based on the HTML5 parsing spec: 7199 // https://html.spec.whatwg.org/multipage/syntax.html#has-an-element-in-scope 7200 // 7201 // Note: this does not catch all invalid nesting, nor does it try to (as it's 7202 // not clear what practical benefit doing so provides); instead, we warn only 7203 // for cases where the parser will give a parse tree differing from what React 7204 // intended. For example, <b><div></div></b> is invalid but we don't warn 7205 // because it still parses correctly; we do warn for other cases like nested 7206 // <p> tags where the beginning of the second element implicitly closes the 7207 // first, causing a confusing mess. 7208 // https://html.spec.whatwg.org/multipage/syntax.html#special 7209 var specialTags = ['address', 'applet', 'area', 'article', 'aside', 'base', 'basefont', 'bgsound', 'blockquote', 'body', 'br', 'button', 'caption', 'center', 'col', 'colgroup', 'dd', 'details', 'dir', 'div', 'dl', 'dt', 'embed', 'fieldset', 'figcaption', 'figure', 'footer', 'form', 'frame', 'frameset', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'head', 'header', 'hgroup', 'hr', 'html', 'iframe', 'img', 'input', 'isindex', 'li', 'link', 'listing', 'main', 'marquee', 'menu', 'menuitem', 'meta', 'nav', 'noembed', 'noframes', 'noscript', 'object', 'ol', 'p', 'param', 'plaintext', 'pre', 'script', 'section', 'select', 'source', 'style', 'summary', 'table', 'tbody', 'td', 'template', 'textarea', 'tfoot', 'th', 'thead', 'title', 'tr', 'track', 'ul', 'wbr', 'xmp']; // https://html.spec.whatwg.org/multipage/syntax.html#has-an-element-in-scope 7210 7211 var inScopeTags = ['applet', 'caption', 'html', 'table', 'td', 'th', 'marquee', 'object', 'template', // https://html.spec.whatwg.org/multipage/syntax.html#html-integration-point 7212 // TODO: Distinguish by namespace here -- for <title>, including it here 7213 // errs on the side of fewer warnings 7214 'foreignObject', 'desc', 'title']; // https://html.spec.whatwg.org/multipage/syntax.html#has-an-element-in-button-scope 7215 7216 var buttonScopeTags = inScopeTags.concat(['button']); // https://html.spec.whatwg.org/multipage/syntax.html#generate-implied-end-tags 7217 7218 var impliedEndTags = ['dd', 'dt', 'li', 'option', 'optgroup', 'p', 'rp', 'rt']; 7219 var emptyAncestorInfo = { 7220 current: null, 7221 formTag: null, 7222 aTagInScope: null, 7223 buttonTagInScope: null, 7224 nobrTagInScope: null, 7225 pTagInButtonScope: null, 7226 listItemTagAutoclosing: null, 7227 dlItemTagAutoclosing: null 7228 }; 7229 7230 updatedAncestorInfo = function (oldInfo, tag) { 7231 var ancestorInfo = _assign({}, oldInfo || emptyAncestorInfo); 7232 7233 var info = { 7234 tag: tag 7235 }; 7236 7237 if (inScopeTags.indexOf(tag) !== -1) { 7238 ancestorInfo.aTagInScope = null; 7239 ancestorInfo.buttonTagInScope = null; 7240 ancestorInfo.nobrTagInScope = null; 7241 } 7242 7243 if (buttonScopeTags.indexOf(tag) !== -1) { 7244 ancestorInfo.pTagInButtonScope = null; 7245 } // See rules for 'li', 'dd', 'dt' start tags in 7246 // https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-inbody 7247 7248 7249 if (specialTags.indexOf(tag) !== -1 && tag !== 'address' && tag !== 'div' && tag !== 'p') { 7250 ancestorInfo.listItemTagAutoclosing = null; 7251 ancestorInfo.dlItemTagAutoclosing = null; 7252 } 7253 7254 ancestorInfo.current = info; 7255 7256 if (tag === 'form') { 7257 ancestorInfo.formTag = info; 7258 } 7259 7260 if (tag === 'a') { 7261 ancestorInfo.aTagInScope = info; 7262 } 7263 7264 if (tag === 'button') { 7265 ancestorInfo.buttonTagInScope = info; 7266 } 7267 7268 if (tag === 'nobr') { 7269 ancestorInfo.nobrTagInScope = info; 7270 } 7271 7272 if (tag === 'p') { 7273 ancestorInfo.pTagInButtonScope = info; 7274 } 7275 7276 if (tag === 'li') { 7277 ancestorInfo.listItemTagAutoclosing = info; 7278 } 7279 7280 if (tag === 'dd' || tag === 'dt') { 7281 ancestorInfo.dlItemTagAutoclosing = info; 7282 } 7283 7284 return ancestorInfo; 7285 }; 7286 /** 7287 * Returns whether 7288 */ 7289 7290 7291 var isTagValidWithParent = function (tag, parentTag) { 7292 // First, let's check if we're in an unusual parsing mode... 7293 switch (parentTag) { 7294 // https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-inselect 7295 case 'select': 7296 return tag === 'option' || tag === 'optgroup' || tag === '#text'; 7297 7298 case 'optgroup': 7299 return tag === 'option' || tag === '#text'; 7300 // Strictly speaking, seeing an <option> doesn't mean we're in a <select> 7301 // but 7302 7303 case 'option': 7304 return tag === '#text'; 7305 // https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-intd 7306 // https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-incaption 7307 // No special behavior since these rules fall back to "in body" mode for 7308 // all except special table nodes which cause bad parsing behavior anyway. 7309 // https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-intr 7310 7311 case 'tr': 7312 return tag === 'th' || tag === 'td' || tag === 'style' || tag === 'script' || tag === 'template'; 7313 // https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-intbody 7314 7315 case 'tbody': 7316 case 'thead': 7317 case 'tfoot': 7318 return tag === 'tr' || tag === 'style' || tag === 'script' || tag === 'template'; 7319 // https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-incolgroup 7320 7321 case 'colgroup': 7322 return tag === 'col' || tag === 'template'; 7323 // https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-intable 7324 7325 case 'table': 7326 return tag === 'caption' || tag === 'colgroup' || tag === 'tbody' || tag === 'tfoot' || tag === 'thead' || tag === 'style' || tag === 'script' || tag === 'template'; 7327 // https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-inhead 7328 7329 case 'head': 7330 return tag === 'base' || tag === 'basefont' || tag === 'bgsound' || tag === 'link' || tag === 'meta' || tag === 'title' || tag === 'noscript' || tag === 'noframes' || tag === 'style' || tag === 'script' || tag === 'template'; 7331 // https://html.spec.whatwg.org/multipage/semantics.html#the-html-element 7332 7333 case 'html': 7334 return tag === 'head' || tag === 'body' || tag === 'frameset'; 7335 7336 case 'frameset': 7337 return tag === 'frame'; 7338 7339 case '#document': 7340 return tag === 'html'; 7341 } // Probably in the "in body" parsing mode, so we outlaw only tag combos 7342 // where the parsing rules cause implicit opens or closes to be added. 7343 // https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-inbody 7344 7345 7346 switch (tag) { 7347 case 'h1': 7348 case 'h2': 7349 case 'h3': 7350 case 'h4': 7351 case 'h5': 7352 case 'h6': 7353 return parentTag !== 'h1' && parentTag !== 'h2' && parentTag !== 'h3' && parentTag !== 'h4' && parentTag !== 'h5' && parentTag !== 'h6'; 7354 7355 case 'rp': 7356 case 'rt': 7357 return impliedEndTags.indexOf(parentTag) === -1; 7358 7359 case 'body': 7360 case 'caption': 7361 case 'col': 7362 case 'colgroup': 7363 case 'frameset': 7364 case 'frame': 7365 case 'head': 7366 case 'html': 7367 case 'tbody': 7368 case 'td': 7369 case 'tfoot': 7370 case 'th': 7371 case 'thead': 7372 case 'tr': 7373 // These tags are only valid with a few parents that have special child 7374 // parsing rules -- if we're down here, then none of those matched and 7375 // so we allow it only if we don't know what the parent is, as all other 7376 // cases are invalid. 7377 return parentTag == null; 7378 } 7379 7380 return true; 7381 }; 7382 /** 7383 * Returns whether 7384 */ 7385 7386 7387 var findInvalidAncestorForTag = function (tag, ancestorInfo) { 7388 switch (tag) { 7389 case 'address': 7390 case 'article': 7391 case 'aside': 7392 case 'blockquote': 7393 case 'center': 7394 case 'details': 7395 case 'dialog': 7396 case 'dir': 7397 case 'div': 7398 case 'dl': 7399 case 'fieldset': 7400 case 'figcaption': 7401 case 'figure': 7402 case 'footer': 7403 case 'header': 7404 case 'hgroup': 7405 case 'main': 7406 case 'menu': 7407 case 'nav': 7408 case 'ol': 7409 case 'p': 7410 case 'section': 7411 case 'summary': 7412 case 'ul': 7413 case 'pre': 7414 case 'listing': 7415 case 'table': 7416 case 'hr': 7417 case 'xmp': 7418 case 'h1': 7419 case 'h2': 7420 case 'h3': 7421 case 'h4': 7422 case 'h5': 7423 case 'h6': 7424 return ancestorInfo.pTagInButtonScope; 7425 7426 case 'form': 7427 return ancestorInfo.formTag || ancestorInfo.pTagInButtonScope; 7428 7429 case 'li': 7430 return ancestorInfo.listItemTagAutoclosing; 7431 7432 case 'dd': 7433 case 'dt': 7434 return ancestorInfo.dlItemTagAutoclosing; 7435 7436 case 'button': 7437 return ancestorInfo.buttonTagInScope; 7438 7439 case 'a': 7440 // Spec says something about storing a list of markers, but it sounds 7441 // equivalent to this check. 7442 return ancestorInfo.aTagInScope; 7443 7444 case 'nobr': 7445 return ancestorInfo.nobrTagInScope; 7446 } 7447 7448 return null; 7449 }; 7450 7451 var didWarn$1 = {}; 7452 7453 validateDOMNesting = function (childTag, childText, ancestorInfo) { 7454 ancestorInfo = ancestorInfo || emptyAncestorInfo; 7455 var parentInfo = ancestorInfo.current; 7456 var parentTag = parentInfo && parentInfo.tag; 7457 7458 if (childText != null) { 7459 if (childTag != null) { 7460 error('validateDOMNesting: when childText is passed, childTag should be null'); 7461 } 7462 7463 childTag = '#text'; 7464 } 7465 7466 var invalidParent = isTagValidWithParent(childTag, parentTag) ? null : parentInfo; 7467 var invalidAncestor = invalidParent ? null : findInvalidAncestorForTag(childTag, ancestorInfo); 7468 var invalidParentOrAncestor = invalidParent || invalidAncestor; 7469 7470 if (!invalidParentOrAncestor) { 7471 return; 7472 } 7473 7474 var ancestorTag = invalidParentOrAncestor.tag; 7475 var addendum = getCurrentFiberStackInDev(); 7476 var warnKey = !!invalidParent + '|' + childTag + '|' + ancestorTag + '|' + addendum; 7477 7478 if (didWarn$1[warnKey]) { 7479 return; 7480 } 7481 7482 didWarn$1[warnKey] = true; 7483 var tagDisplayName = childTag; 7484 var whitespaceInfo = ''; 7485 7486 if (childTag === '#text') { 7487 if (/\S/.test(childText)) { 7488 tagDisplayName = 'Text nodes'; 7489 } else { 7490 tagDisplayName = 'Whitespace text nodes'; 7491 whitespaceInfo = " Make sure you don't have any extra whitespace between tags on " + 'each line of your source code.'; 7492 } 7493 } else { 7494 tagDisplayName = '<' + childTag + '>'; 7495 } 7496 7497 if (invalidParent) { 7498 var info = ''; 7499 7500 if (ancestorTag === 'table' && childTag === 'tr') { 7501 info += ' Add a <tbody>, <thead> or <tfoot> to your code to match the DOM tree generated by ' + 'the browser.'; 7502 } 7503 7504 error('validateDOMNesting(...): %s cannot appear as a child of <%s>.%s%s', tagDisplayName, ancestorTag, whitespaceInfo, info); 7505 } else { 7506 error('validateDOMNesting(...): %s cannot appear as a descendant of ' + '<%s>.', tagDisplayName, ancestorTag); 7507 } 7508 }; 7509 } 7510 7511 var SUPPRESS_HYDRATION_WARNING$1; 7512 7513 { 7514 SUPPRESS_HYDRATION_WARNING$1 = 'suppressHydrationWarning'; 7515 } 7516 7517 var SUSPENSE_START_DATA = '$'; 7518 var SUSPENSE_END_DATA = '/$'; 7519 var SUSPENSE_PENDING_START_DATA = '$?'; 7520 var SUSPENSE_FALLBACK_START_DATA = '$!'; 7521 var STYLE$1 = 'style'; 7522 var eventsEnabled = null; 7523 var selectionInformation = null; 7524 7525 function shouldAutoFocusHostComponent(type, props) { 7526 switch (type) { 7527 case 'button': 7528 case 'input': 7529 case 'select': 7530 case 'textarea': 7531 return !!props.autoFocus; 7532 } 7533 7534 return false; 7535 } 7536 function getRootHostContext(rootContainerInstance) { 7537 var type; 7538 var namespace; 7539 var nodeType = rootContainerInstance.nodeType; 7540 7541 switch (nodeType) { 7542 case DOCUMENT_NODE: 7543 case DOCUMENT_FRAGMENT_NODE: 7544 { 7545 type = nodeType === DOCUMENT_NODE ? '#document' : '#fragment'; 7546 var root = rootContainerInstance.documentElement; 7547 namespace = root ? root.namespaceURI : getChildNamespace(null, ''); 7548 break; 7549 } 7550 7551 default: 7552 { 7553 var container = nodeType === COMMENT_NODE ? rootContainerInstance.parentNode : rootContainerInstance; 7554 var ownNamespace = container.namespaceURI || null; 7555 type = container.tagName; 7556 namespace = getChildNamespace(ownNamespace, type); 7557 break; 7558 } 7559 } 7560 7561 { 7562 var validatedTag = type.toLowerCase(); 7563 var ancestorInfo = updatedAncestorInfo(null, validatedTag); 7564 return { 7565 namespace: namespace, 7566 ancestorInfo: ancestorInfo 7567 }; 7568 } 7569 } 7570 function getChildHostContext(parentHostContext, type, rootContainerInstance) { 7571 { 7572 var parentHostContextDev = parentHostContext; 7573 var namespace = getChildNamespace(parentHostContextDev.namespace, type); 7574 var ancestorInfo = updatedAncestorInfo(parentHostContextDev.ancestorInfo, type); 7575 return { 7576 namespace: namespace, 7577 ancestorInfo: ancestorInfo 7578 }; 7579 } 7580 } 7581 function getPublicInstance(instance) { 7582 return instance; 7583 } 7584 function prepareForCommit(containerInfo) { 7585 eventsEnabled = isEnabled(); 7586 selectionInformation = getSelectionInformation(); 7587 setEnabled(false); 7588 } 7589 function resetAfterCommit(containerInfo) { 7590 restoreSelection(selectionInformation); 7591 setEnabled(eventsEnabled); 7592 eventsEnabled = null; 7593 7594 selectionInformation = null; 7595 } 7596 function createInstance(type, props, rootContainerInstance, hostContext, internalInstanceHandle) { 7597 var parentNamespace; 7598 7599 { 7600 // TODO: take namespace into account when validating. 7601 var hostContextDev = hostContext; 7602 validateDOMNesting(type, null, hostContextDev.ancestorInfo); 7603 7604 if (typeof props.children === 'string' || typeof props.children === 'number') { 7605 var string = '' + props.children; 7606 var ownAncestorInfo = updatedAncestorInfo(hostContextDev.ancestorInfo, type); 7607 validateDOMNesting(null, string, ownAncestorInfo); 7608 } 7609 7610 parentNamespace = hostContextDev.namespace; 7611 } 7612 7613 var domElement = createElement(type, props, rootContainerInstance, parentNamespace); 7614 precacheFiberNode(internalInstanceHandle, domElement); 7615 updateFiberProps(domElement, props); 7616 return domElement; 7617 } 7618 function appendInitialChild(parentInstance, child) { 7619 parentInstance.appendChild(child); 7620 } 7621 function finalizeInitialChildren(domElement, type, props, rootContainerInstance, hostContext) { 7622 setInitialProperties(domElement, type, props, rootContainerInstance); 7623 return shouldAutoFocusHostComponent(type, props); 7624 } 7625 function prepareUpdate(domElement, type, oldProps, newProps, rootContainerInstance, hostContext) { 7626 { 7627 var hostContextDev = hostContext; 7628 7629 if (typeof newProps.children !== typeof oldProps.children && (typeof newProps.children === 'string' || typeof newProps.children === 'number')) { 7630 var string = '' + newProps.children; 7631 var ownAncestorInfo = updatedAncestorInfo(hostContextDev.ancestorInfo, type); 7632 validateDOMNesting(null, string, ownAncestorInfo); 7633 } 7634 } 7635 7636 return diffProperties(domElement, type, oldProps, newProps, rootContainerInstance); 7637 } 7638 function shouldSetTextContent(type, props) { 7639 return type === 'textarea' || type === 'option' || type === 'noscript' || typeof props.children === 'string' || typeof props.children === 'number' || typeof props.dangerouslySetInnerHTML === 'object' && props.dangerouslySetInnerHTML !== null && props.dangerouslySetInnerHTML.__html != null; 7640 } 7641 function shouldDeprioritizeSubtree(type, props) { 7642 return !!props.hidden; 7643 } 7644 function createTextInstance(text, rootContainerInstance, hostContext, internalInstanceHandle) { 7645 { 7646 var hostContextDev = hostContext; 7647 validateDOMNesting(null, text, hostContextDev.ancestorInfo); 7648 } 7649 7650 var textNode = createTextNode(text, rootContainerInstance); 7651 precacheFiberNode(internalInstanceHandle, textNode); 7652 return textNode; 7653 } 7654 // if a component just imports ReactDOM (e.g. for findDOMNode). 7655 // Some environments might not have setTimeout or clearTimeout. 7656 7657 var scheduleTimeout = typeof setTimeout === 'function' ? setTimeout : undefined; 7658 var cancelTimeout = typeof clearTimeout === 'function' ? clearTimeout : undefined; 7659 var noTimeout = -1; // ------------------- 7660 function commitMount(domElement, type, newProps, internalInstanceHandle) { 7661 // Despite the naming that might imply otherwise, this method only 7662 // fires if there is an `Update` effect scheduled during mounting. 7663 // This happens if `finalizeInitialChildren` returns `true` (which it 7664 // does to implement the `autoFocus` attribute on the client). But 7665 // there are also other cases when this might happen (such as patching 7666 // up text content during hydration mismatch). So we'll check this again. 7667 if (shouldAutoFocusHostComponent(type, newProps)) { 7668 domElement.focus(); 7669 } 7670 } 7671 function commitUpdate(domElement, updatePayload, type, oldProps, newProps, internalInstanceHandle) { 7672 // Update the props handle so that we know which props are the ones with 7673 // with current event handlers. 7674 updateFiberProps(domElement, newProps); // Apply the diff to the DOM node. 7675 7676 updateProperties(domElement, updatePayload, type, oldProps, newProps); 7677 } 7678 function resetTextContent(domElement) { 7679 setTextContent(domElement, ''); 7680 } 7681 function commitTextUpdate(textInstance, oldText, newText) { 7682 textInstance.nodeValue = newText; 7683 } 7684 function appendChild(parentInstance, child) { 7685 parentInstance.appendChild(child); 7686 } 7687 function appendChildToContainer(container, child) { 7688 var parentNode; 7689 7690 if (container.nodeType === COMMENT_NODE) { 7691 parentNode = container.parentNode; 7692 parentNode.insertBefore(child, container); 7693 } else { 7694 parentNode = container; 7695 parentNode.appendChild(child); 7696 } // This container might be used for a portal. 7697 // If something inside a portal is clicked, that click should bubble 7698 // through the React tree. However, on Mobile Safari the click would 7699 // never bubble through the *DOM* tree unless an ancestor with onclick 7700 // event exists. So we wouldn't see it and dispatch it. 7701 // This is why we ensure that non React root containers have inline onclick 7702 // defined. 7703 // https://github.com/facebook/react/issues/11918 7704 7705 7706 var reactRootContainer = container._reactRootContainer; 7707 7708 if ((reactRootContainer === null || reactRootContainer === undefined) && parentNode.onclick === null) { 7709 // TODO: This cast may not be sound for SVG, MathML or custom elements. 7710 trapClickOnNonInteractiveElement(parentNode); 7711 } 7712 } 7713 function insertBefore(parentInstance, child, beforeChild) { 7714 parentInstance.insertBefore(child, beforeChild); 7715 } 7716 function insertInContainerBefore(container, child, beforeChild) { 7717 if (container.nodeType === COMMENT_NODE) { 7718 container.parentNode.insertBefore(child, beforeChild); 7719 } else { 7720 container.insertBefore(child, beforeChild); 7721 } 7722 } 7723 function removeChild(parentInstance, child) { 7724 parentInstance.removeChild(child); 7725 } 7726 function removeChildFromContainer(container, child) { 7727 if (container.nodeType === COMMENT_NODE) { 7728 container.parentNode.removeChild(child); 7729 } else { 7730 container.removeChild(child); 7731 } 7732 } 7733 7734 function hideInstance(instance) { 7735 // pass host context to this method? 7736 7737 7738 instance = instance; 7739 var style = instance.style; 7740 7741 if (typeof style.setProperty === 'function') { 7742 style.setProperty('display', 'none', 'important'); 7743 } else { 7744 style.display = 'none'; 7745 } 7746 } 7747 function hideTextInstance(textInstance) { 7748 textInstance.nodeValue = ''; 7749 } 7750 function unhideInstance(instance, props) { 7751 instance = instance; 7752 var styleProp = props[STYLE$1]; 7753 var display = styleProp !== undefined && styleProp !== null && styleProp.hasOwnProperty('display') ? styleProp.display : null; 7754 instance.style.display = dangerousStyleValue('display', display); 7755 } 7756 function unhideTextInstance(textInstance, text) { 7757 textInstance.nodeValue = text; 7758 } // ------------------- 7759 function canHydrateInstance(instance, type, props) { 7760 if (instance.nodeType !== ELEMENT_NODE || type.toLowerCase() !== instance.nodeName.toLowerCase()) { 7761 return null; 7762 } // This has now been refined to an element node. 7763 7764 7765 return instance; 7766 } 7767 function canHydrateTextInstance(instance, text) { 7768 if (text === '' || instance.nodeType !== TEXT_NODE) { 7769 // Empty strings are not parsed by HTML so there won't be a correct match here. 7770 return null; 7771 } // This has now been refined to a text node. 7772 7773 7774 return instance; 7775 } 7776 function isSuspenseInstancePending(instance) { 7777 return instance.data === SUSPENSE_PENDING_START_DATA; 7778 } 7779 function isSuspenseInstanceFallback(instance) { 7780 return instance.data === SUSPENSE_FALLBACK_START_DATA; 7781 } 7782 7783 function getNextHydratable(node) { 7784 // Skip non-hydratable nodes. 7785 for (; node != null; node = node.nextSibling) { 7786 var nodeType = node.nodeType; 7787 7788 if (nodeType === ELEMENT_NODE || nodeType === TEXT_NODE) { 7789 break; 7790 } 7791 } 7792 7793 return node; 7794 } 7795 7796 function getNextHydratableSibling(instance) { 7797 return getNextHydratable(instance.nextSibling); 7798 } 7799 function getFirstHydratableChild(parentInstance) { 7800 return getNextHydratable(parentInstance.firstChild); 7801 } 7802 function hydrateInstance(instance, type, props, rootContainerInstance, hostContext, internalInstanceHandle) { 7803 precacheFiberNode(internalInstanceHandle, instance); // TODO: Possibly defer this until the commit phase where all the events 7804 // get attached. 7805 7806 updateFiberProps(instance, props); 7807 var parentNamespace; 7808 7809 { 7810 var hostContextDev = hostContext; 7811 parentNamespace = hostContextDev.namespace; 7812 } 7813 7814 return diffHydratedProperties(instance, type, props, parentNamespace, rootContainerInstance); 7815 } 7816 function hydrateTextInstance(textInstance, text, internalInstanceHandle) { 7817 precacheFiberNode(internalInstanceHandle, textInstance); 7818 return diffHydratedText(textInstance, text); 7819 } 7820 function getNextHydratableInstanceAfterSuspenseInstance(suspenseInstance) { 7821 var node = suspenseInstance.nextSibling; // Skip past all nodes within this suspense boundary. 7822 // There might be nested nodes so we need to keep track of how 7823 // deep we are and only break out when we're back on top. 7824 7825 var depth = 0; 7826 7827 while (node) { 7828 if (node.nodeType === COMMENT_NODE) { 7829 var data = node.data; 7830 7831 if (data === SUSPENSE_END_DATA) { 7832 if (depth === 0) { 7833 return getNextHydratableSibling(node); 7834 } else { 7835 depth--; 7836 } 7837 } else if (data === SUSPENSE_START_DATA || data === SUSPENSE_FALLBACK_START_DATA || data === SUSPENSE_PENDING_START_DATA) { 7838 depth++; 7839 } 7840 } 7841 7842 node = node.nextSibling; 7843 } // TODO: Warn, we didn't find the end comment boundary. 7844 7845 7846 return null; 7847 } // Returns the SuspenseInstance if this node is a direct child of a 7848 // SuspenseInstance. I.e. if its previous sibling is a Comment with 7849 // SUSPENSE_x_START_DATA. Otherwise, null. 7850 7851 function getParentSuspenseInstance(targetInstance) { 7852 var node = targetInstance.previousSibling; // Skip past all nodes within this suspense boundary. 7853 // There might be nested nodes so we need to keep track of how 7854 // deep we are and only break out when we're back on top. 7855 7856 var depth = 0; 7857 7858 while (node) { 7859 if (node.nodeType === COMMENT_NODE) { 7860 var data = node.data; 7861 7862 if (data === SUSPENSE_START_DATA || data === SUSPENSE_FALLBACK_START_DATA || data === SUSPENSE_PENDING_START_DATA) { 7863 if (depth === 0) { 7864 return node; 7865 } else { 7866 depth--; 7867 } 7868 } else if (data === SUSPENSE_END_DATA) { 7869 depth++; 7870 } 7871 } 7872 7873 node = node.previousSibling; 7874 } 7875 7876 return null; 7877 } 7878 function commitHydratedContainer(container) { 7879 // Retry if any event replaying was blocked on this. 7880 retryIfBlockedOn(container); 7881 } 7882 function commitHydratedSuspenseInstance(suspenseInstance) { 7883 // Retry if any event replaying was blocked on this. 7884 retryIfBlockedOn(suspenseInstance); 7885 } 7886 function didNotMatchHydratedContainerTextInstance(parentContainer, textInstance, text) { 7887 { 7888 warnForUnmatchedText(textInstance, text); 7889 } 7890 } 7891 function didNotMatchHydratedTextInstance(parentType, parentProps, parentInstance, textInstance, text) { 7892 if ( parentProps[SUPPRESS_HYDRATION_WARNING$1] !== true) { 7893 warnForUnmatchedText(textInstance, text); 7894 } 7895 } 7896 function didNotHydrateContainerInstance(parentContainer, instance) { 7897 { 7898 if (instance.nodeType === ELEMENT_NODE) { 7899 warnForDeletedHydratableElement(parentContainer, instance); 7900 } else if (instance.nodeType === COMMENT_NODE) ; else { 7901 warnForDeletedHydratableText(parentContainer, instance); 7902 } 7903 } 7904 } 7905 function didNotHydrateInstance(parentType, parentProps, parentInstance, instance) { 7906 if ( parentProps[SUPPRESS_HYDRATION_WARNING$1] !== true) { 7907 if (instance.nodeType === ELEMENT_NODE) { 7908 warnForDeletedHydratableElement(parentInstance, instance); 7909 } else if (instance.nodeType === COMMENT_NODE) ; else { 7910 warnForDeletedHydratableText(parentInstance, instance); 7911 } 7912 } 7913 } 7914 function didNotFindHydratableContainerInstance(parentContainer, type, props) { 7915 { 7916 warnForInsertedHydratedElement(parentContainer, type); 7917 } 7918 } 7919 function didNotFindHydratableContainerTextInstance(parentContainer, text) { 7920 { 7921 warnForInsertedHydratedText(parentContainer, text); 7922 } 7923 } 7924 function didNotFindHydratableInstance(parentType, parentProps, parentInstance, type, props) { 7925 if ( parentProps[SUPPRESS_HYDRATION_WARNING$1] !== true) { 7926 warnForInsertedHydratedElement(parentInstance, type); 7927 } 7928 } 7929 function didNotFindHydratableTextInstance(parentType, parentProps, parentInstance, text) { 7930 if ( parentProps[SUPPRESS_HYDRATION_WARNING$1] !== true) { 7931 warnForInsertedHydratedText(parentInstance, text); 7932 } 7933 } 7934 function didNotFindHydratableSuspenseInstance(parentType, parentProps, parentInstance) { 7935 if ( parentProps[SUPPRESS_HYDRATION_WARNING$1] !== true) ; 7936 } 7937 7938 var randomKey = Math.random().toString(36).slice(2); 7939 var internalInstanceKey = '__reactInternalInstance$' + randomKey; 7940 var internalEventHandlersKey = '__reactEventHandlers$' + randomKey; 7941 var internalContainerInstanceKey = '__reactContainere$' + randomKey; 7942 function precacheFiberNode(hostInst, node) { 7943 node[internalInstanceKey] = hostInst; 7944 } 7945 function markContainerAsRoot(hostRoot, node) { 7946 node[internalContainerInstanceKey] = hostRoot; 7947 } 7948 function unmarkContainerAsRoot(node) { 7949 node[internalContainerInstanceKey] = null; 7950 } 7951 function isContainerMarkedAsRoot(node) { 7952 return !!node[internalContainerInstanceKey]; 7953 } // Given a DOM node, return the closest HostComponent or HostText fiber ancestor. 7954 // If the target node is part of a hydrated or not yet rendered subtree, then 7955 // this may also return a SuspenseComponent or HostRoot to indicate that. 7956 // Conceptually the HostRoot fiber is a child of the Container node. So if you 7957 // pass the Container node as the targetNode, you will not actually get the 7958 // HostRoot back. To get to the HostRoot, you need to pass a child of it. 7959 // The same thing applies to Suspense boundaries. 7960 7961 function getClosestInstanceFromNode(targetNode) { 7962 var targetInst = targetNode[internalInstanceKey]; 7963 7964 if (targetInst) { 7965 // Don't return HostRoot or SuspenseComponent here. 7966 return targetInst; 7967 } // If the direct event target isn't a React owned DOM node, we need to look 7968 // to see if one of its parents is a React owned DOM node. 7969 7970 7971 var parentNode = targetNode.parentNode; 7972 7973 while (parentNode) { 7974 // We'll check if this is a container root that could include 7975 // React nodes in the future. We need to check this first because 7976 // if we're a child of a dehydrated container, we need to first 7977 // find that inner container before moving on to finding the parent 7978 // instance. Note that we don't check this field on the targetNode 7979 // itself because the fibers are conceptually between the container 7980 // node and the first child. It isn't surrounding the container node. 7981 // If it's not a container, we check if it's an instance. 7982 targetInst = parentNode[internalContainerInstanceKey] || parentNode[internalInstanceKey]; 7983 7984 if (targetInst) { 7985 // Since this wasn't the direct target of the event, we might have 7986 // stepped past dehydrated DOM nodes to get here. However they could 7987 // also have been non-React nodes. We need to answer which one. 7988 // If we the instance doesn't have any children, then there can't be 7989 // a nested suspense boundary within it. So we can use this as a fast 7990 // bailout. Most of the time, when people add non-React children to 7991 // the tree, it is using a ref to a child-less DOM node. 7992 // Normally we'd only need to check one of the fibers because if it 7993 // has ever gone from having children to deleting them or vice versa 7994 // it would have deleted the dehydrated boundary nested inside already. 7995 // However, since the HostRoot starts out with an alternate it might 7996 // have one on the alternate so we need to check in case this was a 7997 // root. 7998 var alternate = targetInst.alternate; 7999 8000 if (targetInst.child !== null || alternate !== null && alternate.child !== null) { 8001 // Next we need to figure out if the node that skipped past is 8002 // nested within a dehydrated boundary and if so, which one. 8003 var suspenseInstance = getParentSuspenseInstance(targetNode); 8004 8005 while (suspenseInstance !== null) { 8006 // We found a suspense instance. That means that we haven't 8007 // hydrated it yet. Even though we leave the comments in the 8008 // DOM after hydrating, and there are boundaries in the DOM 8009 // that could already be hydrated, we wouldn't have found them 8010 // through this pass since if the target is hydrated it would 8011 // have had an internalInstanceKey on it. 8012 // Let's get the fiber associated with the SuspenseComponent 8013 // as the deepest instance. 8014 var targetSuspenseInst = suspenseInstance[internalInstanceKey]; 8015 8016 if (targetSuspenseInst) { 8017 return targetSuspenseInst; 8018 } // If we don't find a Fiber on the comment, it might be because 8019 // we haven't gotten to hydrate it yet. There might still be a 8020 // parent boundary that hasn't above this one so we need to find 8021 // the outer most that is known. 8022 8023 8024 suspenseInstance = getParentSuspenseInstance(suspenseInstance); // If we don't find one, then that should mean that the parent 8025 // host component also hasn't hydrated yet. We can return it 8026 // below since it will bail out on the isMounted check later. 8027 } 8028 } 8029 8030 return targetInst; 8031 } 8032 8033 targetNode = parentNode; 8034 parentNode = targetNode.parentNode; 8035 } 8036 8037 return null; 8038 } 8039 /** 8040 * Given a DOM node, return the ReactDOMComponent or ReactDOMTextComponent 8041 * instance, or null if the node was not rendered by this React. 8042 */ 8043 8044 function getInstanceFromNode$1(node) { 8045 var inst = node[internalInstanceKey] || node[internalContainerInstanceKey]; 8046 8047 if (inst) { 8048 if (inst.tag === HostComponent || inst.tag === HostText || inst.tag === SuspenseComponent || inst.tag === HostRoot) { 8049 return inst; 8050 } else { 8051 return null; 8052 } 8053 } 8054 8055 return null; 8056 } 8057 /** 8058 * Given a ReactDOMComponent or ReactDOMTextComponent, return the corresponding 8059 * DOM node. 8060 */ 8061 8062 function getNodeFromInstance$1(inst) { 8063 if (inst.tag === HostComponent || inst.tag === HostText) { 8064 // In Fiber this, is just the state node right now. We assume it will be 8065 // a host component or host text. 8066 return inst.stateNode; 8067 } // Without this first invariant, passing a non-DOM-component triggers the next 8068 // invariant for a missing parent, which is super confusing. 8069 8070 8071 { 8072 { 8073 throw Error( "getNodeFromInstance: Invalid argument." ); 8074 } 8075 } 8076 } 8077 function getFiberCurrentPropsFromNode$1(node) { 8078 return node[internalEventHandlersKey] || null; 8079 } 8080 function updateFiberProps(node, props) { 8081 node[internalEventHandlersKey] = props; 8082 } 8083 8084 function getParent(inst) { 8085 do { 8086 inst = inst.return; // TODO: If this is a HostRoot we might want to bail out. 8087 // That is depending on if we want nested subtrees (layers) to bubble 8088 // events to their parent. We could also go through parentNode on the 8089 // host node but that wouldn't work for React Native and doesn't let us 8090 // do the portal feature. 8091 } while (inst && inst.tag !== HostComponent); 8092 8093 if (inst) { 8094 return inst; 8095 } 8096 8097 return null; 8098 } 8099 /** 8100 * Return the lowest common ancestor of A and B, or null if they are in 8101 * different trees. 8102 */ 8103 8104 8105 function getLowestCommonAncestor(instA, instB) { 8106 var depthA = 0; 8107 8108 for (var tempA = instA; tempA; tempA = getParent(tempA)) { 8109 depthA++; 8110 } 8111 8112 var depthB = 0; 8113 8114 for (var tempB = instB; tempB; tempB = getParent(tempB)) { 8115 depthB++; 8116 } // If A is deeper, crawl up. 8117 8118 8119 while (depthA - depthB > 0) { 8120 instA = getParent(instA); 8121 depthA--; 8122 } // If B is deeper, crawl up. 8123 8124 8125 while (depthB - depthA > 0) { 8126 instB = getParent(instB); 8127 depthB--; 8128 } // Walk in lockstep until we find a match. 8129 8130 8131 var depth = depthA; 8132 8133 while (depth--) { 8134 if (instA === instB || instA === instB.alternate) { 8135 return instA; 8136 } 8137 8138 instA = getParent(instA); 8139 instB = getParent(instB); 8140 } 8141 8142 return null; 8143 } 8144 /** 8145 * Simulates the traversal of a two-phase, capture/bubble event dispatch. 8146 */ 8147 8148 function traverseTwoPhase(inst, fn, arg) { 8149 var path = []; 8150 8151 while (inst) { 8152 path.push(inst); 8153 inst = getParent(inst); 8154 } 8155 8156 var i; 8157 8158 for (i = path.length; i-- > 0;) { 8159 fn(path[i], 'captured', arg); 8160 } 8161 8162 for (i = 0; i < path.length; i++) { 8163 fn(path[i], 'bubbled', arg); 8164 } 8165 } 8166 /** 8167 * Traverses the ID hierarchy and invokes the supplied `cb` on any IDs that 8168 * should would receive a `mouseEnter` or `mouseLeave` event. 8169 * 8170 * Does not invoke the callback on the nearest common ancestor because nothing 8171 * "entered" or "left" that element. 8172 */ 8173 8174 function traverseEnterLeave(from, to, fn, argFrom, argTo) { 8175 var common = from && to ? getLowestCommonAncestor(from, to) : null; 8176 var pathFrom = []; 8177 8178 while (true) { 8179 if (!from) { 8180 break; 8181 } 8182 8183 if (from === common) { 8184 break; 8185 } 8186 8187 var alternate = from.alternate; 8188 8189 if (alternate !== null && alternate === common) { 8190 break; 8191 } 8192 8193 pathFrom.push(from); 8194 from = getParent(from); 8195 } 8196 8197 var pathTo = []; 8198 8199 while (true) { 8200 if (!to) { 8201 break; 8202 } 8203 8204 if (to === common) { 8205 break; 8206 } 8207 8208 var _alternate = to.alternate; 8209 8210 if (_alternate !== null && _alternate === common) { 8211 break; 8212 } 8213 8214 pathTo.push(to); 8215 to = getParent(to); 8216 } 8217 8218 for (var i = 0; i < pathFrom.length; i++) { 8219 fn(pathFrom[i], 'bubbled', argFrom); 8220 } 8221 8222 for (var _i = pathTo.length; _i-- > 0;) { 8223 fn(pathTo[_i], 'captured', argTo); 8224 } 8225 } 8226 8227 function isInteractive(tag) { 8228 return tag === 'button' || tag === 'input' || tag === 'select' || tag === 'textarea'; 8229 } 8230 8231 function shouldPreventMouseEvent(name, type, props) { 8232 switch (name) { 8233 case 'onClick': 8234 case 'onClickCapture': 8235 case 'onDoubleClick': 8236 case 'onDoubleClickCapture': 8237 case 'onMouseDown': 8238 case 'onMouseDownCapture': 8239 case 'onMouseMove': 8240 case 'onMouseMoveCapture': 8241 case 'onMouseUp': 8242 case 'onMouseUpCapture': 8243 case 'onMouseEnter': 8244 return !!(props.disabled && isInteractive(type)); 8245 8246 default: 8247 return false; 8248 } 8249 } 8250 /** 8251 * @param {object} inst The instance, which is the source of events. 8252 * @param {string} registrationName Name of listener (e.g. `onClick`). 8253 * @return {?function} The stored callback. 8254 */ 8255 8256 8257 function getListener(inst, registrationName) { 8258 var listener; // TODO: shouldPreventMouseEvent is DOM-specific and definitely should not 8259 // live here; needs to be moved to a better place soon 8260 8261 var stateNode = inst.stateNode; 8262 8263 if (!stateNode) { 8264 // Work in progress (ex: onload events in incremental mode). 8265 return null; 8266 } 8267 8268 var props = getFiberCurrentPropsFromNode(stateNode); 8269 8270 if (!props) { 8271 // Work in progress. 8272 return null; 8273 } 8274 8275 listener = props[registrationName]; 8276 8277 if (shouldPreventMouseEvent(registrationName, inst.type, props)) { 8278 return null; 8279 } 8280 8281 if (!(!listener || typeof listener === 'function')) { 8282 { 8283 throw Error( "Expected `" + registrationName + "` listener to be a function, instead got a value of `" + typeof listener + "` type." ); 8284 } 8285 } 8286 8287 return listener; 8288 } 8289 8290 /** 8291 * Some event types have a notion of different registration names for different 8292 * "phases" of propagation. This finds listeners by a given phase. 8293 */ 8294 function listenerAtPhase(inst, event, propagationPhase) { 8295 var registrationName = event.dispatchConfig.phasedRegistrationNames[propagationPhase]; 8296 return getListener(inst, registrationName); 8297 } 8298 /** 8299 * A small set of propagation patterns, each of which will accept a small amount 8300 * of information, and generate a set of "dispatch ready event objects" - which 8301 * are sets of events that have already been annotated with a set of dispatched 8302 * listener functions/ids. The API is designed this way to discourage these 8303 * propagation strategies from actually executing the dispatches, since we 8304 * always want to collect the entire set of dispatches before executing even a 8305 * single one. 8306 */ 8307 8308 /** 8309 * Tags a `SyntheticEvent` with dispatched listeners. Creating this function 8310 * here, allows us to not have to bind or create functions for each event. 8311 * Mutating the event's members allows us to not have to create a wrapping 8312 * "dispatch" object that pairs the event with the listener. 8313 */ 8314 8315 8316 function accumulateDirectionalDispatches(inst, phase, event) { 8317 { 8318 if (!inst) { 8319 error('Dispatching inst must not be null'); 8320 } 8321 } 8322 8323 var listener = listenerAtPhase(inst, event, phase); 8324 8325 if (listener) { 8326 event._dispatchListeners = accumulateInto(event._dispatchListeners, listener); 8327 event._dispatchInstances = accumulateInto(event._dispatchInstances, inst); 8328 } 8329 } 8330 /** 8331 * Collect dispatches (must be entirely collected before dispatching - see unit 8332 * tests). Lazily allocate the array to conserve memory. We must loop through 8333 * each event and perform the traversal for each one. We cannot perform a 8334 * single traversal for the entire collection of events because each event may 8335 * have a different target. 8336 */ 8337 8338 8339 function accumulateTwoPhaseDispatchesSingle(event) { 8340 if (event && event.dispatchConfig.phasedRegistrationNames) { 8341 traverseTwoPhase(event._targetInst, accumulateDirectionalDispatches, event); 8342 } 8343 } 8344 /** 8345 * Accumulates without regard to direction, does not look for phased 8346 * registration names. Same as `accumulateDirectDispatchesSingle` but without 8347 * requiring that the `dispatchMarker` be the same as the dispatched ID. 8348 */ 8349 8350 8351 function accumulateDispatches(inst, ignoredDirection, event) { 8352 if (inst && event && event.dispatchConfig.registrationName) { 8353 var registrationName = event.dispatchConfig.registrationName; 8354 var listener = getListener(inst, registrationName); 8355 8356 if (listener) { 8357 event._dispatchListeners = accumulateInto(event._dispatchListeners, listener); 8358 event._dispatchInstances = accumulateInto(event._dispatchInstances, inst); 8359 } 8360 } 8361 } 8362 /** 8363 * Accumulates dispatches on an `SyntheticEvent`, but only for the 8364 * `dispatchMarker`. 8365 * @param {SyntheticEvent} event 8366 */ 8367 8368 8369 function accumulateDirectDispatchesSingle(event) { 8370 if (event && event.dispatchConfig.registrationName) { 8371 accumulateDispatches(event._targetInst, null, event); 8372 } 8373 } 8374 8375 function accumulateTwoPhaseDispatches(events) { 8376 forEachAccumulated(events, accumulateTwoPhaseDispatchesSingle); 8377 } 8378 function accumulateEnterLeaveDispatches(leave, enter, from, to) { 8379 traverseEnterLeave(from, to, accumulateDispatches, leave, enter); 8380 } 8381 function accumulateDirectDispatches(events) { 8382 forEachAccumulated(events, accumulateDirectDispatchesSingle); 8383 } 8384 8385 /** 8386 * These variables store information about text content of a target node, 8387 * allowing comparison of content before and after a given event. 8388 * 8389 * Identify the node where selection currently begins, then observe 8390 * both its text content and its current position in the DOM. Since the 8391 * browser may natively replace the target node during composition, we can 8392 * use its position to find its replacement. 8393 * 8394 * 8395 */ 8396 var root = null; 8397 var startText = null; 8398 var fallbackText = null; 8399 function initialize(nativeEventTarget) { 8400 root = nativeEventTarget; 8401 startText = getText(); 8402 return true; 8403 } 8404 function reset() { 8405 root = null; 8406 startText = null; 8407 fallbackText = null; 8408 } 8409 function getData() { 8410 if (fallbackText) { 8411 return fallbackText; 8412 } 8413 8414 var start; 8415 var startValue = startText; 8416 var startLength = startValue.length; 8417 var end; 8418 var endValue = getText(); 8419 var endLength = endValue.length; 8420 8421 for (start = 0; start < startLength; start++) { 8422 if (startValue[start] !== endValue[start]) { 8423 break; 8424 } 8425 } 8426 8427 var minEnd = startLength - start; 8428 8429 for (end = 1; end <= minEnd; end++) { 8430 if (startValue[startLength - end] !== endValue[endLength - end]) { 8431 break; 8432 } 8433 } 8434 8435 var sliceTail = end > 1 ? 1 - end : undefined; 8436 fallbackText = endValue.slice(start, sliceTail); 8437 return fallbackText; 8438 } 8439 function getText() { 8440 if ('value' in root) { 8441 return root.value; 8442 } 8443 8444 return root.textContent; 8445 } 8446 8447 var EVENT_POOL_SIZE = 10; 8448 /** 8449 * @interface Event 8450 * @see http://www.w3.org/TR/DOM-Level-3-Events/ 8451 */ 8452 8453 var EventInterface = { 8454 type: null, 8455 target: null, 8456 // currentTarget is set when dispatching; no use in copying it here 8457 currentTarget: function () { 8458 return null; 8459 }, 8460 eventPhase: null, 8461 bubbles: null, 8462 cancelable: null, 8463 timeStamp: function (event) { 8464 return event.timeStamp || Date.now(); 8465 }, 8466 defaultPrevented: null, 8467 isTrusted: null 8468 }; 8469 8470 function functionThatReturnsTrue() { 8471 return true; 8472 } 8473 8474 function functionThatReturnsFalse() { 8475 return false; 8476 } 8477 /** 8478 * Synthetic events are dispatched by event plugins, typically in response to a 8479 * top-level event delegation handler. 8480 * 8481 * These systems should generally use pooling to reduce the frequency of garbage 8482 * collection. The system should check `isPersistent` to determine whether the 8483 * event should be released into the pool after being dispatched. Users that 8484 * need a persisted event should invoke `persist`. 8485 * 8486 * Synthetic events (and subclasses) implement the DOM Level 3 Events API by 8487 * normalizing browser quirks. Subclasses do not necessarily have to implement a 8488 * DOM interface; custom application-specific events can also subclass this. 8489 * 8490 * @param {object} dispatchConfig Configuration used to dispatch this event. 8491 * @param {*} targetInst Marker identifying the event target. 8492 * @param {object} nativeEvent Native browser event. 8493 * @param {DOMEventTarget} nativeEventTarget Target node. 8494 */ 8495 8496 8497 function SyntheticEvent(dispatchConfig, targetInst, nativeEvent, nativeEventTarget) { 8498 { 8499 // these have a getter/setter for warnings 8500 delete this.nativeEvent; 8501 delete this.preventDefault; 8502 delete this.stopPropagation; 8503 delete this.isDefaultPrevented; 8504 delete this.isPropagationStopped; 8505 } 8506 8507 this.dispatchConfig = dispatchConfig; 8508 this._targetInst = targetInst; 8509 this.nativeEvent = nativeEvent; 8510 var Interface = this.constructor.Interface; 8511 8512 for (var propName in Interface) { 8513 if (!Interface.hasOwnProperty(propName)) { 8514 continue; 8515 } 8516 8517 { 8518 delete this[propName]; // this has a getter/setter for warnings 8519 } 8520 8521 var normalize = Interface[propName]; 8522 8523 if (normalize) { 8524 this[propName] = normalize(nativeEvent); 8525 } else { 8526 if (propName === 'target') { 8527 this.target = nativeEventTarget; 8528 } else { 8529 this[propName] = nativeEvent[propName]; 8530 } 8531 } 8532 } 8533 8534 var defaultPrevented = nativeEvent.defaultPrevented != null ? nativeEvent.defaultPrevented : nativeEvent.returnValue === false; 8535 8536 if (defaultPrevented) { 8537 this.isDefaultPrevented = functionThatReturnsTrue; 8538 } else { 8539 this.isDefaultPrevented = functionThatReturnsFalse; 8540 } 8541 8542 this.isPropagationStopped = functionThatReturnsFalse; 8543 return this; 8544 } 8545 8546 _assign(SyntheticEvent.prototype, { 8547 preventDefault: function () { 8548 this.defaultPrevented = true; 8549 var event = this.nativeEvent; 8550 8551 if (!event) { 8552 return; 8553 } 8554 8555 if (event.preventDefault) { 8556 event.preventDefault(); 8557 } else if (typeof event.returnValue !== 'unknown') { 8558 event.returnValue = false; 8559 } 8560 8561 this.isDefaultPrevented = functionThatReturnsTrue; 8562 }, 8563 stopPropagation: function () { 8564 var event = this.nativeEvent; 8565 8566 if (!event) { 8567 return; 8568 } 8569 8570 if (event.stopPropagation) { 8571 event.stopPropagation(); 8572 } else if (typeof event.cancelBubble !== 'unknown') { 8573 // The ChangeEventPlugin registers a "propertychange" event for 8574 // IE. This event does not support bubbling or cancelling, and 8575 // any references to cancelBubble throw "Member not found". A 8576 // typeof check of "unknown" circumvents this issue (and is also 8577 // IE specific). 8578 event.cancelBubble = true; 8579 } 8580 8581 this.isPropagationStopped = functionThatReturnsTrue; 8582 }, 8583 8584 /** 8585 * We release all dispatched `SyntheticEvent`s after each event loop, adding 8586 * them back into the pool. This allows a way to hold onto a reference that 8587 * won't be added back into the pool. 8588 */ 8589 persist: function () { 8590 this.isPersistent = functionThatReturnsTrue; 8591 }, 8592 8593 /** 8594 * Checks if this event should be released back into the pool. 8595 * 8596 * @return {boolean} True if this should not be released, false otherwise. 8597 */ 8598 isPersistent: functionThatReturnsFalse, 8599 8600 /** 8601 * `PooledClass` looks for `destructor` on each instance it releases. 8602 */ 8603 destructor: function () { 8604 var Interface = this.constructor.Interface; 8605 8606 for (var propName in Interface) { 8607 { 8608 Object.defineProperty(this, propName, getPooledWarningPropertyDefinition(propName, Interface[propName])); 8609 } 8610 } 8611 8612 this.dispatchConfig = null; 8613 this._targetInst = null; 8614 this.nativeEvent = null; 8615 this.isDefaultPrevented = functionThatReturnsFalse; 8616 this.isPropagationStopped = functionThatReturnsFalse; 8617 this._dispatchListeners = null; 8618 this._dispatchInstances = null; 8619 8620 { 8621 Object.defineProperty(this, 'nativeEvent', getPooledWarningPropertyDefinition('nativeEvent', null)); 8622 Object.defineProperty(this, 'isDefaultPrevented', getPooledWarningPropertyDefinition('isDefaultPrevented', functionThatReturnsFalse)); 8623 Object.defineProperty(this, 'isPropagationStopped', getPooledWarningPropertyDefinition('isPropagationStopped', functionThatReturnsFalse)); 8624 Object.defineProperty(this, 'preventDefault', getPooledWarningPropertyDefinition('preventDefault', function () {})); 8625 Object.defineProperty(this, 'stopPropagation', getPooledWarningPropertyDefinition('stopPropagation', function () {})); 8626 } 8627 } 8628 }); 8629 8630 SyntheticEvent.Interface = EventInterface; 8631 /** 8632 * Helper to reduce boilerplate when creating subclasses. 8633 */ 8634 8635 SyntheticEvent.extend = function (Interface) { 8636 var Super = this; 8637 8638 var E = function () {}; 8639 8640 E.prototype = Super.prototype; 8641 var prototype = new E(); 8642 8643 function Class() { 8644 return Super.apply(this, arguments); 8645 } 8646 8647 _assign(prototype, Class.prototype); 8648 8649 Class.prototype = prototype; 8650 Class.prototype.constructor = Class; 8651 Class.Interface = _assign({}, Super.Interface, Interface); 8652 Class.extend = Super.extend; 8653 addEventPoolingTo(Class); 8654 return Class; 8655 }; 8656 8657 addEventPoolingTo(SyntheticEvent); 8658 /** 8659 * Helper to nullify syntheticEvent instance properties when destructing 8660 * 8661 * @param {String} propName 8662 * @param {?object} getVal 8663 * @return {object} defineProperty object 8664 */ 8665 8666 function getPooledWarningPropertyDefinition(propName, getVal) { 8667 var isFunction = typeof getVal === 'function'; 8668 return { 8669 configurable: true, 8670 set: set, 8671 get: get 8672 }; 8673 8674 function set(val) { 8675 var action = isFunction ?