export interface MediaDimensions { height: number width: number } const METADATA_TIMEOUT_MS = 10_000 function waitForDimensions( file: File, element: HTMLImageElement | HTMLVideoElement, successEvent: "load" | "loadedmetadata" ): Promise { return new Promise((resolve) => { const objectUrl = URL.createObjectURL(file) let settled = false const timeout = window.setTimeout(finish, METADATA_TIMEOUT_MS) function finish(dimensions?: MediaDimensions) { if (settled) return settled = true window.clearTimeout(timeout) URL.revokeObjectURL(objectUrl) resolve(dimensions) } element.addEventListener( successEvent, () => { const width = element instanceof HTMLVideoElement ? element.videoWidth : element.naturalWidth const height = element instanceof HTMLVideoElement ? element.videoHeight : element.naturalHeight finish(width > 0 && height > 0 ? { height, width } : undefined) }, { once: true } ) element.addEventListener("error", () => finish(), { once: true }) element.src = objectUrl }) } /** Reads intrinsic dimensions before an adapter uploads an image or video. */ export function readMediaDimensions( file: File ): Promise { if (file.type.startsWith("image/")) { return waitForDimensions(file, new Image(), "load") } if (file.type.startsWith("video/")) { const video = document.createElement("video") video.preload = "metadata" return waitForDimensions(file, video, "loadedmetadata") } return Promise.resolve(undefined) }