Skip to content

Commit cfbf7e7

Browse files
committed
Separate Package for @react-native/event-emitter
1 parent be8fe7a commit cfbf7e7

File tree

15 files changed

+2168
-160
lines changed

15 files changed

+2168
-160
lines changed

Libraries/vendor/emitter/EventEmitter.js

Lines changed: 8 additions & 136 deletions
Original file line numberDiff line numberDiff line change
@@ -8,139 +8,11 @@
88
* @format
99
*/
1010

11-
export interface EventSubscription {
12-
remove(): void;
13-
}
14-
15-
export interface IEventEmitter<TEventToArgsMap: {...}> {
16-
addListener<TEvent: $Keys<TEventToArgsMap>>(
17-
eventType: TEvent,
18-
listener: (...args: $ElementType<TEventToArgsMap, TEvent>) => mixed,
19-
context?: mixed,
20-
): EventSubscription;
21-
22-
emit<TEvent: $Keys<TEventToArgsMap>>(
23-
eventType: TEvent,
24-
...args: $ElementType<TEventToArgsMap, TEvent>
25-
): void;
26-
27-
removeAllListeners<TEvent: $Keys<TEventToArgsMap>>(eventType?: ?TEvent): void;
28-
29-
listenerCount<TEvent: $Keys<TEventToArgsMap>>(eventType: TEvent): number;
30-
}
31-
32-
interface Registration<TArgs> {
33-
+context: mixed;
34-
+listener: (...args: TArgs) => mixed;
35-
+remove: () => void;
36-
}
37-
38-
type Registry<TEventToArgsMap: {...}> = $ObjMap<
39-
TEventToArgsMap,
40-
<TArgs>(TArgs) => Set<Registration<TArgs>>,
41-
>;
42-
43-
/**
44-
* EventEmitter manages listeners and publishes events to them.
45-
*
46-
* EventEmitter accepts a single type parameter that defines the valid events
47-
* and associated listener argument(s).
48-
*
49-
* @example
50-
*
51-
* const emitter = new EventEmitter<{
52-
* success: [number, string],
53-
* error: [Error],
54-
* }>();
55-
*
56-
* emitter.on('success', (statusCode, responseText) => {...});
57-
* emitter.emit('success', 200, '...');
58-
*
59-
* emitter.on('error', error => {...});
60-
* emitter.emit('error', new Error('Resource not found'));
61-
*
62-
*/
63-
export default class EventEmitter<TEventToArgsMap: {...}>
64-
implements IEventEmitter<TEventToArgsMap>
65-
{
66-
_registry: Registry<TEventToArgsMap> = {};
67-
68-
/**
69-
* Registers a listener that is called when the supplied event is emitted.
70-
* Returns a subscription that has a `remove` method to undo registration.
71-
*/
72-
addListener<TEvent: $Keys<TEventToArgsMap>>(
73-
eventType: TEvent,
74-
listener: (...args: $ElementType<TEventToArgsMap, TEvent>) => mixed,
75-
context: mixed,
76-
): EventSubscription {
77-
const registrations = allocate(this._registry, eventType);
78-
const registration: Registration<$ElementType<TEventToArgsMap, TEvent>> = {
79-
context,
80-
listener,
81-
remove(): void {
82-
registrations.delete(registration);
83-
},
84-
};
85-
registrations.add(registration);
86-
return registration;
87-
}
88-
89-
/**
90-
* Emits the supplied event. Additional arguments supplied to `emit` will be
91-
* passed through to each of the registered listeners.
92-
*
93-
* If a listener modifies the listeners registered for the same event, those
94-
* changes will not be reflected in the current invocation of `emit`.
95-
*/
96-
emit<TEvent: $Keys<TEventToArgsMap>>(
97-
eventType: TEvent,
98-
...args: $ElementType<TEventToArgsMap, TEvent>
99-
): void {
100-
const registrations: ?Set<
101-
Registration<$ElementType<TEventToArgsMap, TEvent>>,
102-
> = this._registry[eventType];
103-
if (registrations != null) {
104-
for (const registration of [...registrations]) {
105-
registration.listener.apply(registration.context, args);
106-
}
107-
}
108-
}
109-
110-
/**
111-
* Removes all registered listeners.
112-
*/
113-
removeAllListeners<TEvent: $Keys<TEventToArgsMap>>(
114-
eventType?: ?TEvent,
115-
): void {
116-
if (eventType == null) {
117-
this._registry = {};
118-
} else {
119-
delete this._registry[eventType];
120-
}
121-
}
122-
123-
/**
124-
* Returns the number of registered listeners for the supplied event.
125-
*/
126-
listenerCount<TEvent: $Keys<TEventToArgsMap>>(eventType: TEvent): number {
127-
const registrations: ?Set<Registration<mixed>> = this._registry[eventType];
128-
return registrations == null ? 0 : registrations.size;
129-
}
130-
}
131-
132-
function allocate<
133-
TEventToArgsMap: {...},
134-
TEvent: $Keys<TEventToArgsMap>,
135-
TEventArgs: $ElementType<TEventToArgsMap, TEvent>,
136-
>(
137-
registry: Registry<TEventToArgsMap>,
138-
eventType: TEvent,
139-
): Set<Registration<TEventArgs>> {
140-
let registrations: ?Set<Registration<TEventArgs>> = registry[eventType];
141-
if (registrations == null) {
142-
registrations = new Set();
143-
registry[eventType] = registrations;
144-
}
145-
return registrations;
146-
}
11+
import type {
12+
EventSubscription,
13+
IEventEmitter,
14+
} from '@react-native/event-emitter';
15+
import EventEmitter from '@react-native/event-emitter';
16+
17+
export type {EventSubscription, IEventEmitter};
18+
export default EventEmitter;

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@
108108
"@react-native-community/cli-platform-android": "^9.0.0-alpha.10",
109109
"@react-native-community/cli-platform-ios": "^9.0.0-alpha.10",
110110
"@react-native/assets": "1.0.0",
111+
"@react-native/event-emitter": "^0.71.0",
111112
"@react-native/normalize-color": "2.0.0",
112113
"@react-native/polyfills": "2.0.0",
113114
"abort-controller": "^3.0.0",

packages/event-emitter/.babelrc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"presets": ["@babel/preset-flow"]
3+
}

packages/event-emitter/README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# @react-native/event-emitter
2+
3+
`@react-native/event-emitter` is an event library used by React Native that is
4+
published as an independent package so it can also be used by applications.
5+
6+
Consult the included type definitions for usage instructions.
7+
8+
## License
9+
10+
`idx` is [MIT licensed](./LICENSE).
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
/**
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*
7+
* @format
8+
*/
9+
10+
export interface EventSubscription {
11+
remove(): void;
12+
}
13+
14+
export interface IEventEmitter<TEventToArgsMap extends {[eventType: string]: unknown[]}> {
15+
addListener<TEvent extends keyof TEventToArgsMap>(
16+
eventType: TEvent,
17+
listener: (...args: TEventToArgsMap[TEvent]) => void,
18+
context?: unknown,
19+
): EventSubscription;
20+
21+
emit<TEvent extends keyof TEventToArgsMap>(
22+
eventType: TEvent,
23+
...args: TEventToArgsMap[TEvent]
24+
): void;
25+
26+
removeAllListeners<TEvent extends keyof TEventToArgsMap>(eventType?: TEvent | null): void;
27+
28+
listenerCount<TEvent extends keyof TEventToArgsMap>(eventType: TEvent): number;
29+
}
30+
31+
/**
32+
* EventEmitter manages listeners and publishes events to them.
33+
*
34+
* EventEmitter accepts a single type parameter that defines the valid events
35+
* and associated listener argument(s).
36+
*
37+
* @example
38+
*
39+
* const emitter = new EventEmitter<{
40+
* success: [number, string],
41+
* error: [Error],
42+
* }>();
43+
*
44+
* emitter.on('success', (statusCode, responseText) => {...});
45+
* emitter.emit('success', 200, '...');
46+
*
47+
* emitter.on('error', error => {...});
48+
* emitter.emit('error', new Error('Resource not found'));
49+
*
50+
*/
51+
export default class EventEmitter<TEventToArgsMap extends {[eventType: string]: unknown[]}> implements IEventEmitter<TEventToArgsMap> {
52+
/**
53+
* Registers a listener that is called when the supplied event is emitted.
54+
* Returns a subscription that has a `remove` method to undo registration.
55+
*/
56+
addListener<TEvent extends keyof TEventToArgsMap>(
57+
eventType: TEvent,
58+
listener: (...args: TEventToArgsMap[TEvent]) => void,
59+
context?: unknown,
60+
): EventSubscription;
61+
62+
/**
63+
* Emits the supplied event. Additional arguments supplied to `emit` will be
64+
* passed through to each of the registered listeners.
65+
*
66+
* If a listener modifies the listeners registered for the same event, those
67+
* changes will not be reflected in the current invocation of `emit`.
68+
*/
69+
emit<TEvent extends keyof TEventToArgsMap>(
70+
eventType: TEvent,
71+
...args: TEventToArgsMap[TEvent]
72+
): void;
73+
74+
/**
75+
* Removes all registered listeners.
76+
*/
77+
removeAllListeners<TEvent extends keyof TEventToArgsMap>(eventType?: TEvent | null): void;
78+
79+
/**
80+
* Returns the number of registered listeners for the supplied event.
81+
*/
82+
listenerCount<TEvent extends keyof TEventToArgsMap>(eventType: TEvent): number;
83+
}
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
/**
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*
7+
*
8+
* @format
9+
*/
10+
11+
/**
12+
* EventEmitter manages listeners and publishes events to them.
13+
*
14+
* EventEmitter accepts a single type parameter that defines the valid events
15+
* and associated listener argument(s).
16+
*
17+
* @example
18+
*
19+
* const emitter = new EventEmitter<{
20+
* success: [number, string],
21+
* error: [Error],
22+
* }>();
23+
*
24+
* emitter.on('success', (statusCode, responseText) => {...});
25+
* emitter.emit('success', 200, '...');
26+
*
27+
* emitter.on('error', error => {...});
28+
* emitter.emit('error', new Error('Resource not found'));
29+
*
30+
*/
31+
export default class EventEmitter {
32+
_registry = {};
33+
/**
34+
* Registers a listener that is called when the supplied event is emitted.
35+
* Returns a subscription that has a `remove` method to undo registration.
36+
*/
37+
38+
addListener(eventType, listener, context) {
39+
const registrations = allocate(this._registry, eventType);
40+
const registration = {
41+
context,
42+
listener,
43+
44+
remove() {
45+
registrations.delete(registration);
46+
},
47+
};
48+
registrations.add(registration);
49+
return registration;
50+
}
51+
/**
52+
* Emits the supplied event. Additional arguments supplied to `emit` will be
53+
* passed through to each of the registered listeners.
54+
*
55+
* If a listener modifies the listeners registered for the same event, those
56+
* changes will not be reflected in the current invocation of `emit`.
57+
*/
58+
59+
emit(eventType, ...args) {
60+
const registrations = this._registry[eventType];
61+
62+
if (registrations != null) {
63+
for (const registration of [...registrations]) {
64+
registration.listener.apply(registration.context, args);
65+
}
66+
}
67+
}
68+
/**
69+
* Removes all registered listeners.
70+
*/
71+
72+
removeAllListeners(eventType) {
73+
if (eventType == null) {
74+
this._registry = {};
75+
} else {
76+
delete this._registry[eventType];
77+
}
78+
}
79+
/**
80+
* Returns the number of registered listeners for the supplied event.
81+
*/
82+
83+
listenerCount(eventType) {
84+
const registrations = this._registry[eventType];
85+
return registrations == null ? 0 : registrations.size;
86+
}
87+
}
88+
89+
function allocate(registry, eventType) {
90+
let registrations = registry[eventType];
91+
92+
if (registrations == null) {
93+
registrations = new Set();
94+
registry[eventType] = registrations;
95+
}
96+
97+
return registrations;
98+
}

0 commit comments

Comments
 (0)