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