@b9g/crank 0.7.4 → 0.7.6
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/_css.cjs.map +1 -1
- package/_css.js.map +1 -1
- package/_svg.cjs +94 -0
- package/_svg.cjs.map +1 -0
- package/_svg.js +92 -0
- package/_svg.js.map +1 -0
- package/_utils.cjs.map +1 -1
- package/_utils.js.map +1 -1
- 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 +198 -16
- package/crank.cjs.map +1 -1
- package/crank.js +198 -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/event-target.cjs.map +1 -1
- package/event-target.js.map +1 -1
- package/html.cjs +35 -5
- package/html.cjs.map +1 -1
- package/html.js +35 -5
- package/html.js.map +1 -1
- package/jsx-runtime.cjs.map +1 -1
- package/jsx-runtime.js.map +1 -1
- package/jsx-tag.cjs +86 -21
- package/jsx-tag.cjs.map +1 -1
- 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.js +2 -0
- package/standalone.js.map +1 -1
- package/umd.js +653 -285
- package/umd.js.map +1 -1
- package/_css.d.ts +0 -21
- package/_utils.d.ts +0 -14
- package/async.d.ts +0 -107
- package/crank.d.ts +0 -732
- package/dom.d.ts +0 -14
- package/event-target.d.ts +0 -26
- package/html.d.ts +0 -24
- package/jsx-runtime.d.ts +0 -6
- package/jsx-tag.d.ts +0 -4
- package/standalone.d.ts +0 -2
- package/umd.d.ts +0 -3
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)) {
|
|
@@ -2458,6 +2634,11 @@
|
|
|
2458
2634
|
if (!isRetainerActive(initiator, host)) {
|
|
2459
2635
|
return;
|
|
2460
2636
|
}
|
|
2637
|
+
// Check if host has been committed (has a node)
|
|
2638
|
+
// Fixes #334: refresh() called before component yields
|
|
2639
|
+
if (!getFlag(host, DidCommit)) {
|
|
2640
|
+
return;
|
|
2641
|
+
}
|
|
2461
2642
|
const props = stripSpecialProps(host.el.props);
|
|
2462
2643
|
const hostChildren = getChildValues(host, 0);
|
|
2463
2644
|
ctx.adapter.arrange({
|
|
@@ -2467,6 +2648,7 @@
|
|
|
2467
2648
|
props,
|
|
2468
2649
|
oldProps: props,
|
|
2469
2650
|
children: hostChildren,
|
|
2651
|
+
scope: host.scope,
|
|
2470
2652
|
root: ctx.root,
|
|
2471
2653
|
});
|
|
2472
2654
|
flush(ctx.adapter, ctx.root, ctx);
|
|
@@ -2741,6 +2923,96 @@
|
|
|
2741
2923
|
return String(value);
|
|
2742
2924
|
}
|
|
2743
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
|
+
|
|
2744
3016
|
const SVG_NAMESPACE = "http://www.w3.org/2000/svg";
|
|
2745
3017
|
const MATHML_NAMESPACE = "http://www.w3.org/1998/Math/MathML";
|
|
2746
3018
|
function getRootDocument(root) {
|
|
@@ -2798,19 +3070,325 @@
|
|
|
2798
3070
|
}
|
|
2799
3071
|
}
|
|
2800
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
|
+
}
|
|
2801
3370
|
const adapter = {
|
|
2802
|
-
scope({ scope: xmlns, tag, props, }) {
|
|
3371
|
+
scope({ scope: xmlns, tag, props, root, }) {
|
|
2803
3372
|
switch (tag) {
|
|
2804
|
-
case Portal:
|
|
2805
|
-
|
|
2806
|
-
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;
|
|
2807
3381
|
break;
|
|
3382
|
+
}
|
|
2808
3383
|
case "svg":
|
|
2809
3384
|
xmlns = SVG_NAMESPACE;
|
|
2810
3385
|
break;
|
|
2811
3386
|
case "math":
|
|
2812
3387
|
xmlns = MATHML_NAMESPACE;
|
|
2813
3388
|
break;
|
|
3389
|
+
case "foreignObject":
|
|
3390
|
+
xmlns = undefined;
|
|
3391
|
+
break;
|
|
2814
3392
|
}
|
|
2815
3393
|
return props.xmlns || xmlns;
|
|
2816
3394
|
},
|
|
@@ -2824,6 +3402,9 @@
|
|
|
2824
3402
|
else if (tag.toLowerCase() === "math") {
|
|
2825
3403
|
xmlns = MATHML_NAMESPACE;
|
|
2826
3404
|
}
|
|
3405
|
+
else if (tag === "foreignObject") {
|
|
3406
|
+
xmlns = SVG_NAMESPACE;
|
|
3407
|
+
}
|
|
2827
3408
|
const doc = getRootDocument(root);
|
|
2828
3409
|
return xmlns ? doc.createElementNS(xmlns, tag) : doc.createElement(tag);
|
|
2829
3410
|
},
|
|
@@ -2847,7 +3428,7 @@
|
|
|
2847
3428
|
}
|
|
2848
3429
|
return Array.from(node.childNodes);
|
|
2849
3430
|
},
|
|
2850
|
-
patch({ tagName, node, props, oldProps, scope: xmlns, copyProps, quietProps, isHydrating, }) {
|
|
3431
|
+
patch({ tag, tagName, node, props, oldProps, scope: xmlns, copyProps, quietProps, isHydrating, }) {
|
|
2851
3432
|
if (node.nodeType !== Node.ELEMENT_NODE) {
|
|
2852
3433
|
throw new TypeError(`Cannot patch node: ${String(node)}`);
|
|
2853
3434
|
}
|
|
@@ -2855,268 +3436,26 @@
|
|
|
2855
3436
|
console.error(`Both "class" and "className" set in props for <${tagName}>. Use one or the other.`);
|
|
2856
3437
|
}
|
|
2857
3438
|
const element = node;
|
|
2858
|
-
const isSVG = xmlns === SVG_NAMESPACE;
|
|
3439
|
+
const isSVG = xmlns === SVG_NAMESPACE || tag === "foreignObject";
|
|
2859
3440
|
const isMathML = xmlns === MATHML_NAMESPACE;
|
|
2860
|
-
|
|
2861
|
-
|
|
2862
|
-
|
|
2863
|
-
|
|
2864
|
-
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)
|
|
2865
3445
|
continue;
|
|
2866
|
-
|
|
2867
|
-
// handle prop:name or attr:name properties
|
|
2868
|
-
const colonIndex = name.indexOf(":");
|
|
2869
|
-
if (colonIndex !== -1) {
|
|
2870
|
-
const [ns, name1] = [
|
|
2871
|
-
name.slice(0, colonIndex),
|
|
2872
|
-
name.slice(colonIndex + 1),
|
|
2873
|
-
];
|
|
2874
|
-
switch (ns) {
|
|
2875
|
-
case "prop":
|
|
2876
|
-
node[name1] = value;
|
|
2877
|
-
continue;
|
|
2878
|
-
case "attr":
|
|
2879
|
-
if (value == null || value === false) {
|
|
2880
|
-
if (isHydrating && element.hasAttribute(name1)) {
|
|
2881
|
-
emitHydrationWarning(name, quietProps, value, element.getAttribute(name1), element);
|
|
2882
|
-
}
|
|
2883
|
-
element.removeAttribute(name1);
|
|
2884
|
-
}
|
|
2885
|
-
else if (value === true) {
|
|
2886
|
-
if (isHydrating && !element.hasAttribute(name1)) {
|
|
2887
|
-
emitHydrationWarning(name, quietProps, value, null, element);
|
|
2888
|
-
}
|
|
2889
|
-
element.setAttribute(name1, "");
|
|
2890
|
-
}
|
|
2891
|
-
else if (typeof value !== "string") {
|
|
2892
|
-
value = String(value);
|
|
2893
|
-
}
|
|
2894
|
-
if (isHydrating && element.getAttribute(name1) !== value) {
|
|
2895
|
-
emitHydrationWarning(name, quietProps, value, element.getAttribute(name1), element);
|
|
2896
|
-
}
|
|
2897
|
-
element.setAttribute(name1, String(value));
|
|
2898
|
-
continue;
|
|
2899
|
-
}
|
|
2900
|
-
}
|
|
2901
|
-
}
|
|
2902
|
-
switch (name) {
|
|
2903
|
-
// TODO: fix hydration warnings for the style prop
|
|
2904
|
-
case "style": {
|
|
2905
|
-
const style = element.style;
|
|
2906
|
-
if (value == null || value === false) {
|
|
2907
|
-
if (isHydrating && style.cssText !== "") {
|
|
2908
|
-
emitHydrationWarning(name, quietProps, value, style.cssText, element);
|
|
2909
|
-
}
|
|
2910
|
-
element.removeAttribute("style");
|
|
2911
|
-
}
|
|
2912
|
-
else if (value === true) {
|
|
2913
|
-
if (isHydrating && style.cssText !== "") {
|
|
2914
|
-
emitHydrationWarning(name, quietProps, "", style.cssText, element);
|
|
2915
|
-
}
|
|
2916
|
-
element.setAttribute("style", "");
|
|
2917
|
-
}
|
|
2918
|
-
else if (typeof value === "string") {
|
|
2919
|
-
if (style.cssText !== value) {
|
|
2920
|
-
// TODO: Fix hydration warnings for styles
|
|
2921
|
-
//if (isHydrating) {
|
|
2922
|
-
// emitHydrationWarning(
|
|
2923
|
-
// name,
|
|
2924
|
-
// quietProps,
|
|
2925
|
-
// value,
|
|
2926
|
-
// style.cssText,
|
|
2927
|
-
// element,
|
|
2928
|
-
// );
|
|
2929
|
-
//}
|
|
2930
|
-
style.cssText = value;
|
|
2931
|
-
}
|
|
2932
|
-
}
|
|
2933
|
-
else {
|
|
2934
|
-
if (typeof oldValue === "string") {
|
|
2935
|
-
// if the old value was a string, we need to clear the style
|
|
2936
|
-
// TODO: only clear the styles enumerated in the old value
|
|
2937
|
-
style.cssText = "";
|
|
2938
|
-
}
|
|
2939
|
-
for (const styleName in { ...oldValue, ...value }) {
|
|
2940
|
-
const cssName = camelToKebabCase(styleName);
|
|
2941
|
-
const styleValue = value && value[styleName];
|
|
2942
|
-
if (styleValue == null) {
|
|
2943
|
-
if (isHydrating && style.getPropertyValue(cssName) !== "") {
|
|
2944
|
-
emitHydrationWarning(name, quietProps, null, style.getPropertyValue(cssName), element, `style.${styleName}`);
|
|
2945
|
-
}
|
|
2946
|
-
style.removeProperty(cssName);
|
|
2947
|
-
}
|
|
2948
|
-
else {
|
|
2949
|
-
const formattedValue = formatStyleValue(cssName, styleValue);
|
|
2950
|
-
if (style.getPropertyValue(cssName) !== formattedValue) {
|
|
2951
|
-
// TODO: hydration warnings for style props
|
|
2952
|
-
//if (isHydrating) {
|
|
2953
|
-
// emitHydrationWarning(
|
|
2954
|
-
// name,
|
|
2955
|
-
// quietProps,
|
|
2956
|
-
// formattedValue,
|
|
2957
|
-
// style.getPropertyValue(cssName),
|
|
2958
|
-
// element,
|
|
2959
|
-
// `style.${styleName}`,
|
|
2960
|
-
// );
|
|
2961
|
-
//}
|
|
2962
|
-
style.setProperty(cssName, formattedValue);
|
|
2963
|
-
}
|
|
2964
|
-
}
|
|
2965
|
-
}
|
|
2966
|
-
}
|
|
2967
|
-
break;
|
|
2968
|
-
}
|
|
2969
|
-
case "class":
|
|
2970
|
-
case "className":
|
|
2971
|
-
if (value === true) {
|
|
2972
|
-
if (isHydrating && element.getAttribute("class") !== "") {
|
|
2973
|
-
emitHydrationWarning(name, quietProps, "", element.getAttribute("class"), element);
|
|
2974
|
-
}
|
|
2975
|
-
element.setAttribute("class", "");
|
|
2976
|
-
}
|
|
2977
|
-
else if (value == null) {
|
|
2978
|
-
if (isHydrating && element.hasAttribute("class")) {
|
|
2979
|
-
emitHydrationWarning(name, quietProps, value, element.getAttribute("class"), element);
|
|
2980
|
-
}
|
|
2981
|
-
element.removeAttribute("class");
|
|
2982
|
-
}
|
|
2983
|
-
else if (typeof value === "object") {
|
|
2984
|
-
// class={{"included-class": true, "excluded-class": false}} syntax
|
|
2985
|
-
if (typeof oldValue === "string") {
|
|
2986
|
-
// if the old value was a string, we need to clear all classes
|
|
2987
|
-
element.setAttribute("class", "");
|
|
2988
|
-
}
|
|
2989
|
-
let shouldIssueWarning = false;
|
|
2990
|
-
const hydratingClasses = isHydrating
|
|
2991
|
-
? new Set(Array.from(element.classList))
|
|
2992
|
-
: undefined;
|
|
2993
|
-
const hydratingClassName = isHydrating
|
|
2994
|
-
? element.getAttribute("class")
|
|
2995
|
-
: undefined;
|
|
2996
|
-
const allClassNames = { ...oldValue, ...value };
|
|
2997
|
-
// Two passes: removes first, then adds. This ensures that
|
|
2998
|
-
// overlapping classes in different keys are handled correctly.
|
|
2999
|
-
// e.g. {"a b": false, "b c": true} should result in "b c"
|
|
3000
|
-
for (const classNames in allClassNames) {
|
|
3001
|
-
if (!(value && value[classNames])) {
|
|
3002
|
-
const classes = classNames.split(/\s+/).filter(Boolean);
|
|
3003
|
-
element.classList.remove(...classes);
|
|
3004
|
-
}
|
|
3005
|
-
}
|
|
3006
|
-
for (const classNames in allClassNames) {
|
|
3007
|
-
if (value && value[classNames]) {
|
|
3008
|
-
const classes = classNames.split(/\s+/).filter(Boolean);
|
|
3009
|
-
element.classList.add(...classes);
|
|
3010
|
-
for (const className of classes) {
|
|
3011
|
-
if (hydratingClasses && hydratingClasses.has(className)) {
|
|
3012
|
-
hydratingClasses.delete(className);
|
|
3013
|
-
}
|
|
3014
|
-
else if (isHydrating) {
|
|
3015
|
-
shouldIssueWarning = true;
|
|
3016
|
-
}
|
|
3017
|
-
}
|
|
3018
|
-
}
|
|
3019
|
-
}
|
|
3020
|
-
if (shouldIssueWarning ||
|
|
3021
|
-
(hydratingClasses && hydratingClasses.size > 0)) {
|
|
3022
|
-
emitHydrationWarning(name, quietProps, Object.keys(value)
|
|
3023
|
-
.filter((k) => value[k])
|
|
3024
|
-
.join(" "), hydratingClassName || "", element);
|
|
3025
|
-
}
|
|
3026
|
-
}
|
|
3027
|
-
else if (!isSVG && !isMathML) {
|
|
3028
|
-
if (element.className !== value) {
|
|
3029
|
-
if (isHydrating) {
|
|
3030
|
-
emitHydrationWarning(name, quietProps, value, element.className, element);
|
|
3031
|
-
}
|
|
3032
|
-
element.className = value;
|
|
3033
|
-
}
|
|
3034
|
-
}
|
|
3035
|
-
else if (element.getAttribute("class") !== value) {
|
|
3036
|
-
if (isHydrating) {
|
|
3037
|
-
emitHydrationWarning(name, quietProps, value, element.getAttribute("class"), element);
|
|
3038
|
-
}
|
|
3039
|
-
element.setAttribute("class", value);
|
|
3040
|
-
}
|
|
3041
|
-
break;
|
|
3042
|
-
case "innerHTML":
|
|
3043
|
-
if (value !== oldValue) {
|
|
3044
|
-
if (isHydrating) {
|
|
3045
|
-
emitHydrationWarning(name, quietProps, value, element.innerHTML, element);
|
|
3046
|
-
}
|
|
3047
|
-
element.innerHTML = value;
|
|
3048
|
-
}
|
|
3049
|
-
break;
|
|
3050
|
-
default: {
|
|
3051
|
-
if (name[0] === "o" &&
|
|
3052
|
-
name[1] === "n" &&
|
|
3053
|
-
name[2] === name[2].toUpperCase() &&
|
|
3054
|
-
typeof value === "function") {
|
|
3055
|
-
// Support React-style event names (onClick, onChange, etc.)
|
|
3056
|
-
name = name.toLowerCase();
|
|
3057
|
-
}
|
|
3058
|
-
// try to set the property directly
|
|
3059
|
-
if (name in element &&
|
|
3060
|
-
// boolean properties will coerce strings, but sometimes they map to
|
|
3061
|
-
// enumerated attributes, where truthy strings ("false", "no") map to
|
|
3062
|
-
// falsy properties, so we force using setAttribute.
|
|
3063
|
-
!(typeof value === "string" &&
|
|
3064
|
-
typeof element[name] === "boolean") &&
|
|
3065
|
-
isWritableProperty(element, name)) {
|
|
3066
|
-
// For URL properties like src and href, the DOM property returns the
|
|
3067
|
-
// resolved absolute URL. We need to resolve the prop value the same way
|
|
3068
|
-
// to compare correctly.
|
|
3069
|
-
let domValue = element[name];
|
|
3070
|
-
let propValue = value;
|
|
3071
|
-
if ((name === "src" || name === "href") &&
|
|
3072
|
-
typeof value === "string" &&
|
|
3073
|
-
typeof domValue === "string") {
|
|
3074
|
-
try {
|
|
3075
|
-
propValue = new URL(value, element.baseURI).href;
|
|
3076
|
-
}
|
|
3077
|
-
catch {
|
|
3078
|
-
// Invalid URL, use original value for comparison
|
|
3079
|
-
}
|
|
3080
|
-
}
|
|
3081
|
-
if (propValue !== domValue || oldValue === undefined) {
|
|
3082
|
-
if (isHydrating &&
|
|
3083
|
-
typeof element[name] === "string" &&
|
|
3084
|
-
element[name] !== value) {
|
|
3085
|
-
emitHydrationWarning(name, quietProps, value, element[name], element);
|
|
3086
|
-
}
|
|
3087
|
-
// if the property is writable, assign it directly
|
|
3088
|
-
element[name] = value;
|
|
3089
|
-
}
|
|
3090
|
-
continue;
|
|
3091
|
-
}
|
|
3092
|
-
if (value === true) {
|
|
3093
|
-
value = "";
|
|
3094
|
-
}
|
|
3095
|
-
else if (value == null || value === false) {
|
|
3096
|
-
if (isHydrating && element.hasAttribute(name)) {
|
|
3097
|
-
emitHydrationWarning(name, quietProps, value, element.getAttribute(name), element);
|
|
3098
|
-
}
|
|
3099
|
-
element.removeAttribute(name);
|
|
3100
|
-
continue;
|
|
3101
|
-
}
|
|
3102
|
-
else if (typeof value !== "string") {
|
|
3103
|
-
value = String(value);
|
|
3104
|
-
}
|
|
3105
|
-
if (element.getAttribute(name) !== value) {
|
|
3106
|
-
if (isHydrating) {
|
|
3107
|
-
emitHydrationWarning(name, quietProps, value, element.getAttribute(name), element);
|
|
3108
|
-
}
|
|
3109
|
-
element.setAttribute(name, value);
|
|
3110
|
-
}
|
|
3111
|
-
}
|
|
3446
|
+
patchProp(element, name, undefined, oldProps[name], props, isSVG, isMathML, copyProps, quietProps, isHydrating);
|
|
3112
3447
|
}
|
|
3113
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
|
+
}
|
|
3114
3453
|
},
|
|
3115
3454
|
arrange({ tag, node, props, children, }) {
|
|
3116
3455
|
if (tag === Portal && (node == null || typeof node.nodeType !== "number")) {
|
|
3117
3456
|
throw new TypeError(`<Portal> root is not a node. Received: ${String(node)}`);
|
|
3118
3457
|
}
|
|
3119
|
-
if (!("innerHTML" in props)) {
|
|
3458
|
+
if (!("innerHTML" in props) && !("dangerouslySetInnerHTML" in props)) {
|
|
3120
3459
|
let oldChild = node.firstChild;
|
|
3121
3460
|
for (let i = 0; i < children.length; i++) {
|
|
3122
3461
|
const newChild = children[i];
|
|
@@ -3292,12 +3631,20 @@
|
|
|
3292
3631
|
}
|
|
3293
3632
|
return cssStrings.join("");
|
|
3294
3633
|
}
|
|
3295
|
-
function printAttrs(props) {
|
|
3634
|
+
function printAttrs(props, isSVG) {
|
|
3296
3635
|
const attrs = [];
|
|
3297
3636
|
for (let [name, value] of Object.entries(props)) {
|
|
3298
|
-
if (name === "innerHTML" ||
|
|
3637
|
+
if (name === "innerHTML" ||
|
|
3638
|
+
name === "dangerouslySetInnerHTML" ||
|
|
3639
|
+
name.startsWith("prop:")) {
|
|
3299
3640
|
continue;
|
|
3300
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
|
+
}
|
|
3301
3648
|
else if (name === "style") {
|
|
3302
3649
|
if (typeof value === "string") {
|
|
3303
3650
|
attrs.push(`style="${escape(value)}"`);
|
|
@@ -3330,6 +3677,9 @@
|
|
|
3330
3677
|
if (name.startsWith("attr:")) {
|
|
3331
3678
|
name = name.slice("attr:".length);
|
|
3332
3679
|
}
|
|
3680
|
+
else if (isSVG && name in REACT_SVG_PROPS) {
|
|
3681
|
+
name = REACT_SVG_PROPS[name];
|
|
3682
|
+
}
|
|
3333
3683
|
if (typeof value === "string") {
|
|
3334
3684
|
attrs.push(`${escape(name)}="${escape(value)}"`);
|
|
3335
3685
|
}
|
|
@@ -3352,6 +3702,20 @@
|
|
|
3352
3702
|
return result;
|
|
3353
3703
|
}
|
|
3354
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
|
+
},
|
|
3355
3719
|
create() {
|
|
3356
3720
|
return { value: "" };
|
|
3357
3721
|
},
|
|
@@ -3372,14 +3736,14 @@
|
|
|
3372
3736
|
return value.value || "";
|
|
3373
3737
|
}
|
|
3374
3738
|
},
|
|
3375
|
-
arrange({ tag, tagName, node, props, children, }) {
|
|
3739
|
+
arrange({ tag, tagName, node, props, children, scope, }) {
|
|
3376
3740
|
if (tag === Portal) {
|
|
3377
3741
|
return;
|
|
3378
3742
|
}
|
|
3379
3743
|
else if (typeof tag !== "string") {
|
|
3380
3744
|
throw new Error(`Unknown tag: ${tagName}`);
|
|
3381
3745
|
}
|
|
3382
|
-
const attrs = printAttrs(props);
|
|
3746
|
+
const attrs = printAttrs(props, scope === "svg" || tag === "foreignObject");
|
|
3383
3747
|
const open = `<${tag}${attrs.length ? " " : ""}${attrs}>`;
|
|
3384
3748
|
let result;
|
|
3385
3749
|
if (voidTags.has(tag)) {
|
|
@@ -3387,7 +3751,11 @@
|
|
|
3387
3751
|
}
|
|
3388
3752
|
else {
|
|
3389
3753
|
const close = `</${tag}>`;
|
|
3390
|
-
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);
|
|
3391
3759
|
result = `${open}${contents}${close}`;
|
|
3392
3760
|
}
|
|
3393
3761
|
node.value = result;
|
|
@@ -3409,7 +3777,7 @@
|
|
|
3409
3777
|
|
|
3410
3778
|
exports.Context = Context;
|
|
3411
3779
|
exports.Copy = Copy;
|
|
3412
|
-
exports.Element = Element;
|
|
3780
|
+
exports.Element = Element$1;
|
|
3413
3781
|
exports.Fragment = Fragment;
|
|
3414
3782
|
exports.Portal = Portal;
|
|
3415
3783
|
exports.Raw = Raw;
|