evnty 1.5.3 → 2.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 +139 -16
- package/build/index.cjs +57 -50
- package/build/index.cjs.map +1 -1
- package/build/index.d.ts +76 -63
- package/build/index.js +52 -48
- package/build/index.js.map +1 -1
- package/package.json +28 -21
- package/src/__tests__/example.js +45 -0
- package/src/index.ts +135 -112
package/build/index.d.ts
CHANGED
|
@@ -1,23 +1,28 @@
|
|
|
1
1
|
export type MaybePromise<T> = Promise<T> | PromiseLike<T> | T;
|
|
2
|
-
export interface
|
|
3
|
-
():
|
|
2
|
+
export interface Callback<R = void> {
|
|
3
|
+
(): MaybePromise<R>;
|
|
4
4
|
}
|
|
5
|
-
export interface Listener<T
|
|
6
|
-
(
|
|
5
|
+
export interface Listener<T, R = unknown> {
|
|
6
|
+
(event: T): MaybePromise<R | void>;
|
|
7
7
|
}
|
|
8
|
-
export interface
|
|
9
|
-
|
|
8
|
+
export interface Result<T, E> {
|
|
9
|
+
ok: boolean;
|
|
10
|
+
result: T | E;
|
|
10
11
|
}
|
|
11
|
-
export interface
|
|
12
|
-
(
|
|
12
|
+
export interface FilterFunction<T> {
|
|
13
|
+
(event: T): MaybePromise<boolean>;
|
|
13
14
|
}
|
|
14
|
-
export interface
|
|
15
|
-
(
|
|
15
|
+
export interface Predicate<T, P extends T> {
|
|
16
|
+
(event: T): event is P;
|
|
16
17
|
}
|
|
17
|
-
export
|
|
18
|
-
|
|
18
|
+
export type Filter<T, P extends T> = Predicate<T, P> | FilterFunction<T>;
|
|
19
|
+
export interface Mapper<T, R> {
|
|
20
|
+
(event: T): MaybePromise<R>;
|
|
19
21
|
}
|
|
20
|
-
export
|
|
22
|
+
export interface Reducer<T, R> {
|
|
23
|
+
(result: R, event: T): MaybePromise<R>;
|
|
24
|
+
}
|
|
25
|
+
export type Listeners<T, R> = Listener<T, R>[];
|
|
21
26
|
/**
|
|
22
27
|
* An abstract class that extends the built-in Function class. It allows instances of the class
|
|
23
28
|
* to be called as functions. When an instance of FunctionExt is called as a function, it will
|
|
@@ -28,28 +33,27 @@ export declare abstract class FunctionExt extends Function {
|
|
|
28
33
|
constructor(func: Function);
|
|
29
34
|
}
|
|
30
35
|
export interface Dismiss {
|
|
31
|
-
():
|
|
32
|
-
}
|
|
33
|
-
export interface Task {
|
|
34
|
-
(): MaybePromise<unknown>;
|
|
36
|
+
(): MaybePromise<void>;
|
|
35
37
|
}
|
|
36
38
|
/**
|
|
37
39
|
* @internal
|
|
38
40
|
*/
|
|
39
41
|
export declare class Dismiss extends FunctionExt {
|
|
40
|
-
constructor(callback:
|
|
41
|
-
|
|
42
|
-
|
|
42
|
+
constructor(callback: Callback);
|
|
43
|
+
pre(callback: Callback): Dismiss;
|
|
44
|
+
post(callback: Callback): Dismiss;
|
|
45
|
+
countdown(count: number): Dismiss;
|
|
43
46
|
}
|
|
44
|
-
|
|
45
|
-
|
|
47
|
+
type EventType<T> = T extends undefined ? void : T;
|
|
48
|
+
export interface Event<T = unknown, R = void> {
|
|
49
|
+
(event?: EventType<T>): Promise<(R | undefined)[]>;
|
|
46
50
|
}
|
|
47
51
|
export type EventParameters<T> = T extends Event<infer P, unknown> ? P : never;
|
|
48
|
-
export type EventResult<T> = T extends Event<unknown
|
|
49
|
-
export type AllEventsParameters<T extends Event<unknown
|
|
52
|
+
export type EventResult<T> = T extends Event<unknown, infer R> ? R : never;
|
|
53
|
+
export type AllEventsParameters<T extends Event<unknown, unknown>[]> = {
|
|
50
54
|
[K in keyof T]: EventParameters<T[K]>;
|
|
51
55
|
}[number];
|
|
52
|
-
export type AllEventsResults<T extends Event<unknown
|
|
56
|
+
export type AllEventsResults<T extends Event<unknown, unknown>[]> = {
|
|
53
57
|
[K in keyof T]: EventResult<T[K]>;
|
|
54
58
|
}[number];
|
|
55
59
|
/**
|
|
@@ -58,26 +62,7 @@ export type AllEventsResults<T extends Event<unknown[], unknown>[]> = {
|
|
|
58
62
|
* @typeParam T - The tuple of arguments that the event takes.
|
|
59
63
|
* @typeParam R - The return type of the event.
|
|
60
64
|
*/
|
|
61
|
-
export declare class Event<T
|
|
62
|
-
/**
|
|
63
|
-
* Merges multiple events into a single event.
|
|
64
|
-
* @example
|
|
65
|
-
* const inputEvent = Event.merge(mouseEvent, keyboardEvent);
|
|
66
|
-
*
|
|
67
|
-
* @param events - The events to merge.
|
|
68
|
-
* @returns The merged event.
|
|
69
|
-
*/
|
|
70
|
-
static merge<Events extends Event<any[], any>[]>(...events: Events): Event<AllEventsParameters<Events>, AllEventsResults<Events>>;
|
|
71
|
-
/**
|
|
72
|
-
* Creates an event that triggers at a specified interval.
|
|
73
|
-
* @example
|
|
74
|
-
* const tickEvent = Event.interval(1000);
|
|
75
|
-
* tickEvent.on((tickNumber) => console.log(tickNumber));
|
|
76
|
-
*
|
|
77
|
-
* @param interval - The interval at which to trigger the event.
|
|
78
|
-
* @returns The interval event.
|
|
79
|
-
*/
|
|
80
|
-
static interval(interval: number): Event<[number], void>;
|
|
65
|
+
export declare class Event<T, R> extends FunctionExt {
|
|
81
66
|
/**
|
|
82
67
|
* The array of listeners for the event.
|
|
83
68
|
*/
|
|
@@ -85,7 +70,7 @@ export declare class Event<T extends unknown[], R = void> extends FunctionExt {
|
|
|
85
70
|
/**
|
|
86
71
|
* A function that disposes of the event and its listeners.
|
|
87
72
|
*/
|
|
88
|
-
readonly dispose:
|
|
73
|
+
readonly dispose: Callback;
|
|
89
74
|
/**
|
|
90
75
|
* Creates a new event.
|
|
91
76
|
* @example
|
|
@@ -95,7 +80,7 @@ export declare class Event<T extends unknown[], R = void> extends FunctionExt {
|
|
|
95
80
|
*
|
|
96
81
|
* @param dispose - A function to call on the event disposal.
|
|
97
82
|
*/
|
|
98
|
-
constructor(dispose?:
|
|
83
|
+
constructor(dispose?: Callback);
|
|
99
84
|
/**
|
|
100
85
|
* The number of listeners for the event.
|
|
101
86
|
*/
|
|
@@ -129,15 +114,15 @@ export declare class Event<T extends unknown[], R = void> extends FunctionExt {
|
|
|
129
114
|
* @returns An object that can be used to remove the listener.
|
|
130
115
|
*/
|
|
131
116
|
once(listener: Listener<T, R>): Dismiss;
|
|
132
|
-
/**
|
|
133
|
-
* Removes all listeners from the event.
|
|
134
|
-
*/
|
|
135
|
-
clear(): void;
|
|
136
117
|
/**
|
|
137
118
|
* Returns a Promise that resolves with the first emitted by the event arguments.
|
|
138
119
|
* @returns A Promise that resolves with the first emitted by the event.
|
|
139
120
|
*/
|
|
140
|
-
|
|
121
|
+
onceAsync(): Promise<T>;
|
|
122
|
+
/**
|
|
123
|
+
* Removes all listeners from the event.
|
|
124
|
+
*/
|
|
125
|
+
clear(): void;
|
|
141
126
|
/**
|
|
142
127
|
* Returns a new event that only triggers when the provided filter function returns `true`.
|
|
143
128
|
* @example
|
|
@@ -146,7 +131,8 @@ export declare class Event<T extends unknown[], R = void> extends FunctionExt {
|
|
|
146
131
|
* @param filter The filter function to apply to the event.
|
|
147
132
|
* @returns A new event that only triggers when the provided filter function returns `true`.
|
|
148
133
|
*/
|
|
149
|
-
filter<
|
|
134
|
+
filter<P extends T>(predicate: Predicate<T, P>): Event<P, R>;
|
|
135
|
+
filter<P extends T>(filter: FilterFunction<T>): Event<P, R>;
|
|
150
136
|
/**
|
|
151
137
|
* Returns a new event that will only be triggered once the provided filter function returns `true`.
|
|
152
138
|
* @example
|
|
@@ -156,7 +142,18 @@ export declare class Event<T extends unknown[], R = void> extends FunctionExt {
|
|
|
156
142
|
* @param filter - The filter function.
|
|
157
143
|
* @returns A new event that will only be triggered once the provided filter function returns `true`.
|
|
158
144
|
*/
|
|
159
|
-
first<
|
|
145
|
+
first<P extends T>(predicate: Predicate<T, P>): Event<P, R>;
|
|
146
|
+
first<P extends T>(filter: FilterFunction<T>): Event<P, R>;
|
|
147
|
+
/**
|
|
148
|
+
* Returns a new promise that will be resolved once the provided filter function returns `true`.
|
|
149
|
+
* @example
|
|
150
|
+
* const escPressEvent = await keyboardEvent.firstAsync((key) => key === 'Esc');
|
|
151
|
+
*
|
|
152
|
+
* @param filter - The filter function.
|
|
153
|
+
* @returns A new promise that will be resolved once the provided filter function returns `true`.
|
|
154
|
+
*/
|
|
155
|
+
firstAsync<P extends T>(predicate: Predicate<T, P>): Promise<P>;
|
|
156
|
+
firstAsync<P extends T>(filter: FilterFunction<T>): Promise<P>;
|
|
160
157
|
/**
|
|
161
158
|
* Returns a new event that maps the values of this event using the provided mapper function.
|
|
162
159
|
* @example
|
|
@@ -165,7 +162,7 @@ export declare class Event<T extends unknown[], R = void> extends FunctionExt {
|
|
|
165
162
|
* @param mapper A function that maps the values of this event to a new value.
|
|
166
163
|
* @returns A new event that emits the mapped values.
|
|
167
164
|
*/
|
|
168
|
-
map<M, MR =
|
|
165
|
+
map<M, MR = R>(mapper: Mapper<T, M>): Event<M, MR>;
|
|
169
166
|
/**
|
|
170
167
|
* Returns a new event that reduces the emitted values using the provided reducer function.
|
|
171
168
|
* @example
|
|
@@ -181,7 +178,7 @@ export declare class Event<T extends unknown[], R = void> extends FunctionExt {
|
|
|
181
178
|
* @param {A} init The initial value of the accumulated value.
|
|
182
179
|
* @returns {Event<[A], AR>} A new `Event` that emits the reduced value.
|
|
183
180
|
*/
|
|
184
|
-
reduce<A, AR =
|
|
181
|
+
reduce<A, AR = R>(reducer: Reducer<T, A>, init: A): Event<A, AR>;
|
|
185
182
|
/**
|
|
186
183
|
* Returns a new debounced event that will not fire until a certain amount of time has passed
|
|
187
184
|
* since the last time it was triggered.
|
|
@@ -199,14 +196,24 @@ export declare class Event<T extends unknown[], R = void> extends FunctionExt {
|
|
|
199
196
|
debounce(interval: number): Event<T, R>;
|
|
200
197
|
}
|
|
201
198
|
/**
|
|
202
|
-
*
|
|
199
|
+
* Merges multiple events into a single event.
|
|
203
200
|
* @example
|
|
204
|
-
* const
|
|
201
|
+
* const inputEvent = Event.merge(mouseEvent, keyboardEvent);
|
|
205
202
|
*
|
|
206
|
-
* @param
|
|
207
|
-
* @returns
|
|
203
|
+
* @param events - The events to merge.
|
|
204
|
+
* @returns The merged event.
|
|
208
205
|
*/
|
|
209
|
-
export declare const
|
|
206
|
+
export declare const merge: <Events extends Event<any, any>[]>(...events: Events) => Event<AllEventsParameters<Events>, AllEventsResults<Events>>;
|
|
207
|
+
/**
|
|
208
|
+
* Creates an event that triggers at a specified interval.
|
|
209
|
+
* @example
|
|
210
|
+
* const tickEvent = Event.interval(1000);
|
|
211
|
+
* tickEvent.on((tickNumber) => console.log(tickNumber));
|
|
212
|
+
*
|
|
213
|
+
* @param interval - The interval at which to trigger the event.
|
|
214
|
+
* @returns The interval event.
|
|
215
|
+
*/
|
|
216
|
+
export declare const createInterval: <R = void>(interval: number) => Event<number, R>;
|
|
210
217
|
/**
|
|
211
218
|
* Creates a new event instance.
|
|
212
219
|
*
|
|
@@ -219,7 +226,7 @@ export declare const once: <T extends unknown[], R = void>(event: Event<T, R>) =
|
|
|
219
226
|
* myEvent.on((str: string) => str.length);
|
|
220
227
|
* await myEvent('hello'); // [5]
|
|
221
228
|
*/
|
|
222
|
-
export declare const createEvent: <T
|
|
229
|
+
export declare const createEvent: <T, R = void>() => Event<T, R>;
|
|
223
230
|
export default createEvent;
|
|
224
231
|
/**
|
|
225
232
|
* A type helper that extracts the event listener type
|
|
@@ -232,7 +239,13 @@ export type EventHandler<E> = E extends Event<infer T, infer R> ? Listener<T, R>
|
|
|
232
239
|
*
|
|
233
240
|
* @typeParam E The event type to filter.
|
|
234
241
|
*/
|
|
235
|
-
export type EventFilter<E> =
|
|
242
|
+
export type EventFilter<E> = FilterFunction<EventParameters<E>>;
|
|
243
|
+
/**
|
|
244
|
+
* A type helper that extracts the event predicate type
|
|
245
|
+
*
|
|
246
|
+
* @typeParam E The event type to predicate.
|
|
247
|
+
*/
|
|
248
|
+
export type EventPredicate<E, P extends EventParameters<E>> = Predicate<EventParameters<E>, P>;
|
|
236
249
|
/**
|
|
237
250
|
* A type helper that extracts the event mapper type
|
|
238
251
|
*
|
package/build/index.js
CHANGED
|
@@ -8,43 +8,38 @@ export class Dismiss extends FunctionExt {
|
|
|
8
8
|
constructor(callback){
|
|
9
9
|
super(callback);
|
|
10
10
|
}
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
pre(callback) {
|
|
12
|
+
return new Dismiss(async ()=>{
|
|
13
|
+
await callback();
|
|
14
|
+
await this();
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
post(callback) {
|
|
18
|
+
return new Dismiss(async ()=>{
|
|
19
|
+
await this();
|
|
20
|
+
await callback();
|
|
21
|
+
});
|
|
14
22
|
}
|
|
15
|
-
|
|
16
|
-
return ()=>{
|
|
23
|
+
countdown(count) {
|
|
24
|
+
return new Dismiss(async ()=>{
|
|
17
25
|
if (!--count) {
|
|
18
|
-
this();
|
|
26
|
+
await this();
|
|
19
27
|
}
|
|
20
|
-
};
|
|
28
|
+
});
|
|
21
29
|
}
|
|
22
30
|
}
|
|
23
|
-
const eventEmitter =
|
|
24
|
-
return Promise.all(listeners.map((listener)=>listener(...args)));
|
|
25
|
-
};
|
|
31
|
+
const eventEmitter = (listeners, event)=>Promise.all(listeners.map((listener)=>listener(event)));
|
|
26
32
|
export class Event extends FunctionExt {
|
|
27
|
-
static merge(...events) {
|
|
28
|
-
const mergedEvent = new Event();
|
|
29
|
-
events.forEach((event)=>event.on(mergedEvent));
|
|
30
|
-
return mergedEvent;
|
|
31
|
-
}
|
|
32
|
-
static interval(interval) {
|
|
33
|
-
let counter = 0;
|
|
34
|
-
const intervalEvent = new Event(()=>clearInterval(timerId));
|
|
35
|
-
const timerId = setInterval(()=>intervalEvent(counter++), interval);
|
|
36
|
-
return intervalEvent;
|
|
37
|
-
}
|
|
38
33
|
listeners;
|
|
39
34
|
dispose;
|
|
40
35
|
constructor(dispose){
|
|
41
36
|
const listeners = [];
|
|
42
|
-
const fn = (
|
|
37
|
+
const fn = (event)=>eventEmitter(listeners, event);
|
|
43
38
|
super(fn);
|
|
44
39
|
this.listeners = listeners;
|
|
45
|
-
this.dispose = ()=>{
|
|
40
|
+
this.dispose = async ()=>{
|
|
46
41
|
this.clear();
|
|
47
|
-
dispose?.();
|
|
42
|
+
await dispose?.();
|
|
48
43
|
};
|
|
49
44
|
}
|
|
50
45
|
get size() {
|
|
@@ -68,42 +63,45 @@ export class Event extends FunctionExt {
|
|
|
68
63
|
return new Dismiss(()=>this.off(listener));
|
|
69
64
|
}
|
|
70
65
|
once(listener) {
|
|
71
|
-
const oneTimeListener = (
|
|
66
|
+
const oneTimeListener = (event)=>{
|
|
72
67
|
this.off(oneTimeListener);
|
|
73
|
-
return listener(
|
|
68
|
+
return listener(event);
|
|
74
69
|
};
|
|
75
70
|
return this.on(oneTimeListener);
|
|
76
71
|
}
|
|
72
|
+
onceAsync() {
|
|
73
|
+
return new Promise((resolve)=>this.once((event)=>resolve(event)));
|
|
74
|
+
}
|
|
77
75
|
clear() {
|
|
78
76
|
this.listeners.splice(0);
|
|
79
77
|
}
|
|
80
|
-
toPromise() {
|
|
81
|
-
return new Promise((resolve)=>this.once((...args)=>resolve(args)));
|
|
82
|
-
}
|
|
83
78
|
filter(filter) {
|
|
84
|
-
const dispose = this.on(async (
|
|
85
|
-
if (filteredEvent.size > 0 && await filter(
|
|
86
|
-
await filteredEvent(
|
|
79
|
+
const dispose = this.on(async (event)=>{
|
|
80
|
+
if (filteredEvent.size > 0 && await filter(event)) {
|
|
81
|
+
await filteredEvent(event);
|
|
87
82
|
}
|
|
88
83
|
});
|
|
89
84
|
const filteredEvent = new Event(dispose);
|
|
90
85
|
return filteredEvent;
|
|
91
86
|
}
|
|
92
87
|
first(filter) {
|
|
93
|
-
const dispose = this.on(async (
|
|
94
|
-
if (filteredEvent.size > 0 && await filter(
|
|
95
|
-
dispose();
|
|
96
|
-
await filteredEvent(
|
|
88
|
+
const dispose = this.on(async (event)=>{
|
|
89
|
+
if (filteredEvent.size > 0 && await filter(event)) {
|
|
90
|
+
await dispose();
|
|
91
|
+
await filteredEvent(event);
|
|
97
92
|
}
|
|
98
93
|
});
|
|
99
94
|
const filteredEvent = new Event(dispose);
|
|
100
95
|
return filteredEvent;
|
|
101
96
|
}
|
|
97
|
+
firstAsync(filter) {
|
|
98
|
+
return this.first(filter).onceAsync();
|
|
99
|
+
}
|
|
102
100
|
map(mapper) {
|
|
103
|
-
const dispose = this.on(async (
|
|
101
|
+
const dispose = this.on(async (event)=>{
|
|
104
102
|
if (mappedEvent.size > 0) {
|
|
105
|
-
const value = await mapper(
|
|
106
|
-
mappedEvent(value);
|
|
103
|
+
const value = await mapper(event);
|
|
104
|
+
await mappedEvent(value);
|
|
107
105
|
}
|
|
108
106
|
});
|
|
109
107
|
const mappedEvent = new Event(dispose);
|
|
@@ -111,10 +109,10 @@ export class Event extends FunctionExt {
|
|
|
111
109
|
}
|
|
112
110
|
reduce(reducer, init) {
|
|
113
111
|
let value = init;
|
|
114
|
-
const dispose = this.on(async (
|
|
112
|
+
const dispose = this.on(async (event)=>{
|
|
115
113
|
if (reducedEvent.size > 0) {
|
|
116
|
-
value = await reducer(value,
|
|
117
|
-
reducedEvent(value);
|
|
114
|
+
value = await reducer(value, event);
|
|
115
|
+
await reducedEvent(value);
|
|
118
116
|
}
|
|
119
117
|
});
|
|
120
118
|
const reducedEvent = new Event(dispose);
|
|
@@ -122,20 +120,26 @@ export class Event extends FunctionExt {
|
|
|
122
120
|
}
|
|
123
121
|
debounce(interval) {
|
|
124
122
|
let timer;
|
|
125
|
-
const dispose = this.on((
|
|
123
|
+
const dispose = this.on((event)=>{
|
|
126
124
|
clearTimeout(timer);
|
|
127
|
-
timer = setTimeout(()=>debouncedEvent(
|
|
125
|
+
timer = setTimeout(()=>debouncedEvent(event), interval);
|
|
128
126
|
});
|
|
129
127
|
const debouncedEvent = new Event(dispose);
|
|
130
128
|
return debouncedEvent;
|
|
131
129
|
}
|
|
132
130
|
}
|
|
133
|
-
export const
|
|
134
|
-
|
|
131
|
+
export const merge = (...events)=>{
|
|
132
|
+
const mergedEvent = new Event();
|
|
133
|
+
events.forEach((event)=>event.on(mergedEvent));
|
|
134
|
+
return mergedEvent;
|
|
135
135
|
};
|
|
136
|
-
export const
|
|
137
|
-
|
|
136
|
+
export const createInterval = (interval)=>{
|
|
137
|
+
let counter = 0;
|
|
138
|
+
const intervalEvent = new Event(()=>clearInterval(timerId));
|
|
139
|
+
const timerId = setInterval(()=>intervalEvent(counter++), interval);
|
|
140
|
+
return intervalEvent;
|
|
138
141
|
};
|
|
142
|
+
export const createEvent = ()=>new Event();
|
|
139
143
|
export default createEvent;
|
|
140
144
|
|
|
141
145
|
//# sourceMappingURL=index.js.map
|
package/build/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["export type MaybePromise<T> = Promise<T> | PromiseLike<T> | T;\n\nexport interface Unsubscribe {\n (): void;\n}\n\nexport interface Listener<T extends unknown[], R = unknown> {\n (...args: T): MaybePromise<R | void>;\n}\n\nexport interface Dispose {\n (): void;\n}\n\nexport interface Filter<T extends unknown[]> {\n (...args: T): MaybePromise<boolean>;\n}\n\nexport interface Mapper<T extends unknown[], R> {\n (...args: T): MaybePromise<R>;\n}\n\nexport interface Reducer<T extends unknown[], R> {\n (value: R, ...args: T): MaybePromise<R>;\n}\n\nexport type Listeners<T extends unknown[], R> = Listener<T, R>[];\n\n/**\n * An abstract class that extends the built-in Function class. It allows instances of the class\n * to be called as functions. When an instance of FunctionExt is called as a function, it will\n * call the function passed to its constructor with the same arguments.\n * @internal\n */\nexport abstract class FunctionExt extends Function {\n constructor(func: Function) {\n super();\n return Object.setPrototypeOf(func, new.target.prototype);\n }\n}\n\nexport interface Dismiss {\n (): Promise<void> | void;\n}\n\nexport interface Task {\n (): MaybePromise<unknown>;\n}\n\n/**\n * @internal\n */\nexport class Dismiss extends FunctionExt {\n constructor(callback: Unsubscribe) {\n super(callback);\n }\n\n async after(task: Task): Promise<void> {\n await task();\n this();\n }\n\n afterTimes(count: number): () => void {\n return () => {\n if (!--count) {\n this();\n }\n };\n }\n}\n\nconst eventEmitter = async <A extends unknown[], R>(listeners: Listeners<A, R>, ...args: A) => {\n return Promise.all(listeners.map((listener) => listener(...args)));\n};\n\nexport interface Event<T extends unknown[], R> {\n (...args: T): Promise<(R | undefined)[]>;\n}\n\nexport type EventParameters<T> = T extends Event<infer P, unknown> ? P : never;\n\nexport type EventResult<T> = T extends Event<unknown[], infer R> ? R : never;\n\nexport type AllEventsParameters<T extends Event<unknown[], unknown>[]> = { [K in keyof T]: EventParameters<T[K]> }[number];\n\nexport type AllEventsResults<T extends Event<unknown[], unknown>[]> = { [K in keyof T]: EventResult<T[K]> }[number];\n\n/**\n * A class representing an anonymous event that can be listened to or triggered.\n *\n * @typeParam T - The tuple of arguments that the event takes.\n * @typeParam R - The return type of the event.\n */\nexport class Event<T extends unknown[], R = void> extends FunctionExt {\n /**\n * Merges multiple events into a single event.\n * @example\n * const inputEvent = Event.merge(mouseEvent, keyboardEvent);\n *\n * @param events - The events to merge.\n * @returns The merged event.\n */\n static merge<Events extends Event<any[], any>[]>(...events: Events): Event<AllEventsParameters<Events>, AllEventsResults<Events>> {\n const mergedEvent = new Event<AllEventsParameters<Events>, AllEventsResults<Events>>();\n events.forEach((event) => event.on(mergedEvent));\n return mergedEvent;\n }\n\n /**\n * Creates an event that triggers at a specified interval.\n * @example\n * const tickEvent = Event.interval(1000);\n * tickEvent.on((tickNumber) => console.log(tickNumber));\n *\n * @param interval - The interval at which to trigger the event.\n * @returns The interval event.\n */\n static interval(interval: number): Event<[number], void> {\n let counter = 0;\n const intervalEvent = new Event<[number], void>(() => clearInterval(timerId));\n const timerId: ReturnType<typeof setInterval> = setInterval(() => intervalEvent(counter++), interval);\n return intervalEvent;\n }\n\n /**\n * The array of listeners for the event.\n */\n private listeners: Listeners<T, R>;\n\n /**\n * A function that disposes of the event and its listeners.\n */\n readonly dispose: Dispose;\n\n /**\n * Creates a new event.\n * @example\n * // Create a click event.\n * const clickEvent = new Event<[x: number, y: number], void>();\n * clickEvent.on((x, y) => console.log(`Clicked at ${x}, ${y}`));\n *\n * @param dispose - A function to call on the event disposal.\n */\n constructor(dispose?: Dispose) {\n const listeners: Listeners<T, R> = [];\n const fn = (...args: T) => eventEmitter(listeners, ...args);\n\n super(fn);\n this.listeners = listeners;\n this.dispose = () => {\n this.clear();\n dispose?.();\n };\n }\n\n /**\n * The number of listeners for the event.\n */\n get size(): number {\n return this.listeners.length;\n }\n\n /**\n * Checks if a listener is not registered for the event.\n * @param listener - The listener to check.\n * @returns `true` if the listener is not registered, `false` otherwise.\n */\n lacks(listener: Listener<T, R>): boolean {\n return this.listeners.indexOf(listener) === -1;\n }\n\n /**\n * Checks if a listener is registered for the event.\n * @param listener - The listener to check.\n * @returns `true` if the listener is registered, `false` otherwise.\n */\n has(listener: Listener<T, R>): boolean {\n return this.listeners.indexOf(listener) !== -1;\n }\n\n /**\n * Removes a listener from the event.\n * @param listener - The listener to remove.\n */\n off(listener: Listener<T, R>): void {\n let index = this.listeners.indexOf(listener);\n while (~index) {\n this.listeners.splice(index, 1);\n index = this.listeners.indexOf(listener);\n }\n }\n\n /**\n * Adds a listener to the event.\n * @param listener - The listener to add.\n * @returns An object that can be used to remove the listener.\n */\n on(listener: Listener<T, R>): Dismiss {\n this.listeners.push(listener);\n return new Dismiss(() => this.off(listener));\n }\n\n /**\n * Adds a listener to the event that will only be called once.\n * @param listener - The listener to add.\n * @returns An object that can be used to remove the listener.\n */\n once(listener: Listener<T, R>): Dismiss {\n const oneTimeListener = (...args: T) => {\n this.off(oneTimeListener);\n return listener(...args);\n };\n return this.on(oneTimeListener);\n }\n\n /**\n * Removes all listeners from the event.\n */\n clear(): void {\n this.listeners.splice(0);\n }\n\n /**\n * Returns a Promise that resolves with the first emitted by the event arguments.\n * @returns A Promise that resolves with the first emitted by the event.\n */\n toPromise(): Promise<T> {\n return new Promise((resolve) => this.once((...args) => resolve(args)));\n }\n\n /**\n * Returns a new event that only triggers when the provided filter function returns `true`.\n * @example\n * const spacePressEvent = keyboardEvent.filter((key) => key === 'Space');\n *\n * @param filter The filter function to apply to the event.\n * @returns A new event that only triggers when the provided filter function returns `true`.\n */\n filter<F extends T>(filter: Filter<T>): Event<F, R> {\n const dispose = this.on(async (...args: T) => {\n if (filteredEvent.size > 0 && (await filter(...args))) {\n await filteredEvent(...(args as F));\n }\n });\n const filteredEvent = new Event<F, R>(dispose);\n return filteredEvent;\n }\n\n /**\n * Returns a new event that will only be triggered once the provided filter function returns `true`.\n * @example\n * const escPressEvent = keyboardEvent.first((key) => key === 'Esc');\n * await escPressEvent.toPromise();\n *\n * @param filter - The filter function.\n * @returns A new event that will only be triggered once the provided filter function returns `true`.\n */\n first<F extends T>(filter: Filter<T>): Event<F, R> {\n const dispose = this.on(async (...args: T) => {\n if (filteredEvent.size > 0 && (await filter(...args))) {\n dispose();\n await filteredEvent(...(args as F));\n }\n });\n const filteredEvent = new Event<F, R>(dispose);\n return filteredEvent;\n }\n\n /**\n * Returns a new event that maps the values of this event using the provided mapper function.\n * @example\n * const keyPressEvent = keyboardEvent.map((key) => key.toUpperCase()); // ['a'] -> ['A']\n *\n * @param mapper A function that maps the values of this event to a new value.\n * @returns A new event that emits the mapped values.\n */\n map<M, MR = unknown>(mapper: Mapper<T, M>): Event<[M], MR> {\n const dispose = this.on(async (...args) => {\n if (mappedEvent.size > 0) {\n const value = await mapper(...args);\n mappedEvent(value);\n }\n });\n const mappedEvent = new Event<[M], MR>(dispose);\n return mappedEvent;\n }\n\n /**\n * Returns a new event that reduces the emitted values using the provided reducer function.\n * @example\n * const sumEvent = numberEvent.reduce((a, b) => a + b, 0);\n * sumEvent.on((sum) => console.log(sum)); // 1, 3, 6\n * sumEvent(1);\n * sumEvent(2);\n * sumEvent(3);\n *\n * @typeParam A The type of the accumulated value.\n * @typeParam AR The type of the reduced value.\n * @param {Reducer<T, A>} reducer The reducer function that accumulates the values emitted by this `Event`.\n * @param {A} init The initial value of the accumulated value.\n * @returns {Event<[A], AR>} A new `Event` that emits the reduced value.\n */\n reduce<A, AR = unknown>(reducer: Reducer<T, A>, init: A): Event<[A], AR> {\n let value = init;\n const dispose = this.on(async (...args) => {\n if (reducedEvent.size > 0) {\n value = await reducer(value, ...args);\n reducedEvent(value);\n }\n });\n const reducedEvent = new Event<[A], AR>(dispose);\n return reducedEvent;\n }\n\n /**\n * Returns a new debounced event that will not fire until a certain amount of time has passed\n * since the last time it was triggered.\n * @example\n * const debouncedEvent = textInputEvent.debounce(100);\n * debouncedEvent.on((str) => console.log(str)); // 'test'\n * event('t');\n * event('te');\n * event('tes');\n * event('test');\n *\n * @param interval - The amount of time to wait before firing the debounced event, in milliseconds.\n * @returns A new debounced event.\n */\n debounce(interval: number): Event<T, R> {\n let timer: ReturnType<typeof setTimeout>;\n const dispose = this.on((...args) => {\n clearTimeout(timer);\n timer = setTimeout(() => debouncedEvent(...args), interval);\n });\n const debouncedEvent = new Event<T, R>(dispose);\n return debouncedEvent;\n }\n}\n\n/**\n * Returns a promise that resolves with the arguments passed to the first invocation of the given event.\n * @example\n * const [x, y] = await once(mouseEvent);\n *\n * @param event The event to listen for.\n * @returns A promise that resolves with the arguments passed to the first invocation of the given event.\n */\nexport const once = <T extends unknown[], R = void>(event: Event<T, R>): Promise<T> => {\n return new Promise((resolve) => event.once((...args) => resolve(args)));\n};\n\n/**\n * Creates a new event instance.\n *\n * @typeParam T - An array of argument types that the event will accept.\n * @typeParam R - The return type of the event handler function.\n * @returns A new instance of the `Event` class.\n *\n * @example\n * const myEvent = createEvent<[string], number>();\n * myEvent.on((str: string) => str.length);\n * await myEvent('hello'); // [5]\n */\nexport const createEvent = <T extends unknown[], R = void>(): Event<T, R> => {\n return new Event<T, R>();\n};\n\nexport default createEvent;\n\n/**\n * A type helper that extracts the event listener type\n *\n * @typeParam E - The event type.\n */\nexport type EventHandler<E> = E extends Event<infer T, infer R> ? Listener<T, R> : never;\n\n/**\n * A type helper that extracts the event filter type\n *\n * @typeParam E The event type to filter.\n */\nexport type EventFilter<E> = Filter<EventParameters<E>>;\n\n/**\n * A type helper that extracts the event mapper type\n *\n * @typeParam E The event type to map.\n * @typeParam M The new type to map `E` to.\n */\nexport type EventMapper<E, M> = Mapper<EventParameters<E>, M>;\n\n/**\n * A type helper that extracts the event mapper type\n *\n * @typeParam E The type of event to reduce.\n * @typeParam M The type of reduced event.\n */\nexport type EventReducer<E, R> = Reducer<EventParameters<E>, R>;\n"],"names":["FunctionExt","Function","constructor","func","Object","setPrototypeOf","prototype","Dismiss","callback","after","task","afterTimes","count","eventEmitter","listeners","args","Promise","all","map","listener","Event","merge","events","mergedEvent","forEach","event","on","interval","counter","intervalEvent","clearInterval","timerId","setInterval","dispose","fn","clear","size","length","lacks","indexOf","has","off","index","splice","push","once","oneTimeListener","toPromise","resolve","filter","filteredEvent","first","mapper","mappedEvent","value","reduce","reducer","init","reducedEvent","debounce","timer","clearTimeout","setTimeout","debouncedEvent","createEvent"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["export type MaybePromise<T> = Promise<T> | PromiseLike<T> | T;\n\nexport interface Callback<R = void> {\n (): MaybePromise<R>;\n}\n\nexport interface Listener<T, R = unknown> {\n (event: T): MaybePromise<R | void>;\n}\n\nexport interface Result<T, E> {\n ok: boolean;\n result: T | E;\n}\n\nexport interface FilterFunction<T> {\n (event: T): MaybePromise<boolean>;\n}\n\nexport interface Predicate<T, P extends T> {\n (event: T): event is P;\n}\n\nexport type Filter<T, P extends T> = Predicate<T, P> | FilterFunction<T>;\n\nexport interface Mapper<T, R> {\n (event: T): MaybePromise<R>;\n}\n\nexport interface Reducer<T, R> {\n (result: R, event: T): MaybePromise<R>;\n}\n\nexport type Listeners<T, R> = Listener<T, R>[];\n\n/**\n * An abstract class that extends the built-in Function class. It allows instances of the class\n * to be called as functions. When an instance of FunctionExt is called as a function, it will\n * call the function passed to its constructor with the same arguments.\n * @internal\n */\nexport abstract class FunctionExt extends Function {\n constructor(func: Function) {\n super();\n return Object.setPrototypeOf(func, new.target.prototype);\n }\n}\n\nexport interface Dismiss {\n (): MaybePromise<void>;\n}\n\n/**\n * @internal\n */\nexport class Dismiss extends FunctionExt {\n constructor(callback: Callback) {\n super(callback);\n }\n\n pre(callback: Callback): Dismiss {\n return new Dismiss(async () => {\n await callback();\n await this();\n });\n }\n\n post(callback: Callback): Dismiss {\n return new Dismiss(async () => {\n await this();\n await callback();\n });\n }\n\n countdown(count: number): Dismiss {\n return new Dismiss(async () => {\n if (!--count) {\n await this();\n }\n });\n }\n}\n\nconst eventEmitter = <A, R>(listeners: Listeners<A, R>, event: A): Promise<(void | R)[]> => Promise.all(listeners.map((listener) => listener(event)));\n\ntype EventType<T> = T extends undefined ? void : T;\n\nexport interface Event<T = unknown, R = void> {\n (event?: EventType<T>): Promise<(R | undefined)[]>;\n}\n\nexport type EventParameters<T> = T extends Event<infer P, unknown> ? P : never;\n\nexport type EventResult<T> = T extends Event<unknown, infer R> ? R : never;\n\nexport type AllEventsParameters<T extends Event<unknown, unknown>[]> = { [K in keyof T]: EventParameters<T[K]> }[number];\n\nexport type AllEventsResults<T extends Event<unknown, unknown>[]> = { [K in keyof T]: EventResult<T[K]> }[number];\n\n/**\n * A class representing an anonymous event that can be listened to or triggered.\n *\n * @typeParam T - The tuple of arguments that the event takes.\n * @typeParam R - The return type of the event.\n */\nexport class Event<T, R> extends FunctionExt {\n /**\n * The array of listeners for the event.\n */\n private listeners: Listeners<T, R>;\n\n /**\n * A function that disposes of the event and its listeners.\n */\n readonly dispose: Callback;\n\n /**\n * Creates a new event.\n * @example\n * // Create a click event.\n * const clickEvent = new Event<[x: number, y: number], void>();\n * clickEvent.on((x, y) => console.log(`Clicked at ${x}, ${y}`));\n *\n * @param dispose - A function to call on the event disposal.\n */\n constructor(dispose?: Callback) {\n const listeners: Listeners<T, R> = [];\n const fn = (event: T) => eventEmitter(listeners, event);\n\n super(fn);\n this.listeners = listeners;\n this.dispose = async () => {\n this.clear();\n await dispose?.();\n };\n }\n\n /**\n * The number of listeners for the event.\n */\n get size(): number {\n return this.listeners.length;\n }\n\n /**\n * Checks if a listener is not registered for the event.\n * @param listener - The listener to check.\n * @returns `true` if the listener is not registered, `false` otherwise.\n */\n lacks(listener: Listener<T, R>): boolean {\n return this.listeners.indexOf(listener) === -1;\n }\n\n /**\n * Checks if a listener is registered for the event.\n * @param listener - The listener to check.\n * @returns `true` if the listener is registered, `false` otherwise.\n */\n has(listener: Listener<T, R>): boolean {\n return this.listeners.indexOf(listener) !== -1;\n }\n\n /**\n * Removes a listener from the event.\n * @param listener - The listener to remove.\n */\n off(listener: Listener<T, R>): void {\n let index = this.listeners.indexOf(listener);\n while (~index) {\n this.listeners.splice(index, 1);\n index = this.listeners.indexOf(listener);\n }\n }\n\n /**\n * Adds a listener to the event.\n * @param listener - The listener to add.\n * @returns An object that can be used to remove the listener.\n */\n on(listener: Listener<T, R>): Dismiss {\n this.listeners.push(listener);\n return new Dismiss(() => this.off(listener));\n }\n\n /**\n * Adds a listener to the event that will only be called once.\n * @param listener - The listener to add.\n * @returns An object that can be used to remove the listener.\n */\n once(listener: Listener<T, R>): Dismiss {\n const oneTimeListener = (event: T) => {\n this.off(oneTimeListener);\n return listener(event);\n };\n return this.on(oneTimeListener);\n }\n\n /**\n * Returns a Promise that resolves with the first emitted by the event arguments.\n * @returns A Promise that resolves with the first emitted by the event.\n */\n onceAsync(): Promise<T> {\n return new Promise((resolve) => this.once((event) => resolve(event)));\n }\n\n /**\n * Removes all listeners from the event.\n */\n clear(): void {\n this.listeners.splice(0);\n }\n\n /**\n * Returns a new event that only triggers when the provided filter function returns `true`.\n * @example\n * const spacePressEvent = keyboardEvent.filter((key) => key === 'Space');\n *\n * @param filter The filter function to apply to the event.\n * @returns A new event that only triggers when the provided filter function returns `true`.\n */\n filter<P extends T>(predicate: Predicate<T, P>): Event<P, R>;\n filter<P extends T>(filter: FilterFunction<T>): Event<P, R>;\n filter<P extends T>(filter: Filter<T, P>): Event<P, R> {\n const dispose = this.on(async (event: T) => {\n if (filteredEvent.size > 0 && (await filter(event))) {\n await filteredEvent(event as EventType<P>);\n }\n });\n const filteredEvent = new Event<P, R>(dispose);\n return filteredEvent;\n }\n\n /**\n * Returns a new event that will only be triggered once the provided filter function returns `true`.\n * @example\n * const escPressEvent = keyboardEvent.first((key) => key === 'Esc');\n * await escPressEvent.toPromise();\n *\n * @param filter - The filter function.\n * @returns A new event that will only be triggered once the provided filter function returns `true`.\n */\n first<P extends T>(predicate: Predicate<T, P>): Event<P, R>;\n first<P extends T>(filter: FilterFunction<T>): Event<P, R>;\n first<P extends T>(filter: Filter<T, P>): Event<P, R> {\n const dispose = this.on(async (event: T) => {\n if (filteredEvent.size > 0 && (await filter(event))) {\n await dispose();\n await filteredEvent(event as EventType<P>);\n }\n });\n const filteredEvent = new Event<P, R>(dispose);\n return filteredEvent;\n }\n\n /**\n * Returns a new promise that will be resolved once the provided filter function returns `true`.\n * @example\n * const escPressEvent = await keyboardEvent.firstAsync((key) => key === 'Esc');\n *\n * @param filter - The filter function.\n * @returns A new promise that will be resolved once the provided filter function returns `true`.\n */\n firstAsync<P extends T>(predicate: Predicate<T, P>): Promise<P>;\n firstAsync<P extends T>(filter: FilterFunction<T>): Promise<P>;\n firstAsync<P extends T>(filter: Filter<T, P>): Promise<P> {\n return this.first<P>(filter).onceAsync();\n }\n\n /**\n * Returns a new event that maps the values of this event using the provided mapper function.\n * @example\n * const keyPressEvent = keyboardEvent.map((key) => key.toUpperCase()); // ['a'] -> ['A']\n *\n * @param mapper A function that maps the values of this event to a new value.\n * @returns A new event that emits the mapped values.\n */\n map<M, MR = R>(mapper: Mapper<T, M>): Event<M, MR> {\n const dispose = this.on(async (event) => {\n if (mappedEvent.size > 0) {\n const value = await mapper(event);\n await mappedEvent(value as EventType<M>);\n }\n });\n const mappedEvent = new Event<M, MR>(dispose);\n return mappedEvent;\n }\n\n /**\n * Returns a new event that reduces the emitted values using the provided reducer function.\n * @example\n * const sumEvent = numberEvent.reduce((a, b) => a + b, 0);\n * sumEvent.on((sum) => console.log(sum)); // 1, 3, 6\n * sumEvent(1);\n * sumEvent(2);\n * sumEvent(3);\n *\n * @typeParam A The type of the accumulated value.\n * @typeParam AR The type of the reduced value.\n * @param {Reducer<T, A>} reducer The reducer function that accumulates the values emitted by this `Event`.\n * @param {A} init The initial value of the accumulated value.\n * @returns {Event<[A], AR>} A new `Event` that emits the reduced value.\n */\n reduce<A, AR = R>(reducer: Reducer<T, A>, init: A): Event<A, AR> {\n let value = init;\n const dispose = this.on(async (event) => {\n if (reducedEvent.size > 0) {\n value = await reducer(value, event);\n await reducedEvent(value as EventType<A>);\n }\n });\n const reducedEvent = new Event<A, AR>(dispose);\n return reducedEvent;\n }\n\n /**\n * Returns a new debounced event that will not fire until a certain amount of time has passed\n * since the last time it was triggered.\n * @example\n * const debouncedEvent = textInputEvent.debounce(100);\n * debouncedEvent.on((str) => console.log(str)); // 'test'\n * event('t');\n * event('te');\n * event('tes');\n * event('test');\n *\n * @param interval - The amount of time to wait before firing the debounced event, in milliseconds.\n * @returns A new debounced event.\n */\n debounce(interval: number): Event<T, R> {\n let timer: ReturnType<typeof setTimeout>;\n const dispose = this.on((event) => {\n clearTimeout(timer);\n timer = setTimeout(() => debouncedEvent(event as EventType<T>), interval);\n });\n const debouncedEvent = new Event<T, R>(dispose);\n return debouncedEvent;\n }\n}\n\n/**\n * Merges multiple events into a single event.\n * @example\n * const inputEvent = Event.merge(mouseEvent, keyboardEvent);\n *\n * @param events - The events to merge.\n * @returns The merged event.\n */\nexport const merge = <Events extends Event<any, any>[]>(...events: Events): Event<AllEventsParameters<Events>, AllEventsResults<Events>> => {\n const mergedEvent = new Event<AllEventsParameters<Events>, AllEventsResults<Events>>();\n events.forEach((event) => event.on(mergedEvent));\n return mergedEvent;\n};\n\n/**\n * Creates an event that triggers at a specified interval.\n * @example\n * const tickEvent = Event.interval(1000);\n * tickEvent.on((tickNumber) => console.log(tickNumber));\n *\n * @param interval - The interval at which to trigger the event.\n * @returns The interval event.\n */\nexport const createInterval = <R = void>(interval: number): Event<number, R> => {\n let counter = 0;\n const intervalEvent = new Event<number, R>(() => clearInterval(timerId));\n const timerId: ReturnType<typeof setInterval> = setInterval(() => intervalEvent(counter++), interval);\n return intervalEvent;\n};\n\n/**\n * Creates a new event instance.\n *\n * @typeParam T - An array of argument types that the event will accept.\n * @typeParam R - The return type of the event handler function.\n * @returns A new instance of the `Event` class.\n *\n * @example\n * const myEvent = createEvent<[string], number>();\n * myEvent.on((str: string) => str.length);\n * await myEvent('hello'); // [5]\n */\nexport const createEvent = <T, R = void>(): Event<T, R> => new Event<T, R>();\n\nexport default createEvent;\n\n/**\n * A type helper that extracts the event listener type\n *\n * @typeParam E - The event type.\n */\nexport type EventHandler<E> = E extends Event<infer T, infer R> ? Listener<T, R> : never;\n\n/**\n * A type helper that extracts the event filter type\n *\n * @typeParam E The event type to filter.\n */\nexport type EventFilter<E> = FilterFunction<EventParameters<E>>;\n\n/**\n * A type helper that extracts the event predicate type\n *\n * @typeParam E The event type to predicate.\n */\nexport type EventPredicate<E, P extends EventParameters<E>> = Predicate<EventParameters<E>, P>;\n\n/**\n * A type helper that extracts the event mapper type\n *\n * @typeParam E The event type to map.\n * @typeParam M The new type to map `E` to.\n */\nexport type EventMapper<E, M> = Mapper<EventParameters<E>, M>;\n\n/**\n * A type helper that extracts the event mapper type\n *\n * @typeParam E The type of event to reduce.\n * @typeParam M The type of reduced event.\n */\nexport type EventReducer<E, R> = Reducer<EventParameters<E>, R>;\n"],"names":["FunctionExt","Function","constructor","func","Object","setPrototypeOf","prototype","Dismiss","callback","pre","post","countdown","count","eventEmitter","listeners","event","Promise","all","map","listener","Event","dispose","fn","clear","size","length","lacks","indexOf","has","off","index","splice","on","push","once","oneTimeListener","onceAsync","resolve","filter","filteredEvent","first","firstAsync","mapper","mappedEvent","value","reduce","reducer","init","reducedEvent","debounce","interval","timer","clearTimeout","setTimeout","debouncedEvent","merge","events","mergedEvent","forEach","createInterval","counter","intervalEvent","clearInterval","timerId","setInterval","createEvent"],"mappings":"AAyCA,OAAO,MAAeA,oBAAoBC;IACxCC,YAAYC,IAAc,CAAE;QAC1B,KAAK;QACL,OAAOC,OAAOC,cAAc,CAACF,MAAM,WAAWG,SAAS;IACzD;AACF;AASA,OAAO,MAAMC,gBAAgBP;IAC3BE,YAAYM,QAAkB,CAAE;QAC9B,KAAK,CAACA;IACR;IAEAC,IAAID,QAAkB,EAAW;QAC/B,OAAO,IAAID,QAAQ;YACjB,MAAMC;YACN,MAAM,IAAI;QACZ;IACF;IAEAE,KAAKF,QAAkB,EAAW;QAChC,OAAO,IAAID,QAAQ;YACjB,MAAM,IAAI;YACV,MAAMC;QACR;IACF;IAEAG,UAAUC,KAAa,EAAW;QAChC,OAAO,IAAIL,QAAQ;YACjB,IAAI,CAAC,EAAEK,OAAO;gBACZ,MAAM,IAAI;YACZ;QACF;IACF;AACF;AAEA,MAAMC,eAAe,CAAOC,WAA4BC,QAAoCC,QAAQC,GAAG,CAACH,UAAUI,GAAG,CAAC,CAACC,WAAaA,SAASJ;AAsB7I,OAAO,MAAMK,cAAoBpB;IAIvBc,UAA2B;IAK1BO,QAAkB;IAW3BnB,YAAYmB,OAAkB,CAAE;QAC9B,MAAMP,YAA6B,EAAE;QACrC,MAAMQ,KAAK,CAACP,QAAaF,aAAaC,WAAWC;QAEjD,KAAK,CAACO;QACN,IAAI,CAACR,SAAS,GAAGA;QACjB,IAAI,CAACO,OAAO,GAAG;YACb,IAAI,CAACE,KAAK;YACV,MAAMF;QACR;IACF;IAKA,IAAIG,OAAe;QACjB,OAAO,IAAI,CAACV,SAAS,CAACW,MAAM;IAC9B;IAOAC,MAAMP,QAAwB,EAAW;QACvC,OAAO,IAAI,CAACL,SAAS,CAACa,OAAO,CAACR,cAAc,CAAC;IAC/C;IAOAS,IAAIT,QAAwB,EAAW;QACrC,OAAO,IAAI,CAACL,SAAS,CAACa,OAAO,CAACR,cAAc,CAAC;IAC/C;IAMAU,IAAIV,QAAwB,EAAQ;QAClC,IAAIW,QAAQ,IAAI,CAAChB,SAAS,CAACa,OAAO,CAACR;QACnC,MAAO,CAACW,MAAO;YACb,IAAI,CAAChB,SAAS,CAACiB,MAAM,CAACD,OAAO;YAC7BA,QAAQ,IAAI,CAAChB,SAAS,CAACa,OAAO,CAACR;QACjC;IACF;IAOAa,GAAGb,QAAwB,EAAW;QACpC,IAAI,CAACL,SAAS,CAACmB,IAAI,CAACd;QACpB,OAAO,IAAIZ,QAAQ,IAAM,IAAI,CAACsB,GAAG,CAACV;IACpC;IAOAe,KAAKf,QAAwB,EAAW;QACtC,MAAMgB,kBAAkB,CAACpB;YACvB,IAAI,CAACc,GAAG,CAACM;YACT,OAAOhB,SAASJ;QAClB;QACA,OAAO,IAAI,CAACiB,EAAE,CAACG;IACjB;IAMAC,YAAwB;QACtB,OAAO,IAAIpB,QAAQ,CAACqB,UAAY,IAAI,CAACH,IAAI,CAAC,CAACnB,QAAUsB,QAAQtB;IAC/D;IAKAQ,QAAc;QACZ,IAAI,CAACT,SAAS,CAACiB,MAAM,CAAC;IACxB;IAYAO,OAAoBA,MAAoB,EAAe;QACrD,MAAMjB,UAAU,IAAI,CAACW,EAAE,CAAC,OAAOjB;YAC7B,IAAIwB,cAAcf,IAAI,GAAG,KAAM,MAAMc,OAAOvB,QAAS;gBACnD,MAAMwB,cAAcxB;YACtB;QACF;QACA,MAAMwB,gBAAgB,IAAInB,MAAYC;QACtC,OAAOkB;IACT;IAaAC,MAAmBF,MAAoB,EAAe;QACpD,MAAMjB,UAAU,IAAI,CAACW,EAAE,CAAC,OAAOjB;YAC7B,IAAIwB,cAAcf,IAAI,GAAG,KAAM,MAAMc,OAAOvB,QAAS;gBACnD,MAAMM;gBACN,MAAMkB,cAAcxB;YACtB;QACF;QACA,MAAMwB,gBAAgB,IAAInB,MAAYC;QACtC,OAAOkB;IACT;IAYAE,WAAwBH,MAAoB,EAAc;QACxD,OAAO,IAAI,CAACE,KAAK,CAAIF,QAAQF,SAAS;IACxC;IAUAlB,IAAewB,MAAoB,EAAgB;QACjD,MAAMrB,UAAU,IAAI,CAACW,EAAE,CAAC,OAAOjB;YAC7B,IAAI4B,YAAYnB,IAAI,GAAG,GAAG;gBACxB,MAAMoB,QAAQ,MAAMF,OAAO3B;gBAC3B,MAAM4B,YAAYC;YACpB;QACF;QACA,MAAMD,cAAc,IAAIvB,MAAaC;QACrC,OAAOsB;IACT;IAiBAE,OAAkBC,OAAsB,EAAEC,IAAO,EAAgB;QAC/D,IAAIH,QAAQG;QACZ,MAAM1B,UAAU,IAAI,CAACW,EAAE,CAAC,OAAOjB;YAC7B,IAAIiC,aAAaxB,IAAI,GAAG,GAAG;gBACzBoB,QAAQ,MAAME,QAAQF,OAAO7B;gBAC7B,MAAMiC,aAAaJ;YACrB;QACF;QACA,MAAMI,eAAe,IAAI5B,MAAaC;QACtC,OAAO2B;IACT;IAgBAC,SAASC,QAAgB,EAAe;QACtC,IAAIC;QACJ,MAAM9B,UAAU,IAAI,CAACW,EAAE,CAAC,CAACjB;YACvBqC,aAAaD;YACbA,QAAQE,WAAW,IAAMC,eAAevC,QAAwBmC;QAClE;QACA,MAAMI,iBAAiB,IAAIlC,MAAYC;QACvC,OAAOiC;IACT;AACF;AAUA,OAAO,MAAMC,QAAQ,CAAmC,GAAGC;IACzD,MAAMC,cAAc,IAAIrC;IACxBoC,OAAOE,OAAO,CAAC,CAAC3C,QAAUA,MAAMiB,EAAE,CAACyB;IACnC,OAAOA;AACT,EAAE;AAWF,OAAO,MAAME,iBAAiB,CAAWT;IACvC,IAAIU,UAAU;IACd,MAAMC,gBAAgB,IAAIzC,MAAiB,IAAM0C,cAAcC;IAC/D,MAAMA,UAA0CC,YAAY,IAAMH,cAAcD,YAAYV;IAC5F,OAAOW;AACT,EAAE;AAcF,OAAO,MAAMI,cAAc,IAAgC,IAAI7C,QAAc;AAE7E,eAAe6C,YAAY"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "evnty",
|
|
3
|
-
"description": "0-Deps, simple, fast, for browser and node js anonymous event library",
|
|
4
|
-
"version": "1.
|
|
3
|
+
"description": "0-Deps, simple, fast, for browser and node js reactive anonymous event library",
|
|
4
|
+
"version": "2.1.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"types": "build/index.d.ts",
|
|
7
7
|
"main": "build/index.cjs",
|
|
@@ -12,16 +12,10 @@
|
|
|
12
12
|
},
|
|
13
13
|
"files": [
|
|
14
14
|
"build",
|
|
15
|
-
"src/index.ts"
|
|
15
|
+
"src/index.ts",
|
|
16
|
+
"src/__tests__/example.js"
|
|
16
17
|
],
|
|
17
18
|
"sideEffects": false,
|
|
18
|
-
"scripts": {
|
|
19
|
-
"build": "rm -rf build && inop src build -i __tests__ -i *.tmp.ts && tsc --declaration --emitDeclarationOnly",
|
|
20
|
-
"test": "jest",
|
|
21
|
-
"test:build": "node src/__tests__/index.cjs && node src/__tests__/index.mjs",
|
|
22
|
-
"lint": "eslint src",
|
|
23
|
-
"prepare": "husky install"
|
|
24
|
-
},
|
|
25
19
|
"repository": {
|
|
26
20
|
"type": "git",
|
|
27
21
|
"url": "git+https://github.com/3axap4eHko/evnty.git"
|
|
@@ -34,7 +28,13 @@
|
|
|
34
28
|
"emitter",
|
|
35
29
|
"anonymous",
|
|
36
30
|
"flow",
|
|
37
|
-
"event-driven"
|
|
31
|
+
"event-driven",
|
|
32
|
+
"reactive",
|
|
33
|
+
"reactivity",
|
|
34
|
+
"react",
|
|
35
|
+
"signal",
|
|
36
|
+
"functional",
|
|
37
|
+
"stream"
|
|
38
38
|
],
|
|
39
39
|
"runkitExampleFilename": "src/__tests__/example.js",
|
|
40
40
|
"funding": "https://github.com/sponsors/3axap4eHko",
|
|
@@ -49,19 +49,26 @@
|
|
|
49
49
|
},
|
|
50
50
|
"homepage": "https://github.com/3axap4eHko/evnty#readme",
|
|
51
51
|
"devDependencies": {
|
|
52
|
-
"@swc/jest": "^0.2.
|
|
53
|
-
"@types/jest": "^29.5.
|
|
54
|
-
"@
|
|
55
|
-
"@typescript-eslint/
|
|
56
|
-
"eslint": "^
|
|
52
|
+
"@swc/jest": "^0.2.29",
|
|
53
|
+
"@types/jest": "^29.5.5",
|
|
54
|
+
"@types/node": "^20.8.2",
|
|
55
|
+
"@typescript-eslint/eslint-plugin": "^6.7.4",
|
|
56
|
+
"@typescript-eslint/parser": "^6.7.4",
|
|
57
|
+
"eslint": "^8.50.0",
|
|
57
58
|
"eslint-config-airbnb-base": "^15.0.0",
|
|
58
59
|
"eslint-config-prettier": "^9.0.0",
|
|
59
|
-
"eslint-plugin-import": "^2.
|
|
60
|
+
"eslint-plugin-import": "^2.28.1",
|
|
60
61
|
"eslint-plugin-prettier": "^5.0.0",
|
|
61
62
|
"husky": "^8.0.3",
|
|
62
63
|
"inop": "^0.4.2",
|
|
63
|
-
"jest": "^29.
|
|
64
|
-
"prettier": "^3.0.
|
|
65
|
-
"typescript": "^5.
|
|
64
|
+
"jest": "^29.7.0",
|
|
65
|
+
"prettier": "^3.0.3",
|
|
66
|
+
"typescript": "^5.2.2"
|
|
67
|
+
},
|
|
68
|
+
"scripts": {
|
|
69
|
+
"build": "rm -rf build && inop src build -i __tests__ -i *.tmp.ts && tsc --declaration --emitDeclarationOnly",
|
|
70
|
+
"test": "jest",
|
|
71
|
+
"test:build": "node src/__tests__/index.cjs && node src/__tests__/index.mjs",
|
|
72
|
+
"lint": "eslint src"
|
|
66
73
|
}
|
|
67
|
-
}
|
|
74
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
const { createEvent, Event, once } = require('evnty');
|
|
2
|
+
|
|
3
|
+
// Creates a click event
|
|
4
|
+
const clickEvent = createEvent();
|
|
5
|
+
const handleClick = ({ button }) => console.log('Clicked button is', button);
|
|
6
|
+
const unsubscribeClick = clickEvent.on(handleClick);
|
|
7
|
+
|
|
8
|
+
// Creates a key press event
|
|
9
|
+
const keyPressEvent = createEvent();
|
|
10
|
+
const handleKeyPress = ({ key }) => console.log('Key pressed', key);
|
|
11
|
+
const unsubscribeKeyPress = keyPressEvent.on(handleKeyPress);
|
|
12
|
+
|
|
13
|
+
// Merges click and key press events into input event
|
|
14
|
+
const handleInput = (input) => console.log('Input', input);;
|
|
15
|
+
const inputEvent = Event.merge(clickEvent, keyPressEvent);
|
|
16
|
+
inputEvent.on(handleInput);
|
|
17
|
+
|
|
18
|
+
// Filters a click event to only include left-click events.
|
|
19
|
+
const handleLeftClick = () => console.log('Left button is clicked');
|
|
20
|
+
const leftClickEvent = clickEvent.filter(({ button }) => button === 'left');
|
|
21
|
+
leftClickEvent.on(handleLeftClick);
|
|
22
|
+
|
|
23
|
+
// Will press Enter after one second
|
|
24
|
+
setTimeout(keyPressEvent, 1000, { key: 'Enter' });
|
|
25
|
+
// Waits once the first Enter key press event occurs
|
|
26
|
+
await once(keyPressEvent.first(({ key }) => key === 'Enter'));
|
|
27
|
+
|
|
28
|
+
keyPressEvent({ key: 'W' });
|
|
29
|
+
keyPressEvent({ key: 'A' });
|
|
30
|
+
keyPressEvent({ key: 'S' });
|
|
31
|
+
keyPressEvent({ key: 'D' });
|
|
32
|
+
|
|
33
|
+
clickEvent({ button: 'right' });
|
|
34
|
+
clickEvent({ button: 'left' });
|
|
35
|
+
clickEvent({ button: 'middle' });
|
|
36
|
+
|
|
37
|
+
// Unsubscribe click listener
|
|
38
|
+
unsubscribeClick();
|
|
39
|
+
// It does not log anything because of click listener is unsubscribed
|
|
40
|
+
leftClickEvent.off(handleLeftClick);
|
|
41
|
+
|
|
42
|
+
// Unsubscribe key press listener once first Esc key press occur
|
|
43
|
+
unsubscribeKeyPress.after(() => once(keyPressEvent.first(({ key }) => key === 'Esc')));
|
|
44
|
+
// Press Esc to unsubscribe key press listener
|
|
45
|
+
keyPressEvent({ key: 'Esc' });
|