diff --git a/packages/react-dom-bindings/src/client/ReactDOMComponent.js b/packages/react-dom-bindings/src/client/ReactDOMComponent.js index 9f7b23026f758..ac95c91c596a8 100644 --- a/packages/react-dom-bindings/src/client/ReactDOMComponent.js +++ b/packages/react-dom-bindings/src/client/ReactDOMComponent.js @@ -16,7 +16,6 @@ import { possibleRegistrationNames, } from '../events/EventRegistry'; -import {canUseDOM} from 'shared/ExecutionEnvironment'; import {checkHtmlStringCoercion} from 'shared/CheckStringCoercion'; import {checkAttributeStringCoercion} from 'shared/CheckStringCoercion'; import {checkControlledValueProps} from '../shared/ReactControlledValuePropTypes'; @@ -50,7 +49,6 @@ import { } from './ReactDOMTextarea'; import {validateTextNesting} from './validateDOMNesting'; import {track} from './inputValueTracking'; -import setInnerHTML from './setInnerHTML'; import setTextContent from './setTextContent'; import { createDangerousStringForStyles, @@ -66,7 +64,6 @@ import {validateProperties as validateUnknownProperties} from '../shared/ReactDO import sanitizeURL from '../shared/sanitizeURL'; import { - disableIEWorkarounds, enableTrustedTypesIntegration, enableFilterEmptyStringAttributesDOM, } from 'shared/ReactFeatureFlags'; @@ -83,19 +80,8 @@ let didWarnFormActionTarget = false; let didWarnFormActionMethod = false; let didWarnForNewBooleanPropsWithEmptyValue: {[string]: boolean}; let didWarnPopoverTargetObject = false; -let canDiffStyleForHydrationWarning; if (__DEV__) { didWarnForNewBooleanPropsWithEmptyValue = {}; - // IE 11 parses & normalizes the style attribute as opposed to other - // browsers. It adds spaces and sorts the properties in some - // non-alphabetical order. Handling that would require sorting CSS - // properties in the client & server versions or applying - // `expectedStyle` to a temporary DOM node to read its `style` attribute - // normalized. Since it only affects IE, we're skipping style warnings - // in that browser completely in favor of doing all that work. - // See https://github.com/facebook/react/issues/11807 - canDiffStyleForHydrationWarning = - disableIEWorkarounds || (canUseDOM && !document.documentMode); } function validatePropertiesInDevelopment(type: string, props: any) { @@ -579,11 +565,7 @@ function setProp( 'Can only set one of `children` or `props.dangerouslySetInnerHTML`.', ); } - if (disableIEWorkarounds) { - domElement.innerHTML = nextHtml; - } else { - setInnerHTML(domElement, nextHtml); - } + domElement.innerHTML = nextHtml; } } break; @@ -939,11 +921,7 @@ function setPropOnCustomElement( 'Can only set one of `children` or `props.dangerouslySetInnerHTML`.', ); } - if (disableIEWorkarounds) { - domElement.innerHTML = nextHtml; - } else { - setInnerHTML(domElement, nextHtml); - } + domElement.innerHTML = nextHtml; } } break; @@ -1931,27 +1909,23 @@ function diffHydratedStyles( } return; } - if (canDiffStyleForHydrationWarning) { - // First we compare the string form and see if it's equivalent. - // This lets us bail out on anything that used to pass in this form. - // It also lets us compare anything that's not parsed by this browser. - const clientValue = createDangerousStringForStyles(value); - const serverValue = domElement.getAttribute('style'); + // First we compare the string form and see if it's equivalent. + // This lets us bail out on anything that used to pass in this form. + // It also lets us compare anything that's not parsed by this browser. + const clientValue = createDangerousStringForStyles(value); + const serverValue = domElement.getAttribute('style'); - if (serverValue === clientValue) { - return; - } - const normalizedClientValue = - normalizeMarkupForTextOrAttribute(clientValue); - const normalizedServerValue = - normalizeMarkupForTextOrAttribute(serverValue); - if (normalizedServerValue === normalizedClientValue) { - return; - } - - // Otherwise, we create the object from the DOM for the diff view. - serverDifferences.style = getStylesObjectFromElement(domElement); + if (serverValue === clientValue) { + return; + } + const normalizedClientValue = normalizeMarkupForTextOrAttribute(clientValue); + const normalizedServerValue = normalizeMarkupForTextOrAttribute(serverValue); + if (normalizedServerValue === normalizedClientValue) { + return; } + + // Otherwise, we create the object from the DOM for the diff view. + serverDifferences.style = getStylesObjectFromElement(domElement); } function hydrateAttribute( diff --git a/packages/react-dom-bindings/src/client/setInnerHTML.js b/packages/react-dom-bindings/src/client/setInnerHTML.js deleted file mode 100644 index 5f0d630fd38b5..0000000000000 --- a/packages/react-dom-bindings/src/client/setInnerHTML.js +++ /dev/null @@ -1,82 +0,0 @@ -/** - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @flow - */ - -/* globals MSApp */ - -import {SVG_NAMESPACE} from './DOMNamespaces'; -import {enableTrustedTypesIntegration} from 'shared/ReactFeatureFlags'; - -// SVG temp container for IE lacking innerHTML -let reusableSVGContainer: HTMLElement; - -function setInnerHTMLImpl( - node: Element, - html: {valueOf(): {toString(): string, ...}, ...}, -): void { - if (node.namespaceURI === SVG_NAMESPACE) { - if (__DEV__) { - if (enableTrustedTypesIntegration) { - // TODO: reconsider the text of this warning and when it should show - // before enabling the feature flag. - if (typeof trustedTypes !== 'undefined') { - console.error( - "Using 'dangerouslySetInnerHTML' in an svg element with " + - 'Trusted Types enabled in an Internet Explorer will cause ' + - 'the trusted value to be converted to string. Assigning string ' + - "to 'innerHTML' will throw an error if Trusted Types are enforced. " + - "You can try to wrap your svg element inside a div and use 'dangerouslySetInnerHTML' " + - 'on the enclosing div instead.', - ); - } - } - } - if (!('innerHTML' in node)) { - // IE does not have innerHTML for SVG nodes, so instead we inject the - // new markup in a temp node and then move the child nodes across into - // the target node - reusableSVGContainer = - reusableSVGContainer || document.createElement('div'); - reusableSVGContainer.innerHTML = - '' + html.valueOf().toString() + ''; - const svgNode = reusableSVGContainer.firstChild; - while (node.firstChild) { - node.removeChild(node.firstChild); - } - // $FlowFixMe[incompatible-use] - // $FlowFixMe[incompatible-type] - while (svgNode.firstChild) { - node.appendChild(svgNode.firstChild); - } - return; - } - } - node.innerHTML = (html: any); -} - -let setInnerHTML: ( - node: Element, - html: {valueOf(): {toString(): string, ...}, ...}, -) => void = setInnerHTMLImpl; -// $FlowFixMe[cannot-resolve-name] -if (typeof MSApp !== 'undefined' && MSApp.execUnsafeLocalFunction) { - /** - * Create a function which has 'unsafe' privileges (required by windows8 apps) - */ - setInnerHTML = function ( - node: Element, - html: {valueOf(): {toString(): string, ...}, ...}, - ): void { - // $FlowFixMe[cannot-resolve-name] - return MSApp.execUnsafeLocalFunction(function () { - return setInnerHTMLImpl(node, html); - }); - }; -} - -export default setInnerHTML; diff --git a/packages/react-dom/src/client/__tests__/dangerouslySetInnerHTML-test.js b/packages/react-dom/src/client/__tests__/dangerouslySetInnerHTML-test.js index 64b4c0b0f7c98..ccbd41c2f30ad 100644 --- a/packages/react-dom/src/client/__tests__/dangerouslySetInnerHTML-test.js +++ b/packages/react-dom/src/client/__tests__/dangerouslySetInnerHTML-test.js @@ -27,73 +27,4 @@ describe('dangerouslySetInnerHTML', () => { expect(container.firstChild.innerHTML).toBe('

Hello

'); }); }); - - describe('when the node does not have an innerHTML property', () => { - let innerHTMLDescriptor; - - // In some versions of IE (TODO: which ones?) SVG nodes don't have - // innerHTML. To simulate this, we will take it off the Element prototype - // and put it onto the HTMLDivElement prototype. We expect that the logic - // checks for existence of innerHTML on SVG, and if one doesn't exist, falls - // back to using appendChild and removeChild. - - beforeEach(() => { - innerHTMLDescriptor = Object.getOwnPropertyDescriptor( - Element.prototype, - 'innerHTML', - ); - delete Element.prototype.innerHTML; - Object.defineProperty( - HTMLDivElement.prototype, - 'innerHTML', - innerHTMLDescriptor, - ); - }); - - afterEach(() => { - delete HTMLDivElement.prototype.innerHTML; - Object.defineProperty( - Element.prototype, - 'innerHTML', - innerHTMLDescriptor, - ); - }); - - // @gate !disableIEWorkarounds - it('sets innerHTML on it', async () => { - const html = ''; - const container = document.createElementNS( - 'http://www.w3.org/2000/svg', - 'svg', - ); - const root = ReactDOMClient.createRoot(container); - await act(() => { - root.render(); - }); - const circle = container.firstChild.firstChild; - expect(circle.tagName).toBe('circle'); - }); - - // @gate !disableIEWorkarounds - it('clears previous children', async () => { - const firstHtml = ''; - const secondHtml = ''; - - const container = document.createElementNS( - 'http://www.w3.org/2000/svg', - 'svg', - ); - const root = ReactDOMClient.createRoot(container); - await act(() => { - root.render(); - }); - const rect = container.firstChild.firstChild; - expect(rect.tagName).toBe('rect'); - await act(() => { - root.render(); - }); - const circle = container.firstChild.firstChild; - expect(circle.tagName).toBe('circle'); - }); - }); }); diff --git a/packages/react-dom/src/client/__tests__/trustedTypes-test.internal.js b/packages/react-dom/src/client/__tests__/trustedTypes-test.internal.js index abe707badd5ee..923ee1f5d81a6 100644 --- a/packages/react-dom/src/client/__tests__/trustedTypes-test.internal.js +++ b/packages/react-dom/src/client/__tests__/trustedTypes-test.internal.js @@ -206,56 +206,6 @@ describe('when Trusted Types are available in global object', () => { } }); - describe('dangerouslySetInnerHTML in svg elements in Internet Explorer', () => { - let innerHTMLDescriptor; - - // simulate svg elements in Internet Explorer which don't have 'innerHTML' property - beforeEach(() => { - innerHTMLDescriptor = Object.getOwnPropertyDescriptor( - Element.prototype, - 'innerHTML', - ); - delete Element.prototype.innerHTML; - Object.defineProperty( - HTMLDivElement.prototype, - 'innerHTML', - innerHTMLDescriptor, - ); - }); - - afterEach(() => { - delete HTMLDivElement.prototype.innerHTML; - Object.defineProperty( - Element.prototype, - 'innerHTML', - innerHTMLDescriptor, - ); - }); - - // @gate !disableIEWorkarounds - it('should log a warning', async () => { - class Component extends React.Component { - render() { - return ; - } - } - const root = ReactDOMClient.createRoot(container); - await expect(async () => { - await act(() => { - root.render(); - }); - }).toErrorDev( - "Using 'dangerouslySetInnerHTML' in an svg element with " + - 'Trusted Types enabled in an Internet Explorer will cause ' + - 'the trusted value to be converted to string. Assigning string ' + - "to 'innerHTML' will throw an error if Trusted Types are enforced. " + - "You can try to wrap your svg element inside a div and use 'dangerouslySetInnerHTML' " + - 'on the enclosing div instead.', - ); - expect(container.innerHTML).toBe('unsafe html'); - }); - }); - it('should warn once when rendering script tag in jsx on client', async () => { const root = ReactDOMClient.createRoot(container); await expect(async () => { diff --git a/packages/shared/ReactFeatureFlags.js b/packages/shared/ReactFeatureFlags.js index f8aadb9789406..edaf4b2419136 100644 --- a/packages/shared/ReactFeatureFlags.js +++ b/packages/shared/ReactFeatureFlags.js @@ -203,10 +203,6 @@ export const disableLegacyContextForFunctionComponents = true; // TODO: clean up legacy once tests pass WWW. export const useModernStrictMode = true; -// Not ready to break experimental yet. -// Remove IE and MsApp specific workarounds for innerHTML -export const disableIEWorkarounds = true; - // Filter certain DOM attributes (e.g. src, href) if their values are empty // strings. This prevents e.g. from making an unnecessary HTTP // request for certain browsers. diff --git a/packages/shared/forks/ReactFeatureFlags.native-fb.js b/packages/shared/forks/ReactFeatureFlags.native-fb.js index 37991d4c8ffbd..1ecbcfe28f5ce 100644 --- a/packages/shared/forks/ReactFeatureFlags.native-fb.js +++ b/packages/shared/forks/ReactFeatureFlags.native-fb.js @@ -36,7 +36,6 @@ export const debugRenderPhaseSideEffectsForStrictMode = __DEV__; export const disableClientCache = true; export const disableCommentsAsDOMContainers = true; export const disableDefaultPropsExceptForClasses = true; -export const disableIEWorkarounds = true; export const disableInputAttributeSyncing = false; export const disableLegacyContext = false; export const disableLegacyContextForFunctionComponents = false; diff --git a/packages/shared/forks/ReactFeatureFlags.native-oss.js b/packages/shared/forks/ReactFeatureFlags.native-oss.js index eb40dc9123752..0d97b0b68d263 100644 --- a/packages/shared/forks/ReactFeatureFlags.native-oss.js +++ b/packages/shared/forks/ReactFeatureFlags.native-oss.js @@ -23,7 +23,6 @@ export const alwaysThrottleRetries = false; export const disableClientCache = true; export const disableCommentsAsDOMContainers = true; export const disableDefaultPropsExceptForClasses = true; -export const disableIEWorkarounds = true; export const disableInputAttributeSyncing = false; export const disableLegacyContext = true; export const disableLegacyContextForFunctionComponents = true; diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.js index 6673d056d9a09..28f96fb84e6bc 100644 --- a/packages/shared/forks/ReactFeatureFlags.test-renderer.js +++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.js @@ -29,7 +29,6 @@ export const enablePostpone = false; export const enableHalt = false; export const disableCommentsAsDOMContainers = true; export const disableInputAttributeSyncing = false; -export const disableIEWorkarounds = true; export const enableScopeAPI = false; export const enableCreateEventHandleAPI = false; export const enableSuspenseCallback = false; diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js index 3ac86950277d4..fe3e2bd4813b8 100644 --- a/packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js +++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js @@ -15,7 +15,6 @@ export const debugRenderPhaseSideEffectsForStrictMode = false; export const disableClientCache = true; export const disableCommentsAsDOMContainers = true; export const disableDefaultPropsExceptForClasses = true; -export const disableIEWorkarounds = true; export const disableInputAttributeSyncing = false; export const disableLegacyContext = false; export const disableLegacyContextForFunctionComponents = false; diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js index 8ebb4d0dbf8db..1badea3abf309 100644 --- a/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js +++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js @@ -29,7 +29,6 @@ export const enablePostpone = false; export const enableHalt = false; export const disableCommentsAsDOMContainers = true; export const disableInputAttributeSyncing = false; -export const disableIEWorkarounds = true; export const enableScopeAPI = true; export const enableCreateEventHandleAPI = false; export const enableSuspenseCallback = true; diff --git a/packages/shared/forks/ReactFeatureFlags.www.js b/packages/shared/forks/ReactFeatureFlags.www.js index 7a5761932c820..2a432305635d3 100644 --- a/packages/shared/forks/ReactFeatureFlags.www.js +++ b/packages/shared/forks/ReactFeatureFlags.www.js @@ -53,7 +53,6 @@ export const enableFabricCompleteRootInCommitPhase = false; export const enableSuspenseAvoidThisFallback = true; export const enableSuspenseAvoidThisFallbackFizz = false; -export const disableIEWorkarounds = true; export const enableCPUSuspense = true; export const enableUseMemoCacheHook = true; export const enableUseEffectEventHook = true; diff --git a/scripts/jest/setupTests.www.js b/scripts/jest/setupTests.www.js index ba0ee287fd4bd..efee213861ca6 100644 --- a/scripts/jest/setupTests.www.js +++ b/scripts/jest/setupTests.www.js @@ -15,7 +15,6 @@ jest.mock('shared/ReactFeatureFlags', () => { // These are hardcoded to true for the next release, // but still run the tests against both variants until // we remove the flag. - actual.disableIEWorkarounds = __VARIANT__; actual.disableClientCache = __VARIANT__; return actual;