56 lines
1.7 KiB
TypeScript
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)),
|
|
};
|
|
}
|