зеркало из https://github.com/mozilla/gecko-dev.git
2189 строки
70 KiB
JavaScript
2189 строки
70 KiB
JavaScript
/** @license React v16.8.6
|
|
* react-dom-server.browser.production.min.js
|
|
*
|
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*/
|
|
(function (global, factory) {
|
|
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('devtools/client/shared/vendor/react')) :
|
|
typeof define === 'function' && define.amd ? define(['devtools/client/shared/vendor/react'], factory) :
|
|
(global.ReactDOMServer = factory(global.React));
|
|
}(this, (function (React) { 'use strict';
|
|
|
|
/**
|
|
* Use invariant() to assert state which your program assumes to be true.
|
|
*
|
|
* Provide sprintf-style format (only %s is supported) and arguments
|
|
* to provide information about what broke and what you were
|
|
* expecting.
|
|
*
|
|
* The invariant message will be stripped in production, but the invariant
|
|
* will remain to ensure logic does not differ in production.
|
|
*/
|
|
|
|
function invariant(condition, format, a, b, c, d, e, f) {
|
|
if (!condition) {
|
|
var error = void 0;
|
|
if (format === undefined) {
|
|
error = new Error('Minified exception occurred; use the non-minified dev environment ' + 'for the full error message and additional helpful warnings.');
|
|
} else {
|
|
var args = [a, b, c, d, e, f];
|
|
var argIndex = 0;
|
|
error = new Error(format.replace(/%s/g, function () {
|
|
return args[argIndex++];
|
|
}));
|
|
error.name = 'Invariant Violation';
|
|
}
|
|
|
|
error.framesToPop = 1; // we don't care about invariant's own frame
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
// Relying on the `invariant()` implementation lets us
|
|
// preserve the format and params in the www builds.
|
|
/**
|
|
* WARNING: DO NOT manually require this module.
|
|
* This is a replacement for `invariant(...)` used by the error code system
|
|
* and will _only_ be required by the corresponding babel pass.
|
|
* It always throws.
|
|
*/
|
|
function reactProdInvariant(code) {
|
|
var argCount = arguments.length - 1;
|
|
var url = 'https://reactjs.org/docs/error-decoder.html?invariant=' + code;
|
|
for (var argIdx = 0; argIdx < argCount; argIdx++) {
|
|
url += '&args[]=' + encodeURIComponent(arguments[argIdx + 1]);
|
|
}
|
|
// Rename it so that our build transform doesn't attempt
|
|
// to replace this invariant() call with reactProdInvariant().
|
|
var i = invariant;
|
|
i(false,
|
|
// The error code is intentionally part of the message (and
|
|
// not the format argument) so that we could deduplicate
|
|
// different errors in logs based on the code.
|
|
'Minified React error #' + code + '; visit %s ' + 'for the full message or use the non-minified dev environment ' + 'for full errors and additional helpful warnings. ', url);
|
|
}
|
|
|
|
// TODO: this is special because it gets imported during build.
|
|
|
|
var ReactVersion = '16.8.6';
|
|
|
|
var ReactInternals = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
|
|
|
|
var _assign = ReactInternals.assign;
|
|
|
|
/**
|
|
* Similar to invariant but only logs a warning if the condition is not met.
|
|
* This can be used to log issues in development environments in critical
|
|
* paths. Removing the logging code for production environments will keep the
|
|
* same logic and follow the same code paths.
|
|
*/
|
|
|
|
// The Symbol used to tag the ReactElement-like types. If there is no native Symbol
|
|
// nor polyfill, then a plain number is used for performance.
|
|
var hasSymbol = typeof Symbol === 'function' && Symbol.for;
|
|
|
|
|
|
var REACT_PORTAL_TYPE = hasSymbol ? Symbol.for('react.portal') : 0xeaca;
|
|
var REACT_FRAGMENT_TYPE = hasSymbol ? Symbol.for('react.fragment') : 0xeacb;
|
|
var REACT_STRICT_MODE_TYPE = hasSymbol ? Symbol.for('react.strict_mode') : 0xeacc;
|
|
var REACT_PROFILER_TYPE = hasSymbol ? Symbol.for('react.profiler') : 0xead2;
|
|
var REACT_PROVIDER_TYPE = hasSymbol ? Symbol.for('react.provider') : 0xeacd;
|
|
var REACT_CONTEXT_TYPE = hasSymbol ? Symbol.for('react.context') : 0xeace;
|
|
|
|
var REACT_CONCURRENT_MODE_TYPE = hasSymbol ? Symbol.for('react.concurrent_mode') : 0xeacf;
|
|
var REACT_FORWARD_REF_TYPE = hasSymbol ? Symbol.for('react.forward_ref') : 0xead0;
|
|
var REACT_SUSPENSE_TYPE = hasSymbol ? Symbol.for('react.suspense') : 0xead1;
|
|
var REACT_MEMO_TYPE = hasSymbol ? Symbol.for('react.memo') : 0xead3;
|
|
var REACT_LAZY_TYPE = hasSymbol ? Symbol.for('react.lazy') : 0xead4;
|
|
|
|
var Resolved = 1;
|
|
|
|
|
|
function refineResolvedLazyComponent(lazyComponent) {
|
|
return lazyComponent._status === Resolved ? lazyComponent._result : null;
|
|
}
|
|
|
|
function getWrappedName(outerType, innerType, wrapperName) {
|
|
var functionName = innerType.displayName || innerType.name || '';
|
|
return outerType.displayName || (functionName !== '' ? wrapperName + '(' + functionName + ')' : wrapperName);
|
|
}
|
|
|
|
function getComponentName(type) {
|
|
if (type == null) {
|
|
// Host root, text node or just invalid type.
|
|
return null;
|
|
}
|
|
if (typeof type === 'function') {
|
|
return type.displayName || type.name || null;
|
|
}
|
|
if (typeof type === 'string') {
|
|
return type;
|
|
}
|
|
switch (type) {
|
|
case REACT_CONCURRENT_MODE_TYPE:
|
|
return 'ConcurrentMode';
|
|
case REACT_FRAGMENT_TYPE:
|
|
return 'Fragment';
|
|
case REACT_PORTAL_TYPE:
|
|
return 'Portal';
|
|
case REACT_PROFILER_TYPE:
|
|
return 'Profiler';
|
|
case REACT_STRICT_MODE_TYPE:
|
|
return 'StrictMode';
|
|
case REACT_SUSPENSE_TYPE:
|
|
return 'Suspense';
|
|
}
|
|
if (typeof type === 'object') {
|
|
switch (type.$$typeof) {
|
|
case REACT_CONTEXT_TYPE:
|
|
return 'Context.Consumer';
|
|
case REACT_PROVIDER_TYPE:
|
|
return 'Context.Provider';
|
|
case REACT_FORWARD_REF_TYPE:
|
|
return getWrappedName(type, type.render, 'ForwardRef');
|
|
case REACT_MEMO_TYPE:
|
|
return getComponentName(type.type);
|
|
case REACT_LAZY_TYPE:
|
|
{
|
|
var thenable = type;
|
|
var resolvedThenable = refineResolvedLazyComponent(thenable);
|
|
if (resolvedThenable) {
|
|
return getComponentName(resolvedThenable);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Forked from fbjs/warning:
|
|
* https://github.com/facebook/fbjs/blob/e66ba20ad5be433eb54423f2b097d829324d9de6/packages/fbjs/src/__forks__/warning.js
|
|
*
|
|
* Only change is we use console.warn instead of console.error,
|
|
* and do nothing when 'console' is not supported.
|
|
* This really simplifies the code.
|
|
* ---
|
|
* Similar to invariant but only logs a warning if the condition is not met.
|
|
* This can be used to log issues in development environments in critical
|
|
* paths. Removing the logging code for production environments will keep the
|
|
* same logic and follow the same code paths.
|
|
*/
|
|
|
|
var ReactSharedInternals = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
|
|
|
|
// Prevent newer renderers from RTE when used with older react package versions.
|
|
// Current owner and dispatcher used to share the same ref,
|
|
// but PR #14548 split them out to better support the react-debug-tools package.
|
|
if (!ReactSharedInternals.hasOwnProperty('ReactCurrentDispatcher')) {
|
|
ReactSharedInternals.ReactCurrentDispatcher = {
|
|
current: null
|
|
};
|
|
}
|
|
|
|
// Helps identify side effects in begin-phase lifecycle hooks and setState reducers:
|
|
|
|
|
|
// In some cases, StrictMode should also double-render lifecycles.
|
|
// This can be confusing for tests though,
|
|
// And it can be bad for performance in production.
|
|
// This feature flag can be used to control the behavior:
|
|
|
|
|
|
// To preserve the "Pause on caught exceptions" behavior of the debugger, we
|
|
// replay the begin phase of a failed component inside invokeGuardedCallback.
|
|
|
|
|
|
// Warn about deprecated, async-unsafe lifecycles; relates to RFC #6:
|
|
|
|
|
|
// Gather advanced timing metrics for Profiler subtrees.
|
|
|
|
|
|
// Trace which interactions trigger each commit.
|
|
|
|
|
|
// Only used in www builds.
|
|
var enableSuspenseServerRenderer = false; // TODO: false? Here it might just be false.
|
|
|
|
// Only used in www builds.
|
|
|
|
|
|
// Only used in www builds.
|
|
|
|
|
|
// React Fire: prevent the value and checked attributes from syncing
|
|
// with their related DOM properties
|
|
|
|
|
|
// These APIs will no longer be "unstable" in the upcoming 16.7 release,
|
|
// Control this behavior with a flag to support 16.6 minor releases in the meanwhile.
|
|
|
|
/**
|
|
* Copyright (c) 2013-present, Facebook, Inc.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*/
|
|
|
|
var emptyObject = {};
|
|
function maskContext(type, context) {
|
|
var contextTypes = type.contextTypes;
|
|
if (!contextTypes) {
|
|
return emptyObject;
|
|
}
|
|
var maskedContext = {};
|
|
for (var contextName in contextTypes) {
|
|
maskedContext[contextName] = context[contextName];
|
|
}
|
|
return maskedContext;
|
|
}
|
|
|
|
function validateContextBounds(context, threadID) {
|
|
// If we don't have enough slots in this context to store this threadID,
|
|
// fill it in without leaving any holes to ensure that the VM optimizes
|
|
// this as non-holey index properties.
|
|
// (Note: If `react` package is < 16.6, _threadCount is undefined.)
|
|
for (var i = context._threadCount | 0; i <= threadID; i++) {
|
|
// We assume that this is the same as the defaultValue which might not be
|
|
// true if we're rendering inside a secondary renderer but they are
|
|
// secondary because these use cases are very rare.
|
|
context[i] = context._currentValue2;
|
|
context._threadCount = i + 1;
|
|
}
|
|
}
|
|
|
|
function processContext(type, context, threadID) {
|
|
var contextType = type.contextType;
|
|
if (typeof contextType === 'object' && contextType !== null) {
|
|
validateContextBounds(contextType, threadID);
|
|
return contextType[threadID];
|
|
} else {
|
|
var maskedContext = maskContext(type, context);
|
|
return maskedContext;
|
|
}
|
|
}
|
|
|
|
// Allocates a new index for each request. Tries to stay as compact as possible so that these
|
|
// indices can be used to reference a tightly packaged array. As opposed to being used in a Map.
|
|
// The first allocated index is 1.
|
|
|
|
var nextAvailableThreadIDs = new Uint16Array(16);
|
|
for (var i = 0; i < 15; i++) {
|
|
nextAvailableThreadIDs[i] = i + 1;
|
|
}
|
|
nextAvailableThreadIDs[15] = 0;
|
|
|
|
function growThreadCountAndReturnNextAvailable() {
|
|
var oldArray = nextAvailableThreadIDs;
|
|
var oldSize = oldArray.length;
|
|
var newSize = oldSize * 2;
|
|
!(newSize <= 0x10000) ? reactProdInvariant('304') : void 0;
|
|
var newArray = new Uint16Array(newSize);
|
|
newArray.set(oldArray);
|
|
nextAvailableThreadIDs = newArray;
|
|
nextAvailableThreadIDs[0] = oldSize + 1;
|
|
for (var _i = oldSize; _i < newSize - 1; _i++) {
|
|
nextAvailableThreadIDs[_i] = _i + 1;
|
|
}
|
|
nextAvailableThreadIDs[newSize - 1] = 0;
|
|
return oldSize;
|
|
}
|
|
|
|
function allocThreadID() {
|
|
var nextID = nextAvailableThreadIDs[0];
|
|
if (nextID === 0) {
|
|
return growThreadCountAndReturnNextAvailable();
|
|
}
|
|
nextAvailableThreadIDs[0] = nextAvailableThreadIDs[nextID];
|
|
return nextID;
|
|
}
|
|
|
|
function freeThreadID(id) {
|
|
nextAvailableThreadIDs[id] = nextAvailableThreadIDs[0];
|
|
nextAvailableThreadIDs[0] = id;
|
|
}
|
|
|
|
// A reserved attribute.
|
|
// It is handled by React separately and shouldn't be written to the DOM.
|
|
var RESERVED = 0;
|
|
|
|
// A simple string attribute.
|
|
// Attributes that aren't in the whitelist are presumed to have this type.
|
|
var STRING = 1;
|
|
|
|
// A string attribute that accepts booleans in React. In HTML, these are called
|
|
// "enumerated" attributes with "true" and "false" as possible values.
|
|
// When true, it should be set to a "true" string.
|
|
// When false, it should be set to a "false" string.
|
|
var BOOLEANISH_STRING = 2;
|
|
|
|
// A real boolean attribute.
|
|
// When true, it should be present (set either to an empty string or its name).
|
|
// When false, it should be omitted.
|
|
var BOOLEAN = 3;
|
|
|
|
// An attribute that can be used as a flag as well as with a value.
|
|
// When true, it should be present (set either to an empty string or its name).
|
|
// When false, it should be omitted.
|
|
// For any other value, should be present with that value.
|
|
var OVERLOADED_BOOLEAN = 4;
|
|
|
|
// An attribute that must be numeric or parse as a numeric.
|
|
// When falsy, it should be removed.
|
|
var NUMERIC = 5;
|
|
|
|
// An attribute that must be positive numeric or parse as a positive numeric.
|
|
// When falsy, it should be removed.
|
|
var POSITIVE_NUMERIC = 6;
|
|
|
|
/* eslint-disable max-len */
|
|
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';
|
|
/* eslint-enable max-len */
|
|
var ATTRIBUTE_NAME_CHAR = ATTRIBUTE_NAME_START_CHAR + '\\-.0-9\\u00B7\\u0300-\\u036F\\u203F-\\u2040';
|
|
|
|
|
|
var ROOT_ATTRIBUTE_NAME = 'data-reactroot';
|
|
var VALID_ATTRIBUTE_NAME_REGEX = new RegExp('^[' + ATTRIBUTE_NAME_START_CHAR + '][' + ATTRIBUTE_NAME_CHAR + ']*$');
|
|
|
|
var hasOwnProperty$1 = Object.prototype.hasOwnProperty;
|
|
var illegalAttributeNameCache = {};
|
|
var validatedAttributeNameCache = {};
|
|
|
|
function isAttributeNameSafe(attributeName) {
|
|
if (hasOwnProperty$1.call(validatedAttributeNameCache, attributeName)) {
|
|
return true;
|
|
}
|
|
if (hasOwnProperty$1.call(illegalAttributeNameCache, attributeName)) {
|
|
return false;
|
|
}
|
|
if (VALID_ATTRIBUTE_NAME_REGEX.test(attributeName)) {
|
|
validatedAttributeNameCache[attributeName] = true;
|
|
return true;
|
|
}
|
|
illegalAttributeNameCache[attributeName] = true;
|
|
return false;
|
|
}
|
|
|
|
function shouldIgnoreAttribute(name, propertyInfo, isCustomComponentTag) {
|
|
if (propertyInfo !== null) {
|
|
return propertyInfo.type === RESERVED;
|
|
}
|
|
if (isCustomComponentTag) {
|
|
return false;
|
|
}
|
|
if (name.length > 2 && (name[0] === 'o' || name[0] === 'O') && (name[1] === 'n' || name[1] === 'N')) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
function shouldRemoveAttributeWithWarning(name, value, propertyInfo, isCustomComponentTag) {
|
|
if (propertyInfo !== null && propertyInfo.type === RESERVED) {
|
|
return false;
|
|
}
|
|
switch (typeof value) {
|
|
case 'function':
|
|
// $FlowIssue symbol is perfectly valid here
|
|
case 'symbol':
|
|
// eslint-disable-line
|
|
return true;
|
|
case 'boolean':
|
|
{
|
|
if (isCustomComponentTag) {
|
|
return false;
|
|
}
|
|
if (propertyInfo !== null) {
|
|
return !propertyInfo.acceptsBooleans;
|
|
} else {
|
|
var prefix = name.toLowerCase().slice(0, 5);
|
|
return prefix !== 'data-' && prefix !== 'aria-';
|
|
}
|
|
}
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
function shouldRemoveAttribute(name, value, propertyInfo, isCustomComponentTag) {
|
|
if (value === null || typeof value === 'undefined') {
|
|
return true;
|
|
}
|
|
if (shouldRemoveAttributeWithWarning(name, value, propertyInfo, isCustomComponentTag)) {
|
|
return true;
|
|
}
|
|
if (isCustomComponentTag) {
|
|
return false;
|
|
}
|
|
if (propertyInfo !== null) {
|
|
switch (propertyInfo.type) {
|
|
case BOOLEAN:
|
|
return !value;
|
|
case OVERLOADED_BOOLEAN:
|
|
return value === false;
|
|
case NUMERIC:
|
|
return isNaN(value);
|
|
case POSITIVE_NUMERIC:
|
|
return isNaN(value) || value < 1;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
function getPropertyInfo(name) {
|
|
return properties.hasOwnProperty(name) ? properties[name] : null;
|
|
}
|
|
|
|
function PropertyInfoRecord(name, type, mustUseProperty, attributeName, attributeNamespace) {
|
|
this.acceptsBooleans = type === BOOLEANISH_STRING || type === BOOLEAN || type === OVERLOADED_BOOLEAN;
|
|
this.attributeName = attributeName;
|
|
this.attributeNamespace = attributeNamespace;
|
|
this.mustUseProperty = mustUseProperty;
|
|
this.propertyName = name;
|
|
this.type = type;
|
|
}
|
|
|
|
// When adding attributes to this list, be sure to also add them to
|
|
// the `possibleStandardNames` module to ensure casing and incorrect
|
|
// name warnings.
|
|
var properties = {};
|
|
|
|
// These props are reserved by React. They shouldn't be written to the DOM.
|
|
['children', 'dangerouslySetInnerHTML',
|
|
// TODO: This prevents the assignment of defaultValue to regular
|
|
// elements (not just inputs). Now that ReactDOMInput assigns to the
|
|
// defaultValue property -- do we need this?
|
|
'defaultValue', 'defaultChecked', 'innerHTML', 'suppressContentEditableWarning', 'suppressHydrationWarning', 'style'].forEach(function (name) {
|
|
properties[name] = new PropertyInfoRecord(name, RESERVED, false, // mustUseProperty
|
|
name, // attributeName
|
|
null);
|
|
} // attributeNamespace
|
|
);
|
|
|
|
// A few React string attributes have a different name.
|
|
// This is a mapping from React prop names to the attribute names.
|
|
[['acceptCharset', 'accept-charset'], ['className', 'class'], ['htmlFor', 'for'], ['httpEquiv', 'http-equiv']].forEach(function (_ref) {
|
|
var name = _ref[0],
|
|
attributeName = _ref[1];
|
|
|
|
properties[name] = new PropertyInfoRecord(name, STRING, false, // mustUseProperty
|
|
attributeName, // attributeName
|
|
null);
|
|
} // attributeNamespace
|
|
);
|
|
|
|
// These are "enumerated" HTML attributes that accept "true" and "false".
|
|
// In React, we let users pass `true` and `false` even though technically
|
|
// these aren't boolean attributes (they are coerced to strings).
|
|
['contentEditable', 'draggable', 'spellCheck', 'value'].forEach(function (name) {
|
|
properties[name] = new PropertyInfoRecord(name, BOOLEANISH_STRING, false, // mustUseProperty
|
|
name.toLowerCase(), // attributeName
|
|
null);
|
|
} // attributeNamespace
|
|
);
|
|
|
|
// These are "enumerated" SVG attributes that accept "true" and "false".
|
|
// In React, we let users pass `true` and `false` even though technically
|
|
// these aren't boolean attributes (they are coerced to strings).
|
|
// Since these are SVG attributes, their attribute names are case-sensitive.
|
|
['autoReverse', 'externalResourcesRequired', 'focusable', 'preserveAlpha'].forEach(function (name) {
|
|
properties[name] = new PropertyInfoRecord(name, BOOLEANISH_STRING, false, // mustUseProperty
|
|
name, // attributeName
|
|
null);
|
|
} // attributeNamespace
|
|
);
|
|
|
|
// These are HTML boolean attributes.
|
|
['allowFullScreen', 'async',
|
|
// Note: there is a special case that prevents it from being written to the DOM
|
|
// on the client side because the browsers are inconsistent. Instead we call focus().
|
|
'autoFocus', 'autoPlay', 'controls', 'default', 'defer', 'disabled', 'formNoValidate', 'hidden', 'loop', 'noModule', 'noValidate', 'open', 'playsInline', 'readOnly', 'required', 'reversed', 'scoped', 'seamless',
|
|
// Microdata
|
|
'itemScope'].forEach(function (name) {
|
|
properties[name] = new PropertyInfoRecord(name, BOOLEAN, false, // mustUseProperty
|
|
name.toLowerCase(), // attributeName
|
|
null);
|
|
} // attributeNamespace
|
|
);
|
|
|
|
// These are the few React props that we set as DOM properties
|
|
// rather than attributes. These are all booleans.
|
|
['checked',
|
|
// Note: `option.selected` is not updated if `select.multiple` is
|
|
// disabled with `removeAttribute`. We have special logic for handling this.
|
|
'multiple', 'muted', 'selected'].forEach(function (name) {
|
|
properties[name] = new PropertyInfoRecord(name, BOOLEAN, true, // mustUseProperty
|
|
name, // attributeName
|
|
null);
|
|
} // attributeNamespace
|
|
);
|
|
|
|
// These are HTML attributes that are "overloaded booleans": they behave like
|
|
// booleans, but can also accept a string value.
|
|
['capture', 'download'].forEach(function (name) {
|
|
properties[name] = new PropertyInfoRecord(name, OVERLOADED_BOOLEAN, false, // mustUseProperty
|
|
name, // attributeName
|
|
null);
|
|
} // attributeNamespace
|
|
);
|
|
|
|
// These are HTML attributes that must be positive numbers.
|
|
['cols', 'rows', 'size', 'span'].forEach(function (name) {
|
|
properties[name] = new PropertyInfoRecord(name, POSITIVE_NUMERIC, false, // mustUseProperty
|
|
name, // attributeName
|
|
null);
|
|
} // attributeNamespace
|
|
);
|
|
|
|
// These are HTML attributes that must be numbers.
|
|
['rowSpan', 'start'].forEach(function (name) {
|
|
properties[name] = new PropertyInfoRecord(name, NUMERIC, false, // mustUseProperty
|
|
name.toLowerCase(), // attributeName
|
|
null);
|
|
} // attributeNamespace
|
|
);
|
|
|
|
var CAMELIZE = /[\-\:]([a-z])/g;
|
|
var capitalize = function (token) {
|
|
return token[1].toUpperCase();
|
|
};
|
|
|
|
// This is a list of all SVG attributes that need special casing, namespacing,
|
|
// or boolean value assignment. Regular attributes that just accept strings
|
|
// and have the same names are omitted, just like in the HTML whitelist.
|
|
// Some of these attributes can be hard to find. This list was created by
|
|
// scrapping the MDN documentation.
|
|
['accent-height', 'alignment-baseline', 'arabic-form', 'baseline-shift', 'cap-height', 'clip-path', 'clip-rule', 'color-interpolation', 'color-interpolation-filters', 'color-profile', 'color-rendering', 'dominant-baseline', 'enable-background', 'fill-opacity', 'fill-rule', 'flood-color', 'flood-opacity', 'font-family', 'font-size', 'font-size-adjust', 'font-stretch', 'font-style', 'font-variant', 'font-weight', 'glyph-name', 'glyph-orientation-horizontal', 'glyph-orientation-vertical', 'horiz-adv-x', 'horiz-origin-x', 'image-rendering', 'letter-spacing', 'lighting-color', 'marker-end', 'marker-mid', 'marker-start', 'overline-position', 'overline-thickness', 'paint-order', 'panose-1', 'pointer-events', 'rendering-intent', 'shape-rendering', 'stop-color', 'stop-opacity', 'strikethrough-position', 'strikethrough-thickness', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'text-anchor', 'text-decoration', 'text-rendering', 'underline-position', 'underline-thickness', 'unicode-bidi', 'unicode-range', 'units-per-em', 'v-alphabetic', 'v-hanging', 'v-ideographic', 'v-mathematical', 'vector-effect', 'vert-adv-y', 'vert-origin-x', 'vert-origin-y', 'word-spacing', 'writing-mode', 'xmlns:xlink', 'x-height'].forEach(function (attributeName) {
|
|
var name = attributeName.replace(CAMELIZE, capitalize);
|
|
properties[name] = new PropertyInfoRecord(name, STRING, false, // mustUseProperty
|
|
attributeName, null);
|
|
} // attributeNamespace
|
|
);
|
|
|
|
// String SVG attributes with the xlink namespace.
|
|
['xlink:actuate', 'xlink:arcrole', 'xlink:href', 'xlink:role', 'xlink:show', 'xlink:title', 'xlink:type'].forEach(function (attributeName) {
|
|
var name = attributeName.replace(CAMELIZE, capitalize);
|
|
properties[name] = new PropertyInfoRecord(name, STRING, false, // mustUseProperty
|
|
attributeName, 'http://www.w3.org/1999/xlink');
|
|
});
|
|
|
|
// String SVG attributes with the xml namespace.
|
|
['xml:base', 'xml:lang', 'xml:space'].forEach(function (attributeName) {
|
|
var name = attributeName.replace(CAMELIZE, capitalize);
|
|
properties[name] = new PropertyInfoRecord(name, STRING, false, // mustUseProperty
|
|
attributeName, 'http://www.w3.org/XML/1998/namespace');
|
|
});
|
|
|
|
// These attribute exists both in HTML and SVG.
|
|
// The attribute name is case-sensitive in SVG so we can't just use
|
|
// the React name like we do for attributes that exist only in HTML.
|
|
['tabIndex', 'crossOrigin'].forEach(function (attributeName) {
|
|
properties[attributeName] = new PropertyInfoRecord(attributeName, STRING, false, // mustUseProperty
|
|
attributeName.toLowerCase(), // attributeName
|
|
null);
|
|
} // attributeNamespace
|
|
);
|
|
|
|
// code copied and modified from escape-html
|
|
/**
|
|
* Module variables.
|
|
* @private
|
|
*/
|
|
|
|
var matchHtmlRegExp = /["'&<>]/;
|
|
|
|
/**
|
|
* Escapes special characters and HTML entities in a given html string.
|
|
*
|
|
* @param {string} string HTML string to escape for later insertion
|
|
* @return {string}
|
|
* @public
|
|
*/
|
|
|
|
function escapeHtml(string) {
|
|
var str = '' + string;
|
|
var match = matchHtmlRegExp.exec(str);
|
|
|
|
if (!match) {
|
|
return str;
|
|
}
|
|
|
|
var escape = void 0;
|
|
var html = '';
|
|
var index = void 0;
|
|
var lastIndex = 0;
|
|
|
|
for (index = match.index; index < str.length; index++) {
|
|
switch (str.charCodeAt(index)) {
|
|
case 34:
|
|
// "
|
|
escape = '"';
|
|
break;
|
|
case 38:
|
|
// &
|
|
escape = '&';
|
|
break;
|
|
case 39:
|
|
// '
|
|
escape = '''; // modified from escape-html; used to be '''
|
|
break;
|
|
case 60:
|
|
// <
|
|
escape = '<';
|
|
break;
|
|
case 62:
|
|
// >
|
|
escape = '>';
|
|
break;
|
|
default:
|
|
continue;
|
|
}
|
|
|
|
if (lastIndex !== index) {
|
|
html += str.substring(lastIndex, index);
|
|
}
|
|
|
|
lastIndex = index + 1;
|
|
html += escape;
|
|
}
|
|
|
|
return lastIndex !== index ? html + str.substring(lastIndex, index) : html;
|
|
}
|
|
// end code copied and modified from escape-html
|
|
|
|
/**
|
|
* Escapes text to prevent scripting attacks.
|
|
*
|
|
* @param {*} text Text value to escape.
|
|
* @return {string} An escaped string.
|
|
*/
|
|
function escapeTextForBrowser(text) {
|
|
if (typeof text === 'boolean' || typeof text === 'number') {
|
|
// this shortcircuit helps perf for types that we know will never have
|
|
// special characters, especially given that this function is used often
|
|
// for numeric dom ids.
|
|
return '' + text;
|
|
}
|
|
return escapeHtml(text);
|
|
}
|
|
|
|
/**
|
|
* Escapes attribute value to prevent scripting attacks.
|
|
*
|
|
* @param {*} value Value to escape.
|
|
* @return {string} An escaped string.
|
|
*/
|
|
function quoteAttributeValueForBrowser(value) {
|
|
return '"' + escapeTextForBrowser(value) + '"';
|
|
}
|
|
|
|
/**
|
|
* Operations for dealing with DOM properties.
|
|
*/
|
|
|
|
/**
|
|
* Creates markup for the ID property.
|
|
*
|
|
* @param {string} id Unescaped ID.
|
|
* @return {string} Markup string.
|
|
*/
|
|
|
|
|
|
function createMarkupForRoot() {
|
|
return ROOT_ATTRIBUTE_NAME + '=""';
|
|
}
|
|
|
|
/**
|
|
* Creates markup for a property.
|
|
*
|
|
* @param {string} name
|
|
* @param {*} value
|
|
* @return {?string} Markup string, or null if the property was invalid.
|
|
*/
|
|
function createMarkupForProperty(name, value) {
|
|
var propertyInfo = getPropertyInfo(name);
|
|
if (name !== 'style' && shouldIgnoreAttribute(name, propertyInfo, false)) {
|
|
return '';
|
|
}
|
|
if (shouldRemoveAttribute(name, value, propertyInfo, false)) {
|
|
return '';
|
|
}
|
|
if (propertyInfo !== null) {
|
|
var attributeName = propertyInfo.attributeName;
|
|
var type = propertyInfo.type;
|
|
|
|
if (type === BOOLEAN || type === OVERLOADED_BOOLEAN && value === true) {
|
|
return attributeName + '=""';
|
|
} else {
|
|
return attributeName + '=' + quoteAttributeValueForBrowser(value);
|
|
}
|
|
} else if (isAttributeNameSafe(name)) {
|
|
return name + '=' + quoteAttributeValueForBrowser(value);
|
|
}
|
|
return '';
|
|
}
|
|
|
|
/**
|
|
* Creates markup for a custom property.
|
|
*
|
|
* @param {string} name
|
|
* @param {*} value
|
|
* @return {string} Markup string, or empty string if the property was invalid.
|
|
*/
|
|
function createMarkupForCustomAttribute(name, value) {
|
|
if (!isAttributeNameSafe(name) || value == null) {
|
|
return '';
|
|
}
|
|
return name + '=' + quoteAttributeValueForBrowser(value);
|
|
}
|
|
|
|
/**
|
|
* inlined Object.is polyfill to avoid requiring consumers ship their own
|
|
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is
|
|
*/
|
|
function is(x, y) {
|
|
return x === y && (x !== 0 || 1 / x === 1 / y) || x !== x && y !== y // eslint-disable-line no-self-compare
|
|
;
|
|
}
|
|
|
|
var currentlyRenderingComponent = null;
|
|
var firstWorkInProgressHook = null;
|
|
var workInProgressHook = null;
|
|
// Whether the work-in-progress hook is a re-rendered hook
|
|
var isReRender = false;
|
|
// Whether an update was scheduled during the currently executing render pass.
|
|
var didScheduleRenderPhaseUpdate = false;
|
|
// Lazily created map of render-phase updates
|
|
var renderPhaseUpdates = null;
|
|
// Counter to prevent infinite loops.
|
|
var numberOfReRenders = 0;
|
|
var RE_RENDER_LIMIT = 25;
|
|
|
|
function resolveCurrentlyRenderingComponent() {
|
|
!(currentlyRenderingComponent !== null) ? reactProdInvariant('321') : void 0;
|
|
return currentlyRenderingComponent;
|
|
}
|
|
|
|
function areHookInputsEqual(nextDeps, prevDeps) {
|
|
if (prevDeps === null) {
|
|
return false;
|
|
}
|
|
|
|
for (var i = 0; i < prevDeps.length && i < nextDeps.length; i++) {
|
|
if (is(nextDeps[i], prevDeps[i])) {
|
|
continue;
|
|
}
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
function createHook() {
|
|
if (numberOfReRenders > 0) {
|
|
reactProdInvariant('312');
|
|
}
|
|
return {
|
|
memoizedState: null,
|
|
queue: null,
|
|
next: null
|
|
};
|
|
}
|
|
|
|
function createWorkInProgressHook() {
|
|
if (workInProgressHook === null) {
|
|
// This is the first hook in the list
|
|
if (firstWorkInProgressHook === null) {
|
|
isReRender = false;
|
|
firstWorkInProgressHook = workInProgressHook = createHook();
|
|
} else {
|
|
// There's already a work-in-progress. Reuse it.
|
|
isReRender = true;
|
|
workInProgressHook = firstWorkInProgressHook;
|
|
}
|
|
} else {
|
|
if (workInProgressHook.next === null) {
|
|
isReRender = false;
|
|
// Append to the end of the list
|
|
workInProgressHook = workInProgressHook.next = createHook();
|
|
} else {
|
|
// There's already a work-in-progress. Reuse it.
|
|
isReRender = true;
|
|
workInProgressHook = workInProgressHook.next;
|
|
}
|
|
}
|
|
return workInProgressHook;
|
|
}
|
|
|
|
function prepareToUseHooks(componentIdentity) {
|
|
currentlyRenderingComponent = componentIdentity;
|
|
|
|
|
|
// The following should have already been reset
|
|
// didScheduleRenderPhaseUpdate = false;
|
|
// firstWorkInProgressHook = null;
|
|
// numberOfReRenders = 0;
|
|
// renderPhaseUpdates = null;
|
|
// workInProgressHook = null;
|
|
}
|
|
|
|
function finishHooks(Component, props, children, refOrContext) {
|
|
// This must be called after every function component to prevent hooks from
|
|
// being used in classes.
|
|
|
|
while (didScheduleRenderPhaseUpdate) {
|
|
// Updates were scheduled during the render phase. They are stored in
|
|
// the `renderPhaseUpdates` map. Call the component again, reusing the
|
|
// work-in-progress hooks and applying the additional updates on top. Keep
|
|
// restarting until no more updates are scheduled.
|
|
didScheduleRenderPhaseUpdate = false;
|
|
numberOfReRenders += 1;
|
|
|
|
// Start over from the beginning of the list
|
|
workInProgressHook = null;
|
|
|
|
children = Component(props, refOrContext);
|
|
}
|
|
currentlyRenderingComponent = null;
|
|
firstWorkInProgressHook = null;
|
|
numberOfReRenders = 0;
|
|
renderPhaseUpdates = null;
|
|
workInProgressHook = null;
|
|
return children;
|
|
}
|
|
|
|
function readContext(context, observedBits) {
|
|
var threadID = currentThreadID;
|
|
validateContextBounds(context, threadID);
|
|
return context[threadID];
|
|
}
|
|
|
|
function useContext(context, observedBits) {
|
|
resolveCurrentlyRenderingComponent();
|
|
var threadID = currentThreadID;
|
|
validateContextBounds(context, threadID);
|
|
return context[threadID];
|
|
}
|
|
|
|
function basicStateReducer(state, action) {
|
|
return typeof action === 'function' ? action(state) : action;
|
|
}
|
|
|
|
function useState(initialState) {
|
|
return useReducer(basicStateReducer,
|
|
// useReducer has a special case to support lazy useState initializers
|
|
initialState);
|
|
}
|
|
|
|
function useReducer(reducer, initialArg, init) {
|
|
currentlyRenderingComponent = resolveCurrentlyRenderingComponent();
|
|
workInProgressHook = createWorkInProgressHook();
|
|
if (isReRender) {
|
|
// This is a re-render. Apply the new render phase updates to the previous
|
|
var _queue = workInProgressHook.queue;
|
|
var _dispatch = _queue.dispatch;
|
|
if (renderPhaseUpdates !== null) {
|
|
// Render phase updates are stored in a map of queue -> linked list
|
|
var firstRenderPhaseUpdate = renderPhaseUpdates.get(_queue);
|
|
if (firstRenderPhaseUpdate !== undefined) {
|
|
renderPhaseUpdates.delete(_queue);
|
|
var newState = workInProgressHook.memoizedState;
|
|
var update = firstRenderPhaseUpdate;
|
|
do {
|
|
// Process this render phase update. We don't have to check the
|
|
// priority because it will always be the same as the current
|
|
// render's.
|
|
var _action = update.action;
|
|
newState = reducer(newState, _action);
|
|
update = update.next;
|
|
} while (update !== null);
|
|
|
|
workInProgressHook.memoizedState = newState;
|
|
|
|
return [newState, _dispatch];
|
|
}
|
|
}
|
|
return [workInProgressHook.memoizedState, _dispatch];
|
|
} else {
|
|
var initialState = void 0;
|
|
if (reducer === basicStateReducer) {
|
|
// Special case for `useState`.
|
|
initialState = typeof initialArg === 'function' ? initialArg() : initialArg;
|
|
} else {
|
|
initialState = init !== undefined ? init(initialArg) : initialArg;
|
|
}
|
|
workInProgressHook.memoizedState = initialState;
|
|
var _queue2 = workInProgressHook.queue = {
|
|
last: null,
|
|
dispatch: null
|
|
};
|
|
var _dispatch2 = _queue2.dispatch = dispatchAction.bind(null, currentlyRenderingComponent, _queue2);
|
|
return [workInProgressHook.memoizedState, _dispatch2];
|
|
}
|
|
}
|
|
|
|
function useMemo(nextCreate, deps) {
|
|
currentlyRenderingComponent = resolveCurrentlyRenderingComponent();
|
|
workInProgressHook = createWorkInProgressHook();
|
|
|
|
var nextDeps = deps === undefined ? null : deps;
|
|
|
|
if (workInProgressHook !== null) {
|
|
var prevState = workInProgressHook.memoizedState;
|
|
if (prevState !== null) {
|
|
if (nextDeps !== null) {
|
|
var prevDeps = prevState[1];
|
|
if (areHookInputsEqual(nextDeps, prevDeps)) {
|
|
return prevState[0];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
var nextValue = nextCreate();
|
|
workInProgressHook.memoizedState = [nextValue, nextDeps];
|
|
return nextValue;
|
|
}
|
|
|
|
function useRef(initialValue) {
|
|
currentlyRenderingComponent = resolveCurrentlyRenderingComponent();
|
|
workInProgressHook = createWorkInProgressHook();
|
|
var previousRef = workInProgressHook.memoizedState;
|
|
if (previousRef === null) {
|
|
var ref = { current: initialValue };
|
|
workInProgressHook.memoizedState = ref;
|
|
return ref;
|
|
} else {
|
|
return previousRef;
|
|
}
|
|
}
|
|
|
|
function useLayoutEffect(create, inputs) {
|
|
|
|
}
|
|
|
|
function dispatchAction(componentIdentity, queue, action) {
|
|
!(numberOfReRenders < RE_RENDER_LIMIT) ? reactProdInvariant('301') : void 0;
|
|
|
|
if (componentIdentity === currentlyRenderingComponent) {
|
|
// This is a render phase update. Stash it in a lazily-created map of
|
|
// queue -> linked list of updates. After this render pass, we'll restart
|
|
// and apply the stashed updates on top of the work-in-progress hook.
|
|
didScheduleRenderPhaseUpdate = true;
|
|
var update = {
|
|
action: action,
|
|
next: null
|
|
};
|
|
if (renderPhaseUpdates === null) {
|
|
renderPhaseUpdates = new Map();
|
|
}
|
|
var firstRenderPhaseUpdate = renderPhaseUpdates.get(queue);
|
|
if (firstRenderPhaseUpdate === undefined) {
|
|
renderPhaseUpdates.set(queue, update);
|
|
} else {
|
|
// Append the update to the end of the list.
|
|
var lastRenderPhaseUpdate = firstRenderPhaseUpdate;
|
|
while (lastRenderPhaseUpdate.next !== null) {
|
|
lastRenderPhaseUpdate = lastRenderPhaseUpdate.next;
|
|
}
|
|
lastRenderPhaseUpdate.next = update;
|
|
}
|
|
} else {
|
|
// This means an update has happened after the function component has
|
|
// returned. On the server this is a no-op. In React Fiber, the update
|
|
// would be scheduled for a future render.
|
|
}
|
|
}
|
|
|
|
function useCallback(callback, deps) {
|
|
// Callbacks are passed as they are in the server environment.
|
|
return callback;
|
|
}
|
|
|
|
function noop() {}
|
|
|
|
var currentThreadID = 0;
|
|
|
|
function setCurrentThreadID(threadID) {
|
|
currentThreadID = threadID;
|
|
}
|
|
|
|
var Dispatcher = {
|
|
readContext: readContext,
|
|
useContext: useContext,
|
|
useMemo: useMemo,
|
|
useReducer: useReducer,
|
|
useRef: useRef,
|
|
useState: useState,
|
|
useLayoutEffect: useLayoutEffect,
|
|
useCallback: useCallback,
|
|
// useImperativeHandle is not run in the server environment
|
|
useImperativeHandle: noop,
|
|
// Effects are not run in the server environment.
|
|
useEffect: noop,
|
|
// Debugging effect
|
|
useDebugValue: noop
|
|
};
|
|
|
|
var HTML_NAMESPACE = 'http://www.w3.org/1999/xhtml';
|
|
var MATH_NAMESPACE = 'http://www.w3.org/1998/Math/MathML';
|
|
var SVG_NAMESPACE = 'http://www.w3.org/2000/svg';
|
|
|
|
var Namespaces = {
|
|
html: HTML_NAMESPACE,
|
|
mathml: MATH_NAMESPACE,
|
|
svg: SVG_NAMESPACE
|
|
};
|
|
|
|
// Assumes there is no parent namespace.
|
|
function getIntrinsicNamespace(type) {
|
|
switch (type) {
|
|
case 'svg':
|
|
return SVG_NAMESPACE;
|
|
case 'math':
|
|
return MATH_NAMESPACE;
|
|
default:
|
|
return HTML_NAMESPACE;
|
|
}
|
|
}
|
|
|
|
function getChildNamespace(parentNamespace, type) {
|
|
if (parentNamespace == null || parentNamespace === HTML_NAMESPACE) {
|
|
// No (or default) parent namespace: potential entry point.
|
|
return getIntrinsicNamespace(type);
|
|
}
|
|
if (parentNamespace === SVG_NAMESPACE && type === 'foreignObject') {
|
|
// We're leaving SVG.
|
|
return HTML_NAMESPACE;
|
|
}
|
|
// By default, pass namespace below.
|
|
return parentNamespace;
|
|
}
|
|
|
|
// For HTML, certain tags should omit their close tag. We keep a whitelist for
|
|
// those special-case tags.
|
|
|
|
var omittedCloseTags = {
|
|
area: true,
|
|
base: true,
|
|
br: true,
|
|
col: true,
|
|
embed: true,
|
|
hr: true,
|
|
img: true,
|
|
input: true,
|
|
keygen: true,
|
|
link: true,
|
|
meta: true,
|
|
param: true,
|
|
source: true,
|
|
track: true,
|
|
wbr: true
|
|
// NOTE: menuitem's close tag should be omitted, but that causes problems.
|
|
};
|
|
|
|
// For HTML, certain tags cannot have children. This has the same purpose as
|
|
// `omittedCloseTags` except that `menuitem` should still have its closing tag.
|
|
|
|
var voidElementTags = _assign({
|
|
menuitem: true
|
|
}, omittedCloseTags);
|
|
|
|
// TODO: We can remove this if we add invariantWithStack()
|
|
// or add stack by default to invariants where possible.
|
|
var HTML = '__html';
|
|
|
|
function assertValidProps(tag, props) {
|
|
if (!props) {
|
|
return;
|
|
}
|
|
// Note the use of `==` which checks for null or undefined.
|
|
if (voidElementTags[tag]) {
|
|
!(props.children == null && props.dangerouslySetInnerHTML == null) ? reactProdInvariant('137', tag, '') : void 0;
|
|
}
|
|
if (props.dangerouslySetInnerHTML != null) {
|
|
!(props.children == null) ? reactProdInvariant('60') : void 0;
|
|
!(typeof props.dangerouslySetInnerHTML === 'object' && HTML in props.dangerouslySetInnerHTML) ? reactProdInvariant('61') : void 0;
|
|
}
|
|
!(props.style == null || typeof props.style === 'object') ? reactProdInvariant('62', '') : void 0;
|
|
}
|
|
|
|
/**
|
|
* CSS properties which accept numbers but are not in units of "px".
|
|
*/
|
|
var isUnitlessNumber = {
|
|
animationIterationCount: true,
|
|
borderImageOutset: true,
|
|
borderImageSlice: true,
|
|
borderImageWidth: true,
|
|
boxFlex: true,
|
|
boxFlexGroup: true,
|
|
boxOrdinalGroup: true,
|
|
columnCount: true,
|
|
columns: true,
|
|
flex: true,
|
|
flexGrow: true,
|
|
flexPositive: true,
|
|
flexShrink: true,
|
|
flexNegative: true,
|
|
flexOrder: true,
|
|
gridArea: true,
|
|
gridRow: true,
|
|
gridRowEnd: true,
|
|
gridRowSpan: true,
|
|
gridRowStart: true,
|
|
gridColumn: true,
|
|
gridColumnEnd: true,
|
|
gridColumnSpan: true,
|
|
gridColumnStart: true,
|
|
fontWeight: true,
|
|
lineClamp: true,
|
|
lineHeight: true,
|
|
opacity: true,
|
|
order: true,
|
|
orphans: true,
|
|
tabSize: true,
|
|
widows: true,
|
|
zIndex: true,
|
|
zoom: true,
|
|
|
|
// SVG-related properties
|
|
fillOpacity: true,
|
|
floodOpacity: true,
|
|
stopOpacity: true,
|
|
strokeDasharray: true,
|
|
strokeDashoffset: true,
|
|
strokeMiterlimit: true,
|
|
strokeOpacity: true,
|
|
strokeWidth: true
|
|
};
|
|
|
|
/**
|
|
* @param {string} prefix vendor-specific prefix, eg: Webkit
|
|
* @param {string} key style name, eg: transitionDuration
|
|
* @return {string} style name prefixed with `prefix`, properly camelCased, eg:
|
|
* WebkitTransitionDuration
|
|
*/
|
|
function prefixKey(prefix, key) {
|
|
return prefix + key.charAt(0).toUpperCase() + key.substring(1);
|
|
}
|
|
|
|
/**
|
|
* Support style names that may come passed in prefixed by adding permutations
|
|
* of vendor prefixes.
|
|
*/
|
|
var prefixes = ['Webkit', 'ms', 'Moz', 'O'];
|
|
|
|
// Using Object.keys here, or else the vanilla for-in loop makes IE8 go into an
|
|
// infinite loop, because it iterates over the newly added props too.
|
|
Object.keys(isUnitlessNumber).forEach(function (prop) {
|
|
prefixes.forEach(function (prefix) {
|
|
isUnitlessNumber[prefixKey(prefix, prop)] = isUnitlessNumber[prop];
|
|
});
|
|
});
|
|
|
|
/**
|
|
* Convert a value into the proper css writable value. The style name `name`
|
|
* should be logical (no hyphens), as specified
|
|
* in `CSSProperty.isUnitlessNumber`.
|
|
*
|
|
* @param {string} name CSS property name such as `topMargin`.
|
|
* @param {*} value CSS property value such as `10px`.
|
|
* @return {string} Normalized style value with dimensions applied.
|
|
*/
|
|
function dangerousStyleValue(name, value, isCustomProperty) {
|
|
// Note that we've removed escapeTextForBrowser() calls here since the
|
|
// whole string will be escaped when the attribute is injected into
|
|
// the markup. If you provide unsafe user data here they can inject
|
|
// arbitrary CSS which may be problematic (I couldn't repro this):
|
|
// https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet
|
|
// http://www.thespanner.co.uk/2007/11/26/ultimate-xss-css-injection/
|
|
// This is not an XSS hole but instead a potential CSS injection issue
|
|
// which has lead to a greater discussion about how we're going to
|
|
// trust URLs moving forward. See #2115901
|
|
|
|
var isEmpty = value == null || typeof value === 'boolean' || value === '';
|
|
if (isEmpty) {
|
|
return '';
|
|
}
|
|
|
|
if (!isCustomProperty && typeof value === 'number' && value !== 0 && !(isUnitlessNumber.hasOwnProperty(name) && isUnitlessNumber[name])) {
|
|
return value + 'px'; // Presumes implicit 'px' suffix for unitless numbers
|
|
}
|
|
|
|
return ('' + value).trim();
|
|
}
|
|
|
|
var uppercasePattern = /([A-Z])/g;
|
|
var msPattern = /^ms-/;
|
|
|
|
/**
|
|
* Hyphenates a camelcased CSS property name, for example:
|
|
*
|
|
* > hyphenateStyleName('backgroundColor')
|
|
* < "background-color"
|
|
* > hyphenateStyleName('MozTransition')
|
|
* < "-moz-transition"
|
|
* > hyphenateStyleName('msTransition')
|
|
* < "-ms-transition"
|
|
*
|
|
* As Modernizr suggests (http://modernizr.com/docs/#prefixed), an `ms` prefix
|
|
* is converted to `-ms-`.
|
|
*/
|
|
function hyphenateStyleName(name) {
|
|
return name.replace(uppercasePattern, '-$1').toLowerCase().replace(msPattern, '-ms-');
|
|
}
|
|
|
|
function isCustomComponent(tagName, props) {
|
|
if (tagName.indexOf('-') === -1) {
|
|
return typeof props.is === 'string';
|
|
}
|
|
switch (tagName) {
|
|
// These are reserved SVG and MathML elements.
|
|
// We don't mind this whitelist too much because we expect it to never grow.
|
|
// The alternative is to track the namespace in a few places which is convoluted.
|
|
// https://w3c.github.io/webcomponents/spec/custom/#custom-elements-core-concepts
|
|
case 'annotation-xml':
|
|
case 'color-profile':
|
|
case 'font-face':
|
|
case 'font-face-src':
|
|
case 'font-face-uri':
|
|
case 'font-face-format':
|
|
case 'font-face-name':
|
|
case 'missing-glyph':
|
|
return false;
|
|
default:
|
|
return true;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Registers plugins so that they can extract and dispatch events.
|
|
*
|
|
* @see {EventPluginHub}
|
|
*/
|
|
|
|
/**
|
|
* Ordered list of injected plugins.
|
|
*/
|
|
|
|
|
|
/**
|
|
* Mapping from event name to dispatch config
|
|
*/
|
|
|
|
|
|
/**
|
|
* Mapping from registration name to plugin module
|
|
*/
|
|
|
|
|
|
/**
|
|
* Mapping from registration name to event name
|
|
*/
|
|
|
|
|
|
/**
|
|
* Mapping from lowercase registration names to the properly cased version,
|
|
* used to warn in the case of missing event handlers. Available
|
|
* only in false.
|
|
* @type {Object}
|
|
*/
|
|
|
|
// Trust the developer to only use possibleRegistrationNames in false
|
|
|
|
/**
|
|
* Injects an ordering of plugins (by plugin name). This allows the ordering
|
|
* to be decoupled from injection of the actual plugins so that ordering is
|
|
* always deterministic regardless of packaging, on-the-fly injection, etc.
|
|
*
|
|
* @param {array} InjectedEventPluginOrder
|
|
* @internal
|
|
* @see {EventPluginHub.injection.injectEventPluginOrder}
|
|
*/
|
|
|
|
|
|
/**
|
|
* Injects plugins to be used by `EventPluginHub`. The plugin names must be
|
|
* in the ordering injected by `injectEventPluginOrder`.
|
|
*
|
|
* Plugins can be injected as part of page initialization or on-the-fly.
|
|
*
|
|
* @param {object} injectedNamesToPlugins Map from names to plugin modules.
|
|
* @internal
|
|
* @see {EventPluginHub.injection.injectEventPluginsByName}
|
|
*/
|
|
|
|
// When adding attributes to the HTML or SVG whitelist, be sure to
|
|
// also add them to this module to ensure casing and incorrect name
|
|
// warnings.
|
|
|
|
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
|
|
|
// Based on reading the React.Children implementation. TODO: type this somewhere?
|
|
|
|
var toArray = React.Children.toArray;
|
|
|
|
var ReactCurrentDispatcher = ReactSharedInternals.ReactCurrentDispatcher;
|
|
var newlineEatingTags = {
|
|
listing: true,
|
|
pre: true,
|
|
textarea: true
|
|
};
|
|
|
|
// We accept any tag to be rendered but since this gets injected into arbitrary
|
|
// HTML, we want to make sure that it's a safe tag.
|
|
// http://www.w3.org/TR/REC-xml/#NT-Name
|
|
var VALID_TAG_REGEX = /^[a-zA-Z][a-zA-Z:_\.\-\d]*$/; // Simplified subset
|
|
var validatedTagCache = {};
|
|
function validateDangerousTag(tag) {
|
|
if (!validatedTagCache.hasOwnProperty(tag)) {
|
|
!VALID_TAG_REGEX.test(tag) ? reactProdInvariant('65', tag) : void 0;
|
|
validatedTagCache[tag] = true;
|
|
}
|
|
}
|
|
|
|
var styleNameCache = {};
|
|
var processStyleName = function (styleName) {
|
|
if (styleNameCache.hasOwnProperty(styleName)) {
|
|
return styleNameCache[styleName];
|
|
}
|
|
var result = hyphenateStyleName(styleName);
|
|
styleNameCache[styleName] = result;
|
|
return result;
|
|
};
|
|
|
|
function createMarkupForStyles(styles) {
|
|
var serialized = '';
|
|
var delimiter = '';
|
|
for (var styleName in styles) {
|
|
if (!styles.hasOwnProperty(styleName)) {
|
|
continue;
|
|
}
|
|
var isCustomProperty = styleName.indexOf('--') === 0;
|
|
var styleValue = styles[styleName];
|
|
if (styleValue != null) {
|
|
serialized += delimiter + processStyleName(styleName) + ':';
|
|
serialized += dangerousStyleValue(styleName, styleValue, isCustomProperty);
|
|
|
|
delimiter = ';';
|
|
}
|
|
}
|
|
return serialized || null;
|
|
}
|
|
|
|
function shouldConstruct(Component) {
|
|
return Component.prototype && Component.prototype.isReactComponent;
|
|
}
|
|
|
|
function getNonChildrenInnerMarkup(props) {
|
|
var innerHTML = props.dangerouslySetInnerHTML;
|
|
if (innerHTML != null) {
|
|
if (innerHTML.__html != null) {
|
|
return innerHTML.__html;
|
|
}
|
|
} else {
|
|
var content = props.children;
|
|
if (typeof content === 'string' || typeof content === 'number') {
|
|
return escapeTextForBrowser(content);
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
function flattenTopLevelChildren(children) {
|
|
if (!React.isValidElement(children)) {
|
|
return toArray(children);
|
|
}
|
|
var element = children;
|
|
if (element.type !== REACT_FRAGMENT_TYPE) {
|
|
return [element];
|
|
}
|
|
var fragmentChildren = element.props.children;
|
|
if (!React.isValidElement(fragmentChildren)) {
|
|
return toArray(fragmentChildren);
|
|
}
|
|
var fragmentChildElement = fragmentChildren;
|
|
return [fragmentChildElement];
|
|
}
|
|
|
|
function flattenOptionChildren(children) {
|
|
if (children === undefined || children === null) {
|
|
return children;
|
|
}
|
|
var content = '';
|
|
// Flatten children and warn if they aren't strings or numbers;
|
|
// invalid types are ignored.
|
|
React.Children.forEach(children, function (child) {
|
|
if (child == null) {
|
|
return;
|
|
}
|
|
content += child;
|
|
|
|
});
|
|
return content;
|
|
}
|
|
|
|
var hasOwnProperty = Object.prototype.hasOwnProperty;
|
|
var STYLE = 'style';
|
|
var RESERVED_PROPS = {
|
|
children: null,
|
|
dangerouslySetInnerHTML: null,
|
|
suppressContentEditableWarning: null,
|
|
suppressHydrationWarning: null
|
|
};
|
|
|
|
function createOpenTagMarkup(tagVerbatim, tagLowercase, props, namespace, makeStaticMarkup, isRootElement) {
|
|
var ret = '<' + tagVerbatim;
|
|
|
|
for (var propKey in props) {
|
|
if (!hasOwnProperty.call(props, propKey)) {
|
|
continue;
|
|
}
|
|
var propValue = props[propKey];
|
|
if (propValue == null) {
|
|
continue;
|
|
}
|
|
if (propKey === STYLE) {
|
|
propValue = createMarkupForStyles(propValue);
|
|
}
|
|
var markup = null;
|
|
if (isCustomComponent(tagLowercase, props)) {
|
|
if (!RESERVED_PROPS.hasOwnProperty(propKey)) {
|
|
markup = createMarkupForCustomAttribute(propKey, propValue);
|
|
}
|
|
} else {
|
|
markup = createMarkupForProperty(propKey, propValue);
|
|
}
|
|
if (markup) {
|
|
ret += ' ' + markup;
|
|
}
|
|
}
|
|
|
|
// For static pages, no need to put React ID and checksum. Saves lots of
|
|
// bytes.
|
|
if (makeStaticMarkup) {
|
|
return ret;
|
|
}
|
|
|
|
if (isRootElement) {
|
|
ret += ' ' + createMarkupForRoot();
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
function validateRenderResult(child, type) {
|
|
if (child === undefined) {
|
|
reactProdInvariant('152', getComponentName(type) || 'Component');
|
|
}
|
|
}
|
|
|
|
function resolve(child, context, threadID) {
|
|
while (React.isValidElement(child)) {
|
|
// Safe because we just checked it's an element.
|
|
var element = child;
|
|
var Component = element.type;
|
|
if (typeof Component !== 'function') {
|
|
break;
|
|
}
|
|
processChild(element, Component);
|
|
}
|
|
|
|
// Extra closure so queue and replace can be captured properly
|
|
function processChild(element, Component) {
|
|
var publicContext = processContext(Component, context, threadID);
|
|
|
|
var queue = [];
|
|
var replace = false;
|
|
var updater = {
|
|
isMounted: function (publicInstance) {
|
|
return false;
|
|
},
|
|
enqueueForceUpdate: function (publicInstance) {
|
|
if (queue === null) {
|
|
return null;
|
|
}
|
|
},
|
|
enqueueReplaceState: function (publicInstance, completeState) {
|
|
replace = true;
|
|
queue = [completeState];
|
|
},
|
|
enqueueSetState: function (publicInstance, currentPartialState) {
|
|
if (queue === null) {
|
|
return null;
|
|
}
|
|
queue.push(currentPartialState);
|
|
}
|
|
};
|
|
|
|
var inst = void 0;
|
|
if (shouldConstruct(Component)) {
|
|
inst = new Component(element.props, publicContext, updater);
|
|
|
|
if (typeof Component.getDerivedStateFromProps === 'function') {
|
|
var partialState = Component.getDerivedStateFromProps.call(null, element.props, inst.state);
|
|
|
|
if (partialState != null) {
|
|
inst.state = _assign({}, inst.state, partialState);
|
|
}
|
|
}
|
|
} else {
|
|
var componentIdentity = {};
|
|
prepareToUseHooks(componentIdentity);
|
|
inst = Component(element.props, publicContext, updater);
|
|
inst = finishHooks(Component, element.props, inst, publicContext);
|
|
|
|
if (inst == null || inst.render == null) {
|
|
child = inst;
|
|
validateRenderResult(child, Component);
|
|
return;
|
|
}
|
|
}
|
|
|
|
inst.props = element.props;
|
|
inst.context = publicContext;
|
|
inst.updater = updater;
|
|
|
|
var initialState = inst.state;
|
|
if (initialState === undefined) {
|
|
inst.state = initialState = null;
|
|
}
|
|
if (typeof inst.UNSAFE_componentWillMount === 'function' || typeof inst.componentWillMount === 'function') {
|
|
if (typeof inst.componentWillMount === 'function') {
|
|
if (typeof Component.getDerivedStateFromProps !== 'function') {
|
|
inst.componentWillMount();
|
|
}
|
|
}
|
|
if (typeof inst.UNSAFE_componentWillMount === 'function' && typeof Component.getDerivedStateFromProps !== 'function') {
|
|
// In order to support react-lifecycles-compat polyfilled components,
|
|
// Unsafe lifecycles should not be invoked for any component with the new gDSFP.
|
|
inst.UNSAFE_componentWillMount();
|
|
}
|
|
if (queue.length) {
|
|
var oldQueue = queue;
|
|
var oldReplace = replace;
|
|
queue = null;
|
|
replace = false;
|
|
|
|
if (oldReplace && oldQueue.length === 1) {
|
|
inst.state = oldQueue[0];
|
|
} else {
|
|
var nextState = oldReplace ? oldQueue[0] : inst.state;
|
|
var dontMutate = true;
|
|
for (var i = oldReplace ? 1 : 0; i < oldQueue.length; i++) {
|
|
var partial = oldQueue[i];
|
|
var _partialState = typeof partial === 'function' ? partial.call(inst, nextState, element.props, publicContext) : partial;
|
|
if (_partialState != null) {
|
|
if (dontMutate) {
|
|
dontMutate = false;
|
|
nextState = _assign({}, nextState, _partialState);
|
|
} else {
|
|
_assign(nextState, _partialState);
|
|
}
|
|
}
|
|
}
|
|
inst.state = nextState;
|
|
}
|
|
} else {
|
|
queue = null;
|
|
}
|
|
}
|
|
child = inst.render();
|
|
|
|
validateRenderResult(child, Component);
|
|
|
|
var childContext = void 0;
|
|
if (typeof inst.getChildContext === 'function') {
|
|
var childContextTypes = Component.childContextTypes;
|
|
if (typeof childContextTypes === 'object') {
|
|
childContext = inst.getChildContext();
|
|
for (var contextKey in childContext) {
|
|
!(contextKey in childContextTypes) ? reactProdInvariant('108', getComponentName(Component) || 'Unknown', contextKey) : void 0;
|
|
}
|
|
} else {
|
|
|
|
}
|
|
}
|
|
if (childContext) {
|
|
context = _assign({}, context, childContext);
|
|
}
|
|
}
|
|
return { child: child, context: context };
|
|
}
|
|
|
|
var ReactDOMServerRenderer = function () {
|
|
// DEV-only
|
|
|
|
// TODO: type this more strictly:
|
|
function ReactDOMServerRenderer(children, makeStaticMarkup) {
|
|
_classCallCheck(this, ReactDOMServerRenderer);
|
|
|
|
var flatChildren = flattenTopLevelChildren(children);
|
|
|
|
var topFrame = {
|
|
type: null,
|
|
// Assume all trees start in the HTML namespace (not totally true, but
|
|
// this is what we did historically)
|
|
domNamespace: Namespaces.html,
|
|
children: flatChildren,
|
|
childIndex: 0,
|
|
context: emptyObject,
|
|
footer: ''
|
|
};
|
|
this.threadID = allocThreadID();
|
|
this.stack = [topFrame];
|
|
this.exhausted = false;
|
|
this.currentSelectValue = null;
|
|
this.previousWasTextNode = false;
|
|
this.makeStaticMarkup = makeStaticMarkup;
|
|
this.suspenseDepth = 0;
|
|
|
|
// Context (new API)
|
|
this.contextIndex = -1;
|
|
this.contextStack = [];
|
|
this.contextValueStack = [];
|
|
|
|
}
|
|
|
|
ReactDOMServerRenderer.prototype.destroy = function destroy() {
|
|
if (!this.exhausted) {
|
|
this.exhausted = true;
|
|
this.clearProviders();
|
|
freeThreadID(this.threadID);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Note: We use just two stacks regardless of how many context providers you have.
|
|
* Providers are always popped in the reverse order to how they were pushed
|
|
* so we always know on the way down which provider you'll encounter next on the way up.
|
|
* On the way down, we push the current provider, and its context value *before*
|
|
* we mutated it, onto the stacks. Therefore, on the way up, we always know which
|
|
* provider needs to be "restored" to which value.
|
|
* https://github.com/facebook/react/pull/12985#issuecomment-396301248
|
|
*/
|
|
|
|
ReactDOMServerRenderer.prototype.pushProvider = function pushProvider(provider) {
|
|
var index = ++this.contextIndex;
|
|
var context = provider.type._context;
|
|
var threadID = this.threadID;
|
|
validateContextBounds(context, threadID);
|
|
var previousValue = context[threadID];
|
|
|
|
// Remember which value to restore this context to on our way up.
|
|
this.contextStack[index] = context;
|
|
this.contextValueStack[index] = previousValue;
|
|
context[threadID] = provider.props.value;
|
|
};
|
|
|
|
ReactDOMServerRenderer.prototype.popProvider = function popProvider(provider) {
|
|
var index = this.contextIndex;
|
|
var context = this.contextStack[index];
|
|
var previousValue = this.contextValueStack[index];
|
|
|
|
// "Hide" these null assignments from Flow by using `any`
|
|
// because conceptually they are deletions--as long as we
|
|
// promise to never access values beyond `this.contextIndex`.
|
|
this.contextStack[index] = null;
|
|
this.contextValueStack[index] = null;
|
|
this.contextIndex--;
|
|
|
|
// Restore to the previous value we stored as we were walking down.
|
|
// We've already verified that this context has been expanded to accommodate
|
|
// this thread id, so we don't need to do it again.
|
|
context[this.threadID] = previousValue;
|
|
};
|
|
|
|
ReactDOMServerRenderer.prototype.clearProviders = function clearProviders() {
|
|
// Restore any remaining providers on the stack to previous values
|
|
for (var index = this.contextIndex; index >= 0; index--) {
|
|
var _context = this.contextStack[index];
|
|
var previousValue = this.contextValueStack[index];
|
|
_context[this.threadID] = previousValue;
|
|
}
|
|
};
|
|
|
|
ReactDOMServerRenderer.prototype.read = function read(bytes) {
|
|
if (this.exhausted) {
|
|
return null;
|
|
}
|
|
|
|
var prevThreadID = currentThreadID;
|
|
setCurrentThreadID(this.threadID);
|
|
var prevDispatcher = ReactCurrentDispatcher.current;
|
|
ReactCurrentDispatcher.current = Dispatcher;
|
|
try {
|
|
// Markup generated within <Suspense> ends up buffered until we know
|
|
// nothing in that boundary suspended
|
|
var out = [''];
|
|
var suspended = false;
|
|
while (out[0].length < bytes) {
|
|
if (this.stack.length === 0) {
|
|
this.exhausted = true;
|
|
freeThreadID(this.threadID);
|
|
break;
|
|
}
|
|
var frame = this.stack[this.stack.length - 1];
|
|
if (suspended || frame.childIndex >= frame.children.length) {
|
|
var _footer = frame.footer;
|
|
if (_footer !== '') {
|
|
this.previousWasTextNode = false;
|
|
}
|
|
this.stack.pop();
|
|
if (frame.type === 'select') {
|
|
this.currentSelectValue = null;
|
|
} else if (frame.type != null && frame.type.type != null && frame.type.type.$$typeof === REACT_PROVIDER_TYPE) {
|
|
var provider = frame.type;
|
|
this.popProvider(provider);
|
|
} else if (frame.type === REACT_SUSPENSE_TYPE) {
|
|
this.suspenseDepth--;
|
|
var buffered = out.pop();
|
|
|
|
if (suspended) {
|
|
suspended = false;
|
|
// If rendering was suspended at this boundary, render the fallbackFrame
|
|
var _fallbackFrame = frame.fallbackFrame;
|
|
!_fallbackFrame ? reactProdInvariant('303') : void 0;
|
|
this.stack.push(_fallbackFrame);
|
|
// Skip flushing output since we're switching to the fallback
|
|
continue;
|
|
} else {
|
|
out[this.suspenseDepth] += buffered;
|
|
}
|
|
}
|
|
|
|
// Flush output
|
|
out[this.suspenseDepth] += _footer;
|
|
continue;
|
|
}
|
|
var child = frame.children[frame.childIndex++];
|
|
|
|
var outBuffer = '';
|
|
try {
|
|
outBuffer += this.render(child, frame.context, frame.domNamespace);
|
|
} catch (err) {
|
|
if (enableSuspenseServerRenderer && typeof err.then === 'function') {
|
|
suspended = true;
|
|
} else {
|
|
throw err;
|
|
}
|
|
} finally {
|
|
|
|
}
|
|
if (out.length <= this.suspenseDepth) {
|
|
out.push('');
|
|
}
|
|
out[this.suspenseDepth] += outBuffer;
|
|
}
|
|
return out[0];
|
|
} finally {
|
|
ReactCurrentDispatcher.current = prevDispatcher;
|
|
setCurrentThreadID(prevThreadID);
|
|
}
|
|
};
|
|
|
|
ReactDOMServerRenderer.prototype.render = function render(child, context, parentNamespace) {
|
|
if (typeof child === 'string' || typeof child === 'number') {
|
|
var text = '' + child;
|
|
if (text === '') {
|
|
return '';
|
|
}
|
|
if (this.makeStaticMarkup) {
|
|
return escapeTextForBrowser(text);
|
|
}
|
|
if (this.previousWasTextNode) {
|
|
return '<!-- -->' + escapeTextForBrowser(text);
|
|
}
|
|
this.previousWasTextNode = true;
|
|
return escapeTextForBrowser(text);
|
|
} else {
|
|
var nextChild = void 0;
|
|
|
|
var _resolve = resolve(child, context, this.threadID);
|
|
|
|
nextChild = _resolve.child;
|
|
context = _resolve.context;
|
|
|
|
if (nextChild === null || nextChild === false) {
|
|
return '';
|
|
} else if (!React.isValidElement(nextChild)) {
|
|
if (nextChild != null && nextChild.$$typeof != null) {
|
|
// Catch unexpected special types early.
|
|
var $$typeof = nextChild.$$typeof;
|
|
!($$typeof !== REACT_PORTAL_TYPE) ? reactProdInvariant('257') : void 0;
|
|
// Catch-all to prevent an infinite loop if React.Children.toArray() supports some new type.
|
|
reactProdInvariant('258', $$typeof.toString());
|
|
}
|
|
var nextChildren = toArray(nextChild);
|
|
var frame = {
|
|
type: null,
|
|
domNamespace: parentNamespace,
|
|
children: nextChildren,
|
|
childIndex: 0,
|
|
context: context,
|
|
footer: ''
|
|
};
|
|
this.stack.push(frame);
|
|
return '';
|
|
}
|
|
// Safe because we just checked it's an element.
|
|
var nextElement = nextChild;
|
|
var elementType = nextElement.type;
|
|
|
|
if (typeof elementType === 'string') {
|
|
return this.renderDOM(nextElement, context, parentNamespace);
|
|
}
|
|
|
|
switch (elementType) {
|
|
case REACT_STRICT_MODE_TYPE:
|
|
case REACT_CONCURRENT_MODE_TYPE:
|
|
case REACT_PROFILER_TYPE:
|
|
case REACT_FRAGMENT_TYPE:
|
|
{
|
|
var _nextChildren = toArray(nextChild.props.children);
|
|
var _frame = {
|
|
type: null,
|
|
domNamespace: parentNamespace,
|
|
children: _nextChildren,
|
|
childIndex: 0,
|
|
context: context,
|
|
footer: ''
|
|
};
|
|
this.stack.push(_frame);
|
|
return '';
|
|
}
|
|
case REACT_SUSPENSE_TYPE:
|
|
{
|
|
if (enableSuspenseServerRenderer) {
|
|
var fallback = nextChild.props.fallback;
|
|
if (fallback === undefined) {
|
|
// If there is no fallback, then this just behaves as a fragment.
|
|
var _nextChildren3 = toArray(nextChild.props.children);
|
|
var _frame3 = {
|
|
type: null,
|
|
domNamespace: parentNamespace,
|
|
children: _nextChildren3,
|
|
childIndex: 0,
|
|
context: context,
|
|
footer: ''
|
|
};
|
|
this.stack.push(_frame3);
|
|
return '';
|
|
}
|
|
var fallbackChildren = toArray(fallback);
|
|
var _nextChildren2 = toArray(nextChild.props.children);
|
|
var _fallbackFrame2 = {
|
|
type: null,
|
|
domNamespace: parentNamespace,
|
|
children: fallbackChildren,
|
|
childIndex: 0,
|
|
context: context,
|
|
footer: '',
|
|
out: ''
|
|
};
|
|
var _frame2 = {
|
|
fallbackFrame: _fallbackFrame2,
|
|
type: REACT_SUSPENSE_TYPE,
|
|
domNamespace: parentNamespace,
|
|
children: _nextChildren2,
|
|
childIndex: 0,
|
|
context: context,
|
|
footer: '<!--/$-->'
|
|
};
|
|
this.stack.push(_frame2);
|
|
this.suspenseDepth++;
|
|
return '<!--$-->';
|
|
} else {
|
|
reactProdInvariant('294');
|
|
}
|
|
}
|
|
// eslint-disable-next-line-no-fallthrough
|
|
default:
|
|
break;
|
|
}
|
|
if (typeof elementType === 'object' && elementType !== null) {
|
|
switch (elementType.$$typeof) {
|
|
case REACT_FORWARD_REF_TYPE:
|
|
{
|
|
var element = nextChild;
|
|
var _nextChildren4 = void 0;
|
|
var componentIdentity = {};
|
|
prepareToUseHooks(componentIdentity);
|
|
_nextChildren4 = elementType.render(element.props, element.ref);
|
|
_nextChildren4 = finishHooks(elementType.render, element.props, _nextChildren4, element.ref);
|
|
_nextChildren4 = toArray(_nextChildren4);
|
|
var _frame4 = {
|
|
type: null,
|
|
domNamespace: parentNamespace,
|
|
children: _nextChildren4,
|
|
childIndex: 0,
|
|
context: context,
|
|
footer: ''
|
|
};
|
|
this.stack.push(_frame4);
|
|
return '';
|
|
}
|
|
case REACT_MEMO_TYPE:
|
|
{
|
|
var _element = nextChild;
|
|
var _nextChildren5 = [React.createElement(elementType.type, _assign({ ref: _element.ref }, _element.props))];
|
|
var _frame5 = {
|
|
type: null,
|
|
domNamespace: parentNamespace,
|
|
children: _nextChildren5,
|
|
childIndex: 0,
|
|
context: context,
|
|
footer: ''
|
|
};
|
|
this.stack.push(_frame5);
|
|
return '';
|
|
}
|
|
case REACT_PROVIDER_TYPE:
|
|
{
|
|
var provider = nextChild;
|
|
var nextProps = provider.props;
|
|
var _nextChildren6 = toArray(nextProps.children);
|
|
var _frame6 = {
|
|
type: provider,
|
|
domNamespace: parentNamespace,
|
|
children: _nextChildren6,
|
|
childIndex: 0,
|
|
context: context,
|
|
footer: ''
|
|
};
|
|
this.pushProvider(provider);
|
|
|
|
this.stack.push(_frame6);
|
|
return '';
|
|
}
|
|
case REACT_CONTEXT_TYPE:
|
|
{
|
|
var reactContext = nextChild.type;
|
|
// The logic below for Context differs depending on PROD or DEV mode. In
|
|
// DEV mode, we create a separate object for Context.Consumer that acts
|
|
// like a proxy to Context. This proxy object adds unnecessary code in PROD
|
|
// so we use the old behaviour (Context.Consumer references Context) to
|
|
// reduce size and overhead. The separate object references context via
|
|
// a property called "_context", which also gives us the ability to check
|
|
// in DEV mode if this property exists or not and warn if it does not.
|
|
var _nextProps = nextChild.props;
|
|
var threadID = this.threadID;
|
|
validateContextBounds(reactContext, threadID);
|
|
var nextValue = reactContext[threadID];
|
|
|
|
var _nextChildren7 = toArray(_nextProps.children(nextValue));
|
|
var _frame7 = {
|
|
type: nextChild,
|
|
domNamespace: parentNamespace,
|
|
children: _nextChildren7,
|
|
childIndex: 0,
|
|
context: context,
|
|
footer: ''
|
|
};
|
|
this.stack.push(_frame7);
|
|
return '';
|
|
}
|
|
case REACT_LAZY_TYPE:
|
|
reactProdInvariant('295');
|
|
}
|
|
}
|
|
|
|
var info = '';
|
|
reactProdInvariant('130', elementType == null ? elementType : typeof elementType, info);
|
|
}
|
|
};
|
|
|
|
ReactDOMServerRenderer.prototype.renderDOM = function renderDOM(element, context, parentNamespace) {
|
|
var tag = element.type.toLowerCase();
|
|
|
|
var namespace = parentNamespace;
|
|
if (parentNamespace === Namespaces.html) {
|
|
namespace = getIntrinsicNamespace(tag);
|
|
}
|
|
|
|
validateDangerousTag(tag);
|
|
|
|
var props = element.props;
|
|
if (tag === 'input') {
|
|
props = _assign({
|
|
type: undefined
|
|
}, props, {
|
|
defaultChecked: undefined,
|
|
defaultValue: undefined,
|
|
value: props.value != null ? props.value : props.defaultValue,
|
|
checked: props.checked != null ? props.checked : props.defaultChecked
|
|
});
|
|
} else if (tag === 'textarea') {
|
|
var initialValue = props.value;
|
|
if (initialValue == null) {
|
|
var defaultValue = props.defaultValue;
|
|
// TODO (yungsters): Remove support for children content in <textarea>.
|
|
var textareaChildren = props.children;
|
|
if (textareaChildren != null) {
|
|
!(defaultValue == null) ? reactProdInvariant('92') : void 0;
|
|
if (Array.isArray(textareaChildren)) {
|
|
!(textareaChildren.length <= 1) ? reactProdInvariant('93') : void 0;
|
|
textareaChildren = textareaChildren[0];
|
|
}
|
|
|
|
defaultValue = '' + textareaChildren;
|
|
}
|
|
if (defaultValue == null) {
|
|
defaultValue = '';
|
|
}
|
|
initialValue = defaultValue;
|
|
}
|
|
|
|
props = _assign({}, props, {
|
|
value: undefined,
|
|
children: '' + initialValue
|
|
});
|
|
} else if (tag === 'select') {
|
|
this.currentSelectValue = props.value != null ? props.value : props.defaultValue;
|
|
props = _assign({}, props, {
|
|
value: undefined
|
|
});
|
|
} else if (tag === 'option') {
|
|
var selected = null;
|
|
var selectValue = this.currentSelectValue;
|
|
var optionChildren = flattenOptionChildren(props.children);
|
|
if (selectValue != null) {
|
|
var value = void 0;
|
|
if (props.value != null) {
|
|
value = props.value + '';
|
|
} else {
|
|
value = optionChildren;
|
|
}
|
|
selected = false;
|
|
if (Array.isArray(selectValue)) {
|
|
// multiple
|
|
for (var j = 0; j < selectValue.length; j++) {
|
|
if ('' + selectValue[j] === value) {
|
|
selected = true;
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
selected = '' + selectValue === value;
|
|
}
|
|
|
|
props = _assign({
|
|
selected: undefined,
|
|
children: undefined
|
|
}, props, {
|
|
selected: selected,
|
|
children: optionChildren
|
|
});
|
|
}
|
|
}
|
|
|
|
assertValidProps(tag, props);
|
|
|
|
var out = createOpenTagMarkup(element.type, tag, props, namespace, this.makeStaticMarkup, this.stack.length === 1);
|
|
var footer = '';
|
|
if (omittedCloseTags.hasOwnProperty(tag)) {
|
|
out += '/>';
|
|
} else {
|
|
out += '>';
|
|
footer = '</' + element.type + '>';
|
|
}
|
|
var children = void 0;
|
|
var innerMarkup = getNonChildrenInnerMarkup(props);
|
|
if (innerMarkup != null) {
|
|
children = [];
|
|
if (newlineEatingTags[tag] && innerMarkup.charAt(0) === '\n') {
|
|
// text/html ignores the first character in these tags if it's a newline
|
|
// Prefer to break application/xml over text/html (for now) by adding
|
|
// a newline specifically to get eaten by the parser. (Alternately for
|
|
// textareas, replacing "^\n" with "\r\n" doesn't get eaten, and the first
|
|
// \r is normalized out by HTMLTextAreaElement#value.)
|
|
// See: <http://www.w3.org/TR/html-polyglot/#newlines-in-textarea-and-pre>
|
|
// See: <http://www.w3.org/TR/html5/syntax.html#element-restrictions>
|
|
// See: <http://www.w3.org/TR/html5/syntax.html#newlines>
|
|
// See: Parsing of "textarea" "listing" and "pre" elements
|
|
// from <http://www.w3.org/TR/html5/syntax.html#parsing-main-inbody>
|
|
out += '\n';
|
|
}
|
|
out += innerMarkup;
|
|
} else {
|
|
children = toArray(props.children);
|
|
}
|
|
var frame = {
|
|
domNamespace: getChildNamespace(parentNamespace, element.type),
|
|
type: tag,
|
|
children: children,
|
|
childIndex: 0,
|
|
context: context,
|
|
footer: footer
|
|
};
|
|
this.stack.push(frame);
|
|
this.previousWasTextNode = false;
|
|
return out;
|
|
};
|
|
|
|
return ReactDOMServerRenderer;
|
|
}();
|
|
|
|
/**
|
|
* Render a ReactElement to its initial HTML. This should only be used on the
|
|
* server.
|
|
* See https://reactjs.org/docs/react-dom-server.html#rendertostring
|
|
*/
|
|
function renderToString(element) {
|
|
var renderer = new ReactDOMServerRenderer(element, false);
|
|
try {
|
|
var markup = renderer.read(Infinity);
|
|
return markup;
|
|
} finally {
|
|
renderer.destroy();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Similar to renderToString, except this doesn't create extra DOM attributes
|
|
* such as data-react-id that React uses internally.
|
|
* See https://reactjs.org/docs/react-dom-server.html#rendertostaticmarkup
|
|
*/
|
|
function renderToStaticMarkup(element) {
|
|
var renderer = new ReactDOMServerRenderer(element, true);
|
|
try {
|
|
var markup = renderer.read(Infinity);
|
|
return markup;
|
|
} finally {
|
|
renderer.destroy();
|
|
}
|
|
}
|
|
|
|
function renderToNodeStream() {
|
|
reactProdInvariant('207');
|
|
}
|
|
|
|
function renderToStaticNodeStream() {
|
|
reactProdInvariant('208');
|
|
}
|
|
|
|
// Note: when changing this, also consider https://github.com/facebook/react/issues/11526
|
|
var ReactDOMServerBrowser = {
|
|
renderToString: renderToString,
|
|
renderToStaticMarkup: renderToStaticMarkup,
|
|
renderToNodeStream: renderToNodeStream,
|
|
renderToStaticNodeStream: renderToStaticNodeStream,
|
|
version: ReactVersion
|
|
};
|
|
|
|
var ReactDOMServerBrowser$1 = ({
|
|
default: ReactDOMServerBrowser
|
|
});
|
|
|
|
var ReactDOMServer = ( ReactDOMServerBrowser$1 && ReactDOMServerBrowser ) || ReactDOMServerBrowser$1;
|
|
|
|
// TODO: decide on the top-level export form.
|
|
// This is hacky but makes it work with both Rollup and Jest
|
|
var server_browser = ReactDOMServer.default || ReactDOMServer;
|
|
|
|
return server_browser;
|
|
|
|
})));
|