small-events-ts
v1.0.1
Published
Type-safe event dispatcher utility for JS/TS
Readme
Small Events Ts
A lightweight hierarchical asynchronous event dispatcher for TypeScript projects.
- Async dispatch
- Hierarchical selectors (
a:b:ctriggersa,a:b,a:b:c) once()listenersstopPropagation()support- Remove listeners
- Zero dependencies
- Works in Svelte, Node, Vite, SSR
Installation
npm install small-events-tsor
pnpm add small-events-tsWhy this exists
JavaScript has:
window.addEventListener→ only global and DOM-related- Node
EventEmitter→ no hierarchy, no async ordering guarantees - Svelte stores → no event bus pattern
This library provides:
- namespaced events
ui:modal:open - hierarchical propagation
ui → ui:modal → ui:modal:open - predictable async order
- full control over propagation
- small & dependency-free
Usage
import { EventDispatcher } from "small-events-ts";
const dispatcher = new EventDispatcher();
dispatcher.listen("test", (event) => {
console.log(event.data);
});
dispatcher.dispatch({ selector: "test", data: "Hello" });Output:
HelloHierarchical Selectors
dispatcher.listen("a", () => console.log("root"));
dispatcher.listen("a:b", () => console.log("sub"));
dispatcher.dispatch({ selector: "a:b", data: null });Output:
root
subAsync Dispatch
dispatcher.listen("async", async () => {
await new Promise(r => setTimeout(r, 100));
console.log("async done");
});
dispatcher.listen("async", () => {
console.log("sync");
});
await dispatcher.dispatch({ selector: "async", data: null });Output:
async done
sync- Listeners run in order and
awaitasync handlers
Once Listeners
dispatcher.once("load", () => console.log("only once"));
dispatcher.dispatch({ selector: "load", data: null });
dispatcher.dispatch({ selector: "load", data: null });Output:
only onceStop Propagation
dispatcher.listen("x", (e) => {
console.log("first");
e.stopPropagation();
});
dispatcher.listen("x", () => console.log("second"));
dispatcher.dispatch({ selector: "x", data: null });Output:
first- The second listener is not called
Remove Listener
const fn = () => console.log("removed");
dispatcher.listen("event", fn);
dispatcher.remove("event", fn);
dispatcher.dispatch({ selector: "event", data: null });- Listener is removed
API Documentation
Event
interface Event {
selector: string;
data: any;
stopPropagation(): void;
}EventDispatcher
listen(selector, callable)
Registers a listener.
once(selector, callable)
Registers a listener that auto-removes after first call.
dispatch(event)
Triggers all matching listeners in order.
Supports:
- async listeners
- stopPropagation
- hierarchical selectors
remove(selector, callable)
Removes a specific listener.
Advanced Usage
Return unsubscribe
const off = dispatcher.listen("chat", handler);
// later
off();Global event bus (Svelte)
src/lib/events.ts:
import { EventDispatcher } from "small-events-ts";
export const events = new EventDispatcher();Use in components:
<script>
import { events } from "$lib/events";
events.listen("ui:open", () => modal = true);
</script>Trigger:
<script>
import { events } from "$lib/events";
events.dispatch({ selector: "ui:open" });
</script>Unit Tests
This package includes full Vitest coverage.
Run tests:
npm testCoverage:
100%Roadmap
- Svelte integration
- TypeScript types
⬜ Wildcard selectors (ui:*)
⬜ Selector filtering (ui:**)
⬜ Plugin system
License
MIT © Sébastien Kus
