@@ -991,7 +991,74 @@ export const vnode_insertBefore = (
991
991
}
992
992
}
993
993
994
- // ensure that the previous node is unlinked.
994
+ /**
995
+ * Find the parent node and the dom children with the correct namespaces before we unlink the
996
+ * previous node. If we don't do this, we will end up with situations where we inflate text nodes
997
+ * from shared text node not correctly.
998
+ *
999
+ * Example:
1000
+ *
1001
+ * ```
1002
+ * <Component>
1003
+ * <Projection>a</Projection>
1004
+ * <Projection>b</Projection>
1005
+ * </Component>
1006
+ * ```
1007
+ *
1008
+ * Projection nodes are virtual nodes, so they don't have a dom parent. They will be written to
1009
+ * the q:template element if not visible at the start. Inside the q:template element, the
1010
+ * projection nodes will be streamed as single text node "ab". We need to split it, but if we
1011
+ * unlink the previous or next sibling, we don't know that after "a" node is "b". So we need to
1012
+ * find children first (and inflate them).
1013
+ */
1014
+ const domParentVNode = vnode_getDomParentVNode ( parent ) ;
1015
+ const parentNode = domParentVNode && domParentVNode [ ElementVNodeProps . element ] ;
1016
+ let domChildren : ( Element | Text ) [ ] | null = null ;
1017
+ if ( domParentVNode ) {
1018
+ domChildren = vnode_getDomChildrenWithCorrectNamespacesToInsert (
1019
+ journal ,
1020
+ domParentVNode ,
1021
+ newChild
1022
+ ) ;
1023
+ }
1024
+
1025
+ /**
1026
+ * Ensure that the previous node is unlinked.
1027
+ *
1028
+ * We need to do it before finding the adjustedInsertBefore. The problem is when you try to render
1029
+ * the same projection multiple times in the same node but under different conditions. We reuse
1030
+ * projection nodes, so when this happens, we can end up with a situation where the node is
1031
+ * inserted before node above it.
1032
+ *
1033
+ * Example:
1034
+ *
1035
+ * ```
1036
+ * <>
1037
+ * {props.toggle && <Slot />}
1038
+ * {!props.toggle && (
1039
+ * <>
1040
+ * <Slot />
1041
+ * </>
1042
+ * )}
1043
+ * </>
1044
+ * ```
1045
+ *
1046
+ * Projected content:
1047
+ *
1048
+ * ```
1049
+ * <h1>Test</h1>
1050
+ * <p>Test content</p>
1051
+ * ```
1052
+ *
1053
+ * If we don't unlink the previous node, we will end up at some point with the following:
1054
+ *
1055
+ * ```
1056
+ * <h1>Test</h1>
1057
+ * <p>Test content</p> // <-- inserted before the first h1
1058
+ * <h1>Test</h1> // <-- to remove, but still in the tree
1059
+ * <p>Test content</p> // <-- to remove
1060
+ * ```
1061
+ */
995
1062
if (
996
1063
newChildCurrentParent &&
997
1064
( newChild [ VNodeProps . previousSibling ] ||
@@ -1008,7 +1075,6 @@ export const vnode_insertBefore = (
1008
1075
// Well, not quite. If the parent is a virtual node, our "last node" is not the same
1009
1076
// as the DOM "last node". So in that case we need to look for the "next node" from
1010
1077
// our parent.
1011
-
1012
1078
adjustedInsertBefore = vnode_getDomSibling ( parent , true , false ) ;
1013
1079
}
1014
1080
} else if ( vnode_isVirtualVNode ( insertBefore ) ) {
@@ -1018,30 +1084,15 @@ export const vnode_insertBefore = (
1018
1084
adjustedInsertBefore = insertBefore ;
1019
1085
}
1020
1086
adjustedInsertBefore && vnode_ensureInflatedIfText ( journal , adjustedInsertBefore ) ;
1021
- // If `insertBefore` is null, than we need to insert at the end of the list.
1022
- // Well, not quite. If the parent is a virtual node, our "last node" is not the same
1023
- // as the DOM "last node". So in that case we need to look for the "next node" from
1024
- // our parent.
1025
- // const shouldWeUseParentVirtual = insertBefore == null && vnode_isVirtualVNode(parent);
1026
- // const insertBeforeNode = shouldWeUseParentVirtual
1027
- // ? vnode_getDomSibling(parent, true)
1028
- // : insertBefore;
1029
- const domParentVNode = vnode_getDomParentVNode ( parent ) ;
1030
- const parentNode = domParentVNode && domParentVNode [ ElementVNodeProps . element ] ;
1031
1087
1032
- if ( parentNode ) {
1033
- const domChildren = vnode_getDomChildrenWithCorrectNamespacesToInsert (
1034
- journal ,
1035
- domParentVNode ,
1036
- newChild
1088
+ // Here we know the insertBefore node
1089
+ if ( domChildren && domChildren . length ) {
1090
+ journal . push (
1091
+ VNodeJournalOpCode . Insert ,
1092
+ parentNode ,
1093
+ vnode_getNode ( adjustedInsertBefore ) ,
1094
+ ...domChildren
1037
1095
) ;
1038
- domChildren . length &&
1039
- journal . push (
1040
- VNodeJournalOpCode . Insert ,
1041
- parentNode ,
1042
- vnode_getNode ( adjustedInsertBefore ) ,
1043
- ...domChildren
1044
- ) ;
1045
1096
}
1046
1097
1047
1098
// link newChild into the previous/next list
0 commit comments