@expressive/dom 0.1.0 → 0.3.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,357 +1,10 @@
1
- import { a as vnode, i as isVNode, n as childrenOf, r as createPortal, t as PORTAL } from "./chunk-vnode-DA7cLTKP.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-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";
2
3
  import "./jsx-runtime.js";
3
- import { Component, Context, State, has, map, pending, unbind } from "@expressive/mvc";
4
+ import { Component, Context, State, has, map } from "@expressive/mvc";
4
5
  import { watch } from "@expressive/mvc/observable";
5
- import { Fragment } from "@expressive/mvc/runtime";
6
+ import { Fragment as Fragment$1, compose } from "@expressive/mvc/jsx-runtime";
6
7
 
7
- //#region src/scheduler.ts
8
- const urgent = /* @__PURE__ */ new Set();
9
- const passive = /* @__PURE__ */ new Set();
10
- const after = [];
11
- let depth$1 = 0;
12
- let urgentQueued = false;
13
- let passiveQueued = false;
14
- function flush(scopes) {
15
- for (const scope of scopes) {
16
- scopes.delete(scope);
17
- scope.queued = void 0;
18
- let waiting = void 0;
19
- try {
20
- waiting = scope.update(false);
21
- } catch (error) {
22
- console.error(error);
23
- }
24
- settle$1(scope);
25
- if (!waiting) unblock(scope);
26
- }
27
- }
28
- function flushUrgent() {
29
- urgentQueued = false;
30
- flush(urgent);
31
- for (const run of after.splice(0)) run();
32
- }
33
- function afterFlush(run) {
34
- after.push(run);
35
- if (!urgentQueued) {
36
- urgentQueued = true;
37
- queueMicrotask(flushUrgent);
38
- }
39
- }
40
- function flushPassive() {
41
- passiveQueued = false;
42
- const batch = [...passive].filter((scope) => scope.queued === "passive");
43
- passive.clear();
44
- for (const scope of batch) {
45
- const waiting = scope.probe?.();
46
- if (waiting) return defer(batch, waiting, scope);
47
- }
48
- batch.sort((a, b) => Number(!!b.empty?.()) - Number(!!a.empty?.()));
49
- for (let index = 0; index < batch.length; index++) {
50
- const scope = batch[index];
51
- if (scope.queued !== "passive") continue;
52
- scope.queued = void 0;
53
- let waiting = void 0;
54
- try {
55
- waiting = scope.update(true);
56
- } catch (error) {
57
- console.error(error);
58
- }
59
- settle$1(scope);
60
- if (waiting) return defer(batch.slice(index + 1), waiting, scope);
61
- unblock(scope);
62
- }
63
- }
64
- function defer(scopes, waiting, source) {
65
- const held = scopes.filter((scope) => scope.queued === "passive");
66
- for (const scope of held) {
67
- scope.queued = "deferred";
68
- scope.probed = void 0;
69
- }
70
- const resume = () => {
71
- for (const scope of held) if (scope.queued === "deferred") {
72
- scope.queued = void 0;
73
- transition(() => schedule(scope));
74
- }
75
- };
76
- (source.blocking ||= []).push(resume);
77
- waiting.then(resume, resume);
78
- }
79
- function unblock(scope) {
80
- const { blocking } = scope;
81
- scope.blocking = void 0;
82
- blocking?.forEach((resume) => resume());
83
- }
84
- function release(holds) {
85
- holds?.forEach((held) => held());
86
- }
87
- function settle$1(scope) {
88
- const { holds } = scope;
89
- scope.holds = void 0;
90
- release(holds);
91
- }
92
- function schedule(scope) {
93
- const held = pending();
94
- if (held) (scope.holds ||= []).push(held);
95
- scope.probed = void 0;
96
- if (!depth$1) {
97
- passive.delete(scope);
98
- scope.queued = "urgent";
99
- urgent.add(scope);
100
- if (!urgentQueued) {
101
- urgentQueued = true;
102
- queueMicrotask(flushUrgent);
103
- }
104
- return;
105
- }
106
- if (scope.queued && scope.queued !== "deferred") return;
107
- scope.queued = "passive";
108
- passive.add(scope);
109
- if (!passiveQueued) {
110
- passiveQueued = true;
111
- setTimeout(flushPassive);
112
- }
113
- }
114
- function transition(work) {
115
- depth$1++;
116
- try {
117
- work();
118
- } finally {
119
- depth$1--;
120
- }
121
- }
122
- function claim$1(scope) {
123
- urgent.delete(scope);
124
- passive.delete(scope);
125
- scope.queued = void 0;
126
- scope.probed = void 0;
127
- }
128
- function unschedule(scope) {
129
- urgent.delete(scope);
130
- passive.delete(scope);
131
- scope.queued = void 0;
132
- scope.probed = void 0;
133
- settle$1(scope);
134
- unblock(scope);
135
- }
136
-
137
- //#endregion
138
- //#region src/adapter.ts
139
- let current;
140
- let collecting;
141
- function enter(scope, render) {
142
- const parent = current;
143
- const releases = collecting;
144
- const next = [];
145
- current = scope;
146
- collecting = next;
147
- scope.childContext = scope.context;
148
- scope.useIndex = 0;
149
- try {
150
- const output = render();
151
- if (scope.kind == "function" && scope.useIndex !== scope.uses.length) throw new Error("State.use() calls must keep the same order on every function-component render.");
152
- return output;
153
- } finally {
154
- current = parent;
155
- collecting = releases;
156
- scope.subscriptions.forEach((release) => release());
157
- scope.subscriptions = next;
158
- }
159
- }
160
- function dispose(scope) {
161
- scope.active = false;
162
- unschedule(scope);
163
- scope.subscriptions.forEach((release) => release());
164
- scope.subscriptions = [];
165
- for (let i = scope.uses.length - 1; i >= 0; i--) {
166
- const slot = scope.uses[i];
167
- slot.release();
168
- if (typeof slot.cleanup == "function") slot.cleanup();
169
- slot.context.pop();
170
- slot.instance.set(null);
171
- }
172
- scope.uses = [];
173
- }
174
- function commit(scope) {
175
- for (const slot of scope.uses) if (!slot.mounted) {
176
- slot.mounted = true;
177
- slot.cleanup = slot.instance.mount?.();
178
- }
179
- }
180
- function requireScope() {
181
- if (!current) throw new Error("State.get() and State.use() may only run while @expressive/dom is rendering.");
182
- return current;
183
- }
184
- function tracked(target, required) {
185
- const scope = requireScope();
186
- let proxy = target;
187
- let first = true;
188
- const release = watch(target, (next) => {
189
- proxy = next;
190
- if (!first && scope.active) schedule(scope);
191
- first = false;
192
- }, required, transition);
193
- collecting.push(release);
194
- return proxy;
195
- }
196
- State.get = function get(argument) {
197
- const scope = requireScope();
198
- const instance = scope.childContext.get(this, argument === false ? false : true);
199
- if (!instance) return void 0;
200
- const proxy = tracked(instance, argument === true);
201
- if (typeof argument != "function") return proxy;
202
- const refresh = ((action) => {
203
- if (typeof action == "function") action = action();
204
- schedule(scope);
205
- return action instanceof Promise ? action.finally(() => schedule(scope)) : void 0;
206
- });
207
- return argument.call(proxy, proxy, refresh) ?? null;
208
- };
209
- State.use = function use(...args) {
210
- const scope = requireScope();
211
- if (scope.kind != "function") throw new Error("State.use() is only available at the top level of a function component.");
212
- const index = scope.useIndex++;
213
- let slot = scope.uses[index];
214
- if (slot && slot.Type !== this) throw new Error("State.use() calls must keep the same order on every function-component render.");
215
- if (!slot) {
216
- let instance;
217
- const assign = (value) => typeof value == "object" && value && instance.set(value);
218
- let apply = (...values) => Promise.all(values.flat().map(assign));
219
- instance = new this((self) => {
220
- const own = self;
221
- if (typeof own.use == "function") {
222
- apply = own.use.bind(own);
223
- apply(...args);
224
- return;
225
- }
226
- return args;
227
- });
228
- const context = scope.childContext.push(instance);
229
- slot = {
230
- Type: this,
231
- context,
232
- instance,
233
- proxy: instance,
234
- release: void 0,
235
- apply
236
- };
237
- let first = true;
238
- slot.release = watch(instance, (proxy) => {
239
- slot.proxy = proxy;
240
- if (!first && scope.active) schedule(scope);
241
- first = false;
242
- }, void 0, transition);
243
- slot.apply = apply;
244
- scope.uses.push(slot);
245
- } else slot.apply(...args);
246
- scope.childContext = slot.context;
247
- return slot.proxy;
248
- };
249
- Object.defineProperty(Component, "use", {
250
- configurable: true,
251
- value() {
252
- throw new Error(`${this} is a Component - render it instead of calling use().`);
253
- }
254
- });
255
- Component.on({
256
- type(type) {
257
- subcomponents(type.prototype);
258
- },
259
- before(self) {
260
- subcomponents(self, true);
261
- }
262
- });
263
- function subcomponents(target, configurable) {
264
- for (const key of Object.getOwnPropertyNames(target)) {
265
- if (!/^[A-Z]/.test(key)) continue;
266
- const { value } = Object.getOwnPropertyDescriptor(target, key);
267
- if (typeof value != "function") continue;
268
- Object.defineProperty(target, key, {
269
- configurable,
270
- get() {
271
- const owner = this.is;
272
- let render = unbind(value);
273
- const Subcomponent = (props) => render.call(tracked(owner), props);
274
- Object.defineProperty(owner, key, {
275
- configurable: true,
276
- get: () => Subcomponent,
277
- set(next) {
278
- render = next;
279
- }
280
- });
281
- return Subcomponent;
282
- },
283
- set(next) {
284
- Object.defineProperty(this, key, {
285
- value: next,
286
- writable: true,
287
- enumerable: true,
288
- configurable: true
289
- });
290
- subcomponents(this, true);
291
- }
292
- });
293
- }
294
- }
295
-
296
- //#endregion
297
- //#region src/context.ts
298
- function Consumer(props) {
299
- return props.for.get((value) => props.children(value));
300
- }
301
- function Provider(_props) {
302
- throw new Error("Provider must be rendered by @expressive/dom.");
303
- }
304
- function provide(context, props) {
305
- const { for: input, is, children: _children, fallback: _fallback, name: _name, ...rest } = props;
306
- const mount = [];
307
- let single;
308
- const solo = State.is(input) || input instanceof State;
309
- context.set(input || {}, (state, owned) => {
310
- if (solo) single = state;
311
- is?.(state);
312
- if (owned) {
313
- let cleanup;
314
- mount.push(() => {
315
- cleanup = state.mount?.();
316
- });
317
- return () => cleanup?.();
318
- }
319
- });
320
- if (solo && !single) {
321
- const Type = input instanceof State ? input.constructor : input;
322
- single = context.get(Type, false);
323
- }
324
- if (single && Object.keys(rest).length) single.set(rest);
325
- return () => mount.forEach((commit) => commit());
326
- }
327
-
328
- //#endregion
329
- //#region src/lazy.ts
330
- function lazy(load) {
331
- let pending;
332
- let resolved;
333
- let rejected;
334
- let failed = false;
335
- return function Lazy(props) {
336
- if (failed) throw rejected;
337
- if (resolved) return vnode(resolved, props);
338
- if (!pending) pending = load().then((module) => {
339
- const output = typeof module == "function" ? module : module?.default;
340
- if (typeof output != "function") {
341
- failed = true;
342
- rejected = /* @__PURE__ */ new Error("lazy() loader resolved no component.");
343
- return;
344
- }
345
- resolved = output;
346
- }, (error) => {
347
- failed = true;
348
- rejected = error;
349
- });
350
- throw pending;
351
- };
352
- }
353
-
354
- //#endregion
355
8
  //#region src/css.ts
356
9
  const unitless = /* @__PURE__ */ new Map();
357
10
  let probe;
@@ -457,7 +110,7 @@ const bases = /* @__PURE__ */ new WeakMap();
457
110
  const chains = /* @__PURE__ */ new WeakMap();
458
111
  const contexts = /* @__PURE__ */ new WeakMap();
459
112
  const rootScopes = /* @__PURE__ */ new WeakMap();
460
- const styles = /* @__PURE__ */ new WeakMap();
113
+ const STYLES = Symbol("@expressive/dom.styles");
461
114
  const entered = /* @__PURE__ */ new WeakSet();
462
115
  const globals = [];
463
116
  let globalContext;
@@ -546,14 +199,16 @@ function baseToken(scope) {
546
199
  }
547
200
  function style$1(type, rules) {
548
201
  if (entered.has(type)) throw new Error("Cannot add styles after a component has rendered.");
549
- const maps = styles.get(type);
550
- if (maps) maps.push(rules);
202
+ if (Object.hasOwn(type, STYLES)) type[STYLES].push(rules);
551
203
  else {
552
204
  const label = type.displayName || type.name;
553
- styles.set(type, [rules]);
205
+ Object.defineProperty(type, STYLES, {
206
+ configurable: true,
207
+ value: [rules]
208
+ });
554
209
  registerAppearance(type, (parent) => {
555
210
  entered.add(type);
556
- return extendContext(parent, styles.get(type), label);
211
+ return extendContext(parent, type[STYLES], label);
557
212
  });
558
213
  }
559
214
  return type;
@@ -747,6 +402,71 @@ function serialize(document, declarations) {
747
402
  return value.cssText;
748
403
  }
749
404
 
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
431
+ const DETACHED = /* @__PURE__ */ new WeakMap();
432
+ let batch;
433
+ /** Run `run` once `fiber` is on the page: now, after the current batch, or when its detached root attaches. */
434
+ function inserted(fiber, run) {
435
+ enqueue([fiber, run]);
436
+ }
437
+ /** A fragment whose commits wait until it attaches. */
438
+ function fragment() {
439
+ const root = document.createDocumentFragment();
440
+ DETACHED.set(root, []);
441
+ return root;
442
+ }
443
+ function attach(root) {
444
+ const held = DETACHED.get(root);
445
+ DETACHED.delete(root);
446
+ held?.forEach(enqueue);
447
+ }
448
+ /** Defer commits made during `work` until it returns or throws. */
449
+ function batched(work) {
450
+ if (batch) return work();
451
+ const entries = batch = [];
452
+ try {
453
+ return work();
454
+ } finally {
455
+ batch = void 0;
456
+ entries.forEach(deliver);
457
+ }
458
+ }
459
+ function enqueue(entry) {
460
+ if (batch) batch.push(entry);
461
+ else deliver(entry);
462
+ }
463
+ function deliver(entry) {
464
+ const [fiber, run] = entry;
465
+ const held = DETACHED.get(fiber.start.getRootNode());
466
+ if (held) held.push(entry);
467
+ else if (!fiber.dead) run();
468
+ }
469
+
750
470
  //#endregion
751
471
  //#region src/render.ts
752
472
  const roots = /* @__PURE__ */ new WeakMap();
@@ -769,7 +489,7 @@ const focusing = [];
769
489
  const controlled = /* @__PURE__ */ new WeakMap();
770
490
  const restoring = /* @__PURE__ */ new WeakSet();
771
491
  let passiveRender = false;
772
- let inserting;
492
+ let holding;
773
493
  let depth = 0;
774
494
  let settling = false;
775
495
  let rendering;
@@ -830,11 +550,17 @@ function makeScope(kind, context, update) {
830
550
  uses: []
831
551
  };
832
552
  }
553
+ function park(fiber) {
554
+ move(fiber, fragment(), null);
555
+ }
833
556
  function complete(fiber, work) {
834
557
  try {
835
558
  work();
836
559
  } catch (error) {
837
- unmountFiber(fiber);
560
+ if (holding && error === holding.thrown) {
561
+ park(fiber);
562
+ holding.fiber = fiber;
563
+ } else unmountFiber(fiber);
838
564
  throw error;
839
565
  }
840
566
  return fiber;
@@ -875,21 +601,20 @@ function mount(value, parent, before, context, boundary, appearance) {
875
601
  children: []
876
602
  };
877
603
  }
878
- if (value instanceof Component) return mountComponent(value, parent, before, context, boundary, appearance);
604
+ if (renderable(value)) return mountComponent(value, parent, before, context, boundary, appearance);
879
605
  if (isCollection(value)) return mountCollection(value, parent, before, context, boundary, appearance);
880
606
  if (!isVNode(value)) throw new TypeError(`Cannot render ${String(value)}.`);
881
- if (value.type === Fragment) return mountFragment(value, parent, before, context, boundary, appearance);
607
+ if (value.type === Fragment$1) return mountFragment(value, parent, before, context, boundary, appearance);
882
608
  if (value.type === PORTAL) return mountPortal(value, parent, before, context, boundary, appearance);
883
- if (value.type === Provider) return mountProvider(value, parent, before, context, boundary, appearance);
884
609
  if (typeof value.type == "string") return mountElement(value, parent, before, context, boundary, appearance);
885
610
  if (typeof value.type != "function") throw new Error(`Cannot render ${String(value.type)}.`);
886
- if (value.type.prototype instanceof Component) return mountOwnedComponent(value, parent, before, context, boundary, appearance);
611
+ if (value.type.prototype instanceof State) return mountOwnedComponent(value, parent, before, context, boundary, appearance);
887
612
  return mountFunction(value, parent, before, context, boundary, appearance);
888
613
  }
889
614
  function mountFragment(value, parent, before, context, boundary, appearance) {
890
615
  const fiber = range("fragment", parent, before, context);
891
616
  fiber.key = value.key;
892
- fiber.type = Fragment;
617
+ fiber.type = Fragment$1;
893
618
  fiber.appearance = appearance;
894
619
  return complete(fiber, () => {
895
620
  reconcile(fiber, value.props.children, context, boundary, appearance);
@@ -904,7 +629,11 @@ function mountFunction(value, parent, before, context, boundary, appearance) {
904
629
  fiber.boundary = boundary;
905
630
  fiber.appearance = resolved.appearance;
906
631
  fiber.scope = makeScope("function", context, (passive) => runFunction(fiber, passive));
907
- fiber.render = () => enter(fiber.scope, () => fiber.type(fiber.props));
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);
908
637
  probing(fiber);
909
638
  return complete(fiber, () => {
910
639
  runFunction(fiber, passiveRender);
@@ -912,7 +641,10 @@ function mountFunction(value, parent, before, context, boundary, appearance) {
912
641
  }
913
642
  function mountOwnedComponent(value, parent, before, context, boundary, appearance) {
914
643
  const resolved = componentProps(value.type, value.props, appearance);
915
- return mountComponent(new value.type(observe(resolved.props)), parent, before, context, boundary, resolved.appearance, true, value.key);
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);
916
648
  }
917
649
  function runFunction(fiber, passive) {
918
650
  const result = attempt(fiber, passive, fiber.render);
@@ -930,12 +662,19 @@ function probing(fiber) {
930
662
  }
931
663
  };
932
664
  }
933
- function mountComponent(instance, parent, before, context, inherited, appearance, owned = false, key) {
665
+ function mountComponent(instance, parent, before, context, inherited, appearance, owned = false, key, props = instance.props) {
934
666
  const fiber = range("component", parent, before, context);
935
667
  const childContext = context.push(instance);
936
- const ownBoundary = instance.fallback !== false || instance.catch ? {
937
- catch: instance.catch?.bind(instance),
938
- fallback: () => instance.fallback,
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
+ },
939
678
  owner: fiber,
940
679
  parent: inherited
941
680
  } : inherited;
@@ -945,11 +684,11 @@ function mountComponent(instance, parent, before, context, inherited, appearance
945
684
  fiber.instance = instance;
946
685
  fiber.key = owned ? key : instance.key;
947
686
  fiber.type = instance.constructor;
948
- fiber.props = instance.props;
687
+ fiber.props = props;
949
688
  fiber.owned = owned;
950
689
  fiber.appearance = appearance;
951
690
  fiber.scope = makeScope("component", childContext, (passive) => runComponent(fiber, passive));
952
- fiber.render = () => enter(fiber.scope, () => instance.render.call(fiber.value, instance.props));
691
+ fiber.render = () => enter(fiber.scope, () => compose.call(fiber.value, fiber.props));
953
692
  probing(fiber);
954
693
  let first = true;
955
694
  let proxy = instance;
@@ -962,10 +701,13 @@ function mountComponent(instance, parent, before, context, inherited, appearance
962
701
  first = false;
963
702
  }, void 0, transition);
964
703
  Object.defineProperty(fiber, "value", { get: () => proxy });
965
- complete(fiber, () => {
966
- runComponent(fiber, passiveRender);
967
- });
968
- if (owned) inserted(fiber, () => fiber.cleanup = instance.mount?.());
704
+ try {
705
+ complete(fiber, () => {
706
+ runComponent(fiber, passiveRender);
707
+ });
708
+ } finally {
709
+ if (owned && !fiber.dead) inserted(fiber, () => fiber.cleanup = instance.mount?.());
710
+ }
969
711
  return fiber;
970
712
  }
971
713
  function runComponent(fiber, passive) {
@@ -995,31 +737,9 @@ function runCollection(fiber, passive) {
995
737
  return value instanceof map.Managed ? [...value.values()] : [...value];
996
738
  });
997
739
  }
998
- function mountProvider(value, parent, before, context, inherited, appearance) {
999
- const fiber = range("provider", parent, before, context);
1000
- const childContext = new Context(context);
1001
- fiber.key = value.key;
1002
- fiber.type = Provider;
1003
- fiber.props = value.props;
1004
- fiber.appearance = appearance;
1005
- fiber.childContext = childContext;
1006
- const commit = provide(childContext, value.props);
1007
- const boundary = value.props.fallback !== void 0 ? {
1008
- fallback: () => fiber.props.fallback,
1009
- owner: fiber,
1010
- parent: inherited
1011
- } : inherited;
1012
- fiber.boundary = boundary;
1013
- if (boundary !== inherited) fiber.ownBoundary = boundary;
1014
- complete(fiber, () => {
1015
- reconcile(fiber, value.props.children, childContext, boundary, appearance);
1016
- });
1017
- commit();
1018
- return fiber;
1019
- }
1020
740
  function mountPortal(value, parent, before, context, boundary, appearance) {
1021
741
  const marker = document.createComment("portal");
1022
- const container = value.props.container;
742
+ const container = target(value.props.into, parent);
1023
743
  const portalStart = document.createComment("portal-root");
1024
744
  const portalEnd = document.createComment("/portal-root");
1025
745
  parent.insertBefore(marker, before);
@@ -1043,6 +763,14 @@ function mountPortal(value, parent, before, context, boundary, appearance) {
1043
763
  reconcilePortal(output, value.props.children, context, boundary, appearance);
1044
764
  });
1045
765
  }
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];
773
+ }
1046
774
  function mountElement(value, parent, before, context, boundary, appearance) {
1047
775
  const tag = value.type;
1048
776
  let host = parent;
@@ -1085,38 +813,31 @@ function attempt(fiber, passive, render) {
1085
813
  const previous = passiveRender;
1086
814
  const scope = fiber.scope;
1087
815
  const probed = scope.probed;
816
+ const empty = !fiber.children.length;
1088
817
  scope.probed = void 0;
1089
818
  passiveRender ||= passive;
1090
- if (passive && !depth && !fiber.children.length && !fiber.stash) fiber.staging ||= document.createDocumentFragment();
1091
- const outer = inserting;
1092
- if (fiber.staging) inserting = fiber.inserted ||= [];
1093
- try {
1094
- return pass(() => {
1095
- try {
1096
- reconcile(fiber, probed ? probed.output : consume(fiber, render), scope.childContext, fiber.boundary, renderedAppearance(fiber));
1097
- if (fiber.staging) {
1098
- const queued = fiber.inserted;
1099
- fiber.end.parentNode.insertBefore(fiber.staging, fiber.end);
1100
- fiber.staging = fiber.inserted = void 0;
1101
- inserting = outer;
1102
- queued.forEach((run) => run());
1103
- }
1104
- if (!fiber.recovering) unwait(fiber);
1105
- fiber.retried = void 0;
1106
- return true;
1107
- } catch (thrown) {
1108
- return suspend(fiber, thrown, 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;
1109
827
  }
1110
- });
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();
1111
837
  } finally {
1112
838
  passiveRender = previous;
1113
- inserting = outer;
1114
839
  }
1115
840
  }
1116
- function inserted(fiber, run) {
1117
- if (inserting) inserting.push(() => fiber.dead || run());
1118
- else run();
1119
- }
1120
841
  function observe(props) {
1121
842
  if (!("style" in props)) return props;
1122
843
  let output = observed.get(props);
@@ -1238,11 +959,15 @@ function moveRange(start, end, target) {
1238
959
  node = next;
1239
960
  }
1240
961
  }
1241
- function suspend(fiber, thrown, passive) {
962
+ function suspend(fiber, thrown, passive, empty) {
1242
963
  const boundary = fiber.boundary;
1243
964
  if (isThenable(thrown)) {
1244
965
  if (!boundary) throw thrown;
1245
- if (passive && !fiber.children.length && depth > 1) throw thrown;
966
+ if (passive && empty && depth > 1) {
967
+ if (holding?.thrown !== thrown) holding = { thrown };
968
+ throw thrown;
969
+ }
970
+ holding = void 0;
1246
971
  if (!passive) wait(fiber, boundary);
1247
972
  const scope = fiber.scope;
1248
973
  let held = scope.holds;
@@ -1308,26 +1033,32 @@ function reconcileChildren(owner, parent, before, value, context, boundary, appe
1308
1033
  let child = key !== null && key !== void 0 ? keyed.get(key) : old[index]?.key == null ? old[index] : void 0;
1309
1034
  if (child && used.has(child)) child = void 0;
1310
1035
  if (child) used.add(child);
1311
- next.push(patch(child, value, parent, before, context, boundary, appearance));
1036
+ const fiber = patch(child, value, parent, before, context, boundary, appearance);
1037
+ if (fiber !== child) used.delete(child);
1038
+ next.push(fiber);
1312
1039
  }
1313
1040
  } 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
+ }
1314
1046
  owner.children = [...next, ...old.filter((child) => !child.dead && !next.includes(child))];
1315
1047
  throw error;
1316
1048
  }
1317
1049
  for (const child of old) if (!used.has(child)) unmountFiber(child);
1318
1050
  let anchor = before;
1319
1051
  for (let index = next.length - 1; index >= 0; index--) {
1320
- move(next[index], parent, anchor);
1321
- anchor = next[index].start;
1052
+ const child = next[index];
1053
+ const root = child.start.getRootNode();
1054
+ move(child, parent, anchor);
1055
+ anchor = child.start;
1056
+ if (child.start.getRootNode() !== root) attach(root);
1322
1057
  }
1323
1058
  owner.children = next;
1324
1059
  }
1325
1060
  function patch(old, value, parent, before, context, boundary, appearance) {
1326
- if (!old || !compatible(old, value)) {
1327
- const next = mount(value, parent, old?.start || before, context, boundary, appearance);
1328
- if (old) unmountFiber(old);
1329
- return next;
1330
- }
1061
+ if (!old || !compatible(old, value)) return mount(value, parent, old?.start || before, context, boundary, appearance);
1331
1062
  if (old.ownBoundary) old.ownBoundary.parent = boundary;
1332
1063
  old.boundary = old.ownBoundary || boundary;
1333
1064
  if (old.kind == "collection") {
@@ -1349,28 +1080,30 @@ function patch(old, value, parent, before, context, boundary, appearance) {
1349
1080
  } else if (old.kind == "function") {
1350
1081
  const vnode = value;
1351
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
+ }
1352
1089
  old.appearance = resolved.appearance;
1353
1090
  old.props = observe(resolved.props);
1354
1091
  rerun(old, () => runFunction(old, passiveRender));
1355
1092
  } else if (old.kind == "component") {
1356
1093
  const resolved = isVNode(value) ? componentProps(value.type, value.props, appearance) : {
1357
1094
  appearance,
1358
- props: old.instance.props
1095
+ props: old.props
1359
1096
  };
1360
1097
  old.appearance = resolved.appearance;
1361
1098
  const props = isVNode(value) ? observe(resolved.props) : resolved.props;
1362
- if (isVNode(value) && props !== old.instance.props) {
1099
+ if (isVNode(value) && props !== old.props) {
1100
+ const instance = old.instance;
1363
1101
  if (passiveRender) old.applied = true;
1364
- old.instance.props = props;
1102
+ if (instance instanceof Component) instance.props = props;
1103
+ else instance.set(merge(old.props, props));
1365
1104
  }
1366
1105
  old.props = props;
1367
1106
  rerun(old, () => runComponent(old, passiveRender));
1368
- } else if (old.kind == "provider") {
1369
- old.appearance = appearance;
1370
- old.props = value.props;
1371
- const commit = provide(old.childContext, old.props);
1372
- reconcile(old, old.props.children, old.childContext, old.boundary, appearance);
1373
- commit();
1374
1107
  } else {
1375
1108
  old.appearance = appearance;
1376
1109
  const vnode = value;
@@ -1390,23 +1123,34 @@ function compatible(fiber, value) {
1390
1123
  "number",
1391
1124
  "bigint"
1392
1125
  ].includes(typeof value);
1393
- if (value instanceof Component) return fiber.kind == "component" && fiber.instance === value;
1126
+ if (renderable(value)) return fiber.kind == "component" && fiber.instance === value;
1394
1127
  if (isCollection(value)) return fiber.kind == "collection" && fiber.source === value;
1395
1128
  if (!isVNode(value)) return false;
1396
- if (fiber.key !== value.key || fiber.type !== value.type) return false;
1397
- if (fiber.kind == "portal") return fiber.portalContainer === value.props.container;
1129
+ if (fiber.key !== value.key || !same(fiber.type, value.type)) return false;
1130
+ if (fiber.kind == "portal") return fiber.props.into === value.props.into;
1398
1131
  return true;
1399
1132
  }
1400
1133
  function source(value) {
1401
- if (value instanceof Component) return value.is;
1134
+ if (value instanceof State) return value.is;
1402
1135
  while (isCollection(value) && isCollection(Object.getPrototypeOf(value))) value = Object.getPrototypeOf(value);
1403
1136
  return value;
1404
1137
  }
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
+ }
1405
1149
  function isCollection(value) {
1406
1150
  return value instanceof has.List || value instanceof has.Pool || value instanceof map.Managed;
1407
1151
  }
1408
1152
  function keyOf(value) {
1409
- if (value instanceof Component) return value.key;
1153
+ if (renderable(value)) return value.key;
1410
1154
  return isVNode(value) ? value.key : void 0;
1411
1155
  }
1412
1156
  function move(fiber, parent, before) {
@@ -1548,7 +1292,7 @@ function renderedAppearance(fiber) {
1548
1292
  style
1549
1293
  }));
1550
1294
  const inherited = fiber.appearance?.context || appearanceRoot();
1551
- const context = enterAppearance(inherited, fiber.type);
1295
+ const context = enterAppearance(inherited, latest(fiber.type));
1552
1296
  if (context?.base && context !== inherited) entries.push({
1553
1297
  hops: 0,
1554
1298
  style: context.base
@@ -1629,6 +1373,7 @@ function unmountFiber(fiber) {
1629
1373
  for (let index = fiber.children.length - 1; index >= 0; index--) unmountFiber(fiber.children[index]);
1630
1374
  if (fiber.placeholder) unmountFiber(fiber.placeholder);
1631
1375
  fiber.suspended?.forEach((clear) => clear());
1376
+ if (fiber.kind == "function") untrack(fiber.type, fiber.scope);
1632
1377
  if (fiber.scope) dispose(fiber.scope);
1633
1378
  fiber.release?.();
1634
1379
  if (fiber.kind == "element") {
@@ -1642,8 +1387,7 @@ function unmountFiber(fiber) {
1642
1387
  if (typeof fiber.cleanup == "function") fiber.cleanup();
1643
1388
  fiber.childContext?.pop();
1644
1389
  if (fiber.owned && !fiber.instance.get(null)) fiber.instance.set(null);
1645
- } else if (fiber.kind == "provider") fiber.childContext?.pop();
1646
- else if (fiber.kind == "portal") {
1390
+ } else if (fiber.kind == "portal") {
1647
1391
  fiber.portalStart.remove();
1648
1392
  fiber.portalEnd.remove();
1649
1393
  }
@@ -1660,5 +1404,5 @@ function removeRange(start, end) {
1660
1404
  }
1661
1405
 
1662
1406
  //#endregion
1663
- export { Consumer, Provider, createPortal, css, lazy, macro, render, style };
1407
+ export { Fragment, Portal, createElement, css, macro, render, style };
1664
1408
  //# sourceMappingURL=index.js.map