@expressive/mvc 1.0.0-beta.34 → 1.0.0-beta.35

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