@remix-run/ui 0.2.0 → 0.3.0
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/dist/animation/demos/animation.demo.d.ts +5 -0
- package/dist/animation/demos/animation.demo.js +92 -0
- package/dist/animation/demos/animation.demo.js.map +1 -0
- package/dist/animation/demos/aspect-ratio.d.ts +2 -0
- package/dist/animation/demos/aspect-ratio.js +69 -0
- package/dist/animation/demos/aspect-ratio.js.map +1 -0
- package/dist/animation/demos/bouncy-switch.d.ts +2 -0
- package/dist/animation/demos/bouncy-switch.js +36 -0
- package/dist/animation/demos/bouncy-switch.js.map +1 -0
- package/dist/animation/demos/color-interpolation.d.ts +1 -0
- package/dist/animation/demos/color-interpolation.js +53 -0
- package/dist/animation/demos/color-interpolation.js.map +1 -0
- package/dist/animation/demos/cube.d.ts +2 -0
- package/dist/animation/demos/cube.js +86 -0
- package/dist/animation/demos/cube.js.map +1 -0
- package/dist/animation/demos/default-animate.d.ts +2 -0
- package/dist/animation/demos/default-animate.js +89 -0
- package/dist/animation/demos/default-animate.js.map +1 -0
- package/dist/animation/demos/drag-release.d.ts +24 -0
- package/dist/animation/demos/drag-release.js +96 -0
- package/dist/animation/demos/drag-release.js.map +1 -0
- package/dist/animation/demos/enter.d.ts +1 -0
- package/dist/animation/demos/enter.js +19 -0
- package/dist/animation/demos/enter.js.map +1 -0
- package/dist/animation/demos/exit.d.ts +2 -0
- package/dist/animation/demos/exit.js +58 -0
- package/dist/animation/demos/exit.js.map +1 -0
- package/dist/animation/demos/flip-toggle.d.ts +2 -0
- package/dist/animation/demos/flip-toggle.js +37 -0
- package/dist/animation/demos/flip-toggle.js.map +1 -0
- package/dist/animation/demos/hold-to-confirm.d.ts +13 -0
- package/dist/animation/demos/hold-to-confirm.js +211 -0
- package/dist/animation/demos/hold-to-confirm.js.map +1 -0
- package/dist/animation/demos/html-content.d.ts +2 -0
- package/dist/animation/demos/html-content.js +30 -0
- package/dist/animation/demos/html-content.js.map +1 -0
- package/dist/animation/demos/interruptible-keyframes.d.ts +1 -0
- package/dist/animation/demos/interruptible-keyframes.js +48 -0
- package/dist/animation/demos/interruptible-keyframes.js.map +1 -0
- package/dist/animation/demos/keyframes.d.ts +1 -0
- package/dist/animation/demos/keyframes.js +24 -0
- package/dist/animation/demos/keyframes.js.map +1 -0
- package/dist/animation/demos/material-ripple.d.ts +2 -0
- package/dist/animation/demos/material-ripple.js +127 -0
- package/dist/animation/demos/material-ripple.js.map +1 -0
- package/dist/animation/demos/mixin-presence-list.d.ts +2 -0
- package/dist/animation/demos/mixin-presence-list.js +88 -0
- package/dist/animation/demos/mixin-presence-list.js.map +1 -0
- package/dist/animation/demos/mixin-reclaim.d.ts +2 -0
- package/dist/animation/demos/mixin-reclaim.js +90 -0
- package/dist/animation/demos/mixin-reclaim.js.map +1 -0
- package/dist/animation/demos/multi-state-badge.d.ts +2 -0
- package/dist/animation/demos/multi-state-badge.js +231 -0
- package/dist/animation/demos/multi-state-badge.js.map +1 -0
- package/dist/animation/demos/press.d.ts +2 -0
- package/dist/animation/demos/press.js +63 -0
- package/dist/animation/demos/press.js.map +1 -0
- package/dist/animation/demos/reordering.d.ts +2 -0
- package/dist/animation/demos/reordering.js +50 -0
- package/dist/animation/demos/reordering.js.map +1 -0
- package/dist/animation/demos/rolling-square.d.ts +2 -0
- package/dist/animation/demos/rolling-square.js +42 -0
- package/dist/animation/demos/rolling-square.js.map +1 -0
- package/dist/animation/demos/rotate.d.ts +1 -0
- package/dist/animation/demos/rotate.js +18 -0
- package/dist/animation/demos/rotate.js.map +1 -0
- package/dist/animation/demos/shared-layout.d.ts +2 -0
- package/dist/animation/demos/shared-layout.js +114 -0
- package/dist/animation/demos/shared-layout.js.map +1 -0
- package/dist/animation/demos/spring.demo.d.ts +6 -0
- package/dist/animation/demos/spring.demo.js +304 -0
- package/dist/animation/demos/spring.demo.js.map +1 -0
- package/dist/animation/demos/transition-options.d.ts +1 -0
- package/dist/animation/demos/transition-options.js +21 -0
- package/dist/animation/demos/transition-options.js.map +1 -0
- package/dist/animation/spring.d.ts +22 -0
- package/dist/animation/spring.js +22 -0
- package/dist/animation/spring.js.map +1 -1
- package/dist/components/accordion/demos/card.demo.d.ts +1 -0
- package/dist/components/accordion/demos/card.demo.js +1 -0
- package/dist/components/accordion/demos/card.demo.js.map +1 -1
- package/dist/components/accordion/demos/multiple.demo.d.ts +1 -0
- package/dist/components/accordion/demos/multiple.demo.js +1 -0
- package/dist/components/accordion/demos/multiple.demo.js.map +1 -1
- package/dist/components/accordion/demos/overview.demo.d.ts +1 -0
- package/dist/components/accordion/demos/overview.demo.js +1 -0
- package/dist/components/accordion/demos/overview.demo.js.map +1 -1
- package/dist/components/anchor/anchor.d.ts +8 -1
- package/dist/components/anchor/anchor.js +30 -11
- package/dist/components/anchor/anchor.js.map +1 -1
- package/dist/components/breadcrumbs/{demos/basic.demo.d.ts → basic.demo.d.ts} +1 -0
- package/dist/components/breadcrumbs/{demos/basic.demo.js → basic.demo.js} +1 -0
- package/dist/components/breadcrumbs/basic.demo.js.map +1 -0
- package/dist/components/breadcrumbs/{demos/separator.demo.d.ts → separator.demo.d.ts} +1 -0
- package/dist/components/breadcrumbs/{demos/separator.demo.js → separator.demo.js} +1 -0
- package/dist/components/breadcrumbs/separator.demo.js.map +1 -0
- package/dist/components/button/demos/aliases.demo.d.ts +1 -0
- package/dist/components/button/demos/aliases.demo.js +1 -0
- package/dist/components/button/demos/aliases.demo.js.map +1 -1
- package/dist/components/button/demos/basic.demo.d.ts +1 -0
- package/dist/components/button/demos/basic.demo.js +1 -0
- package/dist/components/button/demos/basic.demo.js.map +1 -1
- package/dist/components/button/demos/states.demo.d.ts +1 -0
- package/dist/components/button/demos/states.demo.js +1 -0
- package/dist/components/button/demos/states.demo.js.map +1 -1
- package/dist/components/combobox/{demos/overview.demo.d.ts → overview.demo.d.ts} +1 -0
- package/dist/components/combobox/{demos/overview.demo.js → overview.demo.js} +1 -0
- package/dist/components/combobox/overview.demo.js.map +1 -0
- package/dist/components/listbox/{demos/overview.demo.d.ts → overview.demo.d.ts} +1 -0
- package/dist/components/listbox/{demos/overview.demo.js → overview.demo.js} +1 -0
- package/dist/components/listbox/overview.demo.js.map +1 -0
- package/dist/components/menu/demos/bubbling.demo.d.ts +1 -0
- package/dist/components/menu/demos/bubbling.demo.js +1 -0
- package/dist/components/menu/demos/bubbling.demo.js.map +1 -1
- package/dist/components/menu/demos/context-trigger.demo.d.ts +7 -0
- package/dist/components/menu/demos/context-trigger.demo.js +87 -0
- package/dist/components/menu/demos/context-trigger.demo.js.map +1 -0
- package/dist/components/menu/demos/overview.demo.d.ts +1 -0
- package/dist/components/menu/demos/overview.demo.js +1 -0
- package/dist/components/menu/demos/overview.demo.js.map +1 -1
- package/dist/components/menu/menu.d.ts +3 -0
- package/dist/components/menu/menu.js +55 -0
- package/dist/components/menu/menu.js.map +1 -1
- package/dist/components/popover/{demos/overview.demo.d.ts → overview.demo.d.ts} +1 -0
- package/dist/components/popover/{demos/overview.demo.js → overview.demo.js} +1 -0
- package/dist/components/popover/overview.demo.js.map +1 -0
- package/dist/components/popover/popover.d.ts +2 -2
- package/dist/components/popover/popover.js +11 -4
- package/dist/components/popover/popover.js.map +1 -1
- package/dist/components/select/{demos/deconstructed.demo.d.ts → deconstructed.demo.d.ts} +1 -0
- package/dist/components/select/{demos/deconstructed.demo.js → deconstructed.demo.js} +1 -0
- package/dist/components/select/deconstructed.demo.js.map +1 -0
- package/dist/components/select/{demos/overview.demo.d.ts → overview.demo.d.ts} +1 -0
- package/dist/components/select/{demos/overview.demo.js → overview.demo.js} +1 -0
- package/dist/components/select/overview.demo.js.map +1 -0
- package/dist/components/select/select.js +1 -1
- package/dist/components/select/select.js.map +1 -1
- package/dist/runtime/client-entries.d.ts +1 -2
- package/dist/runtime/client-entries.js.map +1 -1
- package/dist/runtime/component.d.ts +2 -2
- package/dist/runtime/component.js +1 -1
- package/dist/runtime/component.js.map +1 -1
- package/dist/runtime/demos/basic.demo.d.ts +6 -0
- package/dist/runtime/demos/basic.demo.js +16 -0
- package/dist/runtime/demos/basic.demo.js.map +1 -0
- package/dist/runtime/demos/controlled-uncontrolled-values.demo.d.ts +6 -0
- package/dist/runtime/demos/controlled-uncontrolled-values.demo.js +77 -0
- package/dist/runtime/demos/controlled-uncontrolled-values.demo.js.map +1 -0
- package/dist/runtime/demos/keyed-list.demo.d.ts +6 -0
- package/dist/runtime/demos/keyed-list.demo.js +62 -0
- package/dist/runtime/demos/keyed-list.demo.js.map +1 -0
- package/dist/runtime/demos/readme.demo.d.ts +5 -0
- package/dist/runtime/demos/readme.demo.js +396 -0
- package/dist/runtime/demos/readme.demo.js.map +1 -0
- package/dist/runtime/diff-dom.js +194 -21
- package/dist/runtime/diff-dom.js.map +1 -1
- package/dist/runtime/frame.d.ts +7 -0
- package/dist/runtime/frame.js +176 -41
- package/dist/runtime/frame.js.map +1 -1
- package/dist/runtime/jsx.d.ts +2 -3
- package/dist/runtime/jsx.js.map +1 -1
- package/dist/server/stream.js +3 -2
- package/dist/server/stream.js.map +1 -1
- package/dist/style/style.js +27 -10
- package/dist/style/style.js.map +1 -1
- package/package.json +3 -3
- package/src/animation/demos/animation.demo.tsx +194 -0
- package/src/animation/demos/aspect-ratio.tsx +120 -0
- package/src/animation/demos/bouncy-switch.tsx +47 -0
- package/src/animation/demos/color-interpolation.tsx +73 -0
- package/src/animation/demos/cube.tsx +116 -0
- package/src/animation/demos/default-animate.tsx +129 -0
- package/src/animation/demos/drag-release.ts +118 -0
- package/src/animation/demos/enter.tsx +22 -0
- package/src/animation/demos/exit.tsx +79 -0
- package/src/animation/demos/flip-toggle.tsx +46 -0
- package/src/animation/demos/hold-to-confirm.tsx +317 -0
- package/src/animation/demos/html-content.tsx +41 -0
- package/src/animation/demos/interruptible-keyframes.tsx +62 -0
- package/src/animation/demos/keyframes.tsx +29 -0
- package/src/animation/demos/material-ripple.tsx +158 -0
- package/src/animation/demos/mixin-presence-list.tsx +121 -0
- package/src/animation/demos/mixin-reclaim.tsx +125 -0
- package/src/animation/demos/multi-state-badge.tsx +426 -0
- package/src/animation/demos/press.tsx +67 -0
- package/src/animation/demos/reordering.tsx +65 -0
- package/src/animation/demos/rolling-square.tsx +57 -0
- package/src/animation/demos/rotate.tsx +21 -0
- package/src/animation/demos/shared-layout.tsx +211 -0
- package/src/animation/demos/spring.demo.tsx +385 -0
- package/src/animation/demos/transition-options.tsx +24 -0
- package/src/animation/spring.ts +22 -0
- package/src/components/accordion/demos/card.demo.tsx +1 -0
- package/src/components/accordion/demos/multiple.demo.tsx +1 -0
- package/src/components/accordion/demos/overview.demo.tsx +1 -0
- package/src/components/anchor/README.md +11 -3
- package/src/components/anchor/anchor.ts +53 -12
- package/src/components/breadcrumbs/{demos/basic.demo.tsx → basic.demo.tsx} +1 -0
- package/src/components/breadcrumbs/{demos/separator.demo.tsx → separator.demo.tsx} +1 -0
- package/src/components/button/demos/aliases.demo.tsx +1 -0
- package/src/components/button/demos/basic.demo.tsx +1 -0
- package/src/components/button/demos/states.demo.tsx +1 -0
- package/src/components/combobox/{demos/overview.demo.tsx → overview.demo.tsx} +1 -0
- package/src/components/listbox/{demos/overview.demo.tsx → overview.demo.tsx} +1 -0
- package/src/components/menu/README.md +26 -2
- package/src/components/menu/demos/bubbling.demo.tsx +1 -0
- package/src/components/menu/demos/context-trigger.demo.tsx +133 -0
- package/src/components/menu/demos/overview.demo.tsx +1 -0
- package/src/components/menu/menu.tsx +73 -1
- package/src/components/popover/{demos/overview.demo.tsx → overview.demo.tsx} +1 -0
- package/src/components/popover/popover.ts +18 -9
- package/src/components/select/{demos/deconstructed.demo.tsx → deconstructed.demo.tsx} +1 -0
- package/src/components/select/{demos/overview.demo.tsx → overview.demo.tsx} +1 -0
- package/src/components/select/select.tsx +1 -1
- package/src/runtime/client-entries.ts +1 -5
- package/src/runtime/component.ts +3 -3
- package/src/runtime/demos/basic.demo.tsx +21 -0
- package/src/runtime/demos/controlled-uncontrolled-values.demo.tsx +177 -0
- package/src/runtime/demos/keyed-list.demo.tsx +94 -0
- package/src/runtime/demos/readme.demo.tsx +702 -0
- package/src/runtime/diff-dom.ts +270 -20
- package/src/runtime/frame.ts +218 -41
- package/src/runtime/jsx.ts +6 -10
- package/src/server/stream.ts +7 -2
- package/src/style/style.ts +29 -10
- package/dist/components/breadcrumbs/demos/basic.demo.js.map +0 -1
- package/dist/components/breadcrumbs/demos/separator.demo.js.map +0 -1
- package/dist/components/combobox/demos/overview.demo.js.map +0 -1
- package/dist/components/listbox/demos/overview.demo.js.map +0 -1
- package/dist/components/popover/demos/overview.demo.js.map +0 -1
- package/dist/components/select/demos/deconstructed.demo.js.map +0 -1
- package/dist/components/select/demos/overview.demo.js.map +0 -1
package/src/runtime/diff-dom.ts
CHANGED
|
@@ -7,6 +7,13 @@ type HydratedVirtualRootStartMarker = Comment & {
|
|
|
7
7
|
}
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
+
type CommentMarkerRangeReplacement = {
|
|
11
|
+
currentStart: Comment
|
|
12
|
+
nextStart: Comment
|
|
13
|
+
currentEndIndex: number
|
|
14
|
+
nextEndIndex: number
|
|
15
|
+
}
|
|
16
|
+
|
|
10
17
|
export function diffNodes(curr: Node[], next: Node[], context: FrameContext) {
|
|
11
18
|
let parent = curr[0]?.parentNode ?? context.regionParent ?? null
|
|
12
19
|
invariant(parent, 'Parent node not found')
|
|
@@ -17,10 +24,11 @@ export function diffNodes(curr: Node[], next: Node[], context: FrameContext) {
|
|
|
17
24
|
context.regionTailRef ??
|
|
18
25
|
(curr.length > 0 ? (curr[curr.length - 1].nextSibling as ChildNode | null) : null)
|
|
19
26
|
|
|
20
|
-
let
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
let
|
|
27
|
+
let currentIndex = 0
|
|
28
|
+
let nextIndex = 0
|
|
29
|
+
while (currentIndex < curr.length || nextIndex < next.length) {
|
|
30
|
+
let c = curr[currentIndex]
|
|
31
|
+
let n = next[nextIndex]
|
|
24
32
|
|
|
25
33
|
if (!c && n) {
|
|
26
34
|
if (regionTailRef) {
|
|
@@ -28,10 +36,28 @@ export function diffNodes(curr: Node[], next: Node[], context: FrameContext) {
|
|
|
28
36
|
} else {
|
|
29
37
|
parent.appendChild(n)
|
|
30
38
|
}
|
|
39
|
+
nextIndex++
|
|
31
40
|
} else if (c && !n) {
|
|
32
41
|
removeNode(c, parent, context)
|
|
42
|
+
currentIndex++
|
|
33
43
|
} else if (c && n) {
|
|
34
|
-
|
|
44
|
+
let replacement = getCommentMarkerRangeReplacement(
|
|
45
|
+
c,
|
|
46
|
+
n,
|
|
47
|
+
curr,
|
|
48
|
+
next,
|
|
49
|
+
currentIndex,
|
|
50
|
+
nextIndex,
|
|
51
|
+
context,
|
|
52
|
+
)
|
|
53
|
+
if (replacement) {
|
|
54
|
+
replaceCommentMarkerRange(replacement, parent, context)
|
|
55
|
+
currentIndex = replacement.currentEndIndex + 1
|
|
56
|
+
nextIndex = replacement.nextEndIndex + 1
|
|
57
|
+
continue
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Skip hydrated client-entry marker ranges; hydration pass re-renders
|
|
35
61
|
// roots with new props from incoming payload
|
|
36
62
|
if (isVirtualRootStartMarker(c) && isVirtualRootStartMarker(n)) {
|
|
37
63
|
let currentEnd = findHydrationEndMarker(c)
|
|
@@ -41,14 +67,25 @@ export function diffNodes(curr: Node[], next: Node[], context: FrameContext) {
|
|
|
41
67
|
|
|
42
68
|
let currentEndIndex = curr.indexOf(currentEnd)
|
|
43
69
|
let nextEndIndex = next.indexOf(nextEnd)
|
|
44
|
-
|
|
70
|
+
currentIndex = currentEndIndex + 1
|
|
71
|
+
nextIndex = nextEndIndex + 1
|
|
45
72
|
continue
|
|
46
73
|
}
|
|
47
74
|
|
|
48
75
|
let cursor = diffNode(c, n, context)
|
|
49
76
|
if (cursor) {
|
|
50
|
-
|
|
77
|
+
let nextEndIndex = next.indexOf(cursor)
|
|
78
|
+
let currentEndIndex =
|
|
79
|
+
isFrameStartMarker(c) && isFrameEndMarker(cursor)
|
|
80
|
+
? findFrameEndIndex(curr, currentIndex)
|
|
81
|
+
: currentIndex
|
|
82
|
+
currentIndex = currentEndIndex + 1
|
|
83
|
+
nextIndex = nextEndIndex + 1
|
|
84
|
+
continue
|
|
51
85
|
}
|
|
86
|
+
|
|
87
|
+
currentIndex++
|
|
88
|
+
nextIndex++
|
|
52
89
|
}
|
|
53
90
|
}
|
|
54
91
|
}
|
|
@@ -61,7 +98,7 @@ function diffNode(current: Node, next: Node, context: FrameContext): ChildNode |
|
|
|
61
98
|
return
|
|
62
99
|
}
|
|
63
100
|
|
|
64
|
-
// Hydration
|
|
101
|
+
// Hydration marker range -> Hydration marker range
|
|
65
102
|
if (isVirtualRootStartMarker(current) && isVirtualRootStartMarker(next)) {
|
|
66
103
|
let nextData = next.data
|
|
67
104
|
if (current.data !== nextData) {
|
|
@@ -77,8 +114,41 @@ function diffNode(current: Node, next: Node, context: FrameContext): ChildNode |
|
|
|
77
114
|
if (isCommentNode(current) && isCommentNode(next)) {
|
|
78
115
|
let newData = next.data
|
|
79
116
|
if (current.data !== newData) {
|
|
80
|
-
|
|
81
|
-
current
|
|
117
|
+
let updated = false
|
|
118
|
+
if (isFrameStartMarker(current)) {
|
|
119
|
+
if (shouldPreserveFrameStartMarker(current, next, context)) {
|
|
120
|
+
current.data = newData
|
|
121
|
+
updated = true
|
|
122
|
+
|
|
123
|
+
let frame = context.frameInstances.get(current)
|
|
124
|
+
let nextMarkerData = getFrameMarkerData(next, context)
|
|
125
|
+
if (frame && nextMarkerData) {
|
|
126
|
+
if (nextMarkerData.status === 'resolved') {
|
|
127
|
+
let nextEnd = findFrameEndMarker(next)
|
|
128
|
+
let nextContent = collectFrameContentFragment(current.ownerDocument, next, nextEnd)
|
|
129
|
+
void frame.renderMarkerContent(
|
|
130
|
+
{ ...nextMarkerData, id: getFrameId(next) },
|
|
131
|
+
nextContent,
|
|
132
|
+
{
|
|
133
|
+
signal: context.signal,
|
|
134
|
+
},
|
|
135
|
+
)
|
|
136
|
+
return nextEnd
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (frame.isDisplayingResolvedContent()) {
|
|
140
|
+
return findFrameEndMarker(next)
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
} else {
|
|
144
|
+
disposeFrameStartMarker(current, context)
|
|
145
|
+
current.data = newData
|
|
146
|
+
updated = true
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
if (!updated) {
|
|
150
|
+
current.data = newData
|
|
151
|
+
}
|
|
82
152
|
}
|
|
83
153
|
return
|
|
84
154
|
}
|
|
@@ -224,7 +294,14 @@ function diffElementChildren(current: Element, next: Element, context: FrameCont
|
|
|
224
294
|
let nextChild = nextChildren[i]
|
|
225
295
|
let matchIndex = -1
|
|
226
296
|
|
|
227
|
-
if (
|
|
297
|
+
if (isFrameEndMarker(nextChild)) {
|
|
298
|
+
for (let j = 0; j < currentChildren.length; j++) {
|
|
299
|
+
if (!used[j] && isFrameEndMarker(currentChildren[j])) {
|
|
300
|
+
matchIndex = j
|
|
301
|
+
break
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
} else if (isElement(nextChild)) {
|
|
228
305
|
let key = nextChild.getAttribute('data-key')
|
|
229
306
|
if (key != null && keyToIndex.has(key)) {
|
|
230
307
|
let idx = keyToIndex.get(key)!
|
|
@@ -253,14 +330,42 @@ function diffElementChildren(current: Element, next: Element, context: FrameCont
|
|
|
253
330
|
let mi = matchIndexForNext[i]
|
|
254
331
|
if (mi !== -1) {
|
|
255
332
|
let curChild = currentChildren[mi]
|
|
256
|
-
let
|
|
333
|
+
let nextChild = nextChildren[i]
|
|
334
|
+
|
|
335
|
+
let replacement = getCommentMarkerRangeReplacement(
|
|
336
|
+
curChild,
|
|
337
|
+
nextChild,
|
|
338
|
+
currentChildren,
|
|
339
|
+
nextChildren,
|
|
340
|
+
mi,
|
|
341
|
+
i,
|
|
342
|
+
context,
|
|
343
|
+
)
|
|
344
|
+
if (replacement) {
|
|
345
|
+
replaceCommentMarkerRange(replacement, current, context)
|
|
346
|
+
|
|
347
|
+
for (let k = mi; k <= replacement.currentEndIndex; k++) used[k] = true
|
|
348
|
+
|
|
349
|
+
committed[i] = replacement.nextStart
|
|
350
|
+
committed[replacement.nextEndIndex] = nextChildren[replacement.nextEndIndex]
|
|
351
|
+
for (let j = i + 1; j < replacement.nextEndIndex; j++) committed[j] = undefined
|
|
352
|
+
|
|
353
|
+
i = replacement.nextEndIndex
|
|
354
|
+
continue
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
let cursor = diffNode(curChild, nextChild, context)
|
|
257
358
|
if (cursor) {
|
|
258
|
-
//
|
|
359
|
+
// `diffNode` can preserve hydration and frame marker ranges by returning
|
|
360
|
+
// the next end marker, so skip the owned interior nodes here.
|
|
259
361
|
let nextEndIdx = nextChildren.indexOf(cursor)
|
|
260
|
-
let currEndIdx =
|
|
362
|
+
let currEndIdx =
|
|
363
|
+
isFrameStartMarker(curChild) && isFrameEndMarker(cursor)
|
|
364
|
+
? findFrameEndIndex(currentChildren, mi)
|
|
365
|
+
: findHydrationEndIndex(currentChildren, mi)
|
|
261
366
|
|
|
262
|
-
// Adjacent
|
|
263
|
-
//
|
|
367
|
+
// Adjacent marker ranges can pre-match into the next range and leave an
|
|
368
|
+
// orphaned end marker behind. Clear those stale matches first.
|
|
264
369
|
for (let j = i + 1; j <= nextEndIdx; j++) {
|
|
265
370
|
let matchedIndex = matchIndexForNext[j]
|
|
266
371
|
if (matchedIndex > currEndIdx) {
|
|
@@ -272,7 +377,7 @@ function diffElementChildren(current: Element, next: Element, context: FrameCont
|
|
|
272
377
|
// Mark the entire current region as used to avoid removals.
|
|
273
378
|
for (let k = mi; k <= currEndIdx; k++) used[k] = true
|
|
274
379
|
|
|
275
|
-
// Preserve both
|
|
380
|
+
// Preserve both comment markers in committed; skip interior in reorder pass.
|
|
276
381
|
committed[i] = curChild // start marker
|
|
277
382
|
committed[nextEndIdx] = currentChildren[currEndIdx] // end marker
|
|
278
383
|
for (let j = i + 1; j < nextEndIdx; j++) committed[j] = undefined
|
|
@@ -296,9 +401,15 @@ function diffElementChildren(current: Element, next: Element, context: FrameCont
|
|
|
296
401
|
// Use only an anchor that is actually a child of the current parent
|
|
297
402
|
let ref = anchor && anchor.parentNode === current ? anchor : null
|
|
298
403
|
|
|
299
|
-
//
|
|
300
|
-
//
|
|
301
|
-
|
|
404
|
+
// Existing comment markers delimit live ranges, so do not reorder them
|
|
405
|
+
// independently from their contents. New markers still need to be inserted
|
|
406
|
+
// before they can be used as anchors.
|
|
407
|
+
if (
|
|
408
|
+
isVirtualRootStartMarker(node) ||
|
|
409
|
+
isVirtualRootEndMarker(node) ||
|
|
410
|
+
isFrameStartMarker(node) ||
|
|
411
|
+
isFrameEndMarker(node)
|
|
412
|
+
) {
|
|
302
413
|
if (node.parentNode !== current) {
|
|
303
414
|
current.insertBefore(node, ref)
|
|
304
415
|
}
|
|
@@ -372,6 +483,37 @@ function findHydrationEndIndex(nodes: Node[], startIdx: number): number {
|
|
|
372
483
|
return startIdx
|
|
373
484
|
}
|
|
374
485
|
|
|
486
|
+
function findFrameEndMarker(start: Comment): Comment {
|
|
487
|
+
let node: Node | null = start.nextSibling
|
|
488
|
+
let depth = 1
|
|
489
|
+
|
|
490
|
+
while (node) {
|
|
491
|
+
if (isFrameStartMarker(node)) depth++
|
|
492
|
+
if (isFrameEndMarker(node)) {
|
|
493
|
+
depth--
|
|
494
|
+
if (depth === 0) return node
|
|
495
|
+
}
|
|
496
|
+
node = node.nextSibling
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
throw new Error('Frame end marker not found')
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
function findFrameEndIndex(nodes: Node[], startIdx: number): number {
|
|
503
|
+
let depth = 1
|
|
504
|
+
|
|
505
|
+
for (let j = startIdx + 1; j < nodes.length; j++) {
|
|
506
|
+
let node = nodes[j]
|
|
507
|
+
if (isFrameStartMarker(node)) depth++
|
|
508
|
+
if (isFrameEndMarker(node)) {
|
|
509
|
+
depth--
|
|
510
|
+
if (depth === 0) return j
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
return startIdx
|
|
515
|
+
}
|
|
516
|
+
|
|
375
517
|
function isTextNode(node: Node): node is Text {
|
|
376
518
|
return node.nodeType === Node.TEXT_NODE
|
|
377
519
|
}
|
|
@@ -388,6 +530,114 @@ function isFrameStartMarker(node: Node): node is Comment {
|
|
|
388
530
|
return node instanceof Comment && node.data.trim().startsWith('rmx:f:')
|
|
389
531
|
}
|
|
390
532
|
|
|
533
|
+
function isFrameEndMarker(node: Node): node is Comment {
|
|
534
|
+
return node instanceof Comment && node.data.trim() === '/rmx:f'
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
function shouldPreserveFrameStartMarker(
|
|
538
|
+
current: Comment,
|
|
539
|
+
next: Comment,
|
|
540
|
+
context: FrameContext,
|
|
541
|
+
): boolean {
|
|
542
|
+
if (!isFrameStartMarker(next)) return false
|
|
543
|
+
|
|
544
|
+
let currentData = getFrameMarkerData(current, context)
|
|
545
|
+
let nextData = getFrameMarkerData(next, context)
|
|
546
|
+
|
|
547
|
+
return (
|
|
548
|
+
currentData !== undefined &&
|
|
549
|
+
nextData !== undefined &&
|
|
550
|
+
currentData.src === nextData.src &&
|
|
551
|
+
currentData.name === nextData.name
|
|
552
|
+
)
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
function getCommentMarkerRangeReplacement(
|
|
556
|
+
current: Node,
|
|
557
|
+
next: Node,
|
|
558
|
+
currentNodes: Node[],
|
|
559
|
+
nextNodes: Node[],
|
|
560
|
+
currentIndex: number,
|
|
561
|
+
nextIndex: number,
|
|
562
|
+
context: FrameContext,
|
|
563
|
+
): CommentMarkerRangeReplacement | undefined {
|
|
564
|
+
// Comment markers can represent owned DOM ranges, not standalone comments. If
|
|
565
|
+
// the incoming range no longer has the same identity, replace the whole range
|
|
566
|
+
// before regular node diffing mutates either marker.
|
|
567
|
+
if (
|
|
568
|
+
isFrameStartMarker(current) &&
|
|
569
|
+
isFrameStartMarker(next) &&
|
|
570
|
+
!shouldPreserveFrameStartMarker(current, next, context)
|
|
571
|
+
) {
|
|
572
|
+
return {
|
|
573
|
+
currentStart: current,
|
|
574
|
+
nextStart: next,
|
|
575
|
+
currentEndIndex: findFrameEndIndex(currentNodes, currentIndex),
|
|
576
|
+
nextEndIndex: findFrameEndIndex(nextNodes, nextIndex),
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
function getFrameMarkerData(marker: Comment, context: FrameContext) {
|
|
582
|
+
let id = getFrameId(marker)
|
|
583
|
+
return context.data.f?.[id]
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
function getFrameId(marker: Comment): string {
|
|
587
|
+
let trimmed = marker.data.trim()
|
|
588
|
+
invariant(trimmed.startsWith('rmx:f:'), 'Invalid frame start marker')
|
|
589
|
+
return trimmed.slice('rmx:f:'.length)
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
function replaceCommentMarkerRange(
|
|
593
|
+
replacement: CommentMarkerRangeReplacement,
|
|
594
|
+
parent: ParentNode,
|
|
595
|
+
context: FrameContext,
|
|
596
|
+
): void {
|
|
597
|
+
let currentEnd = findFrameEndMarker(replacement.currentStart)
|
|
598
|
+
let nextEnd = findFrameEndMarker(replacement.nextStart)
|
|
599
|
+
let nextNodes = collectNodeRange(replacement.nextStart, nextEnd)
|
|
600
|
+
let currentNodes = collectNodeRange(replacement.currentStart, currentEnd)
|
|
601
|
+
|
|
602
|
+
for (let node of nextNodes) {
|
|
603
|
+
parent.insertBefore(node, replacement.currentStart)
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
for (let node of currentNodes) {
|
|
607
|
+
removeNode(node, parent, context)
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
function collectNodeRange(start: Node, end: Node): Node[] {
|
|
612
|
+
let nodes: Node[] = []
|
|
613
|
+
let node: Node | null = start
|
|
614
|
+
|
|
615
|
+
while (node) {
|
|
616
|
+
nodes.push(node)
|
|
617
|
+
if (node === end) break
|
|
618
|
+
node = node.nextSibling
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
return nodes
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
function collectFrameContentFragment(
|
|
625
|
+
doc: Document,
|
|
626
|
+
start: Comment,
|
|
627
|
+
end: Comment,
|
|
628
|
+
): DocumentFragment {
|
|
629
|
+
let fragment = doc.createDocumentFragment()
|
|
630
|
+
let node = start.nextSibling
|
|
631
|
+
|
|
632
|
+
while (node && node !== end) {
|
|
633
|
+
let next = node.nextSibling
|
|
634
|
+
fragment.appendChild(node)
|
|
635
|
+
node = next
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
return fragment
|
|
639
|
+
}
|
|
640
|
+
|
|
391
641
|
function removeNode(node: Node, parent: ParentNode, context: FrameContext): void {
|
|
392
642
|
disposeRemovedVirtualRoots(node)
|
|
393
643
|
disposeRemovedSubFrames(node, context)
|