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