@abide/abide 0.105.0 → 0.105.1
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/CHANGELOG.md +6 -0
- package/package.json +1 -1
- package/src/ui/leave.ts +5 -0
- package/src/ui/reconcile.ts +25 -0
- package/src/ui/regions.ts +27 -2
package/CHANGELOG.md
CHANGED
package/package.json
CHANGED
package/src/ui/leave.ts
CHANGED
|
@@ -23,6 +23,11 @@ export function holdWhileLeaving(
|
|
|
23
23
|
settling.then(done, done)
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
+
/** Whether any element is leaving, so a removal has to ask each node whether it holds one. */
|
|
27
|
+
export function anyLeaving(): boolean {
|
|
28
|
+
return LEAVING.size !== 0
|
|
29
|
+
}
|
|
30
|
+
|
|
26
31
|
/** Removes `node`, or holds it where it is while an element it holds is leaving. */
|
|
27
32
|
export function leave(node: ChildNode): void {
|
|
28
33
|
if (LEAVING.size !== 0)
|
package/src/ui/reconcile.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { LAYER_RECONCILE } from './LAYER_NAMES.ts'
|
|
|
3
3
|
import type { List } from './List.ts'
|
|
4
4
|
import { HYDRATE_LOG } from './Mismatch.ts'
|
|
5
5
|
import { beginLayer, endLayer } from './measureLayer.ts'
|
|
6
|
+
import { emptyRegion } from './regions.ts'
|
|
6
7
|
import { dropRow, makeRow, moveRow, type Row } from './rows.ts'
|
|
7
8
|
|
|
8
9
|
// 41.8 — a KEYED list, reconciled by moving the nodes that are already there rather than by
|
|
@@ -21,6 +22,10 @@ import { dropRow, makeRow, moveRow, type Row } from './rows.ts'
|
|
|
21
22
|
* survive are MOVED, never remade.
|
|
22
23
|
*/
|
|
23
24
|
export function reconcile(list: List, data: unknown[]): void {
|
|
25
|
+
if (data.length === 0) {
|
|
26
|
+
clear(list)
|
|
27
|
+
return
|
|
28
|
+
}
|
|
24
29
|
const region = list.region
|
|
25
30
|
const current = list.rows
|
|
26
31
|
const wanted = data.length
|
|
@@ -182,6 +187,26 @@ export function reconcile(list: List, data: unknown[]): void {
|
|
|
182
187
|
}
|
|
183
188
|
}
|
|
184
189
|
|
|
190
|
+
/**
|
|
191
|
+
* Drops every row, emptying the region in one write rather than one removal a row.
|
|
192
|
+
*
|
|
193
|
+
* NOTHING WANTED IS ITS OWN SHAPE: there is no key to match and no order to keep, so the map,
|
|
194
|
+
* the survivor walk and the placement walk all answer nothing. Every row is still STOPPED first,
|
|
195
|
+
* as `dropRow` would, so a binding cannot wake over a node that is already gone.
|
|
196
|
+
*/
|
|
197
|
+
function clear(list: List): void {
|
|
198
|
+
const parent = list.region.close.parentNode
|
|
199
|
+
if (parent === null) return
|
|
200
|
+
beginLayer(LAYER_RECONCILE)
|
|
201
|
+
try {
|
|
202
|
+
for (const row of list.rows) row.scope.stop()
|
|
203
|
+
list.rows = []
|
|
204
|
+
emptyRegion(list.region, parent)
|
|
205
|
+
} finally {
|
|
206
|
+
endLayer(LAYER_RECONCILE)
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
185
210
|
/**
|
|
186
211
|
* Whether a patch wrote to the row's item since the row was made.
|
|
187
212
|
*
|
package/src/ui/regions.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { REGION_CLOSE, REGION_OPEN } from '#shared/ANCHORS.ts'
|
|
2
2
|
import { LAYER_FILL } from './LAYER_NAMES.ts'
|
|
3
|
-
import { leave } from './leave.ts'
|
|
3
|
+
import { anyLeaving, leave } from './leave.ts'
|
|
4
4
|
import { Mismatch } from './Mismatch.ts'
|
|
5
5
|
import { beginLayer, endLayer } from './measureLayer.ts'
|
|
6
6
|
|
|
@@ -97,7 +97,7 @@ export function fillRegion(
|
|
|
97
97
|
throw new Mismatch(
|
|
98
98
|
`abide: this region is not in a document, so the client and the server disagree about this region's shape (41.10).`,
|
|
99
99
|
)
|
|
100
|
-
|
|
100
|
+
emptyRegion(region, parent)
|
|
101
101
|
if (build === undefined) return
|
|
102
102
|
beginLayer(LAYER_FILL)
|
|
103
103
|
try {
|
|
@@ -126,6 +126,31 @@ export function fillEmpty(
|
|
|
126
126
|
return true
|
|
127
127
|
}
|
|
128
128
|
|
|
129
|
+
/**
|
|
130
|
+
* Removes everything between a region's anchors, which stay.
|
|
131
|
+
*
|
|
132
|
+
* ONE WRITE WHERE THE REGION IS ALL ITS PARENT HOLDS — a `<tbody>` or a `<ul>` around one
|
|
133
|
+
* `{#for}`, the common shape of a list emptied — and the anchors put back after it. A removal per
|
|
134
|
+
* node is a crossing into the engine per node; the engine's own clear is one.
|
|
135
|
+
*
|
|
136
|
+
* NODE BY NODE WHILE ANYTHING IS LEAVING (32.38), because a node holding a leaving element has to
|
|
137
|
+
* stay where it stands, and only `leave` asks.
|
|
138
|
+
*/
|
|
139
|
+
export function emptyRegion(region: Region, parent: ParentNode): void {
|
|
140
|
+
const { open, close } = region
|
|
141
|
+
if (
|
|
142
|
+
anyLeaving() ||
|
|
143
|
+
parent.firstChild !== open ||
|
|
144
|
+
parent.lastChild !== close
|
|
145
|
+
) {
|
|
146
|
+
removeUntil(open.nextSibling, close)
|
|
147
|
+
return
|
|
148
|
+
}
|
|
149
|
+
if (open.nextSibling === close) return
|
|
150
|
+
parent.textContent = ''
|
|
151
|
+
parent.append(open, close)
|
|
152
|
+
}
|
|
153
|
+
|
|
129
154
|
/** Removes `from` and every sibling after it, up to and not including `end`. */
|
|
130
155
|
export function removeUntil(from: ChildNode | null, end: Node | null): void {
|
|
131
156
|
let node = from
|