From dd7ca72f3aead25816775a412a9f4e20c7ce33fe Mon Sep 17 00:00:00 2001 From: Chris Wanstrath Date: Wed, 8 Oct 2025 10:38:41 -0700 Subject: [PATCH] typed events --- public/bundle.js | 20 +++++++++++++++----- src/js/event.ts | 31 +++++++++++++++++++++++++++++++ src/js/session.ts | 6 +++--- src/js/statusbar.ts | 11 +++++------ 4 files changed, 54 insertions(+), 14 deletions(-) create mode 100644 src/js/event.ts diff --git a/public/bundle.js b/public/bundle.js index 711841c..0843020 100644 --- a/public/bundle.js +++ b/public/bundle.js @@ -1,5 +1,5 @@ //// -// version: 7f31112 +// version: 52aae6c // src/js/dom.ts var content2 = $("content"); @@ -160,6 +160,16 @@ function handleOutput(msg) { addOutput(id, result.output); } +// src/js/event.ts +function fire(eventName, detail) { + window.dispatchEvent(new CustomEvent(eventName, { detail })); +} +function on(eventName, handler) { + const listener = handler; + window.addEventListener(eventName, listener); + return () => window.removeEventListener(eventName, listener); +} + // src/js/session.ts var sessionId = randomId(); var sessionStore = new Map; @@ -167,13 +177,13 @@ function initSession() {} function handleSessionStart(msg) { for (const key of Object.keys(msg.data)) sessionStore.set(key, msg.data[key] || ""); - window.dispatchEvent(new CustomEvent("session:update", { detail: msg.data })); + fire("session:update", msg.data); mode(msg.data.mode); } function handleSessionUpdate(msg) { for (const key of Object.keys(msg.data)) sessionStore.set(key, msg.data[key] || ""); - window.dispatchEvent(new CustomEvent("session:update", { detail: msg.data })); + fire("session:update", msg.data); } // src/js/webapp.ts @@ -1293,8 +1303,8 @@ function initStatusbar() { registerEvents(); } function registerEvents() { - window.addEventListener("apps:change", (e) => updateWww(sessionStore.get("project") || "root")); - window.addEventListener("session:update", (e) => { + on("apps:change", (e) => updateWww(sessionStore.get("project") || "root")); + on("session:update", (e) => { const ev = e; const data = ev.detail; if (data.project) diff --git a/src/js/event.ts b/src/js/event.ts new file mode 100644 index 0000000..01b5e4f --- /dev/null +++ b/src/js/event.ts @@ -0,0 +1,31 @@ +//// +// Custom event system + +type Events = { + "apps:change": {}, + "session:update": Record, +} + +export function fire(eventName: K, detail: Events[K]) { + window.dispatchEvent(new CustomEvent(eventName, { detail })) +} + +export function on(eventName: K, handler: (e: CustomEvent) => void) { + const listener = handler as EventListener + window.addEventListener(eventName, listener) + + // cleanup + return () => window.removeEventListener(eventName, listener) +} + +export function once(eventName: K, handler: (e: CustomEvent) => void) { + const listener = handler as EventListener; + window.addEventListener(eventName, listener, { once: true }) + + // cleanup + return () => window.removeEventListener(eventName, listener) +} + +export function off(eventName: K, handler: (e: CustomEvent) => void) { + window.removeEventListener(eventName, handler as EventListener) +} \ No newline at end of file diff --git a/src/js/session.ts b/src/js/session.ts index 65dbe98..d06b6cd 100644 --- a/src/js/session.ts +++ b/src/js/session.ts @@ -5,6 +5,7 @@ import type { SessionStartMessage, SessionUpdateMessage } from "@/shared/types" import { randomId } from "../shared/utils" import { mode } from "./commands" +import { fire } from "./event" export const sessionId = randomId() export const sessionStore = new Map() @@ -15,8 +16,7 @@ export function handleSessionStart(msg: SessionStartMessage) { for (const key of Object.keys(msg.data)) sessionStore.set(key, (msg.data as any)[key] || "") - window.dispatchEvent(new CustomEvent("session:update", { detail: msg.data })) - + fire("session:update", msg.data) mode(msg.data.mode) } @@ -24,5 +24,5 @@ export function handleSessionUpdate(msg: SessionUpdateMessage) { for (const key of Object.keys(msg.data)) sessionStore.set(key, msg.data[key] || "") - window.dispatchEvent(new CustomEvent("session:update", { detail: msg.data })) + fire("session:update", msg.data) } diff --git a/src/js/statusbar.ts b/src/js/statusbar.ts index 42a1ebb..422b869 100644 --- a/src/js/statusbar.ts +++ b/src/js/statusbar.ts @@ -2,6 +2,7 @@ // Temporarily display a message to the user in the status bar. import { $ } from "./dom" +import { on } from "./event" import { sessionStore } from "./session" import { apps } from "./webapp" @@ -21,19 +22,17 @@ export function initStatusbar() { } function registerEvents() { - window.addEventListener("apps:change", e => + on("apps:change", e => updateWww(sessionStore.get("project") || "root") ) - window.addEventListener("session:update", (e) => { + on("session:update", (e) => { const ev = e as CustomEvent const data = ev.detail - if (data.project) - updateProjectName(data.project) + if (data.project) updateProjectName(data.project) - if (data.cwd) - updateCwd(data.cwd) + if (data.cwd) updateCwd(data.cwd) }) }