mirror of
https://github.com/shishantbiswas/bknd.git
synced 2026-03-16 04:27:21 +00:00
feat: implement file acceptance validation in utils and integrate with Dropzone component
This commit is contained in:
@@ -264,6 +264,35 @@ describe("Core Utils", async () => {
|
|||||||
height: 512,
|
height: 512,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("isFileAccepted", () => {
|
||||||
|
const file = new File([""], "file.txt", {
|
||||||
|
type: "text/plain",
|
||||||
|
});
|
||||||
|
expect(utils.isFileAccepted(file, "text/plain")).toBe(true);
|
||||||
|
expect(utils.isFileAccepted(file, "text/plain,text/html")).toBe(true);
|
||||||
|
expect(utils.isFileAccepted(file, "text/html")).toBe(false);
|
||||||
|
|
||||||
|
{
|
||||||
|
const file = new File([""], "file.jpg", {
|
||||||
|
type: "image/jpeg",
|
||||||
|
});
|
||||||
|
expect(utils.isFileAccepted(file, "image/jpeg")).toBe(true);
|
||||||
|
expect(utils.isFileAccepted(file, "image/jpeg,image/png")).toBe(true);
|
||||||
|
expect(utils.isFileAccepted(file, "image/png")).toBe(false);
|
||||||
|
expect(utils.isFileAccepted(file, "image/*")).toBe(true);
|
||||||
|
expect(utils.isFileAccepted(file, ".jpg")).toBe(true);
|
||||||
|
expect(utils.isFileAccepted(file, ".jpg,.png")).toBe(true);
|
||||||
|
expect(utils.isFileAccepted(file, ".png")).toBe(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const file = new File([""], "file.png");
|
||||||
|
expect(utils.isFileAccepted(file, undefined as any)).toBe(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(() => utils.isFileAccepted(null as any, "text/plain")).toThrow();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("dates", () => {
|
describe("dates", () => {
|
||||||
|
|||||||
@@ -240,3 +240,46 @@ export async function blobToFile(
|
|||||||
lastModified: Date.now(),
|
lastModified: Date.now(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isFileAccepted(file: File | unknown, _accept: string | string[]): boolean {
|
||||||
|
const accept = Array.isArray(_accept) ? _accept.join(",") : _accept;
|
||||||
|
if (!accept || !accept.trim()) return true; // no restrictions
|
||||||
|
if (!isFile(file)) {
|
||||||
|
throw new Error("Given file is not a File instance");
|
||||||
|
}
|
||||||
|
|
||||||
|
const name = file.name.toLowerCase();
|
||||||
|
const type = (file.type || "").trim().toLowerCase();
|
||||||
|
|
||||||
|
// split on commas, trim whitespace
|
||||||
|
const tokens = accept
|
||||||
|
.split(",")
|
||||||
|
.map((t) => t.trim().toLowerCase())
|
||||||
|
.filter(Boolean);
|
||||||
|
|
||||||
|
// try each token until one matches
|
||||||
|
return tokens.some((token) => {
|
||||||
|
if (token.startsWith(".")) {
|
||||||
|
// extension match, e.g. ".png" or ".tar.gz"
|
||||||
|
return name.endsWith(token);
|
||||||
|
}
|
||||||
|
|
||||||
|
const slashIdx = token.indexOf("/");
|
||||||
|
if (slashIdx !== -1) {
|
||||||
|
const [major, minor] = token.split("/");
|
||||||
|
if (minor === "*") {
|
||||||
|
// wildcard like "image/*"
|
||||||
|
if (!type) return false;
|
||||||
|
const [fMajor] = type.split("/");
|
||||||
|
return fMajor === major;
|
||||||
|
} else {
|
||||||
|
// exact MIME like "image/svg+xml" or "application/pdf"
|
||||||
|
// because of "text/plain;charset=utf-8"
|
||||||
|
return type.startsWith(token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// unknown token shape, ignore
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ import {
|
|||||||
useEffect,
|
useEffect,
|
||||||
useMemo,
|
useMemo,
|
||||||
useRef,
|
useRef,
|
||||||
useState,
|
|
||||||
} from "react";
|
} from "react";
|
||||||
|
import { isFileAccepted } from "bknd/utils";
|
||||||
import { type FileWithPath, useDropzone } from "./use-dropzone";
|
import { type FileWithPath, useDropzone } from "./use-dropzone";
|
||||||
import { checkMaxReached } from "./helper";
|
import { checkMaxReached } from "./helper";
|
||||||
import { DropzoneInner } from "./DropzoneInner";
|
import { DropzoneInner } from "./DropzoneInner";
|
||||||
@@ -173,12 +173,14 @@ export function Dropzone({
|
|||||||
|
|
||||||
return specs.every((spec) => {
|
return specs.every((spec) => {
|
||||||
if (spec.kind !== "file") {
|
if (spec.kind !== "file") {
|
||||||
console.log("not a file", spec.kind);
|
console.warn("file not accepted: not a file", spec.kind);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (allowedMimeTypes && allowedMimeTypes.length > 0) {
|
if (allowedMimeTypes && allowedMimeTypes.length > 0) {
|
||||||
console.log("not allowed mimetype", spec.type);
|
if (!isFileAccepted(i, allowedMimeTypes)) {
|
||||||
return allowedMimeTypes.includes(spec.type);
|
console.warn("file not accepted: not allowed mimetype", spec.type);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user