NODEDC_DESIGN_GUIDELINE/packages/ui-dom/src/mediaSource.ts

56 lines
1.7 KiB
TypeScript

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<HTMLElement>("[data-nodedc-media-source-option]"));
const panels = Array.from(root.querySelectorAll<HTMLElement>("[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)),
};
}