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