easy-signal 3.0.3 → 3.0.4

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.
@@ -49,3 +49,4 @@ export function eventSignal() {
49
49
  }
50
50
  return signal;
51
51
  }
52
+ //# sourceMappingURL=eventSignal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eventSignal.js","sourceRoot":"","sources":["../src/eventSignal.ts"],"names":[],"mappings":"AAiBA,MAAM,CAAC,MAAM,WAAW,GAAG,MAAM,EAAE,CAAC;AACpC,MAAM,CAAC,MAAM,WAAW,GAAG,MAAM,EAAE,CAAC;AACpC,MAAM,CAAC,MAAM,SAAS,GAAG,MAAM,EAAE,CAAC;AAElC;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,WAAW;IACzB,MAAM,WAAW,GAAG,IAAI,GAAG,EAAyB,CAAC;IACrD,MAAM,cAAc,GAAG,IAAI,GAAG,EAAyB,CAAC;IAExD,SAAS,QAAQ,CAAC,UAA+B,EAAE,IAAuB;QACxE,MAAM,SAAS,GAAG,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,WAAW,CAAC;QACpE,SAAS,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QAC1B,OAAO,GAAG,EAAE;YACV,SAAS,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QAC/B,CAAC,CAAC;IACJ,CAAC;IAQD,SAAS,MAAM,CAAC,GAAG,IAAW;QAC5B,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QACpB,IAAI,OAAO,GAAG,KAAK,UAAU,EAAE;YAC7B,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC;SACtB;aAAM,IAAI,GAAG,KAAK,WAAW,EAAE;YAC9B,WAAW,CAAC,KAAK,EAAE,CAAC;YACpB,cAAc,CAAC,KAAK,EAAE,CAAC;SACxB;aAAM,IAAI,GAAG,KAAK,WAAW,EAAE;YAC9B,OAAO,QAAuB,CAAC;SAChC;aAAM,IAAI,GAAG,YAAY,KAAK,EAAE;YAC/B,cAAc,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;SACnD;aAAM;YACL,WAAW,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC;SACpD;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -1,3 +1,4 @@
1
1
  export * from './eventSignal';
2
2
  export * from './reactiveSignal';
3
3
  export * from './signalStore';
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC;AACjC,cAAc,eAAe,CAAC"}
@@ -208,3 +208,4 @@ export function computedSignal(fn, when) {
208
208
  // Return the signal
209
209
  return computed;
210
210
  }
211
+ //# sourceMappingURL=reactiveSignal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reactiveSignal.js","sourceRoot":"","sources":["../src/reactiveSignal.ts"],"names":[],"mappings":"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"}
@@ -11,3 +11,4 @@ export function signalStore(signal) {
11
11
  subscribe: (sub) => subscribe(signal, sub),
12
12
  };
13
13
  }
14
+ //# sourceMappingURL=signalStore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"signalStore.js","sourceRoot":"","sources":["../src/signalStore.ts"],"names":[],"mappings":"AAAA,OAAO,EAA4C,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAEvF;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAI,MAAyB;IACtD,OAAO;QACL,GAAG,EAAE,MAAM;QACX,GAAG,EAAE,MAAM;QACX,MAAM,EAAE,MAAM;QACd,SAAS,EAAE,CAAC,GAAgC,EAAE,EAAE,CAAC,SAAS,CAAC,MAAM,EAAE,GAAG,CAAC;KACxE,CAAC;AACJ,CAAC"}
package/package.json CHANGED
@@ -1,11 +1,14 @@
1
1
  {
2
2
  "name": "easy-signal",
3
- "version": "3.0.3",
3
+ "version": "3.0.4",
4
4
  "description": "A tiny (25 LOC), simple utility for alerting subscribers when an event happens, allowing for error handling and clearing.",
5
- "main": "index.js",
5
+ "files": [
6
+ "dist"
7
+ ],
8
+ "main": "dist/index.js",
6
9
  "scripts": {
7
10
  "build": "tsc",
8
- "prepare": "tsc",
11
+ "watch": "tsc --watch",
9
12
  "prepublishOnly": "tsc"
10
13
  },
11
14
  "repository": {
package/.gitattributes DELETED
@@ -1,2 +0,0 @@
1
- # Auto detect text files and perform LF normalization
2
- * text=auto
package/.prettierrc.cjs DELETED
@@ -1,8 +0,0 @@
1
- module.exports = {
2
- printWidth: 120,
3
- singleQuote: true,
4
- trailingComma: 'es5',
5
- semi: true,
6
- bracketSpacing: true,
7
- arrowParens: 'avoid',
8
- };
@@ -1,18 +0,0 @@
1
- {
2
- "[typescript]": {
3
- "editor.defaultFormatter": "esbenp.prettier-vscode"
4
- },
5
- "[json]": {
6
- "editor.defaultFormatter": "esbenp.prettier-vscode"
7
- },
8
- "eslint.format.enable": true,
9
- "editor.codeActionsOnSave": {
10
- "source.organizeImports": "explicit"
11
- },
12
- "editor.formatOnSave": true,
13
- "eslint.validate": [
14
- "javascript",
15
- "javascriptreact",
16
- "svelte"
17
- ]
18
- }
package/eventSignal.ts DELETED
@@ -1,74 +0,0 @@
1
- type Args<T> = T extends (...args: infer A) => any ? A : never;
2
- export type EventSignalSubscriber = (...args: any[]) => any;
3
- export type ErrorSubscriber = (error: Error) => any;
4
- export type Unsubscriber = () => void;
5
-
6
- export type OnSignal<T extends EventSignalSubscriber = EventSignalSubscriber> = {
7
- (subscriber: T): Unsubscriber;
8
- (errorListener: ErrorSubscriber, what: typeof ForErrors): Unsubscriber;
9
- };
10
-
11
- export type EventSignal<T extends EventSignalSubscriber = EventSignalSubscriber> = OnSignal<T> & {
12
- (...args: Args<T>): void;
13
- (data: Error): void;
14
- (data: typeof ClearSignal): void;
15
- (data: typeof GetOnSignal): OnSignal<T>;
16
- };
17
-
18
- export const ClearSignal = Symbol();
19
- export const GetOnSignal = Symbol();
20
- export const ForErrors = Symbol();
21
-
22
- /**
23
- * Creates a signal, a function that can be used to subscribe to events. The signal can be called with a subscriber
24
- * function, which will be called when the signal is dispatched. The signal can also be called with data, which will
25
- * dispatch to all subscribers. An optional second argument can be passed to subscribe to errors instead. When the
26
- * signal is called with an instance of Error, it will dispatch to all error listeners.
27
- * The signal can also be called with `ClearSignal`, which will clear all subscribers.
28
- * @example
29
- * const onLoad = signal();
30
- *
31
- * // Subscribe to data
32
- * onLoad((data) => console.log('loaded', data));
33
- * onLoad((error) => console.error('error', error), true);
34
- *
35
- * // Dispatch data
36
- * onLoad('data'); // logs 'loaded data'
37
- * onLoad(new Error('error')); // logs 'error Error: error'
38
- */
39
- export function eventSignal<T extends EventSignalSubscriber = EventSignalSubscriber>(): EventSignal<T> {
40
- const subscribers = new Set<EventSignalSubscriber>();
41
- const errorListeners = new Set<EventSignalSubscriber>();
42
-
43
- function onSignal(subscriber: T | ErrorSubscriber, what?: typeof ForErrors): Unsubscriber {
44
- const listeners = what === ForErrors ? errorListeners : subscribers;
45
- listeners.add(subscriber);
46
- return () => {
47
- listeners.delete(subscriber);
48
- };
49
- }
50
-
51
- function signal(...args: Args<T>): void;
52
- function signal(error: Error): void;
53
- function signal(data: typeof ClearSignal): void;
54
- function signal(data: typeof GetOnSignal): OnSignal<T>;
55
- function signal(subscriber: T): Unsubscriber;
56
- function signal(errorListener: EventSignalSubscriber, what: typeof ForErrors): Unsubscriber;
57
- function signal(...args: any[]): Unsubscriber | OnSignal<T> | void {
58
- const arg = args[0];
59
- if (typeof arg === 'function') {
60
- return onSignal(arg);
61
- } else if (arg === ClearSignal) {
62
- subscribers.clear();
63
- errorListeners.clear();
64
- } else if (arg === GetOnSignal) {
65
- return onSignal as OnSignal<T>;
66
- } else if (arg instanceof Error) {
67
- errorListeners.forEach(listener => listener(arg));
68
- } else {
69
- subscribers.forEach(listener => listener(...args));
70
- }
71
- }
72
-
73
- return signal;
74
- }
package/index.ts DELETED
@@ -1,3 +0,0 @@
1
- export * from './eventSignal';
2
- export * from './reactiveSignal';
3
- export * from './signalStore';
package/reactiveSignal.ts DELETED
@@ -1,311 +0,0 @@
1
- // The options for a Signal
2
- export interface SignalOptions<T> {
3
- equals?: false | ((prev: T, next: T) => boolean);
4
- }
5
-
6
- // The types for an unsubscribe and cancel function
7
- export type Unsubscribe = () => void;
8
- export type Cancel = () => void;
9
-
10
- // Different timings for when to execute an observer observing a signal
11
- export const Timing = {
12
- // Execute the function on the next tick of the event loop
13
- Tick: (fn: () => void) => {
14
- Promise.resolve(fn);
15
- },
16
- // Execute the function on the next animation frame
17
- AnimationFrame: (fn: () => void) => {
18
- (globalThis as any).requestAnimationFrame(fn);
19
- },
20
- };
21
-
22
- // The context for the current run and its unsubscribes
23
- let context: { subscriber: ReactiveSignalSubscriber<any>; unsubscribes: Set<Unsubscribe> } | null = null;
24
-
25
- // A map to keep track of listeners to subscription changes
26
- const onSubscriptionChanges = new WeakMap<ReactiveSignal<any>, Set<SubscriptionChange>>();
27
-
28
- /**
29
- * A Signal is a single getter/setter function that holds a value and notifies subscribers when the value changes
30
- * The signal function can be called with no arguments to get the current value, with a function argument to run an
31
- * update function which should receive the value and return a new one, or with a value argument which will replace the
32
- * signal's current value. The signal function always returns the current value.
33
- *
34
- * The optional second argument, `set`, can be used to force the first argument as the new value. This is useful when
35
- * the first argument is a function or `undefined` since the signal will assume any function is an updater function and
36
- * any `undefined` value is a request to get the current value.
37
- */
38
- export type ReactiveSignal<T> = {
39
- (): T;
40
- (value: T | ReactiveSignalUpdater<T>, set?: false): T;
41
- (value: T, set: true): T;
42
- };
43
-
44
- /**
45
- * A Computed Signal is a signal that is the result of a function that depends on other signals. The function is called
46
- * whenever the computed signal is accessed if there are no subscribers, or whenever its dependent signals change if
47
- * there are subscribers so that subscribers to the computed signal can be informed.
48
- */
49
- export type ComputedSignal<T> = () => T;
50
-
51
- /**
52
- * A Signal Subscriber is a function that will be called whenever the signal's value changes. The subscriber will be
53
- * called with the new value. The subscriber can be used to update the DOM or trigger other side effects.
54
- */
55
- export type ReactiveSignalSubscriber<T> = (value: T) => void;
56
-
57
- /**
58
- * A Signal Updater is a function that will be called with the current value of the signal and should return a new
59
- * value. The updater can be used to update the signal's value based on its current value.
60
- */
61
- export type ReactiveSignalUpdater<T> = (prev: T) => T;
62
-
63
- /**
64
- * An Observer is a function that will be called whenever any of the signals it depends on change. The observer can be
65
- * used to update the DOM or trigger other side effects.
66
- * The observer will be called immediately (or after certain a timing option) and whenever any of the signals it depends
67
- * on change.
68
- */
69
- export type ReactiveSignalObserver = () => void;
70
-
71
- /**
72
- * A Timing is a function that will be called with a function to execute. The timing function should execute the passed
73
- * function at some point in the future. The default timing is `Timing.Immediate` which executes the function
74
- * immediately.
75
- */
76
- export type Timing = (fn: () => void) => void;
77
-
78
- /**
79
- * A Subscription Change is a function that will be called whenever the signal's subscribers changes from none to some
80
- * or some to none. The subscription change will be called with a boolean indicating whether there are any subscribers.
81
- */
82
- export type SubscriptionChange = (hasSubscribers: boolean) => void;
83
-
84
- /**
85
- * Create a Signal with an initial value and optional options. The options can include an `equals` function which will
86
- * be used to determine if the new value is different from the current value. If the new value is different, the signal
87
- * will be updated and all subscribers will be notified.
88
- * The returned signal function can be called with no arguments to get the current value, with a function argument to
89
- * run an update function which should receive the value and return a new one, or with a value argument which will
90
- * replace the signal's current value. The signal function always returns the current value.
91
- */
92
- export function reactiveSignal<T>(value: T, options?: SignalOptions<T>): ReactiveSignal<T> {
93
- // A map to keep track of subscribers
94
- const subscribers = new Map<ReactiveSignalSubscriber<T>, Unsubscribe>();
95
-
96
- // The signal is a function that will return a value when called without arguments, or update the value when called
97
- // with an argument. The update value can be a new value or an updater function.
98
- const signal = ((newValue?: T | ReactiveSignalUpdater<T>, set?: boolean) => {
99
- // If no new value is provided, subscribe the current run to this signal and return the current value
100
- if (!set && newValue === undefined) {
101
- // If there is a context (an observer is running), add the observer's subscriber to the signal
102
- if (context) {
103
- const { subscriber: run, unsubscribes } = context;
104
- let unsubscribe = subscribers.get(run);
105
-
106
- // If the run is not already subscribed, subscribe it
107
- if (!unsubscribe) {
108
- // Create the unsubscribe function
109
- unsubscribe = () => {
110
- subscribers.delete(run);
111
-
112
- // If there are no more subscribers, notify the subscription changes
113
- if (subscribers.size === 0) {
114
- const onChanges = onSubscriptionChanges.get(signal);
115
- if (onChanges) onChanges.forEach(onChange => onChange(false));
116
- }
117
- };
118
-
119
- // Add the unsubscribe function to the signal's subscribers
120
- subscribers.set(run, unsubscribe);
121
-
122
- // If this changed the number of subscribers from 0 to 1, notify any subscription change subscribers
123
- if (subscribers.size === 1) {
124
- const onChanges = onSubscriptionChanges.get(signal);
125
- if (onChanges) onChanges.forEach(onChange => onChange(true));
126
- }
127
- }
128
-
129
- // Add the unsubscribe function to the run's unsubscribes
130
- unsubscribes.add(unsubscribe);
131
- }
132
-
133
- // Return the current value
134
- return value;
135
- }
136
-
137
- // If the new value is a function, call it with the current value as an argument
138
- if (!set && typeof newValue === 'function') {
139
- newValue = (newValue as ReactiveSignalUpdater<T>)(value);
140
- }
141
-
142
- // If the new value is different from the current value (according to the equals function if provided), update the
143
- // value and notify all subscribers
144
- if (options?.equals ? !options.equals(value!, newValue as T) : value !== newValue) {
145
- value = newValue as T;
146
- subscribers.forEach((_, run) => run(value!));
147
- }
148
- return value;
149
- }) as ReactiveSignal<T>;
150
-
151
- // Return the signal function
152
- return signal;
153
- }
154
-
155
- /**
156
- * Subscribe to be notified whenever a Signal's value changes. The Subscriber function will be called immediately with
157
- * the current value of the Signal and again whenever the Signal's value changes.
158
- *
159
- * The optional third argument, `timing`, can be used to specify when the function should be called. The default is
160
- * `Timing.Immediate` which executes the function immediately.
161
- *
162
- * The returned function can be called to unsubscribe from the Signal.
163
- */
164
- export function subscribe<T>(
165
- signal: ReactiveSignal<T>,
166
- subscriber: ReactiveSignalSubscriber<T>,
167
- timing: Timing | null = Timing.Tick
168
- ): Unsubscribe {
169
- if (timing) {
170
- let queued = false;
171
- const subFn = subscriber;
172
- subscriber = () => {
173
- if (!queued) {
174
- queued = true;
175
- timing(() => {
176
- queued = false;
177
- subFn(signal());
178
- });
179
- }
180
- };
181
- }
182
-
183
- // Set the current context so we can get the unsubscribe
184
- context = { subscriber, unsubscribes: new Set() };
185
-
186
- // Get the current value of the signal
187
- const value = signal();
188
-
189
- // Get the unsubscribe function for the subscriber
190
- const unsubscribe = context.unsubscribes.values().next().value;
191
-
192
- // Clear the current context
193
- context = null;
194
-
195
- // Call the subscriber with the current value
196
- subscriber(value);
197
-
198
- // Return the unsubscribe function
199
- return unsubscribe;
200
- }
201
-
202
- /**
203
- * Get notified when a Signal's subscribers changes from none to some or some to none.
204
- */
205
- export function onSubscriptionChange(
206
- signal: ReactiveSignal<any>,
207
- onChange: (hasSubscribers: boolean) => void
208
- ): Unsubscribe {
209
- // Get the set of onChange functions for the signal
210
- let onChanges = onSubscriptionChanges.get(signal);
211
-
212
- // If there is no set, create one and add it to the map
213
- if (!onChanges) onSubscriptionChanges.set(signal, (onChanges = new Set()));
214
-
215
- // Add the onChange function to the set
216
- onChanges.add(onChange);
217
-
218
- // Return a function that removes the onChange function from the set
219
- return () => {
220
- onChanges!.delete(onChange);
221
- };
222
- }
223
-
224
- /**
225
- * Calls an Observer function after Timing amount of time (default is immediate, but can be on the next tick or the next
226
- * animation frame) and again after Timing whenever any of the signals it depends on change.
227
- * The Observer function will be called immediately (or after the timing) and again whenever any of the signals it
228
- * depends on change.
229
- * The returned function can be called to unsubscribe from the signals that are called when the effect is run.
230
- *
231
- * The optional second argument, `timing`, can be used to specify when the function should be called. The default is
232
- * undefined which executes the function immediately.
233
- */
234
- export function observe(fn: ReactiveSignalObserver, timing?: Timing): Unsubscribe {
235
- let dirty = true;
236
- let unsubscribes = new Set<Unsubscribe>();
237
-
238
- // Subscribe to all the signals that are called when the effect is run
239
- const subscriber = () => {
240
- if (dirty) return;
241
- dirty = true;
242
- if (timing) timing(() => onChange());
243
- else onChange();
244
- };
245
-
246
- // Called immediately and whenever any of the signals it depends on change (after the timing)
247
- const onChange = () => {
248
- if (!dirty) return;
249
- dirty = false;
250
-
251
- // Set the context for the effect
252
- context = { subscriber, unsubscribes: new Set() };
253
-
254
- // Run the effect collecting all the unsubscribes from the signals that are called when it is run
255
- fn();
256
-
257
- // Filter out unchanged unsubscribes, leaving only those which no longer apply
258
- context.unsubscribes.forEach(u => unsubscribes.delete(u));
259
-
260
- // Unsubscribe from all the signals that are no longer needed
261
- unsubscribes.forEach(u => u());
262
-
263
- // Set the new unsubscribes
264
- unsubscribes = context.unsubscribes;
265
-
266
- // Clear the context
267
- context = null;
268
- };
269
-
270
- // Call immediately (or on the next timing)
271
- if (timing) timing(() => onChange());
272
- else onChange();
273
-
274
- // Return a function that unsubscribes from all the signals that are called when the effect is run
275
- return () => unsubscribes.forEach(u => u());
276
- }
277
-
278
- /**
279
- * Create a Computed Signal which is a signal that is the result of a function that depends on other signals. The
280
- * function is called immediately whenever the computed signal is accessed if there are no subscribers, or whenever its
281
- * dependent signals change if there are subscribers so that subscribers to the computed signal can be informed.
282
- *
283
- * The optional second argument, `when`, can be used to specify when updater function should be called. The default is
284
- * undefined which executes the function immediately after any change to any signal it relies on. This can
285
- * prevent unnecessary updates if the function is expensive to run.
286
- */
287
- export function computedSignal<T>(fn: ReactiveSignalUpdater<T>, when?: Timing): ComputedSignal<T> {
288
- // Create the signal
289
- const signal = reactiveSignal<T>(undefined as T);
290
-
291
- // Store the unsubscribe function from the observer. We will only observe the function when there are subscribers to
292
- // this computed signal.
293
- let unsubscribe: Unsubscribe | null = null;
294
-
295
- // Subscribe to the signal's subscription changes so we know when to start and stop observing
296
- onSubscriptionChange(signal, hasSubscribers => {
297
- // If there are subscribers, start observing the function
298
- if (hasSubscribers) {
299
- if (!unsubscribe) unsubscribe = observe(() => signal(fn), when);
300
- } else if (unsubscribe) {
301
- // If there are no subscribers, stop observing the function
302
- unsubscribe();
303
- unsubscribe = null;
304
- }
305
- });
306
-
307
- const computed = () => (unsubscribe ? signal() : signal(fn));
308
-
309
- // Return the signal
310
- return computed;
311
- }
package/signalStore.ts DELETED
@@ -1,14 +0,0 @@
1
- import { ReactiveSignal, ReactiveSignalSubscriber, subscribe } from './reactiveSignal';
2
-
3
- /**
4
- * A store wrapper around a reactive signal. The store can be used to get, set, update, and subscribe to the signal.
5
- * This is for use in Svelte 3-4.
6
- */
7
- export function signalStore<T>(signal: ReactiveSignal<T>) {
8
- return {
9
- get: signal,
10
- set: signal,
11
- update: signal,
12
- subscribe: (sub: ReactiveSignalSubscriber<T>) => subscribe(signal, sub),
13
- };
14
- }
package/tsconfig.json DELETED
@@ -1,16 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "target": "es2021",
4
- "declaration": true,
5
- "moduleResolution": "node",
6
- "esModuleInterop": true,
7
- "allowJs": true,
8
- "allowSyntheticDefaultImports": true,
9
- "isolatedModules": true,
10
- "lib": [
11
- "es2021"
12
- ],
13
- "resolveJsonModule": true
14
- },
15
- "exclude": ["node_modules"]
16
- }
File without changes
File without changes
File without changes