@alwatr/signal 9.26.0 → 9.29.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 +197 -603
- package/dist/core/channel-signal.d.ts +12 -53
- package/dist/core/channel-signal.d.ts.map +1 -1
- package/dist/core/computed-signal.d.ts +19 -33
- package/dist/core/computed-signal.d.ts.map +1 -1
- package/dist/core/derived-signal.d.ts +71 -0
- package/dist/core/derived-signal.d.ts.map +1 -0
- package/dist/core/effect-signal.d.ts +15 -1
- package/dist/core/effect-signal.d.ts.map +1 -1
- package/dist/core/event-signal.d.ts +11 -4
- package/dist/core/event-signal.d.ts.map +1 -1
- package/dist/core/persistent-state-signal.d.ts +21 -2
- package/dist/core/persistent-state-signal.d.ts.map +1 -1
- package/dist/core/session-state-signal.d.ts +19 -2
- package/dist/core/session-state-signal.d.ts.map +1 -1
- package/dist/core/signal-base.d.ts +58 -38
- package/dist/core/signal-base.d.ts.map +1 -1
- package/dist/core/state-signal.d.ts +33 -14
- package/dist/core/state-signal.d.ts.map +1 -1
- package/dist/creators/channel.d.ts +1 -1
- package/dist/creators/channel.d.ts.map +1 -1
- package/dist/creators/derived.d.ts +31 -0
- package/dist/creators/derived.d.ts.map +1 -0
- package/dist/main.d.ts +2 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +3 -3
- package/dist/main.js.map +16 -15
- package/dist/operators/debounce.d.ts +2 -3
- package/dist/operators/debounce.d.ts.map +1 -1
- package/dist/operators/filter.d.ts +14 -13
- package/dist/operators/filter.d.ts.map +1 -1
- package/dist/type.d.ts +68 -3
- package/dist/type.d.ts.map +1 -1
- package/package.json +6 -6
- package/src/core/channel-signal.ts +25 -68
- package/src/core/computed-signal.ts +50 -74
- package/src/core/derived-signal.ts +166 -0
- package/src/core/effect-signal.ts +23 -11
- package/src/core/event-signal.ts +14 -9
- package/src/core/persistent-state-signal.ts +21 -4
- package/src/core/session-state-signal.ts +19 -4
- package/src/core/signal-base.ts +98 -61
- package/src/core/state-signal.ts +48 -29
- package/src/creators/channel.ts +1 -2
- package/src/creators/derived.ts +34 -0
- package/src/main.ts +2 -1
- package/src/operators/debounce.ts +13 -23
- package/src/operators/filter.ts +20 -26
- package/src/type.ts +71 -3
- package/dist/operators/map.d.ts +0 -36
- package/dist/operators/map.d.ts.map +0 -1
- package/src/operators/map.ts +0 -48
package/src/operators/filter.ts
CHANGED
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
import {createComputedSignal} from '../creators/computed.js';
|
|
2
1
|
import {createStateSignal} from '../creators/state.js';
|
|
3
|
-
|
|
4
|
-
import type {ComputedSignal} from '../core/computed-signal.js';
|
|
5
2
|
import type {IReadonlySignal} from '../type.js';
|
|
6
3
|
|
|
7
4
|
/**
|
|
@@ -24,40 +21,45 @@ import type {IReadonlySignal} from '../type.js';
|
|
|
24
21
|
* @returns A new computed signal that emits filtered values.
|
|
25
22
|
*
|
|
26
23
|
* @example
|
|
24
|
+
* ```typescript
|
|
27
25
|
* const numberSignal = createStateSignal({ name: 'number', initialValue: 0 });
|
|
28
26
|
*
|
|
29
27
|
* const evenNumberSignal = createFilteredSignal(
|
|
30
|
-
*
|
|
31
|
-
*
|
|
28
|
+
* numberSignal,
|
|
29
|
+
* (num) => num % 2 === 0,
|
|
32
30
|
* );
|
|
33
31
|
*
|
|
34
32
|
* createEffect({
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
33
|
+
* deps: [evenNumberSignal],
|
|
34
|
+
* run: () => {
|
|
35
|
+
* // This effect only runs for even numbers.
|
|
36
|
+
* // The value can be `undefined` on the first run if initialValue is not even.
|
|
37
|
+
* if (evenNumberSignal.get() !== undefined) {
|
|
38
|
+
* console.log(`Even number detected: ${evenNumberSignal.get()}`);
|
|
39
|
+
* }
|
|
40
|
+
* },
|
|
41
|
+
* runImmediately: true,
|
|
44
42
|
* });
|
|
45
43
|
* // Logs: "Even number detected: 0"
|
|
46
44
|
*
|
|
47
45
|
* numberSignal.set(1); // Effect does not run
|
|
48
46
|
* numberSignal.set(2); // Logs: "Even number detected: 2"
|
|
47
|
+
* ```
|
|
49
48
|
*/
|
|
50
49
|
export function createFilteredSignal<T>(
|
|
51
50
|
sourceSignal: IReadonlySignal<T>,
|
|
52
51
|
predicate: (value: T) => boolean,
|
|
53
|
-
name = `${sourceSignal.name}
|
|
54
|
-
):
|
|
52
|
+
name = `${sourceSignal.name}_filtered`,
|
|
53
|
+
): IReadonlySignal<T | undefined> {
|
|
55
54
|
const sourceValue = sourceSignal.get();
|
|
56
55
|
const initialValue = predicate(sourceValue) ? sourceValue : undefined;
|
|
57
56
|
|
|
58
57
|
const internalSignal = createStateSignal({
|
|
59
|
-
name
|
|
58
|
+
name,
|
|
60
59
|
initialValue,
|
|
60
|
+
onDestroy() {
|
|
61
|
+
subscription.unsubscribe();
|
|
62
|
+
},
|
|
61
63
|
});
|
|
62
64
|
|
|
63
65
|
const subscription = sourceSignal.subscribe((newValue) => {
|
|
@@ -66,13 +68,5 @@ export function createFilteredSignal<T>(
|
|
|
66
68
|
}
|
|
67
69
|
});
|
|
68
70
|
|
|
69
|
-
return
|
|
70
|
-
name: name,
|
|
71
|
-
deps: [internalSignal],
|
|
72
|
-
get: () => internalSignal.get(),
|
|
73
|
-
onDestroy: () => {
|
|
74
|
-
subscription.unsubscribe();
|
|
75
|
-
internalSignal.destroy();
|
|
76
|
-
},
|
|
77
|
-
});
|
|
71
|
+
return internalSignal;
|
|
78
72
|
}
|
package/src/type.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type {Awaitable} from '@alwatr/type-helper';
|
|
2
1
|
import type {DebouncerConfig} from '@alwatr/debounce';
|
|
3
2
|
import type {LocalStorageProviderConfig} from '@alwatr/local-storage';
|
|
4
3
|
import type {SessionStorageProviderConfig} from '@alwatr/session-storage';
|
|
@@ -11,7 +10,7 @@ import type {SessionStorageProviderConfig} from '@alwatr/session-storage';
|
|
|
11
10
|
*
|
|
12
11
|
* @template T The type of the value that the signal holds or dispatches.
|
|
13
12
|
*/
|
|
14
|
-
export type ListenerCallback<T> = (value: T) =>
|
|
13
|
+
export type ListenerCallback<T> = (value: T) => void;
|
|
15
14
|
|
|
16
15
|
/**
|
|
17
16
|
* Options for fine-tuning the behavior of a subscription to a signal.
|
|
@@ -225,6 +224,23 @@ export interface ComputedSignalConfig<T> extends SignalConfig {
|
|
|
225
224
|
get: () => T;
|
|
226
225
|
}
|
|
227
226
|
|
|
227
|
+
/**
|
|
228
|
+
* Configuration for creating a `DerivedSignal`.
|
|
229
|
+
* @template S The type of the source signal state.
|
|
230
|
+
* @template T The type of the projected derived state.
|
|
231
|
+
*/
|
|
232
|
+
export interface DerivedSignalConfig<S, T> extends SignalConfig {
|
|
233
|
+
/**
|
|
234
|
+
* The single upstream readonly source signal.
|
|
235
|
+
*/
|
|
236
|
+
readonly source: IReadonlySignal<S>;
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Projection mapping function transforming source S to derived T.
|
|
240
|
+
*/
|
|
241
|
+
readonly projector: (value: S) => T;
|
|
242
|
+
}
|
|
243
|
+
|
|
228
244
|
/**
|
|
229
245
|
* Configuration for creating an `EffectSignal`.
|
|
230
246
|
*/
|
|
@@ -258,7 +274,7 @@ export interface EffectSignalConfig {
|
|
|
258
274
|
* run: () => console.log(`The counter is now: ${counter.get()}`),
|
|
259
275
|
* });
|
|
260
276
|
*/
|
|
261
|
-
run: () =>
|
|
277
|
+
run: () => void;
|
|
262
278
|
|
|
263
279
|
/**
|
|
264
280
|
* If `true`, the effect's `run` function will be executed once immediately upon initialization.
|
|
@@ -406,3 +422,55 @@ export interface SessionStateSignalConfig<T> extends StateSignalConfig<T>, Sessi
|
|
|
406
422
|
*/
|
|
407
423
|
saveDebounceDelay?: number;
|
|
408
424
|
}
|
|
425
|
+
|
|
426
|
+
/**
|
|
427
|
+
* Determines whether the payload argument for a given channel message is
|
|
428
|
+
* required or optional, based solely on the declared type in `TMap`.
|
|
429
|
+
*
|
|
430
|
+
* - `void | undefined` → payload is optional (second arg may be omitted).
|
|
431
|
+
* - anything else → payload is **required** (omitting it is a compile error).
|
|
432
|
+
*
|
|
433
|
+
* This is used to build the rest-parameter tuple for `dispatch()` so that
|
|
434
|
+
* TypeScript enforces the correct call signature at every dispatch site.
|
|
435
|
+
*
|
|
436
|
+
* @template TMap A record mapping message names to their payload types.
|
|
437
|
+
* @template K The specific message name key.
|
|
438
|
+
*
|
|
439
|
+
* @example
|
|
440
|
+
* ```ts
|
|
441
|
+
* // ActionRecord: { 'logout': void; 'add-to-cart': {productId: number} }
|
|
442
|
+
* type A = DispatchArgs<ActionRecord, 'logout'>; // [name: 'logout', payload?: void]
|
|
443
|
+
* type B = DispatchArgs<ActionRecord, 'add-to-cart'>; // [name: 'add-to-cart', payload: {productId: number}]
|
|
444
|
+
* ```
|
|
445
|
+
*/
|
|
446
|
+
export type DispatchArgs<TMap extends object, K extends keyof TMap> =
|
|
447
|
+
TMap[K] extends void | undefined ? [name: K, payload?: TMap[K]] : [name: K, payload: TMap[K]];
|
|
448
|
+
|
|
449
|
+
/**
|
|
450
|
+
* A single message dispatched through a `ChannelSignal`.
|
|
451
|
+
*
|
|
452
|
+
* `name` identifies the message type (e.g. `'open-drawer'`, `'add-to-cart'`).
|
|
453
|
+
* `payload` carries the associated data, whose type is determined by the generic `TMap` based on the `name`.
|
|
454
|
+
*
|
|
455
|
+
* @template TMap A record mapping message names to their payload types.
|
|
456
|
+
* @template K The specific message name key (inferred, not set manually).
|
|
457
|
+
*/
|
|
458
|
+
export type ChannelMessage<TMap extends object, K extends keyof TMap = keyof TMap> = {name: K; payload: TMap[K]};
|
|
459
|
+
|
|
460
|
+
/**
|
|
461
|
+
* A typed handler for a specific named message on a `ChannelSignal`.
|
|
462
|
+
* Receives only the `payload` — the name is already known at subscription time.
|
|
463
|
+
*
|
|
464
|
+
* The payload type mirrors `DispatchArgs`: it is `TMap[K] | undefined` only
|
|
465
|
+
* when the declared type is `void | undefined`; otherwise it is exactly `TMap[K]`
|
|
466
|
+
* (non-optional) so handlers do not need unnecessary null-guards.
|
|
467
|
+
*
|
|
468
|
+
* @template TMap A record mapping message names to their payload types.
|
|
469
|
+
* @template K The specific message name key.
|
|
470
|
+
*/
|
|
471
|
+
export type ChannelHandler<TMap extends object, K extends keyof TMap = keyof TMap> = (payload: TMap[K]) => void;
|
|
472
|
+
|
|
473
|
+
/**
|
|
474
|
+
* Configuration for creating a `ChannelSignal`.
|
|
475
|
+
*/
|
|
476
|
+
export interface ChannelSignalConfig extends SignalConfig {}
|
package/dist/operators/map.d.ts
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import type { ComputedSignal } from '../core/computed-signal.js';
|
|
2
|
-
import type { IReadonlySignal } from '../type.js';
|
|
3
|
-
/**
|
|
4
|
-
* Creates a new read-only computed signal that transforms the value of a source
|
|
5
|
-
* signal using a projection function.
|
|
6
|
-
*
|
|
7
|
-
* This operator is analogous to `Array.prototype.map`. It applies a function to
|
|
8
|
-
* each value emitted by the source signal and emits the result.
|
|
9
|
-
*
|
|
10
|
-
* @template T The type of the source signal's value.
|
|
11
|
-
* @template R The type of the projected value.
|
|
12
|
-
*
|
|
13
|
-
* @param sourceSignal The original signal to transform.
|
|
14
|
-
* @param projectFunction A function to apply to each value from the source signal.
|
|
15
|
-
* @param [name] An optional, unique identifier for the new signal for debugging. default: `${sourceSignal.name}-mapped`
|
|
16
|
-
*
|
|
17
|
-
* @returns A new, read-only computed signal with the transformed values.
|
|
18
|
-
*
|
|
19
|
-
* @example
|
|
20
|
-
* const userSignal = createStateSignal({
|
|
21
|
-
* name: 'user',
|
|
22
|
-
* initialValue: { name: 'John', age: 30 },
|
|
23
|
-
* });
|
|
24
|
-
*
|
|
25
|
-
* const userNameSignal = createMappedSignal(
|
|
26
|
-
* userSignal,
|
|
27
|
-
* (user) => user.name,
|
|
28
|
-
* );
|
|
29
|
-
*
|
|
30
|
-
* console.log(userNameSignal.get()); // Outputs: "John"
|
|
31
|
-
* // in next macro-task ...
|
|
32
|
-
* userSignal.set({ name: 'Jane', age: 32 });
|
|
33
|
-
* console.log(userNameSignal.get()); // Outputs: "Jane"
|
|
34
|
-
*/
|
|
35
|
-
export declare function createMappedSignal<T, R>(sourceSignal: IReadonlySignal<T>, projectFunction: (value: T) => R, name?: string): ComputedSignal<R>;
|
|
36
|
-
//# sourceMappingURL=map.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"map.d.ts","sourceRoot":"","sources":["../../src/operators/map.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,4BAA4B,CAAC;AAC/D,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,YAAY,CAAC;AAEhD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,CAAC,EACrC,YAAY,EAAE,eAAe,CAAC,CAAC,CAAC,EAChC,eAAe,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,EAChC,IAAI,SAAgC,GACnC,cAAc,CAAC,CAAC,CAAC,CAMnB"}
|
package/src/operators/map.ts
DELETED
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import {createComputedSignal} from '../creators/computed.js';
|
|
2
|
-
|
|
3
|
-
import type {ComputedSignal} from '../core/computed-signal.js';
|
|
4
|
-
import type {IReadonlySignal} from '../type.js';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Creates a new read-only computed signal that transforms the value of a source
|
|
8
|
-
* signal using a projection function.
|
|
9
|
-
*
|
|
10
|
-
* This operator is analogous to `Array.prototype.map`. It applies a function to
|
|
11
|
-
* each value emitted by the source signal and emits the result.
|
|
12
|
-
*
|
|
13
|
-
* @template T The type of the source signal's value.
|
|
14
|
-
* @template R The type of the projected value.
|
|
15
|
-
*
|
|
16
|
-
* @param sourceSignal The original signal to transform.
|
|
17
|
-
* @param projectFunction A function to apply to each value from the source signal.
|
|
18
|
-
* @param [name] An optional, unique identifier for the new signal for debugging. default: `${sourceSignal.name}-mapped`
|
|
19
|
-
*
|
|
20
|
-
* @returns A new, read-only computed signal with the transformed values.
|
|
21
|
-
*
|
|
22
|
-
* @example
|
|
23
|
-
* const userSignal = createStateSignal({
|
|
24
|
-
* name: 'user',
|
|
25
|
-
* initialValue: { name: 'John', age: 30 },
|
|
26
|
-
* });
|
|
27
|
-
*
|
|
28
|
-
* const userNameSignal = createMappedSignal(
|
|
29
|
-
* userSignal,
|
|
30
|
-
* (user) => user.name,
|
|
31
|
-
* );
|
|
32
|
-
*
|
|
33
|
-
* console.log(userNameSignal.get()); // Outputs: "John"
|
|
34
|
-
* // in next macro-task ...
|
|
35
|
-
* userSignal.set({ name: 'Jane', age: 32 });
|
|
36
|
-
* console.log(userNameSignal.get()); // Outputs: "Jane"
|
|
37
|
-
*/
|
|
38
|
-
export function createMappedSignal<T, R>(
|
|
39
|
-
sourceSignal: IReadonlySignal<T>,
|
|
40
|
-
projectFunction: (value: T) => R,
|
|
41
|
-
name = `${sourceSignal.name}-mapped`,
|
|
42
|
-
): ComputedSignal<R> {
|
|
43
|
-
return createComputedSignal({
|
|
44
|
-
name: name,
|
|
45
|
-
deps: [sourceSignal],
|
|
46
|
-
get: () => projectFunction(sourceSignal.get()),
|
|
47
|
-
});
|
|
48
|
-
}
|