feat: add extractImageFromClipboard utility with broad image/* MIME matching

This commit is contained in:
2026-04-08 19:58:01 -04:00
parent 722c0f0f7d
commit 2d34bbebc4

View File

@@ -0,0 +1,45 @@
/**
* Extracts the first image File from a DataTransfer object.
*
* Resolution order (most → least reliable across browsers/OS):
* 1. clipboardData.files browser-normalised FileList; Chrome/Linux/Mac/Safari
* all populate this for real paste events. Most reliable.
* 2. clipboardData.items DataTransferItemList fallback for edge cases where
* files is empty but items contains a "file" kind entry.
*
* MIME matching: type.startsWith("image/") intentionally accepts any image
* subtype, including OS-specific variants like "image/x-png" on Linux that
* a strict allowlist (["image/png", ...]) would silently reject.
*
* The caller (onImageSelect / handleImageSelect) still runs validateImageFile
* which enforces the app's supported format allowlist — so we stay permissive
* here and strict at the validation boundary.
*/
export function extractImageFromClipboard(
clipboardData: DataTransfer | null | undefined,
): File | null {
if (!clipboardData) return null;
// ── 1. files array (primary) ──────────────────────────────────────────────
const { files } = clipboardData;
if (files?.length) {
for (let i = 0; i < files.length; i++) {
const file = files[i];
if (file.type.startsWith("image/")) return file;
}
}
// ── 2. items fallback ─────────────────────────────────────────────────────
const { items } = clipboardData;
if (items?.length) {
for (let i = 0; i < items.length; i++) {
const item = items[i];
if (item.kind === "file" && item.type.startsWith("image/")) {
const file = item.getAsFile();
if (file) return file;
}
}
}
return null;
}