diff --git a/compiled/facebook-www/REVISION b/compiled/facebook-www/REVISION index 2893ed166de0a..bc4eba233a6f3 100644 --- a/compiled/facebook-www/REVISION +++ b/compiled/facebook-www/REVISION @@ -1 +1 @@ -0131d0cff40d4054ac72c857d3a13c5173c46e0a +520f7f3ed4d01e9e50a73d7d04ff138e3c71ac86 diff --git a/compiled/facebook-www/React-dev.modern.js b/compiled/facebook-www/React-dev.modern.js index b79edb61aafdb..c5ae457906864 100644 --- a/compiled/facebook-www/React-dev.modern.js +++ b/compiled/facebook-www/React-dev.modern.js @@ -27,7 +27,7 @@ if ( } "use strict"; -var ReactVersion = "18.3.0-www-modern-1ad200fa"; +var ReactVersion = "18.3.0-www-modern-04bef010"; // ATTENTION // When adding new symbols to this file, diff --git a/compiled/facebook-www/ReactART-dev.classic.js b/compiled/facebook-www/ReactART-dev.classic.js index 3e98b0e7d2d0d..8fa0cca7f4465 100644 --- a/compiled/facebook-www/ReactART-dev.classic.js +++ b/compiled/facebook-www/ReactART-dev.classic.js @@ -69,7 +69,7 @@ function _assertThisInitialized(self) { return self; } -var ReactVersion = "18.3.0-www-classic-ca4ffb9c"; +var ReactVersion = "18.3.0-www-classic-5ff0222e"; var LegacyRoot = 0; var ConcurrentRoot = 1; diff --git a/compiled/facebook-www/ReactART-prod.modern.js b/compiled/facebook-www/ReactART-prod.modern.js index c782702af9708..2338e9ffa3654 100644 --- a/compiled/facebook-www/ReactART-prod.modern.js +++ b/compiled/facebook-www/ReactART-prod.modern.js @@ -9610,7 +9610,7 @@ var slice = Array.prototype.slice, return null; }, bundleType: 0, - version: "18.3.0-www-modern-52358352", + version: "18.3.0-www-modern-4e328d6f", rendererPackageName: "react-art" }; var internals$jscomp$inline_1313 = { @@ -9641,7 +9641,7 @@ var internals$jscomp$inline_1313 = { scheduleRoot: null, setRefreshHandler: null, getCurrentFiber: null, - reconcilerVersion: "18.3.0-www-modern-52358352" + reconcilerVersion: "18.3.0-www-modern-4e328d6f" }; if ("undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__) { var hook$jscomp$inline_1314 = __REACT_DEVTOOLS_GLOBAL_HOOK__; diff --git a/compiled/facebook-www/ReactDOM-dev.classic.js b/compiled/facebook-www/ReactDOM-dev.classic.js index 37cbb1ea16d3d..54a0a4347d58f 100644 --- a/compiled/facebook-www/ReactDOM-dev.classic.js +++ b/compiled/facebook-www/ReactDOM-dev.classic.js @@ -1227,9 +1227,6 @@ function checkFormFieldValueStringCoercion(value) { } } -// 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 filter are presumed to have this type. var STRING = 1; // A string attribute that accepts booleans in React. In HTML, these are called @@ -1288,134 +1285,6 @@ function isAttributeNameSafe(attributeName) { 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": - 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) { - if (enableCustomElementPropertySupport) { - if (value === false) { - return true; - } - } - - return false; - } - - if (propertyInfo !== null) { - { - if (propertyInfo.removeEmptyString && value === "") { - { - if (name === "src") { - error( - 'An empty string ("") was passed to the %s attribute. ' + - "This may cause the browser to download the whole page again over the network. " + - "To fix this, either do not render the element at all " + - "or pass null to %s instead of an empty string.", - name, - name - ); - } else { - error( - 'An empty string ("") was passed to the %s attribute. ' + - "To fix this, either do not render the element at all " + - "or pass null to %s instead of an empty string.", - name, - name - ); - } - } - - return true; - } - } - - 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; } // $FlowFixMe[missing-this-annot] @@ -1444,37 +1313,7 @@ function PropertyInfoRecord( // 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. - -var reservedProps = [ - "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" -]; - -if (enableCustomElementPropertySupport) { - reservedProps.push("innerText", "textContent"); -} - -reservedProps.forEach(function (name) { - // $FlowFixMe[invalid-constructor] Flow no longer supports calling new on functions - properties[name] = new PropertyInfoRecord( - name, - RESERVED, - false, // mustUseProperty - name, // attributeName - null, // attributeNamespace - false, // sanitizeURL - false - ); -}); // A few React string attributes have a different name. +var properties = {}; // A few React string attributes have a different name. // This is a mapping from React prop names to the attribute names. [ @@ -1875,62 +1714,156 @@ function getValueForProperty(node, name, expected, propertyInfo) { if (propertyInfo.mustUseProperty) { var propertyName = propertyInfo.propertyName; return node[propertyName]; - } else { - // This check protects multiple uses of `expected`, which is why the - // react-internal/safe-string-coercion rule is disabled in several spots - // below. - { - checkAttributeStringCoercion(expected, name); + } + + var attributeName = propertyInfo.attributeName; + + if (!node.hasAttribute(attributeName)) { + // shouldRemoveAttribute + switch (typeof expected) { + case "function": + case "symbol": + // eslint-disable-line + return expected; + + case "boolean": { + if (!propertyInfo.acceptsBooleans) { + return expected; + } + } } - var attributeName = propertyInfo.attributeName; - var stringValue = null; + switch (propertyInfo.type) { + case BOOLEAN: { + if (!expected) { + return expected; + } - if (propertyInfo.type === OVERLOADED_BOOLEAN) { - if (node.hasAttribute(attributeName)) { - var value = node.getAttribute(attributeName); + break; + } - if (value === "") { - return true; + case OVERLOADED_BOOLEAN: { + if (expected === false) { + return expected; } - if (shouldRemoveAttribute(name, expected, propertyInfo, false)) { - return value; - } // eslint-disable-next-line react-internal/safe-string-coercion + break; + } - if (value === "" + expected) { + case NUMERIC: { + if (isNaN(expected)) { return expected; } - return value; + break; } - } else if (node.hasAttribute(attributeName)) { - if (shouldRemoveAttribute(name, expected, propertyInfo, false)) { - // We had an attribute but shouldn't have had one, so read it - // for the error message. - return node.getAttribute(attributeName); + + case POSITIVE_NUMERIC: { + if (isNaN(expected) || expected < 1) { + return expected; + } + + break; } + } + + { + if (propertyInfo.removeEmptyString && expected === "") { + { + if (name === "src") { + error( + 'An empty string ("") was passed to the %s attribute. ' + + "This may cause the browser to download the whole page again over the network. " + + "To fix this, either do not render the element at all " + + "or pass null to %s instead of an empty string.", + name, + name + ); + } else { + error( + 'An empty string ("") was passed to the %s attribute. ' + + "To fix this, either do not render the element at all " + + "or pass null to %s instead of an empty string.", + name, + name + ); + } + } - if (propertyInfo.type === BOOLEAN) { + return expected; + } + } + + return expected === undefined ? undefined : null; + } // Even if this property uses a namespace we use getAttribute + // because we assume its namespaced name is the same as our config. + // To use getAttributeNS we need the local name which we don't have + // in our config atm. + + var value = node.getAttribute(attributeName); + + if (expected == null) { + // We had an attribute but shouldn't have had one, so read it + // for the error message. + return value; + } // shouldRemoveAttribute + + switch (propertyInfo.type) { + case BOOLEAN: { + if (expected) { // If this was a boolean, it doesn't matter what the value is // the fact that we have it is the same as the expected. + // As long as it's positive. return expected; - } // Even if this property uses a namespace we use getAttribute - // because we assume its namespaced name is the same as our config. - // To use getAttributeNS we need the local name which we don't have - // in our config atm. + } - stringValue = node.getAttribute(attributeName); + return value; } - if (shouldRemoveAttribute(name, expected, propertyInfo, false)) { - return stringValue === null ? expected : stringValue; // eslint-disable-next-line react-internal/safe-string-coercion - } else if (stringValue === "" + expected) { - return expected; - } else { - return stringValue; + case OVERLOADED_BOOLEAN: { + if (value === "") { + return true; + } + + if (expected === false) { + // We had an attribute but shouldn't have had one, so read it + // for the error message. + return value; + } + + break; + } + + case NUMERIC: { + if (isNaN(expected)) { + // We had an attribute but shouldn't have had one, so read it + // for the error message. + return value; + } + + break; + } + + case POSITIVE_NUMERIC: { + if (isNaN(expected) || expected < 1) { + // We had an attribute but shouldn't have had one, so read it + // for the error message. + return value; + } + + break; } } + + { + checkAttributeStringCoercion(expected, name); + } + + if (value === "" + expected) { + return expected; + } + + return value; } } /** @@ -1939,20 +1872,87 @@ function getValueForProperty(node, name, expected, propertyInfo) { * attributes have multiple equivalent values. */ -function getValueForAttribute(node, name, expected, isCustomComponentTag) { +function getValueForAttribute(node, name, expected) { { if (!isAttributeNameSafe(name)) { return; } if (!node.hasAttribute(name)) { + // shouldRemoveAttribute + switch (typeof expected) { + case "function": + case "symbol": + // eslint-disable-line + return expected; + + case "boolean": { + var prefix = name.toLowerCase().slice(0, 5); + + if (prefix !== "data-" && prefix !== "aria-") { + return expected; + } + } + } + return expected === undefined ? undefined : null; } var value = node.getAttribute(name); + { + checkAttributeStringCoercion(expected, name); + } + + if (value === "" + expected) { + return expected; + } + + return value; + } +} +function getValueForAttributeOnCustomComponent(node, name, expected) { + { + if (!isAttributeNameSafe(name)) { + return; + } + + if (!node.hasAttribute(name)) { + // shouldRemoveAttribute + switch (typeof expected) { + case "symbol": + case "object": + // Symbols and objects are ignored when they're emitted so + // it would be expected that they end up not having an attribute. + return expected; + + case "function": + if (enableCustomElementPropertySupport) { + return expected; + } + + break; + + case "boolean": + if (enableCustomElementPropertySupport) { + if (expected === false) { + return expected; + } + } + } + + return expected === undefined ? undefined : null; + } + + if (enableCustomElementPropertySupport && name === "className") { + // className is a special cased property on the server to render as an attribute. + name = "class"; + } + + var value = node.getAttribute(name); + if (enableCustomElementPropertySupport) { - if (isCustomComponentTag && value === "") { + if (value === "" && expected === true) { return true; } } @@ -1976,22 +1976,203 @@ function getValueForAttribute(node, name, expected, isCustomComponentTag) { * @param {*} value */ -function setValueForProperty(node, name, value, isCustomComponentTag) { - var propertyInfo = getPropertyInfo(name); - - if (shouldIgnoreAttribute(name, propertyInfo, isCustomComponentTag)) { +function setValueForProperty(node, name, value) { + if ( + // shouldIgnoreAttribute + // We have already filtered out reserved words. + name.length > 2 && + (name[0] === "o" || name[0] === "O") && + (name[1] === "n" || name[1] === "N") + ) { return; } + var propertyInfo = getPropertyInfo(name); + + if (propertyInfo !== null) { + if (propertyInfo.mustUseProperty) { + // We assume mustUseProperty are of BOOLEAN type because that's the only way we use it + // right now. + node[propertyInfo.propertyName] = + value && typeof value !== "function" && typeof value !== "symbol"; + return; + } // The rest are treated as attributes with special cases. + + var attributeName = propertyInfo.attributeName; + + if (value === null) { + node.removeAttribute(attributeName); + return; + } // shouldRemoveAttribute + + switch (typeof value) { + case "undefined": + case "function": + case "symbol": + // eslint-disable-line + node.removeAttribute(attributeName); + return; + + case "boolean": { + if (!propertyInfo.acceptsBooleans) { + node.removeAttribute(attributeName); + return; + } + } + } + + { + if (propertyInfo.removeEmptyString && value === "") { + { + if (name === "src") { + error( + 'An empty string ("") was passed to the %s attribute. ' + + "This may cause the browser to download the whole page again over the network. " + + "To fix this, either do not render the element at all " + + "or pass null to %s instead of an empty string.", + name, + name + ); + } else { + error( + 'An empty string ("") was passed to the %s attribute. ' + + "To fix this, either do not render the element at all " + + "or pass null to %s instead of an empty string.", + name, + name + ); + } + } + + node.removeAttribute(attributeName); + return; + } + } + + switch (propertyInfo.type) { + case BOOLEAN: + if (value) { + node.setAttribute(attributeName, ""); + } else { + node.removeAttribute(attributeName); + return; + } + + break; + + case OVERLOADED_BOOLEAN: + if (value === true) { + node.setAttribute(attributeName, ""); + } else if (value === false) { + node.removeAttribute(attributeName); + } else { + { + checkAttributeStringCoercion(value, attributeName); + } + + node.setAttribute(attributeName, value); + } + + return; + + case NUMERIC: + if (!isNaN(value)) { + { + checkAttributeStringCoercion(value, attributeName); + } + + node.setAttribute(attributeName, value); + } else { + node.removeAttribute(attributeName); + } + + break; + + case POSITIVE_NUMERIC: + if (!isNaN(value) && value >= 1) { + { + checkAttributeStringCoercion(value, attributeName); + } + + node.setAttribute(attributeName, value); + } else { + node.removeAttribute(attributeName); + } + + break; + + default: { + var attributeValue; // `setAttribute` with objects becomes only `[object]` in IE8/9, + // ('' + value) makes it output the correct toString()-value. + + if (enableTrustedTypesIntegration) { + attributeValue = value; + } else { + { + checkAttributeStringCoercion(value, attributeName); + } + + attributeValue = "" + value; + } + + if (propertyInfo.sanitizeURL) { + sanitizeURL(attributeValue.toString()); + } + + var attributeNamespace = propertyInfo.attributeNamespace; + + if (attributeNamespace) { + node.setAttributeNS( + attributeNamespace, + attributeName, + attributeValue + ); + } else { + node.setAttribute(attributeName, attributeValue); + } + } + } + } else if (isAttributeNameSafe(name)) { + // If the prop isn't in the special list, treat it as a simple attribute. + // shouldRemoveAttribute + if (value === null) { + node.removeAttribute(name); + return; + } + + switch (typeof value) { + case "undefined": + case "function": + case "symbol": + // eslint-disable-line + node.removeAttribute(name); + return; + + case "boolean": { + var prefix = name.toLowerCase().slice(0, 5); + + if (prefix !== "data-" && prefix !== "aria-") { + node.removeAttribute(name); + return; + } + } + } + + { + checkAttributeStringCoercion(value, name); + } + + node.setAttribute(name, enableTrustedTypesIntegration ? value : "" + value); + } +} +function setValueForPropertyOnCustomComponent(node, name, value) { if ( enableCustomElementPropertySupport && - isCustomComponentTag && name[0] === "o" && name[1] === "n" ) { - var eventName = name.replace(/Capture$/, ""); - var useCapture = name !== eventName; - eventName = eventName.slice(2); + var useCapture = name.endsWith("Capture"); + var eventName = name.substr(2, useCapture ? name.length - 9 : undefined); var prevProps = getFiberCurrentPropsFromNode(node); var prevValue = prevProps != null ? prevProps[name] : null; @@ -2015,99 +2196,44 @@ function setValueForProperty(node, name, value, isCustomComponentTag) { } } - if ( - enableCustomElementPropertySupport && - isCustomComponentTag && - name in node - ) { + if (enableCustomElementPropertySupport && name in node) { node[name] = value; return; } - if (shouldRemoveAttribute(name, value, propertyInfo, isCustomComponentTag)) { - value = null; - } - - if (enableCustomElementPropertySupport) { - if (isCustomComponentTag && value === true) { - value = ""; - } - } // If the prop isn't in the special list, treat it as a simple attribute. - - if (isCustomComponentTag || propertyInfo === null) { - if (isAttributeNameSafe(name)) { - var _attributeName = name; - - if (value === null) { - node.removeAttribute(_attributeName); - } else { - { - checkAttributeStringCoercion(value, name); - } - - node.setAttribute( - _attributeName, - enableTrustedTypesIntegration ? value : "" + value - ); - } - } - - return; - } - - var mustUseProperty = propertyInfo.mustUseProperty; - - if (mustUseProperty) { - var propertyName = propertyInfo.propertyName; - + if (isAttributeNameSafe(name)) { + // shouldRemoveAttribute if (value === null) { - var type = propertyInfo.type; - node[propertyName] = type === BOOLEAN ? false : ""; - } else { - // Contrary to `setAttribute`, object properties are properly - // `toString`ed by IE8/9. - node[propertyName] = value; + node.removeAttribute(name); + return; } - return; - } // The rest are treated as attributes with special cases. - - var attributeName = propertyInfo.attributeName, - attributeNamespace = propertyInfo.attributeNamespace; + switch (typeof value) { + case "undefined": + case "function": + case "symbol": + // eslint-disable-line + node.removeAttribute(name); + return; - if (value === null) { - node.removeAttribute(attributeName); - } else { - var _type = propertyInfo.type; - var attributeValue; + case "boolean": { + if (enableCustomElementPropertySupport) { + if (value === true) { + node.setAttribute(name, ""); + return; + } - if (_type === BOOLEAN || (_type === OVERLOADED_BOOLEAN && value === true)) { - // If attribute type is boolean, we know for sure it won't be an execution sink - // and we won't require Trusted Type here. - attributeValue = ""; - } else { - // `setAttribute` with objects becomes only `[object]` in IE8/9, - // ('' + value) makes it output the correct toString()-value. - if (enableTrustedTypesIntegration) { - attributeValue = value; - } else { - { - checkAttributeStringCoercion(value, attributeName); + node.removeAttribute(name); + return; } - - attributeValue = "" + value; - } - - if (propertyInfo.sanitizeURL) { - sanitizeURL(attributeValue.toString()); } } - if (attributeNamespace) { - node.setAttributeNS(attributeNamespace, attributeName, attributeValue); - } else { - node.setAttribute(attributeName, attributeValue); + { + checkAttributeStringCoercion(value, name); } + + node.setAttribute(name, enableTrustedTypesIntegration ? value : "" + value); } } @@ -2884,7 +3010,7 @@ function updateChecked(element, props) { var checked = props.checked; if (checked != null) { - setValueForProperty(node, "checked", checked, false); + node.checked = checked; } } function updateWrapper$1(element, props) { @@ -3884,122 +4010,6 @@ var shorthandToLonghand = { wordWrap: ["overflowWrap"] }; -/** - * CSS properties which accept numbers but are not in units of "px". - */ -var isUnitlessNumber = { - animationIterationCount: true, - aspectRatio: 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, - scale: 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 - } - - { - checkCSSPropertyStringCoercion(value, name); - } - - return ("" + value).trim(); -} - var uppercasePattern = /([A-Z])/g; var msPattern$1 = /^ms-/; /** @@ -4138,6 +4148,80 @@ function warnValidStyle(name, value) { } } +/** + * CSS properties which accept numbers but are not in units of "px". + */ +var isUnitlessNumber = { + animationIterationCount: true, + aspectRatio: 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, + scale: 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]; + }); +}); + /** * Operations for dealing with CSS properties. */ @@ -4159,19 +4243,41 @@ function createDangerousStringForStyles(styles) { continue; } - var styleValue = styles[styleName]; + var value = styles[styleName]; - if (styleValue != null) { + if (value != null && typeof value !== "boolean" && value !== "") { var isCustomProperty = styleName.indexOf("--") === 0; - serialized += - delimiter + - (isCustomProperty ? styleName : hyphenateStyleName(styleName)) + - ":"; - serialized += dangerousStyleValue( - styleName, - styleValue, - isCustomProperty - ); + + if (isCustomProperty) { + { + checkCSSPropertyStringCoercion(value, styleName); + } + + serialized += delimiter + styleName + ":" + ("" + value).trim(); + } else { + if ( + typeof value === "number" && + value !== 0 && + !( + isUnitlessNumber.hasOwnProperty(styleName) && + isUnitlessNumber[styleName] + ) + ) { + serialized += + delimiter + hyphenateStyleName(styleName) + ":" + value + "px"; + } else { + { + checkCSSPropertyStringCoercion(value, styleName); + } + + serialized += + delimiter + + hyphenateStyleName(styleName) + + ":" + + ("" + value).trim(); + } + } + delimiter = ";"; } } @@ -4195,28 +4301,44 @@ function setValueForStyles(node, styles) { continue; } + var value = styles[styleName]; var isCustomProperty = styleName.indexOf("--") === 0; { if (!isCustomProperty) { - warnValidStyle(styleName, styles[styleName]); + warnValidStyle(styleName, value); } } - var styleValue = dangerousStyleValue( - styleName, - styles[styleName], - isCustomProperty - ); - - if (styleName === "float") { - styleName = "cssFloat"; - } - - if (isCustomProperty) { - style.setProperty(styleName, styleValue); + if (value == null || typeof value === "boolean" || value === "") { + if (isCustomProperty) { + style.setProperty(styleName, ""); + } else if (styleName === "float") { + style.cssFloat = ""; + } else { + style[styleName] = ""; + } + } else if (isCustomProperty) { + style.setProperty(styleName, value); + } else if ( + typeof value === "number" && + value !== 0 && + !( + isUnitlessNumber.hasOwnProperty(styleName) && + isUnitlessNumber[styleName] + ) + ) { + style[styleName] = value + "px"; // Presumes implicit 'px' suffix for unitless numbers } else { - style[styleName] = styleValue; + if (styleName === "float") { + style.cssFloat = value; + } else { + { + checkCSSPropertyStringCoercion(value, styleName); + } + + style[styleName] = ("" + value).trim(); + } } } } @@ -4299,95 +4421,6 @@ function validateShorthandPropertyCollisionInDev(styleUpdates, nextStyles) { } } -// For HTML, certain tags should omit their close tag. We keep a list 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. -}; - -// `omittedCloseTags` except that `menuitem` should still have its closing tag. - -var voidElementTags = assign( - { - menuitem: true - }, - omittedCloseTags -); - -var HTML$1 = "__html"; - -function assertValidProps(tag, props) { - if (!props) { - return; - } // Note the use of `==` which checks for null or undefined. - - if (voidElementTags[tag]) { - if (props.children != null || props.dangerouslySetInnerHTML != null) { - throw new Error( - tag + - " is a void element tag and must neither have `children` nor " + - "use `dangerouslySetInnerHTML`." - ); - } - } - - if (props.dangerouslySetInnerHTML != null) { - if (props.children != null) { - throw new Error( - "Can only set one of `children` or `props.dangerouslySetInnerHTML`." - ); - } - - if ( - typeof props.dangerouslySetInnerHTML !== "object" || - !(HTML$1 in props.dangerouslySetInnerHTML) - ) { - throw new Error( - "`props.dangerouslySetInnerHTML` must be in the form `{__html: ...}`. " + - "Please visit https://reactjs.org/link/dangerously-set-inner-html " + - "for more information." - ); - } - } - - { - if ( - !props.suppressContentEditableWarning && - props.contentEditable && - props.children != null - ) { - 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." - ); - } - } - - if (props.style != null && typeof props.style !== "object") { - 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." - ); - } -} - function isCustomComponent(tagName, props) { if (tagName.indexOf("-") === -1) { return typeof props.is === "string"; @@ -5236,8 +5269,7 @@ function validateProperty(tagName, name, value, eventRegistry) { return true; } - var propertyInfo = getPropertyInfo(name); - var isReserved = propertyInfo !== null && propertyInfo.type === RESERVED; // Known attributes should match the casing specified in the property config. + var propertyInfo = getPropertyInfo(name); // Known attributes should match the casing specified in the property config. if (possibleStandardNames.hasOwnProperty(lowerCasedName)) { var standardName = possibleStandardNames[lowerCasedName]; @@ -5252,7 +5284,7 @@ function validateProperty(tagName, name, value, eventRegistry) { warnedProperties[name] = true; return true; } - } else if (!isReserved && name !== lowerCasedName) { + } else if (name !== lowerCasedName) { // Unknown attributes should have lowercase casing since that's how they // will be cased anyway with server rendering. error( @@ -5267,52 +5299,77 @@ function validateProperty(tagName, name, value, eventRegistry) { warnedProperties[name] = true; return true; + } // Now that we've validated casing, do not validate + // data types for reserved props + + switch (name) { + case "dangerouslySetInnerHTML": + case "children": + case "style": + case "suppressContentEditableWarning": + case "suppressHydrationWarning": + case "defaultValue": // Reserved + + case "defaultChecked": + case "innerHTML": { + return true; + } + + case "innerText": // Properties + + case "textContent": + if (enableCustomElementPropertySupport) { + return true; + } } - if ( - typeof value === "boolean" && - shouldRemoveAttributeWithWarning(name, value, propertyInfo, false) - ) { - if (value) { - 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 - ); - } else { - 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 - ); + if (typeof value === "boolean") { + var prefix = name.toLowerCase().slice(0, 5); + var acceptsBooleans = + propertyInfo !== null + ? propertyInfo.acceptsBooleans + : prefix === "data-" || prefix === "aria-"; + + if (!acceptsBooleans) { + if (value) { + 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 + ); + } else { + 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 + ); + } } warnedProperties[name] = true; return true; - } // Now that we've validated casing, do not validate - // data types for reserved props - - if (isReserved) { - return true; } // Warn when a known attribute is a bad type - if (shouldRemoveAttributeWithWarning(name, value, propertyInfo, false)) { - warnedProperties[name] = true; - return false; + switch (typeof value) { + case "function": + case "symbol": + // eslint-disable-line + warnedProperties[name] = true; + return false; } // Warn when passing the strings 'false' or 'true' into a boolean prop if ( @@ -5389,13 +5446,6 @@ function validateProperties(type, props, eventRegistry) { var didWarnInvalidHydration = false; var didWarnScriptTags = false; -var DANGEROUSLY_SET_INNER_HTML = "dangerouslySetInnerHTML"; -var SUPPRESS_CONTENT_EDITABLE_WARNING = "suppressContentEditableWarning"; -var SUPPRESS_HYDRATION_WARNING$1 = "suppressHydrationWarning"; -var AUTOFOCUS = "autoFocus"; -var CHILDREN = "children"; -var STYLE$1 = "style"; -var HTML = "__html"; var warnedUnknownTags; var canDiffStyleForHydrationWarning; @@ -5430,6 +5480,19 @@ function validatePropertiesInDevelopment(type, props) { registrationNameDependencies: registrationNameDependencies, possibleRegistrationNames: possibleRegistrationNames }); + + if ( + props.contentEditable && + !props.suppressContentEditableWarning && + props.children != null + ) { + 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." + ); + } } } @@ -5598,62 +5661,135 @@ function setInitialDOMProperties( var nextProp = nextProps[propKey]; - if (propKey === STYLE$1) { - { - if (nextProp) { - // Freeze the next style object so that we can assume it won't be - // mutated. We have already warned for this in the past. - Object.freeze(nextProp); + switch (propKey) { + case "style": { + if (nextProp != null && typeof nextProp !== "object") { + 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." + ); } - } // Relies on `updateStylesByID` not mutating `styleUpdates`. - setValueForStyles(domElement, nextProp); - } else if (propKey === DANGEROUSLY_SET_INNER_HTML) { - var nextHtml = nextProp ? nextProp[HTML] : undefined; + { + if (nextProp) { + // Freeze the next style object so that we can assume it won't be + // mutated. We have already warned for this in the past. + Object.freeze(nextProp); + } + } // Relies on `updateStylesByID` not mutating `styleUpdates`. - if (nextHtml != null) { - if (disableIEWorkarounds) { - domElement.innerHTML = nextHtml; - } else { - setInnerHTML$1(domElement, nextHtml); + setValueForStyles(domElement, nextProp); + break; + } + + case "dangerouslySetInnerHTML": { + if (nextProp != null) { + if (typeof nextProp !== "object" || !("__html" in nextProp)) { + throw new Error( + "`props.dangerouslySetInnerHTML` must be in the form `{__html: ...}`. " + + "Please visit https://reactjs.org/link/dangerously-set-inner-html " + + "for more information." + ); + } + + var nextHtml = nextProp.__html; + + if (nextHtml != null) { + if (nextProps.children != null) { + throw new Error( + "Can only set one of `children` or `props.dangerouslySetInnerHTML`." + ); + } + + if (disableIEWorkarounds) { + domElement.innerHTML = nextHtml; + } else { + setInnerHTML$1(domElement, nextHtml); + } + } } + + break; } - } else if (propKey === CHILDREN) { - if (typeof nextProp === "string") { - // Avoid setting initial textContent when the text is empty. In IE11 setting - // textContent on a