@alwatr/signal 9.11.2 → 9.13.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 +377 -0
- package/dist/core/channel-signal.d.ts +177 -0
- package/dist/core/channel-signal.d.ts.map +1 -0
- package/dist/core/signal-base.d.ts +1 -0
- package/dist/core/signal-base.d.ts.map +1 -1
- package/dist/creators/channel.d.ts +39 -0
- package/dist/creators/channel.d.ts.map +1 -0
- package/dist/main.d.ts +2 -0
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +3 -3
- package/dist/main.js.map +6 -4
- package/package.json +2 -2
- package/src/core/channel-signal.ts +263 -0
- package/src/core/signal-base.ts +24 -7
- package/src/creators/channel.ts +44 -0
- package/src/main.ts +2 -0
package/src/core/signal-base.ts
CHANGED
|
@@ -135,6 +135,8 @@ export abstract class SignalBase<T> {
|
|
|
135
135
|
}
|
|
136
136
|
}
|
|
137
137
|
|
|
138
|
+
private pendingRejects__ = new Set<(reason?: any) => void>();
|
|
139
|
+
|
|
138
140
|
/**
|
|
139
141
|
* Returns a Promise that resolves with the next value dispatched by the signal.
|
|
140
142
|
* This provides an elegant way to wait for a single, future event using `async/await`.
|
|
@@ -151,12 +153,19 @@ export abstract class SignalBase<T> {
|
|
|
151
153
|
public untilNext(): Promise<T> {
|
|
152
154
|
this.logger_.logMethod?.('untilNext');
|
|
153
155
|
this.checkDestroyed_();
|
|
154
|
-
return new Promise((resolve) => {
|
|
155
|
-
this.
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
156
|
+
return new Promise((resolve, reject) => {
|
|
157
|
+
this.pendingRejects__.add(reject);
|
|
158
|
+
this.subscribe(
|
|
159
|
+
(value) => {
|
|
160
|
+
this.pendingRejects__.delete(reject);
|
|
161
|
+
resolve(value);
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
once: true,
|
|
165
|
+
priority: true, // Resolve the promise before other listeners are called.
|
|
166
|
+
receivePrevious: false, // We only want the *next* value, not the current one.
|
|
167
|
+
},
|
|
168
|
+
);
|
|
160
169
|
});
|
|
161
170
|
}
|
|
162
171
|
|
|
@@ -173,7 +182,15 @@ export abstract class SignalBase<T> {
|
|
|
173
182
|
this.logger_.incident?.('destroy_', 'double_destroy_attempt');
|
|
174
183
|
return;
|
|
175
184
|
}
|
|
176
|
-
this.isDestroyed__ = true;
|
|
185
|
+
this.isDestroyed__ = true; // Mark the signal as destroyed.
|
|
186
|
+
// Reject all pending promises.
|
|
187
|
+
if (this.pendingRejects__.size) {
|
|
188
|
+
const error = new Error('signal_destroyed');
|
|
189
|
+
for (const reject of this.pendingRejects__) {
|
|
190
|
+
reject(error);
|
|
191
|
+
}
|
|
192
|
+
this.pendingRejects__.clear(); // Clear all pending rejects.
|
|
193
|
+
}
|
|
177
194
|
this.priorityObservers_.clear(); // Clear all priority observers.
|
|
178
195
|
this.observers_.clear(); // Clear all normal observers.
|
|
179
196
|
this.config_.onDestroy?.(); // Call the optional onDestroy callback.
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import {ChannelSignal} from '../core/channel-signal.js';
|
|
2
|
+
|
|
3
|
+
import type {ChannelSignalConfig} from '../core/channel-signal.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Creates a stateless multi-channel signal that acts as a typed message bus.
|
|
7
|
+
*
|
|
8
|
+
* `ChannelSignal` is ideal when you need a single signal to carry multiple
|
|
9
|
+
* distinct message types — each identified by a `name` — rather than creating
|
|
10
|
+
* a separate `EventSignal` for every event.
|
|
11
|
+
*
|
|
12
|
+
* The generic parameter `TMap` is a record that maps every valid message name
|
|
13
|
+
* to its payload type, giving you full type safety at both dispatch and subscribe sites.
|
|
14
|
+
*
|
|
15
|
+
* @template TMap A record mapping message names to their payload types.
|
|
16
|
+
*
|
|
17
|
+
* @param config The configuration for the channel signal.
|
|
18
|
+
* @returns A new instance of `ChannelSignal`.
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```ts
|
|
22
|
+
* interface AppMessages {
|
|
23
|
+
* 'open-drawer': {panel: string};
|
|
24
|
+
* 'close-drawer': void;
|
|
25
|
+
* 'show-toast': {message: string; type: 'info' | 'error'};
|
|
26
|
+
* }
|
|
27
|
+
*
|
|
28
|
+
* const appChannel = createChannelSignal<AppMessages>({name: 'app-channel'});
|
|
29
|
+
*
|
|
30
|
+
* // Subscribe to a specific message
|
|
31
|
+
* appChannel.on('show-toast', (payload) => {
|
|
32
|
+
* toast.show(payload!.message, payload!.type);
|
|
33
|
+
* });
|
|
34
|
+
*
|
|
35
|
+
* // Dispatch a message
|
|
36
|
+
* appChannel.dispatch('show-toast', {message: 'Saved!', type: 'info'});
|
|
37
|
+
* appChannel.dispatch('close-drawer');
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
export function createChannelSignal<TMap extends Record<string, unknown>>(
|
|
41
|
+
config: ChannelSignalConfig,
|
|
42
|
+
): ChannelSignal<TMap> {
|
|
43
|
+
return new ChannelSignal<TMap>(config);
|
|
44
|
+
}
|
package/src/main.ts
CHANGED
|
@@ -5,6 +5,7 @@ export * from './core/computed-signal.js';
|
|
|
5
5
|
export * from './core/effect-signal.js';
|
|
6
6
|
export * from './core/persistent-state-signal.js';
|
|
7
7
|
export * from './core/session-state-signal.js';
|
|
8
|
+
export * from './core/channel-signal.js';
|
|
8
9
|
|
|
9
10
|
export * from './creators/event.js';
|
|
10
11
|
export * from './creators/state.js';
|
|
@@ -12,6 +13,7 @@ export * from './creators/computed.js';
|
|
|
12
13
|
export * from './creators/effect.js';
|
|
13
14
|
export * from './creators/persistent-state.js';
|
|
14
15
|
export * from './creators/session-state.js';
|
|
16
|
+
export * from './creators/channel.js';
|
|
15
17
|
|
|
16
18
|
export * from './operators/debounce.js';
|
|
17
19
|
export * from './operators/filter.js';
|