@peerigon/typescript-toolkit 2.2.0 → 3.0.0
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 +1 -1
- package/dist/signals/signals.d.ts +16 -14
- package/dist/signals/signals.d.ts.map +1 -1
- package/dist/signals/signals.js +56 -33
- package/dist/signals/signals.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -46,7 +46,7 @@ import { assert } from "@peerigon/typescript-toolkit/assert";
|
|
|
46
46
|
| [`enums`](./src/enums/README.md) | Lightweight string-enum alternative for `erasableSyntaxOnly` TypeScript projects | [→](./src/enums/README.md) |
|
|
47
47
|
| [`match`](./src/match/README.md) | Exhaustive pattern matching with compile-time case checks, similar to `switch` | [→](./src/match/README.md) |
|
|
48
48
|
| [`result`](./src/result/README.md) | Type-safe error handling with pending, success, and error states | [→](./src/result/README.md) |
|
|
49
|
-
| [`signals`](./src/signals/README.md) | Push-based reactive state with explicit
|
|
49
|
+
| [`signals`](./src/signals/README.md) | Push-based reactive state with explicit watchers and `signal.from` adapters | [→](./src/signals/README.md) |
|
|
50
50
|
| [`unwrap`](./src/unwrap/README.md) | Extract values from `Result` or nullable types, with optional fallback support | [→](./src/unwrap/README.md) |
|
|
51
51
|
|
|
52
52
|
## License
|
|
@@ -1,19 +1,21 @@
|
|
|
1
|
-
export
|
|
1
|
+
export declare const signal: {
|
|
2
|
+
<Value>(initialValue: Value): Signal<Value>;
|
|
3
|
+
from<Value>(getFromSource: () => Value, subscribeToSource: (notify: () => void) => () => void): Omit<Signal<Value>, "set">;
|
|
4
|
+
};
|
|
5
|
+
export type SignalGetter<Value> = {
|
|
2
6
|
(): Value;
|
|
3
|
-
|
|
7
|
+
watch: (watcher: SignalWatcher<Value>) => SignalUnwatch;
|
|
4
8
|
};
|
|
5
|
-
export type
|
|
6
|
-
export type
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
subscribe: ReadSignal<Value>["subscribe"];
|
|
9
|
+
export type SignalWatcher<Value> = (update: SignalUpdate<Value>) => void;
|
|
10
|
+
export type SignalUpdate<Value> = {
|
|
11
|
+
new: Value;
|
|
12
|
+
old: Value;
|
|
10
13
|
};
|
|
11
|
-
export
|
|
12
|
-
|
|
13
|
-
|
|
14
|
+
export type SignalSetter<Value> = (value: Value) => void;
|
|
15
|
+
export type SignalUnwatch = (() => void) & Disposable;
|
|
16
|
+
export type Signal<Value> = Disposable & {
|
|
17
|
+
get: SignalGetter<Value>;
|
|
18
|
+
set: SignalSetter<Value>;
|
|
19
|
+
watch: SignalGetter<Value>["watch"];
|
|
14
20
|
};
|
|
15
|
-
export type SignalReader<Value> = ({ value, previousValue, }: {
|
|
16
|
-
value: Value;
|
|
17
|
-
previousValue: Value;
|
|
18
|
-
}) => void;
|
|
19
21
|
//# sourceMappingURL=signals.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"signals.d.ts","sourceRoot":"","sources":["../../src/signals/signals.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,
|
|
1
|
+
{"version":3,"file":"signals.d.ts","sourceRoot":"","sources":["../../src/signals/signals.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,MAAM;KAAI,KAAK,gBAAgB,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC;SAiClD,KAAK,iBACH,MAAM,KAAK,qBACP,CAAC,MAAM,EAAE,MAAM,IAAI,KAAK,MAAM,IAAI,GACpD,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC;CAL5B,CAAC;AAyDF,MAAM,MAAM,YAAY,CAAC,KAAK,IAAI;IAChC,IAAI,KAAK,CAAC;IACV,KAAK,EAAE,CAAC,OAAO,EAAE,aAAa,CAAC,KAAK,CAAC,KAAK,aAAa,CAAC;CACzD,CAAC;AAEF,MAAM,MAAM,aAAa,CAAC,KAAK,IAAI,CAAC,MAAM,EAAE,YAAY,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC;AAEzE,MAAM,MAAM,YAAY,CAAC,KAAK,IAAI;IAChC,GAAG,EAAE,KAAK,CAAC;IACX,GAAG,EAAE,KAAK,CAAC;CACZ,CAAC;AAEF,MAAM,MAAM,YAAY,CAAC,KAAK,IAAI,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;AAEzD,MAAM,MAAM,aAAa,GAAG,CAAC,MAAM,IAAI,CAAC,GAAG,UAAU,CAAC;AAEtD,MAAM,MAAM,MAAM,CAAC,KAAK,IAAI,UAAU,GAAG;IACvC,GAAG,EAAE,YAAY,CAAC,KAAK,CAAC,CAAC;IACzB,GAAG,EAAE,YAAY,CAAC,KAAK,CAAC,CAAC;IACzB,KAAK,EAAE,YAAY,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC;CACrC,CAAC"}
|
package/dist/signals/signals.js
CHANGED
|
@@ -1,51 +1,74 @@
|
|
|
1
1
|
export const signal = (initialValue) => {
|
|
2
|
-
const
|
|
2
|
+
const watchers = new Set();
|
|
3
3
|
let value = initialValue;
|
|
4
|
-
const
|
|
5
|
-
|
|
6
|
-
return () => {
|
|
7
|
-
|
|
8
|
-
};
|
|
4
|
+
const watch = (watcher) => {
|
|
5
|
+
watchers.add(watcher);
|
|
6
|
+
return createUnwatch(() => {
|
|
7
|
+
watchers.delete(watcher);
|
|
8
|
+
});
|
|
9
9
|
};
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
const
|
|
13
|
-
const
|
|
10
|
+
const get = () => value;
|
|
11
|
+
get.watch = watch;
|
|
12
|
+
const set = (newValue) => {
|
|
13
|
+
const oldValue = value;
|
|
14
14
|
value = newValue;
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
const update = {
|
|
16
|
+
new: newValue,
|
|
17
|
+
old: oldValue,
|
|
18
|
+
};
|
|
19
|
+
for (const watcher of watchers) {
|
|
20
|
+
watcher(update);
|
|
17
21
|
}
|
|
18
22
|
};
|
|
19
23
|
const dispose = () => {
|
|
20
|
-
|
|
24
|
+
watchers.clear();
|
|
21
25
|
};
|
|
22
|
-
return {
|
|
26
|
+
return { get, set, watch, [Symbol.dispose]: dispose };
|
|
23
27
|
};
|
|
24
|
-
signal.from = (
|
|
25
|
-
const derivedSignal = signal(
|
|
26
|
-
let
|
|
27
|
-
let
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
28
|
+
signal.from = (getFromSource, subscribeToSource) => {
|
|
29
|
+
const derivedSignal = signal(getFromSource());
|
|
30
|
+
let watcherCount = 0;
|
|
31
|
+
let unwatchFromSource;
|
|
32
|
+
let disposed = false;
|
|
33
|
+
const watch = (watcher) => {
|
|
34
|
+
const unwatch = derivedSignal.watch(watcher);
|
|
35
|
+
if (watcherCount === 0) {
|
|
36
|
+
unwatchFromSource = subscribeToSource(() => {
|
|
37
|
+
derivedSignal.set(getFromSource());
|
|
33
38
|
});
|
|
34
39
|
}
|
|
35
|
-
|
|
36
|
-
return () => {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
if (readerCount === 0) {
|
|
40
|
-
unsubscribeFromSource?.();
|
|
41
|
-
unsubscribeFromSource = undefined;
|
|
40
|
+
watcherCount++;
|
|
41
|
+
return createUnwatch(() => {
|
|
42
|
+
if (disposed) {
|
|
43
|
+
return;
|
|
42
44
|
}
|
|
43
|
-
|
|
45
|
+
unwatch();
|
|
46
|
+
watcherCount--;
|
|
47
|
+
if (watcherCount === 0) {
|
|
48
|
+
unwatchFromSource?.();
|
|
49
|
+
unwatchFromSource = undefined;
|
|
50
|
+
}
|
|
51
|
+
});
|
|
44
52
|
};
|
|
53
|
+
const get = () => derivedSignal.get();
|
|
54
|
+
get.watch = watch;
|
|
45
55
|
const dispose = () => {
|
|
46
|
-
|
|
56
|
+
if (disposed) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
disposed = true;
|
|
60
|
+
unwatchFromSource?.();
|
|
61
|
+
unwatchFromSource = undefined;
|
|
62
|
+
watcherCount = 0;
|
|
47
63
|
derivedSignal[Symbol.dispose]();
|
|
48
64
|
};
|
|
49
|
-
return {
|
|
65
|
+
return { get, watch, [Symbol.dispose]: dispose };
|
|
66
|
+
};
|
|
67
|
+
const createUnwatch = (remove) => {
|
|
68
|
+
const unwatch = () => {
|
|
69
|
+
remove();
|
|
70
|
+
};
|
|
71
|
+
unwatch[Symbol.dispose] = unwatch;
|
|
72
|
+
return unwatch;
|
|
50
73
|
};
|
|
51
74
|
//# sourceMappingURL=signals.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"signals.js","sourceRoot":"","sources":["../../src/signals/signals.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"signals.js","sourceRoot":"","sources":["../../src/signals/signals.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,MAAM,GAAG,CAAQ,YAAmB,EAAiB,EAAE;IAClE,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAwB,CAAC;IACjD,IAAI,KAAK,GAAG,YAAY,CAAC;IAEzB,MAAM,KAAK,GAAiC,CAAC,OAAO,EAAE,EAAE;QACtD,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACtB,OAAO,aAAa,CAAC,GAAG,EAAE;YACxB,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAC3B,CAAC,CAAC,CAAC;IACL,CAAC,CAAC;IAEF,MAAM,GAAG,GAAwB,GAAG,EAAE,CAAC,KAAK,CAAC;IAC7C,GAAG,CAAC,KAAK,GAAG,KAAK,CAAC;IAElB,MAAM,GAAG,GAAwB,CAAC,QAAQ,EAAE,EAAE;QAC5C,MAAM,QAAQ,GAAG,KAAK,CAAC;QACvB,KAAK,GAAG,QAAQ,CAAC;QACjB,MAAM,MAAM,GAAwB;YAClC,GAAG,EAAE,QAAQ;YACb,GAAG,EAAE,QAAQ;SACd,CAAC;QACF,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;YAC/B,OAAO,CAAC,MAAM,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC;IAEF,MAAM,OAAO,GAAG,GAAG,EAAE;QACnB,QAAQ,CAAC,KAAK,EAAE,CAAC;IACnB,CAAC,CAAC;IAEF,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,CAAC;AACxD,CAAC,CAAC;AAEF,MAAM,CAAC,IAAI,GAAG,CACZ,aAA0B,EAC1B,iBAAqD,EACzB,EAAE;IAC9B,MAAM,aAAa,GAAG,MAAM,CAAC,aAAa,EAAE,CAAC,CAAC;IAE9C,IAAI,YAAY,GAAG,CAAC,CAAC;IACrB,IAAI,iBAA2C,CAAC;IAChD,IAAI,QAAQ,GAAG,KAAK,CAAC;IACrB,MAAM,KAAK,GAAG,CAAC,OAA6B,EAAE,EAAE;QAC9C,MAAM,OAAO,GAAG,aAAa,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAC7C,IAAI,YAAY,KAAK,CAAC,EAAE,CAAC;YACvB,iBAAiB,GAAG,iBAAiB,CAAC,GAAG,EAAE;gBACzC,aAAa,CAAC,GAAG,CAAC,aAAa,EAAE,CAAC,CAAC;YACrC,CAAC,CAAC,CAAC;QACL,CAAC;QACD,YAAY,EAAE,CAAC;QACf,OAAO,aAAa,CAAC,GAAG,EAAE;YACxB,IAAI,QAAQ,EAAE,CAAC;gBACb,OAAO;YACT,CAAC;YACD,OAAO,EAAE,CAAC;YACV,YAAY,EAAE,CAAC;YACf,IAAI,YAAY,KAAK,CAAC,EAAE,CAAC;gBACvB,iBAAiB,EAAE,EAAE,CAAC;gBACtB,iBAAiB,GAAG,SAAS,CAAC;YAChC,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC,CAAC;IAEF,MAAM,GAAG,GAAwB,GAAG,EAAE,CAAC,aAAa,CAAC,GAAG,EAAE,CAAC;IAC3D,GAAG,CAAC,KAAK,GAAG,KAAK,CAAC;IAElB,MAAM,OAAO,GAAG,GAAG,EAAE;QACnB,IAAI,QAAQ,EAAE,CAAC;YACb,OAAO;QACT,CAAC;QACD,QAAQ,GAAG,IAAI,CAAC;QAChB,iBAAiB,EAAE,EAAE,CAAC;QACtB,iBAAiB,GAAG,SAAS,CAAC;QAC9B,YAAY,GAAG,CAAC,CAAC;QACjB,aAAa,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC;IAClC,CAAC,CAAC;IAEF,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,CAAC;AACnD,CAAC,CAAC;AAEF,MAAM,aAAa,GAAG,CAAC,MAAkB,EAAiB,EAAE;IAC1D,MAAM,OAAO,GAAG,GAAG,EAAE;QACnB,MAAM,EAAE,CAAC;IACX,CAAC,CAAC;IACF,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;IAClC,OAAO,OAAO,CAAC;AACjB,CAAC,CAAC","sourcesContent":["export const signal = <Value>(initialValue: Value): Signal<Value> => {\n const watchers = new Set<SignalWatcher<Value>>();\n let value = initialValue;\n\n const watch: SignalGetter<Value>[\"watch\"] = (watcher) => {\n watchers.add(watcher);\n return createUnwatch(() => {\n watchers.delete(watcher);\n });\n };\n\n const get: SignalGetter<Value> = () => value;\n get.watch = watch;\n\n const set: SignalSetter<Value> = (newValue) => {\n const oldValue = value;\n value = newValue;\n const update: SignalUpdate<Value> = {\n new: newValue,\n old: oldValue,\n };\n for (const watcher of watchers) {\n watcher(update);\n }\n };\n\n const dispose = () => {\n watchers.clear();\n };\n\n return { get, set, watch, [Symbol.dispose]: dispose };\n};\n\nsignal.from = <Value>(\n getFromSource: () => Value,\n subscribeToSource: (notify: () => void) => () => void,\n): Omit<Signal<Value>, \"set\"> => {\n const derivedSignal = signal(getFromSource());\n\n let watcherCount = 0;\n let unwatchFromSource: (() => void) | undefined;\n let disposed = false;\n const watch = (watcher: SignalWatcher<Value>) => {\n const unwatch = derivedSignal.watch(watcher);\n if (watcherCount === 0) {\n unwatchFromSource = subscribeToSource(() => {\n derivedSignal.set(getFromSource());\n });\n }\n watcherCount++;\n return createUnwatch(() => {\n if (disposed) {\n return;\n }\n unwatch();\n watcherCount--;\n if (watcherCount === 0) {\n unwatchFromSource?.();\n unwatchFromSource = undefined;\n }\n });\n };\n\n const get: SignalGetter<Value> = () => derivedSignal.get();\n get.watch = watch;\n\n const dispose = () => {\n if (disposed) {\n return;\n }\n disposed = true;\n unwatchFromSource?.();\n unwatchFromSource = undefined;\n watcherCount = 0;\n derivedSignal[Symbol.dispose]();\n };\n\n return { get, watch, [Symbol.dispose]: dispose };\n};\n\nconst createUnwatch = (remove: () => void): SignalUnwatch => {\n const unwatch = () => {\n remove();\n };\n unwatch[Symbol.dispose] = unwatch;\n return unwatch;\n};\n\nexport type SignalGetter<Value> = {\n (): Value;\n watch: (watcher: SignalWatcher<Value>) => SignalUnwatch;\n};\n\nexport type SignalWatcher<Value> = (update: SignalUpdate<Value>) => void;\n\nexport type SignalUpdate<Value> = {\n new: Value;\n old: Value;\n};\n\nexport type SignalSetter<Value> = (value: Value) => void;\n\nexport type SignalUnwatch = (() => void) & Disposable;\n\nexport type Signal<Value> = Disposable & {\n get: SignalGetter<Value>;\n set: SignalSetter<Value>;\n watch: SignalGetter<Value>[\"watch\"];\n};\n"]}
|
package/package.json
CHANGED