sia-reactor 0.0.20 → 0.0.21
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 +6 -8
- package/dist/{TimeTravelOverlay-BYSnHBXx.d.cts → TimeTravelOverlay-CJv-S_Km.d.cts} +2 -2
- package/dist/{TimeTravelOverlay-DoNrZwvX.d.ts → TimeTravelOverlay-DxqJL0Zk.d.ts} +2 -2
- package/dist/adapters/react.cjs +78 -96
- package/dist/adapters/react.d.cts +47 -6
- package/dist/adapters/react.d.ts +47 -6
- package/dist/adapters/react.js +34 -10
- package/dist/adapters/vanilla.cjs +45 -89
- package/dist/adapters/vanilla.d.cts +4 -4
- package/dist/adapters/vanilla.d.ts +4 -4
- package/dist/adapters/vanilla.js +2 -2
- package/dist/{chunk-VPR5SP3E.js → chunk-2WBPGSRL.js} +28 -40
- package/dist/{chunk-RFQ2JJSV.js → chunk-TFLYCXK4.js} +18 -50
- package/dist/{index-DCG3sacH.d.cts → index-Oie9hhE8.d.cts} +6 -5
- package/dist/{index-DCG3sacH.d.ts → index-Oie9hhE8.d.ts} +6 -5
- package/dist/index.cjs +28 -40
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/plugins.cjs +46 -51
- package/dist/plugins.d.cts +3 -3
- package/dist/plugins.d.ts +3 -3
- package/dist/plugins.js +19 -12
- package/dist/styles/time-travel-overlay.css +1 -1
- package/dist/super.d.ts +15 -13
- package/dist/super.global.js +63 -100
- package/dist/{timeTravel-Bv_u5M1D.d.ts → timeTravel-B1vedDQc.d.ts} +10 -9
- package/dist/{timeTravel-L8CEhHIo.d.cts → timeTravel-WpgWmKu-.d.cts} +10 -9
- package/dist/utils.d.cts +1 -1
- package/dist/utils.d.ts +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -143,8 +143,8 @@ getReactor(state); state.__Reactor__; // Reference to the underlying reactor
|
|
|
143
143
|
|
|
144
144
|
Alternatively, you can instantiate the `Reactor` class directly to keep the API from interfering with your data or [try this](#reactive-preferences-method-naming):
|
|
145
145
|
```javascript
|
|
146
|
-
const reactor = new Reactor({ player: { volume: 50 } }, { debug: true
|
|
147
|
-
reactor.core.player.volume = 100;
|
|
146
|
+
const reactor = new Reactor({ player: { volume: 50 } }, { debug: true });
|
|
147
|
+
reactor.core.player.volume = 100; // re-assign core if desired
|
|
148
148
|
```
|
|
149
149
|
|
|
150
150
|
### Core Methods
|
|
@@ -197,13 +197,13 @@ The engine provides native React bindings utilizing `useSyncExternalStore` and a
|
|
|
197
197
|
|
|
198
198
|
```javascript
|
|
199
199
|
import { reactive } from 'sia-reactor';
|
|
200
|
-
import { useReactor, useSelector, usePath, effect } from 'sia-reactor/react';
|
|
200
|
+
import { useReactor, useAnyReactor, useSelector, useAnySelector, usePath, effect } from 'sia-reactor/react';
|
|
201
201
|
|
|
202
202
|
const state = reactive({ user: { name: "Ada", age: 25 }, theme: "dark" });
|
|
203
203
|
|
|
204
204
|
// 1. The Tracked State (Valtio-style)
|
|
205
205
|
function Profile() {
|
|
206
|
-
const sameState = useReactor(state); //
|
|
206
|
+
const sameState = useReactor(state); // `useReactorSnapshot()` if mutable issues arise
|
|
207
207
|
useAnyReactor(); // use this when you just want to use any state from any reactor
|
|
208
208
|
// Only re-renders if state.user.name mutates. Completely ignores age and theme!
|
|
209
209
|
return <div>{sameState.user.name + otherState.user.name}</div>;
|
|
@@ -211,7 +211,7 @@ function Profile() {
|
|
|
211
211
|
|
|
212
212
|
// 2. The Slice Selector (Zustand-style)
|
|
213
213
|
function Theme() {
|
|
214
|
-
const theme = useSelector(state, (s) => s.theme); //
|
|
214
|
+
const theme = useSelector(state, (s) => s.theme); // `useSelectorSnapshot()` if mutable issues arise
|
|
215
215
|
const newName = useAnySelector(() => state.user.name + spouseState.user.name); // use this when you just want to derive any state from any reactor
|
|
216
216
|
return <div>Theme: {theme}</div>;
|
|
217
217
|
}
|
|
@@ -223,9 +223,7 @@ function AgeObserver() {
|
|
|
223
223
|
}
|
|
224
224
|
|
|
225
225
|
// 4. Vanilla Side Effects (Runs anywhere, framework agnostic)
|
|
226
|
-
const stopTracking = effect(() =>
|
|
227
|
-
console.log("User name changed to:", state.user.name);
|
|
228
|
-
});
|
|
226
|
+
const stopTracking = effect(() => console.log("User name changed to:", state.user.name)); // read or write as you wish
|
|
229
227
|
```
|
|
230
228
|
|
|
231
229
|
### Plugins: The Extension Port
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { R as Reactive } from './index-
|
|
2
|
-
import { T as TimeTravelPlugin } from './timeTravel-
|
|
1
|
+
import { R as Reactive } from './index-Oie9hhE8.cjs';
|
|
2
|
+
import { T as TimeTravelPlugin } from './timeTravel-WpgWmKu-.cjs';
|
|
3
3
|
|
|
4
4
|
/** Reactive options for the TimeTravel overlay instance. */
|
|
5
5
|
interface TimeTravelConfig {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { R as Reactive } from './index-
|
|
2
|
-
import { T as TimeTravelPlugin } from './timeTravel-
|
|
1
|
+
import { R as Reactive } from './index-Oie9hhE8.js';
|
|
2
|
+
import { T as TimeTravelPlugin } from './timeTravel-B1vedDQc.js';
|
|
3
3
|
|
|
4
4
|
/** Reactive options for the TimeTravel overlay instance. */
|
|
5
5
|
interface TimeTravelConfig {
|
package/dist/adapters/react.cjs
CHANGED
|
@@ -26,7 +26,9 @@ __export(react_exports, {
|
|
|
26
26
|
useISOLayoutEffect: () => useISOLayoutEffect,
|
|
27
27
|
usePath: () => usePath,
|
|
28
28
|
useReactor: () => useReactor,
|
|
29
|
-
|
|
29
|
+
useReactorSnapshot: () => useReactorSnapshot,
|
|
30
|
+
useSelector: () => useSelector,
|
|
31
|
+
useSelectorSnapshot: () => useSelectorSnapshot
|
|
30
32
|
});
|
|
31
33
|
module.exports = __toCommonJS(react_exports);
|
|
32
34
|
|
|
@@ -326,27 +328,27 @@ var Reactor = class {
|
|
|
326
328
|
listeners;
|
|
327
329
|
/**
|
|
328
330
|
* Creates a new Reactor instance.
|
|
329
|
-
* @param
|
|
331
|
+
* @param target Initial state target.
|
|
330
332
|
* @param build Reactor bootstrap/build configuration.
|
|
331
333
|
* @example
|
|
332
334
|
* const rtr = new Reactor({ count: 0 });
|
|
333
335
|
*/
|
|
334
|
-
constructor(
|
|
336
|
+
constructor(target = {}, build) {
|
|
335
337
|
this[INERTIA] = true;
|
|
336
338
|
this.config = { crossRealms: false, smartCloning: false, eventBubbling: true, lineageTracing: false, preserveContext: false, equalityFunction: Object.is, batchingFunction: RTR_BATCH, ...build };
|
|
337
|
-
this.core = this.proxied(
|
|
339
|
+
this.core = this.proxied(target);
|
|
338
340
|
if (build) this.canLog = !!build.debug;
|
|
339
341
|
}
|
|
340
|
-
proxied(
|
|
341
|
-
if (!
|
|
342
|
-
|
|
343
|
-
if (this.config.referenceTracking && parent && key && !this.link(
|
|
344
|
-
const cached = this.proxyCache.get(
|
|
342
|
+
proxied(target, rejectable = false, indiffable = false, parent, key, path) {
|
|
343
|
+
if (!target || "object" !== typeof target) return target;
|
|
344
|
+
target = target[RAW] || target;
|
|
345
|
+
if (this.config.referenceTracking && parent && key && !this.link(target, parent, key, false)) return target;
|
|
346
|
+
const cached = this.proxyCache.get(target);
|
|
345
347
|
if (cached) return cached;
|
|
346
|
-
if (
|
|
347
|
-
rejectable ||=
|
|
348
|
-
indiffable ||=
|
|
349
|
-
const proxy = new Proxy(
|
|
348
|
+
if (target[INERTIA] || !canHandle(target, this.config, false)) return target;
|
|
349
|
+
rejectable ||= target[REJECTABLE];
|
|
350
|
+
indiffable ||= target[INDIFFABLE];
|
|
351
|
+
const proxy = new Proxy(target, {
|
|
350
352
|
// Robust Proxy handler
|
|
351
353
|
get: (object, key2, receiver) => {
|
|
352
354
|
if (key2 === RAW) return this.log(`\u{1F440} [Reactor \`get\` Trap] Peeked at ${object}`), object;
|
|
@@ -359,10 +361,10 @@ var Reactor = class {
|
|
|
359
361
|
for (let i = 0, len = this.config.lineageTracing ? paths.length : 1; i < len; i++) {
|
|
360
362
|
const currPath = this.config.lineageTracing ? paths[i] : fullPath, cords = this.getters.get(currPath);
|
|
361
363
|
if (!cords && !wildcords) continue;
|
|
362
|
-
const
|
|
364
|
+
const target2 = { path: currPath, value, key: keyStr, hadKey: true, object: receiver }, payload = { type: "get", target: target2, currentTarget: target2, root: this.core, rejectable };
|
|
363
365
|
if (cords) value = this.mediate(currPath, payload, "get", cords);
|
|
364
366
|
if (!wildcords) continue;
|
|
365
|
-
|
|
367
|
+
target2.value = value;
|
|
366
368
|
value = this.mediate("*", payload, "get", wildcords);
|
|
367
369
|
}
|
|
368
370
|
}
|
|
@@ -384,13 +386,13 @@ var Reactor = class {
|
|
|
384
386
|
for (let i = 0; i < loopLen; i++) {
|
|
385
387
|
const currPath = this.config.lineageTracing ? paths[i] : fullPath, cords = this.setters.get(currPath);
|
|
386
388
|
if (!cords && !wildcords) continue;
|
|
387
|
-
const
|
|
389
|
+
const target2 = { path: currPath, value, oldValue, key: keyStr, hadKey, object: receiver }, payload = { type: "set", target: target2, currentTarget: target2, root: this.core, terminated, rejectable };
|
|
388
390
|
if (cords) {
|
|
389
391
|
const result2 = this.mediate(currPath, payload, "set", cords);
|
|
390
392
|
if (!(terminated ||= payload.terminated)) value = result2;
|
|
391
393
|
}
|
|
392
394
|
if (!wildcords) continue;
|
|
393
|
-
|
|
395
|
+
target2.value = value;
|
|
394
396
|
const result = this.mediate("*", payload, "set", wildcords);
|
|
395
397
|
if (!(terminated ||= payload.terminated)) value = result;
|
|
396
398
|
}
|
|
@@ -401,8 +403,8 @@ var Reactor = class {
|
|
|
401
403
|
if (this.config.referenceTracking && !unchanged) this.config.smartCloning && this.stamp(object), this.unlink(safeOldValue, object, keyStr), this.link(safeValue, object, keyStr);
|
|
402
404
|
if (this.watchers || this.listeners)
|
|
403
405
|
for (let i = 0; i < loopLen; i++) {
|
|
404
|
-
const currPath = this.config.lineageTracing ? paths[i] : fullPath,
|
|
405
|
-
this.notify(currPath, { type: "set", target, currentTarget:
|
|
406
|
+
const currPath = this.config.lineageTracing ? paths[i] : fullPath, target2 = { path: currPath, value, oldValue, key: keyStr, hadKey, object: receiver };
|
|
407
|
+
this.notify(currPath, { type: "set", target: target2, currentTarget: target2, root: this.core, terminated, rejectable });
|
|
406
408
|
}
|
|
407
409
|
return true;
|
|
408
410
|
},
|
|
@@ -416,7 +418,7 @@ var Reactor = class {
|
|
|
416
418
|
for (let i = 0; i < loopLen; i++) {
|
|
417
419
|
const currPath = this.config.lineageTracing ? paths[i] : fullPath, cords = this.deleters.get(currPath);
|
|
418
420
|
if (!cords && !wildcords) continue;
|
|
419
|
-
const
|
|
421
|
+
const target2 = { path: currPath, value, oldValue, key: keyStr, hadKey, object: receiver }, payload = { type: "delete", target: target2, currentTarget: target2, root: this.core, rejectable };
|
|
420
422
|
if (cords) {
|
|
421
423
|
const result2 = this.mediate(currPath, payload, "delete", cords);
|
|
422
424
|
if (!(terminated ||= payload.terminated)) value = result2;
|
|
@@ -432,8 +434,8 @@ var Reactor = class {
|
|
|
432
434
|
if (this.config.referenceTracking) this.config.smartCloning && this.stamp(object), this.unlink(oldValue?.[RAW] || oldValue, object, keyStr);
|
|
433
435
|
if (this.watchers || this.listeners)
|
|
434
436
|
for (let i = 0; i < loopLen; i++) {
|
|
435
|
-
const currPath = this.config.lineageTracing ? paths[i] : fullPath,
|
|
436
|
-
this.notify(currPath, { type: "delete", target, currentTarget:
|
|
437
|
+
const currPath = this.config.lineageTracing ? paths[i] : fullPath, target2 = { path: currPath, value, oldValue, key: keyStr, hadKey, object: receiver };
|
|
438
|
+
this.notify(currPath, { type: "delete", target: target2, currentTarget: target2, root: this.core, rejectable });
|
|
437
439
|
}
|
|
438
440
|
return true;
|
|
439
441
|
},
|
|
@@ -459,7 +461,7 @@ var Reactor = class {
|
|
|
459
461
|
return ownKeys;
|
|
460
462
|
}
|
|
461
463
|
});
|
|
462
|
-
return this.proxyCache.set(
|
|
464
|
+
return this.proxyCache.set(target, proxy), proxy;
|
|
463
465
|
}
|
|
464
466
|
trace(target, path, paths = [], seen = /* @__PURE__ */ new WeakSet()) {
|
|
465
467
|
if (Object.is(target, this.core[RAW] || this.core)) return paths.push(path), paths;
|
|
@@ -612,15 +614,14 @@ var Reactor = class {
|
|
|
612
614
|
if (sig) sig.aborted ? cord.clup() : sig.addEventListener("abort", cord.clup, { once: true });
|
|
613
615
|
return cord.sclup = !sig || sig.aborted ? NOOP : () => sig.removeEventListener("abort", cord.clup), cord.clup;
|
|
614
616
|
}
|
|
615
|
-
cloned(
|
|
616
|
-
if (!
|
|
617
|
-
obj =
|
|
618
|
-
const cloned = seen.get(obj);
|
|
617
|
+
cloned(target, raw, seen = /* @__PURE__ */ new WeakMap()) {
|
|
618
|
+
if (!target || "object" !== typeof target) return target;
|
|
619
|
+
const obj = target[RAW] || target, cloned = seen.get(obj);
|
|
619
620
|
if (cloned) return cloned;
|
|
620
621
|
if (!canHandle(obj, this.config, false)) return obj;
|
|
621
622
|
const version = obj[VERSION] || 0, cached = !raw && this.config.smartCloning && (this.snapCache ??= /* @__PURE__ */ new WeakMap()).get(obj);
|
|
622
623
|
if (cached && obj[SSVERSION] === version) return cached;
|
|
623
|
-
const clone = !raw ? this.config.preserveContext ? Object.create(Object.getPrototypeOf(obj)) : Array.isArray(obj) ? [] : {} : obj
|
|
624
|
+
const clone = !raw ? this.config.preserveContext ? Object.create(Object.getPrototypeOf(obj)) : Array.isArray(obj) ? [] : {} : obj;
|
|
624
625
|
seen.set(obj, clone);
|
|
625
626
|
const keys2 = this.config.preserveContext ? Reflect.ownKeys(obj) : Object.keys(obj);
|
|
626
627
|
for (let i = 0, len = keys2.length; i < len; i++) clone[keys2[i]] = this.cloned(obj[keys2[i]], raw, seen);
|
|
@@ -804,19 +805,8 @@ var Reactor = class {
|
|
|
804
805
|
for (let i = 0, len = cords.length; i < len; i++) if (Object.is(cords[i].cb, callback) && cords[i].capture === capture) return cords[i].sclup(), cords.splice((len--, i--), 1), !cords.length && this.listeners.delete(path), true;
|
|
805
806
|
return false;
|
|
806
807
|
}
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
* You could alternatively use or serialize your proxied state "as is" except the environment demands no proxies or new references.
|
|
810
|
-
* @param raw Use raw (deep unproxied & uncloned) version of branch.
|
|
811
|
-
* @param branch Branch to clone.
|
|
812
|
-
* @returns Snapshot deep or smart (structurally shared) clone.
|
|
813
|
-
* @example
|
|
814
|
-
* const snap = rtr.snapshot();
|
|
815
|
-
* @example
|
|
816
|
-
* const snap = rtr.snapshot(false, rtr.core.history.past);
|
|
817
|
-
*/
|
|
818
|
-
snapshot(raw = !this.config.smartCloning, branch = this.core) {
|
|
819
|
-
return this.cloned(branch, raw);
|
|
808
|
+
snapshot(raw = !this.config.smartCloning, branch) {
|
|
809
|
+
return this.cloned(arguments.length < 2 ? this.core : branch, raw);
|
|
820
810
|
}
|
|
821
811
|
/**
|
|
822
812
|
* Cascades object updates into direct child paths.
|
|
@@ -1032,7 +1022,7 @@ function useReactor(target, options = NIL, build) {
|
|
|
1032
1022
|
const versionRef = (0, import_react2.useRef)(0), tgtRef = (0, import_react2.useRef)(), rtrRef = (0, import_react2.useRef)(), rtr = tgtRef.current !== target || !rtrRef.current ? (tgtRef.current = target, rtrRef.current = getReactor(target, true, build)) : rtrRef.current, atrkrRef = (0, import_react2.useRef)(), prevTrkr = CTX.autotracker, atrkr = CTX.autotracker = atrkrRef.current ||= new Autotracker(), optsRef = (0, import_react2.useRef)(options), notifyRef = (0, import_react2.useRef)(NOOP);
|
|
1033
1023
|
optsRef.current = options;
|
|
1034
1024
|
atrkr.unblock(rtr), queueMicrotask(() => CTX.autotracker === atrkr && (CTX.autotracker = prevTrkr));
|
|
1035
|
-
const subscribe = (0, import_react2.useCallback)((notify) => atrkr.callback(notifyRef.current = () => (versionRef.current++, notify())), []);
|
|
1025
|
+
const subscribe = (0, import_react2.useCallback)((notify) => atrkr.callback(notifyRef.current = () => (versionRef.current++, notify())), [atrkr]);
|
|
1036
1026
|
const getSnapshot = (0, import_react2.useCallback)(() => versionRef.current, []);
|
|
1037
1027
|
(0, import_react2.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
|
|
1038
1028
|
return useISOLayoutEffect(() => (CTX.autotracker = prevTrkr, atrkr.callback(notifyRef.current, optsRef.current)), [atrkr]), rtr.core;
|
|
@@ -1041,11 +1031,21 @@ function useAnyReactor(options = NIL) {
|
|
|
1041
1031
|
const versionRef = (0, import_react2.useRef)(0), atrkrRef = (0, import_react2.useRef)(), prevTrkr = CTX.autotracker, atrkr = CTX.autotracker = atrkrRef.current ||= new Autotracker(), optsRef = (0, import_react2.useRef)(options), notifyRef = (0, import_react2.useRef)(NOOP);
|
|
1042
1032
|
optsRef.current = options;
|
|
1043
1033
|
atrkr.unblock(), queueMicrotask(() => CTX.autotracker === atrkr && (CTX.autotracker = prevTrkr));
|
|
1044
|
-
const subscribe = (0, import_react2.useCallback)((notify) => atrkr.callback(notifyRef.current = () => (versionRef.current++, notify())), []);
|
|
1034
|
+
const subscribe = (0, import_react2.useCallback)((notify) => atrkr.callback(notifyRef.current = () => (versionRef.current++, notify())), [atrkr]);
|
|
1045
1035
|
const getSnapshot = (0, import_react2.useCallback)(() => versionRef.current, []);
|
|
1046
1036
|
(0, import_react2.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
|
|
1047
1037
|
useISOLayoutEffect(() => (CTX.autotracker = prevTrkr, atrkr.callback(notifyRef.current, optsRef.current)), [atrkr]);
|
|
1048
1038
|
}
|
|
1039
|
+
function useReactorSnapshot(target, options, build = { referenceTracking: true, smartCloning: true }) {
|
|
1040
|
+
const tgtRef = (0, import_react2.useRef)(), rtrRef = (0, import_react2.useRef)(), rtr = tgtRef.current !== target || !rtrRef.current ? (tgtRef.current = target, rtrRef.current = getReactor(target, true, build)) : rtrRef.current, atrkrRef = (0, import_react2.useRef)(), atrkrRtrRef = (0, import_react2.useRef)(), atrkr = atrkrRtrRef.current !== rtr || !atrkrRef.current ? (atrkrRtrRef.current = rtr, atrkrRef.current = new Autotracker(rtr)) : atrkrRef.current, notifyRef = (0, import_react2.useRef)(NOOP), optsRef = (0, import_react2.useRef)(options);
|
|
1041
|
+
rtr.config.referenceTracking = rtr.config.smartCloning = true;
|
|
1042
|
+
optsRef.current = options;
|
|
1043
|
+
const subscribe = (0, import_react2.useCallback)((notify) => (atrkr.callback(notifyRef.current = notify, optsRef.current), () => atrkr.cleanup()), [atrkr]);
|
|
1044
|
+
const getSnapshot = () => rtr.snapshot();
|
|
1045
|
+
const snapshot = (0, import_react2.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
|
|
1046
|
+
const proxy = (0, import_react2.useMemo)(() => atrkr.tracked(snapshot), [atrkr, snapshot]);
|
|
1047
|
+
return useISOLayoutEffect(() => atrkr.callback(notifyRef.current, optsRef.current), [atrkr, proxy]), proxy;
|
|
1048
|
+
}
|
|
1049
1049
|
|
|
1050
1050
|
// src/ts/adapters/react/hooks/useSelector.ts
|
|
1051
1051
|
var import_react3 = require("react");
|
|
@@ -1071,6 +1071,18 @@ function useAnySelector(sel, eq = Object.is, options = NIL) {
|
|
|
1071
1071
|
const slice = (0, import_react3.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
|
|
1072
1072
|
return useISOLayoutEffect(() => atrkr.callback(notifyRef.current, optsRef.current), [atrkr, slice]), slice;
|
|
1073
1073
|
}
|
|
1074
|
+
function useSelectorSnapshot(target, sel, eq = Object.is, options, build = { referenceTracking: true, smartCloning: true }) {
|
|
1075
|
+
const tgtRef = (0, import_react3.useRef)(), rtrRef = (0, import_react3.useRef)(), rtr = tgtRef.current !== target || !rtrRef.current ? (tgtRef.current = target, rtrRef.current = getReactor(target, true, build)) : rtrRef.current, atrkrRef = (0, import_react3.useRef)(), atrkrRtrRef = (0, import_react3.useRef)(), atrkr = atrkrRtrRef.current !== rtr || !atrkrRef.current ? (atrkrRtrRef.current = rtr, atrkrRef.current = new Autotracker(rtr)) : atrkrRef.current, notifyRef = (0, import_react3.useRef)(NOOP), sliceRef = (0, import_react3.useRef)(), selRef = (0, import_react3.useRef)(sel), eqRef = (0, import_react3.useRef)(eq), optsRef = (0, import_react3.useRef)(options);
|
|
1076
|
+
rtr.config.referenceTracking = rtr.config.smartCloning = true;
|
|
1077
|
+
optsRef.current = options, selRef.current = sel, eqRef.current = eq;
|
|
1078
|
+
const subscribe = (0, import_react3.useCallback)((notify) => (atrkr.callback(notifyRef.current = notify, optsRef.current), () => atrkr.cleanup()), [atrkr]);
|
|
1079
|
+
const getSnapshot = (0, import_react3.useCallback)(() => {
|
|
1080
|
+
const next = selRef.current(atrkr.tracked(rtr.snapshot()));
|
|
1081
|
+
return eqRef.current(sliceRef.current, next) ? sliceRef.current : sliceRef.current = next;
|
|
1082
|
+
}, [atrkr]);
|
|
1083
|
+
const slice = (0, import_react3.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
|
|
1084
|
+
return useISOLayoutEffect(() => atrkr.callback(notifyRef.current, optsRef.current), [atrkr, slice]), slice;
|
|
1085
|
+
}
|
|
1074
1086
|
|
|
1075
1087
|
// src/ts/adapters/react/hooks/usePath.ts
|
|
1076
1088
|
var import_react4 = require("react");
|
|
@@ -1187,41 +1199,16 @@ var TimeTravelOverlay = class _TimeTravelOverlay {
|
|
|
1187
1199
|
*/
|
|
1188
1200
|
constructor(time, build = {}) {
|
|
1189
1201
|
this.time = time;
|
|
1190
|
-
this.config = reactive({
|
|
1202
|
+
this.config = reactive({ title: `Time Travel Overlay ${this.index = ++_TimeTravelOverlay.count}`, ...build });
|
|
1191
1203
|
this.state.open = !!this.config.startOpen;
|
|
1192
|
-
const host = createEl("div", { className: "tt-overlay-host" });
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
const title = createEl("div", { className: "title" });
|
|
1196
|
-
const frame = createEl("span", { className: "muted" });
|
|
1197
|
-
const history = createEl("span", { className: "muted" });
|
|
1198
|
-
const paused = createEl("span", { className: "muted" });
|
|
1199
|
-
const clrHistory = createEl("button", { textContent: `Clear History${formatKeyForDisplay(keys.shortcuts.clrHistory)}`, ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.clrHistory, false), onclick: () => (this.time.clear(), this.state.import = "") });
|
|
1200
|
-
const undo = createEl("button", { textContent: `Undo${formatKeyForDisplay(keys.shortcuts.undo[0])}`, ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.undo, false), onclick: this.time.undo });
|
|
1201
|
-
const redo = createEl("button", { textContent: `Redo${formatKeyForDisplay(keys.shortcuts.redo[0])}`, ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.redo, false), onclick: this.time.redo });
|
|
1202
|
-
const genesis = createEl("button", { textContent: `Genesis${formatKeyForDisplay(keys.shortcuts.genesis[0])}`, ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.genesis, false), onclick: () => this.time.jumpTo(0) });
|
|
1203
|
-
const playPause = createEl("button", { onclick: () => this.time[this.time.state.paused ? "play" : "pause"](), ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.playPause, false) });
|
|
1204
|
-
const rewind = createEl("button", { textContent: `Rewind${formatKeyForDisplay(keys.shortcuts.rewind)}`, ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.rewind, false), onclick: this.time.rewind });
|
|
1205
|
-
const 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)) });
|
|
1206
|
-
const exp = createEl("button", { textContent: `Export${formatKeyForDisplay(keys.shortcuts.export)}`, ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.export, false), onclick: () => this.state.import = this.time.export() });
|
|
1207
|
-
const 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) });
|
|
1208
|
-
const clr = createEl("button", { textContent: `Clear${formatKeyForDisplay(keys.shortcuts.clear)}`, ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.clear, false), onclick: () => this.state.import = "" });
|
|
1209
|
-
const io = createEl("textarea", { className: "tt-io", placeholder: "timeline payload json", oninput: () => this.state.import = io.value });
|
|
1210
|
-
const foot = createEl("p", { className: "tt-footnote", textContent: "Want this in your app? " });
|
|
1211
|
-
const link = createEl("a", { target: "_blank", rel: "noreferrer noopener", textContent: "sia-reactor", href: "https://www.npmjs.com/package/sia-reactor" });
|
|
1212
|
-
const box = createEl("div", { className: "tt-status-box" });
|
|
1213
|
-
const status = createEl("div", { className: "tt-status-row" });
|
|
1214
|
-
const row1 = createEl("div", { className: "tt-row" });
|
|
1215
|
-
const row2 = createEl("div", { className: "tt-row" });
|
|
1216
|
-
const row3 = createEl("div", { className: "tt-row" });
|
|
1217
|
-
status.append((box.append(frame, history, paused), box), clrHistory);
|
|
1218
|
-
panel.append(title, status, (row1.append(undo, redo, genesis), row1), (row2.append(playPause, rewind), row2), range, (row3.append(exp, imp, clr), row3), io, (foot.appendChild(link), foot));
|
|
1204
|
+
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[0])}`, 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" });
|
|
1205
|
+
status.append((box.append(frame), box), clrHistory);
|
|
1206
|
+
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));
|
|
1219
1207
|
host.append(toggle, panel);
|
|
1220
|
-
this.els = { host, toggle, panel, title, frame,
|
|
1208
|
+
this.els = { host, toggle, panel, title, frame, clrHistory, undo, redo, genesis, playPause, rewind, range, exp, imp, clr, payload, io };
|
|
1221
1209
|
this.keyup = (e) => {
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
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[this.time.state.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 = "");
|
|
1210
|
+
const a = this.state.open && keyEventAllowed(e, keys);
|
|
1211
|
+
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 = "");
|
|
1225
1212
|
};
|
|
1226
1213
|
window.addEventListener("keydown", this.keyup);
|
|
1227
1214
|
const sync = [
|
|
@@ -1231,26 +1218,19 @@ var TimeTravelOverlay = class _TimeTravelOverlay {
|
|
|
1231
1218
|
const dock = getDock(this.config.container);
|
|
1232
1219
|
if (host.parentNode !== dock) dock.appendChild(host);
|
|
1233
1220
|
}),
|
|
1234
|
-
effect(() =>
|
|
1221
|
+
effect(() => toggle.textContent = `${(panel.hidden = !this.state.open) ? "Show" : "Hide"} ${title.textContent = this.config.title ?? ""}`),
|
|
1222
|
+
effect(() => playPause.textContent = `${s.paused ? "Play" : "Pause"}${formatKeyForDisplay(keys.shortcuts.playPause)}`),
|
|
1235
1223
|
effect(() => {
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1224
|
+
frame.textContent = `Frame: ${s.currentFrame} / ${s.history.length}`;
|
|
1225
|
+
range.disabled = clrHistory.disabled = !s.history.length;
|
|
1226
|
+
genesis.disabled = rewind.disabled = undo.disabled = !s.currentFrame;
|
|
1227
|
+
playPause.disabled = redo.disabled = s.currentFrame >= s.history.length;
|
|
1228
|
+
range.max = String(s.history.length);
|
|
1229
|
+
range.value = String(Math.min(s.currentFrame, s.history.length));
|
|
1230
|
+
payload.value = JSON.stringify(s.currentFrame ? s.history[s.currentFrame - 1] : { type: "genesis", value: s.initialState }, null, 2);
|
|
1241
1231
|
}),
|
|
1242
1232
|
effect(() => {
|
|
1243
|
-
|
|
1244
|
-
undo.disabled = this.time.state.currentFrame <= 0;
|
|
1245
|
-
redo.disabled = this.time.state.currentFrame >= this.time.state.history.length;
|
|
1246
|
-
genesis.disabled = this.time.state.currentFrame <= 0;
|
|
1247
|
-
playPause.disabled = this.time.state.currentFrame === this.time.state.history.length;
|
|
1248
|
-
rewind.disabled = !this.time.state.currentFrame;
|
|
1249
|
-
range.max = String(this.time.state.history.length);
|
|
1250
|
-
range.value = String(Math.min(this.time.state.currentFrame, this.time.state.history.length));
|
|
1251
|
-
range.disabled = !this.time.state.history.length;
|
|
1252
|
-
imp.disabled = !this.state.import.trim().length;
|
|
1253
|
-
clr.disabled = !this.state.import.trim().length;
|
|
1233
|
+
clr.disabled = imp.disabled = !this.state.import.trim().length;
|
|
1254
1234
|
io.value !== this.state.import && (io.value = this.state.import);
|
|
1255
1235
|
})
|
|
1256
1236
|
];
|
|
@@ -1277,12 +1257,12 @@ function getDock(container) {
|
|
|
1277
1257
|
|
|
1278
1258
|
// src/ts/adapters/react/TimeTravelOverlay.tsx
|
|
1279
1259
|
function TimeTravelOverlay2(props) {
|
|
1280
|
-
const vRef = (0, import_react5.useRef)(null), { time, title, color
|
|
1281
|
-
(
|
|
1260
|
+
const vRef = (0, import_react5.useRef)(null), { time, title, color, devOnly, startOpen, container } = props;
|
|
1261
|
+
useISOLayoutEffect(() => {
|
|
1282
1262
|
vRef.current = new TimeTravelOverlay(time, props);
|
|
1283
1263
|
return () => void (vRef.current?.destroy(), vRef.current = null);
|
|
1284
1264
|
}, [time]);
|
|
1285
|
-
useISOLayoutEffect(() => void (vRef.current && (title !== void 0 && (vRef.current.config.title = title), vRef.current.config.color = color, vRef.current.config.devOnly = devOnly, vRef.current.config.container = container
|
|
1265
|
+
useISOLayoutEffect(() => void (vRef.current && (title !== void 0 && (vRef.current.config.title = title), vRef.current.config.color = color, vRef.current.config.devOnly = devOnly, vRef.current.config.container = container, vRef.current.state.open = startOpen)), [title, color, devOnly, container, startOpen]);
|
|
1286
1266
|
return null;
|
|
1287
1267
|
}
|
|
1288
1268
|
// Annotate the CommonJS export names for ESM import in node:
|
|
@@ -1293,5 +1273,7 @@ function TimeTravelOverlay2(props) {
|
|
|
1293
1273
|
useISOLayoutEffect,
|
|
1294
1274
|
usePath,
|
|
1295
1275
|
useReactor,
|
|
1296
|
-
|
|
1276
|
+
useReactorSnapshot,
|
|
1277
|
+
useSelector,
|
|
1278
|
+
useSelectorSnapshot
|
|
1297
1279
|
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { E as EffectOptions, b as Reactor, R as Reactive, o as ReactorBuild, W as WildPaths, q as PathValue } from '../index-
|
|
1
|
+
import { E as EffectOptions, b as Reactor, R as Reactive, o as ReactorBuild, W as WildPaths, q as PathValue } from '../index-Oie9hhE8.cjs';
|
|
2
2
|
import { useLayoutEffect } from 'react';
|
|
3
|
-
import { T as TimeTravelPlugin } from '../timeTravel-
|
|
4
|
-
import { T as TimeTravelConfig } from '../TimeTravelOverlay-
|
|
3
|
+
import { T as TimeTravelPlugin } from '../timeTravel-WpgWmKu-.cjs';
|
|
4
|
+
import { T as TimeTravelConfig } from '../TimeTravelOverlay-CJv-S_Km.cjs';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Subscribes a component to desired Reactor state and returns it.
|
|
@@ -12,7 +12,7 @@ import { T as TimeTravelConfig } from '../TimeTravelOverlay-BYSnHBXx.cjs';
|
|
|
12
12
|
* @param build Optional Reactor build options used when creating a scoped Reactor for plain objects.
|
|
13
13
|
* @returns State for render usage if state is scoped locally or just desired.
|
|
14
14
|
* @example
|
|
15
|
-
* const a = useReactor({ user: { name: "Ada" } });
|
|
15
|
+
* const a = useReactor({ user: { name: "Ada" } }); // per-component scoped
|
|
16
16
|
* @example
|
|
17
17
|
* const state = reactive({ user: { name: "Ada" } });
|
|
18
18
|
* const b = useReactor(state);
|
|
@@ -29,6 +29,25 @@ declare function useReactor<T extends object>(target: T | Reactor<T> | Reactive<
|
|
|
29
29
|
* useAnyReactor();
|
|
30
30
|
*/
|
|
31
31
|
declare function useAnyReactor(options?: EffectOptions): void;
|
|
32
|
+
/**
|
|
33
|
+
* Subscribes a component to Reactor state and returns a tracked snapshot.
|
|
34
|
+
* Rule of thumb: read from snapshots, mutate the source.
|
|
35
|
+
* The hook uses access tracking so re-renders occur only when accessed fields change.
|
|
36
|
+
* @typeParam T Root state object type.
|
|
37
|
+
* @param target Reactive object, Reactor instance, or plain object.
|
|
38
|
+
* @param options Watcher options if `options.sync: false` else Listener options.
|
|
39
|
+
* @param build Optional Reactor build options used when creating a scoped Reactor for plain objects.
|
|
40
|
+
* @returns Tracked snapshot snap for render usage.
|
|
41
|
+
* @example
|
|
42
|
+
* const a = useReactorSnapshot({ user: { name: "Ada" } }); // per-component scoped
|
|
43
|
+
* @example
|
|
44
|
+
* const state = reactive({ user: { name: "Ada" } });
|
|
45
|
+
* const b = useReactorSnapshot(state);
|
|
46
|
+
* @example
|
|
47
|
+
* const rtr = new Reactor({ user: { name: "Ada" } });
|
|
48
|
+
* const c = useReactorSnapshot(rtr);
|
|
49
|
+
*/
|
|
50
|
+
declare function useReactorSnapshot<T extends object>(target: T | Reactor<T> | Reactive<T>, options?: EffectOptions, build?: ReactorBuild<T>): T;
|
|
32
51
|
|
|
33
52
|
/**
|
|
34
53
|
* Subscribes to a derived slice of Reactor state.
|
|
@@ -43,7 +62,7 @@ declare function useAnyReactor(options?: EffectOptions): void;
|
|
|
43
62
|
* @param build Optional Reactor build options used when creating a scoped Reactor for plain objects.
|
|
44
63
|
* @returns The selected slice.
|
|
45
64
|
* @example
|
|
46
|
-
* const a = useSelector({ user: { name: "Ada" } }, (s) => s.user.name);
|
|
65
|
+
* const a = useSelector({ user: { name: "Ada" } }, (s) => s.user.name); // per-component scoped
|
|
47
66
|
* @example
|
|
48
67
|
* const state = reactive({ user: { name: "Ada" } });
|
|
49
68
|
* const b = useSelector(state, (s) => s.user.name);
|
|
@@ -63,6 +82,28 @@ declare function useSelector<T extends object, R>(target: T | Reactor<T> | React
|
|
|
63
82
|
* @returns The selected slice.
|
|
64
83
|
*/
|
|
65
84
|
declare function useAnySelector<R>(sel: () => R, eq?: (value1: any, value2: any) => boolean, options?: EffectOptions): R;
|
|
85
|
+
/**
|
|
86
|
+
* Subscribes to a derived slice of Reactor state.
|
|
87
|
+
* The selector runs against a tracked snapshot and uses the provided equality function
|
|
88
|
+
* to suppress unchanged results.
|
|
89
|
+
* @typeParam T Root state object type.
|
|
90
|
+
* @typeParam R Selector return type.
|
|
91
|
+
* @param target Reactive object, Reactor instance, or plain object.
|
|
92
|
+
* @param sel Slice selector.
|
|
93
|
+
* @param eq Equality function used to compare consecutive selector results.
|
|
94
|
+
* @param options Watcher options if `options.sync: false` else Listener options.
|
|
95
|
+
* @param build Optional Reactor build options used when creating a scoped Reactor for plain objects.
|
|
96
|
+
* @returns The selected slice.
|
|
97
|
+
* @example
|
|
98
|
+
* const a = useSelectorSnapshot({ user: { name: "Ada" } }, (s) => s.user.name); // per-component scoped
|
|
99
|
+
* @example
|
|
100
|
+
* const state = reactive({ user: { name: "Ada" } });
|
|
101
|
+
* const b = useSelectorSnapshot(state, (s) => s.user.name);
|
|
102
|
+
* @example
|
|
103
|
+
* const rtr = new Reactor({ user: { name: "Ada" } });
|
|
104
|
+
* const c = useSelectorSnapshot(rtr, (s) => s.user.name);
|
|
105
|
+
*/
|
|
106
|
+
declare function useSelectorSnapshot<T extends object, R>(target: T | Reactor<T> | Reactive<T>, sel: (state: T) => R, eq?: (value1: any, value2: any) => boolean, options?: EffectOptions, build?: ReactorBuild<T>): R;
|
|
66
107
|
|
|
67
108
|
/**
|
|
68
109
|
* Subscribes to a single path in Reactor state.
|
|
@@ -102,4 +143,4 @@ interface TimeTravelOverlayProps extends Partial<TimeTravelConfig> {
|
|
|
102
143
|
*/
|
|
103
144
|
declare function TimeTravelOverlay(props: TimeTravelOverlayProps): null;
|
|
104
145
|
|
|
105
|
-
export { TimeTravelOverlay, type TimeTravelOverlayProps, useAnyReactor, useAnySelector, useISOLayoutEffect, usePath, useReactor, useSelector };
|
|
146
|
+
export { TimeTravelOverlay, type TimeTravelOverlayProps, useAnyReactor, useAnySelector, useISOLayoutEffect, usePath, useReactor, useReactorSnapshot, useSelector, useSelectorSnapshot };
|
package/dist/adapters/react.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { E as EffectOptions, b as Reactor, R as Reactive, o as ReactorBuild, W as WildPaths, q as PathValue } from '../index-
|
|
1
|
+
import { E as EffectOptions, b as Reactor, R as Reactive, o as ReactorBuild, W as WildPaths, q as PathValue } from '../index-Oie9hhE8.js';
|
|
2
2
|
import { useLayoutEffect } from 'react';
|
|
3
|
-
import { T as TimeTravelPlugin } from '../timeTravel-
|
|
4
|
-
import { T as TimeTravelConfig } from '../TimeTravelOverlay-
|
|
3
|
+
import { T as TimeTravelPlugin } from '../timeTravel-B1vedDQc.js';
|
|
4
|
+
import { T as TimeTravelConfig } from '../TimeTravelOverlay-DxqJL0Zk.js';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Subscribes a component to desired Reactor state and returns it.
|
|
@@ -12,7 +12,7 @@ import { T as TimeTravelConfig } from '../TimeTravelOverlay-DoNrZwvX.js';
|
|
|
12
12
|
* @param build Optional Reactor build options used when creating a scoped Reactor for plain objects.
|
|
13
13
|
* @returns State for render usage if state is scoped locally or just desired.
|
|
14
14
|
* @example
|
|
15
|
-
* const a = useReactor({ user: { name: "Ada" } });
|
|
15
|
+
* const a = useReactor({ user: { name: "Ada" } }); // per-component scoped
|
|
16
16
|
* @example
|
|
17
17
|
* const state = reactive({ user: { name: "Ada" } });
|
|
18
18
|
* const b = useReactor(state);
|
|
@@ -29,6 +29,25 @@ declare function useReactor<T extends object>(target: T | Reactor<T> | Reactive<
|
|
|
29
29
|
* useAnyReactor();
|
|
30
30
|
*/
|
|
31
31
|
declare function useAnyReactor(options?: EffectOptions): void;
|
|
32
|
+
/**
|
|
33
|
+
* Subscribes a component to Reactor state and returns a tracked snapshot.
|
|
34
|
+
* Rule of thumb: read from snapshots, mutate the source.
|
|
35
|
+
* The hook uses access tracking so re-renders occur only when accessed fields change.
|
|
36
|
+
* @typeParam T Root state object type.
|
|
37
|
+
* @param target Reactive object, Reactor instance, or plain object.
|
|
38
|
+
* @param options Watcher options if `options.sync: false` else Listener options.
|
|
39
|
+
* @param build Optional Reactor build options used when creating a scoped Reactor for plain objects.
|
|
40
|
+
* @returns Tracked snapshot snap for render usage.
|
|
41
|
+
* @example
|
|
42
|
+
* const a = useReactorSnapshot({ user: { name: "Ada" } }); // per-component scoped
|
|
43
|
+
* @example
|
|
44
|
+
* const state = reactive({ user: { name: "Ada" } });
|
|
45
|
+
* const b = useReactorSnapshot(state);
|
|
46
|
+
* @example
|
|
47
|
+
* const rtr = new Reactor({ user: { name: "Ada" } });
|
|
48
|
+
* const c = useReactorSnapshot(rtr);
|
|
49
|
+
*/
|
|
50
|
+
declare function useReactorSnapshot<T extends object>(target: T | Reactor<T> | Reactive<T>, options?: EffectOptions, build?: ReactorBuild<T>): T;
|
|
32
51
|
|
|
33
52
|
/**
|
|
34
53
|
* Subscribes to a derived slice of Reactor state.
|
|
@@ -43,7 +62,7 @@ declare function useAnyReactor(options?: EffectOptions): void;
|
|
|
43
62
|
* @param build Optional Reactor build options used when creating a scoped Reactor for plain objects.
|
|
44
63
|
* @returns The selected slice.
|
|
45
64
|
* @example
|
|
46
|
-
* const a = useSelector({ user: { name: "Ada" } }, (s) => s.user.name);
|
|
65
|
+
* const a = useSelector({ user: { name: "Ada" } }, (s) => s.user.name); // per-component scoped
|
|
47
66
|
* @example
|
|
48
67
|
* const state = reactive({ user: { name: "Ada" } });
|
|
49
68
|
* const b = useSelector(state, (s) => s.user.name);
|
|
@@ -63,6 +82,28 @@ declare function useSelector<T extends object, R>(target: T | Reactor<T> | React
|
|
|
63
82
|
* @returns The selected slice.
|
|
64
83
|
*/
|
|
65
84
|
declare function useAnySelector<R>(sel: () => R, eq?: (value1: any, value2: any) => boolean, options?: EffectOptions): R;
|
|
85
|
+
/**
|
|
86
|
+
* Subscribes to a derived slice of Reactor state.
|
|
87
|
+
* The selector runs against a tracked snapshot and uses the provided equality function
|
|
88
|
+
* to suppress unchanged results.
|
|
89
|
+
* @typeParam T Root state object type.
|
|
90
|
+
* @typeParam R Selector return type.
|
|
91
|
+
* @param target Reactive object, Reactor instance, or plain object.
|
|
92
|
+
* @param sel Slice selector.
|
|
93
|
+
* @param eq Equality function used to compare consecutive selector results.
|
|
94
|
+
* @param options Watcher options if `options.sync: false` else Listener options.
|
|
95
|
+
* @param build Optional Reactor build options used when creating a scoped Reactor for plain objects.
|
|
96
|
+
* @returns The selected slice.
|
|
97
|
+
* @example
|
|
98
|
+
* const a = useSelectorSnapshot({ user: { name: "Ada" } }, (s) => s.user.name); // per-component scoped
|
|
99
|
+
* @example
|
|
100
|
+
* const state = reactive({ user: { name: "Ada" } });
|
|
101
|
+
* const b = useSelectorSnapshot(state, (s) => s.user.name);
|
|
102
|
+
* @example
|
|
103
|
+
* const rtr = new Reactor({ user: { name: "Ada" } });
|
|
104
|
+
* const c = useSelectorSnapshot(rtr, (s) => s.user.name);
|
|
105
|
+
*/
|
|
106
|
+
declare function useSelectorSnapshot<T extends object, R>(target: T | Reactor<T> | Reactive<T>, sel: (state: T) => R, eq?: (value1: any, value2: any) => boolean, options?: EffectOptions, build?: ReactorBuild<T>): R;
|
|
66
107
|
|
|
67
108
|
/**
|
|
68
109
|
* Subscribes to a single path in Reactor state.
|
|
@@ -102,4 +143,4 @@ interface TimeTravelOverlayProps extends Partial<TimeTravelConfig> {
|
|
|
102
143
|
*/
|
|
103
144
|
declare function TimeTravelOverlay(props: TimeTravelOverlayProps): null;
|
|
104
145
|
|
|
105
|
-
export { TimeTravelOverlay, type TimeTravelOverlayProps, useAnyReactor, useAnySelector, useISOLayoutEffect, usePath, useReactor, useSelector };
|
|
146
|
+
export { TimeTravelOverlay, type TimeTravelOverlayProps, useAnyReactor, useAnySelector, useISOLayoutEffect, usePath, useReactor, useReactorSnapshot, useSelector, useSelectorSnapshot };
|