Land enableNewBooleanProps everywhere (#28676)
Rolled out internally. Removing flag.
Jack Pope committed
Mar 29, 2024 at 16:02 UTC
6cd6ba703de77e332ab201518b6e30e47cd49aaf
14 files changed
+74
-140
packages/react-dom-bindings/src/client/ReactDOMComponent.js
+34
-41
@@ -70,7 +70,6 @@ import {
70
disableIEWorkarounds,
71
enableTrustedTypesIntegration,
72
enableFilterEmptyStringAttributesDOM,
73
- enableNewBooleanProps,
73
} from 'shared/ReactFeatureFlags';
74
import {
75
mediaEventTypes,
@@ -668,24 +667,20 @@ function setProp(
667
break;
668
}
669
// Boolean
671
- case 'inert':
672
- if (!enableNewBooleanProps) {
673
- setValueForAttribute(domElement, key, value);
674
- break;
675
- } else {
676
- if (__DEV__) {
677
- if (value === '' && !didWarnForNewBooleanPropsWithEmptyValue[key]) {
678
- didWarnForNewBooleanPropsWithEmptyValue[key] = true;
679
- console.error(
680
- 'Received an empty string for a boolean attribute `%s`. ' +
681
- 'This will treat the attribute as if it were false. ' +
682
- 'Either pass `false` to silence this warning, or ' +
683
- 'pass `true` if you used an empty string in earlier versions of React to indicate this attribute is true.',
684
- key,
685
- );
686
- }
670
+ case 'inert': {
671
+ if (__DEV__) {
672
+ if (value === '' && !didWarnForNewBooleanPropsWithEmptyValue[key]) {
673
+ didWarnForNewBooleanPropsWithEmptyValue[key] = true;
674
+ console.error(
675
+ 'Received an empty string for a boolean attribute `%s`. ' +
676
+ 'This will treat the attribute as if it were false. ' +
677
+ 'Either pass `false` to silence this warning, or ' +
678
+ 'pass `true` if you used an empty string in earlier versions of React to indicate this attribute is true.',
679
+ key,
680
+ );
681
}
682
}
683
+ }
684
// fallthrough for new boolean props without the flag on
685
case 'allowFullScreen':
686
case 'async':
@@ -2764,32 +2759,30 @@ function diffHydratedGenericElement(
2759
);
2760
continue;
2761
case 'inert':
2767
- if (enableNewBooleanProps) {
2768
- if (__DEV__) {
2769
- if (
2770
- value === '' &&
2771
- !didWarnForNewBooleanPropsWithEmptyValue[propKey]
2772
- ) {
2773
- didWarnForNewBooleanPropsWithEmptyValue[propKey] = true;
2774
- console.error(
2775
- 'Received an empty string for a boolean attribute `%s`. ' +
2776
- 'This will treat the attribute as if it were false. ' +
2777
- 'Either pass `false` to silence this warning, or ' +
2778
- 'pass `true` if you used an empty string in earlier versions of React to indicate this attribute is true.',
2779
- propKey,
2780
- );
2781
- }
2762
+ if (__DEV__) {
2763
+ if (
2764
+ value === '' &&
2765
+ !didWarnForNewBooleanPropsWithEmptyValue[propKey]
2766
+ ) {
2767
+ didWarnForNewBooleanPropsWithEmptyValue[propKey] = true;
2768
+ console.error(
2769
+ 'Received an empty string for a boolean attribute `%s`. ' +
2770
+ 'This will treat the attribute as if it were false. ' +
2771
+ 'Either pass `false` to silence this warning, or ' +
2772
+ 'pass `true` if you used an empty string in earlier versions of React to indicate this attribute is true.',
2773
+ propKey,
2774
+ );
2775
}
2783
- hydrateBooleanAttribute(
2784
- domElement,
2785
- propKey,
2786
- propKey,
2787
- value,
2788
- extraAttributes,
2789
- serverDifferences,
2790
- );
2791
- continue;
2776
}
2777
+ hydrateBooleanAttribute(
2778
+ domElement,
2779
+ propKey,
2780
+ propKey,
2781
+ value,
2782
+ extraAttributes,
2783
+ serverDifferences,
2784
+ );
2785
+ continue;
2786
// fallthrough for new boolean props without the flag on
2787
default: {
2788
if (
packages/react-dom-bindings/src/server/ReactFizzConfigDOM.js
+18
-21
@@ -31,7 +31,6 @@ import {
31
enableBigIntSupport,
32
enableFilterEmptyStringAttributesDOM,
33
enableFizzExternalRuntime,
34
- enableNewBooleanProps,
34
} from 'shared/ReactFeatureFlags';
35
36
import type {
@@ -1423,29 +1422,27 @@ function pushAttribute(
1422
pushStringAttribute(target, 'xml:space', value);
1423
return;
1424
case 'inert': {
1426
- if (enableNewBooleanProps) {
1427
- if (__DEV__) {
1428
- if (value === '' && !didWarnForNewBooleanPropsWithEmptyValue[name]) {
1429
- didWarnForNewBooleanPropsWithEmptyValue[name] = true;
1430
- console.error(
1431
- 'Received an empty string for a boolean attribute `%s`. ' +
1432
- 'This will treat the attribute as if it were false. ' +
1433
- 'Either pass `false` to silence this warning, or ' +
1434
- 'pass `true` if you used an empty string in earlier versions of React to indicate this attribute is true.',
1435
- name,
1436
- );
1437
- }
1438
- }
1439
- // Boolean
1440
- if (value && typeof value !== 'function' && typeof value !== 'symbol') {
1441
- target.push(
1442
- attributeSeparator,
1443
- stringToChunk(name),
1444
- attributeEmptyString,
1425
+ if (__DEV__) {
1426
+ if (value === '' && !didWarnForNewBooleanPropsWithEmptyValue[name]) {
1427
+ didWarnForNewBooleanPropsWithEmptyValue[name] = true;
1428
+ console.error(
1429
+ 'Received an empty string for a boolean attribute `%s`. ' +
1430
+ 'This will treat the attribute as if it were false. ' +
1431
+ 'Either pass `false` to silence this warning, or ' +
1432
+ 'pass `true` if you used an empty string in earlier versions of React to indicate this attribute is true.',
1433
+ name,
1434
);
1435
}
1447
- return;
1436
}
1437
+ // Boolean
1438
+ if (value && typeof value !== 'function' && typeof value !== 'symbol') {
1439
+ target.push(
1440
+ attributeSeparator,
1441
+ stringToChunk(name),
1442
+ attributeEmptyString,
1443
+ );
1444
+ }
1445
+ return;
1446
}
1447
// fallthrough for new boolean props without the flag on
1448
default:
packages/react-dom-bindings/src/shared/ReactDOMUnknownPropertyHook.js
+4
-16
@@ -9,7 +9,6 @@ import {ATTRIBUTE_NAME_CHAR} from './isAttributeNameSafe';
9
import isCustomElement from './isCustomElement';
10
import possibleStandardNames from './possibleStandardNames';
11
import hasOwnProperty from 'shared/hasOwnProperty';
12
-import {enableNewBooleanProps} from 'shared/ReactFeatureFlags';
12
13
const warnedProperties = {};
14
const EVENT_NAME_REGEX = /^on./;
@@ -228,18 +227,12 @@ function validateProperty(tagName, name, value, eventRegistry) {
227
case 'seamless':
228
case 'itemScope':
229
case 'capture':
231
- case 'download': {
230
+ case 'download':
231
+ case 'inert': {
232
// Boolean properties can accept boolean values
233
return true;
234
}
235
// fallthrough
236
- case 'inert': {
237
- if (enableNewBooleanProps) {
238
- // Boolean properties can accept boolean values
239
- return true;
240
- }
241
- }
242
- // fallthrough for new boolean props without the flag on
236
default: {
237
const prefix = name.toLowerCase().slice(0, 5);
238
if (prefix === 'data-' || prefix === 'aria-') {
@@ -311,15 +304,10 @@ function validateProperty(tagName, name, value, eventRegistry) {
304
case 'reversed':
305
case 'scoped':
306
case 'seamless':
314
- case 'itemScope': {
315
- break;
316
- }
307
+ case 'itemScope':
308
case 'inert': {
318
- if (enableNewBooleanProps) {
319
- break;
320
- }
309
+ break;
310
}
322
- // fallthrough for new boolean props without the flag on
311
default: {
312
return true;
313
}
packages/react-dom-bindings/src/shared/possibleStandardNames.js
+1
-5
@@ -4,7 +4,6 @@
4
* This source code is licensed under the MIT license found in the
5
* LICENSE file in the root directory of this source tree.
6
*/
7
-import {enableNewBooleanProps} from 'shared/ReactFeatureFlags';
7
8
// When adding attributes to the HTML or SVG allowed attribute list, be sure to
9
// also add them to this module to ensure casing and incorrect name
@@ -83,6 +82,7 @@ const possibleStandardNames = {
82
id: 'id',
83
imagesizes: 'imageSizes',
84
imagesrcset: 'imageSrcSet',
85
+ inert: 'inert',
86
innerhtml: 'innerHTML',
87
inputmode: 'inputMode',
88
integrity: 'integrity',
@@ -503,8 +503,4 @@ const possibleStandardNames = {
503
zoomandpan: 'zoomAndPan',
504
};
505
506
-if (enableNewBooleanProps) {
507
- possibleStandardNames.inert = 'inert';
508
-}
509
-
506
export default possibleStandardNames;
packages/react-dom/src/__tests__/ReactDOMAttribute-test.js
+10
-24
@@ -12,14 +12,12 @@
12
describe('ReactDOM unknown attribute', () => {
13
let React;
14
let ReactDOMClient;
15
- let ReactFeatureFlags;
15
let act;
16
17
beforeEach(() => {
18
jest.resetModules();
19
React = require('react');
20
ReactDOMClient = require('react-dom/client');
22
- ReactFeatureFlags = require('shared/ReactFeatureFlags');
21
act = require('internal-test-utils').act;
22
});
23
@@ -98,15 +96,9 @@ describe('ReactDOM unknown attribute', () => {
96
await act(() => {
97
root.render(<div inert={true} />);
98
});
101
- }).toErrorDev(
102
- ReactFeatureFlags.enableNewBooleanProps
103
- ? []
104
- : ['Warning: Received `true` for a non-boolean attribute `inert`.'],
105
- );
99
+ }).toErrorDev([]);
100
107
- expect(el.firstChild.getAttribute('inert')).toBe(
108
- ReactFeatureFlags.enableNewBooleanProps ? '' : null,
109
- );
101
+ expect(el.firstChild.getAttribute('inert')).toBe(true ? '' : null);
102
});
103
104
it('warns once for empty strings in new boolean props', async () => {
@@ -117,20 +109,14 @@ describe('ReactDOM unknown attribute', () => {
109
await act(() => {
110
root.render(<div inert="" />);
111
});
120
- }).toErrorDev(
121
- ReactFeatureFlags.enableNewBooleanProps
122
- ? [
123
- 'Warning: Received an empty string for a boolean attribute `inert`. ' +
124
- 'This will treat the attribute as if it were false. ' +
125
- 'Either pass `false` to silence this warning, or ' +
126
- 'pass `true` if you used an empty string in earlier versions of React to indicate this attribute is true.',
127
- ]
128
- : [],
129
- );
130
-
131
- expect(el.firstChild.getAttribute('inert')).toBe(
132
- ReactFeatureFlags.enableNewBooleanProps ? null : '',
133
- );
112
+ }).toErrorDev([
113
+ 'Warning: Received an empty string for a boolean attribute `inert`. ' +
114
+ 'This will treat the attribute as if it were false. ' +
115
+ 'Either pass `false` to silence this warning, or ' +
116
+ 'pass `true` if you used an empty string in earlier versions of React to indicate this attribute is true.',
117
+ ]);
118
+
119
+ expect(el.firstChild.getAttribute('inert')).toBe(true ? null : '');
120
121
// The warning is only printed once.
122
await act(() => {
packages/react-dom/src/__tests__/ReactDOMServerIntegrationAttributes-test.js
+7
-19
@@ -742,36 +742,24 @@ describe('ReactDOMServerIntegration', () => {
742
});
743
744
itRenders('new boolean `true` attributes', async render => {
745
- const element = await render(
746
- <div inert={true} />,
747
- ReactFeatureFlags.enableNewBooleanProps ? 0 : 1,
748
- );
745
+ const element = await render(<div inert={true} />, 0);
746
750
- expect(element.getAttribute('inert')).toBe(
751
- ReactFeatureFlags.enableNewBooleanProps ? '' : null,
752
- );
747
+ expect(element.getAttribute('inert')).toBe('');
748
});
749
750
itRenders('new boolean `""` attributes', async render => {
751
const element = await render(
752
<div inert="" />,
758
- ReactFeatureFlags.enableNewBooleanProps
759
- ? // Warns since this used to render `inert=""` like `inert={true}`
760
- // but now renders it like `inert={false}`.
761
- 1
762
- : 0,
753
+ // Warns since this used to render `inert=""` like `inert={true}`
754
+ // but now renders it like `inert={false}`.
755
+ 1,
756
);
757
765
- expect(element.getAttribute('inert')).toBe(
766
- ReactFeatureFlags.enableNewBooleanProps ? null : '',
767
- );
758
+ expect(element.getAttribute('inert')).toBe(null);
759
});
760
761
itRenders('new boolean `false` attributes', async render => {
771
- const element = await render(
772
- <div inert={false} />,
773
- ReactFeatureFlags.enableNewBooleanProps ? 0 : 1,
774
- );
762
+ const element = await render(<div inert={false} />, 0);
763
764
expect(element.getAttribute('inert')).toBe(null);
765
});
packages/shared/ReactFeatureFlags.js
-7
@@ -183,13 +183,6 @@ export const disableLegacyMode = __NEXT_MAJOR__;
183
184
export const disableDOMTestUtils = __NEXT_MAJOR__;
185
186
-// HTML boolean attributes need a special PropertyInfoRecord.
187
-// Between support of these attributes in browsers and React supporting them as
188
-// boolean props library users can use them as `<div someBooleanAttribute="" />`.
189
-// However, once React considers them as boolean props an empty string will
190
-// result in false property i.e. break existing usage.
191
-export const enableNewBooleanProps = __NEXT_MAJOR__;
192
-
186
// Make <Context> equivalent to <Context.Provider> instead of <Context.Consumer>
187
export const enableRenderableContext = __NEXT_MAJOR__;
188
packages/shared/forks/ReactFeatureFlags.native-fb.js
-1
@@ -78,7 +78,6 @@ export const enableLazyContextPropagation = false;
78
export const enableLegacyHidden = false;
79
export const forceConcurrentByDefaultForTesting = false;
80
export const allowConcurrentByDefault = false;
81
-export const enableNewBooleanProps = true;
81
82
export const enableTransitionTracing = false;
83
packages/shared/forks/ReactFeatureFlags.native-oss.js
-1
@@ -99,7 +99,6 @@ export const enableLazyContextPropagation = false;
99
export const enableLegacyHidden = false;
100
export const forceConcurrentByDefaultForTesting = false;
101
export const allowConcurrentByDefault = false;
102
-export const enableNewBooleanProps = true;
102
export const enableTransitionTracing = false;
103
export const enableDO_NOT_USE_disableStrictPassiveEffect = false;
104
export const passChildrenWhenCloningPersistedNodes = false;
packages/shared/forks/ReactFeatureFlags.test-renderer.js
-1
@@ -92,7 +92,6 @@ export const enableBigIntSupport = __NEXT_MAJOR__;
92
export const disableLegacyMode = __NEXT_MAJOR__;
93
export const disableLegacyContext = __NEXT_MAJOR__;
94
export const disableDOMTestUtils = __NEXT_MAJOR__;
95
-export const enableNewBooleanProps = __NEXT_MAJOR__;
95
export const enableRenderableContext = __NEXT_MAJOR__;
96
export const enableReactTestRendererWarning = __NEXT_MAJOR__;
97
packages/shared/forks/ReactFeatureFlags.test-renderer.native.js
-1
@@ -59,7 +59,6 @@ export const enableLegacyHidden = false;
59
export const forceConcurrentByDefaultForTesting = false;
60
export const enableUnifiedSyncLane = true;
61
export const allowConcurrentByDefault = true;
62
-export const enableNewBooleanProps = true;
62
63
export const consoleManagedByDevToolsDuringStrictMode = false;
64
packages/shared/forks/ReactFeatureFlags.test-renderer.www.js
-1
@@ -59,7 +59,6 @@ export const enableLegacyHidden = false;
59
export const forceConcurrentByDefaultForTesting = false;
60
export const enableUnifiedSyncLane = true;
61
export const allowConcurrentByDefault = true;
62
-export const enableNewBooleanProps = false;
62
63
export const consoleManagedByDevToolsDuringStrictMode = false;
64
packages/shared/forks/ReactFeatureFlags.www-dynamic.js
-1
@@ -30,7 +30,6 @@ export const enableUseDeferredValueInitialArg = __VARIANT__;
30
export const enableRenderableContext = __VARIANT__;
31
export const useModernStrictMode = __VARIANT__;
32
export const enableRefAsProp = __VARIANT__;
33
-export const enableNewBooleanProps = __VARIANT__;
33
export const enableRetryLaneExpiration = __VARIANT__;
34
export const favorSafetyOverHydrationPerf = __VARIANT__;
35
export const retryLaneExpirationMs = 5000;
packages/shared/forks/ReactFeatureFlags.www.js
-1
@@ -38,7 +38,6 @@ export const {
38
enableRenderableContext,
39
useModernStrictMode,
40
enableRefAsProp,
41
- enableNewBooleanProps,
41
favorSafetyOverHydrationPerf,
42
} = dynamicFeatureFlags;
43