/* * events.ts — typed event emitter for the ribbit editor. */ import type { RibbitTheme, PeerInfo, Revision } from './types'; export interface ContentPayload { markdown: string; html: string; } export interface ModeChangePayload { current: string; previous: string | null; } export interface ThemeChangePayload { current: RibbitTheme; previous: RibbitTheme; } export interface ReadyPayload { markdown: string; html: string; mode: string; theme: RibbitTheme; } export interface RibbitEventMap { /* * Content was modified. Fires on every edit. * * editor.on('change', ({ markdown }) => { * localStorage.setItem('draft', markdown); * }); */ change: (payload: ContentPayload) => void; /* * Save requested via editor.save(), toolbar button, or Ctrl+S. * * editor.on('save', ({ markdown, html }) => { * fetch('/api/save', { method: 'POST', body: markdown }); * }); */ save: (payload: ContentPayload) => void; /* * Editor mode switched between view, edit, and wysiwyg. * * editor.on('modeChange', ({ current, previous }) => { * toolbar.toggle(current !== 'view'); * main.classList.toggle('editing', current !== 'view'); * }); */ modeChange: (payload: ModeChangePayload) => void; /* * Theme switched via editor.themes.set(). * * editor.on('themeChange', ({ current, previous }) => { * analytics.track('theme_switch', { from: previous.name, to: current.name }); * }); */ themeChange: (payload: ThemeChangePayload) => void; /* * Editor initialized and first render complete. * * editor.on('ready', ({ mode, theme }) => { * console.log(`Editor ready in ${mode} mode with ${theme.name} theme`); * }); */ ready: (payload: ReadyPayload) => void; /* * Remote users connected, disconnected, or moved their cursors. * * editor.on('peerChange', ({ peers }) => { * updateUserList(peers); * }); */ peerChange: (payload: { peers: PeerInfo[] }) => void; /* * Document lock acquired or released. * * editor.on('lockChange', ({ holder }) => { * if (holder) showBanner(`Locked by ${holder.displayName}`); * else hideBanner(); * }); */ lockChange: (payload: { holder: PeerInfo | null }) => void; /* * Remote changes received while in source mode. * * editor.on('remoteActivity', ({ count }) => { * statusBar.textContent = `${count} remote changes`; * }); */ remoteActivity: (payload: { count: number }) => void; /* * A revision was created. * * editor.on('revisionCreated', ({ revision }) => { * console.log(`Revision ${revision.id} saved`); * }); */ revisionCreated: (payload: { revision: Revision }) => void; } type EventName = keyof RibbitEventMap; /** * Typed event emitter for ribbit editor lifecycle and collaboration events. * * @example * const emitter = new RibbitEmitter(); * emitter.on('change', ({ markdown }) => console.log(markdown)); * emitter.emit('change', { markdown: '# Hello', html: '