@torpor/view 0.3.0 → 0.3.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/dist/index.cjs ADDED
@@ -0,0 +1,906 @@
1
+ const require_formatText = require('./formatText-DufG5l83.cjs');
2
+
3
+ //#region src/render/$mount.ts
4
+ /**
5
+ * Runs and re-runs a function on component mount
6
+ *
7
+ * @param fn The function to run, which may return a cleanup function
8
+ */
9
+ function $mount(fn) {
10
+ require_formatText.context_default.mountEffects.push(fn);
11
+ }
12
+
13
+ //#endregion
14
+ //#region src/render/$run.ts
15
+ /**
16
+ * Runs and re-runs a function that depends on a watched object
17
+ *
18
+ * @param fn The function to run, which may return a cleanup function.
19
+ */
20
+ function $run(fn, name) {
21
+ let effect = {
22
+ type: require_formatText.EFFECT_TYPE,
23
+ run: fn,
24
+ cleanup: void 0,
25
+ firstSource: null,
26
+ nextEffect: null,
27
+ extent: 0,
28
+ nextEffectToRun: null,
29
+ didError: false,
30
+ name
31
+ };
32
+ require_formatText.runEffect(effect);
33
+ return effect;
34
+ }
35
+
36
+ //#endregion
37
+ //#region src/watch/symbols.ts
38
+ const proxyDataSymbol = Symbol("_proxy_data");
39
+ const proxyHandledSymbol = Symbol("_proxy_handled");
40
+
41
+ //#endregion
42
+ //#region src/render/$unwrap.ts
43
+ /**
44
+ * Returns the target object of a proxy
45
+ *
46
+ * @param object The proxy object
47
+ */
48
+ function $unwrap(object) {
49
+ return object !== void 0 && object !== null && object[proxyDataSymbol] !== void 0 ? object[proxyDataSymbol].target ?? object : object;
50
+ }
51
+
52
+ //#endregion
53
+ //#region src/watch/trackProxyEffect.ts
54
+ function trackProxyEffect(data, key) {
55
+ let signal = data.signals.get(key);
56
+ if (signal === void 0) {
57
+ signal = {
58
+ type: require_formatText.SIGNAL_TYPE,
59
+ firstTarget: null,
60
+ nextSignalToUpdate: null
61
+ };
62
+ data.signals.set(key, signal);
63
+ }
64
+ require_formatText.trackEffect(signal);
65
+ }
66
+
67
+ //#endregion
68
+ //#region src/watch/updateSignal.ts
69
+ let lastEffect;
70
+ /**
71
+ * When a signal is changed, we need to
72
+ * - Set the signal's subscriptions to recalc
73
+ * - Set any dependent computed values to recalc
74
+ * - Gather dependent effects that will need to be re-run
75
+ */
76
+ function updateSignal(proxy, key) {
77
+ let signal = proxy.signals.get(key);
78
+ if (signal !== void 0 && signal.firstTarget !== null) {
79
+ require_formatText.batchStart();
80
+ try {
81
+ if (require_formatText.context_default.firstSignalToUpdate === null) require_formatText.context_default.firstSignalToUpdate = signal;
82
+ else if (signal.nextSignalToUpdate === null) {
83
+ let lastSignal = require_formatText.context_default.firstSignalToUpdate;
84
+ while (lastSignal.nextSignalToUpdate !== null) lastSignal = lastSignal.nextSignalToUpdate;
85
+ lastSignal.nextSignalToUpdate = signal;
86
+ }
87
+ lastEffect = require_formatText.context_default.firstEffectToRun;
88
+ if (lastEffect !== null) while (lastEffect.nextEffectToRun !== null) lastEffect = lastEffect.nextEffectToRun;
89
+ let targetSub = signal.firstTarget;
90
+ let computed;
91
+ outer: while (true) {
92
+ targetSub.active = false;
93
+ targetSub.recalc = true;
94
+ const target = targetSub.target;
95
+ if (target.type === require_formatText.EFFECT_TYPE) {
96
+ if (lastEffect === null) {
97
+ require_formatText.context_default.firstEffectToRun = target;
98
+ lastEffect = target;
99
+ } else if (target.nextEffectToRun === null && lastEffect !== target) {
100
+ lastEffect.nextEffectToRun = target;
101
+ lastEffect = target;
102
+ }
103
+ } else if (!target.recalc) {
104
+ target.recalc = true;
105
+ if (target.firstTarget !== null) {
106
+ computed = target;
107
+ computed.rollback = targetSub;
108
+ targetSub = target.firstTarget;
109
+ continue;
110
+ }
111
+ }
112
+ while (targetSub.nextTarget === null && computed !== void 0) {
113
+ targetSub = computed.rollback;
114
+ if (targetSub.source.type !== require_formatText.COMPUTED_TYPE) {
115
+ computed = void 0;
116
+ continue outer;
117
+ }
118
+ computed = targetSub.source;
119
+ }
120
+ if (targetSub.nextTarget === null) break;
121
+ targetSub = targetSub.nextTarget;
122
+ }
123
+ } finally {
124
+ require_formatText.batchEnd();
125
+ }
126
+ }
127
+ }
128
+
129
+ //#endregion
130
+ //#region src/watch/proxyGet.ts
131
+ function proxyGet(target, key, receiver) {
132
+ let data = target[proxyDataSymbol];
133
+ if (key === proxyDataSymbol) return data;
134
+ let signal = data.signals.get(key);
135
+ if (signal === void 0) {
136
+ const propDescriptor = Object.getOwnPropertyDescriptor(target, key);
137
+ if (propDescriptor !== void 0) {
138
+ if (propDescriptor.writable) {
139
+ if (data.shallow !== true) {
140
+ const value = target[key];
141
+ if (value !== void 0 && value !== null && typeof value === "object" && value[proxyDataSymbol] === void 0 && value.then === void 0) target[key] = $watch(value);
142
+ }
143
+ trackProxyEffect(data, key);
144
+ } else if (propDescriptor.get) {
145
+ const oldRegisterComputed = require_formatText.context_default.registerComputed;
146
+ try {
147
+ require_formatText.context_default.registerComputed = (computed) => {
148
+ data.signals.set(key, computed);
149
+ };
150
+ return Reflect.get(target, key, receiver);
151
+ } finally {
152
+ require_formatText.context_default.registerComputed = oldRegisterComputed;
153
+ }
154
+ }
155
+ } else if (data.isArray) {
156
+ if (arrayWrapper[key] !== void 0) return arrayWrapper[key](data, target, key);
157
+ }
158
+ } else if (signal.type === require_formatText.SIGNAL_TYPE) trackProxyEffect(data, key);
159
+ else if (signal.type === require_formatText.COMPUTED_TYPE) {
160
+ if (signal.running) throw new Error("Cycle detected");
161
+ else if (signal.recalc) require_formatText.checkComputed(signal);
162
+ else if (signal.didError) throw signal.value;
163
+ else require_formatText.trackEffect(signal);
164
+ return signal.value;
165
+ }
166
+ return Reflect.get(target, key, receiver);
167
+ }
168
+ const arrayWrapper = {
169
+ [Symbol.iterator]: function(data, target, key) {
170
+ trackProxyEffect(data, "length");
171
+ require_formatText.context_default.activeTarget = null;
172
+ return target[key];
173
+ },
174
+ pop: arrayHandle,
175
+ push: arrayHandle,
176
+ reverse: arrayHandle,
177
+ shift: arrayHandle,
178
+ sort: arrayHandle,
179
+ splice: arrayHandle,
180
+ unshift: arrayHandle
181
+ };
182
+ function arrayHandle(data, target, key) {
183
+ return function(...args) {
184
+ const result = target[key].apply(target, args);
185
+ updateSignal(data, "length");
186
+ return result;
187
+ };
188
+ }
189
+
190
+ //#endregion
191
+ //#region src/watch/proxySet.ts
192
+ function proxySet(target, key, value, receiver) {
193
+ const oldValue = target[key];
194
+ if (value !== oldValue) {
195
+ if (require_formatText.context_default.batchOperation > 100) throw new Error("Cycle detected");
196
+ let data = target[proxyDataSymbol];
197
+ if (oldValue && oldValue[proxyDataSymbol] !== void 0) value = $watch(value, { shallow: oldValue[proxyDataSymbol].shallow });
198
+ Reflect.set(target, key, value, receiver);
199
+ updateSignal(data, key);
200
+ if (data.isArray && !isNaN(+String(key))) updateSignal(data, "length");
201
+ }
202
+ return true;
203
+ }
204
+
205
+ //#endregion
206
+ //#region src/render/$watch.ts
207
+ /**
208
+ * Watches an object and runs effects when its properties are changed
209
+ *
210
+ * @param object The object to watch
211
+ */
212
+ function $watch(object, options) {
213
+ if (object === void 0 || object === null || object[proxyDataSymbol] !== void 0) return object;
214
+ object[proxyDataSymbol] = {
215
+ target: object,
216
+ isArray: Array.isArray(object),
217
+ shallow: options?.shallow === true,
218
+ signals: /* @__PURE__ */ new Map()
219
+ };
220
+ const handler = {
221
+ get: proxyGet,
222
+ set: proxySet
223
+ };
224
+ return new Proxy(object, handler);
225
+ }
226
+
227
+ //#endregion
228
+ //#region src/render/addAnimation.ts
229
+ function addAnimation(el, entry, exit) {
230
+ require_formatText.context_default.stashedAnimations.push({
231
+ range: require_formatText.context_default.activeRange,
232
+ el,
233
+ in: entry,
234
+ out: exit
235
+ });
236
+ }
237
+
238
+ //#endregion
239
+ //#region src/render/addEvent.ts
240
+ function addEvent(el, type, listener) {
241
+ require_formatText.context_default.stashedEvents.push({
242
+ range: require_formatText.context_default.activeRange,
243
+ el,
244
+ type,
245
+ listener
246
+ });
247
+ }
248
+
249
+ //#endregion
250
+ //#region src/motion/animate.ts
251
+ /**
252
+ * Adds an animation for an element
253
+ * @param el The element to animate
254
+ * @param enter Whether the animation is being run on enter
255
+ * @param keyframes The Web Animation API keyframes
256
+ * @param options The Web Animmation API options
257
+ */
258
+ async function animate(el, enter, keyframes, options) {
259
+ let animationOptions = Object.assign({
260
+ direction: enter ? "normal" : "reverse",
261
+ duration: 300,
262
+ easing: "ease-in-out",
263
+ fill: "forwards"
264
+ }, options);
265
+ const animation = el.animate(keyframes, animationOptions);
266
+ setTimeout(() => {
267
+ animation.timeline = el.ownerDocument.timeline;
268
+ }, 1);
269
+ let activeRange = require_formatText.context_default.activeRange;
270
+ if (activeRange) {
271
+ activeRange.animations ??= /* @__PURE__ */ new Set();
272
+ activeRange.animations.add(animation);
273
+ await animation.finished;
274
+ activeRange.animations.delete(animation);
275
+ }
276
+ }
277
+
278
+ //#endregion
279
+ //#region src/render/isFragmentNode.ts
280
+ function isFragmentNode(node) {
281
+ return node.nodeType === 11;
282
+ }
283
+
284
+ //#endregion
285
+ //#region src/render/addFragment.ts
286
+ function addFragment(fragment, parent, before, endNode) {
287
+ const range = require_formatText.context_default.activeRange;
288
+ const hydrationNode = require_formatText.context_default.hydrationNode;
289
+ if (hydrationNode !== null) range.endNode = endNode ?? hydrationNode;
290
+ else {
291
+ range.startNode = fragment.firstChild;
292
+ range.endNode = fragment.lastChild;
293
+ }
294
+ parent = before?.parentNode ?? parent;
295
+ if (hydrationNode === null) parent.insertBefore(fragment, before);
296
+ if (!isFragmentNode(parent)) {
297
+ if (hydrationNode === null) {
298
+ for (let effect of require_formatText.context_default.mountEffects) $run(effect);
299
+ require_formatText.context_default.mountEffects.length = 0;
300
+ }
301
+ for (let event of require_formatText.context_default.stashedEvents) {
302
+ require_formatText.context_default.activeRange = event.range;
303
+ $run(function addFragmentEvent() {
304
+ event.el.addEventListener(event.type, event.listener);
305
+ return () => {
306
+ event.el.removeEventListener(event.type, event.listener);
307
+ };
308
+ });
309
+ }
310
+ require_formatText.context_default.stashedEvents.length = 0;
311
+ for (let animation of require_formatText.context_default.stashedAnimations) {
312
+ require_formatText.context_default.activeRange = animation.range;
313
+ $run(function addFragmentAnimation() {
314
+ if (animation.in !== void 0) animate(animation.el, true, animation.in.keyframes, animation.in.options);
315
+ if (animation.out !== void 0) return () => {
316
+ animate(animation.el, false, animation.out.keyframes, animation.out.options);
317
+ };
318
+ });
319
+ }
320
+ require_formatText.context_default.stashedAnimations.length = 0;
321
+ require_formatText.context_default.activeRange = range;
322
+ }
323
+ }
324
+
325
+ //#endregion
326
+ //#region src/render/applyProps.ts
327
+ function applyProps(el, props, propNamesUsed) {
328
+ if (props !== void 0) {
329
+ for (let [name, value] of Object.entries(props)) if (!propNamesUsed.includes(name)) if (name.startsWith("on")) {
330
+ const eventName = name.substring(2);
331
+ el.addEventListener(eventName, value);
332
+ } else $run(function setAttribute$1() {
333
+ el.setAttribute(name, value);
334
+ });
335
+ }
336
+ }
337
+
338
+ //#endregion
339
+ //#region src/render/clearRange.ts
340
+ function clearRange(range) {
341
+ let animations = range.animations !== null ? Array.from(range.animations) : void 0;
342
+ let childRange = range.nextRange;
343
+ while (childRange !== null && childRange.depth > range.depth) {
344
+ if (childRange.animations !== null) {
345
+ animations ??= [];
346
+ animations.push(...childRange.animations);
347
+ }
348
+ releaseRange(childRange);
349
+ childRange.depth = -2;
350
+ childRange = childRange.nextRange;
351
+ }
352
+ range.nextRange = childRange;
353
+ if (range.previousRange !== null) range.previousRange.nextRange = range.nextRange;
354
+ if (range.nextRange !== null) range.nextRange.previousRange = range.previousRange;
355
+ if (animations !== void 0) Promise.all(animations.map((a) => a.finished)).then(() => clearNodes(range));
356
+ else clearNodes(range);
357
+ }
358
+ function clearNodes(range) {
359
+ if (range.startNode !== null && range.endNode !== null) {
360
+ let currentNode = range.endNode;
361
+ while (currentNode !== range.startNode) {
362
+ let previousNode = currentNode.previousSibling;
363
+ currentNode.remove();
364
+ currentNode = previousNode;
365
+ }
366
+ currentNode.remove();
367
+ }
368
+ releaseRange(range);
369
+ }
370
+ function releaseRange(range) {
371
+ range.startNode = null;
372
+ range.endNode = null;
373
+ range.previousRange = null;
374
+ range.nextRange = null;
375
+ range.animations = null;
376
+ }
377
+
378
+ //#endregion
379
+ //#region src/render/clearLayoutSlot.ts
380
+ function clearLayoutSlot(range) {
381
+ clearRange(range);
382
+ }
383
+
384
+ //#endregion
385
+ //#region src/render/newRange.ts
386
+ function newRange(name) {
387
+ return {
388
+ startNode: null,
389
+ endNode: null,
390
+ previousRange: null,
391
+ nextRange: null,
392
+ depth: -1,
393
+ animations: null,
394
+ name
395
+ };
396
+ }
397
+
398
+ //#endregion
399
+ //#region src/render/popRange.ts
400
+ function popRange(oldRange) {
401
+ require_formatText.context_default.activeRange = oldRange;
402
+ }
403
+
404
+ //#endregion
405
+ //#region src/render/pushRange.ts
406
+ function pushRange(range, toParent = false) {
407
+ const activeRange = require_formatText.context_default.activeRange;
408
+ if (toParent) {
409
+ const previousRange = require_formatText.context_default.previousRange;
410
+ range.previousRange = previousRange;
411
+ const nextRange = previousRange.nextRange;
412
+ previousRange.nextRange = range;
413
+ range.nextRange = nextRange;
414
+ range.depth = activeRange.depth + 1;
415
+ }
416
+ require_formatText.context_default.activeRange = range;
417
+ require_formatText.context_default.previousRange = range;
418
+ return activeRange;
419
+ }
420
+
421
+ //#endregion
422
+ //#region src/render/fillLayoutSlot.ts
423
+ function fillLayoutSlot(component, slot, parent, anchor, $props, $context) {
424
+ const range = newRange();
425
+ const oldRange = pushRange(range);
426
+ component(parent, anchor, $props, $context, { _: slot });
427
+ popRange(oldRange);
428
+ return range;
429
+ }
430
+
431
+ //#endregion
432
+ //#region src/render/getFragment.ts
433
+ function getFragment(document, array, index, html, ns) {
434
+ if (array[index] === void 0) if (ns === true) {
435
+ const template = document.createElementNS("http://www.w3.org/2000/svg", "template");
436
+ template.innerHTML = html;
437
+ const fragment = new DocumentFragment();
438
+ fragment.append(...template.childNodes);
439
+ array[index] = fragment;
440
+ } else {
441
+ const template = document.createElement("template");
442
+ template.innerHTML = html;
443
+ array[index] = template.content;
444
+ }
445
+ return array[index].cloneNode(true);
446
+ }
447
+
448
+ //#endregion
449
+ //#region src/render/hydrate.ts
450
+ /**
451
+ * Hydrates a component into an existing DOM tree
452
+ * @param parent The parent node
453
+ * @param component The component to mount
454
+ * @param props An object containing component props
455
+ */
456
+ function hydrate(parent, component, props, slots) {
457
+ require_formatText.context_default.hydrationNode = parent.firstChild;
458
+ require_formatText.context_default.rootRange = newRange();
459
+ require_formatText.context_default.previousRange = require_formatText.context_default.rootRange;
460
+ pushRange(require_formatText.context_default.rootRange);
461
+ component(parent, null, props, void 0, slots);
462
+ require_formatText.context_default.hydrationNode = null;
463
+ for (let effect of require_formatText.context_default.mountEffects) $run(effect);
464
+ require_formatText.context_default.mountEffects.length = 0;
465
+ }
466
+
467
+ //#endregion
468
+ //#region src/render/mount.ts
469
+ /**
470
+ * Mounts a component into a DOM node
471
+ *
472
+ * @param parent The node to mount the component into
473
+ * @param component The component to mount
474
+ * @param props An object containing component props
475
+ */
476
+ function mount(parent, component, props, slots) {
477
+ if (parent.childElementCount > 0) throw new Error("The parent node must have no child elements");
478
+ while (parent.firstChild !== null) parent.firstChild.remove();
479
+ require_formatText.context_default.rootRange = newRange();
480
+ require_formatText.context_default.previousRange = require_formatText.context_default.rootRange;
481
+ pushRange(require_formatText.context_default.rootRange);
482
+ component(parent, null, props, void 0, slots);
483
+ }
484
+
485
+ //#endregion
486
+ //#region src/render/newListItem.ts
487
+ function newListItem(data, key) {
488
+ return {
489
+ startNode: null,
490
+ endNode: null,
491
+ previousRange: null,
492
+ nextRange: null,
493
+ depth: -1,
494
+ animations: null,
495
+ data,
496
+ key
497
+ };
498
+ }
499
+
500
+ //#endregion
501
+ //#region src/render/hydrationMarkers.ts
502
+ const HYDRATION_START = "[";
503
+ const HYDRATION_END = "]";
504
+ const HYDRATION_BREAK = "^";
505
+
506
+ //#endregion
507
+ //#region src/render/isCommentNode.ts
508
+ function isCommentNode(node) {
509
+ return node.nodeType === 8;
510
+ }
511
+
512
+ //#endregion
513
+ //#region src/render/isTextNode.ts
514
+ function isTextNode(node) {
515
+ return node.nodeType === 3;
516
+ }
517
+
518
+ //#endregion
519
+ //#region src/render/nodeCheckHydrationBreak.ts
520
+ /**
521
+ * When hydrating, removes and skips hydration comments that are inserted at the
522
+ * start of branches and used to split up text nodes that would otherwise be
523
+ * joined in HTML.
524
+ *
525
+ * @param node The node to check and maybe skip.
526
+ * @returns The next node.
527
+ */
528
+ function nodeCheckHydrationBreak(node) {
529
+ if (require_formatText.context_default.hydrationNode !== null) {
530
+ if (node !== null && isCommentNode(node) && node.data === HYDRATION_BREAK) {
531
+ let comment = node;
532
+ node = node.nextSibling;
533
+ comment.remove();
534
+ }
535
+ require_formatText.context_default.hydrationNode = node;
536
+ }
537
+ return node;
538
+ }
539
+
540
+ //#endregion
541
+ //#region src/render/nodeNext.ts
542
+ /**
543
+ * Gets the next sibling of a node.
544
+ *
545
+ * When hydrating, sets the hydration node.
546
+ *
547
+ * @param node The node.
548
+ * @param text Whether we require a text node.
549
+ */
550
+ function nodeNext(node, text = false) {
551
+ if (require_formatText.context_default.hydrationNode !== null && text && isTextNode(node)) return node;
552
+ return nodeCheckHydrationBreak(node.nextSibling);
553
+ }
554
+
555
+ //#endregion
556
+ //#region src/render/nodeAnchor.ts
557
+ /**
558
+ * Gets the anchor node for a control statement or component.
559
+ *
560
+ * When mounting, this just returns the anchor node parameter (because it was
561
+ * created).
562
+ *
563
+ * When hydrating, there should be matched <![> and <!]> comments in the HTML,
564
+ * and the anchor node should be after the end comment. The matched comment
565
+ * nodes will be deleted, and the hydration node set to the first node inside
566
+ * the matched comments.
567
+ *
568
+ * @param node The potential anchor node.
569
+ * @returns The anchor node.
570
+ */
571
+ function nodeAnchor(node) {
572
+ if (require_formatText.context_default.hydrationNode !== null) {
573
+ if (isCommentNode(node) && node.data === HYDRATION_START) {
574
+ let currentNode = nodeNext(node);
575
+ node.remove();
576
+ let level = 1;
577
+ while (currentNode !== null) {
578
+ if (isCommentNode(currentNode)) {
579
+ if (currentNode.data === HYDRATION_START) level += 1;
580
+ else if (currentNode.data === HYDRATION_END) {
581
+ level -= 1;
582
+ if (level === 0) {
583
+ const endNode = currentNode.nextSibling;
584
+ currentNode.remove();
585
+ if (require_formatText.context_default.hydrationNode === currentNode) require_formatText.context_default.hydrationNode = endNode;
586
+ return endNode;
587
+ }
588
+ }
589
+ }
590
+ currentNode = currentNode.nextSibling;
591
+ }
592
+ if (currentNode === null) throw new Error("End hydration comment not found");
593
+ }
594
+ }
595
+ return node;
596
+ }
597
+
598
+ //#endregion
599
+ //#region src/render/nodeChild.ts
600
+ /**
601
+ * Gets the first child of a node.
602
+ *
603
+ * Sets the hydration node.
604
+ *
605
+ * @param parent The parent node.
606
+ */
607
+ function nodeChild(parent) {
608
+ let childNode = parent.firstChild;
609
+ if (require_formatText.context_default.hydrationNode !== null) {
610
+ if (childNode === null) childNode = parent.appendChild(parent.ownerDocument.createTextNode(""));
611
+ require_formatText.context_default.hydrationNode = childNode;
612
+ }
613
+ return childNode;
614
+ }
615
+
616
+ //#endregion
617
+ //#region src/render/nodeRoot.ts
618
+ /**
619
+ * Gets the first child in a fragment.
620
+ *
621
+ * When hydrating, also sets the active range's start node, while we have it.
622
+ *
623
+ * @param parent The parent of the fragment.
624
+ * @param text Whether we require a text node.
625
+ */
626
+ function nodeRoot(parent, text = false) {
627
+ if (require_formatText.context_default.hydrationNode !== null) {
628
+ let rootNode = require_formatText.context_default.hydrationNode;
629
+ if (text && !isTextNode(rootNode) && rootNode.previousSibling !== null && isTextNode(rootNode.previousSibling)) {
630
+ rootNode = rootNode.previousSibling;
631
+ require_formatText.context_default.hydrationNode = rootNode;
632
+ }
633
+ if (isCommentNode(rootNode) && rootNode.data === HYDRATION_START) {
634
+ rootNode = rootNode.nextSibling;
635
+ require_formatText.context_default.hydrationNode = rootNode;
636
+ }
637
+ const range = require_formatText.context_default.activeRange;
638
+ if (range.startNode === null) range.startNode = rootNode;
639
+ return rootNode;
640
+ } else return parent.firstChild;
641
+ }
642
+
643
+ //#endregion
644
+ //#region src/render/nodeSkip.ts
645
+ /**
646
+ * Gets the sibling of a node, x nodes after it.
647
+ *
648
+ * When hydrating, sets the hydration node.
649
+ *
650
+ * @param node The node.
651
+ * @param count The number of nodes to skip.
652
+ */
653
+ function nodeSkip(node, count) {
654
+ let nextNode = node;
655
+ for (let i = 0; i < count; i++) nextNode = nodeCheckHydrationBreak(nextNode.nextSibling);
656
+ return nextNode;
657
+ }
658
+
659
+ //#endregion
660
+ //#region src/render/runControl.ts
661
+ /**
662
+ * Runs an`if`, `switch` or `await` control statement
663
+ * @param create A function that creates the control statement's branches
664
+ */
665
+ function runControl(range, anchor, create) {
666
+ const oldRange = pushRange(range, true);
667
+ $run(function runControl$1() {
668
+ const oldBranchRange = pushRange(range);
669
+ create(anchor);
670
+ popRange(oldBranchRange);
671
+ });
672
+ if (require_formatText.context_default.hydrationNode) anchor = require_formatText.context_default.hydrationNode.nextSibling;
673
+ popRange(oldRange);
674
+ }
675
+
676
+ //#endregion
677
+ //#region src/render/runControlBranch.ts
678
+ function runControlBranch(range, create) {
679
+ if (range.depth === -2) return;
680
+ if (range.nextRange !== null && range.nextRange.depth > range.depth) clearRange(range.nextRange);
681
+ const oldRange = pushRange(newRange(), true);
682
+ create();
683
+ popRange(oldRange);
684
+ }
685
+
686
+ //#endregion
687
+ //#region src/render/moveRange.ts
688
+ function moveRange(parent, range, before) {
689
+ parent = before?.parentNode ?? parent;
690
+ const endNode = range.endNode ?? range.startNode;
691
+ let currentNode = range.startNode;
692
+ while (currentNode !== null) {
693
+ const nextNode = currentNode.nextSibling;
694
+ parent.insertBefore(currentNode, before);
695
+ if (currentNode === endNode) break;
696
+ currentNode = nextNode;
697
+ }
698
+ }
699
+
700
+ //#endregion
701
+ //#region src/render/runListItems.ts
702
+ /**
703
+ * @param range The list's range
704
+ * @param parent The parent DOM element
705
+ * @param anchor The DOM element to create new items before
706
+ * @param oldItems The list of current items
707
+ * @param newItems The list of future items
708
+ * @param create A function that creates the DOM elements for a new item
709
+ */
710
+ function runListItems(range, parent, anchor, oldItems, newItems, create, update) {
711
+ let oldStartIndex = 0;
712
+ let oldEndIndex = oldItems.length - 1;
713
+ let oldStartItem = oldItems[0];
714
+ let oldEndItem = oldItems[oldEndIndex];
715
+ let newStartIndex = 0;
716
+ let newEndIndex = newItems.length - 1;
717
+ let newStartItem = newItems[0];
718
+ let newEndItem = newItems[newEndIndex];
719
+ let oldKeyToIndex;
720
+ let newKeyToIndex;
721
+ while (oldStartIndex <= oldEndIndex && newStartIndex <= newEndIndex) if (oldStartItem === null) oldStartItem = oldItems[++oldStartIndex];
722
+ else if (oldEndItem === null) oldEndItem = oldItems[--oldEndIndex];
723
+ else if (newStartItem === null) newStartItem = newItems[++newStartIndex];
724
+ else if (newEndItem === null) newEndItem = newItems[--newEndIndex];
725
+ else if (oldStartItem.key === newStartItem.key) {
726
+ transferListItemData(oldStartItem, newStartItem, update);
727
+ oldStartItem = oldItems[++oldStartIndex];
728
+ newStartItem = newItems[++newStartIndex];
729
+ } else if (oldEndItem.key === newEndItem.key) {
730
+ transferListItemData(oldEndItem, newEndItem, update);
731
+ oldEndItem = oldItems[--oldEndIndex];
732
+ newEndItem = newItems[--newEndIndex];
733
+ } else if (oldStartItem.key === newEndItem.key) {
734
+ moveRange(parent, oldStartItem, oldEndItem.endNode.nextSibling);
735
+ transferListItemData(oldStartItem, newEndItem, update);
736
+ oldStartItem = oldItems[++oldStartIndex];
737
+ newEndItem = newItems[--newEndIndex];
738
+ } else if (oldEndItem.key === newStartItem.key) {
739
+ moveRange(parent, oldEndItem, oldStartItem.startNode);
740
+ transferListItemData(oldEndItem, newStartItem, update);
741
+ oldEndItem = oldItems[--oldEndIndex];
742
+ newStartItem = newItems[++newStartIndex];
743
+ } else {
744
+ if (oldKeyToIndex === void 0 || newKeyToIndex === void 0) {
745
+ oldKeyToIndex = /* @__PURE__ */ new Map();
746
+ for (let i = oldStartIndex; i < oldEndIndex; i++) oldKeyToIndex.set(oldItems[i].key, i);
747
+ newKeyToIndex = /* @__PURE__ */ new Map();
748
+ for (let i = newStartIndex; i < newEndIndex; i++) newKeyToIndex.set(newItems[i].key, i);
749
+ }
750
+ let oldIndex = oldKeyToIndex.get(newStartItem.key);
751
+ let newIndex = newKeyToIndex.get(oldStartItem.key);
752
+ if (oldIndex === void 0 && newIndex === void 0) {
753
+ newStartItem.data = $watch(newStartItem.data, { shallow: true });
754
+ create(newStartItem, oldStartItem.startNode);
755
+ newStartItem.previousRange = oldStartItem.previousRange;
756
+ newStartItem.nextRange = oldStartItem;
757
+ oldStartItem.previousRange = newStartItem;
758
+ clearRange(oldStartItem);
759
+ oldStartItem = oldItems[++oldStartIndex];
760
+ newStartItem = newItems[++newStartIndex];
761
+ } else if (oldIndex === void 0) {
762
+ newStartItem.data = $watch(newStartItem.data, { shallow: true });
763
+ create(newStartItem, oldStartItem.startNode);
764
+ newStartItem = newItems[++newStartIndex];
765
+ } else if (newIndex === void 0) {
766
+ clearRange(oldStartItem);
767
+ oldStartItem = oldItems[++oldStartIndex];
768
+ } else {
769
+ const oldData = oldItems[oldIndex];
770
+ moveRange(parent, oldData, oldStartItem.startNode);
771
+ transferListItemData(oldData, newStartItem, update);
772
+ oldItems[oldIndex] = null;
773
+ newStartItem = newItems[++newStartIndex];
774
+ }
775
+ }
776
+ if (oldStartIndex <= oldEndIndex || newStartIndex <= newEndIndex) if (oldStartIndex > oldEndIndex) {
777
+ let before = oldStartItem?.startNode ?? oldItems[oldItems.length - 1]?.endNode?.nextSibling ?? anchor;
778
+ for (; newStartIndex <= newEndIndex; newStartItem = newItems[++newStartIndex]) {
779
+ newStartItem.data = $watch(newStartItem.data, { shallow: true });
780
+ create(newStartItem, before);
781
+ before = newStartItem.endNode.nextSibling;
782
+ }
783
+ } else for (; oldEndIndex >= oldStartIndex; oldStartItem = oldItems[oldEndIndex--]) clearRange(oldStartItem);
784
+ if (newItems.length > 0) range.nextRange = newItems[0];
785
+ else if (oldItems.length > 0) range.nextRange = oldItems[oldItems.length - 1].nextRange;
786
+ }
787
+ function transferListItemData(oldItem, newItem, update) {
788
+ newItem.startNode = oldItem.startNode;
789
+ newItem.endNode = oldItem.endNode;
790
+ update(oldItem, newItem);
791
+ newItem.data = oldItem.data;
792
+ }
793
+
794
+ //#endregion
795
+ //#region src/render/runList.ts
796
+ /**
797
+ * Runs a `for` control statement
798
+ * @param create A function that creates the control statement's branches
799
+ */
800
+ function runList(range, parent, anchor, buildItems, create, update) {
801
+ const oldRange = pushRange(range, true);
802
+ let listItems = [];
803
+ $run(function runList$1() {
804
+ const oldBranchRange = pushRange(range);
805
+ const newItems = buildItems();
806
+ require_formatText.context_default.activeTarget = null;
807
+ runListItems(range, parent, anchor, listItems, newItems, create, update);
808
+ listItems = newItems;
809
+ popRange(oldBranchRange);
810
+ });
811
+ if (require_formatText.context_default.hydrationNode !== null) anchor = require_formatText.context_default.hydrationNode.nextSibling;
812
+ popRange(oldRange);
813
+ }
814
+
815
+ //#endregion
816
+ //#region src/render/setAttribute.ts
817
+ function setAttribute(el, name, value) {
818
+ if (value === false || value === void 0 || value === null) el.removeAttribute(name);
819
+ else el.setAttribute(name, value);
820
+ }
821
+
822
+ //#endregion
823
+ //#region src/render/setDynamicElement.ts
824
+ function setDynamicElement(el, tag) {
825
+ if (require_formatText.context_default.hydrationNode !== null) return el;
826
+ let newElement = el.ownerDocument.createElement(tag);
827
+ el.replaceWith(newElement);
828
+ return newElement;
829
+ }
830
+
831
+ //#endregion
832
+ //#region src/wrappers/ReactiveDate.ts
833
+ let initialized = false;
834
+ /**
835
+ * Wraps a Date object for $watching.
836
+ */
837
+ var ReactiveDate = class ReactiveDate extends Date {
838
+ constructor(...params) {
839
+ super(...params);
840
+ if (!initialized) this.#init();
841
+ this[proxyHandledSymbol] = true;
842
+ this[proxyDataSymbol] = {
843
+ target: this,
844
+ isArray: false,
845
+ shallow: true,
846
+ signals: /* @__PURE__ */ new Map()
847
+ };
848
+ }
849
+ #init() {
850
+ initialized = true;
851
+ let reactivePrototype = ReactiveDate.prototype;
852
+ let datePrototype = Date.prototype;
853
+ const methods = Object.getOwnPropertyNames(datePrototype);
854
+ for (const method of methods) {
855
+ if (method.startsWith("get") || method.startsWith("to") || method === "valueOf") reactivePrototype[method] = function(...args) {
856
+ const data = this[proxyDataSymbol];
857
+ const result = datePrototype[method].apply(this, args);
858
+ trackProxyEffect(data, "#time");
859
+ return result;
860
+ };
861
+ if (method.startsWith("set")) reactivePrototype[method] = function(...args) {
862
+ const data = this[proxyDataSymbol];
863
+ const result = datePrototype[method].apply(this, args);
864
+ updateSignal(data, "#time");
865
+ return result;
866
+ };
867
+ }
868
+ }
869
+ };
870
+
871
+ //#endregion
872
+ exports.$batch = require_formatText.$batch;
873
+ exports.$cache = require_formatText.$cache;
874
+ exports.$mount = $mount;
875
+ exports.$peek = require_formatText.$peek;
876
+ exports.$run = $run;
877
+ exports.$unwrap = $unwrap;
878
+ exports.$watch = $watch;
879
+ exports.ReactiveDate = ReactiveDate;
880
+ exports.clearLayoutSlot = clearLayoutSlot;
881
+ exports.fillLayoutSlot = fillLayoutSlot;
882
+ exports.hydrate = hydrate;
883
+ exports.mount = mount;
884
+ exports.t_add_fragment = addFragment;
885
+ exports.t_anchor = nodeAnchor;
886
+ exports.t_animate = addAnimation;
887
+ exports.t_apply_props = applyProps;
888
+ exports.t_attribute = setAttribute;
889
+ exports.t_child = nodeChild;
890
+ exports.t_class = require_formatText.buildClasses;
891
+ exports.t_dynamic = setDynamicElement;
892
+ exports.t_event = addEvent;
893
+ exports.t_fmt = require_formatText.formatText;
894
+ exports.t_fragment = getFragment;
895
+ exports.t_list_item = newListItem;
896
+ exports.t_next = nodeNext;
897
+ exports.t_pop_range = popRange;
898
+ exports.t_push_range = pushRange;
899
+ exports.t_range = newRange;
900
+ exports.t_root = nodeRoot;
901
+ exports.t_run_branch = runControlBranch;
902
+ exports.t_run_control = runControl;
903
+ exports.t_run_list = runList;
904
+ exports.t_skip = nodeSkip;
905
+ exports.t_style = require_formatText.buildStyles;
906
+ //# sourceMappingURL=index.cjs.map