export type MediaSource = "file" | "url"; export interface MediaSourceController { getSource: () => MediaSource; setSource: (source: MediaSource) => void; destroy: () => void; } export interface MediaSourceControllerOptions { root: HTMLElement; source?: MediaSource; onChange?: (source: MediaSource) => void; } export function createMediaSourceController({ root, source = "file", onChange }: MediaSourceControllerOptions): MediaSourceController { const options = Array.from(root.querySelectorAll("[data-nodedc-media-source-option]")); const panels = Array.from(root.querySelectorAll("[data-nodedc-media-source-panel]")); let current = source; const render = () => { root.dataset.source = current; options.forEach((option) => { const active = option.dataset.nodedcMediaSourceOption === current; option.dataset.active = active ? "true" : "false"; option.setAttribute("aria-pressed", String(active)); }); panels.forEach((panel) => { panel.hidden = panel.dataset.nodedcMediaSourcePanel !== current; }); }; const setSource = (next: MediaSource) => { if (next === current) return; current = next; render(); onChange?.(current); }; const handlers = options.map((option) => { const handler = () => { const next = option.dataset.nodedcMediaSourceOption; if (next === "file" || next === "url") setSource(next); }; option.addEventListener("click", handler); return { option, handler }; }); render(); return { getSource: () => current, setSource, destroy: () => handlers.forEach(({ option, handler }) => option.removeEventListener("click", handler)), }; }