@expressive/dom 0.3.0 → 0.4.0

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.js CHANGED
@@ -1,11 +1,11 @@
1
- import { a as untrack, c as dispose, d as claim$1, f as release, h as transition, i as track, l as enter, m as settle$1, n as latest, o as call, p as schedule, r as same, s as commit, u as afterFlush } from "./chunk-hot-BAqPvKEQ.js";
2
- import { a as createElement, i as childrenOf, n as PORTAL, o as isVNode, r as Portal, s as vnode, t as Fragment } from "./chunk-vnode-BG1Cv8F9.js";
1
+ import { a as untrack, c as dispose, d as claim$1, f as release, h as transition, i as track, l as enter, m as settle$1, n as latest, o as call, p as schedule, r as same, s as commit, u as afterFlush } from "./chunk-hot-9LhRiwFx.js";
2
+ import { a as createElement, i as childrenOf, n as PORTAL, o as isVNode, r as Portal, s as vnode, t as Fragment } from "./chunk-vnode-wpCWQ_Zg.js";
3
3
  import "./jsx-runtime.js";
4
- import { Component, Context, State, has, map } from "@expressive/mvc";
4
+ import { Component, Context, Model, has, map, unbind } from "@expressive/mvc";
5
5
  import { watch } from "@expressive/mvc/observable";
6
- import { Fragment as Fragment$1, compose } from "@expressive/mvc/jsx-runtime";
6
+ import { Fragment as Fragment$1 } from "@expressive/mvc/jsx-runtime";
7
7
 
8
- //#region src/css.ts
8
+ //#region src/style/css.ts
9
9
  const unitless = /* @__PURE__ */ new Map();
10
10
  let probe;
11
11
  /**
@@ -58,7 +58,7 @@ const css = {
58
58
  };
59
59
 
60
60
  //#endregion
61
- //#region src/appearance-protocol.ts
61
+ //#region src/style/protocol.ts
62
62
  const registrations = /* @__PURE__ */ new WeakMap();
63
63
  const tokens = /* @__PURE__ */ new WeakMap();
64
64
  let root;
@@ -105,7 +105,7 @@ function appearanceToken(value) {
105
105
  }
106
106
 
107
107
  //#endregion
108
- //#region src/appearance.ts
108
+ //#region src/style/appearance.ts
109
109
  const bases = /* @__PURE__ */ new WeakMap();
110
110
  const chains = /* @__PURE__ */ new WeakMap();
111
111
  const contexts = /* @__PURE__ */ new WeakMap();
@@ -332,7 +332,7 @@ function isObject(value) {
332
332
  }
333
333
 
334
334
  //#endregion
335
- //#region src/declarations.ts
335
+ //#region src/style/declarations.ts
336
336
  function applyDeclarations(style, declarations, previous = {}) {
337
337
  const target = style;
338
338
  for (const key of Object.keys({
@@ -351,7 +351,7 @@ function applyDeclarations(style, declarations, previous = {}) {
351
351
  }
352
352
 
353
353
  //#endregion
354
- //#region src/stylesheet.ts
354
+ //#region src/style/stylesheet.ts
355
355
  const sheets = /* @__PURE__ */ new WeakMap();
356
356
  function style(type, rules) {
357
357
  style$1(type, rules);
@@ -403,31 +403,7 @@ function serialize(document, declarations) {
403
403
  }
404
404
 
405
405
  //#endregion
406
- //#region src/loader.ts
407
- const LOADS = /* @__PURE__ */ new WeakMap();
408
- function resolve(type, props, run) {
409
- const load = LOADS.get(type);
410
- if (load?.resolved) return vnode(load.resolved, props);
411
- if (load?.failed) {
412
- LOADS.delete(type);
413
- throw load.failed.error;
414
- }
415
- if (load) throw load.pending;
416
- const output = run();
417
- if (!output || typeof output.then != "function") return output;
418
- const next = {};
419
- LOADS.set(type, next);
420
- throw next.pending = output.then((module) => {
421
- const component = typeof module == "function" ? module : module?.default;
422
- if (typeof component == "function") next.resolved = component;
423
- else next.failed = { error: /* @__PURE__ */ new Error("Loader resolved no component.") };
424
- }, (error) => {
425
- next.failed = { error };
426
- });
427
- }
428
-
429
- //#endregion
430
- //#region src/commits.ts
406
+ //#region src/render/commits.ts
431
407
  const DETACHED = /* @__PURE__ */ new WeakMap();
432
408
  let batch;
433
409
  /** Run `run` once `fiber` is on the page: now, after the current batch, or when its detached root attaches. */
@@ -468,63 +444,7 @@ function deliver(entry) {
468
444
  }
469
445
 
470
446
  //#endregion
471
- //#region src/render.ts
472
- const roots = /* @__PURE__ */ new WeakMap();
473
- const SVG = "http://www.w3.org/2000/svg";
474
- const dirty = /* @__PURE__ */ new Set();
475
- const stashes = /* @__PURE__ */ new WeakMap();
476
- const CONTROLS = ["checked", "value"];
477
- const ENUMERATED = [
478
- "contentEditable",
479
- "contenteditable",
480
- "draggable",
481
- "spellcheck"
482
- ];
483
- const ALIASES = {
484
- autoFocus: "autofocus",
485
- contentEditable: "contenteditable",
486
- htmlFor: "for"
487
- };
488
- const focusing = [];
489
- const controlled = /* @__PURE__ */ new WeakMap();
490
- const restoring = /* @__PURE__ */ new WeakSet();
491
- let passiveRender = false;
492
- let holding;
493
- let depth = 0;
494
- let settling = false;
495
- let rendering;
496
- let touched = false;
497
- const observed = /* @__PURE__ */ new WeakMap();
498
- const tickets = /* @__PURE__ */ new WeakMap();
499
- function render(node, container) {
500
- roots.get(container)?.();
501
- container.replaceChildren();
502
- const context = new Context(Context.root);
503
- const fiber = range("fragment", container, null, context);
504
- try {
505
- pass(() => {
506
- const appearanceContext = appearanceRoot();
507
- reconcile(fiber, node, context, void 0, appearanceContext ? {
508
- context: appearanceContext,
509
- entries: []
510
- } : void 0);
511
- });
512
- } catch (error) {
513
- unmountFiber(fiber);
514
- context.pop();
515
- throw error;
516
- }
517
- let active = true;
518
- const unmount = () => {
519
- if (!active) return;
520
- active = false;
521
- unmountFiber(fiber);
522
- context.pop();
523
- roots.delete(container);
524
- };
525
- roots.set(container, unmount);
526
- return unmount;
527
- }
447
+ //#region src/render/fiber.ts
528
448
  function range(kind, parent, before, context) {
529
449
  const start = document.createComment(kind);
530
450
  const end = document.createComment(`/${kind}`);
@@ -550,170 +470,37 @@ function makeScope(kind, context, update) {
550
470
  uses: []
551
471
  };
552
472
  }
553
- function park(fiber) {
554
- move(fiber, fragment(), null);
555
- }
556
- function complete(fiber, work) {
557
- try {
558
- work();
559
- } catch (error) {
560
- if (holding && error === holding.thrown) {
561
- park(fiber);
562
- holding.fiber = fiber;
563
- } else unmountFiber(fiber);
564
- throw error;
473
+ function moveRange(start, end, target) {
474
+ let node = start;
475
+ while (node) {
476
+ const next = node.nextSibling;
477
+ target.appendChild(node);
478
+ if (node === end) break;
479
+ node = next;
565
480
  }
566
- return fiber;
567
- }
568
- function componentProps(type, props, appearance) {
569
- const context = appearance?.context;
570
- if (!context || typeof type != "function") return {
571
- appearance,
572
- props
573
- };
574
- const value = context.resolve(props);
575
- const entries = appearance.entries;
576
- if (!value) return {
577
- appearance: { entries },
578
- props
579
- };
580
- return {
581
- appearance: {
582
- context: value.context,
583
- entries
584
- },
585
- props: {
586
- ...props,
587
- style: [createAppearanceToken(value), props.style]
588
- }
589
- };
590
481
  }
591
- function mount(value, parent, before, context, boundary, appearance) {
592
- if (typeof value == "string" || typeof value == "number" || typeof value == "bigint") {
593
- const text = document.createTextNode(String(value));
594
- parent.insertBefore(text, before);
595
- return {
596
- kind: "text",
597
- value,
598
- context,
599
- start: text,
600
- end: text,
601
- children: []
602
- };
482
+ function move(fiber, parent, before) {
483
+ if (fiber.start.parentNode === parent && fiber.end.nextSibling === before) return;
484
+ let node = fiber.start;
485
+ while (node) {
486
+ const next = node.nextSibling;
487
+ parent.insertBefore(node, before);
488
+ if (node === fiber.end) break;
489
+ node = next;
603
490
  }
604
- if (renderable(value)) return mountComponent(value, parent, before, context, boundary, appearance);
605
- if (isCollection(value)) return mountCollection(value, parent, before, context, boundary, appearance);
606
- if (!isVNode(value)) throw new TypeError(`Cannot render ${String(value)}.`);
607
- if (value.type === Fragment$1) return mountFragment(value, parent, before, context, boundary, appearance);
608
- if (value.type === PORTAL) return mountPortal(value, parent, before, context, boundary, appearance);
609
- if (typeof value.type == "string") return mountElement(value, parent, before, context, boundary, appearance);
610
- if (typeof value.type != "function") throw new Error(`Cannot render ${String(value.type)}.`);
611
- if (value.type.prototype instanceof State) return mountOwnedComponent(value, parent, before, context, boundary, appearance);
612
- return mountFunction(value, parent, before, context, boundary, appearance);
613
- }
614
- function mountFragment(value, parent, before, context, boundary, appearance) {
615
- const fiber = range("fragment", parent, before, context);
616
- fiber.key = value.key;
617
- fiber.type = Fragment$1;
618
- fiber.appearance = appearance;
619
- return complete(fiber, () => {
620
- reconcile(fiber, value.props.children, context, boundary, appearance);
621
- });
622
- }
623
- function mountFunction(value, parent, before, context, boundary, appearance) {
624
- const fiber = range("function", parent, before, context);
625
- const resolved = componentProps(value.type, value.props, appearance);
626
- fiber.key = value.key;
627
- fiber.type = value.type;
628
- fiber.props = observe(resolved.props);
629
- fiber.boundary = boundary;
630
- fiber.appearance = resolved.appearance;
631
- fiber.scope = makeScope("function", context, (passive) => runFunction(fiber, passive));
632
- fiber.render = () => enter(fiber.scope, () => {
633
- const type = latest(fiber.type);
634
- return resolve(type, fiber.props, () => call(type, fiber.props));
635
- });
636
- track(fiber.type, fiber.scope);
637
- probing(fiber);
638
- return complete(fiber, () => {
639
- runFunction(fiber, passiveRender);
640
- });
641
- }
642
- function mountOwnedComponent(value, parent, before, context, boundary, appearance) {
643
- const resolved = componentProps(value.type, value.props, appearance);
644
- const Type = value.type;
645
- const props = observe(resolved.props);
646
- const instance = new Type(props, Type.prototype instanceof Component ? void 0 : () => props.is?.(instance));
647
- return mountComponent(instance, parent, before, context, boundary, resolved.appearance, true, value.key, props);
648
- }
649
- function runFunction(fiber, passive) {
650
- const result = attempt(fiber, passive, fiber.render);
651
- if (result === true) inserted(fiber, () => commit(fiber.scope));
652
- else return result;
653
- }
654
- function probing(fiber) {
655
- const scope = fiber.scope;
656
- scope.empty = () => !fiber.children.length;
657
- scope.probe = () => {
658
- try {
659
- scope.probed = { output: consume(fiber, fiber.render) };
660
- } catch (thrown) {
661
- if (isThenable(thrown)) return thrown;
662
- }
663
- };
664
491
  }
665
- function mountComponent(instance, parent, before, context, inherited, appearance, owned = false, key, props = instance.props) {
666
- const fiber = range("component", parent, before, context);
667
- const childContext = context.push(instance);
668
- const element = owned ? props : {};
669
- const fallback = element.fallback !== void 0 ? element.fallback : instance.fallback;
670
- const ownBoundary = fallback !== void 0 && fallback !== false || element.catch || instance.catch ? {
671
- catch: element.catch || instance.catch ? (error) => {
672
- return (owned && fiber.props.catch || instance.catch).call(instance, error, instance);
673
- } : void 0,
674
- fallback: () => {
675
- const placed = owned ? fiber.props.fallback : void 0;
676
- return placed !== void 0 ? placed : instance.fallback;
677
- },
678
- owner: fiber,
679
- parent: inherited
680
- } : inherited;
681
- fiber.boundary = ownBoundary;
682
- if (ownBoundary !== inherited) fiber.ownBoundary = ownBoundary;
683
- fiber.childContext = childContext;
684
- fiber.instance = instance;
685
- fiber.key = owned ? key : instance.key;
686
- fiber.type = instance.constructor;
687
- fiber.props = props;
688
- fiber.owned = owned;
689
- fiber.appearance = appearance;
690
- fiber.scope = makeScope("component", childContext, (passive) => runComponent(fiber, passive));
691
- fiber.render = () => enter(fiber.scope, () => compose.call(fiber.value, fiber.props));
692
- probing(fiber);
693
- let first = true;
694
- let proxy = instance;
695
- fiber.release = watch(instance, (current, events) => {
696
- const { applied, scope } = fiber;
697
- proxy = current;
698
- fiber.applied = void 0;
699
- if (!first && scope.active) if (applied && events.includes("props")) transition(() => schedule(scope));
700
- else schedule(scope);
701
- first = false;
702
- }, void 0, transition);
703
- Object.defineProperty(fiber, "value", { get: () => proxy });
704
- try {
705
- complete(fiber, () => {
706
- runComponent(fiber, passiveRender);
707
- });
708
- } finally {
709
- if (owned && !fiber.dead) inserted(fiber, () => fiber.cleanup = instance.mount?.());
492
+ function removeRange(start, end) {
493
+ let node = start;
494
+ while (true) {
495
+ const next = node.nextSibling;
496
+ node.remove();
497
+ if (node === end) break;
498
+ node = next;
710
499
  }
711
- return fiber;
712
- }
713
- function runComponent(fiber, passive) {
714
- const result = attempt(fiber, passive, fiber.render);
715
- if (result !== true) return result;
716
500
  }
501
+
502
+ //#endregion
503
+ //#region src/render/collection.ts
717
504
  function mountCollection(value, parent, before, context, boundary, appearance) {
718
505
  const fiber = range("collection", parent, before, context);
719
506
  fiber.source = value;
@@ -737,107 +524,159 @@ function runCollection(fiber, passive) {
737
524
  return value instanceof map.Managed ? [...value.values()] : [...value];
738
525
  });
739
526
  }
740
- function mountPortal(value, parent, before, context, boundary, appearance) {
741
- const marker = document.createComment("portal");
742
- const container = target(value.props.into, parent);
743
- const portalStart = document.createComment("portal-root");
744
- const portalEnd = document.createComment("/portal-root");
745
- parent.insertBefore(marker, before);
746
- container.append(portalStart, portalEnd);
747
- const output = {
748
- kind: "portal",
749
- key: value.key,
750
- type: PORTAL,
751
- props: value.props,
752
- context,
753
- boundary,
754
- appearance,
755
- start: marker,
756
- end: marker,
757
- children: [],
758
- portalContainer: container,
759
- portalStart,
760
- portalEnd
761
- };
762
- return complete(output, () => {
763
- reconcilePortal(output, value.props.children, context, boundary, appearance);
527
+ function patchCollection(fiber, appearance) {
528
+ if (fiber.appearance === appearance) return;
529
+ fiber.appearance = appearance;
530
+ runCollection(fiber, passiveRender);
531
+ }
532
+ function isCollection(value) {
533
+ return value instanceof has.List || value instanceof has.Pool || value instanceof map.Managed;
534
+ }
535
+
536
+ //#endregion
537
+ //#region src/node/loader.ts
538
+ const LOADS = /* @__PURE__ */ new WeakMap();
539
+ function resolve(type, props, run) {
540
+ const load = LOADS.get(type);
541
+ if (load?.resolved) return vnode(load.resolved, props);
542
+ if (load?.failed) {
543
+ LOADS.delete(type);
544
+ throw load.failed.error;
545
+ }
546
+ if (load) throw load.pending;
547
+ const output = run();
548
+ if (!output || typeof output.then != "function") return output;
549
+ const next = {};
550
+ LOADS.set(type, next);
551
+ throw next.pending = output.then((module) => {
552
+ const component = typeof module == "function" ? module : module?.default;
553
+ if (typeof component == "function") next.resolved = component;
554
+ else next.failed = { error: /* @__PURE__ */ new Error("Loader resolved no component.") };
555
+ }, (error) => {
556
+ next.failed = { error };
764
557
  });
765
558
  }
766
- function target(into, parent) {
767
- if (typeof into != "string") return into;
768
- const root = parent.getRootNode();
769
- const found = [...document.querySelectorAll(into)];
770
- if (root instanceof DocumentFragment) found.push(...root.querySelectorAll(into));
771
- if (found.length != 1) throw new Error(`Portal target "${into}" ${found.length ? "is ambiguous" : "was not found"}.`);
772
- return found[0];
559
+
560
+ //#endregion
561
+ //#region src/style/claim.ts
562
+ const tickets = /* @__PURE__ */ new WeakMap();
563
+ function componentProps(type, props, appearance) {
564
+ const context = appearance?.context;
565
+ if (!context || typeof type != "function") return {
566
+ appearance,
567
+ props
568
+ };
569
+ const value = context.resolve(props);
570
+ const entries = appearance.entries;
571
+ if (!value) return {
572
+ appearance: { entries },
573
+ props
574
+ };
575
+ return {
576
+ appearance: {
577
+ context: value.context,
578
+ entries
579
+ },
580
+ props: {
581
+ ...props,
582
+ style: [createAppearanceToken(value), props.style]
583
+ }
584
+ };
773
585
  }
774
- function mountElement(value, parent, before, context, boundary, appearance) {
775
- const tag = value.type;
776
- let host = parent;
777
- for (let owner = stashes.get(host); owner; owner = stashes.get(host)) host = owner.end.parentNode;
778
- const element = (tag == "svg" || host instanceof SVGElement && host.localName != "foreignObject" ? SVG : void 0) ? document.createElementNS(SVG, tag) : document.createElement(tag);
779
- const fiber = {
780
- kind: "element",
781
- key: value.key,
782
- type: tag,
783
- props: {},
784
- context,
785
- boundary,
786
- start: element,
787
- end: element,
788
- children: [],
789
- events: /* @__PURE__ */ new Map()
586
+ function door(value) {
587
+ const collected = {
588
+ classes: [],
589
+ declarations: {},
590
+ tokens: []
790
591
  };
791
- parent.insertBefore(element, before);
792
- complete(fiber, () => {
793
- patchProps(fiber, value.props, appearance);
592
+ const { classes, declarations, tokens } = collected;
593
+ collect(value, collected, 1);
594
+ if (!classes.length && !tokens.length && !Object.keys(declarations).length) return void 0;
595
+ const key = Object.freeze({});
596
+ tickets.set(key, {
597
+ classes,
598
+ tokens
599
+ });
600
+ return Object.freeze({
601
+ ...declarations,
602
+ [Symbol("style")]: key
794
603
  });
795
- if (value.props.autofocus || value.props.autoFocus) focusing.push(element);
796
- return fiber;
797
604
  }
798
- function pass(work) {
799
- depth++;
800
- try {
801
- return work();
802
- } finally {
803
- if (!--depth) {
804
- settle();
805
- focus();
605
+ function claim(element, appearance, resolved, className, value) {
606
+ const collected = {
607
+ classes: [],
608
+ declarations: {},
609
+ tokens: []
610
+ };
611
+ const entries = appearance?.entries || [];
612
+ let context = appearance?.context;
613
+ let reach = -1;
614
+ if (resolved) collect(createAppearanceToken(resolved), collected, 0);
615
+ appendClasses(collected.classes, className);
616
+ collect(value, collected, 0);
617
+ for (let index = entries.length - 1; index >= 0; index--) collect(entries[index].style, collected, entries[index].hops);
618
+ for (const { appearance, doors } of collected.tokens) {
619
+ for (const block of appearance.blocks || []) collected.classes.push(emitClass(block, doors, element.ownerDocument));
620
+ if (appearance.classes) collected.classes.push(...appearance.classes);
621
+ if (appearance.context && doors >= reach) {
622
+ context = appearance.context;
623
+ reach = doors;
806
624
  }
807
625
  }
626
+ return {
627
+ className: [...new Set(collected.classes)].join(" "),
628
+ context,
629
+ declarations: collected.declarations
630
+ };
808
631
  }
809
- function focus() {
810
- for (const element of focusing.splice(0)) if (element.isConnected) element.focus();
632
+ function applyClaim(element, before, after) {
633
+ const previous = before || {
634
+ className: "",
635
+ declarations: {}
636
+ };
637
+ if (previous.className !== after.className) if (after.className) element.setAttribute("class", after.className);
638
+ else element.removeAttribute("class");
639
+ applyDeclarations(element.style, after.declarations, previous.declarations);
811
640
  }
812
- function attempt(fiber, passive, render) {
813
- const previous = passiveRender;
814
- const scope = fiber.scope;
815
- const probed = scope.probed;
816
- const empty = !fiber.children.length;
817
- scope.probed = void 0;
818
- passiveRender ||= passive;
819
- if (passive && !depth && empty && !fiber.stash) fiber.staging ||= fragment();
820
- const run = () => pass(() => {
821
- try {
822
- reconcile(fiber, probed ? probed.output : consume(fiber, render), scope.childContext, fiber.boundary, renderedAppearance(fiber));
823
- if (fiber.staging) {
824
- fiber.end.parentNode.insertBefore(fiber.staging, fiber.end);
825
- attach(fiber.staging);
826
- fiber.staging = void 0;
827
- }
828
- if (!fiber.recovering) unwait(fiber);
829
- fiber.retried = void 0;
830
- return true;
831
- } catch (thrown) {
832
- return suspend(fiber, thrown, passive, empty);
833
- }
834
- });
835
- try {
836
- return passive ? batched(run) : run();
837
- } finally {
838
- passiveRender = previous;
641
+ function collect(value, collected, doors) {
642
+ if (!value) return;
643
+ const token = appearanceToken(value);
644
+ if (token) {
645
+ collected.tokens.push({
646
+ appearance: token,
647
+ doors
648
+ });
649
+ Object.assign(collected.declarations, token.declarations);
650
+ return;
651
+ }
652
+ if (typeof value == "string") {
653
+ appendClasses(collected.classes, value);
654
+ return;
655
+ }
656
+ if (Array.isArray(value)) {
657
+ value.forEach((entry) => collect(entry, collected, doors));
658
+ return;
659
+ }
660
+ for (const symbol of Object.getOwnPropertySymbols(value)) {
661
+ const ticket = tickets.get(value[symbol]);
662
+ if (!ticket) continue;
663
+ collected.classes.push(...ticket.classes);
664
+ for (const carried of ticket.tokens) collected.tokens.push({
665
+ appearance: carried.appearance,
666
+ doors: carried.doors + doors
667
+ });
839
668
  }
669
+ for (const key of Object.keys(value)) collected.declarations[key] = value[key];
670
+ }
671
+ function appendClasses(classes, value) {
672
+ if (typeof value == "string") classes.push(...value.split(/\s+/).filter(Boolean));
840
673
  }
674
+
675
+ //#endregion
676
+ //#region src/render/style.ts
677
+ let rendering;
678
+ let touched = false;
679
+ const observed = /* @__PURE__ */ new WeakMap();
841
680
  function observe(props) {
842
681
  if (!("style" in props)) return props;
843
682
  let output = observed.get(props);
@@ -860,25 +699,6 @@ function observe(props) {
860
699
  }
861
700
  return output;
862
701
  }
863
- function door(value) {
864
- const collected = {
865
- classes: [],
866
- declarations: {},
867
- tokens: []
868
- };
869
- const { classes, declarations, tokens } = collected;
870
- collect(value, collected, 1);
871
- if (!classes.length && !tokens.length && !Object.keys(declarations).length) return void 0;
872
- const key = Object.freeze({});
873
- tickets.set(key, {
874
- classes,
875
- tokens
876
- });
877
- return Object.freeze({
878
- ...declarations,
879
- [Symbol("style")]: key
880
- });
881
- }
882
702
  function consume(fiber, render) {
883
703
  const previous = rendering;
884
704
  const read = touched;
@@ -893,136 +713,250 @@ function consume(fiber, render) {
893
713
  touched = read;
894
714
  }
895
715
  }
896
- function wait(fiber, boundary) {
897
- if (fiber.waitingOn !== boundary) unwait(fiber);
898
- fiber.waitingOn = boundary;
899
- (boundary.waiting ||= /* @__PURE__ */ new Set()).add(fiber);
900
- dirty.add(boundary);
901
- }
902
- function unwait(fiber) {
903
- const boundary = fiber.waitingOn;
904
- if (!boundary) return;
905
- fiber.waitingOn = void 0;
906
- boundary.waiting.delete(fiber);
907
- if (!boundary.owner.dead) dirty.add(boundary);
908
- }
909
- function settle() {
910
- if (settling) return;
911
- settling = true;
912
- try {
913
- for (const boundary of dirty) {
914
- dirty.delete(boundary);
915
- const owner = boundary.owner;
916
- const waiting = boundary.waiting.size > 0;
917
- if (!owner.dead && waiting != !!owner.stash) waiting ? hide(owner, boundary) : reveal(owner);
918
- }
919
- } finally {
920
- settling = false;
921
- }
922
- }
923
- function hide(owner, boundary) {
924
- const stash = document.createDocumentFragment();
925
- for (const child of owner.children) move(child, stash, null);
926
- owner.portals = portals(owner, []).map((portal) => {
927
- const content = document.createDocumentFragment();
928
- moveRange(portal.portalStart, portal.portalEnd, content);
929
- return [portal, content];
716
+ function renderedAppearance(fiber) {
717
+ if (fiber.kind != "component" && fiber.kind != "function") return fiber.appearance;
718
+ const style = fiber.props?.style;
719
+ const entries = (fiber.appearance?.entries || []).map(({ hops, style }) => ({
720
+ hops: hops + 1,
721
+ style
722
+ }));
723
+ const inherited = fiber.appearance?.context || appearanceRoot();
724
+ const context = enterAppearance(inherited, latest(fiber.type));
725
+ if (context?.base && context !== inherited) entries.push({
726
+ hops: 0,
727
+ style: context.base
930
728
  });
931
- stashes.set(stash, owner);
932
- const context = owner.childContext;
933
- const placeholder = range("fragment", owner.end.parentNode, owner.end, context);
934
- owner.stash = stash;
935
- owner.placeholder = placeholder;
936
- reconcile(placeholder, boundary.fallback(), context, boundary.parent);
729
+ if (style && !fiber.consumed && !(fiber.instance && "style" in fiber.instance)) entries.push({
730
+ hops: 0,
731
+ style
732
+ });
733
+ return entries.length || context ? {
734
+ context,
735
+ entries
736
+ } : void 0;
937
737
  }
938
- function reveal(owner) {
939
- unmountFiber(owner.placeholder);
940
- owner.end.parentNode.insertBefore(owner.stash, owner.end);
941
- for (const [portal, content] of owner.portals) if (!portal.dead) portal.portalContainer.append(content);
942
- owner.portals = void 0;
943
- owner.placeholder = void 0;
944
- owner.stash = void 0;
738
+
739
+ //#endregion
740
+ //#region src/render/element.ts
741
+ const SVG = "http://www.w3.org/2000/svg";
742
+ const CONTROLS = ["checked", "value"];
743
+ const ENUMERATED = [
744
+ "contentEditable",
745
+ "contenteditable",
746
+ "draggable",
747
+ "spellcheck"
748
+ ];
749
+ const ALIASES = {
750
+ autoFocus: "autofocus",
751
+ contentEditable: "contenteditable",
752
+ htmlFor: "for"
753
+ };
754
+ const controlled = /* @__PURE__ */ new WeakMap();
755
+ const restoring = /* @__PURE__ */ new WeakSet();
756
+ function mountElement(value, parent, before, context, boundary, appearance) {
757
+ const tag = value.type;
758
+ const host = hostOf(parent);
759
+ const element = (tag == "svg" || host instanceof SVGElement && host.localName != "foreignObject" ? SVG : void 0) ? document.createElementNS(SVG, tag) : document.createElement(tag);
760
+ const fiber = {
761
+ kind: "element",
762
+ key: value.key,
763
+ type: tag,
764
+ props: {},
765
+ context,
766
+ boundary,
767
+ start: element,
768
+ end: element,
769
+ children: [],
770
+ events: /* @__PURE__ */ new Map()
771
+ };
772
+ parent.insertBefore(element, before);
773
+ complete(fiber, () => {
774
+ patchProps(fiber, value.props, appearance);
775
+ });
776
+ if (value.props.autofocus || value.props.autoFocus) focusing.push(element);
777
+ return fiber;
945
778
  }
946
- function portals(fiber, found) {
947
- for (const child of fiber.children) {
948
- if (child.kind == "portal") found.push(child);
949
- portals(child, found);
779
+ function patchProps(fiber, next, appearance) {
780
+ const element = fiber.start;
781
+ const previous = fiber.props;
782
+ const raw = "dangerouslySetInnerHTML" in next;
783
+ const resolved = appearance?.context?.resolve(next, fiber.type);
784
+ if (raw) {
785
+ for (let index = fiber.children.length - 1; index >= 0; index--) unmountFiber(fiber.children[index]);
786
+ fiber.children = [];
950
787
  }
951
- return found;
952
- }
953
- function moveRange(start, end, target) {
954
- let node = start;
955
- while (node) {
956
- const next = node.nextSibling;
957
- target.appendChild(node);
958
- if (node === end) break;
959
- node = next;
788
+ for (const key of Object.keys({
789
+ ...previous,
790
+ ...next
791
+ })) {
792
+ if (key.startsWith("_") || key == "children" || key == "className" || key == "key" || key == "ref" || key == "style" || CONTROLS.includes(key)) continue;
793
+ if (previous[key] === next[key]) continue;
794
+ patchProp(fiber, element, key, previous[key], next[key]);
960
795
  }
961
- }
962
- function suspend(fiber, thrown, passive, empty) {
963
- const boundary = fiber.boundary;
964
- if (isThenable(thrown)) {
965
- if (!boundary) throw thrown;
966
- if (passive && empty && depth > 1) {
967
- if (holding?.thrown !== thrown) holding = { thrown };
968
- throw thrown;
796
+ const claimed = claim(element, appearance, resolved, next.className, next.style);
797
+ applyClaim(element, fiber.claimed, claimed);
798
+ fiber.claimed = claimed;
799
+ fiber.props = next;
800
+ fiber.appearance = appearance;
801
+ if (!raw) reconcileChildren(fiber, element, null, next.children, fiber.context, fiber.boundary, claimed.context ? {
802
+ context: claimed.context,
803
+ entries: []
804
+ } : void 0);
805
+ for (const key of CONTROLS) {
806
+ const value = next[key];
807
+ const live = element[key];
808
+ if (value == null || !(key in element) ? previous[key] !== value : key == "value" ? String(live) !== String(value) : live !== value) patchProp(fiber, element, key, previous[key], value);
809
+ }
810
+ if (CONTROLS.some((key) => next[key] != null)) {
811
+ const document = element.ownerDocument;
812
+ controlled.set(element, fiber);
813
+ if (!restoring.has(document)) {
814
+ restoring.add(document);
815
+ document.addEventListener("input", restoreTarget);
816
+ document.addEventListener("change", restoreTarget);
969
817
  }
970
- holding = void 0;
971
- if (!passive) wait(fiber, boundary);
972
- const scope = fiber.scope;
973
- let held = scope.holds;
974
- scope.holds = void 0;
975
- const clear = () => {
976
- fiber.suspended.delete(clear);
977
- release(held);
978
- held = void 0;
979
- };
980
- (fiber.suspended ||= /* @__PURE__ */ new Set()).add(clear);
981
- const resume = (retry) => {
982
- fiber.suspended.delete(clear);
983
- if (!scope.active) return clear();
984
- if (held) (scope.holds ||= []).push(...held);
985
- held = void 0;
986
- retry();
987
- };
988
- thrown.then(() => resume(() => passive ? transition(() => schedule(scope)) : schedule(scope)), (error) => resume(() => pass(() => recover(fiber, error, fiber.boundary))));
989
- return thrown;
990
818
  }
991
- recover(fiber, thrown, fiber.boundary);
819
+ if (previous.ref !== next.ref) patchProp(fiber, element, "ref", previous.ref, next.ref);
992
820
  }
993
- function recover(fiber, thrown, boundary) {
994
- const error = thrown instanceof Error ? thrown : new Error(String(thrown));
995
- while (boundary && !boundary.catch) boundary = boundary.parent;
996
- if (!boundary) throw error;
997
- const handler = boundary;
998
- const token = {};
999
- wait(fiber, handler);
1000
- fiber.recovering = token;
1001
- Promise.resolve(handler.catch(error)).then(() => {
1002
- if (fiber.recovering !== token) return;
1003
- fiber.recovering = void 0;
1004
- if (!fiber.scope.active || fiber.retried) return;
1005
- fiber.retried = true;
1006
- schedule(fiber.scope);
1007
- }, (next) => {
1008
- if (fiber.recovering === token && fiber.scope.active) pass(() => recover(fiber, next, handler.parent));
1009
- });
821
+ function patchProp(fiber, element, key, previous, next) {
822
+ if (key == "ref") {
823
+ applyRef(previous, null);
824
+ inserted(fiber, () => applyRef(next, element));
825
+ return;
826
+ }
827
+ if (key == "dangerouslySetInnerHTML") {
828
+ element.innerHTML = next?.__html || "";
829
+ return;
830
+ }
831
+ if (/^on[A-Z]/.test(key)) {
832
+ const capture = key.endsWith("Capture");
833
+ const lower = (capture ? key.slice(2, -7) : key.slice(2)).toLowerCase();
834
+ const name = lower == "doubleclick" ? "dblclick" : lower;
835
+ const id = `${name}:${capture}`;
836
+ const current = fiber.events.get(id);
837
+ if (current) element.removeEventListener(name, current, capture);
838
+ if (typeof next == "function") {
839
+ fiber.events.set(id, next);
840
+ element.addEventListener(name, next, capture);
841
+ } else fiber.events.delete(id);
842
+ return;
843
+ }
844
+ const name = ALIASES[key] || key;
845
+ if ((key.startsWith("aria-") || key.startsWith("data-") || ENUMERATED.includes(key)) && next != null) {
846
+ element.setAttribute(name, String(next));
847
+ return;
848
+ }
849
+ if (next === null || next === void 0 || next === false) {
850
+ if (key in element && typeof element[key] != "function") try {
851
+ const current = element[key];
852
+ element[key] = typeof current == "boolean" ? false : typeof current == "number" ? 0 : "";
853
+ } catch {}
854
+ element.removeAttribute(element.namespaceURI === SVG ? name.toLowerCase() : name);
855
+ element.removeAttribute(name);
856
+ return;
857
+ }
858
+ if (key in element && (element.namespaceURI !== SVG || settable(element, key))) try {
859
+ element[key] = next;
860
+ return;
861
+ } catch {}
862
+ element.setAttribute(name, next === true ? "" : String(next));
1010
863
  }
1011
- function isThenable(value) {
1012
- return !!value && typeof value.then == "function";
864
+ function restoreTarget(event) {
865
+ const element = event.target;
866
+ const fiber = controlled.get(element);
867
+ if (fiber && event.type == settles(fiber.props, element)) queueMicrotask(() => afterFlush(() => restore(fiber)));
1013
868
  }
1014
- function reconcile(fiber, value, context, boundary, appearance) {
1015
- const detached = fiber.stash || fiber.staging;
1016
- if (detached) reconcileChildren(fiber, detached, null, value, context, boundary, appearance);
1017
- else reconcileChildren(fiber, fiber.end.parentNode, fiber.end, value, context, boundary, appearance);
869
+ function settles(props, element) {
870
+ if (props.onInput) return "input";
871
+ if (props.onChange) return "change";
872
+ return element.type == "checkbox" || element.type == "radio" || element.localName == "select" ? "change" : "input";
1018
873
  }
1019
- function reconcilePortal(fiber, value, context, boundary, appearance) {
1020
- reconcileChildren(fiber, fiber.portalEnd.parentNode, fiber.portalEnd, value, context, boundary, appearance);
874
+ function restore(fiber) {
875
+ const element = fiber.start;
876
+ for (const key of CONTROLS) {
877
+ const value = fiber.props[key];
878
+ if (value == null || fiber.dead) continue;
879
+ if (key == "value" ? String(element.value) !== String(value) : element[key] !== value) element[key] = value;
880
+ }
1021
881
  }
1022
- function reconcileChildren(owner, parent, before, value, context, boundary, appearance) {
1023
- const values = childrenOf(value);
1024
- const old = owner.children;
1025
- const keyed = /* @__PURE__ */ new Map();
882
+ function settable(element, key) {
883
+ let target = element;
884
+ let descriptor;
885
+ while (!(descriptor = Object.getOwnPropertyDescriptor(target, key))) target = Object.getPrototypeOf(target);
886
+ return !!(descriptor.set || descriptor.writable);
887
+ }
888
+ function applyRef(ref, value) {
889
+ if (typeof ref == "function") ref(value);
890
+ else if (ref && typeof ref == "object" && "current" in ref) ref.current = value;
891
+ }
892
+ function unmountElement(fiber) {
893
+ applyRef(fiber.props?.ref, null);
894
+ for (const [id, listener] of fiber.events) {
895
+ const [name, capture] = id.split(":");
896
+ fiber.start.removeEventListener(name, listener, capture === "true");
897
+ }
898
+ }
899
+
900
+ //#endregion
901
+ //#region src/render/portal.ts
902
+ function mountPortal(value, parent, before, context, boundary, appearance) {
903
+ const marker = document.createComment("portal");
904
+ const container = target(value.props.into, parent);
905
+ const portalStart = document.createComment("portal-root");
906
+ const portalEnd = document.createComment("/portal-root");
907
+ parent.insertBefore(marker, before);
908
+ container.append(portalStart, portalEnd);
909
+ const output = {
910
+ kind: "portal",
911
+ key: value.key,
912
+ type: PORTAL,
913
+ props: value.props,
914
+ context,
915
+ boundary,
916
+ appearance,
917
+ start: marker,
918
+ end: marker,
919
+ children: [],
920
+ portalContainer: container,
921
+ portalStart,
922
+ portalEnd
923
+ };
924
+ return complete(output, () => {
925
+ reconcilePortal(output, value.props.children, context, boundary, appearance);
926
+ });
927
+ }
928
+ function target(into, parent) {
929
+ if (typeof into != "string") return into;
930
+ const root = parent.getRootNode();
931
+ const found = [...document.querySelectorAll(into)];
932
+ if (root instanceof DocumentFragment) found.push(...root.querySelectorAll(into));
933
+ if (found.length != 1) throw new Error(`Portal target "${into}" ${found.length ? "is ambiguous" : "was not found"}.`);
934
+ return found[0];
935
+ }
936
+ function reconcilePortal(fiber, value, context, boundary, appearance) {
937
+ reconcileChildren(fiber, fiber.portalEnd.parentNode, fiber.portalEnd, value, context, boundary, appearance);
938
+ }
939
+ function patchPortal(fiber, value, context, appearance) {
940
+ fiber.appearance = appearance;
941
+ fiber.props = value.props;
942
+ reconcilePortal(fiber, value.props.children, context, fiber.boundary, appearance);
943
+ }
944
+ function unmountPortal(fiber) {
945
+ fiber.portalStart.remove();
946
+ fiber.portalEnd.remove();
947
+ }
948
+
949
+ //#endregion
950
+ //#region src/render/reconcile.ts
951
+ function reconcile(fiber, value, context, boundary, appearance) {
952
+ const detached = fiber.stash || fiber.staging;
953
+ if (detached) reconcileChildren(fiber, detached, null, value, context, boundary, appearance);
954
+ else reconcileChildren(fiber, fiber.end.parentNode, fiber.end, value, context, boundary, appearance);
955
+ }
956
+ function reconcileChildren(owner, parent, before, value, context, boundary, appearance) {
957
+ const values = childrenOf(value);
958
+ const old = owner.children;
959
+ const keyed = /* @__PURE__ */ new Map();
1026
960
  const used = /* @__PURE__ */ new Set();
1027
961
  const next = [];
1028
962
  for (const child of old) if (child.key !== null && child.key !== void 0) keyed.set(child.key, child);
@@ -1038,11 +972,7 @@ function reconcileChildren(owner, parent, before, value, context, boundary, appe
1038
972
  next.push(fiber);
1039
973
  }
1040
974
  } catch (error) {
1041
- if (holding && error === holding.thrown) {
1042
- for (const fiber of next) if (!old.includes(fiber)) park(fiber);
1043
- if (holding.fiber) next.push(holding.fiber);
1044
- holding.fiber = void 0;
1045
- }
975
+ gather(error, next, old);
1046
976
  owner.children = [...next, ...old.filter((child) => !child.dead && !next.includes(child))];
1047
977
  throw error;
1048
978
  }
@@ -1061,62 +991,15 @@ function patch(old, value, parent, before, context, boundary, appearance) {
1061
991
  if (!old || !compatible(old, value)) return mount(value, parent, old?.start || before, context, boundary, appearance);
1062
992
  if (old.ownBoundary) old.ownBoundary.parent = boundary;
1063
993
  old.boundary = old.ownBoundary || boundary;
1064
- if (old.kind == "collection") {
1065
- if (old.appearance !== appearance) {
1066
- old.appearance = appearance;
1067
- runCollection(old, passiveRender);
1068
- }
1069
- return old;
1070
- }
1071
- if (old.kind == "text") {
1072
- const next = String(value);
1073
- if (old.start.nodeValue !== next) old.start.nodeValue = next;
1074
- old.value = value;
1075
- } else if (old.kind == "element") patchProps(old, value.props, appearance);
1076
- else if (old.kind == "fragment") {
1077
- old.context = context;
1078
- old.appearance = appearance;
1079
- reconcile(old, value.props.children, context, old.boundary, appearance);
1080
- } else if (old.kind == "function") {
1081
- const vnode = value;
1082
- const resolved = componentProps(vnode.type, vnode.props, appearance);
1083
- if (old.type !== vnode.type) {
1084
- untrack(old.type, old.scope);
1085
- old.type = vnode.type;
1086
- old.scope.hot = true;
1087
- track(old.type, old.scope);
1088
- }
1089
- old.appearance = resolved.appearance;
1090
- old.props = observe(resolved.props);
1091
- rerun(old, () => runFunction(old, passiveRender));
1092
- } else if (old.kind == "component") {
1093
- const resolved = isVNode(value) ? componentProps(value.type, value.props, appearance) : {
1094
- appearance,
1095
- props: old.props
1096
- };
1097
- old.appearance = resolved.appearance;
1098
- const props = isVNode(value) ? observe(resolved.props) : resolved.props;
1099
- if (isVNode(value) && props !== old.props) {
1100
- const instance = old.instance;
1101
- if (passiveRender) old.applied = true;
1102
- if (instance instanceof Component) instance.props = props;
1103
- else instance.set(merge(old.props, props));
1104
- }
1105
- old.props = props;
1106
- rerun(old, () => runComponent(old, passiveRender));
1107
- } else {
1108
- old.appearance = appearance;
1109
- const vnode = value;
1110
- old.props = vnode.props;
1111
- reconcilePortal(old, vnode.props.children, context, old.boundary, appearance);
1112
- }
994
+ if (old.kind == "collection") patchCollection(old, appearance);
995
+ else if (old.kind == "text") patchText(old, value);
996
+ else if (old.kind == "element") patchProps(old, value.props, appearance);
997
+ else if (old.kind == "fragment") patchFragment(old, value, context, appearance);
998
+ else if (old.kind == "function") patchFunction(old, value, appearance);
999
+ else if (old.kind == "component") patchComponent(old, value, appearance);
1000
+ else patchPortal(old, value, context, appearance);
1113
1001
  return old;
1114
1002
  }
1115
- function rerun(fiber, run) {
1116
- claim$1(fiber.scope);
1117
- run();
1118
- settle$1(fiber.scope);
1119
- }
1120
1003
  function compatible(fiber, value) {
1121
1004
  if (fiber.kind == "text") return [
1122
1005
  "string",
@@ -1131,241 +1014,352 @@ function compatible(fiber, value) {
1131
1014
  return true;
1132
1015
  }
1133
1016
  function source(value) {
1134
- if (value instanceof State) return value.is;
1017
+ if (value instanceof Model) return value.is;
1135
1018
  while (isCollection(value) && isCollection(Object.getPrototypeOf(value))) value = Object.getPrototypeOf(value);
1136
1019
  return value;
1137
1020
  }
1138
- function renderable(value) {
1139
- return value instanceof State && typeof value.render == "function";
1140
- }
1141
- function merge(previous, next) {
1142
- const output = {};
1143
- for (const key in previous) output[key] = void 0;
1144
- return {
1145
- ...output,
1146
- ...next
1147
- };
1148
- }
1149
- function isCollection(value) {
1150
- return value instanceof has.List || value instanceof has.Pool || value instanceof map.Managed;
1151
- }
1152
1021
  function keyOf(value) {
1153
1022
  if (renderable(value)) return value.key;
1154
1023
  return isVNode(value) ? value.key : void 0;
1155
1024
  }
1156
- function move(fiber, parent, before) {
1157
- if (fiber.start.parentNode === parent && fiber.end.nextSibling === before) return;
1158
- let node = fiber.start;
1159
- while (node) {
1160
- const next = node.nextSibling;
1161
- parent.insertBefore(node, before);
1162
- if (node === fiber.end) break;
1163
- node = next;
1164
- }
1025
+
1026
+ //#endregion
1027
+ //#region src/render/suspense.ts
1028
+ const dirty = /* @__PURE__ */ new Set();
1029
+ const stashes = /* @__PURE__ */ new WeakMap();
1030
+ let holding;
1031
+ let settling = false;
1032
+ function park(fiber) {
1033
+ move(fiber, fragment(), null);
1165
1034
  }
1166
- function patchProps(fiber, next, appearance) {
1167
- const element = fiber.start;
1168
- const previous = fiber.props;
1169
- const raw = "dangerouslySetInnerHTML" in next;
1170
- const resolved = appearance?.context?.resolve(next, fiber.type);
1171
- if (raw) {
1172
- for (let index = fiber.children.length - 1; index >= 0; index--) unmountFiber(fiber.children[index]);
1173
- fiber.children = [];
1174
- }
1175
- for (const key of Object.keys({
1176
- ...previous,
1177
- ...next
1178
- })) {
1179
- if (key.startsWith("_") || key == "children" || key == "className" || key == "key" || key == "ref" || key == "style" || CONTROLS.includes(key)) continue;
1180
- if (previous[key] === next[key]) continue;
1181
- patchProp(fiber, element, key, previous[key], next[key]);
1182
- }
1183
- const claimed = claim(element, appearance, resolved, next.className, next.style);
1184
- applyClaim(element, fiber.claimed, claimed);
1185
- fiber.claimed = claimed;
1186
- fiber.props = next;
1187
- fiber.appearance = appearance;
1188
- if (!raw) reconcileChildren(fiber, element, null, next.children, fiber.context, fiber.boundary, claimed.context ? {
1189
- context: claimed.context,
1190
- entries: []
1191
- } : void 0);
1192
- for (const key of CONTROLS) {
1193
- const value = next[key];
1194
- const live = element[key];
1195
- if (value == null || !(key in element) ? previous[key] !== value : key == "value" ? String(live) !== String(value) : live !== value) patchProp(fiber, element, key, previous[key], value);
1196
- }
1197
- if (CONTROLS.some((key) => next[key] != null)) {
1198
- const document = element.ownerDocument;
1199
- controlled.set(element, fiber);
1200
- if (!restoring.has(document)) {
1201
- restoring.add(document);
1202
- document.addEventListener("input", restoreTarget);
1203
- document.addEventListener("change", restoreTarget);
1035
+ function hold(fiber, error) {
1036
+ if (!holding || error !== holding.thrown) return false;
1037
+ park(fiber);
1038
+ holding.fiber = fiber;
1039
+ return true;
1040
+ }
1041
+ function gather(error, next, old) {
1042
+ if (!holding || error !== holding.thrown) return;
1043
+ for (const fiber of next) if (!old.includes(fiber)) park(fiber);
1044
+ if (holding.fiber) next.push(holding.fiber);
1045
+ holding.fiber = void 0;
1046
+ }
1047
+ function hostOf(parent) {
1048
+ let host = parent;
1049
+ for (let owner = stashes.get(host); owner; owner = stashes.get(host)) host = owner.end.parentNode;
1050
+ return host;
1051
+ }
1052
+ function wait(fiber, boundary) {
1053
+ if (fiber.waitingOn !== boundary) unwait(fiber);
1054
+ fiber.waitingOn = boundary;
1055
+ (boundary.waiting ||= /* @__PURE__ */ new Set()).add(fiber);
1056
+ dirty.add(boundary);
1057
+ }
1058
+ function unwait(fiber) {
1059
+ const boundary = fiber.waitingOn;
1060
+ if (!boundary) return;
1061
+ fiber.waitingOn = void 0;
1062
+ boundary.waiting.delete(fiber);
1063
+ if (!boundary.owner.dead) dirty.add(boundary);
1064
+ }
1065
+ function settle() {
1066
+ if (settling) return;
1067
+ settling = true;
1068
+ try {
1069
+ for (const boundary of dirty) {
1070
+ dirty.delete(boundary);
1071
+ const owner = boundary.owner;
1072
+ const waiting = boundary.waiting.size > 0;
1073
+ if (!owner.dead && waiting != !!owner.stash) waiting ? hide(owner, boundary) : reveal(owner);
1204
1074
  }
1075
+ } finally {
1076
+ settling = false;
1205
1077
  }
1206
- if (previous.ref !== next.ref) patchProp(fiber, element, "ref", previous.ref, next.ref);
1207
1078
  }
1208
- function patchProp(fiber, element, key, previous, next) {
1209
- if (key == "ref") {
1210
- applyRef(previous, null);
1211
- inserted(fiber, () => applyRef(next, element));
1212
- return;
1213
- }
1214
- if (key == "dangerouslySetInnerHTML") {
1215
- element.innerHTML = next?.__html || "";
1216
- return;
1217
- }
1218
- if (/^on[A-Z]/.test(key)) {
1219
- const capture = key.endsWith("Capture");
1220
- const lower = (capture ? key.slice(2, -7) : key.slice(2)).toLowerCase();
1221
- const name = lower == "doubleclick" ? "dblclick" : lower;
1222
- const id = `${name}:${capture}`;
1223
- const current = fiber.events.get(id);
1224
- if (current) element.removeEventListener(name, current, capture);
1225
- if (typeof next == "function") {
1226
- fiber.events.set(id, next);
1227
- element.addEventListener(name, next, capture);
1228
- } else fiber.events.delete(id);
1229
- return;
1079
+ function hide(owner, boundary) {
1080
+ const stash = document.createDocumentFragment();
1081
+ for (const child of owner.children) move(child, stash, null);
1082
+ owner.portals = portals(owner, []).map((portal) => {
1083
+ const content = document.createDocumentFragment();
1084
+ moveRange(portal.portalStart, portal.portalEnd, content);
1085
+ return [portal, content];
1086
+ });
1087
+ stashes.set(stash, owner);
1088
+ const context = owner.childContext;
1089
+ const placeholder = range("fragment", owner.end.parentNode, owner.end, context);
1090
+ owner.stash = stash;
1091
+ owner.placeholder = placeholder;
1092
+ reconcile(placeholder, boundary.fallback(), context, boundary.parent);
1093
+ }
1094
+ function reveal(owner) {
1095
+ unmountFiber(owner.placeholder);
1096
+ owner.end.parentNode.insertBefore(owner.stash, owner.end);
1097
+ for (const [portal, content] of owner.portals) if (!portal.dead) portal.portalContainer.append(content);
1098
+ owner.portals = void 0;
1099
+ owner.placeholder = void 0;
1100
+ owner.stash = void 0;
1101
+ }
1102
+ function portals(fiber, found) {
1103
+ for (const child of fiber.children) {
1104
+ if (child.kind == "portal") found.push(child);
1105
+ portals(child, found);
1230
1106
  }
1231
- const name = ALIASES[key] || key;
1232
- if ((key.startsWith("aria-") || key.startsWith("data-") || ENUMERATED.includes(key)) && next != null) {
1233
- element.setAttribute(name, String(next));
1234
- return;
1107
+ return found;
1108
+ }
1109
+ function suspend(fiber, thrown, passive, empty) {
1110
+ const boundary = fiber.boundary;
1111
+ if (isThenable(thrown)) {
1112
+ if (!boundary) throw thrown;
1113
+ if (passive && empty && depth > 1) {
1114
+ if (holding?.thrown !== thrown) holding = { thrown };
1115
+ throw thrown;
1116
+ }
1117
+ holding = void 0;
1118
+ if (!passive) wait(fiber, boundary);
1119
+ const scope = fiber.scope;
1120
+ let held = scope.holds;
1121
+ scope.holds = void 0;
1122
+ const clear = () => {
1123
+ fiber.suspended.delete(clear);
1124
+ release(held);
1125
+ held = void 0;
1126
+ };
1127
+ (fiber.suspended ||= /* @__PURE__ */ new Set()).add(clear);
1128
+ const resume = (retry) => {
1129
+ fiber.suspended.delete(clear);
1130
+ if (!scope.active) return clear();
1131
+ if (held) (scope.holds ||= []).push(...held);
1132
+ held = void 0;
1133
+ retry();
1134
+ };
1135
+ thrown.then(() => resume(() => passive ? transition(() => schedule(scope)) : schedule(scope)), (error) => resume(() => pass(() => recover(fiber, error, fiber.boundary))));
1136
+ return thrown;
1235
1137
  }
1236
- if (next === null || next === void 0 || next === false) {
1237
- if (key in element && typeof element[key] != "function") try {
1238
- const current = element[key];
1239
- element[key] = typeof current == "boolean" ? false : typeof current == "number" ? 0 : "";
1240
- } catch {}
1241
- element.removeAttribute(element.namespaceURI === SVG ? name.toLowerCase() : name);
1242
- element.removeAttribute(name);
1243
- return;
1138
+ recover(fiber, thrown, fiber.boundary);
1139
+ }
1140
+ function recover(fiber, thrown, boundary) {
1141
+ const error = thrown instanceof Error ? thrown : new Error(String(thrown));
1142
+ while (boundary && !boundary.catch) boundary = boundary.parent;
1143
+ if (!boundary) throw error;
1144
+ const handler = boundary;
1145
+ const token = {};
1146
+ wait(fiber, handler);
1147
+ fiber.recovering = token;
1148
+ Promise.resolve(handler.catch(error)).then(() => {
1149
+ if (fiber.recovering !== token) return;
1150
+ fiber.recovering = void 0;
1151
+ if (!fiber.scope.active || fiber.retried) return;
1152
+ fiber.retried = true;
1153
+ schedule(fiber.scope);
1154
+ }, (next) => {
1155
+ if (fiber.recovering === token && fiber.scope.active) pass(() => recover(fiber, next, handler.parent));
1156
+ });
1157
+ }
1158
+ function isThenable(value) {
1159
+ return !!value && typeof value.then == "function";
1160
+ }
1161
+
1162
+ //#endregion
1163
+ //#region src/render/component.ts
1164
+ function mountFunction(value, parent, before, context, boundary, appearance) {
1165
+ const fiber = range("function", parent, before, context);
1166
+ const resolved = componentProps(value.type, value.props, appearance);
1167
+ fiber.key = value.key;
1168
+ fiber.type = value.type;
1169
+ fiber.props = observe(resolved.props);
1170
+ fiber.boundary = boundary;
1171
+ fiber.appearance = resolved.appearance;
1172
+ fiber.scope = makeScope("function", context, (passive) => runFunction(fiber, passive));
1173
+ fiber.render = () => enter(fiber.scope, () => {
1174
+ const type = latest(fiber.type);
1175
+ return resolve(type, fiber.props, () => call(type, fiber.props));
1176
+ });
1177
+ track(fiber.type, fiber.scope);
1178
+ probing(fiber);
1179
+ return complete(fiber, () => {
1180
+ runFunction(fiber, passiveRender);
1181
+ });
1182
+ }
1183
+ function mountOwnedComponent(value, parent, before, context, boundary, appearance) {
1184
+ const resolved = componentProps(value.type, value.props, appearance);
1185
+ const Type = value.type;
1186
+ const props = observe(resolved.props);
1187
+ const instance = new Type(props, Type.prototype instanceof Component ? void 0 : () => props.is?.(instance));
1188
+ return mountComponent(instance, parent, before, context, boundary, resolved.appearance, true, value.key, props);
1189
+ }
1190
+ function mountComponent(instance, parent, before, context, inherited, appearance, owned = false, key, props = instance.props) {
1191
+ const fiber = range("component", parent, before, context);
1192
+ const childContext = context.push(instance);
1193
+ const element = owned ? props : {};
1194
+ const fallback = element.fallback !== void 0 ? element.fallback : instance.fallback;
1195
+ const ownBoundary = fallback !== void 0 && fallback !== false || element.catch || instance.catch ? {
1196
+ catch: element.catch || instance.catch ? (error) => {
1197
+ return (owned && fiber.props.catch || instance.catch).call(instance, error, instance);
1198
+ } : void 0,
1199
+ fallback: () => {
1200
+ const placed = owned ? fiber.props.fallback : void 0;
1201
+ return placed !== void 0 ? placed : instance.fallback;
1202
+ },
1203
+ owner: fiber,
1204
+ parent: inherited
1205
+ } : inherited;
1206
+ fiber.boundary = ownBoundary;
1207
+ if (ownBoundary !== inherited) fiber.ownBoundary = ownBoundary;
1208
+ fiber.childContext = childContext;
1209
+ fiber.instance = instance;
1210
+ fiber.key = owned ? key : instance.key;
1211
+ fiber.type = instance.constructor;
1212
+ fiber.props = props;
1213
+ fiber.owned = owned;
1214
+ fiber.appearance = appearance;
1215
+ fiber.scope = makeScope("component", childContext, (passive) => runComponent(fiber, passive));
1216
+ fiber.render = () => enter(fiber.scope, () => {
1217
+ const { render } = fiber.value;
1218
+ return render ? unbind(render).call(fiber.value, fiber.props) : fiber.props.children ?? null;
1219
+ });
1220
+ probing(fiber);
1221
+ let first = true;
1222
+ let proxy = instance;
1223
+ fiber.release = watch(instance, (current, events) => {
1224
+ const { applied, scope } = fiber;
1225
+ proxy = current;
1226
+ fiber.applied = void 0;
1227
+ if (!first && scope.active) if (applied && events.includes("props")) transition(() => schedule(scope));
1228
+ else schedule(scope);
1229
+ first = false;
1230
+ }, void 0, transition);
1231
+ Object.defineProperty(fiber, "value", { get: () => proxy });
1232
+ try {
1233
+ complete(fiber, () => {
1234
+ runComponent(fiber, passiveRender);
1235
+ });
1236
+ } finally {
1237
+ if (owned && !fiber.dead) inserted(fiber, () => fiber.cleanup = instance.mount?.());
1244
1238
  }
1245
- if (key in element && (element.namespaceURI !== SVG || settable(element, key))) try {
1246
- element[key] = next;
1247
- return;
1248
- } catch {}
1249
- element.setAttribute(name, next === true ? "" : String(next));
1239
+ return fiber;
1250
1240
  }
1251
- function applyClaim(element, before, after) {
1252
- const previous = before || {
1253
- className: "",
1254
- declarations: {}
1255
- };
1256
- if (previous.className !== after.className) if (after.className) element.setAttribute("class", after.className);
1257
- else element.removeAttribute("class");
1258
- applyDeclarations(element.style, after.declarations, previous.declarations);
1241
+ function runFunction(fiber, passive) {
1242
+ const result = attempt(fiber, passive, fiber.render);
1243
+ if (result === true) inserted(fiber, () => commit(fiber.scope));
1244
+ else return result;
1259
1245
  }
1260
- function claim(element, appearance, resolved, className, value) {
1261
- const collected = {
1262
- classes: [],
1263
- declarations: {},
1264
- tokens: []
1265
- };
1266
- const entries = appearance?.entries || [];
1267
- let context = appearance?.context;
1268
- let reach = -1;
1269
- if (resolved) collect(createAppearanceToken(resolved), collected, 0);
1270
- appendClasses(collected.classes, className);
1271
- collect(value, collected, 0);
1272
- for (let index = entries.length - 1; index >= 0; index--) collect(entries[index].style, collected, entries[index].hops);
1273
- for (const { appearance, doors } of collected.tokens) {
1274
- for (const block of appearance.blocks || []) collected.classes.push(emitClass(block, doors, element.ownerDocument));
1275
- if (appearance.classes) collected.classes.push(...appearance.classes);
1276
- if (appearance.context && doors >= reach) {
1277
- context = appearance.context;
1278
- reach = doors;
1246
+ function runComponent(fiber, passive) {
1247
+ const result = attempt(fiber, passive, fiber.render);
1248
+ if (result !== true) return result;
1249
+ }
1250
+ function probing(fiber) {
1251
+ const scope = fiber.scope;
1252
+ scope.empty = () => !fiber.children.length;
1253
+ scope.probe = () => {
1254
+ try {
1255
+ scope.probed = { output: consume(fiber, fiber.render) };
1256
+ } catch (thrown) {
1257
+ if (isThenable(thrown)) return thrown;
1279
1258
  }
1280
- }
1281
- return {
1282
- className: [...new Set(collected.classes)].join(" "),
1283
- context,
1284
- declarations: collected.declarations
1285
1259
  };
1286
1260
  }
1287
- function renderedAppearance(fiber) {
1288
- if (fiber.kind != "component" && fiber.kind != "function") return fiber.appearance;
1289
- const style = fiber.props?.style;
1290
- const entries = (fiber.appearance?.entries || []).map(({ hops, style }) => ({
1291
- hops: hops + 1,
1292
- style
1293
- }));
1294
- const inherited = fiber.appearance?.context || appearanceRoot();
1295
- const context = enterAppearance(inherited, latest(fiber.type));
1296
- if (context?.base && context !== inherited) entries.push({
1297
- hops: 0,
1298
- style: context.base
1299
- });
1300
- if (style && !fiber.consumed && !(fiber.instance && "style" in fiber.instance)) entries.push({
1301
- hops: 0,
1302
- style
1303
- });
1304
- return entries.length || context ? {
1305
- context,
1306
- entries
1307
- } : void 0;
1308
- }
1309
- function collect(value, collected, doors) {
1310
- if (!value) return;
1311
- const token = appearanceToken(value);
1312
- if (token) {
1313
- collected.tokens.push({
1314
- appearance: token,
1315
- doors
1316
- });
1317
- Object.assign(collected.declarations, token.declarations);
1318
- return;
1319
- }
1320
- if (typeof value == "string") {
1321
- appendClasses(collected.classes, value);
1322
- return;
1323
- }
1324
- if (Array.isArray(value)) {
1325
- value.forEach((entry) => collect(entry, collected, doors));
1326
- return;
1261
+ function patchFunction(fiber, value, appearance) {
1262
+ const resolved = componentProps(value.type, value.props, appearance);
1263
+ if (fiber.type !== value.type) {
1264
+ untrack(fiber.type, fiber.scope);
1265
+ fiber.type = value.type;
1266
+ fiber.scope.hot = true;
1267
+ track(fiber.type, fiber.scope);
1327
1268
  }
1328
- for (const symbol of Object.getOwnPropertySymbols(value)) {
1329
- const ticket = tickets.get(value[symbol]);
1330
- if (!ticket) continue;
1331
- collected.classes.push(...ticket.classes);
1332
- for (const carried of ticket.tokens) collected.tokens.push({
1333
- appearance: carried.appearance,
1334
- doors: carried.doors + doors
1335
- });
1269
+ fiber.appearance = resolved.appearance;
1270
+ fiber.props = observe(resolved.props);
1271
+ rerun(fiber, () => runFunction(fiber, passiveRender));
1272
+ }
1273
+ function patchComponent(fiber, value, appearance) {
1274
+ const resolved = isVNode(value) ? componentProps(value.type, value.props, appearance) : {
1275
+ appearance,
1276
+ props: fiber.props
1277
+ };
1278
+ fiber.appearance = resolved.appearance;
1279
+ const props = isVNode(value) ? observe(resolved.props) : resolved.props;
1280
+ if (isVNode(value) && props !== fiber.props) {
1281
+ const instance = fiber.instance;
1282
+ if (passiveRender) fiber.applied = true;
1283
+ if (instance instanceof Component) instance.props = props;
1284
+ else instance.set(merge(fiber.props, props));
1336
1285
  }
1337
- for (const key of Object.keys(value)) collected.declarations[key] = value[key];
1286
+ fiber.props = props;
1287
+ rerun(fiber, () => runComponent(fiber, passiveRender));
1338
1288
  }
1339
- function appendClasses(classes, value) {
1340
- if (typeof value == "string") classes.push(...value.split(/\s+/).filter(Boolean));
1289
+ function rerun(fiber, run) {
1290
+ claim$1(fiber.scope);
1291
+ run();
1292
+ settle$1(fiber.scope);
1341
1293
  }
1342
- function restoreTarget(event) {
1343
- const element = event.target;
1344
- const fiber = controlled.get(element);
1345
- if (fiber && event.type == settles(fiber.props, element)) queueMicrotask(() => afterFlush(() => restore(fiber)));
1294
+ function unmountComponent(fiber) {
1295
+ if (typeof fiber.cleanup == "function") fiber.cleanup();
1296
+ fiber.childContext?.pop();
1297
+ if (fiber.owned && !fiber.instance.get(null)) fiber.instance.set(null);
1346
1298
  }
1347
- function settles(props, element) {
1348
- if (props.onInput) return "input";
1349
- if (props.onChange) return "change";
1350
- return element.type == "checkbox" || element.type == "radio" || element.localName == "select" ? "change" : "input";
1299
+ function renderable(value) {
1300
+ return value instanceof Model && typeof value.render == "function";
1351
1301
  }
1352
- function restore(fiber) {
1353
- const element = fiber.start;
1354
- for (const key of CONTROLS) {
1355
- const value = fiber.props[key];
1356
- if (value == null || fiber.dead) continue;
1357
- if (key == "value" ? String(element.value) !== String(value) : element[key] !== value) element[key] = value;
1302
+ function merge(previous, next) {
1303
+ const output = {};
1304
+ for (const key in previous) output[key] = void 0;
1305
+ return {
1306
+ ...output,
1307
+ ...next
1308
+ };
1309
+ }
1310
+
1311
+ //#endregion
1312
+ //#region src/render/mount.ts
1313
+ function complete(fiber, work) {
1314
+ try {
1315
+ work();
1316
+ } catch (error) {
1317
+ if (!hold(fiber, error)) unmountFiber(fiber);
1318
+ throw error;
1358
1319
  }
1320
+ return fiber;
1359
1321
  }
1360
- function settable(element, key) {
1361
- let target = element;
1362
- let descriptor;
1363
- while (!(descriptor = Object.getOwnPropertyDescriptor(target, key))) target = Object.getPrototypeOf(target);
1364
- return !!(descriptor.set || descriptor.writable);
1322
+ function mount(value, parent, before, context, boundary, appearance) {
1323
+ if (typeof value == "string" || typeof value == "number" || typeof value == "bigint") {
1324
+ const text = document.createTextNode(String(value));
1325
+ parent.insertBefore(text, before);
1326
+ return {
1327
+ kind: "text",
1328
+ value,
1329
+ context,
1330
+ start: text,
1331
+ end: text,
1332
+ children: []
1333
+ };
1334
+ }
1335
+ if (renderable(value)) return mountComponent(value, parent, before, context, boundary, appearance);
1336
+ if (isCollection(value)) return mountCollection(value, parent, before, context, boundary, appearance);
1337
+ if (!isVNode(value)) throw new TypeError(`Cannot render ${String(value)}.`);
1338
+ if (value.type === Fragment$1) return mountFragment(value, parent, before, context, boundary, appearance);
1339
+ if (value.type === PORTAL) return mountPortal(value, parent, before, context, boundary, appearance);
1340
+ if (typeof value.type == "string") return mountElement(value, parent, before, context, boundary, appearance);
1341
+ if (typeof value.type != "function") throw new Error(`Cannot render ${String(value.type)}.`);
1342
+ if (value.type.prototype instanceof Model) return mountOwnedComponent(value, parent, before, context, boundary, appearance);
1343
+ return mountFunction(value, parent, before, context, boundary, appearance);
1365
1344
  }
1366
- function applyRef(ref, value) {
1367
- if (typeof ref == "function") ref(value);
1368
- else if (ref && typeof ref == "object" && "current" in ref) ref.current = value;
1345
+ function mountFragment(value, parent, before, context, boundary, appearance) {
1346
+ const fiber = range("fragment", parent, before, context);
1347
+ fiber.key = value.key;
1348
+ fiber.type = Fragment$1;
1349
+ fiber.appearance = appearance;
1350
+ return complete(fiber, () => {
1351
+ reconcile(fiber, value.props.children, context, boundary, appearance);
1352
+ });
1353
+ }
1354
+ function patchText(fiber, value) {
1355
+ const next = String(value);
1356
+ if (fiber.start.nodeValue !== next) fiber.start.nodeValue = next;
1357
+ fiber.value = value;
1358
+ }
1359
+ function patchFragment(fiber, value, context, appearance) {
1360
+ fiber.context = context;
1361
+ fiber.appearance = appearance;
1362
+ reconcile(fiber, value.props.children, context, fiber.boundary, appearance);
1369
1363
  }
1370
1364
  function unmountFiber(fiber) {
1371
1365
  fiber.dead = true;
@@ -1376,30 +1370,88 @@ function unmountFiber(fiber) {
1376
1370
  if (fiber.kind == "function") untrack(fiber.type, fiber.scope);
1377
1371
  if (fiber.scope) dispose(fiber.scope);
1378
1372
  fiber.release?.();
1379
- if (fiber.kind == "element") {
1380
- applyRef(fiber.props?.ref, null);
1381
- for (const [id, listener] of fiber.events) {
1382
- const [name, capture] = id.split(":");
1383
- fiber.start.removeEventListener(name, listener, capture === "true");
1384
- }
1373
+ if (fiber.kind == "element") unmountElement(fiber);
1374
+ else if (fiber.kind == "component") unmountComponent(fiber);
1375
+ else if (fiber.kind == "portal") unmountPortal(fiber);
1376
+ removeRange(fiber.start, fiber.end);
1377
+ }
1378
+
1379
+ //#endregion
1380
+ //#region src/render/render.ts
1381
+ const roots = /* @__PURE__ */ new WeakMap();
1382
+ const focusing = [];
1383
+ let passiveRender = false;
1384
+ let depth = 0;
1385
+ function render(node, container) {
1386
+ roots.get(container)?.();
1387
+ container.replaceChildren();
1388
+ const context = new Context(Context.root);
1389
+ const fiber = range("fragment", container, null, context);
1390
+ try {
1391
+ pass(() => {
1392
+ const appearanceContext = appearanceRoot();
1393
+ reconcile(fiber, node, context, void 0, appearanceContext ? {
1394
+ context: appearanceContext,
1395
+ entries: []
1396
+ } : void 0);
1397
+ });
1398
+ } catch (error) {
1399
+ unmountFiber(fiber);
1400
+ context.pop();
1401
+ throw error;
1385
1402
  }
1386
- if (fiber.kind == "component") {
1387
- if (typeof fiber.cleanup == "function") fiber.cleanup();
1388
- fiber.childContext?.pop();
1389
- if (fiber.owned && !fiber.instance.get(null)) fiber.instance.set(null);
1390
- } else if (fiber.kind == "portal") {
1391
- fiber.portalStart.remove();
1392
- fiber.portalEnd.remove();
1403
+ let active = true;
1404
+ const unmount = () => {
1405
+ if (!active) return;
1406
+ active = false;
1407
+ unmountFiber(fiber);
1408
+ context.pop();
1409
+ roots.delete(container);
1410
+ };
1411
+ roots.set(container, unmount);
1412
+ return unmount;
1413
+ }
1414
+ function pass(work) {
1415
+ depth++;
1416
+ try {
1417
+ return work();
1418
+ } finally {
1419
+ if (!--depth) {
1420
+ settle();
1421
+ focus();
1422
+ }
1393
1423
  }
1394
- removeRange(fiber.start, fiber.end);
1395
1424
  }
1396
- function removeRange(start, end) {
1397
- let node = start;
1398
- while (true) {
1399
- const next = node.nextSibling;
1400
- node.remove();
1401
- if (node === end) break;
1402
- node = next;
1425
+ function focus() {
1426
+ for (const element of focusing.splice(0)) if (element.isConnected) element.focus();
1427
+ }
1428
+ function attempt(fiber, passive, render) {
1429
+ const previous = passiveRender;
1430
+ const scope = fiber.scope;
1431
+ const probed = scope.probed;
1432
+ const empty = !fiber.children.length;
1433
+ scope.probed = void 0;
1434
+ passiveRender ||= passive;
1435
+ if (passive && !depth && empty && !fiber.stash) fiber.staging ||= fragment();
1436
+ const run = () => pass(() => {
1437
+ try {
1438
+ reconcile(fiber, probed ? probed.output : consume(fiber, render), scope.childContext, fiber.boundary, renderedAppearance(fiber));
1439
+ if (fiber.staging) {
1440
+ fiber.end.parentNode.insertBefore(fiber.staging, fiber.end);
1441
+ attach(fiber.staging);
1442
+ fiber.staging = void 0;
1443
+ }
1444
+ if (!fiber.recovering) unwait(fiber);
1445
+ fiber.retried = void 0;
1446
+ return true;
1447
+ } catch (thrown) {
1448
+ return suspend(fiber, thrown, passive, empty);
1449
+ }
1450
+ });
1451
+ try {
1452
+ return passive ? batched(run) : run();
1453
+ } finally {
1454
+ passiveRender = previous;
1403
1455
  }
1404
1456
  }
1405
1457