@dom-expressions/runtime 0.50.0-next.15

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/src/client.js ADDED
@@ -0,0 +1,893 @@
1
+ import { ChildProperties, Namespaces, DelegatedEvents, $$SLOT, $$HOST } from "./constants";
2
+ import {
3
+ root,
4
+ effect,
5
+ memo,
6
+ getOwner,
7
+ createComponent,
8
+ sharedConfig,
9
+ untrack,
10
+ runWithOwner,
11
+ mergeProps,
12
+ flatten
13
+ } from "rxcore";
14
+ import reconcileArrays from "./reconcile";
15
+ import { DOMWithState } from "./constants";
16
+ export {
17
+ DOMWithState,
18
+ ChildProperties,
19
+ DOMElements,
20
+ SVGElements,
21
+ MathMLElements,
22
+ VoidElements,
23
+ RawTextElements,
24
+ Namespaces,
25
+ DelegatedEvents
26
+ } from "./constants";
27
+
28
+ const $$EVENT_OWNER = "_$DX_EVENT_OWNER";
29
+ const INNER_OWNED = {};
30
+ const delegatedEvents = new Set();
31
+ const delegatedContainers = new Map();
32
+
33
+ export {
34
+ effect,
35
+ memo,
36
+ untrack,
37
+ getOwner,
38
+ createComponent,
39
+ mergeProps,
40
+ voidFn as useAssets,
41
+ voidFn as getAssets,
42
+ voidFn as Assets,
43
+ voidFn as generateHydrationScript,
44
+ voidFn as HydrationScript,
45
+ voidFn as getRequestEvent
46
+ };
47
+
48
+ export function render(code, element, init, options = {}) {
49
+ if ("_DX_DEV_" && !element) {
50
+ throw new Error(
51
+ "The `element` passed to `render(..., element)` doesn't exist. Make sure `element` exists in the document."
52
+ );
53
+ }
54
+ let disposer;
55
+ registerDelegatedRoot(element);
56
+ try {
57
+ root(
58
+ dispose => {
59
+ disposer = dispose;
60
+ if (element === document) {
61
+ const tree = code();
62
+ effect(
63
+ () => flatten(tree),
64
+ () => {}
65
+ );
66
+ } else {
67
+ const tree = code();
68
+ insert(
69
+ element,
70
+ () => tree,
71
+ element.firstChild ? null : undefined,
72
+ init,
73
+ options.insertOptions
74
+ );
75
+ }
76
+ },
77
+ { id: options.renderId }
78
+ );
79
+ } catch (err) {
80
+ if (disposer) disposer();
81
+ unregisterDelegatedRoot(element);
82
+ throw err;
83
+ }
84
+ return () => {
85
+ disposer();
86
+ unregisterDelegatedRoot(element);
87
+ element.textContent = "";
88
+ };
89
+ }
90
+
91
+ function create(html, bypassGuard, flag) {
92
+ if ("_DX_DEV_" && isHydrating() && !bypassGuard)
93
+ throw new Error(
94
+ "Failed attempt to create new DOM elements during hydration. Check that the libraries you are using support hydration."
95
+ );
96
+ const t = document.createElement("template");
97
+ t.innerHTML = html;
98
+ return flag === 2 ? t.content.firstChild.firstChild : t.content.firstChild;
99
+ }
100
+
101
+ export function template(html, flag) {
102
+ let node;
103
+ const fn =
104
+ flag === 1
105
+ ? bypassGuard => document.importNode(node || (node = create(html, bypassGuard, flag)), true)
106
+ : bypassGuard => (node || (node = create(html, bypassGuard, flag))).cloneNode(true);
107
+
108
+ if ("_DX_DEV_") fn._html = flag === 2 ? html.replace(/^<[^>]+>/, "") : html;
109
+ return fn;
110
+ }
111
+ export function delegateEvents(eventNames) {
112
+ for (let i = 0, l = eventNames.length; i < l; i++) {
113
+ const name = eventNames[i];
114
+ if (!delegatedEvents.has(name)) {
115
+ delegatedEvents.add(name);
116
+ delegatedContainers.forEach((state, container) =>
117
+ attachDelegatedEvent(name, container, state)
118
+ );
119
+ }
120
+ }
121
+ }
122
+
123
+ export function registerDelegatedRoot(root) {
124
+ const state = registerDelegatedContainer(root, root);
125
+ if (state) state.roots = (state.roots || 0) + 1;
126
+ }
127
+
128
+ export function unregisterDelegatedRoot(root) {
129
+ const state = delegatedContainers.get(root);
130
+ if (state) state.roots > 1 ? state.roots-- : delete state.roots;
131
+ unregisterDelegatedContainer(root, root);
132
+ }
133
+
134
+ export function registerDelegatedContainer(container, owner = container) {
135
+ if (!container || !owner) return;
136
+ let state = delegatedContainers.get(container);
137
+ if (!state)
138
+ delegatedContainers.set(
139
+ container,
140
+ (state = {
141
+ owners: new Map(),
142
+ handlers: new Map()
143
+ })
144
+ );
145
+ state.owners.set(owner, (state.owners.get(owner) || 0) + 1);
146
+ delegatedEvents.forEach(name => attachDelegatedEvent(name, container, state));
147
+ return state;
148
+ }
149
+
150
+ export function unregisterDelegatedContainer(container, owner = container) {
151
+ const state = delegatedContainers.get(container);
152
+ if (!state) return;
153
+ const count = state.owners.get(owner);
154
+ if (count > 1) state.owners.set(owner, count - 1);
155
+ else state.owners.delete(owner);
156
+ if (state.owners.size) return;
157
+ state.handlers.forEach((handler, name) => container.removeEventListener(name, handler));
158
+ delegatedContainers.delete(container);
159
+ }
160
+
161
+ function attachDelegatedEvent(name, container, state) {
162
+ if (state.handlers.has(name)) return;
163
+ const handler = e => eventHandler(e, container, state);
164
+ state.handlers.set(name, handler);
165
+ container.addEventListener(name, handler);
166
+ }
167
+
168
+ export function getDelegatedRoot(node) {
169
+ while (node) {
170
+ if (delegatedContainers.get(node)?.roots) return node;
171
+ node = node._$host || node.parentNode || node.host;
172
+ }
173
+ }
174
+
175
+ function findOwner(target, state) {
176
+ let node = target;
177
+ let distance = 0;
178
+ while (node) {
179
+ if (state.owners.has(node)) return { owner: node, distance };
180
+ distance++;
181
+ node = node._$host || node.parentNode || node.host;
182
+ }
183
+ }
184
+
185
+ export function setProperty(node, name, value) {
186
+ if (isHydrating(node)) return;
187
+ node[name] = value;
188
+ }
189
+
190
+ export function setAttribute(node, name, value) {
191
+ if (isHydrating(node)) return;
192
+ if (value == null || value === false) node.removeAttribute(name);
193
+ else node.setAttribute(name, value === true ? "" : value);
194
+ }
195
+
196
+ export function setAttributeNS(node, namespace, name, value) {
197
+ if (isHydrating(node)) return;
198
+ // removeAttributeNS takes the local name; setAttributeNS accepts the qualified form.
199
+ if (value == null || value === false)
200
+ node.removeAttributeNS(namespace, name.indexOf(":") > -1 ? name.split(":").pop() : name);
201
+ else node.setAttributeNS(namespace, name, value === true ? "" : value);
202
+ }
203
+
204
+ export function className(node, value, prev) {
205
+ if (isHydrating(node)) return;
206
+ if (value == null || value === false) {
207
+ prev && node.removeAttribute("class");
208
+ return;
209
+ }
210
+ if (typeof value === "string") {
211
+ value !== prev && node.setAttribute("class", value);
212
+ return;
213
+ }
214
+ if (typeof prev === "string") {
215
+ prev = {};
216
+ node.removeAttribute("class");
217
+ } else prev = classListToObject(prev || {});
218
+ value = classListToObject(value);
219
+ const classKeys = Object.keys(value || {});
220
+ const prevKeys = Object.keys(prev);
221
+ let i, len;
222
+ for (i = 0, len = prevKeys.length; i < len; i++) {
223
+ const key = prevKeys[i];
224
+ if (!key || key === "undefined" || value[key]) continue;
225
+ node.classList.remove(key);
226
+ }
227
+ for (i = 0, len = classKeys.length; i < len; i++) {
228
+ const key = classKeys[i],
229
+ classValue = !!value[key];
230
+ if (!key || key === "undefined" || prev[key] === classValue || !classValue) continue;
231
+ node.classList.add(key);
232
+ }
233
+ }
234
+
235
+ export function addEvent(node, name, handler, delegate) {
236
+ if (delegate) {
237
+ if (Array.isArray(handler)) {
238
+ node[`$$${name}`] = handler[0];
239
+ node[`$$${name}Data`] = handler[1];
240
+ } else node[`$$${name}`] = handler;
241
+ } else if (Array.isArray(handler)) {
242
+ const handlerFn = handler[0];
243
+ node.addEventListener(name, (handler[0] = e => handlerFn.call(node, handler[1], e)));
244
+ } else node.addEventListener(name, handler, typeof handler !== "function" && handler);
245
+ }
246
+
247
+ export function style(node, value, prev) {
248
+ if (!value) {
249
+ if (prev) setAttribute(node, "style");
250
+ return;
251
+ }
252
+ const nodeStyle = node.style;
253
+ if (typeof value === "string") return (nodeStyle.cssText = value);
254
+ typeof prev === "string" && (nodeStyle.cssText = prev = undefined);
255
+ prev || (prev = {});
256
+ let v, s;
257
+ for (s in value) {
258
+ v = value[s];
259
+ if (v !== prev[s]) nodeStyle.setProperty(s, v);
260
+ delete prev[s];
261
+ }
262
+ for (s in prev) value[s] == null && nodeStyle.removeProperty(s);
263
+ }
264
+
265
+ export function setStyleProperty(node, name, value) {
266
+ value != null ? node.style.setProperty(name, value) : node.style.removeProperty(name);
267
+ }
268
+
269
+ // TODO: make this better
270
+ export function spread(node, props = {}, skipChildren) {
271
+ const prevProps = {};
272
+ if (!skipChildren) insert(node, () => props.children);
273
+ effect(
274
+ () => {
275
+ const r = props.ref;
276
+ (typeof r === "function" || Array.isArray(r)) && ref(() => r, node);
277
+ },
278
+ () => {}
279
+ );
280
+ effect(
281
+ () => {
282
+ const newProps = {};
283
+ for (const prop in props) {
284
+ if (prop === "children" || prop === "ref") continue;
285
+ newProps[prop] = props[prop];
286
+ }
287
+ return newProps;
288
+ },
289
+ props => assign(node, props, true, prevProps, true)
290
+ );
291
+ return prevProps;
292
+ }
293
+
294
+ export function dynamicProperty(props, key) {
295
+ const src = props[key];
296
+ Object.defineProperty(props, key, {
297
+ get() {
298
+ return src();
299
+ },
300
+ enumerable: true
301
+ });
302
+ return props;
303
+ }
304
+
305
+ export function applyRef(r, element) {
306
+ Array.isArray(r) ? r.flat(Infinity).forEach(f => f && f(element)) : r(element);
307
+ }
308
+
309
+ export function ref(fn, element) {
310
+ const resolved = untrack(fn);
311
+ runWithOwner(null, () => applyRef(resolved, element));
312
+ }
313
+
314
+ export function insert(parent, accessor, marker, initial, options) {
315
+ const multi = marker !== undefined;
316
+ const host = options && options.host;
317
+ if (multi && !initial) initial = [];
318
+ if (isHydrating(parent)) {
319
+ if (!multi && initial === undefined && parent) initial = [...parent.childNodes];
320
+ if (Array.isArray(initial)) {
321
+ let j = 0;
322
+ for (let i = 0; i < initial.length; i++) {
323
+ if (initial[i].nodeType === 8 && initial[i].nodeValue === "!$") initial[i].remove();
324
+ else initial[j++] = initial[i];
325
+ }
326
+ initial.length = j;
327
+ }
328
+ }
329
+ if (typeof accessor !== "function") {
330
+ accessor = normalize(accessor, initial, multi, true);
331
+ if (typeof accessor !== "function") {
332
+ insertExpression(parent, accessor, initial, marker);
333
+ host && tagHost(accessor, host);
334
+ return;
335
+ }
336
+ }
337
+ if (multi && initial.length === 0) {
338
+ const placeholder = document.createTextNode("");
339
+ parent.insertBefore(placeholder, marker);
340
+ initial = [placeholder];
341
+ }
342
+ let current = initial;
343
+ effect(
344
+ prev => {
345
+ const value = normalize(accessor(), current, multi, true);
346
+ if (typeof value !== "function") return value;
347
+ effect(
348
+ () => normalize(value, current, multi),
349
+ inner => {
350
+ insertExpression(parent, inner, current, marker);
351
+ current = inner;
352
+ host && tagHost(current, host);
353
+ },
354
+ prev !== undefined && !(options && options.schedule)
355
+ ? { ...options, schedule: true }
356
+ : options
357
+ );
358
+ return INNER_OWNED;
359
+ },
360
+ value => {
361
+ if (value === INNER_OWNED) return;
362
+ insertExpression(parent, value, current, marker);
363
+ current = value;
364
+ host && tagHost(current, host);
365
+ },
366
+ options
367
+ );
368
+ }
369
+
370
+ export function assign(node, props, skipChildren, prevProps = {}, skipRef = false) {
371
+ const nodeName = node.nodeName;
372
+ props || (props = {});
373
+ for (const prop in prevProps) {
374
+ if (!(prop in props)) {
375
+ if (prop === "children") continue;
376
+ prevProps[prop] = assignProp(node, prop, null, prevProps[prop], skipRef, nodeName);
377
+ }
378
+ }
379
+ for (const prop in props) {
380
+ if (prop === "children") {
381
+ if (!skipChildren) insertExpression(node, normalize(props.children, undefined, false));
382
+ continue;
383
+ }
384
+ prevProps[prop] = assignProp(node, prop, props[prop], prevProps[prop], skipRef, nodeName);
385
+ }
386
+ }
387
+
388
+ // Module asset loading for hydration
389
+ function loadModuleAssets(mapping) {
390
+ const hy = globalThis._$HY;
391
+ if (!hy) return;
392
+ const pending = [];
393
+ for (const moduleUrl in mapping) {
394
+ if (hy.modules[moduleUrl]) continue;
395
+ const entryUrl = mapping[moduleUrl];
396
+ if (!hy.loading[moduleUrl]) {
397
+ hy.loading[moduleUrl] = import(/* @vite-ignore */ entryUrl).then(mod => {
398
+ hy.modules[moduleUrl] = mod;
399
+ });
400
+ }
401
+ pending.push(hy.loading[moduleUrl]);
402
+ }
403
+ return pending.length ? Promise.all(pending).then(() => {}) : undefined;
404
+ }
405
+
406
+ // Hydrate
407
+ export function hydrate(code, element, options = {}) {
408
+ if (globalThis._$HY.done) return render(code, element, [...element.childNodes], options);
409
+ options.renderId ||= "";
410
+ if (!globalThis._$HY.modules) globalThis._$HY.modules = {};
411
+ if (!globalThis._$HY.loading) globalThis._$HY.loading = {};
412
+ sharedConfig.completed = globalThis._$HY.completed;
413
+ sharedConfig.events = globalThis._$HY.events;
414
+ sharedConfig.load = id => globalThis._$HY.r[id];
415
+ sharedConfig.has = id => id in globalThis._$HY.r;
416
+ sharedConfig.gather = root => gatherHydratable(element, root);
417
+ sharedConfig.loadModuleAssets = loadModuleAssets;
418
+ sharedConfig.cleanupFragment = id => {
419
+ const tpl = document.getElementById("pl-" + id);
420
+ if (tpl) {
421
+ let node = tpl.nextSibling;
422
+ while (node) {
423
+ const next = node.nextSibling;
424
+ if (node.nodeType === 8 && node.nodeValue === "pl-" + id) {
425
+ node.remove();
426
+ break;
427
+ }
428
+ node.remove();
429
+ node = next;
430
+ }
431
+ tpl.remove();
432
+ }
433
+ };
434
+ sharedConfig.registry = new Map();
435
+ sharedConfig.hydrating = true;
436
+ if ("_DX_DEV_") {
437
+ sharedConfig.verifyHydration = () => {
438
+ if (sharedConfig.registry && sharedConfig.registry.size) {
439
+ const orphaned = [...sharedConfig.registry.values()].filter(node => node.isConnected);
440
+ sharedConfig.registry.clear();
441
+ if (!orphaned.length) return;
442
+ console.warn(
443
+ `Hydration completed with ${orphaned.length} unclaimed server-rendered node(s):\n` +
444
+ orphaned.map(node => ` ${node.outerHTML.slice(0, 100)}`).join("\n")
445
+ );
446
+ }
447
+ };
448
+ }
449
+ const rootMapping = globalThis._$HY.r && globalThis._$HY.r["_assets"];
450
+ if (rootMapping && typeof rootMapping === "object") {
451
+ const p = loadModuleAssets(rootMapping);
452
+ if (p) {
453
+ gatherHydratable(element, options.renderId);
454
+ let disposer;
455
+ p.then(
456
+ () => {
457
+ try {
458
+ disposer = render(code, element, [...element.childNodes], options);
459
+ } finally {
460
+ sharedConfig.hydrating = false;
461
+ }
462
+ },
463
+ () => {
464
+ sharedConfig.hydrating = false;
465
+ }
466
+ );
467
+ return () => disposer && disposer();
468
+ }
469
+ }
470
+ try {
471
+ gatherHydratable(element, options.renderId);
472
+ return render(code, element, [...element.childNodes], options);
473
+ } finally {
474
+ sharedConfig.hydrating = false;
475
+ }
476
+ }
477
+
478
+ export function getNextElement(template) {
479
+ let node,
480
+ key,
481
+ hydrating = isHydrating();
482
+ if (!hydrating || !(node = sharedConfig.registry.get((key = getHydrationKey())))) {
483
+ if (!template) {
484
+ throw new Error(`Hydration Mismatch. Unable to find DOM nodes for hydration key: ${key}`);
485
+ }
486
+ return template(true);
487
+ }
488
+ if ("_DX_DEV_" && template && template._html) {
489
+ const expected = template._html.match(/^<(\w+)/)?.[1];
490
+ if (expected && node.localName !== expected) {
491
+ console.warn(
492
+ `Hydration tag mismatch for key "${key}": expected <${expected}> but found`,
493
+ node
494
+ );
495
+ }
496
+ }
497
+ if (sharedConfig.completed) sharedConfig.completed.add(node);
498
+ sharedConfig.registry.delete(key);
499
+ return node;
500
+ }
501
+
502
+ export function getNextMatch(el, nodeName) {
503
+ while (el && el.localName !== nodeName) el = el.nextSibling;
504
+ return el;
505
+ }
506
+
507
+ export function getNextMarker(start) {
508
+ let end = start,
509
+ count = 0,
510
+ current = [];
511
+ if (isHydrating(start)) {
512
+ while (end) {
513
+ if (end.nodeType === 8) {
514
+ const v = end.nodeValue;
515
+ if (v === "$") count++;
516
+ else if (v === "/") {
517
+ if (count === 0) return [end, current];
518
+ count--;
519
+ }
520
+ }
521
+ current.push(end);
522
+ end = end.nextSibling;
523
+ }
524
+ }
525
+ return [end, current];
526
+ }
527
+
528
+ export function getFirstChild(node, expectedTag) {
529
+ const child = node.firstChild;
530
+ if ("_DX_DEV_" && isHydrating() && expectedTag && child?.localName !== expectedTag) {
531
+ const isMissing = !child || child.nodeType !== 1;
532
+ console.warn(
533
+ "Hydration structure mismatch: expected <" + expectedTag + "> as first child of",
534
+ node,
535
+ "\n " + describeSiblings(node, child, expectedTag, isMissing)
536
+ );
537
+ }
538
+ return child;
539
+ }
540
+
541
+ export function getNextSibling(node, expectedTag) {
542
+ const sibling = node.nextSibling;
543
+ if ("_DX_DEV_" && isHydrating() && expectedTag && sibling?.localName !== expectedTag) {
544
+ const parent = node.parentNode;
545
+ const isMissing = !sibling || sibling.nodeType !== 1;
546
+ console.warn(
547
+ "Hydration structure mismatch: expected <" + expectedTag + "> after",
548
+ node,
549
+ "in",
550
+ parent,
551
+ "\n " + describeSiblings(parent, sibling, expectedTag, isMissing)
552
+ );
553
+ }
554
+ return sibling;
555
+ }
556
+
557
+ function describeSiblings(parent, mismatchChild, expectedTag, isMissing) {
558
+ if (!parent) return `<${expectedTag} \u2190 parent unavailable>`;
559
+ const children = [];
560
+ let child = parent.firstChild;
561
+ while (child) {
562
+ if (child.nodeType === 1) children.push(child);
563
+ child = child.nextSibling;
564
+ }
565
+ const pTag = parent.localName || "#fragment";
566
+ if (isMissing) {
567
+ const tags = children.map(c => `<${c.localName}>`).join("");
568
+ return `<${pTag}>${tags}<${expectedTag} \u2190 missing></${pTag}>`;
569
+ }
570
+ const idx = children.indexOf(mismatchChild);
571
+ let start = 0,
572
+ end = children.length;
573
+ let prefix = "",
574
+ suffix = "";
575
+ if (children.length > 6) {
576
+ start = Math.max(0, idx - 2);
577
+ end = Math.min(children.length, idx + 3);
578
+ if (start > 0) prefix = "...";
579
+ if (end < children.length) suffix = "...";
580
+ }
581
+ const tags = children
582
+ .slice(start, end)
583
+ .map(c =>
584
+ c === mismatchChild ? `<${c.localName} \u2190 expected ${expectedTag}>` : `<${c.localName}>`
585
+ )
586
+ .join("");
587
+ return `<${pTag}>${prefix}${tags}${suffix}</${pTag}>`;
588
+ }
589
+
590
+ export function runHydrationEvents() {
591
+ if (sharedConfig.events && !sharedConfig.events.queued) {
592
+ queueMicrotask(() => {
593
+ const { completed, events } = sharedConfig;
594
+ if (!events) return;
595
+ events.queued = false;
596
+ while (events.length) {
597
+ const [el, e] = events[0];
598
+ if (!completed.has(el)) return;
599
+ events.shift();
600
+ let match;
601
+ for (const [container, state] of delegatedContainers) {
602
+ if (!state.handlers.has(e.type)) continue;
603
+ const entry = findOwner(e.target, state);
604
+ if (entry && (!match || entry.distance < match.distance))
605
+ match = { container, state, distance: entry.distance };
606
+ }
607
+ if (match) eventHandler(e, match.container, match.state);
608
+ }
609
+ if (sharedConfig.done) {
610
+ sharedConfig.events = _$HY.events = null;
611
+ sharedConfig.completed = _$HY.completed = null;
612
+ }
613
+ });
614
+ sharedConfig.events.queued = true;
615
+ }
616
+ }
617
+
618
+ // Internal Functions
619
+ function isHydrating(node) {
620
+ return sharedConfig.hydrating && (!node || node.isConnected);
621
+ }
622
+
623
+ function classListToObject(classList) {
624
+ if (Array.isArray(classList)) {
625
+ const result = {};
626
+ flattenClassList(classList, result);
627
+ classList = result;
628
+ }
629
+ if (classList && typeof classList === "object") {
630
+ const result = {},
631
+ keys = Object.keys(classList);
632
+ for (let i = 0, len = keys.length; i < len; i++) {
633
+ const key = keys[i];
634
+ if (!classList[key]) continue;
635
+ const classNames = key.trim().split(/\s+/);
636
+ for (let j = 0, nameLen = classNames.length; j < nameLen; j++)
637
+ classNames[j] && (result[classNames[j]] = true);
638
+ }
639
+ return result;
640
+ }
641
+ return classList;
642
+ }
643
+
644
+ function flattenClassList(list, result) {
645
+ for (let i = 0, len = list.length; i < len; i++) {
646
+ const item = list[i];
647
+ if (Array.isArray(item)) flattenClassList(item, result);
648
+ else if (typeof item === "object" && item != null) Object.assign(result, item);
649
+ else if (item || item === 0) result[item] = true;
650
+ }
651
+ }
652
+
653
+ function assignProp(node, prop, value, prev, skipRef, nodeName) {
654
+ if (prop === "style") return (style(node, value, prev), value);
655
+ if (prop === "class") return (className(node, value, prev), value);
656
+ // dom with state may differs from reactive state
657
+ // dom value derives from reactive state
658
+ if (value === prev && DOMWithState[nodeName]?.[prop] !== 1) return prev;
659
+ if (prop === "ref") {
660
+ if (!skipRef && value) ref(() => value, node);
661
+ return value;
662
+ }
663
+
664
+ const hasNamespace = prop.indexOf(":") > -1;
665
+
666
+ if (!hasNamespace && prop.slice(0, 2) === "on") {
667
+ const name = prop.slice(2).toLowerCase();
668
+ const delegate = DelegatedEvents.has(name);
669
+ if (!delegate && prev) {
670
+ const h = Array.isArray(prev) ? prev[0] : prev;
671
+ node.removeEventListener(name, h);
672
+ }
673
+ if (delegate || value) {
674
+ addEvent(node, name, value, delegate);
675
+ delegate && delegateEvents([name]);
676
+ }
677
+ } else if (
678
+ (hasNamespace && prop.slice(0, 5) === "prop:") ||
679
+ ChildProperties.has(prop) ||
680
+ DOMWithState[nodeName]?.[prop]
681
+ ) {
682
+ if (hasNamespace) prop = prop.slice(5);
683
+ else if (isHydrating(node)) return value; // TODO IS this correct?
684
+ if (prop === "value" && nodeName === "SELECT")
685
+ queueMicrotask(() => (node.value = value)) || (node.value = value);
686
+ else node[prop] = value;
687
+ } else {
688
+ const ns = hasNamespace && Namespaces[prop.split(":")[0]];
689
+ if (ns) setAttributeNS(node, ns, prop, value);
690
+ else setAttribute(node, prop, value);
691
+ }
692
+ return value;
693
+ }
694
+
695
+ function eventHandler(e, container, state) {
696
+ if (sharedConfig.registry && sharedConfig.events) {
697
+ if (sharedConfig.events.find(([el, ev]) => ev === e)) return;
698
+ }
699
+ if (e[$$EVENT_OWNER]) return;
700
+ const owner =
701
+ state &&
702
+ (state.owners.size === 1 && state.owners.has(container)
703
+ ? container
704
+ : findOwner(e.target, state)?.owner);
705
+ if (state && !owner) return;
706
+ e[$$EVENT_OWNER] = owner || true;
707
+
708
+ let node = e.target;
709
+ const key = `$$${e.type}`;
710
+ const oriTarget = e.target;
711
+ const boundary = owner || container || e.currentTarget;
712
+ const retarget = value =>
713
+ Object.defineProperty(e, "target", {
714
+ configurable: true,
715
+ value
716
+ });
717
+ const handleNode = () => {
718
+ const handler = node[key];
719
+ if (handler && !node.disabled) {
720
+ const data = node[`${key}Data`];
721
+ data !== undefined ? handler.call(node, data, e) : handler.call(node, e);
722
+ if (e.cancelBubble) return;
723
+ }
724
+ node.host &&
725
+ typeof node.host !== "string" &&
726
+ !node.host._$host &&
727
+ node.contains(e.target) &&
728
+ retarget(node.host);
729
+ return true;
730
+ };
731
+ const walkUpTree = () => {
732
+ while (handleNode()) {
733
+ if (node === boundary || node.parentNode === boundary) break;
734
+ node = node._$host || node.parentNode || node.host;
735
+ }
736
+ };
737
+
738
+ // simulate currentTarget
739
+ Object.defineProperty(e, "currentTarget", {
740
+ configurable: true,
741
+ get() {
742
+ return node || boundary || document;
743
+ }
744
+ });
745
+ if (e.composedPath) {
746
+ const path = e.composedPath();
747
+ if (path.length) {
748
+ retarget(path[0]);
749
+ for (let i = 0; i < path.length; i++) {
750
+ node = path[i];
751
+ if (!handleNode()) break;
752
+ if (node._$host) {
753
+ node = node._$host;
754
+ // bubble up from portal mount instead of composedPath
755
+ walkUpTree();
756
+ break;
757
+ }
758
+ if (node === boundary || node.parentNode === boundary) {
759
+ break; // don't bubble above root of event delegation
760
+ }
761
+ }
762
+ } else walkUpTree();
763
+ }
764
+ // fallback for browsers that don't support composedPath
765
+ else walkUpTree();
766
+ // Mixing portals and shadow dom can lead to a nonstandard target, so reset here.
767
+ retarget(oriTarget);
768
+ }
769
+
770
+ function insertExpression(parent, value, current, marker) {
771
+ if (isHydrating(parent)) return;
772
+ if (value === current) return;
773
+ const t = typeof value,
774
+ multi = marker !== undefined;
775
+
776
+ if (t === "string" || t === "number") {
777
+ const tc = typeof current;
778
+ if (tc === "string" || tc === "number") {
779
+ parent.firstChild.data = value;
780
+ } else parent.textContent = value;
781
+ } else if (value === undefined) {
782
+ cleanChildren(parent, current, marker);
783
+ } else if (value.nodeType) {
784
+ if (Array.isArray(current)) {
785
+ cleanChildren(parent, current, multi ? marker : null, value);
786
+ } else if (current && current.nodeType) {
787
+ // `current` is a node we previously inserted but it may have been
788
+ // moved out by user code (e.g. ref-driven migration, JSX wrapping)
789
+ // since the last render. If it's still here, replace it in place;
790
+ // otherwise append — never `replaceChild` a node that isn't ours.
791
+ current.parentNode === parent
792
+ ? parent.replaceChild(value, current)
793
+ : parent.appendChild(value);
794
+ } else if (current && parent.firstChild) {
795
+ parent.replaceChild(value, parent.firstChild);
796
+ } else {
797
+ parent.appendChild(value);
798
+ }
799
+ if (marker) value[$$SLOT] = marker;
800
+ } else if (Array.isArray(value)) {
801
+ const currentArray = current && Array.isArray(current);
802
+ if (value.length === 0) {
803
+ cleanChildren(parent, current, marker);
804
+ } else if (currentArray) {
805
+ if (current.length === 0) {
806
+ appendNodes(parent, value, marker);
807
+ } else reconcileArrays(parent, current, value, marker);
808
+ } else {
809
+ current && cleanChildren(parent);
810
+ appendNodes(parent, value);
811
+ }
812
+ } else if ("_DX_DEV_") console.warn(`Unrecognized value. Skipped inserting`, value);
813
+ }
814
+
815
+ function normalize(value, current, multi, doNotUnwrap) {
816
+ value = flatten(value, { skipNonRendered: true, doNotUnwrap });
817
+ if (doNotUnwrap && typeof value === "function") return value;
818
+ if (multi && !Array.isArray(value)) value = [value != null ? value : ""];
819
+ if (Array.isArray(value)) {
820
+ for (let i = 0, len = value.length; i < len; i++) {
821
+ const item = value[i],
822
+ prev = current && current[i],
823
+ t = typeof item;
824
+ if (t === "string" || t === "number")
825
+ value[i] =
826
+ prev && prev.nodeType === 3 && (sharedConfig.hydrating || prev.data === "" + item)
827
+ ? prev
828
+ : document.createTextNode(item);
829
+ }
830
+ }
831
+ return value;
832
+ }
833
+
834
+ // Applied after each `insert` update when the `host` option is present (e.g.
835
+ // portals): the slot's top-level nodes get a live `_$host` getter so event
836
+ // retargeting can route back to the slot's logical position in the source
837
+ // tree. Tagging here — rather than intercepting individual DOM calls — covers
838
+ // every insertion path (append, replaceChild, reconcile, hydration claim)
839
+ // without touching the hot reconcile loops. `$$HOST` short-circuits nodes
840
+ // already tagged for this host on subsequent updates.
841
+ function tagHost(value, host) {
842
+ if (Array.isArray(value)) {
843
+ for (let i = 0, len = value.length; i < len; i++) tagHost(value[i], host);
844
+ } else if (value && value.nodeType && value[$$HOST] !== host) {
845
+ value[$$HOST] = host;
846
+ Object.defineProperty(value, "_$host", { get: host, configurable: true });
847
+ }
848
+ }
849
+
850
+ function appendNodes(parent, array, marker = null) {
851
+ for (let i = 0, len = array.length; i < len; i++) {
852
+ const n = array[i];
853
+ parent.insertBefore(n, marker);
854
+ if (marker) n[$$SLOT] = marker;
855
+ }
856
+ }
857
+
858
+ function cleanChildren(parent, current, marker, replacement) {
859
+ if (marker === undefined) return (parent.textContent = "");
860
+ if (current.length) {
861
+ let inserted = false;
862
+ for (let i = current.length - 1; i >= 0; i--) {
863
+ const el = current[i];
864
+ if (replacement !== el) {
865
+ const tag = el[$$SLOT];
866
+ const owns = el.parentNode === parent && (!tag || tag === marker);
867
+ if (replacement && !inserted && !i)
868
+ owns ? parent.replaceChild(replacement, el) : parent.insertBefore(replacement, marker);
869
+ else if (owns) el.remove();
870
+ } else inserted = true;
871
+ }
872
+ } else if (replacement) parent.insertBefore(replacement, marker);
873
+ if (replacement && marker) replacement[$$SLOT] = marker;
874
+ }
875
+
876
+ function gatherHydratable(element, root) {
877
+ const templates = element.querySelectorAll(`*[_hk]`);
878
+ for (let i = 0; i < templates.length; i++) {
879
+ const node = templates[i];
880
+ const key = node.getAttribute("_hk");
881
+ if ((!root || key.startsWith(root)) && !sharedConfig.registry.has(key))
882
+ sharedConfig.registry.set(key, node);
883
+ }
884
+ }
885
+
886
+ export function getHydrationKey() {
887
+ return sharedConfig.getNextContextId();
888
+ }
889
+
890
+ const voidFn = () => undefined;
891
+
892
+ // experimental
893
+ export const RequestContext = Symbol();