Files
cinny/src/app/hooks/useFileDrop.ts
T
Lotus Bot 7079462503 chore: upgrade React 18→19 and fix breaking type changes
- react 18.2.0 to 19.2.6
- react-dom 18.2.0 to 19.2.6
- @types/react 18.2.39 to 19.2.15
- @types/react-dom 18.2.17 to 19.2.3

React 19 breaking changes fixed:
- useRef<T>(null) now returns RefObject<T | null>; cast to
  RefObject<T> at 16 component call sites (safe, runtime unchanged)
- useRef<T>() without arg no longer valid; add | undefined>(undefined)
  in useDebounce, useFileDrop, useThrottle, useVirtualPaginator hooks,
  RoomInput, RoomTimeline, and ClientNonUIFeatures
- useReducer<typeof reducer> 1-arg form removed; drop explicit type arg
  in useForceUpdate (inferred from reducer function)
- global JSX namespace removed; import type { JSX } from react in
  react-custom-html-parser.tsx

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 13:24:07 -04:00

67 lines
2.0 KiB
TypeScript

import { useCallback, DragEventHandler, RefObject, useState, useEffect, useRef } from 'react';
import { getDataTransferFiles } from '../utils/dom';
export const useFileDropHandler = (onDrop: (file: File[]) => void): DragEventHandler =>
useCallback(
(evt) => {
const files = getDataTransferFiles(evt.dataTransfer);
if (files) onDrop(files);
},
[onDrop],
);
export const useFileDropZone = (
zoneRef: RefObject<HTMLElement>,
onDrop: (file: File[]) => void,
): boolean => {
const dragStateRef = useRef<'start' | 'leave' | 'over' | undefined>(undefined);
const [active, setActive] = useState(false);
useEffect(() => {
const target = zoneRef.current;
const handleDrop = (evt: DragEvent) => {
evt.preventDefault();
dragStateRef.current = undefined;
setActive(false);
if (!evt.dataTransfer) return;
const files = getDataTransferFiles(evt.dataTransfer);
if (files) onDrop(files);
};
target?.addEventListener('drop', handleDrop);
return () => {
target?.removeEventListener('drop', handleDrop);
};
}, [zoneRef, onDrop]);
useEffect(() => {
const target = zoneRef.current;
const handleDragEnter = (evt: DragEvent) => {
if (evt.dataTransfer?.types.includes('Files')) {
dragStateRef.current = 'start';
setActive(true);
}
};
const handleDragLeave = () => {
if (dragStateRef.current !== 'over') return;
dragStateRef.current = 'leave';
setActive(false);
};
const handleDragOver = (evt: DragEvent) => {
evt.preventDefault();
dragStateRef.current = 'over';
};
target?.addEventListener('dragenter', handleDragEnter);
target?.addEventListener('dragleave', handleDragLeave);
target?.addEventListener('dragover', handleDragOver);
return () => {
target?.removeEventListener('dragenter', handleDragEnter);
target?.removeEventListener('dragleave', handleDragLeave);
target?.removeEventListener('dragover', handleDragOver);
};
}, [zoneRef]);
return active;
};