diff --git a/fixtures/attribute-behavior/AttributeTableSnapshot.md b/fixtures/attribute-behavior/AttributeTableSnapshot.md index f3a8ebfde9923..220cbd0d3ed51 100644 --- a/fixtures/attribute-behavior/AttributeTableSnapshot.md +++ b/fixtures/attribute-behavior/AttributeTableSnapshot.md @@ -4926,21 +4926,21 @@ ## `hidden` (on `
` inside `
`) | Test Case | Flags | Result | | --- | --- | --- | -| `hidden=(string)`| (changed)| `` | -| `hidden=(empty string)`| (initial)| `` | -| `hidden=(array with string)`| (changed)| `` | +| `hidden=(string)`| (changed)| `"until-found"` | +| `hidden=(empty string)`| (changed)| `` | +| `hidden=(array with string)`| (changed)| `"until-found"` | | `hidden=(empty array)`| (changed)| `` | | `hidden=(object)`| (changed)| `` | | `hidden=(numeric string)`| (changed)| `` | | `hidden=(-1)`| (changed)| `` | -| `hidden=(0)`| (initial)| `` | +| `hidden=(0)`| (changed)| `` | | `hidden=(integer)`| (changed)| `` | -| `hidden=(NaN)`| (initial, warning)| `` | +| `hidden=(NaN)`| (changed, warning)| `` | | `hidden=(float)`| (changed)| `` | | `hidden=(true)`| (changed)| `` | | `hidden=(false)`| (initial)| `` | -| `hidden=(string 'true')`| (changed, warning)| `` | -| `hidden=(string 'false')`| (changed, warning)| `` | +| `hidden=(string 'true')`| (changed)| `` | +| `hidden=(string 'false')`| (changed)| `` | | `hidden=(string 'on')`| (changed)| `` | | `hidden=(string 'off')`| (changed)| `` | | `hidden=(symbol)`| (initial, warning)| `` | diff --git a/packages/react-dom-bindings/src/client/ReactDOMComponent.js b/packages/react-dom-bindings/src/client/ReactDOMComponent.js index 24462c1d2bb5a..a33db152b3bd3 100644 --- a/packages/react-dom-bindings/src/client/ReactDOMComponent.js +++ b/packages/react-dom-bindings/src/client/ReactDOMComponent.js @@ -78,6 +78,7 @@ import { mediaEventTypes, listenToNonDelegatedEvent, } from '../events/DOMPluginEventSystem'; +import {enableNewDOMProps} from '../../../shared/ReactFeatureFlags'; let didWarnControlledToUncontrolled = false; let didWarnUncontrolledToControlled = false; @@ -722,7 +723,6 @@ function setProp( case 'disablePictureInPicture': case 'disableRemotePlayback': case 'formNoValidate': - case 'hidden': case 'loop': case 'noModule': case 'noValidate': @@ -742,6 +742,16 @@ function setProp( break; } // Overloaded Boolean + case 'hidden': + if (!enableNewDOMProps) { + if (value && typeof value !== 'function' && typeof value !== 'symbol') { + domElement.setAttribute(key, ''); + } else { + domElement.removeAttribute(key); + } + break; + } + // fallthrough to overloaded boolean with enableNewDOMProps case 'capture': case 'download': { // An attribute that can be used as a flag as well as with a value. @@ -2507,7 +2517,6 @@ function diffHydratedGenericElement( case 'disablePictureInPicture': case 'disableRemotePlayback': case 'formNoValidate': - case 'hidden': case 'loop': case 'noModule': case 'noValidate': @@ -2529,6 +2538,19 @@ function diffHydratedGenericElement( ); continue; } + case 'hidden': + if (!enableNewDOMProps) { + // Some of these need to be lower case to remove them from the extraAttributes list. + hydrateBooleanAttribute( + domElement, + propKey, + propKey.toLowerCase(), + value, + extraAttributes, + ); + continue; + } + // fallthrough to overloaded boolean with enableNewDOMProps case 'capture': case 'download': { hydrateOverloadedBooleanAttribute( diff --git a/packages/react-dom-bindings/src/events/DOMEventNames.js b/packages/react-dom-bindings/src/events/DOMEventNames.js index 9145e316f9d1f..9ba08d742a937 100644 --- a/packages/react-dom-bindings/src/events/DOMEventNames.js +++ b/packages/react-dom-bindings/src/events/DOMEventNames.js @@ -18,6 +18,7 @@ export type DOMEventName = // 'animationstart' | | 'beforeblur' // Not a real event. This is used by event experiments. | 'beforeinput' + | 'beforematch' | 'blur' | 'canplay' | 'canplaythrough' diff --git a/packages/react-dom-bindings/src/events/DOMEventProperties.js b/packages/react-dom-bindings/src/events/DOMEventProperties.js index 55b3c4f987186..72e928a021a3f 100644 --- a/packages/react-dom-bindings/src/events/DOMEventProperties.js +++ b/packages/react-dom-bindings/src/events/DOMEventProperties.js @@ -34,6 +34,7 @@ export const topLevelEventsToReactNames: Map = const simpleEventPluginEvents = [ 'abort', 'auxClick', + 'beforematch', 'cancel', 'canPlay', 'canPlayThrough', diff --git a/packages/react-dom-bindings/src/events/ReactDOMEventListener.js b/packages/react-dom-bindings/src/events/ReactDOMEventListener.js index 237cde231176b..578e98700fffc 100644 --- a/packages/react-dom-bindings/src/events/ReactDOMEventListener.js +++ b/packages/react-dom-bindings/src/events/ReactDOMEventListener.js @@ -53,6 +53,7 @@ import { } from 'react-reconciler/src/ReactEventPriorities'; import ReactSharedInternals from 'shared/ReactSharedInternals'; import {isRootDehydrated} from 'react-reconciler/src/ReactFiberShellHydration'; +import {enableNewDOMProps} from 'shared/ReactFeatureFlags'; const {ReactCurrentBatchConfig} = ReactSharedInternals; @@ -386,6 +387,11 @@ export function getEventPriority(domEventName: DOMEventName): EventPriority { return DefaultEventPriority; } } + case 'beforematch': + if (enableNewDOMProps) { + return DiscreteEventPriority; + } + // fall through without enableNewDOMProps default: return DefaultEventPriority; } diff --git a/packages/react-dom-bindings/src/server/ReactFizzConfigDOM.js b/packages/react-dom-bindings/src/server/ReactFizzConfigDOM.js index a469b5587d79a..8f3a5dd7b9c96 100644 --- a/packages/react-dom-bindings/src/server/ReactFizzConfigDOM.js +++ b/packages/react-dom-bindings/src/server/ReactFizzConfigDOM.js @@ -34,6 +34,7 @@ import { enableFloat, enableFormActions, enableFizzExternalRuntime, + enableNewDOMProps, } from 'shared/ReactFeatureFlags'; import type { @@ -1290,7 +1291,6 @@ function pushAttribute( case 'disablePictureInPicture': case 'disableRemotePlayback': case 'formNoValidate': - case 'hidden': case 'loop': case 'noModule': case 'noValidate': @@ -1312,6 +1312,18 @@ function pushAttribute( } return; } + case 'hidden': + if (!enableNewDOMProps) { + // Boolean + if (value && typeof value !== 'function' && typeof value !== 'symbol') { + target.push( + attributeSeparator, + stringToChunk(name), + attributeEmptyString, + ); + } + } + // fallthrough to overloaded boolean with enableNewDOMProps case 'capture': case 'download': { // Overloaded Boolean @@ -4994,7 +5006,16 @@ function writeStyleResourceAttributeInJS( if (value === false) { return; } - attributeValue = ''; + if (enableNewDOMProps) { + // overloaded Boolean + if (__DEV__) { + checkAttributeStringCoercion(value, attributeName); + } + attributeValue = '' + (value: any); + } else { + // just Boolean + attributeValue = ''; + } break; } // Santized URLs @@ -5189,7 +5210,16 @@ function writeStyleResourceAttributeInAttr( if (value === false) { return; } - attributeValue = ''; + if (enableNewDOMProps) { + // overloaded Boolean + if (__DEV__) { + checkAttributeStringCoercion(value, attributeName); + } + attributeValue = '' + (value: any); + } else { + // just Boolean + attributeValue = ''; + } break; } diff --git a/packages/react-dom-bindings/src/shared/ReactDOMUnknownPropertyHook.js b/packages/react-dom-bindings/src/shared/ReactDOMUnknownPropertyHook.js index 3dbb1d8e2c315..4ef0397b180b0 100644 --- a/packages/react-dom-bindings/src/shared/ReactDOMUnknownPropertyHook.js +++ b/packages/react-dom-bindings/src/shared/ReactDOMUnknownPropertyHook.js @@ -12,6 +12,7 @@ import hasOwnProperty from 'shared/hasOwnProperty'; import { enableCustomElementPropertySupport, enableFormActions, + enableNewDOMProps, } from 'shared/ReactFeatureFlags'; const warnedProperties = {}; @@ -300,7 +301,6 @@ function validateProperty(tagName, name, value, eventRegistry) { case 'disablePictureInPicture': case 'disableRemotePlayback': case 'formNoValidate': - case 'hidden': case 'loop': case 'noModule': case 'noValidate': @@ -314,6 +314,12 @@ function validateProperty(tagName, name, value, eventRegistry) { case 'itemScope': { break; } + case 'hidden': { + if (!enableNewDOMProps) { + break; + } + } + // fallthrough to overloaded boolean with enableNewDOMProps default: { return true; } diff --git a/packages/react-dom/src/__tests__/ReactDOMComponent-test.js b/packages/react-dom/src/__tests__/ReactDOMComponent-test.js index 6541293f51333..a41a1213a0a29 100644 --- a/packages/react-dom/src/__tests__/ReactDOMComponent-test.js +++ b/packages/react-dom/src/__tests__/ReactDOMComponent-test.js @@ -3452,15 +3452,15 @@ describe('ReactDOMComponent', () => { const root = ReactDOMClient.createRoot(container); await act(() => { - root.render(