mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-08 02:36:10 +00:00
DOM-free SlideshowController (discrete nav, fragment holds, branch stack) driving the existing player; <hyperframes-slideshow> web component with a unified mute+nav capsule (conditional prev/next), floating hotspot overlays, presenter mode (BroadcastChannel), keyboard/touch, and a scenes getter fed via the runtime message handler. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
47 lines
1.2 KiB
TypeScript
47 lines
1.2 KiB
TypeScript
/**
|
|
* Vitest setup: install a minimal in-memory BroadcastChannel polyfill so that
|
|
* happy-dom tests can exercise the presenter/audience channel code path.
|
|
* This polyfill is intentionally NOT shipped in production code.
|
|
*/
|
|
|
|
type MsgHandler = (event: MessageEvent) => void;
|
|
|
|
const registry = new Map<string, Set<InMemoryBroadcastChannel>>();
|
|
|
|
class InMemoryBroadcastChannel {
|
|
onmessage: MsgHandler | null = null;
|
|
readonly name: string;
|
|
private _closed = false;
|
|
|
|
constructor(name: string) {
|
|
this.name = name;
|
|
let set = registry.get(name);
|
|
if (!set) {
|
|
set = new Set();
|
|
registry.set(name, set);
|
|
}
|
|
set.add(this);
|
|
}
|
|
|
|
// fallow-ignore-next-line complexity
|
|
postMessage(data: unknown): void {
|
|
if (this._closed) return;
|
|
const peers = registry.get(this.name);
|
|
if (!peers) return;
|
|
for (const peer of peers) {
|
|
if (peer === this) continue;
|
|
peer.onmessage?.(new MessageEvent("message", { data }));
|
|
}
|
|
}
|
|
|
|
close(): void {
|
|
if (this._closed) return;
|
|
this._closed = true;
|
|
registry.get(this.name)?.delete(this);
|
|
}
|
|
}
|
|
|
|
if (typeof globalThis.BroadcastChannel === "undefined") {
|
|
(globalThis as Record<string, unknown>)["BroadcastChannel"] = InMemoryBroadcastChannel;
|
|
}
|