tangled
alpha
login
or
join now
tombl.dev
/
dhtml
1
fork
atom
a post-component library for building user-interfaces on the web.
1
fork
atom
overview
issues
pulls
pipelines
use child part for list items, not root
tombl.dev
8 months ago
fb40985d
6408419a
verified
This commit was signed with the committer's
known signature
.
tombl.dev
SSH Key Fingerprint:
SHA256:d8AHgL5V+3WdvGdDb3SVBfb0RIRJfkKcqhQ5aG1mVNk=
+52
-60
1 changed file
expand all
collapse all
unified
split
src
client
parts.ts
+52
-60
src/client/parts.ts
reviewed
···
15
15
export type Part = (value: unknown) => void
16
16
17
17
export function create_child_part(parent_node: Node | Span, child_index: number): Part {
18
18
+
let child: ChildNode | null
19
19
+
20
20
+
if (parent_node instanceof Node) {
21
21
+
child = parent_node.childNodes[child_index]
22
22
+
assert(child)
23
23
+
} else {
24
24
+
child = parent_node._start.nextSibling
25
25
+
assert(child)
26
26
+
for (let i = 0; i < child_index; i++) {
27
27
+
child = child.nextSibling
28
28
+
assert(child !== null, 'expected more siblings')
29
29
+
assert(child !== parent_node._end, 'ran out of siblings before the end')
30
30
+
}
31
31
+
}
32
32
+
33
33
+
return create_child_part_inner(() => create_span(child))
34
34
+
}
35
35
+
36
36
+
function create_child_part_inner(get_span: () => Span): Part {
18
37
let span: Span | undefined
19
38
20
39
// for when we're rendering a renderable:
···
25
44
let root: Root | undefined
26
45
27
46
// for when we're rendering multiple values:
28
28
-
let spans: Span[] | undefined
29
29
-
let roots: Root[] | undefined
30
30
-
let keys: Key[] | undefined
47
47
+
let entries: Array<{ _span: Span; _part: Part; _key: Key }> | undefined
31
48
32
49
// for when we're rendering a string/single dom node:
33
50
// undefined means no previous value, because a user-specified undefined is remapped to null
···
55
72
root = undefined
56
73
}
57
74
58
58
-
let child: ChildNode | null
59
59
-
if (parent_node instanceof Node) {
60
60
-
child = parent_node.childNodes[child_index]
61
61
-
assert(child)
62
62
-
} else {
63
63
-
child = parent_node._start.nextSibling
64
64
-
assert(child)
65
65
-
for (let i = 0; i < child_index; i++) {
66
66
-
child = child.nextSibling
67
67
-
assert(child !== null, 'expected more siblings')
68
68
-
assert(child !== parent_node._end, 'ran out of siblings before the end')
69
69
-
}
70
70
-
}
71
71
-
72
75
return function update(value) {
73
73
-
span ??= create_span(child)
76
76
+
span ??= get_span()
74
77
75
78
if (is_renderable(value)) {
76
79
if (!needs_revalidate && value === current_renderable) return
···
114
117
// NOTE: we're explicitly not caching/diffing the value when it's an iterable,
115
118
// given it can yield different values but have the same identity. (e.g. arrays)
116
119
if (is_iterable(value)) {
117
117
-
if (!roots) {
120
120
+
if (!entries) {
118
121
// we previously rendered a single value, so we need to clear it.
119
122
disconnect_root()
120
123
delete_contents(span)
121
121
-
122
122
-
spans = []
123
123
-
roots = []
124
124
-
keys = []
124
124
+
entries = []
125
125
}
126
126
-
assert(spans)
127
127
-
assert(keys)
128
126
129
127
// create or update a root for every item.
130
128
let i = 0
131
129
let end = span._start
132
130
for (const item of value) {
133
133
-
const key = get_key(item)
134
134
-
let span = (spans[i] ??= create_span_after(end))
135
135
-
let root = (roots[i] ??= create_root(span))
131
131
+
const key = get_key(item) as Key
132
132
+
if (entries.length <= i) {
133
133
+
const span = create_span_after(end)
134
134
+
entries[i] = { _span: span, _part: create_child_part_inner(() => span), _key: key }
135
135
+
}
136
136
137
137
-
if (key !== undefined && keys[i] !== key) {
138
138
-
for (let j = i; j < roots.length; j++) {
139
139
-
const root1 = root
140
140
-
const root2 = roots[j]
141
141
-
const span1 = spans[i]
142
142
-
const span2 = spans[j]
137
137
+
if (key !== undefined && entries[i]._key !== key) {
138
138
+
for (let j = i + 1; j < entries.length; j++) {
139
139
+
const entry1 = entries[i]
140
140
+
const entry2 = entries[j]
143
141
144
144
-
if (keys[j] === key) {
142
142
+
if (entry2._key === key) {
145
143
// swap the contents of the spans
146
146
-
const tmp_content = extract_contents(span1)
147
147
-
insert_node(span1, extract_contents(span2))
148
148
-
insert_node(span2, tmp_content)
144
144
+
const tmp_content = extract_contents(entry1._span)
145
145
+
insert_node(entry1._span, extract_contents(entry2._span))
146
146
+
insert_node(entry2._span, tmp_content)
149
147
150
148
// swap the spans back
151
151
-
const tmp_span = { ...span1 }
152
152
-
Object.assign(span1, span2)
153
153
-
Object.assign(span2, tmp_span)
149
149
+
const tmp_span = { ...entry1._span }
150
150
+
Object.assign(entry1._span, entry2._span)
151
151
+
Object.assign(entry2._span, tmp_span)
154
152
155
153
// swap the roots
156
156
-
spans[j] = span1
157
157
-
span = spans[i] = span2
158
158
-
roots[j] = root1
159
159
-
root = roots[i] = root2
160
160
-
keys[j] = keys[i]
161
161
-
keys[i] = key
154
154
+
entries[j] = entry1
155
155
+
entries[i] = entry2
162
156
163
157
break
164
158
}
165
159
}
166
160
167
167
-
keys[i] = key
161
161
+
entries[i]._key = key
168
162
}
169
163
170
170
-
root.render(item as Displayable)
171
171
-
end = span._end
164
164
+
entries[i]._part(item as Displayable)
165
165
+
end = entries[i]._span._end
172
166
i++
173
167
}
174
168
175
175
-
// and now remove excess roots if the iterable has shrunk.
176
176
-
while (roots.length > i) {
177
177
-
const root = roots.pop()
178
178
-
assert(root)
179
179
-
root.render(null)
169
169
+
// and now remove excess parts if the iterable has shrunk.
170
170
+
while (entries.length > i) {
171
171
+
const entry = entries.pop()
172
172
+
assert(entry)
173
173
+
entry._part(null)
180
174
}
181
175
182
176
return
183
183
-
} else if (roots) {
184
184
-
for (const root of roots) root.render(null)
185
185
-
spans = undefined
186
186
-
roots = undefined
187
187
-
keys = undefined
177
177
+
} else if (entries) {
178
178
+
for (const entry of entries) entry._part(null)
179
179
+
entries = undefined
188
180
}
189
181
190
182
// now early return if the value hasn't changed.