7079462503
- 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>
67 lines
2.0 KiB
TypeScript
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;
|
|
};
|