@expressive/mvc 1.0.0-beta.44 → 1.0.0-beta.45
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 +27 -37
- package/lib/index.esm.js +268 -205
- package/lib/index.esm.js.map +1 -1
- package/lib/index.js +268 -204
- package/lib/index.js.map +1 -1
- package/package.json +1 -1
package/lib/index.d.ts
CHANGED
|
@@ -18,6 +18,8 @@ declare function act<S>(action: Async<S>): typeof action & {
|
|
|
18
18
|
active: boolean;
|
|
19
19
|
};
|
|
20
20
|
|
|
21
|
+
declare function array<T = any>(): T[];
|
|
22
|
+
|
|
21
23
|
type Callback = () => void;
|
|
22
24
|
type Class = new (...args: any[]) => any;
|
|
23
25
|
type InstanceOf<T> = T extends { prototype: infer U } ? U : never;
|
|
@@ -34,7 +36,7 @@ declare class Subscriber<T extends Stateful = any> {
|
|
|
34
36
|
commit: () => () => void;
|
|
35
37
|
active: boolean;
|
|
36
38
|
dependant: Set<Listener>;
|
|
37
|
-
watch: { [key in Model.Event<T, Model>]:
|
|
39
|
+
watch: { [key in Model.Event<T, Model>]: boolean | Callback; };
|
|
38
40
|
constructor(target: Controller<T> | T, onUpdate: Controller.OnEvent);
|
|
39
41
|
}
|
|
40
42
|
|
|
@@ -200,43 +202,31 @@ declare class Controller<T extends Stateful = any> {
|
|
|
200
202
|
* Property initializer, will run upon instance creation.
|
|
201
203
|
* Optional returned callback will run when once upon first access.
|
|
202
204
|
*/
|
|
203
|
-
type Instruction<T> = (this: Controller, key: string, thisArg: Controller) =>
|
|
204
|
-
| Instruction.Getter<T>
|
|
205
|
-
| Instruction.ExplicitDescriptor
|
|
206
|
-
| Instruction.Descriptor<T>
|
|
207
|
-
| Instruction.RecursiveDescriptor<T>
|
|
208
|
-
| boolean
|
|
209
|
-
| void;
|
|
210
|
-
|
|
205
|
+
declare type Instruction<T> = (this: Controller, key: string, thisArg: Controller) => Instruction.Getter<T> | Instruction.ExplicitDescriptor | Instruction.Descriptor<T> | Instruction.RecursiveDescriptor<T> | boolean | void;
|
|
211
206
|
declare namespace Instruction {
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
value?: T;
|
|
235
|
-
set?: Setter<T> | false;
|
|
236
|
-
suspense?: boolean;
|
|
237
|
-
}
|
|
207
|
+
type Getter<T> = (state: T, within?: Subscriber) => T;
|
|
208
|
+
type Setter<T> = (value: T, state: any) => boolean | void;
|
|
209
|
+
type Runner<T> = (this: Controller, key: string, on: Controller) => Instruction.Descriptor<T> | boolean | undefined;
|
|
210
|
+
interface Descriptor<T> {
|
|
211
|
+
configurable?: boolean;
|
|
212
|
+
enumerable?: boolean;
|
|
213
|
+
value?: T;
|
|
214
|
+
writable?: boolean;
|
|
215
|
+
get?: Getter<T>;
|
|
216
|
+
set?: Setter<T> | false;
|
|
217
|
+
suspense?: boolean;
|
|
218
|
+
}
|
|
219
|
+
interface ExplicitDescriptor extends PropertyDescriptor {
|
|
220
|
+
explicit: true;
|
|
221
|
+
}
|
|
222
|
+
interface RecursiveDescriptor<T> {
|
|
223
|
+
recursive: true;
|
|
224
|
+
enumerable?: boolean;
|
|
225
|
+
value?: T;
|
|
226
|
+
set?: Setter<T> | false;
|
|
227
|
+
suspense?: boolean;
|
|
228
|
+
}
|
|
238
229
|
}
|
|
239
|
-
|
|
240
230
|
/**
|
|
241
231
|
* Run instruction as controller sets itself up.
|
|
242
232
|
* This will specialize the behavior of a given property.
|
|
@@ -607,4 +597,4 @@ declare function useTap<T extends Stateful, K extends Model.Field<T>>(source: T
|
|
|
607
597
|
declare function useTap<T extends Stateful, R>(source: T | (() => T) | useTap.Tappable, compute: (this: T, from: T) => R, expect: true): Exclude<R, undefined>;
|
|
608
598
|
declare function useTap<T extends Stateful, R>(source: T | (() => T) | useTap.Tappable, compute: (this: T, from: T) => R, expect?: boolean): R;
|
|
609
599
|
|
|
610
|
-
export { CONTROL, Consumer, Global, LOCAL, MVC as Model, Provider, STATE, Stateful, WHY, act, apply, MVC as default, from, parent, ref, set, tap, use, useFrom, useInContext, useModel, useTap };
|
|
600
|
+
export { CONTROL, Consumer, Global, LOCAL, MVC as Model, Provider, STATE, Stateful, WHY, act, apply, array, MVC as default, from, parent, ref, set, tap, use, useFrom, useInContext, useModel, useTap };
|
package/lib/index.esm.js
CHANGED
|
@@ -93,6 +93,149 @@ function applyUpdate(subject, keys) {
|
|
|
93
93
|
};
|
|
94
94
|
}
|
|
95
95
|
|
|
96
|
+
const CONTROL = Symbol("CONTROL");
|
|
97
|
+
const WHY = Symbol("UPDATE");
|
|
98
|
+
const LOCAL = Symbol("LOCAL");
|
|
99
|
+
const STATE = Symbol("STATE");
|
|
100
|
+
class Model {
|
|
101
|
+
constructor() {
|
|
102
|
+
define(this, CONTROL, new Controller(this));
|
|
103
|
+
define(this, "get", this);
|
|
104
|
+
define(this, "set", this);
|
|
105
|
+
}
|
|
106
|
+
get [STATE]() {
|
|
107
|
+
return this[CONTROL].state;
|
|
108
|
+
}
|
|
109
|
+
get [WHY]() {
|
|
110
|
+
return UPDATE.get(this);
|
|
111
|
+
}
|
|
112
|
+
on(select, handler, squash, once) {
|
|
113
|
+
return control(this, control => {
|
|
114
|
+
if (typeof select == "function")
|
|
115
|
+
return control.addListener(select);
|
|
116
|
+
const keys = typeof select == "string" ? [select] :
|
|
117
|
+
!select.length ? getOwnPropertyNames(control.state) :
|
|
118
|
+
select;
|
|
119
|
+
ensure(control, keys);
|
|
120
|
+
const callback = squash
|
|
121
|
+
? handler.bind(this)
|
|
122
|
+
: frame => frame
|
|
123
|
+
.filter(k => keys.includes(k))
|
|
124
|
+
.forEach(k => handler.call(this, control.state[k], k));
|
|
125
|
+
const trigger = once
|
|
126
|
+
? frame => { remove(); callback(frame); }
|
|
127
|
+
: callback;
|
|
128
|
+
const remove = control.addListener(key => {
|
|
129
|
+
if (keys.includes(key))
|
|
130
|
+
return trigger;
|
|
131
|
+
});
|
|
132
|
+
return remove;
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
once(select, callback, squash) {
|
|
136
|
+
if (callback)
|
|
137
|
+
return this.on(select, callback, squash, true);
|
|
138
|
+
return new Promise(resolve => {
|
|
139
|
+
this.on(select, resolve, true, true);
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
effect(callback, select) {
|
|
143
|
+
const effect = createEffect(callback);
|
|
144
|
+
return control(this, control => {
|
|
145
|
+
if (!select) {
|
|
146
|
+
const sub = new Subscriber(control, () => invoke);
|
|
147
|
+
const invoke = () => {
|
|
148
|
+
const x = sub.proxy;
|
|
149
|
+
effect.call(x, x);
|
|
150
|
+
};
|
|
151
|
+
invoke();
|
|
152
|
+
return sub.commit();
|
|
153
|
+
}
|
|
154
|
+
const invoke = () => {
|
|
155
|
+
effect.call(this.get, this.get);
|
|
156
|
+
};
|
|
157
|
+
invoke();
|
|
158
|
+
if (!select.length) {
|
|
159
|
+
control.onDestroy.add(invoke);
|
|
160
|
+
return () => {
|
|
161
|
+
control.onDestroy.delete(invoke);
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
return control.addListener(key => {
|
|
165
|
+
if (select.includes(key))
|
|
166
|
+
return invoke;
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
// TODO: account for exotic properties
|
|
171
|
+
import(source, select) {
|
|
172
|
+
const { subject } = control(this);
|
|
173
|
+
if (!select)
|
|
174
|
+
select = getOwnPropertyNames(subject);
|
|
175
|
+
for (const key of select)
|
|
176
|
+
if (key in source)
|
|
177
|
+
this[key] = source[key];
|
|
178
|
+
}
|
|
179
|
+
export(subset) {
|
|
180
|
+
const { state } = control(this);
|
|
181
|
+
const output = {};
|
|
182
|
+
if (!subset)
|
|
183
|
+
subset = getOwnPropertyNames(state);
|
|
184
|
+
for (const key of subset)
|
|
185
|
+
output[key] = state[key];
|
|
186
|
+
return output;
|
|
187
|
+
}
|
|
188
|
+
update(arg, tag) {
|
|
189
|
+
const target = control(this);
|
|
190
|
+
if (typeof arg == "string") {
|
|
191
|
+
target.update(arg);
|
|
192
|
+
if (1 in arguments && arg in this) {
|
|
193
|
+
const method = this[arg];
|
|
194
|
+
if (typeof method == "function")
|
|
195
|
+
if (typeof tag != "boolean")
|
|
196
|
+
method.call(this, tag);
|
|
197
|
+
else if (tag)
|
|
198
|
+
method.call(this);
|
|
199
|
+
}
|
|
200
|
+
arg = undefined;
|
|
201
|
+
}
|
|
202
|
+
return target.requestUpdate(arg);
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Mark this instance for garbage-collection and send `willDestroy` event to all listeners.
|
|
206
|
+
*/
|
|
207
|
+
destroy() {
|
|
208
|
+
control(this).stop();
|
|
209
|
+
}
|
|
210
|
+
toString() {
|
|
211
|
+
return this.constructor.name;
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Creates a new instance of this controller.
|
|
215
|
+
*
|
|
216
|
+
* Beyond `new this(...)`, method will activate managed-state.
|
|
217
|
+
*
|
|
218
|
+
* @param args - arguments sent to constructor
|
|
219
|
+
*/
|
|
220
|
+
static create(...args) {
|
|
221
|
+
const instance = new this(...args);
|
|
222
|
+
control(instance);
|
|
223
|
+
return instance;
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Static equivalent of `x instanceof this`.
|
|
227
|
+
*
|
|
228
|
+
* Will determine if provided class is a subtype of this one.
|
|
229
|
+
*/
|
|
230
|
+
static isTypeof(maybe) {
|
|
231
|
+
return (typeof maybe == "function" &&
|
|
232
|
+
maybe.prototype instanceof this);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
defineLazy(Model, CONTROL, function () {
|
|
236
|
+
return new Controller(this);
|
|
237
|
+
});
|
|
238
|
+
|
|
96
239
|
class Subscriber {
|
|
97
240
|
constructor(target, onUpdate) {
|
|
98
241
|
this.onUpdate = onUpdate;
|
|
@@ -304,6 +447,7 @@ const Oops$9 = issues({
|
|
|
304
447
|
StrictUpdate: () => `Strict update() did not find pending updates.`,
|
|
305
448
|
NoChaining: () => `Then called with undefined; update promise will never catch nor supports chaining.`
|
|
306
449
|
});
|
|
450
|
+
const PENDING = new Map();
|
|
307
451
|
const READY = new WeakSet();
|
|
308
452
|
class Controller {
|
|
309
453
|
constructor(subject) {
|
|
@@ -329,52 +473,28 @@ class Controller {
|
|
|
329
473
|
const { value: entry } = getOwnPropertyDescriptor(subject, key);
|
|
330
474
|
if (typeof entry == "function")
|
|
331
475
|
return;
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
const instruction = Pending.get(entry);
|
|
338
|
-
if (instruction) {
|
|
339
|
-
Pending.delete(entry);
|
|
340
|
-
delete subject[key];
|
|
341
|
-
const desc = instruction.call(this, key, this);
|
|
342
|
-
if (desc === false)
|
|
343
|
-
return;
|
|
344
|
-
if (typeof desc == "object") {
|
|
345
|
-
if ("value" in desc)
|
|
346
|
-
state[key] = desc.value;
|
|
347
|
-
onSet = desc.set;
|
|
348
|
-
onGet = desc.get;
|
|
349
|
-
suspense = desc.suspense;
|
|
350
|
-
enumerable = desc.enumerable;
|
|
351
|
-
}
|
|
476
|
+
if (typeof entry == "symbol") {
|
|
477
|
+
const instruction = PENDING.get(entry);
|
|
478
|
+
if (instruction)
|
|
479
|
+
instruction.call(this, key, this);
|
|
480
|
+
return;
|
|
352
481
|
}
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
if (onSet !== false)
|
|
356
|
-
set = this.ref(key, onSet);
|
|
357
|
-
const get = (local) => {
|
|
358
|
-
if (!(key in state) && suspense)
|
|
359
|
-
throw suspend(this, key);
|
|
360
|
-
const value = state[key];
|
|
361
|
-
if (onGet)
|
|
362
|
-
return local
|
|
363
|
-
? onGet(value, local)
|
|
364
|
-
: onGet(value);
|
|
365
|
-
return value;
|
|
366
|
-
};
|
|
482
|
+
state[key] = entry;
|
|
483
|
+
const set = this.ref(key);
|
|
367
484
|
defineProperty(subject, key, {
|
|
368
|
-
enumerable
|
|
485
|
+
enumerable: false,
|
|
486
|
+
get: () => state[key],
|
|
487
|
+
set
|
|
369
488
|
});
|
|
370
489
|
defineProperty(proxy, key, {
|
|
371
|
-
enumerable
|
|
490
|
+
enumerable: false,
|
|
372
491
|
get() {
|
|
373
492
|
const local = this[LOCAL];
|
|
374
493
|
if (local && !local.watch[key])
|
|
375
494
|
local.watch[key] = true;
|
|
376
|
-
return
|
|
377
|
-
}
|
|
495
|
+
return state[key];
|
|
496
|
+
},
|
|
497
|
+
set
|
|
378
498
|
});
|
|
379
499
|
}
|
|
380
500
|
ref(key, handler) {
|
|
@@ -473,179 +593,55 @@ function control(subject, cb) {
|
|
|
473
593
|
return cb(control);
|
|
474
594
|
}
|
|
475
595
|
|
|
476
|
-
const CONTROL = Symbol("CONTROL");
|
|
477
|
-
const WHY = Symbol("UPDATE");
|
|
478
|
-
const LOCAL = Symbol("LOCAL");
|
|
479
|
-
const STATE = Symbol("STATE");
|
|
480
|
-
class Model {
|
|
481
|
-
constructor() {
|
|
482
|
-
define(this, CONTROL, new Controller(this));
|
|
483
|
-
define(this, "get", this);
|
|
484
|
-
define(this, "set", this);
|
|
485
|
-
}
|
|
486
|
-
get [STATE]() {
|
|
487
|
-
return this[CONTROL].state;
|
|
488
|
-
}
|
|
489
|
-
get [WHY]() {
|
|
490
|
-
return UPDATE.get(this);
|
|
491
|
-
}
|
|
492
|
-
on(select, handler, squash, once) {
|
|
493
|
-
return control(this, control => {
|
|
494
|
-
if (typeof select == "function")
|
|
495
|
-
return control.addListener(select);
|
|
496
|
-
const keys = typeof select == "string" ? [select] :
|
|
497
|
-
!select.length ? getOwnPropertyNames(control.state) :
|
|
498
|
-
select;
|
|
499
|
-
ensure(control, keys);
|
|
500
|
-
const callback = squash
|
|
501
|
-
? handler.bind(this)
|
|
502
|
-
: frame => frame
|
|
503
|
-
.filter(k => keys.includes(k))
|
|
504
|
-
.forEach(k => handler.call(this, control.state[k], k));
|
|
505
|
-
const trigger = once
|
|
506
|
-
? frame => { remove(); callback(frame); }
|
|
507
|
-
: callback;
|
|
508
|
-
const remove = control.addListener(key => {
|
|
509
|
-
if (keys.includes(key))
|
|
510
|
-
return trigger;
|
|
511
|
-
});
|
|
512
|
-
return remove;
|
|
513
|
-
});
|
|
514
|
-
}
|
|
515
|
-
once(select, callback, squash) {
|
|
516
|
-
if (callback)
|
|
517
|
-
return this.on(select, callback, squash, true);
|
|
518
|
-
return new Promise(resolve => {
|
|
519
|
-
this.on(select, resolve, true, true);
|
|
520
|
-
});
|
|
521
|
-
}
|
|
522
|
-
effect(callback, select) {
|
|
523
|
-
const effect = createEffect(callback);
|
|
524
|
-
return control(this, control => {
|
|
525
|
-
if (!select) {
|
|
526
|
-
const sub = new Subscriber(control, () => invoke);
|
|
527
|
-
const invoke = () => {
|
|
528
|
-
const x = sub.proxy;
|
|
529
|
-
effect.call(x, x);
|
|
530
|
-
};
|
|
531
|
-
invoke();
|
|
532
|
-
return sub.commit();
|
|
533
|
-
}
|
|
534
|
-
const invoke = () => {
|
|
535
|
-
effect.call(this.get, this.get);
|
|
536
|
-
};
|
|
537
|
-
invoke();
|
|
538
|
-
if (!select.length) {
|
|
539
|
-
control.onDestroy.add(invoke);
|
|
540
|
-
return () => {
|
|
541
|
-
control.onDestroy.delete(invoke);
|
|
542
|
-
};
|
|
543
|
-
}
|
|
544
|
-
return control.addListener(key => {
|
|
545
|
-
if (select.includes(key))
|
|
546
|
-
return invoke;
|
|
547
|
-
});
|
|
548
|
-
});
|
|
549
|
-
}
|
|
550
|
-
// TODO: account for exotic properties
|
|
551
|
-
import(source, select) {
|
|
552
|
-
const { subject } = control(this);
|
|
553
|
-
if (!select)
|
|
554
|
-
select = getOwnPropertyNames(subject);
|
|
555
|
-
for (const key of select)
|
|
556
|
-
if (key in source)
|
|
557
|
-
this[key] = source[key];
|
|
558
|
-
}
|
|
559
|
-
export(subset) {
|
|
560
|
-
const { state } = control(this);
|
|
561
|
-
const output = {};
|
|
562
|
-
if (!subset)
|
|
563
|
-
subset = getOwnPropertyNames(state);
|
|
564
|
-
for (const key of subset)
|
|
565
|
-
output[key] = state[key];
|
|
566
|
-
return output;
|
|
567
|
-
}
|
|
568
|
-
update(arg, tag) {
|
|
569
|
-
const target = control(this);
|
|
570
|
-
if (typeof arg == "string") {
|
|
571
|
-
target.update(arg);
|
|
572
|
-
if (1 in arguments && arg in this) {
|
|
573
|
-
const method = this[arg];
|
|
574
|
-
if (typeof method == "function")
|
|
575
|
-
if (typeof tag != "boolean")
|
|
576
|
-
method.call(this, tag);
|
|
577
|
-
else if (tag)
|
|
578
|
-
method.call(this);
|
|
579
|
-
}
|
|
580
|
-
arg = undefined;
|
|
581
|
-
}
|
|
582
|
-
return target.requestUpdate(arg);
|
|
583
|
-
}
|
|
584
|
-
/**
|
|
585
|
-
* Mark this instance for garbage-collection and send `willDestroy` event to all listeners.
|
|
586
|
-
*/
|
|
587
|
-
destroy() {
|
|
588
|
-
control(this).stop();
|
|
589
|
-
}
|
|
590
|
-
toString() {
|
|
591
|
-
return this.constructor.name;
|
|
592
|
-
}
|
|
593
|
-
/**
|
|
594
|
-
* Creates a new instance of this controller.
|
|
595
|
-
*
|
|
596
|
-
* Beyond `new this(...)`, method will activate managed-state.
|
|
597
|
-
*
|
|
598
|
-
* @param args - arguments sent to constructor
|
|
599
|
-
*/
|
|
600
|
-
static create(...args) {
|
|
601
|
-
const instance = new this(...args);
|
|
602
|
-
control(instance);
|
|
603
|
-
return instance;
|
|
604
|
-
}
|
|
605
|
-
/**
|
|
606
|
-
* Static equivalent of `x instanceof this`.
|
|
607
|
-
*
|
|
608
|
-
* Will determine if provided class is a subtype of this one.
|
|
609
|
-
*/
|
|
610
|
-
static isTypeof(maybe) {
|
|
611
|
-
return (typeof maybe == "function" &&
|
|
612
|
-
maybe.prototype instanceof this);
|
|
613
|
-
}
|
|
614
|
-
}
|
|
615
|
-
defineLazy(Model, CONTROL, function () {
|
|
616
|
-
return new Controller(this);
|
|
617
|
-
});
|
|
618
|
-
|
|
619
|
-
const Pending = new Map();
|
|
620
596
|
function apply(fn, label) {
|
|
621
597
|
const name = label || fn.name || "pending";
|
|
622
598
|
const placeholder = Symbol(`${name} instruction`);
|
|
623
599
|
function setup(key) {
|
|
600
|
+
const { proxy, state, subject } = this;
|
|
601
|
+
const control = this;
|
|
602
|
+
PENDING.delete(placeholder);
|
|
603
|
+
delete subject[key];
|
|
624
604
|
let output = fn.call(this, key, this);
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
}
|
|
633
|
-
if ("recursive" in output && output.recursive)
|
|
634
|
-
return Object.assign(Object.assign({}, output), { get: recursive(this, key) });
|
|
635
|
-
}
|
|
636
|
-
case "boolean":
|
|
637
|
-
return output;
|
|
605
|
+
if (typeof output == "function")
|
|
606
|
+
output = { get: output };
|
|
607
|
+
if (typeof output != "object")
|
|
608
|
+
return;
|
|
609
|
+
if ("explicit" in output && output.explicit) {
|
|
610
|
+
defineProperty(subject, key, output);
|
|
611
|
+
return false;
|
|
638
612
|
}
|
|
639
|
-
|
|
613
|
+
if ("recursive" in output && output.recursive)
|
|
614
|
+
output = Object.assign(Object.assign({}, output), { get: recursive(this, key) });
|
|
615
|
+
const desc = output;
|
|
616
|
+
if ("value" in desc)
|
|
617
|
+
state[key] = desc.value;
|
|
618
|
+
const { get: onGet, set: onSet, enumerable, suspense } = desc;
|
|
619
|
+
let set = onSet === false
|
|
620
|
+
? undefined
|
|
621
|
+
: this.ref(key, onSet);
|
|
622
|
+
function get() {
|
|
623
|
+
if (!(key in state) && suspense)
|
|
624
|
+
throw suspend(control, key);
|
|
625
|
+
const local = this[LOCAL];
|
|
626
|
+
if (local && !(key in local.watch))
|
|
627
|
+
local.watch[key] = true;
|
|
628
|
+
const value = state[key];
|
|
629
|
+
if (!onGet)
|
|
630
|
+
return value;
|
|
631
|
+
return local
|
|
632
|
+
? onGet(value, local)
|
|
633
|
+
: onGet(value);
|
|
634
|
+
}
|
|
635
|
+
for (const x of [subject, proxy])
|
|
636
|
+
defineProperty(x, key, { enumerable, get, set });
|
|
640
637
|
}
|
|
641
|
-
|
|
638
|
+
PENDING.set(placeholder, setup);
|
|
642
639
|
return placeholder;
|
|
643
640
|
}
|
|
644
641
|
function recursive(source, key) {
|
|
645
|
-
|
|
646
|
-
const subscribe = (parent) => {
|
|
642
|
+
return forSubscriber((parent, context) => {
|
|
647
643
|
let child;
|
|
648
|
-
|
|
644
|
+
function init() {
|
|
649
645
|
if (child) {
|
|
650
646
|
child.release();
|
|
651
647
|
parent.dependant.delete(child);
|
|
@@ -660,15 +656,23 @@ function recursive(source, key) {
|
|
|
660
656
|
parent.dependant.add(child);
|
|
661
657
|
context.set(parent, child.proxy);
|
|
662
658
|
}
|
|
663
|
-
}
|
|
659
|
+
}
|
|
664
660
|
init();
|
|
665
661
|
parent.watch[key] = init;
|
|
666
|
-
};
|
|
662
|
+
});
|
|
663
|
+
}
|
|
664
|
+
function forSubscriber(fn) {
|
|
665
|
+
const context = new WeakMap();
|
|
667
666
|
return (value, local) => {
|
|
668
667
|
if (!local)
|
|
669
668
|
return value;
|
|
670
|
-
if (!context.has(local))
|
|
671
|
-
|
|
669
|
+
if (!context.has(local)) {
|
|
670
|
+
const output = fn(local, context);
|
|
671
|
+
if (output) {
|
|
672
|
+
context.set(local, output);
|
|
673
|
+
return output;
|
|
674
|
+
}
|
|
675
|
+
}
|
|
672
676
|
return context.get(local);
|
|
673
677
|
};
|
|
674
678
|
}
|
|
@@ -702,6 +706,65 @@ function act(task) {
|
|
|
702
706
|
});
|
|
703
707
|
}
|
|
704
708
|
|
|
709
|
+
class Managed extends Array {
|
|
710
|
+
constructor(onUpdate) {
|
|
711
|
+
super();
|
|
712
|
+
this.lastUpdate = [0, 0];
|
|
713
|
+
this.update = (from, to) => {
|
|
714
|
+
this.lastUpdate = [from, to];
|
|
715
|
+
onUpdate();
|
|
716
|
+
};
|
|
717
|
+
}
|
|
718
|
+
push(...items) {
|
|
719
|
+
const length = this.length;
|
|
720
|
+
const end = super.push(...items);
|
|
721
|
+
this.update(length, end);
|
|
722
|
+
return end;
|
|
723
|
+
}
|
|
724
|
+
unshift(...items) {
|
|
725
|
+
const end = super.push(...items);
|
|
726
|
+
this.update(0, end);
|
|
727
|
+
return end;
|
|
728
|
+
}
|
|
729
|
+
splice(start, deleteCount, ...rest) {
|
|
730
|
+
this.update(start, deleteCount !== rest.length ? Infinity : deleteCount);
|
|
731
|
+
return super.splice(start, deleteCount, ...rest);
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
function array() {
|
|
735
|
+
return apply(function array(key) {
|
|
736
|
+
const array = new Managed(() => this.update(key));
|
|
737
|
+
const access = forSubscriber(context => {
|
|
738
|
+
const local = Object.create(array);
|
|
739
|
+
const update = context.onUpdate(key, this);
|
|
740
|
+
let rangeA = 0;
|
|
741
|
+
let rangeB = 0;
|
|
742
|
+
function onUpdate() {
|
|
743
|
+
const [lastA, lastB] = array.lastUpdate;
|
|
744
|
+
if (rangeA <= lastB && rangeB >= lastA)
|
|
745
|
+
return update;
|
|
746
|
+
}
|
|
747
|
+
function listen(eventA, eventB) {
|
|
748
|
+
if (context.active)
|
|
749
|
+
return;
|
|
750
|
+
context.watch[key] = onUpdate;
|
|
751
|
+
rangeA = Math.min(rangeA, eventA);
|
|
752
|
+
rangeB = Math.max(rangeB, eventB);
|
|
753
|
+
}
|
|
754
|
+
local[Symbol.iterator] = () => {
|
|
755
|
+
listen(0, Infinity);
|
|
756
|
+
return array[Symbol.iterator]();
|
|
757
|
+
};
|
|
758
|
+
return local;
|
|
759
|
+
});
|
|
760
|
+
return {
|
|
761
|
+
get: access,
|
|
762
|
+
set: false,
|
|
763
|
+
value: array
|
|
764
|
+
};
|
|
765
|
+
});
|
|
766
|
+
}
|
|
767
|
+
|
|
705
768
|
function ref(arg) {
|
|
706
769
|
return apply(function ref(key) {
|
|
707
770
|
let value = {};
|
|
@@ -1287,5 +1350,5 @@ class Global extends MVC {
|
|
|
1287
1350
|
}
|
|
1288
1351
|
}
|
|
1289
1352
|
|
|
1290
|
-
export { CONTROL, Consumer, Global, LOCAL, MVC as Model, Provider, STATE, WHY, act, apply, MVC as default, from, parent, ref, set, tap, use$1 as use, useFrom, useInContext, useModel, useTap };
|
|
1353
|
+
export { CONTROL, Consumer, Global, LOCAL, MVC as Model, Provider, STATE, WHY, act, apply, array, MVC as default, from, parent, ref, set, tap, use$1 as use, useFrom, useInContext, useModel, useTap };
|
|
1291
1354
|
//# sourceMappingURL=index.esm.js.map
|