use-typed-event 0.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/dist/index.cjs ADDED
@@ -0,0 +1,159 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ createEmitter: () => createEmitter,
24
+ createSelectors: () => createSelectors
25
+ });
26
+ module.exports = __toCommonJS(index_exports);
27
+
28
+ // src/emitter.ts
29
+ var matchesHandler = (registered, target) => registered === target || typeof registered !== "function" && registered.handler === target;
30
+ var keyOf = (name) => typeof name === "string" ? name : String(name);
31
+ var copyWithout = (list, index) => {
32
+ const length = list.length;
33
+ const next = new Array(length - 1);
34
+ for (let i = 0; i < index; i++) next[i] = list[i];
35
+ for (let i = index + 1; i < length; i++) next[i - 1] = list[i];
36
+ return next;
37
+ };
38
+ var createEmitter = () => {
39
+ const handlers = /* @__PURE__ */ new Map();
40
+ let anyHandlers = [];
41
+ const removeFromList = (name, slot, target) => {
42
+ const length = slot.length;
43
+ let index = 0;
44
+ while (index < length && !matchesHandler(slot[index], target)) index++;
45
+ if (index === length) return;
46
+ if (length === 2) handlers.set(name, slot[1 - index]);
47
+ else handlers.set(name, copyWithout(slot, index));
48
+ };
49
+ const removeNamed = (name, target) => {
50
+ const slot = handlers.get(name);
51
+ if (slot === void 0) return;
52
+ if (Array.isArray(slot)) removeFromList(name, slot, target);
53
+ else if (matchesHandler(slot, target)) handlers.set(name, void 0);
54
+ };
55
+ const subscribe = (name, entry) => {
56
+ const key = keyOf(name);
57
+ const slot = handlers.get(key);
58
+ if (slot === void 0) handlers.set(key, entry);
59
+ else if (Array.isArray(slot)) slot.push(entry);
60
+ else handlers.set(key, [slot, entry]);
61
+ let active = true;
62
+ return () => {
63
+ if (!active) return;
64
+ active = false;
65
+ const current = handlers.get(key);
66
+ if (current === entry) handlers.set(key, void 0);
67
+ else if (Array.isArray(current)) removeFromList(key, current, entry);
68
+ };
69
+ };
70
+ const once = (name, handler) => subscribe(keyOf(name), { handler });
71
+ const off = (name, handler) => {
72
+ const key = keyOf(name);
73
+ if (!handler) {
74
+ handlers.delete(key);
75
+ return;
76
+ }
77
+ removeNamed(key, handler);
78
+ };
79
+ const emit = (name, payload) => {
80
+ const key = keyOf(name);
81
+ const slot = handlers.get(key);
82
+ if (slot !== void 0) {
83
+ if (typeof slot === "function") slot(payload);
84
+ else if (Array.isArray(slot)) {
85
+ const length = slot.length;
86
+ for (let i = 0; i < length; i++) {
87
+ const entry = slot[i];
88
+ if (typeof entry === "function") entry(payload);
89
+ else {
90
+ removeNamed(key, entry);
91
+ entry.handler(payload);
92
+ }
93
+ }
94
+ } else {
95
+ handlers.set(key, void 0);
96
+ slot.handler(payload);
97
+ }
98
+ }
99
+ const anyList = anyHandlers;
100
+ const anyLength = anyList.length;
101
+ for (let i = 0; i < anyLength; i++) anyList[i](key, payload);
102
+ };
103
+ const onAny = (handler) => {
104
+ anyHandlers.push(handler);
105
+ let active = true;
106
+ return () => {
107
+ if (!active) return;
108
+ active = false;
109
+ const index = anyHandlers.indexOf(handler);
110
+ if (index !== -1) anyHandlers = copyWithout(anyHandlers, index);
111
+ };
112
+ };
113
+ const waitFor = (name, options) => {
114
+ const key = keyOf(name);
115
+ const signal = options?.signal;
116
+ if (signal?.aborted) return Promise.reject(signal.reason);
117
+ return new Promise((resolve, reject) => {
118
+ const onAbort = () => {
119
+ unsubscribe();
120
+ reject(signal?.reason);
121
+ };
122
+ const unsubscribe = once(key, (payload) => {
123
+ signal?.removeEventListener("abort", onAbort);
124
+ resolve(payload);
125
+ });
126
+ signal?.addEventListener("abort", onAbort, { once: true });
127
+ });
128
+ };
129
+ const clear = () => {
130
+ handlers.clear();
131
+ anyHandlers = [];
132
+ };
133
+ return {
134
+ on: subscribe,
135
+ once,
136
+ off,
137
+ emit,
138
+ onAny,
139
+ waitFor,
140
+ clear
141
+ };
142
+ };
143
+
144
+ // src/selectors.ts
145
+ var build = (path) => new Proxy({}, {
146
+ get(_t, prop) {
147
+ if (prop === Symbol.toPrimitive || prop === "toString" || prop === "valueOf")
148
+ return () => path.join(".");
149
+ if (prop === "$") return path.join(".");
150
+ if (typeof prop === "symbol") return void 0;
151
+ return build([...path, prop]);
152
+ }
153
+ });
154
+ var createSelectors = () => build([]);
155
+ // Annotate the CommonJS export names for ESM import in node:
156
+ 0 && (module.exports = {
157
+ createEmitter,
158
+ createSelectors
159
+ });
@@ -0,0 +1,80 @@
1
+ /** Maps event names to their payload types. Use `void` for payload-less events. */
2
+ type EventMap = Record<string, unknown>;
3
+ /**
4
+ * Argument tuple for a payload of type `P`: no argument for `void` events,
5
+ * an optional argument when `undefined` is part of the payload type, and a
6
+ * required argument otherwise.
7
+ */
8
+ type PayloadArgs<P> = [P] extends [void] ? [] : undefined extends P ? [payload?: P] : [payload: P];
9
+ /** Handler invoked with the payload of a single event. */
10
+ type EventHandler<P> = (payload: P) => void;
11
+ /** Union of `[name, payload]` tuples across every event in the map. */
12
+ type EventTuple<E extends EventMap> = {
13
+ [K in keyof E & string]: [name: K, payload: E[K]];
14
+ }[keyof E & string];
15
+ /**
16
+ * Wildcard handler receiving `(name, payload)` for every emit. Narrowing on
17
+ * `name` narrows `payload` to the mapped type.
18
+ */
19
+ type AnyHandler<E extends EventMap> = (...event: EventTuple<E>) => void;
20
+ /** Detaches a previously registered handler. Safe to call more than once. */
21
+ type Unsubscribe = () => void;
22
+ /** Options for {@link Emitter.waitFor}. */
23
+ type WaitForOptions = {
24
+ /** Rejects the pending promise with `signal.reason` when aborted. */
25
+ signal?: AbortSignal;
26
+ };
27
+ /** A typed event emitter over the event map `E`. */
28
+ type Emitter<E extends EventMap> = {
29
+ /** Registers `handler` for `name`. Returns an idempotent unsubscribe. */
30
+ on: <K extends keyof E & string>(name: K, handler: EventHandler<E[K]>) => Unsubscribe;
31
+ /** Registers `handler` for `name`, invoked at most once. Returns an idempotent unsubscribe. */
32
+ once: <K extends keyof E & string>(name: K, handler: EventHandler<E[K]>) => Unsubscribe;
33
+ /**
34
+ * Removes the first registration of `handler` for `name` — including
35
+ * `once` registrations, matched by their original handler reference — or
36
+ * every handler for `name` when omitted.
37
+ */
38
+ off: <K extends keyof E & string>(name: K, handler?: EventHandler<E[K]>) => void;
39
+ /** Emits `name`, delivering the payload to named handlers first, then wildcard handlers. */
40
+ emit: <K extends keyof E & string>(name: K, ...args: PayloadArgs<E[K]>) => void;
41
+ /** Registers a wildcard handler for every event. Returns an idempotent unsubscribe. */
42
+ onAny: (handler: AnyHandler<E>) => Unsubscribe;
43
+ /** Resolves with the next payload of `name`; rejects with `signal.reason` on abort. */
44
+ waitFor: <K extends keyof E & string>(name: K, options?: WaitForOptions) => Promise<E[K]>;
45
+ /** Removes every named and wildcard handler. */
46
+ clear: () => void;
47
+ };
48
+
49
+ /**
50
+ * Creates a typed event emitter for the event map `E`.
51
+ */
52
+ declare const createEmitter: <E extends EventMap>() => Emitter<E>;
53
+
54
+ type After<K extends string, Prefix extends string> = K extends `${Prefix}${infer R}` ? R : never;
55
+ type HeadSeg<R extends string> = R extends `${infer H}.${string}` ? H : R;
56
+ /** The exact event key at `Prefix + Head`, or `never` if no such event exists. */
57
+ type Leaf<E extends EventMap, Prefix extends string, Head extends string> = `${Prefix}${Head}` & (keyof E & string);
58
+ /** The nested selector under `Prefix + Head + "."`, or `never` if nothing nests there. */
59
+ type Deeper<E extends EventMap, Prefix extends string, Head extends string> = After<keyof E & string, `${Prefix}${Head}.`> extends never ? never : EventSelectors<E, `${Prefix}${Head}.`>;
60
+ /**
61
+ * Nested selector object mirroring the dotted event keys of `E`. Each leaf is
62
+ * typed as its exact event key literal — `events.cart.add` has type `"cart.add"`
63
+ * — driving the same payload inference as the raw string. A key that is both a
64
+ * leaf and a prefix exposes its own key via the reserved `$` accessor:
65
+ * `events.cart.$` has type `"cart"`.
66
+ */
67
+ type EventSelectors<E extends EventMap, Prefix extends string = ""> = {
68
+ [Head in HeadSeg<After<keyof E & string, Prefix>>]: [Leaf<E, Prefix, Head>] extends [never] ? Deeper<E, Prefix, Head> : [Deeper<E, Prefix, Head>] extends [never] ? Leaf<E, Prefix, Head> : Deeper<E, Prefix, Head> & {
69
+ readonly $: Leaf<E, Prefix, Head>;
70
+ };
71
+ };
72
+ /**
73
+ * Builds a typed selector proxy for the event map `E`. Property access
74
+ * accumulates a path that coerces to the dotted event key —
75
+ * `String(createSelectors<E>().cart.add) === "cart.add"`. The reserved `$`
76
+ * accessor returns the current path as a plain string.
77
+ */
78
+ declare const createSelectors: <E extends EventMap>() => EventSelectors<E>;
79
+
80
+ export { type AnyHandler, type Emitter, type EventHandler, type EventMap, type EventSelectors, type EventTuple, type PayloadArgs, type Unsubscribe, type WaitForOptions, createEmitter, createSelectors };
@@ -0,0 +1,80 @@
1
+ /** Maps event names to their payload types. Use `void` for payload-less events. */
2
+ type EventMap = Record<string, unknown>;
3
+ /**
4
+ * Argument tuple for a payload of type `P`: no argument for `void` events,
5
+ * an optional argument when `undefined` is part of the payload type, and a
6
+ * required argument otherwise.
7
+ */
8
+ type PayloadArgs<P> = [P] extends [void] ? [] : undefined extends P ? [payload?: P] : [payload: P];
9
+ /** Handler invoked with the payload of a single event. */
10
+ type EventHandler<P> = (payload: P) => void;
11
+ /** Union of `[name, payload]` tuples across every event in the map. */
12
+ type EventTuple<E extends EventMap> = {
13
+ [K in keyof E & string]: [name: K, payload: E[K]];
14
+ }[keyof E & string];
15
+ /**
16
+ * Wildcard handler receiving `(name, payload)` for every emit. Narrowing on
17
+ * `name` narrows `payload` to the mapped type.
18
+ */
19
+ type AnyHandler<E extends EventMap> = (...event: EventTuple<E>) => void;
20
+ /** Detaches a previously registered handler. Safe to call more than once. */
21
+ type Unsubscribe = () => void;
22
+ /** Options for {@link Emitter.waitFor}. */
23
+ type WaitForOptions = {
24
+ /** Rejects the pending promise with `signal.reason` when aborted. */
25
+ signal?: AbortSignal;
26
+ };
27
+ /** A typed event emitter over the event map `E`. */
28
+ type Emitter<E extends EventMap> = {
29
+ /** Registers `handler` for `name`. Returns an idempotent unsubscribe. */
30
+ on: <K extends keyof E & string>(name: K, handler: EventHandler<E[K]>) => Unsubscribe;
31
+ /** Registers `handler` for `name`, invoked at most once. Returns an idempotent unsubscribe. */
32
+ once: <K extends keyof E & string>(name: K, handler: EventHandler<E[K]>) => Unsubscribe;
33
+ /**
34
+ * Removes the first registration of `handler` for `name` — including
35
+ * `once` registrations, matched by their original handler reference — or
36
+ * every handler for `name` when omitted.
37
+ */
38
+ off: <K extends keyof E & string>(name: K, handler?: EventHandler<E[K]>) => void;
39
+ /** Emits `name`, delivering the payload to named handlers first, then wildcard handlers. */
40
+ emit: <K extends keyof E & string>(name: K, ...args: PayloadArgs<E[K]>) => void;
41
+ /** Registers a wildcard handler for every event. Returns an idempotent unsubscribe. */
42
+ onAny: (handler: AnyHandler<E>) => Unsubscribe;
43
+ /** Resolves with the next payload of `name`; rejects with `signal.reason` on abort. */
44
+ waitFor: <K extends keyof E & string>(name: K, options?: WaitForOptions) => Promise<E[K]>;
45
+ /** Removes every named and wildcard handler. */
46
+ clear: () => void;
47
+ };
48
+
49
+ /**
50
+ * Creates a typed event emitter for the event map `E`.
51
+ */
52
+ declare const createEmitter: <E extends EventMap>() => Emitter<E>;
53
+
54
+ type After<K extends string, Prefix extends string> = K extends `${Prefix}${infer R}` ? R : never;
55
+ type HeadSeg<R extends string> = R extends `${infer H}.${string}` ? H : R;
56
+ /** The exact event key at `Prefix + Head`, or `never` if no such event exists. */
57
+ type Leaf<E extends EventMap, Prefix extends string, Head extends string> = `${Prefix}${Head}` & (keyof E & string);
58
+ /** The nested selector under `Prefix + Head + "."`, or `never` if nothing nests there. */
59
+ type Deeper<E extends EventMap, Prefix extends string, Head extends string> = After<keyof E & string, `${Prefix}${Head}.`> extends never ? never : EventSelectors<E, `${Prefix}${Head}.`>;
60
+ /**
61
+ * Nested selector object mirroring the dotted event keys of `E`. Each leaf is
62
+ * typed as its exact event key literal — `events.cart.add` has type `"cart.add"`
63
+ * — driving the same payload inference as the raw string. A key that is both a
64
+ * leaf and a prefix exposes its own key via the reserved `$` accessor:
65
+ * `events.cart.$` has type `"cart"`.
66
+ */
67
+ type EventSelectors<E extends EventMap, Prefix extends string = ""> = {
68
+ [Head in HeadSeg<After<keyof E & string, Prefix>>]: [Leaf<E, Prefix, Head>] extends [never] ? Deeper<E, Prefix, Head> : [Deeper<E, Prefix, Head>] extends [never] ? Leaf<E, Prefix, Head> : Deeper<E, Prefix, Head> & {
69
+ readonly $: Leaf<E, Prefix, Head>;
70
+ };
71
+ };
72
+ /**
73
+ * Builds a typed selector proxy for the event map `E`. Property access
74
+ * accumulates a path that coerces to the dotted event key —
75
+ * `String(createSelectors<E>().cart.add) === "cart.add"`. The reserved `$`
76
+ * accessor returns the current path as a plain string.
77
+ */
78
+ declare const createSelectors: <E extends EventMap>() => EventSelectors<E>;
79
+
80
+ export { type AnyHandler, type Emitter, type EventHandler, type EventMap, type EventSelectors, type EventTuple, type PayloadArgs, type Unsubscribe, type WaitForOptions, createEmitter, createSelectors };
package/dist/index.js ADDED
@@ -0,0 +1,8 @@
1
+ import {
2
+ createEmitter,
3
+ createSelectors
4
+ } from "./chunk-ZRE57KHP.js";
5
+ export {
6
+ createEmitter,
7
+ createSelectors
8
+ };
package/dist/react.cjs ADDED
@@ -0,0 +1,234 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/react.ts
21
+ var react_exports = {};
22
+ __export(react_exports, {
23
+ createEmitter: () => createEmitter,
24
+ createEventBus: () => createEventBus,
25
+ createEventHooks: () => createEventHooks,
26
+ createSelectors: () => createSelectors
27
+ });
28
+ module.exports = __toCommonJS(react_exports);
29
+
30
+ // src/emitter.ts
31
+ var matchesHandler = (registered, target) => registered === target || typeof registered !== "function" && registered.handler === target;
32
+ var keyOf = (name) => typeof name === "string" ? name : String(name);
33
+ var copyWithout = (list, index) => {
34
+ const length = list.length;
35
+ const next = new Array(length - 1);
36
+ for (let i = 0; i < index; i++) next[i] = list[i];
37
+ for (let i = index + 1; i < length; i++) next[i - 1] = list[i];
38
+ return next;
39
+ };
40
+ var createEmitter = () => {
41
+ const handlers = /* @__PURE__ */ new Map();
42
+ let anyHandlers = [];
43
+ const removeFromList = (name, slot, target) => {
44
+ const length = slot.length;
45
+ let index = 0;
46
+ while (index < length && !matchesHandler(slot[index], target)) index++;
47
+ if (index === length) return;
48
+ if (length === 2) handlers.set(name, slot[1 - index]);
49
+ else handlers.set(name, copyWithout(slot, index));
50
+ };
51
+ const removeNamed = (name, target) => {
52
+ const slot = handlers.get(name);
53
+ if (slot === void 0) return;
54
+ if (Array.isArray(slot)) removeFromList(name, slot, target);
55
+ else if (matchesHandler(slot, target)) handlers.set(name, void 0);
56
+ };
57
+ const subscribe = (name, entry) => {
58
+ const key = keyOf(name);
59
+ const slot = handlers.get(key);
60
+ if (slot === void 0) handlers.set(key, entry);
61
+ else if (Array.isArray(slot)) slot.push(entry);
62
+ else handlers.set(key, [slot, entry]);
63
+ let active = true;
64
+ return () => {
65
+ if (!active) return;
66
+ active = false;
67
+ const current = handlers.get(key);
68
+ if (current === entry) handlers.set(key, void 0);
69
+ else if (Array.isArray(current)) removeFromList(key, current, entry);
70
+ };
71
+ };
72
+ const once = (name, handler) => subscribe(keyOf(name), { handler });
73
+ const off = (name, handler) => {
74
+ const key = keyOf(name);
75
+ if (!handler) {
76
+ handlers.delete(key);
77
+ return;
78
+ }
79
+ removeNamed(key, handler);
80
+ };
81
+ const emit = (name, payload) => {
82
+ const key = keyOf(name);
83
+ const slot = handlers.get(key);
84
+ if (slot !== void 0) {
85
+ if (typeof slot === "function") slot(payload);
86
+ else if (Array.isArray(slot)) {
87
+ const length = slot.length;
88
+ for (let i = 0; i < length; i++) {
89
+ const entry = slot[i];
90
+ if (typeof entry === "function") entry(payload);
91
+ else {
92
+ removeNamed(key, entry);
93
+ entry.handler(payload);
94
+ }
95
+ }
96
+ } else {
97
+ handlers.set(key, void 0);
98
+ slot.handler(payload);
99
+ }
100
+ }
101
+ const anyList = anyHandlers;
102
+ const anyLength = anyList.length;
103
+ for (let i = 0; i < anyLength; i++) anyList[i](key, payload);
104
+ };
105
+ const onAny = (handler) => {
106
+ anyHandlers.push(handler);
107
+ let active = true;
108
+ return () => {
109
+ if (!active) return;
110
+ active = false;
111
+ const index = anyHandlers.indexOf(handler);
112
+ if (index !== -1) anyHandlers = copyWithout(anyHandlers, index);
113
+ };
114
+ };
115
+ const waitFor = (name, options) => {
116
+ const key = keyOf(name);
117
+ const signal = options?.signal;
118
+ if (signal?.aborted) return Promise.reject(signal.reason);
119
+ return new Promise((resolve, reject) => {
120
+ const onAbort = () => {
121
+ unsubscribe();
122
+ reject(signal?.reason);
123
+ };
124
+ const unsubscribe = once(key, (payload) => {
125
+ signal?.removeEventListener("abort", onAbort);
126
+ resolve(payload);
127
+ });
128
+ signal?.addEventListener("abort", onAbort, { once: true });
129
+ });
130
+ };
131
+ const clear = () => {
132
+ handlers.clear();
133
+ anyHandlers = [];
134
+ };
135
+ return {
136
+ on: subscribe,
137
+ once,
138
+ off,
139
+ emit,
140
+ onAny,
141
+ waitFor,
142
+ clear
143
+ };
144
+ };
145
+
146
+ // src/react/use-event.ts
147
+ var import_react = require("react");
148
+ var makeUseEvent = (emitter) => {
149
+ const useEvent = (name, handler) => {
150
+ const key = keyOf(name);
151
+ const handlerRef = (0, import_react.useRef)(handler);
152
+ (0, import_react.useEffect)(() => {
153
+ handlerRef.current = handler;
154
+ });
155
+ (0, import_react.useEffect)(() => emitter.on(key, (payload) => handlerRef.current(payload)), [key]);
156
+ };
157
+ return useEvent;
158
+ };
159
+
160
+ // src/react/use-event-state.ts
161
+ var import_react2 = require("react");
162
+ var makeUseEventState = (emitter, last) => {
163
+ function useEventState(name, initialValue) {
164
+ const initialRef = (0, import_react2.useRef)(initialValue);
165
+ const key = keyOf(name);
166
+ const subscribe = (0, import_react2.useCallback)(
167
+ (onStoreChange) => emitter.on(key, (payload) => {
168
+ last.set(key, payload);
169
+ onStoreChange();
170
+ }),
171
+ [key]
172
+ );
173
+ const getSnapshot = () => last.has(key) ? last.get(key) : initialRef.current;
174
+ const getServerSnapshot = () => initialRef.current;
175
+ const value = (0, import_react2.useSyncExternalStore)(subscribe, getSnapshot, getServerSnapshot);
176
+ const setValue = (0, import_react2.useCallback)(
177
+ (...args) => {
178
+ emitter.emit(key, ...args);
179
+ },
180
+ [key]
181
+ );
182
+ return [value, setValue];
183
+ }
184
+ return useEventState;
185
+ };
186
+
187
+ // src/selectors.ts
188
+ var build = (path) => new Proxy({}, {
189
+ get(_t, prop) {
190
+ if (prop === Symbol.toPrimitive || prop === "toString" || prop === "valueOf")
191
+ return () => path.join(".");
192
+ if (prop === "$") return path.join(".");
193
+ if (typeof prop === "symbol") return void 0;
194
+ return build([...path, prop]);
195
+ }
196
+ });
197
+ var createSelectors = () => build([]);
198
+
199
+ // src/react.ts
200
+ var setUpHooks = (emitter) => {
201
+ const last = /* @__PURE__ */ new Map();
202
+ const record = (name, payload) => {
203
+ last.set(name, payload);
204
+ };
205
+ const installRecorder = () => {
206
+ emitter.onAny(record);
207
+ };
208
+ installRecorder();
209
+ const hooks = {
210
+ useEvent: makeUseEvent(emitter),
211
+ useEventState: makeUseEventState(emitter, last)
212
+ };
213
+ return { hooks, last, installRecorder };
214
+ };
215
+ var createEventHooks = (emitter) => setUpHooks(emitter).hooks;
216
+ var createEventBus = () => {
217
+ const emitter = createEmitter();
218
+ const bus = { ...emitter };
219
+ const { hooks, last, installRecorder } = setUpHooks(bus);
220
+ const clear = () => {
221
+ emitter.clear();
222
+ last.clear();
223
+ installRecorder();
224
+ };
225
+ const events = createSelectors();
226
+ return Object.assign(bus, hooks, { clear, events });
227
+ };
228
+ // Annotate the CommonJS export names for ESM import in node:
229
+ 0 && (module.exports = {
230
+ createEmitter,
231
+ createEventBus,
232
+ createEventHooks,
233
+ createSelectors
234
+ });
@@ -0,0 +1,50 @@
1
+ import { EventMap, EventHandler, PayloadArgs, Emitter, EventSelectors } from './index.cjs';
2
+ export { AnyHandler, EventTuple, Unsubscribe, WaitForOptions, createEmitter, createSelectors } from './index.cjs';
3
+
4
+ /**
5
+ * Subscribes to an event for the lifetime of the component. The latest
6
+ * `handler` is always invoked.
7
+ */
8
+ type UseEvent<E extends EventMap> = <K extends keyof E & string>(name: K, handler: EventHandler<E[K]>) => void;
9
+
10
+ /**
11
+ * Returns a `[value, setValue]` tuple. `value` is the last emitted payload of
12
+ * the event as React state: without an `initialValue` it is `undefined` until
13
+ * the first emit. The `initialValue` is pinned on the first render; later
14
+ * changes to it are ignored. Emits carrying a value equal (`Object.is`) to the
15
+ * current one do not re-render.
16
+ *
17
+ * `setValue` is not local state — it emits the event on the bus
18
+ * (`emit(name, ...)`), so **every** subscriber of `name` updates, not just the
19
+ * calling component. Its argument follows `PayloadArgs`. It is referentially
20
+ * stable across renders for a given `name`.
21
+ */
22
+ type UseEventState<E extends EventMap> = {
23
+ <K extends keyof E & string>(name: K): [value: E[K] | undefined, setValue: (...args: PayloadArgs<E[K]>) => void];
24
+ <K extends keyof E & string>(name: K, initialValue: E[K]): [value: E[K], setValue: (...args: PayloadArgs<E[K]>) => void];
25
+ };
26
+
27
+ /** React hooks bound to a single emitter. */
28
+ type EventHooks<E extends EventMap> = {
29
+ /** Subscribes `handler` to `name` for the component's lifetime. */
30
+ useEvent: UseEvent<E>;
31
+ /**
32
+ * Returns a `[value, setValue]` tuple: the last emitted payload of `name`
33
+ * as React state, and a stable setter that emits `name` on the bus so
34
+ * every subscriber updates.
35
+ */
36
+ useEventState: UseEventState<E>;
37
+ };
38
+ /** A typed emitter with bound React hooks. */
39
+ type EventBus<E extends EventMap> = Omit<Emitter<E>, "clear"> & EventHooks<E> & {
40
+ /** Removes every handler and forgets all recorded payloads. */
41
+ clear: () => void;
42
+ /** typed selector object; `bus.events.cart.add` === the event name `"cart.add"`. */
43
+ events: EventSelectors<E>;
44
+ };
45
+ /** Binds React hooks to an existing emitter. */
46
+ declare const createEventHooks: <E extends EventMap>(emitter: Emitter<E>) => EventHooks<E>;
47
+ /** Creates a fresh emitter with bound React hooks, spread into one bus object. */
48
+ declare const createEventBus: <E extends EventMap>() => EventBus<E>;
49
+
50
+ export { Emitter, type EventBus, EventHandler, type EventHooks, EventMap, EventSelectors, PayloadArgs, type UseEvent, type UseEventState, createEventBus, createEventHooks };
@@ -0,0 +1,50 @@
1
+ import { EventMap, EventHandler, PayloadArgs, Emitter, EventSelectors } from './index.js';
2
+ export { AnyHandler, EventTuple, Unsubscribe, WaitForOptions, createEmitter, createSelectors } from './index.js';
3
+
4
+ /**
5
+ * Subscribes to an event for the lifetime of the component. The latest
6
+ * `handler` is always invoked.
7
+ */
8
+ type UseEvent<E extends EventMap> = <K extends keyof E & string>(name: K, handler: EventHandler<E[K]>) => void;
9
+
10
+ /**
11
+ * Returns a `[value, setValue]` tuple. `value` is the last emitted payload of
12
+ * the event as React state: without an `initialValue` it is `undefined` until
13
+ * the first emit. The `initialValue` is pinned on the first render; later
14
+ * changes to it are ignored. Emits carrying a value equal (`Object.is`) to the
15
+ * current one do not re-render.
16
+ *
17
+ * `setValue` is not local state — it emits the event on the bus
18
+ * (`emit(name, ...)`), so **every** subscriber of `name` updates, not just the
19
+ * calling component. Its argument follows `PayloadArgs`. It is referentially
20
+ * stable across renders for a given `name`.
21
+ */
22
+ type UseEventState<E extends EventMap> = {
23
+ <K extends keyof E & string>(name: K): [value: E[K] | undefined, setValue: (...args: PayloadArgs<E[K]>) => void];
24
+ <K extends keyof E & string>(name: K, initialValue: E[K]): [value: E[K], setValue: (...args: PayloadArgs<E[K]>) => void];
25
+ };
26
+
27
+ /** React hooks bound to a single emitter. */
28
+ type EventHooks<E extends EventMap> = {
29
+ /** Subscribes `handler` to `name` for the component's lifetime. */
30
+ useEvent: UseEvent<E>;
31
+ /**
32
+ * Returns a `[value, setValue]` tuple: the last emitted payload of `name`
33
+ * as React state, and a stable setter that emits `name` on the bus so
34
+ * every subscriber updates.
35
+ */
36
+ useEventState: UseEventState<E>;
37
+ };
38
+ /** A typed emitter with bound React hooks. */
39
+ type EventBus<E extends EventMap> = Omit<Emitter<E>, "clear"> & EventHooks<E> & {
40
+ /** Removes every handler and forgets all recorded payloads. */
41
+ clear: () => void;
42
+ /** typed selector object; `bus.events.cart.add` === the event name `"cart.add"`. */
43
+ events: EventSelectors<E>;
44
+ };
45
+ /** Binds React hooks to an existing emitter. */
46
+ declare const createEventHooks: <E extends EventMap>(emitter: Emitter<E>) => EventHooks<E>;
47
+ /** Creates a fresh emitter with bound React hooks, spread into one bus object. */
48
+ declare const createEventBus: <E extends EventMap>() => EventBus<E>;
49
+
50
+ export { Emitter, type EventBus, EventHandler, type EventHooks, EventMap, EventSelectors, PayloadArgs, type UseEvent, type UseEventState, createEventBus, createEventHooks };