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