Mercurial
comparison third_party/bun/node_modules/react-dom/cjs/react-dom-server.node.development.js @ 12:de54585a40f1
Adding bun and node modules.
| author | June Park <parkjune1995@gmail.com> |
|---|---|
| date | Thu, 02 Oct 2025 14:39:48 -0700 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 11:f33d9ff8b6e8 | 12:de54585a40f1 |
|---|---|
| 1 /** | |
| 2 * @license React | |
| 3 * react-dom-server.node.development.js | |
| 4 * | |
| 5 * Copyright (c) Facebook, Inc. and its affiliates. | |
| 6 * | |
| 7 * This source code is licensed under the MIT license found in the | |
| 8 * LICENSE file in the root directory of this source tree. | |
| 9 */ | |
| 10 | |
| 11 'use strict'; | |
| 12 | |
| 13 if (process.env.NODE_ENV !== "production") { | |
| 14 (function() { | |
| 15 'use strict'; | |
| 16 | |
| 17 var React = require('react'); | |
| 18 var util = require('util'); | |
| 19 | |
| 20 var ReactVersion = '18.3.1'; | |
| 21 | |
| 22 var ReactSharedInternals = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; | |
| 23 | |
| 24 // by calls to these methods by a Babel plugin. | |
| 25 // | |
| 26 // In PROD (or in packages without access to React internals), | |
| 27 // they are left as they are instead. | |
| 28 | |
| 29 function warn(format) { | |
| 30 { | |
| 31 { | |
| 32 for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { | |
| 33 args[_key - 1] = arguments[_key]; | |
| 34 } | |
| 35 | |
| 36 printWarning('warn', format, args); | |
| 37 } | |
| 38 } | |
| 39 } | |
| 40 function error(format) { | |
| 41 { | |
| 42 { | |
| 43 for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) { | |
| 44 args[_key2 - 1] = arguments[_key2]; | |
| 45 } | |
| 46 | |
| 47 printWarning('error', format, args); | |
| 48 } | |
| 49 } | |
| 50 } | |
| 51 | |
| 52 function printWarning(level, format, args) { | |
| 53 // When changing this logic, you might want to also | |
| 54 // update consoleWithStackDev.www.js as well. | |
| 55 { | |
| 56 var ReactDebugCurrentFrame = ReactSharedInternals.ReactDebugCurrentFrame; | |
| 57 var stack = ReactDebugCurrentFrame.getStackAddendum(); | |
| 58 | |
| 59 if (stack !== '') { | |
| 60 format += '%s'; | |
| 61 args = args.concat([stack]); | |
| 62 } // eslint-disable-next-line react-internal/safe-string-coercion | |
| 63 | |
| 64 | |
| 65 var argsWithFormat = args.map(function (item) { | |
| 66 return String(item); | |
| 67 }); // Careful: RN currently depends on this prefix | |
| 68 | |
| 69 argsWithFormat.unshift('Warning: ' + format); // We intentionally don't use spread (or .apply) directly because it | |
| 70 // breaks IE9: https://github.com/facebook/react/issues/13610 | |
| 71 // eslint-disable-next-line react-internal/no-production-logging | |
| 72 | |
| 73 Function.prototype.apply.call(console[level], console, argsWithFormat); | |
| 74 } | |
| 75 } | |
| 76 | |
| 77 function scheduleWork(callback) { | |
| 78 setImmediate(callback); | |
| 79 } | |
| 80 function flushBuffered(destination) { | |
| 81 // If we don't have any more data to send right now. | |
| 82 // Flush whatever is in the buffer to the wire. | |
| 83 if (typeof destination.flush === 'function') { | |
| 84 // By convention the Zlib streams provide a flush function for this purpose. | |
| 85 // For Express, compression middleware adds this method. | |
| 86 destination.flush(); | |
| 87 } | |
| 88 } | |
| 89 var VIEW_SIZE = 2048; | |
| 90 var currentView = null; | |
| 91 var writtenBytes = 0; | |
| 92 var destinationHasCapacity = true; | |
| 93 function beginWriting(destination) { | |
| 94 currentView = new Uint8Array(VIEW_SIZE); | |
| 95 writtenBytes = 0; | |
| 96 destinationHasCapacity = true; | |
| 97 } | |
| 98 | |
| 99 function writeStringChunk(destination, stringChunk) { | |
| 100 if (stringChunk.length === 0) { | |
| 101 return; | |
| 102 } // maximum possible view needed to encode entire string | |
| 103 | |
| 104 | |
| 105 if (stringChunk.length * 3 > VIEW_SIZE) { | |
| 106 if (writtenBytes > 0) { | |
| 107 writeToDestination(destination, currentView.subarray(0, writtenBytes)); | |
| 108 currentView = new Uint8Array(VIEW_SIZE); | |
| 109 writtenBytes = 0; | |
| 110 } | |
| 111 | |
| 112 writeToDestination(destination, textEncoder.encode(stringChunk)); | |
| 113 return; | |
| 114 } | |
| 115 | |
| 116 var target = currentView; | |
| 117 | |
| 118 if (writtenBytes > 0) { | |
| 119 target = currentView.subarray(writtenBytes); | |
| 120 } | |
| 121 | |
| 122 var _textEncoder$encodeIn = textEncoder.encodeInto(stringChunk, target), | |
| 123 read = _textEncoder$encodeIn.read, | |
| 124 written = _textEncoder$encodeIn.written; | |
| 125 | |
| 126 writtenBytes += written; | |
| 127 | |
| 128 if (read < stringChunk.length) { | |
| 129 writeToDestination(destination, currentView); | |
| 130 currentView = new Uint8Array(VIEW_SIZE); | |
| 131 writtenBytes = textEncoder.encodeInto(stringChunk.slice(read), currentView).written; | |
| 132 } | |
| 133 | |
| 134 if (writtenBytes === VIEW_SIZE) { | |
| 135 writeToDestination(destination, currentView); | |
| 136 currentView = new Uint8Array(VIEW_SIZE); | |
| 137 writtenBytes = 0; | |
| 138 } | |
| 139 } | |
| 140 | |
| 141 function writeViewChunk(destination, chunk) { | |
| 142 if (chunk.byteLength === 0) { | |
| 143 return; | |
| 144 } | |
| 145 | |
| 146 if (chunk.byteLength > VIEW_SIZE) { | |
| 147 // this chunk may overflow a single view which implies it was not | |
| 148 // one that is cached by the streaming renderer. We will enqueu | |
| 149 // it directly and expect it is not re-used | |
| 150 if (writtenBytes > 0) { | |
| 151 writeToDestination(destination, currentView.subarray(0, writtenBytes)); | |
| 152 currentView = new Uint8Array(VIEW_SIZE); | |
| 153 writtenBytes = 0; | |
| 154 } | |
| 155 | |
| 156 writeToDestination(destination, chunk); | |
| 157 return; | |
| 158 } | |
| 159 | |
| 160 var bytesToWrite = chunk; | |
| 161 var allowableBytes = currentView.length - writtenBytes; | |
| 162 | |
| 163 if (allowableBytes < bytesToWrite.byteLength) { | |
| 164 // this chunk would overflow the current view. We enqueue a full view | |
| 165 // and start a new view with the remaining chunk | |
| 166 if (allowableBytes === 0) { | |
| 167 // the current view is already full, send it | |
| 168 writeToDestination(destination, currentView); | |
| 169 } else { | |
| 170 // fill up the current view and apply the remaining chunk bytes | |
| 171 // to a new view. | |
| 172 currentView.set(bytesToWrite.subarray(0, allowableBytes), writtenBytes); | |
| 173 writtenBytes += allowableBytes; | |
| 174 writeToDestination(destination, currentView); | |
| 175 bytesToWrite = bytesToWrite.subarray(allowableBytes); | |
| 176 } | |
| 177 | |
| 178 currentView = new Uint8Array(VIEW_SIZE); | |
| 179 writtenBytes = 0; | |
| 180 } | |
| 181 | |
| 182 currentView.set(bytesToWrite, writtenBytes); | |
| 183 writtenBytes += bytesToWrite.byteLength; | |
| 184 | |
| 185 if (writtenBytes === VIEW_SIZE) { | |
| 186 writeToDestination(destination, currentView); | |
| 187 currentView = new Uint8Array(VIEW_SIZE); | |
| 188 writtenBytes = 0; | |
| 189 } | |
| 190 } | |
| 191 | |
| 192 function writeChunk(destination, chunk) { | |
| 193 if (typeof chunk === 'string') { | |
| 194 writeStringChunk(destination, chunk); | |
| 195 } else { | |
| 196 writeViewChunk(destination, chunk); | |
| 197 } | |
| 198 } | |
| 199 | |
| 200 function writeToDestination(destination, view) { | |
| 201 var currentHasCapacity = destination.write(view); | |
| 202 destinationHasCapacity = destinationHasCapacity && currentHasCapacity; | |
| 203 } | |
| 204 | |
| 205 function writeChunkAndReturn(destination, chunk) { | |
| 206 writeChunk(destination, chunk); | |
| 207 return destinationHasCapacity; | |
| 208 } | |
| 209 function completeWriting(destination) { | |
| 210 if (currentView && writtenBytes > 0) { | |
| 211 destination.write(currentView.subarray(0, writtenBytes)); | |
| 212 } | |
| 213 | |
| 214 currentView = null; | |
| 215 writtenBytes = 0; | |
| 216 destinationHasCapacity = true; | |
| 217 } | |
| 218 function close(destination) { | |
| 219 destination.end(); | |
| 220 } | |
| 221 var textEncoder = new util.TextEncoder(); | |
| 222 function stringToChunk(content) { | |
| 223 return content; | |
| 224 } | |
| 225 function stringToPrecomputedChunk(content) { | |
| 226 return textEncoder.encode(content); | |
| 227 } | |
| 228 function closeWithError(destination, error) { | |
| 229 // $FlowFixMe: This is an Error object or the destination accepts other types. | |
| 230 destination.destroy(error); | |
| 231 } | |
| 232 | |
| 233 /* | |
| 234 * The `'' + value` pattern (used in in perf-sensitive code) throws for Symbol | |
| 235 * and Temporal.* types. See https://github.com/facebook/react/pull/22064. | |
| 236 * | |
| 237 * The functions in this module will throw an easier-to-understand, | |
| 238 * easier-to-debug exception with a clear errors message message explaining the | |
| 239 * problem. (Instead of a confusing exception thrown inside the implementation | |
| 240 * of the `value` object). | |
| 241 */ | |
| 242 // $FlowFixMe only called in DEV, so void return is not possible. | |
| 243 function typeName(value) { | |
| 244 { | |
| 245 // toStringTag is needed for namespaced types like Temporal.Instant | |
| 246 var hasToStringTag = typeof Symbol === 'function' && Symbol.toStringTag; | |
| 247 var type = hasToStringTag && value[Symbol.toStringTag] || value.constructor.name || 'Object'; | |
| 248 return type; | |
| 249 } | |
| 250 } // $FlowFixMe only called in DEV, so void return is not possible. | |
| 251 | |
| 252 | |
| 253 function willCoercionThrow(value) { | |
| 254 { | |
| 255 try { | |
| 256 testStringCoercion(value); | |
| 257 return false; | |
| 258 } catch (e) { | |
| 259 return true; | |
| 260 } | |
| 261 } | |
| 262 } | |
| 263 | |
| 264 function testStringCoercion(value) { | |
| 265 // If you ended up here by following an exception call stack, here's what's | |
| 266 // happened: you supplied an object or symbol value to React (as a prop, key, | |
| 267 // DOM attribute, CSS property, string ref, etc.) and when React tried to | |
| 268 // coerce it to a string using `'' + value`, an exception was thrown. | |
| 269 // | |
| 270 // The most common types that will cause this exception are `Symbol` instances | |
| 271 // and Temporal objects like `Temporal.Instant`. But any object that has a | |
| 272 // `valueOf` or `[Symbol.toPrimitive]` method that throws will also cause this | |
| 273 // exception. (Library authors do this to prevent users from using built-in | |
| 274 // numeric operators like `+` or comparison operators like `>=` because custom | |
| 275 // methods are needed to perform accurate arithmetic or comparison.) | |
| 276 // | |
| 277 // To fix the problem, coerce this object or symbol value to a string before | |
| 278 // passing it to React. The most reliable way is usually `String(value)`. | |
| 279 // | |
| 280 // To find which value is throwing, check the browser or debugger console. | |
| 281 // Before this exception was thrown, there should be `console.error` output | |
| 282 // that shows the type (Symbol, Temporal.PlainDate, etc.) that caused the | |
| 283 // problem and how that type was used: key, atrribute, input value prop, etc. | |
| 284 // In most cases, this console output also shows the component and its | |
| 285 // ancestor components where the exception happened. | |
| 286 // | |
| 287 // eslint-disable-next-line react-internal/safe-string-coercion | |
| 288 return '' + value; | |
| 289 } | |
| 290 | |
| 291 function checkAttributeStringCoercion(value, attributeName) { | |
| 292 { | |
| 293 if (willCoercionThrow(value)) { | |
| 294 error('The provided `%s` attribute is an unsupported type %s.' + ' This value must be coerced to a string before before using it here.', attributeName, typeName(value)); | |
| 295 | |
| 296 return testStringCoercion(value); // throw (to help callers find troubleshooting comments) | |
| 297 } | |
| 298 } | |
| 299 } | |
| 300 function checkCSSPropertyStringCoercion(value, propName) { | |
| 301 { | |
| 302 if (willCoercionThrow(value)) { | |
| 303 error('The provided `%s` CSS property is an unsupported type %s.' + ' This value must be coerced to a string before before using it here.', propName, typeName(value)); | |
| 304 | |
| 305 return testStringCoercion(value); // throw (to help callers find troubleshooting comments) | |
| 306 } | |
| 307 } | |
| 308 } | |
| 309 function checkHtmlStringCoercion(value) { | |
| 310 { | |
| 311 if (willCoercionThrow(value)) { | |
| 312 error('The provided HTML markup uses a value of unsupported type %s.' + ' This value must be coerced to a string before before using it here.', typeName(value)); | |
| 313 | |
| 314 return testStringCoercion(value); // throw (to help callers find troubleshooting comments) | |
| 315 } | |
| 316 } | |
| 317 } | |
| 318 | |
| 319 var hasOwnProperty = Object.prototype.hasOwnProperty; | |
| 320 | |
| 321 // A reserved attribute. | |
| 322 // It is handled by React separately and shouldn't be written to the DOM. | |
| 323 var RESERVED = 0; // A simple string attribute. | |
| 324 // Attributes that aren't in the filter are presumed to have this type. | |
| 325 | |
| 326 var STRING = 1; // A string attribute that accepts booleans in React. In HTML, these are called | |
| 327 // "enumerated" attributes with "true" and "false" as possible values. | |
| 328 // When true, it should be set to a "true" string. | |
| 329 // When false, it should be set to a "false" string. | |
| 330 | |
| 331 var BOOLEANISH_STRING = 2; // A real boolean attribute. | |
| 332 // When true, it should be present (set either to an empty string or its name). | |
| 333 // When false, it should be omitted. | |
| 334 | |
| 335 var BOOLEAN = 3; // An attribute that can be used as a flag as well as with a value. | |
| 336 // When true, it should be present (set either to an empty string or its name). | |
| 337 // When false, it should be omitted. | |
| 338 // For any other value, should be present with that value. | |
| 339 | |
| 340 var OVERLOADED_BOOLEAN = 4; // An attribute that must be numeric or parse as a numeric. | |
| 341 // When falsy, it should be removed. | |
| 342 | |
| 343 var NUMERIC = 5; // An attribute that must be positive numeric or parse as a positive numeric. | |
| 344 // When falsy, it should be removed. | |
| 345 | |
| 346 var POSITIVE_NUMERIC = 6; | |
| 347 | |
| 348 /* eslint-disable max-len */ | |
| 349 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"; | |
| 350 /* eslint-enable max-len */ | |
| 351 | |
| 352 var ATTRIBUTE_NAME_CHAR = ATTRIBUTE_NAME_START_CHAR + "\\-.0-9\\u00B7\\u0300-\\u036F\\u203F-\\u2040"; | |
| 353 var VALID_ATTRIBUTE_NAME_REGEX = new RegExp('^[' + ATTRIBUTE_NAME_START_CHAR + '][' + ATTRIBUTE_NAME_CHAR + ']*$'); | |
| 354 var illegalAttributeNameCache = {}; | |
| 355 var validatedAttributeNameCache = {}; | |
| 356 function isAttributeNameSafe(attributeName) { | |
| 357 if (hasOwnProperty.call(validatedAttributeNameCache, attributeName)) { | |
| 358 return true; | |
| 359 } | |
| 360 | |
| 361 if (hasOwnProperty.call(illegalAttributeNameCache, attributeName)) { | |
| 362 return false; | |
| 363 } | |
| 364 | |
| 365 if (VALID_ATTRIBUTE_NAME_REGEX.test(attributeName)) { | |
| 366 validatedAttributeNameCache[attributeName] = true; | |
| 367 return true; | |
| 368 } | |
| 369 | |
| 370 illegalAttributeNameCache[attributeName] = true; | |
| 371 | |
| 372 { | |
| 373 error('Invalid attribute name: `%s`', attributeName); | |
| 374 } | |
| 375 | |
| 376 return false; | |
| 377 } | |
| 378 function shouldRemoveAttributeWithWarning(name, value, propertyInfo, isCustomComponentTag) { | |
| 379 if (propertyInfo !== null && propertyInfo.type === RESERVED) { | |
| 380 return false; | |
| 381 } | |
| 382 | |
| 383 switch (typeof value) { | |
| 384 case 'function': // $FlowIssue symbol is perfectly valid here | |
| 385 | |
| 386 case 'symbol': | |
| 387 // eslint-disable-line | |
| 388 return true; | |
| 389 | |
| 390 case 'boolean': | |
| 391 { | |
| 392 if (isCustomComponentTag) { | |
| 393 return false; | |
| 394 } | |
| 395 | |
| 396 if (propertyInfo !== null) { | |
| 397 return !propertyInfo.acceptsBooleans; | |
| 398 } else { | |
| 399 var prefix = name.toLowerCase().slice(0, 5); | |
| 400 return prefix !== 'data-' && prefix !== 'aria-'; | |
| 401 } | |
| 402 } | |
| 403 | |
| 404 default: | |
| 405 return false; | |
| 406 } | |
| 407 } | |
| 408 function getPropertyInfo(name) { | |
| 409 return properties.hasOwnProperty(name) ? properties[name] : null; | |
| 410 } | |
| 411 | |
| 412 function PropertyInfoRecord(name, type, mustUseProperty, attributeName, attributeNamespace, sanitizeURL, removeEmptyString) { | |
| 413 this.acceptsBooleans = type === BOOLEANISH_STRING || type === BOOLEAN || type === OVERLOADED_BOOLEAN; | |
| 414 this.attributeName = attributeName; | |
| 415 this.attributeNamespace = attributeNamespace; | |
| 416 this.mustUseProperty = mustUseProperty; | |
| 417 this.propertyName = name; | |
| 418 this.type = type; | |
| 419 this.sanitizeURL = sanitizeURL; | |
| 420 this.removeEmptyString = removeEmptyString; | |
| 421 } // When adding attributes to this list, be sure to also add them to | |
| 422 // the `possibleStandardNames` module to ensure casing and incorrect | |
| 423 // name warnings. | |
| 424 | |
| 425 | |
| 426 var properties = {}; // These props are reserved by React. They shouldn't be written to the DOM. | |
| 427 | |
| 428 var reservedProps = ['children', 'dangerouslySetInnerHTML', // TODO: This prevents the assignment of defaultValue to regular | |
| 429 // elements (not just inputs). Now that ReactDOMInput assigns to the | |
| 430 // defaultValue property -- do we need this? | |
| 431 'defaultValue', 'defaultChecked', 'innerHTML', 'suppressContentEditableWarning', 'suppressHydrationWarning', 'style']; | |
| 432 | |
| 433 reservedProps.forEach(function (name) { | |
| 434 properties[name] = new PropertyInfoRecord(name, RESERVED, false, // mustUseProperty | |
| 435 name, // attributeName | |
| 436 null, // attributeNamespace | |
| 437 false, // sanitizeURL | |
| 438 false); | |
| 439 }); // A few React string attributes have a different name. | |
| 440 // This is a mapping from React prop names to the attribute names. | |
| 441 | |
| 442 [['acceptCharset', 'accept-charset'], ['className', 'class'], ['htmlFor', 'for'], ['httpEquiv', 'http-equiv']].forEach(function (_ref) { | |
| 443 var name = _ref[0], | |
| 444 attributeName = _ref[1]; | |
| 445 properties[name] = new PropertyInfoRecord(name, STRING, false, // mustUseProperty | |
| 446 attributeName, // attributeName | |
| 447 null, // attributeNamespace | |
| 448 false, // sanitizeURL | |
| 449 false); | |
| 450 }); // These are "enumerated" HTML attributes that accept "true" and "false". | |
| 451 // In React, we let users pass `true` and `false` even though technically | |
| 452 // these aren't boolean attributes (they are coerced to strings). | |
| 453 | |
| 454 ['contentEditable', 'draggable', 'spellCheck', 'value'].forEach(function (name) { | |
| 455 properties[name] = new PropertyInfoRecord(name, BOOLEANISH_STRING, false, // mustUseProperty | |
| 456 name.toLowerCase(), // attributeName | |
| 457 null, // attributeNamespace | |
| 458 false, // sanitizeURL | |
| 459 false); | |
| 460 }); // These are "enumerated" SVG attributes that accept "true" and "false". | |
| 461 // In React, we let users pass `true` and `false` even though technically | |
| 462 // these aren't boolean attributes (they are coerced to strings). | |
| 463 // Since these are SVG attributes, their attribute names are case-sensitive. | |
| 464 | |
| 465 ['autoReverse', 'externalResourcesRequired', 'focusable', 'preserveAlpha'].forEach(function (name) { | |
| 466 properties[name] = new PropertyInfoRecord(name, BOOLEANISH_STRING, false, // mustUseProperty | |
| 467 name, // attributeName | |
| 468 null, // attributeNamespace | |
| 469 false, // sanitizeURL | |
| 470 false); | |
| 471 }); // These are HTML boolean attributes. | |
| 472 | |
| 473 ['allowFullScreen', 'async', // Note: there is a special case that prevents it from being written to the DOM | |
| 474 // on the client side because the browsers are inconsistent. Instead we call focus(). | |
| 475 'autoFocus', 'autoPlay', 'controls', 'default', 'defer', 'disabled', 'disablePictureInPicture', 'disableRemotePlayback', 'formNoValidate', 'hidden', 'loop', 'noModule', 'noValidate', 'open', 'playsInline', 'readOnly', 'required', 'reversed', 'scoped', 'seamless', // Microdata | |
| 476 'itemScope'].forEach(function (name) { | |
| 477 properties[name] = new PropertyInfoRecord(name, BOOLEAN, false, // mustUseProperty | |
| 478 name.toLowerCase(), // attributeName | |
| 479 null, // attributeNamespace | |
| 480 false, // sanitizeURL | |
| 481 false); | |
| 482 }); // These are the few React props that we set as DOM properties | |
| 483 // rather than attributes. These are all booleans. | |
| 484 | |
| 485 ['checked', // Note: `option.selected` is not updated if `select.multiple` is | |
| 486 // disabled with `removeAttribute`. We have special logic for handling this. | |
| 487 'multiple', 'muted', 'selected' // NOTE: if you add a camelCased prop to this list, | |
| 488 // you'll need to set attributeName to name.toLowerCase() | |
| 489 // instead in the assignment below. | |
| 490 ].forEach(function (name) { | |
| 491 properties[name] = new PropertyInfoRecord(name, BOOLEAN, true, // mustUseProperty | |
| 492 name, // attributeName | |
| 493 null, // attributeNamespace | |
| 494 false, // sanitizeURL | |
| 495 false); | |
| 496 }); // These are HTML attributes that are "overloaded booleans": they behave like | |
| 497 // booleans, but can also accept a string value. | |
| 498 | |
| 499 ['capture', 'download' // NOTE: if you add a camelCased prop to this list, | |
| 500 // you'll need to set attributeName to name.toLowerCase() | |
| 501 // instead in the assignment below. | |
| 502 ].forEach(function (name) { | |
| 503 properties[name] = new PropertyInfoRecord(name, OVERLOADED_BOOLEAN, false, // mustUseProperty | |
| 504 name, // attributeName | |
| 505 null, // attributeNamespace | |
| 506 false, // sanitizeURL | |
| 507 false); | |
| 508 }); // These are HTML attributes that must be positive numbers. | |
| 509 | |
| 510 ['cols', 'rows', 'size', 'span' // NOTE: if you add a camelCased prop to this list, | |
| 511 // you'll need to set attributeName to name.toLowerCase() | |
| 512 // instead in the assignment below. | |
| 513 ].forEach(function (name) { | |
| 514 properties[name] = new PropertyInfoRecord(name, POSITIVE_NUMERIC, false, // mustUseProperty | |
| 515 name, // attributeName | |
| 516 null, // attributeNamespace | |
| 517 false, // sanitizeURL | |
| 518 false); | |
| 519 }); // These are HTML attributes that must be numbers. | |
| 520 | |
| 521 ['rowSpan', 'start'].forEach(function (name) { | |
| 522 properties[name] = new PropertyInfoRecord(name, NUMERIC, false, // mustUseProperty | |
| 523 name.toLowerCase(), // attributeName | |
| 524 null, // attributeNamespace | |
| 525 false, // sanitizeURL | |
| 526 false); | |
| 527 }); | |
| 528 var CAMELIZE = /[\-\:]([a-z])/g; | |
| 529 | |
| 530 var capitalize = function (token) { | |
| 531 return token[1].toUpperCase(); | |
| 532 }; // This is a list of all SVG attributes that need special casing, namespacing, | |
| 533 // or boolean value assignment. Regular attributes that just accept strings | |
| 534 // and have the same names are omitted, just like in the HTML attribute filter. | |
| 535 // Some of these attributes can be hard to find. This list was created by | |
| 536 // scraping the MDN documentation. | |
| 537 | |
| 538 | |
| 539 ['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, | |
| 540 // you'll need to set attributeName to name.toLowerCase() | |
| 541 // instead in the assignment below. | |
| 542 ].forEach(function (attributeName) { | |
| 543 var name = attributeName.replace(CAMELIZE, capitalize); | |
| 544 properties[name] = new PropertyInfoRecord(name, STRING, false, // mustUseProperty | |
| 545 attributeName, null, // attributeNamespace | |
| 546 false, // sanitizeURL | |
| 547 false); | |
| 548 }); // String SVG attributes with the xlink namespace. | |
| 549 | |
| 550 ['xlink:actuate', 'xlink:arcrole', 'xlink:role', 'xlink:show', 'xlink:title', 'xlink:type' // NOTE: if you add a camelCased prop to this list, | |
| 551 // you'll need to set attributeName to name.toLowerCase() | |
| 552 // instead in the assignment below. | |
| 553 ].forEach(function (attributeName) { | |
| 554 var name = attributeName.replace(CAMELIZE, capitalize); | |
| 555 properties[name] = new PropertyInfoRecord(name, STRING, false, // mustUseProperty | |
| 556 attributeName, 'http://www.w3.org/1999/xlink', false, // sanitizeURL | |
| 557 false); | |
| 558 }); // String SVG attributes with the xml namespace. | |
| 559 | |
| 560 ['xml:base', 'xml:lang', 'xml:space' // NOTE: if you add a camelCased prop to this list, | |
| 561 // you'll need to set attributeName to name.toLowerCase() | |
| 562 // instead in the assignment below. | |
| 563 ].forEach(function (attributeName) { | |
| 564 var name = attributeName.replace(CAMELIZE, capitalize); | |
| 565 properties[name] = new PropertyInfoRecord(name, STRING, false, // mustUseProperty | |
| 566 attributeName, 'http://www.w3.org/XML/1998/namespace', false, // sanitizeURL | |
| 567 false); | |
| 568 }); // These attribute exists both in HTML and SVG. | |
| 569 // The attribute name is case-sensitive in SVG so we can't just use | |
| 570 // the React name like we do for attributes that exist only in HTML. | |
| 571 | |
| 572 ['tabIndex', 'crossOrigin'].forEach(function (attributeName) { | |
| 573 properties[attributeName] = new PropertyInfoRecord(attributeName, STRING, false, // mustUseProperty | |
| 574 attributeName.toLowerCase(), // attributeName | |
| 575 null, // attributeNamespace | |
| 576 false, // sanitizeURL | |
| 577 false); | |
| 578 }); // These attributes accept URLs. These must not allow javascript: URLS. | |
| 579 // These will also need to accept Trusted Types object in the future. | |
| 580 | |
| 581 var xlinkHref = 'xlinkHref'; | |
| 582 properties[xlinkHref] = new PropertyInfoRecord('xlinkHref', STRING, false, // mustUseProperty | |
| 583 'xlink:href', 'http://www.w3.org/1999/xlink', true, // sanitizeURL | |
| 584 false); | |
| 585 ['src', 'href', 'action', 'formAction'].forEach(function (attributeName) { | |
| 586 properties[attributeName] = new PropertyInfoRecord(attributeName, STRING, false, // mustUseProperty | |
| 587 attributeName.toLowerCase(), // attributeName | |
| 588 null, // attributeNamespace | |
| 589 true, // sanitizeURL | |
| 590 true); | |
| 591 }); | |
| 592 | |
| 593 /** | |
| 594 * CSS properties which accept numbers but are not in units of "px". | |
| 595 */ | |
| 596 var isUnitlessNumber = { | |
| 597 animationIterationCount: true, | |
| 598 aspectRatio: true, | |
| 599 borderImageOutset: true, | |
| 600 borderImageSlice: true, | |
| 601 borderImageWidth: true, | |
| 602 boxFlex: true, | |
| 603 boxFlexGroup: true, | |
| 604 boxOrdinalGroup: true, | |
| 605 columnCount: true, | |
| 606 columns: true, | |
| 607 flex: true, | |
| 608 flexGrow: true, | |
| 609 flexPositive: true, | |
| 610 flexShrink: true, | |
| 611 flexNegative: true, | |
| 612 flexOrder: true, | |
| 613 gridArea: true, | |
| 614 gridRow: true, | |
| 615 gridRowEnd: true, | |
| 616 gridRowSpan: true, | |
| 617 gridRowStart: true, | |
| 618 gridColumn: true, | |
| 619 gridColumnEnd: true, | |
| 620 gridColumnSpan: true, | |
| 621 gridColumnStart: true, | |
| 622 fontWeight: true, | |
| 623 lineClamp: true, | |
| 624 lineHeight: true, | |
| 625 opacity: true, | |
| 626 order: true, | |
| 627 orphans: true, | |
| 628 tabSize: true, | |
| 629 widows: true, | |
| 630 zIndex: true, | |
| 631 zoom: true, | |
| 632 // SVG-related properties | |
| 633 fillOpacity: true, | |
| 634 floodOpacity: true, | |
| 635 stopOpacity: true, | |
| 636 strokeDasharray: true, | |
| 637 strokeDashoffset: true, | |
| 638 strokeMiterlimit: true, | |
| 639 strokeOpacity: true, | |
| 640 strokeWidth: true | |
| 641 }; | |
| 642 /** | |
| 643 * @param {string} prefix vendor-specific prefix, eg: Webkit | |
| 644 * @param {string} key style name, eg: transitionDuration | |
| 645 * @return {string} style name prefixed with `prefix`, properly camelCased, eg: | |
| 646 * WebkitTransitionDuration | |
| 647 */ | |
| 648 | |
| 649 function prefixKey(prefix, key) { | |
| 650 return prefix + key.charAt(0).toUpperCase() + key.substring(1); | |
| 651 } | |
| 652 /** | |
| 653 * Support style names that may come passed in prefixed by adding permutations | |
| 654 * of vendor prefixes. | |
| 655 */ | |
| 656 | |
| 657 | |
| 658 var prefixes = ['Webkit', 'ms', 'Moz', 'O']; // Using Object.keys here, or else the vanilla for-in loop makes IE8 go into an | |
| 659 // infinite loop, because it iterates over the newly added props too. | |
| 660 | |
| 661 Object.keys(isUnitlessNumber).forEach(function (prop) { | |
| 662 prefixes.forEach(function (prefix) { | |
| 663 isUnitlessNumber[prefixKey(prefix, prop)] = isUnitlessNumber[prop]; | |
| 664 }); | |
| 665 }); | |
| 666 | |
| 667 var hasReadOnlyValue = { | |
| 668 button: true, | |
| 669 checkbox: true, | |
| 670 image: true, | |
| 671 hidden: true, | |
| 672 radio: true, | |
| 673 reset: true, | |
| 674 submit: true | |
| 675 }; | |
| 676 function checkControlledValueProps(tagName, props) { | |
| 677 { | |
| 678 if (!(hasReadOnlyValue[props.type] || props.onChange || props.onInput || props.readOnly || props.disabled || props.value == null)) { | |
| 679 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`.'); | |
| 680 } | |
| 681 | |
| 682 if (!(props.onChange || props.readOnly || props.disabled || props.checked == null)) { | |
| 683 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`.'); | |
| 684 } | |
| 685 } | |
| 686 } | |
| 687 | |
| 688 function isCustomComponent(tagName, props) { | |
| 689 if (tagName.indexOf('-') === -1) { | |
| 690 return typeof props.is === 'string'; | |
| 691 } | |
| 692 | |
| 693 switch (tagName) { | |
| 694 // These are reserved SVG and MathML elements. | |
| 695 // We don't mind this list too much because we expect it to never grow. | |
| 696 // The alternative is to track the namespace in a few places which is convoluted. | |
| 697 // https://w3c.github.io/webcomponents/spec/custom/#custom-elements-core-concepts | |
| 698 case 'annotation-xml': | |
| 699 case 'color-profile': | |
| 700 case 'font-face': | |
| 701 case 'font-face-src': | |
| 702 case 'font-face-uri': | |
| 703 case 'font-face-format': | |
| 704 case 'font-face-name': | |
| 705 case 'missing-glyph': | |
| 706 return false; | |
| 707 | |
| 708 default: | |
| 709 return true; | |
| 710 } | |
| 711 } | |
| 712 | |
| 713 var ariaProperties = { | |
| 714 'aria-current': 0, | |
| 715 // state | |
| 716 'aria-description': 0, | |
| 717 'aria-details': 0, | |
| 718 'aria-disabled': 0, | |
| 719 // state | |
| 720 'aria-hidden': 0, | |
| 721 // state | |
| 722 'aria-invalid': 0, | |
| 723 // state | |
| 724 'aria-keyshortcuts': 0, | |
| 725 'aria-label': 0, | |
| 726 'aria-roledescription': 0, | |
| 727 // Widget Attributes | |
| 728 'aria-autocomplete': 0, | |
| 729 'aria-checked': 0, | |
| 730 'aria-expanded': 0, | |
| 731 'aria-haspopup': 0, | |
| 732 'aria-level': 0, | |
| 733 'aria-modal': 0, | |
| 734 'aria-multiline': 0, | |
| 735 'aria-multiselectable': 0, | |
| 736 'aria-orientation': 0, | |
| 737 'aria-placeholder': 0, | |
| 738 'aria-pressed': 0, | |
| 739 'aria-readonly': 0, | |
| 740 'aria-required': 0, | |
| 741 'aria-selected': 0, | |
| 742 'aria-sort': 0, | |
| 743 'aria-valuemax': 0, | |
| 744 'aria-valuemin': 0, | |
| 745 'aria-valuenow': 0, | |
| 746 'aria-valuetext': 0, | |
| 747 // Live Region Attributes | |
| 748 'aria-atomic': 0, | |
| 749 'aria-busy': 0, | |
| 750 'aria-live': 0, | |
| 751 'aria-relevant': 0, | |
| 752 // Drag-and-Drop Attributes | |
| 753 'aria-dropeffect': 0, | |
| 754 'aria-grabbed': 0, | |
| 755 // Relationship Attributes | |
| 756 'aria-activedescendant': 0, | |
| 757 'aria-colcount': 0, | |
| 758 'aria-colindex': 0, | |
| 759 'aria-colspan': 0, | |
| 760 'aria-controls': 0, | |
| 761 'aria-describedby': 0, | |
| 762 'aria-errormessage': 0, | |
| 763 'aria-flowto': 0, | |
| 764 'aria-labelledby': 0, | |
| 765 'aria-owns': 0, | |
| 766 'aria-posinset': 0, | |
| 767 'aria-rowcount': 0, | |
| 768 'aria-rowindex': 0, | |
| 769 'aria-rowspan': 0, | |
| 770 'aria-setsize': 0 | |
| 771 }; | |
| 772 | |
| 773 var warnedProperties = {}; | |
| 774 var rARIA = new RegExp('^(aria)-[' + ATTRIBUTE_NAME_CHAR + ']*$'); | |
| 775 var rARIACamel = new RegExp('^(aria)[A-Z][' + ATTRIBUTE_NAME_CHAR + ']*$'); | |
| 776 | |
| 777 function validateProperty(tagName, name) { | |
| 778 { | |
| 779 if (hasOwnProperty.call(warnedProperties, name) && warnedProperties[name]) { | |
| 780 return true; | |
| 781 } | |
| 782 | |
| 783 if (rARIACamel.test(name)) { | |
| 784 var ariaName = 'aria-' + name.slice(4).toLowerCase(); | |
| 785 var correctName = ariaProperties.hasOwnProperty(ariaName) ? ariaName : null; // If this is an aria-* attribute, but is not listed in the known DOM | |
| 786 // DOM properties, then it is an invalid aria-* attribute. | |
| 787 | |
| 788 if (correctName == null) { | |
| 789 error('Invalid ARIA attribute `%s`. ARIA attributes follow the pattern aria-* and must be lowercase.', name); | |
| 790 | |
| 791 warnedProperties[name] = true; | |
| 792 return true; | |
| 793 } // aria-* attributes should be lowercase; suggest the lowercase version. | |
| 794 | |
| 795 | |
| 796 if (name !== correctName) { | |
| 797 error('Invalid ARIA attribute `%s`. Did you mean `%s`?', name, correctName); | |
| 798 | |
| 799 warnedProperties[name] = true; | |
| 800 return true; | |
| 801 } | |
| 802 } | |
| 803 | |
| 804 if (rARIA.test(name)) { | |
| 805 var lowerCasedName = name.toLowerCase(); | |
| 806 var standardName = ariaProperties.hasOwnProperty(lowerCasedName) ? lowerCasedName : null; // If this is an aria-* attribute, but is not listed in the known DOM | |
| 807 // DOM properties, then it is an invalid aria-* attribute. | |
| 808 | |
| 809 if (standardName == null) { | |
| 810 warnedProperties[name] = true; | |
| 811 return false; | |
| 812 } // aria-* attributes should be lowercase; suggest the lowercase version. | |
| 813 | |
| 814 | |
| 815 if (name !== standardName) { | |
| 816 error('Unknown ARIA attribute `%s`. Did you mean `%s`?', name, standardName); | |
| 817 | |
| 818 warnedProperties[name] = true; | |
| 819 return true; | |
| 820 } | |
| 821 } | |
| 822 } | |
| 823 | |
| 824 return true; | |
| 825 } | |
| 826 | |
| 827 function warnInvalidARIAProps(type, props) { | |
| 828 { | |
| 829 var invalidProps = []; | |
| 830 | |
| 831 for (var key in props) { | |
| 832 var isValid = validateProperty(type, key); | |
| 833 | |
| 834 if (!isValid) { | |
| 835 invalidProps.push(key); | |
| 836 } | |
| 837 } | |
| 838 | |
| 839 var unknownPropString = invalidProps.map(function (prop) { | |
| 840 return '`' + prop + '`'; | |
| 841 }).join(', '); | |
| 842 | |
| 843 if (invalidProps.length === 1) { | |
| 844 error('Invalid aria prop %s on <%s> tag. ' + 'For details, see https://reactjs.org/link/invalid-aria-props', unknownPropString, type); | |
| 845 } else if (invalidProps.length > 1) { | |
| 846 error('Invalid aria props %s on <%s> tag. ' + 'For details, see https://reactjs.org/link/invalid-aria-props', unknownPropString, type); | |
| 847 } | |
| 848 } | |
| 849 } | |
| 850 | |
| 851 function validateProperties(type, props) { | |
| 852 if (isCustomComponent(type, props)) { | |
| 853 return; | |
| 854 } | |
| 855 | |
| 856 warnInvalidARIAProps(type, props); | |
| 857 } | |
| 858 | |
| 859 var didWarnValueNull = false; | |
| 860 function validateProperties$1(type, props) { | |
| 861 { | |
| 862 if (type !== 'input' && type !== 'textarea' && type !== 'select') { | |
| 863 return; | |
| 864 } | |
| 865 | |
| 866 if (props != null && props.value === null && !didWarnValueNull) { | |
| 867 didWarnValueNull = true; | |
| 868 | |
| 869 if (type === 'select' && props.multiple) { | |
| 870 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); | |
| 871 } else { | |
| 872 error('`value` prop on `%s` should not be null. ' + 'Consider using an empty string to clear the component or `undefined` ' + 'for uncontrolled components.', type); | |
| 873 } | |
| 874 } | |
| 875 } | |
| 876 } | |
| 877 | |
| 878 // When adding attributes to the HTML or SVG allowed attribute list, be sure to | |
| 879 // also add them to this module to ensure casing and incorrect name | |
| 880 // warnings. | |
| 881 var possibleStandardNames = { | |
| 882 // HTML | |
| 883 accept: 'accept', | |
| 884 acceptcharset: 'acceptCharset', | |
| 885 'accept-charset': 'acceptCharset', | |
| 886 accesskey: 'accessKey', | |
| 887 action: 'action', | |
| 888 allowfullscreen: 'allowFullScreen', | |
| 889 alt: 'alt', | |
| 890 as: 'as', | |
| 891 async: 'async', | |
| 892 autocapitalize: 'autoCapitalize', | |
| 893 autocomplete: 'autoComplete', | |
| 894 autocorrect: 'autoCorrect', | |
| 895 autofocus: 'autoFocus', | |
| 896 autoplay: 'autoPlay', | |
| 897 autosave: 'autoSave', | |
| 898 capture: 'capture', | |
| 899 cellpadding: 'cellPadding', | |
| 900 cellspacing: 'cellSpacing', | |
| 901 challenge: 'challenge', | |
| 902 charset: 'charSet', | |
| 903 checked: 'checked', | |
| 904 children: 'children', | |
| 905 cite: 'cite', | |
| 906 class: 'className', | |
| 907 classid: 'classID', | |
| 908 classname: 'className', | |
| 909 cols: 'cols', | |
| 910 colspan: 'colSpan', | |
| 911 content: 'content', | |
| 912 contenteditable: 'contentEditable', | |
| 913 contextmenu: 'contextMenu', | |
| 914 controls: 'controls', | |
| 915 controlslist: 'controlsList', | |
| 916 coords: 'coords', | |
| 917 crossorigin: 'crossOrigin', | |
| 918 dangerouslysetinnerhtml: 'dangerouslySetInnerHTML', | |
| 919 data: 'data', | |
| 920 datetime: 'dateTime', | |
| 921 default: 'default', | |
| 922 defaultchecked: 'defaultChecked', | |
| 923 defaultvalue: 'defaultValue', | |
| 924 defer: 'defer', | |
| 925 dir: 'dir', | |
| 926 disabled: 'disabled', | |
| 927 disablepictureinpicture: 'disablePictureInPicture', | |
| 928 disableremoteplayback: 'disableRemotePlayback', | |
| 929 download: 'download', | |
| 930 draggable: 'draggable', | |
| 931 enctype: 'encType', | |
| 932 enterkeyhint: 'enterKeyHint', | |
| 933 for: 'htmlFor', | |
| 934 form: 'form', | |
| 935 formmethod: 'formMethod', | |
| 936 formaction: 'formAction', | |
| 937 formenctype: 'formEncType', | |
| 938 formnovalidate: 'formNoValidate', | |
| 939 formtarget: 'formTarget', | |
| 940 frameborder: 'frameBorder', | |
| 941 headers: 'headers', | |
| 942 height: 'height', | |
| 943 hidden: 'hidden', | |
| 944 high: 'high', | |
| 945 href: 'href', | |
| 946 hreflang: 'hrefLang', | |
| 947 htmlfor: 'htmlFor', | |
| 948 httpequiv: 'httpEquiv', | |
| 949 'http-equiv': 'httpEquiv', | |
| 950 icon: 'icon', | |
| 951 id: 'id', | |
| 952 imagesizes: 'imageSizes', | |
| 953 imagesrcset: 'imageSrcSet', | |
| 954 innerhtml: 'innerHTML', | |
| 955 inputmode: 'inputMode', | |
| 956 integrity: 'integrity', | |
| 957 is: 'is', | |
| 958 itemid: 'itemID', | |
| 959 itemprop: 'itemProp', | |
| 960 itemref: 'itemRef', | |
| 961 itemscope: 'itemScope', | |
| 962 itemtype: 'itemType', | |
| 963 keyparams: 'keyParams', | |
| 964 keytype: 'keyType', | |
| 965 kind: 'kind', | |
| 966 label: 'label', | |
| 967 lang: 'lang', | |
| 968 list: 'list', | |
| 969 loop: 'loop', | |
| 970 low: 'low', | |
| 971 manifest: 'manifest', | |
| 972 marginwidth: 'marginWidth', | |
| 973 marginheight: 'marginHeight', | |
| 974 max: 'max', | |
| 975 maxlength: 'maxLength', | |
| 976 media: 'media', | |
| 977 mediagroup: 'mediaGroup', | |
| 978 method: 'method', | |
| 979 min: 'min', | |
| 980 minlength: 'minLength', | |
| 981 multiple: 'multiple', | |
| 982 muted: 'muted', | |
| 983 name: 'name', | |
| 984 nomodule: 'noModule', | |
| 985 nonce: 'nonce', | |
| 986 novalidate: 'noValidate', | |
| 987 open: 'open', | |
| 988 optimum: 'optimum', | |
| 989 pattern: 'pattern', | |
| 990 placeholder: 'placeholder', | |
| 991 playsinline: 'playsInline', | |
| 992 poster: 'poster', | |
| 993 preload: 'preload', | |
| 994 profile: 'profile', | |
| 995 radiogroup: 'radioGroup', | |
| 996 readonly: 'readOnly', | |
| 997 referrerpolicy: 'referrerPolicy', | |
| 998 rel: 'rel', | |
| 999 required: 'required', | |
| 1000 reversed: 'reversed', | |
| 1001 role: 'role', | |
| 1002 rows: 'rows', | |
| 1003 rowspan: 'rowSpan', | |
| 1004 sandbox: 'sandbox', | |
| 1005 scope: 'scope', | |
| 1006 scoped: 'scoped', | |
| 1007 scrolling: 'scrolling', | |
| 1008 seamless: 'seamless', | |
| 1009 selected: 'selected', | |
| 1010 shape: 'shape', | |
| 1011 size: 'size', | |
| 1012 sizes: 'sizes', | |
| 1013 span: 'span', | |
| 1014 spellcheck: 'spellCheck', | |
| 1015 src: 'src', | |
| 1016 srcdoc: 'srcDoc', | |
| 1017 srclang: 'srcLang', | |
| 1018 srcset: 'srcSet', | |
| 1019 start: 'start', | |
| 1020 step: 'step', | |
| 1021 style: 'style', | |
| 1022 summary: 'summary', | |
| 1023 tabindex: 'tabIndex', | |
| 1024 target: 'target', | |
| 1025 title: 'title', | |
| 1026 type: 'type', | |
| 1027 usemap: 'useMap', | |
| 1028 value: 'value', | |
| 1029 width: 'width', | |
| 1030 wmode: 'wmode', | |
| 1031 wrap: 'wrap', | |
| 1032 // SVG | |
| 1033 about: 'about', | |
| 1034 accentheight: 'accentHeight', | |
| 1035 'accent-height': 'accentHeight', | |
| 1036 accumulate: 'accumulate', | |
| 1037 additive: 'additive', | |
| 1038 alignmentbaseline: 'alignmentBaseline', | |
| 1039 'alignment-baseline': 'alignmentBaseline', | |
| 1040 allowreorder: 'allowReorder', | |
| 1041 alphabetic: 'alphabetic', | |
| 1042 amplitude: 'amplitude', | |
| 1043 arabicform: 'arabicForm', | |
| 1044 'arabic-form': 'arabicForm', | |
| 1045 ascent: 'ascent', | |
| 1046 attributename: 'attributeName', | |
| 1047 attributetype: 'attributeType', | |
| 1048 autoreverse: 'autoReverse', | |
| 1049 azimuth: 'azimuth', | |
| 1050 basefrequency: 'baseFrequency', | |
| 1051 baselineshift: 'baselineShift', | |
| 1052 'baseline-shift': 'baselineShift', | |
| 1053 baseprofile: 'baseProfile', | |
| 1054 bbox: 'bbox', | |
| 1055 begin: 'begin', | |
| 1056 bias: 'bias', | |
| 1057 by: 'by', | |
| 1058 calcmode: 'calcMode', | |
| 1059 capheight: 'capHeight', | |
| 1060 'cap-height': 'capHeight', | |
| 1061 clip: 'clip', | |
| 1062 clippath: 'clipPath', | |
| 1063 'clip-path': 'clipPath', | |
| 1064 clippathunits: 'clipPathUnits', | |
| 1065 cliprule: 'clipRule', | |
| 1066 'clip-rule': 'clipRule', | |
| 1067 color: 'color', | |
| 1068 colorinterpolation: 'colorInterpolation', | |
| 1069 'color-interpolation': 'colorInterpolation', | |
| 1070 colorinterpolationfilters: 'colorInterpolationFilters', | |
| 1071 'color-interpolation-filters': 'colorInterpolationFilters', | |
| 1072 colorprofile: 'colorProfile', | |
| 1073 'color-profile': 'colorProfile', | |
| 1074 colorrendering: 'colorRendering', | |
| 1075 'color-rendering': 'colorRendering', | |
| 1076 contentscripttype: 'contentScriptType', | |
| 1077 contentstyletype: 'contentStyleType', | |
| 1078 cursor: 'cursor', | |
| 1079 cx: 'cx', | |
| 1080 cy: 'cy', | |
| 1081 d: 'd', | |
| 1082 datatype: 'datatype', | |
| 1083 decelerate: 'decelerate', | |
| 1084 descent: 'descent', | |
| 1085 diffuseconstant: 'diffuseConstant', | |
| 1086 direction: 'direction', | |
| 1087 display: 'display', | |
| 1088 divisor: 'divisor', | |
| 1089 dominantbaseline: 'dominantBaseline', | |
| 1090 'dominant-baseline': 'dominantBaseline', | |
| 1091 dur: 'dur', | |
| 1092 dx: 'dx', | |
| 1093 dy: 'dy', | |
| 1094 edgemode: 'edgeMode', | |
| 1095 elevation: 'elevation', | |
| 1096 enablebackground: 'enableBackground', | |
| 1097 'enable-background': 'enableBackground', | |
| 1098 end: 'end', | |
| 1099 exponent: 'exponent', | |
| 1100 externalresourcesrequired: 'externalResourcesRequired', | |
| 1101 fill: 'fill', | |
| 1102 fillopacity: 'fillOpacity', | |
| 1103 'fill-opacity': 'fillOpacity', | |
| 1104 fillrule: 'fillRule', | |
| 1105 'fill-rule': 'fillRule', | |
| 1106 filter: 'filter', | |
| 1107 filterres: 'filterRes', | |
| 1108 filterunits: 'filterUnits', | |
| 1109 floodopacity: 'floodOpacity', | |
| 1110 'flood-opacity': 'floodOpacity', | |
| 1111 floodcolor: 'floodColor', | |
| 1112 'flood-color': 'floodColor', | |
| 1113 focusable: 'focusable', | |
| 1114 fontfamily: 'fontFamily', | |
| 1115 'font-family': 'fontFamily', | |
| 1116 fontsize: 'fontSize', | |
| 1117 'font-size': 'fontSize', | |
| 1118 fontsizeadjust: 'fontSizeAdjust', | |
| 1119 'font-size-adjust': 'fontSizeAdjust', | |
| 1120 fontstretch: 'fontStretch', | |
| 1121 'font-stretch': 'fontStretch', | |
| 1122 fontstyle: 'fontStyle', | |
| 1123 'font-style': 'fontStyle', | |
| 1124 fontvariant: 'fontVariant', | |
| 1125 'font-variant': 'fontVariant', | |
| 1126 fontweight: 'fontWeight', | |
| 1127 'font-weight': 'fontWeight', | |
| 1128 format: 'format', | |
| 1129 from: 'from', | |
| 1130 fx: 'fx', | |
| 1131 fy: 'fy', | |
| 1132 g1: 'g1', | |
| 1133 g2: 'g2', | |
| 1134 glyphname: 'glyphName', | |
| 1135 'glyph-name': 'glyphName', | |
| 1136 glyphorientationhorizontal: 'glyphOrientationHorizontal', | |
| 1137 'glyph-orientation-horizontal': 'glyphOrientationHorizontal', | |
| 1138 glyphorientationvertical: 'glyphOrientationVertical', | |
| 1139 'glyph-orientation-vertical': 'glyphOrientationVertical', | |
| 1140 glyphref: 'glyphRef', | |
| 1141 gradienttransform: 'gradientTransform', | |
| 1142 gradientunits: 'gradientUnits', | |
| 1143 hanging: 'hanging', | |
| 1144 horizadvx: 'horizAdvX', | |
| 1145 'horiz-adv-x': 'horizAdvX', | |
| 1146 horizoriginx: 'horizOriginX', | |
| 1147 'horiz-origin-x': 'horizOriginX', | |
| 1148 ideographic: 'ideographic', | |
| 1149 imagerendering: 'imageRendering', | |
| 1150 'image-rendering': 'imageRendering', | |
| 1151 in2: 'in2', | |
| 1152 in: 'in', | |
| 1153 inlist: 'inlist', | |
| 1154 intercept: 'intercept', | |
| 1155 k1: 'k1', | |
| 1156 k2: 'k2', | |
| 1157 k3: 'k3', | |
| 1158 k4: 'k4', | |
| 1159 k: 'k', | |
| 1160 kernelmatrix: 'kernelMatrix', | |
| 1161 kernelunitlength: 'kernelUnitLength', | |
| 1162 kerning: 'kerning', | |
| 1163 keypoints: 'keyPoints', | |
| 1164 keysplines: 'keySplines', | |
| 1165 keytimes: 'keyTimes', | |
| 1166 lengthadjust: 'lengthAdjust', | |
| 1167 letterspacing: 'letterSpacing', | |
| 1168 'letter-spacing': 'letterSpacing', | |
| 1169 lightingcolor: 'lightingColor', | |
| 1170 'lighting-color': 'lightingColor', | |
| 1171 limitingconeangle: 'limitingConeAngle', | |
| 1172 local: 'local', | |
| 1173 markerend: 'markerEnd', | |
| 1174 'marker-end': 'markerEnd', | |
| 1175 markerheight: 'markerHeight', | |
| 1176 markermid: 'markerMid', | |
| 1177 'marker-mid': 'markerMid', | |
| 1178 markerstart: 'markerStart', | |
| 1179 'marker-start': 'markerStart', | |
| 1180 markerunits: 'markerUnits', | |
| 1181 markerwidth: 'markerWidth', | |
| 1182 mask: 'mask', | |
| 1183 maskcontentunits: 'maskContentUnits', | |
| 1184 maskunits: 'maskUnits', | |
| 1185 mathematical: 'mathematical', | |
| 1186 mode: 'mode', | |
| 1187 numoctaves: 'numOctaves', | |
| 1188 offset: 'offset', | |
| 1189 opacity: 'opacity', | |
| 1190 operator: 'operator', | |
| 1191 order: 'order', | |
| 1192 orient: 'orient', | |
| 1193 orientation: 'orientation', | |
| 1194 origin: 'origin', | |
| 1195 overflow: 'overflow', | |
| 1196 overlineposition: 'overlinePosition', | |
| 1197 'overline-position': 'overlinePosition', | |
| 1198 overlinethickness: 'overlineThickness', | |
| 1199 'overline-thickness': 'overlineThickness', | |
| 1200 paintorder: 'paintOrder', | |
| 1201 'paint-order': 'paintOrder', | |
| 1202 panose1: 'panose1', | |
| 1203 'panose-1': 'panose1', | |
| 1204 pathlength: 'pathLength', | |
| 1205 patterncontentunits: 'patternContentUnits', | |
| 1206 patterntransform: 'patternTransform', | |
| 1207 patternunits: 'patternUnits', | |
| 1208 pointerevents: 'pointerEvents', | |
| 1209 'pointer-events': 'pointerEvents', | |
| 1210 points: 'points', | |
| 1211 pointsatx: 'pointsAtX', | |
| 1212 pointsaty: 'pointsAtY', | |
| 1213 pointsatz: 'pointsAtZ', | |
| 1214 prefix: 'prefix', | |
| 1215 preservealpha: 'preserveAlpha', | |
| 1216 preserveaspectratio: 'preserveAspectRatio', | |
| 1217 primitiveunits: 'primitiveUnits', | |
| 1218 property: 'property', | |
| 1219 r: 'r', | |
| 1220 radius: 'radius', | |
| 1221 refx: 'refX', | |
| 1222 refy: 'refY', | |
| 1223 renderingintent: 'renderingIntent', | |
| 1224 'rendering-intent': 'renderingIntent', | |
| 1225 repeatcount: 'repeatCount', | |
| 1226 repeatdur: 'repeatDur', | |
| 1227 requiredextensions: 'requiredExtensions', | |
| 1228 requiredfeatures: 'requiredFeatures', | |
| 1229 resource: 'resource', | |
| 1230 restart: 'restart', | |
| 1231 result: 'result', | |
| 1232 results: 'results', | |
| 1233 rotate: 'rotate', | |
| 1234 rx: 'rx', | |
| 1235 ry: 'ry', | |
| 1236 scale: 'scale', | |
| 1237 security: 'security', | |
| 1238 seed: 'seed', | |
| 1239 shaperendering: 'shapeRendering', | |
| 1240 'shape-rendering': 'shapeRendering', | |
| 1241 slope: 'slope', | |
| 1242 spacing: 'spacing', | |
| 1243 specularconstant: 'specularConstant', | |
| 1244 specularexponent: 'specularExponent', | |
| 1245 speed: 'speed', | |
| 1246 spreadmethod: 'spreadMethod', | |
| 1247 startoffset: 'startOffset', | |
| 1248 stddeviation: 'stdDeviation', | |
| 1249 stemh: 'stemh', | |
| 1250 stemv: 'stemv', | |
| 1251 stitchtiles: 'stitchTiles', | |
| 1252 stopcolor: 'stopColor', | |
| 1253 'stop-color': 'stopColor', | |
| 1254 stopopacity: 'stopOpacity', | |
| 1255 'stop-opacity': 'stopOpacity', | |
| 1256 strikethroughposition: 'strikethroughPosition', | |
| 1257 'strikethrough-position': 'strikethroughPosition', | |
| 1258 strikethroughthickness: 'strikethroughThickness', | |
| 1259 'strikethrough-thickness': 'strikethroughThickness', | |
| 1260 string: 'string', | |
| 1261 stroke: 'stroke', | |
| 1262 strokedasharray: 'strokeDasharray', | |
| 1263 'stroke-dasharray': 'strokeDasharray', | |
| 1264 strokedashoffset: 'strokeDashoffset', | |
| 1265 'stroke-dashoffset': 'strokeDashoffset', | |
| 1266 strokelinecap: 'strokeLinecap', | |
| 1267 'stroke-linecap': 'strokeLinecap', | |
| 1268 strokelinejoin: 'strokeLinejoin', | |
| 1269 'stroke-linejoin': 'strokeLinejoin', | |
| 1270 strokemiterlimit: 'strokeMiterlimit', | |
| 1271 'stroke-miterlimit': 'strokeMiterlimit', | |
| 1272 strokewidth: 'strokeWidth', | |
| 1273 'stroke-width': 'strokeWidth', | |
| 1274 strokeopacity: 'strokeOpacity', | |
| 1275 'stroke-opacity': 'strokeOpacity', | |
| 1276 suppresscontenteditablewarning: 'suppressContentEditableWarning', | |
| 1277 suppresshydrationwarning: 'suppressHydrationWarning', | |
| 1278 surfacescale: 'surfaceScale', | |
| 1279 systemlanguage: 'systemLanguage', | |
| 1280 tablevalues: 'tableValues', | |
| 1281 targetx: 'targetX', | |
| 1282 targety: 'targetY', | |
| 1283 textanchor: 'textAnchor', | |
| 1284 'text-anchor': 'textAnchor', | |
| 1285 textdecoration: 'textDecoration', | |
| 1286 'text-decoration': 'textDecoration', | |
| 1287 textlength: 'textLength', | |
| 1288 textrendering: 'textRendering', | |
| 1289 'text-rendering': 'textRendering', | |
| 1290 to: 'to', | |
| 1291 transform: 'transform', | |
| 1292 typeof: 'typeof', | |
| 1293 u1: 'u1', | |
| 1294 u2: 'u2', | |
| 1295 underlineposition: 'underlinePosition', | |
| 1296 'underline-position': 'underlinePosition', | |
| 1297 underlinethickness: 'underlineThickness', | |
| 1298 'underline-thickness': 'underlineThickness', | |
| 1299 unicode: 'unicode', | |
| 1300 unicodebidi: 'unicodeBidi', | |
| 1301 'unicode-bidi': 'unicodeBidi', | |
| 1302 unicoderange: 'unicodeRange', | |
| 1303 'unicode-range': 'unicodeRange', | |
| 1304 unitsperem: 'unitsPerEm', | |
| 1305 'units-per-em': 'unitsPerEm', | |
| 1306 unselectable: 'unselectable', | |
| 1307 valphabetic: 'vAlphabetic', | |
| 1308 'v-alphabetic': 'vAlphabetic', | |
| 1309 values: 'values', | |
| 1310 vectoreffect: 'vectorEffect', | |
| 1311 'vector-effect': 'vectorEffect', | |
| 1312 version: 'version', | |
| 1313 vertadvy: 'vertAdvY', | |
| 1314 'vert-adv-y': 'vertAdvY', | |
| 1315 vertoriginx: 'vertOriginX', | |
| 1316 'vert-origin-x': 'vertOriginX', | |
| 1317 vertoriginy: 'vertOriginY', | |
| 1318 'vert-origin-y': 'vertOriginY', | |
| 1319 vhanging: 'vHanging', | |
| 1320 'v-hanging': 'vHanging', | |
| 1321 videographic: 'vIdeographic', | |
| 1322 'v-ideographic': 'vIdeographic', | |
| 1323 viewbox: 'viewBox', | |
| 1324 viewtarget: 'viewTarget', | |
| 1325 visibility: 'visibility', | |
| 1326 vmathematical: 'vMathematical', | |
| 1327 'v-mathematical': 'vMathematical', | |
| 1328 vocab: 'vocab', | |
| 1329 widths: 'widths', | |
| 1330 wordspacing: 'wordSpacing', | |
| 1331 'word-spacing': 'wordSpacing', | |
| 1332 writingmode: 'writingMode', | |
| 1333 'writing-mode': 'writingMode', | |
| 1334 x1: 'x1', | |
| 1335 x2: 'x2', | |
| 1336 x: 'x', | |
| 1337 xchannelselector: 'xChannelSelector', | |
| 1338 xheight: 'xHeight', | |
| 1339 'x-height': 'xHeight', | |
| 1340 xlinkactuate: 'xlinkActuate', | |
| 1341 'xlink:actuate': 'xlinkActuate', | |
| 1342 xlinkarcrole: 'xlinkArcrole', | |
| 1343 'xlink:arcrole': 'xlinkArcrole', | |
| 1344 xlinkhref: 'xlinkHref', | |
| 1345 'xlink:href': 'xlinkHref', | |
| 1346 xlinkrole: 'xlinkRole', | |
| 1347 'xlink:role': 'xlinkRole', | |
| 1348 xlinkshow: 'xlinkShow', | |
| 1349 'xlink:show': 'xlinkShow', | |
| 1350 xlinktitle: 'xlinkTitle', | |
| 1351 'xlink:title': 'xlinkTitle', | |
| 1352 xlinktype: 'xlinkType', | |
| 1353 'xlink:type': 'xlinkType', | |
| 1354 xmlbase: 'xmlBase', | |
| 1355 'xml:base': 'xmlBase', | |
| 1356 xmllang: 'xmlLang', | |
| 1357 'xml:lang': 'xmlLang', | |
| 1358 xmlns: 'xmlns', | |
| 1359 'xml:space': 'xmlSpace', | |
| 1360 xmlnsxlink: 'xmlnsXlink', | |
| 1361 'xmlns:xlink': 'xmlnsXlink', | |
| 1362 xmlspace: 'xmlSpace', | |
| 1363 y1: 'y1', | |
| 1364 y2: 'y2', | |
| 1365 y: 'y', | |
| 1366 ychannelselector: 'yChannelSelector', | |
| 1367 z: 'z', | |
| 1368 zoomandpan: 'zoomAndPan' | |
| 1369 }; | |
| 1370 | |
| 1371 var validateProperty$1 = function () {}; | |
| 1372 | |
| 1373 { | |
| 1374 var warnedProperties$1 = {}; | |
| 1375 var EVENT_NAME_REGEX = /^on./; | |
| 1376 var INVALID_EVENT_NAME_REGEX = /^on[^A-Z]/; | |
| 1377 var rARIA$1 = new RegExp('^(aria)-[' + ATTRIBUTE_NAME_CHAR + ']*$'); | |
| 1378 var rARIACamel$1 = new RegExp('^(aria)[A-Z][' + ATTRIBUTE_NAME_CHAR + ']*$'); | |
| 1379 | |
| 1380 validateProperty$1 = function (tagName, name, value, eventRegistry) { | |
| 1381 if (hasOwnProperty.call(warnedProperties$1, name) && warnedProperties$1[name]) { | |
| 1382 return true; | |
| 1383 } | |
| 1384 | |
| 1385 var lowerCasedName = name.toLowerCase(); | |
| 1386 | |
| 1387 if (lowerCasedName === 'onfocusin' || lowerCasedName === 'onfocusout') { | |
| 1388 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.'); | |
| 1389 | |
| 1390 warnedProperties$1[name] = true; | |
| 1391 return true; | |
| 1392 } // We can't rely on the event system being injected on the server. | |
| 1393 | |
| 1394 | |
| 1395 if (eventRegistry != null) { | |
| 1396 var registrationNameDependencies = eventRegistry.registrationNameDependencies, | |
| 1397 possibleRegistrationNames = eventRegistry.possibleRegistrationNames; | |
| 1398 | |
| 1399 if (registrationNameDependencies.hasOwnProperty(name)) { | |
| 1400 return true; | |
| 1401 } | |
| 1402 | |
| 1403 var registrationName = possibleRegistrationNames.hasOwnProperty(lowerCasedName) ? possibleRegistrationNames[lowerCasedName] : null; | |
| 1404 | |
| 1405 if (registrationName != null) { | |
| 1406 error('Invalid event handler property `%s`. Did you mean `%s`?', name, registrationName); | |
| 1407 | |
| 1408 warnedProperties$1[name] = true; | |
| 1409 return true; | |
| 1410 } | |
| 1411 | |
| 1412 if (EVENT_NAME_REGEX.test(name)) { | |
| 1413 error('Unknown event handler property `%s`. It will be ignored.', name); | |
| 1414 | |
| 1415 warnedProperties$1[name] = true; | |
| 1416 return true; | |
| 1417 } | |
| 1418 } else if (EVENT_NAME_REGEX.test(name)) { | |
| 1419 // If no event plugins have been injected, we are in a server environment. | |
| 1420 // So we can't tell if the event name is correct for sure, but we can filter | |
| 1421 // out known bad ones like `onclick`. We can't suggest a specific replacement though. | |
| 1422 if (INVALID_EVENT_NAME_REGEX.test(name)) { | |
| 1423 error('Invalid event handler property `%s`. ' + 'React events use the camelCase naming convention, for example `onClick`.', name); | |
| 1424 } | |
| 1425 | |
| 1426 warnedProperties$1[name] = true; | |
| 1427 return true; | |
| 1428 } // Let the ARIA attribute hook validate ARIA attributes | |
| 1429 | |
| 1430 | |
| 1431 if (rARIA$1.test(name) || rARIACamel$1.test(name)) { | |
| 1432 return true; | |
| 1433 } | |
| 1434 | |
| 1435 if (lowerCasedName === 'innerhtml') { | |
| 1436 error('Directly setting property `innerHTML` is not permitted. ' + 'For more information, lookup documentation on `dangerouslySetInnerHTML`.'); | |
| 1437 | |
| 1438 warnedProperties$1[name] = true; | |
| 1439 return true; | |
| 1440 } | |
| 1441 | |
| 1442 if (lowerCasedName === 'aria') { | |
| 1443 error('The `aria` attribute is reserved for future use in React. ' + 'Pass individual `aria-` attributes instead.'); | |
| 1444 | |
| 1445 warnedProperties$1[name] = true; | |
| 1446 return true; | |
| 1447 } | |
| 1448 | |
| 1449 if (lowerCasedName === 'is' && value !== null && value !== undefined && typeof value !== 'string') { | |
| 1450 error('Received a `%s` for a string attribute `is`. If this is expected, cast ' + 'the value to a string.', typeof value); | |
| 1451 | |
| 1452 warnedProperties$1[name] = true; | |
| 1453 return true; | |
| 1454 } | |
| 1455 | |
| 1456 if (typeof value === 'number' && isNaN(value)) { | |
| 1457 error('Received NaN for the `%s` attribute. If this is expected, cast ' + 'the value to a string.', name); | |
| 1458 | |
| 1459 warnedProperties$1[name] = true; | |
| 1460 return true; | |
| 1461 } | |
| 1462 | |
| 1463 var propertyInfo = getPropertyInfo(name); | |
| 1464 var isReserved = propertyInfo !== null && propertyInfo.type === RESERVED; // Known attributes should match the casing specified in the property config. | |
| 1465 | |
| 1466 if (possibleStandardNames.hasOwnProperty(lowerCasedName)) { | |
| 1467 var standardName = possibleStandardNames[lowerCasedName]; | |
| 1468 | |
| 1469 if (standardName !== name) { | |
| 1470 error('Invalid DOM property `%s`. Did you mean `%s`?', name, standardName); | |
| 1471 | |
| 1472 warnedProperties$1[name] = true; | |
| 1473 return true; | |
| 1474 } | |
| 1475 } else if (!isReserved && name !== lowerCasedName) { | |
| 1476 // Unknown attributes should have lowercase casing since that's how they | |
| 1477 // will be cased anyway with server rendering. | |
| 1478 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); | |
| 1479 | |
| 1480 warnedProperties$1[name] = true; | |
| 1481 return true; | |
| 1482 } | |
| 1483 | |
| 1484 if (typeof value === 'boolean' && shouldRemoveAttributeWithWarning(name, value, propertyInfo, false)) { | |
| 1485 if (value) { | |
| 1486 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); | |
| 1487 } else { | |
| 1488 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); | |
| 1489 } | |
| 1490 | |
| 1491 warnedProperties$1[name] = true; | |
| 1492 return true; | |
| 1493 } // Now that we've validated casing, do not validate | |
| 1494 // data types for reserved props | |
| 1495 | |
| 1496 | |
| 1497 if (isReserved) { | |
| 1498 return true; | |
| 1499 } // Warn when a known attribute is a bad type | |
| 1500 | |
| 1501 | |
| 1502 if (shouldRemoveAttributeWithWarning(name, value, propertyInfo, false)) { | |
| 1503 warnedProperties$1[name] = true; | |
| 1504 return false; | |
| 1505 } // Warn when passing the strings 'false' or 'true' into a boolean prop | |
| 1506 | |
| 1507 | |
| 1508 if ((value === 'false' || value === 'true') && propertyInfo !== null && propertyInfo.type === BOOLEAN) { | |
| 1509 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); | |
| 1510 | |
| 1511 warnedProperties$1[name] = true; | |
| 1512 return true; | |
| 1513 } | |
| 1514 | |
| 1515 return true; | |
| 1516 }; | |
| 1517 } | |
| 1518 | |
| 1519 var warnUnknownProperties = function (type, props, eventRegistry) { | |
| 1520 { | |
| 1521 var unknownProps = []; | |
| 1522 | |
| 1523 for (var key in props) { | |
| 1524 var isValid = validateProperty$1(type, key, props[key], eventRegistry); | |
| 1525 | |
| 1526 if (!isValid) { | |
| 1527 unknownProps.push(key); | |
| 1528 } | |
| 1529 } | |
| 1530 | |
| 1531 var unknownPropString = unknownProps.map(function (prop) { | |
| 1532 return '`' + prop + '`'; | |
| 1533 }).join(', '); | |
| 1534 | |
| 1535 if (unknownProps.length === 1) { | |
| 1536 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://reactjs.org/link/attribute-behavior ', unknownPropString, type); | |
| 1537 } else if (unknownProps.length > 1) { | |
| 1538 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://reactjs.org/link/attribute-behavior ', unknownPropString, type); | |
| 1539 } | |
| 1540 } | |
| 1541 }; | |
| 1542 | |
| 1543 function validateProperties$2(type, props, eventRegistry) { | |
| 1544 if (isCustomComponent(type, props)) { | |
| 1545 return; | |
| 1546 } | |
| 1547 | |
| 1548 warnUnknownProperties(type, props, eventRegistry); | |
| 1549 } | |
| 1550 | |
| 1551 var warnValidStyle = function () {}; | |
| 1552 | |
| 1553 { | |
| 1554 // 'msTransform' is correct, but the other prefixes should be capitalized | |
| 1555 var badVendoredStyleNamePattern = /^(?:webkit|moz|o)[A-Z]/; | |
| 1556 var msPattern = /^-ms-/; | |
| 1557 var hyphenPattern = /-(.)/g; // style values shouldn't contain a semicolon | |
| 1558 | |
| 1559 var badStyleValueWithSemicolonPattern = /;\s*$/; | |
| 1560 var warnedStyleNames = {}; | |
| 1561 var warnedStyleValues = {}; | |
| 1562 var warnedForNaNValue = false; | |
| 1563 var warnedForInfinityValue = false; | |
| 1564 | |
| 1565 var camelize = function (string) { | |
| 1566 return string.replace(hyphenPattern, function (_, character) { | |
| 1567 return character.toUpperCase(); | |
| 1568 }); | |
| 1569 }; | |
| 1570 | |
| 1571 var warnHyphenatedStyleName = function (name) { | |
| 1572 if (warnedStyleNames.hasOwnProperty(name) && warnedStyleNames[name]) { | |
| 1573 return; | |
| 1574 } | |
| 1575 | |
| 1576 warnedStyleNames[name] = true; | |
| 1577 | |
| 1578 error('Unsupported style property %s. Did you mean %s?', name, // As Andi Smith suggests | |
| 1579 // (http://www.andismith.com/blog/2012/02/modernizr-prefixed/), an `-ms` prefix | |
| 1580 // is converted to lowercase `ms`. | |
| 1581 camelize(name.replace(msPattern, 'ms-'))); | |
| 1582 }; | |
| 1583 | |
| 1584 var warnBadVendoredStyleName = function (name) { | |
| 1585 if (warnedStyleNames.hasOwnProperty(name) && warnedStyleNames[name]) { | |
| 1586 return; | |
| 1587 } | |
| 1588 | |
| 1589 warnedStyleNames[name] = true; | |
| 1590 | |
| 1591 error('Unsupported vendor-prefixed style property %s. Did you mean %s?', name, name.charAt(0).toUpperCase() + name.slice(1)); | |
| 1592 }; | |
| 1593 | |
| 1594 var warnStyleValueWithSemicolon = function (name, value) { | |
| 1595 if (warnedStyleValues.hasOwnProperty(value) && warnedStyleValues[value]) { | |
| 1596 return; | |
| 1597 } | |
| 1598 | |
| 1599 warnedStyleValues[value] = true; | |
| 1600 | |
| 1601 error("Style property values shouldn't contain a semicolon. " + 'Try "%s: %s" instead.', name, value.replace(badStyleValueWithSemicolonPattern, '')); | |
| 1602 }; | |
| 1603 | |
| 1604 var warnStyleValueIsNaN = function (name, value) { | |
| 1605 if (warnedForNaNValue) { | |
| 1606 return; | |
| 1607 } | |
| 1608 | |
| 1609 warnedForNaNValue = true; | |
| 1610 | |
| 1611 error('`NaN` is an invalid value for the `%s` css style property.', name); | |
| 1612 }; | |
| 1613 | |
| 1614 var warnStyleValueIsInfinity = function (name, value) { | |
| 1615 if (warnedForInfinityValue) { | |
| 1616 return; | |
| 1617 } | |
| 1618 | |
| 1619 warnedForInfinityValue = true; | |
| 1620 | |
| 1621 error('`Infinity` is an invalid value for the `%s` css style property.', name); | |
| 1622 }; | |
| 1623 | |
| 1624 warnValidStyle = function (name, value) { | |
| 1625 if (name.indexOf('-') > -1) { | |
| 1626 warnHyphenatedStyleName(name); | |
| 1627 } else if (badVendoredStyleNamePattern.test(name)) { | |
| 1628 warnBadVendoredStyleName(name); | |
| 1629 } else if (badStyleValueWithSemicolonPattern.test(value)) { | |
| 1630 warnStyleValueWithSemicolon(name, value); | |
| 1631 } | |
| 1632 | |
| 1633 if (typeof value === 'number') { | |
| 1634 if (isNaN(value)) { | |
| 1635 warnStyleValueIsNaN(name, value); | |
| 1636 } else if (!isFinite(value)) { | |
| 1637 warnStyleValueIsInfinity(name, value); | |
| 1638 } | |
| 1639 } | |
| 1640 }; | |
| 1641 } | |
| 1642 | |
| 1643 var warnValidStyle$1 = warnValidStyle; | |
| 1644 | |
| 1645 // code copied and modified from escape-html | |
| 1646 var matchHtmlRegExp = /["'&<>]/; | |
| 1647 /** | |
| 1648 * Escapes special characters and HTML entities in a given html string. | |
| 1649 * | |
| 1650 * @param {string} string HTML string to escape for later insertion | |
| 1651 * @return {string} | |
| 1652 * @public | |
| 1653 */ | |
| 1654 | |
| 1655 function escapeHtml(string) { | |
| 1656 { | |
| 1657 checkHtmlStringCoercion(string); | |
| 1658 } | |
| 1659 | |
| 1660 var str = '' + string; | |
| 1661 var match = matchHtmlRegExp.exec(str); | |
| 1662 | |
| 1663 if (!match) { | |
| 1664 return str; | |
| 1665 } | |
| 1666 | |
| 1667 var escape; | |
| 1668 var html = ''; | |
| 1669 var index; | |
| 1670 var lastIndex = 0; | |
| 1671 | |
| 1672 for (index = match.index; index < str.length; index++) { | |
| 1673 switch (str.charCodeAt(index)) { | |
| 1674 case 34: | |
| 1675 // " | |
| 1676 escape = '"'; | |
| 1677 break; | |
| 1678 | |
| 1679 case 38: | |
| 1680 // & | |
| 1681 escape = '&'; | |
| 1682 break; | |
| 1683 | |
| 1684 case 39: | |
| 1685 // ' | |
| 1686 escape = '''; // modified from escape-html; used to be ''' | |
| 1687 | |
| 1688 break; | |
| 1689 | |
| 1690 case 60: | |
| 1691 // < | |
| 1692 escape = '<'; | |
| 1693 break; | |
| 1694 | |
| 1695 case 62: | |
| 1696 // > | |
| 1697 escape = '>'; | |
| 1698 break; | |
| 1699 | |
| 1700 default: | |
| 1701 continue; | |
| 1702 } | |
| 1703 | |
| 1704 if (lastIndex !== index) { | |
| 1705 html += str.substring(lastIndex, index); | |
| 1706 } | |
| 1707 | |
| 1708 lastIndex = index + 1; | |
| 1709 html += escape; | |
| 1710 } | |
| 1711 | |
| 1712 return lastIndex !== index ? html + str.substring(lastIndex, index) : html; | |
| 1713 } // end code copied and modified from escape-html | |
| 1714 | |
| 1715 /** | |
| 1716 * Escapes text to prevent scripting attacks. | |
| 1717 * | |
| 1718 * @param {*} text Text value to escape. | |
| 1719 * @return {string} An escaped string. | |
| 1720 */ | |
| 1721 | |
| 1722 | |
| 1723 function escapeTextForBrowser(text) { | |
| 1724 if (typeof text === 'boolean' || typeof text === 'number') { | |
| 1725 // this shortcircuit helps perf for types that we know will never have | |
| 1726 // special characters, especially given that this function is used often | |
| 1727 // for numeric dom ids. | |
| 1728 return '' + text; | |
| 1729 } | |
| 1730 | |
| 1731 return escapeHtml(text); | |
| 1732 } | |
| 1733 | |
| 1734 var uppercasePattern = /([A-Z])/g; | |
| 1735 var msPattern$1 = /^ms-/; | |
| 1736 /** | |
| 1737 * Hyphenates a camelcased CSS property name, for example: | |
| 1738 * | |
| 1739 * > hyphenateStyleName('backgroundColor') | |
| 1740 * < "background-color" | |
| 1741 * > hyphenateStyleName('MozTransition') | |
| 1742 * < "-moz-transition" | |
| 1743 * > hyphenateStyleName('msTransition') | |
| 1744 * < "-ms-transition" | |
| 1745 * | |
| 1746 * As Modernizr suggests (http://modernizr.com/docs/#prefixed), an `ms` prefix | |
| 1747 * is converted to `-ms-`. | |
| 1748 */ | |
| 1749 | |
| 1750 function hyphenateStyleName(name) { | |
| 1751 return name.replace(uppercasePattern, '-$1').toLowerCase().replace(msPattern$1, '-ms-'); | |
| 1752 } | |
| 1753 | |
| 1754 // and any newline or tab are filtered out as if they're not part of the URL. | |
| 1755 // https://url.spec.whatwg.org/#url-parsing | |
| 1756 // Tab or newline are defined as \r\n\t: | |
| 1757 // https://infra.spec.whatwg.org/#ascii-tab-or-newline | |
| 1758 // A C0 control is a code point in the range \u0000 NULL to \u001F | |
| 1759 // INFORMATION SEPARATOR ONE, inclusive: | |
| 1760 // https://infra.spec.whatwg.org/#c0-control-or-space | |
| 1761 | |
| 1762 /* eslint-disable max-len */ | |
| 1763 | |
| 1764 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; | |
| 1765 var didWarn = false; | |
| 1766 | |
| 1767 function sanitizeURL(url) { | |
| 1768 { | |
| 1769 if (!didWarn && isJavaScriptProtocol.test(url)) { | |
| 1770 didWarn = true; | |
| 1771 | |
| 1772 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)); | |
| 1773 } | |
| 1774 } | |
| 1775 } | |
| 1776 | |
| 1777 var isArrayImpl = Array.isArray; // eslint-disable-next-line no-redeclare | |
| 1778 | |
| 1779 function isArray(a) { | |
| 1780 return isArrayImpl(a); | |
| 1781 } | |
| 1782 | |
| 1783 var startInlineScript = stringToPrecomputedChunk('<script>'); | |
| 1784 var endInlineScript = stringToPrecomputedChunk('</script>'); | |
| 1785 var startScriptSrc = stringToPrecomputedChunk('<script src="'); | |
| 1786 var startModuleSrc = stringToPrecomputedChunk('<script type="module" src="'); | |
| 1787 var endAsyncScript = stringToPrecomputedChunk('" async=""></script>'); | |
| 1788 /** | |
| 1789 * This escaping function is designed to work with bootstrapScriptContent only. | |
| 1790 * because we know we are escaping the entire script. We can avoid for instance | |
| 1791 * escaping html comment string sequences that are valid javascript as well because | |
| 1792 * if there are no sebsequent <script sequences the html parser will never enter | |
| 1793 * script data double escaped state (see: https://www.w3.org/TR/html53/syntax.html#script-data-double-escaped-state) | |
| 1794 * | |
| 1795 * While untrusted script content should be made safe before using this api it will | |
| 1796 * ensure that the script cannot be early terminated or never terminated state | |
| 1797 */ | |
| 1798 | |
| 1799 function escapeBootstrapScriptContent(scriptText) { | |
| 1800 { | |
| 1801 checkHtmlStringCoercion(scriptText); | |
| 1802 } | |
| 1803 | |
| 1804 return ('' + scriptText).replace(scriptRegex, scriptReplacer); | |
| 1805 } | |
| 1806 | |
| 1807 var scriptRegex = /(<\/|<)(s)(cript)/gi; | |
| 1808 | |
| 1809 var scriptReplacer = function (match, prefix, s, suffix) { | |
| 1810 return "" + prefix + (s === 's' ? "\\u0073" : "\\u0053") + suffix; | |
| 1811 }; // Allows us to keep track of what we've already written so we can refer back to it. | |
| 1812 | |
| 1813 | |
| 1814 function createResponseState(identifierPrefix, nonce, bootstrapScriptContent, bootstrapScripts, bootstrapModules) { | |
| 1815 var idPrefix = identifierPrefix === undefined ? '' : identifierPrefix; | |
| 1816 var inlineScriptWithNonce = nonce === undefined ? startInlineScript : stringToPrecomputedChunk('<script nonce="' + escapeTextForBrowser(nonce) + '">'); | |
| 1817 var bootstrapChunks = []; | |
| 1818 | |
| 1819 if (bootstrapScriptContent !== undefined) { | |
| 1820 bootstrapChunks.push(inlineScriptWithNonce, stringToChunk(escapeBootstrapScriptContent(bootstrapScriptContent)), endInlineScript); | |
| 1821 } | |
| 1822 | |
| 1823 if (bootstrapScripts !== undefined) { | |
| 1824 for (var i = 0; i < bootstrapScripts.length; i++) { | |
| 1825 bootstrapChunks.push(startScriptSrc, stringToChunk(escapeTextForBrowser(bootstrapScripts[i])), endAsyncScript); | |
| 1826 } | |
| 1827 } | |
| 1828 | |
| 1829 if (bootstrapModules !== undefined) { | |
| 1830 for (var _i = 0; _i < bootstrapModules.length; _i++) { | |
| 1831 bootstrapChunks.push(startModuleSrc, stringToChunk(escapeTextForBrowser(bootstrapModules[_i])), endAsyncScript); | |
| 1832 } | |
| 1833 } | |
| 1834 | |
| 1835 return { | |
| 1836 bootstrapChunks: bootstrapChunks, | |
| 1837 startInlineScript: inlineScriptWithNonce, | |
| 1838 placeholderPrefix: stringToPrecomputedChunk(idPrefix + 'P:'), | |
| 1839 segmentPrefix: stringToPrecomputedChunk(idPrefix + 'S:'), | |
| 1840 boundaryPrefix: idPrefix + 'B:', | |
| 1841 idPrefix: idPrefix, | |
| 1842 nextSuspenseID: 0, | |
| 1843 sentCompleteSegmentFunction: false, | |
| 1844 sentCompleteBoundaryFunction: false, | |
| 1845 sentClientRenderFunction: false | |
| 1846 }; | |
| 1847 } // Constants for the insertion mode we're currently writing in. We don't encode all HTML5 insertion | |
| 1848 // modes. We only include the variants as they matter for the sake of our purposes. | |
| 1849 // We don't actually provide the namespace therefore we use constants instead of the string. | |
| 1850 | |
| 1851 var ROOT_HTML_MODE = 0; // Used for the root most element tag. | |
| 1852 | |
| 1853 var HTML_MODE = 1; | |
| 1854 var SVG_MODE = 2; | |
| 1855 var MATHML_MODE = 3; | |
| 1856 var HTML_TABLE_MODE = 4; | |
| 1857 var HTML_TABLE_BODY_MODE = 5; | |
| 1858 var HTML_TABLE_ROW_MODE = 6; | |
| 1859 var HTML_COLGROUP_MODE = 7; // We have a greater than HTML_TABLE_MODE check elsewhere. If you add more cases here, make sure it | |
| 1860 // still makes sense | |
| 1861 | |
| 1862 function createFormatContext(insertionMode, selectedValue) { | |
| 1863 return { | |
| 1864 insertionMode: insertionMode, | |
| 1865 selectedValue: selectedValue | |
| 1866 }; | |
| 1867 } | |
| 1868 | |
| 1869 function createRootFormatContext(namespaceURI) { | |
| 1870 var insertionMode = namespaceURI === 'http://www.w3.org/2000/svg' ? SVG_MODE : namespaceURI === 'http://www.w3.org/1998/Math/MathML' ? MATHML_MODE : ROOT_HTML_MODE; | |
| 1871 return createFormatContext(insertionMode, null); | |
| 1872 } | |
| 1873 function getChildFormatContext(parentContext, type, props) { | |
| 1874 switch (type) { | |
| 1875 case 'select': | |
| 1876 return createFormatContext(HTML_MODE, props.value != null ? props.value : props.defaultValue); | |
| 1877 | |
| 1878 case 'svg': | |
| 1879 return createFormatContext(SVG_MODE, null); | |
| 1880 | |
| 1881 case 'math': | |
| 1882 return createFormatContext(MATHML_MODE, null); | |
| 1883 | |
| 1884 case 'foreignObject': | |
| 1885 return createFormatContext(HTML_MODE, null); | |
| 1886 // Table parents are special in that their children can only be created at all if they're | |
| 1887 // wrapped in a table parent. So we need to encode that we're entering this mode. | |
| 1888 | |
| 1889 case 'table': | |
| 1890 return createFormatContext(HTML_TABLE_MODE, null); | |
| 1891 | |
| 1892 case 'thead': | |
| 1893 case 'tbody': | |
| 1894 case 'tfoot': | |
| 1895 return createFormatContext(HTML_TABLE_BODY_MODE, null); | |
| 1896 | |
| 1897 case 'colgroup': | |
| 1898 return createFormatContext(HTML_COLGROUP_MODE, null); | |
| 1899 | |
| 1900 case 'tr': | |
| 1901 return createFormatContext(HTML_TABLE_ROW_MODE, null); | |
| 1902 } | |
| 1903 | |
| 1904 if (parentContext.insertionMode >= HTML_TABLE_MODE) { | |
| 1905 // Whatever tag this was, it wasn't a table parent or other special parent, so we must have | |
| 1906 // entered plain HTML again. | |
| 1907 return createFormatContext(HTML_MODE, null); | |
| 1908 } | |
| 1909 | |
| 1910 if (parentContext.insertionMode === ROOT_HTML_MODE) { | |
| 1911 // We've emitted the root and is now in plain HTML mode. | |
| 1912 return createFormatContext(HTML_MODE, null); | |
| 1913 } | |
| 1914 | |
| 1915 return parentContext; | |
| 1916 } | |
| 1917 var UNINITIALIZED_SUSPENSE_BOUNDARY_ID = null; | |
| 1918 function assignSuspenseBoundaryID(responseState) { | |
| 1919 var generatedID = responseState.nextSuspenseID++; | |
| 1920 return stringToPrecomputedChunk(responseState.boundaryPrefix + generatedID.toString(16)); | |
| 1921 } | |
| 1922 function makeId(responseState, treeId, localId) { | |
| 1923 var idPrefix = responseState.idPrefix; | |
| 1924 var id = ':' + idPrefix + 'R' + treeId; // Unless this is the first id at this level, append a number at the end | |
| 1925 // that represents the position of this useId hook among all the useId | |
| 1926 // hooks for this fiber. | |
| 1927 | |
| 1928 if (localId > 0) { | |
| 1929 id += 'H' + localId.toString(32); | |
| 1930 } | |
| 1931 | |
| 1932 return id + ':'; | |
| 1933 } | |
| 1934 | |
| 1935 function encodeHTMLTextNode(text) { | |
| 1936 return escapeTextForBrowser(text); | |
| 1937 } | |
| 1938 | |
| 1939 var textSeparator = stringToPrecomputedChunk('<!-- -->'); | |
| 1940 function pushTextInstance(target, text, responseState, textEmbedded) { | |
| 1941 if (text === '') { | |
| 1942 // Empty text doesn't have a DOM node representation and the hydration is aware of this. | |
| 1943 return textEmbedded; | |
| 1944 } | |
| 1945 | |
| 1946 if (textEmbedded) { | |
| 1947 target.push(textSeparator); | |
| 1948 } | |
| 1949 | |
| 1950 target.push(stringToChunk(encodeHTMLTextNode(text))); | |
| 1951 return true; | |
| 1952 } // Called when Fizz is done with a Segment. Currently the only purpose is to conditionally | |
| 1953 // emit a text separator when we don't know for sure it is safe to omit | |
| 1954 | |
| 1955 function pushSegmentFinale(target, responseState, lastPushedText, textEmbedded) { | |
| 1956 if (lastPushedText && textEmbedded) { | |
| 1957 target.push(textSeparator); | |
| 1958 } | |
| 1959 } | |
| 1960 var styleNameCache = new Map(); | |
| 1961 | |
| 1962 function processStyleName(styleName) { | |
| 1963 var chunk = styleNameCache.get(styleName); | |
| 1964 | |
| 1965 if (chunk !== undefined) { | |
| 1966 return chunk; | |
| 1967 } | |
| 1968 | |
| 1969 var result = stringToPrecomputedChunk(escapeTextForBrowser(hyphenateStyleName(styleName))); | |
| 1970 styleNameCache.set(styleName, result); | |
| 1971 return result; | |
| 1972 } | |
| 1973 | |
| 1974 var styleAttributeStart = stringToPrecomputedChunk(' style="'); | |
| 1975 var styleAssign = stringToPrecomputedChunk(':'); | |
| 1976 var styleSeparator = stringToPrecomputedChunk(';'); | |
| 1977 | |
| 1978 function pushStyle(target, responseState, style) { | |
| 1979 if (typeof style !== 'object') { | |
| 1980 throw new Error('The `style` prop expects a mapping from style properties to values, ' + "not a string. For example, style={{marginRight: spacing + 'em'}} when " + 'using JSX.'); | |
| 1981 } | |
| 1982 | |
| 1983 var isFirst = true; | |
| 1984 | |
| 1985 for (var styleName in style) { | |
| 1986 if (!hasOwnProperty.call(style, styleName)) { | |
| 1987 continue; | |
| 1988 } // If you provide unsafe user data here they can inject arbitrary CSS | |
| 1989 // which may be problematic (I couldn't repro this): | |
| 1990 // https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet | |
| 1991 // http://www.thespanner.co.uk/2007/11/26/ultimate-xss-css-injection/ | |
| 1992 // This is not an XSS hole but instead a potential CSS injection issue | |
| 1993 // which has lead to a greater discussion about how we're going to | |
| 1994 // trust URLs moving forward. See #2115901 | |
| 1995 | |
| 1996 | |
| 1997 var styleValue = style[styleName]; | |
| 1998 | |
| 1999 if (styleValue == null || typeof styleValue === 'boolean' || styleValue === '') { | |
| 2000 // TODO: We used to set empty string as a style with an empty value. Does that ever make sense? | |
| 2001 continue; | |
| 2002 } | |
| 2003 | |
| 2004 var nameChunk = void 0; | |
| 2005 var valueChunk = void 0; | |
| 2006 var isCustomProperty = styleName.indexOf('--') === 0; | |
| 2007 | |
| 2008 if (isCustomProperty) { | |
| 2009 nameChunk = stringToChunk(escapeTextForBrowser(styleName)); | |
| 2010 | |
| 2011 { | |
| 2012 checkCSSPropertyStringCoercion(styleValue, styleName); | |
| 2013 } | |
| 2014 | |
| 2015 valueChunk = stringToChunk(escapeTextForBrowser(('' + styleValue).trim())); | |
| 2016 } else { | |
| 2017 { | |
| 2018 warnValidStyle$1(styleName, styleValue); | |
| 2019 } | |
| 2020 | |
| 2021 nameChunk = processStyleName(styleName); | |
| 2022 | |
| 2023 if (typeof styleValue === 'number') { | |
| 2024 if (styleValue !== 0 && !hasOwnProperty.call(isUnitlessNumber, styleName)) { | |
| 2025 valueChunk = stringToChunk(styleValue + 'px'); // Presumes implicit 'px' suffix for unitless numbers | |
| 2026 } else { | |
| 2027 valueChunk = stringToChunk('' + styleValue); | |
| 2028 } | |
| 2029 } else { | |
| 2030 { | |
| 2031 checkCSSPropertyStringCoercion(styleValue, styleName); | |
| 2032 } | |
| 2033 | |
| 2034 valueChunk = stringToChunk(escapeTextForBrowser(('' + styleValue).trim())); | |
| 2035 } | |
| 2036 } | |
| 2037 | |
| 2038 if (isFirst) { | |
| 2039 isFirst = false; // If it's first, we don't need any separators prefixed. | |
| 2040 | |
| 2041 target.push(styleAttributeStart, nameChunk, styleAssign, valueChunk); | |
| 2042 } else { | |
| 2043 target.push(styleSeparator, nameChunk, styleAssign, valueChunk); | |
| 2044 } | |
| 2045 } | |
| 2046 | |
| 2047 if (!isFirst) { | |
| 2048 target.push(attributeEnd); | |
| 2049 } | |
| 2050 } | |
| 2051 | |
| 2052 var attributeSeparator = stringToPrecomputedChunk(' '); | |
| 2053 var attributeAssign = stringToPrecomputedChunk('="'); | |
| 2054 var attributeEnd = stringToPrecomputedChunk('"'); | |
| 2055 var attributeEmptyString = stringToPrecomputedChunk('=""'); | |
| 2056 | |
| 2057 function pushAttribute(target, responseState, name, value) { | |
| 2058 switch (name) { | |
| 2059 case 'style': | |
| 2060 { | |
| 2061 pushStyle(target, responseState, value); | |
| 2062 return; | |
| 2063 } | |
| 2064 | |
| 2065 case 'defaultValue': | |
| 2066 case 'defaultChecked': // These shouldn't be set as attributes on generic HTML elements. | |
| 2067 | |
| 2068 case 'innerHTML': // Must use dangerouslySetInnerHTML instead. | |
| 2069 | |
| 2070 case 'suppressContentEditableWarning': | |
| 2071 case 'suppressHydrationWarning': | |
| 2072 // Ignored. These are built-in to React on the client. | |
| 2073 return; | |
| 2074 } | |
| 2075 | |
| 2076 if ( // shouldIgnoreAttribute | |
| 2077 // We have already filtered out null/undefined and reserved words. | |
| 2078 name.length > 2 && (name[0] === 'o' || name[0] === 'O') && (name[1] === 'n' || name[1] === 'N')) { | |
| 2079 return; | |
| 2080 } | |
| 2081 | |
| 2082 var propertyInfo = getPropertyInfo(name); | |
| 2083 | |
| 2084 if (propertyInfo !== null) { | |
| 2085 // shouldRemoveAttribute | |
| 2086 switch (typeof value) { | |
| 2087 case 'function': // $FlowIssue symbol is perfectly valid here | |
| 2088 | |
| 2089 case 'symbol': | |
| 2090 // eslint-disable-line | |
| 2091 return; | |
| 2092 | |
| 2093 case 'boolean': | |
| 2094 { | |
| 2095 if (!propertyInfo.acceptsBooleans) { | |
| 2096 return; | |
| 2097 } | |
| 2098 } | |
| 2099 } | |
| 2100 | |
| 2101 var attributeName = propertyInfo.attributeName; | |
| 2102 var attributeNameChunk = stringToChunk(attributeName); // TODO: If it's known we can cache the chunk. | |
| 2103 | |
| 2104 switch (propertyInfo.type) { | |
| 2105 case BOOLEAN: | |
| 2106 if (value) { | |
| 2107 target.push(attributeSeparator, attributeNameChunk, attributeEmptyString); | |
| 2108 } | |
| 2109 | |
| 2110 return; | |
| 2111 | |
| 2112 case OVERLOADED_BOOLEAN: | |
| 2113 if (value === true) { | |
| 2114 target.push(attributeSeparator, attributeNameChunk, attributeEmptyString); | |
| 2115 } else if (value === false) ; else { | |
| 2116 target.push(attributeSeparator, attributeNameChunk, attributeAssign, stringToChunk(escapeTextForBrowser(value)), attributeEnd); | |
| 2117 } | |
| 2118 | |
| 2119 return; | |
| 2120 | |
| 2121 case NUMERIC: | |
| 2122 if (!isNaN(value)) { | |
| 2123 target.push(attributeSeparator, attributeNameChunk, attributeAssign, stringToChunk(escapeTextForBrowser(value)), attributeEnd); | |
| 2124 } | |
| 2125 | |
| 2126 break; | |
| 2127 | |
| 2128 case POSITIVE_NUMERIC: | |
| 2129 if (!isNaN(value) && value >= 1) { | |
| 2130 target.push(attributeSeparator, attributeNameChunk, attributeAssign, stringToChunk(escapeTextForBrowser(value)), attributeEnd); | |
| 2131 } | |
| 2132 | |
| 2133 break; | |
| 2134 | |
| 2135 default: | |
| 2136 if (propertyInfo.sanitizeURL) { | |
| 2137 { | |
| 2138 checkAttributeStringCoercion(value, attributeName); | |
| 2139 } | |
| 2140 | |
| 2141 value = '' + value; | |
| 2142 sanitizeURL(value); | |
| 2143 } | |
| 2144 | |
| 2145 target.push(attributeSeparator, attributeNameChunk, attributeAssign, stringToChunk(escapeTextForBrowser(value)), attributeEnd); | |
| 2146 } | |
| 2147 } else if (isAttributeNameSafe(name)) { | |
| 2148 // shouldRemoveAttribute | |
| 2149 switch (typeof value) { | |
| 2150 case 'function': // $FlowIssue symbol is perfectly valid here | |
| 2151 | |
| 2152 case 'symbol': | |
| 2153 // eslint-disable-line | |
| 2154 return; | |
| 2155 | |
| 2156 case 'boolean': | |
| 2157 { | |
| 2158 var prefix = name.toLowerCase().slice(0, 5); | |
| 2159 | |
| 2160 if (prefix !== 'data-' && prefix !== 'aria-') { | |
| 2161 return; | |
| 2162 } | |
| 2163 } | |
| 2164 } | |
| 2165 | |
| 2166 target.push(attributeSeparator, stringToChunk(name), attributeAssign, stringToChunk(escapeTextForBrowser(value)), attributeEnd); | |
| 2167 } | |
| 2168 } | |
| 2169 | |
| 2170 var endOfStartTag = stringToPrecomputedChunk('>'); | |
| 2171 var endOfStartTagSelfClosing = stringToPrecomputedChunk('/>'); | |
| 2172 | |
| 2173 function pushInnerHTML(target, innerHTML, children) { | |
| 2174 if (innerHTML != null) { | |
| 2175 if (children != null) { | |
| 2176 throw new Error('Can only set one of `children` or `props.dangerouslySetInnerHTML`.'); | |
| 2177 } | |
| 2178 | |
| 2179 if (typeof innerHTML !== 'object' || !('__html' in innerHTML)) { | |
| 2180 throw new Error('`props.dangerouslySetInnerHTML` must be in the form `{__html: ...}`. ' + 'Please visit https://reactjs.org/link/dangerously-set-inner-html ' + 'for more information.'); | |
| 2181 } | |
| 2182 | |
| 2183 var html = innerHTML.__html; | |
| 2184 | |
| 2185 if (html !== null && html !== undefined) { | |
| 2186 { | |
| 2187 checkHtmlStringCoercion(html); | |
| 2188 } | |
| 2189 | |
| 2190 target.push(stringToChunk('' + html)); | |
| 2191 } | |
| 2192 } | |
| 2193 } // TODO: Move these to ResponseState so that we warn for every request. | |
| 2194 // It would help debugging in stateful servers (e.g. service worker). | |
| 2195 | |
| 2196 | |
| 2197 var didWarnDefaultInputValue = false; | |
| 2198 var didWarnDefaultChecked = false; | |
| 2199 var didWarnDefaultSelectValue = false; | |
| 2200 var didWarnDefaultTextareaValue = false; | |
| 2201 var didWarnInvalidOptionChildren = false; | |
| 2202 var didWarnInvalidOptionInnerHTML = false; | |
| 2203 var didWarnSelectedSetOnOption = false; | |
| 2204 | |
| 2205 function checkSelectProp(props, propName) { | |
| 2206 { | |
| 2207 var value = props[propName]; | |
| 2208 | |
| 2209 if (value != null) { | |
| 2210 var array = isArray(value); | |
| 2211 | |
| 2212 if (props.multiple && !array) { | |
| 2213 error('The `%s` prop supplied to <select> must be an array if ' + '`multiple` is true.', propName); | |
| 2214 } else if (!props.multiple && array) { | |
| 2215 error('The `%s` prop supplied to <select> must be a scalar ' + 'value if `multiple` is false.', propName); | |
| 2216 } | |
| 2217 } | |
| 2218 } | |
| 2219 } | |
| 2220 | |
| 2221 function pushStartSelect(target, props, responseState) { | |
| 2222 { | |
| 2223 checkControlledValueProps('select', props); | |
| 2224 checkSelectProp(props, 'value'); | |
| 2225 checkSelectProp(props, 'defaultValue'); | |
| 2226 | |
| 2227 if (props.value !== undefined && props.defaultValue !== undefined && !didWarnDefaultSelectValue) { | |
| 2228 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://reactjs.org/link/controlled-components'); | |
| 2229 | |
| 2230 didWarnDefaultSelectValue = true; | |
| 2231 } | |
| 2232 } | |
| 2233 | |
| 2234 target.push(startChunkForTag('select')); | |
| 2235 var children = null; | |
| 2236 var innerHTML = null; | |
| 2237 | |
| 2238 for (var propKey in props) { | |
| 2239 if (hasOwnProperty.call(props, propKey)) { | |
| 2240 var propValue = props[propKey]; | |
| 2241 | |
| 2242 if (propValue == null) { | |
| 2243 continue; | |
| 2244 } | |
| 2245 | |
| 2246 switch (propKey) { | |
| 2247 case 'children': | |
| 2248 children = propValue; | |
| 2249 break; | |
| 2250 | |
| 2251 case 'dangerouslySetInnerHTML': | |
| 2252 // TODO: This doesn't really make sense for select since it can't use the controlled | |
| 2253 // value in the innerHTML. | |
| 2254 innerHTML = propValue; | |
| 2255 break; | |
| 2256 | |
| 2257 case 'defaultValue': | |
| 2258 case 'value': | |
| 2259 // These are set on the Context instead and applied to the nested options. | |
| 2260 break; | |
| 2261 | |
| 2262 default: | |
| 2263 pushAttribute(target, responseState, propKey, propValue); | |
| 2264 break; | |
| 2265 } | |
| 2266 } | |
| 2267 } | |
| 2268 | |
| 2269 target.push(endOfStartTag); | |
| 2270 pushInnerHTML(target, innerHTML, children); | |
| 2271 return children; | |
| 2272 } | |
| 2273 | |
| 2274 function flattenOptionChildren(children) { | |
| 2275 var content = ''; // Flatten children and warn if they aren't strings or numbers; | |
| 2276 // invalid types are ignored. | |
| 2277 | |
| 2278 React.Children.forEach(children, function (child) { | |
| 2279 if (child == null) { | |
| 2280 return; | |
| 2281 } | |
| 2282 | |
| 2283 content += child; | |
| 2284 | |
| 2285 { | |
| 2286 if (!didWarnInvalidOptionChildren && typeof child !== 'string' && typeof child !== 'number') { | |
| 2287 didWarnInvalidOptionChildren = true; | |
| 2288 | |
| 2289 error('Cannot infer the option value of complex children. ' + 'Pass a `value` prop or use a plain string as children to <option>.'); | |
| 2290 } | |
| 2291 } | |
| 2292 }); | |
| 2293 return content; | |
| 2294 } | |
| 2295 | |
| 2296 var selectedMarkerAttribute = stringToPrecomputedChunk(' selected=""'); | |
| 2297 | |
| 2298 function pushStartOption(target, props, responseState, formatContext) { | |
| 2299 var selectedValue = formatContext.selectedValue; | |
| 2300 target.push(startChunkForTag('option')); | |
| 2301 var children = null; | |
| 2302 var value = null; | |
| 2303 var selected = null; | |
| 2304 var innerHTML = null; | |
| 2305 | |
| 2306 for (var propKey in props) { | |
| 2307 if (hasOwnProperty.call(props, propKey)) { | |
| 2308 var propValue = props[propKey]; | |
| 2309 | |
| 2310 if (propValue == null) { | |
| 2311 continue; | |
| 2312 } | |
| 2313 | |
| 2314 switch (propKey) { | |
| 2315 case 'children': | |
| 2316 children = propValue; | |
| 2317 break; | |
| 2318 | |
| 2319 case 'selected': | |
| 2320 // ignore | |
| 2321 selected = propValue; | |
| 2322 | |
| 2323 { | |
| 2324 // TODO: Remove support for `selected` in <option>. | |
| 2325 if (!didWarnSelectedSetOnOption) { | |
| 2326 error('Use the `defaultValue` or `value` props on <select> instead of ' + 'setting `selected` on <option>.'); | |
| 2327 | |
| 2328 didWarnSelectedSetOnOption = true; | |
| 2329 } | |
| 2330 } | |
| 2331 | |
| 2332 break; | |
| 2333 | |
| 2334 case 'dangerouslySetInnerHTML': | |
| 2335 innerHTML = propValue; | |
| 2336 break; | |
| 2337 // eslint-disable-next-line-no-fallthrough | |
| 2338 | |
| 2339 case 'value': | |
| 2340 value = propValue; | |
| 2341 // We intentionally fallthrough to also set the attribute on the node. | |
| 2342 // eslint-disable-next-line-no-fallthrough | |
| 2343 | |
| 2344 default: | |
| 2345 pushAttribute(target, responseState, propKey, propValue); | |
| 2346 break; | |
| 2347 } | |
| 2348 } | |
| 2349 } | |
| 2350 | |
| 2351 if (selectedValue != null) { | |
| 2352 var stringValue; | |
| 2353 | |
| 2354 if (value !== null) { | |
| 2355 { | |
| 2356 checkAttributeStringCoercion(value, 'value'); | |
| 2357 } | |
| 2358 | |
| 2359 stringValue = '' + value; | |
| 2360 } else { | |
| 2361 { | |
| 2362 if (innerHTML !== null) { | |
| 2363 if (!didWarnInvalidOptionInnerHTML) { | |
| 2364 didWarnInvalidOptionInnerHTML = true; | |
| 2365 | |
| 2366 error('Pass a `value` prop if you set dangerouslyInnerHTML so React knows ' + 'which value should be selected.'); | |
| 2367 } | |
| 2368 } | |
| 2369 } | |
| 2370 | |
| 2371 stringValue = flattenOptionChildren(children); | |
| 2372 } | |
| 2373 | |
| 2374 if (isArray(selectedValue)) { | |
| 2375 // multiple | |
| 2376 for (var i = 0; i < selectedValue.length; i++) { | |
| 2377 { | |
| 2378 checkAttributeStringCoercion(selectedValue[i], 'value'); | |
| 2379 } | |
| 2380 | |
| 2381 var v = '' + selectedValue[i]; | |
| 2382 | |
| 2383 if (v === stringValue) { | |
| 2384 target.push(selectedMarkerAttribute); | |
| 2385 break; | |
| 2386 } | |
| 2387 } | |
| 2388 } else { | |
| 2389 { | |
| 2390 checkAttributeStringCoercion(selectedValue, 'select.value'); | |
| 2391 } | |
| 2392 | |
| 2393 if ('' + selectedValue === stringValue) { | |
| 2394 target.push(selectedMarkerAttribute); | |
| 2395 } | |
| 2396 } | |
| 2397 } else if (selected) { | |
| 2398 target.push(selectedMarkerAttribute); | |
| 2399 } | |
| 2400 | |
| 2401 target.push(endOfStartTag); | |
| 2402 pushInnerHTML(target, innerHTML, children); | |
| 2403 return children; | |
| 2404 } | |
| 2405 | |
| 2406 function pushInput(target, props, responseState) { | |
| 2407 { | |
| 2408 checkControlledValueProps('input', props); | |
| 2409 | |
| 2410 if (props.checked !== undefined && props.defaultChecked !== undefined && !didWarnDefaultChecked) { | |
| 2411 error('%s contains an input of type %s with both checked and defaultChecked props. ' + 'Input elements must be either controlled or uncontrolled ' + '(specify either the checked prop, or the defaultChecked prop, but not ' + 'both). Decide between using a controlled or uncontrolled input ' + 'element and remove one of these props. More info: ' + 'https://reactjs.org/link/controlled-components', 'A component', props.type); | |
| 2412 | |
| 2413 didWarnDefaultChecked = true; | |
| 2414 } | |
| 2415 | |
| 2416 if (props.value !== undefined && props.defaultValue !== undefined && !didWarnDefaultInputValue) { | |
| 2417 error('%s contains an input of type %s with both value and defaultValue props. ' + 'Input elements must be either controlled or uncontrolled ' + '(specify either the value prop, or the defaultValue prop, but not ' + 'both). Decide between using a controlled or uncontrolled input ' + 'element and remove one of these props. More info: ' + 'https://reactjs.org/link/controlled-components', 'A component', props.type); | |
| 2418 | |
| 2419 didWarnDefaultInputValue = true; | |
| 2420 } | |
| 2421 } | |
| 2422 | |
| 2423 target.push(startChunkForTag('input')); | |
| 2424 var value = null; | |
| 2425 var defaultValue = null; | |
| 2426 var checked = null; | |
| 2427 var defaultChecked = null; | |
| 2428 | |
| 2429 for (var propKey in props) { | |
| 2430 if (hasOwnProperty.call(props, propKey)) { | |
| 2431 var propValue = props[propKey]; | |
| 2432 | |
| 2433 if (propValue == null) { | |
| 2434 continue; | |
| 2435 } | |
| 2436 | |
| 2437 switch (propKey) { | |
| 2438 case 'children': | |
| 2439 case 'dangerouslySetInnerHTML': | |
| 2440 throw new Error('input' + " is a self-closing tag and must neither have `children` nor " + 'use `dangerouslySetInnerHTML`.'); | |
| 2441 // eslint-disable-next-line-no-fallthrough | |
| 2442 | |
| 2443 case 'defaultChecked': | |
| 2444 defaultChecked = propValue; | |
| 2445 break; | |
| 2446 | |
| 2447 case 'defaultValue': | |
| 2448 defaultValue = propValue; | |
| 2449 break; | |
| 2450 | |
| 2451 case 'checked': | |
| 2452 checked = propValue; | |
| 2453 break; | |
| 2454 | |
| 2455 case 'value': | |
| 2456 value = propValue; | |
| 2457 break; | |
| 2458 | |
| 2459 default: | |
| 2460 pushAttribute(target, responseState, propKey, propValue); | |
| 2461 break; | |
| 2462 } | |
| 2463 } | |
| 2464 } | |
| 2465 | |
| 2466 if (checked !== null) { | |
| 2467 pushAttribute(target, responseState, 'checked', checked); | |
| 2468 } else if (defaultChecked !== null) { | |
| 2469 pushAttribute(target, responseState, 'checked', defaultChecked); | |
| 2470 } | |
| 2471 | |
| 2472 if (value !== null) { | |
| 2473 pushAttribute(target, responseState, 'value', value); | |
| 2474 } else if (defaultValue !== null) { | |
| 2475 pushAttribute(target, responseState, 'value', defaultValue); | |
| 2476 } | |
| 2477 | |
| 2478 target.push(endOfStartTagSelfClosing); | |
| 2479 return null; | |
| 2480 } | |
| 2481 | |
| 2482 function pushStartTextArea(target, props, responseState) { | |
| 2483 { | |
| 2484 checkControlledValueProps('textarea', props); | |
| 2485 | |
| 2486 if (props.value !== undefined && props.defaultValue !== undefined && !didWarnDefaultTextareaValue) { | |
| 2487 error('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://reactjs.org/link/controlled-components'); | |
| 2488 | |
| 2489 didWarnDefaultTextareaValue = true; | |
| 2490 } | |
| 2491 } | |
| 2492 | |
| 2493 target.push(startChunkForTag('textarea')); | |
| 2494 var value = null; | |
| 2495 var defaultValue = null; | |
| 2496 var children = null; | |
| 2497 | |
| 2498 for (var propKey in props) { | |
| 2499 if (hasOwnProperty.call(props, propKey)) { | |
| 2500 var propValue = props[propKey]; | |
| 2501 | |
| 2502 if (propValue == null) { | |
| 2503 continue; | |
| 2504 } | |
| 2505 | |
| 2506 switch (propKey) { | |
| 2507 case 'children': | |
| 2508 children = propValue; | |
| 2509 break; | |
| 2510 | |
| 2511 case 'value': | |
| 2512 value = propValue; | |
| 2513 break; | |
| 2514 | |
| 2515 case 'defaultValue': | |
| 2516 defaultValue = propValue; | |
| 2517 break; | |
| 2518 | |
| 2519 case 'dangerouslySetInnerHTML': | |
| 2520 throw new Error('`dangerouslySetInnerHTML` does not make sense on <textarea>.'); | |
| 2521 // eslint-disable-next-line-no-fallthrough | |
| 2522 | |
| 2523 default: | |
| 2524 pushAttribute(target, responseState, propKey, propValue); | |
| 2525 break; | |
| 2526 } | |
| 2527 } | |
| 2528 } | |
| 2529 | |
| 2530 if (value === null && defaultValue !== null) { | |
| 2531 value = defaultValue; | |
| 2532 } | |
| 2533 | |
| 2534 target.push(endOfStartTag); // TODO (yungsters): Remove support for children content in <textarea>. | |
| 2535 | |
| 2536 if (children != null) { | |
| 2537 { | |
| 2538 error('Use the `defaultValue` or `value` props instead of setting ' + 'children on <textarea>.'); | |
| 2539 } | |
| 2540 | |
| 2541 if (value != null) { | |
| 2542 throw new Error('If you supply `defaultValue` on a <textarea>, do not pass children.'); | |
| 2543 } | |
| 2544 | |
| 2545 if (isArray(children)) { | |
| 2546 if (children.length > 1) { | |
| 2547 throw new Error('<textarea> can only have at most one child.'); | |
| 2548 } // TODO: remove the coercion and the DEV check below because it will | |
| 2549 // always be overwritten by the coercion several lines below it. #22309 | |
| 2550 | |
| 2551 | |
| 2552 { | |
| 2553 checkHtmlStringCoercion(children[0]); | |
| 2554 } | |
| 2555 | |
| 2556 value = '' + children[0]; | |
| 2557 } | |
| 2558 | |
| 2559 { | |
| 2560 checkHtmlStringCoercion(children); | |
| 2561 } | |
| 2562 | |
| 2563 value = '' + children; | |
| 2564 } | |
| 2565 | |
| 2566 if (typeof value === 'string' && value[0] === '\n') { | |
| 2567 // text/html ignores the first character in these tags if it's a newline | |
| 2568 // Prefer to break application/xml over text/html (for now) by adding | |
| 2569 // a newline specifically to get eaten by the parser. (Alternately for | |
| 2570 // textareas, replacing "^\n" with "\r\n" doesn't get eaten, and the first | |
| 2571 // \r is normalized out by HTMLTextAreaElement#value.) | |
| 2572 // See: <http://www.w3.org/TR/html-polyglot/#newlines-in-textarea-and-pre> | |
| 2573 // See: <http://www.w3.org/TR/html5/syntax.html#element-restrictions> | |
| 2574 // See: <http://www.w3.org/TR/html5/syntax.html#newlines> | |
| 2575 // See: Parsing of "textarea" "listing" and "pre" elements | |
| 2576 // from <http://www.w3.org/TR/html5/syntax.html#parsing-main-inbody> | |
| 2577 target.push(leadingNewline); | |
| 2578 } // ToString and push directly instead of recurse over children. | |
| 2579 // We don't really support complex children in the value anyway. | |
| 2580 // This also currently avoids a trailing comment node which breaks textarea. | |
| 2581 | |
| 2582 | |
| 2583 if (value !== null) { | |
| 2584 { | |
| 2585 checkAttributeStringCoercion(value, 'value'); | |
| 2586 } | |
| 2587 | |
| 2588 target.push(stringToChunk(encodeHTMLTextNode('' + value))); | |
| 2589 } | |
| 2590 | |
| 2591 return null; | |
| 2592 } | |
| 2593 | |
| 2594 function pushSelfClosing(target, props, tag, responseState) { | |
| 2595 target.push(startChunkForTag(tag)); | |
| 2596 | |
| 2597 for (var propKey in props) { | |
| 2598 if (hasOwnProperty.call(props, propKey)) { | |
| 2599 var propValue = props[propKey]; | |
| 2600 | |
| 2601 if (propValue == null) { | |
| 2602 continue; | |
| 2603 } | |
| 2604 | |
| 2605 switch (propKey) { | |
| 2606 case 'children': | |
| 2607 case 'dangerouslySetInnerHTML': | |
| 2608 throw new Error(tag + " is a self-closing tag and must neither have `children` nor " + 'use `dangerouslySetInnerHTML`.'); | |
| 2609 // eslint-disable-next-line-no-fallthrough | |
| 2610 | |
| 2611 default: | |
| 2612 pushAttribute(target, responseState, propKey, propValue); | |
| 2613 break; | |
| 2614 } | |
| 2615 } | |
| 2616 } | |
| 2617 | |
| 2618 target.push(endOfStartTagSelfClosing); | |
| 2619 return null; | |
| 2620 } | |
| 2621 | |
| 2622 function pushStartMenuItem(target, props, responseState) { | |
| 2623 target.push(startChunkForTag('menuitem')); | |
| 2624 | |
| 2625 for (var propKey in props) { | |
| 2626 if (hasOwnProperty.call(props, propKey)) { | |
| 2627 var propValue = props[propKey]; | |
| 2628 | |
| 2629 if (propValue == null) { | |
| 2630 continue; | |
| 2631 } | |
| 2632 | |
| 2633 switch (propKey) { | |
| 2634 case 'children': | |
| 2635 case 'dangerouslySetInnerHTML': | |
| 2636 throw new Error('menuitems cannot have `children` nor `dangerouslySetInnerHTML`.'); | |
| 2637 // eslint-disable-next-line-no-fallthrough | |
| 2638 | |
| 2639 default: | |
| 2640 pushAttribute(target, responseState, propKey, propValue); | |
| 2641 break; | |
| 2642 } | |
| 2643 } | |
| 2644 } | |
| 2645 | |
| 2646 target.push(endOfStartTag); | |
| 2647 return null; | |
| 2648 } | |
| 2649 | |
| 2650 function pushStartTitle(target, props, responseState) { | |
| 2651 target.push(startChunkForTag('title')); | |
| 2652 var children = null; | |
| 2653 | |
| 2654 for (var propKey in props) { | |
| 2655 if (hasOwnProperty.call(props, propKey)) { | |
| 2656 var propValue = props[propKey]; | |
| 2657 | |
| 2658 if (propValue == null) { | |
| 2659 continue; | |
| 2660 } | |
| 2661 | |
| 2662 switch (propKey) { | |
| 2663 case 'children': | |
| 2664 children = propValue; | |
| 2665 break; | |
| 2666 | |
| 2667 case 'dangerouslySetInnerHTML': | |
| 2668 throw new Error('`dangerouslySetInnerHTML` does not make sense on <title>.'); | |
| 2669 // eslint-disable-next-line-no-fallthrough | |
| 2670 | |
| 2671 default: | |
| 2672 pushAttribute(target, responseState, propKey, propValue); | |
| 2673 break; | |
| 2674 } | |
| 2675 } | |
| 2676 } | |
| 2677 | |
| 2678 target.push(endOfStartTag); | |
| 2679 | |
| 2680 { | |
| 2681 var child = Array.isArray(children) && children.length < 2 ? children[0] || null : children; | |
| 2682 | |
| 2683 if (Array.isArray(children) && children.length > 1) { | |
| 2684 error('A title element received an array with more than 1 element as children. ' + 'In browsers title Elements can only have Text Nodes as children. If ' + 'the children being rendered output more than a single text node in aggregate the browser ' + 'will display markup and comments as text in the title and hydration will likely fail and ' + 'fall back to client rendering'); | |
| 2685 } else if (child != null && child.$$typeof != null) { | |
| 2686 error('A title element received a React element for children. ' + 'In the browser title Elements can only have Text Nodes as children. If ' + 'the children being rendered output more than a single text node in aggregate the browser ' + 'will display markup and comments as text in the title and hydration will likely fail and ' + 'fall back to client rendering'); | |
| 2687 } else if (child != null && typeof child !== 'string' && typeof child !== 'number') { | |
| 2688 error('A title element received a value that was not a string or number for children. ' + 'In the browser title Elements can only have Text Nodes as children. If ' + 'the children being rendered output more than a single text node in aggregate the browser ' + 'will display markup and comments as text in the title and hydration will likely fail and ' + 'fall back to client rendering'); | |
| 2689 } | |
| 2690 } | |
| 2691 | |
| 2692 return children; | |
| 2693 } | |
| 2694 | |
| 2695 function pushStartGenericElement(target, props, tag, responseState) { | |
| 2696 target.push(startChunkForTag(tag)); | |
| 2697 var children = null; | |
| 2698 var innerHTML = null; | |
| 2699 | |
| 2700 for (var propKey in props) { | |
| 2701 if (hasOwnProperty.call(props, propKey)) { | |
| 2702 var propValue = props[propKey]; | |
| 2703 | |
| 2704 if (propValue == null) { | |
| 2705 continue; | |
| 2706 } | |
| 2707 | |
| 2708 switch (propKey) { | |
| 2709 case 'children': | |
| 2710 children = propValue; | |
| 2711 break; | |
| 2712 | |
| 2713 case 'dangerouslySetInnerHTML': | |
| 2714 innerHTML = propValue; | |
| 2715 break; | |
| 2716 | |
| 2717 default: | |
| 2718 pushAttribute(target, responseState, propKey, propValue); | |
| 2719 break; | |
| 2720 } | |
| 2721 } | |
| 2722 } | |
| 2723 | |
| 2724 target.push(endOfStartTag); | |
| 2725 pushInnerHTML(target, innerHTML, children); | |
| 2726 | |
| 2727 if (typeof children === 'string') { | |
| 2728 // Special case children as a string to avoid the unnecessary comment. | |
| 2729 // TODO: Remove this special case after the general optimization is in place. | |
| 2730 target.push(stringToChunk(encodeHTMLTextNode(children))); | |
| 2731 return null; | |
| 2732 } | |
| 2733 | |
| 2734 return children; | |
| 2735 } | |
| 2736 | |
| 2737 function pushStartCustomElement(target, props, tag, responseState) { | |
| 2738 target.push(startChunkForTag(tag)); | |
| 2739 var children = null; | |
| 2740 var innerHTML = null; | |
| 2741 | |
| 2742 for (var propKey in props) { | |
| 2743 if (hasOwnProperty.call(props, propKey)) { | |
| 2744 var propValue = props[propKey]; | |
| 2745 | |
| 2746 if (propValue == null) { | |
| 2747 continue; | |
| 2748 } | |
| 2749 | |
| 2750 switch (propKey) { | |
| 2751 case 'children': | |
| 2752 children = propValue; | |
| 2753 break; | |
| 2754 | |
| 2755 case 'dangerouslySetInnerHTML': | |
| 2756 innerHTML = propValue; | |
| 2757 break; | |
| 2758 | |
| 2759 case 'style': | |
| 2760 pushStyle(target, responseState, propValue); | |
| 2761 break; | |
| 2762 | |
| 2763 case 'suppressContentEditableWarning': | |
| 2764 case 'suppressHydrationWarning': | |
| 2765 // Ignored. These are built-in to React on the client. | |
| 2766 break; | |
| 2767 | |
| 2768 default: | |
| 2769 if (isAttributeNameSafe(propKey) && typeof propValue !== 'function' && typeof propValue !== 'symbol') { | |
| 2770 target.push(attributeSeparator, stringToChunk(propKey), attributeAssign, stringToChunk(escapeTextForBrowser(propValue)), attributeEnd); | |
| 2771 } | |
| 2772 | |
| 2773 break; | |
| 2774 } | |
| 2775 } | |
| 2776 } | |
| 2777 | |
| 2778 target.push(endOfStartTag); | |
| 2779 pushInnerHTML(target, innerHTML, children); | |
| 2780 return children; | |
| 2781 } | |
| 2782 | |
| 2783 var leadingNewline = stringToPrecomputedChunk('\n'); | |
| 2784 | |
| 2785 function pushStartPreformattedElement(target, props, tag, responseState) { | |
| 2786 target.push(startChunkForTag(tag)); | |
| 2787 var children = null; | |
| 2788 var innerHTML = null; | |
| 2789 | |
| 2790 for (var propKey in props) { | |
| 2791 if (hasOwnProperty.call(props, propKey)) { | |
| 2792 var propValue = props[propKey]; | |
| 2793 | |
| 2794 if (propValue == null) { | |
| 2795 continue; | |
| 2796 } | |
| 2797 | |
| 2798 switch (propKey) { | |
| 2799 case 'children': | |
| 2800 children = propValue; | |
| 2801 break; | |
| 2802 | |
| 2803 case 'dangerouslySetInnerHTML': | |
| 2804 innerHTML = propValue; | |
| 2805 break; | |
| 2806 | |
| 2807 default: | |
| 2808 pushAttribute(target, responseState, propKey, propValue); | |
| 2809 break; | |
| 2810 } | |
| 2811 } | |
| 2812 } | |
| 2813 | |
| 2814 target.push(endOfStartTag); // text/html ignores the first character in these tags if it's a newline | |
| 2815 // Prefer to break application/xml over text/html (for now) by adding | |
| 2816 // a newline specifically to get eaten by the parser. (Alternately for | |
| 2817 // textareas, replacing "^\n" with "\r\n" doesn't get eaten, and the first | |
| 2818 // \r is normalized out by HTMLTextAreaElement#value.) | |
| 2819 // See: <http://www.w3.org/TR/html-polyglot/#newlines-in-textarea-and-pre> | |
| 2820 // See: <http://www.w3.org/TR/html5/syntax.html#element-restrictions> | |
| 2821 // See: <http://www.w3.org/TR/html5/syntax.html#newlines> | |
| 2822 // See: Parsing of "textarea" "listing" and "pre" elements | |
| 2823 // from <http://www.w3.org/TR/html5/syntax.html#parsing-main-inbody> | |
| 2824 // TODO: This doesn't deal with the case where the child is an array | |
| 2825 // or component that returns a string. | |
| 2826 | |
| 2827 if (innerHTML != null) { | |
| 2828 if (children != null) { | |
| 2829 throw new Error('Can only set one of `children` or `props.dangerouslySetInnerHTML`.'); | |
| 2830 } | |
| 2831 | |
| 2832 if (typeof innerHTML !== 'object' || !('__html' in innerHTML)) { | |
| 2833 throw new Error('`props.dangerouslySetInnerHTML` must be in the form `{__html: ...}`. ' + 'Please visit https://reactjs.org/link/dangerously-set-inner-html ' + 'for more information.'); | |
| 2834 } | |
| 2835 | |
| 2836 var html = innerHTML.__html; | |
| 2837 | |
| 2838 if (html !== null && html !== undefined) { | |
| 2839 if (typeof html === 'string' && html.length > 0 && html[0] === '\n') { | |
| 2840 target.push(leadingNewline, stringToChunk(html)); | |
| 2841 } else { | |
| 2842 { | |
| 2843 checkHtmlStringCoercion(html); | |
| 2844 } | |
| 2845 | |
| 2846 target.push(stringToChunk('' + html)); | |
| 2847 } | |
| 2848 } | |
| 2849 } | |
| 2850 | |
| 2851 if (typeof children === 'string' && children[0] === '\n') { | |
| 2852 target.push(leadingNewline); | |
| 2853 } | |
| 2854 | |
| 2855 return children; | |
| 2856 } // We accept any tag to be rendered but since this gets injected into arbitrary | |
| 2857 // HTML, we want to make sure that it's a safe tag. | |
| 2858 // http://www.w3.org/TR/REC-xml/#NT-Name | |
| 2859 | |
| 2860 | |
| 2861 var VALID_TAG_REGEX = /^[a-zA-Z][a-zA-Z:_\.\-\d]*$/; // Simplified subset | |
| 2862 | |
| 2863 var validatedTagCache = new Map(); | |
| 2864 | |
| 2865 function startChunkForTag(tag) { | |
| 2866 var tagStartChunk = validatedTagCache.get(tag); | |
| 2867 | |
| 2868 if (tagStartChunk === undefined) { | |
| 2869 if (!VALID_TAG_REGEX.test(tag)) { | |
| 2870 throw new Error("Invalid tag: " + tag); | |
| 2871 } | |
| 2872 | |
| 2873 tagStartChunk = stringToPrecomputedChunk('<' + tag); | |
| 2874 validatedTagCache.set(tag, tagStartChunk); | |
| 2875 } | |
| 2876 | |
| 2877 return tagStartChunk; | |
| 2878 } | |
| 2879 | |
| 2880 var DOCTYPE = stringToPrecomputedChunk('<!DOCTYPE html>'); | |
| 2881 function pushStartInstance(target, type, props, responseState, formatContext) { | |
| 2882 { | |
| 2883 validateProperties(type, props); | |
| 2884 validateProperties$1(type, props); | |
| 2885 validateProperties$2(type, props, null); | |
| 2886 | |
| 2887 if (!props.suppressContentEditableWarning && props.contentEditable && props.children != null) { | |
| 2888 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.'); | |
| 2889 } | |
| 2890 | |
| 2891 if (formatContext.insertionMode !== SVG_MODE && formatContext.insertionMode !== MATHML_MODE) { | |
| 2892 if (type.indexOf('-') === -1 && typeof props.is !== 'string' && type.toLowerCase() !== type) { | |
| 2893 error('<%s /> is using incorrect casing. ' + 'Use PascalCase for React components, ' + 'or lowercase for HTML elements.', type); | |
| 2894 } | |
| 2895 } | |
| 2896 } | |
| 2897 | |
| 2898 switch (type) { | |
| 2899 // Special tags | |
| 2900 case 'select': | |
| 2901 return pushStartSelect(target, props, responseState); | |
| 2902 | |
| 2903 case 'option': | |
| 2904 return pushStartOption(target, props, responseState, formatContext); | |
| 2905 | |
| 2906 case 'textarea': | |
| 2907 return pushStartTextArea(target, props, responseState); | |
| 2908 | |
| 2909 case 'input': | |
| 2910 return pushInput(target, props, responseState); | |
| 2911 | |
| 2912 case 'menuitem': | |
| 2913 return pushStartMenuItem(target, props, responseState); | |
| 2914 | |
| 2915 case 'title': | |
| 2916 return pushStartTitle(target, props, responseState); | |
| 2917 // Newline eating tags | |
| 2918 | |
| 2919 case 'listing': | |
| 2920 case 'pre': | |
| 2921 { | |
| 2922 return pushStartPreformattedElement(target, props, type, responseState); | |
| 2923 } | |
| 2924 // Omitted close tags | |
| 2925 | |
| 2926 case 'area': | |
| 2927 case 'base': | |
| 2928 case 'br': | |
| 2929 case 'col': | |
| 2930 case 'embed': | |
| 2931 case 'hr': | |
| 2932 case 'img': | |
| 2933 case 'keygen': | |
| 2934 case 'link': | |
| 2935 case 'meta': | |
| 2936 case 'param': | |
| 2937 case 'source': | |
| 2938 case 'track': | |
| 2939 case 'wbr': | |
| 2940 { | |
| 2941 return pushSelfClosing(target, props, type, responseState); | |
| 2942 } | |
| 2943 // These are reserved SVG and MathML elements, that are never custom elements. | |
| 2944 // https://w3c.github.io/webcomponents/spec/custom/#custom-elements-core-concepts | |
| 2945 | |
| 2946 case 'annotation-xml': | |
| 2947 case 'color-profile': | |
| 2948 case 'font-face': | |
| 2949 case 'font-face-src': | |
| 2950 case 'font-face-uri': | |
| 2951 case 'font-face-format': | |
| 2952 case 'font-face-name': | |
| 2953 case 'missing-glyph': | |
| 2954 { | |
| 2955 return pushStartGenericElement(target, props, type, responseState); | |
| 2956 } | |
| 2957 | |
| 2958 case 'html': | |
| 2959 { | |
| 2960 if (formatContext.insertionMode === ROOT_HTML_MODE) { | |
| 2961 // If we're rendering the html tag and we're at the root (i.e. not in foreignObject) | |
| 2962 // then we also emit the DOCTYPE as part of the root content as a convenience for | |
| 2963 // rendering the whole document. | |
| 2964 target.push(DOCTYPE); | |
| 2965 } | |
| 2966 | |
| 2967 return pushStartGenericElement(target, props, type, responseState); | |
| 2968 } | |
| 2969 | |
| 2970 default: | |
| 2971 { | |
| 2972 if (type.indexOf('-') === -1 && typeof props.is !== 'string') { | |
| 2973 // Generic element | |
| 2974 return pushStartGenericElement(target, props, type, responseState); | |
| 2975 } else { | |
| 2976 // Custom element | |
| 2977 return pushStartCustomElement(target, props, type, responseState); | |
| 2978 } | |
| 2979 } | |
| 2980 } | |
| 2981 } | |
| 2982 var endTag1 = stringToPrecomputedChunk('</'); | |
| 2983 var endTag2 = stringToPrecomputedChunk('>'); | |
| 2984 function pushEndInstance(target, type, props) { | |
| 2985 switch (type) { | |
| 2986 // Omitted close tags | |
| 2987 // TODO: Instead of repeating this switch we could try to pass a flag from above. | |
| 2988 // That would require returning a tuple. Which might be ok if it gets inlined. | |
| 2989 case 'area': | |
| 2990 case 'base': | |
| 2991 case 'br': | |
| 2992 case 'col': | |
| 2993 case 'embed': | |
| 2994 case 'hr': | |
| 2995 case 'img': | |
| 2996 case 'input': | |
| 2997 case 'keygen': | |
| 2998 case 'link': | |
| 2999 case 'meta': | |
| 3000 case 'param': | |
| 3001 case 'source': | |
| 3002 case 'track': | |
| 3003 case 'wbr': | |
| 3004 { | |
| 3005 // No close tag needed. | |
| 3006 break; | |
| 3007 } | |
| 3008 | |
| 3009 default: | |
| 3010 { | |
| 3011 target.push(endTag1, stringToChunk(type), endTag2); | |
| 3012 } | |
| 3013 } | |
| 3014 } | |
| 3015 function writeCompletedRoot(destination, responseState) { | |
| 3016 var bootstrapChunks = responseState.bootstrapChunks; | |
| 3017 var i = 0; | |
| 3018 | |
| 3019 for (; i < bootstrapChunks.length - 1; i++) { | |
| 3020 writeChunk(destination, bootstrapChunks[i]); | |
| 3021 } | |
| 3022 | |
| 3023 if (i < bootstrapChunks.length) { | |
| 3024 return writeChunkAndReturn(destination, bootstrapChunks[i]); | |
| 3025 } | |
| 3026 | |
| 3027 return true; | |
| 3028 } // Structural Nodes | |
| 3029 // A placeholder is a node inside a hidden partial tree that can be filled in later, but before | |
| 3030 // display. It's never visible to users. We use the template tag because it can be used in every | |
| 3031 // type of parent. <script> tags also work in every other tag except <colgroup>. | |
| 3032 | |
| 3033 var placeholder1 = stringToPrecomputedChunk('<template id="'); | |
| 3034 var placeholder2 = stringToPrecomputedChunk('"></template>'); | |
| 3035 function writePlaceholder(destination, responseState, id) { | |
| 3036 writeChunk(destination, placeholder1); | |
| 3037 writeChunk(destination, responseState.placeholderPrefix); | |
| 3038 var formattedID = stringToChunk(id.toString(16)); | |
| 3039 writeChunk(destination, formattedID); | |
| 3040 return writeChunkAndReturn(destination, placeholder2); | |
| 3041 } // Suspense boundaries are encoded as comments. | |
| 3042 | |
| 3043 var startCompletedSuspenseBoundary = stringToPrecomputedChunk('<!--$-->'); | |
| 3044 var startPendingSuspenseBoundary1 = stringToPrecomputedChunk('<!--$?--><template id="'); | |
| 3045 var startPendingSuspenseBoundary2 = stringToPrecomputedChunk('"></template>'); | |
| 3046 var startClientRenderedSuspenseBoundary = stringToPrecomputedChunk('<!--$!-->'); | |
| 3047 var endSuspenseBoundary = stringToPrecomputedChunk('<!--/$-->'); | |
| 3048 var clientRenderedSuspenseBoundaryError1 = stringToPrecomputedChunk('<template'); | |
| 3049 var clientRenderedSuspenseBoundaryErrorAttrInterstitial = stringToPrecomputedChunk('"'); | |
| 3050 var clientRenderedSuspenseBoundaryError1A = stringToPrecomputedChunk(' data-dgst="'); | |
| 3051 var clientRenderedSuspenseBoundaryError1B = stringToPrecomputedChunk(' data-msg="'); | |
| 3052 var clientRenderedSuspenseBoundaryError1C = stringToPrecomputedChunk(' data-stck="'); | |
| 3053 var clientRenderedSuspenseBoundaryError2 = stringToPrecomputedChunk('></template>'); | |
| 3054 function writeStartCompletedSuspenseBoundary(destination, responseState) { | |
| 3055 return writeChunkAndReturn(destination, startCompletedSuspenseBoundary); | |
| 3056 } | |
| 3057 function writeStartPendingSuspenseBoundary(destination, responseState, id) { | |
| 3058 writeChunk(destination, startPendingSuspenseBoundary1); | |
| 3059 | |
| 3060 if (id === null) { | |
| 3061 throw new Error('An ID must have been assigned before we can complete the boundary.'); | |
| 3062 } | |
| 3063 | |
| 3064 writeChunk(destination, id); | |
| 3065 return writeChunkAndReturn(destination, startPendingSuspenseBoundary2); | |
| 3066 } | |
| 3067 function writeStartClientRenderedSuspenseBoundary(destination, responseState, errorDigest, errorMesssage, errorComponentStack) { | |
| 3068 var result; | |
| 3069 result = writeChunkAndReturn(destination, startClientRenderedSuspenseBoundary); | |
| 3070 writeChunk(destination, clientRenderedSuspenseBoundaryError1); | |
| 3071 | |
| 3072 if (errorDigest) { | |
| 3073 writeChunk(destination, clientRenderedSuspenseBoundaryError1A); | |
| 3074 writeChunk(destination, stringToChunk(escapeTextForBrowser(errorDigest))); | |
| 3075 writeChunk(destination, clientRenderedSuspenseBoundaryErrorAttrInterstitial); | |
| 3076 } | |
| 3077 | |
| 3078 { | |
| 3079 if (errorMesssage) { | |
| 3080 writeChunk(destination, clientRenderedSuspenseBoundaryError1B); | |
| 3081 writeChunk(destination, stringToChunk(escapeTextForBrowser(errorMesssage))); | |
| 3082 writeChunk(destination, clientRenderedSuspenseBoundaryErrorAttrInterstitial); | |
| 3083 } | |
| 3084 | |
| 3085 if (errorComponentStack) { | |
| 3086 writeChunk(destination, clientRenderedSuspenseBoundaryError1C); | |
| 3087 writeChunk(destination, stringToChunk(escapeTextForBrowser(errorComponentStack))); | |
| 3088 writeChunk(destination, clientRenderedSuspenseBoundaryErrorAttrInterstitial); | |
| 3089 } | |
| 3090 } | |
| 3091 | |
| 3092 result = writeChunkAndReturn(destination, clientRenderedSuspenseBoundaryError2); | |
| 3093 return result; | |
| 3094 } | |
| 3095 function writeEndCompletedSuspenseBoundary(destination, responseState) { | |
| 3096 return writeChunkAndReturn(destination, endSuspenseBoundary); | |
| 3097 } | |
| 3098 function writeEndPendingSuspenseBoundary(destination, responseState) { | |
| 3099 return writeChunkAndReturn(destination, endSuspenseBoundary); | |
| 3100 } | |
| 3101 function writeEndClientRenderedSuspenseBoundary(destination, responseState) { | |
| 3102 return writeChunkAndReturn(destination, endSuspenseBoundary); | |
| 3103 } | |
| 3104 var startSegmentHTML = stringToPrecomputedChunk('<div hidden id="'); | |
| 3105 var startSegmentHTML2 = stringToPrecomputedChunk('">'); | |
| 3106 var endSegmentHTML = stringToPrecomputedChunk('</div>'); | |
| 3107 var startSegmentSVG = stringToPrecomputedChunk('<svg aria-hidden="true" style="display:none" id="'); | |
| 3108 var startSegmentSVG2 = stringToPrecomputedChunk('">'); | |
| 3109 var endSegmentSVG = stringToPrecomputedChunk('</svg>'); | |
| 3110 var startSegmentMathML = stringToPrecomputedChunk('<math aria-hidden="true" style="display:none" id="'); | |
| 3111 var startSegmentMathML2 = stringToPrecomputedChunk('">'); | |
| 3112 var endSegmentMathML = stringToPrecomputedChunk('</math>'); | |
| 3113 var startSegmentTable = stringToPrecomputedChunk('<table hidden id="'); | |
| 3114 var startSegmentTable2 = stringToPrecomputedChunk('">'); | |
| 3115 var endSegmentTable = stringToPrecomputedChunk('</table>'); | |
| 3116 var startSegmentTableBody = stringToPrecomputedChunk('<table hidden><tbody id="'); | |
| 3117 var startSegmentTableBody2 = stringToPrecomputedChunk('">'); | |
| 3118 var endSegmentTableBody = stringToPrecomputedChunk('</tbody></table>'); | |
| 3119 var startSegmentTableRow = stringToPrecomputedChunk('<table hidden><tr id="'); | |
| 3120 var startSegmentTableRow2 = stringToPrecomputedChunk('">'); | |
| 3121 var endSegmentTableRow = stringToPrecomputedChunk('</tr></table>'); | |
| 3122 var startSegmentColGroup = stringToPrecomputedChunk('<table hidden><colgroup id="'); | |
| 3123 var startSegmentColGroup2 = stringToPrecomputedChunk('">'); | |
| 3124 var endSegmentColGroup = stringToPrecomputedChunk('</colgroup></table>'); | |
| 3125 function writeStartSegment(destination, responseState, formatContext, id) { | |
| 3126 switch (formatContext.insertionMode) { | |
| 3127 case ROOT_HTML_MODE: | |
| 3128 case HTML_MODE: | |
| 3129 { | |
| 3130 writeChunk(destination, startSegmentHTML); | |
| 3131 writeChunk(destination, responseState.segmentPrefix); | |
| 3132 writeChunk(destination, stringToChunk(id.toString(16))); | |
| 3133 return writeChunkAndReturn(destination, startSegmentHTML2); | |
| 3134 } | |
| 3135 | |
| 3136 case SVG_MODE: | |
| 3137 { | |
| 3138 writeChunk(destination, startSegmentSVG); | |
| 3139 writeChunk(destination, responseState.segmentPrefix); | |
| 3140 writeChunk(destination, stringToChunk(id.toString(16))); | |
| 3141 return writeChunkAndReturn(destination, startSegmentSVG2); | |
| 3142 } | |
| 3143 | |
| 3144 case MATHML_MODE: | |
| 3145 { | |
| 3146 writeChunk(destination, startSegmentMathML); | |
| 3147 writeChunk(destination, responseState.segmentPrefix); | |
| 3148 writeChunk(destination, stringToChunk(id.toString(16))); | |
| 3149 return writeChunkAndReturn(destination, startSegmentMathML2); | |
| 3150 } | |
| 3151 | |
| 3152 case HTML_TABLE_MODE: | |
| 3153 { | |
| 3154 writeChunk(destination, startSegmentTable); | |
| 3155 writeChunk(destination, responseState.segmentPrefix); | |
| 3156 writeChunk(destination, stringToChunk(id.toString(16))); | |
| 3157 return writeChunkAndReturn(destination, startSegmentTable2); | |
| 3158 } | |
| 3159 // TODO: For the rest of these, there will be extra wrapper nodes that never | |
| 3160 // get deleted from the document. We need to delete the table too as part | |
| 3161 // of the injected scripts. They are invisible though so it's not too terrible | |
| 3162 // and it's kind of an edge case to suspend in a table. Totally supported though. | |
| 3163 | |
| 3164 case HTML_TABLE_BODY_MODE: | |
| 3165 { | |
| 3166 writeChunk(destination, startSegmentTableBody); | |
| 3167 writeChunk(destination, responseState.segmentPrefix); | |
| 3168 writeChunk(destination, stringToChunk(id.toString(16))); | |
| 3169 return writeChunkAndReturn(destination, startSegmentTableBody2); | |
| 3170 } | |
| 3171 | |
| 3172 case HTML_TABLE_ROW_MODE: | |
| 3173 { | |
| 3174 writeChunk(destination, startSegmentTableRow); | |
| 3175 writeChunk(destination, responseState.segmentPrefix); | |
| 3176 writeChunk(destination, stringToChunk(id.toString(16))); | |
| 3177 return writeChunkAndReturn(destination, startSegmentTableRow2); | |
| 3178 } | |
| 3179 | |
| 3180 case HTML_COLGROUP_MODE: | |
| 3181 { | |
| 3182 writeChunk(destination, startSegmentColGroup); | |
| 3183 writeChunk(destination, responseState.segmentPrefix); | |
| 3184 writeChunk(destination, stringToChunk(id.toString(16))); | |
| 3185 return writeChunkAndReturn(destination, startSegmentColGroup2); | |
| 3186 } | |
| 3187 | |
| 3188 default: | |
| 3189 { | |
| 3190 throw new Error('Unknown insertion mode. This is a bug in React.'); | |
| 3191 } | |
| 3192 } | |
| 3193 } | |
| 3194 function writeEndSegment(destination, formatContext) { | |
| 3195 switch (formatContext.insertionMode) { | |
| 3196 case ROOT_HTML_MODE: | |
| 3197 case HTML_MODE: | |
| 3198 { | |
| 3199 return writeChunkAndReturn(destination, endSegmentHTML); | |
| 3200 } | |
| 3201 | |
| 3202 case SVG_MODE: | |
| 3203 { | |
| 3204 return writeChunkAndReturn(destination, endSegmentSVG); | |
| 3205 } | |
| 3206 | |
| 3207 case MATHML_MODE: | |
| 3208 { | |
| 3209 return writeChunkAndReturn(destination, endSegmentMathML); | |
| 3210 } | |
| 3211 | |
| 3212 case HTML_TABLE_MODE: | |
| 3213 { | |
| 3214 return writeChunkAndReturn(destination, endSegmentTable); | |
| 3215 } | |
| 3216 | |
| 3217 case HTML_TABLE_BODY_MODE: | |
| 3218 { | |
| 3219 return writeChunkAndReturn(destination, endSegmentTableBody); | |
| 3220 } | |
| 3221 | |
| 3222 case HTML_TABLE_ROW_MODE: | |
| 3223 { | |
| 3224 return writeChunkAndReturn(destination, endSegmentTableRow); | |
| 3225 } | |
| 3226 | |
| 3227 case HTML_COLGROUP_MODE: | |
| 3228 { | |
| 3229 return writeChunkAndReturn(destination, endSegmentColGroup); | |
| 3230 } | |
| 3231 | |
| 3232 default: | |
| 3233 { | |
| 3234 throw new Error('Unknown insertion mode. This is a bug in React.'); | |
| 3235 } | |
| 3236 } | |
| 3237 } // Instruction Set | |
| 3238 // The following code is the source scripts that we then minify and inline below, | |
| 3239 // with renamed function names that we hope don't collide: | |
| 3240 // const COMMENT_NODE = 8; | |
| 3241 // const SUSPENSE_START_DATA = '$'; | |
| 3242 // const SUSPENSE_END_DATA = '/$'; | |
| 3243 // const SUSPENSE_PENDING_START_DATA = '$?'; | |
| 3244 // const SUSPENSE_FALLBACK_START_DATA = '$!'; | |
| 3245 // | |
| 3246 // function clientRenderBoundary(suspenseBoundaryID, errorDigest, errorMsg, errorComponentStack) { | |
| 3247 // // Find the fallback's first element. | |
| 3248 // const suspenseIdNode = document.getElementById(suspenseBoundaryID); | |
| 3249 // if (!suspenseIdNode) { | |
| 3250 // // The user must have already navigated away from this tree. | |
| 3251 // // E.g. because the parent was hydrated. | |
| 3252 // return; | |
| 3253 // } | |
| 3254 // // Find the boundary around the fallback. This is always the previous node. | |
| 3255 // const suspenseNode = suspenseIdNode.previousSibling; | |
| 3256 // // Tag it to be client rendered. | |
| 3257 // suspenseNode.data = SUSPENSE_FALLBACK_START_DATA; | |
| 3258 // // assign error metadata to first sibling | |
| 3259 // let dataset = suspenseIdNode.dataset; | |
| 3260 // if (errorDigest) dataset.dgst = errorDigest; | |
| 3261 // if (errorMsg) dataset.msg = errorMsg; | |
| 3262 // if (errorComponentStack) dataset.stck = errorComponentStack; | |
| 3263 // // Tell React to retry it if the parent already hydrated. | |
| 3264 // if (suspenseNode._reactRetry) { | |
| 3265 // suspenseNode._reactRetry(); | |
| 3266 // } | |
| 3267 // } | |
| 3268 // | |
| 3269 // function completeBoundary(suspenseBoundaryID, contentID) { | |
| 3270 // // Find the fallback's first element. | |
| 3271 // const suspenseIdNode = document.getElementById(suspenseBoundaryID); | |
| 3272 // const contentNode = document.getElementById(contentID); | |
| 3273 // // We'll detach the content node so that regardless of what happens next we don't leave in the tree. | |
| 3274 // // This might also help by not causing recalcing each time we move a child from here to the target. | |
| 3275 // contentNode.parentNode.removeChild(contentNode); | |
| 3276 // if (!suspenseIdNode) { | |
| 3277 // // The user must have already navigated away from this tree. | |
| 3278 // // E.g. because the parent was hydrated. That's fine there's nothing to do | |
| 3279 // // but we have to make sure that we already deleted the container node. | |
| 3280 // return; | |
| 3281 // } | |
| 3282 // // Find the boundary around the fallback. This is always the previous node. | |
| 3283 // const suspenseNode = suspenseIdNode.previousSibling; | |
| 3284 // | |
| 3285 // // Clear all the existing children. This is complicated because | |
| 3286 // // there can be embedded Suspense boundaries in the fallback. | |
| 3287 // // This is similar to clearSuspenseBoundary in ReactDOMHostConfig. | |
| 3288 // // TODO: We could avoid this if we never emitted suspense boundaries in fallback trees. | |
| 3289 // // They never hydrate anyway. However, currently we support incrementally loading the fallback. | |
| 3290 // const parentInstance = suspenseNode.parentNode; | |
| 3291 // let node = suspenseNode.nextSibling; | |
| 3292 // let depth = 0; | |
| 3293 // do { | |
| 3294 // if (node && node.nodeType === COMMENT_NODE) { | |
| 3295 // const data = node.data; | |
| 3296 // if (data === SUSPENSE_END_DATA) { | |
| 3297 // if (depth === 0) { | |
| 3298 // break; | |
| 3299 // } else { | |
| 3300 // depth--; | |
| 3301 // } | |
| 3302 // } else if ( | |
| 3303 // data === SUSPENSE_START_DATA || | |
| 3304 // data === SUSPENSE_PENDING_START_DATA || | |
| 3305 // data === SUSPENSE_FALLBACK_START_DATA | |
| 3306 // ) { | |
| 3307 // depth++; | |
| 3308 // } | |
| 3309 // } | |
| 3310 // | |
| 3311 // const nextNode = node.nextSibling; | |
| 3312 // parentInstance.removeChild(node); | |
| 3313 // node = nextNode; | |
| 3314 // } while (node); | |
| 3315 // | |
| 3316 // const endOfBoundary = node; | |
| 3317 // | |
| 3318 // // Insert all the children from the contentNode between the start and end of suspense boundary. | |
| 3319 // while (contentNode.firstChild) { | |
| 3320 // parentInstance.insertBefore(contentNode.firstChild, endOfBoundary); | |
| 3321 // } | |
| 3322 // suspenseNode.data = SUSPENSE_START_DATA; | |
| 3323 // if (suspenseNode._reactRetry) { | |
| 3324 // suspenseNode._reactRetry(); | |
| 3325 // } | |
| 3326 // } | |
| 3327 // | |
| 3328 // function completeSegment(containerID, placeholderID) { | |
| 3329 // const segmentContainer = document.getElementById(containerID); | |
| 3330 // const placeholderNode = document.getElementById(placeholderID); | |
| 3331 // // We always expect both nodes to exist here because, while we might | |
| 3332 // // have navigated away from the main tree, we still expect the detached | |
| 3333 // // tree to exist. | |
| 3334 // segmentContainer.parentNode.removeChild(segmentContainer); | |
| 3335 // while (segmentContainer.firstChild) { | |
| 3336 // placeholderNode.parentNode.insertBefore( | |
| 3337 // segmentContainer.firstChild, | |
| 3338 // placeholderNode, | |
| 3339 // ); | |
| 3340 // } | |
| 3341 // placeholderNode.parentNode.removeChild(placeholderNode); | |
| 3342 // } | |
| 3343 | |
| 3344 var completeSegmentFunction = 'function $RS(a,b){a=document.getElementById(a);b=document.getElementById(b);for(a.parentNode.removeChild(a);a.firstChild;)b.parentNode.insertBefore(a.firstChild,b);b.parentNode.removeChild(b)}'; | |
| 3345 var completeBoundaryFunction = 'function $RC(a,b){a=document.getElementById(a);b=document.getElementById(b);b.parentNode.removeChild(b);if(a){a=a.previousSibling;var f=a.parentNode,c=a.nextSibling,e=0;do{if(c&&8===c.nodeType){var d=c.data;if("/$"===d)if(0===e)break;else e--;else"$"!==d&&"$?"!==d&&"$!"!==d||e++}d=c.nextSibling;f.removeChild(c);c=d}while(c);for(;b.firstChild;)f.insertBefore(b.firstChild,c);a.data="$";a._reactRetry&&a._reactRetry()}}'; | |
| 3346 var clientRenderFunction = 'function $RX(b,c,d,e){var a=document.getElementById(b);a&&(b=a.previousSibling,b.data="$!",a=a.dataset,c&&(a.dgst=c),d&&(a.msg=d),e&&(a.stck=e),b._reactRetry&&b._reactRetry())}'; | |
| 3347 var completeSegmentScript1Full = stringToPrecomputedChunk(completeSegmentFunction + ';$RS("'); | |
| 3348 var completeSegmentScript1Partial = stringToPrecomputedChunk('$RS("'); | |
| 3349 var completeSegmentScript2 = stringToPrecomputedChunk('","'); | |
| 3350 var completeSegmentScript3 = stringToPrecomputedChunk('")</script>'); | |
| 3351 function writeCompletedSegmentInstruction(destination, responseState, contentSegmentID) { | |
| 3352 writeChunk(destination, responseState.startInlineScript); | |
| 3353 | |
| 3354 if (!responseState.sentCompleteSegmentFunction) { | |
| 3355 // The first time we write this, we'll need to include the full implementation. | |
| 3356 responseState.sentCompleteSegmentFunction = true; | |
| 3357 writeChunk(destination, completeSegmentScript1Full); | |
| 3358 } else { | |
| 3359 // Future calls can just reuse the same function. | |
| 3360 writeChunk(destination, completeSegmentScript1Partial); | |
| 3361 } | |
| 3362 | |
| 3363 writeChunk(destination, responseState.segmentPrefix); | |
| 3364 var formattedID = stringToChunk(contentSegmentID.toString(16)); | |
| 3365 writeChunk(destination, formattedID); | |
| 3366 writeChunk(destination, completeSegmentScript2); | |
| 3367 writeChunk(destination, responseState.placeholderPrefix); | |
| 3368 writeChunk(destination, formattedID); | |
| 3369 return writeChunkAndReturn(destination, completeSegmentScript3); | |
| 3370 } | |
| 3371 var completeBoundaryScript1Full = stringToPrecomputedChunk(completeBoundaryFunction + ';$RC("'); | |
| 3372 var completeBoundaryScript1Partial = stringToPrecomputedChunk('$RC("'); | |
| 3373 var completeBoundaryScript2 = stringToPrecomputedChunk('","'); | |
| 3374 var completeBoundaryScript3 = stringToPrecomputedChunk('")</script>'); | |
| 3375 function writeCompletedBoundaryInstruction(destination, responseState, boundaryID, contentSegmentID) { | |
| 3376 writeChunk(destination, responseState.startInlineScript); | |
| 3377 | |
| 3378 if (!responseState.sentCompleteBoundaryFunction) { | |
| 3379 // The first time we write this, we'll need to include the full implementation. | |
| 3380 responseState.sentCompleteBoundaryFunction = true; | |
| 3381 writeChunk(destination, completeBoundaryScript1Full); | |
| 3382 } else { | |
| 3383 // Future calls can just reuse the same function. | |
| 3384 writeChunk(destination, completeBoundaryScript1Partial); | |
| 3385 } | |
| 3386 | |
| 3387 if (boundaryID === null) { | |
| 3388 throw new Error('An ID must have been assigned before we can complete the boundary.'); | |
| 3389 } | |
| 3390 | |
| 3391 var formattedContentID = stringToChunk(contentSegmentID.toString(16)); | |
| 3392 writeChunk(destination, boundaryID); | |
| 3393 writeChunk(destination, completeBoundaryScript2); | |
| 3394 writeChunk(destination, responseState.segmentPrefix); | |
| 3395 writeChunk(destination, formattedContentID); | |
| 3396 return writeChunkAndReturn(destination, completeBoundaryScript3); | |
| 3397 } | |
| 3398 var clientRenderScript1Full = stringToPrecomputedChunk(clientRenderFunction + ';$RX("'); | |
| 3399 var clientRenderScript1Partial = stringToPrecomputedChunk('$RX("'); | |
| 3400 var clientRenderScript1A = stringToPrecomputedChunk('"'); | |
| 3401 var clientRenderScript2 = stringToPrecomputedChunk(')</script>'); | |
| 3402 var clientRenderErrorScriptArgInterstitial = stringToPrecomputedChunk(','); | |
| 3403 function writeClientRenderBoundaryInstruction(destination, responseState, boundaryID, errorDigest, errorMessage, errorComponentStack) { | |
| 3404 writeChunk(destination, responseState.startInlineScript); | |
| 3405 | |
| 3406 if (!responseState.sentClientRenderFunction) { | |
| 3407 // The first time we write this, we'll need to include the full implementation. | |
| 3408 responseState.sentClientRenderFunction = true; | |
| 3409 writeChunk(destination, clientRenderScript1Full); | |
| 3410 } else { | |
| 3411 // Future calls can just reuse the same function. | |
| 3412 writeChunk(destination, clientRenderScript1Partial); | |
| 3413 } | |
| 3414 | |
| 3415 if (boundaryID === null) { | |
| 3416 throw new Error('An ID must have been assigned before we can complete the boundary.'); | |
| 3417 } | |
| 3418 | |
| 3419 writeChunk(destination, boundaryID); | |
| 3420 writeChunk(destination, clientRenderScript1A); | |
| 3421 | |
| 3422 if (errorDigest || errorMessage || errorComponentStack) { | |
| 3423 writeChunk(destination, clientRenderErrorScriptArgInterstitial); | |
| 3424 writeChunk(destination, stringToChunk(escapeJSStringsForInstructionScripts(errorDigest || ''))); | |
| 3425 } | |
| 3426 | |
| 3427 if (errorMessage || errorComponentStack) { | |
| 3428 writeChunk(destination, clientRenderErrorScriptArgInterstitial); | |
| 3429 writeChunk(destination, stringToChunk(escapeJSStringsForInstructionScripts(errorMessage || ''))); | |
| 3430 } | |
| 3431 | |
| 3432 if (errorComponentStack) { | |
| 3433 writeChunk(destination, clientRenderErrorScriptArgInterstitial); | |
| 3434 writeChunk(destination, stringToChunk(escapeJSStringsForInstructionScripts(errorComponentStack))); | |
| 3435 } | |
| 3436 | |
| 3437 return writeChunkAndReturn(destination, clientRenderScript2); | |
| 3438 } | |
| 3439 var regexForJSStringsInScripts = /[<\u2028\u2029]/g; | |
| 3440 | |
| 3441 function escapeJSStringsForInstructionScripts(input) { | |
| 3442 var escaped = JSON.stringify(input); | |
| 3443 return escaped.replace(regexForJSStringsInScripts, function (match) { | |
| 3444 switch (match) { | |
| 3445 // santizing breaking out of strings and script tags | |
| 3446 case '<': | |
| 3447 return "\\u003c"; | |
| 3448 | |
| 3449 case "\u2028": | |
| 3450 return "\\u2028"; | |
| 3451 | |
| 3452 case "\u2029": | |
| 3453 return "\\u2029"; | |
| 3454 | |
| 3455 default: | |
| 3456 { | |
| 3457 // eslint-disable-next-line react-internal/prod-error-codes | |
| 3458 throw new Error('escapeJSStringsForInstructionScripts encountered a match it does not know how to replace. this means the match regex and the replacement characters are no longer in sync. This is a bug in React'); | |
| 3459 } | |
| 3460 } | |
| 3461 }); | |
| 3462 } | |
| 3463 | |
| 3464 var assign = Object.assign; | |
| 3465 | |
| 3466 // ATTENTION | |
| 3467 // When adding new symbols to this file, | |
| 3468 // Please consider also adding to 'react-devtools-shared/src/backend/ReactSymbols' | |
| 3469 // The Symbol used to tag the ReactElement-like types. | |
| 3470 var REACT_ELEMENT_TYPE = Symbol.for('react.element'); | |
| 3471 var REACT_PORTAL_TYPE = Symbol.for('react.portal'); | |
| 3472 var REACT_FRAGMENT_TYPE = Symbol.for('react.fragment'); | |
| 3473 var REACT_STRICT_MODE_TYPE = Symbol.for('react.strict_mode'); | |
| 3474 var REACT_PROFILER_TYPE = Symbol.for('react.profiler'); | |
| 3475 var REACT_PROVIDER_TYPE = Symbol.for('react.provider'); | |
| 3476 var REACT_CONTEXT_TYPE = Symbol.for('react.context'); | |
| 3477 var REACT_FORWARD_REF_TYPE = Symbol.for('react.forward_ref'); | |
| 3478 var REACT_SUSPENSE_TYPE = Symbol.for('react.suspense'); | |
| 3479 var REACT_SUSPENSE_LIST_TYPE = Symbol.for('react.suspense_list'); | |
| 3480 var REACT_MEMO_TYPE = Symbol.for('react.memo'); | |
| 3481 var REACT_LAZY_TYPE = Symbol.for('react.lazy'); | |
| 3482 var REACT_SCOPE_TYPE = Symbol.for('react.scope'); | |
| 3483 var REACT_DEBUG_TRACING_MODE_TYPE = Symbol.for('react.debug_trace_mode'); | |
| 3484 var REACT_LEGACY_HIDDEN_TYPE = Symbol.for('react.legacy_hidden'); | |
| 3485 var REACT_SERVER_CONTEXT_DEFAULT_VALUE_NOT_LOADED = Symbol.for('react.default_value'); | |
| 3486 var MAYBE_ITERATOR_SYMBOL = Symbol.iterator; | |
| 3487 var FAUX_ITERATOR_SYMBOL = '@@iterator'; | |
| 3488 function getIteratorFn(maybeIterable) { | |
| 3489 if (maybeIterable === null || typeof maybeIterable !== 'object') { | |
| 3490 return null; | |
| 3491 } | |
| 3492 | |
| 3493 var maybeIterator = MAYBE_ITERATOR_SYMBOL && maybeIterable[MAYBE_ITERATOR_SYMBOL] || maybeIterable[FAUX_ITERATOR_SYMBOL]; | |
| 3494 | |
| 3495 if (typeof maybeIterator === 'function') { | |
| 3496 return maybeIterator; | |
| 3497 } | |
| 3498 | |
| 3499 return null; | |
| 3500 } | |
| 3501 | |
| 3502 function getWrappedName(outerType, innerType, wrapperName) { | |
| 3503 var displayName = outerType.displayName; | |
| 3504 | |
| 3505 if (displayName) { | |
| 3506 return displayName; | |
| 3507 } | |
| 3508 | |
| 3509 var functionName = innerType.displayName || innerType.name || ''; | |
| 3510 return functionName !== '' ? wrapperName + "(" + functionName + ")" : wrapperName; | |
| 3511 } // Keep in sync with react-reconciler/getComponentNameFromFiber | |
| 3512 | |
| 3513 | |
| 3514 function getContextName(type) { | |
| 3515 return type.displayName || 'Context'; | |
| 3516 } // Note that the reconciler package should generally prefer to use getComponentNameFromFiber() instead. | |
| 3517 | |
| 3518 | |
| 3519 function getComponentNameFromType(type) { | |
| 3520 if (type == null) { | |
| 3521 // Host root, text node or just invalid type. | |
| 3522 return null; | |
| 3523 } | |
| 3524 | |
| 3525 { | |
| 3526 if (typeof type.tag === 'number') { | |
| 3527 error('Received an unexpected object in getComponentNameFromType(). ' + 'This is likely a bug in React. Please file an issue.'); | |
| 3528 } | |
| 3529 } | |
| 3530 | |
| 3531 if (typeof type === 'function') { | |
| 3532 return type.displayName || type.name || null; | |
| 3533 } | |
| 3534 | |
| 3535 if (typeof type === 'string') { | |
| 3536 return type; | |
| 3537 } | |
| 3538 | |
| 3539 switch (type) { | |
| 3540 case REACT_FRAGMENT_TYPE: | |
| 3541 return 'Fragment'; | |
| 3542 | |
| 3543 case REACT_PORTAL_TYPE: | |
| 3544 return 'Portal'; | |
| 3545 | |
| 3546 case REACT_PROFILER_TYPE: | |
| 3547 return 'Profiler'; | |
| 3548 | |
| 3549 case REACT_STRICT_MODE_TYPE: | |
| 3550 return 'StrictMode'; | |
| 3551 | |
| 3552 case REACT_SUSPENSE_TYPE: | |
| 3553 return 'Suspense'; | |
| 3554 | |
| 3555 case REACT_SUSPENSE_LIST_TYPE: | |
| 3556 return 'SuspenseList'; | |
| 3557 | |
| 3558 } | |
| 3559 | |
| 3560 if (typeof type === 'object') { | |
| 3561 switch (type.$$typeof) { | |
| 3562 case REACT_CONTEXT_TYPE: | |
| 3563 var context = type; | |
| 3564 return getContextName(context) + '.Consumer'; | |
| 3565 | |
| 3566 case REACT_PROVIDER_TYPE: | |
| 3567 var provider = type; | |
| 3568 return getContextName(provider._context) + '.Provider'; | |
| 3569 | |
| 3570 case REACT_FORWARD_REF_TYPE: | |
| 3571 return getWrappedName(type, type.render, 'ForwardRef'); | |
| 3572 | |
| 3573 case REACT_MEMO_TYPE: | |
| 3574 var outerName = type.displayName || null; | |
| 3575 | |
| 3576 if (outerName !== null) { | |
| 3577 return outerName; | |
| 3578 } | |
| 3579 | |
| 3580 return getComponentNameFromType(type.type) || 'Memo'; | |
| 3581 | |
| 3582 case REACT_LAZY_TYPE: | |
| 3583 { | |
| 3584 var lazyComponent = type; | |
| 3585 var payload = lazyComponent._payload; | |
| 3586 var init = lazyComponent._init; | |
| 3587 | |
| 3588 try { | |
| 3589 return getComponentNameFromType(init(payload)); | |
| 3590 } catch (x) { | |
| 3591 return null; | |
| 3592 } | |
| 3593 } | |
| 3594 | |
| 3595 // eslint-disable-next-line no-fallthrough | |
| 3596 } | |
| 3597 } | |
| 3598 | |
| 3599 return null; | |
| 3600 } | |
| 3601 | |
| 3602 // Helpers to patch console.logs to avoid logging during side-effect free | |
| 3603 // replaying on render function. This currently only patches the object | |
| 3604 // lazily which won't cover if the log function was extracted eagerly. | |
| 3605 // We could also eagerly patch the method. | |
| 3606 var disabledDepth = 0; | |
| 3607 var prevLog; | |
| 3608 var prevInfo; | |
| 3609 var prevWarn; | |
| 3610 var prevError; | |
| 3611 var prevGroup; | |
| 3612 var prevGroupCollapsed; | |
| 3613 var prevGroupEnd; | |
| 3614 | |
| 3615 function disabledLog() {} | |
| 3616 | |
| 3617 disabledLog.__reactDisabledLog = true; | |
| 3618 function disableLogs() { | |
| 3619 { | |
| 3620 if (disabledDepth === 0) { | |
| 3621 /* eslint-disable react-internal/no-production-logging */ | |
| 3622 prevLog = console.log; | |
| 3623 prevInfo = console.info; | |
| 3624 prevWarn = console.warn; | |
| 3625 prevError = console.error; | |
| 3626 prevGroup = console.group; | |
| 3627 prevGroupCollapsed = console.groupCollapsed; | |
| 3628 prevGroupEnd = console.groupEnd; // https://github.com/facebook/react/issues/19099 | |
| 3629 | |
| 3630 var props = { | |
| 3631 configurable: true, | |
| 3632 enumerable: true, | |
| 3633 value: disabledLog, | |
| 3634 writable: true | |
| 3635 }; // $FlowFixMe Flow thinks console is immutable. | |
| 3636 | |
| 3637 Object.defineProperties(console, { | |
| 3638 info: props, | |
| 3639 log: props, | |
| 3640 warn: props, | |
| 3641 error: props, | |
| 3642 group: props, | |
| 3643 groupCollapsed: props, | |
| 3644 groupEnd: props | |
| 3645 }); | |
| 3646 /* eslint-enable react-internal/no-production-logging */ | |
| 3647 } | |
| 3648 | |
| 3649 disabledDepth++; | |
| 3650 } | |
| 3651 } | |
| 3652 function reenableLogs() { | |
| 3653 { | |
| 3654 disabledDepth--; | |
| 3655 | |
| 3656 if (disabledDepth === 0) { | |
| 3657 /* eslint-disable react-internal/no-production-logging */ | |
| 3658 var props = { | |
| 3659 configurable: true, | |
| 3660 enumerable: true, | |
| 3661 writable: true | |
| 3662 }; // $FlowFixMe Flow thinks console is immutable. | |
| 3663 | |
| 3664 Object.defineProperties(console, { | |
| 3665 log: assign({}, props, { | |
| 3666 value: prevLog | |
| 3667 }), | |
| 3668 info: assign({}, props, { | |
| 3669 value: prevInfo | |
| 3670 }), | |
| 3671 warn: assign({}, props, { | |
| 3672 value: prevWarn | |
| 3673 }), | |
| 3674 error: assign({}, props, { | |
| 3675 value: prevError | |
| 3676 }), | |
| 3677 group: assign({}, props, { | |
| 3678 value: prevGroup | |
| 3679 }), | |
| 3680 groupCollapsed: assign({}, props, { | |
| 3681 value: prevGroupCollapsed | |
| 3682 }), | |
| 3683 groupEnd: assign({}, props, { | |
| 3684 value: prevGroupEnd | |
| 3685 }) | |
| 3686 }); | |
| 3687 /* eslint-enable react-internal/no-production-logging */ | |
| 3688 } | |
| 3689 | |
| 3690 if (disabledDepth < 0) { | |
| 3691 error('disabledDepth fell below zero. ' + 'This is a bug in React. Please file an issue.'); | |
| 3692 } | |
| 3693 } | |
| 3694 } | |
| 3695 | |
| 3696 var ReactCurrentDispatcher = ReactSharedInternals.ReactCurrentDispatcher; | |
| 3697 var prefix; | |
| 3698 function describeBuiltInComponentFrame(name, source, ownerFn) { | |
| 3699 { | |
| 3700 if (prefix === undefined) { | |
| 3701 // Extract the VM specific prefix used by each line. | |
| 3702 try { | |
| 3703 throw Error(); | |
| 3704 } catch (x) { | |
| 3705 var match = x.stack.trim().match(/\n( *(at )?)/); | |
| 3706 prefix = match && match[1] || ''; | |
| 3707 } | |
| 3708 } // We use the prefix to ensure our stacks line up with native stack frames. | |
| 3709 | |
| 3710 | |
| 3711 return '\n' + prefix + name; | |
| 3712 } | |
| 3713 } | |
| 3714 var reentry = false; | |
| 3715 var componentFrameCache; | |
| 3716 | |
| 3717 { | |
| 3718 var PossiblyWeakMap = typeof WeakMap === 'function' ? WeakMap : Map; | |
| 3719 componentFrameCache = new PossiblyWeakMap(); | |
| 3720 } | |
| 3721 | |
| 3722 function describeNativeComponentFrame(fn, construct) { | |
| 3723 // If something asked for a stack inside a fake render, it should get ignored. | |
| 3724 if ( !fn || reentry) { | |
| 3725 return ''; | |
| 3726 } | |
| 3727 | |
| 3728 { | |
| 3729 var frame = componentFrameCache.get(fn); | |
| 3730 | |
| 3731 if (frame !== undefined) { | |
| 3732 return frame; | |
| 3733 } | |
| 3734 } | |
| 3735 | |
| 3736 var control; | |
| 3737 reentry = true; | |
| 3738 var previousPrepareStackTrace = Error.prepareStackTrace; // $FlowFixMe It does accept undefined. | |
| 3739 | |
| 3740 Error.prepareStackTrace = undefined; | |
| 3741 var previousDispatcher; | |
| 3742 | |
| 3743 { | |
| 3744 previousDispatcher = ReactCurrentDispatcher.current; // Set the dispatcher in DEV because this might be call in the render function | |
| 3745 // for warnings. | |
| 3746 | |
| 3747 ReactCurrentDispatcher.current = null; | |
| 3748 disableLogs(); | |
| 3749 } | |
| 3750 | |
| 3751 try { | |
| 3752 // This should throw. | |
| 3753 if (construct) { | |
| 3754 // Something should be setting the props in the constructor. | |
| 3755 var Fake = function () { | |
| 3756 throw Error(); | |
| 3757 }; // $FlowFixMe | |
| 3758 | |
| 3759 | |
| 3760 Object.defineProperty(Fake.prototype, 'props', { | |
| 3761 set: function () { | |
| 3762 // We use a throwing setter instead of frozen or non-writable props | |
| 3763 // because that won't throw in a non-strict mode function. | |
| 3764 throw Error(); | |
| 3765 } | |
| 3766 }); | |
| 3767 | |
| 3768 if (typeof Reflect === 'object' && Reflect.construct) { | |
| 3769 // We construct a different control for this case to include any extra | |
| 3770 // frames added by the construct call. | |
| 3771 try { | |
| 3772 Reflect.construct(Fake, []); | |
| 3773 } catch (x) { | |
| 3774 control = x; | |
| 3775 } | |
| 3776 | |
| 3777 Reflect.construct(fn, [], Fake); | |
| 3778 } else { | |
| 3779 try { | |
| 3780 Fake.call(); | |
| 3781 } catch (x) { | |
| 3782 control = x; | |
| 3783 } | |
| 3784 | |
| 3785 fn.call(Fake.prototype); | |
| 3786 } | |
| 3787 } else { | |
| 3788 try { | |
| 3789 throw Error(); | |
| 3790 } catch (x) { | |
| 3791 control = x; | |
| 3792 } | |
| 3793 | |
| 3794 fn(); | |
| 3795 } | |
| 3796 } catch (sample) { | |
| 3797 // This is inlined manually because closure doesn't do it for us. | |
| 3798 if (sample && control && typeof sample.stack === 'string') { | |
| 3799 // This extracts the first frame from the sample that isn't also in the control. | |
| 3800 // Skipping one frame that we assume is the frame that calls the two. | |
| 3801 var sampleLines = sample.stack.split('\n'); | |
| 3802 var controlLines = control.stack.split('\n'); | |
| 3803 var s = sampleLines.length - 1; | |
| 3804 var c = controlLines.length - 1; | |
| 3805 | |
| 3806 while (s >= 1 && c >= 0 && sampleLines[s] !== controlLines[c]) { | |
| 3807 // We expect at least one stack frame to be shared. | |
| 3808 // Typically this will be the root most one. However, stack frames may be | |
| 3809 // cut off due to maximum stack limits. In this case, one maybe cut off | |
| 3810 // earlier than the other. We assume that the sample is longer or the same | |
| 3811 // and there for cut off earlier. So we should find the root most frame in | |
| 3812 // the sample somewhere in the control. | |
| 3813 c--; | |
| 3814 } | |
| 3815 | |
| 3816 for (; s >= 1 && c >= 0; s--, c--) { | |
| 3817 // Next we find the first one that isn't the same which should be the | |
| 3818 // frame that called our sample function and the control. | |
| 3819 if (sampleLines[s] !== controlLines[c]) { | |
| 3820 // In V8, the first line is describing the message but other VMs don't. | |
| 3821 // If we're about to return the first line, and the control is also on the same | |
| 3822 // line, that's a pretty good indicator that our sample threw at same line as | |
| 3823 // the control. I.e. before we entered the sample frame. So we ignore this result. | |
| 3824 // This can happen if you passed a class to function component, or non-function. | |
| 3825 if (s !== 1 || c !== 1) { | |
| 3826 do { | |
| 3827 s--; | |
| 3828 c--; // We may still have similar intermediate frames from the construct call. | |
| 3829 // The next one that isn't the same should be our match though. | |
| 3830 | |
| 3831 if (c < 0 || sampleLines[s] !== controlLines[c]) { | |
| 3832 // V8 adds a "new" prefix for native classes. Let's remove it to make it prettier. | |
| 3833 var _frame = '\n' + sampleLines[s].replace(' at new ', ' at '); // If our component frame is labeled "<anonymous>" | |
| 3834 // but we have a user-provided "displayName" | |
| 3835 // splice it in to make the stack more readable. | |
| 3836 | |
| 3837 | |
| 3838 if (fn.displayName && _frame.includes('<anonymous>')) { | |
| 3839 _frame = _frame.replace('<anonymous>', fn.displayName); | |
| 3840 } | |
| 3841 | |
| 3842 { | |
| 3843 if (typeof fn === 'function') { | |
| 3844 componentFrameCache.set(fn, _frame); | |
| 3845 } | |
| 3846 } // Return the line we found. | |
| 3847 | |
| 3848 | |
| 3849 return _frame; | |
| 3850 } | |
| 3851 } while (s >= 1 && c >= 0); | |
| 3852 } | |
| 3853 | |
| 3854 break; | |
| 3855 } | |
| 3856 } | |
| 3857 } | |
| 3858 } finally { | |
| 3859 reentry = false; | |
| 3860 | |
| 3861 { | |
| 3862 ReactCurrentDispatcher.current = previousDispatcher; | |
| 3863 reenableLogs(); | |
| 3864 } | |
| 3865 | |
| 3866 Error.prepareStackTrace = previousPrepareStackTrace; | |
| 3867 } // Fallback to just using the name if we couldn't make it throw. | |
| 3868 | |
| 3869 | |
| 3870 var name = fn ? fn.displayName || fn.name : ''; | |
| 3871 var syntheticFrame = name ? describeBuiltInComponentFrame(name) : ''; | |
| 3872 | |
| 3873 { | |
| 3874 if (typeof fn === 'function') { | |
| 3875 componentFrameCache.set(fn, syntheticFrame); | |
| 3876 } | |
| 3877 } | |
| 3878 | |
| 3879 return syntheticFrame; | |
| 3880 } | |
| 3881 | |
| 3882 function describeClassComponentFrame(ctor, source, ownerFn) { | |
| 3883 { | |
| 3884 return describeNativeComponentFrame(ctor, true); | |
| 3885 } | |
| 3886 } | |
| 3887 function describeFunctionComponentFrame(fn, source, ownerFn) { | |
| 3888 { | |
| 3889 return describeNativeComponentFrame(fn, false); | |
| 3890 } | |
| 3891 } | |
| 3892 | |
| 3893 function shouldConstruct(Component) { | |
| 3894 var prototype = Component.prototype; | |
| 3895 return !!(prototype && prototype.isReactComponent); | |
| 3896 } | |
| 3897 | |
| 3898 function describeUnknownElementTypeFrameInDEV(type, source, ownerFn) { | |
| 3899 | |
| 3900 if (type == null) { | |
| 3901 return ''; | |
| 3902 } | |
| 3903 | |
| 3904 if (typeof type === 'function') { | |
| 3905 { | |
| 3906 return describeNativeComponentFrame(type, shouldConstruct(type)); | |
| 3907 } | |
| 3908 } | |
| 3909 | |
| 3910 if (typeof type === 'string') { | |
| 3911 return describeBuiltInComponentFrame(type); | |
| 3912 } | |
| 3913 | |
| 3914 switch (type) { | |
| 3915 case REACT_SUSPENSE_TYPE: | |
| 3916 return describeBuiltInComponentFrame('Suspense'); | |
| 3917 | |
| 3918 case REACT_SUSPENSE_LIST_TYPE: | |
| 3919 return describeBuiltInComponentFrame('SuspenseList'); | |
| 3920 } | |
| 3921 | |
| 3922 if (typeof type === 'object') { | |
| 3923 switch (type.$$typeof) { | |
| 3924 case REACT_FORWARD_REF_TYPE: | |
| 3925 return describeFunctionComponentFrame(type.render); | |
| 3926 | |
| 3927 case REACT_MEMO_TYPE: | |
| 3928 // Memo may contain any component type so we recursively resolve it. | |
| 3929 return describeUnknownElementTypeFrameInDEV(type.type, source, ownerFn); | |
| 3930 | |
| 3931 case REACT_LAZY_TYPE: | |
| 3932 { | |
| 3933 var lazyComponent = type; | |
| 3934 var payload = lazyComponent._payload; | |
| 3935 var init = lazyComponent._init; | |
| 3936 | |
| 3937 try { | |
| 3938 // Lazy may contain any component type so we recursively resolve it. | |
| 3939 return describeUnknownElementTypeFrameInDEV(init(payload), source, ownerFn); | |
| 3940 } catch (x) {} | |
| 3941 } | |
| 3942 } | |
| 3943 } | |
| 3944 | |
| 3945 return ''; | |
| 3946 } | |
| 3947 | |
| 3948 var loggedTypeFailures = {}; | |
| 3949 var ReactDebugCurrentFrame = ReactSharedInternals.ReactDebugCurrentFrame; | |
| 3950 | |
| 3951 function setCurrentlyValidatingElement(element) { | |
| 3952 { | |
| 3953 if (element) { | |
| 3954 var owner = element._owner; | |
| 3955 var stack = describeUnknownElementTypeFrameInDEV(element.type, element._source, owner ? owner.type : null); | |
| 3956 ReactDebugCurrentFrame.setExtraStackFrame(stack); | |
| 3957 } else { | |
| 3958 ReactDebugCurrentFrame.setExtraStackFrame(null); | |
| 3959 } | |
| 3960 } | |
| 3961 } | |
| 3962 | |
| 3963 function checkPropTypes(typeSpecs, values, location, componentName, element) { | |
| 3964 { | |
| 3965 // $FlowFixMe This is okay but Flow doesn't know it. | |
| 3966 var has = Function.call.bind(hasOwnProperty); | |
| 3967 | |
| 3968 for (var typeSpecName in typeSpecs) { | |
| 3969 if (has(typeSpecs, typeSpecName)) { | |
| 3970 var error$1 = void 0; // Prop type validation may throw. In case they do, we don't want to | |
| 3971 // fail the render phase where it didn't fail before. So we log it. | |
| 3972 // After these have been cleaned up, we'll let them throw. | |
| 3973 | |
| 3974 try { | |
| 3975 // This is intentionally an invariant that gets caught. It's the same | |
| 3976 // behavior as without this statement except with a better message. | |
| 3977 if (typeof typeSpecs[typeSpecName] !== 'function') { | |
| 3978 // eslint-disable-next-line react-internal/prod-error-codes | |
| 3979 var err = Error((componentName || 'React class') + ': ' + location + ' type `' + typeSpecName + '` is invalid; ' + 'it must be a function, usually from the `prop-types` package, but received `' + typeof typeSpecs[typeSpecName] + '`.' + 'This often happens because of typos such as `PropTypes.function` instead of `PropTypes.func`.'); | |
| 3980 err.name = 'Invariant Violation'; | |
| 3981 throw err; | |
| 3982 } | |
| 3983 | |
| 3984 error$1 = typeSpecs[typeSpecName](values, typeSpecName, componentName, location, null, 'SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED'); | |
| 3985 } catch (ex) { | |
| 3986 error$1 = ex; | |
| 3987 } | |
| 3988 | |
| 3989 if (error$1 && !(error$1 instanceof Error)) { | |
| 3990 setCurrentlyValidatingElement(element); | |
| 3991 | |
| 3992 error('%s: type specification of %s' + ' `%s` is invalid; the type checker ' + 'function must return `null` or an `Error` but returned a %s. ' + 'You may have forgotten to pass an argument to the type checker ' + 'creator (arrayOf, instanceOf, objectOf, oneOf, oneOfType, and ' + 'shape all require an argument).', componentName || 'React class', location, typeSpecName, typeof error$1); | |
| 3993 | |
| 3994 setCurrentlyValidatingElement(null); | |
| 3995 } | |
| 3996 | |
| 3997 if (error$1 instanceof Error && !(error$1.message in loggedTypeFailures)) { | |
| 3998 // Only monitor this failure once because there tends to be a lot of the | |
| 3999 // same error. | |
| 4000 loggedTypeFailures[error$1.message] = true; | |
| 4001 setCurrentlyValidatingElement(element); | |
| 4002 | |
| 4003 error('Failed %s type: %s', location, error$1.message); | |
| 4004 | |
| 4005 setCurrentlyValidatingElement(null); | |
| 4006 } | |
| 4007 } | |
| 4008 } | |
| 4009 } | |
| 4010 } | |
| 4011 | |
| 4012 var warnedAboutMissingGetChildContext; | |
| 4013 | |
| 4014 { | |
| 4015 warnedAboutMissingGetChildContext = {}; | |
| 4016 } | |
| 4017 | |
| 4018 var emptyContextObject = {}; | |
| 4019 | |
| 4020 { | |
| 4021 Object.freeze(emptyContextObject); | |
| 4022 } | |
| 4023 | |
| 4024 function getMaskedContext(type, unmaskedContext) { | |
| 4025 { | |
| 4026 var contextTypes = type.contextTypes; | |
| 4027 | |
| 4028 if (!contextTypes) { | |
| 4029 return emptyContextObject; | |
| 4030 } | |
| 4031 | |
| 4032 var context = {}; | |
| 4033 | |
| 4034 for (var key in contextTypes) { | |
| 4035 context[key] = unmaskedContext[key]; | |
| 4036 } | |
| 4037 | |
| 4038 { | |
| 4039 var name = getComponentNameFromType(type) || 'Unknown'; | |
| 4040 checkPropTypes(contextTypes, context, 'context', name); | |
| 4041 } | |
| 4042 | |
| 4043 return context; | |
| 4044 } | |
| 4045 } | |
| 4046 function processChildContext(instance, type, parentContext, childContextTypes) { | |
| 4047 { | |
| 4048 // TODO (bvaughn) Replace this behavior with an invariant() in the future. | |
| 4049 // It has only been added in Fiber to match the (unintentional) behavior in Stack. | |
| 4050 if (typeof instance.getChildContext !== 'function') { | |
| 4051 { | |
| 4052 var componentName = getComponentNameFromType(type) || 'Unknown'; | |
| 4053 | |
| 4054 if (!warnedAboutMissingGetChildContext[componentName]) { | |
| 4055 warnedAboutMissingGetChildContext[componentName] = true; | |
| 4056 | |
| 4057 error('%s.childContextTypes is specified but there is no getChildContext() method ' + 'on the instance. You can either define getChildContext() on %s or remove ' + 'childContextTypes from it.', componentName, componentName); | |
| 4058 } | |
| 4059 } | |
| 4060 | |
| 4061 return parentContext; | |
| 4062 } | |
| 4063 | |
| 4064 var childContext = instance.getChildContext(); | |
| 4065 | |
| 4066 for (var contextKey in childContext) { | |
| 4067 if (!(contextKey in childContextTypes)) { | |
| 4068 throw new Error((getComponentNameFromType(type) || 'Unknown') + ".getChildContext(): key \"" + contextKey + "\" is not defined in childContextTypes."); | |
| 4069 } | |
| 4070 } | |
| 4071 | |
| 4072 { | |
| 4073 var name = getComponentNameFromType(type) || 'Unknown'; | |
| 4074 checkPropTypes(childContextTypes, childContext, 'child context', name); | |
| 4075 } | |
| 4076 | |
| 4077 return assign({}, parentContext, childContext); | |
| 4078 } | |
| 4079 } | |
| 4080 | |
| 4081 var rendererSigil; | |
| 4082 | |
| 4083 { | |
| 4084 // Use this to detect multiple renderers using the same context | |
| 4085 rendererSigil = {}; | |
| 4086 } // Used to store the parent path of all context overrides in a shared linked list. | |
| 4087 // Forming a reverse tree. | |
| 4088 | |
| 4089 | |
| 4090 var rootContextSnapshot = null; // We assume that this runtime owns the "current" field on all ReactContext instances. | |
| 4091 // This global (actually thread local) state represents what state all those "current", | |
| 4092 // fields are currently in. | |
| 4093 | |
| 4094 var currentActiveSnapshot = null; | |
| 4095 | |
| 4096 function popNode(prev) { | |
| 4097 { | |
| 4098 prev.context._currentValue = prev.parentValue; | |
| 4099 } | |
| 4100 } | |
| 4101 | |
| 4102 function pushNode(next) { | |
| 4103 { | |
| 4104 next.context._currentValue = next.value; | |
| 4105 } | |
| 4106 } | |
| 4107 | |
| 4108 function popToNearestCommonAncestor(prev, next) { | |
| 4109 if (prev === next) ; else { | |
| 4110 popNode(prev); | |
| 4111 var parentPrev = prev.parent; | |
| 4112 var parentNext = next.parent; | |
| 4113 | |
| 4114 if (parentPrev === null) { | |
| 4115 if (parentNext !== null) { | |
| 4116 throw new Error('The stacks must reach the root at the same time. This is a bug in React.'); | |
| 4117 } | |
| 4118 } else { | |
| 4119 if (parentNext === null) { | |
| 4120 throw new Error('The stacks must reach the root at the same time. This is a bug in React.'); | |
| 4121 } | |
| 4122 | |
| 4123 popToNearestCommonAncestor(parentPrev, parentNext); | |
| 4124 } // On the way back, we push the new ones that weren't common. | |
| 4125 | |
| 4126 | |
| 4127 pushNode(next); | |
| 4128 } | |
| 4129 } | |
| 4130 | |
| 4131 function popAllPrevious(prev) { | |
| 4132 popNode(prev); | |
| 4133 var parentPrev = prev.parent; | |
| 4134 | |
| 4135 if (parentPrev !== null) { | |
| 4136 popAllPrevious(parentPrev); | |
| 4137 } | |
| 4138 } | |
| 4139 | |
| 4140 function pushAllNext(next) { | |
| 4141 var parentNext = next.parent; | |
| 4142 | |
| 4143 if (parentNext !== null) { | |
| 4144 pushAllNext(parentNext); | |
| 4145 } | |
| 4146 | |
| 4147 pushNode(next); | |
| 4148 } | |
| 4149 | |
| 4150 function popPreviousToCommonLevel(prev, next) { | |
| 4151 popNode(prev); | |
| 4152 var parentPrev = prev.parent; | |
| 4153 | |
| 4154 if (parentPrev === null) { | |
| 4155 throw new Error('The depth must equal at least at zero before reaching the root. This is a bug in React.'); | |
| 4156 } | |
| 4157 | |
| 4158 if (parentPrev.depth === next.depth) { | |
| 4159 // We found the same level. Now we just need to find a shared ancestor. | |
| 4160 popToNearestCommonAncestor(parentPrev, next); | |
| 4161 } else { | |
| 4162 // We must still be deeper. | |
| 4163 popPreviousToCommonLevel(parentPrev, next); | |
| 4164 } | |
| 4165 } | |
| 4166 | |
| 4167 function popNextToCommonLevel(prev, next) { | |
| 4168 var parentNext = next.parent; | |
| 4169 | |
| 4170 if (parentNext === null) { | |
| 4171 throw new Error('The depth must equal at least at zero before reaching the root. This is a bug in React.'); | |
| 4172 } | |
| 4173 | |
| 4174 if (prev.depth === parentNext.depth) { | |
| 4175 // We found the same level. Now we just need to find a shared ancestor. | |
| 4176 popToNearestCommonAncestor(prev, parentNext); | |
| 4177 } else { | |
| 4178 // We must still be deeper. | |
| 4179 popNextToCommonLevel(prev, parentNext); | |
| 4180 } | |
| 4181 | |
| 4182 pushNode(next); | |
| 4183 } // Perform context switching to the new snapshot. | |
| 4184 // To make it cheap to read many contexts, while not suspending, we make the switch eagerly by | |
| 4185 // updating all the context's current values. That way reads, always just read the current value. | |
| 4186 // At the cost of updating contexts even if they're never read by this subtree. | |
| 4187 | |
| 4188 | |
| 4189 function switchContext(newSnapshot) { | |
| 4190 // The basic algorithm we need to do is to pop back any contexts that are no longer on the stack. | |
| 4191 // We also need to update any new contexts that are now on the stack with the deepest value. | |
| 4192 // The easiest way to update new contexts is to just reapply them in reverse order from the | |
| 4193 // perspective of the backpointers. To avoid allocating a lot when switching, we use the stack | |
| 4194 // for that. Therefore this algorithm is recursive. | |
| 4195 // 1) First we pop which ever snapshot tree was deepest. Popping old contexts as we go. | |
| 4196 // 2) Then we find the nearest common ancestor from there. Popping old contexts as we go. | |
| 4197 // 3) Then we reapply new contexts on the way back up the stack. | |
| 4198 var prev = currentActiveSnapshot; | |
| 4199 var next = newSnapshot; | |
| 4200 | |
| 4201 if (prev !== next) { | |
| 4202 if (prev === null) { | |
| 4203 // $FlowFixMe: This has to be non-null since it's not equal to prev. | |
| 4204 pushAllNext(next); | |
| 4205 } else if (next === null) { | |
| 4206 popAllPrevious(prev); | |
| 4207 } else if (prev.depth === next.depth) { | |
| 4208 popToNearestCommonAncestor(prev, next); | |
| 4209 } else if (prev.depth > next.depth) { | |
| 4210 popPreviousToCommonLevel(prev, next); | |
| 4211 } else { | |
| 4212 popNextToCommonLevel(prev, next); | |
| 4213 } | |
| 4214 | |
| 4215 currentActiveSnapshot = next; | |
| 4216 } | |
| 4217 } | |
| 4218 function pushProvider(context, nextValue) { | |
| 4219 var prevValue; | |
| 4220 | |
| 4221 { | |
| 4222 prevValue = context._currentValue; | |
| 4223 context._currentValue = nextValue; | |
| 4224 | |
| 4225 { | |
| 4226 if (context._currentRenderer !== undefined && context._currentRenderer !== null && context._currentRenderer !== rendererSigil) { | |
| 4227 error('Detected multiple renderers concurrently rendering the ' + 'same context provider. This is currently unsupported.'); | |
| 4228 } | |
| 4229 | |
| 4230 context._currentRenderer = rendererSigil; | |
| 4231 } | |
| 4232 } | |
| 4233 | |
| 4234 var prevNode = currentActiveSnapshot; | |
| 4235 var newNode = { | |
| 4236 parent: prevNode, | |
| 4237 depth: prevNode === null ? 0 : prevNode.depth + 1, | |
| 4238 context: context, | |
| 4239 parentValue: prevValue, | |
| 4240 value: nextValue | |
| 4241 }; | |
| 4242 currentActiveSnapshot = newNode; | |
| 4243 return newNode; | |
| 4244 } | |
| 4245 function popProvider(context) { | |
| 4246 var prevSnapshot = currentActiveSnapshot; | |
| 4247 | |
| 4248 if (prevSnapshot === null) { | |
| 4249 throw new Error('Tried to pop a Context at the root of the app. This is a bug in React.'); | |
| 4250 } | |
| 4251 | |
| 4252 { | |
| 4253 if (prevSnapshot.context !== context) { | |
| 4254 error('The parent context is not the expected context. This is probably a bug in React.'); | |
| 4255 } | |
| 4256 } | |
| 4257 | |
| 4258 { | |
| 4259 var value = prevSnapshot.parentValue; | |
| 4260 | |
| 4261 if (value === REACT_SERVER_CONTEXT_DEFAULT_VALUE_NOT_LOADED) { | |
| 4262 prevSnapshot.context._currentValue = prevSnapshot.context._defaultValue; | |
| 4263 } else { | |
| 4264 prevSnapshot.context._currentValue = value; | |
| 4265 } | |
| 4266 | |
| 4267 { | |
| 4268 if (context._currentRenderer !== undefined && context._currentRenderer !== null && context._currentRenderer !== rendererSigil) { | |
| 4269 error('Detected multiple renderers concurrently rendering the ' + 'same context provider. This is currently unsupported.'); | |
| 4270 } | |
| 4271 | |
| 4272 context._currentRenderer = rendererSigil; | |
| 4273 } | |
| 4274 } | |
| 4275 | |
| 4276 return currentActiveSnapshot = prevSnapshot.parent; | |
| 4277 } | |
| 4278 function getActiveContext() { | |
| 4279 return currentActiveSnapshot; | |
| 4280 } | |
| 4281 function readContext(context) { | |
| 4282 var value = context._currentValue ; | |
| 4283 return value; | |
| 4284 } | |
| 4285 | |
| 4286 /** | |
| 4287 * `ReactInstanceMap` maintains a mapping from a public facing stateful | |
| 4288 * instance (key) and the internal representation (value). This allows public | |
| 4289 * methods to accept the user facing instance as an argument and map them back | |
| 4290 * to internal methods. | |
| 4291 * | |
| 4292 * Note that this module is currently shared and assumed to be stateless. | |
| 4293 * If this becomes an actual Map, that will break. | |
| 4294 */ | |
| 4295 function get(key) { | |
| 4296 return key._reactInternals; | |
| 4297 } | |
| 4298 function set(key, value) { | |
| 4299 key._reactInternals = value; | |
| 4300 } | |
| 4301 | |
| 4302 var didWarnAboutNoopUpdateForComponent = {}; | |
| 4303 var didWarnAboutDeprecatedWillMount = {}; | |
| 4304 var didWarnAboutUninitializedState; | |
| 4305 var didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate; | |
| 4306 var didWarnAboutLegacyLifecyclesAndDerivedState; | |
| 4307 var didWarnAboutUndefinedDerivedState; | |
| 4308 var warnOnUndefinedDerivedState; | |
| 4309 var warnOnInvalidCallback; | |
| 4310 var didWarnAboutDirectlyAssigningPropsToState; | |
| 4311 var didWarnAboutContextTypeAndContextTypes; | |
| 4312 var didWarnAboutInvalidateContextType; | |
| 4313 | |
| 4314 { | |
| 4315 didWarnAboutUninitializedState = new Set(); | |
| 4316 didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate = new Set(); | |
| 4317 didWarnAboutLegacyLifecyclesAndDerivedState = new Set(); | |
| 4318 didWarnAboutDirectlyAssigningPropsToState = new Set(); | |
| 4319 didWarnAboutUndefinedDerivedState = new Set(); | |
| 4320 didWarnAboutContextTypeAndContextTypes = new Set(); | |
| 4321 didWarnAboutInvalidateContextType = new Set(); | |
| 4322 var didWarnOnInvalidCallback = new Set(); | |
| 4323 | |
| 4324 warnOnInvalidCallback = function (callback, callerName) { | |
| 4325 if (callback === null || typeof callback === 'function') { | |
| 4326 return; | |
| 4327 } | |
| 4328 | |
| 4329 var key = callerName + '_' + callback; | |
| 4330 | |
| 4331 if (!didWarnOnInvalidCallback.has(key)) { | |
| 4332 didWarnOnInvalidCallback.add(key); | |
| 4333 | |
| 4334 error('%s(...): Expected the last optional `callback` argument to be a ' + 'function. Instead received: %s.', callerName, callback); | |
| 4335 } | |
| 4336 }; | |
| 4337 | |
| 4338 warnOnUndefinedDerivedState = function (type, partialState) { | |
| 4339 if (partialState === undefined) { | |
| 4340 var componentName = getComponentNameFromType(type) || 'Component'; | |
| 4341 | |
| 4342 if (!didWarnAboutUndefinedDerivedState.has(componentName)) { | |
| 4343 didWarnAboutUndefinedDerivedState.add(componentName); | |
| 4344 | |
| 4345 error('%s.getDerivedStateFromProps(): A valid state object (or null) must be returned. ' + 'You have returned undefined.', componentName); | |
| 4346 } | |
| 4347 } | |
| 4348 }; | |
| 4349 } | |
| 4350 | |
| 4351 function warnNoop(publicInstance, callerName) { | |
| 4352 { | |
| 4353 var _constructor = publicInstance.constructor; | |
| 4354 var componentName = _constructor && getComponentNameFromType(_constructor) || 'ReactClass'; | |
| 4355 var warningKey = componentName + '.' + callerName; | |
| 4356 | |
| 4357 if (didWarnAboutNoopUpdateForComponent[warningKey]) { | |
| 4358 return; | |
| 4359 } | |
| 4360 | |
| 4361 error('%s(...): Can only update a mounting component. ' + 'This usually means you called %s() outside componentWillMount() on the server. ' + 'This is a no-op.\n\nPlease check the code for the %s component.', callerName, callerName, componentName); | |
| 4362 | |
| 4363 didWarnAboutNoopUpdateForComponent[warningKey] = true; | |
| 4364 } | |
| 4365 } | |
| 4366 | |
| 4367 var classComponentUpdater = { | |
| 4368 isMounted: function (inst) { | |
| 4369 return false; | |
| 4370 }, | |
| 4371 enqueueSetState: function (inst, payload, callback) { | |
| 4372 var internals = get(inst); | |
| 4373 | |
| 4374 if (internals.queue === null) { | |
| 4375 warnNoop(inst, 'setState'); | |
| 4376 } else { | |
| 4377 internals.queue.push(payload); | |
| 4378 | |
| 4379 { | |
| 4380 if (callback !== undefined && callback !== null) { | |
| 4381 warnOnInvalidCallback(callback, 'setState'); | |
| 4382 } | |
| 4383 } | |
| 4384 } | |
| 4385 }, | |
| 4386 enqueueReplaceState: function (inst, payload, callback) { | |
| 4387 var internals = get(inst); | |
| 4388 internals.replace = true; | |
| 4389 internals.queue = [payload]; | |
| 4390 | |
| 4391 { | |
| 4392 if (callback !== undefined && callback !== null) { | |
| 4393 warnOnInvalidCallback(callback, 'setState'); | |
| 4394 } | |
| 4395 } | |
| 4396 }, | |
| 4397 enqueueForceUpdate: function (inst, callback) { | |
| 4398 var internals = get(inst); | |
| 4399 | |
| 4400 if (internals.queue === null) { | |
| 4401 warnNoop(inst, 'forceUpdate'); | |
| 4402 } else { | |
| 4403 { | |
| 4404 if (callback !== undefined && callback !== null) { | |
| 4405 warnOnInvalidCallback(callback, 'setState'); | |
| 4406 } | |
| 4407 } | |
| 4408 } | |
| 4409 } | |
| 4410 }; | |
| 4411 | |
| 4412 function applyDerivedStateFromProps(instance, ctor, getDerivedStateFromProps, prevState, nextProps) { | |
| 4413 var partialState = getDerivedStateFromProps(nextProps, prevState); | |
| 4414 | |
| 4415 { | |
| 4416 warnOnUndefinedDerivedState(ctor, partialState); | |
| 4417 } // Merge the partial state and the previous state. | |
| 4418 | |
| 4419 | |
| 4420 var newState = partialState === null || partialState === undefined ? prevState : assign({}, prevState, partialState); | |
| 4421 return newState; | |
| 4422 } | |
| 4423 | |
| 4424 function constructClassInstance(ctor, props, maskedLegacyContext) { | |
| 4425 var context = emptyContextObject; | |
| 4426 var contextType = ctor.contextType; | |
| 4427 | |
| 4428 { | |
| 4429 if ('contextType' in ctor) { | |
| 4430 var isValid = // Allow null for conditional declaration | |
| 4431 contextType === null || contextType !== undefined && contextType.$$typeof === REACT_CONTEXT_TYPE && contextType._context === undefined; // Not a <Context.Consumer> | |
| 4432 | |
| 4433 if (!isValid && !didWarnAboutInvalidateContextType.has(ctor)) { | |
| 4434 didWarnAboutInvalidateContextType.add(ctor); | |
| 4435 var addendum = ''; | |
| 4436 | |
| 4437 if (contextType === undefined) { | |
| 4438 addendum = ' However, it is set to undefined. ' + 'This can be caused by a typo or by mixing up named and default imports. ' + 'This can also happen due to a circular dependency, so ' + 'try moving the createContext() call to a separate file.'; | |
| 4439 } else if (typeof contextType !== 'object') { | |
| 4440 addendum = ' However, it is set to a ' + typeof contextType + '.'; | |
| 4441 } else if (contextType.$$typeof === REACT_PROVIDER_TYPE) { | |
| 4442 addendum = ' Did you accidentally pass the Context.Provider instead?'; | |
| 4443 } else if (contextType._context !== undefined) { | |
| 4444 // <Context.Consumer> | |
| 4445 addendum = ' Did you accidentally pass the Context.Consumer instead?'; | |
| 4446 } else { | |
| 4447 addendum = ' However, it is set to an object with keys {' + Object.keys(contextType).join(', ') + '}.'; | |
| 4448 } | |
| 4449 | |
| 4450 error('%s defines an invalid contextType. ' + 'contextType should point to the Context object returned by React.createContext().%s', getComponentNameFromType(ctor) || 'Component', addendum); | |
| 4451 } | |
| 4452 } | |
| 4453 } | |
| 4454 | |
| 4455 if (typeof contextType === 'object' && contextType !== null) { | |
| 4456 context = readContext(contextType); | |
| 4457 } else { | |
| 4458 context = maskedLegacyContext; | |
| 4459 } | |
| 4460 | |
| 4461 var instance = new ctor(props, context); | |
| 4462 | |
| 4463 { | |
| 4464 if (typeof ctor.getDerivedStateFromProps === 'function' && (instance.state === null || instance.state === undefined)) { | |
| 4465 var componentName = getComponentNameFromType(ctor) || 'Component'; | |
| 4466 | |
| 4467 if (!didWarnAboutUninitializedState.has(componentName)) { | |
| 4468 didWarnAboutUninitializedState.add(componentName); | |
| 4469 | |
| 4470 error('`%s` uses `getDerivedStateFromProps` but its initial state is ' + '%s. This is not recommended. Instead, define the initial state by ' + 'assigning an object to `this.state` in the constructor of `%s`. ' + 'This ensures that `getDerivedStateFromProps` arguments have a consistent shape.', componentName, instance.state === null ? 'null' : 'undefined', componentName); | |
| 4471 } | |
| 4472 } // If new component APIs are defined, "unsafe" lifecycles won't be called. | |
| 4473 // Warn about these lifecycles if they are present. | |
| 4474 // Don't warn about react-lifecycles-compat polyfilled methods though. | |
| 4475 | |
| 4476 | |
| 4477 if (typeof ctor.getDerivedStateFromProps === 'function' || typeof instance.getSnapshotBeforeUpdate === 'function') { | |
| 4478 var foundWillMountName = null; | |
| 4479 var foundWillReceivePropsName = null; | |
| 4480 var foundWillUpdateName = null; | |
| 4481 | |
| 4482 if (typeof instance.componentWillMount === 'function' && instance.componentWillMount.__suppressDeprecationWarning !== true) { | |
| 4483 foundWillMountName = 'componentWillMount'; | |
| 4484 } else if (typeof instance.UNSAFE_componentWillMount === 'function') { | |
| 4485 foundWillMountName = 'UNSAFE_componentWillMount'; | |
| 4486 } | |
| 4487 | |
| 4488 if (typeof instance.componentWillReceiveProps === 'function' && instance.componentWillReceiveProps.__suppressDeprecationWarning !== true) { | |
| 4489 foundWillReceivePropsName = 'componentWillReceiveProps'; | |
| 4490 } else if (typeof instance.UNSAFE_componentWillReceiveProps === 'function') { | |
| 4491 foundWillReceivePropsName = 'UNSAFE_componentWillReceiveProps'; | |
| 4492 } | |
| 4493 | |
| 4494 if (typeof instance.componentWillUpdate === 'function' && instance.componentWillUpdate.__suppressDeprecationWarning !== true) { | |
| 4495 foundWillUpdateName = 'componentWillUpdate'; | |
| 4496 } else if (typeof instance.UNSAFE_componentWillUpdate === 'function') { | |
| 4497 foundWillUpdateName = 'UNSAFE_componentWillUpdate'; | |
| 4498 } | |
| 4499 | |
| 4500 if (foundWillMountName !== null || foundWillReceivePropsName !== null || foundWillUpdateName !== null) { | |
| 4501 var _componentName = getComponentNameFromType(ctor) || 'Component'; | |
| 4502 | |
| 4503 var newApiName = typeof ctor.getDerivedStateFromProps === 'function' ? 'getDerivedStateFromProps()' : 'getSnapshotBeforeUpdate()'; | |
| 4504 | |
| 4505 if (!didWarnAboutLegacyLifecyclesAndDerivedState.has(_componentName)) { | |
| 4506 didWarnAboutLegacyLifecyclesAndDerivedState.add(_componentName); | |
| 4507 | |
| 4508 error('Unsafe legacy lifecycles will not be called for components using new component APIs.\n\n' + '%s uses %s but also contains the following legacy lifecycles:%s%s%s\n\n' + 'The above lifecycles should be removed. Learn more about this warning here:\n' + 'https://reactjs.org/link/unsafe-component-lifecycles', _componentName, newApiName, foundWillMountName !== null ? "\n " + foundWillMountName : '', foundWillReceivePropsName !== null ? "\n " + foundWillReceivePropsName : '', foundWillUpdateName !== null ? "\n " + foundWillUpdateName : ''); | |
| 4509 } | |
| 4510 } | |
| 4511 } | |
| 4512 } | |
| 4513 | |
| 4514 return instance; | |
| 4515 } | |
| 4516 | |
| 4517 function checkClassInstance(instance, ctor, newProps) { | |
| 4518 { | |
| 4519 var name = getComponentNameFromType(ctor) || 'Component'; | |
| 4520 var renderPresent = instance.render; | |
| 4521 | |
| 4522 if (!renderPresent) { | |
| 4523 if (ctor.prototype && typeof ctor.prototype.render === 'function') { | |
| 4524 error('%s(...): No `render` method found on the returned component ' + 'instance: did you accidentally return an object from the constructor?', name); | |
| 4525 } else { | |
| 4526 error('%s(...): No `render` method found on the returned component ' + 'instance: you may have forgotten to define `render`.', name); | |
| 4527 } | |
| 4528 } | |
| 4529 | |
| 4530 if (instance.getInitialState && !instance.getInitialState.isReactClassApproved && !instance.state) { | |
| 4531 error('getInitialState was defined on %s, a plain JavaScript class. ' + 'This is only supported for classes created using React.createClass. ' + 'Did you mean to define a state property instead?', name); | |
| 4532 } | |
| 4533 | |
| 4534 if (instance.getDefaultProps && !instance.getDefaultProps.isReactClassApproved) { | |
| 4535 error('getDefaultProps was defined on %s, a plain JavaScript class. ' + 'This is only supported for classes created using React.createClass. ' + 'Use a static property to define defaultProps instead.', name); | |
| 4536 } | |
| 4537 | |
| 4538 if (instance.propTypes) { | |
| 4539 error('propTypes was defined as an instance property on %s. Use a static ' + 'property to define propTypes instead.', name); | |
| 4540 } | |
| 4541 | |
| 4542 if (instance.contextType) { | |
| 4543 error('contextType was defined as an instance property on %s. Use a static ' + 'property to define contextType instead.', name); | |
| 4544 } | |
| 4545 | |
| 4546 { | |
| 4547 if (instance.contextTypes) { | |
| 4548 error('contextTypes was defined as an instance property on %s. Use a static ' + 'property to define contextTypes instead.', name); | |
| 4549 } | |
| 4550 | |
| 4551 if (ctor.contextType && ctor.contextTypes && !didWarnAboutContextTypeAndContextTypes.has(ctor)) { | |
| 4552 didWarnAboutContextTypeAndContextTypes.add(ctor); | |
| 4553 | |
| 4554 error('%s declares both contextTypes and contextType static properties. ' + 'The legacy contextTypes property will be ignored.', name); | |
| 4555 } | |
| 4556 } | |
| 4557 | |
| 4558 if (typeof instance.componentShouldUpdate === 'function') { | |
| 4559 error('%s has a method called ' + 'componentShouldUpdate(). Did you mean shouldComponentUpdate()? ' + 'The name is phrased as a question because the function is ' + 'expected to return a value.', name); | |
| 4560 } | |
| 4561 | |
| 4562 if (ctor.prototype && ctor.prototype.isPureReactComponent && typeof instance.shouldComponentUpdate !== 'undefined') { | |
| 4563 error('%s has a method called shouldComponentUpdate(). ' + 'shouldComponentUpdate should not be used when extending React.PureComponent. ' + 'Please extend React.Component if shouldComponentUpdate is used.', getComponentNameFromType(ctor) || 'A pure component'); | |
| 4564 } | |
| 4565 | |
| 4566 if (typeof instance.componentDidUnmount === 'function') { | |
| 4567 error('%s has a method called ' + 'componentDidUnmount(). But there is no such lifecycle method. ' + 'Did you mean componentWillUnmount()?', name); | |
| 4568 } | |
| 4569 | |
| 4570 if (typeof instance.componentDidReceiveProps === 'function') { | |
| 4571 error('%s has a method called ' + 'componentDidReceiveProps(). But there is no such lifecycle method. ' + 'If you meant to update the state in response to changing props, ' + 'use componentWillReceiveProps(). If you meant to fetch data or ' + 'run side-effects or mutations after React has updated the UI, use componentDidUpdate().', name); | |
| 4572 } | |
| 4573 | |
| 4574 if (typeof instance.componentWillRecieveProps === 'function') { | |
| 4575 error('%s has a method called ' + 'componentWillRecieveProps(). Did you mean componentWillReceiveProps()?', name); | |
| 4576 } | |
| 4577 | |
| 4578 if (typeof instance.UNSAFE_componentWillRecieveProps === 'function') { | |
| 4579 error('%s has a method called ' + 'UNSAFE_componentWillRecieveProps(). Did you mean UNSAFE_componentWillReceiveProps()?', name); | |
| 4580 } | |
| 4581 | |
| 4582 var hasMutatedProps = instance.props !== newProps; | |
| 4583 | |
| 4584 if (instance.props !== undefined && hasMutatedProps) { | |
| 4585 error('%s(...): When calling super() in `%s`, make sure to pass ' + "up the same props that your component's constructor was passed.", name, name); | |
| 4586 } | |
| 4587 | |
| 4588 if (instance.defaultProps) { | |
| 4589 error('Setting defaultProps as an instance property on %s is not supported and will be ignored.' + ' Instead, define defaultProps as a static property on %s.', name, name); | |
| 4590 } | |
| 4591 | |
| 4592 if (typeof instance.getSnapshotBeforeUpdate === 'function' && typeof instance.componentDidUpdate !== 'function' && !didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate.has(ctor)) { | |
| 4593 didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate.add(ctor); | |
| 4594 | |
| 4595 error('%s: getSnapshotBeforeUpdate() should be used with componentDidUpdate(). ' + 'This component defines getSnapshotBeforeUpdate() only.', getComponentNameFromType(ctor)); | |
| 4596 } | |
| 4597 | |
| 4598 if (typeof instance.getDerivedStateFromProps === 'function') { | |
| 4599 error('%s: getDerivedStateFromProps() is defined as an instance method ' + 'and will be ignored. Instead, declare it as a static method.', name); | |
| 4600 } | |
| 4601 | |
| 4602 if (typeof instance.getDerivedStateFromError === 'function') { | |
| 4603 error('%s: getDerivedStateFromError() is defined as an instance method ' + 'and will be ignored. Instead, declare it as a static method.', name); | |
| 4604 } | |
| 4605 | |
| 4606 if (typeof ctor.getSnapshotBeforeUpdate === 'function') { | |
| 4607 error('%s: getSnapshotBeforeUpdate() is defined as a static method ' + 'and will be ignored. Instead, declare it as an instance method.', name); | |
| 4608 } | |
| 4609 | |
| 4610 var _state = instance.state; | |
| 4611 | |
| 4612 if (_state && (typeof _state !== 'object' || isArray(_state))) { | |
| 4613 error('%s.state: must be set to an object or null', name); | |
| 4614 } | |
| 4615 | |
| 4616 if (typeof instance.getChildContext === 'function' && typeof ctor.childContextTypes !== 'object') { | |
| 4617 error('%s.getChildContext(): childContextTypes must be defined in order to ' + 'use getChildContext().', name); | |
| 4618 } | |
| 4619 } | |
| 4620 } | |
| 4621 | |
| 4622 function callComponentWillMount(type, instance) { | |
| 4623 var oldState = instance.state; | |
| 4624 | |
| 4625 if (typeof instance.componentWillMount === 'function') { | |
| 4626 { | |
| 4627 if ( instance.componentWillMount.__suppressDeprecationWarning !== true) { | |
| 4628 var componentName = getComponentNameFromType(type) || 'Unknown'; | |
| 4629 | |
| 4630 if (!didWarnAboutDeprecatedWillMount[componentName]) { | |
| 4631 warn( // keep this warning in sync with ReactStrictModeWarning.js | |
| 4632 'componentWillMount has been renamed, and is not recommended for use. ' + 'See https://reactjs.org/link/unsafe-component-lifecycles for details.\n\n' + '* Move code from componentWillMount to componentDidMount (preferred in most cases) ' + 'or the constructor.\n' + '\nPlease update the following components: %s', componentName); | |
| 4633 | |
| 4634 didWarnAboutDeprecatedWillMount[componentName] = true; | |
| 4635 } | |
| 4636 } | |
| 4637 } | |
| 4638 | |
| 4639 instance.componentWillMount(); | |
| 4640 } | |
| 4641 | |
| 4642 if (typeof instance.UNSAFE_componentWillMount === 'function') { | |
| 4643 instance.UNSAFE_componentWillMount(); | |
| 4644 } | |
| 4645 | |
| 4646 if (oldState !== instance.state) { | |
| 4647 { | |
| 4648 error('%s.componentWillMount(): Assigning directly to this.state is ' + "deprecated (except inside a component's " + 'constructor). Use setState instead.', getComponentNameFromType(type) || 'Component'); | |
| 4649 } | |
| 4650 | |
| 4651 classComponentUpdater.enqueueReplaceState(instance, instance.state, null); | |
| 4652 } | |
| 4653 } | |
| 4654 | |
| 4655 function processUpdateQueue(internalInstance, inst, props, maskedLegacyContext) { | |
| 4656 if (internalInstance.queue !== null && internalInstance.queue.length > 0) { | |
| 4657 var oldQueue = internalInstance.queue; | |
| 4658 var oldReplace = internalInstance.replace; | |
| 4659 internalInstance.queue = null; | |
| 4660 internalInstance.replace = false; | |
| 4661 | |
| 4662 if (oldReplace && oldQueue.length === 1) { | |
| 4663 inst.state = oldQueue[0]; | |
| 4664 } else { | |
| 4665 var nextState = oldReplace ? oldQueue[0] : inst.state; | |
| 4666 var dontMutate = true; | |
| 4667 | |
| 4668 for (var i = oldReplace ? 1 : 0; i < oldQueue.length; i++) { | |
| 4669 var partial = oldQueue[i]; | |
| 4670 var partialState = typeof partial === 'function' ? partial.call(inst, nextState, props, maskedLegacyContext) : partial; | |
| 4671 | |
| 4672 if (partialState != null) { | |
| 4673 if (dontMutate) { | |
| 4674 dontMutate = false; | |
| 4675 nextState = assign({}, nextState, partialState); | |
| 4676 } else { | |
| 4677 assign(nextState, partialState); | |
| 4678 } | |
| 4679 } | |
| 4680 } | |
| 4681 | |
| 4682 inst.state = nextState; | |
| 4683 } | |
| 4684 } else { | |
| 4685 internalInstance.queue = null; | |
| 4686 } | |
| 4687 } // Invokes the mount life-cycles on a previously never rendered instance. | |
| 4688 | |
| 4689 | |
| 4690 function mountClassInstance(instance, ctor, newProps, maskedLegacyContext) { | |
| 4691 { | |
| 4692 checkClassInstance(instance, ctor, newProps); | |
| 4693 } | |
| 4694 | |
| 4695 var initialState = instance.state !== undefined ? instance.state : null; | |
| 4696 instance.updater = classComponentUpdater; | |
| 4697 instance.props = newProps; | |
| 4698 instance.state = initialState; // We don't bother initializing the refs object on the server, since we're not going to resolve them anyway. | |
| 4699 // The internal instance will be used to manage updates that happen during this mount. | |
| 4700 | |
| 4701 var internalInstance = { | |
| 4702 queue: [], | |
| 4703 replace: false | |
| 4704 }; | |
| 4705 set(instance, internalInstance); | |
| 4706 var contextType = ctor.contextType; | |
| 4707 | |
| 4708 if (typeof contextType === 'object' && contextType !== null) { | |
| 4709 instance.context = readContext(contextType); | |
| 4710 } else { | |
| 4711 instance.context = maskedLegacyContext; | |
| 4712 } | |
| 4713 | |
| 4714 { | |
| 4715 if (instance.state === newProps) { | |
| 4716 var componentName = getComponentNameFromType(ctor) || 'Component'; | |
| 4717 | |
| 4718 if (!didWarnAboutDirectlyAssigningPropsToState.has(componentName)) { | |
| 4719 didWarnAboutDirectlyAssigningPropsToState.add(componentName); | |
| 4720 | |
| 4721 error('%s: It is not recommended to assign props directly to state ' + "because updates to props won't be reflected in state. " + 'In most cases, it is better to use props directly.', componentName); | |
| 4722 } | |
| 4723 } | |
| 4724 } | |
| 4725 | |
| 4726 var getDerivedStateFromProps = ctor.getDerivedStateFromProps; | |
| 4727 | |
| 4728 if (typeof getDerivedStateFromProps === 'function') { | |
| 4729 instance.state = applyDerivedStateFromProps(instance, ctor, getDerivedStateFromProps, initialState, newProps); | |
| 4730 } // In order to support react-lifecycles-compat polyfilled components, | |
| 4731 // Unsafe lifecycles should not be invoked for components using the new APIs. | |
| 4732 | |
| 4733 | |
| 4734 if (typeof ctor.getDerivedStateFromProps !== 'function' && typeof instance.getSnapshotBeforeUpdate !== 'function' && (typeof instance.UNSAFE_componentWillMount === 'function' || typeof instance.componentWillMount === 'function')) { | |
| 4735 callComponentWillMount(ctor, instance); // If we had additional state updates during this life-cycle, let's | |
| 4736 // process them now. | |
| 4737 | |
| 4738 processUpdateQueue(internalInstance, instance, newProps, maskedLegacyContext); | |
| 4739 } | |
| 4740 } | |
| 4741 | |
| 4742 // Ids are base 32 strings whose binary representation corresponds to the | |
| 4743 // position of a node in a tree. | |
| 4744 // Every time the tree forks into multiple children, we add additional bits to | |
| 4745 // the left of the sequence that represent the position of the child within the | |
| 4746 // current level of children. | |
| 4747 // | |
| 4748 // 00101 00010001011010101 | |
| 4749 // ╰─┬─╯ ╰───────┬───────╯ | |
| 4750 // Fork 5 of 20 Parent id | |
| 4751 // | |
| 4752 // The leading 0s are important. In the above example, you only need 3 bits to | |
| 4753 // represent slot 5. However, you need 5 bits to represent all the forks at | |
| 4754 // the current level, so we must account for the empty bits at the end. | |
| 4755 // | |
| 4756 // For this same reason, slots are 1-indexed instead of 0-indexed. Otherwise, | |
| 4757 // the zeroth id at a level would be indistinguishable from its parent. | |
| 4758 // | |
| 4759 // If a node has only one child, and does not materialize an id (i.e. does not | |
| 4760 // contain a useId hook), then we don't need to allocate any space in the | |
| 4761 // sequence. It's treated as a transparent indirection. For example, these two | |
| 4762 // trees produce the same ids: | |
| 4763 // | |
| 4764 // <> <> | |
| 4765 // <Indirection> <A /> | |
| 4766 // <A /> <B /> | |
| 4767 // </Indirection> </> | |
| 4768 // <B /> | |
| 4769 // </> | |
| 4770 // | |
| 4771 // However, we cannot skip any node that materializes an id. Otherwise, a parent | |
| 4772 // id that does not fork would be indistinguishable from its child id. For | |
| 4773 // example, this tree does not fork, but the parent and child must have | |
| 4774 // different ids. | |
| 4775 // | |
| 4776 // <Parent> | |
| 4777 // <Child /> | |
| 4778 // </Parent> | |
| 4779 // | |
| 4780 // To handle this scenario, every time we materialize an id, we allocate a | |
| 4781 // new level with a single slot. You can think of this as a fork with only one | |
| 4782 // prong, or an array of children with length 1. | |
| 4783 // | |
| 4784 // It's possible for the size of the sequence to exceed 32 bits, the max | |
| 4785 // size for bitwise operations. When this happens, we make more room by | |
| 4786 // converting the right part of the id to a string and storing it in an overflow | |
| 4787 // variable. We use a base 32 string representation, because 32 is the largest | |
| 4788 // power of 2 that is supported by toString(). We want the base to be large so | |
| 4789 // that the resulting ids are compact, and we want the base to be a power of 2 | |
| 4790 // because every log2(base) bits corresponds to a single character, i.e. every | |
| 4791 // log2(32) = 5 bits. That means we can lop bits off the end 5 at a time without | |
| 4792 // affecting the final result. | |
| 4793 var emptyTreeContext = { | |
| 4794 id: 1, | |
| 4795 overflow: '' | |
| 4796 }; | |
| 4797 function getTreeId(context) { | |
| 4798 var overflow = context.overflow; | |
| 4799 var idWithLeadingBit = context.id; | |
| 4800 var id = idWithLeadingBit & ~getLeadingBit(idWithLeadingBit); | |
| 4801 return id.toString(32) + overflow; | |
| 4802 } | |
| 4803 function pushTreeContext(baseContext, totalChildren, index) { | |
| 4804 var baseIdWithLeadingBit = baseContext.id; | |
| 4805 var baseOverflow = baseContext.overflow; // The leftmost 1 marks the end of the sequence, non-inclusive. It's not part | |
| 4806 // of the id; we use it to account for leading 0s. | |
| 4807 | |
| 4808 var baseLength = getBitLength(baseIdWithLeadingBit) - 1; | |
| 4809 var baseId = baseIdWithLeadingBit & ~(1 << baseLength); | |
| 4810 var slot = index + 1; | |
| 4811 var length = getBitLength(totalChildren) + baseLength; // 30 is the max length we can store without overflowing, taking into | |
| 4812 // consideration the leading 1 we use to mark the end of the sequence. | |
| 4813 | |
| 4814 if (length > 30) { | |
| 4815 // We overflowed the bitwise-safe range. Fall back to slower algorithm. | |
| 4816 // This branch assumes the length of the base id is greater than 5; it won't | |
| 4817 // work for smaller ids, because you need 5 bits per character. | |
| 4818 // | |
| 4819 // We encode the id in multiple steps: first the base id, then the | |
| 4820 // remaining digits. | |
| 4821 // | |
| 4822 // Each 5 bit sequence corresponds to a single base 32 character. So for | |
| 4823 // example, if the current id is 23 bits long, we can convert 20 of those | |
| 4824 // bits into a string of 4 characters, with 3 bits left over. | |
| 4825 // | |
| 4826 // First calculate how many bits in the base id represent a complete | |
| 4827 // sequence of characters. | |
| 4828 var numberOfOverflowBits = baseLength - baseLength % 5; // Then create a bitmask that selects only those bits. | |
| 4829 | |
| 4830 var newOverflowBits = (1 << numberOfOverflowBits) - 1; // Select the bits, and convert them to a base 32 string. | |
| 4831 | |
| 4832 var newOverflow = (baseId & newOverflowBits).toString(32); // Now we can remove those bits from the base id. | |
| 4833 | |
| 4834 var restOfBaseId = baseId >> numberOfOverflowBits; | |
| 4835 var restOfBaseLength = baseLength - numberOfOverflowBits; // Finally, encode the rest of the bits using the normal algorithm. Because | |
| 4836 // we made more room, this time it won't overflow. | |
| 4837 | |
| 4838 var restOfLength = getBitLength(totalChildren) + restOfBaseLength; | |
| 4839 var restOfNewBits = slot << restOfBaseLength; | |
| 4840 var id = restOfNewBits | restOfBaseId; | |
| 4841 var overflow = newOverflow + baseOverflow; | |
| 4842 return { | |
| 4843 id: 1 << restOfLength | id, | |
| 4844 overflow: overflow | |
| 4845 }; | |
| 4846 } else { | |
| 4847 // Normal path | |
| 4848 var newBits = slot << baseLength; | |
| 4849 | |
| 4850 var _id = newBits | baseId; | |
| 4851 | |
| 4852 var _overflow = baseOverflow; | |
| 4853 return { | |
| 4854 id: 1 << length | _id, | |
| 4855 overflow: _overflow | |
| 4856 }; | |
| 4857 } | |
| 4858 } | |
| 4859 | |
| 4860 function getBitLength(number) { | |
| 4861 return 32 - clz32(number); | |
| 4862 } | |
| 4863 | |
| 4864 function getLeadingBit(id) { | |
| 4865 return 1 << getBitLength(id) - 1; | |
| 4866 } // TODO: Math.clz32 is supported in Node 12+. Maybe we can drop the fallback. | |
| 4867 | |
| 4868 | |
| 4869 var clz32 = Math.clz32 ? Math.clz32 : clz32Fallback; // Count leading zeros. | |
| 4870 // Based on: | |
| 4871 // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/clz32 | |
| 4872 | |
| 4873 var log = Math.log; | |
| 4874 var LN2 = Math.LN2; | |
| 4875 | |
| 4876 function clz32Fallback(x) { | |
| 4877 var asUint = x >>> 0; | |
| 4878 | |
| 4879 if (asUint === 0) { | |
| 4880 return 32; | |
| 4881 } | |
| 4882 | |
| 4883 return 31 - (log(asUint) / LN2 | 0) | 0; | |
| 4884 } | |
| 4885 | |
| 4886 /** | |
| 4887 * inlined Object.is polyfill to avoid requiring consumers ship their own | |
| 4888 * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is | |
| 4889 */ | |
| 4890 function is(x, y) { | |
| 4891 return x === y && (x !== 0 || 1 / x === 1 / y) || x !== x && y !== y // eslint-disable-line no-self-compare | |
| 4892 ; | |
| 4893 } | |
| 4894 | |
| 4895 var objectIs = typeof Object.is === 'function' ? Object.is : is; | |
| 4896 | |
| 4897 var currentlyRenderingComponent = null; | |
| 4898 var currentlyRenderingTask = null; | |
| 4899 var firstWorkInProgressHook = null; | |
| 4900 var workInProgressHook = null; // Whether the work-in-progress hook is a re-rendered hook | |
| 4901 | |
| 4902 var isReRender = false; // Whether an update was scheduled during the currently executing render pass. | |
| 4903 | |
| 4904 var didScheduleRenderPhaseUpdate = false; // Counts the number of useId hooks in this component | |
| 4905 | |
| 4906 var localIdCounter = 0; // Lazily created map of render-phase updates | |
| 4907 | |
| 4908 var renderPhaseUpdates = null; // Counter to prevent infinite loops. | |
| 4909 | |
| 4910 var numberOfReRenders = 0; | |
| 4911 var RE_RENDER_LIMIT = 25; | |
| 4912 var isInHookUserCodeInDev = false; // In DEV, this is the name of the currently executing primitive hook | |
| 4913 | |
| 4914 var currentHookNameInDev; | |
| 4915 | |
| 4916 function resolveCurrentlyRenderingComponent() { | |
| 4917 if (currentlyRenderingComponent === null) { | |
| 4918 throw new Error('Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for' + ' one of the following reasons:\n' + '1. You might have mismatching versions of React and the renderer (such as React DOM)\n' + '2. You might be breaking the Rules of Hooks\n' + '3. You might have more than one copy of React in the same app\n' + 'See https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.'); | |
| 4919 } | |
| 4920 | |
| 4921 { | |
| 4922 if (isInHookUserCodeInDev) { | |
| 4923 error('Do not call Hooks inside useEffect(...), useMemo(...), or other built-in Hooks. ' + 'You can only call Hooks at the top level of your React function. ' + 'For more information, see ' + 'https://reactjs.org/link/rules-of-hooks'); | |
| 4924 } | |
| 4925 } | |
| 4926 | |
| 4927 return currentlyRenderingComponent; | |
| 4928 } | |
| 4929 | |
| 4930 function areHookInputsEqual(nextDeps, prevDeps) { | |
| 4931 if (prevDeps === null) { | |
| 4932 { | |
| 4933 error('%s received a final argument during this render, but not during ' + 'the previous render. Even though the final argument is optional, ' + 'its type cannot change between renders.', currentHookNameInDev); | |
| 4934 } | |
| 4935 | |
| 4936 return false; | |
| 4937 } | |
| 4938 | |
| 4939 { | |
| 4940 // Don't bother comparing lengths in prod because these arrays should be | |
| 4941 // passed inline. | |
| 4942 if (nextDeps.length !== prevDeps.length) { | |
| 4943 error('The final argument passed to %s changed size between renders. The ' + 'order and size of this array must remain constant.\n\n' + 'Previous: %s\n' + 'Incoming: %s', currentHookNameInDev, "[" + nextDeps.join(', ') + "]", "[" + prevDeps.join(', ') + "]"); | |
| 4944 } | |
| 4945 } | |
| 4946 | |
| 4947 for (var i = 0; i < prevDeps.length && i < nextDeps.length; i++) { | |
| 4948 if (objectIs(nextDeps[i], prevDeps[i])) { | |
| 4949 continue; | |
| 4950 } | |
| 4951 | |
| 4952 return false; | |
| 4953 } | |
| 4954 | |
| 4955 return true; | |
| 4956 } | |
| 4957 | |
| 4958 function createHook() { | |
| 4959 if (numberOfReRenders > 0) { | |
| 4960 throw new Error('Rendered more hooks than during the previous render'); | |
| 4961 } | |
| 4962 | |
| 4963 return { | |
| 4964 memoizedState: null, | |
| 4965 queue: null, | |
| 4966 next: null | |
| 4967 }; | |
| 4968 } | |
| 4969 | |
| 4970 function createWorkInProgressHook() { | |
| 4971 if (workInProgressHook === null) { | |
| 4972 // This is the first hook in the list | |
| 4973 if (firstWorkInProgressHook === null) { | |
| 4974 isReRender = false; | |
| 4975 firstWorkInProgressHook = workInProgressHook = createHook(); | |
| 4976 } else { | |
| 4977 // There's already a work-in-progress. Reuse it. | |
| 4978 isReRender = true; | |
| 4979 workInProgressHook = firstWorkInProgressHook; | |
| 4980 } | |
| 4981 } else { | |
| 4982 if (workInProgressHook.next === null) { | |
| 4983 isReRender = false; // Append to the end of the list | |
| 4984 | |
| 4985 workInProgressHook = workInProgressHook.next = createHook(); | |
| 4986 } else { | |
| 4987 // There's already a work-in-progress. Reuse it. | |
| 4988 isReRender = true; | |
| 4989 workInProgressHook = workInProgressHook.next; | |
| 4990 } | |
| 4991 } | |
| 4992 | |
| 4993 return workInProgressHook; | |
| 4994 } | |
| 4995 | |
| 4996 function prepareToUseHooks(task, componentIdentity) { | |
| 4997 currentlyRenderingComponent = componentIdentity; | |
| 4998 currentlyRenderingTask = task; | |
| 4999 | |
| 5000 { | |
| 5001 isInHookUserCodeInDev = false; | |
| 5002 } // The following should have already been reset | |
| 5003 // didScheduleRenderPhaseUpdate = false; | |
| 5004 // localIdCounter = 0; | |
| 5005 // firstWorkInProgressHook = null; | |
| 5006 // numberOfReRenders = 0; | |
| 5007 // renderPhaseUpdates = null; | |
| 5008 // workInProgressHook = null; | |
| 5009 | |
| 5010 | |
| 5011 localIdCounter = 0; | |
| 5012 } | |
| 5013 function finishHooks(Component, props, children, refOrContext) { | |
| 5014 // This must be called after every function component to prevent hooks from | |
| 5015 // being used in classes. | |
| 5016 while (didScheduleRenderPhaseUpdate) { | |
| 5017 // Updates were scheduled during the render phase. They are stored in | |
| 5018 // the `renderPhaseUpdates` map. Call the component again, reusing the | |
| 5019 // work-in-progress hooks and applying the additional updates on top. Keep | |
| 5020 // restarting until no more updates are scheduled. | |
| 5021 didScheduleRenderPhaseUpdate = false; | |
| 5022 localIdCounter = 0; | |
| 5023 numberOfReRenders += 1; // Start over from the beginning of the list | |
| 5024 | |
| 5025 workInProgressHook = null; | |
| 5026 children = Component(props, refOrContext); | |
| 5027 } | |
| 5028 | |
| 5029 resetHooksState(); | |
| 5030 return children; | |
| 5031 } | |
| 5032 function checkDidRenderIdHook() { | |
| 5033 // This should be called immediately after every finishHooks call. | |
| 5034 // Conceptually, it's part of the return value of finishHooks; it's only a | |
| 5035 // separate function to avoid using an array tuple. | |
| 5036 var didRenderIdHook = localIdCounter !== 0; | |
| 5037 return didRenderIdHook; | |
| 5038 } // Reset the internal hooks state if an error occurs while rendering a component | |
| 5039 | |
| 5040 function resetHooksState() { | |
| 5041 { | |
| 5042 isInHookUserCodeInDev = false; | |
| 5043 } | |
| 5044 | |
| 5045 currentlyRenderingComponent = null; | |
| 5046 currentlyRenderingTask = null; | |
| 5047 didScheduleRenderPhaseUpdate = false; | |
| 5048 firstWorkInProgressHook = null; | |
| 5049 numberOfReRenders = 0; | |
| 5050 renderPhaseUpdates = null; | |
| 5051 workInProgressHook = null; | |
| 5052 } | |
| 5053 | |
| 5054 function readContext$1(context) { | |
| 5055 { | |
| 5056 if (isInHookUserCodeInDev) { | |
| 5057 error('Context can only be read while React is rendering. ' + 'In classes, you can read it in the render method or getDerivedStateFromProps. ' + 'In function components, you can read it directly in the function body, but not ' + 'inside Hooks like useReducer() or useMemo().'); | |
| 5058 } | |
| 5059 } | |
| 5060 | |
| 5061 return readContext(context); | |
| 5062 } | |
| 5063 | |
| 5064 function useContext(context) { | |
| 5065 { | |
| 5066 currentHookNameInDev = 'useContext'; | |
| 5067 } | |
| 5068 | |
| 5069 resolveCurrentlyRenderingComponent(); | |
| 5070 return readContext(context); | |
| 5071 } | |
| 5072 | |
| 5073 function basicStateReducer(state, action) { | |
| 5074 // $FlowFixMe: Flow doesn't like mixed types | |
| 5075 return typeof action === 'function' ? action(state) : action; | |
| 5076 } | |
| 5077 | |
| 5078 function useState(initialState) { | |
| 5079 { | |
| 5080 currentHookNameInDev = 'useState'; | |
| 5081 } | |
| 5082 | |
| 5083 return useReducer(basicStateReducer, // useReducer has a special case to support lazy useState initializers | |
| 5084 initialState); | |
| 5085 } | |
| 5086 function useReducer(reducer, initialArg, init) { | |
| 5087 { | |
| 5088 if (reducer !== basicStateReducer) { | |
| 5089 currentHookNameInDev = 'useReducer'; | |
| 5090 } | |
| 5091 } | |
| 5092 | |
| 5093 currentlyRenderingComponent = resolveCurrentlyRenderingComponent(); | |
| 5094 workInProgressHook = createWorkInProgressHook(); | |
| 5095 | |
| 5096 if (isReRender) { | |
| 5097 // This is a re-render. Apply the new render phase updates to the previous | |
| 5098 // current hook. | |
| 5099 var queue = workInProgressHook.queue; | |
| 5100 var dispatch = queue.dispatch; | |
| 5101 | |
| 5102 if (renderPhaseUpdates !== null) { | |
| 5103 // Render phase updates are stored in a map of queue -> linked list | |
| 5104 var firstRenderPhaseUpdate = renderPhaseUpdates.get(queue); | |
| 5105 | |
| 5106 if (firstRenderPhaseUpdate !== undefined) { | |
| 5107 renderPhaseUpdates.delete(queue); | |
| 5108 var newState = workInProgressHook.memoizedState; | |
| 5109 var update = firstRenderPhaseUpdate; | |
| 5110 | |
| 5111 do { | |
| 5112 // Process this render phase update. We don't have to check the | |
| 5113 // priority because it will always be the same as the current | |
| 5114 // render's. | |
| 5115 var action = update.action; | |
| 5116 | |
| 5117 { | |
| 5118 isInHookUserCodeInDev = true; | |
| 5119 } | |
| 5120 | |
| 5121 newState = reducer(newState, action); | |
| 5122 | |
| 5123 { | |
| 5124 isInHookUserCodeInDev = false; | |
| 5125 } | |
| 5126 | |
| 5127 update = update.next; | |
| 5128 } while (update !== null); | |
| 5129 | |
| 5130 workInProgressHook.memoizedState = newState; | |
| 5131 return [newState, dispatch]; | |
| 5132 } | |
| 5133 } | |
| 5134 | |
| 5135 return [workInProgressHook.memoizedState, dispatch]; | |
| 5136 } else { | |
| 5137 { | |
| 5138 isInHookUserCodeInDev = true; | |
| 5139 } | |
| 5140 | |
| 5141 var initialState; | |
| 5142 | |
| 5143 if (reducer === basicStateReducer) { | |
| 5144 // Special case for `useState`. | |
| 5145 initialState = typeof initialArg === 'function' ? initialArg() : initialArg; | |
| 5146 } else { | |
| 5147 initialState = init !== undefined ? init(initialArg) : initialArg; | |
| 5148 } | |
| 5149 | |
| 5150 { | |
| 5151 isInHookUserCodeInDev = false; | |
| 5152 } | |
| 5153 | |
| 5154 workInProgressHook.memoizedState = initialState; | |
| 5155 | |
| 5156 var _queue = workInProgressHook.queue = { | |
| 5157 last: null, | |
| 5158 dispatch: null | |
| 5159 }; | |
| 5160 | |
| 5161 var _dispatch = _queue.dispatch = dispatchAction.bind(null, currentlyRenderingComponent, _queue); | |
| 5162 | |
| 5163 return [workInProgressHook.memoizedState, _dispatch]; | |
| 5164 } | |
| 5165 } | |
| 5166 | |
| 5167 function useMemo(nextCreate, deps) { | |
| 5168 currentlyRenderingComponent = resolveCurrentlyRenderingComponent(); | |
| 5169 workInProgressHook = createWorkInProgressHook(); | |
| 5170 var nextDeps = deps === undefined ? null : deps; | |
| 5171 | |
| 5172 if (workInProgressHook !== null) { | |
| 5173 var prevState = workInProgressHook.memoizedState; | |
| 5174 | |
| 5175 if (prevState !== null) { | |
| 5176 if (nextDeps !== null) { | |
| 5177 var prevDeps = prevState[1]; | |
| 5178 | |
| 5179 if (areHookInputsEqual(nextDeps, prevDeps)) { | |
| 5180 return prevState[0]; | |
| 5181 } | |
| 5182 } | |
| 5183 } | |
| 5184 } | |
| 5185 | |
| 5186 { | |
| 5187 isInHookUserCodeInDev = true; | |
| 5188 } | |
| 5189 | |
| 5190 var nextValue = nextCreate(); | |
| 5191 | |
| 5192 { | |
| 5193 isInHookUserCodeInDev = false; | |
| 5194 } | |
| 5195 | |
| 5196 workInProgressHook.memoizedState = [nextValue, nextDeps]; | |
| 5197 return nextValue; | |
| 5198 } | |
| 5199 | |
| 5200 function useRef(initialValue) { | |
| 5201 currentlyRenderingComponent = resolveCurrentlyRenderingComponent(); | |
| 5202 workInProgressHook = createWorkInProgressHook(); | |
| 5203 var previousRef = workInProgressHook.memoizedState; | |
| 5204 | |
| 5205 if (previousRef === null) { | |
| 5206 var ref = { | |
| 5207 current: initialValue | |
| 5208 }; | |
| 5209 | |
| 5210 { | |
| 5211 Object.seal(ref); | |
| 5212 } | |
| 5213 | |
| 5214 workInProgressHook.memoizedState = ref; | |
| 5215 return ref; | |
| 5216 } else { | |
| 5217 return previousRef; | |
| 5218 } | |
| 5219 } | |
| 5220 | |
| 5221 function useLayoutEffect(create, inputs) { | |
| 5222 { | |
| 5223 currentHookNameInDev = 'useLayoutEffect'; | |
| 5224 | |
| 5225 error('useLayoutEffect does nothing on the server, because its effect cannot ' + "be encoded into the server renderer's output format. This will lead " + 'to a mismatch between the initial, non-hydrated UI and the intended ' + 'UI. To avoid this, useLayoutEffect should only be used in ' + 'components that render exclusively on the client. ' + 'See https://reactjs.org/link/uselayouteffect-ssr for common fixes.'); | |
| 5226 } | |
| 5227 } | |
| 5228 | |
| 5229 function dispatchAction(componentIdentity, queue, action) { | |
| 5230 if (numberOfReRenders >= RE_RENDER_LIMIT) { | |
| 5231 throw new Error('Too many re-renders. React limits the number of renders to prevent ' + 'an infinite loop.'); | |
| 5232 } | |
| 5233 | |
| 5234 if (componentIdentity === currentlyRenderingComponent) { | |
| 5235 // This is a render phase update. Stash it in a lazily-created map of | |
| 5236 // queue -> linked list of updates. After this render pass, we'll restart | |
| 5237 // and apply the stashed updates on top of the work-in-progress hook. | |
| 5238 didScheduleRenderPhaseUpdate = true; | |
| 5239 var update = { | |
| 5240 action: action, | |
| 5241 next: null | |
| 5242 }; | |
| 5243 | |
| 5244 if (renderPhaseUpdates === null) { | |
| 5245 renderPhaseUpdates = new Map(); | |
| 5246 } | |
| 5247 | |
| 5248 var firstRenderPhaseUpdate = renderPhaseUpdates.get(queue); | |
| 5249 | |
| 5250 if (firstRenderPhaseUpdate === undefined) { | |
| 5251 renderPhaseUpdates.set(queue, update); | |
| 5252 } else { | |
| 5253 // Append the update to the end of the list. | |
| 5254 var lastRenderPhaseUpdate = firstRenderPhaseUpdate; | |
| 5255 | |
| 5256 while (lastRenderPhaseUpdate.next !== null) { | |
| 5257 lastRenderPhaseUpdate = lastRenderPhaseUpdate.next; | |
| 5258 } | |
| 5259 | |
| 5260 lastRenderPhaseUpdate.next = update; | |
| 5261 } | |
| 5262 } | |
| 5263 } | |
| 5264 | |
| 5265 function useCallback(callback, deps) { | |
| 5266 return useMemo(function () { | |
| 5267 return callback; | |
| 5268 }, deps); | |
| 5269 } // TODO Decide on how to implement this hook for server rendering. | |
| 5270 // If a mutation occurs during render, consider triggering a Suspense boundary | |
| 5271 // and falling back to client rendering. | |
| 5272 | |
| 5273 function useMutableSource(source, getSnapshot, subscribe) { | |
| 5274 resolveCurrentlyRenderingComponent(); | |
| 5275 return getSnapshot(source._source); | |
| 5276 } | |
| 5277 | |
| 5278 function useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot) { | |
| 5279 if (getServerSnapshot === undefined) { | |
| 5280 throw new Error('Missing getServerSnapshot, which is required for ' + 'server-rendered content. Will revert to client rendering.'); | |
| 5281 } | |
| 5282 | |
| 5283 return getServerSnapshot(); | |
| 5284 } | |
| 5285 | |
| 5286 function useDeferredValue(value) { | |
| 5287 resolveCurrentlyRenderingComponent(); | |
| 5288 return value; | |
| 5289 } | |
| 5290 | |
| 5291 function unsupportedStartTransition() { | |
| 5292 throw new Error('startTransition cannot be called during server rendering.'); | |
| 5293 } | |
| 5294 | |
| 5295 function useTransition() { | |
| 5296 resolveCurrentlyRenderingComponent(); | |
| 5297 return [false, unsupportedStartTransition]; | |
| 5298 } | |
| 5299 | |
| 5300 function useId() { | |
| 5301 var task = currentlyRenderingTask; | |
| 5302 var treeId = getTreeId(task.treeContext); | |
| 5303 var responseState = currentResponseState; | |
| 5304 | |
| 5305 if (responseState === null) { | |
| 5306 throw new Error('Invalid hook call. Hooks can only be called inside of the body of a function component.'); | |
| 5307 } | |
| 5308 | |
| 5309 var localId = localIdCounter++; | |
| 5310 return makeId(responseState, treeId, localId); | |
| 5311 } | |
| 5312 | |
| 5313 function noop() {} | |
| 5314 | |
| 5315 var Dispatcher = { | |
| 5316 readContext: readContext$1, | |
| 5317 useContext: useContext, | |
| 5318 useMemo: useMemo, | |
| 5319 useReducer: useReducer, | |
| 5320 useRef: useRef, | |
| 5321 useState: useState, | |
| 5322 useInsertionEffect: noop, | |
| 5323 useLayoutEffect: useLayoutEffect, | |
| 5324 useCallback: useCallback, | |
| 5325 // useImperativeHandle is not run in the server environment | |
| 5326 useImperativeHandle: noop, | |
| 5327 // Effects are not run in the server environment. | |
| 5328 useEffect: noop, | |
| 5329 // Debugging effect | |
| 5330 useDebugValue: noop, | |
| 5331 useDeferredValue: useDeferredValue, | |
| 5332 useTransition: useTransition, | |
| 5333 useId: useId, | |
| 5334 // Subscriptions are not setup in a server environment. | |
| 5335 useMutableSource: useMutableSource, | |
| 5336 useSyncExternalStore: useSyncExternalStore | |
| 5337 }; | |
| 5338 | |
| 5339 var currentResponseState = null; | |
| 5340 function setCurrentResponseState(responseState) { | |
| 5341 currentResponseState = responseState; | |
| 5342 } | |
| 5343 | |
| 5344 function getStackByComponentStackNode(componentStack) { | |
| 5345 try { | |
| 5346 var info = ''; | |
| 5347 var node = componentStack; | |
| 5348 | |
| 5349 do { | |
| 5350 switch (node.tag) { | |
| 5351 case 0: | |
| 5352 info += describeBuiltInComponentFrame(node.type, null, null); | |
| 5353 break; | |
| 5354 | |
| 5355 case 1: | |
| 5356 info += describeFunctionComponentFrame(node.type, null, null); | |
| 5357 break; | |
| 5358 | |
| 5359 case 2: | |
| 5360 info += describeClassComponentFrame(node.type, null, null); | |
| 5361 break; | |
| 5362 } | |
| 5363 | |
| 5364 node = node.parent; | |
| 5365 } while (node); | |
| 5366 | |
| 5367 return info; | |
| 5368 } catch (x) { | |
| 5369 return '\nError generating stack: ' + x.message + '\n' + x.stack; | |
| 5370 } | |
| 5371 } | |
| 5372 | |
| 5373 var ReactCurrentDispatcher$1 = ReactSharedInternals.ReactCurrentDispatcher; | |
| 5374 var ReactDebugCurrentFrame$1 = ReactSharedInternals.ReactDebugCurrentFrame; | |
| 5375 var PENDING = 0; | |
| 5376 var COMPLETED = 1; | |
| 5377 var FLUSHED = 2; | |
| 5378 var ABORTED = 3; | |
| 5379 var ERRORED = 4; | |
| 5380 var OPEN = 0; | |
| 5381 var CLOSING = 1; | |
| 5382 var CLOSED = 2; | |
| 5383 // This is a default heuristic for how to split up the HTML content into progressive | |
| 5384 // loading. Our goal is to be able to display additional new content about every 500ms. | |
| 5385 // Faster than that is unnecessary and should be throttled on the client. It also | |
| 5386 // adds unnecessary overhead to do more splits. We don't know if it's a higher or lower | |
| 5387 // end device but higher end suffer less from the overhead than lower end does from | |
| 5388 // not getting small enough pieces. We error on the side of low end. | |
| 5389 // We base this on low end 3G speeds which is about 500kbits per second. We assume | |
| 5390 // that there can be a reasonable drop off from max bandwidth which leaves you with | |
| 5391 // as little as 80%. We can receive half of that each 500ms - at best. In practice, | |
| 5392 // a little bandwidth is lost to processing and contention - e.g. CSS and images that | |
| 5393 // are downloaded along with the main content. So we estimate about half of that to be | |
| 5394 // the lower end throughput. In other words, we expect that you can at least show | |
| 5395 // about 12.5kb of content per 500ms. Not counting starting latency for the first | |
| 5396 // paint. | |
| 5397 // 500 * 1024 / 8 * .8 * 0.5 / 2 | |
| 5398 var DEFAULT_PROGRESSIVE_CHUNK_SIZE = 12800; | |
| 5399 | |
| 5400 function defaultErrorHandler(error) { | |
| 5401 console['error'](error); // Don't transform to our wrapper | |
| 5402 | |
| 5403 return null; | |
| 5404 } | |
| 5405 | |
| 5406 function noop$1() {} | |
| 5407 | |
| 5408 function createRequest(children, responseState, rootFormatContext, progressiveChunkSize, onError, onAllReady, onShellReady, onShellError, onFatalError) { | |
| 5409 var pingedTasks = []; | |
| 5410 var abortSet = new Set(); | |
| 5411 var request = { | |
| 5412 destination: null, | |
| 5413 responseState: responseState, | |
| 5414 progressiveChunkSize: progressiveChunkSize === undefined ? DEFAULT_PROGRESSIVE_CHUNK_SIZE : progressiveChunkSize, | |
| 5415 status: OPEN, | |
| 5416 fatalError: null, | |
| 5417 nextSegmentId: 0, | |
| 5418 allPendingTasks: 0, | |
| 5419 pendingRootTasks: 0, | |
| 5420 completedRootSegment: null, | |
| 5421 abortableTasks: abortSet, | |
| 5422 pingedTasks: pingedTasks, | |
| 5423 clientRenderedBoundaries: [], | |
| 5424 completedBoundaries: [], | |
| 5425 partialBoundaries: [], | |
| 5426 onError: onError === undefined ? defaultErrorHandler : onError, | |
| 5427 onAllReady: onAllReady === undefined ? noop$1 : onAllReady, | |
| 5428 onShellReady: onShellReady === undefined ? noop$1 : onShellReady, | |
| 5429 onShellError: onShellError === undefined ? noop$1 : onShellError, | |
| 5430 onFatalError: onFatalError === undefined ? noop$1 : onFatalError | |
| 5431 }; // This segment represents the root fallback. | |
| 5432 | |
| 5433 var rootSegment = createPendingSegment(request, 0, null, rootFormatContext, // Root segments are never embedded in Text on either edge | |
| 5434 false, false); // There is no parent so conceptually, we're unblocked to flush this segment. | |
| 5435 | |
| 5436 rootSegment.parentFlushed = true; | |
| 5437 var rootTask = createTask(request, children, null, rootSegment, abortSet, emptyContextObject, rootContextSnapshot, emptyTreeContext); | |
| 5438 pingedTasks.push(rootTask); | |
| 5439 return request; | |
| 5440 } | |
| 5441 | |
| 5442 function pingTask(request, task) { | |
| 5443 var pingedTasks = request.pingedTasks; | |
| 5444 pingedTasks.push(task); | |
| 5445 | |
| 5446 if (pingedTasks.length === 1) { | |
| 5447 scheduleWork(function () { | |
| 5448 return performWork(request); | |
| 5449 }); | |
| 5450 } | |
| 5451 } | |
| 5452 | |
| 5453 function createSuspenseBoundary(request, fallbackAbortableTasks) { | |
| 5454 return { | |
| 5455 id: UNINITIALIZED_SUSPENSE_BOUNDARY_ID, | |
| 5456 rootSegmentID: -1, | |
| 5457 parentFlushed: false, | |
| 5458 pendingTasks: 0, | |
| 5459 forceClientRender: false, | |
| 5460 completedSegments: [], | |
| 5461 byteSize: 0, | |
| 5462 fallbackAbortableTasks: fallbackAbortableTasks, | |
| 5463 errorDigest: null | |
| 5464 }; | |
| 5465 } | |
| 5466 | |
| 5467 function createTask(request, node, blockedBoundary, blockedSegment, abortSet, legacyContext, context, treeContext) { | |
| 5468 request.allPendingTasks++; | |
| 5469 | |
| 5470 if (blockedBoundary === null) { | |
| 5471 request.pendingRootTasks++; | |
| 5472 } else { | |
| 5473 blockedBoundary.pendingTasks++; | |
| 5474 } | |
| 5475 | |
| 5476 var task = { | |
| 5477 node: node, | |
| 5478 ping: function () { | |
| 5479 return pingTask(request, task); | |
| 5480 }, | |
| 5481 blockedBoundary: blockedBoundary, | |
| 5482 blockedSegment: blockedSegment, | |
| 5483 abortSet: abortSet, | |
| 5484 legacyContext: legacyContext, | |
| 5485 context: context, | |
| 5486 treeContext: treeContext | |
| 5487 }; | |
| 5488 | |
| 5489 { | |
| 5490 task.componentStack = null; | |
| 5491 } | |
| 5492 | |
| 5493 abortSet.add(task); | |
| 5494 return task; | |
| 5495 } | |
| 5496 | |
| 5497 function createPendingSegment(request, index, boundary, formatContext, lastPushedText, textEmbedded) { | |
| 5498 return { | |
| 5499 status: PENDING, | |
| 5500 id: -1, | |
| 5501 // lazily assigned later | |
| 5502 index: index, | |
| 5503 parentFlushed: false, | |
| 5504 chunks: [], | |
| 5505 children: [], | |
| 5506 formatContext: formatContext, | |
| 5507 boundary: boundary, | |
| 5508 lastPushedText: lastPushedText, | |
| 5509 textEmbedded: textEmbedded | |
| 5510 }; | |
| 5511 } // DEV-only global reference to the currently executing task | |
| 5512 | |
| 5513 | |
| 5514 var currentTaskInDEV = null; | |
| 5515 | |
| 5516 function getCurrentStackInDEV() { | |
| 5517 { | |
| 5518 if (currentTaskInDEV === null || currentTaskInDEV.componentStack === null) { | |
| 5519 return ''; | |
| 5520 } | |
| 5521 | |
| 5522 return getStackByComponentStackNode(currentTaskInDEV.componentStack); | |
| 5523 } | |
| 5524 } | |
| 5525 | |
| 5526 function pushBuiltInComponentStackInDEV(task, type) { | |
| 5527 { | |
| 5528 task.componentStack = { | |
| 5529 tag: 0, | |
| 5530 parent: task.componentStack, | |
| 5531 type: type | |
| 5532 }; | |
| 5533 } | |
| 5534 } | |
| 5535 | |
| 5536 function pushFunctionComponentStackInDEV(task, type) { | |
| 5537 { | |
| 5538 task.componentStack = { | |
| 5539 tag: 1, | |
| 5540 parent: task.componentStack, | |
| 5541 type: type | |
| 5542 }; | |
| 5543 } | |
| 5544 } | |
| 5545 | |
| 5546 function pushClassComponentStackInDEV(task, type) { | |
| 5547 { | |
| 5548 task.componentStack = { | |
| 5549 tag: 2, | |
| 5550 parent: task.componentStack, | |
| 5551 type: type | |
| 5552 }; | |
| 5553 } | |
| 5554 } | |
| 5555 | |
| 5556 function popComponentStackInDEV(task) { | |
| 5557 { | |
| 5558 if (task.componentStack === null) { | |
| 5559 error('Unexpectedly popped too many stack frames. This is a bug in React.'); | |
| 5560 } else { | |
| 5561 task.componentStack = task.componentStack.parent; | |
| 5562 } | |
| 5563 } | |
| 5564 } // stash the component stack of an unwinding error until it is processed | |
| 5565 | |
| 5566 | |
| 5567 var lastBoundaryErrorComponentStackDev = null; | |
| 5568 | |
| 5569 function captureBoundaryErrorDetailsDev(boundary, error) { | |
| 5570 { | |
| 5571 var errorMessage; | |
| 5572 | |
| 5573 if (typeof error === 'string') { | |
| 5574 errorMessage = error; | |
| 5575 } else if (error && typeof error.message === 'string') { | |
| 5576 errorMessage = error.message; | |
| 5577 } else { | |
| 5578 // eslint-disable-next-line react-internal/safe-string-coercion | |
| 5579 errorMessage = String(error); | |
| 5580 } | |
| 5581 | |
| 5582 var errorComponentStack = lastBoundaryErrorComponentStackDev || getCurrentStackInDEV(); | |
| 5583 lastBoundaryErrorComponentStackDev = null; | |
| 5584 boundary.errorMessage = errorMessage; | |
| 5585 boundary.errorComponentStack = errorComponentStack; | |
| 5586 } | |
| 5587 } | |
| 5588 | |
| 5589 function logRecoverableError(request, error) { | |
| 5590 // If this callback errors, we intentionally let that error bubble up to become a fatal error | |
| 5591 // so that someone fixes the error reporting instead of hiding it. | |
| 5592 var errorDigest = request.onError(error); | |
| 5593 | |
| 5594 if (errorDigest != null && typeof errorDigest !== 'string') { | |
| 5595 // eslint-disable-next-line react-internal/prod-error-codes | |
| 5596 throw new Error("onError returned something with a type other than \"string\". onError should return a string and may return null or undefined but must not return anything else. It received something of type \"" + typeof errorDigest + "\" instead"); | |
| 5597 } | |
| 5598 | |
| 5599 return errorDigest; | |
| 5600 } | |
| 5601 | |
| 5602 function fatalError(request, error) { | |
| 5603 // This is called outside error handling code such as if the root errors outside | |
| 5604 // a suspense boundary or if the root suspense boundary's fallback errors. | |
| 5605 // It's also called if React itself or its host configs errors. | |
| 5606 var onShellError = request.onShellError; | |
| 5607 onShellError(error); | |
| 5608 var onFatalError = request.onFatalError; | |
| 5609 onFatalError(error); | |
| 5610 | |
| 5611 if (request.destination !== null) { | |
| 5612 request.status = CLOSED; | |
| 5613 closeWithError(request.destination, error); | |
| 5614 } else { | |
| 5615 request.status = CLOSING; | |
| 5616 request.fatalError = error; | |
| 5617 } | |
| 5618 } | |
| 5619 | |
| 5620 function renderSuspenseBoundary(request, task, props) { | |
| 5621 pushBuiltInComponentStackInDEV(task, 'Suspense'); | |
| 5622 var parentBoundary = task.blockedBoundary; | |
| 5623 var parentSegment = task.blockedSegment; // Each time we enter a suspense boundary, we split out into a new segment for | |
| 5624 // the fallback so that we can later replace that segment with the content. | |
| 5625 // This also lets us split out the main content even if it doesn't suspend, | |
| 5626 // in case it ends up generating a large subtree of content. | |
| 5627 | |
| 5628 var fallback = props.fallback; | |
| 5629 var content = props.children; | |
| 5630 var fallbackAbortSet = new Set(); | |
| 5631 var newBoundary = createSuspenseBoundary(request, fallbackAbortSet); | |
| 5632 var insertionIndex = parentSegment.chunks.length; // The children of the boundary segment is actually the fallback. | |
| 5633 | |
| 5634 var boundarySegment = createPendingSegment(request, insertionIndex, newBoundary, parentSegment.formatContext, // boundaries never require text embedding at their edges because comment nodes bound them | |
| 5635 false, false); | |
| 5636 parentSegment.children.push(boundarySegment); // The parentSegment has a child Segment at this index so we reset the lastPushedText marker on the parent | |
| 5637 | |
| 5638 parentSegment.lastPushedText = false; // This segment is the actual child content. We can start rendering that immediately. | |
| 5639 | |
| 5640 var contentRootSegment = createPendingSegment(request, 0, null, parentSegment.formatContext, // boundaries never require text embedding at their edges because comment nodes bound them | |
| 5641 false, false); // We mark the root segment as having its parent flushed. It's not really flushed but there is | |
| 5642 // no parent segment so there's nothing to wait on. | |
| 5643 | |
| 5644 contentRootSegment.parentFlushed = true; // Currently this is running synchronously. We could instead schedule this to pingedTasks. | |
| 5645 // I suspect that there might be some efficiency benefits from not creating the suspended task | |
| 5646 // and instead just using the stack if possible. | |
| 5647 // TODO: Call this directly instead of messing with saving and restoring contexts. | |
| 5648 // We can reuse the current context and task to render the content immediately without | |
| 5649 // context switching. We just need to temporarily switch which boundary and which segment | |
| 5650 // we're writing to. If something suspends, it'll spawn new suspended task with that context. | |
| 5651 | |
| 5652 task.blockedBoundary = newBoundary; | |
| 5653 task.blockedSegment = contentRootSegment; | |
| 5654 | |
| 5655 try { | |
| 5656 // We use the safe form because we don't handle suspending here. Only error handling. | |
| 5657 renderNode(request, task, content); | |
| 5658 pushSegmentFinale(contentRootSegment.chunks, request.responseState, contentRootSegment.lastPushedText, contentRootSegment.textEmbedded); | |
| 5659 contentRootSegment.status = COMPLETED; | |
| 5660 queueCompletedSegment(newBoundary, contentRootSegment); | |
| 5661 | |
| 5662 if (newBoundary.pendingTasks === 0) { | |
| 5663 // This must have been the last segment we were waiting on. This boundary is now complete. | |
| 5664 // Therefore we won't need the fallback. We early return so that we don't have to create | |
| 5665 // the fallback. | |
| 5666 popComponentStackInDEV(task); | |
| 5667 return; | |
| 5668 } | |
| 5669 } catch (error) { | |
| 5670 contentRootSegment.status = ERRORED; | |
| 5671 newBoundary.forceClientRender = true; | |
| 5672 newBoundary.errorDigest = logRecoverableError(request, error); | |
| 5673 | |
| 5674 { | |
| 5675 captureBoundaryErrorDetailsDev(newBoundary, error); | |
| 5676 } // We don't need to decrement any task numbers because we didn't spawn any new task. | |
| 5677 // We don't need to schedule any task because we know the parent has written yet. | |
| 5678 // We do need to fallthrough to create the fallback though. | |
| 5679 | |
| 5680 } finally { | |
| 5681 task.blockedBoundary = parentBoundary; | |
| 5682 task.blockedSegment = parentSegment; | |
| 5683 } // We create suspended task for the fallback because we don't want to actually work | |
| 5684 // on it yet in case we finish the main content, so we queue for later. | |
| 5685 | |
| 5686 | |
| 5687 var suspendedFallbackTask = createTask(request, fallback, parentBoundary, boundarySegment, fallbackAbortSet, task.legacyContext, task.context, task.treeContext); | |
| 5688 | |
| 5689 { | |
| 5690 suspendedFallbackTask.componentStack = task.componentStack; | |
| 5691 } // TODO: This should be queued at a separate lower priority queue so that we only work | |
| 5692 // on preparing fallbacks if we don't have any more main content to task on. | |
| 5693 | |
| 5694 | |
| 5695 request.pingedTasks.push(suspendedFallbackTask); | |
| 5696 popComponentStackInDEV(task); | |
| 5697 } | |
| 5698 | |
| 5699 function renderHostElement(request, task, type, props) { | |
| 5700 pushBuiltInComponentStackInDEV(task, type); | |
| 5701 var segment = task.blockedSegment; | |
| 5702 var children = pushStartInstance(segment.chunks, type, props, request.responseState, segment.formatContext); | |
| 5703 segment.lastPushedText = false; | |
| 5704 var prevContext = segment.formatContext; | |
| 5705 segment.formatContext = getChildFormatContext(prevContext, type, props); // We use the non-destructive form because if something suspends, we still | |
| 5706 // need to pop back up and finish this subtree of HTML. | |
| 5707 | |
| 5708 renderNode(request, task, children); // We expect that errors will fatal the whole task and that we don't need | |
| 5709 // the correct context. Therefore this is not in a finally. | |
| 5710 | |
| 5711 segment.formatContext = prevContext; | |
| 5712 pushEndInstance(segment.chunks, type); | |
| 5713 segment.lastPushedText = false; | |
| 5714 popComponentStackInDEV(task); | |
| 5715 } | |
| 5716 | |
| 5717 function shouldConstruct$1(Component) { | |
| 5718 return Component.prototype && Component.prototype.isReactComponent; | |
| 5719 } | |
| 5720 | |
| 5721 function renderWithHooks(request, task, Component, props, secondArg) { | |
| 5722 var componentIdentity = {}; | |
| 5723 prepareToUseHooks(task, componentIdentity); | |
| 5724 var result = Component(props, secondArg); | |
| 5725 return finishHooks(Component, props, result, secondArg); | |
| 5726 } | |
| 5727 | |
| 5728 function finishClassComponent(request, task, instance, Component, props) { | |
| 5729 var nextChildren = instance.render(); | |
| 5730 | |
| 5731 { | |
| 5732 if (instance.props !== props) { | |
| 5733 if (!didWarnAboutReassigningProps) { | |
| 5734 error('It looks like %s is reassigning its own `this.props` while rendering. ' + 'This is not supported and can lead to confusing bugs.', getComponentNameFromType(Component) || 'a component'); | |
| 5735 } | |
| 5736 | |
| 5737 didWarnAboutReassigningProps = true; | |
| 5738 } | |
| 5739 } | |
| 5740 | |
| 5741 { | |
| 5742 var childContextTypes = Component.childContextTypes; | |
| 5743 | |
| 5744 if (childContextTypes !== null && childContextTypes !== undefined) { | |
| 5745 var previousContext = task.legacyContext; | |
| 5746 var mergedContext = processChildContext(instance, Component, previousContext, childContextTypes); | |
| 5747 task.legacyContext = mergedContext; | |
| 5748 renderNodeDestructive(request, task, nextChildren); | |
| 5749 task.legacyContext = previousContext; | |
| 5750 return; | |
| 5751 } | |
| 5752 } | |
| 5753 | |
| 5754 renderNodeDestructive(request, task, nextChildren); | |
| 5755 } | |
| 5756 | |
| 5757 function renderClassComponent(request, task, Component, props) { | |
| 5758 pushClassComponentStackInDEV(task, Component); | |
| 5759 var maskedContext = getMaskedContext(Component, task.legacyContext) ; | |
| 5760 var instance = constructClassInstance(Component, props, maskedContext); | |
| 5761 mountClassInstance(instance, Component, props, maskedContext); | |
| 5762 finishClassComponent(request, task, instance, Component, props); | |
| 5763 popComponentStackInDEV(task); | |
| 5764 } | |
| 5765 | |
| 5766 var didWarnAboutBadClass = {}; | |
| 5767 var didWarnAboutModulePatternComponent = {}; | |
| 5768 var didWarnAboutContextTypeOnFunctionComponent = {}; | |
| 5769 var didWarnAboutGetDerivedStateOnFunctionComponent = {}; | |
| 5770 var didWarnAboutReassigningProps = false; | |
| 5771 var didWarnAboutDefaultPropsOnFunctionComponent = {}; | |
| 5772 var didWarnAboutGenerators = false; | |
| 5773 var didWarnAboutMaps = false; | |
| 5774 var hasWarnedAboutUsingContextAsConsumer = false; // This would typically be a function component but we still support module pattern | |
| 5775 // components for some reason. | |
| 5776 | |
| 5777 function renderIndeterminateComponent(request, task, Component, props) { | |
| 5778 var legacyContext; | |
| 5779 | |
| 5780 { | |
| 5781 legacyContext = getMaskedContext(Component, task.legacyContext); | |
| 5782 } | |
| 5783 | |
| 5784 pushFunctionComponentStackInDEV(task, Component); | |
| 5785 | |
| 5786 { | |
| 5787 if (Component.prototype && typeof Component.prototype.render === 'function') { | |
| 5788 var componentName = getComponentNameFromType(Component) || 'Unknown'; | |
| 5789 | |
| 5790 if (!didWarnAboutBadClass[componentName]) { | |
| 5791 error("The <%s /> component appears to have a render method, but doesn't extend React.Component. " + 'This is likely to cause errors. Change %s to extend React.Component instead.', componentName, componentName); | |
| 5792 | |
| 5793 didWarnAboutBadClass[componentName] = true; | |
| 5794 } | |
| 5795 } | |
| 5796 } | |
| 5797 | |
| 5798 var value = renderWithHooks(request, task, Component, props, legacyContext); | |
| 5799 var hasId = checkDidRenderIdHook(); | |
| 5800 | |
| 5801 { | |
| 5802 // Support for module components is deprecated and is removed behind a flag. | |
| 5803 // Whether or not it would crash later, we want to show a good message in DEV first. | |
| 5804 if (typeof value === 'object' && value !== null && typeof value.render === 'function' && value.$$typeof === undefined) { | |
| 5805 var _componentName = getComponentNameFromType(Component) || 'Unknown'; | |
| 5806 | |
| 5807 if (!didWarnAboutModulePatternComponent[_componentName]) { | |
| 5808 error('The <%s /> component appears to be a function component that returns a class instance. ' + 'Change %s to a class that extends React.Component instead. ' + "If you can't use a class try assigning the prototype on the function as a workaround. " + "`%s.prototype = React.Component.prototype`. Don't use an arrow function since it " + 'cannot be called with `new` by React.', _componentName, _componentName, _componentName); | |
| 5809 | |
| 5810 didWarnAboutModulePatternComponent[_componentName] = true; | |
| 5811 } | |
| 5812 } | |
| 5813 } | |
| 5814 | |
| 5815 if ( // Run these checks in production only if the flag is off. | |
| 5816 // Eventually we'll delete this branch altogether. | |
| 5817 typeof value === 'object' && value !== null && typeof value.render === 'function' && value.$$typeof === undefined) { | |
| 5818 { | |
| 5819 var _componentName2 = getComponentNameFromType(Component) || 'Unknown'; | |
| 5820 | |
| 5821 if (!didWarnAboutModulePatternComponent[_componentName2]) { | |
| 5822 error('The <%s /> component appears to be a function component that returns a class instance. ' + 'Change %s to a class that extends React.Component instead. ' + "If you can't use a class try assigning the prototype on the function as a workaround. " + "`%s.prototype = React.Component.prototype`. Don't use an arrow function since it " + 'cannot be called with `new` by React.', _componentName2, _componentName2, _componentName2); | |
| 5823 | |
| 5824 didWarnAboutModulePatternComponent[_componentName2] = true; | |
| 5825 } | |
| 5826 } | |
| 5827 | |
| 5828 mountClassInstance(value, Component, props, legacyContext); | |
| 5829 finishClassComponent(request, task, value, Component, props); | |
| 5830 } else { | |
| 5831 | |
| 5832 { | |
| 5833 validateFunctionComponentInDev(Component); | |
| 5834 } // We're now successfully past this task, and we don't have to pop back to | |
| 5835 // the previous task every again, so we can use the destructive recursive form. | |
| 5836 | |
| 5837 | |
| 5838 if (hasId) { | |
| 5839 // This component materialized an id. We treat this as its own level, with | |
| 5840 // a single "child" slot. | |
| 5841 var prevTreeContext = task.treeContext; | |
| 5842 var totalChildren = 1; | |
| 5843 var index = 0; | |
| 5844 task.treeContext = pushTreeContext(prevTreeContext, totalChildren, index); | |
| 5845 | |
| 5846 try { | |
| 5847 renderNodeDestructive(request, task, value); | |
| 5848 } finally { | |
| 5849 task.treeContext = prevTreeContext; | |
| 5850 } | |
| 5851 } else { | |
| 5852 renderNodeDestructive(request, task, value); | |
| 5853 } | |
| 5854 } | |
| 5855 | |
| 5856 popComponentStackInDEV(task); | |
| 5857 } | |
| 5858 | |
| 5859 function validateFunctionComponentInDev(Component) { | |
| 5860 { | |
| 5861 if (Component) { | |
| 5862 if (Component.childContextTypes) { | |
| 5863 error('%s(...): childContextTypes cannot be defined on a function component.', Component.displayName || Component.name || 'Component'); | |
| 5864 } | |
| 5865 } | |
| 5866 | |
| 5867 if ( Component.defaultProps !== undefined) { | |
| 5868 var componentName = getComponentNameFromType(Component) || 'Unknown'; | |
| 5869 | |
| 5870 if (!didWarnAboutDefaultPropsOnFunctionComponent[componentName]) { | |
| 5871 error('%s: Support for defaultProps will be removed from function components ' + 'in a future major release. Use JavaScript default parameters instead.', componentName); | |
| 5872 | |
| 5873 didWarnAboutDefaultPropsOnFunctionComponent[componentName] = true; | |
| 5874 } | |
| 5875 } | |
| 5876 | |
| 5877 if (typeof Component.getDerivedStateFromProps === 'function') { | |
| 5878 var _componentName3 = getComponentNameFromType(Component) || 'Unknown'; | |
| 5879 | |
| 5880 if (!didWarnAboutGetDerivedStateOnFunctionComponent[_componentName3]) { | |
| 5881 error('%s: Function components do not support getDerivedStateFromProps.', _componentName3); | |
| 5882 | |
| 5883 didWarnAboutGetDerivedStateOnFunctionComponent[_componentName3] = true; | |
| 5884 } | |
| 5885 } | |
| 5886 | |
| 5887 if (typeof Component.contextType === 'object' && Component.contextType !== null) { | |
| 5888 var _componentName4 = getComponentNameFromType(Component) || 'Unknown'; | |
| 5889 | |
| 5890 if (!didWarnAboutContextTypeOnFunctionComponent[_componentName4]) { | |
| 5891 error('%s: Function components do not support contextType.', _componentName4); | |
| 5892 | |
| 5893 didWarnAboutContextTypeOnFunctionComponent[_componentName4] = true; | |
| 5894 } | |
| 5895 } | |
| 5896 } | |
| 5897 } | |
| 5898 | |
| 5899 function resolveDefaultProps(Component, baseProps) { | |
| 5900 if (Component && Component.defaultProps) { | |
| 5901 // Resolve default props. Taken from ReactElement | |
| 5902 var props = assign({}, baseProps); | |
| 5903 var defaultProps = Component.defaultProps; | |
| 5904 | |
| 5905 for (var propName in defaultProps) { | |
| 5906 if (props[propName] === undefined) { | |
| 5907 props[propName] = defaultProps[propName]; | |
| 5908 } | |
| 5909 } | |
| 5910 | |
| 5911 return props; | |
| 5912 } | |
| 5913 | |
| 5914 return baseProps; | |
| 5915 } | |
| 5916 | |
| 5917 function renderForwardRef(request, task, type, props, ref) { | |
| 5918 pushFunctionComponentStackInDEV(task, type.render); | |
| 5919 var children = renderWithHooks(request, task, type.render, props, ref); | |
| 5920 var hasId = checkDidRenderIdHook(); | |
| 5921 | |
| 5922 if (hasId) { | |
| 5923 // This component materialized an id. We treat this as its own level, with | |
| 5924 // a single "child" slot. | |
| 5925 var prevTreeContext = task.treeContext; | |
| 5926 var totalChildren = 1; | |
| 5927 var index = 0; | |
| 5928 task.treeContext = pushTreeContext(prevTreeContext, totalChildren, index); | |
| 5929 | |
| 5930 try { | |
| 5931 renderNodeDestructive(request, task, children); | |
| 5932 } finally { | |
| 5933 task.treeContext = prevTreeContext; | |
| 5934 } | |
| 5935 } else { | |
| 5936 renderNodeDestructive(request, task, children); | |
| 5937 } | |
| 5938 | |
| 5939 popComponentStackInDEV(task); | |
| 5940 } | |
| 5941 | |
| 5942 function renderMemo(request, task, type, props, ref) { | |
| 5943 var innerType = type.type; | |
| 5944 var resolvedProps = resolveDefaultProps(innerType, props); | |
| 5945 renderElement(request, task, innerType, resolvedProps, ref); | |
| 5946 } | |
| 5947 | |
| 5948 function renderContextConsumer(request, task, context, props) { | |
| 5949 // The logic below for Context differs depending on PROD or DEV mode. In | |
| 5950 // DEV mode, we create a separate object for Context.Consumer that acts | |
| 5951 // like a proxy to Context. This proxy object adds unnecessary code in PROD | |
| 5952 // so we use the old behaviour (Context.Consumer references Context) to | |
| 5953 // reduce size and overhead. The separate object references context via | |
| 5954 // a property called "_context", which also gives us the ability to check | |
| 5955 // in DEV mode if this property exists or not and warn if it does not. | |
| 5956 { | |
| 5957 if (context._context === undefined) { | |
| 5958 // This may be because it's a Context (rather than a Consumer). | |
| 5959 // Or it may be because it's older React where they're the same thing. | |
| 5960 // We only want to warn if we're sure it's a new React. | |
| 5961 if (context !== context.Consumer) { | |
| 5962 if (!hasWarnedAboutUsingContextAsConsumer) { | |
| 5963 hasWarnedAboutUsingContextAsConsumer = true; | |
| 5964 | |
| 5965 error('Rendering <Context> directly is not supported and will be removed in ' + 'a future major release. Did you mean to render <Context.Consumer> instead?'); | |
| 5966 } | |
| 5967 } | |
| 5968 } else { | |
| 5969 context = context._context; | |
| 5970 } | |
| 5971 } | |
| 5972 | |
| 5973 var render = props.children; | |
| 5974 | |
| 5975 { | |
| 5976 if (typeof render !== 'function') { | |
| 5977 error('A context consumer was rendered with multiple children, or a child ' + "that isn't a function. A context consumer expects a single child " + 'that is a function. If you did pass a function, make sure there ' + 'is no trailing or leading whitespace around it.'); | |
| 5978 } | |
| 5979 } | |
| 5980 | |
| 5981 var newValue = readContext(context); | |
| 5982 var newChildren = render(newValue); | |
| 5983 renderNodeDestructive(request, task, newChildren); | |
| 5984 } | |
| 5985 | |
| 5986 function renderContextProvider(request, task, type, props) { | |
| 5987 var context = type._context; | |
| 5988 var value = props.value; | |
| 5989 var children = props.children; | |
| 5990 var prevSnapshot; | |
| 5991 | |
| 5992 { | |
| 5993 prevSnapshot = task.context; | |
| 5994 } | |
| 5995 | |
| 5996 task.context = pushProvider(context, value); | |
| 5997 renderNodeDestructive(request, task, children); | |
| 5998 task.context = popProvider(context); | |
| 5999 | |
| 6000 { | |
| 6001 if (prevSnapshot !== task.context) { | |
| 6002 error('Popping the context provider did not return back to the original snapshot. This is a bug in React.'); | |
| 6003 } | |
| 6004 } | |
| 6005 } | |
| 6006 | |
| 6007 function renderLazyComponent(request, task, lazyComponent, props, ref) { | |
| 6008 pushBuiltInComponentStackInDEV(task, 'Lazy'); | |
| 6009 var payload = lazyComponent._payload; | |
| 6010 var init = lazyComponent._init; | |
| 6011 var Component = init(payload); | |
| 6012 var resolvedProps = resolveDefaultProps(Component, props); | |
| 6013 renderElement(request, task, Component, resolvedProps, ref); | |
| 6014 popComponentStackInDEV(task); | |
| 6015 } | |
| 6016 | |
| 6017 function renderElement(request, task, type, props, ref) { | |
| 6018 if (typeof type === 'function') { | |
| 6019 if (shouldConstruct$1(type)) { | |
| 6020 renderClassComponent(request, task, type, props); | |
| 6021 return; | |
| 6022 } else { | |
| 6023 renderIndeterminateComponent(request, task, type, props); | |
| 6024 return; | |
| 6025 } | |
| 6026 } | |
| 6027 | |
| 6028 if (typeof type === 'string') { | |
| 6029 renderHostElement(request, task, type, props); | |
| 6030 return; | |
| 6031 } | |
| 6032 | |
| 6033 switch (type) { | |
| 6034 // TODO: LegacyHidden acts the same as a fragment. This only works | |
| 6035 // because we currently assume that every instance of LegacyHidden is | |
| 6036 // accompanied by a host component wrapper. In the hidden mode, the host | |
| 6037 // component is given a `hidden` attribute, which ensures that the | |
| 6038 // initial HTML is not visible. To support the use of LegacyHidden as a | |
| 6039 // true fragment, without an extra DOM node, we would have to hide the | |
| 6040 // initial HTML in some other way. | |
| 6041 // TODO: Add REACT_OFFSCREEN_TYPE here too with the same capability. | |
| 6042 case REACT_LEGACY_HIDDEN_TYPE: | |
| 6043 case REACT_DEBUG_TRACING_MODE_TYPE: | |
| 6044 case REACT_STRICT_MODE_TYPE: | |
| 6045 case REACT_PROFILER_TYPE: | |
| 6046 case REACT_FRAGMENT_TYPE: | |
| 6047 { | |
| 6048 renderNodeDestructive(request, task, props.children); | |
| 6049 return; | |
| 6050 } | |
| 6051 | |
| 6052 case REACT_SUSPENSE_LIST_TYPE: | |
| 6053 { | |
| 6054 pushBuiltInComponentStackInDEV(task, 'SuspenseList'); // TODO: SuspenseList should control the boundaries. | |
| 6055 | |
| 6056 renderNodeDestructive(request, task, props.children); | |
| 6057 popComponentStackInDEV(task); | |
| 6058 return; | |
| 6059 } | |
| 6060 | |
| 6061 case REACT_SCOPE_TYPE: | |
| 6062 { | |
| 6063 | |
| 6064 throw new Error('ReactDOMServer does not yet support scope components.'); | |
| 6065 } | |
| 6066 // eslint-disable-next-line-no-fallthrough | |
| 6067 | |
| 6068 case REACT_SUSPENSE_TYPE: | |
| 6069 { | |
| 6070 { | |
| 6071 renderSuspenseBoundary(request, task, props); | |
| 6072 } | |
| 6073 | |
| 6074 return; | |
| 6075 } | |
| 6076 } | |
| 6077 | |
| 6078 if (typeof type === 'object' && type !== null) { | |
| 6079 switch (type.$$typeof) { | |
| 6080 case REACT_FORWARD_REF_TYPE: | |
| 6081 { | |
| 6082 renderForwardRef(request, task, type, props, ref); | |
| 6083 return; | |
| 6084 } | |
| 6085 | |
| 6086 case REACT_MEMO_TYPE: | |
| 6087 { | |
| 6088 renderMemo(request, task, type, props, ref); | |
| 6089 return; | |
| 6090 } | |
| 6091 | |
| 6092 case REACT_PROVIDER_TYPE: | |
| 6093 { | |
| 6094 renderContextProvider(request, task, type, props); | |
| 6095 return; | |
| 6096 } | |
| 6097 | |
| 6098 case REACT_CONTEXT_TYPE: | |
| 6099 { | |
| 6100 renderContextConsumer(request, task, type, props); | |
| 6101 return; | |
| 6102 } | |
| 6103 | |
| 6104 case REACT_LAZY_TYPE: | |
| 6105 { | |
| 6106 renderLazyComponent(request, task, type, props); | |
| 6107 return; | |
| 6108 } | |
| 6109 } | |
| 6110 } | |
| 6111 | |
| 6112 var info = ''; | |
| 6113 | |
| 6114 { | |
| 6115 if (type === undefined || typeof type === 'object' && type !== null && Object.keys(type).length === 0) { | |
| 6116 info += ' You likely forgot to export your component from the file ' + "it's defined in, or you might have mixed up default and " + 'named imports.'; | |
| 6117 } | |
| 6118 } | |
| 6119 | |
| 6120 throw new Error('Element type is invalid: expected a string (for built-in ' + 'components) or a class/function (for composite components) ' + ("but got: " + (type == null ? type : typeof type) + "." + info)); | |
| 6121 } | |
| 6122 | |
| 6123 function validateIterable(iterable, iteratorFn) { | |
| 6124 { | |
| 6125 // We don't support rendering Generators because it's a mutation. | |
| 6126 // See https://github.com/facebook/react/issues/12995 | |
| 6127 if (typeof Symbol === 'function' && // $FlowFixMe Flow doesn't know about toStringTag | |
| 6128 iterable[Symbol.toStringTag] === 'Generator') { | |
| 6129 if (!didWarnAboutGenerators) { | |
| 6130 error('Using Generators as children is unsupported and will likely yield ' + 'unexpected results because enumerating a generator mutates it. ' + 'You may convert it to an array with `Array.from()` or the ' + '`[...spread]` operator before rendering. Keep in mind ' + 'you might need to polyfill these features for older browsers.'); | |
| 6131 } | |
| 6132 | |
| 6133 didWarnAboutGenerators = true; | |
| 6134 } // Warn about using Maps as children | |
| 6135 | |
| 6136 | |
| 6137 if (iterable.entries === iteratorFn) { | |
| 6138 if (!didWarnAboutMaps) { | |
| 6139 error('Using Maps as children is not supported. ' + 'Use an array of keyed ReactElements instead.'); | |
| 6140 } | |
| 6141 | |
| 6142 didWarnAboutMaps = true; | |
| 6143 } | |
| 6144 } | |
| 6145 } | |
| 6146 | |
| 6147 function renderNodeDestructive(request, task, node) { | |
| 6148 { | |
| 6149 // In Dev we wrap renderNodeDestructiveImpl in a try / catch so we can capture | |
| 6150 // a component stack at the right place in the tree. We don't do this in renderNode | |
| 6151 // becuase it is not called at every layer of the tree and we may lose frames | |
| 6152 try { | |
| 6153 return renderNodeDestructiveImpl(request, task, node); | |
| 6154 } catch (x) { | |
| 6155 if (typeof x === 'object' && x !== null && typeof x.then === 'function') ; else { | |
| 6156 // This is an error, stash the component stack if it is null. | |
| 6157 lastBoundaryErrorComponentStackDev = lastBoundaryErrorComponentStackDev !== null ? lastBoundaryErrorComponentStackDev : getCurrentStackInDEV(); | |
| 6158 } // rethrow so normal suspense logic can handle thrown value accordingly | |
| 6159 | |
| 6160 | |
| 6161 throw x; | |
| 6162 } | |
| 6163 } | |
| 6164 } // This function by it self renders a node and consumes the task by mutating it | |
| 6165 // to update the current execution state. | |
| 6166 | |
| 6167 | |
| 6168 function renderNodeDestructiveImpl(request, task, node) { | |
| 6169 // Stash the node we're working on. We'll pick up from this task in case | |
| 6170 // something suspends. | |
| 6171 task.node = node; // Handle object types | |
| 6172 | |
| 6173 if (typeof node === 'object' && node !== null) { | |
| 6174 switch (node.$$typeof) { | |
| 6175 case REACT_ELEMENT_TYPE: | |
| 6176 { | |
| 6177 var element = node; | |
| 6178 var type = element.type; | |
| 6179 var props = element.props; | |
| 6180 var ref = element.ref; | |
| 6181 renderElement(request, task, type, props, ref); | |
| 6182 return; | |
| 6183 } | |
| 6184 | |
| 6185 case REACT_PORTAL_TYPE: | |
| 6186 throw new Error('Portals are not currently supported by the server renderer. ' + 'Render them conditionally so that they only appear on the client render.'); | |
| 6187 // eslint-disable-next-line-no-fallthrough | |
| 6188 | |
| 6189 case REACT_LAZY_TYPE: | |
| 6190 { | |
| 6191 var lazyNode = node; | |
| 6192 var payload = lazyNode._payload; | |
| 6193 var init = lazyNode._init; | |
| 6194 var resolvedNode; | |
| 6195 | |
| 6196 { | |
| 6197 try { | |
| 6198 resolvedNode = init(payload); | |
| 6199 } catch (x) { | |
| 6200 if (typeof x === 'object' && x !== null && typeof x.then === 'function') { | |
| 6201 // this Lazy initializer is suspending. push a temporary frame onto the stack so it can be | |
| 6202 // popped off in spawnNewSuspendedTask. This aligns stack behavior between Lazy in element position | |
| 6203 // vs Component position. We do not want the frame for Errors so we exclusively do this in | |
| 6204 // the wakeable branch | |
| 6205 pushBuiltInComponentStackInDEV(task, 'Lazy'); | |
| 6206 } | |
| 6207 | |
| 6208 throw x; | |
| 6209 } | |
| 6210 } | |
| 6211 | |
| 6212 renderNodeDestructive(request, task, resolvedNode); | |
| 6213 return; | |
| 6214 } | |
| 6215 } | |
| 6216 | |
| 6217 if (isArray(node)) { | |
| 6218 renderChildrenArray(request, task, node); | |
| 6219 return; | |
| 6220 } | |
| 6221 | |
| 6222 var iteratorFn = getIteratorFn(node); | |
| 6223 | |
| 6224 if (iteratorFn) { | |
| 6225 { | |
| 6226 validateIterable(node, iteratorFn); | |
| 6227 } | |
| 6228 | |
| 6229 var iterator = iteratorFn.call(node); | |
| 6230 | |
| 6231 if (iterator) { | |
| 6232 // We need to know how many total children are in this set, so that we | |
| 6233 // can allocate enough id slots to acommodate them. So we must exhaust | |
| 6234 // the iterator before we start recursively rendering the children. | |
| 6235 // TODO: This is not great but I think it's inherent to the id | |
| 6236 // generation algorithm. | |
| 6237 var step = iterator.next(); // If there are not entries, we need to push an empty so we start by checking that. | |
| 6238 | |
| 6239 if (!step.done) { | |
| 6240 var children = []; | |
| 6241 | |
| 6242 do { | |
| 6243 children.push(step.value); | |
| 6244 step = iterator.next(); | |
| 6245 } while (!step.done); | |
| 6246 | |
| 6247 renderChildrenArray(request, task, children); | |
| 6248 return; | |
| 6249 } | |
| 6250 | |
| 6251 return; | |
| 6252 } | |
| 6253 } | |
| 6254 | |
| 6255 var childString = Object.prototype.toString.call(node); | |
| 6256 throw new Error("Objects are not valid as a React child (found: " + (childString === '[object Object]' ? 'object with keys {' + Object.keys(node).join(', ') + '}' : childString) + "). " + 'If you meant to render a collection of children, use an array ' + 'instead.'); | |
| 6257 } | |
| 6258 | |
| 6259 if (typeof node === 'string') { | |
| 6260 var segment = task.blockedSegment; | |
| 6261 segment.lastPushedText = pushTextInstance(task.blockedSegment.chunks, node, request.responseState, segment.lastPushedText); | |
| 6262 return; | |
| 6263 } | |
| 6264 | |
| 6265 if (typeof node === 'number') { | |
| 6266 var _segment = task.blockedSegment; | |
| 6267 _segment.lastPushedText = pushTextInstance(task.blockedSegment.chunks, '' + node, request.responseState, _segment.lastPushedText); | |
| 6268 return; | |
| 6269 } | |
| 6270 | |
| 6271 { | |
| 6272 if (typeof node === 'function') { | |
| 6273 error('Functions are not valid as a React child. This may happen if ' + 'you return a Component instead of <Component /> from render. ' + 'Or maybe you meant to call this function rather than return it.'); | |
| 6274 } | |
| 6275 } | |
| 6276 } | |
| 6277 | |
| 6278 function renderChildrenArray(request, task, children) { | |
| 6279 var totalChildren = children.length; | |
| 6280 | |
| 6281 for (var i = 0; i < totalChildren; i++) { | |
| 6282 var prevTreeContext = task.treeContext; | |
| 6283 task.treeContext = pushTreeContext(prevTreeContext, totalChildren, i); | |
| 6284 | |
| 6285 try { | |
| 6286 // We need to use the non-destructive form so that we can safely pop back | |
| 6287 // up and render the sibling if something suspends. | |
| 6288 renderNode(request, task, children[i]); | |
| 6289 } finally { | |
| 6290 task.treeContext = prevTreeContext; | |
| 6291 } | |
| 6292 } | |
| 6293 } | |
| 6294 | |
| 6295 function spawnNewSuspendedTask(request, task, x) { | |
| 6296 // Something suspended, we'll need to create a new segment and resolve it later. | |
| 6297 var segment = task.blockedSegment; | |
| 6298 var insertionIndex = segment.chunks.length; | |
| 6299 var newSegment = createPendingSegment(request, insertionIndex, null, segment.formatContext, // Adopt the parent segment's leading text embed | |
| 6300 segment.lastPushedText, // Assume we are text embedded at the trailing edge | |
| 6301 true); | |
| 6302 segment.children.push(newSegment); // Reset lastPushedText for current Segment since the new Segment "consumed" it | |
| 6303 | |
| 6304 segment.lastPushedText = false; | |
| 6305 var newTask = createTask(request, task.node, task.blockedBoundary, newSegment, task.abortSet, task.legacyContext, task.context, task.treeContext); | |
| 6306 | |
| 6307 { | |
| 6308 if (task.componentStack !== null) { | |
| 6309 // We pop one task off the stack because the node that suspended will be tried again, | |
| 6310 // which will add it back onto the stack. | |
| 6311 newTask.componentStack = task.componentStack.parent; | |
| 6312 } | |
| 6313 } | |
| 6314 | |
| 6315 var ping = newTask.ping; | |
| 6316 x.then(ping, ping); | |
| 6317 } // This is a non-destructive form of rendering a node. If it suspends it spawns | |
| 6318 // a new task and restores the context of this task to what it was before. | |
| 6319 | |
| 6320 | |
| 6321 function renderNode(request, task, node) { | |
| 6322 // TODO: Store segment.children.length here and reset it in case something | |
| 6323 // suspended partially through writing something. | |
| 6324 // Snapshot the current context in case something throws to interrupt the | |
| 6325 // process. | |
| 6326 var previousFormatContext = task.blockedSegment.formatContext; | |
| 6327 var previousLegacyContext = task.legacyContext; | |
| 6328 var previousContext = task.context; | |
| 6329 var previousComponentStack = null; | |
| 6330 | |
| 6331 { | |
| 6332 previousComponentStack = task.componentStack; | |
| 6333 } | |
| 6334 | |
| 6335 try { | |
| 6336 return renderNodeDestructive(request, task, node); | |
| 6337 } catch (x) { | |
| 6338 resetHooksState(); | |
| 6339 | |
| 6340 if (typeof x === 'object' && x !== null && typeof x.then === 'function') { | |
| 6341 spawnNewSuspendedTask(request, task, x); // Restore the context. We assume that this will be restored by the inner | |
| 6342 // functions in case nothing throws so we don't use "finally" here. | |
| 6343 | |
| 6344 task.blockedSegment.formatContext = previousFormatContext; | |
| 6345 task.legacyContext = previousLegacyContext; | |
| 6346 task.context = previousContext; // Restore all active ReactContexts to what they were before. | |
| 6347 | |
| 6348 switchContext(previousContext); | |
| 6349 | |
| 6350 { | |
| 6351 task.componentStack = previousComponentStack; | |
| 6352 } | |
| 6353 | |
| 6354 return; | |
| 6355 } else { | |
| 6356 // Restore the context. We assume that this will be restored by the inner | |
| 6357 // functions in case nothing throws so we don't use "finally" here. | |
| 6358 task.blockedSegment.formatContext = previousFormatContext; | |
| 6359 task.legacyContext = previousLegacyContext; | |
| 6360 task.context = previousContext; // Restore all active ReactContexts to what they were before. | |
| 6361 | |
| 6362 switchContext(previousContext); | |
| 6363 | |
| 6364 { | |
| 6365 task.componentStack = previousComponentStack; | |
| 6366 } // We assume that we don't need the correct context. | |
| 6367 // Let's terminate the rest of the tree and don't render any siblings. | |
| 6368 | |
| 6369 | |
| 6370 throw x; | |
| 6371 } | |
| 6372 } | |
| 6373 } | |
| 6374 | |
| 6375 function erroredTask(request, boundary, segment, error) { | |
| 6376 // Report the error to a global handler. | |
| 6377 var errorDigest = logRecoverableError(request, error); | |
| 6378 | |
| 6379 if (boundary === null) { | |
| 6380 fatalError(request, error); | |
| 6381 } else { | |
| 6382 boundary.pendingTasks--; | |
| 6383 | |
| 6384 if (!boundary.forceClientRender) { | |
| 6385 boundary.forceClientRender = true; | |
| 6386 boundary.errorDigest = errorDigest; | |
| 6387 | |
| 6388 { | |
| 6389 captureBoundaryErrorDetailsDev(boundary, error); | |
| 6390 } // Regardless of what happens next, this boundary won't be displayed, | |
| 6391 // so we can flush it, if the parent already flushed. | |
| 6392 | |
| 6393 | |
| 6394 if (boundary.parentFlushed) { | |
| 6395 // We don't have a preference where in the queue this goes since it's likely | |
| 6396 // to error on the client anyway. However, intentionally client-rendered | |
| 6397 // boundaries should be flushed earlier so that they can start on the client. | |
| 6398 // We reuse the same queue for errors. | |
| 6399 request.clientRenderedBoundaries.push(boundary); | |
| 6400 } | |
| 6401 } | |
| 6402 } | |
| 6403 | |
| 6404 request.allPendingTasks--; | |
| 6405 | |
| 6406 if (request.allPendingTasks === 0) { | |
| 6407 var onAllReady = request.onAllReady; | |
| 6408 onAllReady(); | |
| 6409 } | |
| 6410 } | |
| 6411 | |
| 6412 function abortTaskSoft(task) { | |
| 6413 // This aborts task without aborting the parent boundary that it blocks. | |
| 6414 // It's used for when we didn't need this task to complete the tree. | |
| 6415 // If task was needed, then it should use abortTask instead. | |
| 6416 var request = this; | |
| 6417 var boundary = task.blockedBoundary; | |
| 6418 var segment = task.blockedSegment; | |
| 6419 segment.status = ABORTED; | |
| 6420 finishedTask(request, boundary, segment); | |
| 6421 } | |
| 6422 | |
| 6423 function abortTask(task, request, reason) { | |
| 6424 // This aborts the task and aborts the parent that it blocks, putting it into | |
| 6425 // client rendered mode. | |
| 6426 var boundary = task.blockedBoundary; | |
| 6427 var segment = task.blockedSegment; | |
| 6428 segment.status = ABORTED; | |
| 6429 | |
| 6430 if (boundary === null) { | |
| 6431 request.allPendingTasks--; // We didn't complete the root so we have nothing to show. We can close | |
| 6432 // the request; | |
| 6433 | |
| 6434 if (request.status !== CLOSED) { | |
| 6435 request.status = CLOSED; | |
| 6436 | |
| 6437 if (request.destination !== null) { | |
| 6438 close(request.destination); | |
| 6439 } | |
| 6440 } | |
| 6441 } else { | |
| 6442 boundary.pendingTasks--; | |
| 6443 | |
| 6444 if (!boundary.forceClientRender) { | |
| 6445 boundary.forceClientRender = true; | |
| 6446 | |
| 6447 var _error = reason === undefined ? new Error('The render was aborted by the server without a reason.') : reason; | |
| 6448 | |
| 6449 boundary.errorDigest = request.onError(_error); | |
| 6450 | |
| 6451 { | |
| 6452 var errorPrefix = 'The server did not finish this Suspense boundary: '; | |
| 6453 | |
| 6454 if (_error && typeof _error.message === 'string') { | |
| 6455 _error = errorPrefix + _error.message; | |
| 6456 } else { | |
| 6457 // eslint-disable-next-line react-internal/safe-string-coercion | |
| 6458 _error = errorPrefix + String(_error); | |
| 6459 } | |
| 6460 | |
| 6461 var previousTaskInDev = currentTaskInDEV; | |
| 6462 currentTaskInDEV = task; | |
| 6463 | |
| 6464 try { | |
| 6465 captureBoundaryErrorDetailsDev(boundary, _error); | |
| 6466 } finally { | |
| 6467 currentTaskInDEV = previousTaskInDev; | |
| 6468 } | |
| 6469 } | |
| 6470 | |
| 6471 if (boundary.parentFlushed) { | |
| 6472 request.clientRenderedBoundaries.push(boundary); | |
| 6473 } | |
| 6474 } // If this boundary was still pending then we haven't already cancelled its fallbacks. | |
| 6475 // We'll need to abort the fallbacks, which will also error that parent boundary. | |
| 6476 | |
| 6477 | |
| 6478 boundary.fallbackAbortableTasks.forEach(function (fallbackTask) { | |
| 6479 return abortTask(fallbackTask, request, reason); | |
| 6480 }); | |
| 6481 boundary.fallbackAbortableTasks.clear(); | |
| 6482 request.allPendingTasks--; | |
| 6483 | |
| 6484 if (request.allPendingTasks === 0) { | |
| 6485 var onAllReady = request.onAllReady; | |
| 6486 onAllReady(); | |
| 6487 } | |
| 6488 } | |
| 6489 } | |
| 6490 | |
| 6491 function queueCompletedSegment(boundary, segment) { | |
| 6492 if (segment.chunks.length === 0 && segment.children.length === 1 && segment.children[0].boundary === null) { | |
| 6493 // This is an empty segment. There's nothing to write, so we can instead transfer the ID | |
| 6494 // to the child. That way any existing references point to the child. | |
| 6495 var childSegment = segment.children[0]; | |
| 6496 childSegment.id = segment.id; | |
| 6497 childSegment.parentFlushed = true; | |
| 6498 | |
| 6499 if (childSegment.status === COMPLETED) { | |
| 6500 queueCompletedSegment(boundary, childSegment); | |
| 6501 } | |
| 6502 } else { | |
| 6503 var completedSegments = boundary.completedSegments; | |
| 6504 completedSegments.push(segment); | |
| 6505 } | |
| 6506 } | |
| 6507 | |
| 6508 function finishedTask(request, boundary, segment) { | |
| 6509 if (boundary === null) { | |
| 6510 if (segment.parentFlushed) { | |
| 6511 if (request.completedRootSegment !== null) { | |
| 6512 throw new Error('There can only be one root segment. This is a bug in React.'); | |
| 6513 } | |
| 6514 | |
| 6515 request.completedRootSegment = segment; | |
| 6516 } | |
| 6517 | |
| 6518 request.pendingRootTasks--; | |
| 6519 | |
| 6520 if (request.pendingRootTasks === 0) { | |
| 6521 // We have completed the shell so the shell can't error anymore. | |
| 6522 request.onShellError = noop$1; | |
| 6523 var onShellReady = request.onShellReady; | |
| 6524 onShellReady(); | |
| 6525 } | |
| 6526 } else { | |
| 6527 boundary.pendingTasks--; | |
| 6528 | |
| 6529 if (boundary.forceClientRender) ; else if (boundary.pendingTasks === 0) { | |
| 6530 // This must have been the last segment we were waiting on. This boundary is now complete. | |
| 6531 if (segment.parentFlushed) { | |
| 6532 // Our parent segment already flushed, so we need to schedule this segment to be emitted. | |
| 6533 // If it is a segment that was aborted, we'll write other content instead so we don't need | |
| 6534 // to emit it. | |
| 6535 if (segment.status === COMPLETED) { | |
| 6536 queueCompletedSegment(boundary, segment); | |
| 6537 } | |
| 6538 } | |
| 6539 | |
| 6540 if (boundary.parentFlushed) { | |
| 6541 // The segment might be part of a segment that didn't flush yet, but if the boundary's | |
| 6542 // parent flushed, we need to schedule the boundary to be emitted. | |
| 6543 request.completedBoundaries.push(boundary); | |
| 6544 } // We can now cancel any pending task on the fallback since we won't need to show it anymore. | |
| 6545 // This needs to happen after we read the parentFlushed flags because aborting can finish | |
| 6546 // work which can trigger user code, which can start flushing, which can change those flags. | |
| 6547 | |
| 6548 | |
| 6549 boundary.fallbackAbortableTasks.forEach(abortTaskSoft, request); | |
| 6550 boundary.fallbackAbortableTasks.clear(); | |
| 6551 } else { | |
| 6552 if (segment.parentFlushed) { | |
| 6553 // Our parent already flushed, so we need to schedule this segment to be emitted. | |
| 6554 // If it is a segment that was aborted, we'll write other content instead so we don't need | |
| 6555 // to emit it. | |
| 6556 if (segment.status === COMPLETED) { | |
| 6557 queueCompletedSegment(boundary, segment); | |
| 6558 var completedSegments = boundary.completedSegments; | |
| 6559 | |
| 6560 if (completedSegments.length === 1) { | |
| 6561 // This is the first time since we last flushed that we completed anything. | |
| 6562 // We can schedule this boundary to emit its partially completed segments early | |
| 6563 // in case the parent has already been flushed. | |
| 6564 if (boundary.parentFlushed) { | |
| 6565 request.partialBoundaries.push(boundary); | |
| 6566 } | |
| 6567 } | |
| 6568 } | |
| 6569 } | |
| 6570 } | |
| 6571 } | |
| 6572 | |
| 6573 request.allPendingTasks--; | |
| 6574 | |
| 6575 if (request.allPendingTasks === 0) { | |
| 6576 // This needs to be called at the very end so that we can synchronously write the result | |
| 6577 // in the callback if needed. | |
| 6578 var onAllReady = request.onAllReady; | |
| 6579 onAllReady(); | |
| 6580 } | |
| 6581 } | |
| 6582 | |
| 6583 function retryTask(request, task) { | |
| 6584 var segment = task.blockedSegment; | |
| 6585 | |
| 6586 if (segment.status !== PENDING) { | |
| 6587 // We completed this by other means before we had a chance to retry it. | |
| 6588 return; | |
| 6589 } // We restore the context to what it was when we suspended. | |
| 6590 // We don't restore it after we leave because it's likely that we'll end up | |
| 6591 // needing a very similar context soon again. | |
| 6592 | |
| 6593 | |
| 6594 switchContext(task.context); | |
| 6595 var prevTaskInDEV = null; | |
| 6596 | |
| 6597 { | |
| 6598 prevTaskInDEV = currentTaskInDEV; | |
| 6599 currentTaskInDEV = task; | |
| 6600 } | |
| 6601 | |
| 6602 try { | |
| 6603 // We call the destructive form that mutates this task. That way if something | |
| 6604 // suspends again, we can reuse the same task instead of spawning a new one. | |
| 6605 renderNodeDestructive(request, task, task.node); | |
| 6606 pushSegmentFinale(segment.chunks, request.responseState, segment.lastPushedText, segment.textEmbedded); | |
| 6607 task.abortSet.delete(task); | |
| 6608 segment.status = COMPLETED; | |
| 6609 finishedTask(request, task.blockedBoundary, segment); | |
| 6610 } catch (x) { | |
| 6611 resetHooksState(); | |
| 6612 | |
| 6613 if (typeof x === 'object' && x !== null && typeof x.then === 'function') { | |
| 6614 // Something suspended again, let's pick it back up later. | |
| 6615 var ping = task.ping; | |
| 6616 x.then(ping, ping); | |
| 6617 } else { | |
| 6618 task.abortSet.delete(task); | |
| 6619 segment.status = ERRORED; | |
| 6620 erroredTask(request, task.blockedBoundary, segment, x); | |
| 6621 } | |
| 6622 } finally { | |
| 6623 { | |
| 6624 currentTaskInDEV = prevTaskInDEV; | |
| 6625 } | |
| 6626 } | |
| 6627 } | |
| 6628 | |
| 6629 function performWork(request) { | |
| 6630 if (request.status === CLOSED) { | |
| 6631 return; | |
| 6632 } | |
| 6633 | |
| 6634 var prevContext = getActiveContext(); | |
| 6635 var prevDispatcher = ReactCurrentDispatcher$1.current; | |
| 6636 ReactCurrentDispatcher$1.current = Dispatcher; | |
| 6637 var prevGetCurrentStackImpl; | |
| 6638 | |
| 6639 { | |
| 6640 prevGetCurrentStackImpl = ReactDebugCurrentFrame$1.getCurrentStack; | |
| 6641 ReactDebugCurrentFrame$1.getCurrentStack = getCurrentStackInDEV; | |
| 6642 } | |
| 6643 | |
| 6644 var prevResponseState = currentResponseState; | |
| 6645 setCurrentResponseState(request.responseState); | |
| 6646 | |
| 6647 try { | |
| 6648 var pingedTasks = request.pingedTasks; | |
| 6649 var i; | |
| 6650 | |
| 6651 for (i = 0; i < pingedTasks.length; i++) { | |
| 6652 var task = pingedTasks[i]; | |
| 6653 retryTask(request, task); | |
| 6654 } | |
| 6655 | |
| 6656 pingedTasks.splice(0, i); | |
| 6657 | |
| 6658 if (request.destination !== null) { | |
| 6659 flushCompletedQueues(request, request.destination); | |
| 6660 } | |
| 6661 } catch (error) { | |
| 6662 logRecoverableError(request, error); | |
| 6663 fatalError(request, error); | |
| 6664 } finally { | |
| 6665 setCurrentResponseState(prevResponseState); | |
| 6666 ReactCurrentDispatcher$1.current = prevDispatcher; | |
| 6667 | |
| 6668 { | |
| 6669 ReactDebugCurrentFrame$1.getCurrentStack = prevGetCurrentStackImpl; | |
| 6670 } | |
| 6671 | |
| 6672 if (prevDispatcher === Dispatcher) { | |
| 6673 // This means that we were in a reentrant work loop. This could happen | |
| 6674 // in a renderer that supports synchronous work like renderToString, | |
| 6675 // when it's called from within another renderer. | |
| 6676 // Normally we don't bother switching the contexts to their root/default | |
| 6677 // values when leaving because we'll likely need the same or similar | |
| 6678 // context again. However, when we're inside a synchronous loop like this | |
| 6679 // we'll to restore the context to what it was before returning. | |
| 6680 switchContext(prevContext); | |
| 6681 } | |
| 6682 } | |
| 6683 } | |
| 6684 | |
| 6685 function flushSubtree(request, destination, segment) { | |
| 6686 segment.parentFlushed = true; | |
| 6687 | |
| 6688 switch (segment.status) { | |
| 6689 case PENDING: | |
| 6690 { | |
| 6691 // We're emitting a placeholder for this segment to be filled in later. | |
| 6692 // Therefore we'll need to assign it an ID - to refer to it by. | |
| 6693 var segmentID = segment.id = request.nextSegmentId++; // When this segment finally completes it won't be embedded in text since it will flush separately | |
| 6694 | |
| 6695 segment.lastPushedText = false; | |
| 6696 segment.textEmbedded = false; | |
| 6697 return writePlaceholder(destination, request.responseState, segmentID); | |
| 6698 } | |
| 6699 | |
| 6700 case COMPLETED: | |
| 6701 { | |
| 6702 segment.status = FLUSHED; | |
| 6703 var r = true; | |
| 6704 var chunks = segment.chunks; | |
| 6705 var chunkIdx = 0; | |
| 6706 var children = segment.children; | |
| 6707 | |
| 6708 for (var childIdx = 0; childIdx < children.length; childIdx++) { | |
| 6709 var nextChild = children[childIdx]; // Write all the chunks up until the next child. | |
| 6710 | |
| 6711 for (; chunkIdx < nextChild.index; chunkIdx++) { | |
| 6712 writeChunk(destination, chunks[chunkIdx]); | |
| 6713 } | |
| 6714 | |
| 6715 r = flushSegment(request, destination, nextChild); | |
| 6716 } // Finally just write all the remaining chunks | |
| 6717 | |
| 6718 | |
| 6719 for (; chunkIdx < chunks.length - 1; chunkIdx++) { | |
| 6720 writeChunk(destination, chunks[chunkIdx]); | |
| 6721 } | |
| 6722 | |
| 6723 if (chunkIdx < chunks.length) { | |
| 6724 r = writeChunkAndReturn(destination, chunks[chunkIdx]); | |
| 6725 } | |
| 6726 | |
| 6727 return r; | |
| 6728 } | |
| 6729 | |
| 6730 default: | |
| 6731 { | |
| 6732 throw new Error('Aborted, errored or already flushed boundaries should not be flushed again. This is a bug in React.'); | |
| 6733 } | |
| 6734 } | |
| 6735 } | |
| 6736 | |
| 6737 function flushSegment(request, destination, segment) { | |
| 6738 var boundary = segment.boundary; | |
| 6739 | |
| 6740 if (boundary === null) { | |
| 6741 // Not a suspense boundary. | |
| 6742 return flushSubtree(request, destination, segment); | |
| 6743 } | |
| 6744 | |
| 6745 boundary.parentFlushed = true; // This segment is a Suspense boundary. We need to decide whether to | |
| 6746 // emit the content or the fallback now. | |
| 6747 | |
| 6748 if (boundary.forceClientRender) { | |
| 6749 // Emit a client rendered suspense boundary wrapper. | |
| 6750 // We never queue the inner boundary so we'll never emit its content or partial segments. | |
| 6751 writeStartClientRenderedSuspenseBoundary(destination, request.responseState, boundary.errorDigest, boundary.errorMessage, boundary.errorComponentStack); // Flush the fallback. | |
| 6752 | |
| 6753 flushSubtree(request, destination, segment); | |
| 6754 return writeEndClientRenderedSuspenseBoundary(destination, request.responseState); | |
| 6755 } else if (boundary.pendingTasks > 0) { | |
| 6756 // This boundary is still loading. Emit a pending suspense boundary wrapper. | |
| 6757 // Assign an ID to refer to the future content by. | |
| 6758 boundary.rootSegmentID = request.nextSegmentId++; | |
| 6759 | |
| 6760 if (boundary.completedSegments.length > 0) { | |
| 6761 // If this is at least partially complete, we can queue it to be partially emitted early. | |
| 6762 request.partialBoundaries.push(boundary); | |
| 6763 } /// This is the first time we should have referenced this ID. | |
| 6764 | |
| 6765 | |
| 6766 var id = boundary.id = assignSuspenseBoundaryID(request.responseState); | |
| 6767 writeStartPendingSuspenseBoundary(destination, request.responseState, id); // Flush the fallback. | |
| 6768 | |
| 6769 flushSubtree(request, destination, segment); | |
| 6770 return writeEndPendingSuspenseBoundary(destination, request.responseState); | |
| 6771 } else if (boundary.byteSize > request.progressiveChunkSize) { | |
| 6772 // This boundary is large and will be emitted separately so that we can progressively show | |
| 6773 // other content. We add it to the queue during the flush because we have to ensure that | |
| 6774 // the parent flushes first so that there's something to inject it into. | |
| 6775 // We also have to make sure that it's emitted into the queue in a deterministic slot. | |
| 6776 // I.e. we can't insert it here when it completes. | |
| 6777 // Assign an ID to refer to the future content by. | |
| 6778 boundary.rootSegmentID = request.nextSegmentId++; | |
| 6779 request.completedBoundaries.push(boundary); // Emit a pending rendered suspense boundary wrapper. | |
| 6780 | |
| 6781 writeStartPendingSuspenseBoundary(destination, request.responseState, boundary.id); // Flush the fallback. | |
| 6782 | |
| 6783 flushSubtree(request, destination, segment); | |
| 6784 return writeEndPendingSuspenseBoundary(destination, request.responseState); | |
| 6785 } else { | |
| 6786 // We can inline this boundary's content as a complete boundary. | |
| 6787 writeStartCompletedSuspenseBoundary(destination, request.responseState); | |
| 6788 var completedSegments = boundary.completedSegments; | |
| 6789 | |
| 6790 if (completedSegments.length !== 1) { | |
| 6791 throw new Error('A previously unvisited boundary must have exactly one root segment. This is a bug in React.'); | |
| 6792 } | |
| 6793 | |
| 6794 var contentSegment = completedSegments[0]; | |
| 6795 flushSegment(request, destination, contentSegment); | |
| 6796 return writeEndCompletedSuspenseBoundary(destination, request.responseState); | |
| 6797 } | |
| 6798 } | |
| 6799 | |
| 6800 function flushClientRenderedBoundary(request, destination, boundary) { | |
| 6801 return writeClientRenderBoundaryInstruction(destination, request.responseState, boundary.id, boundary.errorDigest, boundary.errorMessage, boundary.errorComponentStack); | |
| 6802 } | |
| 6803 | |
| 6804 function flushSegmentContainer(request, destination, segment) { | |
| 6805 writeStartSegment(destination, request.responseState, segment.formatContext, segment.id); | |
| 6806 flushSegment(request, destination, segment); | |
| 6807 return writeEndSegment(destination, segment.formatContext); | |
| 6808 } | |
| 6809 | |
| 6810 function flushCompletedBoundary(request, destination, boundary) { | |
| 6811 var completedSegments = boundary.completedSegments; | |
| 6812 var i = 0; | |
| 6813 | |
| 6814 for (; i < completedSegments.length; i++) { | |
| 6815 var segment = completedSegments[i]; | |
| 6816 flushPartiallyCompletedSegment(request, destination, boundary, segment); | |
| 6817 } | |
| 6818 | |
| 6819 completedSegments.length = 0; | |
| 6820 return writeCompletedBoundaryInstruction(destination, request.responseState, boundary.id, boundary.rootSegmentID); | |
| 6821 } | |
| 6822 | |
| 6823 function flushPartialBoundary(request, destination, boundary) { | |
| 6824 var completedSegments = boundary.completedSegments; | |
| 6825 var i = 0; | |
| 6826 | |
| 6827 for (; i < completedSegments.length; i++) { | |
| 6828 var segment = completedSegments[i]; | |
| 6829 | |
| 6830 if (!flushPartiallyCompletedSegment(request, destination, boundary, segment)) { | |
| 6831 i++; | |
| 6832 completedSegments.splice(0, i); // Only write as much as the buffer wants. Something higher priority | |
| 6833 // might want to write later. | |
| 6834 | |
| 6835 return false; | |
| 6836 } | |
| 6837 } | |
| 6838 | |
| 6839 completedSegments.splice(0, i); | |
| 6840 return true; | |
| 6841 } | |
| 6842 | |
| 6843 function flushPartiallyCompletedSegment(request, destination, boundary, segment) { | |
| 6844 if (segment.status === FLUSHED) { | |
| 6845 // We've already flushed this inline. | |
| 6846 return true; | |
| 6847 } | |
| 6848 | |
| 6849 var segmentID = segment.id; | |
| 6850 | |
| 6851 if (segmentID === -1) { | |
| 6852 // This segment wasn't previously referred to. This happens at the root of | |
| 6853 // a boundary. We make kind of a leap here and assume this is the root. | |
| 6854 var rootSegmentID = segment.id = boundary.rootSegmentID; | |
| 6855 | |
| 6856 if (rootSegmentID === -1) { | |
| 6857 throw new Error('A root segment ID must have been assigned by now. This is a bug in React.'); | |
| 6858 } | |
| 6859 | |
| 6860 return flushSegmentContainer(request, destination, segment); | |
| 6861 } else { | |
| 6862 flushSegmentContainer(request, destination, segment); | |
| 6863 return writeCompletedSegmentInstruction(destination, request.responseState, segmentID); | |
| 6864 } | |
| 6865 } | |
| 6866 | |
| 6867 function flushCompletedQueues(request, destination) { | |
| 6868 beginWriting(); | |
| 6869 | |
| 6870 try { | |
| 6871 // The structure of this is to go through each queue one by one and write | |
| 6872 // until the sink tells us to stop. When we should stop, we still finish writing | |
| 6873 // that item fully and then yield. At that point we remove the already completed | |
| 6874 // items up until the point we completed them. | |
| 6875 // TODO: Emit preloading. | |
| 6876 // TODO: It's kind of unfortunate to keep checking this array after we've already | |
| 6877 // emitted the root. | |
| 6878 var completedRootSegment = request.completedRootSegment; | |
| 6879 | |
| 6880 if (completedRootSegment !== null && request.pendingRootTasks === 0) { | |
| 6881 flushSegment(request, destination, completedRootSegment); | |
| 6882 request.completedRootSegment = null; | |
| 6883 writeCompletedRoot(destination, request.responseState); | |
| 6884 } // We emit client rendering instructions for already emitted boundaries first. | |
| 6885 // This is so that we can signal to the client to start client rendering them as | |
| 6886 // soon as possible. | |
| 6887 | |
| 6888 | |
| 6889 var clientRenderedBoundaries = request.clientRenderedBoundaries; | |
| 6890 var i; | |
| 6891 | |
| 6892 for (i = 0; i < clientRenderedBoundaries.length; i++) { | |
| 6893 var boundary = clientRenderedBoundaries[i]; | |
| 6894 | |
| 6895 if (!flushClientRenderedBoundary(request, destination, boundary)) { | |
| 6896 request.destination = null; | |
| 6897 i++; | |
| 6898 clientRenderedBoundaries.splice(0, i); | |
| 6899 return; | |
| 6900 } | |
| 6901 } | |
| 6902 | |
| 6903 clientRenderedBoundaries.splice(0, i); // Next we emit any complete boundaries. It's better to favor boundaries | |
| 6904 // that are completely done since we can actually show them, than it is to emit | |
| 6905 // any individual segments from a partially complete boundary. | |
| 6906 | |
| 6907 var completedBoundaries = request.completedBoundaries; | |
| 6908 | |
| 6909 for (i = 0; i < completedBoundaries.length; i++) { | |
| 6910 var _boundary = completedBoundaries[i]; | |
| 6911 | |
| 6912 if (!flushCompletedBoundary(request, destination, _boundary)) { | |
| 6913 request.destination = null; | |
| 6914 i++; | |
| 6915 completedBoundaries.splice(0, i); | |
| 6916 return; | |
| 6917 } | |
| 6918 } | |
| 6919 | |
| 6920 completedBoundaries.splice(0, i); // Allow anything written so far to flush to the underlying sink before | |
| 6921 // we continue with lower priorities. | |
| 6922 | |
| 6923 completeWriting(destination); | |
| 6924 beginWriting(destination); // TODO: Here we'll emit data used by hydration. | |
| 6925 // Next we emit any segments of any boundaries that are partially complete | |
| 6926 // but not deeply complete. | |
| 6927 | |
| 6928 var partialBoundaries = request.partialBoundaries; | |
| 6929 | |
| 6930 for (i = 0; i < partialBoundaries.length; i++) { | |
| 6931 var _boundary2 = partialBoundaries[i]; | |
| 6932 | |
| 6933 if (!flushPartialBoundary(request, destination, _boundary2)) { | |
| 6934 request.destination = null; | |
| 6935 i++; | |
| 6936 partialBoundaries.splice(0, i); | |
| 6937 return; | |
| 6938 } | |
| 6939 } | |
| 6940 | |
| 6941 partialBoundaries.splice(0, i); // Next we check the completed boundaries again. This may have had | |
| 6942 // boundaries added to it in case they were too larged to be inlined. | |
| 6943 // New ones might be added in this loop. | |
| 6944 | |
| 6945 var largeBoundaries = request.completedBoundaries; | |
| 6946 | |
| 6947 for (i = 0; i < largeBoundaries.length; i++) { | |
| 6948 var _boundary3 = largeBoundaries[i]; | |
| 6949 | |
| 6950 if (!flushCompletedBoundary(request, destination, _boundary3)) { | |
| 6951 request.destination = null; | |
| 6952 i++; | |
| 6953 largeBoundaries.splice(0, i); | |
| 6954 return; | |
| 6955 } | |
| 6956 } | |
| 6957 | |
| 6958 largeBoundaries.splice(0, i); | |
| 6959 } finally { | |
| 6960 completeWriting(destination); | |
| 6961 flushBuffered(destination); | |
| 6962 | |
| 6963 if (request.allPendingTasks === 0 && request.pingedTasks.length === 0 && request.clientRenderedBoundaries.length === 0 && request.completedBoundaries.length === 0 // We don't need to check any partially completed segments because | |
| 6964 // either they have pending task or they're complete. | |
| 6965 ) { | |
| 6966 { | |
| 6967 if (request.abortableTasks.size !== 0) { | |
| 6968 error('There was still abortable task at the root when we closed. This is a bug in React.'); | |
| 6969 } | |
| 6970 } // We're done. | |
| 6971 | |
| 6972 | |
| 6973 close(destination); | |
| 6974 } | |
| 6975 } | |
| 6976 } | |
| 6977 | |
| 6978 function startWork(request) { | |
| 6979 scheduleWork(function () { | |
| 6980 return performWork(request); | |
| 6981 }); | |
| 6982 } | |
| 6983 function startFlowing(request, destination) { | |
| 6984 if (request.status === CLOSING) { | |
| 6985 request.status = CLOSED; | |
| 6986 closeWithError(destination, request.fatalError); | |
| 6987 return; | |
| 6988 } | |
| 6989 | |
| 6990 if (request.status === CLOSED) { | |
| 6991 return; | |
| 6992 } | |
| 6993 | |
| 6994 if (request.destination !== null) { | |
| 6995 // We're already flowing. | |
| 6996 return; | |
| 6997 } | |
| 6998 | |
| 6999 request.destination = destination; | |
| 7000 | |
| 7001 try { | |
| 7002 flushCompletedQueues(request, destination); | |
| 7003 } catch (error) { | |
| 7004 logRecoverableError(request, error); | |
| 7005 fatalError(request, error); | |
| 7006 } | |
| 7007 } // This is called to early terminate a request. It puts all pending boundaries in client rendered state. | |
| 7008 | |
| 7009 function abort(request, reason) { | |
| 7010 try { | |
| 7011 var abortableTasks = request.abortableTasks; | |
| 7012 abortableTasks.forEach(function (task) { | |
| 7013 return abortTask(task, request, reason); | |
| 7014 }); | |
| 7015 abortableTasks.clear(); | |
| 7016 | |
| 7017 if (request.destination !== null) { | |
| 7018 flushCompletedQueues(request, request.destination); | |
| 7019 } | |
| 7020 } catch (error) { | |
| 7021 logRecoverableError(request, error); | |
| 7022 fatalError(request, error); | |
| 7023 } | |
| 7024 } | |
| 7025 | |
| 7026 function createDrainHandler(destination, request) { | |
| 7027 return function () { | |
| 7028 return startFlowing(request, destination); | |
| 7029 }; | |
| 7030 } | |
| 7031 | |
| 7032 function createAbortHandler(request, reason) { | |
| 7033 return function () { | |
| 7034 return abort(request, reason); | |
| 7035 }; | |
| 7036 } | |
| 7037 | |
| 7038 function createRequestImpl(children, options) { | |
| 7039 return createRequest(children, createResponseState(options ? options.identifierPrefix : undefined, options ? options.nonce : undefined, options ? options.bootstrapScriptContent : undefined, options ? options.bootstrapScripts : undefined, options ? options.bootstrapModules : undefined), createRootFormatContext(options ? options.namespaceURI : undefined), options ? options.progressiveChunkSize : undefined, options ? options.onError : undefined, options ? options.onAllReady : undefined, options ? options.onShellReady : undefined, options ? options.onShellError : undefined, undefined); | |
| 7040 } | |
| 7041 | |
| 7042 function renderToPipeableStream(children, options) { | |
| 7043 var request = createRequestImpl(children, options); | |
| 7044 var hasStartedFlowing = false; | |
| 7045 startWork(request); | |
| 7046 return { | |
| 7047 pipe: function (destination) { | |
| 7048 if (hasStartedFlowing) { | |
| 7049 throw new Error('React currently only supports piping to one writable stream.'); | |
| 7050 } | |
| 7051 | |
| 7052 hasStartedFlowing = true; | |
| 7053 startFlowing(request, destination); | |
| 7054 destination.on('drain', createDrainHandler(destination, request)); | |
| 7055 destination.on('error', createAbortHandler(request, // eslint-disable-next-line react-internal/prod-error-codes | |
| 7056 new Error('The destination stream errored while writing data.'))); | |
| 7057 destination.on('close', createAbortHandler(request, // eslint-disable-next-line react-internal/prod-error-codes | |
| 7058 new Error('The destination stream closed early.'))); | |
| 7059 return destination; | |
| 7060 }, | |
| 7061 abort: function (reason) { | |
| 7062 abort(request, reason); | |
| 7063 } | |
| 7064 }; | |
| 7065 } | |
| 7066 | |
| 7067 exports.renderToPipeableStream = renderToPipeableStream; | |
| 7068 exports.version = ReactVersion; | |
| 7069 })(); | |
| 7070 } |