/** * @oxpulse/chat-widget — Pinned messages banner (#228). * * Renders a banner at the top of the message list showing the currently * pinned messages. When more than one message is pinned, a carousel * (◀ ▶ + index "2/5") lets the user cycle through them. * * Driven by: * - setPins(pins) — initial load from listPins() on mount * - addPin(msgId, pinnedBy) — live SSE op="pin" * - removePin(msgId) — live SSE op="unpin" * * Preview text is resolved from the caller's already-decrypted row store * (MessageList.#rows) via the `resolvePreview` callback — the banner never * fetches or decrypts content itself (E2EE-consistent: the content is * already client-side decrypted; a pin pointing outside the loaded window * shows a graceful "Message not loaded" placeholder). * * Clicking the preview jumps to the source message via `onJumpToMessage`. * * Zero-third-party-dep — plain DOM, matching the widget's existing pattern * (typing-indicator.ts, presence-overlay.ts, etc.). * * Lifecycle: * 1. new PinnedBanner({ container, ... }) — mounts hidden immediately * 2. setPins/addPin/removePin — update state + re-render * 3. destroy() — removes DOM + clears timers */ /** A pinned-message entry — mirrors the fields the banner needs. */ export interface PinnedEntry { msgId: string; pinnedBy: string; pinnedAt: string; } export interface PinnedBannerOptions { /** Container element to mount the banner into (above the message list). */ container: HTMLElement; /** If provided, insert the banner before this element; otherwise append. */ insertBefore?: HTMLElement; /** BCP-47 tag or resolved Locale. */ lang?: string; /** Optional AbortSignal — destroy() is called automatically on abort. */ signal?: AbortSignal; /** Resolve a msgId → preview text from the caller's decrypted row store. * Returns undefined when the message is outside the loaded window. */ resolvePreview?: (msgId: string) => string | undefined; /** Resolve a userId → display name (from roster). Falls back to userId. */ resolveName?: (userId: string) => string | undefined; /** Called when the user clicks the preview to jump to the source message. */ onJumpToMessage?: (msgId: string) => void; } export declare class PinnedBanner { #private; constructor(opts: PinnedBannerOptions); /** Replace the full pinned set (initial load from listPins). */ setPins(pins: readonly PinnedEntry[]): void; /** M4: Set loading state — called before listPins() resolves. */ setLoading(loading: boolean): void; /** Add a pin (live SSE op="pin"). Idempotent — if already present, no-op. */ addPin(msgId: string, pinnedBy: string, pinnedAt: string): void; /** Remove a pin (live SSE op="unpin"). No-op if not present. */ removePin(msgId: string): void; /** Whether a message is currently in the pinned set. */ isPinned(msgId: string): boolean; /** Get the set of pinned msgIds (for footer pin-button state). */ getPinnedMsgIds(): Set; destroy(): void; } //# sourceMappingURL=pinned-banner.d.ts.map