This commit is contained in:
Maze Winther
2026-01-05 01:35:10 +01:00
parent d5ca991501
commit c19f085e48
95 changed files with 4133 additions and 4196 deletions
-19
View File
@@ -1,19 +0,0 @@
{
"name": "@opencut/hooks",
"version": "0.0.0",
"description": "Hooks package for OpenCut",
"main": "./src/index.ts",
"types": "./src/index.ts",
"exports": {
".": "./src/index.ts",
"./use-file-upload": "./src/use-file-upload.ts",
"./use-file-paste": "./src/use-file-paste.ts"
},
"dependencies": {
"@types/react": "^19.2.7",
"react": "^19.2.0"
},
"devDependencies": {
"typescript": "^5.8.3"
}
}
-2
View File
@@ -1,2 +0,0 @@
export * from "./use-file-upload";
export * from "./use-file-paste";
-23
View File
@@ -1,23 +0,0 @@
import { useEffect } from "react";
interface UseFilePasteOptions {
onFilesPaste: (files: File[]) => void;
}
export function useFilePaste({ onFilesPaste }: UseFilePasteOptions) {
useEffect(() => {
function handlePaste(e: ClipboardEvent) {
if (!e.clipboardData?.files.length) return;
const files = Array.from(e.clipboardData.files);
if (files.length > 0) {
e.preventDefault();
onFilesPaste(files);
}
}
window.addEventListener("paste", handlePaste);
return () => window.removeEventListener("paste", handlePaste);
}, [onFilesPaste]);
}
-101
View File
@@ -1,101 +0,0 @@
import { useState, useRef } from "react";
interface UseFileUploadOptions {
accept?: string;
multiple?: boolean;
onFilesSelected?: (files: FileList) => void;
}
function containsFiles(dataTransfer: DataTransfer): boolean {
const isInternalDrag = dataTransfer.types.includes("application/x-media-item");
const hasFiles = dataTransfer.types.includes("Files");
return !isInternalDrag && hasFiles;
}
export function useFileUpload({ accept, multiple, onFilesSelected }: UseFileUploadOptions = {}) {
const [isDragOver, setIsDragOver] = useState(false);
const dragCounterRef = useRef(0);
const inputRef = useRef<HTMLInputElement>(null);
function openFilePicker() {
if (!inputRef.current) return;
inputRef.current.accept = accept || "*";
inputRef.current.multiple = multiple || false;
inputRef.current.click();
}
function handleFileChange(event: React.ChangeEvent<HTMLInputElement>) {
const files = event.target.files;
if (files && files.length > 0 && onFilesSelected) {
onFilesSelected(files);
}
if (event.target) {
event.target.value = "";
}
}
function handleDragEnter(e: React.DragEvent) {
e.preventDefault();
if (!containsFiles(e.dataTransfer)) return;
dragCounterRef.current += 1;
setIsDragOver(true);
}
function handleDragOver(e: React.DragEvent) {
e.preventDefault();
if (!containsFiles(e.dataTransfer)) return;
}
function handleDragLeave(e: React.DragEvent) {
e.preventDefault();
if (!containsFiles(e.dataTransfer)) return;
dragCounterRef.current -= 1;
if (dragCounterRef.current === 0) {
setIsDragOver(false);
}
}
function handleDrop(e: React.DragEvent) {
e.preventDefault();
setIsDragOver(false);
dragCounterRef.current = 0;
if (onFilesSelected && containsFiles(e.dataTransfer)) {
const files = e.dataTransfer.files;
const shouldUseMultiple = multiple ?? false;
if (shouldUseMultiple) {
onFilesSelected(files);
} else if (files.length > 0) {
const dataTransfer = new DataTransfer();
dataTransfer.items.add(files[0]);
onFilesSelected(dataTransfer.files);
}
}
}
return {
isDragOver,
openFilePicker,
fileInputProps: {
ref: inputRef,
type: "file",
style: { display: "none" },
onChange: handleFileChange,
},
dragProps: {
onDragEnter: handleDragEnter,
onDragOver: handleDragOver,
onDragLeave: handleDragLeave,
onDrop: handleDrop,
},
};
}
-20
View File
@@ -1,20 +0,0 @@
{
"compilerOptions": {
"target": "ES2020",
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"module": "ESNext",
"skipLibCheck": true,
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx",
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true
},
"include": ["src/**/*"],
"exclude": ["node_modules"]
}