@expressive/mvc 1.0.0-beta.33 → 1.0.0-beta.36

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/lib/index.esm.js CHANGED
@@ -1,4 +1,31 @@
1
- import { useMemo, useLayoutEffect, useState, createContext, useContext, createElement } from 'react';
1
+ import React from 'react';
2
+
3
+ /*! *****************************************************************************
4
+ Copyright (c) Microsoft Corporation.
5
+
6
+ Permission to use, copy, modify, and/or distribute this software for any
7
+ purpose with or without fee is hereby granted.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
10
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11
+ AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
12
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
14
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15
+ PERFORMANCE OF THIS SOFTWARE.
16
+ ***************************************************************************** */
17
+
18
+ function __rest(s, e) {
19
+ var t = {};
20
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
21
+ t[p] = s[p];
22
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
23
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
24
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
25
+ t[p[i]] = s[p[i]];
26
+ }
27
+ return t;
28
+ }
2
29
 
3
30
  class Issue extends Error {
4
31
  constructor() {
@@ -9,9 +36,6 @@ class Issue extends Error {
9
36
  warn() {
10
37
  console.warn(this.message);
11
38
  }
12
- throw() {
13
- throw this;
14
- }
15
39
  }
16
40
  function issues(register) {
17
41
  const Library = {};
@@ -23,7 +47,7 @@ function issues(register) {
23
47
  const Oops$9 = issues({
24
48
  BadEffectCallback: () => `Callback for effect-callback may only return a function.`
25
49
  });
26
- const { assign, create, defineProperty, entries, getPrototypeOf, getOwnPropertyNames, getOwnPropertyDescriptor, getOwnPropertyDescriptors, getOwnPropertySymbols, keys: keys$1, values } = Object;
50
+ const { assign, create, defineProperty, entries, getPrototypeOf, getOwnPropertyNames, getOwnPropertyDescriptor, getOwnPropertyDescriptors, getOwnPropertySymbols, keys, values } = Object;
27
51
  function define(target, key, value) {
28
52
  defineProperty(target, key, { value });
29
53
  }
@@ -57,7 +81,7 @@ function createValueEffect(callback) {
57
81
  return function (value) {
58
82
  if (typeof unSet == "function")
59
83
  unSet(value);
60
- const out = callback.call(this, value);
84
+ const out = callback.call(this, value, this);
61
85
  if (typeof out == "boolean")
62
86
  return out;
63
87
  if (!out || out instanceof Promise)
@@ -67,93 +91,185 @@ function createValueEffect(callback) {
67
91
  else
68
92
  throw Oops$9.BadEffectCallback();
69
93
  };
70
- }
71
- function select(source, select) {
72
- const proxy = {};
73
- for (const k in source)
74
- proxy[k] = k;
75
- return select(proxy);
76
- }
77
- function selectRecursive(using, keys) {
78
- const found = new Set();
79
- const spy = {};
80
- for (const key of new Set(keys))
81
- defineProperty(spy, key, {
82
- get() {
83
- found.add(key);
84
- return spy;
94
+ }
95
+
96
+ const Oops$8 = issues({
97
+ StrictUpdate: (expected) => `Strict update() did ${expected ? "not " : ""}find pending updates.`,
98
+ NoChaining: () => `Then called with undefined; update promise will never catch nor supports chaining.`
99
+ });
100
+ class Controller {
101
+ constructor(subject) {
102
+ this.subject = subject;
103
+ this.frame = new Set();
104
+ this.waiting = new Set();
105
+ this.followers = new Set();
106
+ }
107
+ start() {
108
+ this.state = {};
109
+ for (const key in this.subject)
110
+ this.manage(key);
111
+ const handle = new Set(this.waiting);
112
+ this.waiting.clear();
113
+ handle.forEach(cb => cb([]));
114
+ return this;
115
+ }
116
+ manage(key, handler) {
117
+ const { state, subject } = this;
118
+ const desc = getOwnPropertyDescriptor(subject, key);
119
+ if (desc && "value" in desc) {
120
+ const { value } = desc;
121
+ const instruction = Pending.get(value);
122
+ if (instruction) {
123
+ Pending.delete(value);
124
+ delete subject[key];
125
+ instruction.call(this, key, this);
85
126
  }
86
- });
87
- using(spy);
88
- return Array.from(found);
127
+ else if (typeof value !== "function" || /^[A-Z]/.test(key)) {
128
+ state[key] = value;
129
+ defineProperty(subject, key, {
130
+ enumerable: true,
131
+ get: () => state[key],
132
+ set: this.setter(key, handler)
133
+ });
134
+ }
135
+ }
136
+ }
137
+ setter(key, handler) {
138
+ const { state, subject } = this;
139
+ return (value) => {
140
+ if (state[key] == value)
141
+ return;
142
+ if (handler)
143
+ switch (handler.call(subject, value, state)) {
144
+ case true:
145
+ this.update(key);
146
+ case false:
147
+ return;
148
+ }
149
+ this.update(key, value);
150
+ };
151
+ }
152
+ addListener(listener) {
153
+ this.followers.add(listener);
154
+ return () => {
155
+ this.followers.delete(listener);
156
+ };
157
+ }
158
+ update(key, value) {
159
+ if (1 in arguments)
160
+ this.state[key] = value;
161
+ if (this.frame.has(key))
162
+ return;
163
+ if (!this.frame.size)
164
+ setTimeout(() => {
165
+ flush(this);
166
+ const keys = Object.freeze([...this.frame]);
167
+ const handle = new Set(this.waiting);
168
+ this.waiting.clear();
169
+ this.frame.clear();
170
+ UPDATE.set(this.subject, keys);
171
+ setTimeout(() => {
172
+ UPDATE.delete(this.subject);
173
+ }, 0);
174
+ handle.forEach(callback => {
175
+ try {
176
+ callback(keys);
177
+ }
178
+ catch (e) { }
179
+ });
180
+ }, 0);
181
+ this.frame.add(key);
182
+ for (const callback of this.followers) {
183
+ const event = callback(key, this);
184
+ if (typeof event == "function")
185
+ this.waiting.add(event);
186
+ }
187
+ }
188
+ requestUpdate(arg) {
189
+ if (typeof arg == "function") {
190
+ this.waiting.add(arg);
191
+ return;
192
+ }
193
+ if (typeof arg == "boolean" && arg !== this.frame.size > 0)
194
+ return Promise.reject(Oops$8.StrictUpdate(arg));
195
+ return {
196
+ then: (callback) => {
197
+ if (callback)
198
+ if (this.frame.size)
199
+ this.waiting.add(callback);
200
+ else
201
+ callback(false);
202
+ else
203
+ throw Oops$8.NoChaining();
204
+ }
205
+ };
206
+ }
89
207
  }
90
208
 
91
209
  class Subscriber {
92
210
  constructor(parent, onUpdate) {
93
211
  this.onUpdate = onUpdate;
94
212
  this.active = false;
95
- this.handle = {};
213
+ this.watch = {};
96
214
  this.dependant = new Set();
97
- this.debug = () => {
98
- const update = [];
99
- this.notify = keys => {
100
- update.splice(0, update.length, ...keys.filter(k => k in this.handle));
101
- };
102
- return update;
103
- };
104
- this.listen = (key, from) => {
105
- const handler = this.handle[key];
106
- if (!handler)
107
- return;
108
- if (typeof handler == "function")
109
- handler();
110
- const notify = this.onUpdate(key, from);
111
- if (notify)
112
- from.waiting.add(notify);
113
- if (this.notify)
114
- from.waiting.add(this.notify);
115
- };
116
215
  if (!(parent instanceof Controller))
117
- parent = manage(parent);
216
+ parent = getController(parent);
118
217
  this.parent = parent;
119
218
  this.source = parent.subject;
120
- this.proxy = create(parent.subject);
121
- define(this.proxy, LOCAL, this);
122
- defineLazy(this.proxy, UPDATE, this.debug);
123
- for (const key in parent.state)
124
- this.spy(key);
125
- }
126
- spy(key) {
127
- const { proxy, source } = this;
128
- const { set } = getOwnPropertyDescriptor(source, key);
129
- const intercept = () => {
130
- this.follow(key);
131
- delete proxy[key];
132
- return proxy[key];
219
+ const proxy = this.proxy = create(parent.subject);
220
+ const DEBUG = (keys) => {
221
+ UPDATE.set(proxy, keys.filter(k => k in this.watch));
133
222
  };
134
- setAlias(intercept, `tap ${key}`);
135
- defineProperty(proxy, key, {
136
- get: intercept,
137
- set,
138
- configurable: true,
139
- enumerable: true
223
+ define(proxy, LOCAL, this);
224
+ defineProperty(this, "proxy", {
225
+ get: () => {
226
+ if (UPDATE.has(proxy))
227
+ setTimeout(() => {
228
+ UPDATE.delete(proxy);
229
+ }, 0);
230
+ return proxy;
231
+ }
140
232
  });
141
- }
142
- follow(key, callback) {
143
- this.handle[key] = callback || true;
144
- }
145
- commit() {
146
- const onDone = this.parent.addListener(this.listen);
147
- this.active = true;
148
- this.dependant.forEach(x => x.commit());
149
- return this.release = () => {
150
- this.dependant.forEach(x => x.release());
151
- onDone();
233
+ for (const key in parent.state) {
234
+ const existing = getOwnPropertyDescriptor(parent.subject, key);
235
+ const isUsing = () => {
236
+ this.watch[key] = true;
237
+ delete proxy[key];
238
+ return proxy[key];
239
+ };
240
+ setAlias(isUsing, `tap ${key}`);
241
+ defineProperty(proxy, key, {
242
+ set: existing.set,
243
+ get: isUsing,
244
+ configurable: true,
245
+ enumerable: true
246
+ });
247
+ }
248
+ this.commit = () => {
249
+ const { parent } = this;
250
+ const onDone = parent.addListener(key => {
251
+ const handler = this.watch[key];
252
+ if (!handler)
253
+ return;
254
+ if (typeof handler == "function")
255
+ handler();
256
+ const notify = this.onUpdate(key, parent);
257
+ if (notify) {
258
+ parent.requestUpdate(DEBUG);
259
+ parent.requestUpdate(notify);
260
+ }
261
+ });
262
+ this.active = true;
263
+ this.dependant.forEach(x => x.commit());
264
+ return this.release = () => {
265
+ this.dependant.forEach(x => x.release());
266
+ onDone();
267
+ };
152
268
  };
153
269
  }
154
270
  }
155
271
 
156
- const Oops$8 = issues({
272
+ const Oops$7 = issues({
157
273
  ComputeFailed: (parent, property, initial) => `An exception was thrown while ${initial ? "initializing" : "refreshing"} [${parent}.${property}].`,
158
274
  ComputedEarly: (property) => `Note: Computed values don't run until accessed, except when subscribed to. '${property}' getter may have run earlier than intended.`
159
275
  });
@@ -179,7 +295,7 @@ function prepare(parent, key, source, setter, getter) {
179
295
  return setter.call(sub.proxy, sub.proxy);
180
296
  }
181
297
  catch (err) {
182
- Oops$8.ComputeFailed(subject, key, !!initial).warn();
298
+ Oops$7.ComputeFailed(subject, key, !!initial).warn();
183
299
  throw err;
184
300
  }
185
301
  }
@@ -225,12 +341,12 @@ function prepare(parent, key, source, setter, getter) {
225
341
  }
226
342
  catch (e) {
227
343
  if (early)
228
- Oops$8.ComputedEarly(key).warn();
344
+ Oops$7.ComputedEarly(key).warn();
229
345
  throw e;
230
346
  }
231
347
  finally {
232
348
  sub.commit();
233
- for (const key in sub.handle) {
349
+ for (const key in sub.watch) {
234
350
  const peer = register.get(key);
235
351
  if (peer && peer.priority >= info.priority)
236
352
  info.priority = peer.priority + 1;
@@ -250,7 +366,7 @@ function prepare(parent, key, source, setter, getter) {
250
366
  enumerable: true
251
367
  });
252
368
  }
253
- function ensure(on, keys) {
369
+ function ensure$1(on, keys) {
254
370
  for (const key of keys) {
255
371
  const desc = getOwnPropertyDescriptor(on.subject, key);
256
372
  const getter = desc && desc.get;
@@ -273,6 +389,287 @@ function flush(on) {
273
389
  KEYS.delete(on);
274
390
  }
275
391
 
392
+ const CONTROL = Symbol("CONTROL");
393
+ const WHY = Symbol("UPDATE");
394
+ const LOCAL = Symbol("LOCAL");
395
+ const STATE = Symbol("STATE");
396
+ const UPDATE = new WeakMap();
397
+ function ensure(subject, callback) {
398
+ const control = subject[CONTROL];
399
+ if (!control.state) {
400
+ let done;
401
+ control.requestUpdate(() => {
402
+ done = callback(control);
403
+ });
404
+ return () => done();
405
+ }
406
+ return callback(control);
407
+ }
408
+ function getController(subject) {
409
+ const control = subject[CONTROL];
410
+ if (!control.state)
411
+ control.start();
412
+ if (subject.didCreate)
413
+ subject.didCreate();
414
+ return control;
415
+ }
416
+ class Model {
417
+ constructor() {
418
+ define(this, CONTROL, new Controller(this));
419
+ define(this, "get", this);
420
+ define(this, "set", this);
421
+ }
422
+ get [STATE]() {
423
+ return this[CONTROL].state;
424
+ }
425
+ get [WHY]() {
426
+ return UPDATE.get(this);
427
+ }
428
+ on(select, handler, squash, once) {
429
+ return ensure(this, control => {
430
+ const keys = typeof select == "string" ? [select] :
431
+ !select.length ? getOwnPropertyNames(control.state) :
432
+ select;
433
+ ensure$1(control, keys);
434
+ const callback = squash
435
+ ? handler.bind(this)
436
+ : frame => frame
437
+ .filter(k => keys.includes(k))
438
+ .forEach(k => handler.call(this, control.state[k], k));
439
+ const trigger = once
440
+ ? frame => { remove(); callback(frame); }
441
+ : callback;
442
+ const remove = control.addListener(key => {
443
+ if (keys.includes(key))
444
+ return trigger;
445
+ });
446
+ return remove;
447
+ });
448
+ }
449
+ once(select, callback, squash) {
450
+ if (callback)
451
+ return this.on(select, callback, squash, true);
452
+ return new Promise(resolve => {
453
+ this.on(select, resolve, true, true);
454
+ });
455
+ }
456
+ effect(callback, select) {
457
+ const effect = createEffect(callback);
458
+ return ensure(this, control => {
459
+ if (!select) {
460
+ const sub = new Subscriber(control, () => invoke);
461
+ const invoke = () => {
462
+ const x = sub.proxy;
463
+ effect.call(x, x);
464
+ };
465
+ invoke();
466
+ return sub.commit();
467
+ }
468
+ const invoke = () => {
469
+ effect.call(this.get, this.get);
470
+ };
471
+ invoke();
472
+ if (!select.length)
473
+ select.push("willDestroy");
474
+ return control.addListener(key => {
475
+ if (select.includes(key))
476
+ return invoke;
477
+ });
478
+ });
479
+ }
480
+ import(from, subset) {
481
+ for (const key of subset || getOwnPropertyNames(this))
482
+ if (key in from)
483
+ this[key] = from[key];
484
+ }
485
+ export(subset) {
486
+ const { state } = getController(this);
487
+ const output = {};
488
+ for (const key of subset || getOwnPropertyNames(state))
489
+ output[key] = state[key];
490
+ return output;
491
+ }
492
+ update(arg, tag) {
493
+ const control = getController(this);
494
+ if (typeof arg == "string") {
495
+ control.update(arg);
496
+ if (1 in arguments && arg in this) {
497
+ const method = this[arg];
498
+ if (typeof method == "function")
499
+ if (typeof tag != "boolean")
500
+ method.call(this, tag);
501
+ else if (tag)
502
+ method.call(this);
503
+ }
504
+ arg = undefined;
505
+ }
506
+ return control.requestUpdate(arg);
507
+ }
508
+ destroy() {
509
+ this.update("willDestroy", true);
510
+ }
511
+ toString() {
512
+ return this.constructor.name;
513
+ }
514
+ static create(...args) {
515
+ const instance = new this(...args);
516
+ getController(instance);
517
+ return instance;
518
+ }
519
+ static isTypeof(maybe) {
520
+ return (typeof maybe == "function" &&
521
+ maybe.prototype instanceof this);
522
+ }
523
+ }
524
+ Model.CONTROL = CONTROL;
525
+ Model.STATE = STATE;
526
+ Model.LOCAL = LOCAL;
527
+ Model.WHY = WHY;
528
+ defineLazy(Model, CONTROL, function () {
529
+ return new Controller(this);
530
+ });
531
+
532
+ const Pending = new Map();
533
+ function apply(fn, label) {
534
+ const name = label || fn.name || "pending";
535
+ const placeholder = Symbol(`${name} instruction`);
536
+ function setup(key) {
537
+ const { subject, state } = this;
538
+ let output = fn.call(this, key, this);
539
+ let desc = {};
540
+ let get;
541
+ let set;
542
+ if (!output)
543
+ return;
544
+ if (typeof output == "function")
545
+ get = output;
546
+ else {
547
+ (({ get, set } = output), desc = __rest(output, ["get", "set"]));
548
+ if ("value" in desc) {
549
+ state[key] = desc.value;
550
+ if (get || set)
551
+ delete desc.value;
552
+ else {
553
+ defineProperty(subject, key, desc);
554
+ return;
555
+ }
556
+ }
557
+ }
558
+ defineProperty(subject, key, Object.assign(Object.assign({}, desc), { set: this.setter(key, set), get: get
559
+ ? function () {
560
+ return get(state[key], this[LOCAL]);
561
+ }
562
+ : () => state[key] }));
563
+ }
564
+ Pending.set(placeholder, setup);
565
+ return placeholder;
566
+ }
567
+
568
+ //TODO: sync instruction
569
+ function child(source, name) {
570
+ return apply(function child(key) {
571
+ const context = new WeakMap();
572
+ const peer = source.call(this, key);
573
+ function subscribe(sub) {
574
+ let child;
575
+ function init() {
576
+ if (child) {
577
+ child.release();
578
+ sub.dependant.delete(child);
579
+ context.set(sub, undefined);
580
+ child = undefined;
581
+ }
582
+ const instance = peer.get();
583
+ if (instance) {
584
+ child = new Subscriber(instance, sub.onUpdate);
585
+ if (sub.active)
586
+ child.commit();
587
+ sub.dependant.add(child);
588
+ context.set(sub, child.proxy);
589
+ }
590
+ }
591
+ init();
592
+ sub.watch[key] = init;
593
+ }
594
+ return {
595
+ value: peer.get(),
596
+ set: peer.set,
597
+ get(_value, local) {
598
+ if (!local)
599
+ return peer.get();
600
+ if (!context.has(local))
601
+ subscribe(local);
602
+ return context.get(local);
603
+ }
604
+ };
605
+ }, name || source.name);
606
+ }
607
+
608
+ const Parent = new WeakMap();
609
+ const Oops$6 = issues({
610
+ ParentRequired: (expects, child) => `New ${child} created standalone but requires parent of type ${expects}. Did you remember to create via use(${child})?`,
611
+ UnexpectedParent: (expects, child, got) => `New ${child} created as child of ${got}, but must be instanceof ${expects}.`,
612
+ BadArgument: (type) => `Instruction \`use\` cannot accept argument type of ${type}.`,
613
+ });
614
+ function bootstrap(object) {
615
+ const breakdown = getOwnPropertyDescriptors(object);
616
+ const control = new Model();
617
+ for (const key in breakdown)
618
+ defineProperty(control, key, breakdown[key]);
619
+ return control;
620
+ }
621
+ function use$1(input, argument) {
622
+ return child(function use(key) {
623
+ const { subject } = this;
624
+ let current;
625
+ const onUpdate = (next) => {
626
+ if (next) {
627
+ current = next instanceof Model
628
+ ? next : bootstrap(next);
629
+ Parent.set(current, subject);
630
+ getController(current);
631
+ }
632
+ else
633
+ current = undefined;
634
+ if (typeof argument == "function")
635
+ return argument(current);
636
+ };
637
+ if (input) {
638
+ const initial = Model.isTypeof(input)
639
+ ? new input() :
640
+ input instanceof Model
641
+ ? input :
642
+ typeof input === "function"
643
+ ? input() :
644
+ typeof input === "object"
645
+ ? bootstrap(input)
646
+ : null;
647
+ if (initial)
648
+ onUpdate(initial);
649
+ else if (initial === null)
650
+ throw Oops$6.BadArgument(typeof input);
651
+ }
652
+ return {
653
+ get: () => current,
654
+ set: onUpdate
655
+ };
656
+ });
657
+ }
658
+ function parent(Expects, required) {
659
+ return apply(function parent() {
660
+ const child = this.subject;
661
+ const expected = Expects.name;
662
+ const value = Parent.get(this.subject);
663
+ if (!value) {
664
+ if (required)
665
+ throw Oops$6.ParentRequired(expected, child);
666
+ }
667
+ else if (!(value instanceof Expects))
668
+ throw Oops$6.UnexpectedParent(expected, child, value);
669
+ return { value };
670
+ });
671
+ }
672
+
276
673
  const Lifecycle = {
277
674
  WILL_RENDER: "willRender",
278
675
  WILL_UPDATE: "willUpdate",
@@ -280,7 +677,7 @@ const Lifecycle = {
280
677
  WILL_UNMOUNT: "willUnmount",
281
678
  DID_MOUNT: "didMount"
282
679
  };
283
- const lifecycleEvents = [
680
+ [
284
681
  "didCreate",
285
682
  "willDestroy",
286
683
  ...values(Lifecycle)
@@ -288,7 +685,7 @@ const lifecycleEvents = [
288
685
  function lifecycle(prefix) {
289
686
  const type = eventsFor(prefix);
290
687
  return function useLifecycle(sub, tag) {
291
- const emit = useMemo(() => {
688
+ const emit = React.useMemo(() => {
292
689
  const subject = sub.source;
293
690
  const id = typeof tag == "function" ? tag(subject) : tag;
294
691
  return (name) => {
@@ -300,7 +697,7 @@ function lifecycle(prefix) {
300
697
  emit(sub.active
301
698
  ? Lifecycle.WILL_UPDATE
302
699
  : Lifecycle.WILL_MOUNT);
303
- useLayoutEffect(() => {
700
+ React.useLayoutEffect(() => {
304
701
  sub.commit();
305
702
  emit(Lifecycle.DID_MOUNT);
306
703
  return () => {
@@ -314,254 +711,264 @@ function eventsFor(prefix) {
314
711
  const map = new Map();
315
712
  for (const name of values(Lifecycle)) {
316
713
  const alias = prefix + name[0].toUpperCase() + name.slice(1);
317
- lifecycleEvents.push(alias);
318
714
  map.set(name, alias);
319
715
  }
320
716
  return (e) => map.get(e);
321
717
  }
322
718
 
323
- const CONTROL = Symbol("control");
324
- const UPDATE = Symbol("update");
325
- const LOCAL = Symbol("local");
326
- const STATE = Symbol("state");
327
- function manage(src) {
328
- return src[CONTROL];
719
+ const useElementLifecycle = lifecycle("element");
720
+ const useComponentLifecycle = lifecycle("component");
721
+ function use(init) {
722
+ const [state, update] = React.useState(() => [
723
+ init(() => update(state.concat()))
724
+ ]);
725
+ return state[0];
329
726
  }
330
- const Pending = new Map();
331
- function apply(fn, label) {
332
- const name = label || fn.name || "pending";
333
- const placeholder = Symbol(`${name} instruction`);
334
- function setup(key) {
335
- let output = fn.call(this, key, this);
336
- if (typeof output == "function") {
337
- const getter = output;
338
- output = Object.assign(Object.assign({}, getOwnPropertyDescriptor(this.subject, key)), { get() {
339
- return getter(this[LOCAL]);
340
- } });
341
- }
342
- if (output)
343
- defineProperty(this.subject, key, output);
344
- }
345
- Pending.set(placeholder, setup);
346
- return placeholder;
727
+ function useTap(model, path, expect) {
728
+ if (typeof path == "function")
729
+ return useComputed(model, path, expect);
730
+ const proxy = useActive(model, path, expect);
731
+ model.update("willRender", true);
732
+ return proxy;
347
733
  }
348
- class Controller {
349
- constructor(subject) {
350
- this.subject = subject;
351
- this.state = {};
352
- this.frame = new Set();
353
- this.waiting = new Set();
354
- this.followers = new Set();
355
- }
356
- static setup(onto) {
357
- const control = new this(onto);
358
- defineLazy(onto, CONTROL, () => {
359
- onto[STATE] = control.state;
360
- control.start();
361
- if (onto.didCreate)
362
- onto.didCreate();
363
- return control;
364
- });
365
- return control;
366
- }
367
- get pending() {
368
- return this.frame.size > 0;
369
- }
370
- start() {
371
- const { subject } = this;
372
- for (const key in subject) {
373
- const desc = getOwnPropertyDescriptor(subject, key);
374
- if (desc && "value" in desc) {
375
- const { value } = desc;
376
- const instruction = Pending.get(value);
377
- if (instruction) {
378
- Pending.delete(value);
379
- delete subject[key];
380
- instruction.call(this, key, this);
734
+ function useTag(model, id) {
735
+ const hook = use(refresh => (new Subscriber(model, () => refresh)));
736
+ useElementLifecycle(hook, id || 0);
737
+ return hook.proxy;
738
+ }
739
+ function useNew(model, callback) {
740
+ const hook = use(refresh => {
741
+ if (callback)
742
+ callback(model);
743
+ return new Subscriber(model, () => refresh);
744
+ });
745
+ useComponentLifecycle(hook);
746
+ return hook.proxy;
747
+ }
748
+ function usePassive(Type, callback) {
749
+ const instance = React.useMemo(() => {
750
+ const instance = Type.create();
751
+ if (callback)
752
+ callback(instance);
753
+ return instance;
754
+ }, []);
755
+ React.useLayoutEffect(() => () => instance.destroy(), []);
756
+ instance.update("willRender", true);
757
+ return instance;
758
+ }
759
+ function useActive(target, focus, expected) {
760
+ const hook = use(refresh => {
761
+ const sub = new Subscriber(target, () => refresh);
762
+ if (focus) {
763
+ const source = sub.proxy;
764
+ defineProperty(sub, "proxy", {
765
+ get() {
766
+ const value = source[focus];
767
+ if (value === undefined && expected)
768
+ throw suspend(sub.parent, focus);
769
+ return value;
381
770
  }
382
- else if (typeof value !== "function" || /^[A-Z]/.test(key))
383
- this.manage(key, value);
771
+ });
772
+ }
773
+ return sub;
774
+ });
775
+ React.useLayoutEffect(() => hook.commit(), []);
776
+ return hook.proxy;
777
+ }
778
+ function useComputed(target, compute, expected) {
779
+ const hook = use(refresh => {
780
+ const sub = new Subscriber(target, () => update);
781
+ const spy = sub.proxy;
782
+ let value = compute.call(spy, spy);
783
+ let update;
784
+ let retry;
785
+ const set = (next) => {
786
+ value = next;
787
+ if (retry) {
788
+ retry();
789
+ retry = undefined;
384
790
  }
791
+ else
792
+ refresh();
793
+ };
794
+ if (value instanceof Promise) {
795
+ value.then(set);
796
+ value = undefined;
385
797
  }
386
- this.emit();
387
- return this;
388
- }
389
- select(using) {
390
- const keys = getOwnPropertyNames(this.state);
391
- return using
392
- ? selectRecursive(using, keys.concat(lifecycleEvents))
393
- : keys;
394
- }
395
- manage(key, initial, effect) {
396
- const { state, subject } = this;
397
- state[key] = initial;
398
- defineProperty(subject, key, {
399
- enumerable: true,
400
- configurable: true,
401
- get: () => state[key],
402
- set: this.setter(key, effect)
798
+ else {
799
+ sub.commit();
800
+ update = () => {
801
+ const next = compute.call(spy, spy);
802
+ if (value != next)
803
+ set(next);
804
+ };
805
+ }
806
+ const get = expected
807
+ ? () => {
808
+ if (value === undefined)
809
+ throw new Promise(res => retry = res);
810
+ return value;
811
+ }
812
+ : () => value;
813
+ defineProperty(sub, "proxy", { get });
814
+ return sub;
815
+ });
816
+ React.useLayoutEffect(() => hook.release, []);
817
+ return hook.proxy;
818
+ }
819
+ function useModel(Type, callback) {
820
+ const hook = use(refresh => {
821
+ const instance = new Type();
822
+ const sub = new Subscriber(instance, () => refresh);
823
+ const release = sub.parent.addListener((key) => {
824
+ if (key == Lifecycle.WILL_UNMOUNT)
825
+ return () => {
826
+ instance.destroy();
827
+ release();
828
+ };
403
829
  });
830
+ if (callback)
831
+ callback(instance);
832
+ return sub;
833
+ });
834
+ useComponentLifecycle(hook);
835
+ usePeerContext(hook.source);
836
+ return hook.proxy;
837
+ }
838
+
839
+ class Lookup {
840
+ constructor() {
841
+ this.table = new Map();
404
842
  }
405
- setter(key, handler) {
406
- const { state, subject } = this;
407
- return (value) => {
408
- if (state[key] == value)
409
- return;
410
- if (handler)
411
- switch (handler.call(subject, value)) {
412
- case true:
413
- this.update(key);
414
- case false:
415
- return;
416
- }
417
- this.update(key, value);
418
- };
419
- }
420
- addListener(listener) {
421
- this.followers.add(listener);
422
- return () => {
423
- this.followers.delete(listener);
424
- };
843
+ get local() {
844
+ return [
845
+ ...new Set(getOwnPropertySymbols(this).map(symbol => this[symbol]))
846
+ ];
425
847
  }
426
- update(key, value) {
427
- if (1 in arguments)
428
- this.state[key] = value;
429
- if (this.frame.has(key))
430
- return;
431
- if (!this.frame.size)
432
- setTimeout(() => this.emit(), 0);
433
- this.frame.add(key);
434
- for (const subscription of this.followers) {
435
- const notify = subscription(key, this);
436
- if (notify)
437
- this.waiting.add(notify);
848
+ key(T) {
849
+ let key = this.table.get(T);
850
+ if (!key) {
851
+ key = Symbol(T.name);
852
+ this.table.set(T, key);
438
853
  }
854
+ return key;
439
855
  }
440
- emit() {
441
- flush(this);
442
- const keys = Object.freeze([...this.frame]);
443
- const handle = new Set(this.waiting);
444
- this.waiting.clear();
445
- this.frame.clear();
446
- defineProperty(this.subject, UPDATE, {
447
- configurable: true,
448
- value: keys
449
- });
450
- handle.forEach(callback => {
451
- try {
452
- callback(keys);
453
- }
454
- catch (e) { }
455
- });
856
+ get(T) {
857
+ return this[this.key(T)];
456
858
  }
457
- }
458
- function keys(from, using) {
459
- if (typeof using == "string")
460
- return [using];
461
- if (typeof using == "object") {
462
- using = Array.from(using);
463
- if (using.length === 0)
464
- using = undefined;
859
+ push(I) {
860
+ const next = create(this);
861
+ if (I instanceof Model || typeof I == "function")
862
+ next.register(I);
465
863
  else
466
- return using;
864
+ for (const i of values(I))
865
+ next.register(i);
866
+ return next;
467
867
  }
468
- return from.select(using);
469
- }
470
-
471
- function child(source, name) {
472
- return apply(function child(key) {
473
- const context = new WeakMap();
474
- const current = source.call(this, key);
475
- function subscribe(sub) {
476
- let child;
477
- function start() {
478
- const instance = current();
479
- if (instance) {
480
- child = new Subscriber(instance, sub.onUpdate);
481
- if (sub.active)
482
- child.commit();
483
- sub.dependant.add(child);
484
- context.set(sub, child.proxy);
485
- }
486
- }
487
- function restart() {
488
- if (child) {
489
- child.release();
490
- sub.dependant.delete(child);
491
- context.set(sub, undefined);
492
- child = undefined;
493
- }
494
- start();
495
- }
496
- start();
497
- sub.follow(key, restart);
868
+ register(I) {
869
+ let writable = true;
870
+ let T;
871
+ if (I instanceof Model) {
872
+ T = I.constructor;
873
+ writable = false;
498
874
  }
499
- return (local) => {
500
- if (!local)
501
- return current();
502
- if (!context.has(local))
503
- subscribe(local);
504
- return context.get(local);
505
- };
506
- }, name || source.name);
875
+ else {
876
+ T = I;
877
+ I = I.create();
878
+ }
879
+ do {
880
+ const key = this.key(T);
881
+ const conflict = this.hasOwnProperty(key);
882
+ defineProperty(this, key, {
883
+ value: conflict ? null : I,
884
+ configurable: true,
885
+ writable
886
+ });
887
+ T = getPrototypeOf(T);
888
+ } while (T !== Model);
889
+ return I;
890
+ }
891
+ pop() {
892
+ for (const key of getOwnPropertySymbols(this)) {
893
+ const entry = getOwnPropertyDescriptor(this, key);
894
+ if (entry.writable)
895
+ entry.value.destroy();
896
+ }
897
+ }
507
898
  }
508
899
 
509
- const Oops$7 = issues({
510
- NonOptional: (Parent, key) => `Property ${Parent}.${key} is marked as required.`,
511
- BadFactory: () => `Set instruction can only accept a factory or undefined.`,
512
- FactoryFailed: (model, key) => `Generating initial value for ${model}.${key} failed.`
900
+ const Oops$5 = issues({
901
+ NoProviderType: () => `Provider 'of' prop must be Model, typeof Model or a collection of them.`,
902
+ NothingInContext: (name) => `Couldn't find ${name} in context; did you forget to use a Provider?`,
903
+ BadConsumerProps: () => `Provider expects either a render function, 'get' or 'has' props.`
513
904
  });
514
- function lazy(value) {
515
- return apply(function lazy(key) {
516
- const source = this.subject;
517
- source[key] = value;
518
- defineProperty(this.state, key, {
519
- get: () => source[key]
520
- });
521
- });
905
+ const LookupContext = React.createContext(new Lookup());
906
+ const useLookup = () => React.useContext(LookupContext);
907
+ function useContext(Type, strict) {
908
+ const instance = useLookup().get(Type);
909
+ if (!instance && strict)
910
+ throw Oops$5.NothingInContext(Type.name);
911
+ return instance;
522
912
  }
523
- function set(factory, argument) {
524
- return apply(function set(key) {
525
- let onSet;
526
- let onGet;
527
- const required = argument === true || argument === undefined;
528
- if (factory === undefined)
529
- onGet = () => pendingValue(this, key);
530
- else if (typeof factory !== "function")
531
- throw Oops$7.BadFactory();
532
- else {
533
- onGet = pendingFactory(this, key, factory);
534
- if (required)
535
- try {
536
- onGet();
537
- }
538
- catch (err) {
539
- if (err instanceof Promise)
540
- ;
541
- else {
542
- Oops$7.FactoryFailed(this.subject, key).warn();
543
- throw err;
544
- }
545
- }
546
- }
547
- if (typeof argument == "function")
548
- onSet = createValueEffect(argument);
549
- else if (required)
550
- onSet = (value) => {
551
- if (value === undefined)
552
- throw Oops$7.NonOptional(this.subject, key);
553
- };
554
- return {
555
- set: this.setter(key, onSet),
556
- get: onGet
913
+ function Consumer(props) {
914
+ const { get, has, children, of: Control } = props;
915
+ if (typeof children == "function")
916
+ return children(useTap(useContext(Control)));
917
+ const callback = has || get;
918
+ if (typeof callback == "function")
919
+ callback(useContext(Control, !!has));
920
+ else
921
+ throw Oops$5.BadConsumerProps();
922
+ return null;
923
+ }
924
+ function useNewContext(inject) {
925
+ const from = useLookup();
926
+ return React.useMemo(() => {
927
+ if (!inject)
928
+ throw Oops$5.NoProviderType();
929
+ const context = from.push(inject);
930
+ for (const instance of context.local)
931
+ if (instance)
932
+ for (const apply of getPending(instance))
933
+ apply(context);
934
+ return context;
935
+ }, []);
936
+ }
937
+ function useAppliedProps(within, props) {
938
+ const update = React.useMemo(() => {
939
+ const targets = within.local;
940
+ return function integrate(props) {
941
+ for (const [key, value] of entries(props))
942
+ if (key != "of" && key != "children")
943
+ for (const into of targets)
944
+ if (into && key in into)
945
+ into[key] = value;
557
946
  };
947
+ }, []);
948
+ update(props);
949
+ }
950
+ function RenderFunction(props) {
951
+ const hook = use(refresh => {
952
+ const targets = props.context.local;
953
+ if (targets.length == 1)
954
+ return new Subscriber(targets[0], () => refresh);
955
+ return {};
558
956
  });
957
+ if (hook.commit)
958
+ React.useLayoutEffect(() => hook.commit(), []);
959
+ return props.render(hook.proxy);
559
960
  }
560
- function on(initial, onUpdate) {
561
- return set(initial && (() => initial), onUpdate);
961
+ function Provider(props) {
962
+ const context = useNewContext(props.of);
963
+ const render = props.children;
964
+ useAppliedProps(context, props);
965
+ React.useLayoutEffect(() => () => context.pop(), []);
966
+ return React.createElement(LookupContext.Provider, { value: context }, typeof render == "function"
967
+ ? React.createElement(RenderFunction, { context, render })
968
+ : render);
562
969
  }
563
970
 
564
- const Oops$6 = issues({
971
+ const Oops$4 = issues({
565
972
  CantAttachGlobal: (parent, child) => `Singleton '${parent}' attempted to attach '${child}' but it is not also a singleton.`,
566
973
  AmbientRequired: (requested, requester, key) => `Attempted to find an instance of ${requested} in context. It is required for [${requester}.${key}], but one could not be found.`
567
974
  });
@@ -569,14 +976,16 @@ const PendingContext = new WeakMap();
569
976
  const ContextWasUsed = new WeakMap();
570
977
  function tap(type, argument) {
571
978
  return child(function tap(key) {
572
- return pendingAccess(this.subject, type, key, argument);
979
+ return {
980
+ get: pendingAccess(this.subject, type, key, argument)
981
+ };
573
982
  });
574
983
  }
575
984
  function pendingAccess(from, type, key, argument) {
576
- if ("current" in type)
577
- return () => type.current;
578
- if ("current" in from.constructor)
579
- throw Oops$6.CantAttachGlobal(from, type.name);
985
+ if ("set" in type)
986
+ return () => type.get();
987
+ if ("set" in from.constructor)
988
+ throw Oops$4.CantAttachGlobal(from, type.name);
580
989
  let instance;
581
990
  getPending(from).push(context => {
582
991
  instance = context.get(type);
@@ -585,7 +994,7 @@ function pendingAccess(from, type, key, argument) {
585
994
  instance = undefined;
586
995
  }
587
996
  else if (!instance && argument)
588
- throw Oops$6.AmbientRequired(type.name, from, key);
997
+ throw Oops$4.AmbientRequired(type.name, from, key);
589
998
  });
590
999
  return () => instance;
591
1000
  }
@@ -611,7 +1020,7 @@ function getPending(subject) {
611
1020
  return pending;
612
1021
  }
613
1022
 
614
- const Oops$5 = issues({
1023
+ const Oops$3 = issues({
615
1024
  DuplicateAction: (key) => `Invoked action ${key} but one is already active.`,
616
1025
  BadComputedSource: (model, property, got) => `Bad from-instruction provided to ${model}.${property}. Expects an arrow-function or a Model as source. Got ${got}.`,
617
1026
  PeerNotAllowed: (model, property) => `Attempted to use an instruction result (probably use or tap) as computed source for ${model}.${property}. This is not possible.`
@@ -628,7 +1037,7 @@ function ref(arg) {
628
1037
  return apply(function ref(key) {
629
1038
  let value = {};
630
1039
  if (typeof arg == "object") {
631
- const source = manage(arg);
1040
+ const source = getController(arg);
632
1041
  for (const key in source.state)
633
1042
  defineLazy(value, key, createRef.bind(source, key));
634
1043
  }
@@ -642,7 +1051,7 @@ function act(task) {
642
1051
  let pending = false;
643
1052
  const invoke = (...args) => {
644
1053
  if (pending)
645
- return Promise.reject(Oops$5.DuplicateAction(key));
1054
+ return Promise.reject(Oops$3.DuplicateAction(key));
646
1055
  pending = true;
647
1056
  this.update(key);
648
1057
  return new Promise(res => {
@@ -665,17 +1074,17 @@ function act(task) {
665
1074
  }
666
1075
  function from(source, setter, argument) {
667
1076
  return apply(function from(key) {
668
- const { subject } = this;
669
1077
  let getSource;
670
- let getter = argument === true
1078
+ const { subject } = this;
1079
+ const getter = argument === true
671
1080
  ? pendingValue
672
1081
  : argument || undefined;
673
1082
  // Easy mistake, using a peer, will always be unresolved.
674
1083
  if (typeof source == "symbol")
675
- throw Oops$5.PeerNotAllowed(subject, key);
1084
+ throw Oops$3.PeerNotAllowed(subject, key);
676
1085
  // replace source controller in-case different
677
1086
  if (typeof source == "object")
678
- getSource = () => manage(source);
1087
+ getSource = () => getController(source);
679
1088
  // specifically an arrow function (getter factory)
680
1089
  else if (!source.prototype) {
681
1090
  setter = source.call(subject, key);
@@ -686,12 +1095,12 @@ function from(source, setter, argument) {
686
1095
  getSource = pendingAccess(subject, source, key, true);
687
1096
  // Regular function is too ambiguous so not allowed.
688
1097
  else
689
- throw Oops$5.BadComputedSource(subject, key, source);
1098
+ throw Oops$3.BadComputedSource(subject, key, source);
690
1099
  prepare(this, key, getSource, setter, getter);
691
1100
  });
692
1101
  }
693
1102
 
694
- const Oops$4 = issues({
1103
+ const Oops$2 = issues({
695
1104
  ValueNotReady: (model, key) => `Value ${model}.${key} value is not yet available.`
696
1105
  });
697
1106
  /* deprecated - ignore coverage */
@@ -725,423 +1134,130 @@ function pendingFactory(via, key, fn) {
725
1134
  if (error)
726
1135
  throw error;
727
1136
  if (key in state)
728
- return state[key];
729
- let output;
730
- try {
731
- output = fn.call(subject, key, subject);
732
- }
733
- catch (err) {
734
- throw error = err;
735
- }
736
- if (output instanceof Promise) {
737
- const issue = Oops$4.ValueNotReady(subject, key);
738
- output
739
- .catch(err => error = err)
740
- .then(out => state[key] = out)
741
- .finally(() => waiting = undefined);
742
- throw waiting = Object.assign(output, {
743
- message: issue.message,
744
- stack: issue.stack
745
- });
746
- }
747
- else {
748
- return state[key] = output;
749
- }
750
- };
751
- }
752
- function suspend(source, key) {
753
- const error = Oops$4.ValueNotReady(source.subject, key);
754
- const promise = new Promise(resolve => {
755
- const release = source.addListener(forKey => {
756
- if (forKey == key)
757
- return () => {
758
- if (source.state[key] !== undefined) {
759
- release();
760
- resolve();
761
- }
762
- };
763
- });
764
- });
765
- return Object.assign(promise, {
766
- toString: () => String(error),
767
- name: "Suspense",
768
- message: error.message,
769
- stack: error.stack
770
- });
771
- }
772
-
773
- function use$1(init) {
774
- const [state, update] = useState(() => [
775
- init(() => update(state.concat()))
776
- ]);
777
- return state[0];
778
- }
779
- function useLazy(Type, callback) {
780
- const instance = useMemo(() => {
781
- const instance = Type.create();
782
- if (callback)
783
- callback(instance);
784
- return instance;
785
- }, []);
786
- useLayoutEffect(() => () => instance.destroy(), []);
787
- return instance;
788
- }
789
- function useWatcher(target, focus, expected) {
790
- const hook = use$1(refresh => {
791
- const sub = new Subscriber(target, () => refresh);
792
- if (focus) {
793
- const source = sub.proxy;
794
- defineProperty(sub, "proxy", {
795
- get() {
796
- const value = source[focus];
797
- if (value === undefined && expected)
798
- throw suspend(sub.parent, focus);
799
- return value;
800
- }
801
- });
802
- }
803
- return sub;
804
- });
805
- useLayoutEffect(() => hook.commit(), []);
806
- return hook.proxy;
807
- }
808
- function useComputed(target, compute, expected) {
809
- const hook = use$1(refresh => {
810
- const sub = new Subscriber(target, () => update);
811
- const { proxy } = sub;
812
- let value;
813
- let retry;
814
- const update = () => {
815
- const next = compute.call(proxy, proxy);
816
- if (value == next)
817
- return;
818
- value = next;
819
- if (retry) {
820
- retry();
821
- retry = undefined;
822
- }
823
- else
824
- refresh();
825
- };
826
- const access = () => {
827
- if (value === undefined && expected)
828
- throw new Promise(res => {
829
- retry = res;
830
- });
831
- return value;
832
- };
833
- value = compute.call(proxy, proxy);
834
- sub.commit();
835
- defineProperty(sub, "proxy", { get: access });
836
- return sub;
837
- });
838
- useLayoutEffect(() => hook.release, []);
839
- return hook.proxy;
840
- }
841
- function useModel(Type, callback) {
842
- const hook = use$1(refresh => {
843
- const instance = new Type();
844
- const control = manage(instance);
845
- const sub = new Subscriber(control, () => refresh);
846
- const release = control.addListener((key) => {
847
- if (key == Lifecycle.WILL_UNMOUNT)
848
- return () => {
849
- instance.destroy();
850
- release();
851
- };
852
- });
853
- if (callback)
854
- callback(instance);
855
- return sub;
856
- });
857
- return hook.proxy;
858
- }
859
-
860
- class Lookup {
861
- constructor() {
862
- this.table = new Map();
863
- }
864
- get local() {
865
- return getOwnPropertySymbols(this).map((symbol) => this[symbol]);
866
- }
867
- key(T) {
868
- let key = this.table.get(T);
869
- if (!key) {
870
- key = Symbol(T.name);
871
- this.table.set(T, key);
872
- }
873
- return key;
874
- }
875
- get(T) {
876
- return this[this.key(T)];
877
- }
878
- push(I) {
879
- const next = create(this);
880
- if (I instanceof Model || typeof I == "function")
881
- next.register(I);
882
- else
883
- for (const i of values(I))
884
- next.register(i);
885
- return next;
886
- }
887
- register(I) {
888
- let writable = true;
889
- let T;
890
- if (I instanceof Model) {
891
- T = I.constructor;
892
- writable = false;
1137
+ return state[key];
1138
+ let output;
1139
+ try {
1140
+ output = fn.call(subject, key, subject);
893
1141
  }
894
- else {
895
- T = I;
896
- I = I.create();
1142
+ catch (err) {
1143
+ throw error = err;
897
1144
  }
898
- do {
899
- defineProperty(this, this.key(T), {
900
- value: I, writable
1145
+ if (output instanceof Promise) {
1146
+ const issue = Oops$2.ValueNotReady(subject, key);
1147
+ output
1148
+ .catch(err => error = err)
1149
+ .then(out => state[key] = out)
1150
+ .finally(() => waiting = undefined);
1151
+ throw waiting = Object.assign(output, {
1152
+ message: issue.message,
1153
+ stack: issue.stack
901
1154
  });
902
- T = getPrototypeOf(T);
903
- } while (T !== Model);
904
- return I;
905
- }
906
- pop() {
907
- for (const key of getOwnPropertySymbols(this)) {
908
- const entry = getOwnPropertyDescriptor(this, key);
909
- if (entry.writable)
910
- entry.value.destroy();
911
1155
  }
912
- }
1156
+ else {
1157
+ return state[key] = output;
1158
+ }
1159
+ };
1160
+ }
1161
+ function suspend(source, key) {
1162
+ const error = Oops$2.ValueNotReady(source.subject, key);
1163
+ const promise = new Promise(resolve => {
1164
+ const release = source.addListener(forKey => {
1165
+ if (forKey == key)
1166
+ return () => {
1167
+ if (source.state[key] !== undefined) {
1168
+ release();
1169
+ resolve();
1170
+ }
1171
+ };
1172
+ });
1173
+ });
1174
+ return Object.assign(promise, {
1175
+ toString: () => String(error),
1176
+ name: "Suspense",
1177
+ message: error.message,
1178
+ stack: error.stack
1179
+ });
913
1180
  }
914
1181
 
915
- const Oops$3 = issues({
916
- NoProviderType: () => `Provider 'of' prop must be Model, typeof Model or a collection of them.`,
917
- NothingInContext: (name) => `Couldn't find ${name} in context; did you forget to use a Provider?`,
918
- BadConsumerProps: () => `Provider expects either a render function, 'get' or 'has' props.`
1182
+ const Oops$1 = issues({
1183
+ NonOptional: (Parent, key) => `Property ${Parent}.${key} is marked as required.`,
1184
+ BadFactory: () => `Set instruction can only accept a factory or undefined.`,
1185
+ FactoryFailed: (model, key) => `Generating initial value for ${model}.${key} failed.`
919
1186
  });
920
- const LookupContext = createContext(new Lookup());
921
- const useLookup = () => useContext(LookupContext);
922
- function useFromContext(Type, strict) {
923
- const instance = useLookup().get(Type);
924
- if (!instance && strict)
925
- throw Oops$3.NothingInContext(Type.name);
926
- return instance;
927
- }
928
- function Consumer(props) {
929
- const { get, has, children, of: Control } = props;
930
- if (typeof children == "function")
931
- return children(Control.tap());
932
- const callback = has || get;
933
- if (typeof callback == "function")
934
- callback(Control.get(!!has));
935
- else
936
- throw Oops$3.BadConsumerProps();
937
- return null;
938
- }
939
- function useNewContext(from, inject) {
940
- return useMemo(() => {
941
- if (!inject)
942
- throw Oops$3.NoProviderType();
943
- const context = from.push(inject);
944
- for (const instance of context.local)
945
- for (const apply of getPending(instance))
946
- apply(context);
947
- return context;
948
- }, []);
949
- }
950
- function useAppliedProps(within, props) {
951
- const update = useMemo(() => {
952
- const targets = within.local;
953
- return function integrate(props) {
954
- for (const [key, value] of entries(props))
955
- if (key != "of" && key != "children")
956
- for (const into of targets)
957
- if (key in into)
958
- into[key] = value;
959
- };
960
- }, []);
961
- update(props);
1187
+ function lazy(value) {
1188
+ return apply(function lazy(key) {
1189
+ const source = this.subject;
1190
+ source[key] = value;
1191
+ defineProperty(this.state, key, {
1192
+ get: () => source[key]
1193
+ });
1194
+ });
962
1195
  }
963
- function RenderFunction(props) {
964
- const hook = use$1(refresh => {
965
- const targets = props.context.local;
966
- if (targets.length == 1)
967
- return new Subscriber(targets[0], () => refresh);
968
- return {};
1196
+ function set(factory, argument) {
1197
+ return apply(function set(key) {
1198
+ let set;
1199
+ let get;
1200
+ const required = argument === true || argument === undefined;
1201
+ if (factory === undefined)
1202
+ get = () => pendingValue(this, key);
1203
+ else if (typeof factory !== "function")
1204
+ throw Oops$1.BadFactory();
1205
+ else {
1206
+ get = pendingFactory(this, key, factory);
1207
+ if (required)
1208
+ try {
1209
+ get();
1210
+ }
1211
+ catch (err) {
1212
+ if (err instanceof Promise)
1213
+ ;
1214
+ else {
1215
+ Oops$1.FactoryFailed(this.subject, key).warn();
1216
+ throw err;
1217
+ }
1218
+ }
1219
+ }
1220
+ if (typeof argument == "function")
1221
+ set = createValueEffect(argument);
1222
+ else
1223
+ set = (value) => {
1224
+ if (value === undefined && required)
1225
+ throw Oops$1.NonOptional(this.subject, key);
1226
+ };
1227
+ return { set, get };
969
1228
  });
970
- if (hook.commit)
971
- useLayoutEffect(() => hook.commit(), []);
972
- return props.render(hook.proxy);
973
1229
  }
974
- function Provider(props) {
975
- const render = props.children;
976
- const current = useLookup();
977
- const context = useNewContext(current, props.of);
978
- useAppliedProps(context, props);
979
- useLayoutEffect(() => () => context.pop(), []);
980
- return createElement(LookupContext.Provider, { value: context }, typeof render == "function"
981
- ? createElement(RenderFunction, { context, render })
982
- : render);
1230
+ function on(initial, onUpdate) {
1231
+ return set(initial && (() => initial), onUpdate);
983
1232
  }
984
1233
 
985
- const Oops$2 = issues({
986
- StrictUpdate: (expected) => `Strict update() did ${expected ? "not " : ""}find pending updates.`,
987
- NoChaining: () => `Then called with undefined; update promise will never catch nor supports chaining.`
988
- });
989
- const useElementLifecycle = lifecycle("element");
990
- const useComponentLifecycle = lifecycle("component");
991
- class Model {
992
- constructor() {
993
- const control = Controller.setup(this);
994
- define(this, "get", this);
995
- define(this, "set", this);
996
- defer(control, "on");
997
- defer(control, "effect");
998
- control.waiting.add(() => {
999
- delete this.on;
1000
- delete this.effect;
1001
- });
1002
- }
1234
+ class MVC extends Model {
1003
1235
  tap(path, expect) {
1004
- if (typeof path == "function")
1005
- return useComputed(this, path, expect);
1006
- const proxy = useWatcher(this, path, expect);
1007
- this.update("willRender", true);
1008
- return proxy;
1236
+ return useTap(this, path, expect);
1009
1237
  }
1010
1238
  tag(id) {
1011
- const hook = use$1(refresh => (new Subscriber(this, () => refresh)));
1012
- useElementLifecycle(hook, id || 0);
1013
- return hook.proxy;
1239
+ return useTag(this, id);
1014
1240
  }
1015
1241
  use(callback) {
1016
- const hook = use$1(refresh => {
1017
- if (callback)
1018
- callback(this);
1019
- return new Subscriber(this, () => refresh);
1020
- });
1021
- useComponentLifecycle(hook);
1022
- return hook.proxy;
1023
- }
1024
- on(subset, handler, squash, once) {
1025
- const control = manage(this);
1026
- const request = keys(control, subset);
1027
- const callback = squash
1028
- ? handler.bind(this)
1029
- : frame => frame
1030
- .filter(k => request.includes(k))
1031
- .forEach(k => handler.call(this, control.state[k], k));
1032
- const trigger = once
1033
- ? frame => { remove(); callback(frame); }
1034
- : callback;
1035
- ensure(control, request);
1036
- const remove = control.addListener(key => {
1037
- if (request.includes(key))
1038
- return trigger;
1039
- });
1040
- return remove;
1041
- }
1042
- once(select, callback, squash) {
1043
- if (callback)
1044
- return this.on(select, callback, squash, true);
1045
- else
1046
- return new Promise(resolve => {
1047
- this.on(select, resolve, true, true);
1048
- });
1049
- }
1050
- effect(callback, select) {
1051
- const control = manage(this);
1052
- let target = this;
1053
- const effect = createEffect(callback);
1054
- const invoke = () => effect.call(target, target);
1055
- if (select) {
1056
- invoke();
1057
- return this.on(select, invoke, true);
1058
- }
1059
- const sub = new Subscriber(control, () => invoke);
1060
- target = sub.proxy;
1061
- invoke();
1062
- return sub.commit();
1063
- }
1064
- import(from, subset) {
1065
- for (const key of keys(manage(this), subset))
1066
- if (key in from)
1067
- this[key] = from[key];
1068
- }
1069
- export(subset) {
1070
- const control = manage(this);
1071
- const output = {};
1072
- for (const key of keys(control, subset))
1073
- output[key] = control.state[key];
1074
- return output;
1075
- }
1076
- update(arg, tag) {
1077
- const control = manage(this);
1078
- if (typeof arg == "function")
1079
- arg = select(this, arg);
1080
- if (typeof arg == "boolean") {
1081
- if (!control.pending === arg)
1082
- return Promise.reject(Oops$2.StrictUpdate(arg));
1083
- }
1084
- else if (arg) {
1085
- control.update(arg);
1086
- if (1 in arguments && arg in this) {
1087
- const method = this[arg];
1088
- if (typeof method == "function")
1089
- if (typeof tag != "boolean")
1090
- method.call(this, tag);
1091
- else if (tag)
1092
- method.call(this);
1093
- }
1094
- }
1095
- return {
1096
- then(callback) {
1097
- if (callback)
1098
- if (control.pending)
1099
- control.waiting.add(callback);
1100
- else
1101
- callback(false);
1102
- else
1103
- throw Oops$2.NoChaining();
1104
- }
1105
- };
1106
- }
1107
- destroy() {
1108
- this.update("willDestroy", true);
1109
- }
1110
- toString() {
1111
- return this.constructor.name;
1112
- }
1113
- static create(...args) {
1114
- const instance = new this(...args);
1115
- manage(instance);
1116
- return instance;
1242
+ return useNew(this, callback);
1117
1243
  }
1118
1244
  static new(callback) {
1119
- const instance = useLazy(this, callback);
1120
- instance.update("willRender", true);
1121
- return instance;
1122
- }
1123
- static find(strict) {
1124
- return useFromContext(this, strict);
1245
+ return usePassive(this, callback);
1125
1246
  }
1126
1247
  static get(key) {
1127
- const instance = this.find(!!key);
1128
- return (typeof key == "function" ?
1129
- key(instance) :
1130
- typeof key == "string" ?
1131
- instance[key] :
1132
- instance);
1248
+ const instance = useContext(this, key !== false);
1249
+ return (typeof key == "string" ?
1250
+ instance[key] :
1251
+ instance);
1133
1252
  }
1134
1253
  static tap(key, expect) {
1135
- return this.find(true).tap(key, expect);
1254
+ return this.get().tap(key, expect);
1136
1255
  }
1137
1256
  static tag(id) {
1138
- return this.find(true).tag(id);
1257
+ return this.get().tag(id);
1139
1258
  }
1140
1259
  static use(callback) {
1141
- const instance = useModel(this, callback);
1142
- useComponentLifecycle(instance[LOCAL]);
1143
- usePeerContext(instance.get);
1144
- return instance;
1260
+ return useModel(this, callback);
1145
1261
  }
1146
1262
  static uses(props, only) {
1147
1263
  return this.use(instance => {
@@ -1153,106 +1269,11 @@ class Model {
1153
1269
  instance.import(props, only);
1154
1270
  return instance;
1155
1271
  }
1156
- static meta(path) {
1272
+ static meta(path, expect) {
1157
1273
  return typeof path == "function"
1158
- ? useComputed(this, path)
1159
- : useWatcher(this, path);
1160
- }
1161
- static isTypeof(maybe) {
1162
- return (typeof maybe == "function" &&
1163
- maybe.prototype instanceof this);
1274
+ ? useComputed(this, path, expect)
1275
+ : useActive(this, path, expect);
1164
1276
  }
1165
- }
1166
- Model.CONTROL = CONTROL;
1167
- Model.STATE = STATE;
1168
- Model.LOCAL = LOCAL;
1169
- Model.WHY = UPDATE;
1170
- defineLazy(Model, CONTROL, function () {
1171
- return new Controller(this).start();
1172
- });
1173
- function defer(on, method) {
1174
- const { subject, waiting } = on;
1175
- const real = subject[method];
1176
- subject[method] = (...args) => {
1177
- let done;
1178
- waiting.add(() => {
1179
- done = real.apply(subject, args);
1180
- });
1181
- return () => done();
1182
- };
1183
- }
1184
-
1185
- const Parent = new WeakMap();
1186
- const Oops$1 = issues({
1187
- ParentRequired: (expects, child) => `New ${child} created standalone but requires parent of type ${expects}. Did you remember to create via use(${child})?`,
1188
- UnexpectedParent: (expects, child, got) => `New ${child} created as child of ${got}, but must be instanceof ${expects}.`,
1189
- UndefinedNotAllowed: (key) => `Child property ${key} may not be undefined.`,
1190
- BadArgument: (type) => `Instruction \`use\` cannot accept argument type of ${type}.`,
1191
- IsReadOnly: (owner, key) => `${owner}.${key} is set to read-only, but tried to reassign assign.`,
1192
- MustBeDefined: (owner, key) => `${owner}.${key} must have initial value, as a read-only property.`
1193
- });
1194
- function bootstrap(object) {
1195
- const breakdown = getOwnPropertyDescriptors(object);
1196
- const control = new Model();
1197
- for (const key in breakdown)
1198
- defineProperty(control, key, breakdown[key]);
1199
- return control;
1200
- }
1201
- function use(input, argument) {
1202
- return child(function use(key) {
1203
- const { subject } = this;
1204
- // `true` => readonly
1205
- // `false` => writable, may be undefined
1206
- // `undefined` => writable (default)
1207
- let mode = argument;
1208
- let current;
1209
- const onUpdate = (next, initial) => {
1210
- if (mode === true && !initial)
1211
- throw Oops$1.IsReadOnly(subject, key);
1212
- if (next) {
1213
- current = next instanceof Model
1214
- ? next : bootstrap(next);
1215
- Parent.set(current, subject);
1216
- manage(current);
1217
- }
1218
- else if (mode === undefined)
1219
- throw Oops$1.UndefinedNotAllowed(key);
1220
- else
1221
- current = undefined;
1222
- if (typeof argument == "function")
1223
- return argument(current);
1224
- };
1225
- if (input) {
1226
- current =
1227
- Model.isTypeof(input) ? new input() :
1228
- input instanceof Model ? input :
1229
- typeof input === "function" ? input() :
1230
- typeof input === "object" ? bootstrap(input) :
1231
- Oops$1.BadArgument(typeof input).throw();
1232
- if (current)
1233
- mode = onUpdate(current, true) || mode;
1234
- else if (mode == true)
1235
- throw Oops$1.MustBeDefined(subject, key);
1236
- }
1237
- else
1238
- mode = false;
1239
- this.manage(key, current, onUpdate);
1240
- return () => current;
1241
- });
1242
- }
1243
- function parent(Expects, required) {
1244
- return apply(function parent() {
1245
- const child = this.subject;
1246
- const expected = Expects.name;
1247
- const value = Parent.get(this.subject);
1248
- if (!value) {
1249
- if (required)
1250
- throw Oops$1.ParentRequired(expected, child);
1251
- }
1252
- else if (!(value instanceof Expects))
1253
- throw Oops$1.UnexpectedParent(expected, child, value);
1254
- return { value };
1255
- });
1256
1277
  }
1257
1278
 
1258
1279
  const Oops = issues({
@@ -1260,35 +1281,32 @@ const Oops = issues({
1260
1281
  GlobalExists: (name) => `Shared instance of ${name} already exists! Consider unmounting existing, or use ${name}.reset() to force-delete it.`
1261
1282
  });
1262
1283
  const Active = new WeakMap();
1263
- class Singleton extends Model {
1264
- static get current() {
1265
- return Active.get(this);
1266
- }
1284
+ class Singleton extends MVC {
1267
1285
  static create(...args) {
1268
1286
  const Type = this;
1269
1287
  if (Active.has(Type))
1270
1288
  throw Oops.GlobalExists(this.name);
1271
- let instance = super.create(...args);
1289
+ const instance = super.create(...args);
1272
1290
  Active.set(Type, instance);
1273
1291
  return instance;
1274
1292
  }
1275
- static update(updates) {
1276
- const instance = this.current || this.create();
1293
+ static set(updates) {
1294
+ const instance = Active.get(this) || this.create();
1277
1295
  instance.import(updates);
1278
1296
  return instance.update();
1279
1297
  }
1280
- static is() {
1281
- return this.find(true);
1282
- }
1283
- static find(strict) {
1284
- const instance = this.current;
1285
- if (!instance && strict)
1298
+ static get(arg) {
1299
+ const instance = Active.get(this);
1300
+ if (!instance && arg !== false)
1286
1301
  throw Oops.GlobalDoesNotExist(this.name);
1287
- return instance;
1302
+ return (typeof arg == "string" ?
1303
+ instance[arg] :
1304
+ instance);
1288
1305
  }
1289
1306
  static reset() {
1290
- if (this.current)
1291
- this.current.destroy();
1307
+ const current = Active.get(this);
1308
+ if (current)
1309
+ current.destroy();
1292
1310
  }
1293
1311
  destroy() {
1294
1312
  super.destroy();
@@ -1296,5 +1314,5 @@ class Singleton extends Model {
1296
1314
  }
1297
1315
  }
1298
1316
 
1299
- export { Consumer, Model, Provider, Singleton, act, apply, child, Model as default, from, lazy, set as memo, on, parent, pending, ref, set, tap, use };
1317
+ export { Consumer, MVC as Model, Provider, Singleton, act, apply, child, MVC as default, from, lazy, set as memo, on, parent, pending, ref, set, tap, use$1 as use };
1300
1318
  //# sourceMappingURL=index.esm.js.map