Skip to content

Commit 0804b78

Browse files
author
smtdfc
committed
fix(browser): preserve custom properties when cloning nodes
1 parent 8bc5026 commit 0804b78

1 file changed

Lines changed: 50 additions & 54 deletions

File tree

packages/browser/src/index.ts

Lines changed: 50 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,10 @@ function createMarkedFragment() {
1717
const end = document.createComment('r:end');
1818
const fragment = document.createDocumentFragment();
1919
fragment.append(start, end);
20-
20+
2121
return {
2222
fragment,
23-
23+
2424
insertAt(el: Node, index: number) {
2525
let ref = start.nextSibling;
2626
let i = 0;
@@ -31,7 +31,7 @@ function createMarkedFragment() {
3131
}
3232
end.parentNode!.insertBefore(el, ref ?? end);
3333
},
34-
34+
3535
insertRange(els: Node[], index: number) {
3636
let node = start.nextSibling;
3737
let i = 0;
@@ -45,7 +45,7 @@ function createMarkedFragment() {
4545
for (const el of els) frag.appendChild(el);
4646
ref.parentNode!.insertBefore(frag, ref);
4747
},
48-
48+
4949
replace(...nodes: Node[]) {
5050
const parent = start.parentNode!;
5151
let node = start.nextSibling;
@@ -54,7 +54,7 @@ function createMarkedFragment() {
5454
parent.removeChild(node);
5555
node = next;
5656
}
57-
57+
5858
if (nodes.length === 0) return;
5959
const frag = document.createDocumentFragment();
6060
for (const n of nodes) frag.appendChild(n);
@@ -69,9 +69,10 @@ export function eventDelegate(events: string[]) {
6969
EVENT_DELEGATION.push(name);
7070
window.addEventListener(name, (event: Event) => {
7171
const target = event.target as HTMLElement & {
72-
[EVENT_DELEGATE_SYMBOL]?: Record<string, (e: Event) => unknown>;
72+
[EVENT_DELEGATE_SYMBOL] ? : Record < string,
73+
(e: Event) => unknown > ;
7374
};
74-
75+
7576
if (
7677
target &&
7778
target[EVENT_DELEGATE_SYMBOL] &&
@@ -88,16 +89,16 @@ export function element(
8889
parent: HTMLElement,
8990
context: RenderContext,
9091
tagName: string,
91-
attrs?: Record<string, string>,
92+
attrs ? : Record < string, string > ,
9293
): HTMLElement {
9394
const el = document.createElement(tagName);
94-
95+
9596
if (attrs) {
9697
for (const key in attrs) {
9798
el.setAttribute(key, attrs[key]);
9899
}
99100
}
100-
101+
101102
parent.appendChild(el);
102103
return el;
103104
}
@@ -115,9 +116,10 @@ export function createEvent(
115116
callback: (e: Event) => unknown,
116117
) {
117118
target = target as HTMLElement & {
118-
[EVENT_DELEGATE_SYMBOL]?: Record<string, (e: Event) => unknown>;
119+
[EVENT_DELEGATE_SYMBOL] ? : Record < string,
120+
(e: Event) => unknown > ;
119121
};
120-
122+
121123
if (!target[EVENT_DELEGATE_SYMBOL]) target[EVENT_DELEGATE_SYMBOL] = {};
122124
target[EVENT_DELEGATE_SYMBOL][name] = callback;
123125
}
@@ -146,43 +148,37 @@ export function appendDynamicValue(
146148
const end = document.createComment('_');
147149
parent.appendChild(start);
148150
parent.appendChild(end);
149-
151+
150152
let prev: unknown = null;
151153
let currentNodes: Node[] = [];
152-
154+
153155
const replaceRange = (nodes: Node[]) => {
154156
//if (end.parentNode !== parent) return;
155-
157+
156158
const range = document.createRange();
157159
range.setStartAfter(start);
158160
range.setEndBefore(end);
159161
range.deleteContents();
160-
161-
const frag = document.createDocumentFragment();
162+
162163
for (let node of nodes) {
163-
if (node.parentNode && node.parentNode !== parent) {
164-
node = node.cloneNode(true);
165-
}
166-
frag.appendChild(node);
164+
range.insertNode(node);
167165
}
168-
169-
range.insertNode(frag);
170166
currentNodes = nodes;
171167
};
172-
168+
173169
const normalize = (val: unknown): Node[] => {
174170
if (Array.isArray(val)) {
175171
const flat: Node[] = [];
176172
for (const v of val) flat.push(...normalize(v));
177173
return flat;
178174
}
179-
175+
180176
if (isRenderContent(val)) {
181177
return [val(context)];
182178
}
183-
179+
184180
if (val == null || typeof val === 'boolean') return [];
185-
181+
186182
if (typeof val === 'string' || typeof val === 'number') {
187183
if (
188184
currentNodes.length === 1 &&
@@ -194,26 +190,26 @@ export function appendDynamicValue(
194190
return [document.createTextNode(String(val))];
195191
}
196192
}
197-
193+
198194
if (val instanceof Node) return [val];
199-
195+
200196
return [document.createTextNode(String(val))];
201197
};
202-
198+
203199
const update = (val: unknown) => {
204200
if (val === prev) return;
205201
prev = val;
206-
202+
207203
const normalized = normalize(val);
208-
204+
209205
if (
210206
normalized.length !== currentNodes.length ||
211207
normalized.some((n, i) => n !== currentNodes[i])
212208
) {
213209
replaceRange(normalized);
214210
}
215211
};
216-
212+
217213
if (value instanceof State) {
218214
context.onRenderFinish.push(() => {
219215
value.reactor.addInternalBinding(() => update(value.get()));
@@ -223,10 +219,10 @@ export function appendDynamicValue(
223219
update(value);
224220
}
225221
}
226-
export function createComponent<T extends object>(
222+
export function createComponent < T extends object > (
227223
parent: HTMLElement,
228224
context: RenderContext,
229-
component: ComponentConstructor<T>,
225+
component: ComponentConstructor < T > ,
230226
props: T,
231227
): HTMLElement {
232228
const element = createComponentElement(component, context, props);
@@ -250,29 +246,29 @@ export function view(
250246
if (value instanceof ViewControl) value.setTarget(element);
251247
}
252248

253-
export function createIfComponent<T>(
249+
export function createIfComponent < T > (
254250
parent: HTMLElement,
255251
context: RenderContext,
256-
props: IfProps<T>,
252+
props: IfProps < T > ,
257253
) {
258254
const onTrue = props.onTrue;
259255
const onFalse = props.onFalse;
260256
const render = () => {
261257
const condition =
262-
props.condition instanceof State
263-
? props.condition.get()
264-
: props.condition;
258+
props.condition instanceof State ?
259+
props.condition.get() :
260+
props.condition;
265261
let templ: DocumentFragment = document.createDocumentFragment();
266-
262+
267263
if (condition && onTrue) {
268264
templ = onTrue(context);
269265
} else if (onFalse && !condition) {
270266
templ = onFalse(context);
271267
}
272-
268+
273269
marker.replace(...templ.childNodes);
274270
};
275-
271+
276272
const marker = createMarkedFragment();
277273
render();
278274
if (props.condition instanceof State) {
@@ -281,26 +277,26 @@ export function createIfComponent<T>(
281277
state.reactor.addInternalBinding(() => render());
282278
});
283279
}
284-
280+
285281
parent.appendChild(marker.fragment);
286282
}
287283

288-
export function createForComponent<T>(
284+
export function createForComponent < T > (
289285
parent: HTMLElement,
290286
context: RenderContext,
291-
props: ForProps<T>,
287+
props: ForProps < T > ,
292288
) {
293289
const tmpl = props.template;
294290
const marker = createMarkedFragment();
295291
const items: HTMLElement[] = [];
296-
292+
297293
// Initial render
298294
const initialList = props.list.get();
299295
for (let i = 0; i < initialList.length; i++) {
300296
const el = tmpl(initialList[i])(context).children[0] as HTMLElement;
301297
items.push(el);
302298
}
303-
299+
304300
parent.appendChild(marker.fragment);
305301
marker.insertRange(items, 0);
306302
context.onRenderFinish.push(() => {
@@ -314,13 +310,13 @@ export function createForComponent<T>(
314310
marker.insertAt(el, key as number);
315311
break;
316312
}
317-
313+
318314
case 'remove': {
319315
const removed = items.splice(key as number, 1)[0];
320316
removed?.remove?.();
321317
break;
322318
}
323-
319+
324320
case 'update': {
325321
const newEl = tmpl(value as T)(context).children[0] as HTMLElement;
326322
const oldEl = items[key as number];
@@ -330,21 +326,21 @@ export function createForComponent<T>(
330326
}
331327
break;
332328
}
333-
329+
334330
case 'set': {
335331
for (const item of items) item.remove?.();
336332
items.length = 0;
337-
333+
338334
const fresh = (value as T[]).map((val) => {
339335
const el = tmpl(val)(context).children[0] as HTMLElement;
340336
items.push(el);
341337
return el;
342338
});
343-
339+
344340
marker.insertRange(fresh, 0);
345341
break;
346342
}
347343
}
348344
});
349345
});
350-
}
346+
}

0 commit comments

Comments
 (0)