@b9g/crank 0.7.5 → 0.7.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -9
- package/_svg.cjs +94 -0
- package/_svg.cjs.map +1 -0
- package/_svg.d.ts +1 -0
- package/_svg.js +92 -0
- package/_svg.js.map +1 -0
- package/async.cjs +2 -1
- package/async.cjs.map +1 -1
- package/async.js +2 -1
- package/async.js.map +1 -1
- package/crank.cjs +193 -16
- package/crank.cjs.map +1 -1
- package/crank.d.ts +1 -0
- package/crank.js +193 -16
- package/crank.js.map +1 -1
- package/dom.cjs +326 -258
- package/dom.cjs.map +1 -1
- package/dom.js +326 -258
- package/dom.js.map +1 -1
- package/html.cjs +35 -5
- package/html.cjs.map +1 -1
- package/html.d.ts +2 -2
- package/html.js +35 -5
- package/html.js.map +1 -1
- package/jsx-tag.cjs +86 -21
- package/jsx-tag.cjs.map +1 -1
- package/jsx-tag.d.ts +41 -0
- package/jsx-tag.js +86 -22
- package/jsx-tag.js.map +1 -1
- package/package.json +1 -2
- package/standalone.cjs +7 -0
- package/standalone.cjs.map +1 -1
- package/standalone.d.ts +3 -1
- package/standalone.js +2 -0
- package/standalone.js.map +1 -1
- package/umd.js +648 -285
- package/umd.js.map +1 -1
package/umd.js
CHANGED
|
@@ -420,14 +420,14 @@
|
|
|
420
420
|
* Typically, you use a helper function like createElement to create elements
|
|
421
421
|
* rather than instatiating this class directly.
|
|
422
422
|
*/
|
|
423
|
-
class Element {
|
|
423
|
+
let Element$1 = class Element {
|
|
424
424
|
constructor(tag, props) {
|
|
425
425
|
this.tag = tag;
|
|
426
426
|
this.props = props;
|
|
427
427
|
}
|
|
428
|
-
}
|
|
428
|
+
};
|
|
429
429
|
// See Element interface
|
|
430
|
-
Element.prototype.$$typeof = ElementSymbol;
|
|
430
|
+
Element$1.prototype.$$typeof = ElementSymbol;
|
|
431
431
|
function isElement(value) {
|
|
432
432
|
return value != null && value.$$typeof === ElementSymbol;
|
|
433
433
|
}
|
|
@@ -469,14 +469,14 @@
|
|
|
469
469
|
else if (children.length === 1) {
|
|
470
470
|
props.children = children[0];
|
|
471
471
|
}
|
|
472
|
-
return new Element(tag, props);
|
|
472
|
+
return new Element$1(tag, props);
|
|
473
473
|
}
|
|
474
474
|
/** Clones a given element, shallowly copying the props object. */
|
|
475
475
|
function cloneElement(el) {
|
|
476
476
|
if (!isElement(el)) {
|
|
477
477
|
throw new TypeError(`Cannot clone non-element: ${String(el)}`);
|
|
478
478
|
}
|
|
479
|
-
return new Element(el.tag, { ...el.props });
|
|
479
|
+
return new Element$1(el.tag, { ...el.props });
|
|
480
480
|
}
|
|
481
481
|
function narrow(value) {
|
|
482
482
|
if (typeof value === "boolean" || value == null) {
|
|
@@ -593,9 +593,15 @@
|
|
|
593
593
|
function getChildValues(ret, startIndex) {
|
|
594
594
|
const values = [];
|
|
595
595
|
const lingerers = ret.lingerers;
|
|
596
|
-
const
|
|
596
|
+
const rawChildren = ret.children;
|
|
597
|
+
const isChildrenArray = Array.isArray(rawChildren);
|
|
598
|
+
const childrenLength = rawChildren === undefined
|
|
599
|
+
? 0
|
|
600
|
+
: isChildrenArray
|
|
601
|
+
? rawChildren.length
|
|
602
|
+
: 1;
|
|
597
603
|
let currentIndex = startIndex;
|
|
598
|
-
for (let i = 0; i <
|
|
604
|
+
for (let i = 0; i < childrenLength; i++) {
|
|
599
605
|
if (lingerers != null && lingerers[i] != null) {
|
|
600
606
|
const rets = lingerers[i];
|
|
601
607
|
for (const ret of rets) {
|
|
@@ -616,7 +622,9 @@
|
|
|
616
622
|
}
|
|
617
623
|
}
|
|
618
624
|
}
|
|
619
|
-
const child =
|
|
625
|
+
const child = isChildrenArray
|
|
626
|
+
? rawChildren[i]
|
|
627
|
+
: rawChildren;
|
|
620
628
|
if (child) {
|
|
621
629
|
const value = getValue(child, true, currentIndex);
|
|
622
630
|
if (Array.isArray(value)) {
|
|
@@ -635,8 +643,8 @@
|
|
|
635
643
|
}
|
|
636
644
|
}
|
|
637
645
|
}
|
|
638
|
-
if (lingerers != null && lingerers.length >
|
|
639
|
-
for (let i =
|
|
646
|
+
if (lingerers != null && lingerers.length > childrenLength) {
|
|
647
|
+
for (let i = childrenLength; i < lingerers.length; i++) {
|
|
640
648
|
const rets = lingerers[i];
|
|
641
649
|
if (rets != null) {
|
|
642
650
|
for (const ret of rets) {
|
|
@@ -795,7 +803,155 @@
|
|
|
795
803
|
}
|
|
796
804
|
return adapter.read(unwrap(getChildValues(ret)));
|
|
797
805
|
}
|
|
806
|
+
function diffChild(adapter, root, host, ctx, scope, parent, newChildren) {
|
|
807
|
+
let child = narrow(newChildren);
|
|
808
|
+
let ret = parent.children;
|
|
809
|
+
let graveyard;
|
|
810
|
+
let diff;
|
|
811
|
+
if (typeof child === "object") {
|
|
812
|
+
let childCopied = false;
|
|
813
|
+
// Check key match
|
|
814
|
+
const oldKey = typeof ret === "object" ? ret.el.props.key : undefined;
|
|
815
|
+
const newKey = child.props.key;
|
|
816
|
+
if (oldKey !== newKey) {
|
|
817
|
+
if (typeof ret === "object") {
|
|
818
|
+
(graveyard = graveyard || []).push(ret);
|
|
819
|
+
}
|
|
820
|
+
ret = undefined;
|
|
821
|
+
}
|
|
822
|
+
if (child.tag === Copy) {
|
|
823
|
+
childCopied = true;
|
|
824
|
+
}
|
|
825
|
+
else if (typeof ret === "object" &&
|
|
826
|
+
ret.el === child &&
|
|
827
|
+
getFlag(ret, DidCommit)) {
|
|
828
|
+
childCopied = true;
|
|
829
|
+
}
|
|
830
|
+
else {
|
|
831
|
+
if (ret && ret.el.tag === child.tag) {
|
|
832
|
+
ret.el = child;
|
|
833
|
+
if (child.props.copy && typeof child.props.copy !== "string") {
|
|
834
|
+
childCopied = true;
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
else if (ret) {
|
|
838
|
+
let candidateFound = false;
|
|
839
|
+
for (let predecessor = ret, candidate = ret.fallback; candidate; predecessor = candidate, candidate = candidate.fallback) {
|
|
840
|
+
if (candidate.el.tag === child.tag) {
|
|
841
|
+
const clone = cloneRetainer(candidate);
|
|
842
|
+
setFlag(clone, IsResurrecting);
|
|
843
|
+
predecessor.fallback = clone;
|
|
844
|
+
const fallback = ret;
|
|
845
|
+
ret = candidate;
|
|
846
|
+
ret.el = child;
|
|
847
|
+
ret.fallback = fallback;
|
|
848
|
+
setFlag(ret, DidDiff, false);
|
|
849
|
+
candidateFound = true;
|
|
850
|
+
break;
|
|
851
|
+
}
|
|
852
|
+
}
|
|
853
|
+
if (!candidateFound) {
|
|
854
|
+
const fallback = ret;
|
|
855
|
+
ret = new Retainer(child);
|
|
856
|
+
ret.fallback = fallback;
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
else {
|
|
860
|
+
ret = new Retainer(child);
|
|
861
|
+
}
|
|
862
|
+
if (childCopied && getFlag(ret, DidCommit)) ;
|
|
863
|
+
else if (child.tag === Raw || child.tag === Text) ;
|
|
864
|
+
else if (child.tag === Fragment) {
|
|
865
|
+
diff = diffChildren(adapter, root, host, ctx, scope, ret, ret.el.props.children);
|
|
866
|
+
}
|
|
867
|
+
else if (typeof child.tag === "function") {
|
|
868
|
+
diff = diffComponent(adapter, root, host, ctx, scope, ret);
|
|
869
|
+
}
|
|
870
|
+
else {
|
|
871
|
+
diff = diffHost(adapter, root, ctx, scope, ret);
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
if (typeof ret === "object") {
|
|
875
|
+
if (childCopied) {
|
|
876
|
+
setFlag(ret, IsCopied);
|
|
877
|
+
diff = getInflightDiff(ret);
|
|
878
|
+
}
|
|
879
|
+
else {
|
|
880
|
+
setFlag(ret, IsCopied, false);
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
else if (typeof child === "string") {
|
|
885
|
+
if (typeof ret === "object" && ret.el.tag === Text) {
|
|
886
|
+
ret.el.props.value = child;
|
|
887
|
+
}
|
|
888
|
+
else {
|
|
889
|
+
if (typeof ret === "object") {
|
|
890
|
+
(graveyard = graveyard || []).push(ret);
|
|
891
|
+
}
|
|
892
|
+
ret = new Retainer(createElement(Text, { value: child }));
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
else {
|
|
896
|
+
if (typeof ret === "object") {
|
|
897
|
+
(graveyard = graveyard || []).push(ret);
|
|
898
|
+
}
|
|
899
|
+
ret = undefined;
|
|
900
|
+
}
|
|
901
|
+
parent.children = ret;
|
|
902
|
+
if (isPromiseLike(diff)) {
|
|
903
|
+
const diff1 = diff.finally(() => {
|
|
904
|
+
setFlag(parent, DidDiff);
|
|
905
|
+
if (graveyard) {
|
|
906
|
+
if (parent.graveyard) {
|
|
907
|
+
for (let i = 0; i < graveyard.length; i++) {
|
|
908
|
+
parent.graveyard.push(graveyard[i]);
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
else {
|
|
912
|
+
parent.graveyard = graveyard;
|
|
913
|
+
}
|
|
914
|
+
}
|
|
915
|
+
});
|
|
916
|
+
let onNextDiffs;
|
|
917
|
+
const diff2 = (parent.pendingDiff = safeRace([
|
|
918
|
+
diff1,
|
|
919
|
+
new Promise((resolve) => (onNextDiffs = resolve)),
|
|
920
|
+
]));
|
|
921
|
+
if (parent.onNextDiff) {
|
|
922
|
+
parent.onNextDiff(diff2);
|
|
923
|
+
}
|
|
924
|
+
parent.onNextDiff = onNextDiffs;
|
|
925
|
+
return diff2;
|
|
926
|
+
}
|
|
927
|
+
else {
|
|
928
|
+
setFlag(parent, DidDiff);
|
|
929
|
+
if (graveyard) {
|
|
930
|
+
if (parent.graveyard) {
|
|
931
|
+
for (let i = 0; i < graveyard.length; i++) {
|
|
932
|
+
parent.graveyard.push(graveyard[i]);
|
|
933
|
+
}
|
|
934
|
+
}
|
|
935
|
+
else {
|
|
936
|
+
parent.graveyard = graveyard;
|
|
937
|
+
}
|
|
938
|
+
}
|
|
939
|
+
if (parent.onNextDiff) {
|
|
940
|
+
parent.onNextDiff(diff);
|
|
941
|
+
parent.onNextDiff = undefined;
|
|
942
|
+
}
|
|
943
|
+
parent.pendingDiff = undefined;
|
|
944
|
+
}
|
|
945
|
+
}
|
|
798
946
|
function diffChildren(adapter, root, host, ctx, scope, parent, newChildren) {
|
|
947
|
+
// Fast path for the common single non-keyed child case
|
|
948
|
+
if (!Array.isArray(newChildren) &&
|
|
949
|
+
(typeof newChildren !== "object" ||
|
|
950
|
+
newChildren === null ||
|
|
951
|
+
typeof newChildren[Symbol.iterator] !== "function") &&
|
|
952
|
+
!Array.isArray(parent.children)) {
|
|
953
|
+
return diffChild(adapter, root, host, ctx, scope, parent, newChildren);
|
|
954
|
+
}
|
|
799
955
|
const oldRetained = wrap(parent.children);
|
|
800
956
|
const newRetained = [];
|
|
801
957
|
const newChildren1 = arrayify(newChildren);
|
|
@@ -1096,7 +1252,7 @@
|
|
|
1096
1252
|
}
|
|
1097
1253
|
}
|
|
1098
1254
|
if (skippedHydrationNodes) {
|
|
1099
|
-
skippedHydrationNodes.splice(0,
|
|
1255
|
+
skippedHydrationNodes.splice(0, value == null ? 0 : Array.isArray(value) ? value.length : 1);
|
|
1100
1256
|
}
|
|
1101
1257
|
if (!getFlag(ret, DidCommit)) {
|
|
1102
1258
|
setFlag(ret, DidCommit);
|
|
@@ -1111,8 +1267,17 @@
|
|
|
1111
1267
|
}
|
|
1112
1268
|
function commitChildren(adapter, host, ctx, scope, root, parent, index, schedulePromises, hydrationNodes) {
|
|
1113
1269
|
let values = [];
|
|
1114
|
-
|
|
1115
|
-
|
|
1270
|
+
const rawChildren = parent.children;
|
|
1271
|
+
const isChildrenArray = Array.isArray(rawChildren);
|
|
1272
|
+
const childrenLength = rawChildren === undefined
|
|
1273
|
+
? 0
|
|
1274
|
+
: isChildrenArray
|
|
1275
|
+
? rawChildren.length
|
|
1276
|
+
: 1;
|
|
1277
|
+
for (let i = 0; i < childrenLength; i++) {
|
|
1278
|
+
let child = isChildrenArray
|
|
1279
|
+
? rawChildren[i]
|
|
1280
|
+
: rawChildren;
|
|
1116
1281
|
let schedulePromises1;
|
|
1117
1282
|
let isSchedulingFallback = false;
|
|
1118
1283
|
while (child &&
|
|
@@ -1397,6 +1562,7 @@
|
|
|
1397
1562
|
props,
|
|
1398
1563
|
children,
|
|
1399
1564
|
oldProps,
|
|
1565
|
+
scope,
|
|
1400
1566
|
root,
|
|
1401
1567
|
});
|
|
1402
1568
|
}
|
|
@@ -1554,12 +1720,18 @@
|
|
|
1554
1720
|
}
|
|
1555
1721
|
ret.graveyard = undefined;
|
|
1556
1722
|
}
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1723
|
+
const rawChildren = ret.children;
|
|
1724
|
+
if (Array.isArray(rawChildren)) {
|
|
1725
|
+
for (let i = 0; i < rawChildren.length; i++) {
|
|
1726
|
+
const child = rawChildren[i];
|
|
1727
|
+
if (typeof child === "object") {
|
|
1728
|
+
unmount(adapter, host, ctx, root, child, isNested);
|
|
1729
|
+
}
|
|
1561
1730
|
}
|
|
1562
1731
|
}
|
|
1732
|
+
else if (rawChildren !== undefined) {
|
|
1733
|
+
unmount(adapter, host, ctx, root, rawChildren, isNested);
|
|
1734
|
+
}
|
|
1563
1735
|
}
|
|
1564
1736
|
const provisionMaps = new WeakMap();
|
|
1565
1737
|
const scheduleMap = new WeakMap();
|
|
@@ -2429,12 +2601,16 @@
|
|
|
2429
2601
|
((typeof current.el.tag === "string" && current.el.tag !== Fragment) ||
|
|
2430
2602
|
current.el.tag === Portal);
|
|
2431
2603
|
if (current.children && !isHostBoundary) {
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
|
|
2604
|
+
if (Array.isArray(current.children)) {
|
|
2605
|
+
for (const child of current.children) {
|
|
2606
|
+
if (child) {
|
|
2607
|
+
stack.push(child);
|
|
2608
|
+
}
|
|
2436
2609
|
}
|
|
2437
2610
|
}
|
|
2611
|
+
else {
|
|
2612
|
+
stack.push(current.children);
|
|
2613
|
+
}
|
|
2438
2614
|
}
|
|
2439
2615
|
// Add fallback chains (only if current retainer is using fallback)
|
|
2440
2616
|
if (current.fallback && !getFlag(current, DidDiff)) {
|
|
@@ -2472,6 +2648,7 @@
|
|
|
2472
2648
|
props,
|
|
2473
2649
|
oldProps: props,
|
|
2474
2650
|
children: hostChildren,
|
|
2651
|
+
scope: host.scope,
|
|
2475
2652
|
root: ctx.root,
|
|
2476
2653
|
});
|
|
2477
2654
|
flush(ctx.adapter, ctx.root, ctx);
|
|
@@ -2746,6 +2923,96 @@
|
|
|
2746
2923
|
return String(value);
|
|
2747
2924
|
}
|
|
2748
2925
|
|
|
2926
|
+
// React SVG camelCase → standard SVG attribute mapping.
|
|
2927
|
+
// Only includes entries where the React name differs from the SVG attribute name.
|
|
2928
|
+
// Canonical source: https://github.com/facebook/react/blob/main/packages/react-dom-bindings/src/shared/possibleStandardNames.js
|
|
2929
|
+
const REACT_SVG_PROPS = {
|
|
2930
|
+
accentHeight: "accent-height",
|
|
2931
|
+
alignmentBaseline: "alignment-baseline",
|
|
2932
|
+
arabicForm: "arabic-form",
|
|
2933
|
+
baselineShift: "baseline-shift",
|
|
2934
|
+
capHeight: "cap-height",
|
|
2935
|
+
clipPath: "clip-path",
|
|
2936
|
+
clipRule: "clip-rule",
|
|
2937
|
+
colorInterpolation: "color-interpolation",
|
|
2938
|
+
colorInterpolationFilters: "color-interpolation-filters",
|
|
2939
|
+
colorProfile: "color-profile",
|
|
2940
|
+
colorRendering: "color-rendering",
|
|
2941
|
+
dominantBaseline: "dominant-baseline",
|
|
2942
|
+
enableBackground: "enable-background",
|
|
2943
|
+
fillOpacity: "fill-opacity",
|
|
2944
|
+
fillRule: "fill-rule",
|
|
2945
|
+
floodColor: "flood-color",
|
|
2946
|
+
floodOpacity: "flood-opacity",
|
|
2947
|
+
fontFamily: "font-family",
|
|
2948
|
+
fontSize: "font-size",
|
|
2949
|
+
fontSizeAdjust: "font-size-adjust",
|
|
2950
|
+
fontStretch: "font-stretch",
|
|
2951
|
+
fontStyle: "font-style",
|
|
2952
|
+
fontVariant: "font-variant",
|
|
2953
|
+
fontWeight: "font-weight",
|
|
2954
|
+
glyphName: "glyph-name",
|
|
2955
|
+
glyphOrientationHorizontal: "glyph-orientation-horizontal",
|
|
2956
|
+
glyphOrientationVertical: "glyph-orientation-vertical",
|
|
2957
|
+
horizAdvX: "horiz-adv-x",
|
|
2958
|
+
horizOriginX: "horiz-origin-x",
|
|
2959
|
+
imageRendering: "image-rendering",
|
|
2960
|
+
letterSpacing: "letter-spacing",
|
|
2961
|
+
lightingColor: "lighting-color",
|
|
2962
|
+
markerEnd: "marker-end",
|
|
2963
|
+
markerMid: "marker-mid",
|
|
2964
|
+
markerStart: "marker-start",
|
|
2965
|
+
overlinePosition: "overline-position",
|
|
2966
|
+
overlineThickness: "overline-thickness",
|
|
2967
|
+
paintOrder: "paint-order",
|
|
2968
|
+
pointerEvents: "pointer-events",
|
|
2969
|
+
renderingIntent: "rendering-intent",
|
|
2970
|
+
shapeRendering: "shape-rendering",
|
|
2971
|
+
stopColor: "stop-color",
|
|
2972
|
+
stopOpacity: "stop-opacity",
|
|
2973
|
+
strikethroughPosition: "strikethrough-position",
|
|
2974
|
+
strikethroughThickness: "strikethrough-thickness",
|
|
2975
|
+
strokeDasharray: "stroke-dasharray",
|
|
2976
|
+
strokeDashoffset: "stroke-dashoffset",
|
|
2977
|
+
strokeLinecap: "stroke-linecap",
|
|
2978
|
+
strokeLinejoin: "stroke-linejoin",
|
|
2979
|
+
strokeMiterlimit: "stroke-miterlimit",
|
|
2980
|
+
strokeOpacity: "stroke-opacity",
|
|
2981
|
+
strokeWidth: "stroke-width",
|
|
2982
|
+
textAnchor: "text-anchor",
|
|
2983
|
+
textDecoration: "text-decoration",
|
|
2984
|
+
textRendering: "text-rendering",
|
|
2985
|
+
transformOrigin: "transform-origin",
|
|
2986
|
+
underlinePosition: "underline-position",
|
|
2987
|
+
underlineThickness: "underline-thickness",
|
|
2988
|
+
unicodeBidi: "unicode-bidi",
|
|
2989
|
+
unicodeRange: "unicode-range",
|
|
2990
|
+
unitsPerEm: "units-per-em",
|
|
2991
|
+
vAlphabetic: "v-alphabetic",
|
|
2992
|
+
vHanging: "v-hanging",
|
|
2993
|
+
vIdeographic: "v-ideographic",
|
|
2994
|
+
vMathematical: "v-mathematical",
|
|
2995
|
+
vectorEffect: "vector-effect",
|
|
2996
|
+
vertAdvY: "vert-adv-y",
|
|
2997
|
+
vertOriginX: "vert-origin-x",
|
|
2998
|
+
vertOriginY: "vert-origin-y",
|
|
2999
|
+
wordSpacing: "word-spacing",
|
|
3000
|
+
writingMode: "writing-mode",
|
|
3001
|
+
xHeight: "x-height",
|
|
3002
|
+
// xlink/xml namespace attributes (deprecated in SVG 2 but still used)
|
|
3003
|
+
xlinkActuate: "xlink:actuate",
|
|
3004
|
+
xlinkArcrole: "xlink:arcrole",
|
|
3005
|
+
xlinkHref: "xlink:href",
|
|
3006
|
+
xlinkRole: "xlink:role",
|
|
3007
|
+
xlinkShow: "xlink:show",
|
|
3008
|
+
xlinkTitle: "xlink:title",
|
|
3009
|
+
xlinkType: "xlink:type",
|
|
3010
|
+
xmlBase: "xml:base",
|
|
3011
|
+
xmlLang: "xml:lang",
|
|
3012
|
+
xmlSpace: "xml:space",
|
|
3013
|
+
xmlnsXlink: "xmlns:xlink",
|
|
3014
|
+
};
|
|
3015
|
+
|
|
2749
3016
|
const SVG_NAMESPACE = "http://www.w3.org/2000/svg";
|
|
2750
3017
|
const MATHML_NAMESPACE = "http://www.w3.org/1998/Math/MathML";
|
|
2751
3018
|
function getRootDocument(root) {
|
|
@@ -2803,19 +3070,325 @@
|
|
|
2803
3070
|
}
|
|
2804
3071
|
}
|
|
2805
3072
|
}
|
|
3073
|
+
function patchProp(element, name, value, oldValue, props, isSVG, isMathML, copyProps, quietProps, isHydrating) {
|
|
3074
|
+
if (copyProps != null && copyProps.has(name)) {
|
|
3075
|
+
return;
|
|
3076
|
+
}
|
|
3077
|
+
// handle prop:name or attr:name properties
|
|
3078
|
+
const colonIndex = name.indexOf(":");
|
|
3079
|
+
if (colonIndex !== -1) {
|
|
3080
|
+
const [ns, name1] = [name.slice(0, colonIndex), name.slice(colonIndex + 1)];
|
|
3081
|
+
switch (ns) {
|
|
3082
|
+
case "prop":
|
|
3083
|
+
element[name1] = value;
|
|
3084
|
+
return;
|
|
3085
|
+
case "attr":
|
|
3086
|
+
if (value == null || value === false) {
|
|
3087
|
+
if (isHydrating && element.hasAttribute(name1)) {
|
|
3088
|
+
emitHydrationWarning(name, quietProps, value, element.getAttribute(name1), element);
|
|
3089
|
+
}
|
|
3090
|
+
element.removeAttribute(name1);
|
|
3091
|
+
return;
|
|
3092
|
+
}
|
|
3093
|
+
else if (value === true) {
|
|
3094
|
+
if (isHydrating && !element.hasAttribute(name1)) {
|
|
3095
|
+
emitHydrationWarning(name, quietProps, value, null, element);
|
|
3096
|
+
}
|
|
3097
|
+
element.setAttribute(name1, "");
|
|
3098
|
+
return;
|
|
3099
|
+
}
|
|
3100
|
+
if (typeof value !== "string") {
|
|
3101
|
+
value = String(value);
|
|
3102
|
+
}
|
|
3103
|
+
if (isHydrating && element.getAttribute(name1) !== value) {
|
|
3104
|
+
emitHydrationWarning(name, quietProps, value, element.getAttribute(name1), element);
|
|
3105
|
+
}
|
|
3106
|
+
element.setAttribute(name1, value);
|
|
3107
|
+
return;
|
|
3108
|
+
}
|
|
3109
|
+
}
|
|
3110
|
+
switch (name) {
|
|
3111
|
+
// TODO: fix hydration warnings for the style prop
|
|
3112
|
+
case "style": {
|
|
3113
|
+
const style = element.style;
|
|
3114
|
+
if (value == null || value === false) {
|
|
3115
|
+
if (isHydrating && style.cssText !== "") {
|
|
3116
|
+
emitHydrationWarning(name, quietProps, value, style.cssText, element);
|
|
3117
|
+
}
|
|
3118
|
+
element.removeAttribute("style");
|
|
3119
|
+
}
|
|
3120
|
+
else if (value === true) {
|
|
3121
|
+
if (isHydrating && style.cssText !== "") {
|
|
3122
|
+
emitHydrationWarning(name, quietProps, "", style.cssText, element);
|
|
3123
|
+
}
|
|
3124
|
+
element.setAttribute("style", "");
|
|
3125
|
+
}
|
|
3126
|
+
else if (typeof value === "string") {
|
|
3127
|
+
if (style.cssText !== value) {
|
|
3128
|
+
// TODO: Fix hydration warnings for styles
|
|
3129
|
+
//if (isHydrating) {
|
|
3130
|
+
// emitHydrationWarning(
|
|
3131
|
+
// name,
|
|
3132
|
+
// quietProps,
|
|
3133
|
+
// value,
|
|
3134
|
+
// style.cssText,
|
|
3135
|
+
// element,
|
|
3136
|
+
// );
|
|
3137
|
+
//}
|
|
3138
|
+
style.cssText = value;
|
|
3139
|
+
}
|
|
3140
|
+
}
|
|
3141
|
+
else {
|
|
3142
|
+
if (typeof oldValue === "string") {
|
|
3143
|
+
// if the old value was a string, we need to clear the style
|
|
3144
|
+
// TODO: only clear the styles enumerated in the old value
|
|
3145
|
+
style.cssText = "";
|
|
3146
|
+
}
|
|
3147
|
+
// First pass: remove styles present in oldValue but not in value
|
|
3148
|
+
if (oldValue) {
|
|
3149
|
+
for (const styleName in oldValue) {
|
|
3150
|
+
if (value && styleName in value)
|
|
3151
|
+
continue;
|
|
3152
|
+
const cssName = camelToKebabCase(styleName);
|
|
3153
|
+
if (isHydrating && style.getPropertyValue(cssName) !== "") {
|
|
3154
|
+
emitHydrationWarning(name, quietProps, null, style.getPropertyValue(cssName), element, `style.${styleName}`);
|
|
3155
|
+
}
|
|
3156
|
+
style.removeProperty(cssName);
|
|
3157
|
+
}
|
|
3158
|
+
}
|
|
3159
|
+
// Second pass: apply all styles from value
|
|
3160
|
+
if (value) {
|
|
3161
|
+
for (const styleName in value) {
|
|
3162
|
+
const cssName = camelToKebabCase(styleName);
|
|
3163
|
+
const styleValue = value[styleName];
|
|
3164
|
+
if (styleValue == null) {
|
|
3165
|
+
if (isHydrating && style.getPropertyValue(cssName) !== "") {
|
|
3166
|
+
emitHydrationWarning(name, quietProps, null, style.getPropertyValue(cssName), element, `style.${styleName}`);
|
|
3167
|
+
}
|
|
3168
|
+
style.removeProperty(cssName);
|
|
3169
|
+
}
|
|
3170
|
+
else {
|
|
3171
|
+
const formattedValue = formatStyleValue(cssName, styleValue);
|
|
3172
|
+
if (style.getPropertyValue(cssName) !== formattedValue) {
|
|
3173
|
+
// TODO: hydration warnings for style props
|
|
3174
|
+
//if (isHydrating) {
|
|
3175
|
+
// emitHydrationWarning(
|
|
3176
|
+
// name,
|
|
3177
|
+
// quietProps,
|
|
3178
|
+
// formattedValue,
|
|
3179
|
+
// style.getPropertyValue(cssName),
|
|
3180
|
+
// element,
|
|
3181
|
+
// `style.${styleName}`,
|
|
3182
|
+
// );
|
|
3183
|
+
//}
|
|
3184
|
+
style.setProperty(cssName, formattedValue);
|
|
3185
|
+
}
|
|
3186
|
+
}
|
|
3187
|
+
}
|
|
3188
|
+
}
|
|
3189
|
+
}
|
|
3190
|
+
break;
|
|
3191
|
+
}
|
|
3192
|
+
case "class":
|
|
3193
|
+
case "className":
|
|
3194
|
+
if (name === "className" && "class" in props)
|
|
3195
|
+
break;
|
|
3196
|
+
if (value === true) {
|
|
3197
|
+
if (isHydrating && element.getAttribute("class") !== "") {
|
|
3198
|
+
emitHydrationWarning(name, quietProps, "", element.getAttribute("class"), element);
|
|
3199
|
+
}
|
|
3200
|
+
element.setAttribute("class", "");
|
|
3201
|
+
}
|
|
3202
|
+
else if (value == null) {
|
|
3203
|
+
if (isHydrating && element.hasAttribute("class")) {
|
|
3204
|
+
emitHydrationWarning(name, quietProps, value, element.getAttribute("class"), element);
|
|
3205
|
+
}
|
|
3206
|
+
element.removeAttribute("class");
|
|
3207
|
+
}
|
|
3208
|
+
else if (typeof value === "object") {
|
|
3209
|
+
// class={{"included-class": true, "excluded-class": false}} syntax
|
|
3210
|
+
if (typeof oldValue === "string") {
|
|
3211
|
+
// if the old value was a string, we need to clear all classes
|
|
3212
|
+
element.setAttribute("class", "");
|
|
3213
|
+
}
|
|
3214
|
+
let shouldIssueWarning = false;
|
|
3215
|
+
const hydratingClasses = isHydrating
|
|
3216
|
+
? new Set(Array.from(element.classList))
|
|
3217
|
+
: undefined;
|
|
3218
|
+
const hydratingClassName = isHydrating
|
|
3219
|
+
? element.getAttribute("class")
|
|
3220
|
+
: undefined;
|
|
3221
|
+
// Two passes: removes first, then adds. This ensures that
|
|
3222
|
+
// overlapping classes in different keys are handled correctly.
|
|
3223
|
+
// e.g. {"a b": false, "b c": true} should result in "b c"
|
|
3224
|
+
// Remove pass: iterate oldValue for classes to remove
|
|
3225
|
+
if (oldValue) {
|
|
3226
|
+
for (const classNames in oldValue) {
|
|
3227
|
+
if (value && value[classNames])
|
|
3228
|
+
continue;
|
|
3229
|
+
const classes = classNames.split(/\s+/).filter(Boolean);
|
|
3230
|
+
element.classList.remove(...classes);
|
|
3231
|
+
}
|
|
3232
|
+
}
|
|
3233
|
+
// Add pass: iterate value for classes to add
|
|
3234
|
+
if (value) {
|
|
3235
|
+
for (const classNames in value) {
|
|
3236
|
+
if (!value[classNames])
|
|
3237
|
+
continue;
|
|
3238
|
+
const classes = classNames.split(/\s+/).filter(Boolean);
|
|
3239
|
+
element.classList.add(...classes);
|
|
3240
|
+
for (const className of classes) {
|
|
3241
|
+
if (hydratingClasses && hydratingClasses.has(className)) {
|
|
3242
|
+
hydratingClasses.delete(className);
|
|
3243
|
+
}
|
|
3244
|
+
else if (isHydrating) {
|
|
3245
|
+
shouldIssueWarning = true;
|
|
3246
|
+
}
|
|
3247
|
+
}
|
|
3248
|
+
}
|
|
3249
|
+
}
|
|
3250
|
+
if (shouldIssueWarning ||
|
|
3251
|
+
(hydratingClasses && hydratingClasses.size > 0)) {
|
|
3252
|
+
emitHydrationWarning(name, quietProps, Object.keys(value)
|
|
3253
|
+
.filter((k) => value[k])
|
|
3254
|
+
.join(" "), hydratingClassName || "", element);
|
|
3255
|
+
}
|
|
3256
|
+
}
|
|
3257
|
+
else if (!isSVG && !isMathML) {
|
|
3258
|
+
if (element.className !== value) {
|
|
3259
|
+
if (isHydrating) {
|
|
3260
|
+
emitHydrationWarning(name, quietProps, value, element.className, element);
|
|
3261
|
+
}
|
|
3262
|
+
element.className = value;
|
|
3263
|
+
}
|
|
3264
|
+
}
|
|
3265
|
+
else if (element.getAttribute("class") !== value) {
|
|
3266
|
+
if (isHydrating) {
|
|
3267
|
+
emitHydrationWarning(name, quietProps, value, element.getAttribute("class"), element);
|
|
3268
|
+
}
|
|
3269
|
+
element.setAttribute("class", value);
|
|
3270
|
+
}
|
|
3271
|
+
break;
|
|
3272
|
+
case "innerHTML":
|
|
3273
|
+
if (value !== oldValue) {
|
|
3274
|
+
if (isHydrating) {
|
|
3275
|
+
emitHydrationWarning(name, quietProps, value, element.innerHTML, element);
|
|
3276
|
+
}
|
|
3277
|
+
element.innerHTML = value;
|
|
3278
|
+
}
|
|
3279
|
+
break;
|
|
3280
|
+
case "dangerouslySetInnerHTML": {
|
|
3281
|
+
const htmlValue = value && typeof value === "object" && "__html" in value
|
|
3282
|
+
? (value.__html ?? "")
|
|
3283
|
+
: "";
|
|
3284
|
+
const oldHtmlValue = oldValue && typeof oldValue === "object" && "__html" in oldValue
|
|
3285
|
+
? (oldValue.__html ?? "")
|
|
3286
|
+
: "";
|
|
3287
|
+
if (htmlValue !== oldHtmlValue) {
|
|
3288
|
+
element.innerHTML = htmlValue;
|
|
3289
|
+
}
|
|
3290
|
+
break;
|
|
3291
|
+
}
|
|
3292
|
+
case "htmlFor":
|
|
3293
|
+
if ("for" in props)
|
|
3294
|
+
break;
|
|
3295
|
+
if (value == null || value === false) {
|
|
3296
|
+
element.removeAttribute("for");
|
|
3297
|
+
}
|
|
3298
|
+
else {
|
|
3299
|
+
element.setAttribute("for", String(value === true ? "" : value));
|
|
3300
|
+
}
|
|
3301
|
+
break;
|
|
3302
|
+
default: {
|
|
3303
|
+
if (name[0] === "o" &&
|
|
3304
|
+
name[1] === "n" &&
|
|
3305
|
+
name[2] === name[2].toUpperCase() &&
|
|
3306
|
+
typeof value === "function") {
|
|
3307
|
+
// Support React-style event names (onClick, onChange, etc.)
|
|
3308
|
+
name = name.toLowerCase();
|
|
3309
|
+
}
|
|
3310
|
+
// Support React-style SVG attribute names (strokeWidth, etc.)
|
|
3311
|
+
if (isSVG && name in REACT_SVG_PROPS) {
|
|
3312
|
+
name = REACT_SVG_PROPS[name];
|
|
3313
|
+
}
|
|
3314
|
+
// try to set the property directly
|
|
3315
|
+
if (name in element &&
|
|
3316
|
+
// boolean properties will coerce strings, but sometimes they map to
|
|
3317
|
+
// enumerated attributes, where truthy strings ("false", "no") map to
|
|
3318
|
+
// falsy properties, so we force using setAttribute.
|
|
3319
|
+
!(typeof value === "string" &&
|
|
3320
|
+
typeof element[name] === "boolean") &&
|
|
3321
|
+
isWritableProperty(element, name)) {
|
|
3322
|
+
// For URL properties like src and href, the DOM property returns the
|
|
3323
|
+
// resolved absolute URL. We need to resolve the prop value the same way
|
|
3324
|
+
// to compare correctly.
|
|
3325
|
+
let domValue = element[name];
|
|
3326
|
+
let propValue = value;
|
|
3327
|
+
if ((name === "src" || name === "href") &&
|
|
3328
|
+
typeof value === "string" &&
|
|
3329
|
+
typeof domValue === "string") {
|
|
3330
|
+
try {
|
|
3331
|
+
propValue = new URL(value, element.baseURI).href;
|
|
3332
|
+
}
|
|
3333
|
+
catch {
|
|
3334
|
+
// Invalid URL, use original value for comparison
|
|
3335
|
+
}
|
|
3336
|
+
}
|
|
3337
|
+
if (propValue !== domValue || oldValue === undefined) {
|
|
3338
|
+
if (isHydrating &&
|
|
3339
|
+
typeof element[name] === "string" &&
|
|
3340
|
+
element[name] !== value) {
|
|
3341
|
+
emitHydrationWarning(name, quietProps, value, element[name], element);
|
|
3342
|
+
}
|
|
3343
|
+
// if the property is writable, assign it directly
|
|
3344
|
+
element[name] = value;
|
|
3345
|
+
}
|
|
3346
|
+
return;
|
|
3347
|
+
}
|
|
3348
|
+
if (value === true) {
|
|
3349
|
+
value = "";
|
|
3350
|
+
}
|
|
3351
|
+
else if (value == null || value === false) {
|
|
3352
|
+
if (isHydrating && element.hasAttribute(name)) {
|
|
3353
|
+
emitHydrationWarning(name, quietProps, value, element.getAttribute(name), element);
|
|
3354
|
+
}
|
|
3355
|
+
element.removeAttribute(name);
|
|
3356
|
+
return;
|
|
3357
|
+
}
|
|
3358
|
+
else if (typeof value !== "string") {
|
|
3359
|
+
value = String(value);
|
|
3360
|
+
}
|
|
3361
|
+
if (element.getAttribute(name) !== value) {
|
|
3362
|
+
if (isHydrating) {
|
|
3363
|
+
emitHydrationWarning(name, quietProps, value, element.getAttribute(name), element);
|
|
3364
|
+
}
|
|
3365
|
+
element.setAttribute(name, value);
|
|
3366
|
+
}
|
|
3367
|
+
}
|
|
3368
|
+
}
|
|
3369
|
+
}
|
|
2806
3370
|
const adapter = {
|
|
2807
|
-
scope({ scope: xmlns, tag, props, }) {
|
|
3371
|
+
scope({ scope: xmlns, tag, props, root, }) {
|
|
2808
3372
|
switch (tag) {
|
|
2809
|
-
case Portal:
|
|
2810
|
-
|
|
2811
|
-
xmlns =
|
|
3373
|
+
case Portal: {
|
|
3374
|
+
const ns = root instanceof Element ? root.namespaceURI : null;
|
|
3375
|
+
xmlns =
|
|
3376
|
+
ns === SVG_NAMESPACE
|
|
3377
|
+
? SVG_NAMESPACE
|
|
3378
|
+
: ns === MATHML_NAMESPACE
|
|
3379
|
+
? MATHML_NAMESPACE
|
|
3380
|
+
: undefined;
|
|
2812
3381
|
break;
|
|
3382
|
+
}
|
|
2813
3383
|
case "svg":
|
|
2814
3384
|
xmlns = SVG_NAMESPACE;
|
|
2815
3385
|
break;
|
|
2816
3386
|
case "math":
|
|
2817
3387
|
xmlns = MATHML_NAMESPACE;
|
|
2818
3388
|
break;
|
|
3389
|
+
case "foreignObject":
|
|
3390
|
+
xmlns = undefined;
|
|
3391
|
+
break;
|
|
2819
3392
|
}
|
|
2820
3393
|
return props.xmlns || xmlns;
|
|
2821
3394
|
},
|
|
@@ -2829,6 +3402,9 @@
|
|
|
2829
3402
|
else if (tag.toLowerCase() === "math") {
|
|
2830
3403
|
xmlns = MATHML_NAMESPACE;
|
|
2831
3404
|
}
|
|
3405
|
+
else if (tag === "foreignObject") {
|
|
3406
|
+
xmlns = SVG_NAMESPACE;
|
|
3407
|
+
}
|
|
2832
3408
|
const doc = getRootDocument(root);
|
|
2833
3409
|
return xmlns ? doc.createElementNS(xmlns, tag) : doc.createElement(tag);
|
|
2834
3410
|
},
|
|
@@ -2852,7 +3428,7 @@
|
|
|
2852
3428
|
}
|
|
2853
3429
|
return Array.from(node.childNodes);
|
|
2854
3430
|
},
|
|
2855
|
-
patch({ tagName, node, props, oldProps, scope: xmlns, copyProps, quietProps, isHydrating, }) {
|
|
3431
|
+
patch({ tag, tagName, node, props, oldProps, scope: xmlns, copyProps, quietProps, isHydrating, }) {
|
|
2856
3432
|
if (node.nodeType !== Node.ELEMENT_NODE) {
|
|
2857
3433
|
throw new TypeError(`Cannot patch node: ${String(node)}`);
|
|
2858
3434
|
}
|
|
@@ -2860,268 +3436,26 @@
|
|
|
2860
3436
|
console.error(`Both "class" and "className" set in props for <${tagName}>. Use one or the other.`);
|
|
2861
3437
|
}
|
|
2862
3438
|
const element = node;
|
|
2863
|
-
const isSVG = xmlns === SVG_NAMESPACE;
|
|
3439
|
+
const isSVG = xmlns === SVG_NAMESPACE || tag === "foreignObject";
|
|
2864
3440
|
const isMathML = xmlns === MATHML_NAMESPACE;
|
|
2865
|
-
|
|
2866
|
-
|
|
2867
|
-
|
|
2868
|
-
|
|
2869
|
-
if (copyProps != null && copyProps.has(name)) {
|
|
3441
|
+
// First pass: iterate oldProps to handle removals
|
|
3442
|
+
if (oldProps) {
|
|
3443
|
+
for (let name in oldProps) {
|
|
3444
|
+
if (name in props)
|
|
2870
3445
|
continue;
|
|
2871
|
-
|
|
2872
|
-
// handle prop:name or attr:name properties
|
|
2873
|
-
const colonIndex = name.indexOf(":");
|
|
2874
|
-
if (colonIndex !== -1) {
|
|
2875
|
-
const [ns, name1] = [
|
|
2876
|
-
name.slice(0, colonIndex),
|
|
2877
|
-
name.slice(colonIndex + 1),
|
|
2878
|
-
];
|
|
2879
|
-
switch (ns) {
|
|
2880
|
-
case "prop":
|
|
2881
|
-
node[name1] = value;
|
|
2882
|
-
continue;
|
|
2883
|
-
case "attr":
|
|
2884
|
-
if (value == null || value === false) {
|
|
2885
|
-
if (isHydrating && element.hasAttribute(name1)) {
|
|
2886
|
-
emitHydrationWarning(name, quietProps, value, element.getAttribute(name1), element);
|
|
2887
|
-
}
|
|
2888
|
-
element.removeAttribute(name1);
|
|
2889
|
-
}
|
|
2890
|
-
else if (value === true) {
|
|
2891
|
-
if (isHydrating && !element.hasAttribute(name1)) {
|
|
2892
|
-
emitHydrationWarning(name, quietProps, value, null, element);
|
|
2893
|
-
}
|
|
2894
|
-
element.setAttribute(name1, "");
|
|
2895
|
-
}
|
|
2896
|
-
else if (typeof value !== "string") {
|
|
2897
|
-
value = String(value);
|
|
2898
|
-
}
|
|
2899
|
-
if (isHydrating && element.getAttribute(name1) !== value) {
|
|
2900
|
-
emitHydrationWarning(name, quietProps, value, element.getAttribute(name1), element);
|
|
2901
|
-
}
|
|
2902
|
-
element.setAttribute(name1, String(value));
|
|
2903
|
-
continue;
|
|
2904
|
-
}
|
|
2905
|
-
}
|
|
2906
|
-
}
|
|
2907
|
-
switch (name) {
|
|
2908
|
-
// TODO: fix hydration warnings for the style prop
|
|
2909
|
-
case "style": {
|
|
2910
|
-
const style = element.style;
|
|
2911
|
-
if (value == null || value === false) {
|
|
2912
|
-
if (isHydrating && style.cssText !== "") {
|
|
2913
|
-
emitHydrationWarning(name, quietProps, value, style.cssText, element);
|
|
2914
|
-
}
|
|
2915
|
-
element.removeAttribute("style");
|
|
2916
|
-
}
|
|
2917
|
-
else if (value === true) {
|
|
2918
|
-
if (isHydrating && style.cssText !== "") {
|
|
2919
|
-
emitHydrationWarning(name, quietProps, "", style.cssText, element);
|
|
2920
|
-
}
|
|
2921
|
-
element.setAttribute("style", "");
|
|
2922
|
-
}
|
|
2923
|
-
else if (typeof value === "string") {
|
|
2924
|
-
if (style.cssText !== value) {
|
|
2925
|
-
// TODO: Fix hydration warnings for styles
|
|
2926
|
-
//if (isHydrating) {
|
|
2927
|
-
// emitHydrationWarning(
|
|
2928
|
-
// name,
|
|
2929
|
-
// quietProps,
|
|
2930
|
-
// value,
|
|
2931
|
-
// style.cssText,
|
|
2932
|
-
// element,
|
|
2933
|
-
// );
|
|
2934
|
-
//}
|
|
2935
|
-
style.cssText = value;
|
|
2936
|
-
}
|
|
2937
|
-
}
|
|
2938
|
-
else {
|
|
2939
|
-
if (typeof oldValue === "string") {
|
|
2940
|
-
// if the old value was a string, we need to clear the style
|
|
2941
|
-
// TODO: only clear the styles enumerated in the old value
|
|
2942
|
-
style.cssText = "";
|
|
2943
|
-
}
|
|
2944
|
-
for (const styleName in { ...oldValue, ...value }) {
|
|
2945
|
-
const cssName = camelToKebabCase(styleName);
|
|
2946
|
-
const styleValue = value && value[styleName];
|
|
2947
|
-
if (styleValue == null) {
|
|
2948
|
-
if (isHydrating && style.getPropertyValue(cssName) !== "") {
|
|
2949
|
-
emitHydrationWarning(name, quietProps, null, style.getPropertyValue(cssName), element, `style.${styleName}`);
|
|
2950
|
-
}
|
|
2951
|
-
style.removeProperty(cssName);
|
|
2952
|
-
}
|
|
2953
|
-
else {
|
|
2954
|
-
const formattedValue = formatStyleValue(cssName, styleValue);
|
|
2955
|
-
if (style.getPropertyValue(cssName) !== formattedValue) {
|
|
2956
|
-
// TODO: hydration warnings for style props
|
|
2957
|
-
//if (isHydrating) {
|
|
2958
|
-
// emitHydrationWarning(
|
|
2959
|
-
// name,
|
|
2960
|
-
// quietProps,
|
|
2961
|
-
// formattedValue,
|
|
2962
|
-
// style.getPropertyValue(cssName),
|
|
2963
|
-
// element,
|
|
2964
|
-
// `style.${styleName}`,
|
|
2965
|
-
// );
|
|
2966
|
-
//}
|
|
2967
|
-
style.setProperty(cssName, formattedValue);
|
|
2968
|
-
}
|
|
2969
|
-
}
|
|
2970
|
-
}
|
|
2971
|
-
}
|
|
2972
|
-
break;
|
|
2973
|
-
}
|
|
2974
|
-
case "class":
|
|
2975
|
-
case "className":
|
|
2976
|
-
if (value === true) {
|
|
2977
|
-
if (isHydrating && element.getAttribute("class") !== "") {
|
|
2978
|
-
emitHydrationWarning(name, quietProps, "", element.getAttribute("class"), element);
|
|
2979
|
-
}
|
|
2980
|
-
element.setAttribute("class", "");
|
|
2981
|
-
}
|
|
2982
|
-
else if (value == null) {
|
|
2983
|
-
if (isHydrating && element.hasAttribute("class")) {
|
|
2984
|
-
emitHydrationWarning(name, quietProps, value, element.getAttribute("class"), element);
|
|
2985
|
-
}
|
|
2986
|
-
element.removeAttribute("class");
|
|
2987
|
-
}
|
|
2988
|
-
else if (typeof value === "object") {
|
|
2989
|
-
// class={{"included-class": true, "excluded-class": false}} syntax
|
|
2990
|
-
if (typeof oldValue === "string") {
|
|
2991
|
-
// if the old value was a string, we need to clear all classes
|
|
2992
|
-
element.setAttribute("class", "");
|
|
2993
|
-
}
|
|
2994
|
-
let shouldIssueWarning = false;
|
|
2995
|
-
const hydratingClasses = isHydrating
|
|
2996
|
-
? new Set(Array.from(element.classList))
|
|
2997
|
-
: undefined;
|
|
2998
|
-
const hydratingClassName = isHydrating
|
|
2999
|
-
? element.getAttribute("class")
|
|
3000
|
-
: undefined;
|
|
3001
|
-
const allClassNames = { ...oldValue, ...value };
|
|
3002
|
-
// Two passes: removes first, then adds. This ensures that
|
|
3003
|
-
// overlapping classes in different keys are handled correctly.
|
|
3004
|
-
// e.g. {"a b": false, "b c": true} should result in "b c"
|
|
3005
|
-
for (const classNames in allClassNames) {
|
|
3006
|
-
if (!(value && value[classNames])) {
|
|
3007
|
-
const classes = classNames.split(/\s+/).filter(Boolean);
|
|
3008
|
-
element.classList.remove(...classes);
|
|
3009
|
-
}
|
|
3010
|
-
}
|
|
3011
|
-
for (const classNames in allClassNames) {
|
|
3012
|
-
if (value && value[classNames]) {
|
|
3013
|
-
const classes = classNames.split(/\s+/).filter(Boolean);
|
|
3014
|
-
element.classList.add(...classes);
|
|
3015
|
-
for (const className of classes) {
|
|
3016
|
-
if (hydratingClasses && hydratingClasses.has(className)) {
|
|
3017
|
-
hydratingClasses.delete(className);
|
|
3018
|
-
}
|
|
3019
|
-
else if (isHydrating) {
|
|
3020
|
-
shouldIssueWarning = true;
|
|
3021
|
-
}
|
|
3022
|
-
}
|
|
3023
|
-
}
|
|
3024
|
-
}
|
|
3025
|
-
if (shouldIssueWarning ||
|
|
3026
|
-
(hydratingClasses && hydratingClasses.size > 0)) {
|
|
3027
|
-
emitHydrationWarning(name, quietProps, Object.keys(value)
|
|
3028
|
-
.filter((k) => value[k])
|
|
3029
|
-
.join(" "), hydratingClassName || "", element);
|
|
3030
|
-
}
|
|
3031
|
-
}
|
|
3032
|
-
else if (!isSVG && !isMathML) {
|
|
3033
|
-
if (element.className !== value) {
|
|
3034
|
-
if (isHydrating) {
|
|
3035
|
-
emitHydrationWarning(name, quietProps, value, element.className, element);
|
|
3036
|
-
}
|
|
3037
|
-
element.className = value;
|
|
3038
|
-
}
|
|
3039
|
-
}
|
|
3040
|
-
else if (element.getAttribute("class") !== value) {
|
|
3041
|
-
if (isHydrating) {
|
|
3042
|
-
emitHydrationWarning(name, quietProps, value, element.getAttribute("class"), element);
|
|
3043
|
-
}
|
|
3044
|
-
element.setAttribute("class", value);
|
|
3045
|
-
}
|
|
3046
|
-
break;
|
|
3047
|
-
case "innerHTML":
|
|
3048
|
-
if (value !== oldValue) {
|
|
3049
|
-
if (isHydrating) {
|
|
3050
|
-
emitHydrationWarning(name, quietProps, value, element.innerHTML, element);
|
|
3051
|
-
}
|
|
3052
|
-
element.innerHTML = value;
|
|
3053
|
-
}
|
|
3054
|
-
break;
|
|
3055
|
-
default: {
|
|
3056
|
-
if (name[0] === "o" &&
|
|
3057
|
-
name[1] === "n" &&
|
|
3058
|
-
name[2] === name[2].toUpperCase() &&
|
|
3059
|
-
typeof value === "function") {
|
|
3060
|
-
// Support React-style event names (onClick, onChange, etc.)
|
|
3061
|
-
name = name.toLowerCase();
|
|
3062
|
-
}
|
|
3063
|
-
// try to set the property directly
|
|
3064
|
-
if (name in element &&
|
|
3065
|
-
// boolean properties will coerce strings, but sometimes they map to
|
|
3066
|
-
// enumerated attributes, where truthy strings ("false", "no") map to
|
|
3067
|
-
// falsy properties, so we force using setAttribute.
|
|
3068
|
-
!(typeof value === "string" &&
|
|
3069
|
-
typeof element[name] === "boolean") &&
|
|
3070
|
-
isWritableProperty(element, name)) {
|
|
3071
|
-
// For URL properties like src and href, the DOM property returns the
|
|
3072
|
-
// resolved absolute URL. We need to resolve the prop value the same way
|
|
3073
|
-
// to compare correctly.
|
|
3074
|
-
let domValue = element[name];
|
|
3075
|
-
let propValue = value;
|
|
3076
|
-
if ((name === "src" || name === "href") &&
|
|
3077
|
-
typeof value === "string" &&
|
|
3078
|
-
typeof domValue === "string") {
|
|
3079
|
-
try {
|
|
3080
|
-
propValue = new URL(value, element.baseURI).href;
|
|
3081
|
-
}
|
|
3082
|
-
catch {
|
|
3083
|
-
// Invalid URL, use original value for comparison
|
|
3084
|
-
}
|
|
3085
|
-
}
|
|
3086
|
-
if (propValue !== domValue || oldValue === undefined) {
|
|
3087
|
-
if (isHydrating &&
|
|
3088
|
-
typeof element[name] === "string" &&
|
|
3089
|
-
element[name] !== value) {
|
|
3090
|
-
emitHydrationWarning(name, quietProps, value, element[name], element);
|
|
3091
|
-
}
|
|
3092
|
-
// if the property is writable, assign it directly
|
|
3093
|
-
element[name] = value;
|
|
3094
|
-
}
|
|
3095
|
-
continue;
|
|
3096
|
-
}
|
|
3097
|
-
if (value === true) {
|
|
3098
|
-
value = "";
|
|
3099
|
-
}
|
|
3100
|
-
else if (value == null || value === false) {
|
|
3101
|
-
if (isHydrating && element.hasAttribute(name)) {
|
|
3102
|
-
emitHydrationWarning(name, quietProps, value, element.getAttribute(name), element);
|
|
3103
|
-
}
|
|
3104
|
-
element.removeAttribute(name);
|
|
3105
|
-
continue;
|
|
3106
|
-
}
|
|
3107
|
-
else if (typeof value !== "string") {
|
|
3108
|
-
value = String(value);
|
|
3109
|
-
}
|
|
3110
|
-
if (element.getAttribute(name) !== value) {
|
|
3111
|
-
if (isHydrating) {
|
|
3112
|
-
emitHydrationWarning(name, quietProps, value, element.getAttribute(name), element);
|
|
3113
|
-
}
|
|
3114
|
-
element.setAttribute(name, value);
|
|
3115
|
-
}
|
|
3116
|
-
}
|
|
3446
|
+
patchProp(element, name, undefined, oldProps[name], props, isSVG, isMathML, copyProps, quietProps, isHydrating);
|
|
3117
3447
|
}
|
|
3118
3448
|
}
|
|
3449
|
+
// Second pass: iterate props to handle additions and updates
|
|
3450
|
+
for (let name in props) {
|
|
3451
|
+
patchProp(element, name, props[name], oldProps ? oldProps[name] : undefined, props, isSVG, isMathML, copyProps, quietProps, isHydrating);
|
|
3452
|
+
}
|
|
3119
3453
|
},
|
|
3120
3454
|
arrange({ tag, node, props, children, }) {
|
|
3121
3455
|
if (tag === Portal && (node == null || typeof node.nodeType !== "number")) {
|
|
3122
3456
|
throw new TypeError(`<Portal> root is not a node. Received: ${String(node)}`);
|
|
3123
3457
|
}
|
|
3124
|
-
if (!("innerHTML" in props)) {
|
|
3458
|
+
if (!("innerHTML" in props) && !("dangerouslySetInnerHTML" in props)) {
|
|
3125
3459
|
let oldChild = node.firstChild;
|
|
3126
3460
|
for (let i = 0; i < children.length; i++) {
|
|
3127
3461
|
const newChild = children[i];
|
|
@@ -3297,12 +3631,20 @@
|
|
|
3297
3631
|
}
|
|
3298
3632
|
return cssStrings.join("");
|
|
3299
3633
|
}
|
|
3300
|
-
function printAttrs(props) {
|
|
3634
|
+
function printAttrs(props, isSVG) {
|
|
3301
3635
|
const attrs = [];
|
|
3302
3636
|
for (let [name, value] of Object.entries(props)) {
|
|
3303
|
-
if (name === "innerHTML" ||
|
|
3637
|
+
if (name === "innerHTML" ||
|
|
3638
|
+
name === "dangerouslySetInnerHTML" ||
|
|
3639
|
+
name.startsWith("prop:")) {
|
|
3304
3640
|
continue;
|
|
3305
3641
|
}
|
|
3642
|
+
else if (name === "htmlFor") {
|
|
3643
|
+
if ("for" in props || value == null || value === false) {
|
|
3644
|
+
continue;
|
|
3645
|
+
}
|
|
3646
|
+
attrs.push(`for="${escape(String(value === true ? "" : value))}"`);
|
|
3647
|
+
}
|
|
3306
3648
|
else if (name === "style") {
|
|
3307
3649
|
if (typeof value === "string") {
|
|
3308
3650
|
attrs.push(`style="${escape(value)}"`);
|
|
@@ -3335,6 +3677,9 @@
|
|
|
3335
3677
|
if (name.startsWith("attr:")) {
|
|
3336
3678
|
name = name.slice("attr:".length);
|
|
3337
3679
|
}
|
|
3680
|
+
else if (isSVG && name in REACT_SVG_PROPS) {
|
|
3681
|
+
name = REACT_SVG_PROPS[name];
|
|
3682
|
+
}
|
|
3338
3683
|
if (typeof value === "string") {
|
|
3339
3684
|
attrs.push(`${escape(name)}="${escape(value)}"`);
|
|
3340
3685
|
}
|
|
@@ -3357,6 +3702,20 @@
|
|
|
3357
3702
|
return result;
|
|
3358
3703
|
}
|
|
3359
3704
|
const impl = {
|
|
3705
|
+
scope({ scope, tag, }) {
|
|
3706
|
+
if (tag === Portal) {
|
|
3707
|
+
return undefined;
|
|
3708
|
+
}
|
|
3709
|
+
switch (tag) {
|
|
3710
|
+
case "svg":
|
|
3711
|
+
return "svg";
|
|
3712
|
+
case "math":
|
|
3713
|
+
return "math";
|
|
3714
|
+
case "foreignObject":
|
|
3715
|
+
return undefined;
|
|
3716
|
+
}
|
|
3717
|
+
return scope;
|
|
3718
|
+
},
|
|
3360
3719
|
create() {
|
|
3361
3720
|
return { value: "" };
|
|
3362
3721
|
},
|
|
@@ -3377,14 +3736,14 @@
|
|
|
3377
3736
|
return value.value || "";
|
|
3378
3737
|
}
|
|
3379
3738
|
},
|
|
3380
|
-
arrange({ tag, tagName, node, props, children, }) {
|
|
3739
|
+
arrange({ tag, tagName, node, props, children, scope, }) {
|
|
3381
3740
|
if (tag === Portal) {
|
|
3382
3741
|
return;
|
|
3383
3742
|
}
|
|
3384
3743
|
else if (typeof tag !== "string") {
|
|
3385
3744
|
throw new Error(`Unknown tag: ${tagName}`);
|
|
3386
3745
|
}
|
|
3387
|
-
const attrs = printAttrs(props);
|
|
3746
|
+
const attrs = printAttrs(props, scope === "svg" || tag === "foreignObject");
|
|
3388
3747
|
const open = `<${tag}${attrs.length ? " " : ""}${attrs}>`;
|
|
3389
3748
|
let result;
|
|
3390
3749
|
if (voidTags.has(tag)) {
|
|
@@ -3392,7 +3751,11 @@
|
|
|
3392
3751
|
}
|
|
3393
3752
|
else {
|
|
3394
3753
|
const close = `</${tag}>`;
|
|
3395
|
-
const contents = "innerHTML" in props
|
|
3754
|
+
const contents = "innerHTML" in props
|
|
3755
|
+
? props["innerHTML"]
|
|
3756
|
+
: "dangerouslySetInnerHTML" in props
|
|
3757
|
+
? (props["dangerouslySetInnerHTML"]?.__html ?? "")
|
|
3758
|
+
: join(children);
|
|
3396
3759
|
result = `${open}${contents}${close}`;
|
|
3397
3760
|
}
|
|
3398
3761
|
node.value = result;
|
|
@@ -3414,7 +3777,7 @@
|
|
|
3414
3777
|
|
|
3415
3778
|
exports.Context = Context;
|
|
3416
3779
|
exports.Copy = Copy;
|
|
3417
|
-
exports.Element = Element;
|
|
3780
|
+
exports.Element = Element$1;
|
|
3418
3781
|
exports.Fragment = Fragment;
|
|
3419
3782
|
exports.Portal = Portal;
|
|
3420
3783
|
exports.Raw = Raw;
|