| name | custom-global-events |
| description | Guidelines for creating/using the app’s typed global events system. |
Overview
Global events are used for cross-component communication without React context dependencies, allowing for simple function calls to trigger events across different parts of the application.
Global Events Guidelines
Global events are used for cross-component communication without React context dependencies, allowing for simple function calls to trigger events across different parts of the application.
Overview
The global events system lives at global-event.tsx and is built on a typed Event subclass (XCustomEvent).
It exposes:
global_event_Event: the canonical type map of event keys →detailpayload typesglobal_event_dispatch(event, payload): dispatch a typed event (works outside React)global_event_listen(event, handler, options?): listen with typed handler (works outside React)useGlobalEvent(event, handler): React hook for subscriptions with stale-closure protection
Event key naming
Event keys are string literals using the pattern:
(module::event_name), for example ai_chat::open_canvas.
How to add or modify an event
When the user requests a new global event, you must:
Update the event map
Add the new event key to the global_event_Event map in global-event.tsx.
Example:
export class global_event_Event extends XCustomEvent<{
"ai_chat::open_canvas": {
pageId: app_convex_Id<"pages">;
mode: "diff" | "editor";
modifiedContent?: string;
threadId: string;
};
"ai_chat::open_canvas_by_path": {
path: string;
};
"docs::focus_path": {
path: string;
};
}> {}
Keep all event keys centralized
All supported global event keys must be declared in that global_event_Event type map. Do not introduce ad-hoc stringly-typed events elsewhere.
Use the exported helpers
Prefer global_event_dispatch / global_event_listen / useGlobalEvent rather than calling window.dispatchEvent(new CustomEvent(...)) directly.
Usage patterns
React components
Use useGlobalEvent(eventName, handler) to subscribe. The handler receives a typed event object, and the payload is on event.detail.
Example (from canvas.tsx):
useGlobalEvent("ai_chat::open_canvas", (e) => {
const payload = e.detail;
// payload.pageId, payload.mode, payload.modifiedContent, payload.threadId
});
Non-React code (or manual lifecycle control)
Use global_event_listen directly when you need to wire AbortController, or you are outside React.
const controller = new AbortController();
const cleanup = global_event_listen(
"ai_chat::open_canvas_by_path",
(e) => {
console.info("path:", e.detail.path);
},
{ signal: controller.signal },
);
// later:
controller.abort();
cleanup();
Dispatching
Use global_event_dispatch(eventName, payload) from anywhere client-side.
Example (from app-ai-chat.tsx):
global_event_dispatch("ai_chat::open_canvas_by_path", { path: args.path });
Handler typing and payload access
Handlers receive the typed event object, not the payload directly:
useGlobalEvent("ai_chat::open_canvas", (e) => {
const payload = e.detail;
});
Files and references
- Core implementation: global-event.tsx
- Typed event base:
XCustomEventin utils.ts - Hook helper:
useLiveRefin utils-hooks.ts - Example consumers: app-ai-chat.tsx, canvas.tsx