import {
registrationNameDependencies,
possibleRegistrationNames,
} from '../events/EventRegistry';
import {canUseDOM} from 'shared/ExecutionEnvironment';
import hasOwnProperty from 'shared/hasOwnProperty';
import {checkHtmlStringCoercion} from 'shared/CheckStringCoercion';
import {
getValueForAttribute,
getValueForProperty,
setValueForProperty,
} from './DOMPropertyOperations';
import {
initWrapperState as ReactDOMInputInitWrapperState,
getHostProps as ReactDOMInputGetHostProps,
postMountWrapper as ReactDOMInputPostMountWrapper,
updateChecked as ReactDOMInputUpdateChecked,
updateWrapper as ReactDOMInputUpdateWrapper,
restoreControlledState as ReactDOMInputRestoreControlledState,
} from './ReactDOMInput';
import {
postMountWrapper as ReactDOMOptionPostMountWrapper,
validateProps as ReactDOMOptionValidateProps,
} from './ReactDOMOption';
import {
initWrapperState as ReactDOMSelectInitWrapperState,
getHostProps as ReactDOMSelectGetHostProps,
postMountWrapper as ReactDOMSelectPostMountWrapper,
restoreControlledState as ReactDOMSelectRestoreControlledState,
postUpdateWrapper as ReactDOMSelectPostUpdateWrapper,
} from './ReactDOMSelect';
import {
initWrapperState as ReactDOMTextareaInitWrapperState,
getHostProps as ReactDOMTextareaGetHostProps,
postMountWrapper as ReactDOMTextareaPostMountWrapper,
updateWrapper as ReactDOMTextareaUpdateWrapper,
restoreControlledState as ReactDOMTextareaRestoreControlledState,
} from './ReactDOMTextarea';
import {track} from './inputValueTracking';
import setInnerHTML from './setInnerHTML';
import setTextContent from './setTextContent';
import {
createDangerousStringForStyles,
setValueForStyles,
validateShorthandPropertyCollisionInDev,
} from './CSSPropertyOperations';
import {HTML_NAMESPACE, getIntrinsicNamespace} from './DOMNamespaces';
import {
getPropertyInfo,
shouldIgnoreAttribute,
shouldRemoveAttribute,
} from '../shared/DOMProperty';
import assertValidProps from './assertValidProps';
import {DOCUMENT_NODE} from './HTMLNodeType';
import isCustomComponent from '../shared/isCustomComponent';
import possibleStandardNames from '../shared/possibleStandardNames';
import {validateProperties as validateARIAProperties} from '../shared/ReactDOMInvalidARIAHook';
import {validateProperties as validateInputProperties} from '../shared/ReactDOMNullInputValuePropHook';
import {validateProperties as validateUnknownProperties} from '../shared/ReactDOMUnknownPropertyHook';
import {
enableTrustedTypesIntegration,
enableCustomElementPropertySupport,
enableClientRenderFallbackOnTextMismatch,
enableHostSingletons,
disableIEWorkarounds,
} from 'shared/ReactFeatureFlags';
import {
mediaEventTypes,
listenToNonDelegatedEvent,
} from '../events/DOMPluginEventSystem';
let didWarnInvalidHydration = false;
let didWarnScriptTags = false;
const DANGEROUSLY_SET_INNER_HTML = 'dangerouslySetInnerHTML';
const SUPPRESS_CONTENT_EDITABLE_WARNING = 'suppressContentEditableWarning';
const SUPPRESS_HYDRATION_WARNING = 'suppressHydrationWarning';
const AUTOFOCUS = 'autoFocus';
const CHILDREN = 'children';
const STYLE = 'style';
const HTML = '__html';
let warnedUnknownTags: {
[key: string]: boolean,
};
let canDiffStyleForHydrationWarning;
if (__DEV__) {
warnedUnknownTags = {
dialog: true,
webview: true,
};
canDiffStyleForHydrationWarning =
disableIEWorkarounds || (canUseDOM && !document.documentMode);
}
function validatePropertiesInDevelopment(type: string, props: any) {
if (__DEV__) {
validateARIAProperties(type, props);
validateInputProperties(type, props);
validateUnknownProperties(type, props, {
registrationNameDependencies,
possibleRegistrationNames,
});
}
}
function warnForPropDifference(
propName: string,
serverValue: mixed,
clientValue: mixed,
) {
if (__DEV__) {
if (didWarnInvalidHydration) {
return;
}
const normalizedClientValue =
normalizeMarkupForTextOrAttribute(clientValue);
const normalizedServerValue =
normalizeMarkupForTextOrAttribute(serverValue);
if (normalizedServerValue === normalizedClientValue) {
return;
}
didWarnInvalidHydration = true;
console.error(
'Prop `%s` did not match. Server: %s Client: %s',
propName,
JSON.stringify(normalizedServerValue),
JSON.stringify(normalizedClientValue),
);
}
}
function warnForExtraAttributes(attributeNames: Set<string>) {
if (__DEV__) {
if (didWarnInvalidHydration) {
return;
}
didWarnInvalidHydration = true;
const names = [];
attributeNames.forEach(function (name) {
names.push(name);
});
console.error('Extra attributes from the server: %s', names);
}
}
function warnForInvalidEventListener(registrationName: string, listener: any) {
if (__DEV__) {
if (listener === false) {
console.error(
'Expected `%s` listener to be a function, instead got `false`.\n\n' +
'If you used to conditionally omit it with %s={condition && value}, ' +
'pass %s={condition ? value : undefined} instead.',
registrationName,
registrationName,
registrationName,
);
} else {
console.error(
'Expected `%s` listener to be a function, instead got a value of `%s` type.',
registrationName,
typeof listener,
);
}
}
}
function normalizeHTML(parent: Element, html: string) {
if (__DEV__) {
const testElement =
parent.namespaceURI === HTML_NAMESPACE
? parent.ownerDocument.createElement(parent.tagName)
: parent.ownerDocument.createElementNS(
(parent.namespaceURI: any),
parent.tagName,
);
testElement.innerHTML = html;
return testElement.innerHTML;
}
}
const NORMALIZE_NEWLINES_REGEX = /\r\n?/g;
const NORMALIZE_NULL_AND_REPLACEMENT_REGEX = /\u0000|\uFFFD/g;
function normalizeMarkupForTextOrAttribute(markup: mixed): string {
if (__DEV__) {
checkHtmlStringCoercion(markup);
}
const markupString = typeof markup === 'string' ? markup : '' + (markup: any);
return markupString
.replace(NORMALIZE_NEWLINES_REGEX, '\n')
.replace(NORMALIZE_NULL_AND_REPLACEMENT_REGEX, '');
}
export function checkForUnmatchedText(
serverText: string,
clientText: string | number,
isConcurrentMode: boolean,
shouldWarnDev: boolean,
) {
const normalizedClientText = normalizeMarkupForTextOrAttribute(clientText);
const normalizedServerText = normalizeMarkupForTextOrAttribute(serverText);
if (normalizedServerText === normalizedClientText) {
return;
}
if (shouldWarnDev) {
if (__DEV__) {
if (!didWarnInvalidHydration) {
didWarnInvalidHydration = true;
console.error(
'Text content did not match. Server: "%s" Client: "%s"',
normalizedServerText,
normalizedClientText,
);
}
}
}
if (isConcurrentMode && enableClientRenderFallbackOnTextMismatch) {
throw new Error('Text content does not match server-rendered HTML.');
}
}
export function getOwnerDocumentFromRootContainer(
rootContainerElement: Element | Document | DocumentFragment,
): Document {
return rootContainerElement.nodeType === DOCUMENT_NODE
? (rootContainerElement: any)
: rootContainerElement.ownerDocument;
}
function noop() {}
export function trapClickOnNonInteractiveElement(node: HTMLElement) {
node.onclick = noop;
}
function setInitialDOMProperties(
tag: string,
domElement: Element,
nextProps: Object,
isCustomComponentTag: boolean,
): void {
for (const propKey in nextProps) {
if (!nextProps.hasOwnProperty(propKey)) {
continue;
}
const nextProp = nextProps[propKey];
if (propKey === STYLE) {
if (__DEV__) {
if (nextProp) {
Object.freeze(nextProp);
}
}
setValueForStyles(domElement, nextProp);
} else if (propKey === DANGEROUSLY_SET_INNER_HTML) {
const nextHtml = nextProp ? nextProp[HTML] : undefined;
if (nextHtml != null) {
if (disableIEWorkarounds) {
domElement.innerHTML = nextHtml;
} else {
setInnerHTML(domElement, nextHtml);
}
}
} else if (propKey === CHILDREN) {
if (typeof nextProp === 'string') {
const canSetTextContent =
(!enableHostSingletons || tag !== 'body') &&
(tag !== 'textarea' || nextProp !== '');
if (canSetTextContent) {
setTextContent(domElement, nextProp);
}
} else if (typeof nextProp === 'number') {
const canSetTextContent = !enableHostSingletons || tag !== 'body';
if (canSetTextContent) {
setTextContent(domElement, '' + nextProp);
}
}
} else if (
propKey === SUPPRESS_CONTENT_EDITABLE_WARNING ||
propKey === SUPPRESS_HYDRATION_WARNING
) {
} else if (propKey === AUTOFOCUS) {
} else if (registrationNameDependencies.hasOwnProperty(propKey)) {
if (nextProp != null) {
if (__DEV__ && typeof nextProp !== 'function') {
warnForInvalidEventListener(propKey, nextProp);
}
if (propKey === 'onScroll') {
listenToNonDelegatedEvent('scroll', domElement);
}
}
} else if (nextProp != null) {
setValueForProperty(domElement, propKey, nextProp, isCustomComponentTag);
}
}
}
function updateDOMProperties(
domElement: Element,
updatePayload: Array<any>,
wasCustomComponentTag: boolean,
isCustomComponentTag: boolean,
): void {
for (let i = 0; i < updatePayload.length; i += 2) {
const propKey = updatePayload[i];
const propValue = updatePayload[i + 1];
if (propKey === STYLE) {
setValueForStyles(domElement, propValue);
} else if (propKey === DANGEROUSLY_SET_INNER_HTML) {
if (disableIEWorkarounds) {
domElement.innerHTML = propValue;
} else {
setInnerHTML(domElement, propValue);
}
} else if (propKey === CHILDREN) {
setTextContent(domElement, propValue);
} else {
setValueForProperty(domElement, propKey, propValue, isCustomComponentTag);
}
}
}
export function createPotentiallyInlineScriptElement(
ownerDocument: Document,
): Element {
const div = ownerDocument.createElement('div');
if (__DEV__) {
if (enableTrustedTypesIntegration && !didWarnScriptTags) {
console.error(
'Encountered a script tag while rendering React component. ' +
'Scripts inside React components are never executed when rendering ' +
'on the client. Consider using template tag instead ' +
'(https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template).',
);
didWarnScriptTags = true;
}
}
div.innerHTML = '<script><' + '/script>';
const firstChild = ((div.firstChild: any): HTMLScriptElement);
const element = div.removeChild(firstChild);
return element;
}
export function createSelectElement(
props: Object,
ownerDocument: Document,
): Element {
let element;
if (typeof props.is === 'string') {
element = ownerDocument.createElement('select', {is: props.is});
} else {
element = ownerDocument.createElement('select');
}
if (props.multiple) {
element.multiple = true;
} else if (props.size) {
element.size = props.size;
}
return element;
}
export function createHTMLElement(
type: string,
props: Object,
ownerDocument: Document,
): Element {
if (__DEV__) {
switch (type) {
case 'script':
case 'select':
console.error(
'createHTMLElement was called with a "%s" type. This type has special creation logic in React and should use the create function implemented specifically for it. This is a bug in React.',
type,
);
break;
case 'svg':
case 'math':
console.error(
'createHTMLElement was called with a "%s" type. This type must be created with Document.createElementNS which this method does not implement. This is a bug in React.',
type,
);
}
}
let isCustomComponentTag;
let element: Element;
if (__DEV__) {
isCustomComponentTag = isCustomComponent(type, props);
if (!isCustomComponentTag && type !== type.toLowerCase()) {
console.error(
'<%s /> is using incorrect casing. ' +
'Use PascalCase for React components, ' +
'or lowercase for HTML elements.',
type,
);
}
}
if (typeof props.is === 'string') {
element = ownerDocument.createElement(type, {is: props.is});
} else {
element = ownerDocument.createElement(type);
}
if (__DEV__) {
if (
!isCustomComponentTag &&
Object.prototype.toString.call(element) ===
'[object HTMLUnknownElement]' &&
!hasOwnProperty.call(warnedUnknownTags, type)
) {
warnedUnknownTags[type] = true;
console.error(
'The tag <%s> is unrecognized in this browser. ' +
'If you meant to render a React component, start its name with ' +
'an uppercase letter.',
type,
);
}
}
return element;
}
export function createTextNode(
text: string,
rootContainerElement: Element | Document | DocumentFragment,
): Text {
return getOwnerDocumentFromRootContainer(rootContainerElement).createTextNode(
text,
);
}
export function setInitialProperties(
domElement: Element,
tag: string,
rawProps: Object,
): void {
const isCustomComponentTag = isCustomComponent(tag, rawProps);
if (__DEV__) {
validatePropertiesInDevelopment(tag, rawProps);
}
let props: Object;
switch (tag) {
case 'dialog':
listenToNonDelegatedEvent('cancel', domElement);
listenToNonDelegatedEvent('close', domElement);
props = rawProps;
break;
case 'iframe':
case 'object':
case 'embed':
listenToNonDelegatedEvent('load', domElement);
props = rawProps;
break;
case 'video':
case 'audio':
for (let i = 0; i < mediaEventTypes.length; i++) {
listenToNonDelegatedEvent(mediaEventTypes[i], domElement);
}
props = rawProps;
break;
case 'source':
listenToNonDelegatedEvent('error', domElement);
props = rawProps;
break;
case 'img':
case 'image':
case 'link':
listenToNonDelegatedEvent('error', domElement);
listenToNonDelegatedEvent('load', domElement);
props = rawProps;
break;
case 'details':
listenToNonDelegatedEvent('toggle', domElement);
props = rawProps;
break;
case 'input':
ReactDOMInputInitWrapperState(domElement, rawProps);
props = ReactDOMInputGetHostProps(domElement, rawProps);
listenToNonDelegatedEvent('invalid', domElement);
break;
case 'option':
ReactDOMOptionValidateProps(domElement, rawProps);
props = rawProps;
break;
case 'select':
ReactDOMSelectInitWrapperState(domElement, rawProps);
props = ReactDOMSelectGetHostProps(domElement, rawProps);
listenToNonDelegatedEvent('invalid', domElement);
break;
case 'textarea':
ReactDOMTextareaInitWrapperState(domElement, rawProps);
props = ReactDOMTextareaGetHostProps(domElement, rawProps);
listenToNonDelegatedEvent('invalid', domElement);
break;
default:
props = rawProps;
}
assertValidProps(tag, props);
setInitialDOMProperties(tag, domElement, props, isCustomComponentTag);
switch (tag) {
case 'input':
track((domElement: any));
ReactDOMInputPostMountWrapper(domElement, rawProps, false);
break;
case 'textarea':
track((domElement: any));
ReactDOMTextareaPostMountWrapper(domElement, rawProps);
break;
case 'option':
ReactDOMOptionPostMountWrapper(domElement, rawProps);
break;
case 'select':
ReactDOMSelectPostMountWrapper(domElement, rawProps);
break;
default:
if (typeof props.onClick === 'function') {
trapClickOnNonInteractiveElement(((domElement: any): HTMLElement));
}
break;
}
}
export function diffProperties(
domElement: Element,
tag: string,
lastRawProps: Object,
nextRawProps: Object,
): null | Array<mixed> {
if (__DEV__) {
validatePropertiesInDevelopment(tag, nextRawProps);
}
let updatePayload: null | Array<any> = null;
let lastProps: Object;
let nextProps: Object;
switch (tag) {
case 'input':
lastProps = ReactDOMInputGetHostProps(domElement, lastRawProps);
nextProps = ReactDOMInputGetHostProps(domElement, nextRawProps);
updatePayload = [];
break;
case 'select':
lastProps = ReactDOMSelectGetHostProps(domElement, lastRawProps);
nextProps = ReactDOMSelectGetHostProps(domElement, nextRawProps);
updatePayload = [];
break;
case 'textarea':
lastProps = ReactDOMTextareaGetHostProps(domElement, lastRawProps);
nextProps = ReactDOMTextareaGetHostProps(domElement, nextRawProps);
updatePayload = [];
break;
default:
lastProps = lastRawProps;
nextProps = nextRawProps;
if (
typeof lastProps.onClick !== 'function' &&
typeof nextProps.onClick === 'function'
) {
trapClickOnNonInteractiveElement(((domElement: any): HTMLElement));
}
break;
}
assertValidProps(tag, nextProps);
let propKey;
let styleName;
let styleUpdates = null;
for (propKey in lastProps) {
if (
nextProps.hasOwnProperty(propKey) ||
!lastProps.hasOwnProperty(propKey) ||
lastProps[propKey] == null
) {
continue;
}
if (propKey === STYLE) {
const lastStyle = lastProps[propKey];
for (styleName in lastStyle) {
if (lastStyle.hasOwnProperty(styleName)) {
if (!styleUpdates) {
styleUpdates = ({}: {[string]: $FlowFixMe});
}
styleUpdates[styleName] = '';
}
}
} else if (propKey === DANGEROUSLY_SET_INNER_HTML || propKey === CHILDREN) {
} else if (
propKey === SUPPRESS_CONTENT_EDITABLE_WARNING ||
propKey === SUPPRESS_HYDRATION_WARNING
) {
} else if (propKey === AUTOFOCUS) {
} else if (registrationNameDependencies.hasOwnProperty(propKey)) {
if (!updatePayload) {
updatePayload = [];
}
} else {
(updatePayload = updatePayload || []).push(propKey, null);
}
}
for (propKey in nextProps) {
const nextProp = nextProps[propKey];
const lastProp = lastProps != null ? lastProps[propKey] : undefined;
if (
!nextProps.hasOwnProperty(propKey) ||
nextProp === lastProp ||
(nextProp == null && lastProp == null)
) {
continue;
}
if (propKey === STYLE) {
if (__DEV__) {
if (nextProp) {
Object.freeze(nextProp);
}
}
if (lastProp) {
for (styleName in lastProp) {
if (
lastProp.hasOwnProperty(styleName) &&
(!nextProp || !nextProp.hasOwnProperty(styleName))
) {
if (!styleUpdates) {
styleUpdates = ({}: {[string]: string});
}
styleUpdates[styleName] = '';
}
}
for (styleName in nextProp) {
if (
nextProp.hasOwnProperty(styleName) &&
lastProp[styleName] !== nextProp[styleName]
) {
if (!styleUpdates) {
styleUpdates = ({}: {[string]: $FlowFixMe});
}
styleUpdates[styleName] = nextProp[styleName];
}
}
} else {
if (!styleUpdates) {
if (!updatePayload) {
updatePayload = [];
}
updatePayload.push(propKey, styleUpdates);
}
styleUpdates = nextProp;
}
} else if (propKey === DANGEROUSLY_SET_INNER_HTML) {
const nextHtml = nextProp ? nextProp[HTML] : undefined;
const lastHtml = lastProp ? lastProp[HTML] : undefined;
if (nextHtml != null) {
if (lastHtml !== nextHtml) {
(updatePayload = updatePayload || []).push(propKey, nextHtml);
}
} else {
}
} else if (propKey === CHILDREN) {
if (typeof nextProp === 'string' || typeof nextProp === 'number') {
(updatePayload = updatePayload || []).push(propKey, '' + nextProp);
}
} else if (
propKey === SUPPRESS_CONTENT_EDITABLE_WARNING ||
propKey === SUPPRESS_HYDRATION_WARNING
) {
} else if (registrationNameDependencies.hasOwnProperty(propKey)) {
if (nextProp != null) {
if (__DEV__ && typeof nextProp !== 'function') {
warnForInvalidEventListener(propKey, nextProp);
}
if (propKey === 'onScroll') {
listenToNonDelegatedEvent('scroll', domElement);
}
}
if (!updatePayload && lastProp !== nextProp) {
updatePayload = [];
}
} else {
(updatePayload = updatePayload || []).push(propKey, nextProp);
}
}
if (styleUpdates) {
if (__DEV__) {
validateShorthandPropertyCollisionInDev(styleUpdates, nextProps[STYLE]);
}
(updatePayload = updatePayload || []).push(STYLE, styleUpdates);
}
return updatePayload;
}
export function updateProperties(
domElement: Element,
updatePayload: Array<any>,
tag: string,
lastRawProps: Object,
nextRawProps: Object,
): void {
if (
tag === 'input' &&
nextRawProps.type === 'radio' &&
nextRawProps.name != null
) {
ReactDOMInputUpdateChecked(domElement, nextRawProps);
}
const wasCustomComponentTag = isCustomComponent(tag, lastRawProps);
const isCustomComponentTag = isCustomComponent(tag, nextRawProps);
updateDOMProperties(
domElement,
updatePayload,
wasCustomComponentTag,
isCustomComponentTag,
);
switch (tag) {
case 'input':
ReactDOMInputUpdateWrapper(domElement, nextRawProps);
break;
case 'textarea':
ReactDOMTextareaUpdateWrapper(domElement, nextRawProps);
break;
case 'select':
ReactDOMSelectPostUpdateWrapper(domElement, nextRawProps);
break;
}
}
function getPossibleStandardName(propName: string): string | null {
if (__DEV__) {
const lowerCasedName = propName.toLowerCase();
if (!possibleStandardNames.hasOwnProperty(lowerCasedName)) {
return null;
}
return possibleStandardNames[lowerCasedName] || null;
}
return null;
}
export function diffHydratedProperties(
domElement: Element,
tag: string,
rawProps: Object,
isConcurrentMode: boolean,
shouldWarnDev: boolean,
parentNamespaceDev: string,
): null | Array<mixed> {
let extraAttributeNames: Set<string>;
if (__DEV__) {
validatePropertiesInDevelopment(tag, rawProps);
}
switch (tag) {
case 'dialog':
listenToNonDelegatedEvent('cancel', domElement);
listenToNonDelegatedEvent('close', domElement);
break;
case 'iframe':
case 'object':
case 'embed':
listenToNonDelegatedEvent('load', domElement);
break;
case 'video':
case 'audio':
for (let i = 0; i < mediaEventTypes.length; i++) {
listenToNonDelegatedEvent(mediaEventTypes[i], domElement);
}
break;
case 'source':
listenToNonDelegatedEvent('error', domElement);
break;
case 'img':
case 'image':
case 'link':
listenToNonDelegatedEvent('error', domElement);
listenToNonDelegatedEvent('load', domElement);
break;
case 'details':
listenToNonDelegatedEvent('toggle', domElement);
break;
case 'input':
ReactDOMInputInitWrapperState(domElement, rawProps);
listenToNonDelegatedEvent('invalid', domElement);
break;
case 'option':
ReactDOMOptionValidateProps(domElement, rawProps);
break;
case 'select':
ReactDOMSelectInitWrapperState(domElement, rawProps);
listenToNonDelegatedEvent('invalid', domElement);
break;
case 'textarea':
ReactDOMTextareaInitWrapperState(domElement, rawProps);
listenToNonDelegatedEvent('invalid', domElement);
break;
}
if (rawProps.hasOwnProperty('onScroll')) {
listenToNonDelegatedEvent('scroll', domElement);
}
assertValidProps(tag, rawProps);
if (__DEV__) {
extraAttributeNames = new Set();
const attributes = domElement.attributes;
for (let i = 0; i < attributes.length; i++) {
const name = attributes[i].name.toLowerCase();
switch (name) {
case 'value':
break;
case 'checked':
break;
case 'selected':
break;
default:
extraAttributeNames.add(attributes[i].name);
}
}
}
let updatePayload = null;
const children = rawProps.children;
if (typeof children === 'string' || typeof children === 'number') {
if (domElement.textContent !== '' + children) {
if (rawProps[SUPPRESS_HYDRATION_WARNING] !== true) {
checkForUnmatchedText(
domElement.textContent,
children,
isConcurrentMode,
shouldWarnDev,
);
}
if (!isConcurrentMode) {
updatePayload = [CHILDREN, children];
}
}
}
if (__DEV__ && shouldWarnDev) {
const isCustomComponentTag = isCustomComponent(tag, rawProps);
for (const propKey in rawProps) {
if (!rawProps.hasOwnProperty(propKey)) {
continue;
}
const nextProp = rawProps[propKey];
if (propKey === CHILDREN) {
} else if (registrationNameDependencies.hasOwnProperty(propKey)) {
if (nextProp != null) {
if (typeof nextProp !== 'function') {
warnForInvalidEventListener(propKey, nextProp);
}
}
} else {
let serverValue;
const propertyInfo =
isCustomComponentTag && enableCustomElementPropertySupport
? null
: getPropertyInfo(propKey);
if (rawProps[SUPPRESS_HYDRATION_WARNING] === true) {
} else if (
propKey === SUPPRESS_CONTENT_EDITABLE_WARNING ||
propKey === SUPPRESS_HYDRATION_WARNING ||
propKey === 'value' ||
propKey === 'checked' ||
propKey === 'selected'
) {
} else if (propKey === DANGEROUSLY_SET_INNER_HTML) {
const serverHTML = domElement.innerHTML;
const nextHtml = nextProp ? nextProp[HTML] : undefined;
if (nextHtml != null) {
const expectedHTML = normalizeHTML(domElement, nextHtml);
if (expectedHTML !== serverHTML) {
warnForPropDifference(propKey, serverHTML, expectedHTML);
}
}
} else if (propKey === STYLE) {
extraAttributeNames.delete(propKey);
if (canDiffStyleForHydrationWarning) {
const expectedStyle = createDangerousStringForStyles(nextProp);
serverValue = domElement.getAttribute('style');
if (expectedStyle !== serverValue) {
warnForPropDifference(propKey, serverValue, expectedStyle);
}
}
} else if (
enableCustomElementPropertySupport &&
isCustomComponentTag &&
(propKey === 'offsetParent' ||
propKey === 'offsetTop' ||
propKey === 'offsetLeft' ||
propKey === 'offsetWidth' ||
propKey === 'offsetHeight' ||
propKey === 'isContentEditable' ||
propKey === 'outerText' ||
propKey === 'outerHTML')
) {
extraAttributeNames.delete(propKey.toLowerCase());
if (__DEV__) {
console.error(
'Assignment to read-only property will result in a no-op: `%s`',
propKey,
);
}
} else if (
isCustomComponentTag &&
!enableCustomElementPropertySupport
) {
extraAttributeNames.delete(propKey.toLowerCase());
serverValue = getValueForAttribute(
domElement,
propKey,
nextProp,
isCustomComponentTag,
);
if (nextProp !== serverValue) {
warnForPropDifference(propKey, serverValue, nextProp);
}
} else if (
!shouldIgnoreAttribute(propKey, propertyInfo, isCustomComponentTag) &&
!shouldRemoveAttribute(
propKey,
nextProp,
propertyInfo,
isCustomComponentTag,
)
) {
let isMismatchDueToBadCasing = false;
if (propertyInfo !== null) {
extraAttributeNames.delete(propertyInfo.attributeName);
serverValue = getValueForProperty(
domElement,
propKey,
nextProp,
propertyInfo,
);
} else {
let ownNamespaceDev = parentNamespaceDev;
if (ownNamespaceDev === HTML_NAMESPACE) {
ownNamespaceDev = getIntrinsicNamespace(tag);
}
if (ownNamespaceDev === HTML_NAMESPACE) {
extraAttributeNames.delete(propKey.toLowerCase());
} else {
const standardName = getPossibleStandardName(propKey);
if (standardName !== null && standardName !== propKey) {
isMismatchDueToBadCasing = true;
extraAttributeNames.delete(standardName);
}
extraAttributeNames.delete(propKey);
}
serverValue = getValueForAttribute(
domElement,
propKey,
nextProp,
isCustomComponentTag,
);
}
const dontWarnCustomElement =
enableCustomElementPropertySupport &&
isCustomComponentTag &&
(typeof nextProp === 'function' || typeof nextProp === 'object');
if (
!dontWarnCustomElement &&
nextProp !== serverValue &&
!isMismatchDueToBadCasing
) {
warnForPropDifference(propKey, serverValue, nextProp);
}
}
}
}
if (
extraAttributeNames.size > 0 &&
rawProps[SUPPRESS_HYDRATION_WARNING] !== true
) {
warnForExtraAttributes(extraAttributeNames);
}
}
switch (tag) {
case 'input':
track((domElement: any));
ReactDOMInputPostMountWrapper(domElement, rawProps, true);
break;
case 'textarea':
track((domElement: any));
ReactDOMTextareaPostMountWrapper(domElement, rawProps);
break;
case 'select':
case 'option':
break;
default:
if (typeof rawProps.onClick === 'function') {
trapClickOnNonInteractiveElement(((domElement: any): HTMLElement));
}
break;
}
return updatePayload;
}
export function diffHydratedText(
textNode: Text,
text: string,
isConcurrentMode: boolean,
): boolean {
const isDifferent = textNode.nodeValue !== text;
return isDifferent;
}
export function warnForDeletedHydratableElement(
parentNode: Element | Document | DocumentFragment,
child: Element,
) {
if (__DEV__) {
if (didWarnInvalidHydration) {
return;
}
didWarnInvalidHydration = true;
console.error(
'Did not expect server HTML to contain a <%s> in <%s>.',
child.nodeName.toLowerCase(),
parentNode.nodeName.toLowerCase(),
);
}
}
export function warnForDeletedHydratableText(
parentNode: Element | Document | DocumentFragment,
child: Text,
) {
if (__DEV__) {
if (didWarnInvalidHydration) {
return;
}
didWarnInvalidHydration = true;
console.error(
'Did not expect server HTML to contain the text node "%s" in <%s>.',
child.nodeValue,
parentNode.nodeName.toLowerCase(),
);
}
}
export function warnForInsertedHydratedElement(
parentNode: Element | Document | DocumentFragment,
tag: string,
props: Object,
) {
if (__DEV__) {
if (didWarnInvalidHydration) {
return;
}
didWarnInvalidHydration = true;
console.error(
'Expected server HTML to contain a matching <%s> in <%s>.',
tag,
parentNode.nodeName.toLowerCase(),
);
}
}
export function warnForInsertedHydratedText(
parentNode: Element | Document | DocumentFragment,
text: string,
) {
if (__DEV__) {
if (text === '') {
return;
}
if (didWarnInvalidHydration) {
return;
}
didWarnInvalidHydration = true;
console.error(
'Expected server HTML to contain a matching text node for "%s" in <%s>.',
text,
parentNode.nodeName.toLowerCase(),
);
}
}
export function restoreControlledState(
domElement: Element,
tag: string,
props: Object,
): void {
switch (tag) {
case 'input':
ReactDOMInputRestoreControlledState(domElement, props);
return;
case 'textarea':
ReactDOMTextareaRestoreControlledState(domElement, props);
return;
case 'select':
ReactDOMSelectRestoreControlledState(domElement, props);
return;
}
}