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