sia-reactor 0.0.21 → 0.0.22
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/README.md +115 -89
- package/dist/{TimeTravelOverlay-CJv-S_Km.d.cts → TimeTravelOverlay-DiXUgbUU.d.cts} +9 -8
- package/dist/{TimeTravelOverlay-DxqJL0Zk.d.ts → TimeTravelOverlay-eWjAy0yr.d.ts} +9 -8
- package/dist/adapters/react.cjs +66 -84
- package/dist/adapters/react.d.cts +23 -22
- package/dist/adapters/react.d.ts +23 -22
- package/dist/adapters/react.js +3 -3
- package/dist/adapters/vanilla.cjs +66 -84
- package/dist/adapters/vanilla.d.cts +4 -4
- package/dist/adapters/vanilla.d.ts +4 -4
- package/dist/adapters/vanilla.js +3 -3
- package/dist/{chunk-2WBPGSRL.js → chunk-3SKLWTEA.js} +52 -70
- package/dist/{chunk-DP74DVRT.js → chunk-BTA6MIQ6.js} +40 -8
- package/dist/{chunk-TFLYCXK4.js → chunk-CS3FOV6J.js} +14 -13
- package/dist/{index-Oie9hhE8.d.cts → index-BgbbNXTW.d.cts} +306 -207
- package/dist/{index-Oie9hhE8.d.ts → index-BgbbNXTW.d.ts} +306 -207
- package/dist/index.cjs +54 -75
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +2 -4
- package/dist/{plugins.cjs → modules.cjs} +437 -166
- package/dist/modules.d.cts +53 -0
- package/dist/modules.d.ts +53 -0
- package/dist/modules.js +627 -0
- package/dist/super.d.ts +610 -281
- package/dist/super.global.js +445 -174
- package/dist/timeTravel-CraHdbXZ.d.cts +352 -0
- package/dist/timeTravel-YUxRHRgh.d.ts +352 -0
- package/dist/utils.cjs +41 -7
- package/dist/utils.d.cts +1 -1
- package/dist/utils.d.ts +1 -1
- package/dist/utils.js +3 -1
- package/package.json +6 -6
- package/dist/plugins.d.cts +0 -112
- package/dist/plugins.d.ts +0 -112
- package/dist/plugins.js +0 -370
- package/dist/timeTravel-B1vedDQc.d.ts +0 -76
- package/dist/timeTravel-WpgWmKu-.d.cts +0 -76
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
CTX,
|
|
3
3
|
EVT_OPTS,
|
|
4
|
-
EVT_WARN,
|
|
5
4
|
INDIFFABLE,
|
|
6
5
|
INERTIA,
|
|
7
6
|
NIL,
|
|
@@ -18,11 +17,10 @@ import {
|
|
|
18
17
|
getAny,
|
|
19
18
|
getTrailRecords,
|
|
20
19
|
inAny,
|
|
21
|
-
mergeObjs,
|
|
22
20
|
nuke,
|
|
23
21
|
parseEvtOpts,
|
|
24
22
|
setAny
|
|
25
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-BTA6MIQ6.js";
|
|
26
24
|
|
|
27
25
|
// src/ts/core/event.ts
|
|
28
26
|
var ReactorEvent = class _ReactorEvent {
|
|
@@ -47,35 +45,34 @@ var ReactorEvent = class _ReactorEvent {
|
|
|
47
45
|
staticType;
|
|
48
46
|
/** Original event target context. */
|
|
49
47
|
target;
|
|
50
|
-
/** Root reactive object for this event wave. */
|
|
48
|
+
/** Root reactive object for this event instance wave. */
|
|
51
49
|
root;
|
|
52
|
-
/** Original target path for this event wave. */
|
|
50
|
+
/** Original target path for this event instance wave. */
|
|
53
51
|
path;
|
|
54
52
|
/** Current value at the event target path. */
|
|
55
53
|
value;
|
|
56
54
|
/** Previous value at the event target path. */
|
|
57
55
|
oldValue;
|
|
58
|
-
/** Whether resolve/reject intent semantics are allowed for this event. */
|
|
56
|
+
/** Whether resolve/reject intent semantics are allowed for this event instance. */
|
|
59
57
|
rejectable;
|
|
60
|
-
/** Whether this event wave can bubble back up to ancestors or just capture down. */
|
|
58
|
+
/** Whether this event instance wave can bubble back up to ancestors or just capture down. */
|
|
61
59
|
bubbles;
|
|
62
60
|
/**
|
|
63
|
-
* `DOMHighResTimeStamp` for this event payload for native event parity and accuracy.
|
|
61
|
+
* `DOMHighResTimeStamp` for this event instance payload for native event parity and accuracy.
|
|
64
62
|
* Enable `eventTimeStamps` option, then use this over custom timestamps in listeners for accuracy.
|
|
65
63
|
* */
|
|
66
64
|
timestamp;
|
|
67
|
-
|
|
65
|
+
/** The `Reactor` instance that dispatched this event instance. */
|
|
66
|
+
reactor;
|
|
68
67
|
_resolved = "";
|
|
69
68
|
_rejected = "";
|
|
70
69
|
_propagationStopped = false;
|
|
71
70
|
_immediatePropagationStopped = false;
|
|
72
71
|
/**
|
|
73
72
|
* @param payload Source payload for this event instance.
|
|
74
|
-
* @param
|
|
75
|
-
* @param canWarn Whether warning output is enabled.
|
|
76
|
-
* @param canStamp Whether timestamping is enabled.
|
|
73
|
+
* @param reactor The `Reactor` instance creating this event instance.
|
|
77
74
|
*/
|
|
78
|
-
constructor(payload,
|
|
75
|
+
constructor(payload, reactor) {
|
|
79
76
|
this.staticType = this.type = payload.type;
|
|
80
77
|
this.target = payload.target;
|
|
81
78
|
this.currentTarget = payload.currentTarget;
|
|
@@ -84,9 +81,9 @@ var ReactorEvent = class _ReactorEvent {
|
|
|
84
81
|
this.value = payload.target.value;
|
|
85
82
|
this.oldValue = payload.target.oldValue;
|
|
86
83
|
this.rejectable = payload.rejectable;
|
|
87
|
-
this.bubbles =
|
|
88
|
-
if (
|
|
89
|
-
|
|
84
|
+
this.bubbles = !!reactor.config.eventBubbling;
|
|
85
|
+
if (reactor.config.eventTimeStamps) this.timestamp = performance.now();
|
|
86
|
+
this.reactor = reactor;
|
|
90
87
|
}
|
|
91
88
|
/** Whether propagation has been stopped. */
|
|
92
89
|
get propagationStopped() {
|
|
@@ -116,9 +113,9 @@ var ReactorEvent = class _ReactorEvent {
|
|
|
116
113
|
* @example e.resolve("API Load successful"); // message
|
|
117
114
|
*/
|
|
118
115
|
resolve(message) {
|
|
119
|
-
if (!this.rejectable) return this.
|
|
120
|
-
if (this.eventPhase !== _ReactorEvent.CAPTURING_PHASE) this.
|
|
121
|
-
if (this.rejectable) this._resolved = message || `Could ${this.staticType} intended value at "${this.path}"
|
|
116
|
+
if (!this.rejectable) return this.reactor.log(`[ReactorEvent] Ignored \`resolve()\` call on a non-rejectable ${this.staticType} at "${this.path}"`);
|
|
117
|
+
if (this.eventPhase !== _ReactorEvent.CAPTURING_PHASE) this.reactor.log(`[ReactorEvent] Resolving an intent on ${this.staticType} at "${this.path}" outside of the capture phase is unadvised.`);
|
|
118
|
+
if (this.rejectable) this.reactor.log(`[ReactorEvent] ${this._resolved = message || `Could ${this.staticType} intended value at "${this.path}"`}`);
|
|
122
119
|
}
|
|
123
120
|
/** Rejection reason for rejectable events. */
|
|
124
121
|
get rejected() {
|
|
@@ -131,9 +128,9 @@ var ReactorEvent = class _ReactorEvent {
|
|
|
131
128
|
* @example e.resolve("User is not logged in"); // reason
|
|
132
129
|
*/
|
|
133
130
|
reject(reason) {
|
|
134
|
-
if (!this.rejectable) return this.
|
|
135
|
-
if (this.eventPhase !== _ReactorEvent.CAPTURING_PHASE) this.
|
|
136
|
-
if (this.rejectable) this._rejected = reason || `Couldn't ${this.staticType} intended value at "${this.path}"
|
|
131
|
+
if (!this.rejectable) return this.reactor.log(`[ReactorEvent] Ignored \`reject()\` call on a non-rejectable ${this.staticType} at "${this.path}"`);
|
|
132
|
+
if (this.eventPhase !== _ReactorEvent.CAPTURING_PHASE) this.reactor.log(`[ReactorEvent] Rejecting an intent on ${this.staticType} at "${this.path}" outside of the capture phase is unadvised.`);
|
|
133
|
+
if (this.rejectable) this.reactor.log(`[ReactorEvent] ${this._rejected = reason || `Couldn't ${this.staticType} intended value at "${this.path}"`}`);
|
|
137
134
|
}
|
|
138
135
|
/**
|
|
139
136
|
* Returns event path values from target to root.
|
|
@@ -142,24 +139,22 @@ var ReactorEvent = class _ReactorEvent {
|
|
|
142
139
|
composedPath() {
|
|
143
140
|
return getTrailRecords(this.root, this.path, true).map((r) => r[2]);
|
|
144
141
|
}
|
|
145
|
-
get canWarn() {
|
|
146
|
-
return this._warn !== NOOP;
|
|
147
|
-
}
|
|
148
142
|
};
|
|
149
143
|
|
|
150
144
|
// src/ts/core/reactor.ts
|
|
151
145
|
var Reactor = class {
|
|
146
|
+
/** Logger function for this reactor instance, override if desired, `this.canLog = false` resets. */
|
|
152
147
|
log = NOOP;
|
|
148
|
+
/** The core state object for this reactor instance. */
|
|
153
149
|
core;
|
|
154
150
|
// `?:`s | pay the ~800 byte price upfront for what u might never use
|
|
155
|
-
|
|
151
|
+
/** The modules being used by this reactor. */
|
|
152
|
+
modules;
|
|
153
|
+
/** Configuration options for this reactor instance. */
|
|
156
154
|
config;
|
|
155
|
+
/** Whether this reactor instance is currently batching updates, a window view into the engine timing */
|
|
157
156
|
isBatching = false;
|
|
158
157
|
// Async Batching
|
|
159
|
-
isCascading = false;
|
|
160
|
-
// Setter Cascading
|
|
161
|
-
isLogging = false;
|
|
162
|
-
// keeping track so API getter doesn't slow down internal iterations in any way
|
|
163
158
|
queue;
|
|
164
159
|
// Tasks to run after flush
|
|
165
160
|
batch;
|
|
@@ -226,7 +221,7 @@ var Reactor = class {
|
|
|
226
221
|
safeValue = value?.[RAW] || value;
|
|
227
222
|
unchanged = this.config.equalityFunction(safeValue, safeOldValue);
|
|
228
223
|
}
|
|
229
|
-
if (!indiffable && unchanged && !
|
|
224
|
+
if (!indiffable && unchanged && !CTX.isCascading) return this.log(`\u{1F504} [Reactor \`set\` Trap] Unchanged for "${keyStr}" on "${paths}"`), true;
|
|
230
225
|
if (this.config.set) terminated = (value = this.config.set(object, key2, value, oldValue, receiver, paths)) === TERMINATOR;
|
|
231
226
|
if (this.setters) {
|
|
232
227
|
const wildcords = this.setters.get("*");
|
|
@@ -380,7 +375,7 @@ var Reactor = class {
|
|
|
380
375
|
if (this.queue?.size) for (const task of this.queue) task(), this.queue.delete(task);
|
|
381
376
|
}
|
|
382
377
|
wave(path, payload) {
|
|
383
|
-
const e = new ReactorEvent(payload, this
|
|
378
|
+
const e = new ReactorEvent(payload, this), chain = getTrailRecords(this.core, path);
|
|
384
379
|
e.eventPhase = ReactorEvent.CAPTURING_PHASE;
|
|
385
380
|
for (let i = 0; i <= chain.length - 2; i++) {
|
|
386
381
|
if (e.propagationStopped) break;
|
|
@@ -454,8 +449,8 @@ var Reactor = class {
|
|
|
454
449
|
return depth;
|
|
455
450
|
}
|
|
456
451
|
getContext(path) {
|
|
457
|
-
const
|
|
458
|
-
return { path, value, key: path.slice(
|
|
452
|
+
const last = path.lastIndexOf("."), value = getAny(this.core, path), object = last === -1 ? this.core : getAny(this.core, path.slice(0, last));
|
|
453
|
+
return { path, value, key: path.slice(last + 1) || "", hadKey: true, object };
|
|
459
454
|
}
|
|
460
455
|
bindSignal(cord, sig) {
|
|
461
456
|
if (sig) sig.aborted ? cord.clup() : sig.addEventListener("abort", cord.clup, { once: true });
|
|
@@ -471,7 +466,11 @@ var Reactor = class {
|
|
|
471
466
|
const clone = !raw ? this.config.preserveContext ? Object.create(Object.getPrototypeOf(obj)) : Array.isArray(obj) ? [] : {} : obj;
|
|
472
467
|
seen.set(obj, clone);
|
|
473
468
|
const keys = this.config.preserveContext ? Reflect.ownKeys(obj) : Object.keys(obj);
|
|
474
|
-
for (let i = 0, len = keys.length; i < len; i++)
|
|
469
|
+
for (let i = 0, len = keys.length; i < len; i++)
|
|
470
|
+
try {
|
|
471
|
+
clone[keys[i]] = this.cloned(obj[keys[i]], raw, seen);
|
|
472
|
+
} catch {
|
|
473
|
+
}
|
|
475
474
|
if (!raw && this.config.smartCloning) this.snapCache.set(obj, clone), obj[SSVERSION] = version;
|
|
476
475
|
return clone;
|
|
477
476
|
}
|
|
@@ -559,7 +558,7 @@ var Reactor = class {
|
|
|
559
558
|
* rtr.delete("cache.temp", () => TERMINATOR);
|
|
560
559
|
*/
|
|
561
560
|
delete(path, callback, options) {
|
|
562
|
-
return this.syncAdd("delete", path, callback, options, (imm) => (imm !== "auto" || inAny(this.core, path)) && deleteAny(this.core, path
|
|
561
|
+
return this.syncAdd("delete", path, callback, options, (imm) => (imm !== "auto" || inAny(this.core, path)) && deleteAny(this.core, path));
|
|
563
562
|
}
|
|
564
563
|
/** Registers a delete mediator for a path that only triggers once. */
|
|
565
564
|
donce(path, callback, options) {
|
|
@@ -576,7 +575,7 @@ var Reactor = class {
|
|
|
576
575
|
}
|
|
577
576
|
/**
|
|
578
577
|
* Registers a watcher for a path.
|
|
579
|
-
* Watch callbacks run synchronously with the operation.
|
|
578
|
+
* Watch callbacks run synchronously with the operation, use leaf paths for reliability as it sees exact sets; no bubbling here.
|
|
580
579
|
* @param path Path or wildcard path.
|
|
581
580
|
* @param callback Watch callback.
|
|
582
581
|
* @param options Sync options.
|
|
@@ -625,7 +624,7 @@ var Reactor = class {
|
|
|
625
624
|
cord = { cb: callback, capture, depth, once, clup: () => this.off(path, callback, options), lDepth: depth !== void 0 ? this.getDepth(path) : depth };
|
|
626
625
|
if (immediate && (immediate !== "auto" || inAny(this.core, path))) {
|
|
627
626
|
const target = this.getContext(path);
|
|
628
|
-
callback(new ReactorEvent({ type: "init", target, currentTarget: target, root: this.core, rejectable: false }, this
|
|
627
|
+
callback(new ReactorEvent({ type: "init", target, currentTarget: target, root: this.core, rejectable: false }, this));
|
|
629
628
|
}
|
|
630
629
|
(cords ?? (this.listeners.set(path, cords = []), cords)).push(cord);
|
|
631
630
|
return this.bindSignal(cord, signal);
|
|
@@ -656,56 +655,39 @@ var Reactor = class {
|
|
|
656
655
|
return this.cloned(arguments.length < 2 ? this.core : branch, raw);
|
|
657
656
|
}
|
|
658
657
|
/**
|
|
659
|
-
*
|
|
660
|
-
* @param
|
|
661
|
-
* @param
|
|
662
|
-
* @
|
|
663
|
-
* rtr.on("user", (event) => rtr.cascade(event));
|
|
664
|
-
* @example
|
|
665
|
-
* rtr.watch("user", (_value, payload) => rtr.cascade(payload));
|
|
666
|
-
*/
|
|
667
|
-
cascade({ type, currentTarget: { path, value: news, oldValue: olds } }, objectSafe = true) {
|
|
668
|
-
if (type !== "set" && type !== "delete" || !canHandle(news, this.config) || (objectSafe ? !canHandle(olds, this.config) : false)) return;
|
|
669
|
-
const obj = objectSafe ? mergeObjs(olds, news) : news, keys = Object.keys(obj);
|
|
670
|
-
this.isCascading = true;
|
|
671
|
-
for (let i = 0, len = keys.length; i < len; i++) setAny(this.core, path === "*" ? keys[i] : path + "." + keys[i], obj[keys[i]]);
|
|
672
|
-
this.isCascading = false;
|
|
673
|
-
}
|
|
674
|
-
/**
|
|
675
|
-
* Installs a plugin instance.
|
|
676
|
-
* @param plugin Plugin instance.
|
|
677
|
-
* @returns Current reactor for fluent chaining.
|
|
658
|
+
* Installs a module instance.
|
|
659
|
+
* @param target Module instance.
|
|
660
|
+
* @param id Optional identification tag for this instance in the module.
|
|
661
|
+
* @returns Current `Reactor` instance for fluent chaining.
|
|
678
662
|
*/
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
this.plugins?.get(name)?.destroy();
|
|
682
|
-
return (this.plugins ??= /* @__PURE__ */ new Map()).set(name, (plugin.setup(this), plugin)), this;
|
|
663
|
+
use(target, id) {
|
|
664
|
+
return (this.modules ??= /* @__PURE__ */ new Set()).add(target.setup(this, id)), this;
|
|
683
665
|
}
|
|
684
|
-
/** Resets
|
|
666
|
+
/** Resets this reactor instance to its initial state. */
|
|
685
667
|
reset() {
|
|
686
668
|
this.getters?.clear(), this.setters?.clear(), this.deleters?.clear(), this.watchers?.clear(), this.listeners?.clear();
|
|
687
669
|
this.batch?.clear(), this.queue?.clear(), this.isBatching = false;
|
|
688
670
|
}
|
|
689
671
|
destroy() {
|
|
690
|
-
if (this.
|
|
672
|
+
if (this.modules) for (const mdle of this.modules) mdle.destroy();
|
|
691
673
|
this.reset(), nuke(this);
|
|
692
674
|
}
|
|
693
675
|
get canLog() {
|
|
694
|
-
return this.
|
|
676
|
+
return this.log !== NOOP;
|
|
695
677
|
}
|
|
696
678
|
set canLog(value) {
|
|
697
|
-
this.log =
|
|
679
|
+
this.log = value ? RTR_LOG : NOOP;
|
|
698
680
|
}
|
|
699
|
-
get
|
|
700
|
-
return this.config.
|
|
681
|
+
get canLineageTrace() {
|
|
682
|
+
return this.config.lineageTracing && this.config.referenceTracking;
|
|
701
683
|
}
|
|
702
684
|
get canSmartClone() {
|
|
703
|
-
return this.config.
|
|
685
|
+
return this.config.smartCloning && this.config.referenceTracking;
|
|
704
686
|
}
|
|
705
687
|
};
|
|
706
688
|
|
|
707
689
|
// src/ts/core/mixins.ts
|
|
708
|
-
var methods = ["tick", "stall", "nostall", "get", "gonce", "noget", "set", "sonce", "noset", "delete", "donce", "nodelete", "watch", "wonce", "nowatch", "on", "once", "off", "snapshot", "
|
|
690
|
+
var methods = ["tick", "stall", "nostall", "get", "gonce", "noget", "set", "sonce", "noset", "delete", "donce", "nodelete", "watch", "wonce", "nowatch", "on", "once", "off", "snapshot", "use", "reset", "destroy"];
|
|
709
691
|
function reactive(target, build, preferences = NIL) {
|
|
710
692
|
if ("__Reactor__" in target) return target;
|
|
711
693
|
const descriptors = {}, rtr = getReactor(target, true, build), locks = { enumerable: false, configurable: true, writable: false }, hasAffix = !!(preferences.prefix || preferences.suffix);
|
|
@@ -713,7 +695,7 @@ function reactive(target, build, preferences = NIL) {
|
|
|
713
695
|
let key = methods[i];
|
|
714
696
|
if (hasAffix) (preferences.whitelist?.includes(key) ?? true) && (key = `${preferences.prefix || ""}${key}${preferences.suffix || ""}`);
|
|
715
697
|
else if (preferences.whitelist?.includes(key)) continue;
|
|
716
|
-
descriptors[key] = { value: rtr[
|
|
698
|
+
descriptors[key] = { value: rtr[methods[i]].bind(rtr), ...locks };
|
|
717
699
|
}
|
|
718
700
|
descriptors["__Reactor__"] = { value: rtr, ...locks };
|
|
719
701
|
return Object.defineProperties(rtr.core, descriptors), rtr.core;
|
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
var CTX = {
|
|
3
3
|
/** Flag indicating whether the application is running in development mode. */
|
|
4
4
|
isDevEnv: "undefined" !== typeof process ? process.env.NODE_ENV !== "production" : true,
|
|
5
|
-
/**
|
|
5
|
+
/** Flag indicating whether a cascade is currently ongoing so reactors can allow all writes. */
|
|
6
|
+
isCascading: false,
|
|
7
|
+
/** Active `Autotracker` instance, override for automatic dependency collection on `Reactor` traps. */
|
|
6
8
|
autotracker: null
|
|
7
9
|
};
|
|
8
10
|
var RAW = /* @__PURE__ */ Symbol.for("S.I.A_RAW");
|
|
@@ -14,7 +16,6 @@ var VERSION = /* @__PURE__ */ Symbol.for("S.I.A_VERSION");
|
|
|
14
16
|
var SSVERSION = /* @__PURE__ */ Symbol.for("S.I.A_SNAPSHOT_VERSION");
|
|
15
17
|
var RTR_BATCH = "undefined" !== typeof window ? ("undefined" !== typeof queueMicrotask ? queueMicrotask : setTimeout).bind(window) : "undefined" !== typeof process && process.nextTick ? process.nextTick : setTimeout;
|
|
16
18
|
var RTR_LOG = console.log.bind(console, "[S.I.A Reactor]");
|
|
17
|
-
var EVT_WARN = console.warn.bind(console, "[S.I.A Event]");
|
|
18
19
|
var EVT_OPTS = { LISTENER: ["capture", "depth", "once", "signal", "immediate"], MEDIATOR: ["lazy", "signal", "immediate"] };
|
|
19
20
|
var NIL = Object.freeze({});
|
|
20
21
|
var NOOP = () => {
|
|
@@ -113,16 +114,43 @@ function inAny(source, key, separator = ".", keyFunc) {
|
|
|
113
114
|
function parseAnyObj(obj, separator = ".", keyFunc = (p) => p, seen = /* @__PURE__ */ new WeakSet()) {
|
|
114
115
|
if (!isObj(obj) || seen.has(obj)) return obj;
|
|
115
116
|
seen.add(obj);
|
|
116
|
-
const result = {};
|
|
117
|
-
|
|
117
|
+
const result = {}, keys = Object.keys(obj);
|
|
118
|
+
for (let i = 0, len = keys.length; i < len; i++) {
|
|
119
|
+
const k = keys[i];
|
|
120
|
+
k === "*" || k.includes(separator) ? setAny(result, k, parseAnyObj(obj[k], separator, keyFunc, seen), separator, keyFunc) : result[k] = isObj(obj[k]) ? parseAnyObj(obj[k], separator, keyFunc, seen) : obj[k];
|
|
121
|
+
}
|
|
118
122
|
return result;
|
|
119
123
|
}
|
|
120
124
|
function parseEvtOpts(options, opts, boolOpt = opts[0], result = {}) {
|
|
121
125
|
return Object.assign(result, "boolean" === typeof options ? { [boolOpt]: options } : options), result;
|
|
122
126
|
}
|
|
127
|
+
function fanout(a, b, c, d) {
|
|
128
|
+
const isEvtPld = !!a?.target, [state, path, news, olds, opts, type] = isEvtPld ? [a.root, a.currentTarget.path, a.currentTarget.value, a.currentTarget.oldValue, b || NIL, a.type] : [a, b, c, (d || NIL).merge ? getAny(a, b) : NIL, d || NIL], target = path === "*" ? state : getAny(state, path);
|
|
129
|
+
if (isEvtPld && type !== "set" && type !== "delete" || !target || !canHandle(news, opts)) return;
|
|
130
|
+
const prev = CTX.isCascading;
|
|
131
|
+
CTX.isCascading = isEvtPld;
|
|
132
|
+
try {
|
|
133
|
+
const walk = (target2, obj, depth = 1, keys = Object.keys(obj)) => {
|
|
134
|
+
for (let i = 0, len = keys.length; i < len; i++) {
|
|
135
|
+
const val = obj[keys[i]];
|
|
136
|
+
try {
|
|
137
|
+
depth > 1 && canHandle(val, opts) ? walk(target2[keys[i]] ||= {}, val, depth - 1) : target2[keys[i]] = val;
|
|
138
|
+
} catch {
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
walk(target, opts.merge && canHandle(olds, opts) ? mergeObjs(olds, news) : news, opts.depth === true ? Infinity : +opts.depth);
|
|
143
|
+
} finally {
|
|
144
|
+
CTX.isCascading = prev;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
123
147
|
function mergeObjs(o1 = {}, o2 = {}) {
|
|
124
|
-
const merged = { ...o1
|
|
125
|
-
|
|
148
|
+
const merged = { ...o1 ||= {}, ...o2 ||= {} }, keys = Object.keys(merged);
|
|
149
|
+
for (let i = 0, len = keys.length; i < len; i++) {
|
|
150
|
+
const k = keys[i];
|
|
151
|
+
if (isObj(o1[k]) && isObj(o2[k])) merged[k] = mergeObjs(o1[k], o2[k]);
|
|
152
|
+
}
|
|
153
|
+
return merged;
|
|
126
154
|
}
|
|
127
155
|
function getTrailRecords(obj, path, reverse = false) {
|
|
128
156
|
const parts = path.split("."), chain = [["*", obj, obj]];
|
|
@@ -137,7 +165,11 @@ function deepClone(obj, config = NIL, seen = /* @__PURE__ */ new WeakMap()) {
|
|
|
137
165
|
const clone = config.preserveContext ? Object.create(Object.getPrototypeOf(obj)) : Array.isArray(obj) ? [] : {};
|
|
138
166
|
seen.set(obj, clone);
|
|
139
167
|
const keys = config.preserveContext ? Reflect.ownKeys(obj) : Object.keys(obj);
|
|
140
|
-
for (let i = 0, len = keys.length; i < len; i++)
|
|
168
|
+
for (let i = 0, len = keys.length; i < len; i++)
|
|
169
|
+
try {
|
|
170
|
+
clone[keys[i]] = deepClone(obj[keys[i]], config, seen);
|
|
171
|
+
} catch {
|
|
172
|
+
}
|
|
141
173
|
return clone;
|
|
142
174
|
}
|
|
143
175
|
function nuke(target) {
|
|
@@ -165,7 +197,6 @@ export {
|
|
|
165
197
|
SSVERSION,
|
|
166
198
|
RTR_BATCH,
|
|
167
199
|
RTR_LOG,
|
|
168
|
-
EVT_WARN,
|
|
169
200
|
EVT_OPTS,
|
|
170
201
|
NIL,
|
|
171
202
|
NOOP,
|
|
@@ -178,6 +209,7 @@ export {
|
|
|
178
209
|
inAny,
|
|
179
210
|
parseAnyObj,
|
|
180
211
|
parseEvtOpts,
|
|
212
|
+
fanout,
|
|
181
213
|
mergeObjs,
|
|
182
214
|
getTrailRecords,
|
|
183
215
|
deepClone,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
reactive
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-3SKLWTEA.js";
|
|
4
4
|
import {
|
|
5
5
|
createEl,
|
|
6
6
|
formatKeyForDisplay,
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
RAW,
|
|
14
14
|
canHandle,
|
|
15
15
|
nuke
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-BTA6MIQ6.js";
|
|
17
17
|
|
|
18
18
|
// src/ts/adapters/autotracker.ts
|
|
19
19
|
var Autotracker = class {
|
|
@@ -119,9 +119,9 @@ var Autotracker = class {
|
|
|
119
119
|
* const stop = atrkr.callback(() => console.log("changed")); // re-run after when ".user.name" changes
|
|
120
120
|
* @example Packaged Customization
|
|
121
121
|
* const atrkr = new Autotracker(); // no reactor passed
|
|
122
|
-
* withTracker(atrkr, () => state.user.name); // import `withTracker`
|
|
122
|
+
* withTracker(atrkr, () => state.user.name); // import `withTracker` too
|
|
123
123
|
* const stop = atrkr.callback(() => console.log("sync"), { sync: true }); // re-run immediately when ".user.name" changes, works on any path used from any reactor state
|
|
124
|
-
* @example Extensive
|
|
124
|
+
* @example Extensive Customization
|
|
125
125
|
* atrkr.unblock();
|
|
126
126
|
* const prev = CTX.autotracker;
|
|
127
127
|
* CTX.autotracker = atrkr; // import CTX first
|
|
@@ -169,8 +169,8 @@ function effect(callback, options) {
|
|
|
169
169
|
|
|
170
170
|
// src/ts/adapters/vanilla/TimeTravelOverlay.ts
|
|
171
171
|
var keys = {
|
|
172
|
-
overrides: ["Ctrl+z", "Cmd+z", "Ctrl+y", "Cmd+y", "Ctrl+Shift+z", "Cmd+Shift+z", "
|
|
173
|
-
shortcuts: { undo: ["Ctrl+z", "Cmd+z"], redo: ["Ctrl+y", "Cmd+y", "Ctrl+Shift+z", "Cmd+Shift+z"], genesis:
|
|
172
|
+
overrides: ["Ctrl+z", "Cmd+z", "Ctrl+y", "Cmd+y", "Ctrl+Shift+z", "Cmd+Shift+z", "Home", "End", ",", ".", "ArrowLeft", "ArrowRight", "Space", "Alt+Space", "Escape", "Delete", "e", "i", "c"],
|
|
173
|
+
shortcuts: { undo: ["Ctrl+z", "Cmd+z"], redo: ["Ctrl+y", "Cmd+y", "Ctrl+Shift+z", "Cmd+Shift+z"], genesis: "Home", ending: "End", prevFrame: ",", nextFrame: ".", skipBwd: "ArrowLeft", skipFwd: "ArrowRight", playPause: "Space", rewind: "Alt+Space", closeOverlay: "Escape", clrHistory: "Delete", export: "e", import: "i", clear: "c" }
|
|
174
174
|
};
|
|
175
175
|
var TimeTravelOverlay = class _TimeTravelOverlay {
|
|
176
176
|
static count = 0;
|
|
@@ -181,22 +181,22 @@ var TimeTravelOverlay = class _TimeTravelOverlay {
|
|
|
181
181
|
els;
|
|
182
182
|
clups = [];
|
|
183
183
|
keyup;
|
|
184
|
-
/** Creates a docked TimeTravel overlay bound to a
|
|
185
|
-
* @param time TimeTravel
|
|
184
|
+
/** Creates a docked TimeTravel overlay bound to a module instance.
|
|
185
|
+
* @param time TimeTravel module instance that owns timeline operations.
|
|
186
186
|
* @param build Optional initial overlay config overrides.
|
|
187
187
|
*/
|
|
188
188
|
constructor(time, build = {}) {
|
|
189
189
|
this.time = time;
|
|
190
190
|
this.config = reactive({ title: `Time Travel Overlay ${this.index = ++_TimeTravelOverlay.count}`, ...build });
|
|
191
191
|
this.state.open = !!this.config.startOpen;
|
|
192
|
-
const s = this.time.state, host = createEl("div", { className: "tt-overlay-host" }), toggle = createEl("button", { className: "tt-overlay-toggle", type: "button", onclick: () => this.state.open = !this.state.open }), panel = createEl("aside", { className: "tt-overlay", ariaLabel: "time travel overlay" }), title = createEl("div", { className: "title" }), frame = createEl("span", { className: "muted" }), clrHistory = createEl("button", { textContent: `Clear History${formatKeyForDisplay(keys.shortcuts.clrHistory)}`, ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.clrHistory, false), onclick: () => (this.time.clear(), this.state.import = "") }), undo = createEl("button", { textContent: `Undo${formatKeyForDisplay(keys.shortcuts.undo[0])}`, ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.undo, false), onclick: this.time.undo }), redo = createEl("button", { textContent: `Redo${formatKeyForDisplay(keys.shortcuts.redo[0])}`, ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.redo, false), onclick: this.time.redo }), genesis = createEl("button", { textContent: `Genesis${formatKeyForDisplay(keys.shortcuts.genesis
|
|
192
|
+
const s = this.time.state, host = createEl("div", { className: "tt-overlay-host" }), toggle = createEl("button", { className: "tt-overlay-toggle", type: "button", onclick: () => this.state.open = !this.state.open }), panel = createEl("aside", { className: "tt-overlay", ariaLabel: "time travel overlay" }), title = createEl("div", { className: "title" }), frame = createEl("span", { className: "muted" }), clrHistory = createEl("button", { textContent: `Clear History${formatKeyForDisplay(keys.shortcuts.clrHistory)}`, ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.clrHistory, false), onclick: () => (this.time.clear(), this.state.import = "") }), undo = createEl("button", { textContent: `Undo${formatKeyForDisplay(keys.shortcuts.undo[0])}`, ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.undo, false), onclick: this.time.undo }), redo = createEl("button", { textContent: `Redo${formatKeyForDisplay(keys.shortcuts.redo[0])}`, ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.redo, false), onclick: this.time.redo }), genesis = createEl("button", { textContent: `Genesis${formatKeyForDisplay(keys.shortcuts.genesis)}`, ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.genesis, false), onclick: () => this.time.jumpTo(0) }), playPause = createEl("button", { onclick: () => this.time[s.paused ? "play" : "pause"](), ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.playPause, false) }), rewind = createEl("button", { textContent: `Rewind${formatKeyForDisplay(keys.shortcuts.rewind)}`, ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.rewind, false), onclick: this.time.rewind }), range = createEl("input", { type: "range", min: "0", max: "0", value: "0", title: "time travel frame", ariaLabel: "time travel frame", oninput: () => this.time.jumpTo(Number(range.value)) }), exp = createEl("button", { textContent: `Export${formatKeyForDisplay(keys.shortcuts.export)}`, ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.export, false), onclick: () => this.state.import = this.time.export(null, 2) }), imp = createEl("button", { textContent: `Import${formatKeyForDisplay(keys.shortcuts.import)}`, ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.import, false), onclick: () => this.state.import.trim().length && this.time.import(this.state.import) }), clr = createEl("button", { textContent: `Clear${formatKeyForDisplay(keys.shortcuts.clear)}`, ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.clear, false), onclick: () => this.state.import = "" }), payload = createEl("textarea", { className: "tt-io", readOnly: true, placeholder: "current payload json", title: "current payload" }), io = createEl("textarea", { className: "tt-io", placeholder: "timeline payload json", oninput: () => this.state.import = io.value }), foot = createEl("p", { className: "tt-footnote", textContent: "Want this in your app? " }), link = createEl("a", { target: "_blank", rel: "noreferrer noopener", textContent: "sia-reactor", href: "https://www.npmjs.com/package/sia-reactor" }), box = createEl("div", { className: "tt-status-box" }), status = createEl("div", { className: "tt-status-row" }), row1 = createEl("div", { className: "tt-row" }), row2 = createEl("div", { className: "tt-row" }), row3 = createEl("div", { className: "tt-row" });
|
|
193
193
|
status.append((box.append(frame), box), clrHistory);
|
|
194
194
|
panel.append(title, status, (row1.append(undo, redo, genesis), row1), (row2.append(playPause, rewind), row2), payload, range, (row3.append(exp, imp, clr), row3), io, (foot.appendChild(link), foot));
|
|
195
195
|
host.append(toggle, panel);
|
|
196
196
|
this.els = { host, toggle, panel, title, frame, clrHistory, undo, redo, genesis, playPause, rewind, range, exp, imp, clr, payload, io };
|
|
197
197
|
this.keyup = (e) => {
|
|
198
|
-
const a = this.state.open && keyEventAllowed(e, keys);
|
|
199
|
-
a === "undo" ? this.time.undo() : a === "redo" ? this.time.redo() : a === "genesis" ? this.time.jumpTo(0) : a === "prevFrame" ? this.time.step(1, false) : a === "nextFrame" ? this.time.step(1, true) : a === "skipBwd" ? this.time.step(5, false) : a === "skipFwd" ? this.time.step(5, true) : a === "rewind" ? this.time.rewind() : a === "playPause" ? this.time[s.paused ? "play" : "pause"]() : a === "clrHistory" ? this.time.clear() : a === "closeOverlay" ? this.state.open = false : a === "export" ? this.state.import = this.time.export() : a === "import" ? this.state.import.trim().length && this.time.import(this.state.import) : a === "clear" && (this.state.import = "");
|
|
198
|
+
const a = this.state.open && (this.config.devOnly ? CTX.isDevEnv : true) && keyEventAllowed(e, keys);
|
|
199
|
+
a === "undo" ? this.time.undo() : a === "redo" ? this.time.redo() : a === "genesis" ? this.time.jumpTo(0) : a === "ending" ? this.time.jumpTo(s.history.length) : a === "prevFrame" ? this.time.step(1, false) : a === "nextFrame" ? this.time.step(1, true) : a === "skipBwd" ? this.time.step(5, false) : a === "skipFwd" ? this.time.step(5, true) : a === "rewind" ? this.time.rewind() : a === "playPause" ? this.time[s.paused ? "play" : "pause"]() : a === "clrHistory" ? this.time.clear() : a === "closeOverlay" ? this.state.open = false : a === "export" ? this.state.import = this.time.export() : a === "import" ? this.state.import.trim().length && this.time.import(this.state.import) : a === "clear" && (this.state.import = "");
|
|
200
200
|
};
|
|
201
201
|
window.addEventListener("keydown", this.keyup);
|
|
202
202
|
const sync = [
|
|
@@ -211,7 +211,8 @@ var TimeTravelOverlay = class _TimeTravelOverlay {
|
|
|
211
211
|
effect(() => {
|
|
212
212
|
frame.textContent = `Frame: ${s.currentFrame} / ${s.history.length}`;
|
|
213
213
|
range.disabled = clrHistory.disabled = !s.history.length;
|
|
214
|
-
genesis.disabled =
|
|
214
|
+
genesis.disabled = undo.disabled = !s.currentFrame;
|
|
215
|
+
rewind.disabled = !s.paused || !s.currentFrame;
|
|
215
216
|
playPause.disabled = redo.disabled = s.currentFrame >= s.history.length;
|
|
216
217
|
range.max = String(s.history.length);
|
|
217
218
|
range.value = String(Math.min(s.currentFrame, s.history.length));
|
|
@@ -225,7 +226,7 @@ var TimeTravelOverlay = class _TimeTravelOverlay {
|
|
|
225
226
|
this.clups.push(...sync);
|
|
226
227
|
}
|
|
227
228
|
destroy() {
|
|
228
|
-
this.clups
|
|
229
|
+
for (const clup of this.clups) clup();
|
|
229
230
|
this.keyup && window.removeEventListener("keydown", this.keyup);
|
|
230
231
|
this.els.host.remove();
|
|
231
232
|
nuke(this), --_TimeTravelOverlay.count;
|