@axijs/emitter 1.0.0 → 1.1.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 +61 -27
- package/dist/index.d.mts +26 -18
- package/dist/index.d.ts +26 -18
- package/dist/index.js +23 -19
- package/dist/index.mjs +23 -19
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -19,9 +19,10 @@ yarn add @axijs/emitter
|
|
|
19
19
|
|
|
20
20
|
## Features
|
|
21
21
|
|
|
22
|
-
- **Strictly Typed**: Full TypeScript support for
|
|
22
|
+
- **Strictly Typed**: Full TypeScript support for emitted values.
|
|
23
23
|
- **No Magic Strings**: Object-based emitters instead of string keys (e.g., `on('event-name')`).
|
|
24
24
|
- **State Emitting**: `StateEmitter` remembers the last emitted value and immediately triggers new subscribers.
|
|
25
|
+
- **Distinct Updates**: `StateEmitter` can optionally skip emitting unchanged values.
|
|
25
26
|
- **Composite Subscriptions**: Easily group multiple subscriptions and teardown logic into a single `Subscription` object to prevent memory leaks.
|
|
26
27
|
|
|
27
28
|
## Usage
|
|
@@ -32,23 +33,18 @@ Create an isolated, strongly-typed event emitter.
|
|
|
32
33
|
```typescript
|
|
33
34
|
import { Emitter } from '@axijs/emitter';
|
|
34
35
|
|
|
35
|
-
|
|
36
|
-
const onPlayerMove = new Emitter<[string, number]>();
|
|
36
|
+
const onPlayerMove = new Emitter<string>();
|
|
37
37
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
console.log(`${player} moved to ${x}`);
|
|
38
|
+
const sub = onPlayerMove.subscribe((player) => {
|
|
39
|
+
console.log(`Player moved: ${player}`);
|
|
41
40
|
});
|
|
42
41
|
|
|
43
|
-
|
|
44
|
-
onPlayerMove.emit('Alice', 10);
|
|
42
|
+
onPlayerMove.emit('Alice');
|
|
45
43
|
|
|
46
|
-
|
|
47
|
-
onPlayerMove.once((player, x) => {
|
|
44
|
+
onPlayerMove.once((player) => {
|
|
48
45
|
console.log('This will only run once!');
|
|
49
46
|
});
|
|
50
47
|
|
|
51
|
-
// Unsubscribe when no longer needed
|
|
52
48
|
sub.unsubscribe();
|
|
53
49
|
```
|
|
54
50
|
|
|
@@ -59,19 +55,61 @@ It holds the latest value and immediately provides it to new subscribers.
|
|
|
59
55
|
```typescript
|
|
60
56
|
import { StateEmitter } from '@axijs/emitter';
|
|
61
57
|
|
|
62
|
-
|
|
63
|
-
const health = new StateEmitter<[number]>([100]);
|
|
58
|
+
const health = new StateEmitter<number>(100);
|
|
64
59
|
|
|
65
|
-
// New subscribers immediately receive the current state (100)
|
|
66
60
|
health.subscribe((currentHealth) => {
|
|
67
|
-
console.log(`Health is: ${currentHealth}`);
|
|
61
|
+
console.log(`Health is: ${currentHealth}`); // Immediately logs: "Health is: 100"
|
|
68
62
|
});
|
|
69
63
|
|
|
70
|
-
|
|
71
|
-
health.emit(80);
|
|
64
|
+
health.emit(80); // Logs: "Health is: 80"
|
|
72
65
|
|
|
73
|
-
//
|
|
74
|
-
|
|
66
|
+
console.log(health.value); // 80
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
#### Distinct Values & Custom Comparison
|
|
70
|
+
You can prevent the emitter from firing consecutively with the same value by using the `StateEmitterOptions`.
|
|
71
|
+
|
|
72
|
+
```typescript
|
|
73
|
+
export interface StateEmitterOptions<T> {
|
|
74
|
+
distinct?: boolean;
|
|
75
|
+
compare?: (prev: T, next: T) => boolean;
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
When `distinct: true` is set, the emitter checks if the new value is the same as the previous one.
|
|
80
|
+
**By default, it uses simple reference equality (`Object.is`)**, which is fast and works perfectly for primitives.
|
|
81
|
+
|
|
82
|
+
```typescript
|
|
83
|
+
// Prevents emitting the same primitive value twice
|
|
84
|
+
const status = new StateEmitter('idle', { distinct: true });
|
|
85
|
+
status.emit('idle'); // Ignored
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
For complex objects, or if you want to apply custom comparison logic, you can provide a `compare` callback.
|
|
89
|
+
This is useful when you only care about specific fields changing (like an `id`) or when using a deep equal function from a library.
|
|
90
|
+
|
|
91
|
+
```typescript
|
|
92
|
+
interface User {
|
|
93
|
+
id: number;
|
|
94
|
+
name: string;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const activeUser = new StateEmitter<User>(
|
|
98
|
+
{ id: 1, name: 'Alice' },
|
|
99
|
+
{
|
|
100
|
+
distinct: true,
|
|
101
|
+
// Custom logic: objects are considered the same if their IDs match
|
|
102
|
+
compare: (prev, next) => prev.id === next.id
|
|
103
|
+
}
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
activeUser.subscribe(user => console.log('User changed:', user.name));
|
|
107
|
+
|
|
108
|
+
// Will NOT emit, because the 'id' is still 1
|
|
109
|
+
activeUser.emit({ id: 1, name: 'Alice Updated' });
|
|
110
|
+
|
|
111
|
+
// WILL emit, because the 'id' has changed
|
|
112
|
+
activeUser.emit({ id: 2, name: 'Bob' });
|
|
75
113
|
```
|
|
76
114
|
|
|
77
115
|
### 3. Composite Subscriptions
|
|
@@ -80,8 +118,8 @@ Group multiple unsubscriptions together. Very useful for cleaning up UI componen
|
|
|
80
118
|
```typescript
|
|
81
119
|
import { Emitter, Subscription } from '@axijs/emitter';
|
|
82
120
|
|
|
83
|
-
const onJump = new Emitter<
|
|
84
|
-
const onShoot = new Emitter<
|
|
121
|
+
const onJump = new Emitter<void>();
|
|
122
|
+
const onShoot = new Emitter<void>();
|
|
85
123
|
|
|
86
124
|
const masterSub = new Subscription();
|
|
87
125
|
|
|
@@ -101,12 +139,8 @@ masterSub.unsubscribe();
|
|
|
101
139
|
|
|
102
140
|
## API Documentation
|
|
103
141
|
|
|
104
|
-
For a complete list of classes, interfaces,
|
|
105
|
-
|
|
106
|
-
## License
|
|
107
|
-
|
|
108
|
-
MIT
|
|
109
|
-
```
|
|
142
|
+
For a complete list of classes, interfaces,
|
|
143
|
+
and methods, please visit the [API Documentation](https://github.com/axijs/tools/tree/main/packages/emitter/docs/api).
|
|
110
144
|
|
|
111
145
|
## License
|
|
112
146
|
|
package/dist/index.d.mts
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
|
+
type ListenerType<T> = (value: T) => void;
|
|
1
2
|
/**
|
|
2
3
|
* Defines the public, read-only contract for an event emitter.
|
|
3
4
|
* It allows subscribing to an event but not emitting it.
|
|
4
|
-
* @template T
|
|
5
|
+
* @template T The type of the emitted value.
|
|
5
6
|
*/
|
|
6
|
-
type Subscribable<T
|
|
7
|
+
type Subscribable<T> = {
|
|
7
8
|
readonly listenerCount: number;
|
|
8
9
|
/**
|
|
9
10
|
* Subscribes a listener to this event.
|
|
10
11
|
* @returns A function to unsubscribe the listener.
|
|
11
12
|
*/
|
|
12
|
-
subscribe(listener: (
|
|
13
|
-
unsubscribe(listener: (
|
|
13
|
+
subscribe(listener: (value: T) => void): Unsubscribable;
|
|
14
|
+
unsubscribe(listener: (value: T) => void): boolean;
|
|
14
15
|
clear(): void;
|
|
15
16
|
};
|
|
16
17
|
/**
|
|
@@ -51,9 +52,9 @@ declare class Subscription implements Unsubscribable {
|
|
|
51
52
|
/**
|
|
52
53
|
* A minimal, type-safe event emitter for a single event.
|
|
53
54
|
* It does not manage state, it only manages subscribers and event dispatching.
|
|
54
|
-
* @template T
|
|
55
|
+
* @template T The type of the emitted value.
|
|
55
56
|
*/
|
|
56
|
-
declare class Emitter<T
|
|
57
|
+
declare class Emitter<T = void> implements Subscribable<T> {
|
|
57
58
|
private listeners;
|
|
58
59
|
/**
|
|
59
60
|
* Returns the number of listeners.
|
|
@@ -63,54 +64,61 @@ declare class Emitter<T extends any[]> implements Subscribable<T> {
|
|
|
63
64
|
* Subscribes a listener to this event.
|
|
64
65
|
* @returns A Subscription object to manage the unsubscription.
|
|
65
66
|
*/
|
|
66
|
-
subscribe(listener:
|
|
67
|
+
subscribe(listener: ListenerType<T>): Subscription;
|
|
67
68
|
/**
|
|
68
69
|
* Subscribes a listener that triggers only once and then automatically unsubscribes.
|
|
69
70
|
* @param listener The callback function to execute once.
|
|
70
71
|
* @returns A Subscription object (can be used to cancel before the event fires).
|
|
71
72
|
*/
|
|
72
|
-
once(listener:
|
|
73
|
+
once(listener: ListenerType<T>): Subscription;
|
|
73
74
|
/**
|
|
74
|
-
* Manually unsubscribe by listener
|
|
75
|
-
* @returns returns true if
|
|
75
|
+
* Manually unsubscribe by listener.
|
|
76
|
+
* @returns returns true if a listener has been removed, or false if it does not exist.
|
|
76
77
|
*/
|
|
77
|
-
unsubscribe(listener:
|
|
78
|
+
unsubscribe(listener: ListenerType<T>): boolean;
|
|
78
79
|
/**
|
|
79
80
|
* Dispatches the event to all subscribed listeners.
|
|
80
81
|
*/
|
|
81
|
-
emit(
|
|
82
|
+
emit(value: T): void;
|
|
82
83
|
/**
|
|
83
84
|
* Clears all listeners.
|
|
84
85
|
*/
|
|
85
86
|
clear(): void;
|
|
86
87
|
}
|
|
87
88
|
|
|
89
|
+
interface StateEmitterOptions<T> {
|
|
90
|
+
distinct?: boolean;
|
|
91
|
+
compare?: (prev: T, next: T) => boolean;
|
|
92
|
+
}
|
|
88
93
|
/**
|
|
89
94
|
* An Emitter that stores the last emitted value.
|
|
90
95
|
* New subscribers immediately receive the last value upon subscription.
|
|
91
96
|
*/
|
|
92
|
-
declare class StateEmitter<T
|
|
97
|
+
declare class StateEmitter<T> extends Emitter<T> {
|
|
93
98
|
private _lastValue;
|
|
99
|
+
private readonly _distinct;
|
|
100
|
+
private readonly _compare;
|
|
94
101
|
/**
|
|
95
102
|
* @param initialValue Optional initial value to set.
|
|
103
|
+
* @param options Optional behavior flags.
|
|
96
104
|
*/
|
|
97
|
-
constructor(initialValue?: T);
|
|
105
|
+
constructor(initialValue?: T, options?: StateEmitterOptions<T>);
|
|
98
106
|
/**
|
|
99
107
|
* Gets the current value synchronously without subscribing.
|
|
100
108
|
*/
|
|
101
109
|
get value(): T | undefined;
|
|
102
110
|
/**
|
|
103
111
|
* Updates the state and notifies all listeners.
|
|
104
|
-
* @param
|
|
112
|
+
* @param value The new value.
|
|
105
113
|
*/
|
|
106
|
-
emit(
|
|
114
|
+
emit(value: T): void;
|
|
107
115
|
/**
|
|
108
116
|
* Subscribes to the event. If a value exists, the listener is called immediately.
|
|
109
117
|
* @param listener The callback function.
|
|
110
118
|
* @returns A Subscription object.
|
|
111
119
|
*/
|
|
112
|
-
subscribe(listener: (
|
|
120
|
+
subscribe(listener: (value: T) => void): Subscription;
|
|
113
121
|
clear(): void;
|
|
114
122
|
}
|
|
115
123
|
|
|
116
|
-
export { Emitter, StateEmitter, type Subscribable, Subscription, type Unsubscribable };
|
|
124
|
+
export { Emitter, type ListenerType, StateEmitter, type StateEmitterOptions, type Subscribable, Subscription, type Unsubscribable };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
|
+
type ListenerType<T> = (value: T) => void;
|
|
1
2
|
/**
|
|
2
3
|
* Defines the public, read-only contract for an event emitter.
|
|
3
4
|
* It allows subscribing to an event but not emitting it.
|
|
4
|
-
* @template T
|
|
5
|
+
* @template T The type of the emitted value.
|
|
5
6
|
*/
|
|
6
|
-
type Subscribable<T
|
|
7
|
+
type Subscribable<T> = {
|
|
7
8
|
readonly listenerCount: number;
|
|
8
9
|
/**
|
|
9
10
|
* Subscribes a listener to this event.
|
|
10
11
|
* @returns A function to unsubscribe the listener.
|
|
11
12
|
*/
|
|
12
|
-
subscribe(listener: (
|
|
13
|
-
unsubscribe(listener: (
|
|
13
|
+
subscribe(listener: (value: T) => void): Unsubscribable;
|
|
14
|
+
unsubscribe(listener: (value: T) => void): boolean;
|
|
14
15
|
clear(): void;
|
|
15
16
|
};
|
|
16
17
|
/**
|
|
@@ -51,9 +52,9 @@ declare class Subscription implements Unsubscribable {
|
|
|
51
52
|
/**
|
|
52
53
|
* A minimal, type-safe event emitter for a single event.
|
|
53
54
|
* It does not manage state, it only manages subscribers and event dispatching.
|
|
54
|
-
* @template T
|
|
55
|
+
* @template T The type of the emitted value.
|
|
55
56
|
*/
|
|
56
|
-
declare class Emitter<T
|
|
57
|
+
declare class Emitter<T = void> implements Subscribable<T> {
|
|
57
58
|
private listeners;
|
|
58
59
|
/**
|
|
59
60
|
* Returns the number of listeners.
|
|
@@ -63,54 +64,61 @@ declare class Emitter<T extends any[]> implements Subscribable<T> {
|
|
|
63
64
|
* Subscribes a listener to this event.
|
|
64
65
|
* @returns A Subscription object to manage the unsubscription.
|
|
65
66
|
*/
|
|
66
|
-
subscribe(listener:
|
|
67
|
+
subscribe(listener: ListenerType<T>): Subscription;
|
|
67
68
|
/**
|
|
68
69
|
* Subscribes a listener that triggers only once and then automatically unsubscribes.
|
|
69
70
|
* @param listener The callback function to execute once.
|
|
70
71
|
* @returns A Subscription object (can be used to cancel before the event fires).
|
|
71
72
|
*/
|
|
72
|
-
once(listener:
|
|
73
|
+
once(listener: ListenerType<T>): Subscription;
|
|
73
74
|
/**
|
|
74
|
-
* Manually unsubscribe by listener
|
|
75
|
-
* @returns returns true if
|
|
75
|
+
* Manually unsubscribe by listener.
|
|
76
|
+
* @returns returns true if a listener has been removed, or false if it does not exist.
|
|
76
77
|
*/
|
|
77
|
-
unsubscribe(listener:
|
|
78
|
+
unsubscribe(listener: ListenerType<T>): boolean;
|
|
78
79
|
/**
|
|
79
80
|
* Dispatches the event to all subscribed listeners.
|
|
80
81
|
*/
|
|
81
|
-
emit(
|
|
82
|
+
emit(value: T): void;
|
|
82
83
|
/**
|
|
83
84
|
* Clears all listeners.
|
|
84
85
|
*/
|
|
85
86
|
clear(): void;
|
|
86
87
|
}
|
|
87
88
|
|
|
89
|
+
interface StateEmitterOptions<T> {
|
|
90
|
+
distinct?: boolean;
|
|
91
|
+
compare?: (prev: T, next: T) => boolean;
|
|
92
|
+
}
|
|
88
93
|
/**
|
|
89
94
|
* An Emitter that stores the last emitted value.
|
|
90
95
|
* New subscribers immediately receive the last value upon subscription.
|
|
91
96
|
*/
|
|
92
|
-
declare class StateEmitter<T
|
|
97
|
+
declare class StateEmitter<T> extends Emitter<T> {
|
|
93
98
|
private _lastValue;
|
|
99
|
+
private readonly _distinct;
|
|
100
|
+
private readonly _compare;
|
|
94
101
|
/**
|
|
95
102
|
* @param initialValue Optional initial value to set.
|
|
103
|
+
* @param options Optional behavior flags.
|
|
96
104
|
*/
|
|
97
|
-
constructor(initialValue?: T);
|
|
105
|
+
constructor(initialValue?: T, options?: StateEmitterOptions<T>);
|
|
98
106
|
/**
|
|
99
107
|
* Gets the current value synchronously without subscribing.
|
|
100
108
|
*/
|
|
101
109
|
get value(): T | undefined;
|
|
102
110
|
/**
|
|
103
111
|
* Updates the state and notifies all listeners.
|
|
104
|
-
* @param
|
|
112
|
+
* @param value The new value.
|
|
105
113
|
*/
|
|
106
|
-
emit(
|
|
114
|
+
emit(value: T): void;
|
|
107
115
|
/**
|
|
108
116
|
* Subscribes to the event. If a value exists, the listener is called immediately.
|
|
109
117
|
* @param listener The callback function.
|
|
110
118
|
* @returns A Subscription object.
|
|
111
119
|
*/
|
|
112
|
-
subscribe(listener: (
|
|
120
|
+
subscribe(listener: (value: T) => void): Subscription;
|
|
113
121
|
clear(): void;
|
|
114
122
|
}
|
|
115
123
|
|
|
116
|
-
export { Emitter, StateEmitter, type Subscribable, Subscription, type Unsubscribable };
|
|
124
|
+
export { Emitter, type ListenerType, StateEmitter, type StateEmitterOptions, type Subscribable, Subscription, type Unsubscribable };
|
package/dist/index.js
CHANGED
|
@@ -26,11 +26,6 @@ __export(index_exports, {
|
|
|
26
26
|
});
|
|
27
27
|
module.exports = __toCommonJS(index_exports);
|
|
28
28
|
|
|
29
|
-
// ../ensure/dist/index.mjs
|
|
30
|
-
function isFunction(value) {
|
|
31
|
-
return typeof value === "function";
|
|
32
|
-
}
|
|
33
|
-
|
|
34
29
|
// src/subscription.ts
|
|
35
30
|
var Subscription = class {
|
|
36
31
|
_closed = false;
|
|
@@ -55,11 +50,12 @@ var Subscription = class {
|
|
|
55
50
|
* @param teardown A function or another Unsubscribable object to be managed.
|
|
56
51
|
*/
|
|
57
52
|
add(teardown) {
|
|
53
|
+
const isFunction = typeof teardown === "function";
|
|
58
54
|
if (this._closed) {
|
|
59
|
-
isFunction
|
|
55
|
+
isFunction ? teardown() : teardown.unsubscribe();
|
|
60
56
|
return;
|
|
61
57
|
}
|
|
62
|
-
this._teardowns.push(isFunction
|
|
58
|
+
this._teardowns.push(isFunction ? teardown : () => teardown.unsubscribe());
|
|
63
59
|
}
|
|
64
60
|
/**
|
|
65
61
|
* Disposes the resources held by the subscription.
|
|
@@ -96,15 +92,15 @@ var Emitter = class {
|
|
|
96
92
|
* @returns A Subscription object (can be used to cancel before the event fires).
|
|
97
93
|
*/
|
|
98
94
|
once(listener) {
|
|
99
|
-
const wrapper = (
|
|
95
|
+
const wrapper = (value) => {
|
|
100
96
|
this.unsubscribe(wrapper);
|
|
101
|
-
listener(
|
|
97
|
+
listener(value);
|
|
102
98
|
};
|
|
103
99
|
return this.subscribe(wrapper);
|
|
104
100
|
}
|
|
105
101
|
/**
|
|
106
|
-
* Manually unsubscribe by listener
|
|
107
|
-
* @returns returns true if
|
|
102
|
+
* Manually unsubscribe by listener.
|
|
103
|
+
* @returns returns true if a listener has been removed, or false if it does not exist.
|
|
108
104
|
*/
|
|
109
105
|
unsubscribe(listener) {
|
|
110
106
|
return this.listeners.delete(listener);
|
|
@@ -112,8 +108,8 @@ var Emitter = class {
|
|
|
112
108
|
/**
|
|
113
109
|
* Dispatches the event to all subscribed listeners.
|
|
114
110
|
*/
|
|
115
|
-
emit(
|
|
116
|
-
this.listeners.forEach((listener) => listener(
|
|
111
|
+
emit(value) {
|
|
112
|
+
this.listeners.forEach((listener) => listener(value));
|
|
117
113
|
}
|
|
118
114
|
/**
|
|
119
115
|
* Clears all listeners.
|
|
@@ -126,12 +122,17 @@ var Emitter = class {
|
|
|
126
122
|
// src/state-emitter.ts
|
|
127
123
|
var StateEmitter = class extends Emitter {
|
|
128
124
|
_lastValue;
|
|
125
|
+
_distinct;
|
|
126
|
+
_compare;
|
|
129
127
|
/**
|
|
130
128
|
* @param initialValue Optional initial value to set.
|
|
129
|
+
* @param options Optional behavior flags.
|
|
131
130
|
*/
|
|
132
|
-
constructor(initialValue) {
|
|
131
|
+
constructor(initialValue, options = {}) {
|
|
133
132
|
super();
|
|
134
133
|
this._lastValue = initialValue ?? void 0;
|
|
134
|
+
this._distinct = options.distinct ?? false;
|
|
135
|
+
this._compare = options.compare ?? Object.is;
|
|
135
136
|
}
|
|
136
137
|
/**
|
|
137
138
|
* Gets the current value synchronously without subscribing.
|
|
@@ -141,11 +142,14 @@ var StateEmitter = class extends Emitter {
|
|
|
141
142
|
}
|
|
142
143
|
/**
|
|
143
144
|
* Updates the state and notifies all listeners.
|
|
144
|
-
* @param
|
|
145
|
+
* @param value The new value.
|
|
145
146
|
*/
|
|
146
|
-
emit(
|
|
147
|
-
this._lastValue
|
|
148
|
-
|
|
147
|
+
emit(value) {
|
|
148
|
+
if (this._distinct && this._lastValue !== void 0 && this._compare(this._lastValue, value)) {
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
this._lastValue = value;
|
|
152
|
+
super.emit(value);
|
|
149
153
|
}
|
|
150
154
|
/**
|
|
151
155
|
* Subscribes to the event. If a value exists, the listener is called immediately.
|
|
@@ -155,7 +159,7 @@ var StateEmitter = class extends Emitter {
|
|
|
155
159
|
subscribe(listener) {
|
|
156
160
|
const unsubscribe = super.subscribe(listener);
|
|
157
161
|
if (this._lastValue !== void 0) {
|
|
158
|
-
listener(
|
|
162
|
+
listener(this._lastValue);
|
|
159
163
|
}
|
|
160
164
|
return unsubscribe;
|
|
161
165
|
}
|
package/dist/index.mjs
CHANGED
|
@@ -1,8 +1,3 @@
|
|
|
1
|
-
// ../ensure/dist/index.mjs
|
|
2
|
-
function isFunction(value) {
|
|
3
|
-
return typeof value === "function";
|
|
4
|
-
}
|
|
5
|
-
|
|
6
1
|
// src/subscription.ts
|
|
7
2
|
var Subscription = class {
|
|
8
3
|
_closed = false;
|
|
@@ -27,11 +22,12 @@ var Subscription = class {
|
|
|
27
22
|
* @param teardown A function or another Unsubscribable object to be managed.
|
|
28
23
|
*/
|
|
29
24
|
add(teardown) {
|
|
25
|
+
const isFunction = typeof teardown === "function";
|
|
30
26
|
if (this._closed) {
|
|
31
|
-
isFunction
|
|
27
|
+
isFunction ? teardown() : teardown.unsubscribe();
|
|
32
28
|
return;
|
|
33
29
|
}
|
|
34
|
-
this._teardowns.push(isFunction
|
|
30
|
+
this._teardowns.push(isFunction ? teardown : () => teardown.unsubscribe());
|
|
35
31
|
}
|
|
36
32
|
/**
|
|
37
33
|
* Disposes the resources held by the subscription.
|
|
@@ -68,15 +64,15 @@ var Emitter = class {
|
|
|
68
64
|
* @returns A Subscription object (can be used to cancel before the event fires).
|
|
69
65
|
*/
|
|
70
66
|
once(listener) {
|
|
71
|
-
const wrapper = (
|
|
67
|
+
const wrapper = (value) => {
|
|
72
68
|
this.unsubscribe(wrapper);
|
|
73
|
-
listener(
|
|
69
|
+
listener(value);
|
|
74
70
|
};
|
|
75
71
|
return this.subscribe(wrapper);
|
|
76
72
|
}
|
|
77
73
|
/**
|
|
78
|
-
* Manually unsubscribe by listener
|
|
79
|
-
* @returns returns true if
|
|
74
|
+
* Manually unsubscribe by listener.
|
|
75
|
+
* @returns returns true if a listener has been removed, or false if it does not exist.
|
|
80
76
|
*/
|
|
81
77
|
unsubscribe(listener) {
|
|
82
78
|
return this.listeners.delete(listener);
|
|
@@ -84,8 +80,8 @@ var Emitter = class {
|
|
|
84
80
|
/**
|
|
85
81
|
* Dispatches the event to all subscribed listeners.
|
|
86
82
|
*/
|
|
87
|
-
emit(
|
|
88
|
-
this.listeners.forEach((listener) => listener(
|
|
83
|
+
emit(value) {
|
|
84
|
+
this.listeners.forEach((listener) => listener(value));
|
|
89
85
|
}
|
|
90
86
|
/**
|
|
91
87
|
* Clears all listeners.
|
|
@@ -98,12 +94,17 @@ var Emitter = class {
|
|
|
98
94
|
// src/state-emitter.ts
|
|
99
95
|
var StateEmitter = class extends Emitter {
|
|
100
96
|
_lastValue;
|
|
97
|
+
_distinct;
|
|
98
|
+
_compare;
|
|
101
99
|
/**
|
|
102
100
|
* @param initialValue Optional initial value to set.
|
|
101
|
+
* @param options Optional behavior flags.
|
|
103
102
|
*/
|
|
104
|
-
constructor(initialValue) {
|
|
103
|
+
constructor(initialValue, options = {}) {
|
|
105
104
|
super();
|
|
106
105
|
this._lastValue = initialValue ?? void 0;
|
|
106
|
+
this._distinct = options.distinct ?? false;
|
|
107
|
+
this._compare = options.compare ?? Object.is;
|
|
107
108
|
}
|
|
108
109
|
/**
|
|
109
110
|
* Gets the current value synchronously without subscribing.
|
|
@@ -113,11 +114,14 @@ var StateEmitter = class extends Emitter {
|
|
|
113
114
|
}
|
|
114
115
|
/**
|
|
115
116
|
* Updates the state and notifies all listeners.
|
|
116
|
-
* @param
|
|
117
|
+
* @param value The new value.
|
|
117
118
|
*/
|
|
118
|
-
emit(
|
|
119
|
-
this._lastValue
|
|
120
|
-
|
|
119
|
+
emit(value) {
|
|
120
|
+
if (this._distinct && this._lastValue !== void 0 && this._compare(this._lastValue, value)) {
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
this._lastValue = value;
|
|
124
|
+
super.emit(value);
|
|
121
125
|
}
|
|
122
126
|
/**
|
|
123
127
|
* Subscribes to the event. If a value exists, the listener is called immediately.
|
|
@@ -127,7 +131,7 @@ var StateEmitter = class extends Emitter {
|
|
|
127
131
|
subscribe(listener) {
|
|
128
132
|
const unsubscribe = super.subscribe(listener);
|
|
129
133
|
if (this._lastValue !== void 0) {
|
|
130
|
-
listener(
|
|
134
|
+
listener(this._lastValue);
|
|
131
135
|
}
|
|
132
136
|
return unsubscribe;
|
|
133
137
|
}
|
package/package.json
CHANGED