Put common aliases in Map/Set instead of switch over strings (#26551)
This is a follow up to https://github.com/facebook/react/pull/26546 This is strictly a perf optimization since we know that switches over strings aren't optimally implemented in current engines. Basically they're a sequence of ifs. As a result, we're better off putting the unusual cases in a Map and the very common cases in the beginning of the switch. We might be better off putting very common cases in explicit ifs - just in case the engine does optimize switches to a hash table which is potentially worse. --------- Co-authored-by: Sophie Alpert <git@sophiebits.com>
Sebastian Markbåge committed
Apr 4, 2023 at 18:06 UTC
c15579631ff4d387401d57d9006d849ca1d5cd71
5 files changed
+492
-1447
packages/react-dom-bindings/src/client/DOMPropertyOperations.js
+27
@@ -140,6 +140,33 @@ export function setValueForAttribute(
140
}
141
}
142
143
+export function setValueForKnownAttribute(
144
+ node: Element,
145
+ name: string,
146
+ value: mixed,
147
+) {
148
+ if (value === null) {
149
+ node.removeAttribute(name);
150
+ return;
151
+ }
152
+ switch (typeof value) {
153
+ case 'undefined':
154
+ case 'function':
155
+ case 'symbol':
156
+ case 'boolean': {
157
+ node.removeAttribute(name);
158
+ return;
159
+ }
160
+ }
161
+ if (__DEV__) {
162
+ checkAttributeStringCoercion(value, name);
163
+ }
164
+ node.setAttribute(
165
+ name,
166
+ enableTrustedTypesIntegration ? (value: any) : '' + (value: any),
167
+ );
168
+}
169
+
170
export function setValueForNamespacedAttribute(
171
node: Element,
172
namespace: string,
packages/react-dom-bindings/src/client/ReactDOMComponent.js
+236
-1097
@@ -22,6 +22,7 @@ import {
22
getValueForAttribute,
23
getValueForAttributeOnCustomComponent,
24
setValueForPropertyOnCustomComponent,
25
+ setValueForKnownAttribute,
26
setValueForAttribute,
27
setValueForNamespacedAttribute,
28
} from './DOMPropertyOperations';
@@ -58,6 +59,7 @@ import {
59
} from './CSSPropertyOperations';
60
import {HTML_NAMESPACE, getIntrinsicNamespace} from './DOMNamespaces';
61
import isCustomElement from '../shared/isCustomElement';
62
+import getAttributeAlias from '../shared/getAttributeAlias';
63
import possibleStandardNames from '../shared/possibleStandardNames';
64
import {validateProperties as validateARIAProperties} from '../shared/ReactDOMInvalidARIAHook';
65
import {validateProperties as validateInputProperties} from '../shared/ReactDOMNullInputValuePropHook';
@@ -275,35 +277,6 @@ function setProp(
277
props: any,
278
): void {
279
switch (key) {
278
- case 'style': {
279
- setValueForStyles(domElement, value);
280
- break;
281
- }
282
- case 'dangerouslySetInnerHTML': {
283
- if (value != null) {
284
- if (typeof value !== 'object' || !('__html' in value)) {
285
- throw new Error(
286
- '`props.dangerouslySetInnerHTML` must be in the form `{__html: ...}`. ' +
287
- 'Please visit https://reactjs.org/link/dangerously-set-inner-html ' +
288
- 'for more information.',
289
- );
290
- }
291
- const nextHtml: any = value.__html;
292
- if (nextHtml != null) {
293
- if (props.children != null) {
294
- throw new Error(
295
- 'Can only set one of `children` or `props.dangerouslySetInnerHTML`.',
296
- );
297
- }
298
- if (disableIEWorkarounds) {
299
- domElement.innerHTML = nextHtml;
300
- } else {
301
- setInnerHTML(domElement, nextHtml);
302
- }
303
- }
304
- }
305
- break;
306
- }
280
case 'children': {
281
if (typeof value === 'string') {
282
// Avoid setting initial textContent when the text is empty. In IE11 setting
@@ -324,50 +297,26 @@ function setProp(
297
}
298
break;
299
}
327
- case 'onScroll': {
328
- if (value != null) {
329
- if (__DEV__ && typeof value !== 'function') {
330
- warnForInvalidEventListener(key, value);
331
- }
332
- listenToNonDelegatedEvent('scroll', domElement);
333
- }
334
- break;
335
- }
336
- case 'onClick': {
337
- // TODO: This cast may not be sound for SVG, MathML or custom elements.
338
- if (value != null) {
339
- if (__DEV__ && typeof value !== 'function') {
340
- warnForInvalidEventListener(key, value);
341
- }
342
- trapClickOnNonInteractiveElement(((domElement: any): HTMLElement));
343
- }
344
- break;
345
- }
346
- // Note: `option.selected` is not updated if `select.multiple` is
347
- // disabled with `removeAttribute`. We have special logic for handling this.
348
- case 'multiple': {
349
- (domElement: any).multiple =
350
- value && typeof value !== 'function' && typeof value !== 'symbol';
300
+ // These are very common props and therefore are in the beginning of the switch.
301
+ // TODO: aria-label is a very common prop but allows booleans so is not like the others
302
+ // but should ideally go in this list too.
303
+ case 'className':
304
+ setValueForKnownAttribute(domElement, 'class', value);
305
break;
352
- }
353
- case 'muted': {
354
- (domElement: any).muted =
355
- value && typeof value !== 'function' && typeof value !== 'symbol';
306
+ case 'tabIndex':
307
+ // This has to be case sensitive in SVG.
308
+ setValueForKnownAttribute(domElement, 'tabindex', value);
309
break;
357
- }
358
- case 'suppressContentEditableWarning':
359
- case 'suppressHydrationWarning':
360
- case 'defaultValue': // Reserved
361
- case 'defaultChecked':
362
- case 'innerHTML': {
363
- // Noop
310
+ case 'dir':
311
+ case 'role':
312
+ case 'viewBox':
313
+ case 'width':
314
+ case 'height': {
315
+ setValueForKnownAttribute(domElement, key, value);
316
break;
317
}
366
- case 'autoFocus': {
367
- // We polyfill it separately on the client during commit.
368
- // We could have excluded it in the property list instead of
369
- // adding a special case here, but then it wouldn't be emitted
370
- // on server rendering (but we *do* want to emit it in SSR).
318
+ case 'style': {
319
+ setValueForStyles(domElement, value);
320
break;
321
}
322
// These attributes accept URLs. These must not allow javascript: URLS.
@@ -423,6 +372,77 @@ function setProp(
372
domElement.setAttribute(key, sanitizedValue);
373
break;
374
}
375
+ case 'onClick': {
376
+ // TODO: This cast may not be sound for SVG, MathML or custom elements.
377
+ if (value != null) {
378
+ if (__DEV__ && typeof value !== 'function') {
379
+ warnForInvalidEventListener(key, value);
380
+ }
381
+ trapClickOnNonInteractiveElement(((domElement: any): HTMLElement));
382
+ }
383
+ break;
384
+ }
385
+ case 'onScroll': {
386
+ if (value != null) {
387
+ if (__DEV__ && typeof value !== 'function') {
388
+ warnForInvalidEventListener(key, value);
389
+ }
390
+ listenToNonDelegatedEvent('scroll', domElement);
391
+ }
392
+ break;
393
+ }
394
+ case 'dangerouslySetInnerHTML': {
395
+ if (value != null) {
396
+ if (typeof value !== 'object' || !('__html' in value)) {
397
+ throw new Error(
398
+ '`props.dangerouslySetInnerHTML` must be in the form `{__html: ...}`. ' +
399
+ 'Please visit https://reactjs.org/link/dangerously-set-inner-html ' +
400
+ 'for more information.',
401
+ );
402
+ }
403
+ const nextHtml: any = value.__html;
404
+ if (nextHtml != null) {
405
+ if (props.children != null) {
406
+ throw new Error(
407
+ 'Can only set one of `children` or `props.dangerouslySetInnerHTML`.',
408
+ );
409
+ }
410
+ if (disableIEWorkarounds) {
411
+ domElement.innerHTML = nextHtml;
412
+ } else {
413
+ setInnerHTML(domElement, nextHtml);
414
+ }
415
+ }
416
+ }
417
+ break;
418
+ }
419
+ // Note: `option.selected` is not updated if `select.multiple` is
420
+ // disabled with `removeAttribute`. We have special logic for handling this.
421
+ case 'multiple': {
422
+ (domElement: any).multiple =
423
+ value && typeof value !== 'function' && typeof value !== 'symbol';
424
+ break;
425
+ }
426
+ case 'muted': {
427
+ (domElement: any).muted =
428
+ value && typeof value !== 'function' && typeof value !== 'symbol';
429
+ break;
430
+ }
431
+ case 'suppressContentEditableWarning':
432
+ case 'suppressHydrationWarning':
433
+ case 'defaultValue': // Reserved
434
+ case 'defaultChecked':
435
+ case 'innerHTML': {
436
+ // Noop
437
+ break;
438
+ }
439
+ case 'autoFocus': {
440
+ // We polyfill it separately on the client during commit.
441
+ // We could have excluded it in the property list instead of
442
+ // adding a special case here, but then it wouldn't be emitted
443
+ // on server rendering (but we *do* want to emit it in SSR).
444
+ break;
445
+ }
446
case 'xlinkHref': {
447
if (
448
value == null ||
@@ -565,251 +585,6 @@ function setProp(
585
}
586
break;
587
}
568
- // A few React string attributes have a different name.
569
- // This is a mapping from React prop names to the attribute names.
570
- case 'acceptCharset':
571
- setValueForAttribute(domElement, 'accept-charset', value);
572
- break;
573
- case 'className':
574
- setValueForAttribute(domElement, 'class', value);
575
- break;
576
- case 'htmlFor':
577
- setValueForAttribute(domElement, 'for', value);
578
- break;
579
- case 'httpEquiv':
580
- setValueForAttribute(domElement, 'http-equiv', value);
581
- break;
582
- // HTML and SVG attributes, but the SVG attribute is case sensitive.
583
- case 'tabIndex':
584
- setValueForAttribute(domElement, 'tabindex', value);
585
- break;
586
- case 'crossOrigin':
587
- setValueForAttribute(domElement, 'crossorigin', value);
588
- break;
589
- // This is a list of all SVG attributes that need special casing.
590
- // Regular attributes that just accept strings.
591
- case 'accentHeight':
592
- setValueForAttribute(domElement, 'accent-height', value);
593
- break;
594
- case 'alignmentBaseline':
595
- setValueForAttribute(domElement, 'alignment-baseline', value);
596
- break;
597
- case 'arabicForm':
598
- setValueForAttribute(domElement, 'arabic-form', value);
599
- break;
600
- case 'baselineShift':
601
- setValueForAttribute(domElement, 'baseline-shift', value);
602
- break;
603
- case 'capHeight':
604
- setValueForAttribute(domElement, 'cap-height', value);
605
- break;
606
- case 'clipPath':
607
- setValueForAttribute(domElement, 'clip-path', value);
608
- break;
609
- case 'clipRule':
610
- setValueForAttribute(domElement, 'clip-rule', value);
611
- break;
612
- case 'colorInterpolation':
613
- setValueForAttribute(domElement, 'color-interpolation', value);
614
- break;
615
- case 'colorInterpolationFilters':
616
- setValueForAttribute(domElement, 'color-interpolation-filters', value);
617
- break;
618
- case 'colorProfile':
619
- setValueForAttribute(domElement, 'color-profile', value);
620
- break;
621
- case 'colorRendering':
622
- setValueForAttribute(domElement, 'color-rendering', value);
623
- break;
624
- case 'dominantBaseline':
625
- setValueForAttribute(domElement, 'dominant-baseline', value);
626
- break;
627
- case 'enableBackground':
628
- setValueForAttribute(domElement, 'enable-background', value);
629
- break;
630
- case 'fillOpacity':
631
- setValueForAttribute(domElement, 'fill-opacity', value);
632
- break;
633
- case 'fillRule':
634
- setValueForAttribute(domElement, 'fill-rule', value);
635
- break;
636
- case 'floodColor':
637
- setValueForAttribute(domElement, 'flood-color', value);
638
- break;
639
- case 'floodOpacity':
640
- setValueForAttribute(domElement, 'flood-opacity', value);
641
- break;
642
- case 'fontFamily':
643
- setValueForAttribute(domElement, 'font-family', value);
644
- break;
645
- case 'fontSize':
646
- setValueForAttribute(domElement, 'font-size', value);
647
- break;
648
- case 'fontSizeAdjust':
649
- setValueForAttribute(domElement, 'font-size-adjust', value);
650
- break;
651
- case 'fontStretch':
652
- setValueForAttribute(domElement, 'font-stretch', value);
653
- break;
654
- case 'fontStyle':
655
- setValueForAttribute(domElement, 'font-style', value);
656
- break;
657
- case 'fontVariant':
658
- setValueForAttribute(domElement, 'font-variant', value);
659
- break;
660
- case 'fontWeight':
661
- setValueForAttribute(domElement, 'font-weight', value);
662
- break;
663
- case 'glyphName':
664
- setValueForAttribute(domElement, 'glyph-name', value);
665
- break;
666
- case 'glyphOrientationHorizontal':
667
- setValueForAttribute(domElement, 'glyph-orientation-horizontal', value);
668
- break;
669
- case 'glyphOrientationVertical':
670
- setValueForAttribute(domElement, 'glyph-orientation-vertical', value);
671
- break;
672
- case 'horizAdvX':
673
- setValueForAttribute(domElement, 'horiz-adv-x', value);
674
- break;
675
- case 'horizOriginX':
676
- setValueForAttribute(domElement, 'horiz-origin-x', value);
677
- break;
678
- case 'imageRendering':
679
- setValueForAttribute(domElement, 'image-rendering', value);
680
- break;
681
- case 'letterSpacing':
682
- setValueForAttribute(domElement, 'letter-spacing', value);
683
- break;
684
- case 'lightingColor':
685
- setValueForAttribute(domElement, 'lighting-color', value);
686
- break;
687
- case 'markerEnd':
688
- setValueForAttribute(domElement, 'marker-end', value);
689
- break;
690
- case 'markerMid':
691
- setValueForAttribute(domElement, 'marker-mid', value);
692
- break;
693
- case 'markerStart':
694
- setValueForAttribute(domElement, 'marker-start', value);
695
- break;
696
- case 'overlinePosition':
697
- setValueForAttribute(domElement, 'overline-position', value);
698
- break;
699
- case 'overlineThickness':
700
- setValueForAttribute(domElement, 'overline-thickness', value);
701
- break;
702
- case 'paintOrder':
703
- setValueForAttribute(domElement, 'paint-order', value);
704
- break;
705
- case 'panose-1':
706
- setValueForAttribute(domElement, 'panose-1', value);
707
- break;
708
- case 'pointerEvents':
709
- setValueForAttribute(domElement, 'pointer-events', value);
710
- break;
711
- case 'renderingIntent':
712
- setValueForAttribute(domElement, 'rendering-intent', value);
713
- break;
714
- case 'shapeRendering':
715
- setValueForAttribute(domElement, 'shape-rendering', value);
716
- break;
717
- case 'stopColor':
718
- setValueForAttribute(domElement, 'stop-color', value);
719
- break;
720
- case 'stopOpacity':
721
- setValueForAttribute(domElement, 'stop-opacity', value);
722
- break;
723
- case 'strikethroughPosition':
724
- setValueForAttribute(domElement, 'strikethrough-position', value);
725
- break;
726
- case 'strikethroughThickness':
727
- setValueForAttribute(domElement, 'strikethrough-thickness', value);
728
- break;
729
- case 'strokeDasharray':
730
- setValueForAttribute(domElement, 'stroke-dasharray', value);
731
- break;
732
- case 'strokeDashoffset':
733
- setValueForAttribute(domElement, 'stroke-dashoffset', value);
734
- break;
735
- case 'strokeLinecap':
736
- setValueForAttribute(domElement, 'stroke-linecap', value);
737
- break;
738
- case 'strokeLinejoin':
739
- setValueForAttribute(domElement, 'stroke-linejoin', value);
740
- break;
741
- case 'strokeMiterlimit':
742
- setValueForAttribute(domElement, 'stroke-miterlimit', value);
743
- break;
744
- case 'strokeOpacity':
745
- setValueForAttribute(domElement, 'stroke-opacity', value);
746
- break;
747
- case 'strokeWidth':
748
- setValueForAttribute(domElement, 'stroke-width', value);
749
- break;
750
- case 'textAnchor':
751
- setValueForAttribute(domElement, 'text-anchor', value);
752
- break;
753
- case 'textDecoration':
754
- setValueForAttribute(domElement, 'text-decoration', value);
755
- break;
756
- case 'textRendering':
757
- setValueForAttribute(domElement, 'text-rendering', value);
758
- break;
759
- case 'transformOrigin':
760
- setValueForAttribute(domElement, 'transform-origin', value);
761
- break;
762
- case 'underlinePosition':
763
- setValueForAttribute(domElement, 'underline-position', value);
764
- break;
765
- case 'underlineThickness':
766
- setValueForAttribute(domElement, 'underline-thickness', value);
767
- break;
768
- case 'unicodeBidi':
769
- setValueForAttribute(domElement, 'unicode-bidi', value);
770
- break;
771
- case 'unicodeRange':
772
- setValueForAttribute(domElement, 'unicode-range', value);
773
- break;
774
- case 'unitsPerEm':
775
- setValueForAttribute(domElement, 'units-per-em', value);
776
- break;
777
- case 'vAlphabetic':
778
- setValueForAttribute(domElement, 'v-alphabetic', value);
779
- break;
780
- case 'vHanging':
781
- setValueForAttribute(domElement, 'v-hanging', value);
782
- break;
783
- case 'vIdeographic':
784
- setValueForAttribute(domElement, 'v-ideographic', value);
785
- break;
786
- case 'vMathematical':
787
- setValueForAttribute(domElement, 'v-mathematical', value);
788
- break;
789
- case 'vectorEffect':
790
- setValueForAttribute(domElement, 'vector-effect', value);
791
- break;
792
- case 'vertAdvY':
793
- setValueForAttribute(domElement, 'vert-adv-y', value);
794
- break;
795
- case 'vertOriginX':
796
- setValueForAttribute(domElement, 'vert-origin-x', value);
797
- break;
798
- case 'vertOriginY':
799
- setValueForAttribute(domElement, 'vert-origin-y', value);
800
- break;
801
- case 'wordSpacing':
802
- setValueForAttribute(domElement, 'word-spacing', value);
803
- break;
804
- case 'writingMode':
805
- setValueForAttribute(domElement, 'writing-mode', value);
806
- break;
807
- case 'xmlnsXlink':
808
- setValueForAttribute(domElement, 'xmlns:xlink', value);
809
- break;
810
- case 'xHeight':
811
- setValueForAttribute(domElement, 'x-height', value);
812
- break;
588
case 'xlinkActuate':
589
setValueForNamespacedAttribute(
590
domElement,
@@ -904,7 +679,8 @@ function setProp(
679
warnForInvalidEventListener(key, value);
680
}
681
} else {
907
- setValueForAttribute(domElement, key, value);
682
+ const attributeName = getAttributeAlias(key);
683
+ setValueForAttribute(domElement, attributeName, value);
684
}
685
}
686
}
@@ -1018,6 +794,17 @@ export function setInitialProperties(
794
// TODO: Make sure that we check isMounted before firing any of these events.
795
796
switch (tag) {
797
+ case 'div':
798
+ case 'span':
799
+ case 'svg':
800
+ case 'path':
801
+ case 'a':
802
+ case 'g':
803
+ case 'p':
804
+ case 'li': {
805
+ // Fast track the most common tag types
806
+ break;
807
+ }
808
case 'input': {
809
ReactDOMInputInitWrapperState(domElement, props);
810
// We listen to this event in case to ensure emulated bubble
@@ -1032,6 +819,21 @@ export function setInitialProperties(
819
continue;
820
}
821
switch (propKey) {
822
+ case 'type': {
823
+ // Fast path since 'type' is very common on inputs
824
+ if (
825
+ propValue != null &&
826
+ typeof propValue !== 'function' &&
827
+ typeof propValue !== 'symbol' &&
828
+ typeof propValue !== 'boolean'
829
+ ) {
830
+ if (__DEV__) {
831
+ checkAttributeStringCoercion(propValue, propKey);
832
+ }
833
+ domElement.setAttribute(propKey, propValue);
834
+ }
835
+ break;
836
+ }
837
case 'checked': {
838
const node = ((domElement: any): InputWithWrapperState);
839
const checked =
@@ -1246,30 +1048,32 @@ export function setInitialProperties(
1048
}
1049
return;
1050
}
1051
+ default: {
1052
+ if (isCustomElement(tag, props)) {
1053
+ for (const propKey in props) {
1054
+ if (!props.hasOwnProperty(propKey)) {
1055
+ continue;
1056
+ }
1057
+ const propValue = props[propKey];
1058
+ if (propValue == null) {
1059
+ continue;
1060
+ }
1061
+ setPropOnCustomElement(domElement, tag, propKey, propValue, props);
1062
+ }
1063
+ return;
1064
+ }
1065
+ }
1066
}
1067
1251
- if (isCustomElement(tag, props)) {
1252
- for (const propKey in props) {
1253
- if (!props.hasOwnProperty(propKey)) {
1254
- continue;
1255
- }
1256
- const propValue = props[propKey];
1257
- if (propValue == null) {
1258
- continue;
1259
- }
1260
- setPropOnCustomElement(domElement, tag, propKey, propValue, props);
1068
+ for (const propKey in props) {
1069
+ if (!props.hasOwnProperty(propKey)) {
1070
+ continue;
1071
}
1262
- } else {
1263
- for (const propKey in props) {
1264
- if (!props.hasOwnProperty(propKey)) {
1265
- continue;
1266
- }
1267
- const propValue = props[propKey];
1268
- if (propValue == null) {
1269
- continue;
1270
- }
1271
- setProp(domElement, tag, propKey, propValue, props);
1072
+ const propValue = props[propKey];
1073
+ if (propValue == null) {
1074
+ continue;
1075
}
1076
+ setProp(domElement, tag, propKey, propValue, props);
1077
}
1078
}
1079
@@ -1395,7 +1199,18 @@ export function updateProperties(
1199
nextProps: Object,
1200
): void {
1201
switch (tag) {
1398
- case 'input': {
1202
+ case 'div':
1203
+ case 'span':
1204
+ case 'svg':
1205
+ case 'path':
1206
+ case 'a':
1207
+ case 'g':
1208
+ case 'p':
1209
+ case 'li': {
1210
+ // Fast track the most common tag types
1211
+ break;
1212
+ }
1213
+ case 'input': {
1214
// Update checked *before* name.
1215
// In the middle of an update, it is possible to have multiple checked.
1216
// When a checked radio tries to change name, browser makes another radio's checked false.
@@ -1552,21 +1367,29 @@ export function updateProperties(
1367
}
1368
return;
1369
}
1370
+ default: {
1371
+ if (isCustomElement(tag, nextProps)) {
1372
+ for (let i = 0; i < updatePayload.length; i += 2) {
1373
+ const propKey = updatePayload[i];
1374
+ const propValue = updatePayload[i + 1];
1375
+ setPropOnCustomElement(
1376
+ domElement,
1377
+ tag,
1378
+ propKey,
1379
+ propValue,
1380
+ nextProps,
1381
+ );
1382
+ }
1383
+ return;
1384
+ }
1385
+ }
1386
}
1387
1388
// Apply the diff.
1558
- if (isCustomElement(tag, nextProps)) {
1559
- for (let i = 0; i < updatePayload.length; i += 2) {
1560
- const propKey = updatePayload[i];
1561
- const propValue = updatePayload[i + 1];
1562
- setPropOnCustomElement(domElement, tag, propKey, propValue, nextProps);
1563
- }
1564
- } else {
1565
- for (let i = 0; i < updatePayload.length; i += 2) {
1566
- const propKey = updatePayload[i];
1567
- const propValue = updatePayload[i + 1];
1568
- setProp(domElement, tag, propKey, propValue, nextProps);
1569
- }
1389
+ for (let i = 0; i < updatePayload.length; i += 2) {
1390
+ const propKey = updatePayload[i];
1391
+ const propValue = updatePayload[i + 1];
1392
+ setProp(domElement, tag, propKey, propValue, nextProps);
1393
}
1394
}
1395
@@ -2048,6 +1871,18 @@ function diffHydratedGenericElement(
1871
warnForPropDifference(propKey, serverHTML, expectedHTML);
1872
}
1873
continue;
1874
+ case 'className':
1875
+ hydrateAttribute(domElement, propKey, 'class', value, extraAttributes);
1876
+ continue;
1877
+ case 'tabIndex':
1878
+ hydrateAttribute(
1879
+ domElement,
1880
+ propKey,
1881
+ 'tabindex',
1882
+ value,
1883
+ extraAttributes,
1884
+ );
1885
+ continue;
1886
case 'style':
1887
extraAttributes.delete(propKey);
1888
diffHydratedStyles(domElement, value);
@@ -2244,828 +2079,132 @@ function diffHydratedGenericElement(
2079
);
2080
continue;
2081
}
2247
- // A few React string attributes have a different name.
2248
- // This is a mapping from React prop names to the attribute names.
2249
- case 'acceptCharset':
2250
- hydrateAttribute(
2251
- domElement,
2252
- propKey,
2253
- 'accept-charset',
2254
- value,
2255
- extraAttributes,
2256
- );
2257
- continue;
2258
- case 'className':
2259
- hydrateAttribute(domElement, propKey, 'class', value, extraAttributes);
2260
- continue;
2261
- case 'htmlFor':
2262
- hydrateAttribute(domElement, propKey, 'for', value, extraAttributes);
2263
- continue;
2264
- case 'httpEquiv':
2265
- hydrateAttribute(
2266
- domElement,
2267
- propKey,
2268
- 'http-equiv',
2269
- value,
2270
- extraAttributes,
2271
- );
2272
- continue;
2273
- case 'tabIndex':
2274
- hydrateAttribute(
2275
- domElement,
2276
- propKey,
2277
- 'tabindex',
2278
- value,
2279
- extraAttributes,
2280
- );
2281
- continue;
2282
- case 'crossOrigin':
2283
- hydrateAttribute(
2284
- domElement,
2285
- propKey,
2286
- 'crossorigin',
2287
- value,
2288
- extraAttributes,
2289
- );
2290
- continue;
2291
- case 'accentHeight':
2292
- hydrateAttribute(
2293
- domElement,
2294
- propKey,
2295
- 'accent-height',
2296
- value,
2297
- extraAttributes,
2298
- );
2299
- continue;
2300
- case 'alignmentBaseline':
2301
- hydrateAttribute(
2302
- domElement,
2303
- propKey,
2304
- 'alignment-baseline',
2305
- value,
2306
- extraAttributes,
2307
- );
2308
- continue;
2309
- case 'arabicForm':
2310
- hydrateAttribute(
2311
- domElement,
2312
- propKey,
2313
- 'arabic-form',
2314
- value,
2315
- extraAttributes,
2316
- );
2317
- continue;
2318
- case 'baselineShift':
2319
- hydrateAttribute(
2320
- domElement,
2321
- propKey,
2322
- 'baseline-shift',
2323
- value,
2324
- extraAttributes,
2325
- );
2326
- continue;
2327
- case 'capHeight':
2328
- hydrateAttribute(
2329
- domElement,
2330
- propKey,
2331
- 'cap-height',
2332
- value,
2333
- extraAttributes,
2334
- );
2335
- continue;
2336
- case 'clipPath':
2337
- hydrateAttribute(
2338
- domElement,
2339
- propKey,
2340
- 'clip-path',
2341
- value,
2342
- extraAttributes,
2343
- );
2344
- continue;
2345
- case 'clipRule':
2346
- hydrateAttribute(
2347
- domElement,
2348
- propKey,
2349
- 'clip-rule',
2350
- value,
2351
- extraAttributes,
2352
- );
2353
- continue;
2354
- case 'colorInterpolation':
2355
- hydrateAttribute(
2356
- domElement,
2357
- propKey,
2358
- 'color-interpolation',
2359
- value,
2360
- extraAttributes,
2361
- );
2362
- continue;
2363
- case 'colorInterpolationFilters':
2364
- hydrateAttribute(
2365
- domElement,
2366
- propKey,
2367
- 'color-interpolation-filters',
2368
- value,
2369
- extraAttributes,
2370
- );
2371
- continue;
2372
- case 'colorProfile':
2373
- hydrateAttribute(
2374
- domElement,
2375
- propKey,
2376
- 'color-profile',
2377
- value,
2378
- extraAttributes,
2379
- );
2380
- continue;
2381
- case 'colorRendering':
2382
- hydrateAttribute(
2383
- domElement,
2384
- propKey,
2385
- 'color-rendering',
2386
- value,
2387
- extraAttributes,
2388
- );
2389
- continue;
2390
- case 'dominantBaseline':
2391
- hydrateAttribute(
2392
- domElement,
2393
- propKey,
2394
- 'dominant-baseline',
2395
- value,
2396
- extraAttributes,
2397
- );
2398
- continue;
2399
- case 'enableBackground':
2400
- hydrateAttribute(
2401
- domElement,
2402
- propKey,
2403
- 'enable-background',
2404
- value,
2405
- extraAttributes,
2406
- );
2407
- continue;
2408
- case 'fillOpacity':
2409
- hydrateAttribute(
2410
- domElement,
2411
- propKey,
2412
- 'fill-opacity',
2413
- value,
2414
- extraAttributes,
2415
- );
2416
- continue;
2417
- case 'fillRule':
2418
- hydrateAttribute(
2419
- domElement,
2420
- propKey,
2421
- 'fill-rule',
2422
- value,
2423
- extraAttributes,
2424
- );
2425
- continue;
2426
- case 'floodColor':
2427
- hydrateAttribute(
2428
- domElement,
2429
- propKey,
2430
- 'flood-color',
2431
- value,
2432
- extraAttributes,
2433
- );
2434
- continue;
2435
- case 'floodOpacity':
2436
- hydrateAttribute(
2437
- domElement,
2438
- propKey,
2439
- 'flood-opacity',
2440
- value,
2441
- extraAttributes,
2442
- );
2443
- continue;
2444
- case 'fontFamily':
2445
- hydrateAttribute(
2446
- domElement,
2447
- propKey,
2448
- 'font-family',
2449
- value,
2450
- extraAttributes,
2451
- );
2452
- continue;
2453
- case 'fontSize':
2454
- hydrateAttribute(
2455
- domElement,
2456
- propKey,
2457
- 'font-size',
2458
- value,
2459
- extraAttributes,
2460
- );
2461
- continue;
2462
- case 'fontSizeAdjust':
2463
- hydrateAttribute(
2464
- domElement,
2465
- propKey,
2466
- 'font-size-adjust',
2467
- value,
2468
- extraAttributes,
2469
- );
2470
- continue;
2471
- case 'fontStretch':
2082
+ case 'xHeight':
2083
hydrateAttribute(
2084
domElement,
2085
propKey,
2475
- 'font-stretch',
2086
+ 'x-height',
2087
value,
2088
extraAttributes,
2089
);
2090
continue;
2480
- case 'fontStyle':
2091
+ case 'xlinkActuate':
2092
hydrateAttribute(
2093
domElement,
2094
propKey,
2484
- 'font-style',
2095
+ 'xlink:actuate',
2096
value,
2097
extraAttributes,
2098
);
2099
continue;
2489
- case 'fontVariant':
2100
+ case 'xlinkArcrole':
2101
hydrateAttribute(
2102
domElement,
2103
propKey,
2493
- 'font-variant',
2104
+ 'xlink:arcrole',
2105
value,
2106
extraAttributes,
2107
);
2108
continue;
2498
- case 'fontWeight':
2109
+ case 'xlinkRole':
2110
hydrateAttribute(
2111
domElement,
2112
propKey,
2502
- 'font-weight',
2113
+ 'xlink:role',
2114
value,
2115
extraAttributes,
2116
);
2117
continue;
2507
- case 'glyphName':
2118
+ case 'xlinkShow':
2119
hydrateAttribute(
2120
domElement,
2121
propKey,
2511
- 'glyph-name',
2122
+ 'xlink:show',
2123
value,
2124
extraAttributes,
2125
);
2126
continue;
2516
- case 'glyphOrientationHorizontal':
2127
+ case 'xlinkTitle':
2128
hydrateAttribute(
2129
domElement,
2130
propKey,
2520
- 'glyph-orientation-horizontal',
2131
+ 'xlink:title',
2132
value,
2133
extraAttributes,
2134
);
2135
continue;
2525
- case 'glyphOrientationVertical':
2136
+ case 'xlinkType':
2137
hydrateAttribute(
2138
domElement,
2139
propKey,
2529
- 'glyph-orientation-vertical',
2140
+ 'xlink:type',
2141
value,
2142
extraAttributes,
2143
);
2144
continue;
2534
- case 'horizAdvX':
2145
+ case 'xmlBase':
2146
hydrateAttribute(
2147
domElement,
2148
propKey,
2538
- 'horiz-adv-x',
2149
+ 'xml:base',
2150
value,
2151
extraAttributes,
2152
);
2153
continue;
2543
- case 'horizOriginX':
2154
+ case 'xmlLang':
2155
hydrateAttribute(
2156
domElement,
2157
propKey,
2547
- 'horiz-origin-x',
2158
+ 'xml:lang',
2159
value,
2160
extraAttributes,
2161
);
2162
continue;
2552
- case 'imageRendering':
2163
+ case 'xmlSpace':
2164
hydrateAttribute(
2165
domElement,
2166
propKey,
2556
- 'image-rendering',
2167
+ 'xml:space',
2168
value,
2169
extraAttributes,
2170
);
2171
continue;
2561
- case 'letterSpacing':
2562
- hydrateAttribute(
2172
+ default: {
2173
+ if (
2174
+ // shouldIgnoreAttribute
2175
+ // We have already filtered out null/undefined and reserved words.
2176
+ propKey.length > 2 &&
2177
+ (propKey[0] === 'o' || propKey[0] === 'O') &&
2178
+ (propKey[1] === 'n' || propKey[1] === 'N')
2179
+ ) {
2180
+ continue;
2181
+ }
2182
+ const attributeName = getAttributeAlias(propKey);
2183
+ let isMismatchDueToBadCasing = false;
2184
+ let ownNamespaceDev = parentNamespaceDev;
2185
+ if (ownNamespaceDev === HTML_NAMESPACE) {
2186
+ ownNamespaceDev = getIntrinsicNamespace(tag);
2187
+ }
2188
+ if (ownNamespaceDev === HTML_NAMESPACE) {
2189
+ extraAttributes.delete(attributeName.toLowerCase());
2190
+ } else {
2191
+ const standardName = getPossibleStandardName(propKey);
2192
+ if (standardName !== null && standardName !== propKey) {
2193
+ // If an SVG prop is supplied with bad casing, it will
2194
+ // be successfully parsed from HTML, but will produce a mismatch
2195
+ // (and would be incorrectly rendered on the client).
2196
+ // However, we already warn about bad casing elsewhere.
2197
+ // So we'll skip the misleading extra mismatch warning in this case.
2198
+ isMismatchDueToBadCasing = true;
2199
+ extraAttributes.delete(standardName);
2200
+ }
2201
+ extraAttributes.delete(attributeName);
2202
+ }
2203
+ const serverValue = getValueForAttribute(
2204
domElement,
2564
- propKey,
2565
- 'letter-spacing',
2205
+ attributeName,
2206
value,
2567
- extraAttributes,
2207
);
2569
- continue;
2570
- case 'lightingColor':
2571
- hydrateAttribute(
2572
- domElement,
2573
- propKey,
2574
- 'lighting-color',
2575
- value,
2576
- extraAttributes,
2577
- );
2578
- continue;
2579
- case 'markerEnd':
2580
- hydrateAttribute(
2581
- domElement,
2582
- propKey,
2583
- 'marker-end',
2584
- value,
2585
- extraAttributes,
2586
- );
2587
- continue;
2588
- case 'markerMid':
2589
- hydrateAttribute(
2590
- domElement,
2591
- propKey,
2592
- 'marker-mid',
2593
- value,
2594
- extraAttributes,
2595
- );
2596
- continue;
2597
- case 'markerStart':
2598
- hydrateAttribute(
2599
- domElement,
2600
- propKey,
2601
- 'marker-start',
2602
- value,
2603
- extraAttributes,
2604
- );
2605
- continue;
2606
- case 'overlinePosition':
2607
- hydrateAttribute(
2608
- domElement,
2609
- propKey,
2610
- 'overline-position',
2611
- value,
2612
- extraAttributes,
2613
- );
2614
- continue;
2615
- case 'overlineThickness':
2616
- hydrateAttribute(
2617
- domElement,
2618
- propKey,
2619
- 'overline-thickness',
2620
- value,
2621
- extraAttributes,
2622
- );
2623
- continue;
2624
- case 'paintOrder':
2625
- hydrateAttribute(
2626
- domElement,
2627
- propKey,
2628
- 'paint-order',
2629
- value,
2630
- extraAttributes,
2631
- );
2632
- continue;
2633
- case 'panose-1':
2634
- hydrateAttribute(
2635
- domElement,
2636
- propKey,
2637
- 'panose-1',
2638
- value,
2639
- extraAttributes,
2640
- );
2641
- continue;
2642
- case 'pointerEvents':
2643
- hydrateAttribute(
2644
- domElement,
2645
- propKey,
2646
- 'pointer-events',
2647
- value,
2648
- extraAttributes,
2649
- );
2650
- continue;
2651
- case 'renderingIntent':
2652
- hydrateAttribute(
2653
- domElement,
2654
- propKey,
2655
- 'rendering-intent',
2656
- value,
2657
- extraAttributes,
2658
- );
2659
- continue;
2660
- case 'shapeRendering':
2661
- hydrateAttribute(
2662
- domElement,
2663
- propKey,
2664
- 'shape-rendering',
2665
- value,
2666
- extraAttributes,
2667
- );
2668
- continue;
2669
- case 'stopColor':
2670
- hydrateAttribute(
2671
- domElement,
2672
- propKey,
2673
- 'stop-color',
2674
- value,
2675
- extraAttributes,
2676
- );
2677
- continue;
2678
- case 'stopOpacity':
2679
- hydrateAttribute(
2680
- domElement,
2681
- propKey,
2682
- 'stop-opacity',
2683
- value,
2684
- extraAttributes,
2685
- );
2686
- continue;
2687
- case 'strikethroughPosition':
2688
- hydrateAttribute(
2689
- domElement,
2690
- propKey,
2691
- 'strikethrough-position',
2692
- value,
2693
- extraAttributes,
2694
- );
2695
- continue;
2696
- case 'strikethroughThickness':
2697
- hydrateAttribute(
2698
- domElement,
2699
- propKey,
2700
- 'strikethrough-thickness',
2701
- value,
2702
- extraAttributes,
2703
- );
2704
- continue;
2705
- case 'strokeDasharray':
2706
- hydrateAttribute(
2707
- domElement,
2708
- propKey,
2709
- 'stroke-dasharray',
2710
- value,
2711
- extraAttributes,
2712
- );
2713
- continue;
2714
- case 'strokeDashoffset':
2715
- hydrateAttribute(
2716
- domElement,
2717
- propKey,
2718
- 'stroke-dashoffset',
2719
- value,
2720
- extraAttributes,
2721
- );
2722
- continue;
2723
- case 'strokeLinecap':
2724
- hydrateAttribute(
2725
- domElement,
2726
- propKey,
2727
- 'stroke-linecap',
2728
- value,
2729
- extraAttributes,
2730
- );
2731
- continue;
2732
- case 'strokeLinejoin':
2733
- hydrateAttribute(
2734
- domElement,
2735
- propKey,
2736
- 'stroke-linejoin',
2737
- value,
2738
- extraAttributes,
2739
- );
2740
- continue;
2741
- case 'strokeMiterlimit':
2742
- hydrateAttribute(
2743
- domElement,
2744
- propKey,
2745
- 'stroke-miterlimit',
2746
- value,
2747
- extraAttributes,
2748
- );
2749
- continue;
2750
- case 'strokeOpacity':
2751
- hydrateAttribute(
2752
- domElement,
2753
- propKey,
2754
- 'stroke-opacity',
2755
- value,
2756
- extraAttributes,
2757
- );
2758
- continue;
2759
- case 'strokeWidth':
2760
- hydrateAttribute(
2761
- domElement,
2762
- propKey,
2763
- 'stroke-width',
2764
- value,
2765
- extraAttributes,
2766
- );
2767
- continue;
2768
- case 'textAnchor':
2769
- hydrateAttribute(
2770
- domElement,
2771
- propKey,
2772
- 'text-anchor',
2773
- value,
2774
- extraAttributes,
2775
- );
2776
- continue;
2777
- case 'textDecoration':
2778
- hydrateAttribute(
2779
- domElement,
2780
- propKey,
2781
- 'text-decoration',
2782
- value,
2783
- extraAttributes,
2784
- );
2785
- continue;
2786
- case 'textRendering':
2787
- hydrateAttribute(
2788
- domElement,
2789
- propKey,
2790
- 'text-rendering',
2791
- value,
2792
- extraAttributes,
2793
- );
2794
- continue;
2795
- case 'transformOrigin':
2796
- hydrateAttribute(
2797
- domElement,
2798
- propKey,
2799
- 'transform-origin',
2800
- value,
2801
- extraAttributes,
2802
- );
2803
- continue;
2804
- case 'underlinePosition':
2805
- hydrateAttribute(
2806
- domElement,
2807
- propKey,
2808
- 'underline-position',
2809
- value,
2810
- extraAttributes,
2811
- );
2812
- continue;
2813
- case 'underlineThickness':
2814
- hydrateAttribute(
2815
- domElement,
2816
- propKey,
2817
- 'underline-thickness',
2818
- value,
2819
- extraAttributes,
2820
- );
2821
- continue;
2822
- case 'unicodeBidi':
2823
- hydrateAttribute(
2824
- domElement,
2825
- propKey,
2826
- 'unicode-bidi',
2827
- value,
2828
- extraAttributes,
2829
- );
2830
- continue;
2831
- case 'unicodeRange':
2832
- hydrateAttribute(
2833
- domElement,
2834
- propKey,
2835
- 'unicode-range',
2836
- value,
2837
- extraAttributes,
2838
- );
2839
- continue;
2840
- case 'unitsPerEm':
2841
- hydrateAttribute(
2842
- domElement,
2843
- propKey,
2844
- 'units-per-em',
2845
- value,
2846
- extraAttributes,
2847
- );
2848
- continue;
2849
- case 'vAlphabetic':
2850
- hydrateAttribute(
2851
- domElement,
2852
- propKey,
2853
- 'v-alphabetic',
2854
- value,
2855
- extraAttributes,
2856
- );
2857
- continue;
2858
- case 'vHanging':
2859
- hydrateAttribute(
2860
- domElement,
2861
- propKey,
2862
- 'v-hanging',
2863
- value,
2864
- extraAttributes,
2865
- );
2866
- continue;
2867
- case 'vIdeographic':
2868
- hydrateAttribute(
2869
- domElement,
2870
- propKey,
2871
- 'v-ideographic',
2872
- value,
2873
- extraAttributes,
2874
- );
2875
- continue;
2876
- case 'vMathematical':
2877
- hydrateAttribute(
2878
- domElement,
2879
- propKey,
2880
- 'v-mathematical',
2881
- value,
2882
- extraAttributes,
2883
- );
2884
- continue;
2885
- case 'vectorEffect':
2886
- hydrateAttribute(
2887
- domElement,
2888
- propKey,
2889
- 'vector-effect',
2890
- value,
2891
- extraAttributes,
2892
- );
2893
- continue;
2894
- case 'vertAdvY':
2895
- hydrateAttribute(
2896
- domElement,
2897
- propKey,
2898
- 'vert-adv-y',
2899
- value,
2900
- extraAttributes,
2901
- );
2902
- continue;
2903
- case 'vertOriginX':
2904
- hydrateAttribute(
2905
- domElement,
2906
- propKey,
2907
- 'vert-origin-x',
2908
- value,
2909
- extraAttributes,
2910
- );
2911
- continue;
2912
- case 'vertOriginY':
2913
- hydrateAttribute(
2914
- domElement,
2915
- propKey,
2916
- 'vert-origin-y',
2917
- value,
2918
- extraAttributes,
2919
- );
2920
- continue;
2921
- case 'wordSpacing':
2922
- hydrateAttribute(
2923
- domElement,
2924
- propKey,
2925
- 'word-spacing',
2926
- value,
2927
- extraAttributes,
2928
- );
2929
- continue;
2930
- case 'writingMode':
2931
- hydrateAttribute(
2932
- domElement,
2933
- propKey,
2934
- 'writing-mode',
2935
- value,
2936
- extraAttributes,
2937
- );
2938
- continue;
2939
- case 'xmlnsXlink':
2940
- hydrateAttribute(
2941
- domElement,
2942
- propKey,
2943
- 'xmlns:xlink',
2944
- value,
2945
- extraAttributes,
2946
- );
2947
- continue;
2948
- case 'xHeight':
2949
- hydrateAttribute(
2950
- domElement,
2951
- propKey,
2952
- 'x-height',
2953
- value,
2954
- extraAttributes,
2955
- );
2956
- continue;
2957
- case 'xlinkActuate':
2958
- hydrateAttribute(
2959
- domElement,
2960
- propKey,
2961
- 'xlink:actuate',
2962
- value,
2963
- extraAttributes,
2964
- );
2965
- continue;
2966
- case 'xlinkArcrole':
2967
- hydrateAttribute(
2968
- domElement,
2969
- propKey,
2970
- 'xlink:arcrole',
2971
- value,
2972
- extraAttributes,
2973
- );
2974
- continue;
2975
- case 'xlinkRole':
2976
- hydrateAttribute(
2977
- domElement,
2978
- propKey,
2979
- 'xlink:role',
2980
- value,
2981
- extraAttributes,
2982
- );
2983
- continue;
2984
- case 'xlinkShow':
2985
- hydrateAttribute(
2986
- domElement,
2987
- propKey,
2988
- 'xlink:show',
2989
- value,
2990
- extraAttributes,
2991
- );
2992
- continue;
2993
- case 'xlinkTitle':
2994
- hydrateAttribute(
2995
- domElement,
2996
- propKey,
2997
- 'xlink:title',
2998
- value,
2999
- extraAttributes,
3000
- );
3001
- continue;
3002
- case 'xlinkType':
3003
- hydrateAttribute(
3004
- domElement,
3005
- propKey,
3006
- 'xlink:type',
3007
- value,
3008
- extraAttributes,
3009
- );
3010
- continue;
3011
- case 'xmlBase':
3012
- hydrateAttribute(
3013
- domElement,
3014
- propKey,
3015
- 'xml:base',
3016
- value,
3017
- extraAttributes,
3018
- );
3019
- continue;
3020
- case 'xmlLang':
3021
- hydrateAttribute(
3022
- domElement,
3023
- propKey,
3024
- 'xml:lang',
3025
- value,
3026
- extraAttributes,
3027
- );
3028
- continue;
3029
- case 'xmlSpace':
3030
- hydrateAttribute(
3031
- domElement,
3032
- propKey,
3033
- 'xml:space',
3034
- value,
3035
- extraAttributes,
3036
- );
3037
- continue;
3038
- default: {
3039
- if (
3040
- // shouldIgnoreAttribute
3041
- // We have already filtered out null/undefined and reserved words.
3042
- propKey.length > 2 &&
3043
- (propKey[0] === 'o' || propKey[0] === 'O') &&
3044
- (propKey[1] === 'n' || propKey[1] === 'N')
3045
- ) {
3046
- continue;
3047
- }
3048
- let isMismatchDueToBadCasing = false;
3049
- let ownNamespaceDev = parentNamespaceDev;
3050
- if (ownNamespaceDev === HTML_NAMESPACE) {
3051
- ownNamespaceDev = getIntrinsicNamespace(tag);
3052
- }
3053
- if (ownNamespaceDev === HTML_NAMESPACE) {
3054
- extraAttributes.delete(propKey.toLowerCase());
3055
- } else {
3056
- const standardName = getPossibleStandardName(propKey);
3057
- if (standardName !== null && standardName !== propKey) {
3058
- // If an SVG prop is supplied with bad casing, it will
3059
- // be successfully parsed from HTML, but will produce a mismatch
3060
- // (and would be incorrectly rendered on the client).
3061
- // However, we already warn about bad casing elsewhere.
3062
- // So we'll skip the misleading extra mismatch warning in this case.
3063
- isMismatchDueToBadCasing = true;
3064
- extraAttributes.delete(standardName);
3065
- }
3066
- extraAttributes.delete(propKey);
3067
- }
3068
- const serverValue = getValueForAttribute(domElement, propKey, value);
2208
if (!isMismatchDueToBadCasing) {
2209
warnForPropDifference(propKey, serverValue, value);
2210
}
packages/react-dom-bindings/src/server/ReactDOMServerFormatConfig.js
+59
-274
@@ -40,6 +40,7 @@ import {
40
41
import isAttributeNameSafe from '../shared/isAttributeNameSafe';
42
import isUnitlessNumber from '../shared/isUnitlessNumber';
43
+import getAttributeAlias from '../shared/getAttributeAlias';
44
45
import {checkControlledValueProps} from '../shared/ReactControlledValuePropTypes';
46
import {validateProperties as validateARIAProperties} from '../shared/ReactDOMInvalidARIAHook';
@@ -640,23 +641,29 @@ function pushAttribute(
641
value: string | boolean | number | Function | Object, // not null or undefined
642
): void {
643
switch (name) {
644
+ // These are very common props and therefore are in the beginning of the switch.
645
+ // TODO: aria-label is a very common prop but allows booleans so is not like the others
646
+ // but should ideally go in this list too.
647
+ case 'className': {
648
+ pushStringAttribute(target, 'class', value);
649
+ break;
650
+ }
651
+ case 'tabIndex': {
652
+ pushStringAttribute(target, 'tabindex', value);
653
+ break;
654
+ }
655
+ case 'dir':
656
+ case 'role':
657
+ case 'viewBox':
658
+ case 'width':
659
+ case 'height': {
660
+ pushStringAttribute(target, name, value);
661
+ break;
662
+ }
663
case 'style': {
664
pushStyleAttribute(target, value);
665
return;
666
}
647
- case 'defaultValue':
648
- case 'defaultChecked': // These shouldn't be set as attributes on generic HTML elements.
649
- case 'innerHTML': // Must use dangerouslySetInnerHTML instead.
650
- case 'suppressContentEditableWarning':
651
- case 'suppressHydrationWarning':
652
- // Ignored. These are built-in to React on the client.
653
- return;
654
- case 'autoFocus':
655
- case 'multiple':
656
- case 'muted': {
657
- pushBooleanAttribute(target, name.toLowerCase(), value);
658
- return;
659
- }
667
case 'src':
668
case 'href':
669
case 'action':
@@ -709,6 +716,19 @@ function pushAttribute(
716
);
717
return;
718
}
719
+ case 'defaultValue':
720
+ case 'defaultChecked': // These shouldn't be set as attributes on generic HTML elements.
721
+ case 'innerHTML': // Must use dangerouslySetInnerHTML instead.
722
+ case 'suppressContentEditableWarning':
723
+ case 'suppressHydrationWarning':
724
+ // Ignored. These are built-in to React on the client.
725
+ return;
726
+ case 'autoFocus':
727
+ case 'multiple':
728
+ case 'muted': {
729
+ pushBooleanAttribute(target, name.toLowerCase(), value);
730
+ return;
731
+ }
732
case 'xlinkHref': {
733
if (
734
typeof value === 'function' ||
@@ -846,278 +866,33 @@ function pushAttribute(
866
}
867
return;
868
}
849
- // A few React string attributes have a different name.
850
- // This is a mapping from React prop names to the attribute names.
851
- case 'acceptCharset':
852
- pushStringAttribute(target, 'accept-charset', value);
853
- return;
854
- case 'className':
855
- pushStringAttribute(target, 'class', value);
856
- return;
857
- case 'htmlFor':
858
- pushStringAttribute(target, 'for', value);
859
- return;
860
- case 'httpEquiv':
861
- pushStringAttribute(target, 'http-equiv', value);
862
- return;
863
- // HTML and SVG attributes, but the SVG attribute is case sensitive.
864
- case 'tabIndex':
865
- pushStringAttribute(target, 'tabindex', value);
866
- return;
867
- case 'crossOrigin':
868
- pushStringAttribute(target, 'crossorigin', value);
869
- return;
870
- // This is a list of all SVG attributes that need special casing.
871
- // Regular attributes that just accept strings.
872
- case 'accentHeight':
873
- pushStringAttribute(target, 'accent-height', value);
874
- return;
875
- case 'alignmentBaseline':
876
- pushStringAttribute(target, 'alignment-baseline', value);
877
- return;
878
- case 'arabicForm':
879
- pushStringAttribute(target, 'arabic-form', value);
880
- return;
881
- case 'baselineShift':
882
- pushStringAttribute(target, 'baseline-shift', value);
883
- return;
884
- case 'capHeight':
885
- pushStringAttribute(target, 'cap-height', value);
886
- return;
887
- case 'clipPath':
888
- pushStringAttribute(target, 'clip-path', value);
889
- return;
890
- case 'clipRule':
891
- pushStringAttribute(target, 'clip-rule', value);
892
- return;
893
- case 'colorInterpolation':
894
- pushStringAttribute(target, 'color-interpolation', value);
895
- return;
896
- case 'colorInterpolationFilters':
897
- pushStringAttribute(target, 'color-interpolation-filters', value);
898
- return;
899
- case 'colorProfile':
900
- pushStringAttribute(target, 'color-profile', value);
901
- return;
902
- case 'colorRendering':
903
- pushStringAttribute(target, 'color-rendering', value);
904
- return;
905
- case 'dominantBaseline':
906
- pushStringAttribute(target, 'dominant-baseline', value);
907
- return;
908
- case 'enableBackground':
909
- pushStringAttribute(target, 'enable-background', value);
910
- return;
911
- case 'fillOpacity':
912
- pushStringAttribute(target, 'fill-opacity', value);
913
- return;
914
- case 'fillRule':
915
- pushStringAttribute(target, 'fill-rule', value);
916
- return;
917
- case 'floodColor':
918
- pushStringAttribute(target, 'flood-color', value);
919
- return;
920
- case 'floodOpacity':
921
- pushStringAttribute(target, 'flood-opacity', value);
922
- return;
923
- case 'fontFamily':
924
- pushStringAttribute(target, 'font-family', value);
925
- return;
926
- case 'fontSize':
927
- pushStringAttribute(target, 'font-size', value);
928
- return;
929
- case 'fontSizeAdjust':
930
- pushStringAttribute(target, 'font-size-adjust', value);
931
- return;
932
- case 'fontStretch':
933
- pushStringAttribute(target, 'font-stretch', value);
934
- return;
935
- case 'fontStyle':
936
- pushStringAttribute(target, 'font-style', value);
937
- return;
938
- case 'fontVariant':
939
- pushStringAttribute(target, 'font-variant', value);
940
- return;
941
- case 'fontWeight':
942
- pushStringAttribute(target, 'font-weight', value);
943
- return;
944
- case 'glyphName':
945
- pushStringAttribute(target, 'glyph-name', value);
946
- return;
947
- case 'glyphOrientationHorizontal':
948
- pushStringAttribute(target, 'glyph-orientation-horizontal', value);
949
- return;
950
- case 'glyphOrientationVertical':
951
- pushStringAttribute(target, 'glyph-orientation-vertical', value);
952
- return;
953
- case 'horizAdvX':
954
- pushStringAttribute(target, 'horiz-adv-x', value);
955
- return;
956
- case 'horizOriginX':
957
- pushStringAttribute(target, 'horiz-origin-x', value);
958
- return;
959
- case 'imageRendering':
960
- pushStringAttribute(target, 'image-rendering', value);
961
- return;
962
- case 'letterSpacing':
963
- pushStringAttribute(target, 'letter-spacing', value);
964
- return;
965
- case 'lightingColor':
966
- pushStringAttribute(target, 'lighting-color', value);
967
- return;
968
- case 'markerEnd':
969
- pushStringAttribute(target, 'marker-end', value);
970
- return;
971
- case 'markerMid':
972
- pushStringAttribute(target, 'marker-mid', value);
973
- return;
974
- case 'markerStart':
975
- pushStringAttribute(target, 'marker-start', value);
976
- return;
977
- case 'overlinePosition':
978
- pushStringAttribute(target, 'overline-position', value);
979
- return;
980
- case 'overlineThickness':
981
- pushStringAttribute(target, 'overline-thickness', value);
982
- return;
983
- case 'paintOrder':
984
- pushStringAttribute(target, 'paint-order', value);
985
- return;
986
- case 'panose-1':
987
- pushStringAttribute(target, 'panose-1', value);
988
- return;
989
- case 'pointerEvents':
990
- pushStringAttribute(target, 'pointer-events', value);
991
- return;
992
- case 'renderingIntent':
993
- pushStringAttribute(target, 'rendering-intent', value);
994
- return;
995
- case 'shapeRendering':
996
- pushStringAttribute(target, 'shape-rendering', value);
997
- return;
998
- case 'stopColor':
999
- pushStringAttribute(target, 'stop-color', value);
1000
- return;
1001
- case 'stopOpacity':
1002
- pushStringAttribute(target, 'stop-opacity', value);
1003
- return;
1004
- case 'strikethroughPosition':
1005
- pushStringAttribute(target, 'strikethrough-position', value);
1006
- return;
1007
- case 'strikethroughThickness':
1008
- pushStringAttribute(target, 'strikethrough-thickness', value);
1009
- return;
1010
- case 'strokeDasharray':
1011
- pushStringAttribute(target, 'stroke-dasharray', value);
1012
- return;
1013
- case 'strokeDashoffset':
1014
- pushStringAttribute(target, 'stroke-dashoffset', value);
1015
- return;
1016
- case 'strokeLinecap':
1017
- pushStringAttribute(target, 'stroke-linecap', value);
1018
- return;
1019
- case 'strokeLinejoin':
1020
- pushStringAttribute(target, 'stroke-linejoin', value);
1021
- return;
1022
- case 'strokeMiterlimit':
1023
- pushStringAttribute(target, 'stroke-miterlimit', value);
1024
- return;
1025
- case 'strokeOpacity':
1026
- pushStringAttribute(target, 'stroke-opacity', value);
1027
- return;
1028
- case 'strokeWidth':
1029
- pushStringAttribute(target, 'stroke-width', value);
1030
- return;
1031
- case 'textAnchor':
1032
- pushStringAttribute(target, 'text-anchor', value);
1033
- return;
1034
- case 'textDecoration':
1035
- pushStringAttribute(target, 'text-decoration', value);
1036
- return;
1037
- case 'textRendering':
1038
- pushStringAttribute(target, 'text-rendering', value);
1039
- return;
1040
- case 'transformOrigin':
1041
- pushStringAttribute(target, 'transform-origin', value);
1042
- return;
1043
- case 'underlinePosition':
1044
- pushStringAttribute(target, 'underline-position', value);
1045
- return;
1046
- case 'underlineThickness':
1047
- pushStringAttribute(target, 'underline-thickness', value);
1048
- return;
1049
- case 'unicodeBidi':
1050
- pushStringAttribute(target, 'unicode-bidi', value);
1051
- return;
1052
- case 'unicodeRange':
1053
- pushStringAttribute(target, 'unicode-range', value);
1054
- return;
1055
- case 'unitsPerEm':
1056
- pushStringAttribute(target, 'units-per-em', value);
1057
- return;
1058
- case 'vAlphabetic':
1059
- pushStringAttribute(target, 'v-alphabetic', value);
1060
- return;
1061
- case 'vHanging':
1062
- pushStringAttribute(target, 'v-hanging', value);
1063
- return;
1064
- case 'vIdeographic':
1065
- pushStringAttribute(target, 'v-ideographic', value);
1066
- return;
1067
- case 'vMathematical':
1068
- pushStringAttribute(target, 'v-mathematical', value);
1069
- return;
1070
- case 'vectorEffect':
1071
- pushStringAttribute(target, 'vector-effect', value);
1072
- return;
1073
- case 'vertAdvY':
1074
- pushStringAttribute(target, 'vert-adv-y', value);
1075
- return;
1076
- case 'vertOriginX':
1077
- pushStringAttribute(target, 'vert-origin-x', value);
1078
- return;
1079
- case 'vertOriginY':
1080
- pushStringAttribute(target, 'vert-origin-y', value);
1081
- return;
1082
- case 'wordSpacing':
1083
- pushStringAttribute(target, 'word-spacing', value);
1084
- return;
1085
- case 'writingMode':
1086
- pushStringAttribute(target, 'writing-mode', value);
1087
- return;
1088
- case 'xmlnsXlink':
1089
- pushStringAttribute(target, 'xmlns:xlink', value);
1090
- return;
1091
- case 'xHeight':
1092
- pushStringAttribute(target, 'x-height', value);
1093
- return;
869
case 'xlinkActuate':
870
pushStringAttribute(target, 'xlink:actuate', value);
1096
- break;
871
+ return;
872
case 'xlinkArcrole':
873
pushStringAttribute(target, 'xlink:arcrole', value);
1099
- break;
874
+ return;
875
case 'xlinkRole':
876
pushStringAttribute(target, 'xlink:role', value);
1102
- break;
877
+ return;
878
case 'xlinkShow':
879
pushStringAttribute(target, 'xlink:show', value);
1105
- break;
880
+ return;
881
case 'xlinkTitle':
882
pushStringAttribute(target, 'xlink:title', value);
1108
- break;
883
+ return;
884
case 'xlinkType':
885
pushStringAttribute(target, 'xlink:type', value);
1111
- break;
886
+ return;
887
case 'xmlBase':
888
pushStringAttribute(target, 'xml:base', value);
1114
- break;
889
+ return;
890
case 'xmlLang':
891
pushStringAttribute(target, 'xml:lang', value);
1117
- break;
892
+ return;
893
case 'xmlSpace':
894
pushStringAttribute(target, 'xml:space', value);
1120
- break;
895
+ return;
896
default:
897
if (
898
// shouldIgnoreAttribute
@@ -1129,14 +904,15 @@ function pushAttribute(
904
return;
905
}
906
1132
- if (isAttributeNameSafe(name)) {
907
+ const attributeName = getAttributeAlias(name);
908
+ if (isAttributeNameSafe(attributeName)) {
909
// shouldRemoveAttribute
910
switch (typeof value) {
911
case 'function':
912
case 'symbol': // eslint-disable-line
913
return;
914
case 'boolean': {
1139
- const prefix = name.toLowerCase().slice(0, 5);
915
+ const prefix = attributeName.toLowerCase().slice(0, 5);
916
if (prefix !== 'data-' && prefix !== 'aria-') {
917
return;
918
}
@@ -1144,7 +920,7 @@ function pushAttribute(
920
}
921
target.push(
922
attributeSeparator,
1147
- stringToChunk(name),
923
+ stringToChunk(attributeName),
924
attributeAssign,
925
stringToChunk(escapeTextForBrowser(value)),
926
attributeEnd,
@@ -2862,6 +2638,16 @@ export function pushStartInstance(
2638
}
2639
2640
switch (type) {
2641
+ case 'div':
2642
+ case 'span':
2643
+ case 'svg':
2644
+ case 'path':
2645
+ case 'a':
2646
+ case 'g':
2647
+ case 'p':
2648
+ case 'li':
2649
+ // Fast track very common tags
2650
+ break;
2651
// Special tags
2652
case 'select':
2653
return pushStartSelect(target, props);
@@ -2971,15 +2757,14 @@ export function pushStartInstance(
2757
);
2758
}
2759
default: {
2974
- if (type.indexOf('-') === -1) {
2975
- // Generic element
2976
- return pushStartGenericElement(target, props, type);
2977
- } else {
2760
+ if (type.indexOf('-') !== -1) {
2761
// Custom element
2762
return pushStartCustomElement(target, props, type);
2763
}
2764
}
2765
}
2766
+ // Generic element
2767
+ return pushStartGenericElement(target, props, type);
2768
}
2769
2770
const endTag1 = stringToPrecomputedChunk('</');
packages/react-dom-bindings/src/shared/getAttributeAlias.js
new
+96
@@ -0,0 +1,96 @@
1
+/**
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
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
+ * @flow
8
+ */
9
+
10
+const aliases = new Map([
11
+ ['acceptCharset', 'accept-charset'],
12
+ ['htmlFor', 'for'],
13
+ ['httpEquiv', 'http-equiv'],
14
+ // HTML and SVG attributes, but the SVG attribute is case sensitive.],
15
+ ['crossOrigin', 'crossorigin'],
16
+ // This is a list of all SVG attributes that need special casing.
17
+ // Regular attributes that just accept strings.],
18
+ ['accentHeight', 'accent-height'],
19
+ ['alignmentBaseline', 'alignment-baseline'],
20
+ ['arabicForm', 'arabic-form'],
21
+ ['baselineShift', 'baseline-shift'],
22
+ ['capHeight', 'cap-height'],
23
+ ['clipPath', 'clip-path'],
24
+ ['clipRule', 'clip-rule'],
25
+ ['colorInterpolation', 'color-interpolation'],
26
+ ['colorInterpolationFilters', 'color-interpolation-filters'],
27
+ ['colorProfile', 'color-profile'],
28
+ ['colorRendering', 'color-rendering'],
29
+ ['dominantBaseline', 'dominant-baseline'],
30
+ ['enableBackground', 'enable-background'],
31
+ ['fillOpacity', 'fill-opacity'],
32
+ ['fillRule', 'fill-rule'],
33
+ ['floodColor', 'flood-color'],
34
+ ['floodOpacity', 'flood-opacity'],
35
+ ['fontFamily', 'font-family'],
36
+ ['fontSize', 'font-size'],
37
+ ['fontSizeAdjust', 'font-size-adjust'],
38
+ ['fontStretch', 'font-stretch'],
39
+ ['fontStyle', 'font-style'],
40
+ ['fontVariant', 'font-variant'],
41
+ ['fontWeight', 'font-weight'],
42
+ ['glyphName', 'glyph-name'],
43
+ ['glyphOrientationHorizontal', 'glyph-orientation-horizontal'],
44
+ ['glyphOrientationVertical', 'glyph-orientation-vertical'],
45
+ ['horizAdvX', 'horiz-adv-x'],
46
+ ['horizOriginX', 'horiz-origin-x'],
47
+ ['imageRendering', 'image-rendering'],
48
+ ['letterSpacing', 'letter-spacing'],
49
+ ['lightingColor', 'lighting-color'],
50
+ ['markerEnd', 'marker-end'],
51
+ ['markerMid', 'marker-mid'],
52
+ ['markerStart', 'marker-start'],
53
+ ['overlinePosition', 'overline-position'],
54
+ ['overlineThickness', 'overline-thickness'],
55
+ ['paintOrder', 'paint-order'],
56
+ ['panose-1', 'panose-1'],
57
+ ['pointerEvents', 'pointer-events'],
58
+ ['renderingIntent', 'rendering-intent'],
59
+ ['shapeRendering', 'shape-rendering'],
60
+ ['stopColor', 'stop-color'],
61
+ ['stopOpacity', 'stop-opacity'],
62
+ ['strikethroughPosition', 'strikethrough-position'],
63
+ ['strikethroughThickness', 'strikethrough-thickness'],
64
+ ['strokeDasharray', 'stroke-dasharray'],
65
+ ['strokeDashoffset', 'stroke-dashoffset'],
66
+ ['strokeLinecap', 'stroke-linecap'],
67
+ ['strokeLinejoin', 'stroke-linejoin'],
68
+ ['strokeMiterlimit', 'stroke-miterlimit'],
69
+ ['strokeOpacity', 'stroke-opacity'],
70
+ ['strokeWidth', 'stroke-width'],
71
+ ['textAnchor', 'text-anchor'],
72
+ ['textDecoration', 'text-decoration'],
73
+ ['textRendering', 'text-rendering'],
74
+ ['transformOrigin', 'transform-origin'],
75
+ ['underlinePosition', 'underline-position'],
76
+ ['underlineThickness', 'underline-thickness'],
77
+ ['unicodeBidi', 'unicode-bidi'],
78
+ ['unicodeRange', 'unicode-range'],
79
+ ['unitsPerEm', 'units-per-em'],
80
+ ['vAlphabetic', 'v-alphabetic'],
81
+ ['vHanging', 'v-hanging'],
82
+ ['vIdeographic', 'v-ideographic'],
83
+ ['vMathematical', 'v-mathematical'],
84
+ ['vectorEffect', 'vector-effect'],
85
+ ['vertAdvY', 'vert-adv-y'],
86
+ ['vertOriginX', 'vert-origin-x'],
87
+ ['vertOriginY', 'vert-origin-y'],
88
+ ['wordSpacing', 'word-spacing'],
89
+ ['writingMode', 'writing-mode'],
90
+ ['xmlnsXlink', 'xmlns:xlink'],
91
+ ['xHeight', 'x-height'],
92
+]);
93
+
94
+export default function (name: string): string {
95
+ return aliases.get(name) || name;
96
+}
packages/react-dom-bindings/src/shared/isUnitlessNumber.js
+74
-76
@@ -10,81 +10,79 @@
10
/**
11
* CSS properties which accept numbers but are not in units of "px".
12
*/
13
+const unitlessNumbers = new Set([
14
+ 'animationIterationCount',
15
+ 'aspectRatio',
16
+ 'borderImageOutset',
17
+ 'borderImageSlice',
18
+ 'borderImageWidth',
19
+ 'boxFlex',
20
+ 'boxFlexGroup',
21
+ 'boxOrdinalGroup',
22
+ 'columnCount',
23
+ 'columns',
24
+ 'flex',
25
+ 'flexGrow',
26
+ 'flexPositive',
27
+ 'flexShrink',
28
+ 'flexNegative',
29
+ 'flexOrder',
30
+ 'gridArea',
31
+ 'gridRow',
32
+ 'gridRowEnd',
33
+ 'gridRowSpan',
34
+ 'gridRowStart',
35
+ 'gridColumn',
36
+ 'gridColumnEnd',
37
+ 'gridColumnSpan',
38
+ 'gridColumnStart',
39
+ 'fontWeight',
40
+ 'lineClamp',
41
+ 'lineHeight',
42
+ 'opacity',
43
+ 'order',
44
+ 'orphans',
45
+ 'scale',
46
+ 'tabSize',
47
+ 'widows',
48
+ 'zIndex',
49
+ 'zoom',
50
+ 'fillOpacity', // SVG-related properties
51
+ 'floodOpacity',
52
+ 'stopOpacity',
53
+ 'strokeDasharray',
54
+ 'strokeDashoffset',
55
+ 'strokeMiterlimit',
56
+ 'strokeOpacity',
57
+ 'strokeWidth',
58
+ 'MozAnimationIterationCount', // Known Prefixed Properties
59
+ 'MozBoxFlex', // TODO: Remove these since they shouldn't be used in modern code
60
+ 'MozBoxFlexGroup',
61
+ 'MozLineClamp',
62
+ 'msAnimationIterationCount',
63
+ 'msFlex',
64
+ 'msZoom',
65
+ 'msFlexGrow',
66
+ 'msFlexNegative',
67
+ 'msFlexOrder',
68
+ 'msFlexPositive',
69
+ 'msFlexShrink',
70
+ 'msGridColumn',
71
+ 'msGridColumnSpan',
72
+ 'msGridRow',
73
+ 'msGridRowSpan',
74
+ 'WebkitAnimationIterationCount',
75
+ 'WebkitBoxFlex',
76
+ 'WebKitBoxFlexGroup',
77
+ 'WebkitBoxOrdinalGroup',
78
+ 'WebkitColumnCount',
79
+ 'WebkitColumns',
80
+ 'WebkitFlex',
81
+ 'WebkitFlexGrow',
82
+ 'WebkitFlexPositive',
83
+ 'WebkitFlexShrink',
84
+ 'WebkitLineClamp',
85
+]);
86
export default function (name: string): boolean {
14
- switch (name) {
15
- case 'animationIterationCount':
16
- case 'aspectRatio':
17
- case 'borderImageOutset':
18
- case 'borderImageSlice':
19
- case 'borderImageWidth':
20
- case 'boxFlex':
21
- case 'boxFlexGroup':
22
- case 'boxOrdinalGroup':
23
- case 'columnCount':
24
- case 'columns':
25
- case 'flex':
26
- case 'flexGrow':
27
- case 'flexPositive':
28
- case 'flexShrink':
29
- case 'flexNegative':
30
- case 'flexOrder':
31
- case 'gridArea':
32
- case 'gridRow':
33
- case 'gridRowEnd':
34
- case 'gridRowSpan':
35
- case 'gridRowStart':
36
- case 'gridColumn':
37
- case 'gridColumnEnd':
38
- case 'gridColumnSpan':
39
- case 'gridColumnStart':
40
- case 'fontWeight':
41
- case 'lineClamp':
42
- case 'lineHeight':
43
- case 'opacity':
44
- case 'order':
45
- case 'orphans':
46
- case 'scale':
47
- case 'tabSize':
48
- case 'widows':
49
- case 'zIndex':
50
- case 'zoom':
51
- case 'fillOpacity': // SVG-related properties
52
- case 'floodOpacity':
53
- case 'stopOpacity':
54
- case 'strokeDasharray':
55
- case 'strokeDashoffset':
56
- case 'strokeMiterlimit':
57
- case 'strokeOpacity':
58
- case 'strokeWidth':
59
- case 'MozAnimationIterationCount': // Known Prefixed Properties
60
- case 'MozBoxFlex': // TODO: Remove these since they shouldn't be used in modern code
61
- case 'MozBoxFlexGroup':
62
- case 'MozLineClamp':
63
- case 'msAnimationIterationCount':
64
- case 'msFlex':
65
- case 'msZoom':
66
- case 'msFlexGrow':
67
- case 'msFlexNegative':
68
- case 'msFlexOrder':
69
- case 'msFlexPositive':
70
- case 'msFlexShrink':
71
- case 'msGridColumn':
72
- case 'msGridColumnSpan':
73
- case 'msGridRow':
74
- case 'msGridRowSpan':
75
- case 'WebkitAnimationIterationCount':
76
- case 'WebkitBoxFlex':
77
- case 'WebKitBoxFlexGroup':
78
- case 'WebkitBoxOrdinalGroup':
79
- case 'WebkitColumnCount':
80
- case 'WebkitColumns':
81
- case 'WebkitFlex':
82
- case 'WebkitFlexGrow':
83
- case 'WebkitFlexPositive':
84
- case 'WebkitFlexShrink':
85
- case 'WebkitLineClamp':
86
- return true;
87
- default:
88
- return false;
89
- }
87
+ return unitlessNumbers.has(name);
88
}