@calmdown/pyxis 1.0.0-rc.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.
@@ -0,0 +1,1828 @@
1
+ //#region src/dev/ComponentRegistry.ts
2
+ var ComponentRegistry = class {
3
+ components = /* @__PURE__ */ new Map();
4
+ isPendingUpdate = false;
5
+ on(id, fn) {
6
+ const entry = this.components.get(id);
7
+ if (!entry) throw new Error(`no component was registered under "${id}"`);
8
+ const listener = {
9
+ fn,
10
+ entry
11
+ };
12
+ if (entry.lt) {
13
+ entry.lt.ln = listener;
14
+ listener.lp = entry.lt;
15
+ } else entry.lh = listener;
16
+ entry.lt = listener;
17
+ fn(entry.component);
18
+ return listener;
19
+ }
20
+ off(listener) {
21
+ const { entry } = listener;
22
+ if (listener.lp) listener.lp.ln = listener.ln;
23
+ else if (entry.lh === listener) entry.lh = listener.ln;
24
+ if (listener.ln) listener.ln.lp = listener.lp;
25
+ else if (entry.lt === listener) entry.lt = listener.lp;
26
+ listener.lp = null;
27
+ listener.ln = null;
28
+ }
29
+ subscribe(id, fn) {
30
+ const listener = this.on(id, fn);
31
+ return () => this.off(listener);
32
+ }
33
+ upsert(id, component) {
34
+ const entry = this.components.get(id);
35
+ if (!entry) {
36
+ this.components.set(id, {
37
+ component,
38
+ dirty: false
39
+ });
40
+ return;
41
+ }
42
+ entry.component = component;
43
+ entry.dirty = true;
44
+ if (!this.isPendingUpdate) {
45
+ queueMicrotask(this.update);
46
+ this.isPendingUpdate = true;
47
+ }
48
+ }
49
+ update = () => {
50
+ this.isPendingUpdate = false;
51
+ this.components.forEach((entry) => {
52
+ if (!entry.dirty) return;
53
+ let current = entry.lh;
54
+ let next;
55
+ while (current) {
56
+ next = current.ln;
57
+ current.fn(entry.component);
58
+ current = next;
59
+ }
60
+ entry.dirty = false;
61
+ });
62
+ };
63
+ };
64
+
65
+ //#endregion
66
+ //#region src/dev/StateRegistry.ts
67
+ var StateRegistry = class {
68
+ state = /* @__PURE__ */ new WeakMap();
69
+ preserve(handle, devId, value) {
70
+ if (!handle || !devId) return;
71
+ let map = this.state.get(handle);
72
+ if (!map) this.state.set(handle, map = {});
73
+ map[devId] = value;
74
+ }
75
+ restore(handle, devId, block) {
76
+ if (!handle || !devId) return;
77
+ const map = this.state.get(handle);
78
+ if (!map || !Object.hasOwn(map, devId)) return;
79
+ return block ? block(map[devId]) : map[devId];
80
+ }
81
+ };
82
+
83
+ //#endregion
84
+ //#region src/dev/PyxisHotReload.ts
85
+ globalThis.__PYXIS_HMR__ = {
86
+ component: new ComponentRegistry(),
87
+ state: new StateRegistry()
88
+ };
89
+
90
+ //#endregion
91
+ //#region src/support/common.ts
92
+ function invoke(callback) {
93
+ return callback.$fn(callback.$a0, callback.$a1);
94
+ }
95
+
96
+ //#endregion
97
+ //#region src/data/Lifecycle.ts
98
+ /**
99
+ * Registers a callback to run just after the current Component has mounted.
100
+ *
101
+ * If a teardown callback is returned, it will be run just before the Component unmounts (equivalent
102
+ * to adding a separate `unmounted` block).
103
+ * @see {@link unmounted}
104
+ */
105
+ function mounted(block, lifecycle = getLifecycle()) {
106
+ onMounted(lifecycle, {
107
+ $fn: invokeMountedCallback,
108
+ $a0: lifecycle,
109
+ $a1: block
110
+ });
111
+ }
112
+ /** @internal */
113
+ function onMounted(lifecycle, callback) {
114
+ (lifecycle.$onMount ??= []).push(callback);
115
+ }
116
+ function invokeMountedCallback(lifecycle, block) {
117
+ const dispose = block();
118
+ if (dispose) onUnmounted(lifecycle, { $fn: dispose });
119
+ }
120
+ /**
121
+ * Registers a callback to run once the current Component is just about to unmount.
122
+ * @see {@link mounted}
123
+ */
124
+ function unmounted(block, lifecycle = getLifecycle()) {
125
+ onUnmounted(lifecycle, { $fn: block });
126
+ }
127
+ /** @internal */
128
+ function onUnmounted(lifecycle, callback) {
129
+ (lifecycle.$onUnmount ??= []).push(callback);
130
+ }
131
+ let $currentLifecycle = null;
132
+ /**
133
+ * Gets the Lifecycle of the calling component.
134
+ */
135
+ function getLifecycle() {
136
+ if (!$currentLifecycle) throw new Error("Cannot get current lifecycle. Are you creating an Atom outside of a Component?");
137
+ return $currentLifecycle;
138
+ }
139
+ /** @internal */
140
+ function setLifecycle(lifecycle) {
141
+ const previous = $currentLifecycle;
142
+ $currentLifecycle = lifecycle;
143
+ return previous;
144
+ }
145
+ function withLifecycle(lifecycle, block, arg) {
146
+ const previousLifecycle = $currentLifecycle;
147
+ $currentLifecycle = lifecycle;
148
+ try {
149
+ return block(arg);
150
+ } finally {
151
+ $currentLifecycle = previousLifecycle;
152
+ }
153
+ }
154
+
155
+ //#endregion
156
+ //#region src/data/Dependency.ts
157
+ function bind(lifecycle, target, block) {
158
+ link(lifecycle, target, { $fn: block });
159
+ block();
160
+ }
161
+ /**
162
+ * Links a Dependency to an Atom and Lifecycle.
163
+ * @internal
164
+ */
165
+ function link(lifecycle, target, dep) {
166
+ if (target.$dt) {
167
+ target.$dt.$an = dep;
168
+ dep.$ap = target.$dt;
169
+ } else target.$dh = dep;
170
+ dep.$target = target;
171
+ target.$dt = dep;
172
+ if (lifecycle.$dt) {
173
+ lifecycle.$dt.$ln = dep;
174
+ dep.$lp = lifecycle.$dt;
175
+ } else lifecycle.$dh = dep;
176
+ dep.$lifecycle = lifecycle;
177
+ lifecycle.$dt = dep;
178
+ }
179
+ /**
180
+ * Unlinks a Dependency from the Atom and Lifecycle it has been linked to.
181
+ * @internal
182
+ */
183
+ function unlink(dep) {
184
+ const target = dep.$target;
185
+ if (!target) return;
186
+ if (dep.$ap) dep.$ap.$an = dep.$an;
187
+ else if (target.$dh === dep) target.$dh = dep.$an;
188
+ if (dep.$an) dep.$an.$ap = dep.$ap;
189
+ else if (target.$dt === dep) target.$dt = dep.$ap;
190
+ dep.$target = null;
191
+ dep.$ap = null;
192
+ dep.$an = null;
193
+ const lifecycle = dep.$lifecycle;
194
+ if (dep.$lp) dep.$lp.$ln = dep.$ln;
195
+ else if (lifecycle.$dh === dep) lifecycle.$dh = dep.$ln;
196
+ if (dep.$ln) dep.$ln.$lp = dep.$lp;
197
+ else if (lifecycle.$dt === dep) lifecycle.$dt = dep.$lp;
198
+ dep.$lifecycle = null;
199
+ dep.$lp = null;
200
+ dep.$ln = null;
201
+ }
202
+ /**
203
+ * Unlinks all Dependencies managed by the given Lifecycle.
204
+ * @internal
205
+ */
206
+ function unlinkAll(lifecycle) {
207
+ let dep = lifecycle.$dh;
208
+ let atom;
209
+ let next;
210
+ while (dep) {
211
+ atom = dep.$target;
212
+ if (dep.$ap) dep.$ap.$an = dep.$an;
213
+ else if (atom.$dh === dep) atom.$dh = dep.$an;
214
+ if (dep.$an) dep.$an.$ap = dep.$ap;
215
+ else if (atom.$dt === dep) atom.$dt = dep.$ap;
216
+ next = dep.$ln;
217
+ dep.$lifecycle = null;
218
+ dep.$target = null;
219
+ dep.$ap = null;
220
+ dep.$an = null;
221
+ dep.$lp = null;
222
+ dep.$ln = null;
223
+ dep = next;
224
+ }
225
+ lifecycle.$dh = null;
226
+ lifecycle.$dt = null;
227
+ }
228
+
229
+ //#endregion
230
+ //#region src/data/Scheduler.ts
231
+ /** @internal */
232
+ function createScheduler(tick) {
233
+ let isPending = false;
234
+ const ticks = [];
235
+ const tocks = [];
236
+ const scheduler = {
237
+ $epoch: 1,
238
+ $onTick: ticks,
239
+ $onTock: tocks,
240
+ $scheduleTick: () => {
241
+ if (isPending) return;
242
+ isPending = true;
243
+ tick(update);
244
+ }
245
+ };
246
+ const update = () => {
247
+ try {
248
+ let index = 0;
249
+ let callback;
250
+ for (; index < ticks.length; index += 1) {
251
+ callback = ticks[index];
252
+ if (callback.$life === callback.$lifecycle.$life) {
253
+ callback.$re = scheduler.$epoch;
254
+ invoke(callback);
255
+ }
256
+ }
257
+ for (index = 0; index < tocks.length; index += 1) {
258
+ callback = tocks[index];
259
+ if (callback.$life === callback.$lifecycle.$life) {
260
+ callback.$re = scheduler.$epoch;
261
+ invoke(callback);
262
+ }
263
+ }
264
+ } finally {
265
+ isPending = false;
266
+ ticks.length = 0;
267
+ tocks.length = 0;
268
+ scheduler.$epoch += 1;
269
+ }
270
+ };
271
+ return scheduler;
272
+ }
273
+ function schedule(lifecycle, queue, callback) {
274
+ const scheduler = lifecycle.$scheduler;
275
+ if (callback.$se === scheduler.$epoch) {
276
+ if (callback.$re === scheduler.$epoch) throw new Error("Refusing to re-schedule an update after it already executed, as it may cause an infinite loop. Are you mutating an Atom inside an effect that observes it?");
277
+ return;
278
+ }
279
+ callback.$lifecycle = lifecycle;
280
+ callback.$life = lifecycle.$life;
281
+ callback.$se = scheduler.$epoch;
282
+ queue.push(callback);
283
+ scheduler.$scheduleTick();
284
+ }
285
+ /** @internal */
286
+ function scheduleTick(lifecycle, callback) {
287
+ schedule(lifecycle, lifecycle.$scheduler.$onTick, callback);
288
+ }
289
+ /**
290
+ * Runs a block of code on the next tick of the scheduler, synchronized with other updates. If a
291
+ * tick is not currently pending, a new one is scheduled.
292
+ */
293
+ function tick(block, lifecycle = getLifecycle()) {
294
+ schedule(lifecycle, lifecycle.$scheduler.$onTick, { $fn: block });
295
+ }
296
+ /** @internal */
297
+ function scheduleTock(lifecycle, callback) {
298
+ schedule(lifecycle, lifecycle.$scheduler.$onTock, callback);
299
+ }
300
+ /**
301
+ * Runs a block of code after the next tick of the scheduler, once all regular updates finished.
302
+ * If a tick is not currently pending, a new one is scheduled.
303
+ */
304
+ function tock(block, lifecycle = getLifecycle()) {
305
+ schedule(lifecycle, lifecycle.$scheduler.$onTock, { $fn: block });
306
+ }
307
+
308
+ //#endregion
309
+ //#region src/data/Effect.ts
310
+ /**
311
+ * Creates an Effect - a block of logic executed each time any of the Atoms accessed within it
312
+ * change. The block is first synchronously executed when the Effect is created.
313
+ *
314
+ * If a teardown callback is returned, it will be run before the next effect re-run, or on component
315
+ * unmount.
316
+ */
317
+ function effect(block, lifecycle = getLifecycle()) {
318
+ runEffect({
319
+ $lifecycle: lifecycle,
320
+ $life: lifecycle.$life,
321
+ $block: block,
322
+ $react: scheduleEffect,
323
+ $cycle: 0
324
+ });
325
+ }
326
+ function scheduleEffect(effect, cycle) {
327
+ if (effect.$cycle > cycle) {
328
+ unlink(this);
329
+ return;
330
+ }
331
+ scheduleTick(effect.$lifecycle, effect.$resolve ??= {
332
+ $fn: runEffect,
333
+ $a0: effect
334
+ });
335
+ }
336
+ function runEffect(effect) {
337
+ if (effect.$life !== effect.$lifecycle.$life) return;
338
+ effect.$dispose?.();
339
+ effect.$dispose = resolve(effect);
340
+ if (!effect.$tracksUnmount && effect.$dispose) {
341
+ effect.$tracksUnmount = true;
342
+ onUnmounted(effect.$lifecycle, {
343
+ $fn: teardownEffect,
344
+ $a0: effect
345
+ });
346
+ }
347
+ }
348
+ function teardownEffect(effect) {
349
+ effect.$dispose?.();
350
+ effect.$dispose = null;
351
+ }
352
+ let $currentEffect = null;
353
+ /**
354
+ * Resolves an Effect: runs user logic tracking accessed Atoms and updating dependency links.
355
+ * Returned value is forwarded.
356
+ * @internal
357
+ */
358
+ function resolve(effect) {
359
+ effect.$deps ??= /* @__PURE__ */ new WeakMap();
360
+ effect.$cycle += 1;
361
+ const previousEffect = $currentEffect;
362
+ const previousLifecycle = setLifecycle(effect.$lifecycle);
363
+ $currentEffect = effect;
364
+ try {
365
+ return effect.$block();
366
+ } finally {
367
+ setLifecycle(previousLifecycle);
368
+ $currentEffect = previousEffect;
369
+ }
370
+ }
371
+ /**
372
+ * Reports an Atom has been accessed. Does nothing if not within an Effect.
373
+ * @internal
374
+ */
375
+ function reportAccess(atom) {
376
+ if (!$currentEffect || $currentEffect.$life !== $currentEffect.$lifecycle.$life) return;
377
+ let dep = $currentEffect.$deps.get(atom);
378
+ if (dep) {
379
+ dep.$a1 = $currentEffect.$cycle;
380
+ if (!dep.$lifecycle) link($currentEffect.$lifecycle, atom, dep);
381
+ } else {
382
+ link($currentEffect.$lifecycle, atom, dep = {
383
+ $fn: $currentEffect.$react,
384
+ $a0: $currentEffect,
385
+ $a1: $currentEffect.$cycle
386
+ });
387
+ $currentEffect.$deps.set(atom, dep);
388
+ }
389
+ }
390
+ /**
391
+ * Asserts that the current code is not running within an effect block.
392
+ * Only used in development; In production, this function should be removed by the bundler.
393
+ */
394
+ function __DEV__assertNotEffect() {
395
+ if ($currentEffect && $currentEffect.$lifecycle === getLifecycle() && $currentEffect.$life === $currentEffect.$lifecycle.$life) throw new Error("Attempt to create an Atom inside an effect block.");
396
+ }
397
+
398
+ //#endregion
399
+ //#region src/data/Atom.ts
400
+ /**
401
+ * Pyxis Atom type guard marker.
402
+ */
403
+ const S_ATOM = Symbol.for("pyxis:atom");
404
+ function atomOf(initialValue, lifecycle = getLifecycle()) {
405
+ __DEV__assertNotEffect();
406
+ if (isAtom(initialValue)) return initialValue;
407
+ const atom = {
408
+ [S_ATOM]: true,
409
+ $value: initialValue,
410
+ $tracksValue: true,
411
+ $lifecycle: lifecycle,
412
+ $lastValue: initialValue,
413
+ get: getValue$1,
414
+ set: setValue$2
415
+ };
416
+ {
417
+ const devId = arguments[2];
418
+ atom.$devId = devId;
419
+ globalThis.__PYXIS_HMR__.state.restore(lifecycle, devId, (value) => {
420
+ atom.$value = value;
421
+ });
422
+ }
423
+ return atom;
424
+ }
425
+ function getValue$1() {
426
+ return this.$value;
427
+ }
428
+ function setValue$2(value) {
429
+ if (Object.is(this.$value, value)) return false;
430
+ this.$value = value;
431
+ globalThis.__PYXIS_HMR__.state.preserve(this.$lifecycle, this.$devId, value);
432
+ return true;
433
+ }
434
+ function isAtom(input) {
435
+ return input !== null && typeof input === "object" && input[S_ATOM] === true;
436
+ }
437
+ function read(input) {
438
+ if (isAtom(input)) {
439
+ reportAccess(input);
440
+ return input.get();
441
+ }
442
+ return input;
443
+ }
444
+ function peek(input) {
445
+ if (isAtom(input)) return input.get();
446
+ return input;
447
+ }
448
+ function write(input, value, force = false) {
449
+ if (isAtom(input)) {
450
+ if (input.set(value) || force) {
451
+ input.$force ||= force;
452
+ scheduleTick(input.$lifecycle, input.$notify ??= {
453
+ $fn: notify$1,
454
+ $a0: input
455
+ });
456
+ }
457
+ return input.get();
458
+ }
459
+ return input;
460
+ }
461
+ function update(input, transform, force = false) {
462
+ if (isAtom(input)) {
463
+ if (input.set(transform(input.get())) || force) {
464
+ input.$force ||= force;
465
+ scheduleTick(input.$lifecycle, input.$notify ??= {
466
+ $fn: notify$1,
467
+ $a0: input
468
+ });
469
+ }
470
+ return input.get();
471
+ }
472
+ return input;
473
+ }
474
+ /**
475
+ * Notifies the dependencies of an Atom.
476
+ * @internal
477
+ */
478
+ function notify$1(input) {
479
+ if (input.$tracksValue) {
480
+ const newValue = input.get();
481
+ if (Object.is(input.$lastValue, newValue) && !input.$force) return;
482
+ input.$lastValue = newValue;
483
+ }
484
+ input.$force = false;
485
+ let current = input.$dh;
486
+ let next;
487
+ while (current) {
488
+ next = current.$an;
489
+ invoke(current);
490
+ current = next;
491
+ }
492
+ }
493
+
494
+ //#endregion
495
+ //#region src/component/Text.ts
496
+ function Text(jsx, hParent, nUsedParent, _nRealParent, nBefore, isBatch) {
497
+ const { adapter } = hParent.$ng;
498
+ let node = null;
499
+ if (isAtom(jsx)) bind(hParent.$ng, jsx, () => {
500
+ node = adapter.text(jsx.get()?.toString() ?? "", node);
501
+ });
502
+ else node = adapter.text(jsx.toString(), null);
503
+ insert(node, null, hParent, nUsedParent, nBefore, isBatch);
504
+ }
505
+
506
+ //#endregion
507
+ //#region src/data/Context.ts
508
+ function createContext() {
509
+ let $symbol = Symbol();
510
+ {
511
+ const devId = arguments[0];
512
+ $symbol = globalThis.__PYXIS_HMR__.state.restore(createContext, devId) ?? $symbol;
513
+ globalThis.__PYXIS_HMR__.state.preserve(createContext, devId, $symbol);
514
+ }
515
+ return { $symbol };
516
+ }
517
+ let $currentContainer;
518
+ let $isNewContainer = false;
519
+ /** @internal */
520
+ function getContextContainer() {
521
+ return $currentContainer;
522
+ }
523
+ /** @internal */
524
+ function setContextContainer(container) {
525
+ $currentContainer = container;
526
+ $isNewContainer = false;
527
+ }
528
+ /**
529
+ * Gets a consumer Atom for the given Context. This atom will be read-only.
530
+ * @see {@link host}
531
+ */
532
+ function consumerOf(context) {
533
+ __DEV__assertNotEffect();
534
+ const { $symbol } = context;
535
+ let ptr = $currentContainer;
536
+ let atom;
537
+ while (ptr && !(atom = ptr[$symbol])) ptr = ptr.$parent;
538
+ return atom ?? null;
539
+ }
540
+ function host(context, defaultValue) {
541
+ __DEV__assertNotEffect();
542
+ if (!$isNewContainer || !$currentContainer) {
543
+ $isNewContainer = true;
544
+ $currentContainer = { $parent: $currentContainer };
545
+ }
546
+ const lifecycle = getLifecycle();
547
+ {
548
+ const devId = arguments[2];
549
+ globalThis.__PYXIS_HMR__.state.restore(lifecycle, devId, (value) => {
550
+ defaultValue = value;
551
+ });
552
+ }
553
+ const localAtom = {
554
+ [S_ATOM]: true,
555
+ $lifecycle: lifecycle,
556
+ $tracksValue: true,
557
+ $value: defaultValue,
558
+ get: getLocalValue,
559
+ set: setValue$1
560
+ };
561
+ if (defaultValue === void 0) {
562
+ const ancestorAtom = consumerOf(context);
563
+ if (ancestorAtom) {
564
+ localAtom.get = getAncestorValue;
565
+ localAtom.$ancestor = ancestorAtom;
566
+ link(lifecycle, ancestorAtom, localAtom.$dep = {
567
+ $fn: notify$1,
568
+ $a0: localAtom
569
+ });
570
+ }
571
+ }
572
+ localAtom.$devId = arguments[2];
573
+ if (Object.hasOwn($currentContainer, context.$symbol)) throw new Error("Component declares multiple hosts of the same Context.");
574
+ $currentContainer[context.$symbol] = localAtom;
575
+ return localAtom;
576
+ }
577
+ function getAncestorValue() {
578
+ return this.$ancestor.get();
579
+ }
580
+ function getLocalValue() {
581
+ return this.$value;
582
+ }
583
+ function setValue$1(value) {
584
+ let oldValue;
585
+ if (this.$ancestor) {
586
+ oldValue = this.$ancestor.get();
587
+ unlink(this.$dep);
588
+ this.$dep = null;
589
+ this.$ancestor = null;
590
+ this.get = getLocalValue;
591
+ } else oldValue = this.$value;
592
+ this.$value = value;
593
+ globalThis.__PYXIS_HMR__.state.preserve(this.$lifecycle, this.$devId, value);
594
+ return !Object.is(oldValue, value);
595
+ }
596
+
597
+ //#endregion
598
+ //#region src/Renderer.ts
599
+ /** @internal */
600
+ const S_COMPONENT = Symbol.for("pyxis:component");
601
+ /** @internal */
602
+ function createRenderer(adapter, extensions) {
603
+ const hGroup = {
604
+ adapter,
605
+ mounted: false,
606
+ $isGroup: true,
607
+ $scheduler: createScheduler(adapter.tick),
608
+ $extensions: extensions,
609
+ $life: 1,
610
+ $pg: null,
611
+ $ng: null,
612
+ unmount: () => unmount(hGroup),
613
+ mount: (nRoot, jsx) => {
614
+ hGroup.$nn = nRoot;
615
+ const isBatch = Boolean(adapter.batch);
616
+ const nParent = isBatch ? adapter.batch() : nRoot;
617
+ mount(jsx, hGroup, nParent, nRoot, null, isBatch);
618
+ if (isBatch) adapter.insert(nParent, nRoot, null);
619
+ }
620
+ };
621
+ hGroup.$ng = hGroup;
622
+ globalThis.__PYXIS_ROOT__ ??= hGroup;
623
+ return hGroup;
624
+ }
625
+ /**
626
+ * Creates a sub-group within the provided MountingGroup. Needed whenever a subtree needs to mount
627
+ * or unmount dynamically.
628
+ */
629
+ function fork(hParent, hBefore = null) {
630
+ const ng = hParent.$ng;
631
+ const hGroup = {
632
+ adapter: ng.adapter,
633
+ mounted: false,
634
+ $isGroup: true,
635
+ $scheduler: ng.$scheduler,
636
+ $extensions: ng.$extensions,
637
+ $life: 1,
638
+ $context: getContextContainer(),
639
+ $pg: ng,
640
+ $ng: null
641
+ };
642
+ hGroup.$ng = hGroup;
643
+ hGroup.$nn = hParent.$nn;
644
+ track(hGroup, hParent, hBefore);
645
+ return hGroup;
646
+ }
647
+ /**
648
+ * Adds a HNode to the hierarchy.
649
+ */
650
+ function track(hNode, hParent, hBefore = null) {
651
+ if (hBefore?.$pg === hParent) if (hBefore.$hp) {
652
+ hNode.$hp = hBefore.$hp;
653
+ hNode.$hn = hBefore;
654
+ hBefore.$hp.$hn = hNode;
655
+ hBefore.$hp = hNode;
656
+ } else {
657
+ hNode.$hp = null;
658
+ hNode.$hn = hParent.$hh;
659
+ if (hParent.$hh === hBefore) hBefore.$hp = hNode;
660
+ hParent.$hh = hNode;
661
+ }
662
+ else {
663
+ if (hParent.$ht) {
664
+ hParent.$ht.$hn = hNode;
665
+ hNode.$hp = hParent.$ht;
666
+ } else hParent.$hh = hNode;
667
+ hParent.$ht = hNode;
668
+ }
669
+ }
670
+ /**
671
+ * Removes a HNode from the tracking hierarchy.
672
+ */
673
+ function untrack(hNode) {
674
+ if (hNode.$hp) hNode.$hp.$hn = hNode.$hn;
675
+ else if (hNode.$pg?.$hh === hNode) hNode.$pg.$hh = hNode.$hn;
676
+ if (hNode.$hn) hNode.$hn.$hp = hNode.$hp;
677
+ else if (hNode.$pg?.$ht === hNode) hNode.$pg.$ht = hNode.$hp;
678
+ hNode.$hp = null;
679
+ hNode.$hn = null;
680
+ }
681
+ /**
682
+ * Mounts a MountingGroup to the specified location in the node tree. If the group is already
683
+ * mounted (i.e. its native nodes are already rendered somewhere), it is moved to the new location
684
+ * without re-mounting Pyxis components.
685
+ *
686
+ * Note that for successfully moving a group within the tree, you should first `untrack` the group,
687
+ * then re-`track` it to the new location and only then call `mount` to commit the move.
688
+ * @see {@link track}
689
+ * @see {@link untrack}
690
+ */
691
+ function mount(jsx, hGroup, nUsedParent, nRealParent, nBefore, isBatch) {
692
+ if (hGroup.mounted) {
693
+ reinsertNodes(hGroup, nUsedParent, nBefore);
694
+ return;
695
+ }
696
+ const previousLifecycle = setLifecycle(hGroup);
697
+ setContextContainer(hGroup.$context);
698
+ try {
699
+ mountJsx(jsx, hGroup, nUsedParent, nRealParent, nBefore, isBatch);
700
+ } finally {
701
+ setLifecycle(previousLifecycle);
702
+ hGroup.mounted = true;
703
+ if (hGroup.$pg?.mounted !== false) notifyMounted(hGroup);
704
+ }
705
+ }
706
+ /**
707
+ * Only used by `mount`, do not call directly.
708
+ *
709
+ * Recursively (dept-first) runs components' `mounted` callbacks.
710
+ * @see {@link mount}
711
+ * @internal
712
+ */
713
+ function notifyMounted(hNode) {
714
+ let current = hNode.$hh;
715
+ while (current) {
716
+ notifyMounted(current);
717
+ current = current.$hn;
718
+ }
719
+ let callbacks;
720
+ if (hNode.$isGroup && hNode.mounted && (callbacks = hNode.$onMount)) {
721
+ const previousLifecycle = setLifecycle(hNode);
722
+ try {
723
+ callbacks.forEach(invoke);
724
+ } finally {
725
+ callbacks.length = 0;
726
+ setLifecycle(previousLifecycle);
727
+ }
728
+ }
729
+ }
730
+ /**
731
+ * Only used by `mount`, do not call directly.
732
+ *
733
+ * Re-inserts native nodes of the given group to the specified location in the native tree. Only
734
+ * moves the uppermost nodes - any children should move implicitly with them.
735
+ * @see {@link mount}
736
+ * @internal
737
+ */
738
+ function reinsertNodes(hGroup, nParent, nBefore) {
739
+ const { adapter } = hGroup;
740
+ let current = hGroup.$hh;
741
+ while (current) {
742
+ if (current.$isNative) adapter.insert(current.$nn, nParent, nBefore);
743
+ else reinsertNodes(current, nParent, nBefore);
744
+ current = current.$hn;
745
+ }
746
+ }
747
+ function unmount(hNode, top = true) {
748
+ if (hNode.$isGroup) {
749
+ if (hNode.mounted) {
750
+ let callbacks;
751
+ if (callbacks = hNode.$onUnmount) {
752
+ const previousLifecycle = setLifecycle(hNode);
753
+ try {
754
+ callbacks.forEach(invoke);
755
+ } finally {
756
+ callbacks.length = 0;
757
+ setLifecycle(previousLifecycle);
758
+ }
759
+ }
760
+ hNode.mounted = false;
761
+ hNode.$life += 1;
762
+ }
763
+ unlinkAll(hNode);
764
+ }
765
+ const { adapter } = hNode.$ng;
766
+ let current = hNode.$hh;
767
+ let next;
768
+ while (current) {
769
+ if (current.$isNative && top) {
770
+ adapter.remove(current.$nn);
771
+ unmount(current, false);
772
+ } else unmount(current, top);
773
+ next = current.$hn;
774
+ current.$hp = null;
775
+ current.$hn = null;
776
+ current = next;
777
+ }
778
+ hNode.$hh = null;
779
+ hNode.$ht = null;
780
+ }
781
+ /**
782
+ * Mounts components described by the JsxResult to the specified location in the node tree.
783
+ */
784
+ function mountJsx(jsx, hParent, nUsedParent, nRealParent, nBefore, isBatch) {
785
+ switch (typeof jsx) {
786
+ case "object":
787
+ if (jsx === null) break;
788
+ if (Array.isArray(jsx)) {
789
+ const { length } = jsx;
790
+ let index = 0;
791
+ for (; index < length; index += 1) mountJsx(jsx[index], hParent, nUsedParent, nRealParent, nBefore, isBatch);
792
+ break;
793
+ }
794
+ if (!isAtom(jsx)) {
795
+ jsx[S_COMPONENT]?.(jsx, hParent, nUsedParent, nRealParent, nBefore, isBatch);
796
+ break;
797
+ }
798
+ case "string":
799
+ case "number":
800
+ case "boolean":
801
+ case "bigint":
802
+ Text(jsx, hParent, nUsedParent, nRealParent, nBefore, isBatch);
803
+ break;
804
+ }
805
+ }
806
+ /**
807
+ * Inserts a native node and adds it to the tracking hierarchy. Necessary to preserve render order.
808
+ * Should only be called by component handlers!
809
+ */
810
+ function insert(nNode, children, hParent, nUsedParent, nBefore, isBatch) {
811
+ let hNative = hParent;
812
+ if (hNative.$isGroup) {
813
+ let hBefore = null;
814
+ if (nBefore) {
815
+ let current = hParent.$ht;
816
+ while (current) {
817
+ if (current.$isNative && current.$nn === nBefore) {
818
+ hBefore = current;
819
+ break;
820
+ }
821
+ current = current.$hp;
822
+ }
823
+ }
824
+ track(hNative = {
825
+ $isNative: true,
826
+ $pg: hNative,
827
+ $ng: hNative,
828
+ $nn: nNode
829
+ }, hParent, hBefore);
830
+ }
831
+ mountJsx(children, hNative, nNode, nNode, null, isBatch);
832
+ hParent.$ng.adapter.insert(nNode, nUsedParent, nBefore);
833
+ }
834
+
835
+ //#endregion
836
+ //#region src/component/Fragment.ts
837
+ function Fragment(jsx, hParent, nUsedParent, nRealParent, nBefore, isBatch) {
838
+ mountJsx(jsx.children, hParent, nUsedParent, nRealParent, nBefore, isBatch);
839
+ }
840
+
841
+ //#endregion
842
+ //#region src/data/ListDelta.ts
843
+ /** @internal */
844
+ const LC_CHANGE = 1;
845
+ /** @internal */
846
+ const LC_INSERT = 2;
847
+ /** @internal */
848
+ const LC_REMOVE = 3;
849
+ /** @internal */
850
+ const LC_CLEAR = 4;
851
+ let ChangeKind = /* @__PURE__ */ function(ChangeKind) {
852
+ ChangeKind[ChangeKind["Change"] = 1] = "Change";
853
+ ChangeKind[ChangeKind["Insert"] = 2] = "Insert";
854
+ ChangeKind[ChangeKind["Remove"] = 3] = "Remove";
855
+ ChangeKind[ChangeKind["Clear"] = 4] = "Clear";
856
+ return ChangeKind;
857
+ }({});
858
+ /** @internal */
859
+ function createDelta() {
860
+ return {
861
+ changes: [],
862
+ lengthChange: 0
863
+ };
864
+ }
865
+ /** @internal */
866
+ function itemChanged({ changes: $changes }, at, oldItem, newItem) {
867
+ const ci = binarySearch($changes, at, latest);
868
+ if (ci < 0) $changes.splice(~ci, 0, {
869
+ kind: 1,
870
+ index: at,
871
+ oldItem,
872
+ newItem
873
+ });
874
+ else {
875
+ const current = $changes[ci];
876
+ switch (current.kind) {
877
+ case 1:
878
+ case 2:
879
+ current.newItem = newItem;
880
+ break;
881
+ case 3:
882
+ $changes.splice(ci + 1, 0, {
883
+ kind: 1,
884
+ index: at,
885
+ oldItem,
886
+ newItem
887
+ });
888
+ break;
889
+ }
890
+ }
891
+ }
892
+ /** @internal */
893
+ function itemInserted(delta, at, item) {
894
+ const { changes: $changes } = delta;
895
+ let ci = binarySearch($changes, at, earliest);
896
+ if (ci < 0) {
897
+ ci = ~ci;
898
+ $changes.splice(ci, 0, {
899
+ kind: 2,
900
+ index: at,
901
+ newItem: item
902
+ });
903
+ } else {
904
+ const current = $changes[ci];
905
+ switch (current.kind) {
906
+ case 1:
907
+ case 2:
908
+ $changes.splice(ci, 0, {
909
+ kind: 2,
910
+ index: at,
911
+ newItem: item
912
+ });
913
+ break;
914
+ case 3:
915
+ current.kind = 1;
916
+ current.newItem = item;
917
+ break;
918
+ }
919
+ }
920
+ const { length } = $changes;
921
+ while (++ci < length) $changes[ci].index += 1;
922
+ delta.lengthChange += 1;
923
+ }
924
+ /** @internal */
925
+ function itemRemoved(delta, at, item) {
926
+ const { changes: $changes } = delta;
927
+ let ci = binarySearch($changes, at, latest);
928
+ if (ci < 0) {
929
+ ci = ~ci;
930
+ $changes.splice(ci, 0, {
931
+ kind: 3,
932
+ index: at,
933
+ oldItem: item
934
+ });
935
+ } else {
936
+ const current = $changes[ci];
937
+ switch (current.kind) {
938
+ case 1:
939
+ current.kind = 3;
940
+ current.newItem = void 0;
941
+ break;
942
+ case 2:
943
+ $changes.splice(ci--, 1);
944
+ break;
945
+ case 3:
946
+ $changes.splice(++ci, 0, {
947
+ kind: 3,
948
+ index: at,
949
+ oldItem: item
950
+ });
951
+ break;
952
+ }
953
+ }
954
+ const { length } = $changes;
955
+ while (++ci < length) $changes[ci].index -= 1;
956
+ delta.lengthChange -= 1;
957
+ }
958
+ /** @internal */
959
+ function listCleared(delta, count) {
960
+ const { changes: $changes } = delta;
961
+ $changes.length = 0;
962
+ $changes.push({
963
+ kind: 4,
964
+ index: -1
965
+ });
966
+ delta.lengthChange -= count;
967
+ }
968
+ /** @internal */
969
+ function listSynced(delta, oldState, newState, eq) {
970
+ let index = 0;
971
+ let N = oldState.length;
972
+ let M = newState.length;
973
+ while (index < N && index < M && eq(oldState[index], newState[index])) index += 1;
974
+ if (index === N && index === M) return;
975
+ while (N > index && M > index && eq(oldState[N - 1], newState[M - 1])) {
976
+ N -= 1;
977
+ M -= 1;
978
+ }
979
+ const Z = (Math.min(N, M) + 1) * 2;
980
+ const L = N + M;
981
+ const state = {
982
+ $eq: eq,
983
+ $list0: oldState,
984
+ $list1: newState,
985
+ $index0: index,
986
+ $index1: index,
987
+ $N: N,
988
+ $M: M,
989
+ $Z: Z,
990
+ $c: 0,
991
+ $buffer: new (L <= 255 ? Uint8Array : L <= 65535 ? Uint16Array : Uint32Array)(Z + Z),
992
+ $stack: [],
993
+ $stackTop: 0,
994
+ $pxs: -1,
995
+ $pxe: -1,
996
+ $pys: -1,
997
+ $pye: -1,
998
+ $oxs: -1,
999
+ $oxe: -1,
1000
+ $oys: -1,
1001
+ $oye: -1
1002
+ };
1003
+ let offset = 0;
1004
+ let rs, re, is, ie, r, i;
1005
+ do {
1006
+ myersDiff(state);
1007
+ if (state.$c === 1) {
1008
+ rs = state.$oxs;
1009
+ re = state.$oxe;
1010
+ is = state.$oys;
1011
+ ie = state.$oye;
1012
+ } else if (state.$pxs >= 0) {
1013
+ rs = state.$pxs;
1014
+ re = state.$pxe;
1015
+ is = state.$pys;
1016
+ ie = state.$pye;
1017
+ } else break;
1018
+ for (r = rs; r < re; r += 1) itemRemoved(delta, rs + offset, oldState[r]);
1019
+ for (i = is; i < ie; i += 1) {
1020
+ itemInserted(delta, rs + offset, newState[i]);
1021
+ offset += 1;
1022
+ }
1023
+ offset -= re - rs;
1024
+ } while (state.$c < 2);
1025
+ }
1026
+ const latest = (changes, index, mid, _min, max) => {
1027
+ let i = mid;
1028
+ while (++i < max && changes[i].index === index);
1029
+ return i - 1;
1030
+ };
1031
+ const earliest = (changes, index, mid, min, _max) => {
1032
+ let i = mid;
1033
+ while (--i >= min && changes[i].index === index);
1034
+ return i + 1;
1035
+ };
1036
+ function binarySearch(changes, index, bias) {
1037
+ let min = 0;
1038
+ let max = changes.length;
1039
+ let mid;
1040
+ let tmp;
1041
+ while (min < max) {
1042
+ mid = min + max >>> 1;
1043
+ tmp = changes[mid].index;
1044
+ if (index < tmp) max = mid;
1045
+ else if (index > tmp) min = mid + 1;
1046
+ else return bias(changes, index, mid, min, max);
1047
+ }
1048
+ return ~min;
1049
+ }
1050
+ function myersDiff(state) {
1051
+ const { $list0, $list1, $buffer, $stack, $eq } = state;
1052
+ let { $index0, $index1, $N, $M, $Z, $c, $stackTop } = state;
1053
+ let W, L, parity, offsetX, offsetY, z, h, hMax, k, kMin, kMax, gkm, gkp, u, v, x, y, pkm, pkp, sx;
1054
+ while (true) switch ($c) {
1055
+ case 0:
1056
+ Z_block: while ($N > 0 && $M > 0) {
1057
+ W = $N - $M;
1058
+ L = $N + $M;
1059
+ parity = L & 1;
1060
+ offsetX = $index0 + $N - 1;
1061
+ offsetY = $index1 + $M - 1;
1062
+ hMax = (L + parity) / 2;
1063
+ $buffer.fill(0, 0, $Z + $Z);
1064
+ h_loop: for (h = 0; h <= hMax; h += 1) {
1065
+ kMin = 2 * Math.max(0, h - $M) - h;
1066
+ kMax = h - 2 * Math.max(0, h - $N);
1067
+ for (k = kMin; k <= kMax; k += 2) {
1068
+ gkm = $buffer[k - 1 - $Z * Math.floor((k - 1) / $Z)];
1069
+ gkp = $buffer[k + 1 - $Z * Math.floor((k + 1) / $Z)];
1070
+ u = k === -h || k !== h && gkm < gkp ? gkp : gkm + 1;
1071
+ v = u - k;
1072
+ x = u;
1073
+ y = v;
1074
+ while (x < $N && y < $M && $eq($list0[$index0 + x], $list1[$index1 + y])) {
1075
+ x += 1;
1076
+ y += 1;
1077
+ }
1078
+ $buffer[k - $Z * Math.floor(k / $Z)] = x;
1079
+ if (parity === 1 && (z = W - k) >= 1 - h && z < h && x + $buffer[$Z + z - $Z * Math.floor(z / $Z)] >= $N) if (h > 1 || x !== u) {
1080
+ $stack[$stackTop++] = $index0 + x;
1081
+ $stack[$stackTop++] = $index1 + y;
1082
+ $stack[$stackTop++] = $N - x;
1083
+ $stack[$stackTop++] = $M - y;
1084
+ $N = u;
1085
+ $M = v;
1086
+ $Z = 2 * (Math.min($N, $M) + 1);
1087
+ continue Z_block;
1088
+ } else break h_loop;
1089
+ }
1090
+ for (k = kMin; k <= kMax; k += 2) {
1091
+ pkm = $buffer[$Z + k - 1 - $Z * Math.floor((k - 1) / $Z)];
1092
+ pkp = $buffer[$Z + k + 1 - $Z * Math.floor((k + 1) / $Z)];
1093
+ u = k === -h || k !== h && pkm < pkp ? pkp : pkm + 1;
1094
+ v = u - k;
1095
+ x = u;
1096
+ y = v;
1097
+ while (x < $N && y < $M && $eq($list0[offsetX - x], $list1[offsetY - y])) {
1098
+ x += 1;
1099
+ y += 1;
1100
+ }
1101
+ $buffer[$Z + k - $Z * Math.floor(k / $Z)] = x;
1102
+ if (parity === 0 && (z = W - k) >= -h && z <= h && x + $buffer[z - $Z * Math.floor(z / $Z)] >= $N) if (h > 0 || x !== u) {
1103
+ $stack[$stackTop++] = $index0 + $N - u;
1104
+ $stack[$stackTop++] = $index1 + $M - v;
1105
+ $stack[$stackTop++] = u;
1106
+ $stack[$stackTop++] = v;
1107
+ $N = $N - x;
1108
+ $M = $M - y;
1109
+ $Z = 2 * (Math.min($N, $M) + 1);
1110
+ continue Z_block;
1111
+ } else break h_loop;
1112
+ }
1113
+ }
1114
+ if ($N === $M) continue;
1115
+ if ($M > $N) {
1116
+ $index0 += $N;
1117
+ $index1 += $N;
1118
+ $M -= $N;
1119
+ $N = 0;
1120
+ } else {
1121
+ $index0 += $M;
1122
+ $index1 += $M;
1123
+ $N -= $M;
1124
+ $M = 0;
1125
+ }
1126
+ break;
1127
+ }
1128
+ if ($N + $M !== 0) if (state.$pxe === $index0 || state.$pye === $index1) {
1129
+ state.$pxe = $index0 + $N;
1130
+ state.$pye = $index1 + $M;
1131
+ } else {
1132
+ sx = state.$pxs;
1133
+ state.$oxs = state.$pxs;
1134
+ state.$oxe = state.$pxe;
1135
+ state.$oys = state.$pys;
1136
+ state.$oye = state.$pye;
1137
+ state.$pxs = $index0;
1138
+ state.$pxe = $index0 + $N;
1139
+ state.$pys = $index1;
1140
+ state.$pye = $index1 + $M;
1141
+ if (sx >= 0) {
1142
+ state.$index0 = $index0;
1143
+ state.$index1 = $index1;
1144
+ state.$N = $N;
1145
+ state.$M = $M;
1146
+ state.$Z = $Z;
1147
+ state.$stackTop = $stackTop;
1148
+ state.$c = 1;
1149
+ return;
1150
+ }
1151
+ }
1152
+ case 1:
1153
+ if ($stackTop === 0) {
1154
+ state.$c = 2;
1155
+ return;
1156
+ }
1157
+ $M = $stack[--$stackTop];
1158
+ $N = $stack[--$stackTop];
1159
+ $index1 = $stack[--$stackTop];
1160
+ $index0 = $stack[--$stackTop];
1161
+ $Z = 2 * (Math.min($N, $M) + 1);
1162
+ $c = 0;
1163
+ }
1164
+ }
1165
+
1166
+ //#endregion
1167
+ //#region src/data/ProxyAtom.ts
1168
+ /**
1169
+ * Creates a ProxyAtom bound to the provided initial value. If it is an Atom, the proxy will mirror
1170
+ * it, otherwise it will be a read-only atom with a static value until rebound.
1171
+ */
1172
+ function proxyOf(initialValue, lifecycle = getLifecycle()) {
1173
+ __DEV__assertNotEffect();
1174
+ const self = {
1175
+ [S_ATOM]: true,
1176
+ $lifecycle: lifecycle,
1177
+ use,
1178
+ get: getStaticValue
1179
+ };
1180
+ self.use(initialValue, false);
1181
+ return self;
1182
+ }
1183
+ function use(value, canNotify = true) {
1184
+ if (this.$dep) unlink(this.$dep);
1185
+ const oldValue = this.get();
1186
+ if (isAtom(value)) {
1187
+ this.$bound = value;
1188
+ this.$value = null;
1189
+ this.get = getBoundValue;
1190
+ this.set = setBoundValue;
1191
+ link(this.$lifecycle, value, this.$dep ??= {
1192
+ $fn: notify$1,
1193
+ $a0: this
1194
+ });
1195
+ } else {
1196
+ this.$bound = null;
1197
+ this.$value = value;
1198
+ this.get = getStaticValue;
1199
+ this.set = setStaticValue;
1200
+ }
1201
+ if (canNotify && !Object.is(oldValue, this.get())) scheduleTick(this.$lifecycle, this.$notify ??= {
1202
+ $fn: notify$1,
1203
+ $a0: this
1204
+ });
1205
+ }
1206
+ function getBoundValue() {
1207
+ return this.$bound.get();
1208
+ }
1209
+ function setBoundValue(value) {
1210
+ const atom = this.$bound;
1211
+ if (atom.set(value)) scheduleTick(atom.$lifecycle, atom.$notify ??= {
1212
+ $fn: notify$1,
1213
+ $a0: atom
1214
+ });
1215
+ return false;
1216
+ }
1217
+ function getStaticValue() {
1218
+ return this.$value;
1219
+ }
1220
+ function setStaticValue() {
1221
+ return false;
1222
+ }
1223
+ const EMPTY_SOURCE = {};
1224
+ /**
1225
+ * Copies select keys from a data object into a new object where values are all wrapped in
1226
+ * ProxyAtoms and can be updated later.
1227
+ * @see {@link updateProxy}
1228
+ * @internal
1229
+ **/
1230
+ function createProxy(lifecycle, data, keys) {
1231
+ const source = isObject(data) ? data : EMPTY_SOURCE;
1232
+ const proxy = {};
1233
+ const { length } = keys;
1234
+ let index = 0;
1235
+ let key;
1236
+ for (; index < length; index += 1) {
1237
+ key = keys[index];
1238
+ proxy[key] = proxyOf(source[key], lifecycle);
1239
+ }
1240
+ proxy.proxied = data;
1241
+ return proxy;
1242
+ }
1243
+ /**
1244
+ * Updates the values proxied by a previously created proxy object. The keys array must be the same
1245
+ * as was used during creation (or a subset).
1246
+ * @see {@link createProxy}
1247
+ * @internal
1248
+ **/
1249
+ function updateProxy(proxy, data, keys) {
1250
+ const source = isObject(data) ? data : EMPTY_SOURCE;
1251
+ const { length } = keys;
1252
+ proxy.proxied = data;
1253
+ let index = 0;
1254
+ let key;
1255
+ for (; index < length; index += 1) {
1256
+ key = keys[index];
1257
+ proxy[key].use(source[key]);
1258
+ }
1259
+ }
1260
+ function isObject(value) {
1261
+ return value !== null && typeof value === "object";
1262
+ }
1263
+
1264
+ //#endregion
1265
+ //#region src/component/Iterator.ts
1266
+ function Iterator(jsx, hParent, nUsedParent, nRealParent, nBefore, isBatch) {
1267
+ const source = jsx.source;
1268
+ const proxyKeys = jsx.proxy;
1269
+ const isProxy = proxyKeys !== void 0;
1270
+ const template = jsx.children[0];
1271
+ const hGroup = fork(hParent);
1272
+ const { adapter } = hGroup;
1273
+ const shouldBatch = Boolean(adapter.batch);
1274
+ const nListEndMarker = adapter.marker("/Iterator");
1275
+ let items;
1276
+ let skipDelta = Boolean(source.$delta);
1277
+ const onDelta = () => {
1278
+ if (skipDelta) {
1279
+ skipDelta = false;
1280
+ return;
1281
+ }
1282
+ const { changes, lengthChange } = source.$delta;
1283
+ const cMax = changes.length;
1284
+ const iMax = items.length + lengthChange;
1285
+ const newItems = new Array(iMax);
1286
+ const pending = [];
1287
+ let recycled = [];
1288
+ let item;
1289
+ let inserted = 0;
1290
+ let ci = 0;
1291
+ let oi = 0;
1292
+ let ni = 0;
1293
+ let change;
1294
+ let ref;
1295
+ let tmp;
1296
+ let isLocalBatch = false;
1297
+ let nBatchParent = nRealParent;
1298
+ let nBatchBefore = null;
1299
+ for (; ci < cMax; ci += 1) {
1300
+ change = changes[ci];
1301
+ while (ni < change.index) newItems[ni++] = items[oi++];
1302
+ switch (change.kind) {
1303
+ case 1:
1304
+ item = newItems[ni++] = items[oi++];
1305
+ if (isProxy) updateProxy(item.$data, change.newItem, proxyKeys);
1306
+ else {
1307
+ unmount(item);
1308
+ ref = items[oi]?.$marker ?? nListEndMarker;
1309
+ insert(item.$marker, null, item, nRealParent, ref, false);
1310
+ mount(withLifecycle(item, template, item.$data = change.newItem), item, nRealParent, nRealParent, ref, false);
1311
+ }
1312
+ break;
1313
+ case 2:
1314
+ if (!isProxy || inserted < lengthChange) {
1315
+ item = newItems[ni++] = fork(hGroup, items[oi]);
1316
+ item.$marker = adapter.marker("IteratorItem");
1317
+ item.$data = isProxy ? createProxy(item, change.newItem, proxyKeys) : change.newItem;
1318
+ inserted += 1;
1319
+ ref = items[oi]?.$marker ?? nListEndMarker;
1320
+ if (!isLocalBatch) if (shouldBatch) {
1321
+ isLocalBatch = true;
1322
+ nBatchParent = adapter.batch();
1323
+ nBatchBefore = null;
1324
+ } else nBatchBefore = ref;
1325
+ insert(item.$marker, null, item, nBatchParent, nBatchBefore, isLocalBatch);
1326
+ mount(withLifecycle(item, template, item.$data), item, nBatchParent, nRealParent, nBatchBefore, isLocalBatch);
1327
+ if (isLocalBatch && (inserted >= lengthChange || !(tmp = changes[ci + 1]) || tmp.kind !== 2 || tmp.index !== ni)) {
1328
+ adapter.insert(nBatchParent, nRealParent, ref);
1329
+ nBatchParent = nRealParent;
1330
+ isLocalBatch = false;
1331
+ }
1332
+ } else pending.push({
1333
+ $index: ni++,
1334
+ $item: change.newItem
1335
+ });
1336
+ break;
1337
+ case 3:
1338
+ item = items[oi++];
1339
+ if (isProxy) recycled.push(item);
1340
+ else unmount(item);
1341
+ untrack(item);
1342
+ break;
1343
+ case 4:
1344
+ if (isProxy) {
1345
+ recycled = items;
1346
+ recycled.forEach(untrack);
1347
+ oi = items.length;
1348
+ } else while (oi < items.length) {
1349
+ item = items[oi++];
1350
+ unmount(item);
1351
+ untrack(item);
1352
+ }
1353
+ break;
1354
+ }
1355
+ }
1356
+ while (ni < iMax) newItems[ni++] = items[oi++];
1357
+ let pi = pending.length - 1;
1358
+ let ri = recycled.length - 1;
1359
+ while (pi >= 0) {
1360
+ tmp = pending[pi--];
1361
+ item = newItems[tmp.$index] = recycled[ri--];
1362
+ updateProxy(item.$data, tmp.$item, proxyKeys);
1363
+ track(item, hGroup, ref = newItems[tmp.$index + 1]);
1364
+ mount(withLifecycle(item, template, item.$data), item, nRealParent, nRealParent, ref?.$marker ?? nListEndMarker, false);
1365
+ }
1366
+ while (ri >= 0) {
1367
+ item = recycled[ri--];
1368
+ unmount(item);
1369
+ untrack(item);
1370
+ }
1371
+ items = newItems;
1372
+ };
1373
+ link(hGroup, source, { $fn: onDelta });
1374
+ {
1375
+ let nBatchParent = nUsedParent;
1376
+ let nBatchBefore = nBefore;
1377
+ const isLocalBatch = shouldBatch && !isBatch && source.$items.length > 0;
1378
+ if (isLocalBatch) {
1379
+ nBatchParent = adapter.batch();
1380
+ nBatchBefore = null;
1381
+ }
1382
+ const isAnyBatch = isLocalBatch || isBatch;
1383
+ items = source.$items.map((data) => {
1384
+ const item = fork(hGroup);
1385
+ item.$marker = adapter.marker("IteratorItem");
1386
+ item.$data = isProxy ? createProxy(item, data, proxyKeys) : data;
1387
+ insert(item.$marker, null, item, nBatchParent, nBatchBefore, isAnyBatch);
1388
+ mount(withLifecycle(item, template, item.$data), item, nBatchParent, nRealParent, nBatchBefore, isAnyBatch);
1389
+ return item;
1390
+ });
1391
+ insert(nListEndMarker, null, hGroup, nBatchParent, nBatchBefore, isAnyBatch);
1392
+ if (isLocalBatch) adapter.insert(nBatchParent, nUsedParent, nBefore);
1393
+ }
1394
+ mount(null, hGroup, nUsedParent, nRealParent, nBefore, isBatch);
1395
+ }
1396
+
1397
+ //#endregion
1398
+ //#region src/component/Native.ts
1399
+ const RE_EXT = /^([^:]+?):(.+)$/;
1400
+ /** @internal */
1401
+ const S_TAG_NAME = Symbol.for("pyxis:tagName");
1402
+ function Native(jsx, hParent, nUsedParent, _nRealParent, nBefore, isBatch) {
1403
+ const hGroup = hParent.$ng;
1404
+ const { adapter, $extensions } = hGroup;
1405
+ const nNode = adapter.element(jsx[S_TAG_NAME]);
1406
+ let name;
1407
+ let match;
1408
+ let value;
1409
+ for (name in jsx) {
1410
+ match = RE_EXT.exec(name);
1411
+ value = jsx[name];
1412
+ if (match) $extensions[match[1]]?.set(nNode, match[2], value, hGroup);
1413
+ else if (name !== "children") if (isAtom(value)) {
1414
+ const prop = name;
1415
+ const atom = value;
1416
+ bind(hGroup, atom, () => {
1417
+ adapter.set(nNode, prop, atom.get());
1418
+ });
1419
+ } else adapter.set(nNode, name, value);
1420
+ }
1421
+ insert(nNode, jsx.children, hParent, nUsedParent, nBefore, isBatch);
1422
+ }
1423
+
1424
+ //#endregion
1425
+ //#region src/component/Show.ts
1426
+ function Show(jsx, hParent, nUsedParent, nRealParent, nBefore, isBatch) {
1427
+ const when = jsx.when;
1428
+ if (!isAtom(when) && when === false) return;
1429
+ const { children, data } = jsx;
1430
+ const proxyKeys = jsx.proxy;
1431
+ const template = Object.hasOwn(jsx, "data") ? children[0] : () => children;
1432
+ let dataOrProxy = data;
1433
+ if (proxyKeys) if (isAtom(data)) {
1434
+ dataOrProxy = createProxy(hParent.$ng, data.get(), proxyKeys);
1435
+ link(hParent.$ng, data, { $fn: () => {
1436
+ updateProxy(dataOrProxy, data.get(), proxyKeys);
1437
+ } });
1438
+ } else dataOrProxy = createProxy(hParent.$ng, data, proxyKeys);
1439
+ const adapter = hParent.$ng.adapter;
1440
+ const shouldBatch = Boolean(adapter.batch);
1441
+ if (!(isAtom(when) || isAtom(template) || !proxyKeys && isAtom(data))) {
1442
+ const isLocalBatch = shouldBatch && !isBatch;
1443
+ let nBatchParent = nUsedParent;
1444
+ let nBatchBefore = nBefore;
1445
+ if (isLocalBatch) {
1446
+ nBatchParent = adapter.batch();
1447
+ nBatchBefore = null;
1448
+ }
1449
+ mountJsx(template(dataOrProxy), hParent, nBatchParent, nRealParent, nBatchBefore, isLocalBatch || isBatch);
1450
+ if (isLocalBatch) adapter.insert(nBatchParent, nUsedParent, nBefore);
1451
+ return;
1452
+ }
1453
+ const hGroup = fork(hParent);
1454
+ let nMarker = nBefore;
1455
+ effect(() => {
1456
+ if (read(when) === false) return;
1457
+ const isLocalBatch = shouldBatch && !isBatch;
1458
+ let nBatchParent = nUsedParent;
1459
+ let nBatchBefore = nMarker;
1460
+ if (isLocalBatch) {
1461
+ nBatchParent = adapter.batch();
1462
+ nBatchBefore = null;
1463
+ }
1464
+ mount(withLifecycle(hGroup, read(template), read(dataOrProxy)), hGroup, nBatchParent, nRealParent, nBatchBefore, isLocalBatch || isBatch);
1465
+ if (isLocalBatch) adapter.insert(nBatchParent, nUsedParent, nMarker);
1466
+ return () => unmount(hGroup);
1467
+ }, hParent.$ng);
1468
+ nMarker = adapter.marker("/Show");
1469
+ insert(nMarker, null, hParent, nUsedParent, nBefore, isBatch);
1470
+ isBatch = false;
1471
+ nUsedParent = nRealParent;
1472
+ }
1473
+
1474
+ //#endregion
1475
+ //#region src/data/Derivation.ts
1476
+ /**
1477
+ * Creates a Derivation - an Atom with its value computed from other Atoms. The block runs once
1478
+ * eagerly to compute the initial value, then re-runs within scheduler ticks whenever its source
1479
+ * Atoms change. Observers are only notified if the new value differs from the previous.
1480
+ */
1481
+ function derived(block, lifecycle = getLifecycle()) {
1482
+ __DEV__assertNotEffect();
1483
+ const atom = {
1484
+ [S_ATOM]: true,
1485
+ $dirty: false,
1486
+ $value: null,
1487
+ $tracksValue: true,
1488
+ $lifecycle: lifecycle,
1489
+ $life: lifecycle.$life,
1490
+ $lastValue: null,
1491
+ $cycle: 0,
1492
+ $block: block,
1493
+ $react: scheduleNotify,
1494
+ get: getValue,
1495
+ set: setValue
1496
+ };
1497
+ const value = resolve(atom);
1498
+ atom.$value = value;
1499
+ atom.$lastValue = value;
1500
+ return atom;
1501
+ }
1502
+ function scheduleNotify(derivation, cycle) {
1503
+ if (derivation.$life !== derivation.$lifecycle.$life || derivation.$cycle > cycle) {
1504
+ unlink(this);
1505
+ return;
1506
+ }
1507
+ derivation.$dirty = true;
1508
+ scheduleTick(derivation.$lifecycle, derivation.$notify ??= {
1509
+ $fn: notify$1,
1510
+ $a0: derivation
1511
+ });
1512
+ }
1513
+ function getValue() {
1514
+ if (this.$dirty && this.$life === this.$lifecycle.$life) {
1515
+ this.$value = resolve(this);
1516
+ this.$dirty = false;
1517
+ }
1518
+ return this.$value;
1519
+ }
1520
+ function setValue() {
1521
+ return false;
1522
+ }
1523
+
1524
+ //#endregion
1525
+ //#region src/data/List.ts
1526
+ function listOf(source, lifecycle = getLifecycle()) {
1527
+ {
1528
+ __DEV__assertNotEffect();
1529
+ const devId = arguments[2];
1530
+ globalThis.__PYXIS_HMR__.state.restore(lifecycle, devId, (value) => {
1531
+ if (Array.isArray(value)) source = value;
1532
+ });
1533
+ }
1534
+ const list = {
1535
+ $lifecycle: lifecycle,
1536
+ $items: source ? Array.from(source) : [],
1537
+ $delta: null,
1538
+ [Symbol.iterator]: getIterator,
1539
+ size,
1540
+ get,
1541
+ delta,
1542
+ raw,
1543
+ forEach,
1544
+ set,
1545
+ clear,
1546
+ insertAt,
1547
+ insertFirst,
1548
+ insertLast,
1549
+ remove,
1550
+ removeAt,
1551
+ removeFirst,
1552
+ removeLast
1553
+ };
1554
+ list.$devId = arguments[2];
1555
+ return list;
1556
+ }
1557
+ /**
1558
+ * Synchronizes the provided List with the given data source. After this operation, the list will
1559
+ * contain an exact copy of the source.
1560
+ *
1561
+ * Note: This function is separated instead of being a List method since the underlying diff
1562
+ * algorithm (Myers) is a relatively large chunk of code which would otherwise always get included
1563
+ * into bundled builds. This way, tools like Terser can eliminate the extra code when unused.
1564
+ */
1565
+ function sync(list, source, eq = defaultEquals) {
1566
+ const oldState = list.$items;
1567
+ list.$items = source.slice();
1568
+ listSynced(list.$delta ??= createDelta(), oldState, source, eq);
1569
+ listMutated(list);
1570
+ }
1571
+ function size() {
1572
+ reportAccess(this);
1573
+ return this.$items.length;
1574
+ }
1575
+ function get(index) {
1576
+ reportAccess(this);
1577
+ return this.$items[index];
1578
+ }
1579
+ function delta() {
1580
+ reportAccess(this);
1581
+ return this.$delta;
1582
+ }
1583
+ function raw() {
1584
+ reportAccess(this);
1585
+ return this.$items;
1586
+ }
1587
+ function forEach(callback, thisArg) {
1588
+ reportAccess(this);
1589
+ this.$items.forEach(callback, thisArg);
1590
+ }
1591
+ function getIterator() {
1592
+ reportAccess(this);
1593
+ return this.$items[Symbol.iterator]();
1594
+ }
1595
+ function set(index, newItem) {
1596
+ assertIndex(this, index);
1597
+ const oldItem = this.$items[index];
1598
+ if (Object.is(newItem, oldItem)) return;
1599
+ this.$items[index] = newItem;
1600
+ if (this.$dh) {
1601
+ itemChanged(this.$delta ??= createDelta(), index, oldItem, newItem);
1602
+ listMutated(this);
1603
+ }
1604
+ }
1605
+ function clear() {
1606
+ const count = this.$items.length;
1607
+ this.$items.length = 0;
1608
+ if (this.$dh) {
1609
+ listCleared(this.$delta ??= createDelta(), count);
1610
+ listMutated(this);
1611
+ }
1612
+ }
1613
+ function insertAt(index, item) {
1614
+ const { $items } = this;
1615
+ if (index === $items.length) $items.push(item);
1616
+ else {
1617
+ assertIndex(this, index);
1618
+ this.$items.splice(index, 0, item);
1619
+ }
1620
+ if (this.$dh) {
1621
+ itemInserted(this.$delta ??= createDelta(), index, item);
1622
+ listMutated(this);
1623
+ }
1624
+ }
1625
+ function insertFirst(item) {
1626
+ this.insertAt(0, item);
1627
+ }
1628
+ function insertLast(item) {
1629
+ this.insertAt(this.$items.length, item);
1630
+ }
1631
+ function remove(item) {
1632
+ const index = this.$items.indexOf(item);
1633
+ if (index === -1) return false;
1634
+ this.removeAt(index);
1635
+ return true;
1636
+ }
1637
+ function removeAt(index) {
1638
+ assertIndex(this, index);
1639
+ const item = this.$items.splice(index, 1)[0];
1640
+ if (this.$dh) {
1641
+ itemRemoved(this.$delta ??= createDelta(), index, item);
1642
+ listMutated(this);
1643
+ }
1644
+ return item;
1645
+ }
1646
+ function removeFirst() {
1647
+ return this.$items.length > 0 ? this.removeAt(0) : void 0;
1648
+ }
1649
+ function removeLast() {
1650
+ const { length } = this.$items;
1651
+ return length > 0 ? this.removeAt(length - 1) : void 0;
1652
+ }
1653
+ function assertIndex(list, index) {
1654
+ if (index >= list.$items.length || index < 0) throw new RangeError("list index out of bounds");
1655
+ }
1656
+ function defaultEquals(item0, item1) {
1657
+ return Object.is(item0, item1);
1658
+ }
1659
+ function listMutated(list) {
1660
+ globalThis.__PYXIS_HMR__.state.preserve(list.$lifecycle, list.$devId, list.$items);
1661
+ scheduleTick(list.$lifecycle, list.$notify ??= {
1662
+ $fn: notify,
1663
+ $a0: list
1664
+ });
1665
+ scheduleTock(list.$lifecycle, list.$cleanup ??= {
1666
+ $fn: cleanup,
1667
+ $a0: list
1668
+ });
1669
+ }
1670
+ function notify(list) {
1671
+ let current = list.$dh;
1672
+ let next;
1673
+ while (current) {
1674
+ next = current.$an;
1675
+ invoke(current);
1676
+ current = next;
1677
+ }
1678
+ }
1679
+ function cleanup(list) {
1680
+ list.$delta = null;
1681
+ }
1682
+
1683
+ //#endregion
1684
+ //#region src/extension/RefExtension.ts
1685
+ /**
1686
+ * Extension adding direct reference access to any element. Recommended prefix:
1687
+ * `"ref"`
1688
+ *
1689
+ * References can be stored into atoms:
1690
+ * ```tsx
1691
+ * const wrapperRef = atomOf<HTMLDivElement>();
1692
+ * <div ref:atom={wrapperRef} />
1693
+ * ```
1694
+ * or handled with a custom callback:
1695
+ * ```tsx
1696
+ * const onWrapperRef = (node: HTMLDivElement) => { ... };
1697
+ * <div ref:call={onWrapperRef} />
1698
+ * ```
1699
+ */
1700
+ const RefExtension = { set: (node, kind, value) => {
1701
+ let method;
1702
+ switch (kind) {
1703
+ case "atom":
1704
+ if (!isAtom(value)) return;
1705
+ method = refAtom;
1706
+ break;
1707
+ case "call":
1708
+ if (typeof value !== "function") return;
1709
+ method = refCall;
1710
+ break;
1711
+ default: return;
1712
+ }
1713
+ const lifecycle = getLifecycle();
1714
+ onMounted(lifecycle, {
1715
+ $fn: method,
1716
+ $a0: value,
1717
+ $a1: node
1718
+ });
1719
+ onUnmounted(lifecycle, {
1720
+ $fn: method,
1721
+ $a0: value,
1722
+ $a1: null
1723
+ });
1724
+ } };
1725
+ function refAtom(atom, node) {
1726
+ atom.set(node);
1727
+ }
1728
+ function refCall(setter, node) {
1729
+ setter(node);
1730
+ }
1731
+
1732
+ //#endregion
1733
+ //#region src/support/text.ts
1734
+ function tag(access, strings, values) {
1735
+ const { length } = values;
1736
+ let index = 0;
1737
+ let text = strings[0];
1738
+ while (index < length) text += access(values[index]) + strings[++index];
1739
+ return text;
1740
+ }
1741
+ /**
1742
+ * A template literal tag that automatically wraps each substitution in a `read` call.
1743
+ * @see {@link read}
1744
+ */
1745
+ function reads(strings, ...values) {
1746
+ return tag(read, strings, values);
1747
+ }
1748
+ /**
1749
+ * A template literal tag that automatically wraps each substitution in a `peek` call.
1750
+ * @see {@link peek}
1751
+ */
1752
+ function peeks(strings, ...values) {
1753
+ return tag(peek, strings, values);
1754
+ }
1755
+
1756
+ //#endregion
1757
+ //#region src/Builder.ts
1758
+ function pyxis(adapter) {
1759
+ const extensions = {};
1760
+ const builder = {
1761
+ build: () => createRenderer(adapter, extensions),
1762
+ extend: (extensionKey, extension) => {
1763
+ extensions[extensionKey] = extension;
1764
+ return builder;
1765
+ }
1766
+ };
1767
+ return builder;
1768
+ }
1769
+
1770
+ //#endregion
1771
+ //#region src/Component.ts
1772
+ function component(block) {
1773
+ let devId;
1774
+ devId = arguments[1];
1775
+ devId && globalThis.__PYXIS_HMR__.component.upsert(devId, block);
1776
+ return (jsx, hParent, nUsedParent, nRealParent, nBefore, isBatch) => {
1777
+ const context = getContextContainer();
1778
+ try {
1779
+ {
1780
+ if (!import.meta.hot || !devId) {
1781
+ setContextContainer(context);
1782
+ mountJsx(block(jsx), hParent, nUsedParent, nRealParent, nBefore, isBatch);
1783
+ return;
1784
+ }
1785
+ const hGroup = fork(hParent);
1786
+ const nMarker = hGroup.adapter.marker(`/${devId}`);
1787
+ insert(nMarker, null, hParent, nUsedParent, nBefore, isBatch);
1788
+ unmounted(globalThis.__PYXIS_HMR__.component.subscribe(devId, (impl) => {
1789
+ unmount(hGroup);
1790
+ mount({
1791
+ ...jsx,
1792
+ [S_COMPONENT]: (() => mountJsx(impl(jsx), hGroup, nUsedParent, nRealParent, nMarker, isBatch))
1793
+ }, hGroup, nUsedParent, nRealParent, nMarker, isBatch);
1794
+ }));
1795
+ nUsedParent = nRealParent;
1796
+ isBatch = false;
1797
+ }
1798
+ } finally {
1799
+ setContextContainer(context);
1800
+ }
1801
+ };
1802
+ }
1803
+
1804
+ //#endregion
1805
+ //#region src/jsx.ts
1806
+ const EMPTY_ARRAY = Object.freeze([]);
1807
+ function jsx(componentOrTagName, props, key) {
1808
+ const { children } = props;
1809
+ props.children = children === void 0 ? EMPTY_ARRAY : Array.isArray(children) ? children : [children];
1810
+ props.key ??= key;
1811
+ if (typeof componentOrTagName === "string") {
1812
+ props[S_COMPONENT] = Native;
1813
+ props[S_TAG_NAME] = componentOrTagName;
1814
+ } else props[S_COMPONENT] = componentOrTagName;
1815
+ return props;
1816
+ }
1817
+ function jsxs(componentOrTagName, props, key) {
1818
+ props.key ??= key;
1819
+ if (typeof componentOrTagName === "string") {
1820
+ props[S_COMPONENT] = Native;
1821
+ props[S_TAG_NAME] = componentOrTagName;
1822
+ } else props[S_COMPONENT] = componentOrTagName;
1823
+ return props;
1824
+ }
1825
+
1826
+ //#endregion
1827
+ export { ChangeKind, Fragment, Iterator, Native, RefExtension, Show, atomOf, bind, component, consumerOf, createContext, derived, effect, fork, getLifecycle, host, insert, isAtom, jsx, jsxs, listOf, mount, mountJsx, mounted, peek, peeks, proxyOf, pyxis, read, reads, sync, tick, tock, track, unmount, unmounted, untrack, update, withLifecycle, write };
1828
+ //# sourceMappingURL=core-dev.js.map